Member Plus Headquarters: Mod Guide

A project of the former MSN Gaming Zone community.



Development Guide

This guide uses as examples the Advanced Genie Editor codes from Wololo Kingdoms DE. Most of those codes are the same for Community Patch 1.6 except for things speciffic for Definitive Edition civilizations that have been deleted for that mod.
Author: [email protected]

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 lockdown. 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. Of course I found DE Balance but that one didn’t have all the civilizations.

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 realising 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. We developed the installer that checked for legitimate copies of the original game and throughout the summer, I added the four new civilizations.

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 distributionper resource, global command queue, improvements for the display of technologies in the game, and new hotkeys.

We also have the help of GorLeon who, appart from creating several graphics mods like Age of Mandala, has a very good grasp of Advanced Genie Editor and has helped me add new bonuses to the game.

I don’t think I’m the leading expert in Advanced Genie Editor but, throughout these months and with a lot of try an error, I’ve grasped a very good understanding of how things can be implemented. 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, and several of the issues you may ran into.

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

Adaptative Age of Mandala

Wololo Kingdoms DE is the first mod to have an adaptative version of Age of Mandala. As of April 2021, Definitive Edition seems to be working on a version of it. It seems a different implementation of what I’m explaining here, judging from the screenshots I’ve seen, and it’s currently only in the beta branch.

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 Wololo Kingdoms DE 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 speciffic civilizations and therefore there is only one set of graphics we have to worry about. Castles and Towers 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 castle, unit 82, we see it has unit 1445, “Castle range 8”, annex. This unit only disapears if the castle 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 castle, you are actually seing two units: the basic castle 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 castle or 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 “Castle” units in the units tab, we can see there are actually two of them, 82 and 1460:
  • Unit 82 is where all techs and units are created but it has no Train location (which should be the villager) and has unit 1460 as Head unit.
  • Unit 1460 does have the villager as the Train location, has a different range unit from unit 82, 1416, and has unit 82 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 1460 and this is the unit villagers build. Once the building is complete, it disapears and is replaced by unit 82, the actual castle.

Let’s look finally at the other range unit, 1416, in castle 1460. This unit is identical to unit 1445 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.

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 it 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')

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 the button in the mill that changes the behaviour of fishermen between using the dock or the town center and mill.

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 Coolor 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!

Advanced Genie Editor - Basics

I reiterate again: I’m not an expert in AGE and only know about what I’ve discovered. If at some point I skip some button or field, it’s most likely because I don’t know what it does or have never needed to investigate it. You know where to contact me to add stuff.

How to open AGE​

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. WololoKingdoms DE uses The Conquerors but you may also use Age of Empires II: HD or 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 in AGE​

  • SLP menu. Only relevant for graphics and icons and only if you added graphics files when opening AGE.
  • +++. Allows to ope 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. 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. 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. 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. When you research a technollogy, it triggers an effect. This tab lists all the effects.
  • Tech tree. This creates the technology tree in the game but has no effect on the actual behavior of the game, everything is done through technologies. It can be useful to locate a unit you don’t know the name of.
  • Civilizations. 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. All the units in the game: actual soldiers, buildings, animals, trees, decorative stuff…
  • SW only. Stands for “Star Wars Only”. Only relevant in that game.
  • Graphics. Lists all the graphics in the game, with links to their corresponding slp files.
  • Terrains. Lists all the terrains the game uses.
  • Sounds 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”. Youcan change the behaviour of “|” from “or” to “and” in the checkbox next to it.
  • The second dialogue box is to write text that must not appear in the object. The symbol “|” works identically.
  • The two dropdown menus are to activate some extra text in the object description such as “Train location”, “Research time”, etc. The first one is asociated to the first dialogue box and the second one to the second dialogue box.
For example, say that you want to check the Mayan castle age unique tech 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 tech before the actual name. Now write in the dialogue box “C 16” and AGE will show the techs that only Mayans can research, making easy to locate what you are looking for.

Advanced Genie Editor - Effects Tab

This is where you edit the effects technologies produce. An effect is made of several commands that modify some aspects of the units or technologies. The most relevant field in this tab is the Command Type, where you select what command to add to the effect. Let’s go over them:
  • Atribute modifier (Set). This allows to modify atributes of individual units or clases of them, like the hit points, the speed, the cost, the training time, etc. Through this effect you set a new value for the atribute.
  • Resource modifier (Set/+/-). This allows to modify resources of the game such as wood and food or the rate at which relics genrate gold. Depending on the mode you choose, you can either set a new value or modify the existing one by adding something.
  • Enable/Disable unit. Mainly used to disable generic units for specific civilizations. Also very important for the queuing techs functionality.
  • Upgrade unit. For things like turning archers into crossbows.
  • Atribute modifier (+/-). To modify the existing value by adding something. Used for blacksmith techs, for example.
  • Atribute modifier (Multiply). To modify the existing value by multiplying by something. Used for civ bonuses mainly.
  • Resource modifier (Multiply). Similar as before but for resources.
  • AoK HD only. Versions of the previous that affect all team members.
  • Tech Cost modifier.
  • Disable Tech.
  • Tech Time modifier.
Let’s look for example at the effect of Husbandry, number 39. The first four commands multiply attribute 5 (movement speed) by 1.1 for several classes of units: scouts (light cavalry), cavalry archers, cavalry (which includes knights, camels, elephants…) and conquistadors (which includes arambais). Appart from those classes, the next commands modify the missionary and the flaming camel, that are class monk and petard respectively and therefore not affected by the previous. All these commands increase the speed of cavalry units by 10%.

Don’t worry right now about the last command in the Wololo Kingdoms DE data file. It is related to the queuing techs functionality that we’ll see later.

Advanced Genie Editor - Graphics Tab

This is where you edit the graphics, animations and assing sounds to them. As with the units tab, most of the fields have explanations on what they are for so you shouldn’t have much troubles. In case of doubt, check an already working unit.

Worth mentioning is the mirror mode field. If you check any unit graphic from Wololo Kingdoms DE with TurtlePack, you will see that they only face left. Right versions of the graphics are obtained by reflecting the ones from the left. Definitive Edition has different graphics for each angle but the original version uses mirror mode to save space.

Another detail is the two sound fields, one in the top of the tab and the other in the “Angle Sounds” sections. The first one plays the sound regardless of the angle the unit is facing, it is mainly used for the burning sound when a building is on fire. The second ones allow to assing different sounds to each angle the unit is facing. In practice, all angles have the same sound but the option is there.

Finally, the Layer field determines how the game handles that graphic. Things like level 20 or 11 are graphics you can attack and damage the unit they belong to, even if the graphic is outside the “collision box” of the unit. Also, depending on the level, the game may activate the silouete around units when the go over it to represent they are behind the object. However, level 5, corresponding to shadows and farms, does not react to interactions when selected outside the collision box. This was an issue in early implementations of the Age of Mandala as, depending on how you configured the circle, it could be interacted which meant that units could damage the unit by attacking the mandala.

Advanced Genie Editor - Techs Tab

The Techs Tab​

This is where you edit the technologies in the game. There are two types of technologies that you can create:
  • 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.

techs.png


Let’s go over some of the fields in this tab:
  • Internal name. Name of the technology in the data file, if a susbtitute is found in the language.dll files, it uses that one.
  • Language File Name. The name of the technology in the game. The number corresponds to the string in language.ini that stores it.
  • Language File Description. Description of the technoly that appears when you hover over the icon. The number corresponds to the string in language.ini that stores it.
  • Hotkey. Useless for technologies. -1 means nothing is assigned.
  • Language File Help. Name displaued in the Tech Tree. If you want the name to split over two lines in the tech tree, that’s how you do it. The number corresponds to the string in language.ini that stores it.
  • Help Converter. Detailed description for the tech tree and if you have “Extended help” activated in the game. The number corresponds to the string in language.ini that stores it.
  • All the text fields that may or not have the description of the technology are not used since all the text is handled through language.ini.
  • Required Techs. All the technologies you need to have researched before being able to research this one.
  • Min Req Techs. Number of technologies from the required ones you actually need to research this one. This allows to give several options to unlock a technology.
  • Type. Usualy 0 except for ages, for which is 2 and allows it to show in the top of the screen.
  • Research time in seconds.
  • Icon. Technologies icons are stored in “50729.slp” in either “graphics_x1_p1.drs” or in the “drs” folder. The first icon is number zero.
  • Button. Position of the tech in the building menu. Numbers 1 to 5 correspond to the first row, 6 to 10 to the second and so on. Number 0 or -1 means it doesn’t show.
  • Effect. Number of the effect that is triggered when the tech is researched.
  • Research Location. Building where the tech is researched and where the button shows. Techs that activate automatically (zero research time) usually have the building set to -1.
  • Civilization that researches the tech. Set to -1 for techs that several civilizations can research.
  • Cost. Here you set the resource Type, the Amount to pay and wether the amount is Deducted from the bank or you just need to have it but not actually pay it. You can set costs of up to 3 resources.

