In this article I’m taking a look at how the characters in my game are designed to behave, from the initial prototype to the final release. Before heading into the main article body know this about the game:
- It’s turn based. So the scoring and decision calculations’s cost are not that heavy (in terms of processing power). They might not work so well in real-time games.
- The game features little to no animation and behavior/actions from and by the characters in the game are described to the player via a short text entry in their log and via visual output (item can be seen coming towards the player — in case it’s thrown, item disappears from the ground on pickup, etc).
- The graphics are minimal. Most characters are just textured quads. With a few proper animations applied to them player feedback can increase tenfold.
- They were initially designed for a quick game prototype and later on expanded. I do not claim this is a good way of handling AI in a dungeon crawler but I believe it’s a good enough method.
Ratio driven, environment evaluating AI
The AI for the creatures in ES:H is the result of combining two well known methods of handling AI’s in the roguelike community: The need driven system and a ratio based decision making system. I will describe these systems from two perspectives: macro and micro.
What is my behavior — Macro
From the get-go I wanted creatures (entities from here on out) to behave different from one another, so that the player would face variety in encounters and surprises at every step. In order for this to happen I needed a way to differentiate them without having to implement custom behavior per individual entity type. As such I turned to the ratio based decision making system by Jared Braysha (known for Labyrinth of Reptoran). In his research paper over at Rogue Basin he describes the ratio approach as simple way of handling dungeons or wilderness encounters, with each monster having a certain probability of doing one actions or another, breaking them down into 4 categories:
Jared went on and described how all 4 possible actions can have a ratio attached to them that dictate how a monster should behave. For movement the behavior is defined by Attack:Pack:Random (the probability of whether a monster will attack the enemy, move towards the nearest monster of it’s type, or just move randomly), Away:Exit:Pack (run away from the monster, run towards the nearest exit or run towards other monsters of it’s type) for Escape, Range:Melee for Attacking and Heal:Teleport:Enhance for Defending.
I only needed to find a way to cycle between possible behaviors so I double down on the algorithm and came up with a master ratio known as AJR — Attack:Join:Random. Attack defines the likeliness to engage the player or another entity, Join the need to group and move together with other entities of it’s type and Random handles moving randomly, searching for valuable items or just doing a random action such as throwing potions at the walls.
During the performAction function the entity checks to see what behavior it should apply and calls the decideRatio function.
If the most desired action is 1 (Attacking) then the entity will perform a check to see if there’s a creature it can attack in it’s movement range:
(distance it can move / turn) * totalEnergy/energyCostForMovement)
An array containing all possible targets is then returned and the target evaluated (stats + equipped inventory items ). The player target get’s a bonus to his evaluation based on his distance from our entity — to avoid having entities fight each other and constantly avoid the player that’s right next to them. If no targets are present in it’s vicinity or if the target is way to
strong (compared to the entity) then the entity will default to doing something random. The same conditions apply if the desired action result Join or Random. In the end if the behavior sought cannot be satisfied it will default on it until an action is found that can be performed (with Random being the last resort).
The easiest way to describe the behavior system based on the AJR ratio is to think of an entity as a zombie with a behavior 1:0:0. Such an entity will always engage other creatures (attack on sight) and move in search of brain(z) when there is nothing to attack. In the same example, a wolf that prefers to engage in a pack would have a behavior of 2:3:1.
Evaluate the environment before it evaluates you — Micro
In the first step, the AI decides what approach to take based on the behavior given to it. Here the AI decides how exactly it should follow that behavior based on what’s happening around it. I call this the environment evaluation phase. I base this approach on Bjorn Bergstrom article on creating interesting
AI’s. The principle behind Bjorn’s system involves “Reasoning and Behaviourism” or, as he likes to put it: “What would happen if I teleported a Kobold into a big dungeon”.
The entire approach tries to map a series of actions and decisions a creature would take in a yet unexplored situation. In the Kobold’s case he would first look around and check if any threat is in sight. He would also feel safer having access to a sword and armor, where safety is set as the most urgent need which needs satisfied. Equipped with both items would change the need to explore the environment, and so on and so forth. The way the system described works seems fairy realistic and not difficult in implementing the behavior, as it boils down to a three step process:
- Observe the environment around the entity (distance check with his viewRange modifier added to his x and y position)
- Evaluate everything in his range (potions, weapons, entities)
- React to the need (if nothing is in his vicinity move towards an unexplored area).
Now, in his article Bjorn assigns sets of values to things that the Kobold can interact with, values such as Love, Fear and Hate (he also recommends evaluating the environment using a LOS — line of sight — algorithm). In ES:H I steer away from evaluating items and entities via the 3 given values and, instead, I score them based on THREAT and VALUE (as in price). The THREAT value applies to other entities and the player and is a direct result based on stats and stats modifiers (such as items in inventory). VALUE is given to items, in the items inception, based on it’s rarity, effects and modifiers.
During the entities evaluateEnvironment( ) phase, it will loop through all elements in it’s range, score them and insert them into an array that is later sorted based on the score. The item at the top of the list is the item that mostly interests our entity. Distance also plays an important factor in the scoring method, since a powerful item nearby > trumps another powerful item far away (more than 1 turn away), especially since there is a chance to meet other THREAT factors on the way there. If nothing of interest is in range the entity will default to the Random behavior and move.
And that is the way creatures that are encountered in the game are designed. A few simple variables with flavored text added to the mix represent the back-bone of the game’s potion throwing, monster summoning, player bashing creatures and characters.
Ebony Spire: Heresy is launching on November 2nd on Steam for Windows and Linux. It’s a first person, dungeon crawling, turn based rpg inspired by roguelikes. The main mechanic revolves around picking up items and using them against your enemies. And the enemies can do the same things you can do.