Map script

Map scripts provide a powerful method to generate diverse, dynamic maps with just a few lines of simple script code. Map scripts can be used to generate new maps, as well as modify existing maps defined as static Map.bmp or dynamic Landscape.txt.

Introduction

A map script is simply a script file called Map.c placed in a scenario. On scenario initialization, the engine calls the local function called InitializeMap in this script. If the function returns true, the map will be used by the engine. If false is returned, the map is discarded and the regular fallback map is created.
Here an example of a simple map script:
/* A simple map */

#include Library_Map

func InitializeMap(proplist map)
{
	// Create a big map
	Resize(150,150);
	// Draw earth
	DrawRegularGround();
	// Draw some resources into the ground
	DrawWaterVeins(3, [0,map.Hgt/3,map.Wdt,map.Hgt*2/3]);
	DrawCoal(6);
	DrawFirestone(4);
	DrawRock(15);
	DrawOre(4);
	DrawGold(2*GetStartupPlayerCount()); // amount of gold depends on player count!
	// Make sure liquids don't border tunnel or sky sideways
	FixLiquidBorders();
	// Done. Use this map.
	return true;
}
This draws a pretty boring standard map with basic resources. It makes use of some high-level helper functions such as DrawRegularGround or DrawCoal. which are included in the definition named Library_Map in Objects.ocd/Libraries.ocd. All map scripts should include this definition.

Layers

All map draw functions work on layers, which are simply 8 bit image surfaces. The map itself is a layer, but additional layers can be created as temporary buffers using the CreateLayer or Duplicate script functions. Additional layers are bound to the map they were created from and destroyed alongside with it when map drawing is complete.
In C4Script, map layers are represented as prop lists. They have the implicit properties Wdt and Hgt, which contain the width and height of the surface respectively. To resize a map or layer, use the Resize() function. Do not modify Wdt or Hgt directly.
For example, the following code:
var layer = CreateLayer("Earth");
layer->DrawCoal();
Blit(layer, [0,0,layer.Wdt/2,layer.Hgt]);
would create a secondary layer filled with earth. It would then draw coal onto the layer and finally copy only the left half of its contents to the main map.

Algorithms

Algorithms are the core concept of dynamic map creation to point drawing operations to specific subregions of the map only. An algorithm is a function that maps a position (int x, int y) to either a pixel color (int) or a mask value (bool).
Algorithms are defined as prop list with the Algo property set to one of the MAPALGO_* constants and additional algorithm parameters set as properties. They can then be passed to one of the drawing functions (Draw or Blit), which will evaluate the algorithm at all positions and draw pixel values accordingly.
For example, the following code would draw rectangles of earth in a checkerboard pattern:
Draw("Earth", {Algo=MAPALGO_RndChecker, Wdt=5, Hgt=5});
You can also set the material within the algorithm via the Material property. In that case, Blit has to be used for drawing. It is thus possible to use multiple materials within one Blit call.
Blit({Material="Earth", Algo=MAPALGO_RndChecker, Wdt=5, Hgt=5});
In addition to pattern-generating algorithms, there are also modifier algorithms that take other algorithms as parameters. For example, the Turbulence algorithm jumbles all pixels of the underlying algorithm around to create a noisy pattern:
var checkerboard = {Algo=MAPALGO_RndChecker, Wdt=10, Hgt=10};
var jumbled_checkerboard = {Algo=MAPALGO_Turbulence, Amplitude=10, Scale=10, Op=checkerboard};
Draw("Earth", jumbled_checkerboard);
Modifier algorithms can also be applied to layer contents directly. For example, to flip the contents of the current map, one could write:
// Backup contents of current map
var copy_layer = Duplicate();
// Redraw flipped horizontally
Blit({Algo=MAPALGO_Scale, OffX=Wdt/2, X=-100, Op=copy_layer});
Note: If you are using the target layer in a drawing command, always draw from a copy. Otherwise, the result is undefined.
Algorithms like MAPALGO_Or can be used to combine multiple algorithms. If different materials are set at different pixels of the operands, they will be preserved. The material can also be set later within a such a combination, which overrides the materials of the operands (in case they have been set.)
// Draws two gold rectangles
Blit({Material="Gold", Algo=MAPALGO_Or, Op=[
	{Algo=MAPALGO_Rect, X=5, Y=0, Wdt=10, Hgt=10},
	{Algo=MAPALGO_Rect, X=20, Y=0, Wdt=10, Hgt=10}
]});
// Draws a gold and an earth rectangle
Blit({Algo=MAPALGO_Or, Op=[
	{Material="Gold", Algo=MAPALGO_Rect, X=5, Y=0, Wdt=10, Hgt=10},
	{Material="Earth", Algo=MAPALGO_Rect, X=20, Y=0, Wdt=10, Hgt=10}
]});

