• Sign up for the Black Forest 2v2 Tournament on Community Patch 1.6 RC and win a Voobly premium membership.     

    [ More Information ]

Member Plus Headquarters: Mod Guide

A project of the former MSN Gaming Zone community.

Disclaimer

All described procedures and programs are published regardless of their existing patent situations. The information on this website is intended for educational purposes only. All technical information and programs have been developed and collected by their authors with great care and were reproduced using effective inspection measures. Nevertheless, errors can never be completely ruled out. We hereby do not hold legal responsibility or liability for any consequence that may result from inaccurate information. The authors are always grateful to be notified in case of spotted errors in our articles. All software names, hardware names and images are owned by their respective companies and are protected by copyright, trademark, and patent laws.

Development Guide

help_center.png

This guide uses as examples the Advanced Genie Editor codes from Community Patch 1.6.
Author: +pancrol@voobly

Foreword​

Back in march 2020 I had no idea how to create mods. I have a basic understanding of programming and assumed that there was a big file somewhere storing unit stats, technologies and so on. With that knowledge, I assumed that adding balance changes like +1 armor for certain units or faster research time for a technology had to be easy.

During that time, Europe was going through the worst of the covid pandemic and several countries, mine included, where on lock down. Despite not being able to go outside, my girlfriend and I like Age of Empires a lot so we had things to do together. However, my girlfriend's computer is not powerful enough to run Age of Empires 2 DE so all we played was WololoKingdoms. I took a look at the mod center several times, thinking that, if adding balance changes was as easy as I suspected, someone must had have the idea to add stuff from DE already.

So I did a bit more research and discovered that mods are created using Advanced Genie Editor. Indeed, through that program you can modify unit stats, costs, research times, and so on. In a couple of days I had copied most of the balance changes that were basically changing numbers in the code. The one that made me decide to publish it was the Khmer farming bonus. After a day trying to understand how DE did it and realizing that I couldn't port it as direct copy, I figured out a way to adapt it in a way that kept the spirit of the original one and worked within the limitations of userpatch.

I uploaded the mod to Voobly before going to bed and next morning I already had a message from Voobly staff. Obviously they had been waiting for someone to do exactly that: a mod with the balance changes from DE that could be played on Voobly. At first my plan was just to add balance changes to the existing civilizations, assuming that the new ones would be off limits legally. After several talks with Voobly's legal experts, we decided that it was fine with civilizations as long as we didn't get into the campaigns created for Definitive Edition. Throughout the summer, I added the four new civilizations, albeit with several issues in their adaptation like the Lithuanian's relic bonus or the Tatar's extra hill damage.

Then, one day in September, someone by the name of katsuie wrote a post with some code that, allegedly, implemented autofarming. I didn't understand the code but he made a functional patch that implemented that functionality. Since then, he has added the villager distribution per resource, global command queue, improvements for the display of technologies in the game, and new hotkeys. Not to mention all the implementations we have been able to properly adapt thanks to him.

Originally my mod was called "Wololo Kingdoms DE'', as a way to reflect the fact that it was meant a version of that mod with updated balance. However, as we started adding new civilizations, features and functionalities, it became apparent that this was not meant to be a branch of the original main mod. Therefore, we changed to the "Community Patch'', hoping to unite the Voobly community in its development and with the version 1.6 as a way to reflect an improvement on the 1.5 patch older games have.

I don't think I'm the leading expert in Advanced Genie Editor but, throughout these years and with a lot of try an error, I've grasped a very good understanding of how things can be implemented and the options Advanced Genie Editor provides. So here is my guide, done as structured as I can, where I'll try to explain what you need for modding AoE 2, how to find the part of code you want to change, several of the issues you may ran into and interesting implementations we have developed for the Community Patch.

This guide is distributed in hope that it will be useful, but without any warranty and confers no rights.​

1. Modding tools and mod structure

In this chapter, we’ll go over all the programs I use for modding, either for data mods or graphical ones, and how the structure of a mod looks like and what each file is for.​

Programs​

Let’s start with the programs you need in order to create mods:​
  • Advanced Genie Editor. Or AGE. The main program, the one you use to access the data files and modify units and technologies. To use this program, you can download it from Age of Kings Heaven or, if you have Definitive Edition installed, access it inside the ``AoE2DE'' folder, in a folder called ``Tools\_Builds''.​
  • Turtle Pack. A program to visualize .slp files (graphic files) and .drs files (compressed files with mostly .slp files inside).​
  • SLX Studio. A program to create graphics, modify DE graphic files and create .slp files from them. It also includes some functionalities like color replace, resizing, format change…​
  • SMX Workshop A program to port the new .sld graphics into .smx ones. It also requires installing Java Run Enviroment.
  • DRS merger. A program created by katsuie to merge several .slp files into a .drs file. Useful to change lots of graphics at once.​
  • Text Editor, like notepad, in order to modify language files, map scripts and AI files.​
  • Image Editor, like Paint or GIMP. Graphics are all bit maps and you'll need one of these in case you need to modify some of the graphics.​

Mod structure​

Inside your AoE 2 folder there’s a folder called "Voobly Mods/AOC". Inside you can find three folders: one for data mods, that modify the game, one for local mods, that includes visual, map or AI mods, and one for patches. We focus here on the data mods, touching briefly into local mods as we go along.
The structure of a mod (data or local) is as follows:​
  • Data. Folder with the main data files:
    • empires2_x1_p1.dat: the master file with the code of the game that you access through AGE.​
    • gamedata_x1.drs: compressed file with the original (common in 1.6) map scripts and ids of the game elements for map scripts to know what to place. Access it with Turtle Pack.​
    • gamedata_x1_p1.drs: compressed file with graphics and sounds. Access it with Turtle Pack.​
  • drs. Folder to store graphics and sounds without adding them to gamedata_x1_p1.drs. More on this in the next section.​
  • History. Text files with historical information about the civilizations. Not relevant for the gameplay.​
  • SaveGame. Where recordings of your single and multiplayer games are stored and where you should store the ones you download in order to replay them.​
  • Scenario. Where custom scenario files are stored.​
  • Screenshots. You can take full screenshots of the map by pressing Ctrl+F12 or by using the PrtScn key. Either way, the game stores them here.​
  • Script.Ai. Folder with the Artificial Intelligence files. I’m no expert in AI but I can give you a basic idea of how AIs are implemented:
    • Every AI needs a .ai file with its name, that’s the file that allows the AI to be selected in game.​
    • The basic code of the AI is stored in a .per file with the same name as the .ai file. You can read this file with a text editor.​
    • Additionally, AIs can separate the code into smaller files and store it in a folder. This is done for convenience when working on it but has no impact in the game.​
    • Inside gamedata_x1.drs there is a file where you can control the AI that is loaded when selecting "computer". This way you can have a default AI for the mod.​
  • Script.Rm. Folder with the map scripts that appear in the Custom maps section. Maps are stored in .rms files that you can open with a text editor.​
  • Sound. Stores music files, mainly:
    • music.m3u. Soundtrack you hear while playing. You can open it with a text editorand will see the paths to the music files. These paths can point anywhere in the computer.​
    • stream. Civilization themes you hear when selecting one.​
    • Scenario. Dialog files from the campaings. They come with WololoKingdoms but are of no use outside scenarios.​
  • Taunt. Audio taunts that you play in the game, such as 1 (yes), 2 (no) or 11 (laugh).​
  • age2_x1.xml. File listing the civilizations with an id, their audio theme and their scout unit. There are some other relevant values in it that we’ll mention in a future section.​
  • language.ini. Language file that you can read with a text editor. Every text string you see inthe game has a number attached to it. The language file lists all the number with the corresponding string. Having different versions of this file with translated text is all you need to play the game in a different language.​
  • Player.nfz. File to have player profiles in the game and store the last configuration of thegame (map, population, size...).​
  • player1.hki. Hotkeys file. If you have several profiles in the single player menu, you willhave several of these files but this one is the main one you use in multiplayer.​
  • version.ini. A text file containing the version of the mod so that Voobly checks that all theplayers have the same one and prevents crashes. This file is mandatory so that Voobly lists the folder as a mod.​
Except for the version file, none of these files need to be present for the mod to work. The difference between a data and a local mod lies in whether they change something inside the "data" folder, whose contents should be the same for all players in the game.​

Priorities when loading files​

As many of the files of mods are replacements of already existing files in the original game, Voobly follows the following rule, from top priority to lowest:​
  1. Files inside a local mod. Within the local mods folder, Voobly loads them in alphabetical order.​
  2. Files inside the "drs" folder of the data mod.​
  3. Files inside the gamedata_x1_p1.drs folder of the data mod.​
  4. Original files in the AoE2/Data folder of the game.​
This happens for graphics or sounds of units but a similar process occurs for music, AI or map files. Local mods have top priority loading, followed by the data mod and last the original files.​

Merging several local mods​

The amount of local mods you can load at the same time is limited but, if you understand how mods are structured, you can combine several of them into a single one.
Take for example mods that are not updated, like your preferred trees and grid mod. By what we saw above, those two mods have a “drs” folder with the modified graphics. Therefore, you can simply copy the contents of one into the other and use only the combined one.​

2.1. Overview of AGE

This chapter will cover all I know about AGE, the tabs I normally use, what the fields mean and some of the values the game admits. This will not be a complete guide, as there are several aspects of the editor I have never used. Nevertheless, given all the features we have included into the Community Patch, it should be very complete.

Open and load a data mod​

When you open Advanced Genie Editor, you will see an open window with several fields to fill. Here are the ones that are actually relevant:
  • Genie version. Which version of the game you are working on. The Community Patch uses The Conquerors+UserPatch but you may also use Age of Empires II: Definitive Edition if you are modding for that game.
  • Compressed data set (*.dat). Path to the file “empires2_x1_p1.dat” in your mod folder.
  • Language file locations. These are .dll language files that only help navigating the code. The one I use, that you can download here, has all the new units and techs, thanks to a program by katsuie.
  • Path for DRS files. Path to the data folder in the root AoE 2 folder. In my case “\Age2HD\data”. Having this file allows to visualize some graphics but only if they are stored there.
  • Recent paths. Saves the last used configurations.
Technically, by adding other files you could access more text strings and graphics but I never made it work.

age_open.png


Main buttons and tabs​

  • SLP menu. Only relevant for graphics and icons and only if you added graphics files when opening AGE.
  • +++ button. Allows to open another window of AGE. This is useful when copying stuff from one data file to another, as opening AGE twice doesn’t allow copy.
  • List button. Useful to leave activated. This way, when you delete text in the search fields, you don’t loose the selected item. If you don’t understand what I’m talking about just trust me.
  • SLP button. Links the graphics from the AoE2 root folder if you selected them when opening AGE. If activated, you won’t be able to open those .drs files with Turtlepack, you have to deactivate it for that.
  • Techs tab. Technologies in the game, the ones you manually research and the ones that activate automatically. In this tab you can modify names, costs, icons, research time, research locations…
  • Effects tab. When you research a technology, it triggers an effect. This tab lists all the effects.
  • Tech tree tab. This creates the technology tree in the game but only the visual layout, it has no effect on the actual behavior of the game. In reality, everything is done through technologies. It can be useful to locate a unit you don't know the name of.
  • Civilizations tab. Lists all the civilizations with their civilization bonus and team bonus (both effects). Also lists all the resources the game uses, from wood, food, etc to other more obscure ones.
  • Units tab. All the units in the game: actual soldiers, buildings, animals, trees, decorative stuff…
  • Graphics tab. Lists all the graphics in the game, with links to their corresponding slp files.
  • Terrains tab. Lists all the terrains the game uses.
  • Sounds tab. Lists all the sounds in the game, with links to their corresponding wav files.

age_tabs.png


The filter box​

One of the few utilities AGE has to help navigate the code. In almost every tab, above the list of objects there are two dialog boxes and two drop-down menus.
  • The first dialogue box is to write text that must appear in the object. To have several strings, separate them with the symbol “|”, which means “or”. You can change the behavior of “|” from “or” to “and” in the check box next to it.
  • The second dialogue box is to write text that must not appear in the object. The symbol “|” works identically.
  • The two drop-down menus are to activate some extra text in the object description such as “Train location”, “Research time”, etc.
For example, say that you want to check the Mayan castle age unique technology but you don’t remember the name. In this case, in the techs tab, you can go to the dropdown menu and select “Civilization”. This shows the civilization that can research each technology before the actual name. Now write in the dialogue box “C 16” and AGE will show the techs that only Mayans can research, making it easy to locate what you are looking for.

2.2 The Technologies tab

In this tab you edit the cost, research time, requirements and access of technologies, not the actual effects of each technology, which is done in the Effects tab.

Language information​

Fields in the Techs Tab:
  • Internal Name Identifier of the technology, usually overrided with the actual name of the tecnology, unless you enable the filter.
  • Language File Name Entry in the language file for the name of the technology. AGE instructs you to set a value between 7000 and 7999 so that it doesn't conflict with other elements of the game.
  • Language File Description Entry in the language file for the short description of the technology. It should be the value of the ``Language File Name plus'' 1,000.
  • Language File Help Not used in the game but linked to the ``Help Converter'' next to it. It should be the value of the file name plus 100,000.
  • Help Converter Linked to the ``Language File Help'' and no need to modify it. Entry in the language file for the long description of the technology. It should be the value of the file name plus 21,000.
  • Lang File Tech Tree Not used in the game but linked to the ``Tech Tree Converter'' next to it. It should be the value of the file name plus 150,000.
  • Tech Tree Converter Linked to the ``Lang File Tech Tree'' and no need to modify it. Entry in the language file for the name of the technology displayed in the technology tree. It should be the value of the file name plus 10,000.
Entries in the language file:
  • n. Corresponding to the ``Language File Name''. Name of the technology.
  • n+1,000. Corresponding to the ``Language File Description''. Short description.
  • n+21,000$. Corresponding to the ``Help Converter''. Long description.
  • n+10,000$. Corresponding to the ``Tech Tree Converter''. Technology tree name.

Code fields​

techs.png

  • Required Techs Six fields to enter technologies that must be researched in order to enable the current technology.
  • Min Req Techs Ammount of the required technologies needed to enable the current technology. Used to allow different ways of enabling a technology. For example, Double-Bit Axe, technology 202, has two required technologies but only requires one of them. This way, it is enabled by reaching Feudal Age or by researching technology 758 that is related to the Burgundian bonus.
  • Type Whether the progress should show in the bar at the top of the screen or not. Set to 0 for everything except for the ages.
  • Research Time in seconds.
  • Icon From the file 50729.slp.
  • Button Position in the interface. 1 to 5 are first row, 6 to 10 the second row, 11 to 15 the third one and extra values create a second page.
  • Effect What to do when the technology is researched. Can be empty if the technology is used as a trigger for others.
  • Research Location Where to show the button. Can be empty if the technology researches automatically.
  • Civilization Who that can research it. Value -1 means every civilization can research it (and later can be disabled with the ``Tech tree'' effect). Any other value enables the technology only for that civilization.
  • Full Tech Mode Controls if the tech appears in that mode of the game. Only relevant for technologies that are researched by only one civilization and is mostly set to 0 (unavailable) for all of them.
  • Costs Requirements to research the technology. In ``Type'' one can put the four normal resources or anything else. ``Amount'' is the quantity needed and ``Deduct'' controls whether the amount has to be paid or not. For technologies there are no examples of this mechanic but units use it.

Types of technologies​

In the game, there are two types of technologies that you can program:
  • Technologies with zero research time. You research these technologies automatically when you meet their “Required techs” conditions, without considering the cost. For example, technology 25, “STBL (make avail)” allows you to create stables. It requires two technologies: “Feudal Age” and “Shadow Node Barracks + Khmer”, a technology that is researched when you build a Barracks or are Khmer (since they don’t need pre-requisite buildings).
  • Technologies with positive research time. You research these technologies by clicking the icon and paying its cost. They are only available once their “Required Techs” are met. For example, technology 200, “Bodkin Arrow”, can only be researched if you are in Castle Age and have already researched Fletching.
Civilization bonuses that give technologies for free (Korean towers, Turks light cavalry…) are created by setting the research time of technologies (and their cost but it turns out that’s irrelevant) to zero.

2.3 Effects Tab

In this tab you control what technologies do by adding ``commands'' to the effect of a technology. The only relevant thing here is the ``Command Type'' field and the different options available. Be aware that Definitive Edition introduced several new types of commands that don't work on the community patch or any other mod based on the Voobly user patch. Here we will only cover the old ones:
  • Attribute Modifier (Set). For setting a new value for an attribute for a unit or a class of units.
  • Resource Modifier (Set/+/-). For changing a resource by increasing or decreasing it or directly setting a new value.
  • Enable/Disable Unit.
  • Upgrade Unit. Change existing and future versions of a unit into another one. The upgrade implementation is a bit counter intuitive, see the section on upgrading units.
  • Attribute Modifier (+/-). For changing the value of an attribute for a unit or a class of units.
  • Attribute Modifier (Multiply). For multiplying the value of an attribute for a unit or a class of units.
  • Resource Modifier (Multiply). For multiplying the value of a resource.
  • Enable/Disable Technology.
  • Modify Technology. Not used in favor of the 101 and 103 effects.
  • Set Player Civ Name. Used in some mods but not common.
