Sam Trenholme's webpage
Support this website or listen to my music

Civ4 Map Script API reference

Part 2: Drawing the map

This is based on looking at the source code to Totestra.

Once getGridSize() is called, the random map generator has all of the information it needs to generate a map. The subsequent functions are used strictly to give to Civilization 4 the information about the generated map.

They are:

getTopLatitude(): Input: none. Output: An integer between -90 and 90. Does not appear to affect gameplay, but the higher this value is to 90, the more likely trees near the north of the map will be drawn with snow on them. Value needs to be higher than getBottomLatitude().

getBottomLatitude(): Input: none. Output: An integer between -90 and 90. Does not appear to affect gameplay, but the lower this number is, the more likely trees near the south of the map will be drawn with snow on them. Value needs to be lower than getTopLatitude().

To be pedantic: we can have getTopLatitude() return, say, -89, and getBottomLatitude() return, say, -90, and have maps with lots of snowy trees on them. Civ4, presumably, calculates the latitude of each horizontal line in the map based on these two values and performing interpolation; the higher the absolute value for a given line based on this calculation determines how frequently we have snowy trees.

getWrapX(): Input: None. Output: True if the map wraps on the X axis, otherwise false. A flat map would have "False" here; a cylindrical or toric map would have "True" here.

getWrapY(): Input: None. Output: True if the map wraps on the Y axis, otherwise false. A non-toric map would usually have "False" here; a toric map would have "True" here. Note that this should be set to "False" for maps played in vanilla Civ4 or in Civ4 Warlords; the rendering of toric maps was buggy until Beyond the Sword.

beforeGeneration(): A map script can safely function without this call

The following functions return one-dimensional arrays the correspond to the Civ4 map thusly:

The one-dimensional array starts in the lower left corner of the map, and goes left to right, bottom to top. For example, the point on the lower left of a 144x96 map will be the first element of the array (which is index number 0 because Python uses 0-indexed arrays). The point to the right of that will be the second element (element #1), and element #144 (the 145th element) will be the point directly above the lower left corner of the map.

In a 5x10 map (not that a map script can actually make a 5x10 map, but humor me), it goes like this:

40 41 42 43 44 45 46 47 48 49
30 31 32 33 34 35 36 37 38 39
20 21 22 23 24 25 26 27 28 29
10 11 12 13 14 15 16 17 18 19
 0  1  2  3  4  5  6  7  8  9
generatePlotTypes(): Input: None. Output: A flat one-dimensional array of "plot types". A single plot type can have one of four possible values:
    CvPythonExtensions.PlotTypes.PLOT_OCEAN
    CvPythonExtensions.PlotTypes.PLOT_LAND
    CvPythonExtensions.PlotTypes.PLOT_HILLS
    CvPythonExtensions.PlotTypes.PLOT_PEAK
generateTerrainTypes(): Input. None. Output: A flat one-dimensional array of integers. The values are 0: Grass 1: Plains 2: Desert 3: Tundra 4: Snow 5: Coast 6: Ocean 7: Peak 8: Hill.

addRivers(): Input: None. Output: None.

Rivers are placed between squares. To add a river to a given square (x, y) on the map, do something like this:

foo = CyGlobalContext()
bar = foo.getMap()
baz = bar.plot(x, y)
And then one or more of:
baz.setWOfRiver(True,CardinalDirectionTypes.CARDINALDIRECTION_SOUTH)
baz.setNOfRiver(True,CardinalDirectionTypes.CARDINALDIRECTION_EAST)
baz.setWOfRiver(True,CardinalDirectionTypes.CARDINALDIRECTION_NORTH)
baz.setNOfRiver(True,CardinalDirectionTypes.CARDINALDIRECTION_WEST)

The second argument determines which direction the river flows.

addLakes(): Input: None. Output: None.

To add a lake to the map at point (x,y), do something like this:

foo = CyGlobalContext()
bar = foo.getMap()
baz = bar.plot(x, y)
baz.setTerrainType(5, True, True)
5 corresponds to a "coast" (shallow water) terrain type.

addFeatures(): Input: None. Output: None.

This is one place where we can add forests, jungles, ice, oasis, and flood plains. To put an oasis at point (x,y), do something like:

foo = CyGlobalContext()
bar = foo.getMap()
baz = bar.plot(x, y)
baz.setFeatureType(2,0)

Possible values to give setFeatureType():

    (0,0) Ice
    (1,0) Jungle
    (2,0) Oasis
    (3,0) Flood plains
    (4,0) Leafy forest
    (4,1) Evergreen forest
    (4,2) Snowy forest

addBonuses(): Input: None. Output: None.

This is one possible place to add bonuses (resources).

To put a bonus (resource) at point (x,y), do something like:

foo = CyGlobalContext()
bar = foo.getMap()
baz = bar.plot(x, y)
count = foo.getNumBonusInfos()
if count > 0:
    baz.setBonusType(0)

isBonusIgnoreLatitude(): A map script can safely run without declaring this function

addGoodies(): This adds huts to the map. If this is not defined, default huts are added. If it is defined, it can be used to add huts, or to disable huts being added (by simply returning without doing anything)

afterGeneration(): A map script can safely run without declaring this function

minStartingDistanceModifier(): A map script can safely run without declaring this function

assignStartingPlots(): Input: None. Output: None.

To make a given square a given player's starting plot, where (x, y) is where they will start and playerNum is the number for this player:

foo = CyGlobalContext()
bar = foo.getMap()
baz = bar.plot(x, y)
boo = foo.getPlayer(playerNum)
boo.setStartingPlot(baz, true)
The "normalize" functions are not used by Totestra:
def normalizeAddRiver():
    return
def normalizeAddLakes():
    return
def normalizeAddGoodTerrain():
    return
def normalizeRemoveBadTerrain():
    return
def normalizeRemoveBadFeatures():
    return
def normalizeAddFoodBonuses():
    return
def normalizeAddExtras():
    return
def normalizeRemovePeaks():
    return

Support

Support for this reference is available here:
http://forums.civfanatics.com/showthread.php?p=11624647

See also