Prelude, if you didn't already know, is my proto-Roguelike in C#. I'm using it as a testbed to develop some concepts for importing into Kharne, as well as developing (hopefully) an enjoyable RL in C#.
To whet your appetites, this is the current version of the main AI loop for each creature. Its not a particularily complicated AI, but it is sufficient to givc the appearance at least of intelligent enemies.
// Namespace: Kharne.Creatures.Classes
// Class/Method: Creature.DoStuff()
///
/// The main creature AI behaviour routine
///
public void DoStuff()
{
// Paranoia Check
if (_alive && _awake && _energy > 0)
{
// If the creature is carrying an item that it can use or wants to use, then use it instead of doing
// something else (e.g. drinking a potion if it is at low health)
if (!_UseCarriedItem())
{
// If there is an item on the current square, and the creature judges it to be of value then
// pick it up and do nothing else
if (!_PickupItem(new Item()))
{
// TODO: also allow orders to influence what a creature does, for example, if a creature is
// a minion of the player or another creature
// The status of the creature governs what it does. Beserking differs from normal
// behaviour in that the creature will not cast spells nor will run away if brought
// to low health but will rather will stand and fight
switch (_status)
{
case CreatureStatus.BERSERK:
case CreatureStatus.NORMAL:
{
// Do we have a direct line of sight from the creature to its target?
if (_CanSee(_target))
{
// Update the target location since we can see the target
_targetLocation = _target._location;
// If the creature has mainly melee-based attacks and isn't adjacent
// to its target then attempt to move one square closer (movement is
// calculated using an A* algoritim). Note that the _Move routine deals
// with opening and closing doors on a creature-by-creature basis
if (_AI == CreatureAI.MELEE || !_Adjacent(_target))
{
if (_status == CreatureStatus.BERSERK)
{
// If we're beserking, then simply move.
_Move(_target.Location);
}
else
{
// Some creatures can cast spells, but there is only a certain
// chance of this happening, so check to see if we can cast a
// spell, if we want to, and if so, cast it
if (_CanCastSpell() && !_CastSpell(_ChooseSpellToCast()))
{
// Don't cast a spell so move towards the target
_Move(_target.Location);
}
else
{
// Can't cast a spell, so just move
_Move(_target.Location);
}
}
}
else if (_AI == CreatureAI.MELEE || _Adjacent(_target))
{
// Next to its target so let rip with melee attacks!
_Attack(_target);
}
else if (_AI == CreatureAI.RANGED || _Adjacent(_target))
{
// The first priority of creatures that have ranged attacks is to
// move to their preferred distance. In both cases below, if we can't
// actually move (due to another creature or the terrain) just attack
// anyway with ranged attacks
if (_Distance(_target) < _preferredrange)
{
if (!_Move(_GetMoveAwayLoc())) { _Attack(_target); }
}
else if (_Distance(_target) > _preferredrange)
{
if (!_Move(_target.Location)) { _Attack(_target); }
}
else
{
// Like the melee situation, check to see if we can cast a spell
// and if so, cast one. If we don't do any spells, just attack
// anyway with ranged attacks
if (_CanCastSpell() && !_CastSpell(_ChooseSpellToCast()))
{
_Attack(_target);
}
else
{
_Attack(_target);
}
}
}
}
else
{
// We can't see the target, thus we move to the last location that we hold
// for the target - of course the target may have moved
_Move(_targetLocation);
}
}
break;
case CreatureStatus.AFRAID:
{
// If the creature is afraid, then highest priority is to move away from the
// source of its fear, but if it can't then turn and prepare to fight
if (!_Move(_GetMoveAwayLoc())) { _status = CreatureStatus.NORMAL; }
}
break;
}
}
}
}
}