Commands that affect all team members, different from team bonuses:
  • Team Attribute Modifier (Set).
  • Team Resource Modifier (Set/+/-).
  • Team Enable/Disable Unit.
  • Team Upgrade Unit.
  • Team Attribute Modifier (+/-).
  • Team Attribute Modifier (Multiply).
  • Team Resource Modifier (Multiply).
  • Team Enable/Disable Technology.
Commands that affect enemies:
  • Enemy Attribute Modifier (Set).
  • Enemy Resource Modifier (Set/+/-).
  • Enemy Enable/Disable Unit.
  • Enemy Upgrade Unit.
  • Enemy Attribute Modifier (+/-).
  • Enemy Attribute Modifier (Multiply).
  • Enemy Resource Modifier (Multiply).
  • Enemy Enable/Disable Technology.
Commands that affect technologies:
  • Tech Cost Modifier (Set/+/-). For changing the cost of a technology.
  • Tech Time Modifier (Set/+/-). For changing the research time of a technology.

2.4 The Civilizations tab

This tab allows you to create new civilization and assign them bonuses. The only two fields that really matter are the following:
  • Technology Tree Here each civilization has an effect that mostly disables the common technologies they don't have access to. It can also be used to add some civilization bonuses like discounts, free technologies, etc.
  • Team bonus This is the effect of the civilization team bonus that will be applied to the allies.

Resources​

Another interesting part of this tab is that it stores the resources the game uses. These go from the actual food, wood, etc. to other elements like the food production of farms, the heal speed of Berserkers and many others that control several aspects of the game.

2.5 The Units tab

The units tab is by far the most complex part of AGE but it's also the most documented one with the descriptions of the fields. Nevertheless, some of the explanations are wrong and I'll try to clarify everything I can.

Edits per civilization​

civilizations.png

On the top left corner of the units tab, you have a drop-down menu to select the civilization with which you want to see the units. In most cases, the civilization chosen there is irrelevant but there are some exceptions:
  • Buildings have different graphics depending on the civilization, this makes architectures possible.
  • Some units may have different values depending on the civilization, this is usually done for simplicity. The most notable example are units 1345, 1346, 1347, that handle the unique technologies and unit upgrades.
At the top of the tab you have a bunch of check boxes, one per civilization. These checks control which civilizations are affected by the changes you make, appart from the selected civilization from the drop-down menu.

This is very important as you can accidentally change things for civilizations with no way of reverting the mistake.

Type and Class of unit​

These values control how the game treats the units and some of their properties. For example, setting a unit to type 80 (building) makes it unable to move, packed units like the Trebuchet being the exception. The class field has similar properties but it's also used to update units in full. For example, range upgrades are applied to the full archer class instead of going unit by unit.

You could produce interesting behaviors by combining types and classes. I don't have an extensive list but we'll see some examples, like units that are type building but class prey animal so they can move and avoid other units.

Descriptive fields​

Fields in the Units Tab:
  • Internal Name Used if the Language File Name is empty or doesn't have a string in the language file.
  • Language File Name Entry in the language file for the name of the unit. AGE instructs you to set a value between 5000 and 5999 so that it doesn't conflict with other elements of the game.
  • Language File Description Entry in the language file for the short description of the unit. It should be the value of the "Language File Name plus'' 1,000.
  • Hotkey
  • Language File Help Not used in the game but linked to the "Help Converter'' next to it. It should be the value of the file name plus 100,000.
  • Help Converter Linked to the "Language File Help'' and no need to modify it. Entry in the language file for the long description of the unit. It should be the value of the file name plus 21,000.
  • Lang File Tech Tree Not used in the game but linked to the "Tech Tree Converter'' next to it. It should be the value of the file name plus 150,000.
  • Tech Tree Converter Linked to the "Lang File Tech Tree'' and no need to modify it. Entry in the language file for the name of the unit displayed in the technology tree. It should be the value of the file name plus 10,000.
Entries in the language file:
  • n. Corresponding to the "Language File Name''. Name of the unit.
  • n+1,000. Corresponding to the "Language File Description''. Short description.
  • n+21,000. Corresponding to the "Help Converter''. Long description.
  • n+9,000. Corresponding to the "Tech Tree Converter''. Technology tree name.

Graphics​

To talk about graphics, we first should mention the button "Show graphics" in the SLP menu. This opens a new window that displays the graphics for the unit. However, you will only see graphics that are in the base .drs or the mod .drs files, the ones you configure when opening AGE. This window can be useful to check some graphics but you may need to go into the drs files to be sure.

Let's go over the fields:
  • Icon From the file 5730.slp.
  • Special Graphic Related to the special abilities, unused.
  • Standing Graphics Those of the unit when it's idle. There are two fields, to have them switch between animations if desired.
  • Dying Graphics Death and collapsing animation of units.
  • Undead Graphics Unused.
  • Walking Graphics For when the unit is moving.
  • Running Graphics For when units have two speeds, used for deers.
  • Snow Graphics Usually only the snow to be placed on top of the building.
  • Construction Graphics Foundation graphics.
  • Attack Graphic For when the unit is attacking.
  • Garrison Graphic Flags to be placed on the unit.

Damage Graphics​

Damage graphics control the flames of buildings and, in the case of the Community Patch, the health bars always visible over units.

They are created by setting a percentage of health that has to be lost for the graphic to appear and the graphic itself. There is also the option to replace the graphics entirely, which is done on buildings.

Statistics​

Here we have some of the stats of the unit, not counting attacks and armors. Some things to remark:
  • A "Rotation Speed'' of zero means that the unit turns instantaneously. It's mostly zero for all units except for some ships.
  • The "`Line of Sight'' is the amount of tiles the unit uncovers in a straight line. The "Search Radius'' is the distance the units look for enemies. For units, both numbers usually coincide but things like the Castle or the Krepost have search radius smaller than the line of sight.
  • "Max Range'' is the maximum distance a unit can shoot and "Shown Range'' is the value displayed in the screen. Both values are the same but, when you research range upgrades, only "Max Range'' is modified, which makes the "4+1'' values appear.

Attacks and armors​

First, a quick reminder on how units deal damage to each other taken from Age of Empires Wiki.

The damage dealt by units is calculated by comparing the different attacks and armors each unit has, adding the elevation multiplier, and setting it to 1 if it's smaller than 1:
1698393631402.png

The value kelev is the elevation multiplier, 1.25 in Age of Conquerors. The multiplier for cracked terrain and the resistance multiplier are not relevan in the Community Patch.

For example, a skirmisher deals 2 pierce damage, 3 damage to archers and 3 damage to spearmen. If it attacks an archer from higher elevation and both have no upgrades, it deals the pierce and archer damage, not the spearman one since its target does not have that armor class, in total:

max(1,1.25 * (max(0, 2-0)+max(0, 3-0)))=max(1, 1.25 * 5) = 6.25.

The decimals are respected, even if the game only shows integers.

For a list of all the armor classes used in the game, see Section 2.7.1.

The "Attacks'' and "Armors'' section have each a list of all the attacks and armor classes the unit has and the values there are the ones used in the damage calculation.

Appart from those values, some other interesting fields:
  • The "Shown'' attack, melee and pierce armor are the values displayed in the screen for the unit and display "+1'' when upgrades are researched. "Shown Attack'' will check for the melee or pierce armor class in the attacks list.
  • "Frame Delay'' affects only units that shoot projectiles. It is the amount of frames in the attack animation that have to pass before the projectile unit is created. This is what makes Manguadai easier to micromanage than Cavalry Archers.
  • "Accuracy Percent'' is the probability (in percentage) of a projectile going for the intended target. For each projectile shot, a random number is generated to see if the unit misses. For missed shots, the "Attack Dispersion'' value comes into play and measures how much do the missed shots actually deviate.

    This means that you could have a unit with 0 accuracy and 0 attack dispersion and still it would hit its targets all the time.
  • "Reload Time'' is the time in seconds that must pass before another projectile is shot or a new attack is computed. "Shown Reload Time'' has no effect.

    This creates a distinction between melee and projectile units. When melee units go into combat, they cycle through their attack animation over and over but that doesn't mean that every hit of the sword is an attack, it's just visual. The reload time is what controls the attacks.

    For projectile units this is a bit different. Once they finish the attack animation and have shot the projectile, they go into idle mode until the reload time has passed, when they shoot again.
  • "Blast Width'' is the radius in tiles where the blast damage is computed.
  • "Blast Attack'' control what type of blast damage units deal. "Blast Defense'' is not taken into account. For more information, read Section 2.7.2.
  • "Base Armor'' is a default armor value used when an attack class is not present in the armors. It is set to 1,000 for everyone so as to ensure that no damage is produced.
  • "Terrain Defense Bonus'' affects buildings and controls extra damage dealt when standing the unit is on a specific terrain. As far as I know, the only example is Cracked Dirt.

Resources and Garrison​

  • Resource Capacity Amount of resource the unit can hold or store. Used mainly for villagers. Mines, farms and other animals use the "Resource Storages'' section.
  • Resource Decay Speed at which units loose resources. Used on rotting animals and on corpses to make them disappear.
  • Work Rate General purpose value used for farms to produce food, villagers to collect resources, buildings to produce units or monks to heal. Resource collection uses some extra values in the tasks section.
  • Garrsion Capacity For transports and buildings.
  • Garrison Type This fields uses a binary code, meaning that each box bellow controls a bit of the number and the value above is the decimal translation. This allows different units to enter buildings.
  • Garrison Heal Rate Health gained per second while garrisoned. The higher the value, the faster the regeneration. This contrasts with the regeneration speed (attribute 45) used by regenerating units. There, the value is the amount of seconds that pass to get a single health point.

Projectiles attributes​

This section controls how units fire projectiles and how projectiles themselves behave.

There are two fields for projectiles: the main one is the one used when the unit shoots a single projectile and the secondary controls all extra projectile. The main projectile uses the statistics of the shooter when computing damage but the secondary ones used the values programmed on them.

"Total Projectiles'' is the base amount of projectiles the unit shoots, usually one except for things like the Kipchak or the Organ Gun. "Max Total Projectiles'' is the amount of projectiles a building can shoot when fully garrisoned.

You can have a unit shooting several projectiles and only use the main projectile field. In that case, all projectiles will use the shooter statistics. If you do set a secondary projectile, all extra projectiles will use that one.

The fields on "Graphic Displacement'' and "Projectile Spawning Area'' only control visuals to make it look that arrows leave the bow or bullets the cannon, it doesn't affect accuracy.

The next fields control how projectiles work:
  • Projectile Type Always has value zero. Other values could be used for lasers in the Star Wars game.
  • Smart Mode Ballistics behavior. All projectiles have it to zero and the technology changes it to one.
  • Hit mode How the projectile behaves when hitting units different from the intended one or how to behave when hitting units in a line.
  • Vanish Mode What happens when the projectile hits a target. It may disappear or pass through.
  • Area Effects Zero for arrows, one for bullets.
  • Projectile Arc How much does the projectile curve.
To understand the types of projectiles you can create, read Section 2.7.3.

Attributes​

This section has several check boxes and fields to control things like the availability of units, where they can walk on or their size. I will only list those that are used, bear in mind that some may be used in the Star Wars game.
  • Available Whether the unit is available from the start of the game or requires a technology.
  • Can be Built on Used to make corpses disappear when you build on top of them.
  • Hide in Editor Whether the unit should appear in the Scenario Editor. Used to hide annex units or corpses.
  • Fly mode To display the shadow properly.
  • Can be Gathered To let the game identify resources and not apply the fog of war rules.
  • Adjacent Mode Mainly used by walls to change shape.
  • Built: Vanishes Used for buildings that have a different foundation unit from the standing one, to make the first one disappear. The most notable example is the Town Center.
Fields:
  • Sort Number Relevant for scenarios, this field doesn't make corpses or farms walkable.
  • Hill Mode What makes buildings require flat surfaces. This controls whether you need a fully flat surface or allow for some slope.
  • Fog Visibility Whether the unit is visible in the fog of war. The game only uses value zero for normal units and one for animals or corpses.
  • Combat Level Used by units to prioritize enemies. This is what makes wolves prefer villagers to military or rams buildings.
  • Interaction Mode What makes units selectable and movable. Doesn't control the interface units show.
  • Minimap Mode How the unit shows in the map. The game mostly uses zero for non-visible units and 1 for visible ones.
  • Minimap Color Set to zero when the unit belongs to a player and a color for resources.
  • Doppelganger I believe this makes fallen trees still not count as dead, and thus walkable, units.
  • Gather Group Probably not used anymore.
  • Task Swap Group This is what makes villagers switch tasks. Whenever a villager is tasked to something, the game looks at units in the same group for a unit that knows what to do with it, based on the tasks at the bottom of the tab.
  • Special Ability Not used but implemented. This has a charge mechanic, for example.
  • Unit Trait This fields uses a binary code, meaning that each box bellow controls a bit of the number and the value above is the decimal translation. This is what allows units to garrison others.
  • Civilization Not used as far as I know.
  • Trait Piece Not used.
  • Dead Unit Into what unit does the unit turn into when it dies. Can be empty for the unit to disappear.
  • Placement Terrains Two fields. Only relevant for docks.
  • Placement Side Terrains Two fields. Only relevant for docks. Also makes shore fish appear in the shore.
  • Terrain Table The actual guide for where a unit can be. Values don't represent single terrains but collections of them, see the "Terrain Tables'' tab.
  • Foundation Terrain For changing a terrain when a building is placed there.
  • Initiates Technology A technology to be researched automatically when the building is finished. Used for age requirements and queuable technologies.
  • Defaut Task Used by animals to be move around the map.
  • Drop Sites Two fields for the buildings villagers use to drop resources. Note that fishermen using the dock is not implemented through here but through the patch. You could do it at the expense of loosing another building.
  • Collision Size Physical space occupied by the unit, specially relevant for missed shots and for bunching units together.
  • Selection Outline X and Y values determine the size of the circle or square around the unit. Z value controls the position of the health bar.
  • Clearance Size As far as I know, the same values as the collision one.
  • Occlusion Mode This fields uses a binary code, but doesn't have check boxes so you need to do the binary translation yourself. This makes units display their outline when passing behind buildings.
  • Obstruction Type This makes buildings have square selection and controls whether units can pass over others.
  • Blockage Class One thing this fields controls is whether buildings can be placed over units, counting that they will move away.
  • Selection Effect Whether to display the health bar or the outline when selecting the unit.
  • Trailing Unit Used by projectiles to leave behind a trail of smoke. "Trail Mode'' is usually set to 2 and "Trail Density'' is usually 0.4.
  • Interface Kind What controls the buttons you see in when selecting the unit, for example the formation buttons for military. Bear in mind that the buttons for units to create or buildings to build are controlled with the following fields.
  • Train Time Also construction time for buildings.
  • Train Location Set to the builder for buildings.
  • Train Button Where in the interface does the button appear. 1 to 5 are first row, 6 to 10 the second row, 11 to 15 the third one and extra values create a second page.

Resources and Costs​

This section controls the resources units give or consume and the costs they have to build.

"Resource Storages'' is used by trees or animals to store resources. Houses and alike use it to provide housing space and units use it to take housing space. Bear in mind that there are several options for the resource:
  • The resource can be stored in the unit and has to be gathered.
  • The resource can be given when the unit is created and never lost.
  • The resource can be given when the unit is created and returned when the unit dies.
Costs control what resources the player needs to build the unit, including population. Resources can be subtracted from the bank or simply present, like the population space.

Looting Table​

As far as I know, this small section only controls resource production buildings, mainly the Feitoria.

Annex units and alike​

Annex units are units that appear next to a building when the unit appears and die with it. This can be with the foundation or with the finished building if it has the attribute "Built: Vanishes''. There can be four annex units and you could add annexes to the annexes. Bellow every annex unit field there are two fields for the position of the annex unit relative to the center of the head building.

Appart from the Annex unit, there are other fields here:
  • Stack Unit The unit that appears after completion. Usually paired with the ``Built: Vanishes'' option.
  • Head Unit As far as I know, it has no effect but informs of the unit an annex one is connected to.
  • Transform Unit Used by trebuchets and gates.
  • Pile Unit Not used.

Sounds​

This section is self explanatory, with the sounds units produced when being created, selected or tasked with something. Bear in mind that Damage and Transform sounds are not used.

Tasks​

The final section of the units tab stores the things units can do. For military units is fairly simple, attack and garrsion. But villagers have tasks to collect resources and Feitoiras have tasks to produce resources. For these two, the field "Productivity Resource'' is very important, as it controls the amount of resource collected or produced. This is what makes Mayans have extra resources.

Healing units​

Although the attribute is not visible in the units tab, it is possible to control the healing rate of units.

Originally, the only unit that could regenerate health (appart from heroes) was the Berserk. This ability was controlled via resource 96. The value of that resource would control the regeneration speed of the Berserk.

