<text>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.</text>
<h>Introduction</h>
<text>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.</text>
<text>Here an example of a simple map script:</text>
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;
}</code>
<text>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.</text>
<h>Layers</h>
<part>
<text>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.</text>
<text>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.</text>
<text>For example, the following code:</text>
<code>var layer = CreateLayer("Earth");
layer->DrawCoal();
Blit(layer, [0,0,layer.Wdt/2,layer.Hgt]);</code>
<text>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.</text>
</part>
<h>Algorithms</h>
<part>
<text>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).</text>
<text>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.</text>
<text>For example, the following code would draw rectangles of earth in a checkerboard pattern:</text>
<text>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:</text>
<text>Modifier algorithms can also be applied to layer contents directly. For example, to flip the contents of the current map, one could write:</text>
<text>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.</text>
<text>Returns one if the point is on regular stripes and zero otherwise.</text>
<text>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.</text>
<text>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.</text>
<col>If nonzero, the offset map is generated from a fixed seed.</col>
</row><row>
<col>Amplitude</col>
<col>10</col>
<col>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.</col>
</row><row>
<col>Scale</col>
<col>10</col>
<col>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.</col>
</row><row>
<col>Iterations</col>
<col>2</col>
<col>Number of times each point is pushed around. The amplitude of the n'th successive push is reduced by 1/n.</col>
<text>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.</text>
<col>Algorithm of which the border is to be determined.</col>
</row><row>
<col>Wdt</col>
<col>1</col>
<col>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.</col>
</row><row>
<col>Left</col>
<col></col>
<col>Border width to the left side. Definition like Wdt. Falls back to Wdt if not specified.</col>
</row><row>
<col>Top</col>
<col></col>
<col>Border width upwards. Definition like Wdt. Falls back to Wdt if not specified.</col>
</row><row>
<col>Right</col>
<col></col>
<col>Border width to the right side. Definition like Wdt. Falls back to Wdt if not specified.</col>
</row><row>
<col>Bottom</col>
<col></col>
<col>Border width downwards. Definition like Wdt. Falls back to Wdt if not specified.</col>
<col>Operand algorithm that is being filtered.</col>
</row><row>
<col>Filter</col>
<col></col>
<col>Mask specification (see section "Material-texture masks" below)</col>
</row>
</table></text></part>
</part>
<h>Script function parameters</h>
<part>
Map drawing functions follow a common syntax for passing certain structures:
<h>Rectangles (array rect)</h>
<text>All rectangles are given in the format <code>[left, top, width, height]</code>, 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 (<code>[0,0,this.Wdt,this.Hgt]</code>).</text>
<col>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.</col>
<col>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.</col>
<col>True for the definition if overground (sky background) only.</col>
</row>
<row>
<col>&Definition</col>
<col>&Liquid</col>
<col>True for the definition if underground (tunnel background) only. The example would match all underground liquids.</col>
</row>
<row>
<col>~Definition</col>
<col>~^*</col>
<col>Inverts the definition, i.e. true only if the definition would originally be false. The example would match all underground materials.</col>
</row>
</table>
</text>
</part>
<h>Script functions</h>
<part>
<text>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).</text>
<text>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.</text>
<text>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.</text>
<text>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.</text>
<text><code>proplist CreateLayer(string mattex_fill, int width, int height);</code></text>
<text>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.</text>
<text><code>bool Resize(int new_width, int new_height);</code></text>
<text>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.</text>
<text>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.</text>
<text>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.</text>
<text>Returns the material-texture index of the given string. Can be either "Sky", "Transparent", a material name, or a material-texture combination.</text>
<text><code>int GetBackPixel(int x, int y);</code></text>
<text>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.</text>
<text><code>bool SetPixel(int x, int y, any new_fg, any new_bg);</code></text>
<text>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.</text>
<text>Returns number of pixels on this layer or map within rect that fulfill mask_spec.</text>
<text><code>bool FindPosition(proplist out_pos, mask_spec, array rect, int max_tries);</code></text>
<text>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.</text>