MAPALGO_Layer

Returns the pixel value at the x,y position of the given layer. Instead of passing a MAPALGO_Layer prop list, layers can also be passed directly as algorithms.
Parameter Default Meaning
Layer The layer from which pixel values are taken.

MAPALGO_RndChecker

Returns values from a checkerboard pattern of rectangles that are filled with ones or zeros.
Parameter Default Meaning
Seed Random(65536) If nonzero, the checkerboard pattern is generated from a fixed seed.
Ratio 50 Percentage of checkerboard fields that are one.
Wdt 10 Width of rectangles.
Hgt 10 Height of rectangles
FixedOffset false If true, the pattern always starts at position (0,0). Otherwise, it is offset by a random phase.

MAPALGO_Rect

Returns one if the position is in a given rectangle and zero otherwise.
Parameter Default Meaning
X 0 Left side of rectangle (pixel is included).
Y 0 Top side of rectangle (pixel is included).
Wdt 0 Width of rectangle.
Hgt 0 Height of rectangle.

MAPALGO_Ellipse

Returns one if the position is in a given ellipse and zero otherwise.
Note: For compatibility reasons, the misspelling "MAPALGO_Ellipsis" is also accepted.
Parameter Default Meaning
X 0 Horizontal center of ellipse.
Y 0 Vertical center of ellipse.
Wdt 10 Horizontal radius of ellipse.
Hgt 10 Vertical radius of ellipse

MAPALGO_Polygon

Returns one if the position is in a given polygon or on its border and zero otherwise.
Parameter Default Meaning
X Array of x coordinates of polygon points.
Y Array of y coordinates of polygon points.
Wdt 1 Width of border lines of polygon.
Empty false If true, the polygon is not filled and only the border is drawn.
Open false If true, the last segment of the polygon is not drawn. Useful to draw lines. Only valid if Empty is true.

MAPALGO_Lines

Returns one if the point is on regular stripes and zero otherwise.
Vector (X,Y) determines both width and direction of the stripes. So, for instance, if you want to draw vertical stripes of 10 pixels width and a gap of 5 pixels between them, you would set X=10, Y=0, Distance=15.
Parameter Default Meaning
X 0 X size of vector that points perpendicular to stripes.
Y 0 Y size of vector that points perpendicular to stripes.
OffX 0 Offset of stripes. If unspecified, stripes begin at (0,0).
OffY 0 Offset of stripes.
Distance 2*Sqrt(X*X+Y*Y) Distance between two stripes. Includes the stripe width!

MAPALGO_And

Returns zero if any of the operands is zero. Otherwise, returns the value of the last operand. If there are zero operands, always returns zero.
Parameter Default Meaning
Op Array of algorithms that are tested.

MAPALGO_Or

Returns the first operand that is nonzero. If all operands are zero, returns zero. If there are zero operands, always returns zero.
Parameter Default Meaning
Op Array of algorithms that are tested.

MAPALGO_Not

Returns one if the operand is zero. Returns zero otherwise.
Parameter Default Meaning
Op Algorithms that is negated.

MAPALGO_Xor

If exactly one of the two operands is nonzero, returns that operand. Otherwise, returns zero.
Parameter Default Meaning
Op Array of two algorithms that are tested.

MAPALGO_Offset

Moves its operand by an offset.
Parameter Default Meaning
Op Algorithms that is being manipulated.
OffX 0 Horizontal offset to the right.
OffY Vertical offset downwards.

MAPALGO_Scale