Advanced Genie Editor - Units Tab

This is where you edit everything related to the ingame units. By units we refer to actual soldiers, buildings, animals, proyectiles, trees, decorative elements and even invisible units that are used to trigger effects.

This tab is the more complex one but, luckily, it’s the best documented one. The fields that have an asterisk (*) sign next to them will display some information about what the field is for. This is how we discovered about the charging ability, for example.

The icons for the units are stored in “50706.slp” for buildings (type 80) and “50730.slp” for actual units (type 70). This second file also includes tech icons due to the queuing techs functionality.

One thing worth mentioning before getting into modifying stuff in this tab is the set of checkboxes in the top of the tab, one per civilization, and the dropdown menu on the left, that selects the civilization to modify.

civilizations.png


Any modification you do to a unit will affect the selected civilization and all civilizations whose checkboxes are checked. By default all checkboxes are all activated which means that any modification you do to a unit will affect all civilizations. If, for example, you want to modify the armor of the champion, having all boxes selected will affect all civilizations. On the other hand, if you want to modify a unit only for a specific civlization, like the graphics for the wonders, you should deselect all boxes so that the changes only apply to the selected civilization.

This is very important to have in mind since AGE doesn’t have an “undo” button. I’ve screwed up tons of times by forgeting to deselect the boxes when I was adding new architectures and it meant loading a backup (if I had it) or fixing the mistake by hand, civilization by civilization.

The best advice I can give for this is to study the code already written for existing units and, most of the time, copy stuff to create new units. I created units like the Leitis by copying the Knight and modifying the necessary attributes. This way, I get less compilation errors.
Later in the guide, I’ll explain in detail the implementation of some things and we will revisit this tab.

A guide worth citing here is this one on how to implement Town Centers and Gates:
http://aok.heavengames.com/university/modding/the-complete-gate-and-town-center-modding-reference/

Town Centers and Gates are very complex objects since the unit you tell villagers to build disapears after completition and is replaced by a different one. Appart from that, the buildings are not a single object but a combination of annex units. A gate is comprised of the side pillars and the actual gate that opens, a Town Center has even more parts. To top it all, gates are different objects depending on the direction they are facing.
This guide explains in detail how these two buildings work and how the graphics are sorted in the game.

Armor and attack classes

I’m assuming you are familiar with how damage is calculated in Age of Empires II. For extra reference, see this page.

Implementing attack and armors is very simple and also allows for a lot of fine tuning. In the units tab you can see two lists, “Attacks” and “Armors”, displaying all the varios armor classes a unit does damage against or has. Appart from those there is the field “Shown Attack”, “Shown Melee Armor” and “Shown Pierce Armor”, for the stats you see in the game. Also note “Base armor”, a default armor for when the game doesn’t find the class in the list on the left; it’s value is very high so that every attack that shouldn’t produce damage, indeed doesn’t.

Among the Attacks and Armors, you will usually find type 3 and 4, which correspond to pierce and melee damage, respectively. Also, all units have zero armor on type 31, which corresponds to the Leitis special armor, and on type 50, which corresponds to the extra damage done by Arambais, see the related document.

Tatar cavalry archers​

Now let’s look at the implementation of the Tatar bonus explained in this document. The bonus implements four new armor types: 40, 41, 42 and 43. If we look at the Archer, unit 4, we can see that it has zero armor on those four types. All other units have the corresponding armors depending on their base pierce armor.

A more complex thing happens when we look at the attack. Take for example the Cavalry archer, unit 39. If have any civ but the Tatars selected, you will see that one of it’s armor types is -1, nonexistent, with value 0. However, if you select Tatars, that armor type turns into 42 with value 1. The extra armor classes that implement the Tatar bonus are only present in the Tatar versions of the units. This is another example where I had to uncheck all civilizations boxes in the top of the tab in order for the changes to only apply to Tatars.

Armor Classes

Armor classes are the base to control damage in the game, both the basic melee and range and all the bonus damage combinations. Most of the classes include a description in the Advanced Genie Editor but we’ve created a lot more so I thought it best to list all the existing ones for reference purposes.
  1. Unused. The Wonder has this armor for some discarded bonus.
  2. Infantry units.
  3. Turtle Ships. Turtle Ships and Thirisadais have the armor. Fire ships have the attack.
  4. Base pierce damage.
  5. Base melee damage.
  6. Elephants.
  7. Extra cavalry class to combine the Bohemian bonus damage and Sicilian and Bengali bonus resistance.
  8. Extra elephant class for damage against Bengali elephants. Read here.
  9. Cavalry.
  10. Extra cavalry class to combine the Gurjara bonus damage and Sicilian and Bengali bonus resistance.
  11. Unused.
  12. All Buildings, including stone walls.
  13. Unused.
  14. Stone Wals and gates, excluding palisades.
  15. Animals have the armor, villagers the attack. For implementing the Magyar bonus.
  16. Archers.
  17. Ships.
  18. Rams, Trebuchets and Siege towers.
  19. Trees. Lumberjacks and Ballista elephants have the attack but no unit has the armor. Probably used to be able to damage trees.
  20. Unique units.
  21. Siege weapons.
  22. Standard Buildings, excluding stone walls.
  23. Walls and gates, including palisades.
  24. Gunpowder units. For the Condottiero bonus.
  25. Boars and alikes. For the Goth bonus.
  26. Monks.
  27. Castle and Krepost.
  28. Spearmen.
  29. Cavalry Archers.
  30. Eagle Warriors.
  31. Camels.
  32. Ignoring armor class. Units have zero armor on this class, buildings have their melee armor. Used by Leitis and Dravidian units after their unique tech.
  33. Condottiero. Used by units with bonus damage against infantry (Cataphract, Slinger) to bypass the Condottiero resistance against Hand Canoneers.
  34. Obuch class to deal extra damage to units with high melee armor. Read here.
  35. Fishing ships. Ships and fortified buildigs have this attack.
  36. Mamelukes. Pikemen and camels have this attack.
  37. Unused.
  38. Hussite Wagon. Mangonels and Bombard cannons have this attack.
  39. Unused.
  40. Unused.
  41. Units with 0 pierce armor. For the Tatar extra damage of cavalry archers. Read here.
  42. Units with 1 or less pierce armor. For the Tatar extra damage of cavalry archers. Read here.
  43. Units with 2 or less pierce armor. For the Tatar extra damage of cavalry archers. Read here.
  44. Units with 3 or less pierce armor. For the Tatar extra damage of cavalry archers. Read here.
  45. Unused.
  46. Unused.
  47. Unused.
  48. Unused.
  49. Extra cavalry class for damage against Sicilian units. Read here.
  50. Atheism trigger. Read here.
  51. Arambai extra damage. Read here.

Artificial Intelligence Scripting

I have basically no idea on AI scripting but there are some things that may be of use for people trying to port other AIs for mods.

Eagle Scouts​

One of the changes in Definitive Edition and in Wololo Kingdoms DE, is that eagle scouts have their line of sight reduced to 5. This is something that needs to be modified for meso american civilizations.

Constants​

AIs include a file full of identifiers of the units, technologies and buildings available in random maps. In Promi’s AIs, this is the const.per file. Artificial intelligences that work on the original Wololo Kingdoms or Definitive Edition, like Promi, work pretty well with Wololo Kingdoms DE except for when it comes to the new civilizations. There are two reasons for that:
  • New civilizations are stored in different order in Definitive Edition and Wololo Kingdoms DE. We need to reorder them.
  • New units and technologies added in Definitive Edition don’t have the same identifiers in AGE. In order for the AI to work properly with theese civilizations, we need to add new constants to the code.

Moreover, Promi versions usually are able to detect whether they are playing on Definitive Edition or older versions of the game, there are some “if” branches in the code, as some units also differ between Wololo Kingdoms and Definitive Edition. As the base code for Wololo Kingdoms DE is the original Wololo Kingdoms, we only need to add constants of the new stuff for it to work.

The following code lists all the constants you need to add to the AI file. The ones mentioning civilizations must replace the existing ones and the rest must be added to the code, making sure they are in an “if” branch that executes when not playing Definitive Edition. In case of doubt, check the existing AI in Community Patch 1.6.

Code:
(defconst BULGARIANS-CIV 0)
(defconst TATARS-CIV 0)
(defconst CUMANS-CIV 0)
(defconst LITHUANIANS-CIV 0)
(defconst BURGUNDIANS-CIV 0)
(defconst SICILIANS-CIV 0)
(defconst POLES-CIV 0)
(defconst BOHEMIANS-CIV 0)
(defconst DRAVIDIANS-CIV 0)
(defconst BENGALIS-CIV 0)
(defconst GURJARAS-CIV 0)

