Trigger - Intro

Translated by Wiesl
Basic Structure[ Copy codeblock ]
<Asset> <Template>Trigger</Template> <Values> <Standard /> <Trigger> <TriggerCondition> //a condition is expected at this place </TriggerCondition> <TriggerActions> <Item> //a condition is expected at this place </Item> </TriggerAction> </Trigger> <TriggerSetup /> </Values> </Asset>

A very simple but powerful concept, which exists since Anno 2205, are triggers.
Discovered by Fishboss in summer 2019, the unlock system is based on triggerable events, that are triggered as soon as their condition is met. Once triggered, they unlock everything they are supposed to unlock and stay triggered.
So a trigger implements the following concept: If the condition is met, it executes one or more actions.

There are a number of predefined conditions and actions in the templates.xml You are limited to these (there is also old code from Anno 2205) - but they can do a lot and are very versatile. These conditions and actions can be combined arbitrarily. For example, you can link the activation of the heavy AI in the AI shipyard to the construction of a building (e.g. an embassy) instead of a reached population. The actions of a trigger are triggered in their order.

Registering triggers

Translated by Wiesl

Imagine the following problem: I wrote a trigger to unlock the bank at 1 engineer and triggered it, unlocked the bank and made the residents happy. But in retrospect I realize that I also want to have the clubhouse from 1 engineer, so I add it to my trigger. If I would reload my savegame, I will notice that it is not activated at all, although I already have 1 engineer?
Why is that so?

Anno manages the triggers in an internal event list, in which a trigger must first be registered. When registering the trigger, the asset is parsed and an event is created for Anno based on it. In our case: 1 engineer reached -> unlock bank. This event gets the GUID of the trigger as ID. If Event 42 is already in the event list, no more changes are made to this event, no matter if we change the trigger. If Event 42 is triggered in the event list, the game remembers this. No matter what we change now on the asset with GUID = 42, the game will not re-register it by itself.

Normally, assets with the template trigger are automatically registered the first time they are used, unless we turn it off. (see below)
Then we have to re-register manually. For testing purposes, it is usually quite helpful to simply change the GUID of the asset, because Anno will then see the trigger as a new event and re-read it accordingly. For the manual registration we now have to do a few steps:

A few tricks using triggers

Translated by Wiesl

To register a trigger not automatically: under TriggerSetup you can disable the automatic registration of the trigger

Register a trigger with another trigger: Via the ActionRegisterTrigger - This works even if the trigger has already been triggered! After the new registration the trigger can be triggered again.

.

Let a trigger reset itself: Via the ActionResetTrigger

Register a trigger only when a certain condition is met: This is done by a SubTrigger in the SubTriggers container. This SubTrigger must be registered under Values/Trigger.

SubTrigger[ Copy codeblock ]
<SubTriggers> <Item> <SubTrigger> <Template>AutoCreateTrigger</Template> <Values> <Trigger> <TriggerCondition> //a condition is expected at this place </TriggerCondition> </Trigger> </Values> </SubTrigger> </Item> </SubTriggers> <SubTriggers> <Item> <SubTrigger> <Template>AutoCreateTrigger</Template> <Values> <Trigger> <TriggerCondition> //a condition is expected at this place </TriggerCondition> </Trigger> </Values> </SubTrigger> </Item> </SubTriggers> <SubTriggers> <Item> <SubTrigger> <Template>AutoCreateTrigger</Template> <Values> <Trigger> <TriggerCondition> //a condition is expected at this place </TriggerCondition> </Trigger> </Values> </SubTrigger> </Item> </SubTriggers> <SubTriggers> <Item> <SubTrigger> <Template>AutoCreateTrigger</Template> <Values> <Trigger> <TriggerCondition> //a condition is expected at this place </TriggerCondition> </Trigger> </Values> </SubTrigger> </Item> </SubTriggers>
Enlarge codebox

A SubTrigger can also have more SubTriggers added to it, if you feel like it you can have a look at the uPlay-Club challenge "Silocon Valley", where it has been pushed to an extreme.

Trigger - Intro

Translated by Wiesl
Basic Structure[ Copy codeblock ]
<Asset> <Template>Trigger</Template> <Values> <Standard /> <Trigger> <TriggerCondition> //a condition is expected at this place </TriggerCondition> <TriggerActions> <Item> //a condition is expected at this place </Item> </TriggerAction> </Trigger> <TriggerSetup /> </Values> </Asset>

A very simple but powerful concept, which exists since Anno 2205, are triggers.
Discovered by Fishboss in summer 2019, the unlock system is based on triggerable events, that are triggered as soon as their condition is met. Once triggered, they unlock everything they are supposed to unlock and stay triggered.
So a trigger implements the following concept: If the condition is met, it executes one or more actions.

There are a number of predefined conditions and actions in the templates.xml You are limited to these (there is also old code from Anno 2205) - but they can do a lot and are very versatile. These conditions and actions can be combined arbitrarily. For example, you can link the activation of the heavy AI in the AI shipyard to the construction of a building (e.g. an embassy) instead of a reached population. The actions of a trigger are triggered in their order.

Registering triggers

Translated by Wiesl

Imagine the following problem: I wrote a trigger to unlock the bank at 1 engineer and triggered it, unlocked the bank and made the residents happy. But in retrospect I realize that I also want to have the clubhouse from 1 engineer, so I add it to my trigger. If I would reload my savegame, I will notice that it is not activated at all, although I already have 1 engineer?
Why is that so?

Anno manages the triggers in an internal event list, in which a trigger must first be registered. When registering the trigger, the asset is parsed and an event is created for Anno based on it. In our case: 1 engineer reached -> unlock bank. This event gets the GUID of the trigger as ID. If Event 42 is already in the event list, no more changes are made to this event, no matter if we change the trigger. If Event 42 is triggered in the event list, the game remembers this. No matter what we change now on the asset with GUID = 42, the game will not re-register it by itself.

Normally, assets with the template trigger are automatically registered the first time they are used, unless we turn it off. (see below)
Then we have to re-register manually. For testing purposes, it is usually quite helpful to simply change the GUID of the asset, because Anno will then see the trigger as a new event and re-read it accordingly. For the manual registration we now have to do a few steps:

A few tricks using triggers

Translated by Wiesl

To register a trigger not automatically: under TriggerSetup you can disable the automatic registration of the trigger

Register a trigger with another trigger: Via the ActionRegisterTrigger - This works even if the trigger has already been triggered! After the new registration the trigger can be triggered again.

.

Let a trigger reset itself: Via the ActionResetTrigger

Register a trigger only when a certain condition is met: This is done by a SubTrigger in the SubTriggers container. This SubTrigger must be registered under Values/Trigger.

SubTrigger[ Copy codeblock ]
<SubTriggers> <Item> <SubTrigger> <Template>AutoCreateTrigger</Template> <Values> <Trigger> <TriggerCondition> //a condition is expected at this place </TriggerCondition> </Trigger> </Values> </SubTrigger> </Item> </SubTriggers> <SubTriggers> <Item> <SubTrigger> <Template>AutoCreateTrigger</Template> <Values> <Trigger> <TriggerCondition> //a condition is expected at this place </TriggerCondition> </Trigger> </Values> </SubTrigger> </Item> </SubTriggers> <SubTriggers> <Item> <SubTrigger> <Template>AutoCreateTrigger</Template> <Values> <Trigger> <TriggerCondition> //a condition is expected at this place </TriggerCondition> </Trigger> </Values> </SubTrigger> </Item> </SubTriggers> <SubTriggers> <Item> <SubTrigger> <Template>AutoCreateTrigger</Template> <Values> <Trigger> <TriggerCondition> //a condition is expected at this place </TriggerCondition> </Trigger> </Values> </SubTrigger> </Item> </SubTriggers>
Enlarge codebox

A SubTrigger can also have more SubTriggers added to it, if you feel like it you can have a look at the uPlay-Club challenge "Silocon Valley", where it has been pushed to an extreme.

The Asset-Library - Basics

Imagine your game like this (very simplified):
Assets + Graphics → Binary (Anno1800.exe) → What you can do and see on screen
You cannot modify the Binary. What you can do, is feeding it new or changed assets and graphics that the game can interpret. That means, you have to stick to the rules, only if you write Code that can be parsed by the game, it will do what you want it to do.

What skills are needed to get started?

First, no, you do not need to be a programmer, although this is always a plus.
If you aren‘t a programmer, it is strongly recommended you familiarize yourself with the concepts of data types, variables, arrays, inheritance as well as (generic) dictionaries and vectors/lists. You don‘t need to write actual code with it, but understanding those is quite valuable.
Most of the game files are using the XML scripting language. I won‘t explain any XML syntax and going to assume basic XML knowledge, if you don‘t know any of this, you should read into that topic first. You should also be or get familiar with Xpath, since this is needed for the modloader later on.

Understand the Asset Library

So, this should be the first in some kind of tutorial series about asset modding. First, I want to apologize (no, not canadian) – the start is gonna be more dry and theoretical stuff, but you‘ll need it in order to get to the interesting parts, especially if you like to inject new functionality.
For Assets, Anno uses a few basic concepts all over again:

  • Assets are actual ingame objects (like a building, a ship, or a construction menu) that are built from a template.
  • Templates are Blueprints for Assets that configure defaults for values in each asset using this template, and say which properties it has.
  • Properties are Containers that are directly contained by an Asset. Properties can contain Containers, but Containers cannot contain a property.
  • Containers are collections of Values, vectors or other containers.
  • Vectors are lists of variables or containers
  • Dictionaries are like vectors, but each element gets a unique name that needs to match a hardcode the game is looking for. Because of this, the size is limited to the amount of available hardcodes.
  • Values are simple variables or arrays
Note: To differentiate between the name of a value and the value itself, I will call the name „variable“ from now on.

Properties

This is the hardest to understand, but once you get it, you will have no problems understanding any templates and assets the game offers.
Properties.xml essentially consists of two parts: DefaultContainerValues and DefaultValues. Those are grouped for better overview in the dev tools, but in general you could narrow it down to those two.
DefaultContainerValues defines which Containers a property uses, define Variables inside those containers, in case the container contains a vector or dictionary, the content type of this data structure is given.
DefaultValues defines the variables that are contained directly inside the property and inherit the Containers from DefaultContainerValues.
As the names might suggest, setting the a value for a variable inside the properties.xml sets this value as default for this variable in every asset using this property.

You can change the values for variables, but you cannot tell the game to load other containers or variables, since this is a direct export of what the game expects!
Note that on rare occasions, some of the export is incomplete, in that case every variable is given inside assets.xml.

If you need any information on what you can do with each property, this is where you should look. The following is a shortened version of the „IrrigationConfig“ property, along with some comments.

Example: Property IrrigationConfig[ Copy codeblock ]
<Properties> <DefaultContainerValues> <Building> <IrrigationConfig> <IrrigationSpreading> <!-- Variable inside Container inside Property: Variable is defined in the same spot --> <IrrigationSpreadRule>MaxAbsDist</IrrigationSpreadRule> </IrrigationSpreading> <!-- IrrigationIslandSeeds is a container containing a vector --> <IrrigationIslandSeeds> <!-- Island is the content type of that vector--> <Island>0</Island> </IrrigationIslandSeeds> </IrrigationConfig> </Building> </DefaultContainerValues> <DefaultValues> <IrrigationConfig> <!-- Containers are inherited --> <IrrigationSpreading /> <IrrigationIslandSeeds /> <!-- Variable directly inside Property: Variable is defined elsewhere, in the Property inside DefaultValues --> <StaticIrrigationRandomizerFrequency>2</StaticIrrigationRandomizerFrequency> </IrrigationConfig> </DefaultValues> </Properties>
Enlarge codebox

In case a container A contains another container B, B is defined in ContainerValues and then inherited by A. If B contains Variables, those are defined in the same spot.
The following example shows the DefaultContainerValues for the IrrigationConfig property:

Example: Container in Container[ Copy codeblock ]
<Properties> <DefaultContainerValues> <IrrigationConfig> <VisualsAndEffects> <!-- Defining the Vegetation Container --> <ContainerValues> <Vegetation> <!-- Variables inside Container inside Container inside Property: Variables are defined in the same spot --> <FadingSpeed>0.05</FadingSpeed> <BlurRadius>1</BlurRadius> </Vegetation> </ContainerValues> <!-- The defined Vegetation Container is now inherited into VisualsAndEffects --> <!-- Note: In this case, Vegetation is just a simple Container --> <!-- but it could also refer to the content type of a vector if VisualsAndEffects was one! --> <Vegetation /> </VisualsAndEffects> </IrrigationConfig> </DefaultContainerValues> <DefaultValues> <IrrigationConfig /> </DefaultValues> </Properties>
Enlarge codebox

The full definition of our IrrigationConfig should look something like this:

Example: Full IrrigationConfig[ Copy codeblock ]
<Properties> <DefaultContainerValues> <Building> <IrrigationConfig> <IrrigationSpreading> <IrrigationSpreadRule>MaxAbsDist</IrrigationSpreadRule> </IrrigationSpreading> <IrrigationIslandSeeds> <Island>0</Island> </IrrigationIslandSeeds> <VisualsAndEffects> <ContainerValues> <Vegetation> <FadingSpeed>0.05</FadingSpeed> <BlurRadius>1</BlurRadius> </Vegetation> </ContainerValues> <Vegetation /> </VisualsAndEffects> </IrrigationConfig> </Building> </DefaultContainerValues> <DefaultValues> <IrrigationConfig> <IrrigationSpreading /> <IrrigationIslandSeeds /> <VisualsAndEffects /> <StaticIrrigationRandomizerFrequency>2</StaticIrrigationRandomizerFrequency> </IrrigationConfig> </DefaultValues> </Properties>
Enlarge codebox

Data Types

The following Data Types are used for variables:

  • int → mostly signed 16 or 32 bit integers
  • float → american style 0.1305
  • boolean → noted as 0 or 1
  • String → without quotation marks
  • Hardcode → used like a String, however only predefined names are accepted.
You need to figure out the data type of a Variable by yourself by taking a look at how it‘s used inside all three files. Also, there is no full list of hard codes that can be used. Previous games like 2205 had a datasets.xml which contained this information, however this is not the case with 1800, and it would be a great thing if something like this could be published in the future by Ubisoft.

Templates

A template consists of a unique name as well as a collection of properties that objects using this template have.
The same as properties, Groups are only there for overview in Dev Tools and essentially are irrelevant

i.e. take a look at the Template „UnlockableAsset“

This one only has the Standard and the Locked Property.
Templates can define default values for any variable inside a property, which is then applied for all assets using this template, and that‘s essentially it.

Inheritance

At this point we should take a quick look at inheritance in general.

This is our custom template „CustomIrrigationConfig“.

As you might recall from earlier, the Property has a default Value of 2 for StaticIrrigationRandomizerFrequency. We now want to change that to 5, but keep the rest.
For this, we do not have to copy+paste everything, we just have to change that variable and leave the rest out.
In templates and assets, containers are automatically inherited, however properties are not (keep this in mind!). We could also manually inherit containers, but we do not have to.

Now, we also want to change the FadingSpeed inside VisualsAndEffects. For that, we have to first manually inherit VisualsAndEffects, inside that manually inherit Vegetation, and inside that override the FadingSpeed.

For dictionaries, the unique names are treated like containers, for vectors, inheritance has to be made manually. For this, see here (Only german).

Now let‘s get to creating actual ingame objects. Each Asset has the Standard property, which defines the GUID of an object.

An Asset consists of a Template and Values. To create our asset, we start of by specifing the template. In our case we will create a simple building from the template FactoryBuilding7. For Values, we will note down the exact properties that this Template has, without any Variables or Containers.

Then we‘ll do the Values.
I have decided to allocate the GUID 1337733142 for my building. This is now added in the Standard property as a Variable. For better overview, we can set a Name inside Standard too, though this is only for us. More about GUIDs you can find here.

Theoretically, we now have a fully functional factory. Except it produces nothing from nothing, does not cost any workforce or credits and does not have construction cost.
So let‘s assign those things to our factory.
We will make a factory that produces canned food from zinc and potatoes, and just because we can, we will do it in the new world with Obreros.

Assign Values[ Copy codeblock ]
<Asset> <Template>FactoryBuilding</Template> <Values> <Standard> <GUID>1337733142</GUID> <Name>Canned Food Factory 02 - Variant uses Potatoes and Zinc</Name> </Standard> <Building> <!-- Building for Colony01 (which is south america) --> <AssociatedRegions>Colony01</AssociatedRegions> <!-- Random rotation in the building preview --> <BuildModeRandomRotation>90</BuildModeRandomRotation> </Building> <Blocking> <!-- The radius in which grass and trees will be hidden in preview/deleted when built--> <HidePropsRadius>0</HidePropsRadius> <DeletePropsRadius>0</DeletePropsRadius> </Blocking> <Cost> <Costs> <Item> <!-- Referencing Money --> <Ingredient>1010017</Ingredient> <Amount>10000</Amount> </Item> <Item> <!-- Referencing Wood --> <Ingredient>1010196</Ingredient> <Amount>50</Amount> </Item> <Item> <!-- Referencing Bricks --> <Ingredient>1010205</Ingredient> <Amount>30</Amount> </Item> <Item> <Ingredient>1010218</Ingredient> </Item> <Item> <Ingredient>1010207</Ingredient> </Item> <Item> <Ingredient>1010202</Ingredient> </Item> </Costs> </Cost> <Object /> <Mesh /> <Selection> <!-- Hardcode, referencing the Participant (Character) that is visible in the menu. --> <!-- in our case it is the Obrero --> <ParticipantMessageArcheType>SA_Resident_tier02_atWork</ParticipantMessageArcheType> </Selection> <Text /> <Constructable /> <Locked /> <SoundEmitter /> <FeedbackController /> <Infolayer /> <UpgradeList /> <Factory7 /> <FactoryBase> <FactoryInputs> <Item> <!-- Product references the GUID of Potatoes --> <Product>1010195</Product> <Amount>1</Amount> <!-- internal Storage for Potatoes --> <StorageAmount>6</StorageAmount> </Item> <Item> <!-- Product references the GUID of Zinc--> <Product>1010229</Product> <Amount>1</Amount> <!-- internal Storage for Zinc --> <StorageAmount>3</StorageAmount> </Item> </FactoryInputs> <FactoryOutputs> <Item> <!-- Product references the GUID of Canned Food --> <Product>1010217</Product> <Amount>1</Amount> <!-- internal storage for Canned Food --> <StorageAmount>4</StorageAmount> </Item> </FactoryOutputs> <!-- Time in seconds needed to produce 1t --> <CycleTime>45</CycleTime> </FactoryBase> <LogisticNode /> <AmbientMoodProvider /> <Maintenance> <!-- Maintenance Cost --> <Maintenances> <Item> <!-- Money --> <Product>1010017</Product> <Amount>40</Amount> <InactiveAmount>20</InactiveAmount> </Item> <Item> <!-- Obrero Workforce --> <Product>1010367</Product> <Amount>25</Amount> </Item> </Maintenances> </Maintenance> <Attackable /> <Pausable /> <IncidentInfectable /> <Industrializable> <!-- Turn off industrialization, since we don't have electricity in the new world --> <BoostedByIndustrialization>0</BoostedByIndustrialization> </Industrializable> <Culture /> <QuestObject /> <Electrifiable /> </Values> </Asset>
Enlarge codebox

One thing is missing now – the visuals. Anno more or less seperates graphics from logic. Everything graphics-related is stored in other files, we simply reference their path, starting from the game‘s „data“ folder.

Assign graphics[ Copy codeblock ]
<Asset> <Template>FactoryBuilding7</Template> <Values> <Standard> <GUID>1337733142</GUID> <Name>Canned Food Factory 02 - Variant uses Potatoes and Zinc</Name> <IconFilename>data/ui/2kimages/main/3dicons/icon_canned_goulash.png</IconFilename> </Standard> <Building> <AssociatedRegions>Colony01</AssociatedRegions> <BuildModeRandomRotation>90</BuildModeRandomRotation> </Building> <Blocking> <HidePropsRadius>0</HidePropsRadius> <DeletePropsRadius>0</DeletePropsRadius> </Blocking> <Cost> <Costs> <Item> <Ingredient>1010017</Ingredient> <Amount>10000</Amount> </Item> <Item> <Ingredient>1010196</Ingredient> <Amount>50</Amount> </Item> <Item> <Ingredient>1010205</Ingredient> <Amount>30</Amount> </Item> <Item> <Ingredient>1010218</Ingredient> </Item> <Item> <Ingredient>1010207</Ingredient> </Item> <Item> <Ingredient>1010202</Ingredient> </Item> </Costs> </Cost> <Object> <Variations> <!-- Multiple cfg files enable scrolling through variations with Shift+V --> <Item> <Filename>data/graphics/buildings/production/workshop_colony01_01/workshop_colony01_01.cfg</Filename> </Item> </Variations> </Object> <Mesh /> <Selection> <ParticipantMessageArcheType>SA_Resident_tier02_atWork</ParticipantMessageArcheType> </Selection> <Text /> <Constructable /> <Locked /> <SoundEmitter /> <FeedbackController /> <Infolayer /> <UpgradeList /> <Factory7 /> <FactoryBase> <FactoryInputs> <Item> <Product>1010195</Product> <Amount>1</Amount> <StorageAmount>6</StorageAmount> </Item> <Item> <Product>1010229</Product> <Amount>1</Amount> <StorageAmount>3</StorageAmount> </Item> </FactoryInputs> <FactoryOutputs> <Item> <Product>1010217</Product> <Amount>1</Amount> <StorageAmount>4</StorageAmount> </Item> </FactoryOutputs> <CycleTime>45</CycleTime> </FactoryBase> <LogisticNode /> <AmbientMoodProvider /> <Maintenance> <Maintenances> <Item> <Product>1010017</Product> <Amount>40</Amount> <InactiveAmount>20</InactiveAmount> </Item> <Item> <Product>1010367</Product> <Amount>25</Amount> </Item> </Maintenances> </Maintenance> <Attackable /> <Pausable /> <IncidentInfectable /> <Industrializable> <BoostedByIndustrialization>0</BoostedByIndustrialization> </Industrializable> <Culture /> <QuestObject /> <Electrifiable /> </Values> </Asset>
Enlarge codebox

Take a look at the example again. You should pay close attention to Building, Maintenance, Object and FactoryBase Containers, you will most likely encounter them many times.
We now have a fully functional asset that we could add ingame, that Anno will interpret correctly.

The Asset-Library - Basics

Imagine your game like this (very simplified):
Assets + Graphics → Binary (Anno1800.exe) → What you can do and see on screen
You cannot modify the Binary. What you can do, is feeding it new or changed assets and graphics that the game can interpret. That means, you have to stick to the rules, only if you write Code that can be parsed by the game, it will do what you want it to do.

What skills are needed to get started?

First, no, you do not need to be a programmer, although this is always a plus.
If you aren‘t a programmer, it is strongly recommended you familiarize yourself with the concepts of data types, variables, arrays, inheritance as well as (generic) dictionaries and vectors/lists. You don‘t need to write actual code with it, but understanding those is quite valuable.
Most of the game files are using the XML scripting language. I won‘t explain any XML syntax and going to assume basic XML knowledge, if you don‘t know any of this, you should read into that topic first. You should also be or get familiar with Xpath, since this is needed for the modloader later on.

Understand the Asset Library

So, this should be the first in some kind of tutorial series about asset modding. First, I want to apologize (no, not canadian) – the start is gonna be more dry and theoretical stuff, but you‘ll need it in order to get to the interesting parts, especially if you like to inject new functionality.
For Assets, Anno uses a few basic concepts all over again:

  • Assets are actual ingame objects (like a building, a ship, or a construction menu) that are built from a template.
  • Templates are Blueprints for Assets that configure defaults for values in each asset using this template, and say which properties it has.
  • Properties are Containers that are directly contained by an Asset. Properties can contain Containers, but Containers cannot contain a property.
  • Containers are collections of Values, vectors or other containers.
  • Vectors are lists of variables or containers
  • Dictionaries are like vectors, but each element gets a unique name that needs to match a hardcode the game is looking for. Because of this, the size is limited to the amount of available hardcodes.
  • Values are simple variables or arrays
Note: To differentiate between the name of a value and the value itself, I will call the name „variable“ from now on.

Properties

This is the hardest to understand, but once you get it, you will have no problems understanding any templates and assets the game offers.
Properties.xml essentially consists of two parts: DefaultContainerValues and DefaultValues. Those are grouped for better overview in the dev tools, but in general you could narrow it down to those two.
DefaultContainerValues defines which Containers a property uses, define Variables inside those containers, in case the container contains a vector or dictionary, the content type of this data structure is given.
DefaultValues defines the variables that are contained directly inside the property and inherit the Containers from DefaultContainerValues.
As the names might suggest, setting the a value for a variable inside the properties.xml sets this value as default for this variable in every asset using this property.

You can change the values for variables, but you cannot tell the game to load other containers or variables, since this is a direct export of what the game expects!
Note that on rare occasions, some of the export is incomplete, in that case every variable is given inside assets.xml.

If you need any information on what you can do with each property, this is where you should look. The following is a shortened version of the „IrrigationConfig“ property, along with some comments.

Example: Property IrrigationConfig[ Copy codeblock ]
<Properties> <DefaultContainerValues> <Building> <IrrigationConfig> <IrrigationSpreading> <!-- Variable inside Container inside Property: Variable is defined in the same spot --> <IrrigationSpreadRule>MaxAbsDist</IrrigationSpreadRule> </IrrigationSpreading> <!-- IrrigationIslandSeeds is a container containing a vector --> <IrrigationIslandSeeds> <!-- Island is the content type of that vector--> <Island>0</Island> </IrrigationIslandSeeds> </IrrigationConfig> </Building> </DefaultContainerValues> <DefaultValues> <IrrigationConfig> <!-- Containers are inherited --> <IrrigationSpreading /> <IrrigationIslandSeeds /> <!-- Variable directly inside Property: Variable is defined elsewhere, in the Property inside DefaultValues --> <StaticIrrigationRandomizerFrequency>2</StaticIrrigationRandomizerFrequency> </IrrigationConfig> </DefaultValues> </Properties>
Enlarge codebox

In case a container A contains another container B, B is defined in ContainerValues and then inherited by A. If B contains Variables, those are defined in the same spot.
The following example shows the DefaultContainerValues for the IrrigationConfig property:

Example: Container in Container[ Copy codeblock ]
<Properties> <DefaultContainerValues> <IrrigationConfig> <VisualsAndEffects> <!-- Defining the Vegetation Container --> <ContainerValues> <Vegetation> <!-- Variables inside Container inside Container inside Property: Variables are defined in the same spot --> <FadingSpeed>0.05</FadingSpeed> <BlurRadius>1</BlurRadius> </Vegetation> </ContainerValues> <!-- The defined Vegetation Container is now inherited into VisualsAndEffects --> <!-- Note: In this case, Vegetation is just a simple Container --> <!-- but it could also refer to the content type of a vector if VisualsAndEffects was one! --> <Vegetation /> </VisualsAndEffects> </IrrigationConfig> </DefaultContainerValues> <DefaultValues> <IrrigationConfig /> </DefaultValues> </Properties>
Enlarge codebox

The full definition of our IrrigationConfig should look something like this:

Example: Full IrrigationConfig[ Copy codeblock ]
<Properties> <DefaultContainerValues> <Building> <IrrigationConfig> <IrrigationSpreading> <IrrigationSpreadRule>MaxAbsDist</IrrigationSpreadRule> </IrrigationSpreading> <IrrigationIslandSeeds> <Island>0</Island> </IrrigationIslandSeeds> <VisualsAndEffects> <ContainerValues> <Vegetation> <FadingSpeed>0.05</FadingSpeed> <BlurRadius>1</BlurRadius> </Vegetation> </ContainerValues> <Vegetation /> </VisualsAndEffects> </IrrigationConfig> </Building> </DefaultContainerValues> <DefaultValues> <IrrigationConfig> <IrrigationSpreading /> <IrrigationIslandSeeds /> <VisualsAndEffects /> <StaticIrrigationRandomizerFrequency>2</StaticIrrigationRandomizerFrequency> </IrrigationConfig> </DefaultValues> </Properties>
Enlarge codebox

Data Types

The following Data Types are used for variables:

  • int → mostly signed 16 or 32 bit integers
  • float → american style 0.1305
  • boolean → noted as 0 or 1
  • String → without quotation marks
  • Hardcode → used like a String, however only predefined names are accepted.
You need to figure out the data type of a Variable by yourself by taking a look at how it‘s used inside all three files. Also, there is no full list of hard codes that can be used. Previous games like 2205 had a datasets.xml which contained this information, however this is not the case with 1800, and it would be a great thing if something like this could be published in the future by Ubisoft.

Templates

A template consists of a unique name as well as a collection of properties that objects using this template have.
The same as properties, Groups are only there for overview in Dev Tools and essentially are irrelevant

i.e. take a look at the Template „UnlockableAsset“

This one only has the Standard and the Locked Property.
Templates can define default values for any variable inside a property, which is then applied for all assets using this template, and that‘s essentially it.

Inheritance

At this point we should take a quick look at inheritance in general.

This is our custom template „CustomIrrigationConfig“.

As you might recall from earlier, the Property has a default Value of 2 for StaticIrrigationRandomizerFrequency. We now want to change that to 5, but keep the rest.
For this, we do not have to copy+paste everything, we just have to change that variable and leave the rest out.
In templates and assets, containers are automatically inherited, however properties are not (keep this in mind!). We could also manually inherit containers, but we do not have to.

Now, we also want to change the FadingSpeed inside VisualsAndEffects. For that, we have to first manually inherit VisualsAndEffects, inside that manually inherit Vegetation, and inside that override the FadingSpeed.

For dictionaries, the unique names are treated like containers, for vectors, inheritance has to be made manually. For this, see here (Only german).

Now let‘s get to creating actual ingame objects. Each Asset has the Standard property, which defines the GUID of an object.

An Asset consists of a Template and Values. To create our asset, we start of by specifing the template. In our case we will create a simple building from the template FactoryBuilding7. For Values, we will note down the exact properties that this Template has, without any Variables or Containers.

Then we‘ll do the Values.
I have decided to allocate the GUID 1337733142 for my building. This is now added in the Standard property as a Variable. For better overview, we can set a Name inside Standard too, though this is only for us. More about GUIDs you can find here.

Theoretically, we now have a fully functional factory. Except it produces nothing from nothing, does not cost any workforce or credits and does not have construction cost.
So let‘s assign those things to our factory.
We will make a factory that produces canned food from zinc and potatoes, and just because we can, we will do it in the new world with Obreros.

Assign Values[ Copy codeblock ]
<Asset> <Template>FactoryBuilding</Template> <Values> <Standard> <GUID>1337733142</GUID> <Name>Canned Food Factory 02 - Variant uses Potatoes and Zinc</Name> </Standard> <Building> <!-- Building for Colony01 (which is south america) --> <AssociatedRegions>Colony01</AssociatedRegions> <!-- Random rotation in the building preview --> <BuildModeRandomRotation>90</BuildModeRandomRotation> </Building> <Blocking> <!-- The radius in which grass and trees will be hidden in preview/deleted when built--> <HidePropsRadius>0</HidePropsRadius> <DeletePropsRadius>0</DeletePropsRadius> </Blocking> <Cost> <Costs> <Item> <!-- Referencing Money --> <Ingredient>1010017</Ingredient> <Amount>10000</Amount> </Item> <Item> <!-- Referencing Wood --> <Ingredient>1010196</Ingredient> <Amount>50</Amount> </Item> <Item> <!-- Referencing Bricks --> <Ingredient>1010205</Ingredient> <Amount>30</Amount> </Item> <Item> <Ingredient>1010218</Ingredient> </Item> <Item> <Ingredient>1010207</Ingredient> </Item> <Item> <Ingredient>1010202</Ingredient> </Item> </Costs> </Cost> <Object /> <Mesh /> <Selection> <!-- Hardcode, referencing the Participant (Character) that is visible in the menu. --> <!-- in our case it is the Obrero --> <ParticipantMessageArcheType>SA_Resident_tier02_atWork</ParticipantMessageArcheType> </Selection> <Text /> <Constructable /> <Locked /> <SoundEmitter /> <FeedbackController /> <Infolayer /> <UpgradeList /> <Factory7 /> <FactoryBase> <FactoryInputs> <Item> <!-- Product references the GUID of Potatoes --> <Product>1010195</Product> <Amount>1</Amount> <!-- internal Storage for Potatoes --> <StorageAmount>6</StorageAmount> </Item> <Item> <!-- Product references the GUID of Zinc--> <Product>1010229</Product> <Amount>1</Amount> <!-- internal Storage for Zinc --> <StorageAmount>3</StorageAmount> </Item> </FactoryInputs> <FactoryOutputs> <Item> <!-- Product references the GUID of Canned Food --> <Product>1010217</Product> <Amount>1</Amount> <!-- internal storage for Canned Food --> <StorageAmount>4</StorageAmount> </Item> </FactoryOutputs> <!-- Time in seconds needed to produce 1t --> <CycleTime>45</CycleTime> </FactoryBase> <LogisticNode /> <AmbientMoodProvider /> <Maintenance> <!-- Maintenance Cost --> <Maintenances> <Item> <!-- Money --> <Product>1010017</Product> <Amount>40</Amount> <InactiveAmount>20</InactiveAmount> </Item> <Item> <!-- Obrero Workforce --> <Product>1010367</Product> <Amount>25</Amount> </Item> </Maintenances> </Maintenance> <Attackable /> <Pausable /> <IncidentInfectable /> <Industrializable> <!-- Turn off industrialization, since we don't have electricity in the new world --> <BoostedByIndustrialization>0</BoostedByIndustrialization> </Industrializable> <Culture /> <QuestObject /> <Electrifiable /> </Values> </Asset>
Enlarge codebox

One thing is missing now – the visuals. Anno more or less seperates graphics from logic. Everything graphics-related is stored in other files, we simply reference their path, starting from the game‘s „data“ folder.

Assign graphics[ Copy codeblock ]
<Asset> <Template>FactoryBuilding7</Template> <Values> <Standard> <GUID>1337733142</GUID> <Name>Canned Food Factory 02 - Variant uses Potatoes and Zinc</Name> <IconFilename>data/ui/2kimages/main/3dicons/icon_canned_goulash.png</IconFilename> </Standard> <Building> <AssociatedRegions>Colony01</AssociatedRegions> <BuildModeRandomRotation>90</BuildModeRandomRotation> </Building> <Blocking> <HidePropsRadius>0</HidePropsRadius> <DeletePropsRadius>0</DeletePropsRadius> </Blocking> <Cost> <Costs> <Item> <Ingredient>1010017</Ingredient> <Amount>10000</Amount> </Item> <Item> <Ingredient>1010196</Ingredient> <Amount>50</Amount> </Item> <Item> <Ingredient>1010205</Ingredient> <Amount>30</Amount> </Item> <Item> <Ingredient>1010218</Ingredient> </Item> <Item> <Ingredient>1010207</Ingredient> </Item> <Item> <Ingredient>1010202</Ingredient> </Item> </Costs> </Cost> <Object> <Variations> <!-- Multiple cfg files enable scrolling through variations with Shift+V --> <Item> <Filename>data/graphics/buildings/production/workshop_colony01_01/workshop_colony01_01.cfg</Filename> </Item> </Variations> </Object> <Mesh /> <Selection> <ParticipantMessageArcheType>SA_Resident_tier02_atWork</ParticipantMessageArcheType> </Selection> <Text /> <Constructable /> <Locked /> <SoundEmitter /> <FeedbackController /> <Infolayer /> <UpgradeList /> <Factory7 /> <FactoryBase> <FactoryInputs> <Item> <Product>1010195</Product> <Amount>1</Amount> <StorageAmount>6</StorageAmount> </Item> <Item> <Product>1010229</Product> <Amount>1</Amount> <StorageAmount>3</StorageAmount> </Item> </FactoryInputs> <FactoryOutputs> <Item> <Product>1010217</Product> <Amount>1</Amount> <StorageAmount>4</StorageAmount> </Item> </FactoryOutputs> <CycleTime>45</CycleTime> </FactoryBase> <LogisticNode /> <AmbientMoodProvider /> <Maintenance> <Maintenances> <Item> <Product>1010017</Product> <Amount>40</Amount> <InactiveAmount>20</InactiveAmount> </Item> <Item> <Product>1010367</Product> <Amount>25</Amount> </Item> </Maintenances> </Maintenance> <Attackable /> <Pausable /> <IncidentInfectable /> <Industrializable> <BoostedByIndustrialization>0</BoostedByIndustrialization> </Industrializable> <Culture /> <QuestObject /> <Electrifiable /> </Values> </Asset>
Enlarge codebox

Take a look at the example again. You should pay close attention to Building, Maintenance, Object and FactoryBase Containers, you will most likely encounter them many times.
We now have a fully functional asset that we could add ingame, that Anno will interpret correctly.