Scales its operand by a point.
Parameter Default Meaning
Op Algorithms that is being manipulated.
X 100 Horizontal scaling in percent. Values smaller than zero flip the operand horizontally.
Y 100 Vertical scaling in percent. Values smaller than zero flip the operand vertically.
OffX 0 X position of fixed point that remains in position. Actual fixed point is translated left by -0.5 pixels to achieve proper pixel mapping.
OffY 0 Y position of fixed point that remains in position. Actual fixed point is translated up by -0.5 pixels to achieve proper pixel mapping.

MAPALGO_Rotate

Rotates its operand around a point.
Parameter Default Meaning
Op Algorithms that is being manipulated.
R 0 Rotation angle in degrees (0 to 360). Positive values rotate counter-clockwise.
OffX 0 X position of fixed point that remains in position.
OffY 0 Y position of fixed point that remains in position.

MAPALGO_Turbulence

Jumbles its operand around by moving points by a randomized offset.
Parameter Default Meaning
Op Algorithms that is being manipulated.
Seed Random(65536) If nonzero, the offset map is generated from a fixed seed.
Amplitude 10 Maximum range by which pixels may be moved in a single step. Movement in any direction is half of the amplitude. Can be an single integer for equal movement in both dimensions or an array of two integers for separate amplitudes for horizontal and vertical movement.
Scale 10 Distance of points for which the amplitude is randomized. A large scale relative to the amplitude creates more broadly scaled, regular turbulence, while a small scale can cause borders to look more jumpey. Can be an single integer for equal scale in both dimensions or an array of two integers for separate scales horizontally and vertically.
Iterations 2 Number of times each point is pushed around. The amplitude of the n'th successive push is reduced by 1/n.

MAPALGO_Border

Returns true for positions that lie on an inner or outer border of an operand. An inner border is defined as a position where the operand is nonzero and a position where it is zero lies within inner border width range. An outer border is defined as a position where the operand is zero and a position where it is nonzero lies within outer border width range. Note that borders are only searched in four directions (left, right, upwards, downwards) and not diagonally. This means that for a square, outer borders to not catch the corners.
Parameter Default Meaning
Op Algorithm of which the border is to be determined.
Wdt 1 Border width in all directions. Positive integer for inner border; negative integer for outer border. Can also be an array of two integers of opposing signs for inner and outer borders.
Left Border width to the left side. Definition like Wdt. Falls back to Wdt if not specified.
Top Border width upwards. Definition like Wdt. Falls back to Wdt if not specified.
Right Border width to the right side. Definition like Wdt. Falls back to Wdt if not specified.
Bottom Border width downwards. Definition like Wdt. Falls back to Wdt if not specified.

MAPALGO_Filter

Return only pixel values of the operand that match the mask specification. Returns zero for other pixels.
Parameter Default Meaning
Op Operand algorithm that is being filtered.
Filter Mask specification (see section "Material-texture masks" below)

Script function parameters

Map drawing functions follow a common syntax for passing certain structures:

Rectangles (array rect)

All rectangles are given in the format [left, top, width, height], where the left and top pixel rows are included and left+width and top+height pixel rows are excluded. Unless otherwise specified, rect can always be nil, in which case the area defaults to the whole map or layer ([0,0,this.Wdt,this.Hgt]).

Material-texture definitions (string mattex)

When a material is specified for the drawing functions, the following definitions are valid:
String Example Meaning
Material Earth Draws the given material in its default texture as underground (tunnel background) material.
Material-Texture Earth-earth_topSoil Draws the given material with the given texture as underground material.
^Material ^Water Draws the given material with its default texture as overground (sky background) material.
^Material-Texture ^Earth-earth_rough Draws the given material with the given texture as overground material.
Sky Sky Draws a sky material. Within the map generator, explicit sky is drawn as index 0xff, which is converted to index zero on map drawing. That way, sky can be blitted to other layers without being transparent.
Transparent Transparent Draws with index 0.
FgMatTex:BgMatTex Water:Tunnel-brickback Draws with a specified background material. In the example, draws water which, when drained, exposes bricks instead of tunnel behind it. FgMatTex and BgMatTex can be any of the other specifications in this table, except the ones prefixed with ^. However, the specification FgMatTex:Sky is equivalent to ^FgMatTex.

Material-texture masks (string mask_spec)

