Ticket #3764: realistic_terrain_demo2016-1-31c.diff

File realistic_terrain_demo2016-1-31c.diff, 114.8 KB (added by FeXoR, 8 years ago)

Inserted a continue, removed commented out code

  • binaries/data/mods/public/maps/random/BaseTerrainDiamondSquare.js

     
     1/**
     2*   ToDo:
     3*   Add resources at start locations
     4*   Add stone and metal
     5*   Place start locations of one team close to each other
     6*
     7*   Add parameters for match setup screen (for later use and demonstration)
     8*
     9*   Extract some functions to an RMGEN lib
     10*   Sort out unneeded functions calling other functions
     11*   Clean up
     12*/
     13
     14RMS.LoadLibrary("rmgen");
     15
     16const BUILDING_ANGlE = -PI/4;
     17
     18/**
     19* initialize map
     20*/
     21
     22log("Initializing map...");
     23
     24InitMap();
     25
     26var numPlayers = g_MapSettings.PlayerData.length;
     27var mapSize = getMapSize();
     28
     29
     30/**
     31* Actually do stuff
     32*/
     33
     34/**
     35* Set target min and max height depending on map size to make average steepness about the same on all map sizes
     36*/
     37var heightRange = {"min": MIN_HEIGHT * (mapSize + 512) / 1024 / 8, "max": MAX_HEIGHT * (mapSize + 512) / 1024 / 8};
     38
     39/**
     40* Set average water coverage
     41*/
     42var averageWaterCoverage = 1/5; // NOTE: Since erosion is not predictable actual water coverage might vary much with the same values
     43var waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min);
     44var waterHeightAdjusted = waterHeight + MIN_HEIGHT;
     45setWaterHeight(waterHeight);
     46
     47/**
     48*  Generate initial reliefmap
     49*/
     50setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, 0.5);
     51
     52
     53/**
     54* Apply simple erosion
     55*/
     56for (var i = 0; i < 5; i++)
     57    globalSmoothHeightmap(0.5);
     58
     59
     60/**
     61* Place start locations and apply terrain texture and decorative props by height
     62*/
     63
     64/**
     65* Set random biome
     66*/
     67randomizeBiome();
     68
     69/**
     70* Define texture textures and decorative props (and density) by height
     71*/
     72var textueByHeight = [];
     73textueByHeight.push({"height": heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), "texture": rbt15, "actor": [rbe9, 0.2]});
     74textueByHeight.push({"height": heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), "texture": rbt15, "actor": [undefined, 0]});
     75textueByHeight.push({"height": heightRange.min + 3/3 * (waterHeightAdjusted - heightRange.min), "texture": rbt15, "actor": [rba3, 0.2]});
     76textueByHeight.push({"height": waterHeightAdjusted + 1/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt14, "actor": [rbe5, 0.1]});
     77textueByHeight.push({"height": waterHeightAdjusted + 2/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt8, "actor": [undefined, 0]});
     78textueByHeight.push({"height": waterHeightAdjusted + 3/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt9, "actor": [undefined, 0]});
     79textueByHeight.push({"height": waterHeightAdjusted + 4/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt1, "actor": [undefined, 0]});
     80textueByHeight.push({"height": waterHeightAdjusted + 5/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt5, "actor": [rbe3, 0.2]});
     81textueByHeight.push({"height": waterHeightAdjusted + 6/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt2, "actor": [rbe1, 0.4]});
     82textueByHeight.push({"height": waterHeightAdjusted + 7/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt3, "actor": [rbe2, 0.4]});
     83textueByHeight.push({"height": waterHeightAdjusted + 8/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt7, "actor": [rbe4, 0.2]});
     84textueByHeight.push({"height": waterHeightAdjusted + 9/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt4, "actor": [undefined, 0]});
     85
     86/**
     87* Get start locations
     88*/
     89rescaleHeightmap(heightRange.min, heightRange.max);
     90var startLocations = getStartLocationsByHeightmap({"min": textueByHeight[4].height, "max": textueByHeight[5].height});
     91
     92/**
     93* Smooth ground at start locations and place starting entities
     94*/
     95var playerHeight = (textueByHeight[4].height + textueByHeight[5].height) / 2;
     96for (var p = 0; p < g_MapSettings.PlayerData.length - 1; p++)
     97{
     98    log("p = " + uneval(p));
     99    log("startLocations[" + p + "] = " + uneval(startLocations[p]));
     100    rectangularSmoothToHeight(startLocations[p], 30, 30, playerHeight);
     101    placeCivDefaultEntities(startLocations[p].x, startLocations[p].y, p + 1, BUILDING_ANGlE, {"iberWall": true});
     102}
     103
     104/**
     105* Normalize and apply reliefmap
     106*/
     107rescaleHeightmap(heightRange.min, heightRange.max);
     108
     109/**
     110* Place terrain texture and decorative props by height
     111*/
     112for(var x = 0; x < mapSize; x++)
     113{
     114    for (var y = 0; y < mapSize; y++)
     115    {
     116        var textureMinHeight = heightRange.min;
     117        for (var i = 0; i < textueByHeight.length; i++)
     118        {
     119            if (g_Map.height[x][y] >= textureMinHeight && g_Map.height[x][y] <= textueByHeight[i].height)
     120            {
     121                if (typeof(textueByHeight[i].texture) == "string")
     122                    g_Map.setTexture(x, y, textueByHeight[i].texture);
     123                else
     124                    g_Map.setTexture(x, y, textueByHeight[i].texture[randInt(textueByHeight[i].texture.length)]);
     125                if (textueByHeight[i].actor[0])
     126                {
     127                    var scaleByDistToPlayer = 1; // ToDo: Make an approximate faster range check!!!
     128                    for (var p = 0; p < g_MapSettings.PlayerData.length; p++)
     129                        scaleByDistToPlayer = min(getDistance(x, y, startLocations[p].x, startLocations[p].y) / 50, scaleByDistToPlayer);
     130                    if (randFloat() < textueByHeight[i].actor[1] * scaleByDistToPlayer)
     131                        placeObject(x + 0.5, y + 0.5, textueByHeight[i].actor[0], 0, randFloat(0, 2*PI));
     132                }
     133                break;
     134            }
     135            else
     136            {
     137                textureMinHeight = textueByHeight[i].height;
     138            }
     139        }
     140    }
     141}
     142
     143/**
     144* Export map data
     145*/
     146ExportMap();
  • binaries/data/mods/public/maps/random/BaseTerrainDiamondSquare.json

     
     1{
     2    "settings" : {
     3        "Name" : "Base Terrain Diamond Square Test",
     4        "Script" : "BaseTerrainDiamondSquare.js",
     5        "Description" : "Testmap for the diamond-square base terrain generation.",
     6        "CircularMap" : false,
     7        "BaseTerrain" : "grass1_spring",
     8        "BaseHeight" : 0,
     9        "Keywords": ["demo"],
     10        "XXXXXX" : "Optionally define other things here, like we would for a scenario"
     11    }
     12}
     13 No newline at end of file
  • binaries/data/mods/public/maps/random/belgian_uplands.js

     
    1 // Prepare progress calculation
     1/**
     2 * Prepare progress calculation
     3 */
    24var timeArray = [];
    35timeArray.push(new Date().getTime());
    46
    5 // Importing rmgen libraries
     7/**
     8 * Importing rmgen libraries
     9 */
    610RMS.LoadLibrary("rmgen");
    711
    812const BUILDING_ANGlE = -PI/4;
    913
    10 // initialize map
    11 
     14/**
     15 * initialize map
     16 */
    1217log("Initializing map...");
    1318
    1419InitMap();
     
    1722var mapSize = getMapSize();
    1823
    1924
    20 //////////
    21 // Heightmap functionality
    22 //////////
     25/**
     26 * Heightmap functionality
     27 */
    2328
    24 // Some general heightmap settings
    25 const MIN_HEIGHT = - SEA_LEVEL; // 20, should be set in the libs!
    26 const MAX_HEIGHT = 0xFFFF/HEIGHT_UNITS_PER_METRE - SEA_LEVEL; // A bit smaler than 90, should be set in the libs!
    27 
    28 // Add random heightmap generation functionality
     29/**
     30 * Add random heightmap generation functionality
     31 */
    2932function getRandomReliefmap(minHeight, maxHeight)
    3033{
    3134    minHeight = (minHeight || MIN_HEIGHT);
     
    3538    if (maxHeight > MAX_HEIGHT)
    3639        warn("getRandomReliefmap: Argument maxHeight is smaler then the supported maximum height of " + MAX_HEIGHT + " (const MAX_HEIGHT): " + maxHeight)
    3740    var reliefmap = [];
    38     for (var x = 0; x <= mapSize; x++)
     41    for (var x = 0; x <= mapSize; ++x)
    3942    {
    4043        reliefmap.push([]);
    41         for (var y = 0; y <= mapSize; y++)
     44        for (var y = 0; y <= mapSize; ++y)
    4245        {
    4346            reliefmap[x].push(randFloat(minHeight, maxHeight));
    4447        }
     
    4649    return reliefmap;
    4750}
    4851
    49 // Apply a heightmap
     52/**
     53 * Apply a heightmap
     54 */
    5055function setReliefmap(reliefmap)
    5156{
    52     // g_Map.height = reliefmap;
    53     for (var x = 0; x <= mapSize; x++)
     57    for (var x = 0; x <= mapSize; ++x)
    5458    {
    55         for (var y = 0; y <= mapSize; y++)
     59        for (var y = 0; y <= mapSize; ++y)
    5660        {
    5761            setHeight(x, y, reliefmap[x][y]);
    5862        }
    5963    }
    6064}
    6165
    62 // Get minimum and maxumum height used in a heightmap
     66/**
     67 * Get minimum and maxumum height used in a heightmap
     68 */
    6369function getMinAndMaxHeight(reliefmap)
    6470{
    6571    var height = {};
    6672    height.min = Infinity;
    6773    height.max = -Infinity;
    68     for (var x = 0; x <= mapSize; x++)
     74    for (var x = 0; x <= mapSize; ++x)
    6975    {
    70         for (var y = 0; y <= mapSize; y++)
     76        for (var y = 0; y <= mapSize; ++y)
    7177        {
    7278            if (reliefmap[x][y] < height.min)
    7379                height.min = reliefmap[x][y];
     
    7884    return height;
    7985}
    8086
    81 // Rescale a heightmap (Waterlevel is not taken into consideration!)
     87/**
     88 * Rescale a heightmap (Waterlevel is not taken into consideration!)
     89 */
    8290function getRescaledReliefmap(reliefmap, minHeight, maxHeight)
    8391{
    8492    var newReliefmap = deepcopy(reliefmap);
     
    8997    if (maxHeight > MAX_HEIGHT)
    9098        warn("getRescaledReliefmap: Argument maxHeight is smaler then the supported maximum height of " + MAX_HEIGHT + " (const MAX_HEIGHT): " + maxHeight)
    9199    var oldHeightRange = getMinAndMaxHeight(reliefmap);
    92     for (var x = 0; x <= mapSize; x++)
     100    for (var x = 0; x <= mapSize; ++x)
    93101    {
    94         for (var y = 0; y <= mapSize; y++)
     102        for (var y = 0; y <= mapSize; ++y)
    95103        {
    96104            newReliefmap[x][y] = minHeight + (reliefmap[x][y] - oldHeightRange.min) / (oldHeightRange.max - oldHeightRange.min) * (maxHeight - minHeight);
    97105        }
     
    99107    return newReliefmap
    100108}
    101109
    102 // Applying decay errosion (terrain independent)
     110/**
     111 * Applying decay errosion (terrain independent)
     112 */
    103113function getHeightErrosionedReliefmap(reliefmap, strength)
    104114{
    105115    var newReliefmap = deepcopy(reliefmap);
    106116    strength = (strength || 1.0); // Values much higher then 1 (1.32+ for an 8 tile map, 1.45+ for a 12 tile map, 1.62+ @ 20 tile map, 0.99 @ 4 tiles) will result in a resonance disaster/self interference
    107117    var map = [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]; // Default
    108     for (var x = 0; x <= mapSize; x++)
     118    for (var x = 0; x <= mapSize; ++x)
    109119    {
    110         for (var y = 0; y <= mapSize; y++)
     120        for (var y = 0; y <= mapSize; ++y)
    111121        {
    112122            var div = 0;
    113             for (var i = 0; i < map.length; i++)
     123            for (var i = 0; i < map.length; ++i)
    114124                newReliefmap[x][y] += strength / map.length * (reliefmap[(x + map[i][0] + mapSize + 1) % (mapSize + 1)][(y + map[i][1] + mapSize + 1) % (mapSize + 1)] - reliefmap[x][y]); // Not entirely sure if scaling with map.length is perfect but tested values seam to indicate it is
    115125        }
    116126    }
     
    118128}
    119129
    120130
    121 //////////
    122 // Prepare for hightmap munipulation
    123 //////////
     131/**
     132 * Prepare for hightmap munipulation
     133 */
    124134
    125 // Set target min and max height depending on map size to make average stepness the same on all map sizes
    126 var heightRange = {"min": MIN_HEIGHT * mapSize / 8192, "max": MAX_HEIGHT * mapSize / 8192};
     135/**
     136 * Set target min and max height depending on map size to make average stepness the same on all map sizes
     137 */
     138var heightRange = { "min": MIN_HEIGHT * (mapSize + 256) / 8192, "max": MAX_HEIGHT * (mapSize + 256) / 8192 };
    127139
    128 // Set average water coverage
     140/**
     141 * Set average water coverage
     142 */
    129143var averageWaterCoverage = 1/3; // NOTE: Since errosion is not predictable actual water coverage might differ much with the same value
    130144if (mapSize < 200) // Sink the waterlevel on tiny maps to ensure enough space
    131145    averageWaterCoverage = 2/3 * averageWaterCoverage;
     
    134148setWaterHeight(waterHeight);
    135149
    136150
    137 //////////
    138 // Prepare terrain texture by height placement
    139 //////////
    140 
     151/**
     152 * Prepare terrain texture by height placement
     153 */
    141154var textueByHeight = [];
    142155
    143 // Deep water
    144 textueByHeight.push({"upperHeightLimit": heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), "terrain": "temp_sea_rocks"});
    145 // Medium deep water (with fish)
    146 var terreins = ["temp_sea_weed"];
    147 terreins = terreins.concat(terreins, terreins, terreins, terreins);
    148 terreins = terreins.concat(terreins, terreins, terreins, terreins);
    149 terreins.push("temp_sea_weed|gaia/fauna_fish");
    150 textueByHeight.push({"upperHeightLimit": heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), "terrain": terreins});
    151 // Flat Water
    152 textueByHeight.push({"upperHeightLimit": heightRange.min + 3/3 * (waterHeightAdjusted - heightRange.min), "terrain": "temp_mud_a"});
    153 // Water surroundings/bog (with stone/metal some rabits and bushes)
    154 var terreins = ["temp_plants_bog", "temp_plants_bog_aut", "temp_dirt_gravel_plants", "temp_grass_d"];
    155 terreins = terreins.concat(terreins, terreins, terreins, terreins, terreins);
    156 terreins = ["temp_plants_bog|gaia/flora_bush_temperate"].concat(terreins, terreins);
    157 terreins = ["temp_dirt_gravel_plants|gaia/geology_metal_temperate", "temp_dirt_gravel_plants|gaia/geology_stone_temperate", "temp_plants_bog|gaia/fauna_rabbit"].concat(terreins, terreins);
    158 terreins = ["temp_plants_bog_aut|gaia/flora_tree_dead"].concat(terreins, terreins);
    159 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 1/6 * (heightRange.max - waterHeightAdjusted), "terrain": terreins});
    160 // Juicy grass near bog
    161 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 2/6 * (heightRange.max - waterHeightAdjusted),
    162     "terrain": ["temp_grass", "temp_grass_d", "temp_grass_long_b", "temp_grass_plants"]});
    163 // Medium level grass
    164 // var testActor = "actor|geology/decal_stone_medit_a.xml";
    165 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 3/6 * (heightRange.max - waterHeightAdjusted),
    166     "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_mossy"]});
    167 // Long grass near forest border
    168 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 4/6 * (heightRange.max - waterHeightAdjusted),
    169     "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_d", "temp_grass_long_b", "temp_grass_clovers_2", "temp_grass_mossy", "temp_grass_plants"]});
    170 // Forest border (With wood/food plants/deer/rabits)
    171 var terreins = ["temp_grass_plants|gaia/flora_tree_euro_beech", "temp_grass_mossy|gaia/flora_tree_poplar", "temp_grass_mossy|gaia/flora_tree_poplar_lombardy",
     156/**
     157 * Deep water
     158 */
     159textueByHeight.push({ "upperHeightLimit": heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), "terrain": "temp_sea_rocks" });
     160
     161/**
     162 * Medium water (with fish)
     163 */
     164var terrains = ["temp_sea_weed"];
     165terrains = terrains.concat(terrains, terrains, terrains, terrains);
     166terrains = terrains.concat(terrains, terrains, terrains, terrains);
     167terrains.push("temp_sea_weed|gaia/fauna_fish");
     168textueByHeight.push({ "upperHeightLimit": heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), "terrain": terrains });
     169
     170/**
     171 * Flat Water
     172 */
     173textueByHeight.push({ "upperHeightLimit": heightRange.min + 3/3 * (waterHeightAdjusted - heightRange.min), "terrain": "temp_mud_a" });
     174
     175/**
     176 * Water surroundings/bog (with stone/metal some rabits and bushes)
     177 */
     178var terrains = ["temp_plants_bog", "temp_plants_bog_aut", "temp_dirt_gravel_plants", "temp_grass_d"];
     179terrains = terrains.concat(terrains, terrains, terrains, terrains, terrains);
     180terrains = ["temp_plants_bog|gaia/flora_bush_temperate"].concat(terrains, terrains);
     181terrains = ["temp_dirt_gravel_plants|gaia/geology_metal_temperate", "temp_dirt_gravel_plants|gaia/geology_stone_temperate", "temp_plants_bog|gaia/fauna_rabbit"].concat(terrains, terrains);
     182terrains = ["temp_plants_bog_aut|gaia/flora_tree_dead"].concat(terrains, terrains);
     183textueByHeight.push({ "upperHeightLimit": waterHeightAdjusted + 1/6 * (heightRange.max - waterHeightAdjusted), "terrain": terrains });
     184
     185/**
     186 * Juicy grass near bog
     187 */
     188textueByHeight.push({ "upperHeightLimit": waterHeightAdjusted + 2/6 * (heightRange.max - waterHeightAdjusted),
     189    "terrain": ["temp_grass", "temp_grass_d", "temp_grass_long_b", "temp_grass_plants"] });
     190
     191/**
     192 * Medium level grass
     193 */
     194textueByHeight.push({ "upperHeightLimit": waterHeightAdjusted + 3/6 * (heightRange.max - waterHeightAdjusted),
     195    "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_mossy"] });
     196
     197/**
     198 * Long grass near forest border
     199 */
     200textueByHeight.push({ "upperHeightLimit": waterHeightAdjusted + 4/6 * (heightRange.max - waterHeightAdjusted),
     201    "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_d", "temp_grass_long_b", "temp_grass_clovers_2", "temp_grass_mossy", "temp_grass_plants"] });
     202
     203/**
     204 * Forest border (With wood/food plants/deer/rabits)
     205 */
     206var terrains = ["temp_grass_plants|gaia/flora_tree_euro_beech", "temp_grass_mossy|gaia/flora_tree_poplar", "temp_grass_mossy|gaia/flora_tree_poplar_lombardy",
    172207    "temp_grass_long|gaia/flora_bush_temperate", "temp_mud_plants|gaia/flora_bush_temperate", "temp_mud_plants|gaia/flora_bush_badlands",
    173208    "temp_grass_long|gaia/flora_tree_apple", "temp_grass_clovers|gaia/flora_bush_berry", "temp_grass_clovers_2|gaia/flora_bush_grapes",
    174209    "temp_grass_plants|gaia/fauna_deer", "temp_grass_long_b|gaia/fauna_rabbit"];
    175 var numTerreins = terreins.length;
    176 for (var i = 0; i < numTerreins; i++)
    177     terreins.push("temp_grass_plants");
    178 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 5/6 * (heightRange.max - waterHeightAdjusted), "terrain": terreins});
    179 // Unpassable woods
    180 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 6/6 * (heightRange.max - waterHeightAdjusted),
     210var numTerreins = terrains.length;
     211for (var i = 0; i < numTerreins; ++i)
     212    terrains.push("temp_grass_plants");
     213textueByHeight.push({ "upperHeightLimit": waterHeightAdjusted + 5/6 * (heightRange.max - waterHeightAdjusted), "terrain": terrains });
     214
     215/**
     216 * Impassable woods
     217 */
     218textueByHeight.push({ "upperHeightLimit": waterHeightAdjusted + 6/6 * (heightRange.max - waterHeightAdjusted),
    181219    "terrain": ["temp_grass_mossy|gaia/flora_tree_oak", "temp_forestfloor_pine|gaia/flora_tree_pine",
    182220    "temp_grass_mossy|gaia/flora_tree_oak", "temp_forestfloor_pine|gaia/flora_tree_pine",
    183221    "temp_mud_plants|gaia/flora_tree_dead", "temp_plants_bog|gaia/flora_tree_oak_large",
    184     "temp_dirt_gravel_plants|gaia/flora_tree_aleppo_pine", "temp_forestfloor_autumn|gaia/flora_tree_carob"]});
     222    "temp_dirt_gravel_plants|gaia/flora_tree_aleppo_pine", "temp_forestfloor_autumn|gaia/flora_tree_carob"] });
    185223var minTerrainDistToBorder = 3;
    186224
    187 // Time check 1
     225/**
     226 * Time check 1
     227 */
    188228timeArray.push(new Date().getTime());
    189229RMS.SetProgress(5);
    190230
    191 
    192 // START THE GIANT WHILE LOOP:
    193 // - Generate Heightmap
    194 // - Search valid start position tiles
    195 // - Choose a good start position derivation (largest distance between closest players)
    196 // - Restart the loop if start positions are invalid or two players are to close to each other
     231/**
     232 * START THE GIANT WHILE LOOP:
     233 * - Generate Heightmap
     234 * - Search valid start position tiles
     235 * - Choose a good start position derivation (largest distance between closest players)
     236 * - Restart the loop if start positions are invalid or two players are to close to each other
     237 */
    197238var goodStartPositionsFound = false;
    198239var minDistBetweenPlayers = 16 + mapSize / 16; // Don't set this higher than 25 for tiny maps! It will take forever with 8 players!
    199240var enoughTiles = false;
    200241var tries = 0;
    201242while (!goodStartPositionsFound)
    202243{
    203     tries++;
     244    ++tries;
    204245    log("Starting giant while loop try " + tries);
    205246    // Generate reliefmap
    206247    var myReliefmap = getRandomReliefmap(heightRange.min, heightRange.max);
    207     for (var i = 0; i < 50 + mapSize/4; i++) // Cycles depend on mapsize (more cycles -> bigger structures)
     248    for (var i = 0; i < 50 + mapSize/4; ++i) // Cycles depend on mapsize (more cycles -> bigger structures)
    208249        myReliefmap = getHeightErrosionedReliefmap(myReliefmap, 1);
    209250    myReliefmap = getRescaledReliefmap(myReliefmap, heightRange.min, heightRange.max);
    210251    setReliefmap(myReliefmap);
     
    217258    var lowerHeightLimit = textueByHeight[3].upperHeightLimit;
    218259    var upperHeightLimit = textueByHeight[6].upperHeightLimit;
    219260    // Check for valid points by height
    220     for (var x = distToBorder + minTerrainDistToBorder; x < mapSize - distToBorder - minTerrainDistToBorder; x++)
     261    for (var x = distToBorder + minTerrainDistToBorder; x < mapSize - distToBorder - minTerrainDistToBorder; ++x)
    221262    {
    222         for (var y = distToBorder + minTerrainDistToBorder; y < mapSize - distToBorder - minTerrainDistToBorder; y++)
     263        for (var y = distToBorder + minTerrainDistToBorder; y < mapSize - distToBorder - minTerrainDistToBorder; ++y)
    223264        {
    224265            var actualHeight = getHeight(x, y);
    225266            if (actualHeight > lowerHeightLimit && actualHeight < upperHeightLimit)
    226267            {
    227268                // Check for points within a valid area by height (rectangular since faster)
    228269                var isPossible = true;
    229                 for (var offX = - neededDistance; offX <= neededDistance; offX++)
     270                for (var offX = - neededDistance; offX <= neededDistance; ++offX)
    230271                {
    231                     for (var offY = - neededDistance; offY <= neededDistance; offY++)
     272                    for (var offY = - neededDistance; offY <= neededDistance; ++offY)
    232273                    {
    233274                        var testHeight = getHeight(x + offX, y + offY);
    234275                        if (testHeight <= lowerHeightLimit || testHeight >= upperHeightLimit)
     
    241282                if (isPossible)
    242283                {
    243284                    possibleStartPositions.push([x, y]);
    244                     // placeTerrain(x, y, "blue"); // For debug reasons. Plz don't remove. // Only works properly for 1 loop
    245285                }
    246286            }
    247287        }
     
    252292    // Reduce to tiles in a circle of mapSize / 2 distance to the center (to avoid players placed in corners)
    253293    var possibleStartPositionsTemp = [];
    254294    var maxDistToCenter = mapSize / 2;
    255     for (var i = 0; i < possibleStartPositions.length; i++)
     295    for (var i = 0; i < possibleStartPositions.length; ++i)
    256296    {
    257297        var deltaX = possibleStartPositions[i][0] - mapSize / 2;
    258298        var deltaY = possibleStartPositions[i][1] - mapSize / 2;
     
    260300        if (distToCenter < maxDistToCenter)
    261301        {
    262302            possibleStartPositionsTemp.push(possibleStartPositions[i]);
    263             // placeTerrain(possibleStartPositions[i][0], possibleStartPositions[i][1], "purple"); // Only works properly for 1 loop
    264303        }
    265304    }
    266305    possibleStartPositions = deepcopy(possibleStartPositionsTemp);
     
    270309    var maxDistToResources = distToBorder; // Has to be <= distToBorder!
    271310    var minNumLowTiles = 10;
    272311    var minNumHighTiles = 10;
    273     for (var i = 0; i < possibleStartPositions.length; i++)
     312    for (var i = 0; i < possibleStartPositions.length; ++i)
    274313    {
    275314        var numLowTiles = 0;
    276315        var numHighTiles = 0;
    277         for (var dx = - maxDistToResources; dx < maxDistToResources; dx++)
     316        for (var dx = - maxDistToResources; dx < maxDistToResources; ++dx)
    278317        {
    279             for (var dy = - maxDistToResources; dy < maxDistToResources; dy++)
     318            for (var dy = - maxDistToResources; dy < maxDistToResources; ++dy)
    280319            {
    281320                var testHeight = getHeight(possibleStartPositions[i][0] + dx, possibleStartPositions[i][1] + dy);
    282321                if (testHeight < lowerHeightLimit)
    283                     numLowTiles++;
     322                    ++numLowTiles;
    284323                if (testHeight > upperHeightLimit)
    285                     numHighTiles++;
     324                    ++numHighTiles;
    286325                if (numLowTiles > minNumLowTiles && numHighTiles > minNumHighTiles)
    287326                    break;
    288327            }
     
    292331        if (numLowTiles > minNumLowTiles && numHighTiles > minNumHighTiles)
    293332        {
    294333            possibleStartPositionsTemp.push(possibleStartPositions[i]);
    295             // placeTerrain(possibleStartPositions[i][0], possibleStartPositions[i][1], "red"); // Only works properly for 1 loop
    296334        }
    297335    }
    298336    possibleStartPositions = deepcopy(possibleStartPositionsTemp);
     
    311349        // Get some random start location derivations. NOTE: Itterating over all possible derivations is just to much (valid points ** numPlayers)
    312350        var maxTries = 100000; // floor(800000 / (Math.pow(numPlayers, 2) / 2));
    313351        var possibleDerivations = [];
    314         for (var i = 0; i < maxTries; i++)
     352        for (var i = 0; i < maxTries; ++i)
    315353        {
    316354            var vector = [];
    317             for (var p = 0; p < numPlayers; p++)
     355            for (var p = 0; p < numPlayers; ++p)
    318356                vector.push(randInt(possibleStartPositions.length));
    319357            possibleDerivations.push(vector);
    320358        }
    321359       
    322360        // Choose the start location derivation with the greatest minimum distance between players
    323361        var maxMinDist = 0;
    324         for (var d = 0; d < possibleDerivations.length; d++)
     362        for (var d = 0; d < possibleDerivations.length; ++d)
    325363        {
    326364            var minDist = 2 * mapSize;
    327             for (var p1 = 0; p1 < numPlayers - 1; p1++)
     365            for (var p1 = 0; p1 < numPlayers - 1; ++p1)
    328366            {
    329                 for (var p2 = p1 + 1; p2 < numPlayers; p2++)
     367                for (var p2 = p1 + 1; p2 < numPlayers; ++p2)
    330368                {
    331369                    if (p1 != p2)
    332370                    {
     
    358396    } // End of derivation check
    359397} // END THE GIANT WHILE LOOP
    360398
    361 // Time check 2
     399/**
     400 * Time check 2
     401 */
    362402timeArray.push(new Date().getTime());
    363403RMS.SetProgress(60);
    364404
    365405
    366 ////////
    367 // Paint terrain by height and add props
    368 ////////
     406/**
     407 * Paint terrain by height and add props
     408 */
    369409
    370410var propDensity = 1; // 1 means as determined in the loop, less for large maps as set below
    371411if (mapSize > 500)
    372412    propDensity = 1/4;
    373413else if (mapSize > 400)
    374414    propDensity = 3/4;
    375 for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; x++)
     415for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; ++x)
    376416{
    377     for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; y++)
     417    for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; ++y)
    378418    {
    379419        var textureMinHeight = heightRange.min;
    380         for (var i = 0; i < textueByHeight.length; i++)
     420        for (var i = 0; i < textueByHeight.length; ++i)
    381421        {
    382422            if (getHeight(x, y) >= textureMinHeight && getHeight(x, y) <= textueByHeight[i].upperHeightLimit)
    383423            {
     
    488528    }
    489529}
    490530
    491 // Time check 3
     531/**
     532 * Time check 3
     533 */
    492534timeArray.push(new Date().getTime());
    493535RMS.SetProgress(90);
    494536
    495537
    496 ////////
    497 // Place players and start resources
    498 ////////
     538/**
     539 * Place players and start resources
     540 */
    499541
    500 for (var p = 0; p < numPlayers; p++)
     542for (var p = 0; p < numPlayers; ++p)
    501543{
    502544    var actualX = possibleStartPositions[bestDerivation[p]][0];
    503545    var actualY = possibleStartPositions[bestDerivation[p]][1];
    504     placeCivDefaultEntities(actualX, actualY, p + 1, BUILDING_ANGlE, {"iberWall" : false});
     546    placeCivDefaultEntities(actualX, actualY, p + 1, BUILDING_ANGlE, { "iberWall" : false });
    505547    // Place some start resources
    506548    var uDist = 8;
    507549    var uSpace = 1;
     
    509551    {
    510552        var uAngle = BUILDING_ANGlE - PI * (2-j) / 2;
    511553        var count = 4;
    512         for (var numberofentities = 0; numberofentities < count; numberofentities++)
     554        for (var numberofentities = 0; numberofentities < count; ++numberofentities)
    513555        {
    514556            var ux = actualX + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2));
    515557            var uz = actualY + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2));
     
    521563    }
    522564}
    523565
    524 
    525 // Export map data
     566/**
     567 * Export map data
     568 */
    526569ExportMap();
    527570
    528 // Time check 7
     571/**
     572 * Time check 7
     573 */
    529574timeArray.push(new Date().getTime());
    530575
    531 // Calculate progress percentage with the time checks
     576/**
     577 * Calculate progress percentage with the time checks
     578 */
    532579var generationTime = timeArray[timeArray.length - 1] - timeArray[0];
    533580log("Total generation time (ms): " + generationTime);
    534 for (var i = 0; i < timeArray.length; i++)
     581for (var i = 0; i < timeArray.length; ++i)
    535582{
    536583    var timeSinceStart = timeArray[i] - timeArray[0];
    537584    var progressPercentage = 100 * timeSinceStart / generationTime;
  • binaries/data/mods/public/maps/random/realisticTerrainDemo.js

     
     1/**
     2*   ToDo:
     3*   Add further biomes
     4*   Place start locations of one team close to each other
     5*   Raise the entire map if to much water
     6*
     7*   Add support for circular maps
     8*   Add parameters for match setup screen (for later use and demonstration)
     9*
     10*   Extract some functions to an RMGEN lib
     11*   Sort out unneeded functions calling other functions
     12*   Clean up
     13*/
     14
     15/**
     16* Start Timer
     17*/
     18var genStartTime = new Date().getTime();
     19
     20RMS.LoadLibrary("rmgen");
     21
     22const BUILDING_ANGlE = -PI/4;
     23
     24/**
     25* initialize map
     26*/
     27log("Initializing map...");
     28InitMap();
     29
     30
     31/**
     32*  Some general functions
     33*/
     34
     35/**
     36*   Takes an array of 2D points (arrays of length 2)
     37*   Returns the order to go through the points for the shortest closed path (array of indices)
     38*/
     39function getOrderOfPointsForShortestClosePath(points)
     40{
     41    var order = [];
     42    var distances = [];
     43    if (points.length <= 3)
     44    {
     45        for (var i = 0; i < points.length; ++i)
     46            order.push(i);
     47       
     48        return order;
     49    }
     50   
     51    // Just add the first 3 points
     52    var pointsToAdd = deepcopy(points);
     53    for (var i = 0; i < min(points.length, 3); ++i)
     54    {
     55        order.push(i)
     56        pointsToAdd.shift(i);
     57        if (i)
     58            distances.push(getDistance(points[order[i]].x, points[order[i]].y, points[order[i - 1]].x, points[order[i - 1]].y));
     59    }
     60    distances.push(getDistance(points[order[0]].x, points[order[0]].y, points[order[order.length - 1]].x, points[order[order.length - 1]].y))
     61   
     62    // Add remaining points so the path lengthens the least
     63    var numPointsToAdd = pointsToAdd.length;
     64    for (var i = 0; i < numPointsToAdd; ++i)
     65    {
     66        var indexToAddTo = undefined;
     67        var minEnlengthen = Infinity;
     68        var minDist1 = 0;
     69        var minDist2 = 0;
     70        for (var k = 0; k < order.length; ++k)
     71        {
     72            var dist1 = getDistance(pointsToAdd[0].x, pointsToAdd[0].y, points[order[k]].x, points[order[k]].y);
     73            var dist2 = getDistance(pointsToAdd[0].x, pointsToAdd[0].y, points[order[(k + 1) % order.length]].x, points[order[(k + 1) % order.length]].y);
     74            var enlengthen = dist1 + dist2 - distances[k];
     75            if (enlengthen < minEnlengthen)
     76            {
     77                indexToAddTo = k;
     78                minEnlengthen = enlengthen;
     79                minDist1 = dist1;
     80                minDist2 = dist2;
     81            }
     82        }
     83        order.splice(indexToAddTo + 1, 0, i + 3);
     84        distances.splice(indexToAddTo, 1, minDist1, minDist2);
     85        pointsToAdd.shift();
     86    }
     87   
     88    return order;
     89}
     90
     91/*
     92Drags a path to a target height smoothing it at the edges and return some points on the path.
     93
     94TODO:
     95Would be nice to tell the function what to do and how often in the arguments
     96Adding painted tiles to a tile class
     97*/
     98function placeRandomPathToHeight(start, paintPathWithTexture, target, targetHeight, width, occurrence, strength, heightmap)
     99{
     100    if (paintPathWithTexture === false)
     101        paintPathWithTexture = [false, ""];
     102    else if (paintPathWithTexture === true)
     103        paintPathWithTexture = [true, ['temp_road', "temp_road_overgrown", 'temp_grass_b']]
     104    else
     105        paintPathWithTexture = (paintPathWithTexture || [false, ['temp_road', "temp_road_overgrown", 'temp_grass_b']]);
     106    var paintPath = paintPathWithTexture[0];
     107    var pathTexture = paintPathWithTexture[1];
     108    width = (width || 10);
     109    occurrence = (occurrence || 2);
     110    strength = (strength || 0.5);
     111    heightmap = (heightmap || g_Map.height);
     112   
     113    var clTempPath = createTileClass();
     114    var targetReached = false;
     115    var position = deepcopy(start);
     116    while (!targetReached)
     117    {
     118        rectangularSmoothToHeight(position, width, width, targetHeight, strength, heightmap);
     119        if (paintPath)
     120        {
     121            var placer = new ClumpPlacer(0.2 * width * width, 1, 1, 1, round(position.x), round(position.y));
     122            var painter = [new TerrainPainter(pathTexture), paintClass(clTempPath)];
     123            createArea(placer, painter);
     124        }
     125       
     126        // Set vars for next loop
     127        var angleToTarget = getAngle(position.x, position.y, target.x, target.y);
     128        var angleOff = PI * (randFloat() - 0.5);
     129        position.x += occurrence * cos(angleToTarget + angleOff);
     130        position.y += occurrence * sin(angleToTarget + angleOff);
     131        if (getDistance(position.x, position.y, target.x, target.y) < occurrence / 2)
     132            targetReached = true;
     133    }
     134    return clTempPath;
     135}
     136
     137
     138/**
     139*  Actually do stuff
     140*/
     141
     142/**
     143* Set height limits and water level by map size
     144*/
     145
     146/**
     147* Set target min and max height depending on map size to make average steepness about the same on all map sizes
     148*/
     149var heightRange = { "min": MIN_HEIGHT * (g_Map.size + 512) / 8192, "max": MAX_HEIGHT * (g_Map.size + 512) / 8192 };
     150
     151/**
     152* Set average water coverage
     153*/
     154var averageWaterCoverage = 1/5; // NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with the same value
     155var waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); // Water height in environment and the engine
     156var waterHeightAdjusted = waterHeight + MIN_HEIGHT; // Water height in RMGEN
     157setWaterHeight(waterHeight);
     158
     159
     160/**
     161* Generate base terrain
     162*/
     163
     164var initialReliefmap = undefined;
     165var low = heightRange.min;
     166var med = 0.5 * (heightRange.min + heightRange.max);
     167var high = heightRange.max;
     168/**
     169* Island
     170*/
     171// initialReliefmap = [[low, low, low], [low, high, low], [low, low, low]];
     172initialReliefmap = [[low, low, low, low], [low, high, high, low], [low, high, high, low], [low, low, low, low]];
     173/**
     174* Mountain
     175*/
     176// initialReliefmap = [[low, med, low], [med, high, med], [low, med, low]];
     177/**
     178* Lake
     179*/
     180// initialReliefmap = [[high, high, high], [high, low, high], [high, high, high]];
     181// initialReliefmap = [[high, high, high, high], [high, low, low, high], [high, low, low, high], [high, high, high, high]];
     182/**
     183* Extreme Edges
     184*/
     185// initialReliefmap = [[high, med, low], [med, med, med], [low, med, high]];
     186// initialReliefmap = [[high, med, med, low], [med, med, med, med], [med, med, med, med], [med, med, med, med], [low, med, med, high]];
     187/**
     188* Extreme Center
     189*/
     190// initialReliefmap = [[med, med, med, med], [med, high, low, med], [med, low, high, med], [med, med, med, med]];
     191setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, /*0.5*/ 0.8, initialReliefmap, g_Map.height);
     192/**
     193* Apply simple erosion
     194*/
     195for (var i = 0; i < 3; ++i)
     196    globalSmoothHeightmap(0.5);
     197rescaleHeightmap(heightRange.min, heightRange.max);
     198
     199
     200/**
     201* Setup biome and texture height limit
     202*/
     203
     204/**
     205* myBiome presets
     206*/
     207
     208/**
     209* Height presets
     210*/
     211var heighLimits = [
     212    heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), // 0 Deep water
     213    heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), // 1 Medium Water
     214    heightRange.min + (waterHeightAdjusted - heightRange.min), // 2 Shallow water
     215    waterHeightAdjusted + 1/8 * (heightRange.max - waterHeightAdjusted), // 3 Shore
     216    waterHeightAdjusted + 2/8 * (heightRange.max - waterHeightAdjusted), // 4 Low ground
     217    waterHeightAdjusted + 3/8 * (heightRange.max - waterHeightAdjusted), // 5 Player and path height
     218    waterHeightAdjusted + 4/8 * (heightRange.max - waterHeightAdjusted), // 6 High ground
     219    waterHeightAdjusted + 5/8 * (heightRange.max - waterHeightAdjusted), // 7 Lower forest border
     220    waterHeightAdjusted + 6/8 * (heightRange.max - waterHeightAdjusted), // 8 Forest
     221    waterHeightAdjusted + 7/8 * (heightRange.max - waterHeightAdjusted), // 9 Upper forest border
     222    waterHeightAdjusted + (heightRange.max - waterHeightAdjusted)]; // 10 Hilltop
     223
     224/**
     225* Add tile painting presets for each biome
     226*/
     227var dummyActor = "actor|props/special/common/waypoint_flag.xml";
     228var myBiome = [];
     229/**
     230* temperate 1
     231*/
     232myBiome.push([]);
     233/**
     234* snowy 2
     235*/
     236myBiome.push([]);
     237/**
     238* desert 3
     239*/
     240myBiome.push([]);
     241/**
     242* Alpine 4
     243*/
     244myBiome.push([]);
     245myBiome[myBiome.length - 1].push({ // 0 Deep water
     246    "texture": ["shoreline_stoney_a"], "actor": [["gaia/fauna_fish", "actor|geology/stone_granite_boulder.xml"], 0.02],
     247    "textureHS": ["alpine_mountainside"], "actorHS": [["gaia/fauna_fish"], 0.1] });
     248myBiome[myBiome.length - 1].push({ // 1 Medium Water
     249    "texture": ["shoreline_stoney_a", "alpine_shore_rocks"], "actor": [["actor|geology/stone_granite_boulder.xml"], 0.03],
     250    "textureHS": ["alpine_mountainside"], "actorHS": [["actor|geology/stone_granite_boulder.xml"], 0.0] });
     251myBiome[myBiome.length - 1].push({ // 2 Shallow water
     252    "texture": ["alpine_shore_rocks"], "actor": [["actor|props/flora/reeds_pond_dry.xml", "actor|geology/stone_granite_large.xml", "actor|geology/stone_granite_med.xml", "actor|props/flora/reeds_pond_lush_b.xml"], 0.2],
     253    "textureHS": ["alpine_mountainside"], "actorHS": [["actor|props/flora/reeds_pond_dry.xml", "actor|geology/stone_granite_med.xml"], 0.1] });
     254myBiome[myBiome.length - 1].push({ // 3 Shore
     255    "texture": ["alpine_shore_rocks_grass_50", "alpine_grass_rocky"], "actor": [["gaia/flora_tree_pine", "gaia/flora_bush_badlands", "actor|geology/highland1_moss.xml", "actor|props/flora/grass_soft_tuft_a.xml", "actor|props/flora/bush.xml"], 0.3],
     256    "textureHS": ["alpine_mountainside"], "actorHS": [["actor|props/flora/grass_soft_tuft_a.xml"], 0.1] });
     257myBiome[myBiome.length - 1].push({ // 4 Low ground
     258    "texture": ["alpine_dirt_grass_50", "alpine_grass_rocky"], "actor": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_soft_tuft_a.xml", "actor|props/flora/bush.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2],
     259    "textureHS": ["alpine_grass_rocky"], "actorHS": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_soft_tuft_a.xml"], 0.1] });
     260myBiome[myBiome.length - 1].push({ // 5 Player and path height
     261    "texture": ["new_alpine_grass_c", "new_alpine_grass_b", "new_alpine_grass_d"], "actor": [["actor|geology/stone_granite_small.xml", "actor|props/flora/grass_soft_small.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2],
     262    "textureHS": ["alpine_grass_rocky"], "actorHS": [["actor|geology/stone_granite_small.xml", "actor|props/flora/grass_soft_small.xml"], 0.1] });
     263myBiome[myBiome.length - 1].push({ // 6 High ground
     264    "texture": ["new_alpine_grass_a", "alpine_grass_rocky"], "actor": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_tufts_a.xml", "actor|props/flora/bush_highlands.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2],
     265    "textureHS": ["alpine_grass_rocky"], "actorHS": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_tufts_a.xml"], 0.1] });
     266myBiome[myBiome.length - 1].push({ // 7 Lower forest border
     267    "texture": ["new_alpine_grass_mossy", "alpine_grass_rocky"], "actor": [["gaia/flora_tree_pine", "actor|props/flora/grass_tufts_a.xml", "gaia/flora_bush_berry", "gaia/flora_bush_berry", "gaia/flora_bush_berry", "actor|geology/highland2_moss.xml", "gaia/fauna_goat", "actor|props/flora/bush_tempe_underbrush.xml"], 0.3],
     268    "textureHS": ["alpine_cliff_c"], "actorHS": [["actor|props/flora/grass_tufts_a.xml", "actor|geology/highland2_moss.xml"], 0.1] });
     269myBiome[myBiome.length - 1].push({ // 8 Forest
     270    "texture": ["alpine_forrestfloor"], "actor": [["gaia/flora_tree_pine", "gaia/flora_tree_pine", "gaia/flora_tree_pine", "gaia/flora_tree_pine", "actor|geology/highland2_moss.xml", "actor|props/flora/bush_highlands.xml"], 0.5],
     271    "textureHS": ["alpine_cliff_c"], "actorHS": [["actor|geology/highland2_moss.xml", "actor|geology/stone_granite_med.xml"], 0.1] });
     272myBiome[myBiome.length - 1].push({ // 9 Upper forest border
     273    "texture": ["alpine_forrestfloor_snow", "new_alpine_grass_dirt_a"], "actor": [["gaia/flora_tree_pine", "actor|geology/snow1.xml"], 0.3],
     274    "textureHS": ["alpine_cliff_b"], "actorHS": [["actor|geology/stone_granite_med.xml", "actor|geology/snow1.xml"], 0.1] });
     275myBiome[myBiome.length - 1].push({ // 10 Hilltop
     276    "texture": ["alpine_cliff_a"], "actor": [["actor|geology/highland1.xml"], 0.05],
     277    "textureHS": ["alpine_cliff_c"], "actorHS": [["actor|geology/highland1.xml"], 0.0] });
     278/**
     279* medit 5
     280*/
     281myBiome.push([]);
     282/**
     283* savanah 6
     284*/
     285myBiome.push([]);
     286/**
     287* tropic 7
     288*/
     289myBiome.push([]);
     290/**
     291* autumn 8
     292*/
     293myBiome.push([]);
     294
     295/**
     296* Set random biome
     297*/
     298while (biomeID != 4)
     299    randomizeBiome();
     300log("biomeID = " + biomeID); // DEBUG
     301
     302if (biomeID == 4)
     303{
     304    g_Environment.Fog.FogColor = { "r": 0.8, "g": 0.8, "b": 0.8, "a": 0 };
     305    g_Environment.Water.WaterBody.Colour = { "r" : 0.0, "g" : 0.05, "b" : 0.1, "a" : 0 };
     306    g_Environment.Water.WaterBody.Murkiness = 0.5;
     307    rbt7 = rbt8;
     308    rbt8 = rbt1
     309    rbt1 = [rbt9[1]];
     310    rbt9 = [rbt9[0]];
     311}
     312if (biomeID == 6)
     313    rbt9 = [rbt9[1]];
     314if (biomeID == 8)
     315    rbt9 = rbt6;
     316
     317
     318/**
     319* Place start locations and apply terrain texture and decorative props by height
     320*/
     321
     322/**
     323* Get start locations
     324*/
     325var startLocations = getStartLocationsByHeightmap({ "min": heighLimits[4], "max": heighLimits[5] });
     326var playerHeight = (heighLimits[4] + heighLimits[5]) / 2;
     327
     328/**
     329* Place start locations
     330*/
     331for (var p = 0; p < g_MapSettings.PlayerData.length - 1; ++p)
     332{
     333    rectangularSmoothToHeight(startLocations[p], 35, 35, playerHeight, 0.8);
     334    placeCivDefaultEntities(startLocations[p].x, startLocations[p].y, p + 1, BUILDING_ANGlE, { "iberWall": true });
     335    // Place resources at start locations
     336    var uDist = 8;
     337    var uSpace = 1.2;
     338    for (var j = 1; j <= 4; ++j)
     339    {
     340        var uAngle = BUILDING_ANGlE - PI * (2-j) / 2;
     341        var count = 4;
     342        for (var numberofentities = 0; numberofentities < count; ++numberofentities)
     343        {
     344            var ux = startLocations[p].x + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2));
     345            var uz = startLocations[p].y + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2));
     346            if (j % 2 == 0)
     347                placeObject(ux, uz, rbe6, 0, randFloat(0, 2*PI));
     348            else
     349                placeObject(ux, uz, rbe4, 0, randFloat(0, 2*PI));
     350        }
     351    }
     352    ux = startLocations[p].x + 10 * cos(BUILDING_ANGlE + PI / 4);
     353    uz = startLocations[p].y + 10 * sin(BUILDING_ANGlE + PI / 4);
     354    placeObject(ux, uz, rbe11, 0, randFloat(0, 2*PI));
     355    ux = startLocations[p].x + 10 * cos(BUILDING_ANGlE - 3 * PI / 4);
     356    uz = startLocations[p].y + 10 * sin(BUILDING_ANGlE - 3 * PI / 4);
     357    placeObject(ux, uz, rbe13, 0, randFloat(0, 2*PI));
     358}
     359
     360/**
     361* Add further stone and metal mines
     362*/
     363distributeEntitiesByHeight({ "min": heighLimits[4], "max": heighLimits[5] }, startLocations);
     364
     365/**
     366* Add paths
     367*/
     368var pathTerrainClasseIDs = [];
     369var pathPointDist = 3;
     370var startLocationOrder = getOrderOfPointsForShortestClosePath(startLocations);
     371// for (var i = 0; i < startLocationOrder.length; ++i)
     372// {
     373    // var start = startLocations[startLocationOrder[i]];
     374    // var target = startLocations[startLocationOrder[(i + 1) % startLocationOrder.length]];
     375    // pathTerrainClasseIDs.push(placeRandomPathToHeight(start, [true, "road_rome_a"], target, playerHeight, 10, pathPointDist, 0.2));
     376// }
     377
     378/**
     379* Calculate slope map (Not entirely sure if correct or slopeMap is the correct term)
     380*/
     381var slopeMap = getSlopeMap();
     382
     383/**
     384* Calculate tileCenteredHeightMap (This has nothing to to with TILE_CENTERED_HEIGHT_MAP which should be false (default) for this map to work properly)
     385*/
     386var tchm = getTileCenteredHeightmap();
     387
     388/**
     389* Divide tiles in areas by height and avoid paths
     390*/
     391var areas = [];
     392var pathAreas = [];
     393for (var i = 0; i < pathTerrainClasseIDs.length; ++i)
     394    pathAreas.push([]);
     395for (var h = 0; h < heighLimits.length; ++h)
     396    areas.push([]);
     397for (var x = 0; x < tchm.length; ++x)
     398{
     399    for (var y = 0; y < tchm[0].length; ++y)
     400    {
     401        var isPath = false;
     402        for (var i = 0; i < pathTerrainClasseIDs.length; ++i)
     403        {
     404            if (getTileClass(pathTerrainClasseIDs[i]).countMembersInRadius(x, y, 0.5))
     405            {
     406                pathAreas[i].push({ "x": x, "y": y });
     407                isPath = true;
     408                break;
     409            }
     410        }
     411        if (isPath)
     412            continue;
     413       
     414        var minHeight = heightRange.min;
     415        for (var h = 0; h < heighLimits.length; ++h)
     416        {
     417            if (tchm[x][y] >= minHeight && tchm[x][y] <= heighLimits[h])
     418            {
     419                areas[h].push({ "x": x, "y": y });
     420                break;
     421            }
     422            else
     423                minHeight = heighLimits[h];
     424        }
     425    }
     426}
     427
     428/**
     429* Get max slope of each area
     430*/
     431var minSlope = new Array(areas.length);
     432var maxSlope = new Array(areas.length);
     433for (var h = 0; h < heighLimits.length; ++h)
     434{
     435    minSlope[h] = Infinity;
     436    maxSlope[h] = 0;
     437    for (var t = 0; t < areas[h].length; ++t)
     438    {
     439        var x = areas[h][t].x;
     440        var y = areas[h][t].y;
     441        var slope = slopeMap[x][y];
     442        if (slope > maxSlope[h])
     443            maxSlope[h] = slope;
     444        if (slope < minSlope[h])
     445            minSlope[h] = slope;
     446    }
     447}
     448
     449/**
     450* Paint areas by height and slope
     451*/
     452for (var h = 0; h < heighLimits.length; ++h)
     453{
     454    for (var t = 0; t < areas[h].length; ++t)
     455    {
     456        var x = areas[h][t].x;
     457        var y = areas[h][t].y;
     458        var actor = undefined;
     459        if (slopeMap[x][y] < 0.5 * (minSlope[h] + maxSlope[h]))
     460        {
     461            var texture = myBiome[biomeID - 1][h].texture[randInt(myBiome[biomeID - 1][h].texture.length)];
     462            if (randFloat() < myBiome[biomeID - 1][h].actor[1])
     463                actor = myBiome[biomeID - 1][h].actor[0][randInt(myBiome[biomeID - 1][h].actor[0].length)];
     464        }
     465        else
     466        {
     467            var texture = myBiome[biomeID - 1][h].textureHS[randInt(myBiome[biomeID - 1][h].textureHS.length)];
     468            if (randFloat() < myBiome[biomeID - 1][h].actorHS[1])
     469                actor = myBiome[biomeID - 1][h].actorHS[0][randInt(myBiome[biomeID - 1][h].actorHS[0].length)];
     470        }
     471        g_Map.setTexture(x, y, texture);
     472        if (actor)
     473            placeObject(x + 0.5, y + 0.5, actor, 0, randFloat() * TWO_PI);
     474    }
     475}
     476
     477/**
     478* Stop Timer
     479*/
     480log("Map generation time: " + (new Date().getTime() - genStartTime))
     481
     482/**
     483* Export map data
     484*/
     485ExportMap();
  • binaries/data/mods/public/maps/random/realisticTerrainDemo.json

     
     1{
     2    "settings" : {
     3        "Name" : "Realistic Terrain Demo",
     4        "Script" : "realisticTerrainDemo.js",
     5        "Description" : "A map to demonstrate playability of more realistic random terrain.",
     6        "CircularMap" : false,
     7        "BaseTerrain" : "whiteness",
     8        "BaseHeight" : 0,
     9        "Keywords": ["demo"],
     10        "XXXXXX" : "Optionally define other things here, like we would for a scenario"
     11    }
     12}
     13 No newline at end of file
  • binaries/data/mods/public/maps/random/rmgen/heightmap_manipulation.js

     
     1/**
     2*   Heightmap manipulation functionality
     3*
     4*   A heightmapt is an array of width arrays of height floats
     5*   Width and height is normally mapSize+1 (Number of vertices is one bigger than number of tiles in each direction)
     6*   The default heightmap is g_Map.height (See the Map object)
     7*
     8*   NOTE (ambiguous naming/potential confusion):
     9*       For using this heightmap functionalities it is VITAL that TILE_CENTERED_HEIGHT_MAP = false (default)!
     10*       Otherwise TILE_CENTERED_HEIGHT_MAP has nothing to do with any tile centered heightmap in this library!
     11*       All tile centered heightmaps in this module are temporary objects only and should never replace g_Map.height!
     12*       (Tile centered heightmaps are one less in width and hight than heightmaps used by the engine)
     13*       (Multiple conversions will lead to strange smoothing effects at best and potentially break the map entirely!)
     14*       In the long run TILE_CENTERED_HEIGHT_MAP should be removed and g_Map.height should never be tile centered...
     15*/
     16
     17/**
     18* getMinAndMaxHeight
     19*   Optionally takes a heightmap, default is g_Map.height
     20*   Returns the minimum and maximum heights present in this heightmap (an associative array of the form {"min": minHeight, "max": maxHeight})
     21*/
     22function getMinAndMaxHeight(heightmap)
     23{
     24    heightmap = (heightmap || g_Map.height)
     25    var height = {};
     26    height.min = Infinity;
     27    height.max = - Infinity;
     28    for (var x = 0; x < heightmap.length; ++x)
     29    {
     30        for (var y = 0; y < heightmap[x].length; ++y)
     31        {
     32            if (heightmap[x][y] < height.min)
     33                height.min = heightmap[x][y];
     34            else if (heightmap[x][y] > height.max)
     35                height.max = heightmap[x][y];
     36        }
     37    }
     38    return height;
     39}
     40
     41/**
     42* rescaleHeightmap
     43*   Takes:
     44*       Optional minHeight(float), minimum height that should be used for the resulting heightmap, default is MIN_HEIGHT
     45*       Optional maxHeight(float), maximum height that should be used for the resulting heightmap, default is MAX_HEIGHT
     46*       Optional heightmap, default is g_Map.height
     47*   Rescales the heightmap so its minimum and maximum height is as the arguments told (preserving it's global shape)
     48*/
     49function rescaleHeightmap(minHeight, maxHeight, heightmap)
     50{
     51    minHeight = (minHeight || MIN_HEIGHT);
     52    maxHeight = (maxHeight || MAX_HEIGHT);
     53    heightmap = (heightmap || g_Map.height);
     54   
     55    var oldHeightRange = getMinAndMaxHeight(heightmap);
     56    var max_x = heightmap.length;
     57    var max_y = heightmap[0].length;
     58    for (var x = 0; x < max_x; ++x)
     59        for (var y = 0; y < max_y; ++y)
     60            heightmap[x][y] = minHeight + (heightmap[x][y] - oldHeightRange.min) / (oldHeightRange.max - oldHeightRange.min) * (maxHeight - minHeight);
     61}
     62
     63/**
     64* getInclineMap
     65*   Optionally takes a heightmap, default is g_Map.height
     66*   Returns an inclination map corresponding to the tiles between the heightmaps vertices:
     67*       array of heightmap width-1 arrays of height-1 vectors (associative arrays) of the from:
     68*           {"x": x_slope, "y": y_slope] so a 2D Vector pointing to the hightest incline (with the length the incline in the vectors direction)
     69* NOTE: The x and y coordinates of a tile in the terrain texture map correspond to those of the inclination map
     70*/
     71function getInclineMap(heightmap)
     72{
     73    heightmap = (heightmap || g_Map.height);
     74    var max_x = heightmap.length - 1;
     75    var max_y = heightmap[0].length - 1;
     76    var inclineMap = [];
     77    for (var x = 0; x < max_x; ++x)
     78    {
     79        inclineMap[x] = [];
     80        for (var y = 0; y < max_y; ++y)
     81        {
     82            var dx = heightmap[x + 1][y] - heightmap[x][y];
     83            var dy = heightmap[x][y + 1] - heightmap[x][y];
     84            var next_dx = heightmap[x + 1][y + 1] - heightmap[x][y + 1];
     85            var next_dy = heightmap[x + 1][y + 1] - heightmap[x + 1][y];
     86            inclineMap[x][y] = {"x": 0.5 * (dx + next_dx), "y": 0.5 * (dy + next_dy)};
     87        }
     88    }
     89    return inclineMap;
     90}
     91
     92/**
     93* getSlopeMap
     94*   Optionally takes an inclineMap, default is getInclineMap(g_Map.height)
     95*   Returns a slope map (same form as the a heightmap with one less width and height)
     96* NOTES:
     97*   Not normalized. Only returns the steepness (float), not the direction of incline.
     98*   The x and y coordinates of a tile in the terrain texture map correspond to those of the slope map
     99*/
     100function getSlopeMap(inclineMap)
     101{
     102    inclineMap = (inclineMap || getInclineMap(g_Map.height));
     103    var max_x = inclineMap.length;
     104    var slopeMap = new Array(max_x);
     105    for (var x = 0; x < max_x; ++x)
     106    {
     107        var max_y = inclineMap[x].length;
     108        slopeMap[x] = new Float32Array(max_y);
     109        for (var y = 0; y < max_y; ++y)
     110            slopeMap[x][y] = Math.pow(inclineMap[x][y].x * inclineMap[x][y].x + inclineMap[x][y].y * inclineMap[x][y].y, 0.5);
     111    }
     112    return slopeMap;
     113}
     114
     115/**
     116* getTileCenteredHeightmap
     117*   Optionally takes a heightmap, default is g_Map.height
     118*   Returns an approximation of the heights of the tiles between the vertices, a tile centered heightmap
     119*   NOTE:
     120*       A tile centered heightmap is one smaller in width and height than an ordinary heightmap
     121*       It is meant to e.g. texture a map by height (x/y coordinates correspond to those of the terrain texture map)
     122*       Don't use this to override g_Map height (Potentially breaks the map)!
     123*/
     124function getTileCenteredHeightmap(heightmap)
     125{
     126    heightmap = (heightmap || g_Map.height);
     127    var max_x = heightmap.length - 1;
     128    var max_y = heightmap[0].length - 1;
     129    var tchm = new Array(max_x);
     130    for (var x = 0; x < max_x; ++x)
     131    {
     132        tchm[x] = new Float32Array(max_y);
     133        for (var y = 0; y < max_y; ++y)
     134        {
     135            tchm[x][y] = 0.25 * (heightmap[x][y] + heightmap[x + 1][y] + heightmap[x][y + 1] + heightmap[x + 1][y + 1]);
     136        }
     137    }
     138    return tchm;
     139}
     140
     141/**
     142*   getStartLocationsByHeightmap
     143*
     144*   Description:
     145*       Get start location with the largest minimum distance between players
     146*   Takes
     147*       hightRange      An associative array with keys "min" and "max" each containing a float (the height range start locations are allowed)
     148*       maxTries        Optional, default is 1000, an integer, how often random player distributions are rolled to be compared
     149*       minDistToBorder Optional, default is 20, an integer, how far start locations have to be away from the map border
     150*       numberOfPlayers Optional, default is g_MapSettings.PlayerData.length, an integer, how many start locations should be placed
     151*       Heightmap       Optional, default is g_Map.height, the heightmap for the start locations to be placed on
     152*   Returns
     153*       An array of 2D points (arrays of length 2)
     154*/
     155function getStartLocationsByHeightmap(hightRange, maxTries, minDistToBorder, numberOfPlayers, heightmap)
     156{
     157    maxTries = (maxTries || 1000);
     158    minDistToBorder = (minDistToBorder || 20);
     159    numberOfPlayers = (numberOfPlayers || g_MapSettings.PlayerData.length);
     160    heightmap = (heightmap || g_Map.height);
     161   
     162    var validStartLoc = [];
     163    for (var x = minDistToBorder; x < heightmap.length - minDistToBorder; ++x)
     164        for (var y = minDistToBorder; y < heightmap[0].length - minDistToBorder; ++y)
     165            if (heightmap[x][y] > hightRange.min && heightmap[x][y] < hightRange.max) // Has the right hight
     166                validStartLoc.push({"x": x, "y": y});
     167   
     168    var maxMinDist = 0;
     169    for (var tries = 0; tries < maxTries; ++tries)
     170    {
     171        var startLoc = [];
     172        var minDist = heightmap.length;
     173        for (var p = 0; p < numberOfPlayers; ++p)
     174            startLoc.push(validStartLoc[randInt(validStartLoc.length)]);
     175        for (var p1 = 0; p1 < numberOfPlayers - 1; ++p1)
     176        {
     177            for (var p2 = p1 + 1; p2 < numberOfPlayers; ++p2)
     178            {
     179                var dist = getDistance(startLoc[p1].x, startLoc[p1].y, startLoc[p2].x, startLoc[p2].y);
     180                if (dist < minDist)
     181                    minDist = dist;
     182            }
     183        }
     184        if (minDist > maxMinDist)
     185        {
     186            maxMinDist = minDist;
     187            var finalStartLoc = startLoc;
     188        }
     189    }
     190   
     191    return finalStartLoc;
     192}
     193
     194/**
     195*   distributeEntitiesByHeight
     196*   Takes
     197*       hightRange      An associative array with keys "min" and "max" each containing a float (the height range start locations are allowed)
     198*       startLoc        An array of 2D points (arrays of length 2)
     199*       heightmap       Optional, default is g_Map.height, an array of (map width) arrays of (map depth) floats
     200*       entityList      Array of entities/actors (strings to be placed with placeObject())
     201*       maxTries        Optional, default is 1000, an integer, how often random player distributions are rolled to be compared
     202*       minDistance     Optional, default is 30, an integer, how far start locations have to be away from start locations and the map border
     203*   Returns
     204*       An array of 2D points (arrays of length 2)
     205*/
     206function distributeEntitiesByHeight(hightRange, startLoc, entityList, maxTries, minDistance, heightmap)
     207{
     208    entityList = (entityList || [rbe11, rbe13]);
     209    maxTries = (maxTries || 1000);
     210    minDistance = (minDistance || 30);
     211    heightmap = (heightmap || g_Map.height);
     212   
     213    var placements = deepcopy(startLoc);
     214    var validTiles = [];
     215    for (var x = minDistance; x < heightmap.length - minDistance; ++x)
     216        for (var y = minDistance; y < heightmap[0].length - minDistance; ++y)
     217            if (heightmap[x][y] > hightRange.min && heightmap[x][y] < hightRange.max) // Has the right hight
     218                validTiles.push({"x": x, "y": y});
     219   
     220    for (var tries = 0; tries < maxTries; ++tries)
     221    {
     222        var tile = validTiles[randInt(validTiles.length)];
     223        var isValid = true;
     224        for (var p = 0; p < placements.length; ++p)
     225        {
     226            if (getDistance(placements[p].x, placements[p].y, tile.x, tile.y) < minDistance)
     227            {
     228                isValid = false;
     229                break;
     230            }
     231        }
     232        if (isValid)
     233        {
     234            placeObject(tile.x, tile.y, entityList[randInt(entityList.length)], 0, randFloat(0, 2*PI));
     235            placements.push(tile);
     236        }
     237    }
     238}
     239
     240/**
     241*   setBaseTerrainDiamondSquare
     242*
     243*   Description:
     244*       Sets the heightmap to a relatively realistic shape.
     245*   Takes:
     246*       minHeight           Optional, Float, Default is the absolute possible minimum height
     247*                           Minimum height that can occur in the resulting heightmap
     248*       maxHeight           Optional, Float, Default is the absolute possible maximum height
     249*                           Maximum height that can occur in the resulting heightmap
     250*       smoothness          Optional, Float between 0 (rough) to 1 (smooth), Default is 0.5
     251*                           Lower values (rough) will generate more local structures (but should be smoothed e.g. with erosion later)
     252*       initialHeightmap    Optional, Array of width Arrays of depth Floats (usually a small square heightmap e.g. 2x2)
     253*                           Sets some initial heights at the edges (square heightmap of size 2) or more more specifically with bigger initial heightmaps
     254*       heightmap           Optional, Array of width Arrays of depth Floats (a heightmap), Default is g_Map.height
     255*                           The heightmap that will be set by this function
     256*   Returns nothing
     257*   NOTES:
     258*       min/maxHeight will not necessarily be present in the heightmap
     259*       This function only supports rectangular heightmaps.
     260*           This means that e.g. the edges (given by initialHeightmap) will not be in the playable map area in circular maps.
     261*       The function doubles the size of the initial heightmap (if given, else a random 2x2 one) until it's big enough.
     262*           Then the extend is cut. So the impact and scale of the initial heightmap depends on its size and the target map size.
     263*/
     264function setBaseTerrainDiamondSquare(minHeight, maxHeight, smoothness, initialHeightmap, heightmap)
     265{
     266    // Make some arguments optional
     267    minHeight = (minHeight || MIN_HEIGHT);
     268    maxHeight = (maxHeight || MAX_HEIGHT);
     269    var heightRange = maxHeight - minHeight;
     270    if (heightRange <= 0)
     271        warn("setBaseTerrainDiamondSquare: heightRange < 0");
     272    smoothness = (smoothness || 0.5);
     273    initialHeightmap = (initialHeightmap || [[randFloat(minHeight / 2, maxHeight / 2), randFloat(minHeight / 2, maxHeight / 2)], [randFloat(minHeight / 2, maxHeight / 2), randFloat(minHeight / 2, maxHeight / 2)]]);
     274    heightmap = (heightmap || g_Map.height);
     275   
     276    var offset = heightRange / 2;
     277   
     278    // Double initialHeightmap width until target width is reached (diamond square method)
     279    while (initialHeightmap.length < heightmap.length)
     280    {
     281        var newHeightmap = [];
     282        var oldWidth = initialHeightmap.length;
     283        // Square
     284        for (var x = 0; x < 2 * oldWidth - 1; ++x)
     285        {
     286            newHeightmap.push([]);
     287            for (var y = 0; y < 2 * oldWidth - 1; ++y)
     288            {
     289                if (x % 2 == 0 && y % 2 == 0) // Old tile
     290                    newHeightmap[x].push(initialHeightmap[x/2][y/2]);
     291                else if (x % 2 == 1 && y % 2 == 1) // New tile with diagonal old tile neighbors
     292                {
     293                    newHeightmap[x].push((initialHeightmap[(x-1)/2][(y-1)/2] + initialHeightmap[(x+1)/2][(y-1)/2] + initialHeightmap[(x-1)/2][(y+1)/2] + initialHeightmap[(x+1)/2][(y+1)/2]) / 4);
     294                    newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset)
     295                }
     296                else // New tile with straight old tile neighbors
     297                    newHeightmap[x].push(undefined); // Define later
     298            }
     299        }
     300        // Diamond
     301        for (var x = 0; x < 2 * oldWidth - 1; ++x)
     302        {
     303            for (var y = 0; y < 2 * oldWidth - 1; ++y)
     304            {
     305                if (newHeightmap[x][y] === undefined)
     306                {
     307                    if (x > 0 && x + 1 < newHeightmap.length - 1 && y > 0 && y + 1 < newHeightmap.length - 1) // Not a border tile
     308                    {
     309                        newHeightmap[x][y] = (newHeightmap[x+1][y] + newHeightmap[x][y+1] + newHeightmap[x-1][y] + newHeightmap[x][y-1]) / 4;
     310                        newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset)
     311                    }
     312                    else if (x < newHeightmap.length - 1 && y > 0 && y < newHeightmap.length - 1) // Left border
     313                    {
     314                        newHeightmap[x][y] = (newHeightmap[x+1][y] + newHeightmap[x][y+1] + newHeightmap[x][y-1]) / 3;
     315                        newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset)
     316                    }
     317                    else if (x > 0 && y > 0 && y < newHeightmap.length - 1) // Right border
     318                    {
     319                        newHeightmap[x][y] = (newHeightmap[x][y+1] + newHeightmap[x-1][y] + newHeightmap[x][y-1]) / 3;
     320                        newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset)
     321                    }
     322                    else if (x > 0 && x < newHeightmap.length - 1 && y < newHeightmap.length - 1) // Bottom border
     323                    {
     324                        newHeightmap[x][y] = (newHeightmap[x+1][y] + newHeightmap[x][y+1] + newHeightmap[x-1][y]) / 3;
     325                        newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset)
     326                    }
     327                    else if (x > 0 && x < newHeightmap.length - 1 && y > 0) // Top border
     328                    {
     329                        newHeightmap[x][y] = (newHeightmap[x+1][y] + newHeightmap[x-1][y] + newHeightmap[x][y-1]) / 3;
     330                        newHeightmap[x][y] += (newHeightmap[x][y] - minHeight) / heightRange * randFloat(-offset, offset)
     331                    }
     332                }
     333            }
     334        }
     335        initialHeightmap = deepcopy(newHeightmap);
     336        offset /= Math.pow(2, smoothness);
     337    }
     338   
     339    // Cut initialHeightmap to fit target width
     340    var shift = [floor((newHeightmap.length - heightmap.length) / 2), floor((newHeightmap[0].length - heightmap[0].length) / 2)];
     341    for (var x = 0; x < heightmap.length; ++x)
     342        for (var y = 0; y < heightmap[0].length; ++y)
     343            heightmap[x][y] = newHeightmap[x][y];
     344}
     345
     346/**
     347*   globalSmoothHeightmap
     348*
     349*   Takes:
     350*       strength    Optional, Float between 0 (no effect) and 1 (2 appending tiles will be set to roughly the same height), default is 0.8
     351*                   How strong the smooth effect should be
     352*       heightmap   Optional, Array of width Arrays of depth Floats (a heightmap), Default is g_Map.height
     353*                   The heightmap to be smoothed
     354*   Returns nothing
     355*   NOTES:
     356*       Strength values >0.9 might result in interference.
     357*       To strengthen the smooth effect it's better to apply it multiple times than using high strength values.
     358*/
     359function globalSmoothHeightmap(strength, heightmap)
     360{
     361    strength = (strength || 0.8); // 0 to 1
     362    heightmap = (heightmap || g_Map.height);
     363   
     364    var referenceHeightmap = deepcopy(heightmap);
     365    // var map = [[1, 0], [0, 1], [-1, 0], [0, -1]]; // faster
     366    var map = [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]; // smoother
     367    var max_x = heightmap.length;
     368    var max_y = heightmap[0].length;
     369    for (var x = 0; x < max_x; ++x)
     370    {
     371        for (var y = 0; y < max_y; ++y)
     372        {
     373            for (var i = 0; i < map.length; ++i)
     374            {
     375                var mapX = x + map[i][0];
     376                var mapY = y + map[i][1];
     377                if (mapX >= 0 && mapX < max_x && mapY >= 0 && mapY < max_y)
     378                    heightmap[x][y] += strength / map.length * (referenceHeightmap[mapX][mapY] - referenceHeightmap[x][y]);
     379            }
     380        }
     381    }
     382}
     383
     384/**
     385*   rectangularSmoothToHeight
     386*
     387*   Description:
     388*       Pushes a rectangular area towards a given height smoothing it into the original terrain
     389*   Takes:
     390*       center          Associative Array with keys x and y containing Floats (the x/y coordinates of the center)
     391*       dx/dy           Float, Distance from the center in x/y direction the rectangle ends (half width/depth)
     392*       targetHeight    Float, Height the center of the rectangle will be pushed to
     393*       strength        Float between 0 (no change) to 1 (center set to target height), how strong the height is pushed
     394*       heightmap       Optional, Array of width Arrays of depth Floats (a heightmap), Default is g_Map.height
     395*                       The heightmap to be manipulated
     396*   Returns nothing
     397*   NOTES:
     398*       The window function to determine the smooth is not exactly a gaussian to ensure smooth edges.
     399*       The optimal function is not clear so several working ones are left in the function (documented out)
     400*/
     401function rectangularSmoothToHeight(center, dx, dy, targetHeight, strength, heightmap)
     402{
     403    var x = round(center.x);
     404    var y = round(center.y);
     405    dx = round(dx);
     406    dy = round(dy);
     407    strength = (strength || 1);
     408    heightmap = (heightmap || g_Map.height);
     409   
     410    var heightmapWin = [];
     411    for (var wx = 0; wx < 2 * dx + 1; ++wx)
     412    {
     413        heightmapWin.push([]);
     414        for (var wy = 0; wy < 2 * dy + 1; ++wy)
     415        {
     416            var actualX = x - dx + wx;
     417            var actualY = y - dy + wy;
     418            if (actualX >= 0 && actualX < heightmap.length - 1 && actualY >= 0 && actualY < heightmap[0].length - 1) // Is in map
     419                heightmapWin[wx].push(heightmap[actualX][actualY]);
     420            else
     421                heightmapWin[wx].push(targetHeight);
     422        }
     423    }
     424    for (var wx = 0; wx < 2 * dx + 1; ++wx)
     425    {
     426        for (var wy = 0; wy < 2 * dy + 1; ++wy)
     427        {
     428            var actualX = x - dx + wx;
     429            var actualY = y - dy + wy;
     430            if (actualX >= 0 && actualX < heightmap.length - 1 && actualY >= 0 && actualY < heightmap[0].length - 1) // Is in map
     431            {
     432                // Window function polynomial 2nd degree
     433                var scaleX = 1 - (wx / dx - 1) * (wx / dx - 1);
     434                var scaleY = 1 - (wy / dy - 1) * (wy / dy - 1);
     435               
     436                heightmap[actualX][actualY] = heightmapWin[wx][wy] + strength * scaleX * scaleY * (targetHeight - heightmapWin[wx][wy]);
     437            }
     438        }
     439    }
     440}
  • binaries/data/mods/public/maps/random/rmgen/library.js

     
    1 
    2 /////////////////////////////////////////////////////////////////////////////////////////////
    3 //  Constant definitions
    4 /////////////////////////////////////////////////////////////////////////////////////////////
    5 
     1/**
     2 * Constant definitions
     3 */
    64const PI = Math.PI;
    7 const TWO_PI = 2 * Math.PI;
     5const TWO_PI = 2 * Math.PI; // mathematically known as 'tau'
    86const TERRAIN_SEPARATOR = "|";
    9 const SEA_LEVEL = 20.0;
     7const SEA_LEVEL = 160.0;
    108const CELL_SIZE = 4;
    119const HEIGHT_UNITS_PER_METRE = 92;
    1210const MIN_MAP_SIZE = 128;
    1311const MAX_MAP_SIZE = 512;
    1412const FALLBACK_CIV = "athen";
    1513
    16 /////////////////////////////////////////////////////////////////////////////////////////////
    17 //  Utility functions
    18 /////////////////////////////////////////////////////////////////////////////////////////////
     14/**
     15 * Constants needed for heightmap_manipulation.js
     16 */
     17const MAX_HEIGHT_RANGE = 0xFFFF / HEIGHT_UNITS_PER_METRE // Engine limit, Roughly 700 meters
     18const MIN_HEIGHT = - SEA_LEVEL;
     19const MAX_HEIGHT = MAX_HEIGHT_RANGE - SEA_LEVEL;
     20/**
     21 * Entity template structure keys that might change, for easier mod support
     22 */
     23const CIV_PLACEHOLDER_STRING = "{civ}";
     24const START_ENTITY_KEYS = ["StartEntities"];
     25const START_ENTITY_TEMPLATE_KEYS = ["Template"];
     26const BUILDER_TEMPLATEPATH_KEYS = ["Builder", "Entities", "_string"];
     27const PRODUCTION_TEMPLATEPATH_KEYS = ["ProductionQueue", "Entities", "_string"];
     28const WALLSET_KEYS = ["WallSet"];
     29const BUILDING_KEYS = ["Obstruction", "Static"];
    1930
     31
     32/**
     33 * Utility functions
     34 */
     35
    2036function fractionToTiles(f)
    2137{
    2238    return getMapSize() * f;
     
    103119    if (numArgs != 1)
    104120    {
    105121        var ret = new Array(numArgs);
    106         for (var i=0; i < numArgs; i++)
     122        for (var i=0; i < numArgs; ++i)
    107123        {
    108124            ret[i] = x[i];
    109125        }
     
    125141    return ar[randInt(ar.length)];
    126142}
    127143
    128 // "Inside-out" implementation of Fisher-Yates shuffle
     144/**
     145 * "Inside-out" implementation of Fisher-Yates shuffle
     146 */
    129147function shuffleArray(source)
    130148{
    131149    if (!source.length)
    132150        return [];
    133151
    134152    var result = [source[0]];
    135     for (var i = 1; i < source.length; i++)
     153    for (var i = 1; i < source.length; ++i)
    136154    {
    137155        var j = randInt(0, i);
    138156        result[i] = result[j];
     
    172190        var area = g_Map.createArea(centeredPlacer, painter, constraint);
    173191        if (area !== undefined)
    174192        {
    175             good++;
     193            ++good;
    176194            result.push(area);
    177195        }
    178196        else
    179197        {
    180             bad++;
     198            ++bad;
    181199        }
    182200    }
    183201    return result;
     
    208226        var area = g_Map.createArea(centeredPlacer, painter, constraint);
    209227        if (area !== undefined)
    210228        {
    211             good++;
     229            ++good;
    212230            result.push(area);
    213231        }
    214232        else
    215233        {
    216             bad++;
     234            ++bad;
    217235        }
    218236    }
    219237    return result;
     
    248266        var result = createObjectGroup(placer, player, constraint);
    249267        if (result !== undefined)
    250268        {
    251             good++;
     269            ++good;
    252270        }
    253271        else
    254272        {
    255             bad++;
     273            ++bad;
    256274        }
    257275    }
    258276    return good;
     
    282300        var result = createObjectGroup(placer, player, constraint);
    283301        if (result !== undefined)
    284302        {
    285             good++;
     303            ++good;
    286304        }
    287305        else
    288306        {
    289             bad++;
     307            ++bad;
    290308        }
    291309    }
    292310    return good;
     
    349367    return (g_MapSettings.CircularMap ? true : false);
    350368}
    351369
    352 /////////////////////////////////////////////////////////////////////////////////////////////
    353 //  Access global map variable
    354 /////////////////////////////////////////////////////////////////////////////////////////////
     370/**
     371 * Access global map variable
     372 */
    355373
    356374function createTileClass()
    357375{
     
    394412    return g_MapSettings.PlayerData.length - 1;
    395413}
    396414
     415/**
     416 * Takes nothing, returns an array of strings representing all available civilizations
     417 */
     418function getCivList()
     419{
     420    var raw_civData = RMS.GetCivData();
     421    var civList = [];
     422    for (var i = 0; i < raw_civData.length; ++i)
     423        civList.push(JSON.parse(raw_civData[i]).Code);
     424   
     425    return civList;
     426}
     427
     428/**
     429 * Takes nothing, returns an associative array with civ strings as keys containing all unpacked civ data (Templates need to be unpacked with RMS.GetTemplate() if needed)
     430 */
     431function getFullCivData()
     432{
     433    var rawCivData = RMS.GetCivData();
     434    var unpackedCivData = {};
     435    for (var i = 0; i < rawCivData.length; ++i)
     436    {
     437        var singleCivData = JSON.parse(rawCivData[i]);
     438        unpackedCivData[singleCivData.Code] = singleCivData;
     439    }
     440   
     441    return unpackedCivData;
     442}
     443
     444/**
     445 * Takes a player number (0-7, so Gaia excluded). Returns this players civ string
     446 * ToDo: If the player number is to high an error will occur (and the fallback won't be reached)!
     447 */
    397448function getCivCode(player)
    398449{
    399450    if (g_MapSettings.PlayerData[player+1].Civ)
    400451        return g_MapSettings.PlayerData[player+1].Civ;
    401452
    402     warn("undefined civ specified for player " + (player + 1) + ", falling back to '" + FALLBACK_CIV + "'");
     453    warn("Undefined civ specified for player " + (player + 1) + ", falling back to '" + FALLBACK_CIV + "'");
    403454    return FALLBACK_CIV;
    404455}
    405456
     457/**
     458 * Takes an entity path and a key list to get the templates value
     459 */
     460function getTemplateValue(entPath, key_list)
     461{
     462    var subdata = RMS.GetTemplate(entPath);
     463    for (var i = 0; i < key_list.length; ++i)
     464    {
     465        if (!subdata[key_list[i]])
     466        {
     467            return false
     468        }
     469        subdata = subdata[key_list[i]];
     470    }
     471    return subdata;
     472}
     473
     474/**
     475 * Returns a list of all templates paths available to the given civ
     476 */
     477function getTempatePathList(civ)
     478{
     479    var templatePaths = getFullCivData();
     480    if (!templatePaths[civ])
     481    {
     482        warn("getTempatePathList: Unknown civ '" + civ + "' not in " + Object.keys(templatePaths));
     483        return false;
     484    }
     485    templatePaths = templatePaths[civ];
     486   
     487    if (!templatePaths[START_ENTITY_KEYS])
     488    {
     489        warn("getTempatePathList: Civ has no starting entities as defined in START_ENTITY_KEYS (" + START_ENTITY_KEYS + "): " + Object.keys(templatePaths));
     490        return false;
     491    }
     492    templatePaths = templatePaths[START_ENTITY_KEYS];
     493   
     494    for (var i = 0; i < templatePaths.length; ++i)
     495    {
     496        if (!templatePaths[i][START_ENTITY_TEMPLATE_KEYS])
     497        {
     498            warn("getTempatePathList: Starting entity list item has no template as defined in START_ENTITY_TEMPLATE_KEYS (" + START_ENTITY_TEMPLATE_KEYS + "): " + Object.keys(templatePaths));
     499            return false;
     500        }
     501        templatePaths[i] = templatePaths[i][START_ENTITY_TEMPLATE_KEYS];
     502    }
     503    var foundNew = 1;
     504    while (foundNew > 0)
     505    {
     506        foundNew = 0;
     507        var methods = [BUILDER_TEMPLATEPATH_KEYS, PRODUCTION_TEMPLATEPATH_KEYS];
     508        for (var m = 0; m < methods.length; ++m)
     509        {
     510            for (var t = 0; t < templatePaths.length; ++t)
     511            {
     512                var pathsToCheck = getTemplateValue(templatePaths[t], methods[m]);
     513                if (typeof(pathsToCheck) === typeof(""))
     514                {
     515                    pathsToCheck = pathsToCheck.split(/\s+/);
     516                    for (var c = 0; c < pathsToCheck.length; ++c)
     517                    {
     518                        var actualPath = pathsToCheck[c].replace(CIV_PLACEHOLDER_STRING, civ);
     519                        if (templatePaths.indexOf(actualPath) == -1 && RMS.TemplateExists(actualPath))
     520                        {
     521                            templatePaths.push(actualPath);
     522                            ++foundNew;
     523                        }
     524                    }
     525                }
     526            }
     527        }
     528    }
     529    return templatePaths;
     530}
     531
     532/**
     533 * Takes a list of entity path strings and returns a list with only those remaining that have the specified keys
     534 */
     535function filterByKeys(entPaths, keys)
     536{
     537    let filteredEntPaths = [];
     538    for (let i = 0; i < entPaths.length; ++i)
     539    {
     540        if (getTemplateValue(entPaths[i], keys))
     541            filteredEntPaths.push(entPaths[i]);
     542    }
     543    return filteredEntPaths;
     544}
     545
    406546function areAllies(player1, player2)
    407547{
    408548    if ((g_MapSettings.PlayerData[player1+1].Team === undefined) || (g_MapSettings.PlayerData[player2+1].Team === undefined) || (g_MapSettings.PlayerData[player2+1].Team == -1) || (g_MapSettings.PlayerData[player1+1].Team == -1))
     
    434574
    435575    var result = new Array(0);
    436576    var team = new Array(5);
    437     for (var q = 0; q < 5; q++)
     577    for (var q = 0; q < 5; ++q)
    438578    {
    439579        team[q] = new Array(1);
    440580    }
    441581
    442     for (var i = -1; i < 4; i++)
     582    for (var i = -1; i < 4; ++i)
    443583    {
    444         for (var j = 0; j < source.length; j++)
     584        for (var j = 0; j < source.length; ++j)
    445585        {
    446586            if (getPlayerTeam(j) == i)
    447             {
    448587                team[i+1].unshift(j+1);
    449             }
    450588        }
    451589        team[i+1].pop();
    452590        result=result.concat(shuffleArray(team[i+1]))
     
    461599
    462600    var prime = new Array(source.length);
    463601
    464     for (var i = 0; i < round(source.length/2); i++)
     602    for (var i = 0; i < round(source.length/2); ++i)
    465603    {
    466604        prime[2*i]=source[i];
    467605        prime[2*i+1]=source[source.length-1-i];
     
    492630    g_Map.setHeight(x, z, height);
    493631}
    494632
    495 /////////////////////////////////////////////////////////////////////////////////////////////
    496 //  Utility functions for classes
    497 /////////////////////////////////////////////////////////////////////////////////////////////
    498633
     634/**
     635 *  Utility functions for classes
     636 */
    499637
    500 // Add point to given class by id
     638/**
     639 * Add point to given class by id
     640 */
    501641function addToClass(x, z, id)
    502642{
    503643    var tileClass = getTileClass(id);
    504644   
    505645    if (tileClass !== null)
    506     {
    507646        tileClass.add(x, z);
    508     }
    509647}
    510648
    511 // Remove point from the given class by id
     649/**
     650 * Remove point from the given class by id
     651 */
    512652function removeFromClass(x, z, id)
    513653{
    514654    var tileClass = getTileClass(id);
    515655   
    516656    if (tileClass !== null)
    517     {
    518657        tileClass.remove(x, z);
    519     }
    520658}
    521659
    522 // Create a painter for the given class
     660/**
     661 * Create a painter for the given class
     662 */
    523663function paintClass(id)
    524664{
    525665    return new TileClassPainter(getTileClass(id));
    526666}
    527667
    528 // Create a painter for the given class
     668/**
     669 * Create a painter for the given class
     670 */
    529671function unPaintClass(id)
    530672{
    531673    return new TileClassUnPainter(getTileClass(id));
    532674}
    533675
    534 // Create an avoid constraint for the given classes by the given distances
     676/**
     677 * Create an avoid constraint for the given classes by the given distances
     678 */
    535679function avoidClasses(/*class1, dist1, class2, dist2, etc*/)
    536680{
    537681    var ar = new Array(arguments.length/2);
    538     for (var i = 0; i < arguments.length/2; i++)
     682    for (var i = 0; i < arguments.length/2; ++i)
    539683    {
    540684        ar[i] = new AvoidTileClassConstraint(arguments[2*i], arguments[2*i+1]);
    541685    }
    542686   
    543687    // Return single constraint
    544688    if (ar.length == 1)
    545     {
    546689        return ar[0];
    547     }
    548690    else
    549691    {
    550692        return new AndConstraint(ar);
    551693    }
    552694}
    553695
    554 // Create a stay constraint for the given classes by the given distances
     696/**
     697 * Create a stay constraint for the given classes by the given distances
     698 */
    555699function stayClasses(/*class1, dist1, class2, dist2, etc*/)
    556700{
    557701    var ar = new Array(arguments.length/2);
    558     for (var i = 0; i < arguments.length/2; i++)
     702    for (var i = 0; i < arguments.length/2; ++i)
    559703    {
    560704        ar[i] = new StayInTileClassConstraint(arguments[2*i], arguments[2*i+1]);
    561705    }
     
    571715    }
    572716}
    573717
    574 // Create a border constraint for the given classes by the given distances
     718/**
     719 * Create a border constraint for the given classes by the given distances
     720 */
    575721function borderClasses(/*class1, idist1, odist1, class2, idist2, odist2, etc*/)
    576722{
    577723    var ar = new Array(arguments.length/3);
    578     for (var i = 0; i < arguments.length/3; i++)
     724    for (var i = 0; i < arguments.length/3; ++i)
    579725    {
    580726        ar[i] = new BorderTileClassConstraint(arguments[3*i], arguments[3*i+1], arguments[3*i+2]);
    581727    }
     
    591737    }
    592738}
    593739
    594 // Checks if the given tile is in class "id"
     740/**
     741 * Checks if the given tile is in class "id"
     742 */
    595743function checkIfInClass(x, z, id)
    596744{
    597745    var tileClass = getTileClass(id);
     
    612760    }
    613761}
    614762
    615 
    616 // Returns the distance between 2 points
     763/**
     764 * Returns the distance between 2 points
     765 */
    617766function getDistance(x1, z1, x2, z2)
    618767{
    619768    return Math.pow(Math.pow(x1 - x2, 2) + Math.pow(z1 - z2, 2), 1/2);
    620769}
    621770
    622 // Returns the angle of the vector between point 1 and point 2.  The angle is anticlockwise from the positive x axis.
     771/**
     772 * Returns the angle of the vector between point 1 and point 2.  The angle is anticlockwise from the positive x axis.
     773 */
    623774function getAngle(x1, z1, x2, z2)
    624775{
    625776    return Math.atan2(z2 - z1, x2 - x1);
    626777}
    627778
    628 // Returns the gradient of the line between point 1 and 2 in the form dz/dx
     779/**
     780 * Returns the gradient of the line between point 1 and 2 in the form dz/dx
     781 */
    629782function getGradient(x1, z1, x2, z2)
    630783{
    631784    if (x1 == x2 && z1 == z2)
     
    642795{
    643796    return g_Map.getTexture(x, y);
    644797}
    645 
  • binaries/data/mods/public/maps/random/rmgen/misc.js

     
    1 /////////////////////////////////////////////////////////////////////////////////////////
    2 //  passageMaker
    3 //
    4 //  Function for creating shallow water between two given points by changing the heiight of all tiles in
    5 //  the path with height less than or equal to "maxheight" to "height"
    6 //
    7 //  x1,z1:  Starting point of path
    8 //  x2,z2:  Ending point of path
    9 //  width:  Width of the shallow
    10 //  maxheight:      Maximum height that it changes
    11 //  height:     Height of the shallow
    12 //  smooth:     smooth elevation in borders
    13 //  tileclass:      (Optianal) - Adds those tiles to the class given
    14 //  terrain:        (Optional) - Changes the texture of the elevated land
    15 //
    16 /////////////////////////////////////////////////////////////////////////////////////////
    17 
     1/**
     2 *  passageMaker
     3 *
     4 *  Function for creating shallow water between two given points by changing the heiight of all tiles in
     5 *  the path with height less than or equal to "maxheight" to "height"
     6 *
     7 *  x1,z1:  Starting point of path
     8 *  x2,z2:  Ending point of path
     9 *  width:  Width of the shallow
     10 *  maxheight:      Maximum height that it changes
     11 *  height:     Height of the shallow
     12 *  smooth:     smooth elevation in borders
     13 *  tileclass:      (Optianal) - Adds those tiles to the class given
     14 *  terrain:        (Optional) - Changes the texture of the elevated land
     15 */
    1816function passageMaker(x1, z1, x2, z2, width, maxheight, height, smooth, tileclass, terrain, riverheight)
    1917{
    2018    var tchm = TILE_CENTERED_HEIGHT_MAP;
    2119    TILE_CENTERED_HEIGHT_MAP = true;
    2220    var mapSize = g_Map.size;
    23     for (var ix = 0; ix < mapSize; ix++)
     21    for (var ix = 0; ix < mapSize; ++ix)
    2422    {
    25         for (var iz = 0; iz < mapSize; iz++)
     23        for (var iz = 0; iz < mapSize; ++iz)
    2624        {
    2725            var a = z1-z2;
    2826            var b = x2-x1;
     
    7371    TILE_CENTERED_HEIGHT_MAP = tchm;
    7472}
    7573
    76 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    77 //rndRiver is a fuction that creates random values useful for making a jagged river.
    78 //
    79 //it works the same as sin or cos function. the only difference is that it's period is 1 instead of 2*pi
    80 //it needs the "seed" parameter to use it to make random curves that don't get broken.
    81 //seed must be created using randFloat(). or else it won't work
    82 //
    83 //  f:  Input: Same as angle in a sine function
    84 //  seed:   Random Seed: Best to implement is to use randFloat()
    85 //
    86 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    87 
     74/**
     75 *rndRiver is a fuction that creates random values useful for making a jagged river.
     76 *
     77 *it works the same as sin or cos function. the only difference is that it's period is 1 instead of 2*pi
     78 *it needs the "seed" parameter to use it to make random curves that don't get broken.
     79 *seed must be created using randFloat(). or else it won't work
     80 *
     81 *  f:  Input: Same as angle in a sine function
     82 *  seed:   Random Seed: Best to implement is to use randFloat()
     83 */
    8884function rndRiver(f, seed)
    8985{
    9086    var rndRq = seed;
     
    9288    var rndRe = 0;
    9389    var rndRr = f-floor(f);
    9490    var rndRa = 0;
    95     for (var rndRx=0; rndRx<=floor(f); rndRx++)
     91    for (var rndRx=0; rndRx<=floor(f); ++rndRx)
    9692    {
    9793        rndRw = 10*(rndRw-floor(rndRw));
    9894    }
     
    129125}
    130126
    131127
    132 /////////////////////////////////////////////////////////////////////////////////////////
    133 // createStartingPlayerEntities
    134 //
    135 //  Creates the starting player entities
    136 //  fx&fz: position of player base
    137 //  playerid: id of player
    138 //  civEntities: use getStartingEntities(id-1) fo this one
    139 //  BUILDING_ANGlE: angle of main base building
    140 //
    141 ///////////////////////////////////////////////////////////////////////////////////////////
     128/**
     129 * createStartingPlayerEntities
     130 *
     131 *  Creates the starting player entities
     132 *  fx&fz: position of player base
     133 *  playerid: id of player
     134 *  civEntities: use getStartingEntities(id-1) fo this one
     135 *  BUILDING_ANGlE: angle of main base building
     136 */
    142137function createStartingPlayerEntities(fx, fz, playerid, civEntities, BUILDING_ANGlE)
    143138{
    144139    var uDist = 6;
     
    148143    {
    149144        var uAngle = BUILDING_ANGlE - PI * (2-j) / 2;
    150145        var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1);
    151         for (var numberofentities = 0; numberofentities < count; numberofentities++)
     146        for (var numberofentities = 0; numberofentities < count; ++numberofentities)
    152147        {
    153148            var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2));
    154149            var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2));
     
    157152    }
    158153}
    159154
    160 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    161 // placeCivDefaultEntities
    162 //
    163 //  Creates the default starting player entities depending on the players civ
    164 //  fx&fy: position of player base
    165 //  playerid: id of player
    166 //  angle: angle of main base building, optional, default is BUILDING_ANGlE
    167 //  kwargs: Takes some optional keyword arguments to tweek things
    168 //      'iberWall': may be false, 'walls' (default) or 'towers'. Determines the defensive structures Iberians get as civ bonus
    169 //
    170 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     155/**
     156 * placeCivDefaultEntities
     157 *
     158 *  Creates the default starting player entities depending on the players civ
     159 *  fx&fy: position of player base
     160 *  playerid: id of player
     161 *  angle: angle of main base building, optional, default is BUILDING_ANGlE
     162 *  kwargs: Optional. Takes an associative array with keyword arguments to tweak things:
     163 *      Known keys: 'iberWall': may be false, 'walls' (default) or 'towers'. Determines the defensive structures Iberians get as civ bonus
     164 */
    171165function placeCivDefaultEntities(fx, fz, playerid, angle, kwargs)
    172166{
    173167    // Unpack kwargs
     
    187181    {
    188182        var uAngle = angle - PI * (2-j) / 2;
    189183        var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1);
    190         for (var numberofentities = 0; numberofentities < count; numberofentities++)
     184        for (var numberofentities = 0; numberofentities < count; ++numberofentities)
    191185        {
    192186            var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2));
    193187            var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2));
     
    205199}
    206200
    207201
    208 /////////////////////////////////////////////////////////////////////////////////////////
    209 // paintTerrainBasedOnHeight
    210 //
    211 //  paints the tiles which have a height between minheight and maxheight with the given terrain
    212 //  minheight: minimum height of the tile
    213 //  maxheight: maximum height of the tile
    214 //  mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight.
    215 //  1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than
    216 //  minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight
    217 //  terrain: intended terrain texture
    218 //
    219 ///////////////////////////////////////////////////////////////////////////////////////////
     202/**
     203 * paintTerrainBasedOnHeight
     204 *
     205 *  paints the tiles which have a height between minheight and maxheight with the given terrain
     206 *  minheight: minimum height of the tile
     207 *  maxheight: maximum height of the tile
     208 *  mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight.
     209 *  1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than
     210 *  minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight
     211 *  terrain: intended terrain texture
     212 */
    220213
    221214function paintTerrainBasedOnHeight(minheight, maxheight, mode, terrain)
    222215{
    223216    var mSize = g_Map.size;
    224     for (var qx = 0; qx < mSize; qx++)
     217    for (var qx = 0; qx < mSize; ++qx)
    225218    {
    226         for (var qz = 0; qz < mSize; qz++)
     219        for (var qz = 0; qz < mSize; ++qz)
    227220        {
    228221            if (mode == 0)
    229222            {
     
    257250    }
    258251}
    259252
    260 /////////////////////////////////////////////////////////////////////////////////////////
    261 // paintTileClassBasedOnHeight and unPaintTileClassBasedOnHeight
    262 //
    263 //  paints or unpaints the tiles which have a height between minheight and maxheight with the given tile class
    264 //  minheight: minimum height of the tile
    265 //  maxheight: maximum height of the tile
    266 //  mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight.
    267 //  1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than
    268 //  minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight
    269 //  tileclass: intended tile class
    270 //
    271 ///////////////////////////////////////////////////////////////////////////////////////////
    272 
     253/**
     254 * paintTileClassBasedOnHeight and unPaintTileClassBasedOnHeight
     255 *
     256 *  paints or unpaints the tiles which have a height between minheight and maxheight with the given tile class
     257 *  minheight: minimum height of the tile
     258 *  maxheight: maximum height of the tile
     259 *  mode: accepts 4 values. 0 means the it will select tiles with height more than minheight and less than maxheight.
     260 *  1 means it selects tiles with height more than or equal to minheight and less than max height. 2 means more than
     261 *  minheight and less than or equal to maxheight. 3 means more than or equal to minheight and less than or equal to maxheight
     262 *  tileclass: intended tile class
     263 */
    273264function paintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass)
    274265{
    275266    var mSize = g_Map.size;
    276     for (var qx = 0; qx < mSize; qx++)
     267    for (var qx = 0; qx < mSize; ++qx)
    277268    {
    278         for (var qz = 0; qz < mSize; qz++)
     269        for (var qz = 0; qz < mSize; ++qz)
    279270        {
    280271            if (mode == 0)
    281272            {
     
    313304function unPaintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass)
    314305{
    315306    var mSize = g_Map.size;
    316     for (var qx = 0; qx < mSize; qx++)
     307    for (var qx = 0; qx < mSize; ++qx)
    317308    {
    318         for (var qz = 0; qz < mSize; qz++)
     309        for (var qz = 0; qz < mSize; ++qz)
    319310        {
    320311            if (mode == 0)
    321312            {
     
    349340    }
    350341}
    351342
    352 /////////////////////////////////////////////////////////////////////////////////////////
    353 // getTIPIADBON
    354 //
    355 //  "get The Intended Point In A Direction Based On Height"
    356 //  gets the N'th point with a specific height in a line and returns it as a [x, y] array
    357 //  startPoint: [x, y] array defining the start point
    358 //  endPoint: [x, y] array defining the ending point
    359 //  heightRange: [min, max] array defining the range which the height of the intended point can be. includes both "min" and "max"
    360 //  step: how much tile units per turn should the search go. more value means faster but less accurate
    361 //  n: how many points to skip before ending the search. skips """n-1 points""".
    362 //
    363 ///////////////////////////////////////////////////////////////////////////////////////////
    364 
     343/**
     344 * getTIPIADBON
     345 *
     346 *  "get The Intended Point In A Direction Based On Height"
     347 *  gets the N'th point with a specific height in a line and returns it as a [x, y] array
     348 *  startPoint: [x, y] array defining the start point
     349 *  endPoint: [x, y] array defining the ending point
     350 *  heightRange: [min, max] array defining the range which the height of the intended point can be. includes both "min" and "max"
     351 *  step: how much tile units per turn should the search go. more value means faster but less accurate
     352 *  n: how many points to skip before ending the search. skips """n-1 points""".
     353 */
    365354function getTIPIADBON(startPoint, endPoint, heightRange, step, n)
    366355{
    367356    var stepX = step*(endPoint[0]-startPoint[0])/(sqrt((endPoint[0]-startPoint[0])*(endPoint[0]-startPoint[0]) + step*(endPoint[1]-startPoint[1])*(endPoint[1]-startPoint[1])));
     
    394383    return undefined;
    395384}
    396385
    397 /////////////////////////////////////////////////////////////////////////////////////////
    398 // doIntersect
    399 //
    400 //  determines if two lines with the width "width" intersect or collide with each other
    401 //  x1, y1, x2, y2: determine the position of the first line
    402 //  x3, y3, x4, y4: determine the position of the second line
    403 //  width: determines the width of the lines
    404 //
    405 ///////////////////////////////////////////////////////////////////////////////////////////
    406 
     386/**
     387 * doIntersect
     388 *
     389 *  determines if two lines with the width "width" intersect or collide with each other
     390 *  x1, y1, x2, y2: determine the position of the first line
     391 *  x3, y3, x4, y4: determine the position of the second line
     392 *  width: determines the width of the lines
     393 */
    407394function checkIfIntersect (x1, y1, x2, y2, x3, y3, x4, y4, width)
    408395{
    409396    if (x1 == x2)
     
    445432    return false;
    446433}
    447434
    448 /////////////////////////////////////////////////////////////////////////////////////////
    449 // distanceOfPointFromLine
    450 //
    451 //  returns the distance of a point from a line
    452 //  x1, y1, x2, y2: determine the position of the line
    453 //  x3, y3: determine the position of the point
    454 //
    455 ///////////////////////////////////////////////////////////////////////////////////////////
    456 
     435/**
     436 * distanceOfPointFromLine
     437 *
     438 *  returns the distance of a point from a line
     439 *  x1, y1, x2, y2: determine the position of the line
     440 *  x3, y3: determine the position of the point
     441 */
    457442function distanceOfPointFromLine (x1, y1, x2, y2, x3, y3)
    458443{
    459444    if (x1 == x2)
     
    473458    }
    474459}
    475460
    476 /////////////////////////////////////////////////////////////////////////////////////////
    477 // createRamp
    478 //
    479 //  creates a ramp from point (x1, y1) to (x2, y2).
    480 //  x1, y1, x2, y2: determine the position of the start and end of the ramp
    481 //  minHeight, maxHeight: determine the height levels of the start and end point
    482 //  width: determines the width of the ramp
    483 //  smoothLevel: determines the smooth level around the edges of the ramp
    484 //  mainTerrain: (Optional) determines the terrain texture for the ramp
    485 //  edgeTerrain: (Optional) determines the terrain texture for the edges
    486 //  tileclass: (Optional) adds the ramp to this tile class
    487 //
    488 ///////////////////////////////////////////////////////////////////////////////////////////
    489 
     461/**
     462 * createRamp
     463 *
     464 *  creates a ramp from point (x1, y1) to (x2, y2).
     465 *  x1, y1, x2, y2: determine the position of the start and end of the ramp
     466 *  minHeight, maxHeight: determine the height levels of the start and end point
     467 *  width: determines the width of the ramp
     468 *  smoothLevel: determines the smooth level around the edges of the ramp
     469 *  mainTerrain: (Optional) determines the terrain texture for the ramp
     470 *  edgeTerrain: (Optional) determines the terrain texture for the edges
     471 *  tileclass: (Optional) adds the ramp to this tile class
     472 */
    490473function createRamp (x1, y1, x2, y2, minHeight, maxHeight, width, smoothLevel, mainTerrain, edgeTerrain, tileclass)
    491474{
    492475    var halfWidth = width / 2;
     
    540523    }
    541524}
    542525
    543 /////////////////////////////////////////////////////////////////////////////////////////
    544 // createMountain
    545 //
    546 //  creates a mountain using a tecnique very similar to chain placer.
    547 //
    548 ///////////////////////////////////////////////////////////////////////////////////////////
     526/**
     527 * createMountain
     528 *
     529 *  creates a mountain using a tecnique very similar to chain placer.
     530 *
     531 */
    549532
    550533function createMountain(maxHeight, minRadius, maxRadius, numCircles, constraint, x, z, terrain, tileclass, fcc, q)
    551534{
     
    617600       
    618601        for (var ix = sx; ix <= lx; ++ix)
    619602        {
    620             for (var iz = sz; iz <= lz; ++ iz)
     603            for (var iz = sz; iz <= lz; ++iz)
    621604            {
    622605                dx = ix - cx;
    623606                dz = iz - cz;
     
    666649       
    667650        for (var ix = sx; ix <= lx; ++ix)
    668651        {
    669             for (var iz = sz; iz <= lz; ++ iz)
     652            for (var iz = sz; iz <= lz; ++iz)
    670653            {
    671654                if (fcc)
    672655                    if ((x - ix) > fcc || (ix - x) > fcc || (z - iz) > fcc || (iz - z) > fcc)
     
    737720       
    738721        for (var ix = sx; ix <= lx; ++ix)
    739722        {
    740             for (var iz = sz; iz <= lz; ++ iz)
     723            for (var iz = sz; iz <= lz; ++iz)
    741724            {
    742725                dx = ix - cx;
    743726                dz = iz - cz;
  • binaries/data/mods/public/maps/random/schwarzwald.js

     
    1 // Created by Niek ten Brinke (aka niektb)
    2 // Based on FeXoR's Daimond Square Algorithm for heightmap generation and several official random maps
     1/**
     2 * Created by Niek ten Brinke (aka niektb)
     3 * Based on FeXoR's Daimond Square Algorithm for heightmap generation and several official random maps
     4 */
    35
    46'use strict';
    57
    68RMS.LoadLibrary('rmgen');
    79
    8 // initialize map
     10/**
     11 * initialize map
     12 */
    913
    1014log('Initializing map...');
    1115
    1216InitMap();
    1317
    1418
    15 ////////////////
    16 //
    17 //  Initializing
    18 //
    19 ////////////////
     19/**
     20 *  Initializing
     21 */
    2022
    21 //sky
     23/**
     24 *sky
     25 */
    2226setSkySet("fog");
    2327setFogFactor(0.35);
    2428setFogThickness(0.19);
    25 
    26 // water
     29/**
     30 * water
     31 */
    2732setWaterColor(0.501961, 0.501961, 0.501961);
    2833setWaterTint(0.25098, 0.501961, 0.501961);
    2934setWaterWaviness(0.5);
    3035setWaterType("clap");
    3136setWaterMurkiness(0.75);
    32 
    33 // post processing
     37/**
     38 * post processing
     39 */
    3440setPPSaturation(0.37);
    3541setPPContrast(0.4);
    3642setPPBrightness(0.4);
    3743setPPEffect("hdr");
    3844setPPBloom(0.4);
    39 
    40 // Setup tile classes
     45/**
     46 * Setup tile classes
     47 */
    4148var clPlayer = createTileClass();
    4249var clPath = createTileClass();
    4350var clHill = createTileClass();
     
    4754var clFood = createTileClass();
    4855var clBaseResource = createTileClass();
    4956var clOpen = createTileClass();
    50 
    51 // Setup Templates
     57/**
     58 * Setup Templates
     59 */
    5260var templateStone = 'gaia/geology_stone_alpine_a';
    5361var templateStoneMine = 'gaia/geology_stonemine_alpine_quarry';
    5462var templateMetal = 'actor|geology/stone_granite_med.xml';
     
    6472var aReeds = 'actor|props/flora/reeds_pond_lush_b.xml';
    6573var oFish = "gaia/fauna_fish";
    6674
    67 
    68 // Setup terrain
     75/**
     76 * Setup terrain
     77 */
    6978var terrainWood = ['alpine_forrestfloor|gaia/flora_tree_oak', 'alpine_forrestfloor|gaia/flora_tree_pine'];
    7079var terrainWoodBorder = ['new_alpine_grass_mossy|gaia/flora_tree_oak', 'alpine_forrestfloor|gaia/flora_tree_pine',
    7180    'temp_grass_long|gaia/flora_bush_temperate', 'temp_grass_clovers|gaia/flora_bush_berry', 'temp_grass_clovers_2|gaia/flora_bush_grapes',
     
    108117
    109118const BUILDING_ANGlE = -PI/4;
    110119
    111 // Setup map
     120/**
     121 * Setup map
     122 */
    112123var mapSize = getMapSize();
    113124var mapRadius = mapSize/2;
    114125var playableMapRadius = mapRadius - 5;
    115126var mapCenterX = mapRadius;
    116127var mapCenterZ = mapRadius;
    117128
    118 // Setup players and bases
     129/**
     130 * Setup players and bases
     131 */
    119132var numPlayers = getNumPlayers();
    120133var baseRadius = 15;
    121134var minPlayerRadius = min(mapRadius-1.5*baseRadius, 5*mapRadius/8);
     
    128141var playerAngleAddAvrg = 2*PI / numPlayers;
    129142var playerAngleMaxOff = playerAngleAddAvrg/4;
    130143
    131 // Setup paths
     144/**
     145 * Setup paths
     146 */
    132147var pathSucsessRadius = baseRadius/2;
    133148var pathAngleOff = PI/2;
    134 var pathWidth = 10; // This is not really the path's thickness in tiles but the number of tiles in the clumbs of the path
     149var pathWidth = 10; // This is not really the path's thickness in tiles but the number of tiles in the clumps of the path
    135150
    136 // Setup additional resources
     151/**
     152 * Setup additional resources
     153 */
    137154var resourceRadius = 2*mapRadius/3; // 3*mapRadius/8;
    138155//var resourcePerPlayer = [templateStone, templateMetalMine];
    139156
    140 // Setup woods
    141 // For large maps there are memory errors with too many trees.  A density of 256*192/mapArea works with 0 players.
    142 // Around each player there is an area without trees so with more players the max density can increase a bit.
     157/**
     158 * Setup woods
     159 * For large maps there are memory errors with too many trees.  A density of 256*192/mapArea works with 0 players.
     160 * Around each player there is an area without trees so with more players the max density can increase a bit.
     161 */
    143162var maxTreeDensity = min(256 * (192 + 8 * numPlayers) / (mapSize * mapSize), 1); // Has to be tweeked but works ok
    144163var bushChance = 1/3; // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood
    145164
    146165
    147 ////////////////
    148 //
    149 //  Some general functions
    150 //
    151 ////////////////
    152 
     166/**
     167 * Some general functions
     168 */
    153169function HeightPlacer(lowerBound, upperBound) {
    154170    this.lowerBound = lowerBound;
    155171    this.upperBound = upperBound;
     
    159175    constraint = (constraint || new NullConstraint());
    160176   
    161177    var ret = [];
    162     for (var x = 0; x < g_Map.size; x++) {
    163         for (var y = 0; y < g_Map.size; y++) {
     178    for (var x = 0; x < g_Map.size; ++x) {
     179        for (var y = 0; y < g_Map.size; ++y) {
    164180            if (g_Map.height[x][y] >= this.lowerBound && g_Map.height[x][y] <= this.upperBound && constraint.allows(x, y)) {
    165181                ret.push(new PointXZ(x, y));
    166182            }
     
    169185    return ret;
    170186};
    171187
    172 /*
    173 Takes an array of 2D points (arrays of length 2)
    174 Returns the order to go through the points for the shortest closed path (array of indices)
    175 */
     188/**
     189 * Takes an array of 2D points (arrays of length 2)
     190 * Returns the order to go through the points for the shortest closed path (array of indices)
     191 */
    176192function getOrderOfPointsForShortestClosePath(points)
    177193{
    178194    var order = [];
    179195    var distances = [];
    180196    if (points.length <= 3)
    181197    {
    182         for (var i = 0; i < points.length; i++)
     198        for (var i = 0; i < points.length; ++i)
    183199            order.push(i);
    184200       
    185201        return order;
     
    187203   
    188204    // Just add the first 3 points
    189205    var pointsToAdd = deepcopy(points);
    190     for (var i = 0; i < min(points.length, 3); i++)
     206    for (var i = 0; i < min(points.length, 3); i)
    191207    {
    192208        order.push(i);
    193209        pointsToAdd.shift(i);
     
    198214   
    199215    // Add remaining points so the path lengthens the least
    200216    var numPointsToAdd = pointsToAdd.length;
    201     for (var i = 0; i < numPointsToAdd; i++)
     217    for (var i = 0; i < numPointsToAdd; ++i)
    202218    {
    203219        var indexToAddTo = undefined;
    204220        var minEnlengthen = Infinity;
    205221        var minDist1 = 0;
    206222        var minDist2 = 0;
    207         for (var k = 0; k < order.length; k++)
     223        for (var k = 0; k < order.length; ++k)
    208224        {
    209225            var dist1 = getDistance(pointsToAdd[0][0], pointsToAdd[0][1], points[order[k]][0], points[order[k]][1]);
    210226            var dist2 = getDistance(pointsToAdd[0][0], pointsToAdd[0][1], points[order[(k + 1) % order.length]][0], points[order[(k + 1) % order.length]][1]);
     
    226242}
    227243
    228244
    229 ////////////////
    230 //
    231 //  Heightmap functionality
    232 //
    233 ////////////////
     245/**
     246 *  Heightmap functionality
     247 */
    234248
    235 // Some heightmap constants
    236 const MIN_HEIGHT = - SEA_LEVEL; // -20
    237 const MAX_HEIGHT = 0xFFFF/HEIGHT_UNITS_PER_METRE - SEA_LEVEL; // A bit smaller than 90
    238 
    239 // Get the diferrence between minimum and maxumum height
     249/**
     250 * Get the diferrence between minimum and maxumum height
     251 */
    240252function getMinAndMaxHeight(reliefmap)
    241253{
    242254    var height = {};
    243255    height.min = Infinity;
    244256    height.max = - Infinity;
    245     for (var x = 0; x < reliefmap.length; x++)
     257    for (var x = 0; x < reliefmap.length; ++x)
    246258    {
    247         for (var y = 0; y < reliefmap[x].length; y++)
     259        for (var y = 0; y < reliefmap[x].length; ++y)
    248260        {
    249261            if (reliefmap[x][y] < height.min)
    250262                height.min = reliefmap[x][y];
     
    264276    var oldHeightRange = getMinAndMaxHeight(heightmap);
    265277    var max_x = heightmap.length;
    266278    var max_y = heightmap[0].length;
    267     for (var x = 0; x < max_x; x++)
    268         for (var y = 0; y < max_y; y++)
     279    for (var x = 0; x < max_x; ++x)
     280        for (var y = 0; y < max_y; ++y)
    269281            heightmap[x][y] = minHeight + (heightmap[x][y] - oldHeightRange.min) / (oldHeightRange.max - oldHeightRange.min) * (maxHeight - minHeight);
    270282}
    271283
    272 /*
    273 getStartLocationsByHeightmap
    274 Takes
    275     hightRange      An associative array with keys 'min' and 'max' each containing a float (the height range start locations are allowed)
    276     heightmap       Optional, default is g_Map.height, an array of (map width) arrays of (map depth) floats
    277     maxTries        Optional, default is 1000, an integer, how often random player distributions are rolled to be compared
    278     minDistToBorder Optional, default is 20, an integer, how far start locations have to be
    279     numberOfPlayers Optional, default is getNumPlayers, an integer, how many start locations should be placed
    280 Returns
    281     An array of 2D points (arrays of length 2)
    282 */
     284/**
     285 * getStartLocationsByHeightmap
     286 * Takes
     287 *  hightRange      An associative array with keys 'min' and 'max' each containing a float (the height range start locations are allowed)
     288 *  heightmap       Optional, default is g_Map.height, an array of (map width) arrays of (map depth) floats
     289 *  maxTries        Optional, default is 1000, an integer, how often random player distributions are rolled to be compared
     290 *  minDistToBorder Optional, default is 20, an integer, how far start locations have to be
     291 *  numberOfPlayers Optional, default is getNumPlayers, an integer, how many start locations should be placed
     292 * Returns
     293 *  An array of 2D points (arrays of length 2)
     294 */
    283295function getStartLocationsByHeightmap(hightRange, maxTries, minDistToBorder, numberOfPlayers, heightmap)
    284296{
    285297    maxTries = (maxTries || 1000);
     
    288300    heightmap = (heightmap || g_Map.height);
    289301   
    290302    var validStartLocTiles = [];
    291     for (var x = minDistToBorder; x < heightmap.length - minDistToBorder; x++)
    292         for (var y = minDistToBorder; y < heightmap[0].length - minDistToBorder; y++)
     303    for (var x = minDistToBorder; x < heightmap.length - minDistToBorder; ++x)
     304        for (var y = minDistToBorder; y < heightmap[0].length - minDistToBorder; ++y)
    293305            if (heightmap[x][y] > hightRange.min && heightmap[x][y] < hightRange.max) // Has the right hight
    294306                validStartLocTiles.push([x, y]);
    295307   
    296308    var maxMinDist = 0;
    297     for (var tries = 0; tries < maxTries; tries++)
     309    for (var tries = 0; tries < maxTries; ++tries)
    298310    {
    299311        var startLoc = [];
    300312        var minDist = heightmap.length;
    301         for (var p = 0; p < numberOfPlayers; p++)
     313        for (var p = 0; p < numberOfPlayers; ++p)
    302314            startLoc.push(validStartLocTiles[randInt(validStartLocTiles.length)]);
    303         for (var p1 = 0; p1 < numberOfPlayers - 1; p1++)
     315        for (var p1 = 0; p1 < numberOfPlayers - 1; ++p1)
    304316        {
    305             for (var p2 = p1 + 1; p2 < numberOfPlayers; p2++)
     317            for (var p2 = p1 + 1; p2 < numberOfPlayers; ++p2)
    306318            {
    307319                var dist = getDistance(startLoc[p1][0], startLoc[p1][1], startLoc[p2][0], startLoc[p2][1]);
    308320                if (dist < minDist)
     
    319331    return finalStartLoc;
    320332}
    321333
    322 /*
    323 derivateEntitiesByHeight
    324 Takes
    325     hightRange      An associative array with keys 'min' and 'max' each containing a float (the height range start locations are allowed)
    326     startLoc        An array of 2D points (arrays of length 2)
    327     heightmap       Optional, default is g_Map.height, an array of (map width) arrays of (map depth) floats
    328     entityList      Array of entities/actors (strings to be placed with placeObject())
    329     maxTries        Optional, default is 1000, an integer, how often random player distributions are rolled to be compared
    330     minDistance     Optional, default is 30, an integer, how far start locations have to be away from start locations and the map border
    331 Returns
    332     An array of 2D points (arrays of length 2)
    333 */
     334/**
     335 *derivateEntitiesByHeight
     336 *Takes
     337 *  hightRange      An associative array with keys 'min' and 'max' each containing a float (the height range start locations are allowed)
     338 *  startLoc        An array of 2D points (arrays of length 2)
     339 *  heightmap       Optional, default is g_Map.height, an array of (map width) arrays of (map depth) floats
     340 *  entityList      Array of entities/actors (strings to be placed with placeObject())
     341 *  maxTries        Optional, default is 1000, an integer, how often random player distributions are rolled to be compared
     342 *  minDistance     Optional, default is 30, an integer, how far start locations have to be away from start locations and the map border
     343 *Returns
     344 *  An array of 2D points (arrays of length 2)
     345 */
    334346function derivateEntitiesByHeight(hightRange, startLoc, entityList, maxTries, minDistance, heightmap)
    335347{
    336348    entityList = (entityList || [templateMetalMine, templateStoneMine]);
     
    340352   
    341353    var placements = deepcopy(startLoc);
    342354    var validTiles = [];
    343     for (var x = minDistance; x < heightmap.length - minDistance; x++)
    344         for (var y = minDistance; y < heightmap[0].length - minDistance; y++)
     355    for (var x = minDistance; x < heightmap.length - minDistance; ++x)
     356        for (var y = minDistance; y < heightmap[0].length - minDistance; ++y)
    345357            if (heightmap[x][y] > hightRange.min && heightmap[x][y] < hightRange.max) // Has the right hight
    346358                validTiles.push([x, y]);
    347359   
    348360    if (!validTiles.length)
    349361        return;
    350362   
    351     for (var tries = 0; tries < maxTries; tries++)
     363    for (var tries = 0; tries < maxTries; ++tries)
    352364    {
    353365        var tile = validTiles[randInt(validTiles.length)];
    354366        var isValid = true;
    355         for (var p = 0; p < placements.length; p++)
     367        for (var p = 0; p < placements.length; ++p)
    356368        {
    357369            if (getDistance(placements[p][0], placements[p][1], tile[0], tile[1]) < minDistance)
    358370            {
     
    370382}
    371383
    372384
    373 ////////////////
    374 //
    375 //  Base terrain generation functionality
    376 //
    377 ////////////////
     385/**
     386 *  Base terrain generation functionality
     387 */
    378388
    379389function setBaseTerrainDiamondSquare(minHeight, maxHeight, smoothness, initialHeightmap, heightmap)
    380390{
     
    395405        var newHeightmap = [];
    396406        var oldWidth = initialHeightmap.length;
    397407        // Square
    398         for (var x = 0; x < 2 * oldWidth - 1; x++)
     408        for (var x = 0; x < 2 * oldWidth - 1; ++x)
    399409        {
    400410            newHeightmap.push([]);
    401             for (var y = 0; y < 2 * oldWidth - 1; y++)
     411            for (var y = 0; y < 2 * oldWidth - 1; ++y)
    402412            {
    403413                if (x % 2 === 0 && y % 2 === 0) // Old tile
    404414                    newHeightmap[x].push(initialHeightmap[x/2][y/2]);
     
    412422            }
    413423        }
    414424        // Diamond
    415         for (var x = 0; x < 2 * oldWidth - 1; x++)
     425        for (var x = 0; x < 2 * oldWidth - 1; ++x)
    416426        {
    417             for (var y = 0; y < 2 * oldWidth - 1; y++)
     427            for (var y = 0; y < 2 * oldWidth - 1; ++y)
    418428            {
    419429                if (newHeightmap[x][y] === undefined)
    420430                {
     
    452462   
    453463    // Cut initialHeightmap to fit target width
    454464    var shift = [floor((newHeightmap.length - heightmap.length) / 2), floor((newHeightmap[0].length - heightmap[0].length) / 2)];
    455     for (var x = 0; x < heightmap.length; x++)
    456         for (var y = 0; y < heightmap[0].length; y++)
     465    for (var x = 0; x < heightmap.length; ++x)
     466        for (var y = 0; y < heightmap[0].length; ++y)
    457467            heightmap[x][y] = newHeightmap[x][y];
    458468}
    459469
    460470
    461 ////////////////
    462 //
    463 //  Terrain erosion functionality
    464 //
    465 ////////////////
    466 
     471/**
     472 *  Terrain erosion functionality
     473 */
    467474function decayErrodeHeightmap(strength, heightmap)
    468475{
    469476    strength = (strength || 0.9); // 0 to 1
     
    474481    var map = [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]; // smoother
    475482    var max_x = heightmap.length;
    476483    var max_y = heightmap[0].length;
    477     for (var x = 0; x < max_x; x++)
    478         for (var y = 0; y < max_y; y++)
    479             for (var i = 0; i < map.length; i++)
     484    for (var x = 0; x < max_x; ++x)
     485        for (var y = 0; y < max_y; ++y)
     486            for (var i = 0; i < map.length; ++i)
    480487                heightmap[x][y] += strength / map.length * (referenceHeightmap[(x + map[i][0] + max_x) % max_x][(y + map[i][1] + max_y) % max_y] - referenceHeightmap[x][y]); // Not entirely sure if scaling with map.length is perfect but tested values seam to indicate it is
    481488}
    482489
     
    490497    heightmap = (heightmap || g_Map.height);
    491498   
    492499    var heightmapWin = [];
    493     for (var wx = 0; wx < 2 * dx + 1; wx++)
     500    for (var wx = 0; wx < 2 * dx + 1; ++wx)
    494501    {
    495502        heightmapWin.push([]);
    496         for (var wy = 0; wy < 2 * dy + 1; wy++)
     503        for (var wy = 0; wy < 2 * dy + 1; ++wy)
    497504        {
    498505            var actualX = x - dx + wx;
    499506            var actualY = y - dy + wy;
     
    503510                heightmapWin[wx].push(targetHeight);
    504511        }
    505512    }
    506     for (var wx = 0; wx < 2 * dx + 1; wx++)
     513    for (var wx = 0; wx < 2 * dx + 1; ++wx)
    507514    {
    508         for (var wy = 0; wy < 2 * dy + 1; wy++)
     515        for (var wy = 0; wy < 2 * dy + 1; ++wy)
    509516        {
    510517            var actualX = x - dx + wx;
    511518            var actualY = y - dy + wy;
     
    522529}
    523530
    524531
    525 ////////////////
    526 //
    527 //  Actually do stuff
    528 //
    529 ////////////////
     532/**
     533 *  Actually do stuff
     534 */
    530535
    531 ////////////////
    532 // Set height limits and water level by map size
    533 ////////////////
     536/**
     537 * Set height limits and water level by map size
     538 */
    534539
    535 // Set target min and max height depending on map size to make average steepness about the same on all map sizes
     540/**
     541 * Set target min and max height depending on map size to make average steepness about the same on all map sizes
     542 */
    536543var heightRange = {'min': MIN_HEIGHT * (g_Map.size + 512) / 8192, 'max': MAX_HEIGHT * (g_Map.size + 512) / 8192, 'avg': (MIN_HEIGHT * (g_Map.size + 512) +MAX_HEIGHT * (g_Map.size + 512))/16384};
    537544
    538 // Set average water coverage
     545/**
     546 * Set average water coverage
     547 */
    539548var averageWaterCoverage = 1/5; // NOTE: Since erosion is not predictable actual water coverage might vary much with the same values
    540549var waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min);
    541550var waterHeightAdjusted = waterHeight + MIN_HEIGHT;
    542551setWaterHeight(waterHeight);
    543552
    544 ////////////////
    545 // Generate base terrain
    546 ////////////////
     553/**
     554 * Generate base terrain
     555 */
    547556
    548 // Setting a 3x3 Grid as initial heightmap
     557/**
     558 * Setting a 3x3 Grid as initial heightmap
     559 */
    549560var initialReliefmap = [[heightRange.max, heightRange.max, heightRange.max], [heightRange.max, heightRange.min, heightRange.max], [heightRange.max, heightRange.max, heightRange.max]];
    550561
    551562setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, 0.5, initialReliefmap, g_Map.height);
    552 // Apply simple erosion
    553 for (var i = 0; i < 5; i++)
     563/**
     564 * Apply simple erosion
     565 */
     566for (var i = 0; i < 5; ++i)
    554567    decayErrodeHeightmap(0.5);
    555568rescaleHeightmap(heightRange.min, heightRange.max);
    556569
    557570RMS.SetProgress(50);
    558571
    559 //////////
    560 // Setup height limit
    561 //////////
     572/**
     573 * Setup height limit
     574 */
    562575
    563 // Height presets
     576/**
     577 * Height presets
     578 */
    564579var heighLimits = [
    565580    heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), // 0 Deep water
    566581    heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), // 1 Medium Water
     
    574589    waterHeightAdjusted + 7/8 * (heightRange.max - waterHeightAdjusted), // 9 Upper forest border
    575590    waterHeightAdjusted + (heightRange.max - waterHeightAdjusted)]; // 10 Hilltop
    576591
    577 //////////
    578 // Place start locations and apply terrain texture and decorative props
    579 //////////
     592/**
     593 * Place start locations and apply terrain texture and decorative props
     594 */
    580595
    581 // Get start locations
     596/**
     597 * Get start locations
     598 */
    582599var startLocations = getStartLocationsByHeightmap({'min': heighLimits[4], 'max': heighLimits[5]});
    583600var playerHeight = (heighLimits[4] + heighLimits[5]) / 2;
    584601
    585 for (var i=0; i < numPlayers; i++)
     602for (var i=0; i < numPlayers; ++i)
    586603{
    587604    playerAngle[i] = (playerAngleStart + i*playerAngleAddAvrg + randFloat(0, playerAngleMaxOff))%(2*PI);
    588605    var x = round(mapCenterX + randFloat(minPlayerRadius, maxPlayerRadius)*cos(playerAngle[i]));
     
    604621    var distToSL = 15;
    605622    var resStartAngle = playerAngle[i] + PI;
    606623    var resAddAngle = 2*PI / startingResources.length;
    607     for (var rIndex = 0; rIndex < startingResources.length; rIndex++)
     624    for (var rIndex = 0; rIndex < startingResources.length; ++rIndex)
    608625    {
    609626        var angleOff = randFloat(-resAddAngle/2, resAddAngle/2);
    610627        var placeX = x + distToSL*cos(resStartAngle + rIndex*resAddAngle + angleOff);
     
    614631    }
    615632}
    616633
    617 // Add further stone and metal mines
     634/**
     635 * Add further stone and metal mines
     636 */
    618637derivateEntitiesByHeight({'min': heighLimits[3], 'max': ((heighLimits[4]+heighLimits[3])/2)}, startLocations);
    619638derivateEntitiesByHeight({'min': ((heighLimits[5]+heighLimits[6])/2), 'max': heighLimits[7]}, startLocations);
    620639
    621640RMS.SetProgress(50);
    622641
    623 //place water & open terrain textures and assign TileClasses
     642/**
     643 * place water & open terrain textures and assign TileClasses
     644 */
    624645log("Painting textures...");
    625646var placer = new HeightPlacer(heighLimits[2], (heighLimits[3]+heighLimits[2])/2);
    626647var painter = new LayeredPainter([terrainBase, terrainBaseBorder], [5]);
     
    634655
    635656RMS.SetProgress(60);
    636657
    637 // Place paths
     658/**
     659 * Place paths
     660 */
    638661log("Placing paths...");
    639662var doublePaths = true;
    640663if (numPlayers > 4)
     
    644667    var maxI = numPlayers+1;
    645668else
    646669    var maxI = numPlayers;
    647 for (var i = 0; i < maxI; i++)
     670for (var i = 0; i < maxI; ++i)
    648671{
    649672    if (doublePaths === true)
    650673        var minJ = 0;
    651674    else
    652675        var minJ = i+1;
    653     for (var j = minJ; j < numPlayers+1; j++)
     676    for (var j = minJ; j < numPlayers+1; ++j)
    654677    {
    655678        // Setup start and target coordinates
    656679        if (i < numPlayers)
     
    700723            }
    701724            if (getDistance(x, z, targetX, targetZ) < pathSucsessRadius)
    702725                targetReached = true;
    703             tries++;
     726            ++tries;
    704727
    705728        }
    706729    }
     
    708731
    709732RMS.SetProgress(75);
    710733
    711 //create general decoration
     734/**
     735 *create general decoration
     736 */
    712737log("Creating decoration...");
    713738createDecoration
    714739(
     
    730755
    731756RMS.SetProgress(80);
    732757
    733 //create fish
     758/**
     759 *create fish
     760 */
    734761log("Growing fish...");
    735762createFood
    736763(
     
    745772
    746773RMS.SetProgress(85);
    747774
    748 // create reeds
     775/**
     776 * create reeds
     777 */
    749778log("Planting reeds...");
    750779var types = [aReeds];   // some variation
    751780for (var i = 0; i < types.length; ++i)
     
    759788
    760789RMS.SetProgress(90);
    761790
    762 // place trees
     791/**
     792 * place trees
     793 */
    763794log("Planting trees...");
    764 for (var x = 0; x < mapSize; x++)
     795for (var x = 0; x < mapSize; ++x)
    765796{
    766     for (var z = 0;z < mapSize;z++)
     797    for (var z = 0; z < mapSize; ++z)
    767798    {
    768799        // Some variables
    769800        var radius = Math.pow(Math.pow(mapCenterX - x - 0.5, 2) + Math.pow(mapCenterZ - z - 0.5, 2), 1/2); // The 0.5 is a correction for the entities placed on the center of tiles
    770801        var minDistToSL = mapSize;
    771         for (var i=0; i < numPlayers; i++)
     802        for (var i=0; i < numPlayers; ++i)
    772803            minDistToSL = min(minDistToSL, getDistance(playerStartLocX[i], playerStartLocZ[i], x, z));
    773804        // Woods tile based
    774805        var tDensFactSL = max(min((minDistToSL - baseRadius) / baseRadius, 1), 0);
     
    793824
    794825RMS.SetProgress(100);
    795826
    796 // Export map data
     827/**
     828 * Export map data
     829 */
    797830ExportMap();