Ticket #3764: realistic_terrain_demo2016-1-31c.diff
File realistic_terrain_demo2016-1-31c.diff, 114.8 KB (added by , 8 years ago) |
---|
-
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 14 RMS.LoadLibrary("rmgen"); 15 16 const BUILDING_ANGlE = -PI/4; 17 18 /** 19 * initialize map 20 */ 21 22 log("Initializing map..."); 23 24 InitMap(); 25 26 var numPlayers = g_MapSettings.PlayerData.length; 27 var 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 */ 37 var heightRange = {"min": MIN_HEIGHT * (mapSize + 512) / 1024 / 8, "max": MAX_HEIGHT * (mapSize + 512) / 1024 / 8}; 38 39 /** 40 * Set average water coverage 41 */ 42 var averageWaterCoverage = 1/5; // NOTE: Since erosion is not predictable actual water coverage might vary much with the same values 43 var waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); 44 var waterHeightAdjusted = waterHeight + MIN_HEIGHT; 45 setWaterHeight(waterHeight); 46 47 /** 48 * Generate initial reliefmap 49 */ 50 setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, 0.5); 51 52 53 /** 54 * Apply simple erosion 55 */ 56 for (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 */ 67 randomizeBiome(); 68 69 /** 70 * Define texture textures and decorative props (and density) by height 71 */ 72 var textueByHeight = []; 73 textueByHeight.push({"height": heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), "texture": rbt15, "actor": [rbe9, 0.2]}); 74 textueByHeight.push({"height": heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), "texture": rbt15, "actor": [undefined, 0]}); 75 textueByHeight.push({"height": heightRange.min + 3/3 * (waterHeightAdjusted - heightRange.min), "texture": rbt15, "actor": [rba3, 0.2]}); 76 textueByHeight.push({"height": waterHeightAdjusted + 1/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt14, "actor": [rbe5, 0.1]}); 77 textueByHeight.push({"height": waterHeightAdjusted + 2/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt8, "actor": [undefined, 0]}); 78 textueByHeight.push({"height": waterHeightAdjusted + 3/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt9, "actor": [undefined, 0]}); 79 textueByHeight.push({"height": waterHeightAdjusted + 4/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt1, "actor": [undefined, 0]}); 80 textueByHeight.push({"height": waterHeightAdjusted + 5/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt5, "actor": [rbe3, 0.2]}); 81 textueByHeight.push({"height": waterHeightAdjusted + 6/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt2, "actor": [rbe1, 0.4]}); 82 textueByHeight.push({"height": waterHeightAdjusted + 7/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt3, "actor": [rbe2, 0.4]}); 83 textueByHeight.push({"height": waterHeightAdjusted + 8/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt7, "actor": [rbe4, 0.2]}); 84 textueByHeight.push({"height": waterHeightAdjusted + 9/9 * (heightRange.max - waterHeightAdjusted), "texture": rbt4, "actor": [undefined, 0]}); 85 86 /** 87 * Get start locations 88 */ 89 rescaleHeightmap(heightRange.min, heightRange.max); 90 var startLocations = getStartLocationsByHeightmap({"min": textueByHeight[4].height, "max": textueByHeight[5].height}); 91 92 /** 93 * Smooth ground at start locations and place starting entities 94 */ 95 var playerHeight = (textueByHeight[4].height + textueByHeight[5].height) / 2; 96 for (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 */ 107 rescaleHeightmap(heightRange.min, heightRange.max); 108 109 /** 110 * Place terrain texture and decorative props by height 111 */ 112 for(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 */ 146 ExportMap(); -
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 */ 2 4 var timeArray = []; 3 5 timeArray.push(new Date().getTime()); 4 6 5 // Importing rmgen libraries 7 /** 8 * Importing rmgen libraries 9 */ 6 10 RMS.LoadLibrary("rmgen"); 7 11 8 12 const BUILDING_ANGlE = -PI/4; 9 13 10 // initialize map 11 14 /** 15 * initialize map 16 */ 12 17 log("Initializing map..."); 13 18 14 19 InitMap(); … … 17 22 var mapSize = getMapSize(); 18 23 19 24 20 / /////////21 //Heightmap functionality22 //////////25 /** 26 * Heightmap functionality 27 */ 23 28 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 */ 29 32 function getRandomReliefmap(minHeight, maxHeight) 30 33 { 31 34 minHeight = (minHeight || MIN_HEIGHT); … … 35 38 if (maxHeight > MAX_HEIGHT) 36 39 warn("getRandomReliefmap: Argument maxHeight is smaler then the supported maximum height of " + MAX_HEIGHT + " (const MAX_HEIGHT): " + maxHeight) 37 40 var reliefmap = []; 38 for (var x = 0; x <= mapSize; x++)41 for (var x = 0; x <= mapSize; ++x) 39 42 { 40 43 reliefmap.push([]); 41 for (var y = 0; y <= mapSize; y++)44 for (var y = 0; y <= mapSize; ++y) 42 45 { 43 46 reliefmap[x].push(randFloat(minHeight, maxHeight)); 44 47 } … … 46 49 return reliefmap; 47 50 } 48 51 49 // Apply a heightmap 52 /** 53 * Apply a heightmap 54 */ 50 55 function setReliefmap(reliefmap) 51 56 { 52 // g_Map.height = reliefmap; 53 for (var x = 0; x <= mapSize; x++) 57 for (var x = 0; x <= mapSize; ++x) 54 58 { 55 for (var y = 0; y <= mapSize; y++)59 for (var y = 0; y <= mapSize; ++y) 56 60 { 57 61 setHeight(x, y, reliefmap[x][y]); 58 62 } 59 63 } 60 64 } 61 65 62 // Get minimum and maxumum height used in a heightmap 66 /** 67 * Get minimum and maxumum height used in a heightmap 68 */ 63 69 function getMinAndMaxHeight(reliefmap) 64 70 { 65 71 var height = {}; 66 72 height.min = Infinity; 67 73 height.max = -Infinity; 68 for (var x = 0; x <= mapSize; x++)74 for (var x = 0; x <= mapSize; ++x) 69 75 { 70 for (var y = 0; y <= mapSize; y++)76 for (var y = 0; y <= mapSize; ++y) 71 77 { 72 78 if (reliefmap[x][y] < height.min) 73 79 height.min = reliefmap[x][y]; … … 78 84 return height; 79 85 } 80 86 81 // Rescale a heightmap (Waterlevel is not taken into consideration!) 87 /** 88 * Rescale a heightmap (Waterlevel is not taken into consideration!) 89 */ 82 90 function getRescaledReliefmap(reliefmap, minHeight, maxHeight) 83 91 { 84 92 var newReliefmap = deepcopy(reliefmap); … … 89 97 if (maxHeight > MAX_HEIGHT) 90 98 warn("getRescaledReliefmap: Argument maxHeight is smaler then the supported maximum height of " + MAX_HEIGHT + " (const MAX_HEIGHT): " + maxHeight) 91 99 var oldHeightRange = getMinAndMaxHeight(reliefmap); 92 for (var x = 0; x <= mapSize; x++)100 for (var x = 0; x <= mapSize; ++x) 93 101 { 94 for (var y = 0; y <= mapSize; y++)102 for (var y = 0; y <= mapSize; ++y) 95 103 { 96 104 newReliefmap[x][y] = minHeight + (reliefmap[x][y] - oldHeightRange.min) / (oldHeightRange.max - oldHeightRange.min) * (maxHeight - minHeight); 97 105 } … … 99 107 return newReliefmap 100 108 } 101 109 102 // Applying decay errosion (terrain independent) 110 /** 111 * Applying decay errosion (terrain independent) 112 */ 103 113 function getHeightErrosionedReliefmap(reliefmap, strength) 104 114 { 105 115 var newReliefmap = deepcopy(reliefmap); 106 116 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 107 117 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) 109 119 { 110 for (var y = 0; y <= mapSize; y++)120 for (var y = 0; y <= mapSize; ++y) 111 121 { 112 122 var div = 0; 113 for (var i = 0; i < map.length; i++)123 for (var i = 0; i < map.length; ++i) 114 124 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 115 125 } 116 126 } … … 118 128 } 119 129 120 130 121 / /////////122 //Prepare for hightmap munipulation123 //////////131 /** 132 * Prepare for hightmap munipulation 133 */ 124 134 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 */ 138 var heightRange = { "min": MIN_HEIGHT * (mapSize + 256) / 8192, "max": MAX_HEIGHT * (mapSize + 256) / 8192 }; 127 139 128 // Set average water coverage 140 /** 141 * Set average water coverage 142 */ 129 143 var averageWaterCoverage = 1/3; // NOTE: Since errosion is not predictable actual water coverage might differ much with the same value 130 144 if (mapSize < 200) // Sink the waterlevel on tiny maps to ensure enough space 131 145 averageWaterCoverage = 2/3 * averageWaterCoverage; … … 134 148 setWaterHeight(waterHeight); 135 149 136 150 137 ////////// 138 // Prepare terrain texture by height placement 139 ////////// 140 151 /** 152 * Prepare terrain texture by height placement 153 */ 141 154 var textueByHeight = []; 142 155 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 */ 159 textueByHeight.push({ "upperHeightLimit": heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), "terrain": "temp_sea_rocks" }); 160 161 /** 162 * Medium water (with fish) 163 */ 164 var terrains = ["temp_sea_weed"]; 165 terrains = terrains.concat(terrains, terrains, terrains, terrains); 166 terrains = terrains.concat(terrains, terrains, terrains, terrains); 167 terrains.push("temp_sea_weed|gaia/fauna_fish"); 168 textueByHeight.push({ "upperHeightLimit": heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), "terrain": terrains }); 169 170 /** 171 * Flat Water 172 */ 173 textueByHeight.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 */ 178 var terrains = ["temp_plants_bog", "temp_plants_bog_aut", "temp_dirt_gravel_plants", "temp_grass_d"]; 179 terrains = terrains.concat(terrains, terrains, terrains, terrains, terrains); 180 terrains = ["temp_plants_bog|gaia/flora_bush_temperate"].concat(terrains, terrains); 181 terrains = ["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); 182 terrains = ["temp_plants_bog_aut|gaia/flora_tree_dead"].concat(terrains, terrains); 183 textueByHeight.push({ "upperHeightLimit": waterHeightAdjusted + 1/6 * (heightRange.max - waterHeightAdjusted), "terrain": terrains }); 184 185 /** 186 * Juicy grass near bog 187 */ 188 textueByHeight.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 */ 194 textueByHeight.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 */ 200 textueByHeight.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 */ 206 var terrains = ["temp_grass_plants|gaia/flora_tree_euro_beech", "temp_grass_mossy|gaia/flora_tree_poplar", "temp_grass_mossy|gaia/flora_tree_poplar_lombardy", 172 207 "temp_grass_long|gaia/flora_bush_temperate", "temp_mud_plants|gaia/flora_bush_temperate", "temp_mud_plants|gaia/flora_bush_badlands", 173 208 "temp_grass_long|gaia/flora_tree_apple", "temp_grass_clovers|gaia/flora_bush_berry", "temp_grass_clovers_2|gaia/flora_bush_grapes", 174 209 "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), 210 var numTerreins = terrains.length; 211 for (var i = 0; i < numTerreins; ++i) 212 terrains.push("temp_grass_plants"); 213 textueByHeight.push({ "upperHeightLimit": waterHeightAdjusted + 5/6 * (heightRange.max - waterHeightAdjusted), "terrain": terrains }); 214 215 /** 216 * Impassable woods 217 */ 218 textueByHeight.push({ "upperHeightLimit": waterHeightAdjusted + 6/6 * (heightRange.max - waterHeightAdjusted), 181 219 "terrain": ["temp_grass_mossy|gaia/flora_tree_oak", "temp_forestfloor_pine|gaia/flora_tree_pine", 182 220 "temp_grass_mossy|gaia/flora_tree_oak", "temp_forestfloor_pine|gaia/flora_tree_pine", 183 221 "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"] }); 185 223 var minTerrainDistToBorder = 3; 186 224 187 // Time check 1 225 /** 226 * Time check 1 227 */ 188 228 timeArray.push(new Date().getTime()); 189 229 RMS.SetProgress(5); 190 230 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 */ 197 238 var goodStartPositionsFound = false; 198 239 var minDistBetweenPlayers = 16 + mapSize / 16; // Don't set this higher than 25 for tiny maps! It will take forever with 8 players! 199 240 var enoughTiles = false; 200 241 var tries = 0; 201 242 while (!goodStartPositionsFound) 202 243 { 203 tries++;244 ++tries; 204 245 log("Starting giant while loop try " + tries); 205 246 // Generate reliefmap 206 247 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) 208 249 myReliefmap = getHeightErrosionedReliefmap(myReliefmap, 1); 209 250 myReliefmap = getRescaledReliefmap(myReliefmap, heightRange.min, heightRange.max); 210 251 setReliefmap(myReliefmap); … … 217 258 var lowerHeightLimit = textueByHeight[3].upperHeightLimit; 218 259 var upperHeightLimit = textueByHeight[6].upperHeightLimit; 219 260 // 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) 221 262 { 222 for (var y = distToBorder + minTerrainDistToBorder; y < mapSize - distToBorder - minTerrainDistToBorder; y++)263 for (var y = distToBorder + minTerrainDistToBorder; y < mapSize - distToBorder - minTerrainDistToBorder; ++y) 223 264 { 224 265 var actualHeight = getHeight(x, y); 225 266 if (actualHeight > lowerHeightLimit && actualHeight < upperHeightLimit) 226 267 { 227 268 // Check for points within a valid area by height (rectangular since faster) 228 269 var isPossible = true; 229 for (var offX = - neededDistance; offX <= neededDistance; offX++)270 for (var offX = - neededDistance; offX <= neededDistance; ++offX) 230 271 { 231 for (var offY = - neededDistance; offY <= neededDistance; offY++)272 for (var offY = - neededDistance; offY <= neededDistance; ++offY) 232 273 { 233 274 var testHeight = getHeight(x + offX, y + offY); 234 275 if (testHeight <= lowerHeightLimit || testHeight >= upperHeightLimit) … … 241 282 if (isPossible) 242 283 { 243 284 possibleStartPositions.push([x, y]); 244 // placeTerrain(x, y, "blue"); // For debug reasons. Plz don't remove. // Only works properly for 1 loop245 285 } 246 286 } 247 287 } … … 252 292 // Reduce to tiles in a circle of mapSize / 2 distance to the center (to avoid players placed in corners) 253 293 var possibleStartPositionsTemp = []; 254 294 var maxDistToCenter = mapSize / 2; 255 for (var i = 0; i < possibleStartPositions.length; i++)295 for (var i = 0; i < possibleStartPositions.length; ++i) 256 296 { 257 297 var deltaX = possibleStartPositions[i][0] - mapSize / 2; 258 298 var deltaY = possibleStartPositions[i][1] - mapSize / 2; … … 260 300 if (distToCenter < maxDistToCenter) 261 301 { 262 302 possibleStartPositionsTemp.push(possibleStartPositions[i]); 263 // placeTerrain(possibleStartPositions[i][0], possibleStartPositions[i][1], "purple"); // Only works properly for 1 loop264 303 } 265 304 } 266 305 possibleStartPositions = deepcopy(possibleStartPositionsTemp); … … 270 309 var maxDistToResources = distToBorder; // Has to be <= distToBorder! 271 310 var minNumLowTiles = 10; 272 311 var minNumHighTiles = 10; 273 for (var i = 0; i < possibleStartPositions.length; i++)312 for (var i = 0; i < possibleStartPositions.length; ++i) 274 313 { 275 314 var numLowTiles = 0; 276 315 var numHighTiles = 0; 277 for (var dx = - maxDistToResources; dx < maxDistToResources; dx++)316 for (var dx = - maxDistToResources; dx < maxDistToResources; ++dx) 278 317 { 279 for (var dy = - maxDistToResources; dy < maxDistToResources; dy++)318 for (var dy = - maxDistToResources; dy < maxDistToResources; ++dy) 280 319 { 281 320 var testHeight = getHeight(possibleStartPositions[i][0] + dx, possibleStartPositions[i][1] + dy); 282 321 if (testHeight < lowerHeightLimit) 283 numLowTiles++;322 ++numLowTiles; 284 323 if (testHeight > upperHeightLimit) 285 numHighTiles++;324 ++numHighTiles; 286 325 if (numLowTiles > minNumLowTiles && numHighTiles > minNumHighTiles) 287 326 break; 288 327 } … … 292 331 if (numLowTiles > minNumLowTiles && numHighTiles > minNumHighTiles) 293 332 { 294 333 possibleStartPositionsTemp.push(possibleStartPositions[i]); 295 // placeTerrain(possibleStartPositions[i][0], possibleStartPositions[i][1], "red"); // Only works properly for 1 loop296 334 } 297 335 } 298 336 possibleStartPositions = deepcopy(possibleStartPositionsTemp); … … 311 349 // Get some random start location derivations. NOTE: Itterating over all possible derivations is just to much (valid points ** numPlayers) 312 350 var maxTries = 100000; // floor(800000 / (Math.pow(numPlayers, 2) / 2)); 313 351 var possibleDerivations = []; 314 for (var i = 0; i < maxTries; i++)352 for (var i = 0; i < maxTries; ++i) 315 353 { 316 354 var vector = []; 317 for (var p = 0; p < numPlayers; p++)355 for (var p = 0; p < numPlayers; ++p) 318 356 vector.push(randInt(possibleStartPositions.length)); 319 357 possibleDerivations.push(vector); 320 358 } 321 359 322 360 // Choose the start location derivation with the greatest minimum distance between players 323 361 var maxMinDist = 0; 324 for (var d = 0; d < possibleDerivations.length; d++)362 for (var d = 0; d < possibleDerivations.length; ++d) 325 363 { 326 364 var minDist = 2 * mapSize; 327 for (var p1 = 0; p1 < numPlayers - 1; p1++)365 for (var p1 = 0; p1 < numPlayers - 1; ++p1) 328 366 { 329 for (var p2 = p1 + 1; p2 < numPlayers; p2++)367 for (var p2 = p1 + 1; p2 < numPlayers; ++p2) 330 368 { 331 369 if (p1 != p2) 332 370 { … … 358 396 } // End of derivation check 359 397 } // END THE GIANT WHILE LOOP 360 398 361 // Time check 2 399 /** 400 * Time check 2 401 */ 362 402 timeArray.push(new Date().getTime()); 363 403 RMS.SetProgress(60); 364 404 365 405 366 / ///////367 //Paint terrain by height and add props368 ////////406 /** 407 * Paint terrain by height and add props 408 */ 369 409 370 410 var propDensity = 1; // 1 means as determined in the loop, less for large maps as set below 371 411 if (mapSize > 500) 372 412 propDensity = 1/4; 373 413 else if (mapSize > 400) 374 414 propDensity = 3/4; 375 for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; x++)415 for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; ++x) 376 416 { 377 for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; y++)417 for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; ++y) 378 418 { 379 419 var textureMinHeight = heightRange.min; 380 for (var i = 0; i < textueByHeight.length; i++)420 for (var i = 0; i < textueByHeight.length; ++i) 381 421 { 382 422 if (getHeight(x, y) >= textureMinHeight && getHeight(x, y) <= textueByHeight[i].upperHeightLimit) 383 423 { … … 488 528 } 489 529 } 490 530 491 // Time check 3 531 /** 532 * Time check 3 533 */ 492 534 timeArray.push(new Date().getTime()); 493 535 RMS.SetProgress(90); 494 536 495 537 496 / ///////497 //Place players and start resources498 ////////538 /** 539 * Place players and start resources 540 */ 499 541 500 for (var p = 0; p < numPlayers; p++)542 for (var p = 0; p < numPlayers; ++p) 501 543 { 502 544 var actualX = possibleStartPositions[bestDerivation[p]][0]; 503 545 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 }); 505 547 // Place some start resources 506 548 var uDist = 8; 507 549 var uSpace = 1; … … 509 551 { 510 552 var uAngle = BUILDING_ANGlE - PI * (2-j) / 2; 511 553 var count = 4; 512 for (var numberofentities = 0; numberofentities < count; numberofentities++)554 for (var numberofentities = 0; numberofentities < count; ++numberofentities) 513 555 { 514 556 var ux = actualX + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); 515 557 var uz = actualY + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); … … 521 563 } 522 564 } 523 565 524 525 // Export map data 566 /** 567 * Export map data 568 */ 526 569 ExportMap(); 527 570 528 // Time check 7 571 /** 572 * Time check 7 573 */ 529 574 timeArray.push(new Date().getTime()); 530 575 531 // Calculate progress percentage with the time checks 576 /** 577 * Calculate progress percentage with the time checks 578 */ 532 579 var generationTime = timeArray[timeArray.length - 1] - timeArray[0]; 533 580 log("Total generation time (ms): " + generationTime); 534 for (var i = 0; i < timeArray.length; i++)581 for (var i = 0; i < timeArray.length; ++i) 535 582 { 536 583 var timeSinceStart = timeArray[i] - timeArray[0]; 537 584 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 */ 18 var genStartTime = new Date().getTime(); 19 20 RMS.LoadLibrary("rmgen"); 21 22 const BUILDING_ANGlE = -PI/4; 23 24 /** 25 * initialize map 26 */ 27 log("Initializing map..."); 28 InitMap(); 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 */ 39 function 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 /* 92 Drags a path to a target height smoothing it at the edges and return some points on the path. 93 94 TODO: 95 Would be nice to tell the function what to do and how often in the arguments 96 Adding painted tiles to a tile class 97 */ 98 function 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 */ 149 var 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 */ 154 var averageWaterCoverage = 1/5; // NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with the same value 155 var waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); // Water height in environment and the engine 156 var waterHeightAdjusted = waterHeight + MIN_HEIGHT; // Water height in RMGEN 157 setWaterHeight(waterHeight); 158 159 160 /** 161 * Generate base terrain 162 */ 163 164 var initialReliefmap = undefined; 165 var low = heightRange.min; 166 var med = 0.5 * (heightRange.min + heightRange.max); 167 var high = heightRange.max; 168 /** 169 * Island 170 */ 171 // initialReliefmap = [[low, low, low], [low, high, low], [low, low, low]]; 172 initialReliefmap = [[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]]; 191 setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, /*0.5*/ 0.8, initialReliefmap, g_Map.height); 192 /** 193 * Apply simple erosion 194 */ 195 for (var i = 0; i < 3; ++i) 196 globalSmoothHeightmap(0.5); 197 rescaleHeightmap(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 */ 211 var 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 */ 227 var dummyActor = "actor|props/special/common/waypoint_flag.xml"; 228 var myBiome = []; 229 /** 230 * temperate 1 231 */ 232 myBiome.push([]); 233 /** 234 * snowy 2 235 */ 236 myBiome.push([]); 237 /** 238 * desert 3 239 */ 240 myBiome.push([]); 241 /** 242 * Alpine 4 243 */ 244 myBiome.push([]); 245 myBiome[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] }); 248 myBiome[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] }); 251 myBiome[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] }); 254 myBiome[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] }); 257 myBiome[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] }); 260 myBiome[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] }); 263 myBiome[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] }); 266 myBiome[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] }); 269 myBiome[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] }); 272 myBiome[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] }); 275 myBiome[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 */ 281 myBiome.push([]); 282 /** 283 * savanah 6 284 */ 285 myBiome.push([]); 286 /** 287 * tropic 7 288 */ 289 myBiome.push([]); 290 /** 291 * autumn 8 292 */ 293 myBiome.push([]); 294 295 /** 296 * Set random biome 297 */ 298 while (biomeID != 4) 299 randomizeBiome(); 300 log("biomeID = " + biomeID); // DEBUG 301 302 if (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 } 312 if (biomeID == 6) 313 rbt9 = [rbt9[1]]; 314 if (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 */ 325 var startLocations = getStartLocationsByHeightmap({ "min": heighLimits[4], "max": heighLimits[5] }); 326 var playerHeight = (heighLimits[4] + heighLimits[5]) / 2; 327 328 /** 329 * Place start locations 330 */ 331 for (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 */ 363 distributeEntitiesByHeight({ "min": heighLimits[4], "max": heighLimits[5] }, startLocations); 364 365 /** 366 * Add paths 367 */ 368 var pathTerrainClasseIDs = []; 369 var pathPointDist = 3; 370 var 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 */ 381 var 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 */ 386 var tchm = getTileCenteredHeightmap(); 387 388 /** 389 * Divide tiles in areas by height and avoid paths 390 */ 391 var areas = []; 392 var pathAreas = []; 393 for (var i = 0; i < pathTerrainClasseIDs.length; ++i) 394 pathAreas.push([]); 395 for (var h = 0; h < heighLimits.length; ++h) 396 areas.push([]); 397 for (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 */ 431 var minSlope = new Array(areas.length); 432 var maxSlope = new Array(areas.length); 433 for (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 */ 452 for (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 */ 480 log("Map generation time: " + (new Date().getTime() - genStartTime)) 481 482 /** 483 * Export map data 484 */ 485 ExportMap(); -
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 */ 22 function 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 */ 49 function 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 */ 71 function 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 */ 100 function 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 */ 124 function 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 */ 155 function 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 */ 206 function 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 */ 264 function 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 */ 359 function 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 */ 401 function 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 */ 6 4 const PI = Math.PI; 7 const TWO_PI = 2 * Math.PI; 5 const TWO_PI = 2 * Math.PI; // mathematically known as 'tau' 8 6 const TERRAIN_SEPARATOR = "|"; 9 const SEA_LEVEL = 20.0;7 const SEA_LEVEL = 160.0; 10 8 const CELL_SIZE = 4; 11 9 const HEIGHT_UNITS_PER_METRE = 92; 12 10 const MIN_MAP_SIZE = 128; 13 11 const MAX_MAP_SIZE = 512; 14 12 const FALLBACK_CIV = "athen"; 15 13 16 ///////////////////////////////////////////////////////////////////////////////////////////// 17 // Utility functions 18 ///////////////////////////////////////////////////////////////////////////////////////////// 14 /** 15 * Constants needed for heightmap_manipulation.js 16 */ 17 const MAX_HEIGHT_RANGE = 0xFFFF / HEIGHT_UNITS_PER_METRE // Engine limit, Roughly 700 meters 18 const MIN_HEIGHT = - SEA_LEVEL; 19 const MAX_HEIGHT = MAX_HEIGHT_RANGE - SEA_LEVEL; 20 /** 21 * Entity template structure keys that might change, for easier mod support 22 */ 23 const CIV_PLACEHOLDER_STRING = "{civ}"; 24 const START_ENTITY_KEYS = ["StartEntities"]; 25 const START_ENTITY_TEMPLATE_KEYS = ["Template"]; 26 const BUILDER_TEMPLATEPATH_KEYS = ["Builder", "Entities", "_string"]; 27 const PRODUCTION_TEMPLATEPATH_KEYS = ["ProductionQueue", "Entities", "_string"]; 28 const WALLSET_KEYS = ["WallSet"]; 29 const BUILDING_KEYS = ["Obstruction", "Static"]; 19 30 31 32 /** 33 * Utility functions 34 */ 35 20 36 function fractionToTiles(f) 21 37 { 22 38 return getMapSize() * f; … … 103 119 if (numArgs != 1) 104 120 { 105 121 var ret = new Array(numArgs); 106 for (var i=0; i < numArgs; i++)122 for (var i=0; i < numArgs; ++i) 107 123 { 108 124 ret[i] = x[i]; 109 125 } … … 125 141 return ar[randInt(ar.length)]; 126 142 } 127 143 128 // "Inside-out" implementation of Fisher-Yates shuffle 144 /** 145 * "Inside-out" implementation of Fisher-Yates shuffle 146 */ 129 147 function shuffleArray(source) 130 148 { 131 149 if (!source.length) 132 150 return []; 133 151 134 152 var result = [source[0]]; 135 for (var i = 1; i < source.length; i++)153 for (var i = 1; i < source.length; ++i) 136 154 { 137 155 var j = randInt(0, i); 138 156 result[i] = result[j]; … … 172 190 var area = g_Map.createArea(centeredPlacer, painter, constraint); 173 191 if (area !== undefined) 174 192 { 175 good++;193 ++good; 176 194 result.push(area); 177 195 } 178 196 else 179 197 { 180 bad++;198 ++bad; 181 199 } 182 200 } 183 201 return result; … … 208 226 var area = g_Map.createArea(centeredPlacer, painter, constraint); 209 227 if (area !== undefined) 210 228 { 211 good++;229 ++good; 212 230 result.push(area); 213 231 } 214 232 else 215 233 { 216 bad++;234 ++bad; 217 235 } 218 236 } 219 237 return result; … … 248 266 var result = createObjectGroup(placer, player, constraint); 249 267 if (result !== undefined) 250 268 { 251 good++;269 ++good; 252 270 } 253 271 else 254 272 { 255 bad++;273 ++bad; 256 274 } 257 275 } 258 276 return good; … … 282 300 var result = createObjectGroup(placer, player, constraint); 283 301 if (result !== undefined) 284 302 { 285 good++;303 ++good; 286 304 } 287 305 else 288 306 { 289 bad++;307 ++bad; 290 308 } 291 309 } 292 310 return good; … … 349 367 return (g_MapSettings.CircularMap ? true : false); 350 368 } 351 369 352 / ////////////////////////////////////////////////////////////////////////////////////////////353 //Access global map variable354 /////////////////////////////////////////////////////////////////////////////////////////////370 /** 371 * Access global map variable 372 */ 355 373 356 374 function createTileClass() 357 375 { … … 394 412 return g_MapSettings.PlayerData.length - 1; 395 413 } 396 414 415 /** 416 * Takes nothing, returns an array of strings representing all available civilizations 417 */ 418 function 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 */ 431 function 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 */ 397 448 function getCivCode(player) 398 449 { 399 450 if (g_MapSettings.PlayerData[player+1].Civ) 400 451 return g_MapSettings.PlayerData[player+1].Civ; 401 452 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 + "'"); 403 454 return FALLBACK_CIV; 404 455 } 405 456 457 /** 458 * Takes an entity path and a key list to get the templates value 459 */ 460 function 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 */ 477 function 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 */ 535 function 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 406 546 function areAllies(player1, player2) 407 547 { 408 548 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)) … … 434 574 435 575 var result = new Array(0); 436 576 var team = new Array(5); 437 for (var q = 0; q < 5; q++)577 for (var q = 0; q < 5; ++q) 438 578 { 439 579 team[q] = new Array(1); 440 580 } 441 581 442 for (var i = -1; i < 4; i++)582 for (var i = -1; i < 4; ++i) 443 583 { 444 for (var j = 0; j < source.length; j++)584 for (var j = 0; j < source.length; ++j) 445 585 { 446 586 if (getPlayerTeam(j) == i) 447 {448 587 team[i+1].unshift(j+1); 449 }450 588 } 451 589 team[i+1].pop(); 452 590 result=result.concat(shuffleArray(team[i+1])) … … 461 599 462 600 var prime = new Array(source.length); 463 601 464 for (var i = 0; i < round(source.length/2); i++)602 for (var i = 0; i < round(source.length/2); ++i) 465 603 { 466 604 prime[2*i]=source[i]; 467 605 prime[2*i+1]=source[source.length-1-i]; … … 492 630 g_Map.setHeight(x, z, height); 493 631 } 494 632 495 /////////////////////////////////////////////////////////////////////////////////////////////496 // Utility functions for classes497 /////////////////////////////////////////////////////////////////////////////////////////////498 633 634 /** 635 * Utility functions for classes 636 */ 499 637 500 // Add point to given class by id 638 /** 639 * Add point to given class by id 640 */ 501 641 function addToClass(x, z, id) 502 642 { 503 643 var tileClass = getTileClass(id); 504 644 505 645 if (tileClass !== null) 506 {507 646 tileClass.add(x, z); 508 }509 647 } 510 648 511 // Remove point from the given class by id 649 /** 650 * Remove point from the given class by id 651 */ 512 652 function removeFromClass(x, z, id) 513 653 { 514 654 var tileClass = getTileClass(id); 515 655 516 656 if (tileClass !== null) 517 {518 657 tileClass.remove(x, z); 519 }520 658 } 521 659 522 // Create a painter for the given class 660 /** 661 * Create a painter for the given class 662 */ 523 663 function paintClass(id) 524 664 { 525 665 return new TileClassPainter(getTileClass(id)); 526 666 } 527 667 528 // Create a painter for the given class 668 /** 669 * Create a painter for the given class 670 */ 529 671 function unPaintClass(id) 530 672 { 531 673 return new TileClassUnPainter(getTileClass(id)); 532 674 } 533 675 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 */ 535 679 function avoidClasses(/*class1, dist1, class2, dist2, etc*/) 536 680 { 537 681 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) 539 683 { 540 684 ar[i] = new AvoidTileClassConstraint(arguments[2*i], arguments[2*i+1]); 541 685 } 542 686 543 687 // Return single constraint 544 688 if (ar.length == 1) 545 {546 689 return ar[0]; 547 }548 690 else 549 691 { 550 692 return new AndConstraint(ar); 551 693 } 552 694 } 553 695 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 */ 555 699 function stayClasses(/*class1, dist1, class2, dist2, etc*/) 556 700 { 557 701 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) 559 703 { 560 704 ar[i] = new StayInTileClassConstraint(arguments[2*i], arguments[2*i+1]); 561 705 } … … 571 715 } 572 716 } 573 717 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 */ 575 721 function borderClasses(/*class1, idist1, odist1, class2, idist2, odist2, etc*/) 576 722 { 577 723 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) 579 725 { 580 726 ar[i] = new BorderTileClassConstraint(arguments[3*i], arguments[3*i+1], arguments[3*i+2]); 581 727 } … … 591 737 } 592 738 } 593 739 594 // Checks if the given tile is in class "id" 740 /** 741 * Checks if the given tile is in class "id" 742 */ 595 743 function checkIfInClass(x, z, id) 596 744 { 597 745 var tileClass = getTileClass(id); … … 612 760 } 613 761 } 614 762 615 616 // Returns the distance between 2 points 763 /** 764 * Returns the distance between 2 points 765 */ 617 766 function getDistance(x1, z1, x2, z2) 618 767 { 619 768 return Math.pow(Math.pow(x1 - x2, 2) + Math.pow(z1 - z2, 2), 1/2); 620 769 } 621 770 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 */ 623 774 function getAngle(x1, z1, x2, z2) 624 775 { 625 776 return Math.atan2(z2 - z1, x2 - x1); 626 777 } 627 778 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 */ 629 782 function getGradient(x1, z1, x2, z2) 630 783 { 631 784 if (x1 == x2 && z1 == z2) … … 642 795 { 643 796 return g_Map.getTexture(x, y); 644 797 } 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 */ 18 16 function passageMaker(x1, z1, x2, z2, width, maxheight, height, smooth, tileclass, terrain, riverheight) 19 17 { 20 18 var tchm = TILE_CENTERED_HEIGHT_MAP; 21 19 TILE_CENTERED_HEIGHT_MAP = true; 22 20 var mapSize = g_Map.size; 23 for (var ix = 0; ix < mapSize; ix++)21 for (var ix = 0; ix < mapSize; ++ix) 24 22 { 25 for (var iz = 0; iz < mapSize; iz++)23 for (var iz = 0; iz < mapSize; ++iz) 26 24 { 27 25 var a = z1-z2; 28 26 var b = x2-x1; … … 73 71 TILE_CENTERED_HEIGHT_MAP = tchm; 74 72 } 75 73 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 */ 88 84 function rndRiver(f, seed) 89 85 { 90 86 var rndRq = seed; … … 92 88 var rndRe = 0; 93 89 var rndRr = f-floor(f); 94 90 var rndRa = 0; 95 for (var rndRx=0; rndRx<=floor(f); rndRx++)91 for (var rndRx=0; rndRx<=floor(f); ++rndRx) 96 92 { 97 93 rndRw = 10*(rndRw-floor(rndRw)); 98 94 } … … 129 125 } 130 126 131 127 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 */ 142 137 function createStartingPlayerEntities(fx, fz, playerid, civEntities, BUILDING_ANGlE) 143 138 { 144 139 var uDist = 6; … … 148 143 { 149 144 var uAngle = BUILDING_ANGlE - PI * (2-j) / 2; 150 145 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) 152 147 { 153 148 var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); 154 149 var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); … … 157 152 } 158 153 } 159 154 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 */ 171 165 function placeCivDefaultEntities(fx, fz, playerid, angle, kwargs) 172 166 { 173 167 // Unpack kwargs … … 187 181 { 188 182 var uAngle = angle - PI * (2-j) / 2; 189 183 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) 191 185 { 192 186 var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); 193 187 var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); … … 205 199 } 206 200 207 201 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 */ 220 213 221 214 function paintTerrainBasedOnHeight(minheight, maxheight, mode, terrain) 222 215 { 223 216 var mSize = g_Map.size; 224 for (var qx = 0; qx < mSize; qx++)217 for (var qx = 0; qx < mSize; ++qx) 225 218 { 226 for (var qz = 0; qz < mSize; qz++)219 for (var qz = 0; qz < mSize; ++qz) 227 220 { 228 221 if (mode == 0) 229 222 { … … 257 250 } 258 251 } 259 252 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 */ 273 264 function paintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass) 274 265 { 275 266 var mSize = g_Map.size; 276 for (var qx = 0; qx < mSize; qx++)267 for (var qx = 0; qx < mSize; ++qx) 277 268 { 278 for (var qz = 0; qz < mSize; qz++)269 for (var qz = 0; qz < mSize; ++qz) 279 270 { 280 271 if (mode == 0) 281 272 { … … 313 304 function unPaintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass) 314 305 { 315 306 var mSize = g_Map.size; 316 for (var qx = 0; qx < mSize; qx++)307 for (var qx = 0; qx < mSize; ++qx) 317 308 { 318 for (var qz = 0; qz < mSize; qz++)309 for (var qz = 0; qz < mSize; ++qz) 319 310 { 320 311 if (mode == 0) 321 312 { … … 349 340 } 350 341 } 351 342 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 */ 365 354 function getTIPIADBON(startPoint, endPoint, heightRange, step, n) 366 355 { 367 356 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]))); … … 394 383 return undefined; 395 384 } 396 385 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 */ 407 394 function checkIfIntersect (x1, y1, x2, y2, x3, y3, x4, y4, width) 408 395 { 409 396 if (x1 == x2) … … 445 432 return false; 446 433 } 447 434 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 */ 457 442 function distanceOfPointFromLine (x1, y1, x2, y2, x3, y3) 458 443 { 459 444 if (x1 == x2) … … 473 458 } 474 459 } 475 460 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 */ 490 473 function createRamp (x1, y1, x2, y2, minHeight, maxHeight, width, smoothLevel, mainTerrain, edgeTerrain, tileclass) 491 474 { 492 475 var halfWidth = width / 2; … … 540 523 } 541 524 } 542 525 543 / ////////////////////////////////////////////////////////////////////////////////////////544 //createMountain545 // 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 */ 549 532 550 533 function createMountain(maxHeight, minRadius, maxRadius, numCircles, constraint, x, z, terrain, tileclass, fcc, q) 551 534 { … … 617 600 618 601 for (var ix = sx; ix <= lx; ++ix) 619 602 { 620 for (var iz = sz; iz <= lz; ++ 603 for (var iz = sz; iz <= lz; ++iz) 621 604 { 622 605 dx = ix - cx; 623 606 dz = iz - cz; … … 666 649 667 650 for (var ix = sx; ix <= lx; ++ix) 668 651 { 669 for (var iz = sz; iz <= lz; ++ 652 for (var iz = sz; iz <= lz; ++iz) 670 653 { 671 654 if (fcc) 672 655 if ((x - ix) > fcc || (ix - x) > fcc || (z - iz) > fcc || (iz - z) > fcc) … … 737 720 738 721 for (var ix = sx; ix <= lx; ++ix) 739 722 { 740 for (var iz = sz; iz <= lz; ++ 723 for (var iz = sz; iz <= lz; ++iz) 741 724 { 742 725 dx = ix - cx; 743 726 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 */ 3 5 4 6 'use strict'; 5 7 6 8 RMS.LoadLibrary('rmgen'); 7 9 8 // initialize map 10 /** 11 * initialize map 12 */ 9 13 10 14 log('Initializing map...'); 11 15 12 16 InitMap(); 13 17 14 18 15 //////////////// 16 // 17 // Initializing 18 // 19 //////////////// 19 /** 20 * Initializing 21 */ 20 22 21 //sky 23 /** 24 *sky 25 */ 22 26 setSkySet("fog"); 23 27 setFogFactor(0.35); 24 28 setFogThickness(0.19); 25 26 // water 29 /** 30 * water 31 */ 27 32 setWaterColor(0.501961, 0.501961, 0.501961); 28 33 setWaterTint(0.25098, 0.501961, 0.501961); 29 34 setWaterWaviness(0.5); 30 35 setWaterType("clap"); 31 36 setWaterMurkiness(0.75); 32 33 // post processing 37 /** 38 * post processing 39 */ 34 40 setPPSaturation(0.37); 35 41 setPPContrast(0.4); 36 42 setPPBrightness(0.4); 37 43 setPPEffect("hdr"); 38 44 setPPBloom(0.4); 39 40 // Setup tile classes 45 /** 46 * Setup tile classes 47 */ 41 48 var clPlayer = createTileClass(); 42 49 var clPath = createTileClass(); 43 50 var clHill = createTileClass(); … … 47 54 var clFood = createTileClass(); 48 55 var clBaseResource = createTileClass(); 49 56 var clOpen = createTileClass(); 50 51 // Setup Templates 57 /** 58 * Setup Templates 59 */ 52 60 var templateStone = 'gaia/geology_stone_alpine_a'; 53 61 var templateStoneMine = 'gaia/geology_stonemine_alpine_quarry'; 54 62 var templateMetal = 'actor|geology/stone_granite_med.xml'; … … 64 72 var aReeds = 'actor|props/flora/reeds_pond_lush_b.xml'; 65 73 var oFish = "gaia/fauna_fish"; 66 74 67 68 // Setup terrain 75 /** 76 * Setup terrain 77 */ 69 78 var terrainWood = ['alpine_forrestfloor|gaia/flora_tree_oak', 'alpine_forrestfloor|gaia/flora_tree_pine']; 70 79 var terrainWoodBorder = ['new_alpine_grass_mossy|gaia/flora_tree_oak', 'alpine_forrestfloor|gaia/flora_tree_pine', 71 80 'temp_grass_long|gaia/flora_bush_temperate', 'temp_grass_clovers|gaia/flora_bush_berry', 'temp_grass_clovers_2|gaia/flora_bush_grapes', … … 108 117 109 118 const BUILDING_ANGlE = -PI/4; 110 119 111 // Setup map 120 /** 121 * Setup map 122 */ 112 123 var mapSize = getMapSize(); 113 124 var mapRadius = mapSize/2; 114 125 var playableMapRadius = mapRadius - 5; 115 126 var mapCenterX = mapRadius; 116 127 var mapCenterZ = mapRadius; 117 128 118 // Setup players and bases 129 /** 130 * Setup players and bases 131 */ 119 132 var numPlayers = getNumPlayers(); 120 133 var baseRadius = 15; 121 134 var minPlayerRadius = min(mapRadius-1.5*baseRadius, 5*mapRadius/8); … … 128 141 var playerAngleAddAvrg = 2*PI / numPlayers; 129 142 var playerAngleMaxOff = playerAngleAddAvrg/4; 130 143 131 // Setup paths 144 /** 145 * Setup paths 146 */ 132 147 var pathSucsessRadius = baseRadius/2; 133 148 var pathAngleOff = PI/2; 134 var pathWidth = 10; // This is not really the path's thickness in tiles but the number of tiles in the clum bs of the path149 var pathWidth = 10; // This is not really the path's thickness in tiles but the number of tiles in the clumps of the path 135 150 136 // Setup additional resources 151 /** 152 * Setup additional resources 153 */ 137 154 var resourceRadius = 2*mapRadius/3; // 3*mapRadius/8; 138 155 //var resourcePerPlayer = [templateStone, templateMetalMine]; 139 156 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 */ 143 162 var maxTreeDensity = min(256 * (192 + 8 * numPlayers) / (mapSize * mapSize), 1); // Has to be tweeked but works ok 144 163 var bushChance = 1/3; // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood 145 164 146 165 147 //////////////// 148 // 149 // Some general functions 150 // 151 //////////////// 152 166 /** 167 * Some general functions 168 */ 153 169 function HeightPlacer(lowerBound, upperBound) { 154 170 this.lowerBound = lowerBound; 155 171 this.upperBound = upperBound; … … 159 175 constraint = (constraint || new NullConstraint()); 160 176 161 177 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) { 164 180 if (g_Map.height[x][y] >= this.lowerBound && g_Map.height[x][y] <= this.upperBound && constraint.allows(x, y)) { 165 181 ret.push(new PointXZ(x, y)); 166 182 } … … 169 185 return ret; 170 186 }; 171 187 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 */ 176 192 function getOrderOfPointsForShortestClosePath(points) 177 193 { 178 194 var order = []; 179 195 var distances = []; 180 196 if (points.length <= 3) 181 197 { 182 for (var i = 0; i < points.length; i++)198 for (var i = 0; i < points.length; ++i) 183 199 order.push(i); 184 200 185 201 return order; … … 187 203 188 204 // Just add the first 3 points 189 205 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) 191 207 { 192 208 order.push(i); 193 209 pointsToAdd.shift(i); … … 198 214 199 215 // Add remaining points so the path lengthens the least 200 216 var numPointsToAdd = pointsToAdd.length; 201 for (var i = 0; i < numPointsToAdd; i++)217 for (var i = 0; i < numPointsToAdd; ++i) 202 218 { 203 219 var indexToAddTo = undefined; 204 220 var minEnlengthen = Infinity; 205 221 var minDist1 = 0; 206 222 var minDist2 = 0; 207 for (var k = 0; k < order.length; k++)223 for (var k = 0; k < order.length; ++k) 208 224 { 209 225 var dist1 = getDistance(pointsToAdd[0][0], pointsToAdd[0][1], points[order[k]][0], points[order[k]][1]); 210 226 var dist2 = getDistance(pointsToAdd[0][0], pointsToAdd[0][1], points[order[(k + 1) % order.length]][0], points[order[(k + 1) % order.length]][1]); … … 226 242 } 227 243 228 244 229 //////////////// 230 // 231 // Heightmap functionality 232 // 233 //////////////// 245 /** 246 * Heightmap functionality 247 */ 234 248 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 */ 240 252 function getMinAndMaxHeight(reliefmap) 241 253 { 242 254 var height = {}; 243 255 height.min = Infinity; 244 256 height.max = - Infinity; 245 for (var x = 0; x < reliefmap.length; x++)257 for (var x = 0; x < reliefmap.length; ++x) 246 258 { 247 for (var y = 0; y < reliefmap[x].length; y++)259 for (var y = 0; y < reliefmap[x].length; ++y) 248 260 { 249 261 if (reliefmap[x][y] < height.min) 250 262 height.min = reliefmap[x][y]; … … 264 276 var oldHeightRange = getMinAndMaxHeight(heightmap); 265 277 var max_x = heightmap.length; 266 278 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) 269 281 heightmap[x][y] = minHeight + (heightmap[x][y] - oldHeightRange.min) / (oldHeightRange.max - oldHeightRange.min) * (maxHeight - minHeight); 270 282 } 271 283 272 /* 273 getStartLocationsByHeightmap274 Takes275 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) floats277 maxTries Optional, default is 1000, an integer, how often random player distributions are rolled to be compared278 minDistToBorder Optional, default is 20, an integer, how far start locations have to be279 numberOfPlayers Optional, default is getNumPlayers, an integer, how many start locations should be placed280 Returns281 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 */ 283 295 function getStartLocationsByHeightmap(hightRange, maxTries, minDistToBorder, numberOfPlayers, heightmap) 284 296 { 285 297 maxTries = (maxTries || 1000); … … 288 300 heightmap = (heightmap || g_Map.height); 289 301 290 302 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) 293 305 if (heightmap[x][y] > hightRange.min && heightmap[x][y] < hightRange.max) // Has the right hight 294 306 validStartLocTiles.push([x, y]); 295 307 296 308 var maxMinDist = 0; 297 for (var tries = 0; tries < maxTries; tries++)309 for (var tries = 0; tries < maxTries; ++tries) 298 310 { 299 311 var startLoc = []; 300 312 var minDist = heightmap.length; 301 for (var p = 0; p < numberOfPlayers; p++)313 for (var p = 0; p < numberOfPlayers; ++p) 302 314 startLoc.push(validStartLocTiles[randInt(validStartLocTiles.length)]); 303 for (var p1 = 0; p1 < numberOfPlayers - 1; p1++)315 for (var p1 = 0; p1 < numberOfPlayers - 1; ++p1) 304 316 { 305 for (var p2 = p1 + 1; p2 < numberOfPlayers; p2++)317 for (var p2 = p1 + 1; p2 < numberOfPlayers; ++p2) 306 318 { 307 319 var dist = getDistance(startLoc[p1][0], startLoc[p1][1], startLoc[p2][0], startLoc[p2][1]); 308 320 if (dist < minDist) … … 319 331 return finalStartLoc; 320 332 } 321 333 322 /* 323 derivateEntitiesByHeight324 Takes325 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) floats328 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 compared330 minDistance Optional, default is 30, an integer, how far start locations have to be away from start locations and the map border331 Returns332 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 */ 334 346 function derivateEntitiesByHeight(hightRange, startLoc, entityList, maxTries, minDistance, heightmap) 335 347 { 336 348 entityList = (entityList || [templateMetalMine, templateStoneMine]); … … 340 352 341 353 var placements = deepcopy(startLoc); 342 354 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) 345 357 if (heightmap[x][y] > hightRange.min && heightmap[x][y] < hightRange.max) // Has the right hight 346 358 validTiles.push([x, y]); 347 359 348 360 if (!validTiles.length) 349 361 return; 350 362 351 for (var tries = 0; tries < maxTries; tries++)363 for (var tries = 0; tries < maxTries; ++tries) 352 364 { 353 365 var tile = validTiles[randInt(validTiles.length)]; 354 366 var isValid = true; 355 for (var p = 0; p < placements.length; p++)367 for (var p = 0; p < placements.length; ++p) 356 368 { 357 369 if (getDistance(placements[p][0], placements[p][1], tile[0], tile[1]) < minDistance) 358 370 { … … 370 382 } 371 383 372 384 373 //////////////// 374 // 375 // Base terrain generation functionality 376 // 377 //////////////// 385 /** 386 * Base terrain generation functionality 387 */ 378 388 379 389 function setBaseTerrainDiamondSquare(minHeight, maxHeight, smoothness, initialHeightmap, heightmap) 380 390 { … … 395 405 var newHeightmap = []; 396 406 var oldWidth = initialHeightmap.length; 397 407 // Square 398 for (var x = 0; x < 2 * oldWidth - 1; x++)408 for (var x = 0; x < 2 * oldWidth - 1; ++x) 399 409 { 400 410 newHeightmap.push([]); 401 for (var y = 0; y < 2 * oldWidth - 1; y++)411 for (var y = 0; y < 2 * oldWidth - 1; ++y) 402 412 { 403 413 if (x % 2 === 0 && y % 2 === 0) // Old tile 404 414 newHeightmap[x].push(initialHeightmap[x/2][y/2]); … … 412 422 } 413 423 } 414 424 // Diamond 415 for (var x = 0; x < 2 * oldWidth - 1; x++)425 for (var x = 0; x < 2 * oldWidth - 1; ++x) 416 426 { 417 for (var y = 0; y < 2 * oldWidth - 1; y++)427 for (var y = 0; y < 2 * oldWidth - 1; ++y) 418 428 { 419 429 if (newHeightmap[x][y] === undefined) 420 430 { … … 452 462 453 463 // Cut initialHeightmap to fit target width 454 464 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) 457 467 heightmap[x][y] = newHeightmap[x][y]; 458 468 } 459 469 460 470 461 //////////////// 462 // 463 // Terrain erosion functionality 464 // 465 //////////////// 466 471 /** 472 * Terrain erosion functionality 473 */ 467 474 function decayErrodeHeightmap(strength, heightmap) 468 475 { 469 476 strength = (strength || 0.9); // 0 to 1 … … 474 481 var map = [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]; // smoother 475 482 var max_x = heightmap.length; 476 483 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) 480 487 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 481 488 } 482 489 … … 490 497 heightmap = (heightmap || g_Map.height); 491 498 492 499 var heightmapWin = []; 493 for (var wx = 0; wx < 2 * dx + 1; wx++)500 for (var wx = 0; wx < 2 * dx + 1; ++wx) 494 501 { 495 502 heightmapWin.push([]); 496 for (var wy = 0; wy < 2 * dy + 1; wy++)503 for (var wy = 0; wy < 2 * dy + 1; ++wy) 497 504 { 498 505 var actualX = x - dx + wx; 499 506 var actualY = y - dy + wy; … … 503 510 heightmapWin[wx].push(targetHeight); 504 511 } 505 512 } 506 for (var wx = 0; wx < 2 * dx + 1; wx++)513 for (var wx = 0; wx < 2 * dx + 1; ++wx) 507 514 { 508 for (var wy = 0; wy < 2 * dy + 1; wy++)515 for (var wy = 0; wy < 2 * dy + 1; ++wy) 509 516 { 510 517 var actualX = x - dx + wx; 511 518 var actualY = y - dy + wy; … … 522 529 } 523 530 524 531 525 //////////////// 526 // 527 // Actually do stuff 528 // 529 //////////////// 532 /** 533 * Actually do stuff 534 */ 530 535 531 / ///////////////532 //Set height limits and water level by map size533 ////////////////536 /** 537 * Set height limits and water level by map size 538 */ 534 539 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 */ 536 543 var 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}; 537 544 538 // Set average water coverage 545 /** 546 * Set average water coverage 547 */ 539 548 var averageWaterCoverage = 1/5; // NOTE: Since erosion is not predictable actual water coverage might vary much with the same values 540 549 var waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); 541 550 var waterHeightAdjusted = waterHeight + MIN_HEIGHT; 542 551 setWaterHeight(waterHeight); 543 552 544 / ///////////////545 //Generate base terrain546 ////////////////553 /** 554 * Generate base terrain 555 */ 547 556 548 // Setting a 3x3 Grid as initial heightmap 557 /** 558 * Setting a 3x3 Grid as initial heightmap 559 */ 549 560 var initialReliefmap = [[heightRange.max, heightRange.max, heightRange.max], [heightRange.max, heightRange.min, heightRange.max], [heightRange.max, heightRange.max, heightRange.max]]; 550 561 551 562 setBaseTerrainDiamondSquare(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 */ 566 for (var i = 0; i < 5; ++i) 554 567 decayErrodeHeightmap(0.5); 555 568 rescaleHeightmap(heightRange.min, heightRange.max); 556 569 557 570 RMS.SetProgress(50); 558 571 559 / /////////560 //Setup height limit561 //////////572 /** 573 * Setup height limit 574 */ 562 575 563 // Height presets 576 /** 577 * Height presets 578 */ 564 579 var heighLimits = [ 565 580 heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), // 0 Deep water 566 581 heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), // 1 Medium Water … … 574 589 waterHeightAdjusted + 7/8 * (heightRange.max - waterHeightAdjusted), // 9 Upper forest border 575 590 waterHeightAdjusted + (heightRange.max - waterHeightAdjusted)]; // 10 Hilltop 576 591 577 / /////////578 //Place start locations and apply terrain texture and decorative props579 //////////592 /** 593 * Place start locations and apply terrain texture and decorative props 594 */ 580 595 581 // Get start locations 596 /** 597 * Get start locations 598 */ 582 599 var startLocations = getStartLocationsByHeightmap({'min': heighLimits[4], 'max': heighLimits[5]}); 583 600 var playerHeight = (heighLimits[4] + heighLimits[5]) / 2; 584 601 585 for (var i=0; i < numPlayers; i++)602 for (var i=0; i < numPlayers; ++i) 586 603 { 587 604 playerAngle[i] = (playerAngleStart + i*playerAngleAddAvrg + randFloat(0, playerAngleMaxOff))%(2*PI); 588 605 var x = round(mapCenterX + randFloat(minPlayerRadius, maxPlayerRadius)*cos(playerAngle[i])); … … 604 621 var distToSL = 15; 605 622 var resStartAngle = playerAngle[i] + PI; 606 623 var resAddAngle = 2*PI / startingResources.length; 607 for (var rIndex = 0; rIndex < startingResources.length; rIndex++)624 for (var rIndex = 0; rIndex < startingResources.length; ++rIndex) 608 625 { 609 626 var angleOff = randFloat(-resAddAngle/2, resAddAngle/2); 610 627 var placeX = x + distToSL*cos(resStartAngle + rIndex*resAddAngle + angleOff); … … 614 631 } 615 632 } 616 633 617 // Add further stone and metal mines 634 /** 635 * Add further stone and metal mines 636 */ 618 637 derivateEntitiesByHeight({'min': heighLimits[3], 'max': ((heighLimits[4]+heighLimits[3])/2)}, startLocations); 619 638 derivateEntitiesByHeight({'min': ((heighLimits[5]+heighLimits[6])/2), 'max': heighLimits[7]}, startLocations); 620 639 621 640 RMS.SetProgress(50); 622 641 623 //place water & open terrain textures and assign TileClasses 642 /** 643 * place water & open terrain textures and assign TileClasses 644 */ 624 645 log("Painting textures..."); 625 646 var placer = new HeightPlacer(heighLimits[2], (heighLimits[3]+heighLimits[2])/2); 626 647 var painter = new LayeredPainter([terrainBase, terrainBaseBorder], [5]); … … 634 655 635 656 RMS.SetProgress(60); 636 657 637 // Place paths 658 /** 659 * Place paths 660 */ 638 661 log("Placing paths..."); 639 662 var doublePaths = true; 640 663 if (numPlayers > 4) … … 644 667 var maxI = numPlayers+1; 645 668 else 646 669 var maxI = numPlayers; 647 for (var i = 0; i < maxI; i++)670 for (var i = 0; i < maxI; ++i) 648 671 { 649 672 if (doublePaths === true) 650 673 var minJ = 0; 651 674 else 652 675 var minJ = i+1; 653 for (var j = minJ; j < numPlayers+1; j++)676 for (var j = minJ; j < numPlayers+1; ++j) 654 677 { 655 678 // Setup start and target coordinates 656 679 if (i < numPlayers) … … 700 723 } 701 724 if (getDistance(x, z, targetX, targetZ) < pathSucsessRadius) 702 725 targetReached = true; 703 tries++;726 ++tries; 704 727 705 728 } 706 729 } … … 708 731 709 732 RMS.SetProgress(75); 710 733 711 //create general decoration 734 /** 735 *create general decoration 736 */ 712 737 log("Creating decoration..."); 713 738 createDecoration 714 739 ( … … 730 755 731 756 RMS.SetProgress(80); 732 757 733 //create fish 758 /** 759 *create fish 760 */ 734 761 log("Growing fish..."); 735 762 createFood 736 763 ( … … 745 772 746 773 RMS.SetProgress(85); 747 774 748 // create reeds 775 /** 776 * create reeds 777 */ 749 778 log("Planting reeds..."); 750 779 var types = [aReeds]; // some variation 751 780 for (var i = 0; i < types.length; ++i) … … 759 788 760 789 RMS.SetProgress(90); 761 790 762 // place trees 791 /** 792 * place trees 793 */ 763 794 log("Planting trees..."); 764 for (var x = 0; x < mapSize; x++)795 for (var x = 0; x < mapSize; ++x) 765 796 { 766 for (var z = 0; z < mapSize;z++)797 for (var z = 0; z < mapSize; ++z) 767 798 { 768 799 // Some variables 769 800 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 770 801 var minDistToSL = mapSize; 771 for (var i=0; i < numPlayers; i++)802 for (var i=0; i < numPlayers; ++i) 772 803 minDistToSL = min(minDistToSL, getDistance(playerStartLocX[i], playerStartLocZ[i], x, z)); 773 804 // Woods tile based 774 805 var tDensFactSL = max(min((minDistToSL - baseRadius) / baseRadius, 1), 0); … … 793 824 794 825 RMS.SetProgress(100); 795 826 796 // Export map data 827 /** 828 * Export map data 829 */ 797 830 ExportMap();