With the introduction of Maghrebi Camels, the game has a new way of giving units regenerating abilities that is programmed as an atribute of speciffic units, so that we can set different regeneration speeds for each unit. This is done via 2 attributes:
  • Attribute 40 seems to control wether the regeneration is active or not. Putting it to 4 is the simplest option. Other values also convert the unit into a hero, thus making it impossible to convert.
  • Attribute 45 controls the regeneration speed. The number is the time in seconds to get a new health point. The smaller the number, the faster the regeneration.
With this, the Berserker no longer uses the dedicated resource, which is reserved for the Caravanserai effect. Starting in Dark Age, attribute 40 is set to 4 and attribute 45 is set to 1.5.

Generating extra resources​


Malians, Mayans or Tatars have some variation of the bonus ``Villagers extract X\% more resources''. For the case of malians, for example, this is 10\% more gold. The way this bonuses are implemented is a bit obscure and worth explaining.

Let's look at the gold miner, unit 579. If we look at it's tasks, one of them is ``Hunt unit 841'', that is, gathering gold from mines. Let's look at the fields, ``Resource In'', ``Productivity Resource'' and ``Resource Out''. These resources work as follows:
  1. The villager extracts a unit of ``Resource In'' from the mine. If we check the actual mine, unit 66, we see that it has 800 units of ``Gold Storage''.
  2. The unit of gold is multiplied by the ``Productivity Resource''.
  3. The amount resulting from the multiplication is added to the player's ``Resource Out'' bank.
If ``Resource Out'' is empty, the same as ``Resource In'' is used. The resources can also be different, as is the case for hunters.

The bonuses that increase the amount of resources obtained modify the corresponding ``Productivity Resource''. In the case of Malians and gold, effect 621 changes the original value of 1 to 1.1.

2.6 The Graphics tab

This tab lets you add graphics and sounds to the units. One important detail to note here is the use of angles.

Units have graphics facing different angles but, in order to save space, the game mirrors angles to reduce graphics. This means that unit graphics have five angles: south, south-west, west, north-west and north, with the east versions being mirrored versions of the west ones for a total of eight angles.

Let's go over the fields in this tab:
  • Internal Name and Sprite Name are used to identify graphics but not by the game, in favor of the "Sprite'' number.
  • Sprite Number of the .slp file that stores the graphic. This file can be in a .drs file, the drs folder of the mod or a local mod folder.
  • Layer Order in which graphics are drawn, the higher the value, the more on top of other things. This makes units show the outline when going behind a building but not its shadow.
  • Transparent Pick Whether the graphic should respond to clicks. This makes buildings clickable only by clicking the actual building, not the shadow or the range indicator lines.
  • Replay Delay The time between repeating an animation. Mostly used for idle units so they are not constantly moving.
  • Frames per Angle Every angle in the .slp file should have the same amount of frames, reflected here.
  • Animation Duration In seconds.
  • Sequence Type Whether the game should use different angles or loop the animation.
  • Mirroring Mode Whether the game should mirror frames to make the other angles. For eight angles, this field should be 6.
  • Sound A sound to be played with the animation. Used for dying units or flames. weapon hits are done below.
  • Forced Player Color Only used for birds.
  • Unit Speed Multiplier Set to 1 for all moving units and 0 for buildings.

Deltas​

This section controls additional graphics displayed with the main one. Its main use is to display shadows, flames or snow over buildings.

Each additional graphic is added with an offset of where to place around the main one and the option to display it only in certain angles.

Angles and sounds​

The final part tells the game how many angles make up the graphic and gives the possibility to add sounds to the animation linked to certain angles (not used as far as I know) and to sync them to a specific frame. This is where the sounds of weapons hitting are programmed to sound as the weapon moves in the animation.

2.7 Parameters and values

This section is intended for documenting values that are not clearly explained in the help of AGE or that is outdated with new features implemented.

2.7.1 Armor classes​

Here is the full list of armor classes the Community Patch uses:
  1. Infantry units.
  2. Turtle Ships. Turtle Ships and Thirisadais have the armor. Fire ships have the attack.
  3. Base pierce damage of non mounted units.
  4. Base melee damage of non mounted units.
  5. Elephants.
  6. Extra cavalry class to combine the Bohemian bonus damage and Sicilian and Bengali bonus resistance.
  7. Extra elephant class for damage against Bengali elephants.
  8. Cavalry.
  9. Extra cavalry class to combine the Gurjara bonus damage and Sicilian and Bengali bonus resistance.
  10. Unused.
  11. All Buildings, including stone walls.
  12. Unused.
  13. Stone Wals and gates, excluding palisades.
  14. Animals have the armor, villagers the attack. For implementing the Magyar bonus.
  15. Archers.
  16. Ships.
  17. Rams, Trebuchets and Siege towers.
  18. Trees. Lumberjacks and Ballista elephants have the attack but no unit has the armor. Probably used to be able to damage trees.
  19. Unique units.
  20. Siege weapons.
  21. Standard Buildings, excluding stone walls.
  22. Walls and gates, including palisades.
  23. Gunpowder units. For the Condottiero bonus.
  24. Boars and alikes. For the Goth bonus.
  25. Monks.
  26. Castle and Krepost.
  27. Spearmen.
  28. Cavalry Archers.
  29. Eagle Warriors.
  30. Camels.
  31. Ignoring armor class. Units have zero armor on this class, buildings have their melee armor. Used by Leitis and Dravidian units after their unique technology.
  32. Condottiero. Used by units with bonus damage against infantry (Cataphract, Slinger) to bypass the Condottiero resistance against Hand Canoneers.
  33. Composite Bowman class to accomodate their ability.
  34. Fishing ships. Ships and fortified buildigs have this attack.
  35. Mamelukes. Pikemen and camels have this attack.
  36. Archers except skirmishers. For implementing the Japanese bonus.
  37. Heavy Siege. Hussite Wagons and Ballista Elephants have the armor, Mangonels and Bombard cannons have the attack.
  38. Skirmishers and Genitours. For implementing the Bengali bonus.
  39. Pierce damage of mounted units.
  40. Melee damage of mounted units.
  41. Unused.
  42. Unused.
  43. Unused.
  44. Unused.
  45. Unused.
  46. Unused.
  47. Unused.
  48. Extra cavalry class for damage against Sicilian units.
  49. Unused.
  50. Extra damage of Arambais.

2.7.2 Blast damage options​

As far as I've gathered, the original blast damage was hardcoded into the game and there is no way of modifying the damage it does. By original blast damage I mean the one done by units up to the Conquerors expansion: the Cataphract, the War Elephant and the Siege Weapons. For these units, we can change the radius of effect but not how much damage is dealt.

Later on, in subsequent expansions, the field ``Blast Attack Level'' can be used to control how much damage units deal around them. This is used in Battle Elephants, Slavic Druzhina, Polish Lechitic Legacy and the Urumi Swordsman. The ``Blast Defense'' field doesn't seem to have any effect.

This field gives different amounts of damage and units affected depending on the binary representation of the number, each bit controls a certain property. The following lists all the existing bits in the Community Patch and, as far as I know, there are additional bits in Definitive Edition.

The first two bits control which units are affected by the attack. The four values are:
  • 00: Units, buildings, trees and other resources receive damage. This destroys stone and gold mines.
  • 01: Units, buildings and trees receive damage but not other resources.
  • 10: Units and buildings receive damage. This is the usual configuration for non-siege units.
  • 11: Only units receive damage.
By default, the blast attack deals full damage, accounting for armor. By setting to one one of the next bits, you can set different amounts of damage:
  • Third bit set to 1: units receive 5 damage, regardless of armor.
  • Fourth bit set to 1: units receive half damage, accounting for armor.
The highest bit set to one has priority when deciding the damage. This means that values from 8 to 11 do the same as values from 12 to 15. After 15, additional bits are not considered so the list repeats.

Full list of values​

0. Full damage (accounting armor). Applies to units, buildings, trees and resources.​
1. Full damage (accounting armor). Applies to units, buildings and trees.​
2. Full damage (accounting armor). Applies to units and buildings.​
3. Full damage (accounting armor). Applies to units.​
4. 5 damge (ignoring armor). Applies to units, buildings, trees and resources.​
5. 5 damge (ignoring armor). Applies to units, buildings and trees.​
6. 5 damge (ignoring armor). Applies to units and buildings.​
7. 5 damge (ignoring armor). Applies to units.​
8. Half damage (accounting armor). Applies to units, buildings, trees and resources.​
9. Half damage (accounting armor). Applies to units, buildings and trees.​
10. Half damage (accounting armor). Applies to units and buildings.​
11. Half damage (accounting armor). Applies to units.​
12. Half damage (accounting armor). Applies to units, buildings, trees and resources.​
13. Half damage (accounting armor). Applies to units, buildings and trees.​
14. Half damage (accounting armor). Applies to units and buildings.​
15. Half damage (accounting armor). Applies to units.​
16. Repeat from 0.​

2.7.3 Projectiles​

How the projectiles behave is controlled with the fields "Hit Mode'' and "Vanish Mode''.

"Hit Mode'' has three possible values:

0. Only damages the intended unit. If it passes through other units, they are not affected. Used by arrows.​
1. Damages the intended unit and deals half damage to others in the way, except for buildings and allies. Used by scorpion bolts and bullets.​
2. Damages every unit, building and ally in the way with full damage. Not used.​

Note that these descriptions have nothing to do with missed shots. If a projectile with hit mode 1 where to miss, it would still deal half damage to units in the way.

"Vanish Mode'' has two possible values:

0. The projectile disappears after hitting a target.​
1. The projectile continues until a bit more pass the target.​
Hit and Vanish modes create different types of projectiles:
  • Arrows have Hit and Vanish mode zero, meaning that, if they don't miss, they hit only the intended objective.
  • Bullets from Organ Guns have Hit mode one and Vanish Mode zero, meaning that they hit the first enemy in the way. If it wasn't the intended one, they deal half damage.
  • Scorpion bolts have Hit mode and Vanish mode one, meaning that they damage all units in the way to the objective.

2.7.4 New resources​

This is just a list of the resources we've introduced in the game for various purposes, as a way of keeping a log:
  • Resource 214. Control free Kipchaks with Cuman mercenaries.
  • Resource 215. Controls Fishermen and Fishing ships productivity.
  • Resource 216. Controls Sheperds productivity.
  • Resource 218. Controls Feudal Cuman Town Centers.
  • Resources 219 to 285. Controls queuable technologies.
  • Resource 286. Controls Poles stone miners and Vietnamese lumberjacks.
  • Resources 287 and 288. Controls First Crusade Serjeants.
  • Resource 289 and 290. Controls queuable ages, not implemented right now.
  • Resource 291. For detecting Strongholds and Chieftains and apply the new effects.
  • Resource 292. Controls Hunters productivity.
  • Resource 293. For detecting Comitatenses and enable charged units
  • Resources 294 to 336. For controlling the charge speed of various units.
  • Resource 337. For keeping track of the roman militia line, in combination with the Centurion effect.
  • Resources 340 to 342. Controls mining and lumber quable technologies.
  • Resources 343 to 377. Used to store game statistics and display them during recordings.
  • Resources 378 to 477. Controls queuable technologies in the Triple Tech Mode.

2.8 Values in age2_x1.xml

In this section we cover some of the values written in age2_x1.xml, that determine the civilization interfaces, descriptions and AI names.

Civilization interfaces​

This aspect became relevant when the number of civilizations surpassed the amount predicted by the Wololo Kingdoms team.

There are three sets of interfaces for the civilizations: sizes 800 x 600, 1024 x 768 and 1280 x 1024 pixels. The game chooses one of them depending on the screen size and, if needed, enlarges it to fit the screen.

The ids of these files are specified in ``age2_x1.xml'', the file that determines the audio file and the scout unit of the civilization. In the first lines there are two values relevant here: uiBaseId, currently value 51100, and uiStride, currently value 60.

The value of uiBaseId determines where the interface files start appearing. To find the 800 x 600 interface file of a given civilization, we add the civilization id to the value of uiBaseId. This way 51101 is the interface for Britons, 51102 is the one for Franks and 51145 is the Georgian one.

The value of uiStride determines how many civilizations we can have and also where the next set of interfaces begins. We currently have space for 60 civilizations and that means that the set of 1024 x 768 interfaces begins at value 51160. Similarly, the set of 1280 x 1024 interfaces begins at value 51220.

Civilization descriptions​

Similar to the above interfaces, the fields langId and descId store the position in the language file of the civilization's name and technology tree description, respectively. Starting from those values and adding the civilization id, we find the corresponding text.

Artificial intelligence names​

Finally we have the field aiNameOffset, to store the names of computer players for each civilization. This one requires more explanation:
  • Every civilization has 20 fields reserved for names.
  • The first field of those 20 is actually a number that determines how many of the remaining 19 fields are actually used.
  • The original Age of Kings civilizations (the first 13) have their names starting at id 4400. This means 4400 is the first id of Britons, 4420 is the first one for French and so on until Celts.
  • Starting with the Age of Conquerors civilizations, the ids are shifted by the value of aiNameOffset. This means that the Spanish first id, that should be 4400+20 x 13=4660 is actually 4660+7480=12140, with 7480 being the current value of aiNameOffset.
Therefore, given the id of a civilization, the formula to find the id with the names is:
4400+(id-1) x 20+aiNameOffset (if id ≥ 13).




3.1 Graphics Basics

As we’ve seen before, graphics in Age of Empires prior to Definitive Edition come in .slp files, either by themselves in the “drs” folder of the mod or compressed into a .drs file. To visualize them, we use Turtle Pack, but that program offers very little features in terms of edditing and, for the most part we use SLX Studio. You can find links to both programs in the introduction.

3.1.1 Turtle Pack​

If you open an .slp file with turtle pack, you’ll see all its frames and for each frame, a couple of elements:
  • The Anchor, that control where the graphic is displayed, to ensure that a unit’s graphic coincides with its phisical position in the game.
  • The Selection mask, the overlay that appears when a unit goes behind a building.
  • You can change the player color of the unit.
In TurtlePack you can move the anchor of the graphics, reorder frames, extract frames as bmp files, load bmp files as new frames and delete frames.

turtlepack-800x529.png


3.1.2 SLX Studio​

If you open an slp file with SLX Studio (by importing or drag-and-drop), you’ll see that each frame is actually comprised of two images: the actual graphic and the data graphic, that stores all the information of the graphic with different colors:
  • The background, in pink, that codes which pixels should not be shown in game.
  • The shadow, in red, that codes which pixels should be painted gray in game, regardless, of what appears in the actual graphic.
  • The outline, in blue, identical to the selection mask.
  • The player color, in green, that codes which pixels change color with the player.
SLX Studio offers a ton of features to modify the graphics, the frames, and generate graphics in different formats. We’ll see some of the features as we go over applications.

slp_components-800x451.png


3.1.3 The Color Palette​

One concept that may confuse people at first is the fact that Age of Empires doesn’t allow for every color to be displayed in the game. Every graphic can only use 256 colors that are coded in the palette. The following is the main palette in the game, used for painting units, buildings, terrain, trees… Things like the main menu or the loading screens have different palettes.

palete.png


Palettes are stored in interfac.drs, in the data folder of the game. You could modify it and have a different version for a mod but I don’t know of any examples.

The issue with palettes is that sometimes, when you are adding new graphics, either created by you or from Definitive Edition which allows more colors, you may notice that the generated slp has some colors different from the original bmp files you were using. This is because SLX studio will convert a bmp file (potentially coded in 24 bit colors) to the palette, looking for the closest valid colors.

3.2 Adding a new graphic

Let’s look first at a situation where we want to add a new graphic to the game but not a unit or a building that would require dealing with the data graphics. I’m going to follow the process I had to do to add an old button in the mill that changed the behaviour of fishermen between using the dock or the town center and mill. Later on we refined the implementation of this and the button become unnecessary.

1. Obtaining the graphics as bmp files.​

First we need to create the graphics to add. In this case, we want a button that is either the dock icon or the icon with a cross in front. To obtain the dock icon, we have to go to file 50706.slp, that stores the building icons, we scroll down until finding the dock icon and extract it.

When you extract a file, Turtle Pack will ask you to choose a background color. The best practice should be to choose pink, number 252, although in this particular case there is no background to show.

graphic1-800x530.png


Now that we have the dock icon as a bmp file, we will use the icon as it is as one of the buttons. For the other we just edit the icon on Paint and draw a cross over it. Save it with a different name and use the format 256 colors bitmap. Otherwise Turtle Pack won’t accept it.

For the purpose of this example, save the image as a 256 color bitmap. When actually doing this process, save the image as a 24 bit bitmap so that the colors don’t change. When you use SLX Studio to apply the palette, the colors will look better than if you let Paint do it.

2. Loading graphics directly with Turtle Pack doesn’t work​