(defconst cumans 32)
(defconst lithuanians 33)
(defconst bulgarians 34)
(defconst tatars 35)
(defconst burgundians 36)
(defconst sicilians 37)
(defconst poles 38)
(defconst bohemians 39)
(defconst dravidians 40)
(defconst bengalis 41)
(defconst gurjaras 42)

(defconst ri-supplies 90)

(defconst krepost 1245)
(defconst donjon 1476)

(defconst ri-elite-konnik 678)
(defconst ri-elite-keshik 680)
(defconst ri-elite-kipchak 682)
(defconst ri-elite-leitis 684)
(defconst ri-elite-coustillier 751)
(defconst ri-elite-serjeant 753)
(defconst ri-elite-obuch 779)
(defconst ri-elite-hussite-wagon 781)
(defconst ri-elite-armored-elephant 883)
(defconst ri-elite-urumi-swordsman 740)
(defconst ri-elite-ratha 891)
(defconst ri-elite-chakram-thrower 891)
(defconst ri-elite-shrivamsha-rider 978)
(defconst ri-stirrups 685)
(defconst ri-bagains 686)
(defconst ri-silk-armor 687)
(defconst ri-timurid-siegecraft 688)
(defconst ri-steppe-husbandry 689)
(defconst ri-cuman-mercenaries 690)
(defconst ri-hill-forts 691)
(defconst ri-tower-shields 692)
(defconst ri-burgundian-vineyards 754)
(defconst ri-flemish-revolution 755)
(defconst ri-first-crusade 756)
(defconst ri-scutage 757)
(defconst ri-elite-steppe-lancer 715)
(defconst ri-szlachta-privileges 782)
(defconst ri-lechitic-legacy 783)
(defconst ri-wagenburg-tactics 784)
(defconst ri-hussite-reforms 785)
#load-if-defined POLES-CIV
(defconst ri-hussar 786)
#end-if
#load-if-defined LITHUANIANS-CIV
(defconst ri-hussar 786)
#end-if
#load-if-defined HINDUSTANIS-CIV
(defconst ri-capped-ram 883)
#end-if
#load-if-defined BENGALIS-CIV
(defconst ri-capped-ram 883)
#end-if
#load-if-defined DRAVIDIANS-CIV
(defconst ri-capped-ram 883)
#end-if
#load-if-defined GURJARAS-CIV
(defconst ri-capped-ram 883)
#end-if

(defconst ri-winged-hussar 786)
(defconst ri-houfnice 787)
(defconst ri-houfnice 787)
(defconst ri-medical-corps 743)
(defconst ri-wootz-steel 744)
(defconst ri-paiks 909)
(defconst ri-mahayana 910)
(defconst ri-kshatriyas 898)
(defconst ri-frontier-guards 977)

(defconst konnik 1246)
(defconst elite-konnik 1247)
(defconst krepost-konnik 1250)
(defconst elite-krepost-konnik 1251)
(defconst foot-konnik 1248)
(defconst elite-foot-konnik 1249)
(defconst leitis 1226)
(defconst elite-leitis 1236)
(defconst kipchak 1374)
(defconst elite-kipchak 1376)
(defconst mercenary-kipchak 1260)
(defconst keshik 1253)
(defconst elite-keshik 1255)
(defconst feudal-battering-ram 35)
(defconst steppe-lancer 1370)
(defconst elite-steppe-lancer 1278)
(defconst flaming-camel 706)
(defconst xolotl-warrior 1570)
(defconst coustillier 1473)
(defconst elite-coustillier 1475)
(defconst serjeant 1480)
(defconst elite-serjeant 1481)
(defconst donjon-serjeant 1477)
(defconst elite-donjon-serjeant 1479)
(defconst obuch 1232)
(defconst elite-obuch 1233)
(defconst hussite-wagon 1241)
(defconst elite-hussite-wagon 1242)
(defconst winged-hussar 727)
(defconst houfnice 1238)
(defconst armored-elephant 1526)
(defconst elite-armored-elephant 1527)
(defconst urumi-swordsman 1549)
(defconst elite-urumi-swordsman 1551)
(defconst thirisadai 1535)
(defconst ratha 1531)
(defconst elite-ratha 1545)
(defconst chakram-thrower 1629)
(defconst elite-chakram-thrower 1632)
(defconst shrivamsha-rider 1629)
(defconst elite-shrivamsha-rider 1632)

(defconst konnik-line -247)
(defconst krepost-konnik-line -246)
(defconst foot-konnik-line -245)
(defconst leitis-line -244)
(defconst kipchak-line -243)
(defconst keshik-line -242)
(defconst steppe-lancer-line -241)
(defconst coustillier-line -240)
(defconst serjeant-line -239)
(defconst donjon-serjeant-line -238)
(defconst obuch-line -237)
(defconst hussite-wagon-line -236)
(defconst bombard-cannon-line bombard-cannon)

Blast damage

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.

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​

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

Circle creator code

Code:
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()

Collaborating with the mod

If you look at the list of new features and units in the v1.6 Game Data mod, you’ll see a lot of units and buildings labeled as “TO DO”. Most of the stuff we have added so far has been focused on random maps and the new civilizations. Alongside with that, Definitive Edition added new hero units and special buildings that you only encounter in scenarios. Similarly, we have added new graphics for normal units and buildings but there are some animals and other decorative elements of random maps that still use the old graphics.

With all the information explained in this guide, you should be able to add some of these units or graphics to the mod. Here I’m going to explain the process you need to do to make sure we can incorporate it to the mod. For doubts or submissions, contact us through the Voobly pages.

New graphics​

New graphics are easy to do, just create the new slp, give it the number displayed in AGE and send it to us, explaining which unit it is so that we can test it. If everything works fine, we’ll add it.

New units​

This one is more complex since you can not merge two .dat files easily. If you want to add new units to the mod, here is what to do:
  1. Make a copy of the .dat file to edit it.
  2. Modify the .dat file and add the new unit and create its graphics.
  3. Send me the .dat file specifying which ID numbers you have created (unit and graphics) and which unit in the .dat file from Definitive Edition it comes from so that I can check it.
  4. If everything is correct, I’ll add your code to the main .dat file that I maintain.

New maps and AI​

Also easy to add. Once it works, just send it over and we’ll add it.

Languages​

We mentioned it a bit in the introduction of the guide but it’s a very straightforward process. The file language.ini can be opened with Notepad and its lines are made of an integer number and a string of text. The game looks for the integer numbers in the file and displays the string. If you translate the strings in the language file, you have translated the game.

Dynasties of India Development Diary

As we did with previous expansions of Definitive Edition, in this page I will document the process of adapting the new civilizations to the Community Patch.

08/04/2022. Some desciptions leaked​

Currently known as the “Porto” DLC, some screenshot was shared in AoEZone about the upcoming expansion. This new expansion of Definitive Edition renames the Indians Hindustanis and adds three new civilizations. What we have right now are only bonus and tech descriptions, no information on the unique unit habilities.

Let’s go over them and comment what may be problematic to adapt.

Hindustanis​

Basically a renaming of the Indians. Still mentions the elephant archer although the image of the unique unit seems to be an infantry unit. It has been rumored that elephant archers will now be a common unit to the four civilizations so it’s likely the elephant archer is not the unique unit of the Hindustanis anymore and they just forgot to change it here.

Gurjaras - Start with two forage bushes.​

An adaptation of the chinese, mayan and incan one. Easy to do.

Herdable animals can garrison in Mills to produce food.​

I assume this will offer a tradeoff between instantaneous food by killing the animal or a small trickle by letting it live.

At the moment katsuie believes he can have herdables have access to the garrison button like he made the Hussite Wagon have access to the ungarrison one. It would remain to see if we can trick the game to allow herdables inside buildings. Currently you can set buildings to allow villagers, infantry or cavalry, which is what makes cavalry able to enter castles but not towers. If that fails, we could try to have mills behave like transport ships which allow way more types of units.

If any of that works, we just need to create an invisible feitoira unit to generate food like we did for the poles.

Alternatively, I’m thinking of an implementation where mills would produce food on their own but shepperds would collect less food from ships, opposite of what Tatars do.

Fishing ships can garrison in Docks.​

As with the previous one, if katsuie can have sheeps enter mills, he should be able to do the same for ships and docks.

Mounted units deal 50% more bonus damage.​

If this means a bonus similar to the Sicilian one, I will adapt it in a similar way.

Kshatriyas (Military units cost -25% less food)​

Easy.

Frontier Guards (camel riders and elephant archers +4 melee armor)​

Easy.

Camel and elephant units trained 20% faster.​

Easy.

Dravidians​

Receive +200 when advancing to the next age.​

Easy

Fishermen and fishing ships carry +15.​

Easy

Barracks technologies cost -50%.​

Easy.

Skirmishers and elephant archers attack 25% faster.​

