Last week I was trying out some basic summoning-minions functionality, so this week I've been trying to flesh it out a bit more. The more I was fleshing it out, the more little things appeared here and there, needing attention. So in the end, I spent quite a bit of time trying to tie loose ends. Here is an example of things that popped up during this little development side-quest:
- Concept of "morale". A typical behavior with minions and a leader is that, when the leader dies, the minions scuttle away. So, this requires the concept of morale, where when it's high, everything is good, whereas when it is low, creature choose to flee from adversaries instead of taking other actions. So, creatures now have morale, which is a number between 0 and 1. 0 means full-on cowardice, 1 means high spirits. Certain actions (TBD) can cause a drop in morale. Morale lower than 0.5 causes morale failure, and AI creatures flee. For the player I haven't figured it out yet, maybe loss of control and force-flee. Now here's the configurable part. Creatures have a recovery rate. So if after a "fear" spell the morale drops to zero, how long will it take the creatures to get back to high morale? And here's the other fun bit: creatures also have a morale range, that can exceed 0 and 1. A particularly brave creature could have morale between 0 and 2. So it will take a lot more to truly strike fear into such a creature. Whereas a particularly wimpy creature could have a morale between -1 and 1, so that, if it reaches rock-bottom morale, it will take even longer to get back to 0.5.
- Morale adjustment effect. To implement actions/spells/etc that adjust morale, we need to write a morale adjustment effect class.
- Minion behavior configuration. Different creatures have different behaviors when they're minions. Wimpy creatures might get scared when the leader dies. Brave creatures might get angry when the leader dies. Angry? What does that mean?
- Add "enraged" status effect. Added an effect that gives 20% more damage and 20% less attack rating (chance to hit). Placeholder.
- Morale failure on leader death. Ok, now I have 2 different minion behaviors: one for enraged, one for getting scared. So, how to implement this behavior? I need to store correspondence between minions and leader. Instead of saving that with the entities, because the minion-leader relationship is a rarer occurence than independent creatures, I chose to store these relationships in the creature system, bidirectionally (leader -> minions and each minion to leader). So, now, when a leader dies, we can access all minions and trigger some "on leader death" behavior. For coward minions, this behavior is setting morale to 0. For some other minions, this behavior is setting the status effect "enraged" for a few rounds.
- No-morale creatures. Not all creatures are susceptible to morale effects. I had to add an "Emotionless" intrinsic property for creatures, so that they don't have morale, and morale effects don't apply to them.
- Minion proximity to leader. Some minions might want to be closer to the leader, others don't mind that much. Again, that's a candidate value in the per-minion configuration. I devised some simple formula which works alright, that based on distance to the leader (in terms of steps) and desire to be nearby (between 0 and 1), return the chance of taking a step towards the leader. This formula is simply clamp(0.8+desire-0.2*max(10 - steps,0)).
- Console commands for kill/teleport. To test the behaviors, I had to implement 2 console commands: "kill" and "teleport", parameterised on the entity (by name, hovered or player). So we can be at a safe distance, hover over the leader, type "teleport" and then watch as the minions chase their telepathically-linked leader (minions always know where their leader is)
- Fleeing behavior bug-fixing. While testing the fleeing behavior, I fixed a couple of bugs I found there
- Creature swapping behavior. I have already implemented creature swapping behavior which works fine. It works with a cooldown, so creatures can't keep swapping on repeat. Now I realised that if a leader is trapped in a small room at the end of a corridor and there's a number of followers on the trail blocking everything, the leader can never leave because the followers will try to approach the leader. So, I've adjusted the creature swapping code so that leaders can always swap with minions (ignoring cooldown), and minions can never swap with a leader. Problem solved!
- Summoned creature duration. If a dire wolf summons some creatures and the creatures live indefinitely, the numbers will grow very quickly. So I've added optional limited duration to summoned creatures. This works great, now they disappear after a while, as I just destroy the entity.
- Summoned entity equipment after they're banished. I added some new creatures with equipment: a goblin commander that can summon goblins, that are equipped with swords. Now, when the goblins were unsummoned, their swords dropped as loot. Oops! I do not like that, as it sounds abusable. So, I had to go back and refactor code and add more listeners, to differentiate between an entity being killed (very gamey, drop loot if it has) and an entity object being destroyed (very programmey: release resources, send messages etc).
So, a seemingly little thing like adding minion/leader relationship can point to lots of areas that need to be implemented to support such behavior. Going through all that I found a few areas for refactor, so onto that...