Talkin’ Battle Systems

Dave here once again to bring you Wednesday’s NCFC update. In the spirit of an NCFC Workshop, I’ll be discussing the basics of the implementation of the battle system. All you game developers lend an ear. You might learn something, or you maybe you’ll think I’m crazy! In either case, I’d love to hear your feedback in the comments.
When it comes to programming, I like to look at the project as a problem. I then identify each part of the problem and divide it up into sub-problems. This gives me an overview of what all I have to do at a glance and allows me to see how each sub-problem relates to the others, and how I can make them interact or where I can re-use code.
A major part of any RPG is its battle system. One might argue that battle systems are what make RPGs games. With this being such an integral piece of the game, I needed to take great care while designing it. I keep things organized through flowcharts and diagrams. Boxes represent classes or structures that represent game elements, arrows show the relationship and flow of information between them. Using a method like this helps keep the project manageable and easy to work with.
So on to the main event. The problem? We need a battle system. The solution? Well, let’s make one.
But how?
What are the sub-problems?
- The player needs to interact with the battle using the player characters.
- The enemies need to attack the player.
- The battle must have a resolution. Win, or lose.
- We must handle what happens after the battle is over.
Before We Begin
We need something to tie all these components together. There needs to be some underlying driving force behind the system. To create this force, I use a priority queue. But “what’s a priority queue Dave?” you might ask. We know what a queue is, it’s a line; you enter is, wait your turn, and come out the other side. First in, first out. But a priority queue is a bit more complex. This isn’t your average amusement park queue, it’s more like an airline queue. Let’s say you’re flying coach. When your flight is boarding, people with higher class tickets will board before you. You could say that they have a higher priority than you in the line. This is how a priority queue works. Each item in the queue is assigned a priority, and the higher priority items will exit the queue first.
So how does this fit into the battle system? A fine question. We’ll use this priority queue to control the actions in the battle. Each turn, the players and enemies will enter their actions into the queue. The priority of these actions is the speed stat of the player or enemy that put it in the queue. This way, players or enemies with higher speed will perform their actions first.
Player Interaction
Player interaction is fairly simple. Accept input from whatever device (the keyboard or the gamepad) and use it to move cursors around menus. Designing the menus is fairly simple, they’re mostly arrays of strings. The player will select an action from the menu, and depending on what action they chose, an action will be entered into the priority queue. Actions differ between normal bash attacks, item usage, defending, etc. The actions will be executed in order of priority at the end of the turn.
Enemy Actions
Enemy actions are a bit different than player actions. We now need to make the enemies “think” a little. In this example, I’ll keep it simple and we’ll have them use a weighted random selection. Using this method, some attacks will be more common than others, so we can make enemies use their more deadly attacks more sparingly. (Further intelligence requires more advanced AI which is outside the scope of this article, but can be accomplished with scripts or AI algorithms.)
So let’s say each enemy has a list of attacks. Each attack also has a percentage attached to it. Summing all the percentages will yield 100%. This makes it easy to pick an attack, we just pick an uniform random integer, 1 to 100, and see where it lands. For example, we’ll say the enemy has four attacks, which are as follow:
- 0 – 5: PK Starstorm (5%)
- 5 – 25: PK Fire ? (20%)
- 25 – 75: Bash (50%)
- 75 – 100: Size up the situation (25%)
You can see that as long as the random variable is uniformly distributed, each attack will occur it’s given percentage of the time. This enemy will bash for the majority of its turns, and will rarely us PK Starstorm. When the attack has been chosen, it will be added to the priority queue. Enemy actions are computed and entered into the queue after the player’s turn.
Enemies can get more complex, but should always follow the same formula. Current battle state in, process, and queue entry. In the example above, the current battle state was replaced with a random variable. The process stage can do whatever it needs to so long as it adds an action to the queue in the end.
Resolution and After the Battle
After each turn, all the actions in the priority queue are performed, and then removed from the queue. When the queue is empty, the round is over and it goes back to the player interaction stage. But the battle isn’t over when the queue is empty! The outcome of the battle depends on these factors:
- All enemies defeated
- All players defeated
- Some other circumstance, eg. a flag was set
So in order to check if all the enemies are dead, we’ll run through them all and check if their HP is less than or equal to zero. If this is true for all of them, we know that all enemies have been defeated. In this case, we should then clear the priority queue of all old actions, and enter actions to show the “You Won” text, the experience gained message, handle the item drops and if need be, the level up text. We’ll also set a flag indicating the player has won the battle. When the queue is empty and this flag is set, we exit the battle.
If only one or a few of the enemies are defeated, we should remove them from the scene, and remove any actions associated with them from the queue. If the action is a player’s attack on them, we can move the target of that attack to an enemy that is still alive.
Likewise, we should perform the same checks for players. If a player character’s HP drops to zero or below, we need to remove their actions from the queue, and if an enemy was targeting them with an attack, move the attack to another live player, or have that attack miss, depending on how difficult you want to make the game. When all the players are defeated, we should set a flag that indicates the player has lost the battle, clear the queue, and enter actions to display the “you lost” message and go to the game over screen.
For special cases, you may want to end the battle early. For example, if the player ran from the battle. In these cases, you simply set a flag indicating what you want, clear the queue, display any messages, and when the queue is empty, end the battle and return to the overworld, or move to another screen. Just like in the above to cases.
Things to Think About
Damage calculation. This should be proportional to a few stats like offense or stat bonuses from equipables. A good place to start is to use Earthbound’s damage calculation formula, which has been dug up from the ROM and discussed here. A lot of the equations in the Mother 4 battle system are based around the equations found there. Of course, they’ve evolved into something of my own in order to fit the needs of Mother 4′s battle system.
Enemy difficulty. Enemies shouldn’t be too hard too soon. Balance in enemy design is important for an enjoyable game. enemies in the beginning of the game could be balanced to give the player a leg up. So they can get a handle on the battle system, but not die every other battle. Using an exponential curve for level up experience point requirements can help with this, as it makes it difficult for the player to stay in one area and grind away at enemies to boost their level indefinitely. It also helps drive the player onward into new areas which in turn advances the story.
Battle backgrounds. There are many ways your could go about achieving these. All will involve trigonometric functions however. You could manipulate individual pixels on a surface, or use a textured polygon that deforms itself based on an equation. A good reference to Earthbound styled background manipulation using individual pixel manipulation can be found here on the Starmen.net forum.
tl;dr
Use a priority queue to handle the battle actions. And do the rest your way since you didn’t read it.
So there you have it. Using this, you should be well on your way to creating a battle system. And if you read through all that, you should be ready for the screenshot of the day. You deserve it.
