darkpanda
Dark Prince
- Joined
- Oct 28, 2007
- Messages
- 843
It took me a while, but I finally nailed it: by diving into CIV.EXE's internal workings (version EN 474.01), I eventually figured out the exact land value computation algorithm employed by CIV to assign values to map squares, in order for AI Civs to choose suitable locations for building cities.
Before going into the details, I want to, once again, express my grateful thanks to Gowron, without whom I would probably never have made it so far.
So, here it goes, in order to compute the land value of map squares, CIV processes as follows:
1. Terrain Type Score Calculation
For each terrain type, the score is calculated based on 2 sets of data:
The terrain production attributes are described by Gowron in this post, under title 4. Terrain Stats.
Basically, they control how each terrain type will generate food, shields and trade, as well as impede movement and benefit defense. CIV keeps different production attributes for normal terrain and for terrain with special resources.
Hereunder are the production attributes for all 24 terrain types in CIV (12 normal, 12 with special resource):
The terrain modification attributes are described by Gowron in this post, under title 5. Terrain Improvement.
They control the modification behaviour of a terrain type: how much food/shields does it provide if mined/irrigated, to which terrain type does it change if mined/irrigated, and additional AI-only data.
CIV only keeps 12 records for modification attributes, which are the same whether a terrain type has a special resource or not:
The score calculation is done as follows:
When applying this calculation formula to CIV's default terrain attributes, the scores obtained are as below:
The scores above are used when calculating the map squares' land value, as described in the next section.
2. Map Square Land Value Calculation
First of all, map squares for which the land value is calculated are in the range [2,2] - [77,47]. That is to say that the 4 rows of arctic and antarctic land (rows 0, 1, 48 and 49), as well as the 4 columns around the "TimeZone Meridian" (columns 0, 1, 78 and 79) have a land value of 0, whatever their type.
For each square within this range, the land value is calculated as follows (initial value is 0):
That's it!
This algorithm was reversed-engineered from CIV.EXE: after some debugging and fine-tuning, I have counter-tested it against a half-dozen random new CIV games, yielding a 100% success rate compared to Civ-calculated values.
If you have any problem implementing or applying it by yourself, or if you are not obtaining the expected values, please let me know, I may have misdescribed or missed some elements from the algorithm.
Obviously, my next step will be to implement it within JCivED
Before going into the details, I want to, once again, express my grateful thanks to Gowron, without whom I would probably never have made it so far.
So, here it goes, in order to compute the land value of map squares, CIV processes as follows:
- Compute a score for each terrain type, based on the terrain type characteristics; this score has a different value for normal terrain types and terrain types with special resources
- Compute the land value for each map square depending on the square's surrounding 'city squares'
1. Terrain Type Score Calculation
For each terrain type, the score is calculated based on 2 sets of data:
- Terrain production attributes
- Terrain modification attributes
The terrain production attributes are described by Gowron in this post, under title 4. Terrain Stats.
Basically, they control how each terrain type will generate food, shields and trade, as well as impede movement and benefit defense. CIV keeps different production attributes for normal terrain and for terrain with special resources.
Hereunder are the production attributes for all 24 terrain types in CIV (12 normal, 12 with special resource):
Name | Movement cost | Defense ratio | Food | Shields | Trade | unknown | ID |
Desert | 1 | 2 | 0 | 1 | 0 | 1 | 14 |
Plains | 1 | 2 | 1 | 1 | 0 | 1 | 6 |
Grassland | 1 | 2 | 2 | 1 | 0 | 1 | 10 |
Forest | 2 | 3 | 1 | 2 | 0 | 2 | 2 |
Hills | 2 | 4 | 1 | 0 | 0 | 2 | 12 |
Mountains | 3 | 6 | 0 | 1 | 0 | 3 | 13 |
Tundra | 1 | 2 | 1 | 0 | 0 | 0 | 7 |
Arctic | 2 | 2 | 0 | 0 | 0 | 0 | 15 |
Swamp | 2 | 3 | 1 | 0 | 0 | 0 | 3 |
Jungle | 2 | 3 | 1 | 0 | 0 | 0 | 11 |
Ocean | 1 | 2 | 1 | 0 | 2 | 0 | 1 |
River | 1 | 3 | 2 | 1 | 1 | 2 | 9 |
Oasis | 1 | 2 | 3 | 1 | 0 | 1 | 14 |
Horses | 1 | 2 | 1 | 3 | 0 | 1 | 6 |
Grassland special | 1 | 2 | 2 | 1 | 0 | 1 | 10 |
Game | 2 | 3 | 3 | 2 | 0 | 2 | 2 |
Coal | 2 | 4 | 1 | 2 | 0 | 2 | 12 |
Gold | 3 | 6 | 0 | 1 | 6 | 3 | 13 |
Game | 1 | 2 | 3 | 0 | 0 | 0 | 7 |
Seals | 2 | 2 | 2 | 0 | 0 | 0 | 15 |
Oil | 2 | 3 | 1 | 4 | 0 | 0 | 3 |
Gems | 2 | 3 | 1 | 0 | 4 | 0 | 11 |
Fish | 1 | 2 | 3 | 0 | 2 | 0 | 1 |
River special | 1 | 3 | 2 | 1 | 1 | 2 | 9 |
The terrain modification attributes are described by Gowron in this post, under title 5. Terrain Improvement.
They control the modification behaviour of a terrain type: how much food/shields does it provide if mined/irrigated, to which terrain type does it change if mined/irrigated, and additional AI-only data.
CIV only keeps 12 records for modification attributes, which are the same whether a terrain type has a special resource or not:
Name | Irrig. food bonus | Irrig. cost | Mining shield bonus | Mining cost | Can AI improve under Despotism/Anarchy? | Can AI improve under Monarchy or above? |
Desert | -2 | 5 | -2 | 5 | no | no |
Plains | -2 | 5 | 2 | 15 | yes | yes |
Grassland | -2 | 5 | 2 | 10 | no | yes |
Forest | 6 | 5 | -1 | 5 | no | no |
Hills | -2 | 10 | -4 | 10 | yes | yes |
Mountains | -1 | 0 | -2 | 10 | no | no |
Tundra | -1 | 0 | -1 | 0 | no | no |
Arctic | -1 | 0 | -1 | 0 | no | no |
Swamp | 10 | 15 | 2 | 15 | no | no |
Jungle | 10 | 15 | 2 | 15 | no | no |
Ocean | -1 | 0 | -1 | 0 | no | no |
River | -2 | 5 | -1 | 0 | no | yes |
The score calculation is done as follows:
- Initial score is trade + 3*food
- If the terrain is neither River nor Grassland, then add 2*shield to the score
- If the terrain has Mining shield bonus (<0), then add -(Mining shield bonus + 1) to the score
- ELSE If the terrain has Irrigation food bonus (<0), then add -2*(Irrigation food bonus + 1) to the score
When applying this calculation formula to CIV's default terrain attributes, the scores obtained are as below:
Name | trade + 3*food | +2*shield (0 if not applicable) | +mining bonus OR +2*irrig bonus | SCORE |
Desert | 0 | 2 | 1 | 3 |
Plains | 3 | 2 | 2 | 7 |
Grassland | 6 | 0 | 2 | 8 |
Forest | 3 | 4 | 0 | 7 |
Hills | 3 | 0 | 3 | 6 |
Mountains | 0 | 2 | 1 | 3 |
Tundra | 3 | 0 | 0 | 3 |
Arctic | 0 | 0 | 0 | 0 |
Swamp | 3 | 0 | 0 | 3 |
Jungle | 3 | 0 | 0 | 3 |
Ocean | 5 | 0 | 0 | 5 |
River | 7 | 0 | 0 | 7 |
Oasis | 9 | 2 | 1 | 12 |
Horses | 3 | 6 | 2 | 11 |
Grassland special | 6 | 0 | 2 | 8 |
Game | 9 | 4 | 0 | 13 |
Coal | 3 | 4 | 3 | 10 |
Gold | 6 | 2 | 1 | 9 |
Game | 9 | 0 | 0 | 9 |
Seals | 6 | 0 | 0 | 6 |
Oil | 3 | 8 | 0 | 11 |
Gems | 7 | 0 | 0 | 7 |
Fish | 11 | 0 | 0 | 11 |
River special | 7 | 0 | 0 | 7 |
The scores above are used when calculating the map squares' land value, as described in the next section.
2. Map Square Land Value Calculation
First of all, map squares for which the land value is calculated are in the range [2,2] - [77,47]. That is to say that the 4 rows of arctic and antarctic land (rows 0, 1, 48 and 49), as well as the 4 columns around the "TimeZone Meridian" (columns 0, 1, 78 and 79) have a land value of 0, whatever their type.
For each square within this range, the land value is calculated as follows (initial value is 0):
- If the square's terrain type is not Plains, Grassland or River, then its land value is 0
- Else, for each 'city square' neighbouring the map square (i.e. each square following the city area pattern, including the map square itself, so totally 21 'neighbours'), compute the following neighbour value(initially 0):
- If the neighbour square type is Grassland special or River special, add 2, then add the non-special Grassland or River terrain type score to the neighbour value
- Else add neighbour's terrain type score to the neighbour value
- If the neighbour square is in the map square inner circle, i.e. one of the 8 neighbours immediatly surrounding the map square, then multiply the neighbour value by 2
- If the neighbour square is the North square (relative offset 0,-1), then multiply the neighbour value by 2 ; note: I actually think that this is a bug, and that the intention was rather to multiply by 2 if the 'neighbour' was the central map square itself... the actual CIV code for this is to check if the 'neighbour index' is '0'; the neighbour index is used to retrieve the neighbour's relative offset coordinates (x,y) from the central square, and the central square itself is actually the last in the list (index 20), the first one (index 0) being the North neighbour; another '7x7 neighbour pattern' table found in CIV code does indeed set the central square at index 0, and this why I believe ths is a programmer's mistake...
- Add the neighbour's value to the map square total value and loop to next neighbour
- After all neighbours are processed, if the central map square's terrain type is non-special Grassland or River, subtract 16 from total land value
- Substract 120 (0x78) from the total land value, and remember its sign
- Set the land value to the absolute land value (i.e. negate it if it is negative)
- Divide the land value by 8
- If the land value was negative 3 steps before, then negate the land value and add 1, i.e. value = 1-value
- Adjust the land value to the range [1..15]
- Divide the land value by 2
- And finally, add 8 to the land value
That's it!
This algorithm was reversed-engineered from CIV.EXE: after some debugging and fine-tuning, I have counter-tested it against a half-dozen random new CIV games, yielding a 100% success rate compared to Civ-calculated values.
If you have any problem implementing or applying it by yourself, or if you are not obtaining the expected values, please let me know, I may have misdescribed or missed some elements from the algorithm.
Obviously, my next step will be to implement it within JCivED

Last edited: