Changes between Initial Version and Version 1 of Random_Map_Generator


Ignore:
Timestamp:
Feb 23, 2008, 4:18:58 AM (16 years ago)
Author:
trac
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Random_Map_Generator

    v1 v1  
     1This 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.
     2
     3= Running the Generator =
     4
     5The 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.
     6
     7Here 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):
     8
     9{{{
     10 C:\Documents and Settings\Administrator>cd "C:\0AD\binaries\system"
     11 
     12 C:\0AD\binaries\system>rmgen.exe cantabrian_highlands cantabrian_generated
     13 Map outputted to ../data/mods/official/maps/scenarios/cantabrian_generated.*
     14 Took 2.156 seconds.
     15 Press any key to continue . . .
     16 
     17 C:\0AD\binaries\system>
     18}}}
     19
     20= Guide to !JavaScript =
     21
     22We 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.
     23
     24= Guide to Random Map Scripting =
     25
     26This section covers the general concepts in the RMS API and how they can be used to make maps.
     27
     28== Initializing the Map ==
     29
     30Every 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.
     31
     32== Map Coordinate System ==
     33
     34The 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).
     35
     36== Terrains ==
     37
     38The 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:
     39
     40 * Specify a texture name. For example, use `init(16, "grass1_a", 0)` creates a 16x16 map covered with grass (at height 0).
     41 * 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.
     42 * 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).
     43
     44'''TODO:''' Later it should be possible to provide custom JS terrain objects as well.
     45
     46== Accessing Map Data Directly ==
     47
     48The 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:
     49 * `placeTerrain(x, y, terrain)`
     50 * `setElevation(x, y, height)`
     51 * `addEntity(type, player, x, y, orientation)`
     52
     53'''TODO:''' Perhaps these should have slightly more consistent names and order of arguments.
     54
     55== Placing Terrain: Areas ==
     56
     57The 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.
     58
     59An area is created in three steps:
     60 1. Choose the shape of the area, by specifying an object called an ''area placer''.
     61 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.)
     62 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.)
     63
     64The 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.
     65
     66This section will talk about area placers and painters; full information on constraints can be found in the Constraints section below.
     67
     68=== Creating a single area ===
     69
     70The 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(...))`).
     71
     72=== Creating multiple areas at random locations ===
     73
     74For 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:
     75 * 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`.
     76 * A painter object.
     77 * 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.
     78 * A number of areas to place.
     79 * 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.
     80The `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.
     81
     82=== Area placers ===
     83
     84The 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.
     85 * `!RectPlacer(x1, y1, x2, y2)`: Places a grid-aligned rectangle from (x1,y1) to (x2,y2), where x1<x2 and y1<y2. (Note: not useable for `createAreas`).
     86 * `!ClumpPlacer(size, coherence, smoothness, [x, y])`: 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:
     87  * '''size''': The average number of tiles in the clump. Individual clumps may have more or fewer.
     88  * '''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.
     89  * '''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.
     90
     91=== Area painters ===
     92
     93The following area painters are available. Remember that terrains can be any of the objects in the "A Note on Terrains" section above.
     94
     95An 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.
     96
     97 * `!TerrainPainter(terrain)`: Fills an entire area with a single terrain.
     98 * `!ElevationPainter(elevation)`: Sets an entire area to a single elevation.
     99 * `!LayeredPainter(widths, terrains)`: 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([1,1], !["grass dirt 25","grass dirt 50","grass dirt 75"])` will create a patch of "grass dirt 75" terrain that will be surrounded by a 1-tile layer of "grass dirt 50" and right outside that a 1-tile layer of "grass dirt 25"; this will look nicer than placing "grass dirt 75" directly onto a field of grass.
     100 * `!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:
     101  * 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.
     102  * 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).
     103
     104== Placing Units: Object Groups ==
     105
     106To be implemented...
     107
     108== Controlling Placement: Constraints ==
     109
     110Both 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.
     111
     112Multiple 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.
     113
     114The following constraints are available:
     115 * `!AvoidTextureConstraint(texture)`: Prevents the area/object from being placed on top of terrain with the given texture.
     116 * `!AvoidAreaConstraint(area)`: Prevents the area/object from being placed on top of the area with the given ID.
     117
     118== Grouping Similar Features: Classes ==
     119
     120To be implemented...
     121
     122== Miscellaneous Functions ==
     123
     124The 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.
     125 * `print(message), println(message)`: Prints a message to the console, for debugging purposes; `println` also starts a new line after the message.
     126 * `error(message)`: Prints an error message and stops the random map generator. The message will be displayed in the game when rmgen is integrated with it.
     127 * `randInt(maxValue)`: Returns a random integer between 0 and `maxValue - 1` (inclusive).
     128 * `randFloat()`: Returns a random floating-point number between 0.0 (inclusive) and 1.0 (exclusive).
     129 * `chooseRand(...)`: Returns one of its arguments at random (takes any number of arguments).
     130
     131== Don't Use Math.random() ==
     132
     133Very often in your random maps you'll want to make random choices: how many islands to place on an islands map, what biome to use on a map with multiple biomes, etc. In this case, '''DO NOT''' use the `Math.random()` function in the standard !JavaScript library. Instead, use the utility functions provided by the RM scripting API:
     134 * `randInt(maxValue)`: Returns a random integer between 0 and `maxValue - 1` (inclusive).
     135 * `randFloat()`: Returns a random floating-point number between 0.0 (inclusive) and 1.0 (exclusive).
     136 * `chooseRand(...)`: Returns one of its arguments at random (takes any number of arguments).
     137The reason for this is that in multiplayer games, each player's computer will generate the map independently, using a common number called a ''seed'' to initialize the random number generator. The functions above return numbers based on this seed, but Math.random() doesn't, so if you use Math.random(), different players may end up with different versions of the map, leading to an Out Of Sync error. (If you wish to write your own random number generator for whatever reason, the seed for the map is stored in a global constant called `SEED`).
     138
     139= API Reference =
     140
     141Is this necessary since the functions are listed above? I guess later the previous section can become a high-level guide while API details are here.