This is only half suggestion, it’s as much ‘discussion of a neat AI strategy as relates to a DF type game for my own amusement’
Context Sensitive AI for various behaviours.
Actors have goals, and have a set of actions they can take to achieve those goals. In a game where you can create any creature imaginable, and doubly so where an AI is expected to be able to generate these creatures on the fly, it’s important to be able to assign behaviours to an actor in a procedural manner. A good model for this is Context Sensitive AI.
Overview: In context sensitive AI, the actor has an overarching goal it’s trying to achieve. During each cognitive ‘turn’, the AI first determines whether it’s overarching goal is still appropriate. This is really ‘be a PC follower, civ member (dwarf), animal, raider, or soldier’. Other than flipping between soldier and civ, the only real change likely to happen is between PC follower and civ member in adventure mode, although if you start a fortress on a dark tower it’s possible to have the AI flip between raider and civ.
The next layer is current activity. For civ members, this involves whatever civ task they are engaged in (mining, building, farming). Attacking, retreating and following are the other major categories here. A check needs to be made that the activity is still valid. (This is where LOS checks for monsters are performed, checks are made to make sure your task destinations aren’t outside your burrow, and verification is made that the task is still the most important thing the dwarf has to do.)
Finally there is the plan step. For civ activities, the plan usually consists of the path. Obviously actors path to an item and remember that path. During the planning step, a dwarf would recheck that path (quick spot check to make sure the bridge isn’t raised and no doors have been locked, and the path doesn’t take you into violation of any standing orders). This is NOT a repath, but could become one if necessary.
Layers could obviously be stacked deeper if need be, for instance, a biological layer could be added over everything to handle the need to eat, sleep, and drink.
Basically, what happens is, every cognitive ‘turn’ (which need not be every actor action turn), the actor digs down through sets of behaviours it has available to it. The behaviours are organized by context, allowing an actor to only compare a small subset of ‘reasonable’ actions each turn. It also creates a generic ‘behaviour fitness test’ that automatically adds behaviours to a creature as they become appropriate for that creature. For example, all actors would test for hunger related activities (go get food, hunt, hunt for vermin), but creatures that don’t eat would never find them to be fit activities because they would never be hungry. The vermin hunter tag would enable that behaviour to be selected. Imps with the ‘throw fireball’ option will be able to select that combat option from their list (and have it automatically sort for when it’s the best option).
Example:
Goblin Siege behaviour.
As it stands goblins show up with murder in their hearts, path to the nearest dwarf, and then run when they are mutilated. Let’s see how this works in a context sensitive world.
Step 1: Arrival.
The goblin shows up at your fort cloaked. He knows he is a raider. His first check is to see whether he should still be a raider. The fitness check is run: He’s a raider class creature at a site owned by a hostile civ. Being a civilian, soldier, PC follower all come back 0. Being an animal comes back rather low, and the raider comes back high. Yup, he’s still going to act like a raider.
He next decides what to do as a raider. At a base level, he can ‘Scout’, ‘Assault’, or ‘Retreat’. He’s cloaked, there are no enemies in sight, and all of his friends are alive and happy. The numbers come back Scout 90, Assault 50, and Retreat 20 (Goblins are inherently skittish critters). Scouting it is.
Under the Scouting AI, the only option is ‘path to closest dwarf’. Later on, we’d like to add a few more options, like ‘ambush specific dwarf’ or ‘disarm traps’, but for now, this is what we’ve got. Pathing to the nearest dwarf comes up with an action plan (the actual path).
Step 2: Stalking
Our murderous goblin is well on his way. He takes a few steps down his path. After he gets a few turns, he stops to rethink things. Yup, he’s still a raider. Yup, he’s still scouting, and still pathing to the nearest dwarf. Checking the path however, there’s a problem. The dwarf has moved! So he recalculates his path and continues on.
Step 3: The Attack
Finally, the dwarf is in sight: A lone wood cutter with naught but 2 dogs to guard him. The goblin reconsiders. He’s still a raider. Now, the numbers are closer. Scout is still 90 (it will be so as long as he’s cloaked.) Assault has increased to 70 (there is an enemy that is close), and he’s rethinking this whole combat thing now that he’s actually seen a foe (Retreat = 40). Scouting is still the high number, so he continues to close.
Step 4: Discovered!
Continuing to simply path to the dwarf, the goblin runs into one of the dogs. He is no longer cloaked. He’s still a raider. Scout has dropped to 50 (where it should stay). Assault is 85 (next to an opponent) and Retreat is 40. The goblin switches contexts to Assault. Assault’s context actions simply consider all enemies in LOS as potential targets. Their potential is a combination of the value of the target, it’s threat rating, and it’s proximity. In this case, the dwarf is worth 50 to the dogs 25, but the adjacent dogs proximity provides a boost to keep it the preferred target (Dog=75, Dwarf = 65, other Dog = 40)
Now that the goblin knows who to attack, it considers how. This is where things get REALLY complicated. It considers a host of combat options, most of which it rejects out of hand (for example, the fitness of the ‘throw fireball’ action is 0). In the end, it’s only real options are ‘attack with sword’, ‘attack with shield’, ‘drop sword and wrestle’, ‘drop shield and wrestle’, and ‘back away’. By far, the sword option is preferred, so it does that.
Step 5: Combat
This process continues for several turn, with the other dog closing to melee, and the fight raging on. Because both dogs are now in melee range, there is nothing to choose between them for attacks. The goblin does, however, have a preference for continuing to attack the same dog he’s been in combat with, although a dodge that bring him out of contact or a chance for a killing strike at the other dog may change that preference.
Step 6: Retreat
Note that throughout this entire process he’s continuing to evaluate his status as a raider and also considering either fleeing or going back into scout mode (unlikely). After the dogs are mobbed and killed, the goblin will likely stay in assault mode and attack the next closest dwarf (since everything is still far away, the closer animals won’t have sufficient nearness weights to overcome DWARFDEATH). At a certain point the changing odds (both through armed dwarves getting closer, and nearby allies dying), the Retreat option will win out over the assault option.
This is another place where the context sensitive AI has power. The switch to retreat is not a single binary moment where everyone runs. Each actor will determine when to retreat based on its own circumstances. Assuming that one units decision to retreat will affect another’s, this will create a ripple effect on the battlefield. Additionally, an actor that finds itself outnumbered in an area may retreat back, but finding itself suddenly in the midst of allies, may reacquire its courage. Imagine a group of goblins attacking with several troll aides. When the fighting starts to go south, the isolated goblins may flee the field, while those surrounded by their troll allies may fight on.[/size]
“But Granite26”, you say, “All of these behaviours describe exactly what goes on now!” That is true, and intentional. The power here is in generalization and decision-making. If you want to complicate the way siegers go about attacking a fort, you’ve got everything divided up into neat little packages. Suppose you want to add a new ‘trap disarm’ behaviour for your goblins. Obviously a goblin in a fight or running isn’t going to stop to disarm traps. Simply add a ‘trap disarm’ context under scouting. In the future, all raiders, of every stripe, will consider entering into the trap disarm context. (and thus looking for traps, or going to traps others have found, and attempting to disarm them). This AI behaviour will be gated. Thus, while all raiders will consider it, only raiders with graspers and intelligence will actually try it. Additionally, the context fitness tests automatically compare this behaviour with all other possible behaviours that are appropriate to the given situation.
Other ways this works:
Hunger: Tired of your dwarves stopping in mid action because they are hungry? High level context weights involving how long a task is expected to complete will compete nicely with increasing hunger. If your dwarf is bored, he’s liable to eat earlier than if he’s in the middle of a task, and a long task that is near to completion may be capable of motivating a dwarf to drive herself to great thirst before stopping for a drink.
Multiple special combat capabilities: Do you spit acid, or throw a fireball? Fitness tests innately compare the merits of all special actions, without the need to program special logic for combinations.
Actor motivated behaviour: When do I run away? How often do I eat? Using actor specific variables in the different fitness tests will allow each individual creature to behave in an entirely different fashion, despite the fact that EVERY ACTOR uses the exact same AI routines.
Multiple leverage of behaviours: There are numerous ways to get into a fight, but they’ve all got different reasons for being there. Hunters, Raiders and Guards all get into fights, but they’ve got different reasons for being there, and need different checks to get out. A hierarchical structure allows for ‘Combat AI’ to be generalized nicely. (For example, a Raider would constantly be checking ‘is it time to run away’, while a Hunter would need to allow animals to escape after it had killed it’s quota)
What vs. How: Things like ‘which side of the tile to mine’ could be decided after ‘mine this tile’. (Even if the best way to mine the tile was part of the decision TO mine that particular tile)
Speed: It may seem like checking ‘Am I still a goblin raiding the fort’ is useless overhead (it’s not, charm skills, etc), but reducing the number of options applicable in a situation WHILE still being able to recognize when a situation has changed (and consider new options) reduces a lot of AI overhead.