Easy.

Medical Cops (Elephant units regenerate 20 HP per minute).​

We were able to do this for poles villagers.

Wootz Steel (infantry ignore melee armor).​

This one is tricky. Ignoring armor like the Leitis does is easy, it uses a different armor class for which there is no protection. However, disabling one armor class and activating the other is not that straightforward, as we can not substract damage from units, only add it. A convoluded workaround is to upgrade infantry units to a new version of them with the new armor class. To the player it would look as the same unit but the damage would be calculated differently. The initial implementation of the Leitis worked like this so it will work even if it’s a lot of effort programming.

Docks provide +5 population room.​

Easy.

Bengalis​

Elephant units receive 33% less damage and are more resistant to conversions.​

Adaptations of the Sicilian bonus. I will use the same ideas.

Town Centers spawn two villagers when the next age is reached.​

Also an adaptation of the chinese, mayan and incan bonus with the twist of repeating it each age. It will be a hell of programming to ensure it happens only with ages and not when building new Town Centers but I believe it’s possible.

Ships regenerate +15 HP per minute.​

We did the same thing with poles.

Paiks (rathas and elephant units attack 20% faster).​

Easy.

Mahayana (Villagers take 10% less population space).​

Possible like the Karambit warrior work but a hell of programing since I’ll have to create new versions of each villager with the updated population space.

Trade units yield 10% food in addition to gold.​

We have a similar thing with Poles miners. The process should be the same but we have to be very cautious of trade units going idle and therefore stop producing food.

09/04/2022. Preliminary implementation of garrisoning sheeps and ships​

We still need to make sure only those units can garrison.


15/04/2022. Official information on the new DLC​

Microsoft officially anounced the DLC, balance changes and civilizations (see here).

To start with, the bonuses that were leaked previously seem to be the same, except for some tweaking on the actual numbers that are not very relevant.

What we have new is information on the unique units so let’s go over it.

New elephan units​

The Elephant Archer is now a shared unit which won’t be a problem to adapt. What actually troubles me here is that we are going to have to move icons around in the Archery Range to make space for it.

There is a new unit called Armored Elephant, which seems to function like a ram. The description says “cannot be converted by enemy Monks from distance”. This is in line with rams and may be the way to adapt the unit into the Community Patch, by having it be a ram under the hood. The unit is created in the siege workshop so it wouldn’t surprise me that it is actually programmed as a ram in Definitive Edition as well.

Hindustanies (Indians)​

Loose Stable units have +1/+2 pierce armor in the Castle/Imperial Age​

Easy to do.

Bonus team changed to Camel and light cavalry units +2 attack vs. buildings​

Easy to do.

Villagers cost -10% Dark, -15% Feudal, -20% Castle, -25% Imperial Age​

Existing bonus.

Camel Riders attack 25% faster​

Easy to do.

Gunpowder units +1/+1P armor​

Easy to do.

Can build Caravanserai in Imperial Age: building that heals and increases speed of Trade Carts in a 10 tile radius.​

A while back, I managed to create a Town Center that was able to heal nearby units. In theory this can be the same principle. However, implementing the Caravanserai like this would mean that the unit heals everyone around it. I’ve asked katsuie to look into having a monk only be able to heal selected untis. Alternatively, we could put a limit on the ammount of units of this kind the player can create so one can not have them all over the map.

For the speed thing, I believe the simplest approach would be increasing the speed a bit when the first Caravanserai is built.

Unique unit: Ghulam​

“Infantry unit that thrusts its spear through multiple targets”. This description leads me to think of Scorpions and Ballista Elephants. I need to study how those units work before deciding how to implement this one.

Bengalis​

Unique unit: Ratha​

“Unique chariot that can switch between melee and ranged attacks”. This one baffles me as having two types of attacks is not possible, at least from an animation point of view. Plus, the logic of how to change from one attack to the other is something we haven’t seen in other units. So far, without looking at the code, my idea is to simply have a range unit, maybe changing the stats to compensate the lack of melee version.

Dravidians​

Unique unit: Urumi Swordsman​

“Infantry unit which can charge its attack”. Coustillier adaptation.

Unique unit: Thirisadai​

“Warship that fires multiple projectiles”. This shouldn’t be hard to adapt either.

Gurjaras​

Unique unit: Chakram Thrower​

“Infantry unit with ranged melee attack”. Similar to the Gbeto, I assume.

Unique unit: Shrivamsha Rider​

“Light cavalry unit which can dodge projectiles”. Another weird description, from a programming point. The only thing that I can think of to adapt it is reducing the size of the collision box, so less astray arrows hit them. Once ballistics are on effect, I don’t know how to handle it.

Unique unit: Camel Scout​

Easy.

16/04/2022. Progress on the Ghulam​

The Hindustani “Infantry unit that thrusts its spear through multiple targets” looks in the description to either be similar to the Kamayuk and Steppe Lancer but also it may work as the Scorpion, hitting units behind the intended target.
I’ve looked at how the Scorpion works and have managed to create a copy of the spearman that hits units behind its target with a one tile reach. If the Ghulam works like I believe, this spearman will be its baseline.
Unit 1524 and 1525

16/04/2022. Initial implementation of the Armoured elephant​

The trick was to have the Ram upgrade to the elephant when playing with the indian civlizations. This way, the game still treats it as a ram and monks need to be beside it to convert it.

Current implementation copies the stats of the ram and uses the War elephant graphics.

Unit 1526, tech 881, effect 869. Disable Capped ram in Indian tech tree.

armored-elephant-400x356.png


21/04/2022. Progress on the Armored elephant​

I’ve implemented the Siege elephant (the upgrade of the armored version) and programmed its presence only for Hindustanis. I still need to program the correct stats but I’ll do that with the code in front of me.

21/04/2022. Some ideas about the Shrivamsha Rider​

Spirit of the Law has published a video where he shows that the ability to “dodge proyectiles” is actually a shield taken from Star Wars Gallactic Battlegrounds. The first thing I’ve tried is enabling this ability through the Genie Editor but I wasn’t surprised when nothing happened, the game is not checking for that value so there is no way to activate it.

Thinking about what to do, I’ve realised that the main role of this unit is exactly what Spirit of the Law shows in the video: a cavalry counter for a civilization without knights. Therefore, if I can not give them a shield, I should find a way to make them as pierce resistent as knights without affecting their performance in melee.

One of the most useful tools the game has to play around with the damage of units are armor classes. They control counter units, hidden bonuses and I’ve used for several new civilizations over the development of the Community Patch (Tatars, Sicilians, Obuch…). I can create new armor classes so that I can control the damage range units deal to the Shrivamsha Rider and set the values that I desire for each unit.

The idea I have in mind right now is that the Shrivamsha Rider should have the ability “proyectiles deal 33% less damage”. I’ve come to this value after noticing that the Shrivamsha Rider has about 33% less HP and costs 33% less resources. With this numbers, a Crossbow that deals 3 damage to a Knight will deal 2 damage to the Shrivamsha Rider and kill it in a similar ammount of hits.

Nevertheless, I’ll do some experiments once I have access to the new units before setting on the numbers. So far I like the idea since it’s not just giving the unit more pierce armor but a multiplicative reduction on the damage taken, which is not a common approach the way damage calculation is done in the game.

23/04/2022. Implementation of the Ratha for the Community Patch​

