Combat Artificial Intelligence Scripting
The Dungeon Craft engine provides a method of selecting the best action for any combatant that is not under player control. Dungeon Craft creates a list of all possible 'Actions' when a combatant's turn arrives. It then calls the script in AIScript.BLK to determine which of the actions is 'best'.
'All possible Actions' doe not include those actions that are clearly detrimental to the combatant of other combatants friendly to him. The following actions are eliminated by the engine before the script is run.
- Actions associated with a spell which has the 'Friendly Fire OK' box checked and which target an un-friendly combatant.
- Actions associated with a spell which has the 'Friendly Fire OK' box NOT checked and which target a friendly combatant.
- Actions which are not associated with a spell and which target a friendly combatant.
The scripts are written in a simple Forth language. There are two reasonable ways of going about the selection:
- Pass a list of all the possible actions to the script and have it choose the best.
- Pass two possible actions to the script and have it choose the better. The engine would repeat this process until only one possible action remains.
Each possible action has the following functions defined that provide information about that action. All the functions return a single integer unless otherwise noted. Each function name has a prefix denoting the type of object to which it refers:
- Combatant functions start with “C:”. For example C:State.
- Weapon functions start with “W:”. For example, W:Type
Before using a function which references data in one of the actions, you must have identified which action of the two you are referring to; action A or action B. You accomplish this with the functions “A” and “B”. After using function “A”, for example, all references to data in an action will refer to action A. Likewise, references to a combatant or his weapons will refer to either the active (attacking) combatant or to the target combatant. You should use the functions “Me” or “He” to identify which combatant you are referring to.
- W:Id - the weapon being used – zero indicates “No Weapon”
- W:Type - Type of weapon. See “Weapon Types” below.
- W:MaxRange - The square of the weapon's range
- W:ShortRange – From $AI_ShortRange – default is 1/3 W:MaxRange
- W:MediumRange – From $AI_MediumRange – default is 2/3 W:MaxRange
- W:Protection -The weapon's protection value
- W:Damage - The average damage done by the weapon
- W:ROF - The weapon's rate of fire per round
- W:Priority – The priority assigned by the game's designer. This number defaults to 500 but can be changed by attaching a Special Ability to the weapon named “$AI_Priority” with a parameter set to the desired number.
- A:Type – The type of action. See “Action Types” below
- A:Damage – The average damage done by this action. For ranged weapons that use ammo, this is the damage computed from the ammo description.
- S:Priority – The priority assigned to any spell that is associated with the action. This number is assigned by the designer using the spell editor and defaults to 500.
- C:State – The state of the combatant. See values below.
- C:Distance – 4 * distance * distancebr />
Examples:
- West 1, North 0 gives 4 * 1 * 1 = 4
- West 1, North 1 gives 4 * sqrt(2) * sqrt(2) = 8
- West 2, North 0 gives 4 * 2 * 2 = 16
- West 2, North 1 gives 4 * sqrt(5) * sqrt(5) = 20
- West 2, North 2 gives 4 * sqrt(8) * sqrt(8) = 32
- West 2, North 3 gives 4 * sqrt(13) * sqrt(13) = 52
- C:Friendly – 1 if currently friendly to the party. Else 0. (can change during combat)
- C:AIBaseclass – The bitwise OR of the parameter values of all the combatant's baseclass Special Abilities named “$AIBaseclass”.
The script will receive two possible actions at a time. They are called 'A' and 'B'. Each of the functions listed above can retrieve information from either of A or B by preceding the function with the word “A” or “B”. They can also retrieve information from either the attacker or the target by preceeding the function with the word “Me” or “He. For example:
This function would return a positive number if the weapon damage of action A was greater than the weapon damage of action B, zero if they are the same, and a negative number if B is greater. If you refer to these very often, you might want to define functions to retrieve them more directly. For example:
: DamageA Me A W:Damage ;
: DamageB Me B W:Damage ;
Explanation of data retrieved by the functions:
Action Types – Result of function A:T
The following constants are defined for the possible action types:
0 CONSTANT A:T:Unknnown
1 CONSTANT A:T:SpellCaster
2 CONSTANT A:T:Advance
3 CONSTANT A:T:RangedWeapon
4 CONSTANT A:T:MeleeWeapon
5 CONSTANT A:T:Judo
6 CONSTANT A:T:SpellLikeAbility
Weapon Types – Result of function W:Type
The following constants are defined for the possible types of weapon:
- 0 CONSTANT W:T:NoWeapon
- 1 CONSTANT W:T:HandBlunt
- 2 CONSTANT W:T:HandCutting
- 3 CONSTANT W:T:HandThrow
- 4 CONSTANT W:T:SlingNoAmmo
- 5 CONSTANT W:T:Bow
- 6 CONSTANT W:T:Crossbow
- 7 CONSTANT W:T:Throw
- 8 CONSTANT W:T:Ammo
- 9 CONSTANT W:T:SpellCaster
C:State
- 0 CONSTANT C:S:None
- 1 CONSTANT C:S:Casting
- 2 CONSTANT C:S:Attacking
- 3 CONSTANT C:S:Guarding
- 4 CONSTANT C:S:Bandaging
- 5 CONSTANT C:S:Using
- 6 CONSTANT C:S:Moving
- 7 CONSTANT C:S:Turning
- 8 CONSTANT C:S:Fleeing
- 9 CONSTANT C:S:Fled
- 10 CONSTANT C:S:ContinueGuarding
- 11 CONSTANT C:S:Petrified
- 12 CONSTANT C:S:Dying
- 13 CONSTANT C:S:Unconscious
- 14 CONSTANT C:S:Dead
- 15 CONSTANT C:S:Gone
How the engine goes about using the scripts
- Clear the list of combatants and available actions
- Look at every combatant. Determine his state – friendly, dying, etc. List his shields. Record his location. Add him to the list. The 'Thinking' combatant is always the first in the list.
- List the 'ready-able' weapons for the 'Thinking' combatant. For each weapon, determine such things as weapon type (throwing, etc), damage dice, priority, ammotype, etc.
- List possible ammo for the 'thinking' combatant. Determine its characteristics such as type, damage dice, rate-of-fire, etc.
- List all possible attacks for the monster. Compute damage for each.
- List all possible cells that the 'thinking' combatant can reach by walking.
- For each combatant (other than himself) list all possible actions for each of the attacker's weapons (or no weapon).
- If the weapon is a 'spellcasting' weapon, call the 'SpellCasterFilter' to see if the action should be retained as a possible action.
- If the weapon has a 'SpellLikeAbility' then call the SpellLikeAbilityFilter to see if the action should be retained as a possible action.
- If the action is a Melee action (adjacent target) then call the MeleeWeaponFilter to determine if the action should be retained as a possible action.
- If the action is a ranged action then for each type of ammo (or no ammo) call the RangedWeaponFilter to determine if the action should be retained as possible action.
- If the action is a 'move' (walk; advance) action then the AdvanceFilter is called to see if the action should be retained as a possible action.
- If the action is an attack without weapon then the JudoFilter is called to see if the action should be retained as a possible action.
After all the 'possible' actions have been listed the engine calls the 'Think' script to compare them in pairs in order to find the best. This assumes that the comparisons are transitive: *IF* action A is better than action B *AND* action B is better than action C *THEN* action A is better than action C.
The best action is the one that is taken. If there are no possible actions then the combatant guards.