The button for which we are creating the icon is a technology. This means that we have to add it to file 50729.slp, that stores the technology icons. Open that file with Turtle Pack and add the new frames.
Note that, when adding frames, the program asks about player color and transparent palette:
  • Player color asks wether or not this graphic is painted with some player color, so that it detects the pixels that should change color, in this case we want it empty, as this icon doesn’t change color with players.
  • Transparent palette reffers to the background color. The ones that are relevant are Null (no background color), and Auto (whatever looks like the background color), I’ve had troubles using the third option. In our case, we put the background as Null as we want the game to display the black background behind the icon.

graphic3-800x529.png


Unfortunately, when we load the new frames we see that the unmodified one looks ok but the one that we modified has the colors wrong. This happened when Paint saved the file, even if we save it as a 256 colors bitmap, the palette get’s scrambled.

To fix this, we’ll need to use SLX studio.

graphic4-800x530.png


3. Doing the graphics with SLX Studio​

Open SLX Studio and drop the graphics on it, they will appear in the list of frames.

Now we need to use the tool Apply Color Palette, which converts an image of any format to one using colors in a given palette. The one we want to use is “Standard_Palette”. This is the palette we use for mostly everything so, unless you want to modify a menu or something like that, don’t even worry about it.

graphic5-800x560.png


Once you have applied the palette, save the file. It will generate an slx file, that we don’t care about, and every frame that make up the file. If you are saving the file in the same folder where the frames were originally, replace them as we want the versions produced by SLX studio.

4. Adding the frames to the slp file​

Open back file 50729.slp and repeat the process of section 2 to add the frames. Since now the files are saved with the correct palette, the colors will display properly in Turtle Pack and therefore in the game.

It only remains to set the anchor point properly. Icons have the anchor on the top left corner, pixel (0, 0). Use the arrows or enter the anchor point manually to put the frame in position.

graphic6-800x529.png


You are done!

3.3 Porting graphics from Definitive Edition (old version)

We now look at the case where we want to port the graphic of a unit from Definitive Edition. This explanation is a bit outdated as Definitive Edition no longer uses ''.smx'' files but you could still find them in old builds of the game or from other visual mods. The new way to port graphics is covered in the next section.

We’ll use the Coustillier as an example. This guide will cover the angle count, the reduction on the number of frames, the recoloring and reduction of the shadow and the generation of data graphics.

The same process is used for buildings, although without having to worry about angles.

1. Locating graphic files from Definitive Edition.​

Graphics in Definitive Edition follow a similar path as in AoE II HD. That is “AoE2DE\resources\_common\drs\graphics”. In there you will see a bunch of .smx files. This folder is easier to navigate since the names are self-descriptive.

The one we are going to use as an example is “u_cav_coustillier_walkA_x1.smx”, which corresponds to the coustillier walking.

Open SLX Studio and drop the .smx file in it. SLX Studio will load all the individual frames and display them.

porting1-800x450.png


2. Angles and frame count​

In order to work with the .smx file, SLX Studio needs to save it as an .slx file. This implies saving each frame individually as a bmp file, both the graphic and the data.
But before we do that, we can greatly reduce the number of frames of the graphic to ease up this process. This is due to two factors:
  1. Definitive Edition graphics use 16 angles, that is, 16 directions the unit faces. On the other hand, AoC uses 5 angles and the mirror mode to mimic all directions. This means that two thirds of the frames are not needed.
  2. Definitive Edition uses way more frames to ensure smoother animations. Of the valid angles, we will delete several of them to accomodate the number of frames programmed in AGE.

2.1 Angles​

Let’s delete the unnecessary angles. First of all, note that the Coustillier file has 481 frames. It’s common in Definitive Edition files that the first and last frame are actually the same. It’s easily identifiable if the total number of frames is not divisible by 16. Select the last frame and, on the left panel, click “Delete” and “Apply”. This will put the frame count in 480 frames, which means 30 frames per angle.

This step of having a number of frames divisible by 16 is important so that the next one works out. Go to “Edit/Multi-Select Frames”. This is a dialog box to automatically select a bunch of frames. The field “Per Direction” is at first set to 1. If you change it to 16, you’ll see the field fpd (Frames Per Direction) is 30. Leave the field “Select Every” to 1 and in “Skip Directions” write “5, 7, 9, 11, 13”. This will select all frames in every direction, except for directions 5, 7, 9, 11, 13, the ones used in AoC.

Press “Apply” and let the program select the desired frames. All these are frames we don’t need so you can delete them as you did before. Once that’s done, we have only 150 frames remaining.

2.2 Frames per angle​

If we look at the data for this graphic in Advanced Genie Editor, Sprite 80, we see that it’s programmed to have 20 frames per angle, not 30. If we were to create the slp like this, the displayed frames would not align to the direction the unit is facing, we have to set them to exactly 20 frames per angle.

To do this we use again the “Multi-Select Frames” tool. This time, we leave the fields “Per Direction” and “Skip Directions” empty, and use only the “Select Every” field. There is no exact formula for the following, as the number of frames in Definitive Edition and in the AGE code vary a lot. The idea is to select the frames in an evenly spaced manner so as to hide the fact the we deleted some when the animation is played.

In our particular case, we need to go from 30 frames per angle to 20, that is, delete 10 out of every 30. This can be done by selecting every 3rd frame with the “Multi-Select” tool, which will select a total of 50 frames evely spaced across the animation. When we delte them, we end up with 100 frames, exactly the 20 times 5 we needed.

2.3 Save the .slx file​

Once we have reduced the frames to the necessary amount, we can save the file. The best practice is to save it in a folder for itself, as you are still going to create 200 bmp files for the graphics and data.

3. Color and shadow correction.​

The next step covers two aspects of the port. First, it converts the bmp files of the graphic to the palete AoC uses, so that when we create the slp files, the colors are correct. Second, it will reduce the shadow of units. Shadows in Definitive Edition have various levels of gray, so as to get a smooth look. However, AoC only has one shade of gray for it. If we were to leave the shadow as it is in the port, we would end up with very obstrussive shadows. Because of this, we’ll modify the shadows and only keep the darkest part.

Go to “Tools/Color Replace Graphics”. The window that opens lets you modify the color of images. Note that in the bottom it already has the palette “Standard Graphics” selected, so it will apply the palette automatically. What we need to use is the section “Replace Color”; there we can choose a “Source Color” to replace, a “New Color” to replace with and a “Tolerance” for similar colors to the source one. When you select a combination of these parameters, click “Add” to put it on the list bellow. The ones that you need to create are the following:
  • AA2F9B to FF0000, 20% tolerance.
  • 850C79 to FF0000, 20% tolerance.
  • 4F004B to FF0000, 20% tolerance.
  • D33AC9 to FF00FF, 20% tolerance.
You can save this configuration as a .csv file, as you will always use the same.

porting2-1200x675.png


Now apply the color replace TWO times. The first one almost does nothing, as it barely detetcs the specified colors, but does apply the color palette and thus changes the colors to the ones the color replace will identify in the second pass.

Once this is done, you will see that the units have a red shadow smaller than before. The reason for it being red is so that the data graphic creator of the next step recognises it as shadow.

Save the file to overwrite the images.

4. Creating data graphics.​

Now that we have corrected the shadow in the graphics, we need to recompile the data graphics, as the red pixels in it are what will create the shadow in the end. Also, we need to add the outline around the unit for when it passes behind buildings.

The problem with recompiling data graphics is that we may loose the green player color pixels, that identify the changes in color of the unit depending on the owner. For this problem, there are two options:
  1. Save the data graphics under a different name so that SLX Studio doesn’t replace them. Then, when you create new data graphics and erase the player color, you still have the original ones to copy those pixels back to the newly generated data graphic. This method requires a way of copying only green pixels and do it automatically for all the frames but preserves the exact same pixels.
  2. Have SLX Studio detect the “blue” pixels and treat them as player color pixels. This option is subjected to the actual colors in the image and the tolerance, and is unlikely that you will get the same result as the original version. However is simpler to do and will cover all frames.
We’ll use option 2 here and mention how to use option 1 at the end of this chapter.
Go to “Tools/Generate Data Graphics”. This tool covers the detection of background, the detection of shadow, the player color and the outlines. Let’s go bit by bit:
  • The Mask section detects the pink pixels as background and will omit them from the graphic. Set the tolernce to 20%.
  • The Shadow section detects the red pixels as shadow and will paint them gray. Set the tolernce to 20%. Note that there is also the option of “Split Shadows”; this creates the shadow in a different file and is uses for buildings like castles and walls.
  • The Player section detects all the pixels that should change color with the owner. Here do the following:
    • Set the tolerance to 30 %.
    • Load the preset [Blue] AoE1.
    • Add two more colors to the preset: 0000FF and 004ABB.
  • The Outlines section will draw the outline around the unit. It should not be used for buildings and for corpse units. Mark the option “Draw outlines” and “Player only”.
Once all that is done, apply the changes. The program will detect the necessary pixels and regenerate the data graphics. Save the file to overwrite the images.

porting-1200x781.png


5. Exporting the graphics.​

Now that the graphics have the correct palette and data graphics. We only need to export them. Go to “File/Export” and select the option “AoE2/SWGB Standard 2.0N SLP File (*.slp)”. SLX will ask you again about the palette, leave Standard_Graphics. This will create an slp that you can open with Turtle Pack.
It only remains to set the name of the file to the slp number written in AGE (175054.slp in the case of the Coustillier) and move it to the drs folder of the mod.

Batch processing​

SLX Studio also has the option to batch process several graphics in one go:
  1. “Graphics/Batch Extract SMX to SLX” will convert all the .smx files in a folder into .slx ones, creating a folder for each one. You’ll have to manually go over them and delete extra frames if necessary but it’s useful for buildings.
  2. “Tools/Batch Image Color Replace” will replace the color of all the graphics. It works exactly as the “Color Replace Graphics” tool.
  3. “Tools/Batch Generate Data Graphics” will create the data graphics. This one is more tricky as it’s bugged. You need to set the options in the single “Generate Data Graphics” tool and then move to the batch version, the configuration will remain. Once the process finishes and you close the tool, SLX studio will freeze so you need to close it through the Task Manager.
  4. “Graphics/Batch Convert SLX to SLP/Standard 2.0N SLP” will export to .slp files all the .slx files in a folder.

Handling the color pixels​

The option for detecting color pixels in the “Generate Data Graphics” tool doesn’t give too good results. As I’ve mentioned before. One way around it is to save the original data graphics before SLX studio replaces them and not generate player color pixels. This leaves you with two sets of data graphics: the new ones with small shadow and outline but without color pixels, and the old ones with big shadows, no outline but with color pixels. Now it’s a question of only copying green pixels from the old data graphics to the new ones.
As far as I know, I’ve come up with two solutions to this, use Paint or a script.

Color pixels with Paint​

This method uses the “transparent selection” functionality of Paint:
  1. Open both the original and new data graphics with Paint.
  2. Select the whole new data graphic, copy it and paste it into the original data graphic. This will momentarily hide the original data graphic completly.
  3. On the “Select” option, select “Transparent Selection”. This will make Paint ignore white pixels from the new data graphic and the green pixels from the image bellow will appear.
This process still requires changing images frame by frame.

porting3-600x449.png


Color pixels with a script​

A script can handle all the graphics in a folder in a single go. I created a function in Python that takes two images, goes over the pixels and copies green pixels from one to the other. We used it for creating all new architecture and units.
The following code covers the needed module and the function itself. You will need to add the code that goes over all the images in a folder but, if you know your way with programming, this shouldn’t be difficult.

Code:
#This module lets Python handle images
from PIL import Image

#Function to copy the color pixels (green in the data file) to the new data file
#As inputs, it receives the two file paths
def data_graphics(original_name,new_name):
    #open both files
    original = Image.open(original_name)
    new = Image.open(new_name)
    #get the size of the image
    (w,h) = original.size
    #go over all pixels in the image
    for i in range(w):
        for j in range(h):
            #if the pixel in the original one is green, change it in the new one
            if original.getpixel((i,j)) == (0,255,0):
                new.putpixel((i,j),(0,255,0))
    #save the modified image
    new.save(new_name)

Brighter images​

Appart from all the stuff explained in this guide, katsuie also worked on making the unit graphics brighter. I wasn’t part of the process but, as far as I understood, he kept a copy of the original images. After the whole process described here, he had the original graphics (with 24 bit color and not the palette) and the modified data graphics. He then corrected the images with imagebatch, making them brighter, and after that, he compiled the slp. This way, he had 24 bit color image right until the end. If you want to know more, write to any of us (Pancrol or katusie) and we’ll share more details.

3.4 Porting graphics from Definitive Edition (new version)

We now cover the way to obtain graphics from Definitive Edition when getting the files with the ''.sld'' type.

The only thing you need is a tool to extract .sld files. The one we find most straightforward is SMX Workshop. It also requires installing Java Run Enviroment.

Open the tool by executing ''SMX Workshop.jar'' and drop the sld file you want to export. The loading process takes a while but. when it finishes, you will see all the frames similarly as to what you see in SLX Studio.
Now execute the funtion ''Tools/Convert to AOE2: DE''. This will adapt the frames so that you can later on save them as an .smx file.
There is also the option to convert several files in batch to .smx format.
Once you have obtained the .smx files, repeat the process explained in the previous section.

3.5 Main menu and other graphics of the game

So far we’ve covered adding graphics to the game that we see while playing. However, if we were to do the same thing for the main menu or other loading screens of the game, we would see that the colors are wrong. The reason for this is again the palettes, these graphics use different ones from the Standard_Graphics one.

The first help I got for this was in this page. However, I’m going to cover it so that you don’t need to download stuff, as the palettes we need are already stored in the game.

Locating the interface data​

All the information and files we need are stored in the file “interfac.drs”. This file is not shipped with the mods, it is stored in the root data folder of AoE II. When you open it with Turtle Pack, you’ll see it contains bina, slp and wav files. The slp files contain the interface graphics that you can take if you want to modify some, file 50189 is the main menu, extract it as an slp file to use as an example. What interests us now are the bina files.

Select file 50089. You’ll see a bunch of lines, the first three say that this file affects file 50189, the main menu. Bellow there is a line mentioning the palette file, 50589.

Go to file 50589, it’s mostly made of sequences of three numbers, those are the colors of the palette written in RGB codes. Copy the text into a text file and save it as 50589.pal. Now take this new .pal file and place it into the “Palettes” folder in the Turtle Pack folder, alongside with other .pal files.

Using palettes in Turtle Pack​

Now try to open the main menu slp file, 50189.slp with Turtle Pack. At first the colors will be all messed up but that’s because you don’t have the correct palette selected. On the left there is a drop down menu called “Palette”, select 50189 and the main menu will look ok.
Now that you are seing the graphics properly, you can also export some of them as bmp files to edit them.

Using palettes in SLX Studio​

Using palettes in SLX Studio is a bit simpler as most of them are already loaded into the program. The one for the main menu is called AoK_Menu_TC. Alternatively, there is the option to load other palettes, by giving the program a .pal file like the one we created.

Known palettes​

Here is a table of the files and palettes I’ve used in the Community Patch for the main menu and some other interfaces.

slp file
Description
bina information
Palette number
SLX palettte
50100​
Background 800×600​
50051​
50532​
AoK_Load_Screen​
50101​
Background 1024×768​
50051​
50532​
AoK_Load_Screen​
50102​
Background 1280×1024​
50051​
50532​
AoK_Load_Screen​
50104​
Civ selection menu​
50053​
50533 (same as 50532)​
AoK_Load_Screen​
50163​
Loading Screen​
50063​
50563​
———–​
50189​
Main menu​
50089​
50589​
AoK_Menu_TC​

4.1 Upgrading Units

The concept of upgrading units is very simple at first glance but, in some cases, it can be quite messy.

Let’s look first at a very simple example. Effect 211 upgrades Militia into Man at arms, specifically the first command, the others are not relevant at this point. Following the Militia line, effect 182 upgrades into Two-handed swordsman. The first command upgrades Militia and the second one the Man at arms.

Now, one could ask, why do we need two commands? If in order to research Two-handed swordsman, one has to research Man at arms, by the time you get to the second tech, all Militias are already Man at arms.

Turns out that the game works the opposite way: all the Men at arms you are about to upgrade are still Millitias for the game. If the upgrade to Two-handed swordsman only had the command for Men at arms, yours wouldn’t be affected.

This doesn’t mean either that Men at arms upgraded from Militias are different from newly created ones once the upgrade is researched. The upgrade from Militia to Man at arms affects both current and future Men at arms. When you create a Man at arms in the Barracks, you are effectively creating a Militia that has been upgraded to Man at arms.

In conclusion: upgrades of units are applied to the first unit in the tech tree and subsequent upgrades replace the previous one.

The next question is, why do we need the upgrade from Man at arms to Two-handed swordsman if only the militia one is used? Well, the Militia one is used in normal games but, if through the scenario editor you place a Man at arms, this is an “actual” Man at arms that needs the second command in the upgrade to Two-handed swordsman.

4.2 Extra villagers or sheep in the Town Center

Another implementation worth explaining for later on, when we reuse it for Burgundians and Sicilians, and because it takes a while to unravel without help. Here we are going to look at the extra villagers or llama Chinese, Mayans and Incas get, and how the Tatar bonus is also an implementation of the first idea.

