This will contain information on how to use !RmGen and on the !JavaScript API as I find the time to write it. There will also be a page on [wiki:Random_Map_Generator_Internals Random Map Generator Internals] about the structure of the source code and the concepts in the design. = Running the Generator = The random map generator is `binaries/system/rmgen_dbg.exe` (`rmgen.exe` should also work if I remember to build the project in release mode every so often). You should run it from within `binaries/system` for it to find paths to the files it needs properly. The program takes 2 arguments: first, the name of the script to run, and second, the name of the scenario to output to, both without file extensions. These are relative to the maps/random and maps/scenarios directories in the default mod (`binaries/data/mods/official`). For example, `rmgen test rm` will read `maps/random/test.js` and generate `maps/scenarios/rm.xml` and `maps/scenarios/rm.pmp`. There is also an optional third argument to specify the random number generator seed (running the same script with the same seed will always generate the exact same map); if no seed is provided, one based on the current time is used. Here is an example Command Prompt session that shows how to run the script `cantabrian_highlands.js` and output the result to the scenario `cantabrian_generated.pmp`, assuming your 0AD is in `C:\0AD` (if your 0AD is in a different directory, use that for the `cd` command): {{{ C:\Documents and Settings\Administrator>cd "C:\0AD\binaries\system" C:\0AD\binaries\system>rmgen.exe cantabrian_highlands cantabrian_generated Map outputted to ../data/mods/official/maps/scenarios/cantabrian_generated.* Took 2.156 seconds. Press any key to continue . . . C:\0AD\binaries\system> }}} = Guide to !JavaScript = We should probably write one or provide a link to one since a lot of the game scripting (not just RMS) is !JavaScript. Here's a good reference for people interested: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/js56jsconJScriptFundamentals.asp. = Guide to Random Map Scripting = This section covers the general concepts in the RMS API and how they can be used to make maps. == Initializing the Map == Every script should start with the call `init(size, terrain, height)` which will set the map size and paint it with a given base terrain an base height. Only after this can other RMS functions be called. Note that the map size has to be a multiple of 16, and the map must be square. == Map Coordinate System == The map uses the same x,z coordinate system as in-game, with all units, including those for height, equal to the size of 1 tile (which is actually 4.0 model-space units). This seemed less confusing because most people will think in terms of tiles. Note that the z axis is often reffered to as y here, maybe this is something I should change to be consistent (y is really up/down). == Terrains == 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). In effect, a "terrain" represents just any object which can texture and add objects onto a single tile in some way; perhaps it should really be called "!TilePainter" or something. For now, the following ways of specifying a terrain are available: * Specify a texture name. For example, use `init(16, "grass1_a", 0)` creates a 16x16 map covered with grass (at height 0). * Specify a texture name and tree type to paint a forest. These should be separated by a "|". For example, use `"forrestfloor|wrld_flora_oak"` instead of `"grass1_a"` above to cover the map with oak forest. * Use a special !RandomTerrain object to paint a random terrain from a list on each tile. For this, just pass in an array of terrains as the terrain argument. For example, pass in `!["grass1_a", "forrestfloor|wrld_floar_oak"]` to paint each tile with either snow or oak forest (in effect creating a sparse forest). '''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 area/object group system. Thus, the !JavaScript API provides functions that give complete control over the map to allow this: * `placeTerrain(x, y, terrain)` * `setElevation(x, y, height)` * `addEntity(type, player, x, y, orientation)` '''TODO:''' Perhaps these should have slightly more consistent names and order of arguments. == 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: 1. Choose the shape of the area, by specifying an object called an ''area placer''. 1. Choose how to fill in the area with terrain, 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("snow"), new !ElevationPainter(4.0)]` to paint an area with snow and also raise it to height 4.) 1. (Optional) Choose ''constraints'' on where the area can be placed; for example, make it avoid specific areas or specific 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 the 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 it and returns a positive area ID for the area placed. If it fails, it returns 0 and does not change any terrain. (Because 0 counts as false in !JavaScript, you can check for failure by `if(createArea(...))`). === Creating multiple areas at random locations === For many areas, you do not want to specify an exact location when creating 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(placer, painter, constraint, number, maxFail)` function. This takes 5 parameters: * A placer object. 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 "y" fields). Many types of placers can do this, although a few, like !RectPlacer, can only be used through `createArea`. * A painter object. * A constraint. 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. * A number of areas to place. * A number of areas that must fail to place for the function to "give up" trying to place more. This should usually be pretty high. Remember that it can't be *too* high if there is enough space on the map for the areas, since it will be easy to randomly place them. The `createAreas` function will then repeatedly try placing areas at random locations (modifying the x,y fields of the `placer`) until either `number` have been placed or `maxFail` have failed to place. It will return an array containing the IDs of the areas placed. === Area placers === The following area placers are available. Placers that can't be used with `createAreas` are marked specifically. Note that most objects have editable fields of the same names as its constructor parameters after you construct it. * `!RectPlacer(x1, y1, x2, y2)`: Places a grid-aligned rectangle from (x1,y1) to (x2,y2), where x1