AI Tokens Combat System
Overview
The AI Tokens Combat System
(ATCS, which also stands for Advanced Train Control System, but I think I can get away with it)
limits how many NPCs can attack or use abilities at the same time.
NPCs spend tokens to act and hand them back when they're done, so enemies take turns instead of all attacking at once.
It's tricky to put AI and tokens in the same phrase without thinking of LLMs, but the name describes how it works really well.
I built it while working on the enemy AI for Tank Lore.
No matter how smart I made an NPC, once they worked in a group, controlling the pace and difficulty of the game became nearly impossible.
Ramping up the difficulty in multiplayer, handling how enemies behave around a miniboss,
and having modes where enemies are more or less aggressive made me realize I needed a proper system for it.
I'd noticed that in some games, enemies almost feel like they're taking turns to attack.
It was something I'd been indirectly trying to do but never really figured out the nuances of.
After some research, I found the system behind it, which goes by many different names depending on how it's implemented.
How It Works
At any given time, the system holds a number of tokens.
NPCs use them to perform actions, mostly attacks and abilities,
and an NPC is only allowed to perform an action if it holds the number of tokens that action needs.
To get tokens, an NPC requests them from the manager.
If they're available and no other requests are pending, they're granted right away.
If other NPCs are holding them, the request waits in a queue.
Once the NPC performs its action, it returns its tokens so other NPCs can use them.
That's the system in a nutshell.
Priorities
When an NPC requests tokens, it can also pass a priority that moves its request up the queue. This comes in handy when minibosses fight alongside mobs and you want the miniboss to get its turn first.
Token Expiry
An NPC can be stunned, knocked back or interrupted mid-attack and never get the chance to return its tokens.
To keep a single NPC from holding up the whole encounter, a request can set how long the tokens may be held.
Once that time runs out, the manager takes the tokens back and hands them to the next NPC in the queue.
If the request had to wait in the queue, the timer only starts once the tokens are granted,
so time spent waiting doesn't count against the NPC.
Behavior Tree Integration
With the system in place, I created 3 behavior tree nodes:
- Request Tokens (action): takes the number of tokens and the priority for the action that follows. Returns success if the tokens are granted and failure if they aren't.
- Return Tokens (action): called after the action to hand the tokens back.
- Wait for Tokens (decorator): lets NPCs that didn't get their tokens keep doing things that don't need any, like moving around or aiming. Once the tokens are granted, it interrupts them so they can go perform the pending action.