Since these bonuses are related to the town center, let’s look at it in the code. If you write “town center” in the filter box, you get 20 different units. There are actually 5 town center versions for each age, you can read this page to learn more about how it works. The unit that interests us is number 109, the dark age town center, the one where villagers and techs are created. If we scroll down to the “Annex units” section, bellow the resources we can see that unit 109 has four different annex units attached to it. The first three are parts of the town center (see the page cited above). The fourth one, “Empty TC annex”, unit 890 is the interesting one.

Let’s look at its stats. Right away we can see that it has no graphics, it’s invisible. Moreover, it has -1 hit points and, as the help says, this means it is an instantly dying unit. Therefore, every time you build a town center, you create this invisible unit that dies instantly. Moreover, this unit’s “Dead unit” is -1, meaning that, when it dies, it just disappears from the game without transforming into something else. Pretty absurd at first sight.

Mayan bonus​

Let’s try to find now how Mayans create the extra villager. Go to the Techs tab and filter with Civilization 16 to see the technologies only Mayans can research. There is a tech called “Start /w 4 villagers”, number 554. Let’s look at its effect, 586. It upgrades unit 890, the “Empty TC annex” from before to unit 1398, “Villager annex (Mayan)”.

Back to the Units tab to check this new unit. It’s still an invisible unit that dies instantly but, if it’s responsible for creating the extra villager, it has to do something else. If we scroll down we can see three things:
  • It initiates technology 552, “Disable TC spawn extra”.
  • It has another annex unit attached to it, 1394, “Villager building”.
  • Its “Dead unit” is still -1.
These two new things are different from the original 890 unit every town center has. It means that, for Mayans, when you build a town center, instead of having unit “Empty TC annex” attached, it has this other unit that triggers a technology and creates a new unit before disappearing.

Let’s look first at the unit, “Villager building”, number 1394. Again an invisible unit that dies instantly without triggering techs or having new annex units. However, its “Dead unit” has something: unit 1397, “Villager building2”.

“Villager building2” also dies instantly but now, its dead unit is an actual villager, unit 83.

Let’s recap what we have discovered. For normal civilizations, the town center has unit 890 attached to it, a useless unit that dies instantly. For Mayans, this unit is changed to unit 1398, which goes through several transformations:
  • It creates unit 1394 attached to it and triggers tech 552.
  • Unit 1394 dies instantly and turns into unit 1397.
  • Unit 1397 dies instantly and turns into a villager.
The fact that units die into others is a necessity to “unlink” from the town center. As unit 1398 and 1394 are annex units, they are glued to the unit they are attached to (this in the code is referred to as “Head unit” but the value of that field has no effect). However, once an annex unit dies and turns into another, the attachment breaks, which allows to take the extra villager out of the town center.

Now, you may think that this code does several redundant steps and that it could achieve a similar thing with less units. That is true in part, unit 1398 could trigger tech 676 and die directly into unit 1397 without having to go through unit 1394. However, this is implemented this way as a copy of the Chinese bonus, which requires the extra process.

Chinese bonus​

Let’s look now at the chinese version to see why so many switches between units are needed. Go to the Techs tab and filter the chinese technologies, number 302, “Start /w 6 villagers”, is the one we care about. Its effect, 302, does something very similar to the Mayan one: it upgrades unit 890 to unit 1396, “Villager annex (Chinese)”.

As with unit 1398 for Mayans, this unit triggers tech 552. The difference is in the annex units; whereas the Mayan version placed only one annex unit, the Chinese one places three copies of unit 1394, one for each new villager. From this point, the process is the same one: turning units 1394 into units 1397 and finally turning into villagers.

"Disable TC spawn" techs​

Finally, let’s look at the technology the civilization bonuses trigger. Techs 552 produces effect 733.

Effect 733, “Disable TC spawn extra” has only command: to upgrade unit 890, “Empty TC annex”, into 889, “Disable TC spawn”, which is basically a copy of unit 890. Recall that this effect happens once units 1394 or 1396 have died and placed the annex units. What this technology is doing is preventing the bonus to happen on extra town centers the player may start the match with. Since the game goes through the town centers sequentially, the first one it encounters creates extra villagers and deactivates it for any other town centers that may be already present.

Tatar’s extra sheep​

The Tatar bonus follows the same ideas but has some variations, since it applies to newly constructed town centers after Castle Age. If we look at the tech that creates it, number 704, we see it requires Castle Age to activate. Its effect, 741, turns unit 890 into unit 1390, “Sheep annex 1”. This does not affect the initial town center as its unit 890 died at the beginning of the match. Unit 1390 goes through several transformations until turning into two sheeps with the difference that it doesn’t trigger the “Disable TC spawn” techs, as it should happen for all new town centers.

4.3 Queuable technologies

The queuable technologiess functionality was first introduced in Tech hotkeys and is probably one of the most clever things ever implemented. As any player from before Definitive Edition knows, it is possible to queue units but not technollogies. However, the units tab has a field called “Initiates technology” that at least can be used to keep track of the buildings required to age up. Most actual units whose production we can queue have this field disabled, all except for the Trebuchet.

That’s the idea: creating a bunch of copies of the Trebuchet, that can be queued but also can be assigned a technology to research upon completion. Assigning each unit the icon, position in the menu, cost and research time of the technology it represents, we can mimic the idea of researching techs when in reality we are creating units. Moreover, this trick allows to have technologies with zero research time but that have to be manually clicked. Definitive Edition claims to have Loom research instantly for Goths when actually it has to take at least one second in order not to be an instantaneous technology (see the section on the Techs Tab for more information on this). The Community Patch really has Loom with zero research time.

Actual implementation​

Appart from actually going over all techs in the game, copying the cost and research time, and having to modify civilization bonuses that affect research time or research cost, there are a number of issues that we have to solve:
  • We need new technologies that “make available” the queuabe version when the requirements of the technology are met. For example, technology 816 researches automatically once you reach Feudal Age and its only effect is to activate the queuabe version of Bloodlines.
  • Thechnologies are programmed into the Technology Tree of civilizations by simply disabling the tech. For the queuable technologies, we also need to disable the techs that make the queuable version available. Effect 258, the Frank Technology Tree, has technology 816 disabled.
  • The queuable technology is actually a unit that should disappear as soon as it has triggered the tech. This is easy to do by setting the hit points of all the queuable techs to -1.
  • Since for all intends and purposes, the queuable techs are units, it is perfectly possible to queue more than one or to shift-click them in a group of buildings. With this you are paying the cost of several techs but only getting the effect once. To solve this we introduce another resource into the cost, a hidden resource of which the player only has one unit. This way, once the player clicks once in the tech, it consumes the single unit of the resource and prevents from researching a technology more than once. We have to create a new resource per technology in order to have this.
  • Once the technology has been researched, the icon doesn’t disapear, as the game treats it like a unit. Therefore, we have to program the effect of every technology to also disable the unit that created it.
  • Additionally, we instruct the technology to move the button to position 255. This effectively hides the button and is implemented as a security measure for scenarios that may want to research technologies using triggers.
  • We need also to disable the button field in the Techs Tab so it doesn’t show in game. This is the only part of the original technology we should modify as the AI still researches technollogies in this fashion. Leaving the research time and cost intact allows to competitively play against AI.

Issues​

The main issue with this functionality is that the icon of the technology doesn’t hide during the research of the technology, giving the impression that the technology is not in progress. We managed to fix this on the Community Patch by modifying the patch.

Another issue that may occur is that, if the building has the gather point set to itself, the technology will appear garrisoned after completion. Regardless of this, its effects are applied.

A more obscure issue​

Technologies researched through units don’t seem to always register as researched technologies for other technologies that have them as required techs. Let’s see the example of Thalassocracy. The basic tech, 624, turns Docks into Harbors. Since Harbors shoot arrows, they are affected by Blacksmith upgrades, Ballistics, Chemistry, etc.

This effects are added through additional techs that have both Thalassocracy and the corresponding technology as required technologies. However, if this technologies are researched with queueable techs, they don’t always register as researched (depending on the order they are researched) and thus Harbors don’t benefit from all upgrades.

A similiar thing could happen with techs that require a previous technology and a new age to be available. Depending on the order things are done, the new technology may be available or not.

This is solved with dummy technologies. Creating technologies without effect whose only prerequisite is the technology they stand for, (technology 78 is an example of this). Since these technologies depend only on one, even if it comes from a queuable tech, it is researched. All the addons on Thalassocracy don’t depend directly on the actual technologies but on dummy version to ensure they are researched. Similarly, all blacksmith technologies that are conected through ages have a dummy version.

In game behavior​

With all this explanation of the implementation, let's see how all the pieces work in game.
  1. When the requisites of the technology are met (age, previous technology) the actual technology is enabled and the "make available" version is activated. Humans don't see the actual technology, as the button is hidden, but AIs do. In the corresponding building, a trebuchet-like unit appears in the position of the technology.
  2. When the unit is created, it dies instantly but triggers the actual technology. Appart from it's effects, this technology hides and disables the unit.
  3. If needed, a dummy version of the technology is triggered to enable future technologies.

Scenario Editor use​

Since now all technologies of the game are hidden and handled through units, if you want to control them in the scenario, you have to be aware of their implementation. Here are some tips:
  • If you want to research a technolgy using triggers, research the actual one. It will take care of hidding the button of the unit.
  • If you want to enable a technology for the player to research, use a trigger to research the "make available" version.
  • If you want to disable a technology for a civilization, disable the "make available" version. The section of the editor where you can disable technologies only uses the actual ones, which may be useful if you expect to use AI players.
  • Unique technologiess and unique units upgrades use all the same three technologies.
  • The effect to research technologies allows to input a number. Some of the useful values you can use with queuable techs are the following. For more information, see here.
    • 0. Research the technology.
    • 2. Disable technology.
    • 3. Enable a technology for researching through triggers.
Both versions of the technologies are accessible through the triggers menu.

4.4 Adaptative Age of Mandala

The Community Patch is the first mod to have an adaptative version of Age of Mandala. As of April 2021, Definitive Edition implemented a version of it. It is a different implementation of what I’m explaining here.

We are going to look at the basic version of Age of Mandala and explain why it's not possible to make it adaptative. Then we'll see how Community Patch handles the adaptative part.

Basic Age of Mandala​

The first implementation of Age of Mandala, available in the mod center and that works on every version of the game, works by modifying the shadow of buildings. Usually the graphics of buildings is separated into two parts, the building and its shadow. Age of Mandala replaces the shadow file for one with the circle.

If one looks at the code of the game, it seems clear why it’s not that simple to make the mandala grow with the range upgrades. There is nothing in the effects of the range upgrades that modifies the graphics of the buildings. Regardless of upgrades, the graphics of the buildings are the same.

Adaptative Age of Mandala​

If we want to have an adaptative version of the mandala, we need to modify the game so that we have a way of having different graphics for different range upgrades.

Easy version​

The solution at first sight is easy: have the range upgrades upgrade the buildings into a different versions of them with extra range. Since they are different units, we can have different graphics in them and thus add a different mandala in each building. This is how it’s done for Kreposts, Harbors and Donjons. For example, there are four versions of the Krepost, 1245, 1465, 1466 and 1467, each with their own graphics that include different versions of the mandala. Range upgrades such as Fletching (effect 192), upgrades one Krepost into the next version and modifies the range, so that the building still looks as having 7+1 range.

Hard version​

The previous implementation is easy to do but benefits on the detail that those buildings are unique to specific civilizations and therefore there is only one set of graphics we have to worry about. Castles, towers and town centers are very hard to do in this fashion as we'd have to create different graphics for each civilization and range upgrade. At first I considered this to be too much work but, after some thought, I found a workaround that allows me not to have to modify the buildings themselves.

The idea is to use annex units that take care of the mandala. If we look at the Watch Tower, unit 79, we see it has unit 1443, ''Tower range 8'', annex. This unit only disappears if the tower itself dies, as it is attached to it. The only relevant thing it has is that it carries the mandala graphic with it. This way, when you see a tower, you are actually seeing two units: the basic tower and the mandala unit attached to it. Range upgrades only have to upgrade the ''range'' units for the Mandala to be adaptative.

This implementation introduces a problem: since the range unit is different from the actual unit, it appears when the tower is placed, before villagers even start working on it. This meant that a player could see a mandala appear as soon as the opponent placed the building but before the villagers arrived, giving him time to react.

To solve this we have to separate the building being built from the building actually standing, like town centers and gates do. If we look for ''Watch tower'' units in the units tab, we can see there are two of them, 79 and 1461:
  • Unit 79 is the unit you see in game but it has no Train location (which should be the villager) and has unit 1461 as Head unit.

  • Unit 1461 does have the villager as the Train location, has a different range unit from unit 79, 1404, and has unit 79 as Stack unit. The description of Stack unit reads ''Second building to be placed directly on top of this building''. Moreover, one of its attributes is ''Built: Vanishes''.
This means that the unit you see in the villager menu is number 1461 and this is the unit villagers build. Once the building is complete, it disappears and is replaced by unit 79, the actual tower.

Let's look finally at the other range unit, 1404, in castle 1461. This unit is identical to unit 1443 except for the hit points, which are set to -1. Then, unit 1416 dies the moment it is created. This is done so that the mandala is visible when you are about to place the building. The game shows the standing graphics of the unit and all its annex units but without creating them. Once the building is placed, the range unit is created and dies instantly. The mandala will reappear once the building is finished and is replaced with the other version.

Final problem​

Although this last implementation is very efficient in the sense that avoids doing it several times for each architecture, having two units connected introduces an issue for castles.

The best way to understand it is to look at the Town Center, which uses the same idea of stack and annex units. If in a normal game you start building a Town Center and, while in construction, you assign the foundation to a control group, once the building finishes the unit disappears from the control group. This is because the option ''Built: vanishes'' effectively kills the unit. For the Town Center this is done so that the foundation is not passable but the actual building is.

If we apply the previous implementation of the mandala to castles, we'd face the same problem of loosing the buildings from control groups. I deemed this not ideal so I ended up creating different graphics for each architecture and range and using the annex building implementation only for towers and town centers

Code for generating the mandalas​

It is unlikely that the game will ever include a building that can not reuse one of the existing mandalas. In any case, here is the Python code I used to create the mandalas, in case it is ever needed.

Adaptative Age of Mandala code​

Code:
from PIL import Image
import math
import numpy as np

'''
This program creates mandalas given the size of the building and its reach
It differentiates between straight lines paralel to the sides of the building and
arcs around the corners, following an ellipse.

To get the distances, the program assumes that the tiles measure 96x96 pixels and that
the perspective shrinks them only vertically, by a factor of 0.5.
'''

global ang,side,horizon
#A tile measures 96 pixels horizontaly and 48 vertically
ang = math.atan(0.5) #angle of the grid lines from the horizontal, 30 degrees.
side = math.sqrt(96**2+48**2)/2 #length of a tile side in pixels
horizon = math.sqrt(2)*48 #length of a tile side when horizontal

def aprox(x):
    return list(map(round,x))

#Create empty image
def empty(base,reach):
    #base: number of tiles of the side of the building
    #reach: in tiles of the building
    global ang, side, horizon
    l = math.ceil(base*96+reach*2*horizon)+4 #length of the picture plus 4 extra pixels
    h = math.ceil(base*48+reach*2*horizon*0.5)+4 #height of the picture plus 4 extra pixels
    return Image.new("RGB", (l,h), (255,0,255)) #blank image in pink

#Paint a pixel and the 8 surounding it
def paint(img,x,color):
    i = [-1, 0, 1,-1,0,1,-1,0,1]
    j = [-1,-1,-1, 0,0,0, 1,1,1]
    for k in range(9):
        img.putpixel((x[0]+i[k],x[1]+j[k]),color)

#Draw straingt lines from point x following vector v in length long(given in tiles)
def straight_line(x,v,long,img):
    global side,trace
    step = 0.01
    for _ in np.arange(0,long+step,step):
        x=x+v*step
        if int(trace)%2==0: #to make discontinuous line
            paint(img,aprox(x),(255,0,0)) #paint in red
        trace += step*4

#Paint arcs at distance reach from x0 starting in angle a0
#The function draws an ellipse
def arc(x0,a0,reach,img):
    global ang,trace,horizon
    step = 0.001
    #Start a bit before a0 and finish a bit after rotating ang, to ensure it connects to the straight lines
    for thet in np.arange(a0-ang*0.7,a0+2.7*ang+step,step):
        x=x0+np.array([reach*horizon*math.cos(thet),reach*horizon*0.5*math.sin(thet)])
        if int(trace)%3==0: #to make discontinuous line
            paint(img,aprox(x),(255,0,0))
        trace += step*(3*horizon/4) #increment: angle in radians times the mean radius of the ellipse