When a material is specified as a masking function, the following definitions are valid:
String Example Meaning
Material Earth True for given material with any texture and any (sky or tunnel) background.
Material-Texture Earth-earth_topSoil True for the given material with the given texture and any (sky or tunnel) background.
Sky Sky True for explicit sky material (0xff) only. Not true for transaprent (0) pixels.
Transparent Transparent True for transparent pixels (index 0) only.
Background Background True for all background materials (e.g. Tunnel, BrickBack and Sky).
Liquid Liquid True for all liquids (e.g. Water, Acid, Lava and DuroLava).
Solid Solid True for solid materials (e.g. Earth, Rock, Brick, etc.).
* * True for all materials, including sky.
^Definition ^Rock-rock_cracked True for the definition if overground (sky background) only.
&Definition &Liquid True for the definition if underground (tunnel background) only. The example would match all underground liquids.
~Definition ~^* Inverts the definition, i.e. true only if the definition would originally be false. The example would match all underground materials.

Script functions

All drawing functions are defined in the MapLayer static prop list. Because the Map.c script file is also evaluated in this context with the current map as this pointer, all drawing functions can be called directly by name in that script (e.g.: Resize(150,150)). In other script contexts or if the function is to be executed on a layer instead of on the main map, the base object must be given explicitely (e.g.: map->Resize(150,150), where map is the parameter passed to InitializeMap).
Because layers derive from the MapLayer prop list, all script functions defined in the Map.c and included script files are also available on any layer.

Internal engine functions

bool Draw(string mattex, proplist mask_algo, array rect);
Draws the material given by mattex on all pixels within rect if the algorithm given by mask_algo returns a value other than zero. Returns true on success.
bool Blit(proplist mask_algo, array rect);
Same as draw, but draws the result of evaluation of mask_algo directly instead of a material given by mattex. Because mask_algo can also be a layer, this function can be used to copy layer contents onto other layers or the map. If mask_algo evaluates to zero, nothing is drawn and the original pixel value is kept.
proplist CreateLayer(string mattex_fill, int width, int height);
Creates a new layer of size width,height. If no size is given, the layer is created in the same size as the calling context layer or map. The new layer is filled with the pixel color given by mattex_fill, or with zeroes if mattex_fill is nil. Returns the newly created layer.
bool Resize(int new_width, int new_height);
Recreates the calling layer or map surface in the given size. All contents are deleted and the layer is filled with zeroes. Use functions Duplicate and Blit to backup and restore any old layer contents if you want to extent the map without losing its contents. Returns true on success.
proplist Duplicate(any mask_spec, array rect);
Creates a new layer with the same size and surface contents as this layer. If a rect is given, the new layer is smaller and contains only the portion included in rect. If mask_spec is given, only pixels passing the mask are set and all other pixels in the new layer are zero.
int GetDefaultBackgroundIndex(any col);
Returns the material-texture index of the default background color of the given color. It may be given either as string (mattex) or palette index.
int GetMaterialTextureIndex(string mattex);
Returns the material-texture index of the given string. Can be either "Sky", "Transparent", a material name, or a material-texture combination.
int GetPixel(int x, int y);
Gets the pixel color at the given position in this layer. If x,y is outside the layer, zero is returned.
int GetBackPixel(int x, int y);
Gets the pixel color of the background material at the given position in this layer. If x,y is outside the layer, zero is returned.
bool SetPixel(int x, int y, any new_fg, any new_bg);
Sets the pixel and the background pixel at position x,y in this layer to new_fg and new_bg, respectively. Color may be given as string (mattex) or palette index. Use nil to keep foreground or background unchanged. Returns true on success.
int GetPixelCount(any mask_spec, array rect);
Returns number of pixels on this layer or map within rect that fulfill mask_spec.
bool FindPosition(proplist out_pos, mask_spec, array rect, int max_tries);
Tries to find a position on this layer for which the pixel color matches mask_spec. If a position is found, true is returned and the position is set as X and Y parameters in the out_pos prop list. If no position is found after max_tries, the function will walk through all pixels of the layer starting from a random starting position to find a point. If still no position is found, false is returned and out_pos is not changed. max_tries defaults to 500.
array CreateMatTexMask(any mask_spec);
Returns mask_spec as an array of 256 bools to be used e.g. in conjunction with the return value of GetPixel.
Sven2, 2013-03