My party has just run through their first combat. It went well, especially considering this was their first combat in Authentic D&D. Over the holiday, I had some time to think about that combat, and whether or not I could use any algorithms to offload any of the work in running the NPCs, particularly dumb ones with simple motivations. In any case, an exploration of that project is sure to be enlightening in itself.
I'll make the code available here.
Another advantage of a system like this is that we can capture a combat in a repeatable (and version-controllable) way. At least to a degree: the beauty of D&D is that a rule system never fully captures the range of human ingenuity, and so to some extent the rule system must always be fluidly updated to match feedback from actual play.
We can break combat action at its simplest level down into:
- move somewhere
- attack something
- interact with something
These actions can be done more than once per turn in any order, depending on the available action points and circumstances, with the goal of breaking the enemy's will through death or morale collapse.
Every action taken by an active participant in the combat should be in service of this goal. Participants who are more intelligent or better trained will select better options than others. [we can also invert this selection function to simulate the actions of PCs, who will choose the worst option in any possible circumstance]
I'll start by tackling movement, which I thought would be the easiest of the three actions. That turned out to not bode well for the others.
Let's consider a battlemap with no obstacles and two actors. We'll play with the actor on the right, giving it 3 AP and the ability to move according to the Authentic D&D rules. Without considering other constraints, this means that for each AP, the actor can move between 1 and 8 hexes in a straight line. This generates the following possibility space:
Movement possibilities: darker hexes mean more possible paths to reach that hex |
However, there are several constraints we must add, which proved to be non-trivial to program. The actor can only change speed once, they can only rotate left or right 60$^\circ$ at the end of each AP, and they can't move through obstacles (in this case, that is only the other actor). That reduces our space to the following:
Possibility space with constraints added |
The space is still mostly symmetrical, but we can also see the disruption caused by the presence of another actor. Keep in mind also that this is the possibility space for exactly 3 AP; in many cases our actor would only want to move one or two AP, or perhaps even look ahead multiple turns.
Movement in 1 AP, darker hexes are a higher stride |
For example, if the actor on the right wants to attack the actor on the left, they will move at stride 2 for 2 hexes to enter melee and then have 2 AP left to attack. In this way, we can build up a desirability score for each possible hex, and take an optimal or near-optimal combination of actions as a result.
I'm not quite done with movement yet. Right now, we only avoid obstacles of other actors. I'll need to do some thinking on how to add simple static obstacles such as walls or buildings.