#function to create the whole mandala
def mandala(base,reach):
    #base: number of tiles of the side of the building
    #reach: in tiles of the building
    global ang,side,trace
    img = empty(base,reach)

    #vectors following the lines in the grid
    v1 = np.array([side*math.cos(ang),side*math.sin(ang),])
    v2 = np.array([-side*math.cos(ang),side*math.sin(ang),])
    (l,h) = img.size

    center = np.array([l/2-1,h/2-1])
 
    trace = 0
    #straight side NW
    x=center-v2*base/2-v1*(base/2+reach)
    straight_line(x,v2,base,img)
 
    #arc W
    x=center+v2*base/2-v1*(base/2)
    arc(x,math.pi-ang,reach,img)
 
    #straight side SW
    x=center-v1*base/2+v2*(base/2+reach)
    straight_line(x,v1,base,img)

    #arc N
    x=center-v2*base/2-v1*(base/2)
    arc(x,3*math.pi/2-ang,reach,img)

    #straight side SE
    x=center+v2*base/2+v1*(base/2+reach)
    straight_line(x,-v2,base,img)

    #arc E
    x=center-v2*base/2+v1*(base/2)
    arc(x,-ang,reach,img)

    #straight side NE
    x=center+v1*base/2-v2*(base/2+reach)
    straight_line(x,-v1,base,img)

    #arc S
    x=center+v2*base/2+v1*(base/2)
    arc(x,math.pi/2-ang,reach,img)
        
    return img

#Tower
for i in range(8,14):
    mandala(1,i).save('tower'+str(i)+'.bmp')

#Donjon
for i in range(8,12):
    mandala(2,i).save('donjon'+str(i)+'.bmp')

#Krepost/Harbor
for i in range(7,11):
    mandala(3,i).save('krepost'+str(i)+'.bmp')

#Castle
for i in range(8,15):
    mandala(4,i).save('castle'+str(i)+'.bmp')

4.5 Random map scripting

There is not too much in the field of random map scripting that I can add. The best thing I can do is share the most complete guide I know of Definitive Random Map Scripting Guide. It’s a very complete and up to date guide, that even informs which version of the game supports each command, so that people programming for older versions of the game are aware of it.

What I can contribute is with ways to include features that are present in Definitive Edition or that, historically, have required the use of a different data mod to work.

Allied vision​

Having allied vision activated at the start of the game is easy. That functionality depends on a resource that is initially set to zero until the players build the market.

To set it to one at the start, in the section PLAYER SETUP, add the following:
#const REVEAL_ALLY 50
effect_amount MOD_RESOURCE REVEAL_ALLY ATTR_ADD 1


The first line declares a value and gives it the resource ID and the second one adds 1 to the value of the resource, setting it to 1.

No onager cutting​

Similarly to the allied vision, preventing onagers from cutting trees depends on disabling the tech that allows it. In the section PLAYER SETUP, add the following:
effect_amount SET_ATTRIBUTE ONAGER ATTR_BLAST_LEVEL 2
#const R_OCUTTING 153
effect_amount ENABLE_TECH R_OCUTTING ATTR_DISABLE 153

Longer lasting resources​

This feature can be added into the map by changing the ammount fo resources the objects carry. You need to add the following lines in the PLAYER SETUP section:

Code:
effect_amount SET_ATTRIBUTE BAMBOO_TREE ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE OAKTREE ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE PINETREE ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE PALMTREE ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE TREE_A ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE TREE_B ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE TREE_C ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE TREE_D ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE TREE_E ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE TREE_F ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE TREE_G ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE TREE_H ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE TREE_I ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE TREE_J ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE TREE_K ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE TREE_L ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE FOREST_TREE ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE SNOWPINETREE ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE JUNGLETREE ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE DRAGONTREE ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE BAOBABTREE ATTR_STORAGE_VALUE 2000
effect_amount SET_ATTRIBUTE ACACIA_TREE ATTR_STORAGE_VALUE 1500
effect_amount SET_ATTRIBUTE DLC_MANGROVE_TREE ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE DLC_RAINTREE ATTR_STORAGE_VALUE 1000

#const GURJARA_BUSH 1628
effect_amount SET_ATTRIBUTE FORAGE_BUSH ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE DLC_ORANGEBUSH ATTR_STORAGE_VALUE 1250
effect_amount SET_ATTRIBUTE GURJARA_BUSH ATTR_STORAGE_VALUE 1250

effect_amount SET_ATTRIBUTE GOLD_MINE ATTR_STORAGE_VALUE 8000
effect_amount SET_ATTRIBUTE STONE_MINE ATTR_STORAGE_VALUE 3500

effect_amount SET_ATTRIBUTE FISH ATTR_STORAGE_VALUE 2000
effect_amount SET_ATTRIBUTE SHORE_FISH ATTR_STORAGE_VALUE 2000
effect_amount SET_ATTRIBUTE GREAT_FISH_MARLIN ATTR_STORAGE_VALUE 3500
effect_amount SET_ATTRIBUTE GREAT_FISH_MARLIN2 ATTR_STORAGE_VALUE 3500
effect_amount SET_ATTRIBUTE DORADO ATTR_STORAGE_VALUE 2250
effect_amount SET_ATTRIBUTE SALMON ATTR_STORAGE_VALUE 2250
effect_amount SET_ATTRIBUTE TUNA ATTR_STORAGE_VALUE 2250
effect_amount SET_ATTRIBUTE 458 ATTR_STORAGE_VALUE 2250

#const GOOSE 382
#const PIG 997
effect_amount SET_ATTRIBUTE DLC_LLAMA ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE GOOSE ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE SHEEP ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE DLC_COW ATTR_STORAGE_VALUE 1500
effect_amount SET_ATTRIBUTE TURKEY ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE PIG ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE DLC_GOAT ATTR_STORAGE_VALUE 1000
effect_amount SET_ATTRIBUTE DLC_WATERBUFFALO ATTR_STORAGE_VALUE 1500

#const IBEX 1472
effect_amount SET_ATTRIBUTE DEER ATTR_STORAGE_VALUE 1400
effect_amount SET_ATTRIBUTE DLC_ZEBRA ATTR_STORAGE_VALUE 1400
effect_amount SET_ATTRIBUTE DLC_OSTRICH ATTR_STORAGE_VALUE 1400
effect_amount SET_ATTRIBUTE IBEX ATTR_STORAGE_VALUE 1400

effect_amount SET_ATTRIBUTE WILD_BOAR ATTR_STORAGE_VALUE 3400
effect_amount SET_ATTRIBUTE JAVELINA ATTR_STORAGE_VALUE 3400
effect_amount SET_ATTRIBUTE ELEPHANT ATTR_STORAGE_VALUE 4000
effect_amount SET_ATTRIBUTE DLC_RHINO ATTR_STORAGE_VALUE 4000

You can change the resource numbers to whatever you want. In this example, it’s just the normal value multiplied by 10.

Triple tech mode​

The triple technology mode is a game mode where most of the technologies (excluding upgrades and ages, for example) can be researched three times. It has existed for years as a separated data mod but there is a way to implemented in combination with the normal data mod.

First, we need to program the extra technologies, effects, queuable versions and extra resources to prevent them from researching more than once, all that we saw about queuable technologies. Additionally, we program the new technologies to appear with the original one. For example, technologies 1480 and 1482 are researched once technology 816 is researched. These three are the ''make available'' technologies for Bloodlines. This way, if a civilization has no access to a technology, the duplicates are also disabled.

With this implementation, a normal game should have the triplicated technologies. To avoid this, we program a disabler in technology 1240, ''Triple Tech Off''. This technology is researched when the Town Center is built, the reason for it we'll see it in a moment, and disables all the duplicates of technologies.

To summarize, we have the triplicated technologies programmed to appear in every game and a disabling technology that is researched at the beginning of every game that prevents the duplicates from appearing. This rather convoluted implementation is done so that the map script can control whether triple tech mode is enabled or not but the mode is disabled unless stated otherwise.

By default, every map doesn't have the triple tech mode but, if we disable the ''Triple Tech Off'', technology, the duplicated technologies appear. For this reason, ''Triple Tech Off'' is connected to the Town Center; we need it to be researched a bit after the map is generated to give time to an eventual disabling.

Therefore, every map that has triple tech mode enabled, has these lines in the PLAYER SETUP section:
#const TRIPLE_TECH_OFF 1240
effect_amount ENABLE_TECH TRIPLE_TECH_OFF ATTR_DISABLE 1240

Empire wars​

The empire wars in the Community Patch differs from the Definitive Edition one in the fact that, although the Barracks, Blacksmith and houses appear at the start of the game, the economic buildings such as mill and lumber camps have to be built. However, the first buildings of this type are free and instantaneous and, once they are placed, buildings return to normal.

Enabling the mode​

The empire wars mode work in a similar way to the triple tech mode. We have technology 2008, ''Empire Wars'', that makes economic buildings free and instantaneous. We also have technology 2007, ''Disable Empire Wars'' that disables the ''Empire Wars'' technology. Both of these technologies are researched when the Town Center is built but the order of them is important; ''Disable Empire Wars'' has to be researched first so as to disable ''Empire Wars'' if needed.

In the map script, we add in the PLAYER SETUP section:
#const DISABLE_EW 2007
effect_amount ENABLE_TECH DISABLE_EW ATTR_DISABLE 2007

Adding initial units and buildings

The PLAYER SETUP section is not the only thing we need to do in order to have the mode functional. We also have to add the barracks, blacksmith, houses, farms, and all the additional villagers. Also, we need to make more of the map visible. This last part is done with a copy of the Outpost that has negative health, so that it discovers map and dies instantly.

The code for adding these outposts is the following:
#const EW_OUTPOST 2801
create_object EW_OUTPOST
{
number_of_objects 1
number_of_groups 8
temp_min_distance_group_placement 6
set_place_for_every_player
group_placement_radius 1
min_distance_to_players 13
max_distance_to_players 15
}


The full list of objects to add to the map, save for the distance which may vary, is the following. Also, map scripts should not have lurable animals or predators nearby.

Code:
create_object FARM
{
number_of_objects 2
set_place_for_every_player
min_distance_to_players 4
max_distance_to_players 4
}

create_object VILLAGER
{
number_of_objects 6
set_place_for_every_player
min_distance_to_players 2
max_distance_to_players 2
}

create_object VILLAGER
{
number_of_objects 2
group_placement_radius  1
set_place_for_every_player
min_distance_to_players 4
max_distance_to_players 4
}

create_object VILLAGER
{
number_of_objects 4
number_of_groups  5
temp_min_distance_group_placement 6
set_place_for_every_player
group_placement_radius  1
min_distance_to_players 10
max_distance_to_players 12
}
#const EW_OUTPOST 2801
create_object EW_OUTPOST
{
number_of_objects 1
number_of_groups  8
temp_min_distance_group_placement 6
set_place_for_every_player
group_placement_radius  1
min_distance_to_players 13
max_distance_to_players 15
}

create_object HERDABLE_A
{
  set_place_for_every_player
  min_distance_to_players 1
  max_distance_to_players 1
  }

create_object HOUSE
{
number_of_objects 6
group_placement_radius  5
set_place_for_every_player
min_distance_to_players 7
max_distance_to_players 7
min_distance_group_placement  1
}

create_object BARRACKS
{
set_place_for_every_player
min_distance_to_players 8
max_distance_to_players 9
min_distance_group_placement  1
}

create_object BLACKSMITH
{
set_place_for_every_player
min_distance_to_players 8
max_distance_to_players 9
min_distance_group_placement  1
}

Re-setting building cost​

Once you have built instantaneously and for free the initial buildings, that is, three lumber camps, one mill and one mining camp, prices should return to normal. Armenians and Georgians have four mule carts and a mill available.

In order to achieve this, economic buildings have annex units that trigger technologies to record that a building is done. Let's look at the case of the lumber camp, as it is more complex:
  1. \item Lumber camps have an annex unit, 2793, called ''EW lumber camp annex 1a''.
  2. ''EW lumber camp annex 1a'' dies instantly and turns into unit 2794, ''EW lumber camp annex 1b''.
  3. ''EW lumber camp annex 1b'' triggers technology 2009, ''EW lumber camp 1''.
  4. The effect of ''EW lumber camp 1'' is to upgrade ''EW lumber camp annex 1a'' to ''EW lumber camp annex 2a'' and ''EW lumber camp annex 1b'' to ''EW lumber camp annex 2b''.
With the different versions of the annex units we can keep track of how many lumber camps have been built. The third annex unit to the lumber camp triggers technology 2011 that resets the cost of the lumber camp.

All these technologies are also disabled with the ''Disable Empire Wars'' technology, so as to not produce any unwanted behavior when not playing empire wars.

Apart from these technologies to reset costs, we have to program additional technologies for the civilizations that have a bonus related to the cost of buildings, like Japanese or Malians. These technologies are researched after the reset of costs.

Circle and fixed placement​

These two features are based on using the “direct_placement” option, that puts objects in speciffic coordinates, rather than the “random_placement” that is usually used in random maps.

Circle placement​

The command "circle-radius" is used to set the bases of the players at the same distance to the center, along a circle of a given radius. This helps avoiding edges of the map.

The idea of placing players along a circle was around before this command was implemented, I’ve seen old scripts by Chrazini that do that. However, I’m not aware of a tool that generates that code automatically, as it can easily be 10,000 extra lines, which is impossible to copy from an existing script in order to adapt it.

The script I’m sharing here creates the necessary code to copy directly into the random map script and handle the random placement of players. It uses the command “assign_to AT_TEAM” that gives the position to a member of the team without considering order. Note the following:
  • You have to set the placement to “direct_placement” in the section. Normal random maps have “random_placement” instead.
  • This code is meant to be placed in the section, where the “create_land” of the players should be.
  • When using it, you need to modify the variable constants with the lines of code that should go in all “create_land” entries, such as terrain_type, land_percent, base size, etc.
  • You can set the radius of the circle for each number of players.
  • This code will add a bit of deviation in the circle when having 4 or less players and put players equidistantly when having 5 or more, so as not to have bases intersecting.
Python:
import math
'''
function to generate all the team distributions of a given number of players
taking care that teams have at least 2 players and only the first teams are filled
n: number of players to assign
distrib: list with the number of players in each team. Initially all zeros
    indexes: 0: unassigned players, 1,2,3,4: teams
t: team to asign, initially 1
'''
def team_variations(n,distrib,t):
    #list with all the variations to be retrieved after all team_variations executions finish
    global variations
 
    #case of unassigned players, team 5
    if t == 5:
        distrib[0]=n #add players to the unasigned players team
        variations.append(distrib)#add distribution to the list of variations
        return
 
    #don't assign less than 2 players to a team
    elif n < 2: #if you have less than two players to assign
        team_variations(n,distrib,t+1) #step team counter until reaching 5, unassigned case
        return
 
    #don't leave teams empty
    elif t >= 2 and distrib[t-1] == 0: #if the team to assign is 2 or more but the previous is empty
        team_variations(n,distrib,t+1) #step team counter until reaching 5, unassigned case
        return
 
    #fill the team with every possible variation of number of players
    #for number of players between 2 and n
    for i in range(2,n+1):
        #create a copy of the current distribution and set the number of players
        #on the current team to assign to i
        distrib_aux = distrib[:]
        distrib_aux[t] = i
        #recursive call with less available players and for the next team
        team_variations(n-i,distrib_aux,t+1)

    #recursive call with all the players in the next team, used to get to the unassigned case
    team_variations(n,distrib,t+1)

'''
function that computes the number of teams with positive number of players
variation: list with the number of players in each team.
    indexes: 0: unassigned players, 1,2,3,4: teams
'''
def number_of_teams(variation):
    k = 0
    for i in range(1,5):
        if variation[i] > 0:
            k += 1
    return k

'''
function that returns a string with the team and the number of players in it
variation: list with the number of players in each team.
    indexes: 0: unassigned players, 1,2,3,4: teams
i: team to display
'''
def team_size(variations,i):
    return 'TEAM'+str(i)+'_SIZE'+str(variations[i])