After seing Spirit’s of the Law video (https://youtu.be/rvJdOKktoMA) I was thinking the only thing remotly similar in the game that can change modes is the trebuchet. I oppened Advanced Genie Editor and 5 minutes later came out with this proof of concept. We need the ratha to use the normal unit interface but have access to the pack/unpack buttons from the trebuchet. We did something similar with the Sicilian Serjeant so it may be possible.


25/04/2022. Chakram Thrower information​

Spirit of the Law just did a video on the Chakram Thrower (https://youtu.be/rvJdOKktoMA). Turns out the implementation of the Ghulam I did a couple of weeks ago where I added damage to the units behind the target is exactly the special ability of this new unit. So I’ll just reuse that code to implement it.
This leads me to the question of what the Ghulam’s ability of “thrusting its spear through multiple targets” means. It’s either a direct port of the Kamayuk ability or it does some kind of area damage.

26/04/2022. Ghulam information​

Spirit of the Law just did a video on the Ghulam (https://youtu.be/rvJdOKktoMA) and it turns out I was right, the unit is meant to damage the enemies behind the target, likely using the scorpion implementation I did a couple of weeks ago.
This means that both the Ghulam and the Chakram Thrower use the scorpion’s mechanism but with different ranges.

26/04/2022. Armored elephant bug avoided​

In another video by Spirit of the Law (https://youtu.be/rvJdOKktoMA) he mentions that armored elephants fight back units. He doesn’t mention it and I don’t know if he tested it but it may be that they actually attack units before buildings. This is likely because the unit hasn’t been programmed as a siege unit, and told to favor buildins and flee from combat.

Funny enough, since the implementation I’ve done for the Community Patch upgrades the Ram, this issue is completly avoided by design.

Of course, it introduces another bug, the Armored elephant has to be repaired, rather than healed, since the game treats it like a ram for all purposes. However, I find this a funny easter egg rather than an issue that may be problematic in game.

26/04/2022. Progress on the Ratha​

After the initial implementation where we reworked the trebuchet to take advantage of its changing unit ability, we found a ton of problems with the unit. It had to be repaired, rather than healed; you needed Redemption in order to convert it and conversion had to be done at distance one. All these was due to the fact that the unit is categorized as a trebuchet for the game.

Fortunately, katusie was able to fix all of this and now the Ratha looks more like a normal unit, hiding its “trebuchet nature”.

We still have some bugs, some icons in the interface are not showing and sometimes the unit freezes (as if it suddently remembers unpacked trebuchets shouldn’t move) but it’s getting there.

02/05/2022. Indians renamed.​

After spending the last days copying all the balance changes of the patch that affect the existing civilizations, I’ve finally started modifying the Hindustanis. So far I’ve disabled the access to the elephant archer and modified their bonuses. Next I have to fix the tech tree as some techs have been disabled/enabled.

We are still working on the Caravanserai, the unique building that heals trade carts. katsuie is looking at an implementation where the building changes the terrain around it and that enables to detect trade carts nearby. It’s still in progress as we need to make sure of its stability and that it doesn’t interfere with other elements of the game.

hindustanis.png


04/05/2022. Progress on the Caravanserai.​

After a lot of trial and error, katsuie has managed to get the coordinates of units and be able to detect when a trade cart is near, activating the healing ability.

The speed boost is going to be implemented as a global increase for all trade once a certain number of caravanserais have been built. I’ll decide the number later on.


05/05/2022. Caravanserai ready.​

I’ve programmed a speed boost of +8%, +10%, +12% when the player builds 4, 5, 6 Caravanserais. This way we force players to have several of them in order to benefit from the speed boost. I’ve added the text, graphics and icon and programmed it only for Hindustanis.

caravanserai.png


07/05/2022. Armored Elephant ready​

It is affected by Blacksmith and Stable upgrades.

armored-elephant2.png


08/05/2022. Ghulam ready​


ghulam.png


10/05/2022. Hindustanis ready​

I will do some tests online to check that the Caravanserai area and some other implementations done in the patch work as intended but the civilization is ready. The mod will be updated next week.

After that, I need to sync with katsuie to see what requires the patch to work (appart from the new units, which he is already working on) so that we can stablish a backlog of things to implement.

17/05/2022. Update on the new civilizations​

After updating the mod with the Hindustanis we are looking again at the new civilizations. We won’t work on them yet as we are preparing an update on the game interface that should be ready during the week. Here is a small update of where we are.

The most important breakthrough katsuie had was being able to enable the faith for other units rather than the monks. This allows to have a counter on the unit that we can control and allows to implement the new abilities. With it, he’s been able to have a unit switch between one version or another when the faith is full, which can be used to replicate the charging ability. Also, he’s been able to direct the damage to the faith bar so that it acts like a shield.


21/05/2022. Working on the new units and Dravidians​

I’ve created the entries of all the new units that have a special ability so that katsuie can program them in the patch.
Meanwhile, I’ve started working in the Dravidians. So far I have programmed their tech tree and interface.

22/05/2022. Elephant archer and Dravidians bonus ready​

Dravidians now have access to the elephant archer and can upgrade it in the Archery Range. Also, I’ve programmed the civilizations bonuses. It remains the two unique techs (both of them may take time) and the two unique units. Plus sounds, dialogue, graphics, Wonder…

24/05/2022. Thirisadai ready​

As I commented a while back, the Thirisadai has not been a problem as the ability to shoot multiple proyectiles is easy to implement. I’ve also prepared the Medical Corps tech, it remains for katsuie to enable healing on elephants so this technology has some effect.

thirisadai.png


26/05/2022. Improvement on the healing ability​

Out of the blue, I’ve discovered how the Maghrebi Camels effect works and I’ve been able to replicate it for all units that are able to heal themselves. This makes the Poles regeneration bonus, Dravidians Medical Corps and Berserkers easier to implement, while avoiding a bug that we were introducing with the caravanserai healing.

30/05/2022. Dravidians ready​

It still remains to incorporate the charging mechanism into the Urumi Swordsman but all I had to do on the mod’s side is done.

dravidians-1200x787.png


31/05/2022. Bengalis villager bonus​

In Definitive Edition, whenver Bengalis reach the next age, every town center spawns two villagers that follow the gather point and start working inmediatly.

I can not do that in the Community Patch. As far as I know, I have two options:
  1. Have the villagers appear in the town center as chinese villagers do. These villagers spawn directly but don’t start working on their own.
  2. Have a second villager unit with zero cost and zero train time like the First Crusade Sergeants. These villagers would follow the gather point and start working inmediatly but the player has to manually create them.
What I’ve decided is to combine both options. In Feudal age I’ll use the first method, since there are not so many things happening then, it should be easier for the player to notice the two idle villagers and get them to work. After Castle age I’ll use the second method; the villagers won’t go idle as they appear but the player has to remember to create them. Since by then there are more villagers around, forgetting about them for a moment shouldn’t be that impacting.

06/06/2022. Bengalis bonus armor​

After a long process of deciding the values, programming the new armor classes and setting the triggers, I’ve finally created the bonus armor for elephant units. You can read the full description here.

06/06/2022. Bengalis healing ships​

Now that I understand how the Berber healing works, creating those bonuses is super easy.

07/06/2022. Bengalis discounted villagers​

Creating a new version of the villagers that take only 0.9 population is easy but I’ve encountered a problem: the game doesn’t update the population when the tech is researched so only new villagers have discounted population.

Even worse: if the villagers that existed before the tech was researched die, they return 0.9 population space instead of 1. This means that, if you have 100 villagers, that occupy 100 population, research the tech and then loose all those villagers, you end up with 10 population even if there are no more units around.

For the time being I’ve programmed a solution for this that works when you have 100 villagers; it eliminates the extra 10 population and makes 100 villagers occupy 90 population. The problem is that it only works with exactly 100 villagers. I hope to get katsuie’s help to have the patch detect the number of existing villagers and modify the population accordingly.

14/06/2022. Lots of progress on Bengalis​

katsuie has been working this past week on all the Bengali bonuses that required the help of the patch to work properly. Specifically, we now have the population correctly updating when the player research Mahayana and the trade carts now should generate food when depositing gold.
I’ve also added the Ratha graphics and all the text description of unique units and technologies.

I still need to make sure everything related to the Ratha is working properly: upgrades, conversions, animations, attack. Since internally the unit is a trbuchet, there are a lot of issues that could arise.

If all of that is done, I just need to create their tech tree and the castle graphics.

ratha.png


18/06/2022. Bengalis ready​

All the graphics, tech tree and techs have been added into the game.

We are planning to release these two new civs in the following weeks, alongside several changes of the patch that adress the older civs plus some new features. We still need to check for bugs on all the new stuff we’ve added, I specially haven’t checked the Urumi Swordsman and Coustillier new charge mechanic.

Bengalis-1200x875.png


22/07/2022. Back to work on the Gurjaras​

After a lot of testing and debugging the new charge mechanic and the Ratha behaviour in the game to make sure we were releasing a stable version of the mod, we have added Bengalis and Dravidians to the game. Only Gurjaras to go.

I have ported the graphics of the three new units. I’ll start by adding the camel scout and trying to fit it in the tech tree without the rest of the civilizations going crazy because of it.

26/07/2022. Camel scout ready​

The camel scout now appears as the starting scout unit for Gurjaras, it gains a bit of attack and speed in feudal and upgrades to camel rider when reaching castle. It correctly displays above the camel rider in the tech tree as well.

camel_scout-800x537.png


26/07/2022. Forage bushes bonus​

At first I thought that the Gurjara bonus where they get two bushes in the town center was going to be easy, given that we have similar bonuses for villagers and llamas. However, bushes present a problem: they don’t exist for the civilizations, only for gaia. Therefore, I could not create the bushes for the Gurjara player.

It has taken me a couple of hours. I have combined the code of a deer and a sheep to create an deer that can belong to other civs appart from gaia, then it can appear in the town center as a llama. The unit appears dead, doesn’t decay and has the graphics of a bush. Appart from that, foragers are the ones that can “hunt” this new unit so it looks like villagers collecting food from a bush.

30/07/2022. Chakram Thrower implemented​

I still need to add the text of the unit, activate it for the Gurjaras and add it to the tech tree but the core behaviour of the unit is done. As I predicted months ago, the unit works like a Scorpion, that’s what allows the proyectiles to pass through units.

chakram.png


31/07/2022. Gurjara tech tree, unique techs and team bonus​

Creating the tech tree and adding the unique techs is a very mechanic process, given that the effects of the technologies are easy to implement.
What has been challenging is the team bonus. It’s supposed to affect armored elephants but, since internally they are rams, I had to make sure it affected rams only for the indian civilizations. After quite a while I’ve managed to implement a version that still fails in very weird situations (most of them requiring the scenario editor) but that works in all standard game modes.

I’m still missing the Shrivamsha rider and the two bonuses related to garrisoning, which will be the hardest ones.

01/08/2022. Garrison bonuses in progress​

Turns out that garrisoning ships and herdables is easy, the game was already prepared for these abilities in the units. Fishing ships already work and herdables are missing the feitoira unit to generate food.

03/08/2022. Herdables garrison bonus and progress on the Shrivamsha rider​

I finished the Feitoira unit and now herdables produce food inside the mill.

On the other hand, I’ve researched how the Shrivamsha rider works in Definitive Edition. Our implementation still has some bugs but the core mechanic is working and it’s only a matter of tweaking. While katsuie fixes the issues, I’ll add the graphics and text to the unit.

04/08/2022. Shrivamsha rider ready​

They withstand the correct ammount of shots and the shield regenerates at the correct speed.

shrivamsha.png

Extra villagers, llama 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, everytime 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 disapears 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 676, “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 disapearing.

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, and it triggers a new technology, 647, “Disable TC spawn”, different from the “Disable TC spawn extra” we encountered before.

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 676.
  • Unit 1394 dies instantly and turns into unit 1397.
  • Unit 1397 tiggers tech 674, 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 glueued 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 ugrades unit 890 to unit 1396, “Villager annex (Chinese)”.

As with unit 1398 for Mayans, this unit triggers tech 676. 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, triggering tech 674 and finally turning into villagers.

Inca bonus​

Inca’s extra llama works in a similar way. Tech 673 triggers effect 704 which turns unit 890 into unit 1118, “Inca llama annex”. Unit 1118 triggers tech 676 and places an annex building, 888. Unit 888 directly triggers tech 674 and dies into a llama.

"Disable TC spawn" techs​

Finally, let’s look at the two technollogies the three civilization bonuses trigger. Techs 674 and 676 produce effects 705 and 733, respectively.

The first one to get executed cronologically is effect 733, “Disable TC spawn extra”. Its only command is 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, 1396 or 1118 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/llama and deactivates it for any other town centers that may be already present.

The second effect, 705 does a similar thing but for town centers to come. It upgrades all the annex units we have mentioned to unit 889, so that any new town center built by Mayans, Chinese or Incas doesn’t produce extra villagers or llamas.

Effect 705 is now redundant, as far as I can see, as everything is handled by effect 733 before, but it’s a consequence of the development process of the bonus. At first, they implemented that the villagers appear when the town center is built, adding effect 705 to prevent it from happening on future town centers. Later on they decided that, on maps with more than one starting town center, extra villagers should appear only in one of them, thus introducing effect 733.

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 begining 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.

Fishermen droping food at docks

Now that we have seen how to upgrade units, let’s see how this is used to implement the new feature where fishermen can use docks and explain a problem that arises.

Villager drop sites​

Let’s first understand how a villager drops resources. Go to the Units tab and, from the filter menu, select “Class”. Now, in the dialogue box write “C 4,”. This filters unit from class 4, that corresponds to civilian units. Now you should see the different variations of villagers.

One of the fields in the units tab are the ones called “Drop sites”, there are two of them: the first one is always the Town Center and the second one the specific for that resource. For the case of original fishermen, units 56 and 57, the second building is the Mill.

Therefore, if we create a new copy of the fishermen and modify one of the drop sites, we can make them use the Dock instead. However, it wasn’t that simple. When testing the functionality, I realised that if I put the Dock as one of the drop sites and left the other as it is, villagers would ignore Docks even if they were closer. Because of this, the new copies of the fishermen, units 1310 and 1311, only have the Dock as a drop site.

Upgrade one fishermen to the other​

Now the idea is that, if the player just wants to take fish from a pond, fishermen should use Town Centers and Mills as drop sites, that is units 56 and 57. If the player builds a dock, then the fishermen should change to recognize the Dock as a drop site, that is upgrade them to units 1310 and 1311 respectively.

Is there a way to detect when the players build a Dock? There is. Every building triggers a technology that mainly serves to count to number of buildings required to advance to the next age. Let’s clear the filter dialogue box and hide the “Class” option. Now we simply write “Dock”. There are several Docks in the game but the one that interests us is unit 45, the one with internal name “DOCK” without any number, which means it is the Dark Age one. One of the fields available is called “Initiates Technology”, which for the dock initiates tech 108.

Let’s check this technology in the Techs tab. It actually as an effect but if you check it, you’ll see it’s empty. What is relevant to note is the fact that “Min Req Techs” is set to 1 but it does not have any “Required Techs” listed. This means that the tech can not be triggered on it’s own when some other techs are researched. It can only be activated by building a Dock.

Now that we know how to detect the presence of a Dock, let’s create a tech that upgrades one fisherman to the other. In Wololo Kingdoms DE, this is tech 738. This tech requires one tech to be available, 108, and has zero research time, which means it’s researched as soon as you build the Dock. It’s effect, number 746, upgrades unit 56 to 1310 and unit 57 to 1311. The third command is not relevant right now.

So there we have it. Once you build a Dock, technology 108 is researched, which in turn researches technology 738 which triggers effect 746 and upgrades one pair of fishermen into the other, making them recognise the Dock as a drop site. Unfortunately this is not the end as you may have guessed by the large amount of fisherman units in the code.

Downgrade the fishermen?​

Let’s now consider the case where the player doesn’t want the fishermen using the Dock once he builds one. We can easily create a free technology whose effect is changing again the fishermen. But, can we actually change units 1310 and 1311 back to 56 and 57? Unfortunately no, the game doesn’t allow to upgrade back to a previous version of the unit. Therefore we can only upgrade the fishermen that use the Dock to a new version of fishermen that use the Town Center and the Mill. Effectively they are identical to units 56 and 57 but it’s the only way the game allows it.

This is where units 1312 til 1329 come into play. Each new pair of fishermen have opposite drop site from the previous ones. This allows to change the behaviour of fishermen back and forth for a couple of times but not indefinitely.

Let’s implement the tech that activates the change. All these techs are encoded in numbers 739 till 747. Let’s see some of their characteristics:
  • All the techs require a previous tech to be available, namely the previous number.
  • The icons are either 122 and 123. You can check them at the end of file 50729.slp in the “drs” folder.
  • The research time is 1, a positive value to ensure that the tech is not researched automatically but that the player has to click on it.
  • The research location is the mill, number 68, and the button is number 2, meaning it will appear next to the farm upgrade.
  • The effects of all these techs upgrade always units 56 and 57. As we mentioned before, the game always considers upgrades of the unit as the first one so there is no need to have the full list of upgrades.
As before, the third command in all the effects is not relevant here. It is related to the burgundian Flemish revolution and we’ll explain it later.

Fixed Positions code

Code:
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()

Graphical mods

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.

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


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


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.

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 the 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 aforemontioned 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.

The 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 either 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 assing 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 posibility 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 “Inititates 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.

The handicap map creator​

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’ve created a program that creates the specific combination the players need. You can see the source code by downloading the mod.

The code reuses the circles and fixed positions code I’ve already shared and adds the extra lands with id for the handicap units. The program is comprised of 4 modules:
  • Handicap. Main one that creates the interface.
  • map_creator. That generates the rms file.
  • circle_creator. That generates the player lands, placing them around a circle. It also creates the lands with id, using the same terrain as the player lands and placing them on top of the player land.
  • indentation. That rewrites the rms to add indentation and help readability.
The program offers several maps that are accessed from the “maps_data” folder. This way, the source code doesn’t have to be modified to add new maps, only their information is needed. Each map is divided into 5 files:
  • constants: Initial constants to decide vegetation and animals.
  • land_generation: code for the <LAND_GENERATION> section that is not player lands.
  • objects_generation: code for the <OBJECTS_GENERATION> section.
  • other_generation: code for the TERRAIN, CLIFF, ELEVATION and CONNECTION sections.
  • main: specific pieces of code that have to be read by the program. The entries have comments and you only need to respect the empty lines between sections.
The map_creator module accesses each file and combines them into an rms file, adding the circle generation and the handicap units when needed.

Healing ability

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.

We’ve been able to activate that healing ability for other units but it comes with a problem: the regeneration speed is controlled by resource 96, which means that every unit with regenerating abilities would regenerate at the same rate. With the introduction of the Caravanserai, this poses a problem for a Viking player allied with a Hindustani. The code would modify the regeneration speed of Berserkers when using trade carts.

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 3. When researching Berserkergang, attribute 45 is modified.

Huns Atheism

The new implementation of atheism, where enemy relics produce less gold, is very tricky to implement. The problem is that none of the available effects in Wololo Kingdoms DE are able to affect enemy players, only the player that research techs and in some cases their allies. In order to affect enemies, we need another way of interacting with them.

The idea came to me after seing a pretty unknown mod: Panic mod. This mod adds a free technollogy that kills every enemy unit and damages castles. The interesting thing is its implementation. The panic button actually creates a demolition ship with -1 hit points, with a super high damage and blast radius. When this unit is created, it dies instantly, triggering an explosion that covers the whole map and strong enough to kill every unit. The fact that only affects units and not buildings is handled with armor classes. Also, the explosion does not affect allied units.

The idea for Atheism is similar. Every player has an invisible unit inmune to all attacks except for one. When a Hun player researches Atheism, it triggers an explosion that only affects those invisible units, killing them. When those units die, they trigger a technollogy that modifies the relic gold generation.

Creating the explosion​

On to the problems. The first one we encounter is that the number of “explosive units” is limited. By explosive unit I mean a unit that, upon death, triggers an explosion. Those units are, specifically, the three Demolition Ships, the Petard and the Saboteur, which in Wololo Kingdoms DE is modified to be the Flaming Camel. In order to implement Atheism, we need to modify one of those, at least for Huns. Huns have access to the Fast Demolition Ship so our only option is the Flaming Camel.

If we look at unit 706 for any civilization except for the Huns, we encounter the Flaming Camel. If we look at the Huns version, we find a unit with -21 hit points (we need this number to compensate Bloodlines), that does damage to classes -1 (non-existent) and 1000 damage to class 49, with a blast width of 400. For comparison, a Sige Onager has 1.5 blast width.

Creating the trigger in the enemies​

The special unit that only dies when Atheism is researched is easy to do once we know our way around annex units from when we saw how to create extra villagers. In this case, we use the Monastery and not the Town Center mainly because the Town Center is full of annex units already.

If we look for unit 104, the basic Monastery, we see it has annex unit 1510, “Monastery annex 0”. This unit exists only to die and become unit 1511, “Monastery annex 1”, that is already independent from the Monastery and will live on even if the Monastery is destroyed. This unit 1511 triggers technology 749, that disables the Monastery annex units to appear in future Monasteries, so that the effect of Atheism is not applied several times.

Let’s look at the unit stats. It has 1000 hit points and only one armor class, 49, the same as the Huns Flaming Camel. This means that, if attacked by the Huns Flaming Camel, it will receive 1000 damage and die but, if attacked by anything else, mainly siege weapons with blast damage attacking the Monastery, it will receive 1 damage per attack, requiring 1000 hits to die.

When 1511 dies, it becomes unit 1512, “Monastery annex 2” that initiates technology 748, that reduces the relic gold generation. In terms of stats, it’s equal to unit 1511 to allow for several Hun enemies to research Atheism and the effect to stack up. For the same reason, it dies into itself.

Since the explosion only affects enemy units, allied Monastery annex units are not affected and thus don’t trigger the Atheism effect.

Bugs and side effects​

This implementation is not perfect and there are some weird situations that may occur and side effects to the explosion:
  • The presence of the trigger is linked to the players having built at least a Monastery before Atheism is researched. This is hardly a problem in a normal game since Atheism is an Imperial tech and likely to be researched late in the game, when the gold mines are gone.
  • The effect of Atheism only applies to players that are enemies in the moment the technology is researched. Therefore, diplomacy games can produce weird situations.
  • Since the Hun Flaming Camel is used to trigger the effect, and even if Huns can not create them, a converted Flaming Camel crashes the game upon exploding.
  • The damage calculation in the game demands that every attack deals at least 1 damage. This means that, when Atheism is researched, every enemy unit will receive 1 damage.

Introduction

Introduction​

The code inside Age of Empires 2 is a mess. I understand budget and time limitations when the game was released but, in the time since, no one has sat down to clean the code. If you look around a little in the data file of the game, you will find animations that are never used, civilization bonuses that do nothing and even things actually in the game but with different names.

In summary: be prepared for frustration, for having to backtrack thorught the code several times until understanding how something works and for finding nonsense.

The best advice I can give you, that also served me, is to look for similar implementations to discover how they work. If you want to create a bonus that stacks through the ages, check how the Goths infantry cost works. If you want a bonus that gives a free technollogy, check how Turks get their free Chemistry or Light Cavalry upgrades.

Also, one can not go without citing Age of Kings Heaven. They have a section on modding articles with information on different parts of the modding process: simple things like creating units or graphics and convoluded ones like gold generating units. I did not need all the information there to start working, as some stuff I could understand by looking at the code, but I’ll mention the ones worth reading.
Having said all that, once you get the hang of it, it’s very straightforward adding stuff and knowing how something may be implemented, at least from my point of view.

My idea with this guide is to give an overview of the programs and files you need to manage to at least give you a starting point from where you can mess around in the code. Later, I’ll explain in detail some examples of implementations and bonuses that I consider worth looking at, like extra villagers in the Town Center or queuable techs.

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. Since the Lords of the West update in Definitve Edition, that game’s data file crashes on the AGE available in the link. Inside the AoE2DE folder, in a folder called Tools_Builds, you can find a new version of AGE able to open de Definitive Edition data file. However, that version of AGE doesn’t show some text properly on the WK DE data file so I only use it to check Definitive Edition implementations.
  • 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 modify DE graphic files and create .slp files from them. It also includes some functionalities like color replace, resizing, format change…
  • Text Editor, like notepad, in order to modify language files, map scripts and AI files.
  • Image Editor, like Paint or GIMP, on case you need to modify some of the graphics.

Structure of the mod folder​

This description is done following the one we use in Wololo Kingdoms DE, copied from the one in the original Wololo Kingdoms. Data mods are stored inside your AoE 2 folder inside the folder “Voobly Mods/AOC/Data mods”.
The structure of this folder is as follows:
  • Data. Folder with the main data files:
    • empires2_x1_p1.dat: the master file with the unit stats that you access through AGE.
    • gamedata_x1.drs: compressed file with original map scripts, access it with Turtle Pack.
    • gamedata_x1_p1.drs: compressed file with graphics and sounds, access it with Turtle Pack.
  • drs. Folder to store extra graphics and sounds without having to add them to gamedata_x1_p1.drs. The game prioritizes files in this folder over the ones in gamedata_x1_p1.drs.
  • History. Text files with historical information about the civilizations. Not relevant for the gameplay.
  • SaveGame. Self explanatory.
  • Scenario. Where custom scenario files are stored.
  • Screenshots. Self explanatory.
  • 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.
  • 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.
    • stream. Civilization themes.
    • 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. The file includes some other information like the unique unit but the game doesn’t seem to use it.
  • language.ini. Language file that you can read with a text editor. Every text string you see in the game has a number attached to it. The language file lists all the number with the corresponding string.
  • Player.nfz. Placeholder file to have player profiles in the game. Not relevant.
  • player1.hki. Hotkeys file. If you have several profiles in the sigle player menu, you will have 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 the players have the same one and prevent crashes.
You may notice that not all the files the game needs are in the mod folder. Most notably, there are way more graphics in the game than the ones stored in gamedata_x1_p1.drs and, in some cases, you can not have a hotkey file in the mod folder. All the indispensable files and the ones that don’t need to be changed are stored in the root folder of the game, there is a data folder there too and a hotkeys file. The game only replaces those files if it finds one with the same name in the mod folder.

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.

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 Wololo Kingdoms DE 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​

Map creation guide for Empire Wars

Empire Wars is a new game mode introduced in Age of Empires II Definitive Edition where the players start already in Feudal Age with an already established economy. The main idea is to bypass the early build-up phase of the game.

Replicating this mode in the old AoC we use in Voobly is virtually impossible. Definitive Edition introduced several new commands on the map generation scripts that allow placing villagers near resources and have them working at the start of the game. All this allows random map generation so that every match is different.

There is however one thing we can do to mimic Empire Wars on Voobly: custom scenarios. Through the scenario editor it’s possible to create a base, populate it with villagers and set them to work right away so that the game feels like an Empire Wars game. You can see an example for that in the scenario “2021-08-25_pancrol” currently included in v1.6 Game Data. Unfortunately, through custom scenarios we can not have random map generation as the scenarios are created manually, one at a time.

And this is where I want to ask for the help of the Voobly community. It is very simple to have a folder full of Empire Wars scenarios and have a script that selects one randomly so that, every time you play a game, you get a different map. For that to work, we need people helping out to produce a large enough sample of Empire Wars maps.

This guide will explain all the process needed to create a map, task villagers to resources and test it, so that everyone can create an Empire Wars scenario and send it to Voobly.​

A big thanks to everyone willing to collaborate on this endeavor.

Should you have any doubts not clarified in this guide, load the demo scenario “2021-08-25_pancrol” shipped with “v1.6 Game Data” in the scenario editor to see how it works.

1. Basic map generation​

Open “v1.6 Game Data” in Single Player Mode, go to the scenario editor and select “Create new scenario”.

scenario_editor-600x449.png


The game will load up a blank map for you to work on.
Go to the “Players” button and set the “Number of players” to “2 players”. Then, for each player, do the following:
  • Set the “Starting Age” to “Feudal Age”.
  • Give them 200 Food, 200 Stone, 200 Pop Limit, 200 Wood and 100 Gold.
  • Set the “Player Type” to “Either” so that they can be controlled by humans.
  • Set the “Personality” to “None”.

players.png


Now go to the “Map” button and select “Random Map”. Set the size of the map to “Tiny (2 players)” and select the map script “EW_Arabia”. This is an adaptation of Arabia with less animals and some of the necessary buildings and units already placed. Select “Generate map” and the game will create a random map with two bases that already have the Town Center, six villagers surrounding a sheep, the scout, six houses, a Barracks and a Blacksmith.

map_creation.png


Please, do not create other scenarios than 1v1 Arabias for the moment. If the Community response is good and I get enough scenarios of this kind, I’ll open the possibility of other maps.

2. Adding additional villagers​

What the random map generation can not do is place the lumber camps, mill, mining camp and farms in their place and have villagers near it. This has to be done by hand. Place the following elements by going to the “Units” button and selecting “Units” or “Buildings” and the corresponding player you are editing:
  • 3 Lumber camps next to forests, each with 4 villagers on them, for a total of 12 villagers on wood.
  • 1 Mill next to the berries with 4 villagers on it.
  • 1 Mining camp next to the main gold with 4 villagers on it.
  • 2 Farms next to the Town Center, each with a villager on it. Place the farms on the left side of the Town center, so as not to overlap with the sheep and villagers on the right side.
Use your best judgement to place the camps. Lumber camps should be placed so that they can be walled in or the villagers can escape to the Town Center in the case of a raid. Lumber camps and Mills should be placed directly next to the resource while Mining camps should leave a one tile gap to the gold. It’s best to have the grid on to do this.

Also, feel free to move some of the existing buildings to make space for the new ones.

3. Putting villagers to work​

Now that we have the necessary villagers in the bases, we need to ensure they start working as the game begins. This is done with triggers and effects.
Go to the “Triggers” button and do the following:
  1. Click on “New” to create a new trigger.
  2. Click on “New Cond” to create a condition that initiates the trigger.
  3. On the “Condition List”, select “Timer” and set it to 0. This will have the trigger start when zero seconds of game have elapsed, that is, at the beginning of the game.
Now the tedious part. For every player and for every villager, except for the six ones in the Town Center around the sheep, do the following:
  1. Click on “New Effect” to create an effect for that villager.
  2. From the “Effect List” select “Task Object” (“Función Objeto” in spanish) to give a task to the villager.
  3. Click on “Set Objects”.
  4. Click on the villager.
  5. Click on “Set Location”.
  6. Click on the desired resource.
Once that’s done, you should see both the villager and the resource selected when having the effect highlighted. If you missclick a villager / resource, you need to click again on “Set Objects” / “Set Location” before selecting the units again.

We have to task villagers one by one in order to ensure they work on all situations. It is possible to task a group of villagers with the “Set Area” button but that also requires setting the “Source Player” to the one villagers belong to. If later the first player in the game room wants to play with color 2, all the triggers will fail.

Once you are done tasking all villagers, you should have 22 effects per player. Note that effects numbers start on zero so that you don’t get confused.
You can also set a trigger per player, so that you can easily navigate between players in case something doesn’t work when testing.

trigger-1200x1077.png


4. Testing the scenario​

Go to the Menu on the top right and press “Test”. This will load the scenario and let you play with Player 1. As soon as a second pass, villagers will start working. Pause the game (default hotkey is F3) to ensure that the AI can not interfere with the villagers, although it is set to “None” personality, it may move some.
Select the “Economic view” of the minimap (you may need to toggle “Advanced commands” to see it, it’s the gears button above the minimap) to see the villager distribution. It should be:
  • 6 Idle villagers.
  • 2 Farmers.
  • 4 Foragers.
  • 12 Lumberjacks.
  • 4 Gold Miners.
Using the commands “Ctrl+Shift+F2”, “Ctrl+Shift+F3”, etc, you can change control to the other players to check the villager distribution on them.

Bear in mind, since the game is paused, the villager distribution doesn’t update automatically when you change players. To force an update, switch back and forth between the normal view and the economic view.

test.png


5. Description of the scenario​

Go to “Messages” and in “Scenario Instructions” write a description of the map, adding your name or the date the map was created. This will help locate the scenario if someone finds an error when playing.

description.png


6. Send the scenario​

If all the villagers of all players are working in their respective resources, the scenario is ready to be used.

Go to “Voobly Mods/AOC/Data Mods/v1.6 Game Data/Scenario” and locate the .scx file you have been working on.

Please, name it following the convention “year-month-day_creator.scx” like “2021-08-25_pancrol.scx”. This way I’ll be able to locate scenarios with errors and have them sorted in the folder.

Send the .scx file to [email protected]. Please, put the scenario inside a .zip or .rar folder so it passes the antivirus check.
I’ll check that the scenario works as intended and add it to the pool of scenarios.

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 and the free Bengali villagers.

Porting graphics from Definitive Edition

We now look at the case where we want to port the graphic of a unit from Definitive Edition.This guide is partly based on this video by Harkamui but some of the steps are different.

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 new data graphic. This will momentarily hide the old 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 fixing 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.

Queuing techs functionality

This 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 tech (see the section on the Techs Tab for more information on this). Wololo Kingdoms DE 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, tech 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 Tech 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 Tech Tree, has tech 816 disabled.
  • The queuable tech 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, in the case of unit upgrades, 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 tech more than once. We have to create a new resource per tech in order to have this.
  • Once the tech 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 tech to also disable the unit that created it.
  • 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 tech 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.

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 tech 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 tech and a new age to be available. Depending on the order things are done, the new tech may be available or not.

This can be solved with dummy objects in two ways:
  • Dummy technologies. Creating technologies without effect whose only prerequisite is the tech they stand for, (tech 78 is an example of this). Since this 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.
  • Dummy units. This is done on sequences of technologies that require a previous tech and a new age. For example, the moment Fletching is researched, technology 776 is researched and enables 958, a unit no one can see or research that stands for Bodkin Arrow during Feudal Age. Once the player reaches Castle, this dummy unit becomes the actual queuable tech that enables Bodkin Arrow.

Issues​

The main issue with this functionality is that the icon of the tech 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 Wololo Kingdoms DE 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.

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 programing for older versions of the game are aware of it.

I have tried to do some research on the field of porting scripts from Definitive Edition to Wololo Kingdoms DE. However I’ve been unable to create a tool able to completly translate the code; there are too many variables I may have not encountered and different scripters have different ways of writting the variables that confuse any automatic translator.

What I can contribute with is with a couple of features added in Definitive Edition for which I have created scripts to add code to existing maps. The first one is the circle_radius, a feature to place players at the same distance from the center of the map, and Fixed Positions, a feature that places players of the same team in order so that players are able to decide whether to be flank or pocket.

This 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.

Also, I’ve seen people using Allied Vision mods all the time when it’s really not needed if you configure the map to have the resource that activates cartography set to 1 from the beginning. I’ll explain how to do so.

circle-radius command​

This command 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.
Access the Python code here.

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.

Access the Python code here.

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.

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.

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.

Villagers switching tasks

This one is a more simple functionality of the game but that I consider worth mentioning as it took me a while to figure out and it will be useful when we talk about the Flemish revolution.

As we can see by filtering only civilian units, Class 4, there is a different unit for every variation of the villager. If we check the “Tasks” section, at the bottom of the units tab, we can see that each variation of the villager has a task related to a resource. For the most part they use action “Gather/Rebuild” on farms, mines, bushes, etc. Having different versions for each villager allows civilization bonuses like the celt or the slav to affect only a speciffic version of the villager.

Now, how does the game change a villager into a lumberjack when you click on a tree? The secret is in the “Task Swap Group” field up in the Attributes section. All Male villagers have this field set to one and all females have it on 2. When you click with the villager on a tree, the game looks for another unit on the same Task Swap Group that has a task involving trees. When it finds it, it changes the villager into a lumberjack.

Wololo Kingdoms DE actually uses a third task swap group, number 3, for the villagers after the Flemish revolution. We’ll see about it later on.

License and Copyright

Copyright © 2009 – 2023 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“.​
Top Bottom