
It all started when I began coding the Dwarf Warrior character actions. After every action I code, I run the game and do a playtest session focusing on that action. During one of those sessions, I noticed that an action I've just implemented wasn't very good. It wasn't interesting and had no appeal to the player. I decided to rework that specific action and came up with a new model for it. The problem was, this model was not used in the game before and it didn't fit with the code structure I was working up until now.
Why planning is so important
In Battle for Enlor, there are 3 different kind of actions: deal damage to the enemy, inflict a status on the enemy and inflict a status on teamates (or yourself). Status inflicted to teamates are generally positive status, while status inflicted to enemies are negative. Every time a player executes an action that targets an enemy, that enemy has a chance to defend it. This is true for all attacks that causes damage. Inflicting status, however, does not trigger the enemy's defense, this means that negative status are sure-hit actions. This was a design decision based on the whole game balance.
This is better explained on the diagrams below:
Note that when I say 'messages' I referring to comunication between game components.
Now, the new action designed for the Dwarf Warrior involved: attacking the boss and, if the boss takes damage, inflict a negative status on it. By using the current structure, the status would be inflicted even if the boss defended or if the player missed the attack. If I had thought about this particular issue during the planning phase, it would be very easy to deal with this. For example, if attacking a boss is basically sending a message with the damage: AttackBoss(Damage), attacking AND inflicting a status could be as simple as: AttackBoss(Damage, Poison). Even so, as simple as it may seem, changing the code to allow that now would be a huge amount of work. This is a small project but imagine on a AAA game where everything is exponential.
This is a lesson I learned the hard way and by making games. I can't stress enough how important is to make games and more games, even small ones, because is doing so that you will learn the most. The big lesson here is that planning is very important. Define how everything will work and playtest that with prototypes: there are several ways you can do this, even with paper. You can face the unexpected, but the more planning you do the less are the chances of facing it.
Dealing with the unexpected
I decided not to go to the route: "let's remake this whole module so now it supports what I need", but decided to try a different approach. I noticed that the only thing I needed to inflict that status was a confirmation that the enemy was hit by the attack. Knowing this there was a solution in sight. In the enemy defense scripts I know exactly when they take damage. My approach was, everytime an enemy takes damage, it sends a message saying that it took damage (refer to the 'messages' meaning above). With this information I can work on a particular script for my new attack:
- Send a message to the enemy with the damage
- The message goes through the enemy defenses
- The enemy sends a message if it was hit or not
- Based on the message received the status is either inflicted or not.
This is illustrated on the diagram below:
With this approach I was able to solve the problem without having to redo a large amount of code. However if this wasn't possible, I would, without thinking, redo it all so I can add it. This added so much value to the game environment to me that it would be pointless to keep the old plain and boring attack just because changing it would led to a lot of work.
There are times where the unexpected happens and we have to sacrifice something to preserve the game. But there are also times when we can deal with it, be it with the exchange of our time, resources or just by applying an idea that wasn't thought before.