'''
Function that computes the coordinates of a player base along a circle
radius: of the circle from the center of the map, measured in percent of total length
players: number of  players to fit in the circle
per_player: number of positions available to every player.
    this controls that, when computing for 2 players, one can create more than 2 positions
    but still have the players opposed.
'''
def circle(radius, players, per_player=1, add_deviations=True):
    '''
    rotations and events handle the probability distribution.
    rotations decide the overall position of players, there are as many as the value of per-player
    events decide which of the positions belong to which player, there are as many as the value of players
    '''
    #rotations, given by per_player
    rotations = [100//per_player]*per_player #probabilities have to be an integer number
    #events, given by players
    events = [100//players]*players #probabilities have to be an integer number

    #distribute the remining probability up to 100
    #per_player
    rem = 100 - rotations[0]*per_player
    while rem > 0:
        for i in range(per_player):
            rotations[i] += 1
            rem -= 1
            if rem == 0:
                break
    #players
    rem = 100 - events[0]*players
    while rem > 0:
        for p in range(players):
            events[p] += 1
            rem -= 1
            if rem == 0:
                break

    #angle to generate as many rotations as given in per_player
    pp_angle = 2*math.pi/(players*per_player)
    #angle between players
    angle = 2*math.pi/(players)

    '''
    output string will hold all the text that nedds to be added to the rms file
    '''
    output = ''
    #write the random sample that generates the cases:
    #rotations
    if per_player > 1:
        output+='  start_random\n'
        for i in range(per_player):
            output+='    percent_chance '+str(rotations[i])
            output+=' #define ROTATION_'+str(i+1)+'\n'
        output+='  end_random\n\n'

    #events
    output+='  start_random\n'
    for p in range(players):
        output+='    percent_chance '+str(events[p])
        output+=' #define PLACE_'+str(p+1)+'\n'
    output+='  end_random\n\n\n'


    #write the coordinates of the positions
    global variations, constants
    '''
    variations will hold all the valid combinations of players and teams
    constants holds the text that has to go in all the create_land entries
    '''
    variations = []
    team_variations(players,[0]*5,1)
    #now variations holds all the possible variations of players per team

    #Create as many lands as players, adding the random cases given by rotation
    for p in range(players):
        '''
        create the player land
        '''
        output += '  create_land {\n'
        output += constants #text that has to be written always
 
        if per_player > 1: #if there is more than one rotation
            first_rotation = True #flag to write "if" or "elseif"
            for i in range(per_player):
                if first_rotation:
                    output += '    if '
                    first_rotation = False
                else:
                    output += '    elseif '
                output += 'ROTATION_'+str(i+1)+'\n'
                #include a random deviation in the angle
                if add_deviations:
                    output += '      start_random\n'
                    for j in range(-1,2):
                        output+='        percent_chance '+str(40-10*abs(j))
                        coord_x = round(50 + radius*math.cos(angle*p+pp_angle*i+angle/4*j))
                        coord_y = round(50 + radius*math.sin(angle*p+pp_angle*i+angle/4*j))
                        output+=' land_position '+str(coord_x)+' '+str(coord_y)+'\n'
                    output += '      end_random\n'
                else:
                    coord_x = round(50 + radius*math.cos(angle*p+pp_angle*i))
                    coord_y = round(50 + radius*math.sin(angle*p+pp_angle*i))
                    output+='      land_position '+str(coord_x)+' '+str(coord_y)+'\n'
            output += '    endif\n\n'
        else: #per_player == 1
            #include a random deviation in the angle
            if add_deviations:
                output += '    start_random\n'
                for j in range(-1,2):
                    output+='      percent_chance '+str(40-10*abs(j))
                    coord_x = round(50 + radius*math.cos(angle*p+angle/4*j))
                    coord_y = round(50 + radius*math.sin(angle*p+angle/4*j))
                    output+=' land_position '+str(coord_x)+' '+str(coord_y)+'\n'
                output += '    end_random\n'
            else:
                coord_x = round(50 + radius*math.cos(angle*p))
                coord_y = round(50 + radius*math.sin(angle*p))
                output+='    land_position '+str(coord_x)+' '+str(coord_y)+'\n\n'

        '''
        assign the player land
        '''
        #for each variation of teams
        for v in variations:
            if v[0] == 0 and v[1] == players:#ignore the case where all players are in team 1
                continue
            output += '    if '
            output += str(number_of_teams(v))+'_TEAM_GAME\n'
   
            #write all the sizes of each team in the variation (with actual players)
            #this creates several nested "if" clauses to act as "and"
            for t in range(1,5): #skip team 0, unassigned
                if v[t] == 0: #if the team is empty, the others will be too
                    break
                output += '      if '+team_size(v,t)+'\n'

            #Distribute land for teams
            #if there are no teams
            if number_of_teams(v) == 0:
                output += '      assign_to AT_TEAM 0 0 0\n'
                output += '    endif\n\n' #this closes the "if" of variation v
                continue #the rest of the loop is needed in case of teams
   
            #if there are teams
            #list with as many elements as the number of players
            #with as many 0s as unassigned players, as many 1s as players in team 1, etc
            teams = [0]*v[0]+[1]*v[1]+[2]*v[2]+[3]*v[3]+[4]*v[4]
            first_players = True #flag to write "if" or "elseif"
            #for each player
            for l in range(players):
                string = 'PLACE_'+str(l+1)#random sample given by the events list, one per player
                if first_players:
                    output+='        if '
                    first_players = False
                else:
                    output+='        elseif '
                output += string+'\n'
                #in each iteration of the l loop, the index (p+l)%players will increase by one
                #the value p is placed so that each land is assigned to consecutive teams
                output += '          assign_to AT_TEAM '+str(teams[(p+l)%players])+' 0 0\n'
            output += '        endif\n'

            #endif for team sizes, this closes the nested "if" from above
            for t in range(1,5): #skip team 0, unassigned
                if v[t] == 0: #if the team is empty, the others will be too
                    break
                output += '      endif\n'
            #endif of variation v
            output += '    endif\n\n'

        output += '  }\n\n' #end of the create_land
    return output


global constants #text that has to be written in every create_land
'''
EDIT THIS with the constants of the particular map
'''
constants='    terrain_type LAYER_A\n    number_of_tiles 300\n    base_size 12\n    clumping_factor 15\n    other_zone_avoidance_distance 8\n'

file=open('circles.txt','w')
per_players = [4,2,2,1,1,1,1] #number of rotations for each number of players
radius = [34,34,35,36,37,38,38] #radius of the circles for each number of players
for p in range(2,9):
    if p == 2:
        file.write('if ')
    else:
        file.write('elseif ')
    file.write(str(p)+'_PLAYER_GAME\n')
    #generate the code for the circle of the given number of players and write it in the file
    if p <=4:
        file.write(circle(radius[p-2],p,per_players[p-2],True))
    else:
        file.write(circle(radius[p-2],p,per_players[p-2],False))
file.write('endif')
file.close()

See the map “DE_Big_Freeze” for an example of where to put the code.

Fixed Positions​

Definitive Edition introduced the option Team Positions that places players of the same team in order, so that middle numbers are always pockets. For Wololo Kingdoms, this was adapted in some maps of the ECL. The script I did is very similar to the one that creates circles except that it only works for 3v3 and 4v4 games and that it replaces the “assign_to AT_TEAM” command with “assign_to AT_COLOR”, that gives the land to the speciffic color. For this reason, players can only use speciffic colors, as explained in Features.

Python:
import math
'''
function to generate all the team distributions of a given number of players
taking care that teams have at least 2 players and only the first teams are filled
n: number of players to assign
distrib: list with the number of players in each team. Initially all zeros
    indexes: 0: unassigned players, 1,2,3,4: teams
t: team to asign, initially 1
'''
def team_variations(n,distrib,t):
    #list with all the variations to be retrieved after all team_variations executions finish
    global variations
 
    #case of unassigned players, team 5
    if t == 5:
        distrib[0]=n #add players to the unasigned players team
        variations.append(distrib)#add distribution to the list of variations
        return
 
    #don't assign less than 2 players to a team
    elif n < 2: #if you have less than two players to assign
        team_variations(n,distrib,t+1) #step team counter until reaching 5, unassigned case
        return
 
    #don't leave teams empty
    elif t >= 2 and distrib[t-1] == 0: #if the team to assign is 2 or more but the previous is empty
        team_variations(n,distrib,t+1) #step team counter until reaching 5, unassigned case
        return
 
    #fill the team with every possible variation of number of players
    #for number of players between 2 and n
    for i in range(2,n+1):
        #create a copy of the current distribution and set the number of players
        #on the current team to assign to i
        distrib_aux = distrib[:]
        distrib_aux[t] = i
        #recursive call with less available players and for the next team
        team_variations(n-i,distrib_aux,t+1)

    #recursive call with all the players in the next team, used to get to the unassigned case
    team_variations(n,distrib,t+1)

'''
function that computes the number of teams with positive number of players
variation: list with the number of players in each team.
    indexes: 0: unassigned players, 1,2,3,4: teams
'''
def number_of_teams(variation):
    k = 0
    for i in range(1,5):
        if variation[i] > 0:
            k += 1
    return k

'''
function that returns a string with the team and the number of players in it
variation: list with the number of players in each team.
    indexes: 0: unassigned players, 1,2,3,4: teams
i: team to display
'''
def team_size(variations,i):
    return 'TEAM'+str(i)+'_SIZE'+str(variations[i])

'''
Function that computes the coordinates of a player base along a circle
radius: of the circle from the center of the map, measured in percent of total length
players: number of  players to fit in the circle
per_player: number of positions available to every player.
    this controls that, when computing for 2 players, one can create more than 2 positions
    but still have the players opposed.
'''
def circle(radius, players, per_player=1):
    '''
    rotations and events handle the probability distribution.
    rotations decide the overall position of players, there are as many as the value of per-player
    events decide which of the positions belong to which player, there are as many as the value of players
    '''
    #rotations, given by per_player
    rotations = [100//per_player]*per_player #probabilities have to be an integer number
    #events, given by players
    events = [100//players]*players #probabilities have to be an integer number

    #distribute the remining probability up to 100
    #per_player
    rem = 100 - rotations[0]*per_player
    while rem > 0:
        for i in range(per_player):
            rotations[i] += 1
            rem -= 1
            if rem == 0:
                break
    #players
    rem = 100 - events[0]*players
    while rem > 0:
        for p in range(players):
            events[p] += 1
            rem -= 1
            if rem == 0:
                break

    #angle to generate as many rotations as given in per_player
    pp_angle = 2*math.pi/(players*per_player)
    #angle between players
    angle = 2*math.pi/(players)

    '''
    output string will hold all the text that nedds to be added to the rms file
    '''
    output = ''
    #write the random sample that generates the cases:
    #rotations
    if per_player > 1:
        output+='  start_random\n'
        for i in range(per_player):
            output+='    percent_chance '+str(rotations[i])
            output+=' #define ROTATION_'+str(i+1)+'\n'
        output+='  end_random\n\n'

    #events
    output+='  start_random\n'
    for p in range(players):
        output+='    percent_chance '+str(events[p])
        output+=' #define PLACE_'+str(p+1)+'\n'
    output+='  end_random\n\n\n'


    #write the coordinates of the positions
    global variations, constants
    '''
    variations will hold all the valid combinations of players and teams
    constants holds the text that has to go in all the create_land entries
    '''
    variations = []
    team_variations(players,[0]*5,1)
    #now variations holds all the possible variations of players per team

    #Create as many lands as players, adding the random cases given by rotation
    for p in range(players):
        '''
        create the player land
        '''
        output += '  create_land {\n'
        output += constants #text that has to be written always
 
        if per_player > 1: #if there is more than one rotation
            first_rotation = True #flag to write "if" or "elseif"
            for i in range(per_player):
                if first_rotation:
                    output += '    if '
                    first_rotation = False
                else:
                    output += '    elseif '
                output += 'ROTATION_'+str(i+1)+'\n'
                coord_x = round(50 + radius*math.cos(angle*p+pp_angle*i))
                coord_y = round(50 + radius*math.sin(angle*p+pp_angle*i))
                output+='      land_position '+str(coord_x)+' '+str(coord_y)+'\n'
            output += '    endif\n\n'
        else: #per_player == 1
            coord_x = round(50 + radius*math.cos(angle*p))
            coord_y = round(50 + radius*math.sin(angle*p))
            output+='    land_position '+str(coord_x)+' '+str(coord_y)+'\n\n'

        '''
        assign the player land
        '''
        #for each variation of teams
        for v in variations:
            if v[1]==v[2] and v[1]+v[2]==players and v[1]>=3: #if there are two even teams
                output += '    if '
                output += str(number_of_teams(v))+'_TEAM_GAME\n'
    
                #write all the sizes of each team in the variation (with actual players)
                #this creates several nested "if" clauses to act as "and"
                for t in range(1,5): #skip team 0, unassigned
                    if v[t] == 0: #if the team is empty, the others will be too
                        break
                    output += '      if '+team_size(v,t)+'\n'

                #Distribute land for teams
                #list with as many elements as the number of players, sorted by team (odds, evens)
                colors =list(range(1,players+1,2))+list(range(2,players+1,2))
                first_players = True #flag to write "if" or "elseif"
                #for each player
                for l in range(players):
                    string = 'PLACE_'+str(l+1)#random sample given by the events list, one per player
                    if first_players:
                        output+='        if '
                        first_players = False
                    else:
                        output+='        elseif '
                    output += string+'\n'
                    #in each iteration of the l loop, the index (p+l)%players will increase by one
                    #the value p is placed so that each land is assigned to consecutive players
                    output += '          assign_to AT_COLOR '+str(colors[(p+l)%players])+' 0 0\n'
                output += '        endif\n'

                #endif for team sizes, this closes the nested "if" from above
                for t in range(1,5): #skip team 0, unassigned
                    if v[t] == 0: #if the team is empty, the others will be too
                        break
                    output += '      endif\n'
                #endif of variation v
                output += '    endif\n\n'

        output += '  }\n\n' #end of the create_land
    return output


global constants #text that has to be written in every create_land
'''
EDIT THIS with the constants of the particular map
'''
constants = '    terrain_type LAYER_A\n    land_percent 4\n    base_size 9\n'

file=open('fixed_positions.txt','w')

file.write('if ')
file.write('6'+'_PLAYER_GAME\n')
#generate the code for the circle of the given number of players and write it in the file
file.write(circle(37,6,1))

file.write('elseif ')
file.write('8'+'_PLAYER_GAME\n')
#generate the code for the circle of the given number of players and write it in the file
file.write(circle(38,8,1))

file.write('endif')
file.close()

Handicap mode​

The Handicap mode is a new feature introduced in Definitive Edition designed to balance teams where players have very different levels. It boosts some players in several ways:
  • Faster gather rate for villagers.
  • Higher carry capacity.
  • More starting resources.
  • Higher Villager HP.
  • Faster build speed.
  • More HP on all buildings.
  • More bonus damage for counter units.
  • Faster work rate for military buildings.
The handicaps levels are set via a percentage, 100% being no boost at all and 200% the maximum value.

Basic implementation of handicap​

An implementation of the handicap mode is very straightforward to come up with. We just need several technologies, each with an effect that boosts the aforementioned stats by the desired percentage. This technologies have positive research time so that they don’t activate on their own and no button to research it with, so that they are hidden from players.

Now, how can we have those technologies affect only specific players? If we were to program them in an scenario, that’s easy; we just need some triggers at the beginning of the game that research the handicap technologies for each player. With that in mind, I made sure that the handicap technologies are visible in the scenario editor, for people to access them easily.

Handicap mode in a random map​

Unfortunately, this idea of the technologies can not be ported to random maps. Random map scripts are very versatile in what you can modify from the game (names, stats, resources…) but all the changes affect all players, there is no way to control that effects only affect some of the players.

However, there is something that we can control for individual players: the units they receive. This neither is a very simple concept, it uses several concepts of random map scripting:
  • Players have to be created with the “direct_placement” command.
  • We create lands and assign them for specific player numbers with the “ASSING_TO_AT COLOR” command.
  • Additionally, we need to identify those lands with the command “land_id”.
  • When creating objects, we can control which players receive them by using the command “place_on_specific_land_id”.
This method gives us a land for each player and the possibility to place individual units in that land that will appear only for the players owning them. These lands with id will be different from the actual player lands where the Town Center and villagers are placed.

Since the only thing we can link to these lands are units, we need units that trigger the handicap technologies. This is easy to do, as buildings have an “Initiates Technology” field. I have created several buildings with no volume, no graphics, that die instantly and that trigger the desired handicap technology.

Let’s see an example. Say you want the player using blue to receive a 120% handicap. In the map script we need to create a land, assign it to color 1 and give it an id. Then we create an object HANDICAP_120 and place it on that land id. Since the land belongs to color 1, it will have that color. When the game begins, the handicap unit will trigger its technology and die instantly, giving the handicap effect.

Creating maps with specific handicap​

The final problem we need to solve is the huge casuistic that comes with colors, teams and handicap levels. Since creating every combination on a map would result on a huge mod with too many files to be possible to find the correct one, I created a program that creates the specific combination the players need. You can see the source code by downloading the Custom map creator mod.

4.6 Gold generation bonuses

Nowadays there are several bonuses that give a certain resource passively, mostly gold. To cite a few we have Poles stone miners, Portuguese foragers or Vietnamese lumberjacks. All these bonuses are implemented with Feitoria units, units that have the ability to generate a certain resource. To illustrate all the details of the implementation, let's look at the burgundian team bonus, that makes relics generate food.

We need to program the creation of a Feitoria unit only for burgundian allies. This unit will appear when a Monastery is built. If we look at the Monastery, unit 104, we can see that it has an annex unit, 903, called ``Burgundian relic annex (dummy)''. This unit does nothing and dies immediately, as most players should not get the bonus.

Whenever a player is allied to a burgundian, effect 738 upgrades the dummy annex to unit 1387, ``relic annex''. This unit dies immediately but turns into unit 1388, ``relic annex food''. With this, it separates from the monastery and won't die if the monastery is destroyed. Also, it triggers technology 805 to disable future monasteries to produce additional annex units.

This new unit has task ``Generate resources''. The fields that interest us are ``Productivity resource'', set to ``Relics captured'', and ``Work value 1'', set to 0.5. Also, the corresponding entry in the ``Looting Table'' must be set to 1. This means that, every second, the unit produces the amount of food equal to the work value multiplied by the productivity resource. Other bonuses like the vietnamese one have as productivity resource a resource that tracks the number of working lumberjacks.

Technically we are done as with this implementation, we obtain the generation of resources. Unfortunately, we still have three problems:
  1. The unit may die from splash damage if not provided with enough health.
  2. Although the unit is invisible, it can be detected by enemy units, thus distracting them.
  3. The unit belongs to the player and therefore has to die in order to eliminate a player. Finding and killing an invisible unit should not be a requirement.
Problem 1 is solved by giving the unit a lot of health and removing any armor classes, this way every attack deals only 1 damage. We could even provide the unit with regeneration.

Problem 2 is solved by giving these units class 9, which corresponds to Prey animals such as deers. This makes enemies ignore it.

Problem 3 is solved via the patch, by instructing the game to kill the unit when all other units are dead.

5. Armenians

The free relic bonus on the first fortified church is implemented in a similar way to the additional villagers seen before. The interesting aspect here is that relics can not be created already belonging to a player, they must always be Gaia units.

To solve this, the unit that is created is actually a copy of the unit ``Monk with relic'', that doesn't count as a unit, dies instantly and without animation. When it dies, the monk drops the relic it was carrying, effectively creating a relic next to the fortified church.

5. Bengalis

Extra villagers per age​

This is implemented with three annex units connected to the town center. However, these units have positive health and stay dormant until the corresponding age is reached, when they are upgraded to villagers.

Elephant units bonus resistance​

The civilization bonus of bengalis where elephant units absorb 25% of the bonus damage is implemented in the Community Patch by increasing the armor of elephants in the special classes, such as elephant, cavalry or archers. The armor increases happen when reaching feudal or when researching the corresponding armor technology. This way, we give the opponent time to research the corresponding counter unit upgrade. The following is a comprehensive list of all the changes.

Elephant archers​

Elephant archers have -4 cavalry archer armor, so keep that in mind when looking at the numbers.
  • Feudal age: elephant archers gain +1 cavalry archer armor for a total of -3.
  • Feudal age: elephant archers gain +4 elephant armor for a total of 4.
  • Feudal age: elephant archers gain +4 cavalry armor for a total of 4.
  • Leather archer armor (castle age): elephant archers gain +1 archer armor, for a total of 1.
  • Leather archer armor (castle age): elephant archers gain +2 elephant armor, for a total of 6.
  • Leather archer armor (castle age): elephant archers gain +1 cavalry armor, for a total of 5.
  • Ring archer armor (imperial age): elephant archers gain +1 cavalry archer armor, for a total of -2.
  • Ring archer armor (imperial age): elephant archers gain +1 archer armor, for a total of 2.
  • Ring archer armor (imperial age): elephant archers gain +1 elephant armor, for a total of 7.
  • Ring archer Armor (imperial age): elephant archers gain +3 cavalry armor, for a total of 8.

Battle Elephants​

  • Feudal age: elephants gain +4 elephant armor for a total of 4.
  • Feudal age: elephants gain +4 cavalry armor for a total of 4.
  • Chain barding armor (castle age): elephants gain +2 elephant armor, for a total of 6.
  • Chain barding armor (castle age): elephants gain +1 cavalry armor, for a total of 5.
  • Plate barding armor (imperial age): elephants gain +1 elephant armor, for a total of 7.
  • Plate barding armor (imperial age): elephants gain +3 cavalry armor, for a total of 8.
The values on the elephant and cavalry armor are based on the bonus damage dealt by spearmen. Since other units, like the camel, deal less bonus damage that may be negated by the increased cavalry armor, I have programmed an extra armor class on Bengali elephants, class 7. This way, other anti-cavalry units deal their remaining bonus damage through that class. If the unit also has bonus against elephants, both classes are combined to get the value. The units affected are:
  • Camel scout (3), camel rider (3), heavy camel rider (4) and imperial camel rider (4).
  • Eagle scout (2), eagle warrior (3) and elite eagle warrior (3).
  • Genoese crossbow (2) and elite genoese crossbow (3).
  • Kamayuk (4) and elite kamayuk (7).
  • Mameluke (3) and elite mameluke (5).
  • Flemish militia (4).
  • Infantry (1) when researching viking’s chieftains.

Armored Elephant​

Since armored elephants have a high cavalry armor that almost negates any bonus except for the spearmen line, they only receive armor in the elephant class, combining the extra armor of the cavalry and elephant class into only one.
  • Chain barding armor (castle age): armored elephants gain +6 elephant armor, for a total of 23.
  • Plate barding armor (imperial age): siege elephants gain +2 elephant armor, for a total of 28.

Bohemian and gurjara bonus damage​

The additional damage dealt by bohemian spearmen and gurjara camels to cavalry is handled through additional cavalry armor classes, 6 and 9 respectively. Bengali elephants also gain armor in those classes whenever they gain cavalry armor.

Mahayana​

This technology is implemented by upgrading the affected units into copies of them where the population resources are 0.9 instead of 1.

This is not the end of the implementation as we need to modify the values of these resources accordingly. This is done via the patch that counts the number of villagers and monks.

5. Bulgarians

The only relevant aspect of the civilization is the konnik and its ability to stand up. Indeed it's a very simple implementation that places the dismounted konnik as the death unit of the konnik with horse, instead of the usual corpse. The death animation shows the horse falling down and the konnik standing up.

The only issue is that, once the death animation finishes and the dismounted konnik appears, the horse vanishes. Definitive Edition solved this issue by introducing an additional graphic to show the horse.

5. Burgundians

The main point for this civilization is the implementation of Flemish Revolution.

At first glance, the implementation seems straightforward: use the upgrade effect to turn villagers into flemish militia. However, this also affects future villagers, rendering the civilization unable to create villagers after the technology is researched. We can either upgrade the villagers again to another villager without converting flemish militia into villagers back. Definitive Edition solved this issue by introducing a flag to upgrade current existing units or all present and future ones.

In order to separate present villagers from future ones, we use the death unit. When flemish revolution is researched, it upgrades villagers into a dummy unit that dies instantly and turns into the actual flemish militia. This way, we can further upgrade villagers into a new villager unit without affecting the ones that turned into flemish militia.

The last issue is how to trigger a technology that upgrades villagers into new villagers, disabling the effect of flemish revolution. This is done in a very clever way by tricking the player to do it.

When flemish revolution is researched, the villager icon is covered with a new technology that has the villager's icon, description and hotkey but no cost or research time. This technology upgrades villagers again to a new villager unit but does not affect flemish militia, that are the result of dead units. When players want to rebuild the economy, they queue a bunch of villagers and unknowingly trigger the technology with the first click.

5. Burmese

The only relevant aspect of this civilization is the way the Arambai's damage is dealt to replicate the way Definitive Edition computes the damage. A full article explains the whole implementation, which can be found here.

5. Cumans

Feudal Town Center​

The implementation of this bonus is handled with extra resources to control the amount of town center that can be in game.

First of all, note that the town center you build and the one standing are different, you build one and the ``Stack unit'' mechanic changes it. This is in order to have part of the building passable. What interest us is the standing building, id 109, and the ones you actually build and then disappear, ids 621, 617, 484 and 597 for the four ages respectively.

Of these last four buildings, note that the ones corresponding to dark and feudal have three resource costs: the usual wood and stone and an extra one, resource 218, of which each town center requires one unit although it's not paid for. The castle and imperial versions of the town center don't require this resource. On the other hand, the standing town center has resource 218 in the ``resource storages'' section, with the instruction to reduce the resource by one unit but return it upon death.

If we now go to the civilizations tab and look for this resource, we see that each civilization has 10002.1 units of it, including Cumans. This would allow to build more than ten thousand town centers per game.

Let's look now at the technology that allows Cumans to build town centers in feudal age, id 709, triggered in feudal age. The effect of this technology reduces resource 218 by ten thousand, leaving it at 2.1. Technology 709 also triggers the one that makes town centers available for builders without having to wait for the castle age technology to do so.

In a normal game, with a starting town center, upon reaching the feudal age and gaining access to extra town centers, a cuman player has exactly 1.1 units of resource 218, which allows to build one extra town center. When they reach castle age, the town center stops requiring resource 218 and they can build as many as they want.

Cuman mercenaries​

This technology allows allies to train five elite kipchaks per castle, present and future. This is achieved via extra resources.

Every castle, apart from the 20 population space, also gives 5 units of resource 214. This resource is programmed to be given once the castle is complete and remain in the bank if the castle is destroyed. This is regardless of the player being allied to a cuman.

On the other hand, there is a second elite kipchak unit apart from the cuman elite unit. Unit 1260 costs only one unit of resource 214.

The final piece is the technology itself, that enables the special elite kipchak for the allies.

5. Ethiopians

Here it is worth talking about Royal heirs, the technology that reduces the damage taken by camels and shotels from mounted units. Definitive Edition implemented this by modifying the damage formula, to allow for negative values. In the Community Patch, we had to be more creative.

Because of this technology, the melee and piercer armor classes are split depending on whether the unit is mounted or not. Mounted units use class 40 for melee and 39 for pierce, the rest of the units use class 4 and 3 respectively. All units have the four classes in their armors so that they can take damage from everyone.

With this, the Royal heirs technology simply increases the armor against mounted units for the affected units.

5. Goths

Nothing too relevant for this civilization except for the opportunity to brag about something that the Community Patch does better than Definitive Edition.

Since technologies with zero research time are researched instantly when their required technologies are satisfied, there is no way to make loom actually research instantly and still be needed to pay the cost and press the button. Definitive Edition overcomes this by setting the research time to the minimum value, one, for goths.

Since, in the Community Patch, technologies are units in order to be queuable, this actually allows to set the research time to zero, closer to the intent of the civilization bonus.

6. Age of Empires 2 Millenium Edition

According to well-versed people in the way Microsoft handles it's games, Age of Empires 2 Definitive Edition should go end of life by the end of 2026, seven years after its release. On the other hand, it is unlikely that this would be the end for the game, as it is by far the most popular game in the franchise. What I predict here, in April of 2025, is the new version of the game they may announce alongside with the end of life of the previous. I'm calling it the Millenium Edition for no specific reason.

The core mechanics should remain intact. That is, the four resources and their role in the game. Similarly, the start of the game with the town center, villagers, boars and the dark age build orders should change very little, so that old players can easily pick up the game.

What should change is the unit interactions, the building requirements, the technologies and, obviously the civilizations. This would be an opportunity to rebuild types of units from the beginning, specially the most discussed water balance. Also, developers could more heavily lean towards regional units with, for example, variations of the spearman with subtle differences depending on the region, something that can be easily ignored by most players but where hard-core ones could look for optimizations or good synergies.

The Chronicles DLC also has a lot of ideas that could be exported to new civilizations. I'm thinking, specifically of the mutually exclusive unique technologies which would allow to specify the civilization mid game depending on the opponent or the map.

Another mechanic that I thought of recently is units of which you can only produce a certain amount of, either throughout the game without the chance of doing more once they die or a simultaneous amount and you can build more once the existing ones die. These units could serve as very powerful siege units for final pushes or sort of captains, "mini-heroes" with conversion resistance that have an aura effect to improve nearby units, like what the centurion does right now but with greater effect.

All the previous ideas can be implemented right away or may require some minor changes to the code. For example, the captain units right now may not cost population space in order to control the maximum number of them. Regardless, it would be a minor development process to adapt the existing engine to the new features.

And right there, in the ease to add these new features to the game, lies the base for what I believe this new Age of Empires 2 Millenium Edition would be: a rework, a reimagination or reinvention of the civilizations and mechanics without actually changing the core game and the way it works. This keeps the competitive scene intact as pro players would just need to learn new unit interactions but not game play mechanics.

Then, Microsoft can release a game with a dozen of civilizations, new editions of existing ones with modified bonuses, two pairs of mutually exclusive technologies, a captain unit and some variations on the common units, not to mention reworked campaigns. From there, you can have periodic DLCs adding new civilizations and keep earning money for another seven or ten years.

If that way of re-monetizing AoE 2 is not enough, they could introduce a subscription to get a “co-pilot”, an additional program that would make sure the town center is producing villagers, they are distributed properly and would build houses when needed, maybe at the expense of slower times or extra cost so that a competent human player could easily overcome it. Also, the co-pilot could monitor the units and upgrades it sees in the game to recommend counter units or strategies. A feature like that, aimed at democratizing the game, would likely be well received, even if it comes at an extra cost.

This idea of a Millenium Edition both interests me and terrifies me. It interests me from a programming point of view, to explore how far we can push the engine of a twenty year old game and imagine things that could have been there since the beginning. On the other hand, it terrifies me because it gives Microsoft yet another way of reselling the game after the HD and DE version, with a likely chance that they would still make a lot of money. I fear that I’ll be right in at least part of this and we’ll be forced to buy a new game if we want to play multiplayer.

Keshiks generating gold

This feature from Definitive Edition was added very late because we couldn’t copy the implementation done in the original game due to limitations on the user patch. Originally it was adapted to “Keshiks return gold when they die” and this is the base for the implementation we finally got. The credit of this idea goes to GorLeon.

Madrasah​

Madrasah is the saracen unique tech that makes monks return gold when they die. Let’s see how it works. If we filter technologies through civilization 9 we find Madrasah is number 490 with effect 545. Its only relevant command is the first one, upgrade unit 134 into unit 936. These two units are monk corpses that stay in the ground and disapear after a while. Their only difference is in the resource storages. Both of them have type 12, “Corpse Decay Time”, a counter for how long the corpse stays. The one that appears with Madrasah also has 33 units of “Gold Storage” on “Store mode” 1 which, as the description says, is stored in the bank even after the unit disapears (contrary to the way houses give population space and remove it when destroyed). This means that saracen monks die into a unit that, upon apearing, generates a one-time payment to the palyer.

Adaptation to Keshiks​

The idea now is to have a way to create a unit every time the Keshik attacks, it can have -1 hit points and die instantly, that generates a small amount of gold. There is actually a way to have a unit like that: arrows. Every time an archer shoots, it creates an arrow object that has its own unit number.

If we look at the Keshik, unit 1253, we can see that it deals normal melee damage but actually shoots unit 1257 “keshik proy”. As the description on the “Secondary Proyectile Unit” hints at, the first arrow a unit fires uses the unit stats and only secondary arrows use their own stats. Therefore, we do not have to worry about the Keshik dealing anything but melee damage even if it’s shooting arrows.

Let’s look now at the arrow itself, unit 1257. There is nothing relevan to see on its stats since it is fired from zero distance so all the proyectile stats are irrelevant. The important thing is that it generates 0.7 gold when appearing. This value is derived from this page, where it is explained that Keshiks generate 0.7 gold per attack.

That’s it, every time the Keshik attacks, it shoots an arrow that, when appearing, generates a bit of gold. You may have noticed that this introduces a bug: Keshiks now generate gold also when attacking buildings, something they do not in Definitive Edition. We decided to leave it like this as the gold generation is very small to really be worth ignoring the enemy units and just attack buildings but we like to have the ability on Keshiks.

Khmer farming bonus

After seing how to have fishermen droping food at Docks, one can easily predict what we should change in order to have Khmer farmers not use drop site. Indeed, if for the farmers, units 214 and 259 we select civilization Khmer, we can see that, as dropsites they have the Town Center and themselves. Contrary to what happened for the Dock, having the Town Center doesn’t disturb the villagers from droping food on themselves. Setting the drop site requires deactivating all checkboxes in the top part of the units tab, so that the change only affects Khmer.

However, this is not the end of the story. If we want to replicate the balance of Definitive Edition as faithfully as possible, we need to check the gather rate.

To do so, I first run experiments on Definitive Edition obtaining the gather rate for various farming upgrades. With that I created several new technologies to adapt the work rate of Khmer farmers in Wololo Kingdoms DE. See the results of the experiments in this spreadsheet.

The modifications on the work rate of Khmer farmers is implemented techs 62 and 214 and through the “Khmer Tech tree” effect, number 646.

Tech tree effects are mainly used to disable technologies for the civilization and create the tech tree. Since it is executed at the start of the match, we can add some other instantaneous effects on it. Commands 49 and 50 modify the attribute 13 (work rate) for the two farmers.

The other two techs are instantaneous techs (research time zero) that are researched once other techs are researched. Specifically, one activates after heavy plow is researched and the other after both heavy plow and wheelbarrow are researched. Their effects multiply the work rate by various values.

MPHQ Website and Content Negotiation

In our Voobly community we communicate mostly in the English language. Most of our work is done in English, but we hope that all Voobly documentation, software and installation will be available in many languages one day. We are constantly working towards that goal, however, many obstacles are still ahead. Voobly consists of volunteers, and we are generally looking for new volunteers who have some technical knowledge, an interest in gaming, and some free time. You too can help Voobly; take a look at the Enrollment info page.

License and Copyright

Copyright © 2009 – 2026 Member Plus Headquarters
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled “GNU Free Documentation License“.
Copyright © 2009 - 2026 Member Plus Headquarters. All rights reserved.
This website was created by volunteers of the Member Plus Program and is not affiliated with Voobly.
Back
Top Bottom