In our last blogpost we talked about abilities, how they are used to define behavior of game entities and had a look at an initial declaration of a
Swordsman unit. This time we are going to investigate how we alter the initial declaration at runtime through the use of
Other articles in the modding API series:
- Units, Buildings & more
- Patching (you're here)
- Inventory System
- Too many villagers!
Most RTS games let players increase the stats of units in one form or another, usually by researching technologies, levelling or giving items to them. Technology heavy games like AoE2 even allow units to upgrade multiple times, e.g. the Miltia unit which can be improved up to four times. One of the easiest methods to accomplish this is by replacing the old unit with an upgraded version that has better stats. For example, the Man-At-Arms upgrade in AoE2 switches all Militia units with Man-At-Arms. While handling upgrades like this is easy, it creates some problems:
- Units cannot improve individually because the individual stats cannot be carried over to the upgraded replacement unit.
- The units will be very generic. A replacement unit has to be designed for every possible unit upgrade.
- Changing ownership of units can create weird bugs because different civilizations could have different upgrade paths for each unit.
We would prefer a more flexible system that is also easy to understand. That's where
Patch comes into play. A patch is a special object that defines attribute changes for another nyan object. Here is one simple example of a
MoreSpeed<engine.Move>(engine.Patch): speed += 0.5
The declaration of a
Patch is very similar to the declaration of a normal object with the exception of
<engine.Move>. The reference in the angled brackets is the target object of the patch. The line below shows the member that is altered by patching. In this case the current value of
speed is increased by
0.5 when the patch is applied. Instead of a relational change, absolute changes are also possible.
MoreSpeedAbsolute<engine.Move>(engine.Patch): speed = 2.0
This alternative patch would set
2.0 when it is applied.
API objects for applying Patches
As stated before, the declaration of a patch does not define in what situation it is applied. However, there are API objects that cover the most common situations, e.g.
Tech objects represent technologies that have to be researched by a
GameEntity with the
Research ability. The member
upgrades stores a set of patches that are the effects the technology has on the player's units. Patches of
Tech are applied as soon as the game entity has finished researching the technology.
Mod also holds a set of patches, but they are automatically applied right at the start of a game with no further requirements. This can be utilized by modders to get their intended alteration into the game (e.g. different animations/sounds or balance changes) without touching the original dataset.
The great advantage of a
Patch is that it only defines what is changed, but when, how often and which unit it will be applied to can be decided elsewhere. The patch
MoreSpeed of our example that changes the
Move ability could be applied on all units, only selected units, a single unit, a class of units, multiple times, once, every 2 minutes, and so on. Furthermore, it allows us to make more fine-grained upgrades, instead of the sledge hammer approach that the unit replacement method is.
So will every upgrade be defined as patches? The answer is yes. Every single upgrade will be done by a patch or a bundle of patches. This goes so far that in the AoE2 swordsman line (Militia, Man-At-Arms, Longswordsman, Two-Handed Swordsman, Champion), Militia will be the only unit that is initially defined. The other units will be defined as patches that upgrade animations, stats and abilities. This might be unintuitive at first, but gives considerably more options to developers and modders.
Now that the basics of abilities and patching are established, we will dive deeper into the topic of abilities and take a look at the
Attack abilitiy. See you next time!
Any more questions? Let us know and discuss those ideas by visiting our subreddit /r/openage!
As always, if you want to reach us directly in the dev chatroom: