Boolean Expression Tutorial
Some information about how to use the Boolean Expressions.
At the moment I write this there are 4 places you can use Boolean Expressions at:
- In the Active tag of property manipulators. They will only have an effect if the Active expression evaluates to true.
- NewCityFree tag in building info. If it evaluates to true when you found a new city, then that building will be added for free (if it can be constructed).
- ConstructCondition tag in building info. If it evaluates to false for a city, then that city won't be able to build that building.
- TrainCondition tag in unit info. Same as ConstructCondition except for units.
Boolean expressions can consist of several different tags of which many also have subexpressions.
Literal
If a tag expects a boolean expression, you can also simply use 0 for false or 1 for true similar to what simple boolean XML tags expect. So this is valid:
<NewCityFree>1</NewCityFree>
The building would always be free in a new city if it can be constructed at that time.
As you can now with all boolean XML tags you can also refer to a boolean global define:
<NewCityFree>BUILDING_X_FREE_IN_NEW_CITY</NewCityFree>
Has
The Has tag is one of the most common tags you will use with boolean expressions. It evaluates if the referenced game object modifier is on the object. Game object modifiers or short GOM are a lot of different things from promotion to religion:
- GOM_BUILDING
- GOM_PROMOTION
- GOM_TRAIT
- GOM_FEATURE
- GOM_OPTION
- GOM_TERRAIN
- GOM_GAMESPEED
- GOM_ROUTE
- GOM_BONUS
- GOM_UNITTYPE
- GOM_TECH
- GOM_CIVIC
- GOM_RELIGION
- GOM_CORPORATION
So to use the Has tag you first specify the type of the GOM and then the ID:
Code:
<NewCityFree>
<Has>
<GOMType>GOM_OPTION</GOMType>
<ID>GAMEOPTION_BUILDING_X_FREE</ID>
</Has>
</NewCityFree>
In this case the building would only be free in a new city if the game option GAMEOPTION_BUILDING_X_FREE is set.
The exact meaning of evaluating if a game object has a certain GOM depends on the GOM type and the game object type. GOM_RELIGION on a city evaluates if the city has the religion, on a player it evaluates if the religion is state religion of that player.
Is
The Is tag is somewhat similar to the Has tag but it doesn't check GOMs but some other states that a game object can have.
An easy example is to check if a game object is on water or next to a river:
Code:
<Active>
<Is>TAG_WATER</Is>
</Active>
Added to the propagators that spread water pollution they would only be active next to rivers or on water instead of spreading the water pollution deep into deserts.
And
The And tag can have any number of subexpressions and it will only evaluate to true if all subexpressions are true.
An example of an And with three subexpressions:
Code:
<ConstructCondition>
<And>
<Is>TAG_FRESH_WATER</Is>
<Has>
<GOMType>GOM_BONUS</GOMType>
<ID>BONUS_APPLE</ID>
</Has>
<Has>
<GOMType>GOM_CIVIC</GOMType>
<ID>CIVIC_FEUDAL</ID>
</Has>
</And>
</ConstructCondition>
So the city will only be able to build that building if it has fresh water, access to apples and its owner runs the feudal civic.
Or
Or is exactly the same as And, except that it is enough if one subexpression evaluates to true.
BEqual
That is short for boolean equal. It takes exactly two subexpressions and evaluates to true if both subexpressions evaluate to the same.
Example:
Code:
<ConstructCondition>
<BEqual>
<Is>TAG_FRESH_WATER</Is>
<Has>
<GOMType>GOM_BONUS</GOMType>
<ID>BONUS_APPLE</ID>
</Has>
</BEqual>
</ConstructCondition>
This building would only be constructable if the city either has fresh water and apples or neither has fresh water nor apples. If it has apples but no fresh water then it won't be able to build it. Ok, not a very meaningful example.
Not
This tag inverts the result of its one subexpression.
Code:
<ConstructCondition>
<Not>
<Has>
<GOMType>GOM_BONUS</GOMType>
<ID>BONUS_APPLE</ID>
</Has>
</Not>
</ConstructCondition>
This building can only be built if there is no access to apples.
If
If has three subexpressions (If Expression then Expression else Expression). The first one decides if the second (if true) or the third (if false) is used.
Code:
<NewCityFree>
<If>
<Has>
<GOMType>GOM_CIVIC</GOMType>
<ID>CIVIC_FEUDAL</ID>
</Has>
<Has>
<GOMType>GOM_FEATURE</GOMType>
<ID>FEATURE_FOREST</ID>
</Has>
<Has>
<GOMType>GOM_FEATURE</GOMType>
<ID>FEATURE_JUNGLE</ID>
</Has>
</If>
</NewCityFree>
If you are running feudal, then you need a forest near the new city to get it for free. Otherwise you need a jungle near it.
IntegrateOr
This tag allows you to query other game objects and if any of them evaluate the subexpression to true, then it will be true.
The way to describe the objects to query is the same as for property manipulators. So you first tell which relation to the primary game object these game objects have in the tag named RelationType. For that you can use these:
- RELATION_ASSOCIATED // owner, owned, ... depending on type
- RELATION_TRADE // trade routes, query from a city to cities
- RELATION_NEAR // needs iDistance tag to specify the distance
- RELATION_SAME_PLOT
- RELATION_WORKING // query plots from a city to get the plots belonging to the city and vice versa get the city to which the plot belongs
Then you specify the target object type, tag name GameObjectType. These are the game object types:
- GAMEOBJECT_GAME
- GAMEOBJECT_TEAM
- GAMEOBJECT_PLAYER
- GAMEOBJECT_CITY
- GAMEOBJECT_UNIT
- GAMEOBJECT_PLOT
Example:
Code:
<ConstructCondition>
<IntegrateOr>
<RelationType>RELATION_TRADE</RelationType>
<GameObjectType>GAMEOBJECT_CITY</GameObjectType>
<Has>
<GOMType>GOM_BUILDING</GOMType>
<ID>BUILDING_PALACE</ID>
</Has>
</IntegrateOr>
</ConstructCondition>
This building can only be built if the city has a trade route with a city that has a palace.