This thread contains documentation of how ToEE's combat AI works, based on experimentation. Most of the basics are covered, though some things still need to be tested. So, how does ToEE's combat AI work? Quite simply, any critter seems to read off of a list of commands stored in the strategy.tab file. A command list is assigned in protos.tab, via 'AI Strategy Type'. E.g. - open up protos.tab with the ToEE World Builder, look up proto 14111 (Noble Salamander) and you'll see his strategy type is 'Salamander', which has a corresponding entry in the strategy.tab file. If no particular strategy is assigned, then it probably uses the Default entry. (or maybe the first entry? needs testing!) How do I interpret all the mumbo jumbo inside strategy.tab? The strategy.tab format mostly seems to be as follows: [strategy name][tab][command][tabx3][command][tabx3]...[command][bunch of tabs] For instance, let's take a look at the new AI for Belsornig. Code: Belsornig New AI (71) use potion target threatened cast single 'Hold Person' class_cleric 2 attack threatened clear target target ranged target closest target high ac cast area 'Unholy Blight' domain_evil 4 cast area 'Dispel Magic' class_cleric 3 cast area 'Sound Burst' class_cleric 2 clear target target self cast single 'Divine Power' class_cleric 4 clear target attack approach It's hard to tell from the formatting in this forum post, but most commands are separated by 3 tabs - so if you were typing this line in notepad, you'd enter it as: Code: Belsornig New AI(71)[tab]use potion[tab][tab][tab]target threatened[tab][tab][tab]cast single[tab][tab]'Hold Person' class_cleric 2[tab]attack threateend[tab][tab][tab]clear target[tab][tab][tab]... I'm not sure if all the tabs are actually needed - this could use some testing I guess - but it seems that's the format that is used. As we can see, most commands are followed by 3 tabs, with the only exception being the cast spell commands (cast single, cast area, cast party, cast fireball) which are followed by 2 tabs, the spell name, and another tab. The way ToEE seems to process these commands is to start from the beginning of the list every new round, and try to execute them in sequence until the NPC runs out of actions. So, taking Belsornig's AI for example, the AI would try to do something like this: use potion - > "Do I have a potion?" If so: Drink it! and move onto next command. If not: skip to next command. target threatened - > "Search for a hostile PC/NPC in melee range" If one is found: Make it the target, and move onto next command. See more detail below. If not: skip to next command. cast single 'Hold Person' class_cleric 2 If it can be cast: cast it on the target! If not: skip to next command. attack threatened If there is a threatened target, and it can be attacked (i.e. enough time is left): whack at it! and move onto next command. See below for more detail. If not: skip to next command. etc etc. I used to think that the target commands had some clever interaction with each other, this doesn't appear to be the case. E.g. commands like 'target closest', 'target high ac' etc. will simply override all previous targeting commands and pick a single new target. And yes, that means there are currently redundant commands in Belsornig's AI. Hey, the AI's pretty stupid! Can't I make it smarter than that? Yes, there is a way. Credit goes to Livonya's ingenuity for this. While ultimately the AI will follow the set of instructions as specified in the strategy.tab, the strategy type itself can be swapped via scripting: Code: obj.obj_set_int(obj_f_critter_strategy, #) Where # denotes the index of the strategy.tab index (the first entry being 0, the second entry being 1, and so on), and obj is the object's handle (usually it's attachee in the san_start_combat script). So, what a clever modder can do, is write some scripting to test how many enemies are close, what classes they are, what the party alignment is, what spell conditions are in effect, who is wounded and how badly, etc., and determine the appropriate strategy.tab entry accordingly. (some new entries may have to be custom tailored, of course) The script should go in the creature's san_start_combat - the script that fires at the beginning of the NPC's round. In pseudo code, such a script may look like this: Code: def san_start_combat( attachee, triggerer ): if important friend is hurt: switch to 'cast heal spells' strategy return if enemy is buffed: switch to 'cast dispel magic' strategy return if party is non-evil aligned: switch to 'cast unholy blight' strategy return if none of the above: switch to 'ordinary' strategy return What AI commands are available? Here is a list of commands taken from the temple.dll file and an explanation of what they do. The commands can roughly be divided into targeting, movement, spell casting, ability usage, and attacks. Most of them have been tested in a controlled environment (so to speak), but some require more testing still. Targeting Commands: target threatened Target highest initiative in melee range. Includes unconscious targets! Summons aren't given special priority. Ranged attack? Spell casting? target closest Target closest conscious (as opposed to target threatened, which will also target unconscious and even dead enemies) Tested both when there are threatened and when there are no threatened, and compared with party/queue order. Summons aren't given special priority. Ranged? Spells? target high ac Target globally highest AC, then sort by initiative. Globally = regardless of range (up to some limit). Conscious targets only. Takes proneness into consideration (but will still attack prone if it has highest AC). Does not take racial modifiers and cover into consideration. target low ac As above, but the other end. target ranged Target closest conscious enemy ranged attacker (i.e. bow/xbow wielder). If there are none, go to next command. Will target prone characters, but not unconscious. Not hypnotized by summons. target bad reflex Seems to target closest member of classes with bad reflex bonuses, or something to that effect. Seems to be unaffected by ability score bonuses. Doesn't target unconscious characters. Is it affected by cloaks of resistance, spell boosts and such? I.e. it will tend to target wizards, sorcerers, druids, clerics, fighters, paladins and barbarians. It will tend to ignore rogues, bards, rangers and monks. Spiritual weapons are level 1 fighters, so this is likely to target them. target bad fort As above, except: Will tend to target wizards, sorcerers, bards, rogues. (the "frail ones") Will tend to ignore rangers, monks, fighters, paladins, barbarians, clerics and druids. Spiritual weapons are level 1 fighters, so this is unlikely to target them. target bad will As above, except: Will tend to target barbarians, fighters, paladins, rogues, rangers. (i.e. mostly your tanks/archers) Will tend to ignore rangers, monks, clerics and druids. Spiritual weapons are level 1 fighters, so this is likely to target them. target damaged Targets character with globally highest number of damage received (absolute number of HP reduced). Doesn't target unconscious characters. Ignores subdual damage. No preference for summons. target prone Target closest prone character. Doesn't target unconscious enemies. No preference for summons. If none are prone, go to next command. target self Target self. Useful for buffs, or AoE spells you wish to radiate from the NPC outwards target nearby buffed Target buffed characters within melee reach. If more than two are present, target the one with highest initiative. Will target unconscious targets! Seems like it only responds to some buff spells. Tested ok with: Bull's Strength, Owl's Wisdom, Resist Energy, Endure Elements, Heroism, Resistance. Tested nagtive with: Cat's grace, Barkskin, Enlarge Person, Good Hope. Shows no preference for summons. target nospell Seems to work just like target closest: targets closest conscious enemy. Has shown no preference for non-spell casters over spell casters. Has shown no preference for non-buffed characters over buffed characters. Perhaps has to do with the attacker being a non-spell caster? Or having run out of spells? Needs testing! Shows no preference for summons (or non-summons for that matter). Needs more testing! target friend hurt Target most badly hurt friend (in terms of percentage). Hurt = 75% of max HP or less. Non-lethal damage doesn't count. Includes unconscious friends. Doesn't include dead friends. Useful for enemy heal spells. Seems to have limited distance - greater than reach, but not much further. (around 35-40 in terms of distance_to() function) Does target unconscious friends. Doesn't target dead friends. target friend nospell For buffing melee ally? I can confirm that it works for buffing at least (e.g. casting Bear's Endurance midfight even if friend is not hurt) needs testing! Possibly - targets someone who doesn't have the specified spell after 2 tabs (going by how it's used in Wizard 5th (old) - needs testing! target friend low ac Seems to target a friendly character with the lowest AC. (not thoroughly tested though) Player summons aren't treated as friends. Does it require the same faction? Only one, or all? Are enemy summons treated so? Seems to have limited distance - greater than reach, but not much further. (around 35-40 in terms of distance_to() function) target friend high ac clear target Clears target. If there are no other target commands, AI will then default to leftmost character portrait in the party order (i.e. game.party[0]), even if he's dead or unconscious. Useful for clearing out initial target acquisition, which may cause unwanted behavior in certain situations. Otherwise, the next target command will just pick a new target according to its own rules. (highest initiative, etc) Spell casting commands: cast single - cast a spell on a single target (might work with AoE spells by causing them to be centered on the target - needs testing) cast area - cast AoE spell cast fireball - seems to be like cast area, but aborts the casting if friendly NPCs are within the area of effect, or at least in some cases adjusts the targetting to hit PCs only (needs testing!) cast party - unknown? needs testing cast single alone - cast spell if no allies are present? needs testing! (probably used to ensure summons are limited) use potion Use a potion or scroll. Will use heal potions on self only, and only if necessary, and other scrolls/potions if they are available. Can be used to script more intelligent spell casting, a la Death Knell and Create Undead scripting seen in Skeleton Priest and Tower Brigand fights. Movement Commands: approach Close the distance to the target. By "close", I mean close. Zero distance. This may trigger unwanted AoOs. Thus in some situations it is better to just use "target X, attack" - the AI will then come just within attacking range. A possible player exploit of this is to 5' step away after attacking, causing the AI to waste a move action to close the distance and possibly take AoOs. A remedy of this could have been the 5 foot step command. Unfortunately, ToEE AI treats 5' step as a "back off with 5' step" command, as long as it is within threat range of enemy. Probably requires some clever scripting (like Livonya's) to handle optimally. Alternately skip the approach command and just attack! sniper Take 5' away when ranged weapon is wielded and NPC is within reach of a melee attacker. If 5' step won't take the NPC out of harm's way, it'll switch to melee. Works right when PC has reach weapons, too. If the NPC wields melee weapon, it seems to do nothing, as long as there is some targeting command. (others may act strange, alternating between targets, etc) Might sometimes cause ranged attackers to switch to melee even if not threatened. five foot step Back away with a 5' step. Archers engaged with melee fighters already have sniper for that, which will also switch to melee if AoO can't be avoided with a 5' step. flank Move so as to try and flank target. Might cause critter to catch a lot of AOOs in the process however! Also, needs testing for when there is no other allied NPC adjacent to the target, etc. Attack / tactical commands: attack Attack target. Will attack friendlies as well if they are targeted. If target is not within reach, will act as move + single attack command. attack threatened Attack target within threat range. If there is none, go to next command. e.g. "target ranged, attack threatened, target high ac" means it will look for ranged attackers within melee range, and if none are available, it will seek out highest AC. ranged AI? spell casting? coup de grace Coup de graced paralyzed characters. Doesn't seem to work on Held and Unconscious targets. Most targeting commands don't target unconscious targets anyway. trip Make a trip attempt. charge Charge attack. Bugged in that it causes nonlethal damage. ready vs spell Useful against casters! As seen in Temple Tower and Moathouse Ambush fights. ready vs approach Best left for humans to use... Abilities: power attack Turns power attack on. (or does it???) Probably sets to maximum value allowed (needs testing!). Apparently cannot be reset? Can be directly manipulated via script - with the command: Code: [object].d20_send_signal(S_SetPowerAttack, #) Where [object] is the object handle and # is the desired Power Attack level (up to the creature's BAB). expertise Turn Combat Expertise on. As with power attack? (needs testing!) rage Fly into barbarian rage. partial charge Related to archery (the code checks for a Ranged Weapon) Doesn't invoke charge attack, certainly. Maybe has to do with enchanted item charges, e.g. Lareth's staff? Or other slider related setting, e.g. Power Attack. Needs testing! reload Reload crossbow. go ranged Switches to ranged weapon if one is available. However, it seems to waste the round in doing so (even if one is already equipped). What if critter has quick draw then? Anyway, might be better to just use Livonya's scripting system to switch weapons around. go melee As above with melee weapon? needs testing! Other relevant links: AI Update (some Livonya + Dulcaion goodness) http://www.co8.org/forum/showthread.php?t=1328 Inventory & AI manipulation (Livonya again; 'twas her last modding effort, it seems )
Very helpful :clap: I can already see a few ways to improve the Mad Wizard. Can I just confirm I have no idea what 'partial charge' does, nor did Liv when I ask her, and the 'sniper' / 'partial charge' strategy line (#8 in KotB) is ugly in practise as it just makes the NPC approach the party rather than shoot them. 'Target threatened' will cause the NPC to keep hitting an enemy on the ground, where-as 'target closest' will cause the NPC to ignore unconscious foes (the difference between whether or not an NPC follows through and kills you when you are -5 on the ground, or whether he just goes and attacks someone else). 5' step is indeed essential for bowmen and spell-casters, but of limited value for melee - the NPC will try to take a 5' step every round, and just as likely step away from the target and end up doing nothing. Liv therefore implemented a script whereby the NPC monitors their health, and if they need to use a healing potion their strategy is changed to one with 5' step / 'use potion', then it is changed back again. 'Power attack' can be switched on but not, I believe, off again. 'Expertise' may be the same. Some of the spell ones are interchangable, as they no doubt appear. 'Target self' / 'Cast Area' can be used for friendly AoE spells, like Bless and Bane, but 'Target Self' / 'Cast Single' works too. While there are limited ways to implement cast-on-demand, one way is to create a potion that simulates a spell, then monitor when it is best to use it, then create that potion in the NPC's inventory and if 'use potion' is the first thing (as it should be, so the NPC uses healing potions as needed) they will automatically use it. This is how the Skeletal Priest, God bless him, knows to pull 'Death Knell' at just the right moment. It even has a counter to make sure he doesn't try it more times than he would have the necessary spell slots.
Sorry for joining in blind (50% miss chance), but this is Partial Charge from SRD: If you are able to take only a standard action or a move action on your turn, you can still charge, but you are only allowed to move up to your speed (instead of up to double your speed). You can’t use this option unless you are restricted to taking only a standard action or move action on your turn. Perhaps it is a command that is used in conjunction with Diehard?
Yes, Slowed restricts a creature to single (aka partial) actions. Zombies are the famous partial chargers. They can also be slowed but not reduced to less than a single action per turn. However, I am not sure if the RAW Partial Charge is the same as what the modders were discussing above.
Helpful strategy.tab tip: if you use Excel to edit this file (I believe Ranth suggested that sometime, and it does work quite well as far as all the tabs and putting stuff in the right place goes), take care to check your edits with a different program afterward. It seems that Excel takes the liberty of removing the first single quotation mark (') from spell names. Some of the time. So you might have a spell entry called Code: Cure Light Wounds' class_cleric 1 and that would probably biff the AI for that spell.
Note on factions: Mobs who have the '0' faction might get attacked by other critters, even if they share other factions. Case in point: Aern and his Hydra would get attacked by their fellow Fire Temple members, even though I gave them the Fire Temple faction (5). They also had faction 0; removing it stopped the friendly fire situation (amusing as it was ). Faction 6 (Water Temple) doesn't seem to cause this. Haven't tested with other factions. More Experiments: If the AI consists of a single target command, it seems possible that the creature will approach and attack despite the lack of such commands - at least that's what I've seen with target threatened. attack threatened alone will have bad target aquisition - seems like it will pick a non-dead target and keep pursuing it (unless it's very far away; even then once the AI "catches scent" of that target, it will move in on it again, ignore all else) Chaining target threatened and target closest one after the other - the latter was selected and had overridden the former. clear target, then target ranged: If there was a ranged character, it went after it. If there was none, it acted the same as clear target mode (i.e. game.party[0] is the target) target ranged, then clear target: Behaved liked clear target, even when there was a ranged guy. target ranged, attack, target closest: If there was a ranger attacker, the AI pursued and attacked it. If there was none, it didn't attack the closest char, rather it seems that the attack command caused it to latch on to its original, first target and fanatically pursue it (i.e. even if it ran away and there were others nearby). Maybe clear target could solve this? In other words, it's not like if one "target" command fails it moves on to the next! target ranged, attack, target closest, approach, attack: Same as above. Ok, I think I've figure it out. When combat begins, the AI acquires initial targets based on proximity, as a default. Or something to that effect. The various "target" commands add a target on top of that. Thus, for instance, in the "target ranged, attack, target closest" sequence, it became stuck with the initial targets, and that's why it didn't pursue the "target closest" enemy. When I added "clear target" at the beginning: clear target, target ranged, attack, target closest It then attacked the closest guy! (tested by bring my guys back and forth, closer and farther from the AI) When someone popped an Xbow, it immediately attacked him instead of course. Also tested same sequence of commands with only one tab in between commands - it indeed makes a difference, tabbing is important, at least to some extent. It seems that the last command doesn't need any tabs following it - at least "clear target, target closest" worked for me that way. A "target X, approach, attack" sequence is suboptimal: "approach" causes the AI to zero the distance. Thus, if the player moves even a little from the AI, probably with 5' step, the AI will use up a move action to close the distance, taking AoOs on the way, and won't be able to follow with a full round attack. A better sequence is "target X, attack, approach" - if the AI is within range, it will just attack with a full round action. If it isn't, it will move to attack. May have to follow up with another attack command. Also, this mainly applies for melee characters - you wouldn't want archers to close the distance... target high ac - indeed, seem to target the highest conscious AC character. Doesn't take into account racial modifiers and cover. Does take into account prone penalty (but will still attack prone character if prone character has highest AC) If two characters have identical AC, it targets the highest initiative - even if it's outside the threatened melee area. Dodge? clear target, target ranged, target high ac, attack - target high ac completely overrode target range - i.e. it went for the highest AC, and if everyone had identical AC, it targeted highest initiative. likewise for the reverse order: "target high ac, target ranged" would go for closest ranged attacker, even if one ranged attacker had a higher AC (but was farther away) attack threatened works as advertised - it will attempt to attack a target in melee range. Spellcasting? Ranged attacker target ranged, attack threatend, target high ac - Made the AI look for ranged targets in its melee range, if none available - go for highest ac. target high ac, attack threatened, attack - the idea was to get it to attack the locally highest AC. No luck, it went for the globally highest AC. A bunch more undocumented experiments for target damaged, target prone, etc. Target friend low ac - Two spawned trolls treated each other as friends, at least. They didn't treat creatures I summoned as friends. Partial Charge - clear target, target ranged, partial charge, target closest, attack - It ignored the ranged attacker and attacked the closest character (unless the ranged attacker was the closest one...) Target command modifiers - Trying to see if target commands can have inputs (like how cast commands have inputs) target ranged [tab] 2 didn't work (thought it might target the next ranged attacker on the list). In fact, it broke the command. Sniper - clear target, sniper - acted like target closest, attack for a troll enemy monster. When I spawned Brigand Archer with that AI, who had a melee weapon, it seemed to target distance enemies (alternating between distant characters, taking AoO on the way) clear target, target ranged, sniper, attack - targeted the right PC, and took 5' steps away from attackers Go ranged - clear target, go ranged, target ranged, attack - indeed caused a brigand archer to wield ranged weapon, but he failed to attack (maybe needs partial charge, sniper?) other variations tried: clear target sniper go ranged partial charge sniper target ranged attack clear target sniper go ranged partial charge sniper target ranged attack clear target sniper go ranged target ranged attack clear target go ranged sniper target ranged attack clear target go ranged target ranged sniper attack clear target go ranged target ranged attack clear target go ranged reload target ranged sniper attack None worked right, it seems as though 'go ranged' wastes the NPC's turn.
Sitra Achara - I got your private message on the Codex forum. The Strategy.tab is primitive. A lot of the commands do NOT work. They do nothing. Before I stopped modding TOEE (the second time) I created an alternate way to control the AI by changing the creatures Strategy.tab reference line. This way I could create very simply Strategy.tab routines, but write very, very detailed AI scripts that would change the Strategy.tab reference each round. That way a single creature can use 5 foot step, charge, feint, etc... depending on the situation. That would be impossible using the Strategy.tab alone. It worked fantastic, and was way, way, way more effective than messing with the Strategy.tab itself. At some point I posted how to do this with some examples of how to do it. I couldn't seem to find the thread, perhaps it is in the private Keep On The Borderlands area... I couldn't figure out how to get back into that area. Maybe someone can point you to that thread. If you are serious about working with TOEE AI then I really suggest you check that out. In my opinion it was a massive step forward in TOEE AI, but it was also a work around that Troika never intended. It was only possible because other TOEE mod folks figured out how to make creatures store unique numbers. I am super rusty with TOEE scripting, and I don't want to get pulled back in. I spent way, way, way too much time with TOEE scripting and had to get back to real life... no time to get sucked back into the void again... I am not good with moderation... always all the way in or all the way out it seems. Anyway, a lot can be done with the TOEE AI by combining scripting with Strategy.tab reference switching. You should look into that... Hopefully someone can point you to my original thread... and I assume others may have radically improved on what I was doing by now. If you can't find that thread, and if no one ever points you there... and you are curious about it then send me another private message and I will see if I can't find it on my hard drive and re-post it for you. Good luck with it. TOEE has a great engine, if only the Troika folks could have fixed a few more core problems... ugh... makes me so frustrated. The greatest RPG combat engine ever designed ruined by the lack of time and the rush to get a product out the door before it was finished... a real travesty. It still makes me angry to this day. Livonya PS: Yeah, it must be in the private Keep On The Borderlands forum area as I did a search for all the threads I ever started and that thread is not there... maybe someone can help you get to that or copy/paste it over into this thread.
Hi Liv, I'm aware of your work - I've mentioned it in the middle of the long-ass first post In fact, messing with it in the first place is the reason I'm investigating the AI commands further now. What I hoped for was to further optimize AI for reach weapons (for when it is in the player's hands as well as the AI's), and try to find a solution for the Spiritual Weapon / Summoned Creatures exploit. Certainly the san_start_combat scripting can be used to great effect, but one must have a solid grasp of strategy.tab commands in order to properly utilize it. Except for a certain few commands, I think I have a much better understanding of it now, through lots of testing. I've documented some of the testing itself in the second post, and the results I've obtained in the first. Ted, could you find the relevant thread in the KotB forum and post it here, if there's anything it could add?
Yah, I'll have a look. Needless to say, the Livonya.py file I just threw into 5.6 is the main thing you needed.
Odd discovery: enemy spellcasters may cast spells that are in their spell lists (in protos.tab) but that don't appear in their strategy.tab assignments. Specifically, I added cantrips to a wizard's spell list that don't appear in his strategy entry, and he started casting them after he was out of all his other spells. Did a good job of it too.
What AI routine was he using? Did he have commands other than spell casting after the spell list? (attack, etc) What were his targets? Did they match the targeting commands? Does this only apply to cantrips? Were the spells offensive spells or defensive spells, and were they appropriately cast on friend/foe?
Wow, that's a lot of questions ... just play around with the 'Wizard' strategy and see what you find.
This doesn't seem to actually work, unfortunately. When added to a san_start_combat script, all it does is break the script. Too bad, I could really have used this feature in one of the upcoming Verbomod battles. (Livonya's also got a custom 'change strategy' script in Livonya.py that doesn't work either.) :cry: