This guide is both a view on monster AIs as they will be in alpha6 and a call for features requests if there are any, about AIs obviously.

The day before

Previously monster AIs were extremely simple:

  1. Check if I want/can cast a spell
  2. If so, then cast it
  3. If not then move toward target in straight line

And .. that's it.

Then DarkGod came and said "Thou shall be smart!"

The day after

In alpha6 monsters will be able(and will have to use) the new AI framework which consists of:

How does AIs work

The engine when it is time to make a monster take its turn lookup the monster current AI and calls it. The AI does its work and returns telling the engine if it must now move the monster in a certain direction or if it must do nothing(i.e: the AI did cast a spell). (Note that it is then possible to make a monster cast 3 spells per turns AND move, isn't that groovy ?)

Simple example

-- Movement AI: The zombie

-- Very basic "zombie-like" AI: move toward the target, and hit it.
ai.new
{
        name    = "ZOMBIE"
        state   =
        {
                MIN_RANGE = -1
                BEST_RANGE = -1
        }
        init    = function(monst, state)
                print("init done")
        end
        exec    = function(m_idx, monst, state)
                local range = flag_get(state, FLAG_BEST_RANGE)
                if range == -1 then range = flag_get(state, FLAG_MIN_RANGE) end
                local y, x = ai.target(monst)
                local dist = ai.distance(monst)
                if range == -1 or dist > range or not los(monst.fy, monst.fx, y, x) then
                        monst.ai_action = ai.action.MOVE
                        monst.ai_move_y = y
                        monst.ai_move_x = x
                else
                        monst.ai_action = ai.action.MOVE
                        monst.ai_move_y = monst.fy * 2 - y
                        monst.ai_move_x = monst.fx * 2 - x
                end
        end
}

What does this do:

That's it! This AI will move dumbly toward its target and hit it when it is close enough.

Spellcasting

Now an example of a dumb caster:

-- Casting AI: The dumb random cast

ai.new
{
        name    = "RANDOM_CAST"
        exec    = function(m_idx, monst, state)
                local y, x = ai.target(monst)
                local spl = flag_get_rand(monst.spells)

                if projectable(monst.fy, monst.fx, y, x) then
                        local level, fail = flag_get(monst.spells, spl), flag_get2(monst.spells, spl)
                        set_auto_cast(m_idx, level, y, x)
                        if get_mana(spl) <= flag_get(monst.flags, FLAG_MANA_CURR) then
                                if cast_monster_spell(m_idx, spl, level, fail, y, x) then
                                        monst.ai_action = ai.action.OTHER
                                        flag_inc(monst.flags, FLAG_MANA_CURR, -get_mana(flag_get(monst.spells, spl)));
                                end
                        end
                        unset_auto_cast()
                else
                        monst.ai_action = ai.action.REST
                end
        end
}

What does it do ?

Easy and dumb! Not we can bypass the mana check, if we do not want monsters spells to use mana.

Combining AIs

-- Combinaision AI: cast spells and move toward target

ai.new
{
        name    = "SPELL_AND_MOVE"
        state   =
        {
                MOVE_AI = ai.NONE
                CASTING_AI = ai.NONE
        }
        init    = function(monst, state)
                ai.init(monst, flag_get(state, FLAG_MOVE_AI))
                ai.init(monst, flag_get(state, FLAG_CASTING_AI))
        end
        exec    = function(m_idx, monst, state)
                if rng.percent(monst.freq_spell) then
                        ai.exec(flag_get(state, FLAG_CASTING_AI), m_idx, monst)
                        if monst.ai_action == ai.action.OTHER then return end
                end
                ai.exec(flag_get(state, FLAG_MOVE_AI), m_idx, monst)
        end
}

This AI combine 2 AIs to work. Basically it is a move or cast spell AI, just like the old T-Engine AI.

What does it do:

Now with this AI we can combine all other basic AIs to make a new range of AIs. If we have a move-like-a-snake AI we can have a random caster snake. If we have a smart-cast AI we can have a smart casting snake-like moving monster. You can make custom AIs for your boss. And so on, the limits and without limits :)

You will have to check the ToME module for a example of a smart casting AI.

Things to remember

The more monsters, the more complex the AIs the slower the game will run. If is fine to do an overly complex AI for 5% of the monsters, but not for 90% of them(probably).

Have fun!

How to use them ?!

Last thing, how to give monsters AIs ? First, remeber, a monster with AI will just stand there doing nothing.

Now it's quite simple, in the monster flags(or default flags) simply add:

AI = ai.ZOMBIE
AI_STATES = getter.flags{ MIN_RANGE=3 }

That's all yes, define the AI and set the parameters you want.

So for the spell-and-move AI we get:

AI = ai.SPELL_AND_MOVE
AI_STATES = getter.flags{ MOVE_AI=ai.SNAKE CASTING_AI=ai.RANDOM_CAST MIN_RANGE=3 }

Chatter

BucketMan: AI will be something we can change at any time from code, yes? So...after the battle with the Red Ribbon Army, I'll be able to assign Mai and Shuu an AI that walks them back at normal speed to their standing position at Emperor Pilaf's side, and once they get their resume never moving? I'll be able to create guards who walk back and forth between two points endlessly, until a condition is met, or the player enters within a certain range? I'll be able to have fast moving 'spell casters' that move AWAY from the player if they're at melee range, and stand stationary and cast if they're at range? Excellent! Since you're asking for feature requests...I suppose pre-defined AI's that did each of those three things would be very nice. ;) (Walk to y/x, 'patrol' between two points unless, and 'avoid' player but cast while at range.)

DarkGod: Indeed you will be able to do that. :) I might add some of those yes but really they are not hardto do, it's good for you .. and THEN I can stealthem and include them in the engine ;>

ReenenLaurie: This is what I envisioned... better AI, and then less crazy monsters (ie. not 50000 HP, just being smarter and therefor trickier to kill).

Anyway, stuff like ball / summon spells when LOS is broken. This would really make the game hard, if not impossible, but it can be balanced or very restricted to *smart* spellcasters.

DarkGod: Yes obviously not every monster should be a walking angel of death with a IQ of 350 :) As for HP actaully for ToME3 we will rescale player & monster HP to be more similar(mainly due to the fact that friendly monsters will work better this way), but it is lpayer HP taht will be reworked, that his player will have about 3 times the HP of ToME2, monsters will have the same as now and monster atatcks will do 3 times the damage they do now. Changes nothing for the player but makes pet much more effective without ugly hacks(and possessors will be easier to compute too ;)

ShrikeDeCil: I think this is possible under what's listed above due to the inclusion of the state variables, but I thought I'd mention it. A collective intelligence type AI. The packs of wolves should work as a team. The worm masses aren't really separable in the first place. Many of the various breeders in fact. Using the state variables to keep track of 'center of mass', or enumerating pack members, or whatever seems like to could be used for adding some simple cooperativeness. Yes?

DarkGod: Sure, although there might not be a need for doing that, in T2 pack animals already worked as a .. pack, without any state machine going on. Anyway I'm planning a "battle mode" subsystem that will add group AIs to create large battles between multiple factions, like helm's deep, the 5 armies, the storming of isengard, the assault on the black gate, ... This will work by having each monster get a very basic AI that just does what the state commands it and an "overmind" AI that compute all the batte strategy and tells which monster to do what. It should also feature a UI mod to allow the player to act as one of the armires general/captpain/whatever and form monsters into battle groups, giving each of them orders and getting visual reports of the groups status.

Module Developers Discussion/Module Writing How-To Guides/How to make monster smart(or dumb), the grand AI guide! (last edited 2006-09-20 07:49:37 by DarkGod)