|Version 21 (modified by FeXoR, 13 months ago) (diff)|
Table of Contents
- Map Coordinate System
- Accessing Map Data Directly
- Placing Terrain: Areas
- Placing Units: Object Groups
- Grouping Similar Features: Tile Classes
- Controlling Placement: Constraints
- Placing walls
- Map Helpers
- Environment Helpers
- Miscellaneous Helpers
- Random Biome System
- Other Helpers
- Script Library
Rmgen is the name of the default script library included with the random map generator. This document describes how to use it.
Map Coordinate System
The rmgen libs use a 2D coordinate system, the standard X/Y plane despite many functions use the letter Z instead of Y (leavings of the originally used 3D behavior). Positive X is left, positive Y is top when the map is not rotated. Coordinate 0/0 is bottom left on the map. The Z coordinate is set automatically and cannot be set otherwise. Angle 0 means facing positive X, raising it means counter clockwise rotation so for example PI/2 means facing top. To simplify terrain texture placement the axis (including height) are scaled to tiles with a tile granting the space used to place a terrain texture (One tile = 4.0 model-space units that are used in the engine). While placing a terrain texture is only allowed on a tile (defined by integer coordinates) entities for example can be placed anywhere on the map (float coordinates). Note that a terrain texture on 0/0 is placed on the square from 0/0 to 1/1 so an entity placed at 0.5/0.5 would be in the middle of that terrain texture. Before the random map is saved the coordinates and angles are converted to the 3D behavior of the engine (see getMapData in map.js).
The concept of terrains in rmgen is more than just textures that are painted onto a tile. As part of the terrain, a tile can also have objects on it that are "attached" to the terrain and hence removed when the tile is painted with a different terrain (for example, if you paint a forest and then paint a patch of desert inside of it, there will be no trees on the desert). Furthermore, API functions that require terrains can also take a number of complex objects that might paint different tiles with different textures but still make up one type of "logical terrain" (for example, something that paints mixed types of dirt for variation). The following ways of specifying a terrain are available:
- Specify a texture name. Valid textures are dds files which can be found in /art/textures/terrain/types/. One example of such a texture is "medit_grass_field_dry" from the Mediterranean biome.
- Specify a texture name and tree type to paint a forest. Tree types are specified in xml files in /simulation/templates/gaia. The texture and tree are combined one string, separate by a pipe character "|". For example, use "medit_grass_wild|gaia/flora_tree_euro_beech" to paint Mediterranean wild grass and beech trees.
- Specify an array with any combination of the above methods, which will be randomly chosen for each tile. For example, ["medit_grass_wild|gaia/flora_tree_euro_beech", "medit_grass_field_dry"] would paint either grassy forest or a dry field.
TODO: Later it should be possible to provide custom JS terrain objects as well.
Accessing Map Data Directly
The lowest-level way to create a map is to set terrain and elevation for each tile specifically and place objects individually. Although this is often not what you'll want to use for ease-of-use reasons, there might be cases (such as non-standard gameplay maps) where you might want to do something not possible with the higher-level API. Thus, the API provides functions that give complete control over the map to allow this:
- placeTerrain(x, z, terrain): Manually set the terrain for tile (x,z).
- placeObject(x, z, type, player, angle): Manually place object of given type, player, and angle on tile (x,z).
- setHeight(x, z, height): Manually set the terrain height for tile (x,z).
- getHeight(x, z): Returns height of tile (x,z).
- getTerrainTexture(x, y): Returns terrain texture of tile (x,z).
Note: By default the height map refers to the corners of the terrain grid, so is one unit larger in both directions. Setting TILE_CENTERED_HEIGHT_MAP = true; makes the height map define the height of the centres of each terrain grid square (interpolated to the corners at the export stage).
Placing Terrain: Areas
The core concept of terrain placement is that of areas. An area is a set of tiles of related terrain that constitutes a feature of the map, such as a body of water, a forest, etc. Once you have placed areas, you can also refer to them to control placement of other areas or objects; for example, place gold mines only on dirt patch areas, place fish only on water areas, or make forests avoid player base areas.
An area is created in three steps:
- Choose the shape of the area, by specifying an object called an area placer.
- Choose how to fill in the area, by specifying an area painter. An area can also be painted with multiple painters in sequence by specifying an array of area painters as the painter argument; for example, specify [new TerrainPainter("medit_grass_field_a"), new ElevationPainter(4.0)] to paint an area with grassy field and also raise it to height 4.
- (Optional) Choose constraints on where the area can be placed; for example, make it avoid specific areas or types of terrain. (Multiple constraints can also be passed as an array.)
The reason we separate area placement (choosing the tiles which the area will occupy) from area painting (setting terrain and elevation on those tiles) is that we might want to use the same painting algorithm for a bunch of areas of different shapes, or alternatively use the same placement algorithm but paint similarly-shaped areas, created in different ways. Instead of trying to handle all possible combinations of shapes and paints in one parameter, we separate it into two. We also separate out constraints because the same type of constraint might be required on several different areas (for example, both mountains and forests should avoid the water body on the Mediterranean map). We will see below that constraints are also used for object placement.
This section will talk about area placers and painters; full information on constraints can be found in the Constraints section below.
Creating a single area
The simplest way to create an area is using the createArea(placer, painter, constraint) function. This takes a given placer object and tries to place the area within the given constraint. If it succeeds, it paints the area and returns the area object. If it fails, it returns undefined and does not change any terrain. (You can check for failure with if(createArea(...) === undefined)).
Creating multiple areas at random locations
For many areas, you do not want to specify an exact location for the area placer, you just want to place it at a random place that satisfies the constraint you provide. You might also want to create several similar areas using the same placer and painter but in different locations within the same constraints. Thus, the most common way to place areas is using the createAreas(centeredPlacer, painter, constraint, number, retryFactor) function. This takes 5 parameters:
- centeredPlacer: This must be a special kind of placer which supports having a center location specified, called a "centered placer" (specifically, anything that has "x" and "z" fields). Many types of placers can do this, although a few, like RectPlacer?, can only be used through createArea.
- painter: A painter object.
- constraint: A constraint object. Note that if multiple areas are to be placed, each area will take into account previously placed ones when evaluating the constraint. For example, you can use createAreas to place a group of forests that avoid each other.
- number: The number of areas to create.
- retryFactor: A number that specifies how many times to try placing an area before stopping. The createAreas function will then repeatedly try placing areas at random locations. For example, if you want to create 10 areas and choose a retry factor of 5, there will be at most 50 attempts to create the areas.
It returns an array of the areas placed (or an empty array if none).
The following area placers are available. Centered placers can be used with createAreas. Note that most objects have editable fields of the same names as its constructor parameters after you construct it.
- ClumpPlacer(size, coherence, smoothness, x, z): Places an irregular "clump" or "blob" of terrain at a specified point (or could be placed at a random point with createAreas. The parameters mean the following:
- size: The average number of tiles in the clump. Individual clumps may have more or fewer.
- coherence: A value from 0.0 to 1.0 saying how much the radius of the clump varies, that is, how close the clump is in shape to a perfect circle. Coherence of 1.0 means a perfect circle (constant radius), while 0.0 means wild variations in radius.
- smoothness: A value from 0.0 to 1.0 saying how smooth the border of the clump is, that is, approximately how many "peaks" and "valleys" stick out from the clump (between these the border is a smooth curve). 1.0 will have 2 or 3 "peaks" while 0.0 will have features the size of a single tile. Use high smoothness for areas like seas, cliffs and lakes, and low smoothness for areas like forests.
- x, z: Optional tile coordinates of placer.
- PathPlacer(x1, z1, x2, z2, width, waviness, smoothness, offset, taper): Places a wavy path of terrain between two points. The parameters mean the following:
- x1, z1: Coordinates of the starting point.
- x2, z2: Coordinates of the ending point.
- width: Width of the path
- waviness: How wavy the path will be (higher is wavier, 0.0 is straight line)
- smoothness: How smooth the path will be (higher is smoother)
- offset: Max amplitude of waves along the path (0.0 is straight line)
- taper: How much the width of the path changes from start to end. If positive, the width will decrease by that factor, if negative the width will increase by that factor.
- RectPlacer(x1, z1, x2, z2): Places a grid-aligned rectangle from (x1,z1) to (x2,z2), where x1 < x2 and z1 < z2. Not usable with createAreas since it's not a centered placer.
The following area painters are available. Remember that terrains can be any of the objects in the "A Note on Terrains" section above.
An area can also be painted with multiple painters in sequence by specifying an array of area painters as the painter argument. For example, specify [new TerrainPainter("snow"), new ElevationPainter(4.0)] to paint an area with snow and also raise it to height 4.
- TerrainPainter(terrain): Fills an entire area with a single terrain.
- ElevationPainter(elevation): Sets an entire area to a single elevation.
- LayeredPainter(terrains, widths): Fills different tiles of an area with different terrains based on distance from its border. This can be used to paint water bodies with shorelines or dirt patches with smooth transition from grass, for example. There can be multiple "layers" from the border inwards of different terrains, and there must also be a central terrain with which tiles farther than all the borders can be filled. The widths array should contain the widths of the layers in order from the outside in, while the terrains array should contain the widths.length border terrains and finally the central terrain (hence, widths.length+1 total elements). For example, new LayeredPainter(["medit_dirt_c","medit_dirt_b","medit_dirt"], [1, 1]) will create a patch of "medit_dirt" terrain that will be surrounded by a 1-tile layer of "medit_dirt_b" and right outside that a 1-tile layer of "medit_dirt_c"; this will look nicer than placing "grass dirt 75" directly onto a field of grass.
- SmoothElevationPainter(type, elevation, blendRadius): Smoothly alters elevation for an area. It can do this in different ways depending on the type parameter. In both cases, the change happens gradually; points at the edge of the area are not affected, while only points above blendRadius distance from the edge will get the full effect; thus, use the blendRadius parameter to set how "steep" the sides of the area will be. There are currently two modes supported:
- If the type is set to ELEVATION_SET, it raises/lowers all tiles in the area towards the specified elevation. This is probably the most common usage.
- If the type is set to ELEVATION_MODIFY, it raises/lowers all tiles in the area by the specified amount (for example, elevation = 2 would increase them by 2 and elevation = -3 would lower them by 3).
Placing Units: Object Groups
An object or entity is the game's representation of various units, buildings, and props that occur on a map. You can place objects in a similar way to painting terrains by using object groups. An object group is one or more types of objects which can be placed according to an optional constraint. This process is analogous to creating an area, but it doesn't modify the terrain.
Currently there is one way to specify a type of object, SimpleObject(type, minCount, maxCount, minDistance, maxDistance, minAngle, maxAngle):
- type: This is the name of an entity's XML file, which can be found under /simulation/templates/. An example type of entity is "/structures/hele_civil_centre". Note that entities are often prefixed with a civilization identifier.
- minCount, maxCount: The number of objects to place.
- minDistance, maxDistance: The distance between placed objects.
- (Optional) minAngle, maxAngle: The variation in angle of placed objects (to make them all face the same direction, set these equal). Default to 0 and 2*PI, respectively.
Creating a single object group
To place one object group at a known location, use the function createObjectGroup(placer, player, constraint). Given a placer, player ID, and optional constraint, it will try to create the object group. If successful it will return true, or false on failure.
Creating multiple object groups at random locations
Just like createAreas for terrains, there is a createObjectGroups(placer, player, constraint, number, retryFactor) function for placing multiple object groups at random locations.
Object group placers
Currently there is only one object group placer SimpleGroup(objects, avoidSelf, tileClass, x, z):
- objects: This is an array of SimpleObjects.
- (optional) avoidSelf: If true, groups of objects will not overlap.
- (Optional) tileClass: An optional tile class to add with these objects. In this way you could place some stone mines grouped together with decorative rocks, and make sure that they would have a certain minimum distance between them.
- (Optional) x, z: Tile coordinates of the center of the placer.
Grouping Similar Features: Tile Classes
In random maps, it is often the case that terrain types and objects will be interconnected. Also when creating the map, we want to avoid some features when placing others. One way of achieving this is by using tile classes. Tile classes can be painted like terrains, although they don't affect the appearance by themselves. They are like placeholders that tell the map script where to place or avoid placing other things. An example usage of tile classes could be to define a "base" area at the starting location of each player. Within this area you probably would want to exclude some things: forests, lakes, and opponents. Likewise you'd want to include resources like berry bushes and sheep.
Working with tile classes
To create a tile class call createTileClass() which will return a new integer ID. Store the ID in a variable for future reference. If you want to get the tile class object, call getTileClass(id) and it will return the object or undefined if the ID was invalid.
Points can be added individually to a tile class with addToClass(x, z, id). In practice this would be tedious, and one advantage of areas is they allow a simple representation of points. There is a special area painter just for this purpose, TileClassPainter(tileClass). This could be used directly if you have a tile class object, but more common is using the paintClass(id) helper function, which will return a TileClassPainter matching the given ID. For removing tiles from a tile class, you can use unPaintClass(id) or TileClassUnPainter in a similar way. You can also check if a tile is in a class by using checkIfInClass(x, z, id) function.
Controlling Placement: Constraints
Both areas and object groups use constraints to limit their placement to specific parts of the map. This is usually the key to making realistic and fair random maps. For example, on most maps, you want a number of clumps of forest, but you want them to be spread out to make most areas of the map reachable, so you will probably want to use an "avoid forest by X meters" constraint on your forest objects. Similarly, you want iron mines to be spread out fairly, and you also don't want them to be inside forests, or under water. If you're making some kind of "king of the hill" map though, you might want the same mines to be only in some area in the center of the map. The list goes on.
Multiple constraints can be combined by passing an array of constraints as a constraint argument. For example, use [new AvoidTextureConstraint("snow"), new AvoidTextureConstraint("desert")] to place an object or area that avoids both snow and desert.
The following constraints are available:
- NullConstraint(): This is the same as no constraint, it will always allow placement.
- AndConstraint(constraint): Combines multiple constraints using AND logic. In other words, give it an array of constraints and all must be satisfied for placement.
- AvoidAreaConstraint(area): Prevents the area/object from being placed on top of the given area.
- AvoidTextureConstraint(textureID): Prevents the area/object from being placed on top of terrain with the given texture.
- AvoidTileClassConstraint(tileClassID, distance): Prevents the area/object from being placed within distance tiles of the given tile class.
- StayInTileClassConstraint(tileClassID, distance): Keeps the area/object placement within distance tiles of the given tile class.
- BorderTileClassConstraint(tileClassID, distanceInside, distanceOutside): Makes the placed area/object border the given tile class. It must be no more than distanceOutside tiles outside of the class and no more than distanceInside tiles inside of it.
There are two helpers for tile class constraints, which accept arguments of the form (class1, distance1, class2, distance2, ...):
- stayClasses(...): Stay within all the given tile classes with maximum distances specified.
- avoidClasses(...): Avoid all the given tile classes by the minimum distances specified.
The functions and data provided in wall_builder.js allow easy placements of multiple entities to shape walls. fist some concepts used:
- The 'wall style' is chosen by a wall style string for example like the civ strings ('cart' or 'celt') or other descriptive strings ('palisades' or 'romeSiege').
- To provide easy placement of fortresses there are some predefined 'fortresses' commonly chosen by a string describing their size (like map sizes) for example 'tiny' or 'veryLarge'.
- 'Wall elements' are commonly chosen by strings like 'wall', 'tower', 'gate' etc. (see WallElement? class definition for more documentation).
- Wall elements are merged in an array that then defines a 'wall' or a 'wall part'. Those walls can then be placed with the functions.
The most simple placement methods are:
- 'placeFortress()': Places a default fortress by it's fortress name string centered at the given coordinates with its entrance facing 'orientation'.
- 'placeLinearWall()': Places a wall from start X/Y to target X/Y with repeated usage of the given 'wall part'.
- 'placeCircularWall()': Places a wall circle centered at the given coordinates with a given radius and repeated usage of the given 'wall part'.
- 'placeWall()': Function to place a simple wall defined by a 'wall' array starting with the first wall element placed as coordinates and angle given.
Other functions are in there helpful to generate custom walls and fortresses:
- 'WallElement?()': Defines a wall element including its entity and a name string to easily access it.
- 'Fortress()': Defines a fortress mainly by its 'wall' and a name string to easily access it.
- 'wallStyles': An associative array that holds all default wall styles with the civ strings as keys (like 'cart' or 'celt') or other descriptive strings (like
'palisades' or 'romeSiege'). A wall style itself again is an associative array holding all the default wall elements with their name string as key (like 'wall' or 'tower').
- 'fortressTypes': An associative array that holds all default fortress types by a key that is mainly chosen like the map sizes (like 'tiny' or 'veryLarge').
- 'getWallAlignment()': A function to get a walls 'alignment' that mainly includes everything needed to place all the wall's elements.
- 'getWallCenter()': A function to get the 'center of mass' of a wall by giving its 'alignment' and returning the vector from the first element to the center.
To see examples for the common methods look at the demo random map 'Wall Demo' (wall_demo.js). An example for placing a custom fortress can be found in 'Fortress' (fortress.js).
These functions are for accessing properties of the map settings:
- getMapSize(): Returns map size in tiles.
- getMapArea(): Returns map area in square tiles.
- getNumPlayers(): Returns number of players.
- getCivCode(player): Returns the 4-character civ code of the given player.
- getStartingEntities(player): Returns an array of civ-specific starting entity objects, as defined in /civs/*.json. Each object has a Template and an optional Count property. The first entry is usually the civ centre.
- isCircularMap(): Returns true if the map is circular.
The environment of a map represents sky, lighting, and water settings. For example a tropical island map might have a clear blue sky, bright sun, and light blue water, whereas a temperate map might have muddy water and an overcast sky. The environment doesn't affect gameplay but does provide a more realistic setting. The following are some functions to adjust the environment of a random map.
- setSkySet(set): Sets skyset name; examples are "sunny", "default" and "cirrus".
- setSunColour(r, g, b): Sets RGB colour of sunlight (0.0 - 1.0+)
- setTerrainAmbientColour(r, g, b): Sets RGB colour of ambient terrain lighting (0.0 - 1.0)
- setUnitsAmbientColour(r, g, b): Sets RGB colour of ambient unit lighting (0.0 - 1.0)
- setWaterColour(r, g, b): Sets RGB colour of water (0.0 - 1.0)
- setWaterTint(r, g, b): Sets RGB colour of water tint (0.0 - 1.0)
- setWaterReflectionTint(r, g, b): Sets RGB colour of water reflection tint (0.0 - 1.0)
The following utility functions are available to scripts. Especially useful are the randomization functions for when you want parameters like terrains or area sizes to vary.
- randInt(maxValue): Returns a random integer between 0 and maxValue - 1 (exclusive).
- randInt(minValue, maxValue): Returns a random integer between minValue (inclusive) and maxValue - 1 (inclusive).
- randFloat(): Returns a random floating-point number between 0.0 (inclusive) and 1.0 (exclusive).
- randFloat(minValue, maxValue): Returns a random floating-point number between minValue (inclusive) and maxValue (exclusive).
- chooseRand(...): Returns one of its arguments at random (takes any number of arguments).
- getDistance(x1, z1, x2, z2): Function to get the distance between 2 points
Random Biome System
The random biome system is a series of terrain, entity and actor presets that can be used to generate maps with random biomes. Here is a list of related functions:
- randomizeBiome(): Randomizes the biome sets. Returns a value indicating the used set. These values are:
- rBiomeTn(): "n" in the end of the function can be any number from 1 to 15. Returns the n'th terrain of the current set. For example rBiomeT2() returns the second terrain of the set which is reserved for forest floors. These terrains are used for:
- "1":Main terrain texture
- "2-3":Forest floors
- "5-7":Other terrain textures. Usually used for grass.
- "8-9":Other terrain textures. Usually used for dirt.
- "10":Main road/citytile texture
- "11":Outer road/citytile texture. Better used as a border between main terrain and main road.
- "12-13":Other miscellaneous terrain textures.
- "14":A texture to be used as a border between water and main terrain.
- "15":Water/Shore? terrain.
- rBiomeEn(): "n" in the end of the function can be any number from 1 to 13. Returns the n'th entity of the current set. For example rBiomeE9() returns the ninth entity of the set which is reserved for fish. These entities are used for:
- "1-2":Main trees
- "3-5":Secondary trees
- "8":First hunting animal
- "10":Second hunting animal
- "11":Large stone mine
- "12":Small stone mine
- "13":Large metal mine
- rBiomeAn(): "n" in the end of the function can be any number from 1 to 9. Returns the n'th actor of the current set. For example rBiomeA3() returns the third actor of the set which is reserved for water reeds. These actors are used for:
- "3-4":Water decoration
- "9":Tree actors. Used as eyecandy for unreachable areas (eg: hilltops)
- createStartingPlayerEntities(x, z, playerid, civEntities, BUILDING_ANGlE): Creates starting player entities of a selected player in the given coordinates.
- passageMaker(x1, z1, x2, z2, width, maxheight, height, smooth, tileclass, terrain): Function for creating shallow water between two given points
- paintTerrainBasedOnHeight(minheight, maxheight, mode, terrain): Paints the tiles which have a height between minheight and maxheight with the given terrain
- paintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass): Paints the tiles which have a height between minheight and maxheight with the given tile class
These are the scripts that are part of the rmgen library:
- area.js: Defines area data structure
- constraint.js: Defines constraints
- entity.js: Defines the structure of an entity/object
- environment.js: Defines environment helper functions
- library.js: Defines various constants and helper functions
- map.js: Defines the map data structure
- mapgen.js: Defines settings and functions for all map scripts
- misc.js: Defines miscellaneous functions that don't belong to any other group
- noise.js: Defines 2D and 3D noise maps
- painter.js: Defines area painters
- placer.js: Defines area and object placers
- point.js: Defines 2D point data structure
- random.js: Defines helpers for random numbers
- randombiome.js: Defines random biome system's functions
- terrain.js: Defines terrain placers
- tileclass.js: Defines tile class data structure and rangeOp (see here for details)
- vector.js: Defines 2D and 3D vector data structures (used for noise)