Ticket #2944: gen_wall_builder2015-08-23.diff
File gen_wall_builder2015-08-23.diff, 225.4 KB (added by , 9 years ago) |
---|
-
binaries/data/mods/public/globalscripts/Templates.js
251 251 "templates": { 252 252 "tower": template.WallSet.Templates.Tower, 253 253 "gate": template.WallSet.Templates.Gate, 254 "fort": template.WallSet.Templates.Fort || "structures/{civ}_fortress", 254 255 "long": template.WallSet.Templates.WallLong, 255 256 "medium": template.WallSet.Templates.WallMedium, 256 257 "short": template.WallSet.Templates.WallShort, … … 258 259 "maxTowerOverlap": +template.WallSet.MaxTowerOverlap, 259 260 "minTowerOverlap": +template.WallSet.MinTowerOverlap, 260 261 }; 262 if (template.WallSet.Templates.WallEnd) 263 ret.wallSet.templates.end = template.WallSet.Templates.WallEnd; 264 if (template.WallSet.Templates.WallCurveQuarter) 265 ret.wallSet.templates.quarterCurve = template.WallSet.Templates.WallCurveQuarter; 266 if (template.WallSet.Templates.WallCurveEighth) 267 ret.wallSet.templates.eighthCurve = template.WallSet.Templates.WallCurveEighth; 261 268 } 262 269 263 270 if (template.WallPiece) 264 ret.wallPiece = {"length": +template.WallPiece.Length}; 271 ret.wallPiece = { 272 "length": +template.WallPiece.Length, 273 "angle": +(template.WallPiece.Orientation || 1) * Math.PI, 274 "indent": +(template.WallPiece.Indent || 0), 275 "bend": +(template.WallPiece.Bend || 0) * Math.PI, 276 }; 265 277 266 278 return ret; 267 279 } -
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 57 // g_Map.height = reliefmap; 53 for (var x = 0; x <= mapSize; x++)58 for (var x = 0; x <= mapSize; ++x) 54 59 { 55 for (var y = 0; y <= mapSize; y++)60 for (var y = 0; y <= mapSize; ++y) 56 61 { 57 62 setHeight(x, y, reliefmap[x][y]); 58 63 } 59 64 } 60 65 } 61 66 62 // Get minimum and maxumum height used in a heightmap 67 /** 68 * Get minimum and maxumum height used in a heightmap 69 */ 63 70 function getMinAndMaxHeight(reliefmap) 64 71 { 65 72 var height = {}; 66 73 height.min = Infinity; 67 74 height.max = -Infinity; 68 for (var x = 0; x <= mapSize; x++)75 for (var x = 0; x <= mapSize; ++x) 69 76 { 70 for (var y = 0; y <= mapSize; y++)77 for (var y = 0; y <= mapSize; ++y) 71 78 { 72 79 if (reliefmap[x][y] < height.min) 73 80 height.min = reliefmap[x][y]; … … 78 85 return height; 79 86 } 80 87 81 // Rescale a heightmap (Waterlevel is not taken into consideration!) 88 /** 89 * Rescale a heightmap (Waterlevel is not taken into consideration!) 90 */ 82 91 function getRescaledReliefmap(reliefmap, minHeight, maxHeight) 83 92 { 84 93 var newReliefmap = deepcopy(reliefmap); … … 89 98 if (maxHeight > MAX_HEIGHT) 90 99 warn("getRescaledReliefmap: Argument maxHeight is smaler then the supported maximum height of " + MAX_HEIGHT + " (const MAX_HEIGHT): " + maxHeight) 91 100 var oldHeightRange = getMinAndMaxHeight(reliefmap); 92 for (var x = 0; x <= mapSize; x++)101 for (var x = 0; x <= mapSize; ++x) 93 102 { 94 for (var y = 0; y <= mapSize; y++)103 for (var y = 0; y <= mapSize; ++y) 95 104 { 96 105 newReliefmap[x][y] = minHeight + (reliefmap[x][y] - oldHeightRange.min) / (oldHeightRange.max - oldHeightRange.min) * (maxHeight - minHeight); 97 106 } … … 99 108 return newReliefmap 100 109 } 101 110 102 // Applying decay errosion (terrain independent) 111 /** 112 * Applying decay errosion (terrain independent) 113 */ 103 114 function getHeightErrosionedReliefmap(reliefmap, strength) 104 115 { 105 116 var newReliefmap = deepcopy(reliefmap); 106 117 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 118 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++)119 for (var x = 0; x <= mapSize; ++x) 109 120 { 110 for (var y = 0; y <= mapSize; y++)121 for (var y = 0; y <= mapSize; ++y) 111 122 { 112 123 var div = 0; 113 for (var i = 0; i < map.length; i++)124 for (var i = 0; i < map.length; ++i) 114 125 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 126 } 116 127 } … … 118 129 } 119 130 120 131 121 / /////////122 //Prepare for hightmap munipulation123 //////////132 /** 133 * Prepare for hightmap munipulation 134 */ 124 135 125 // Set target min and max height depending on map size to make average stepness the same on all map sizes 136 /** 137 * Set target min and max height depending on map size to make average stepness the same on all map sizes 138 */ 126 139 var heightRange = {"min": MIN_HEIGHT * mapSize / 8192, "max": MAX_HEIGHT * mapSize / 8192}; 127 140 128 // Set average water coverage 141 /** 142 * Set average water coverage 143 */ 129 144 var averageWaterCoverage = 1/3; // NOTE: Since errosion is not predictable actual water coverage might differ much with the same value 130 145 if (mapSize < 200) // Sink the waterlevel on tiny maps to ensure enough space 131 146 averageWaterCoverage = 2/3 * averageWaterCoverage; … … 134 149 setWaterHeight(waterHeight); 135 150 136 151 137 ////////// 138 // Prepare terrain texture by height placement 139 ////////// 140 152 /** 153 * Prepare terrain texture by height placement 154 */ 141 155 var textueByHeight = []; 142 156 143 // Deep water 157 /** 158 * Deep water 159 */ 144 160 textueByHeight.push({"upperHeightLimit": heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), "terrain": "temp_sea_rocks"}); 145 // Medium deep water (with fish) 161 /** 162 * Medium deep water (with fish) 163 */ 146 164 var terreins = ["temp_sea_weed"]; 147 165 terreins = terreins.concat(terreins, terreins, terreins, terreins); 148 166 terreins = terreins.concat(terreins, terreins, terreins, terreins); 149 167 terreins.push("temp_sea_weed|gaia/fauna_fish"); 150 168 textueByHeight.push({"upperHeightLimit": heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), "terrain": terreins}); 151 // Flat Water 169 /** 170 * Flat Water 171 */ 152 172 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) 173 /** 174 * Water surroundings/bog (with stone/metal some rabits and bushes) 175 */ 154 176 var terreins = ["temp_plants_bog", "temp_plants_bog_aut", "temp_dirt_gravel_plants", "temp_grass_d"]; 155 177 terreins = terreins.concat(terreins, terreins, terreins, terreins, terreins); 156 178 terreins = ["temp_plants_bog|gaia/flora_bush_temperate"].concat(terreins, terreins); 157 179 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 180 terreins = ["temp_plants_bog_aut|gaia/flora_tree_dead"].concat(terreins, terreins); 159 181 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 1/6 * (heightRange.max - waterHeightAdjusted), "terrain": terreins}); 160 // Juicy grass near bog 182 /** 183 * Juicy grass near bog 184 */ 161 185 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 2/6 * (heightRange.max - waterHeightAdjusted), 162 186 "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"; 187 /** 188 * Medium level grass 189 */ 165 190 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 3/6 * (heightRange.max - waterHeightAdjusted), 166 191 "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_mossy"]}); 167 // Long grass near forest border 192 /** 193 * Long grass near forest border 194 */ 168 195 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 4/6 * (heightRange.max - waterHeightAdjusted), 169 196 "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) 197 /** 198 * Forest border (With wood/food plants/deer/rabits) 199 */ 171 200 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", 172 201 "temp_grass_long|gaia/flora_bush_temperate", "temp_mud_plants|gaia/flora_bush_temperate", "temp_mud_plants|gaia/flora_bush_badlands", 173 202 "temp_grass_long|gaia/flora_tree_apple", "temp_grass_clovers|gaia/flora_bush_berry", "temp_grass_clovers_2|gaia/flora_bush_grapes", 174 203 "temp_grass_plants|gaia/fauna_deer", "temp_grass_long_b|gaia/fauna_rabbit"]; 175 204 var numTerreins = terreins.length; 176 for (var i = 0; i < numTerreins; i++)205 for (var i = 0; i < numTerreins; ++i) 177 206 terreins.push("temp_grass_plants"); 178 207 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 5/6 * (heightRange.max - waterHeightAdjusted), "terrain": terreins}); 179 // Unpassable woods 208 /** 209 * Unpassable woods 210 */ 180 211 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 6/6 * (heightRange.max - waterHeightAdjusted), 181 212 "terrain": ["temp_grass_mossy|gaia/flora_tree_oak", "temp_forestfloor_pine|gaia/flora_tree_pine", 182 213 "temp_grass_mossy|gaia/flora_tree_oak", "temp_forestfloor_pine|gaia/flora_tree_pine", … … 184 215 "temp_dirt_gravel_plants|gaia/flora_tree_aleppo_pine", "temp_forestfloor_autumn|gaia/flora_tree_carob"]}); 185 216 var minTerrainDistToBorder = 3; 186 217 187 // Time check 1 218 /** 219 * Time check 1 220 */ 188 221 timeArray.push(new Date().getTime()); 189 222 RMS.SetProgress(5); 190 223 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 224 /** 225 * START THE GIANT WHILE LOOP: 226 * - Generate Heightmap 227 * - Search valid start position tiles 228 * - Choose a good start position derivation (largest distance between closest players) 229 * - Restart the loop if start positions are invalid or two players are to close to each other 230 */ 197 231 var goodStartPositionsFound = false; 198 232 var minDistBetweenPlayers = 16 + mapSize / 16; // Don't set this higher than 25 for tiny maps! It will take forever with 8 players! 199 233 var enoughTiles = false; 200 234 var tries = 0; 201 235 while (!goodStartPositionsFound) 202 236 { 203 tries++;237 ++tries; 204 238 log("Starting giant while loop try " + tries); 205 239 // Generate reliefmap 206 240 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)241 for (var i = 0; i < 50 + mapSize/4; ++i) // Cycles depend on mapsize (more cycles -> bigger structures) 208 242 myReliefmap = getHeightErrosionedReliefmap(myReliefmap, 1); 209 243 myReliefmap = getRescaledReliefmap(myReliefmap, heightRange.min, heightRange.max); 210 244 setReliefmap(myReliefmap); … … 217 251 var lowerHeightLimit = textueByHeight[3].upperHeightLimit; 218 252 var upperHeightLimit = textueByHeight[6].upperHeightLimit; 219 253 // Check for valid points by height 220 for (var x = distToBorder + minTerrainDistToBorder; x < mapSize - distToBorder - minTerrainDistToBorder; x++)254 for (var x = distToBorder + minTerrainDistToBorder; x < mapSize - distToBorder - minTerrainDistToBorder; ++x) 221 255 { 222 for (var y = distToBorder + minTerrainDistToBorder; y < mapSize - distToBorder - minTerrainDistToBorder; y++)256 for (var y = distToBorder + minTerrainDistToBorder; y < mapSize - distToBorder - minTerrainDistToBorder; ++y) 223 257 { 224 258 var actualHeight = getHeight(x, y); 225 259 if (actualHeight > lowerHeightLimit && actualHeight < upperHeightLimit) 226 260 { 227 261 // Check for points within a valid area by height (rectangular since faster) 228 262 var isPossible = true; 229 for (var offX = - neededDistance; offX <= neededDistance; offX++)263 for (var offX = - neededDistance; offX <= neededDistance; ++offX) 230 264 { 231 for (var offY = - neededDistance; offY <= neededDistance; offY++)265 for (var offY = - neededDistance; offY <= neededDistance; ++offY) 232 266 { 233 267 var testHeight = getHeight(x + offX, y + offY); 234 268 if (testHeight <= lowerHeightLimit || testHeight >= upperHeightLimit) … … 252 286 // Reduce to tiles in a circle of mapSize / 2 distance to the center (to avoid players placed in corners) 253 287 var possibleStartPositionsTemp = []; 254 288 var maxDistToCenter = mapSize / 2; 255 for (var i = 0; i < possibleStartPositions.length; i++)289 for (var i = 0; i < possibleStartPositions.length; ++i) 256 290 { 257 291 var deltaX = possibleStartPositions[i][0] - mapSize / 2; 258 292 var deltaY = possibleStartPositions[i][1] - mapSize / 2; … … 270 304 var maxDistToResources = distToBorder; // Has to be <= distToBorder! 271 305 var minNumLowTiles = 10; 272 306 var minNumHighTiles = 10; 273 for (var i = 0; i < possibleStartPositions.length; i++)307 for (var i = 0; i < possibleStartPositions.length; ++i) 274 308 { 275 309 var numLowTiles = 0; 276 310 var numHighTiles = 0; 277 for (var dx = - maxDistToResources; dx < maxDistToResources; dx++)311 for (var dx = - maxDistToResources; dx < maxDistToResources; ++dx) 278 312 { 279 for (var dy = - maxDistToResources; dy < maxDistToResources; dy++)313 for (var dy = - maxDistToResources; dy < maxDistToResources; ++dy) 280 314 { 281 315 var testHeight = getHeight(possibleStartPositions[i][0] + dx, possibleStartPositions[i][1] + dy); 282 316 if (testHeight < lowerHeightLimit) 283 numLowTiles++;317 ++numLowTiles; 284 318 if (testHeight > upperHeightLimit) 285 numHighTiles++;319 ++numHighTiles; 286 320 if (numLowTiles > minNumLowTiles && numHighTiles > minNumHighTiles) 287 321 break; 288 322 } … … 311 345 // Get some random start location derivations. NOTE: Itterating over all possible derivations is just to much (valid points ** numPlayers) 312 346 var maxTries = 100000; // floor(800000 / (Math.pow(numPlayers, 2) / 2)); 313 347 var possibleDerivations = []; 314 for (var i = 0; i < maxTries; i++)348 for (var i = 0; i < maxTries; ++i) 315 349 { 316 350 var vector = []; 317 for (var p = 0; p < numPlayers; p++)351 for (var p = 0; p < numPlayers; ++p) 318 352 vector.push(randInt(possibleStartPositions.length)); 319 353 possibleDerivations.push(vector); 320 354 } 321 355 322 356 // Choose the start location derivation with the greatest minimum distance between players 323 357 var maxMinDist = 0; 324 for (var d = 0; d < possibleDerivations.length; d++)358 for (var d = 0; d < possibleDerivations.length; ++d) 325 359 { 326 360 var minDist = 2 * mapSize; 327 for (var p1 = 0; p1 < numPlayers - 1; p1++)361 for (var p1 = 0; p1 < numPlayers - 1; ++p1) 328 362 { 329 for (var p2 = p1 + 1; p2 < numPlayers; p2++)363 for (var p2 = p1 + 1; p2 < numPlayers; ++p2) 330 364 { 331 365 if (p1 != p2) 332 366 { … … 358 392 } // End of derivation check 359 393 } // END THE GIANT WHILE LOOP 360 394 361 // Time check 2 395 /** 396 * Time check 2 397 */ 362 398 timeArray.push(new Date().getTime()); 363 399 RMS.SetProgress(60); 364 400 365 401 366 / ///////367 //Paint terrain by height and add props368 ////////402 /** 403 * Paint terrain by height and add props 404 */ 369 405 370 406 var propDensity = 1; // 1 means as determined in the loop, less for large maps as set below 371 407 if (mapSize > 500) 372 408 propDensity = 1/4; 373 409 else if (mapSize > 400) 374 410 propDensity = 3/4; 375 for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; x++)411 for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; ++x) 376 412 { 377 for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; y++)413 for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; ++y) 378 414 { 379 415 var textureMinHeight = heightRange.min; 380 for (var i = 0; i < textueByHeight.length; i++)416 for (var i = 0; i < textueByHeight.length; ++i) 381 417 { 382 418 if (getHeight(x, y) >= textureMinHeight && getHeight(x, y) <= textueByHeight[i].upperHeightLimit) 383 419 { … … 488 524 } 489 525 } 490 526 491 // Time check 3 527 /** 528 * Time check 3 529 */ 492 530 timeArray.push(new Date().getTime()); 493 531 RMS.SetProgress(90); 494 532 495 533 496 / ///////497 //Place players and start resources498 ////////534 /** 535 * Place players and start resources 536 */ 499 537 500 for (var p = 0; p < numPlayers; p++)538 for (var p = 0; p < numPlayers; ++p) 501 539 { 502 540 var actualX = possibleStartPositions[bestDerivation[p]][0]; 503 541 var actualY = possibleStartPositions[bestDerivation[p]][1]; … … 509 547 { 510 548 var uAngle = BUILDING_ANGlE - PI * (2-j) / 2; 511 549 var count = 4; 512 for (var numberofentities = 0; numberofentities < count; numberofentities++)550 for (var numberofentities = 0; numberofentities < count; ++numberofentities) 513 551 { 514 552 var ux = actualX + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); 515 553 var uz = actualY + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); … … 521 559 } 522 560 } 523 561 524 525 // Export map data 562 /** 563 * Export map data 564 */ 526 565 ExportMap(); 527 566 528 // Time check 7 567 /** 568 * Time check 7 569 */ 529 570 timeArray.push(new Date().getTime()); 530 571 531 // Calculate progress percentage with the time checks 572 /** 573 * Calculate progress percentage with the time checks 574 */ 532 575 var generationTime = timeArray[timeArray.length - 1] - timeArray[0]; 533 576 log("Total generation time (ms): " + generationTime); 534 for (var i = 0; i < timeArray.length; i++)577 for (var i = 0; i < timeArray.length; ++i) 535 578 { 536 579 var timeSinceStart = timeArray[i] - timeArray[0]; 537 580 var progressPercentage = 100 * timeSinceStart / generationTime; -
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 {return false}; 467 subdata = subdata[key_list[i]]; 468 } 469 return subdata; 470 } 471 472 /** 473 * Returns a list of all templates paths available to the given civ 474 */ 475 function getTempatePathList(civ) 476 { 477 var templatePaths = getFullCivData(); 478 if (!templatePaths[civ]) 479 { 480 warn("getTempatePathList: Unknown civ '" + civ + "' not in " + Object.keys(templatePaths)); 481 return false; 482 } 483 templatePaths = templatePaths[civ]; 484 485 if (!templatePaths[START_ENTITY_KEYS]) 486 { 487 warn("getTempatePathList: Civ has no starting entities as defined in START_ENTITY_KEYS (" + START_ENTITY_KEYS + "): " + Object.keys(templatePaths)); 488 return false; 489 } 490 templatePaths = templatePaths[START_ENTITY_KEYS]; 491 492 for (var i = 0; i < templatePaths.length; ++i) 493 { 494 if (!templatePaths[i][START_ENTITY_TEMPLATE_KEYS]) 495 { 496 warn("getTempatePathList: Starting entity list item has no template as defined in START_ENTITY_TEMPLATE_KEYS (" + START_ENTITY_TEMPLATE_KEYS + "): " + Object.keys(templatePaths)); 497 return false; 498 } 499 templatePaths[i] = templatePaths[i][START_ENTITY_TEMPLATE_KEYS]; 500 } 501 var foundNew = 1; 502 while (foundNew > 0) 503 { 504 foundNew = 0; 505 var methods = [BUILDER_TEMPLATEPATH_KEYS, PRODUCTION_TEMPLATEPATH_KEYS]; 506 for (var m = 0; m < methods.length; ++m) 507 { 508 for (var t = 0; t < templatePaths.length; ++t) 509 { 510 var pathsToCheck = getTemplateValue(templatePaths[t], methods[m]); 511 if (typeof(pathsToCheck) === typeof("")) 512 { 513 pathsToCheck = pathsToCheck.split(/\s+/); 514 for (var c = 0; c < pathsToCheck.length; ++c) 515 { 516 var actualPath = pathsToCheck[c].replace(CIV_PLACEHOLDER_STRING, civ); 517 if (templatePaths.indexOf(actualPath) == -1 && RMS.TemplateExists(actualPath)) 518 { 519 templatePaths.push(actualPath); 520 ++foundNew; 521 } 522 } 523 } 524 } 525 } 526 } 527 return templatePaths; 528 } 529 530 /** 531 * Takes a list of entity path strings and returns a list with only those remaining that have the specified keys 532 */ 533 function filterByKeys(entPaths, keys) 534 { 535 let filteredEntPaths = []; 536 for (let i = 0; i < entPaths.length; ++i) 537 { 538 if (getTemplateValue(entPaths[i], keys)) 539 filteredEntPaths.push(entPaths[i]); 540 } 541 return filteredEntPaths; 542 } 543 406 544 function areAllies(player1, player2) 407 545 { 408 546 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 572 435 573 var result = new Array(0); 436 574 var team = new Array(5); 437 for (var q = 0; q < 5; q++)575 for (var q = 0; q < 5; ++q) 438 576 { 439 577 team[q] = new Array(1); 440 578 } 441 579 442 for (var i = -1; i < 4; i++)580 for (var i = -1; i < 4; ++i) 443 581 { 444 for (var j = 0; j < source.length; j++)582 for (var j = 0; j < source.length; ++j) 445 583 { 446 584 if (getPlayerTeam(j) == i) 447 585 { … … 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); … … 508 648 } 509 649 } 510 650 511 // Remove point from the given class by id 651 /** 652 * Remove point from the given class by id 653 */ 512 654 function removeFromClass(x, z, id) 513 655 { 514 656 var tileClass = getTileClass(id); … … 519 661 } 520 662 } 521 663 522 // Create a painter for the given class 664 /** 665 * Create a painter for the given class 666 */ 523 667 function paintClass(id) 524 668 { 525 669 return new TileClassPainter(getTileClass(id)); 526 670 } 527 671 528 // Create a painter for the given class 672 /** 673 * Create a painter for the given class 674 */ 529 675 function unPaintClass(id) 530 676 { 531 677 return new TileClassUnPainter(getTileClass(id)); 532 678 } 533 679 534 // Create an avoid constraint for the given classes by the given distances 680 /** 681 * Create an avoid constraint for the given classes by the given distances 682 */ 535 683 function avoidClasses(/*class1, dist1, class2, dist2, etc*/) 536 684 { 537 685 var ar = new Array(arguments.length/2); 538 for (var i = 0; i < arguments.length/2; i++)686 for (var i = 0; i < arguments.length/2; ++i) 539 687 { 540 688 ar[i] = new AvoidTileClassConstraint(arguments[2*i], arguments[2*i+1]); 541 689 } … … 551 699 } 552 700 } 553 701 554 // Create a stay constraint for the given classes by the given distances 702 /** 703 * Create a stay constraint for the given classes by the given distances 704 */ 555 705 function stayClasses(/*class1, dist1, class2, dist2, etc*/) 556 706 { 557 707 var ar = new Array(arguments.length/2); 558 for (var i = 0; i < arguments.length/2; i++)708 for (var i = 0; i < arguments.length/2; ++i) 559 709 { 560 710 ar[i] = new StayInTileClassConstraint(arguments[2*i], arguments[2*i+1]); 561 711 } … … 571 721 } 572 722 } 573 723 574 // Create a border constraint for the given classes by the given distances 724 /** 725 * Create a border constraint for the given classes by the given distances 726 */ 575 727 function borderClasses(/*class1, idist1, odist1, class2, idist2, odist2, etc*/) 576 728 { 577 729 var ar = new Array(arguments.length/3); 578 for (var i = 0; i < arguments.length/3; i++)730 for (var i = 0; i < arguments.length/3; ++i) 579 731 { 580 732 ar[i] = new BorderTileClassConstraint(arguments[3*i], arguments[3*i+1], arguments[3*i+2]); 581 733 } … … 591 743 } 592 744 } 593 745 594 // Checks if the given tile is in class "id" 746 /** 747 * Checks if the given tile is in class "id" 748 */ 595 749 function checkIfInClass(x, z, id) 596 750 { 597 751 var tileClass = getTileClass(id); … … 612 766 } 613 767 } 614 768 615 616 // Returns the distance between 2 points 769 /** 770 * Returns the distance between 2 points 771 */ 617 772 function getDistance(x1, z1, x2, z2) 618 773 { 619 774 return Math.pow(Math.pow(x1 - x2, 2) + Math.pow(z1 - z2, 2), 1/2); 620 775 } 621 776 622 // Returns the angle of the vector between point 1 and point 2. The angle is anticlockwise from the positive x axis. 777 /** 778 * Returns the angle of the vector between point 1 and point 2. The angle is anticlockwise from the positive x axis. 779 */ 623 780 function getAngle(x1, z1, x2, z2) 624 781 { 625 782 return Math.atan2(z2 - z1, x2 - x1); 626 783 } 627 784 628 // Returns the gradient of the line between point 1 and 2 in the form dz/dx 785 /** 786 * Returns the gradient of the line between point 1 and 2 in the form dz/dx 787 */ 629 788 function getGradient(x1, z1, x2, z2) 630 789 { 631 790 if (x1 == x2 && z1 == z2) … … 642 801 { 643 802 return g_Map.getTexture(x, y); 644 803 } 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/rmgen/wall_builder.js
1 //////////////////////////////////////////////////////////////////// 2 // This file contains functionality to place walls on random maps // 3 //////////////////////////////////////////////////////////////////// 1 /** 2 * This file contains functionality to place walls on random maps 3 * 4 * 5 * To do: 6 * Check if all wall placement methods work with wall elements with entity === undefined (some still might raise errors in that case) 7 * Rename wall elements to fit the entity names so that entity = "structures/" + "civ + "_" + wallElement.type in the common case (as far as possible) 8 * Perhaps add Roman army camp to style palisades and add upgraded/balanced default palisade fortress types matching civ default fortresses strength 9 * Perhaps add further wall elements cornerInHalf, cornerOutHalf (banding PI/4) and adjust default fortress types to better fit in the octagonal territory of a civil center 10 * Perhaps swap angle and width in WallElement class(?) definition 11 * Adjust argument order to be always the same: 12 * Coordinates (center/start/target) 13 * Wall element arguments (wall/wallPart/fortressType/cornerElement) 14 * playerId (optional, default is 0/gaia) 15 * wallStyle (optional, default is the players civ/"palisades for gaia") 16 * angle/orientation (optional, default is 0) 17 * other (all optional) arguments especially those hard to define (wallPartsAssortment, maybe make an own function for it) 18 * Some arguments don't clearly match to this concept: 19 * endWithFirst (wall or other) 20 * skipFirstWall (wall or other) 21 * gateOccurence (wall or other) 22 * numCorners (wall or other) 23 * skipFirstWall (wall or other) 24 * maxAngle (angle or other) 25 * maxBendOff (angle or other, unused ATM!!!) 26 * irregularity 27 * maxTrys 28 * Add treasures to wall style "others" 29 * Adjust documentation 30 * ?Use available civ-type wall elements rather than palisades: Remove "end" as a default wall element and adjust default palisade fortress types? 31 * ?Adjust generic fortress types palisades? 32 * ?Think of something to enable splitting walls into two walls so more complex walls can be built? 33 * ?Readjust placement angle for wall elements with bending when used in linear/circular walls by their bending? 34 */ 4 35 5 // To do: 6 // Check if all wall placement methods work with wall elements with entity === undefined (some still might raise errors in that case) 7 // Rename wall elements to fit the entity names so that entity = "structures/" + "civ + "_" + wallElement.type in the common case (as far as possible) 8 // Perhaps add Roman army camp to style palisades and add upgraded/balanced default palisade fortress types matching civ default fortresses strength 9 // Perhaps add further wall elements cornerInHalf, cornerOutHalf (banding PI/4) and adjust default fortress types to better fit in the octagonal territory of a civil center 10 // Perhaps swap angle and width in WallElement class(?) definition 11 // Adjust argument order to be always the same: 12 // Coordinates (center/start/target) 13 // Wall element arguments (wall/wallPart/fortressType/cornerElement) 14 // playerId (optional, default is 0/gaia) 15 // wallStyle (optional, default is the players civ/"palisades for gaia") 16 // angle/orientation (optional, default is 0) 17 // other (all optional) arguments especially those hard to define (wallPartsAssortment, maybe make an own function for it) 18 // Some arguments don't clearly match to this concept: 19 // endWithFirst (wall or other) 20 // skipFirstWall (wall or other) 21 // gateOccurence (wall or other) 22 // numCorners (wall or other) 23 // skipFirstWall (wall or other) 24 // maxAngle (angle or other) 25 // maxBendOff (angle or other, unused ATM!!!) 26 // irregularity 27 // maxTrys 28 // Add treasures to wall style "others" 29 // Adjust documentation 30 // Perhaps rename "endLeft" to "start" and "endRight" to "end" 31 // ?Use available civ-type wall elements rather than palisades: Remove "endLeft" and "endRight" as default wall elements and adjust default palisade fortress types? 32 // ?Remove "endRight", "endLeft" and adjust generic fortress types palisades? 33 // ?Think of something to enable splitting walls into two walls so more complex walls can be build and roads can have branches/crossroads? 34 // ?Readjust placement angle for wall elements with bending when used in linear/circular walls by their bending? 36 /** 37 * Set some globals for this module 38 */ 39 var g_WallStyles = {}; 40 var g_WallStyleList = []; 41 var g_CivData = getFullCivData(); 42 var g_CivList = Object.keys(g_CivData); 43 var g_FortressTypes = {}; 44 var g_FortressTypeKeys = ["tiny", "small", "medium", "normal", "large", "veryLarge", "giant"]; 35 45 46 /** 47 * Basic Initialisation 48 * 49 * Fetches wallsets from {civ}.json files, and then uses them to load 50 * basic wall elements 51 */ 52 for (let civ of g_CivList) 53 { 54 let civInfo = g_CivData[civ]; 55 if (!civInfo.WallSets) 56 continue; 36 57 37 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 38 // WallElement class definition 39 // 40 // Concept: If placed unrotated the wall's course is towards positive Y (top) with "outside" right (+X) and "inside" left (-X) like unrotated entities has their drop-points right (in rmgen) 41 // The course of the wall will be changed by corners (bending != 0) and so the "inside"/"outside" direction 42 // 43 // type Descriptive string, example: "wallLong". NOTE: Not really needed. Mainly for custom wall elements and to get the wall element type in code 44 // entity Optional. Template name string of the entity to be placed, example: "structures/cart_wall_long". Default is undefined (No entity placed) 45 // angle Optional. The angle (float) added to place the entity so "outside" is right when the wall element is placed unrotated. Default is 0 46 // width Optional. How far this wall element lengthens the wall (float), if unrotated the Y space needed. Default is 0 47 // indent Optional. The lateral indentation of the entity, drawn "inside" (positive values) or pushed "outside" (negative values). Default is 0 48 // bending Optional. How the course of the wall is changed after this element, positive is bending "in"/left/counter clockwise (like entity placement) 49 // NOTE: Bending is not supported by all placement functions (see there) 50 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 51 function WallElement(type, entity, angle, width, indent, bending) 52 { 53 this.type = type; 54 // Default wall element type documentation: 55 // Lengthening straight blocking (mainly left/right symmetric) wall elements (Walls and wall fortifications) 56 // "wall" A blocking straight wall element that mainly lengthens the wall, self-explanatory 57 // "wallShort" self-explanatory 58 // "wallLong" self-explanatory 59 // "tower" A blocking straight wall element with damage potential (but for palisades) that slightly lengthens the wall, example: wall tower, palisade tower(No attack) 60 // "wallFort" A blocking straight wall element with massive damage potential that lengthens the wall, example: fortress, palisade fort 61 // Lengthening straight non/custom blocking (mainly left/right symmetric) wall elements (Gates and entries) 62 // "gate" A blocking straight wall element with passability determined by owner, example: gate (Functionality not yet implemented) 63 // "entry" A non-blocking straight wall element (same width as gate) but without an actual template or just a flag/column/obelisk 64 // "entryTower" A non-blocking straight wall element (same width as gate) represented by a single (maybe indented) template, example: defence tower, wall tower, outpost, watchtower 65 // "entryFort" A non-blocking straight wall element represented by a single (maybe indented) template, example: fortress, palisade fort 66 // Bending wall elements (Wall corners) 67 // "cornerIn" A wall element bending the wall by PI/2 "inside" (left, +, see above), example: wall tower, palisade curve 68 // "cornerOut" A wall element bending the wall by PI/2 "outside" (right, -, see above), example: wall tower, palisade curve 69 // "cornerHalfIn" A wall element bending the wall by PI/4 "inside" (left, +, see above), example: wall tower, palisade curve. NOTE: Not yet implemented 70 // "cornerHalfOut" A wall element bending the wall by PI/4 "outside" (right, -, see above), example: wall tower, palisade curve. NOTE: Not yet implemented 71 // Zero length straight indented (mainly left/right symmetric) wall elements (Outposts/watchtowers and non-defensive base structures) 72 // "outpost" A zero-length wall element without bending far indented so it stands outside the wall, example: outpost, defence tower, watchtower 73 // "house" A zero-length wall element without bending far indented so it stands inside the wall that grants population bonus, example: house, hut, longhouse 74 // "barracks" A zero-length wall element without bending far indented so it stands inside the wall that grants unit production, example: barracks, tavern, ... 75 this.entity = entity; 76 this.angle = (angle !== undefined) ? angle : 0*PI; 77 this.width = (width !== undefined) ? width : 0; 78 this.indent = (indent !== undefined) ? indent : 0; 79 this.bending = (bending !== undefined) ? bending : 0*PI; 58 for (let path of civInfo.WallSets) 59 { 60 let style = path.split("/")[1].split("_"); 61 style = (style[0]=="wallset") ? style[1] : style[0]+"_"+style[2]; 62 63 if (g_WallStyleList.indexOf(style) == -1) 64 { 65 g_WallStyleList.push(style); 66 g_WallStyles[style] = {}; 67 let wallset = GetTemplateDataHelper(RMS.GetTemplate(path)).wallSet; 68 for (let element in wallset.templates) 69 setWallElement(style, element, wallset.templates[element].replace("{civ}",civ)) 70 g_WallStyles[style]["@overlap"] = wallset.minTowerOverlap * getWallElement(style, "tower").length; 71 } 72 } 80 73 } 81 74 82 / ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////83 //Fortress class definition84 // 85 //A "fortress" here is a closed wall build of multiple wall elements attached together defined in Fortress.wall86 //It's mainly the abstract shape defined in a Fortress instances wall because different styles can be used for it (see wallStyles)87 // 88 //type Descriptive string, example: "tiny". Not really needed (WallTool.wallTypes["type string"] is used). Mainly for custom wall elements89 // wall Optional. Array of wall element strings. Can be set afterwards. Default is an epty array.90 //Example: ["entrance", "wall", "cornerIn", "wall", "gate", "wall", "entrance", "wall", "cornerIn", "wall", "gate", "wall", "cornerIn", "wall"]91 //centerToFirstElement Optional. Object with properties "x" and "y" representing a vector from the visual center to the first wall element. Default is undefined92 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////75 /** 76 * Fortress class definition 77 * 78 * A "fortress" here is a closed wall build of multiple wall elements attached together defined in Fortress.wall 79 * It's mainly the abstract shape defined in a Fortress instances wall because different styles can be used for it (see wallStyles) 80 * 81 * type Descriptive string, example: "tiny". Not really needed (WallTool.wallTypes["type string"] is used). Mainly for custom wall elements 82 * wall Optional. Array of wall element strings. Can be set afterwards. Default is an empty array. 83 * Example: ["entrance", "wall", "cornerIn", "wall", "gate", "wall", "entrance", "wall", "cornerIn", "wall", "gate", "wall", "cornerIn", "wall"] 84 * centerToFirstElement Optional. Object with properties "x" and "y" representing a vector from the visual center to the first wall element. Default is undefined 85 */ 93 86 function Fortress(type, wall, centerToFirstElement) 94 87 { 95 this.type = type; // Only usefull to get the type of the actual fortress96 this.wall = (wall !== undefined) ? wall :[];97 this.centerToFirstElement = undefined;88 this.type = type; 89 this.wall = wall || []; 90 this.centerToFirstElement = centerToFirstElement; 98 91 } 99 92 93 /** 94 * g_FortressTypes data structure for some default fortress types (defined above) 95 * 96 * A fortress type is just an instance of the Fortress class with actually something in it 97 * fortressTypes holds all the fortresses within an associative array with a descriptive string as key (e.g. matching the map size) 98 * Examples: "tiny", "veryLarge" 99 */ 100 100 101 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 102 // wallStyles data structure for default wall styles 103 // 104 // A wall style is an associative array with all wall elements of that style in it associated with the wall element type string 105 // wallStyles holds all the wall styles within an associative array with the civ string or another descriptive strings as key 106 // Examples: "athen", "rome_siege", "palisades", "fence", "road" 107 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 108 var wallStyles = {}; 101 /** 102 * Set some default fortress types 103 */ 104 for (let key of g_FortressTypeKeys) 105 g_FortressTypes[key] = new Fortress(key); 109 106 110 // Generic civ dependent wall style definition. "rome_siege" needs some tweek... 111 var wallScaleByType = {"athen" : 1.5, "brit" : 1.5, "cart" : 1.8, "gaul" : 1.5, "iber" : 1.5, "mace" : 1.5, "maur": 1.5, "pers" : 1.5, "ptol" : 1.5, "rome" : 1.5, "sele" : 1.5, "spart" : 1.5, "rome_siege" : 1.5}; 112 for (var style in wallScaleByType) 107 g_FortressTypes["tiny"].wall = ["gate", "tower", "short", "cornerIn", "short", "tower"]; 108 g_FortressTypes["small"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "tower"]; 109 g_FortressTypes["medium"].wall = ["gate", "tower", "long", "cornerIn", "long", "tower"]; 110 g_FortressTypes["normal"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "cornerOut", "medium", "cornerIn", "medium", "tower"]; 111 g_FortressTypes["large"].wall = ["gate", "tower", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "tower"]; 112 g_FortressTypes["veryLarge"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "cornerOut", "long", "cornerIn", "long", "cornerOut", "medium", "cornerIn", "medium", "tower"]; 113 g_FortressTypes["giant"].wall = ["gate", "tower", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "tower"]; 114 115 for (let type in g_FortressTypes) 113 116 { 114 var civ = style; 115 if (style == "rome_siege") 116 civ = "rome"; 117 wallStyles[style] = {}; 118 // Default wall elements 119 wallStyles[style]["tower"] = new WallElement("tower", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); 120 wallStyles[style]["endLeft"] = new WallElement("endLeft", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades... 121 wallStyles[style]["endRight"] = new WallElement("endRight", "structures/" + style + "_wall_tower", PI, wallScaleByType[style]); // Same as tower. To be compatible with palisades... 122 wallStyles[style]["cornerIn"] = new WallElement("cornerIn", "structures/" + style + "_wall_tower", 5*PI/4, 0, 0.35*wallScaleByType[style], PI/2); // 2^0.5 / 4 ~= 0.35 ~= 1/3 123 wallStyles[style]["cornerOut"] = new WallElement("cornerOut", "structures/" + style + "_wall_tower", 3*PI/4, 0.71*wallScaleByType[style], 0, -PI/2); // // 2^0.5 / 2 ~= 0.71 ~= 2/3 124 wallStyles[style]["wallShort"] = new WallElement("wallShort", "structures/" + style + "_wall_short", 0*PI, 2*wallScaleByType[style]); 125 wallStyles[style]["wall"] = new WallElement("wall", "structures/" + style + "_wall_medium", 0*PI, 4*wallScaleByType[style]); 126 wallStyles[style]["wallMedium"] = new WallElement("wall", "structures/" + style + "_wall_medium", 0*PI, 4*wallScaleByType[style]); 127 wallStyles[style]["wallLong"] = new WallElement("wallLong", "structures/" + style + "_wall_long", 0*PI, 6*wallScaleByType[style]); 128 // Gate and entrance wall elements 129 var gateWidth = 6*wallScaleByType[style]; 130 wallStyles[style]["gate"] = new WallElement("gate", "structures/" + style + "_wall_gate", PI, gateWidth); 131 wallStyles[style]["entry"] = new WallElement("entry", undefined, 0*PI, gateWidth); 132 wallStyles[style]["entryTower"] = new WallElement("entryTower", "structures/" + civ + "_defense_tower", PI, gateWidth, -4*wallScaleByType[style]); 133 wallStyles[style]["entryFort"] = new WallElement("entryFort", "structures/" + civ + "_fortress", 0*PI, 8*wallScaleByType[style], 6*wallScaleByType[style]); 134 // Defensive wall elements with 0 width outside the wall 135 wallStyles[style]["outpost"] = new WallElement("outpost", "structures/" + civ + "_outpost", PI, 0, -4*wallScaleByType[style]); 136 wallStyles[style]["defenseTower"] = new WallElement("defenseTower", "structures/" + civ + "_defense_tower", PI, 0, -4*wallScaleByType[style]); 137 // Base buildings wall elements with 0 width inside the wall 138 wallStyles[style]["barracks"] = new WallElement("barracks", "structures/" + civ + "_barracks", PI, 0, 4.5*wallScaleByType[style]); 139 wallStyles[style]["civilCentre"] = new WallElement("civilCentre", "structures/" + civ + "_civil_centre", PI, 0, 4.5*wallScaleByType[style]); 140 wallStyles[style]["farmstead"] = new WallElement("farmstead", "structures/" + civ + "_farmstead", PI, 0, 4.5*wallScaleByType[style]); 141 wallStyles[style]["field"] = new WallElement("field", "structures/" + civ + "_field", PI, 0, 4.5*wallScaleByType[style]); 142 wallStyles[style]["fortress"] = new WallElement("fortress", "structures/" + civ + "_fortress", PI, 0, 4.5*wallScaleByType[style]); 143 wallStyles[style]["house"] = new WallElement("house", "structures/" + civ + "_house", PI, 0, 4.5*wallScaleByType[style]); 144 wallStyles[style]["market"] = new WallElement("market", "structures/" + civ + "_market", PI, 0, 4.5*wallScaleByType[style]); 145 wallStyles[style]["storehouse"] = new WallElement("storehouse", "structures/" + civ + "_storehouse", PI, 0, 4.5*wallScaleByType[style]); 146 wallStyles[style]["temple"] = new WallElement("temple", "structures/" + civ + "_temple", PI, 0, 4.5*wallScaleByType[style]); 147 // Generic space/gap wall elements 148 wallStyles[style]["space1"] = new WallElement("space1", undefined, 0*PI, wallScaleByType[style]); 149 wallStyles[style]["space2"] = new WallElement("space2", undefined, 0*PI, 2*wallScaleByType[style]); 150 wallStyles[style]["space3"] = new WallElement("space3", undefined, 0*PI, 3*wallScaleByType[style]); 151 wallStyles[style]["space4"] = new WallElement("space4", undefined, 0*PI, 4*wallScaleByType[style]); 117 let wallPart = g_FortressTypes[type].wall; 118 g_FortressTypes[type].wall = wallPart.concat(wallPart, wallPart, wallPart); 152 119 } 153 // Add wall fortresses for all generic styles154 wallStyles["athen"]["wallFort"] = new WallElement("wallFort", "structures/athen_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);155 wallStyles["brit"]["wallFort"] = new WallElement("wallFort", "structures/brit_fortress", PI, 2.8);156 wallStyles["cart"]["wallFort"] = new WallElement("wallFort", "structures/cart_fortress", PI, 5.1, 1.6);157 wallStyles["gaul"]["wallFort"] = new WallElement("wallFort", "structures/gaul_fortress", PI, 4.2, 1.5);158 wallStyles["iber"]["wallFort"] = new WallElement("wallFort", "structures/iber_fortress", PI, 5, 0.2);159 wallStyles["mace"]["wallFort"] = new WallElement("wallFort", "structures/mace_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);160 wallStyles["maur"]["wallFort"] = new WallElement("wallFort", "structures/maur_fortress", PI, 5.5);161 wallStyles["pers"]["wallFort"] = new WallElement("wallFort", "structures/pers_fortress", PI, 5.6/*5.5*/, 1.9/*1.7*/);162 wallStyles["ptol"]["wallFort"] = new WallElement("wallFort", "structures/ptol_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);163 wallStyles["rome"]["wallFort"] = new WallElement("wallFort", "structures/rome_fortress", PI, 6.3, 2.1);164 wallStyles["sele"]["wallFort"] = new WallElement("wallFort", "structures/sele_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);165 wallStyles["spart"]["wallFort"] = new WallElement("wallFort", "structures/spart_fortress", 2*PI/2 /* PI/2 */, 5.1 /* 5.6 */, 1.9 /* 1.9 */);166 // Adjust "rome_siege" style167 wallStyles["rome_siege"]["wallFort"] = new WallElement("wallFort", "structures/rome_army_camp", PI, 7.2, 2);168 wallStyles["rome_siege"]["entryFort"] = new WallElement("entryFort", "structures/rome_army_camp", PI, 12, 7);169 wallStyles["rome_siege"]["house"] = new WallElement("house", "structures/rome_tent", PI, 0, 4);170 120 171 // Add special wall styles not well to implement generic (and to show how custom styles can be added) 172 173 // Add wall style "palisades" 174 wallScaleByType["palisades"] = 0.55; 175 wallStyles["palisades"] = {}; 176 wallStyles["palisades"]["wall"] = new WallElement("wall", "other/palisades_rocks_medium", 0*PI, 2.3); 177 wallStyles["palisades"]["wallMedium"] = new WallElement("wall", "other/palisades_rocks_medium", 0*PI, 2.3); 178 wallStyles["palisades"]["wallLong"] = new WallElement("wall", "other/palisades_rocks_long", 0*PI, 3.5); 179 wallStyles["palisades"]["wallShort"] = new WallElement("wall", "other/palisades_rocks_short", 0*PI, 1.2); 180 wallStyles["palisades"]["tower"] = new WallElement("tower", "other/palisades_rocks_tower", -PI/2, 0.7); 181 wallStyles["palisades"]["wallFort"] = new WallElement("wallFort", "other/palisades_rocks_fort", PI, 1.7); 182 wallStyles["palisades"]["gate"] = new WallElement("gate", "other/palisades_rocks_gate", PI, 3.6); 183 wallStyles["palisades"]["entry"] = new WallElement("entry", undefined, wallStyles["palisades"]["gate"].angle, wallStyles["palisades"]["gate"].width); 184 wallStyles["palisades"]["entryTower"] = new WallElement("entryTower", "other/palisades_rocks_watchtower", 0*PI, wallStyles["palisades"]["gate"].width, -3); 185 wallStyles["palisades"]["entryFort"] = new WallElement("entryFort", "other/palisades_rocks_fort", PI, 6, 3); 186 wallStyles["palisades"]["cornerIn"] = new WallElement("cornerIn", "other/palisades_rocks_curve", 3*PI/4, 2.1, 0.7, PI/2); 187 wallStyles["palisades"]["cornerOut"] = new WallElement("cornerOut", "other/palisades_rocks_curve", 5*PI/4, 2.1, -0.7, -PI/2); 188 wallStyles["palisades"]["outpost"] = new WallElement("outpost", "other/palisades_rocks_outpost", PI, 0, -2); 189 wallStyles["palisades"]["house"] = new WallElement("house", "other/celt_hut", PI, 0, 5); 190 wallStyles["palisades"]["barracks"] = new WallElement("barracks", "structures/gaul_tavern", PI, 0, 5); 191 wallStyles["palisades"]["endRight"] = new WallElement("endRight", "other/palisades_rocks_end", -PI/2, 0.2); 192 wallStyles["palisades"]["endLeft"] = new WallElement("endLeft", "other/palisades_rocks_end", PI/2, 0.2); 193 194 // Add special wall style "road" 195 // NOTE: This is not a wall style in the common sense. Use with care! 196 wallStyles["road"] = {}; 197 wallStyles["road"]["short"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_short.xml", PI/2, 4.5); 198 wallStyles["road"]["long"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_long.xml", PI/2, 9.5); 199 wallStyles["road"]["cornerLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_corner.xml", -PI/2, 4.5-2*1.25, 1.25, PI/2); // Correct width by -2*indent to fit xStraicht/corner 200 wallStyles["road"]["cornerRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_corner.xml", 0*PI, 4.5-2*1.25, -1.25, -PI/2); // Correct width by -2*indent to fit xStraicht/corner 201 wallStyles["road"]["curveLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_curve_small.xml", -PI/2, 4.5+2*0.2, -0.2, PI/2); // Correct width by -2*indent to fit xStraicht/corner 202 wallStyles["road"]["curveRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_curve_small.xml", 0*PI, 4.5+2*0.2, 0.2, -PI/2); // Correct width by -2*indent to fit xStraicht/corner 203 wallStyles["road"]["start"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", PI/2, 2); 204 wallStyles["road"]["end"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_end.xml", -PI/2, 2); 205 wallStyles["road"]["xStraight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5); 206 wallStyles["road"]["xLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, PI/2); 207 wallStyles["road"]["xRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_x.xml", 0*PI, 4.5, 0, -PI/2); 208 wallStyles["road"]["tLeft"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", PI, 4.5, 1.25); 209 wallStyles["road"]["tRight"] = new WallElement("road", "actor|props/special/eyecandy/road_temperate_intersect_T.xml", 0*PI, 4.5, -1.25); 210 211 // Add special wall element collection "other" 212 // NOTE: This is not a wall style in the common sense. Use with care! 213 wallStyles["other"] = {}; 214 wallStyles["other"]["fence"] = new WallElement("fence", "other/fence_long", -PI/2, 3.1); 215 wallStyles["other"]["fence_medium"] = new WallElement("fence", "other/fence_long", -PI/2, 3.1); 216 wallStyles["other"]["fence_short"] = new WallElement("fence_short", "other/fence_short", -PI/2, 1.5); 217 wallStyles["other"]["fence_stone"] = new WallElement("fence_stone", "other/fence_stone", -PI/2, 2.5); 218 wallStyles["other"]["palisade"] = new WallElement("palisade", "other/palisades_rocks_short", 0, 1.2); 219 wallStyles["other"]["column"] = new WallElement("column", "other/column_doric", 0, 1); 220 wallStyles["other"]["obelisk"] = new WallElement("obelisk", "other/obelisk", 0, 2); 221 wallStyles["other"]["spike"] = new WallElement("spike", "other/palisades_angle_spike", -PI/2, 1); 222 wallStyles["other"]["bench"] = new WallElement("bench", "other/bench", PI/2, 1.5); 223 wallStyles["other"]["benchForTable"] = new WallElement("benchForTable", "other/bench", 0, 0.5); 224 wallStyles["other"]["table"] = new WallElement("table", "other/table_rectangle", 0, 1); 225 wallStyles["other"]["table_square"] = new WallElement("table_square", "other/table_square", PI/2, 1); 226 wallStyles["other"]["flag"] = new WallElement("flag", "special/rallypoint", PI, 1); 227 wallStyles["other"]["standing_stone"] = new WallElement("standing_stone", "gaia/special_ruins_standing_stone", PI, 1); 228 wallStyles["other"]["settlement"] = new WallElement("settlement", "gaia/special_settlement", PI, 6); 229 wallStyles["other"]["gap"] = new WallElement("gap", undefined, 0, 2); 230 wallStyles["other"]["gapSmall"] = new WallElement("gapSmall", undefined, 0, 1); 231 wallStyles["other"]["gapLarge"] = new WallElement("gapLarge", undefined, 0, 4); 232 wallStyles["other"]["cornerIn"] = new WallElement("cornerIn", undefined, 0, 0, 0, PI/2); 233 wallStyles["other"]["cornerOut"] = new WallElement("cornerOut", undefined, 0, 0, 0, -PI/2); 234 235 236 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 237 // fortressTypes data structure for some default fortress types 238 // 239 // A fortress type is just an instance of the Fortress class with actually something in it 240 // fortressTypes holds all the fortresses within an associative array with a descriptive string as key (e.g. matching the map size) 241 // Examples: "tiny", "veryLarge" 242 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 243 var fortressTypes = {}; 244 // Setup some default fortress types 245 // Add fortress type "tiny" 246 fortressTypes["tiny"] = new Fortress("tiny"); 247 var wallPart = ["gate", "tower", "wallShort", "cornerIn", "wallShort", "tower"]; 248 fortressTypes["tiny"].wall = wallPart.concat(wallPart, wallPart, wallPart); 249 // Add fortress type "small" 250 fortressTypes["small"] = new Fortress("small"); 251 var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "tower"]; 252 fortressTypes["small"].wall = wallPart.concat(wallPart, wallPart, wallPart); 253 // Add fortress type "medium" 254 fortressTypes["medium"] = new Fortress("medium"); 255 var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "tower"]; 256 fortressTypes["medium"].wall = wallPart.concat(wallPart, wallPart, wallPart); 257 // Add fortress type "normal" 258 fortressTypes["normal"] = new Fortress("normal"); 259 var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "cornerOut", "wall", "cornerIn", "wall", "tower"]; 260 fortressTypes["normal"].wall = wallPart.concat(wallPart, wallPart, wallPart); 261 // Add fortress type "large" 262 fortressTypes["large"] = new Fortress("large"); 263 var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "tower"]; 264 fortressTypes["large"].wall = wallPart.concat(wallPart, wallPart, wallPart); 265 // Add fortress type "veryLarge" 266 fortressTypes["veryLarge"] = new Fortress("veryLarge"); 267 var wallPart = ["gate", "tower", "wall", "cornerIn", "wall", "cornerOut", "wallLong", "cornerIn", "wallLong", "cornerOut", "wall", "cornerIn", "wall", "tower"]; 268 fortressTypes["veryLarge"].wall = wallPart.concat(wallPart, wallPart, wallPart); 269 // Add fortress type "giant" 270 fortressTypes["giant"] = new Fortress("giant"); 271 var wallPart = ["gate", "tower", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "cornerOut", "wallLong", "cornerIn", "wallLong", "tower"]; 272 fortressTypes["giant"].wall = wallPart.concat(wallPart, wallPart, wallPart); 273 274 // Setup some better looking semi default fortresses for "palisades" style 275 var fortressTypeKeys = ["tiny", "small", "medium", "normal", "large", "veryLarge", "giant"]; 276 for (var i = 0; i < fortressTypeKeys.length; i++) 121 /** 122 * Setup some better looking semi default fortresses for "palisades" style 123 */ 124 for (let fortType of g_FortressTypeKeys) 277 125 { 278 var newKey = fort ressTypeKeys[i]+ "Palisades";279 var oldWall = fortressTypes[fortressTypeKeys[i]].wall;280 fortressTypes[newKey] = new Fortress(newKey);126 var newKey = fortType + "Palisades"; 127 var oldWall = g_FortressTypes[fortType].wall; 128 g_FortressTypes[newKey] = new Fortress(newKey); 281 129 var fillTowersBetween = ["wallShort", "wall", "wallLong", "endLeft", "endRight", "cornerIn", "cornerOut"]; 282 for (var j = 0; j < oldWall.length; j++)130 for (var j = 0; j < oldWall.length; ++j) 283 131 { 284 fortressTypes[newKey].wall.push(oldWall[j]); // Only works if the first element is not in fillTowersBetween (e.g. entry or gate like it should be)132 g_FortressTypes[newKey].wall.push(oldWall[j]); // Only works if the first element is not in fillTowersBetween (e.g. entry or gate like it should be) 285 133 if (j+1 < oldWall.length) 286 134 if (fillTowersBetween.indexOf(oldWall[j]) > -1 && fillTowersBetween.indexOf(oldWall[j+1]) > -1) // ... > -1 means "exists" here 287 fortressTypes[newKey].wall.push("tower");135 g_FortressTypes[newKey].wall.push("tower"); 288 136 } 289 137 } 290 138 291 // Setup some balanced (to civ type fortresses) semi default fortresses for "palisades" style 292 // TODO 139 /** 140 * Define some helper functions 141 */ 293 142 294 // Add some "fortress types" for roads (will only work with style "road") 295 // ["start", "short", "xRight", "xLeft", "cornerLeft", "xStraight", "long", "xLeft", "xRight", "cornerRight", "tRight", "tLeft", "xRight", "xLeft", "curveLeft", "xStraight", "curveRight", "end"]; 296 var wall = ["short", "curveLeft", "short", "curveLeft", "short", "curveLeft", "short", "curveLeft"]; 297 fortressTypes["road01"] = new Fortress("road01", wall); 298 var wall = ["short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft", "short", "cornerLeft"]; 299 fortressTypes["road02"] = new Fortress("road02", wall); 300 var wall = ["xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft", "xStraight", "curveLeft"]; 301 fortressTypes["road03"] = new Fortress("road03", wall); 302 var wall = ["start", "curveLeft", "tRight", "cornerLeft", "tRight", "curveRight", "short", "xRight", "curveLeft", "xRight", "short", "cornerLeft", "tRight", "short", 303 "curveLeft", "short", "tRight", "cornerLeft", "short", "xRight", "curveLeft", "xRight", "short", "curveRight", "tRight", "cornerLeft", "tRight", "curveLeft", "end"]; 304 fortressTypes["road04"] = new Fortress("road04", wall); 305 var wall = ["start", "tLeft", "short", "xRight", 306 "curveLeft", "xRight", "tRight", "cornerLeft", "tRight", 307 "curveLeft", "short", "tRight", "cornerLeft", "xRight", 308 "cornerLeft", "xRight", "short", "tRight", "curveLeft", "end"]; 309 fortressTypes["road05"] = new Fortress("road05", wall); 143 /** 144 * Get a wall element of a style. 145 * 146 * Valid elements: 147 * long, medium, short, start, end, cornerIn, cornerOut, tower, fort, gate 148 * 149 * Kept for backwards compatibility: 150 * wallLong, wallMedium, wall, wallShort, endLeft, endRight, entry, entryTower, entryFort 151 * 152 * If an element of the form `gap{x}` is requested, where `{x}` is a number, 153 * then a non-blocking gap of `x` length is returned. 154 * 155 * If an element of the form `turn{x}` is requested where `{x}` is either 156 * `out` or `in` (case in-sensitive), then a 90 degree (PI/2 radians) bend 157 * with zero length is returned in the specified direction. 158 * 159 * You can specify a normal structure (ie. `house`, `apadana` `barracks`) 160 * and the function will attempt to return the appropriate civ's building 161 * of that type with appropriate indentation away from the wall. 162 * @todo do something about the arbitrary-ness of the indent. 163 * 164 * If after all that, the function still can't work out what's requested, 165 * it returns a wall tower. 166 * 167 * @param style The style from which this element should come from 168 * @param element The element to fetch 169 * @return The wall element requested. Or a tower element. 170 */ 171 function getWallElement(style="athen_stone", element) 172 { 173 if (g_WallStyleList.indexOf(style) < 0) 174 { 175 warn("getWallElement: Style '"+style+"' not recognised. (Falling back to '" + FALLBACK_CIV + "_stone'.)"); 176 style = FALLBACK_CIV + "_stone"; 177 } 178 if (g_WallStyles[style][element]) 179 return g_WallStyles[style][element]; 310 180 181 // Attempt to derive any unknown elements. 182 // Defaults to a wall tower piece 183 var wallset = g_WallStyles[style]; 184 var civ = style.split("_")[0]; 185 var ret = clone(wallset.tower); 311 186 312 /////////////////////////////// 313 // Define some helper functions 314 /////////////////////////////// 187 // We use clone() so we don't change the attributes of the object we're referencing 188 switch (element) 189 { 315 190 316 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 317 // getWallAlignment 318 // 319 // Returns a list of objects containing all information to place all the wall elements entities with placeObject (but the player ID) 320 // Placing the first wall element at startX/startY placed with an angle given by orientation 321 // An alignment can be used to get the "center" of a "wall" (more likely used for fortresses) with getCenterToFirstElement 322 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 323 function getWallAlignment(startX, startY, wall, style, orientation) 191 case "cornerIn": 192 if (wallset.quarterCurve) 193 ret = clone(wallset.quarterCurve); 194 else 195 { 196 ret.angle += PI/4 197 ret.indent = ret.length * 0.25; 198 ret.length = 0; 199 } 200 ret.bend = PI/2; 201 break; 202 203 case "cornerOut": 204 if (wallset.quarterCurve) 205 { 206 ret = clone(wallset.quarterCurve); 207 ret.angle += PI/2; 208 ret.indent -= ret.indent*2; 209 } 210 else 211 { 212 ret.angle -= PI/4; 213 ret.length *= 0.71; 214 } 215 ret.bend = -PI/2; 216 break; 217 218 case "wallShort": 219 warn("getWallElement: Deprecated use of 'wallShort' (please use 'short')"); 220 ret = clone(wallset.short); 221 break; 222 223 case "wallMedium": 224 case "wall": 225 warn("getWallElement: Deprecated use of '"+element+"' (please use 'medium')"); 226 ret = clone(wallset.medium); 227 break; 228 229 case "wallLong": 230 warn("getWallElement: Deprecated use of 'wallLong' (please use 'long')"); 231 ret = clone(wallset.long); 232 break; 233 234 case "entry": 235 ret.entPath = undefined; 236 ret.length = clone(g_WallStyles[style].gate.length); 237 break; 238 239 case "entryTower": 240 ret.entPath = (g_CivList.indexOf(civ) > -1) ? "structures/"+civ+"_defense_tower" : "other/palisades_rocks_watchtower"; 241 ret.indent = ret.length * -3; 242 ret.length = clone(g_WallStyles[style].gate.length); 243 break; 244 245 case "entryFort": 246 ret = clone(g_WallStyles[style].fort); 247 ret.angle -= PI; 248 ret.length *= 1.5; 249 ret.indent = ret.length; 250 break; 251 252 case "endLeft": 253 warn("getWallElement: Deprecated use of 'endLeft' (please use 'start')"); 254 case "start": 255 if (wallset.end) 256 { 257 ret = clone(wallset.end); 258 ret.angle += PI; 259 } 260 break; 261 262 case "endRight": 263 warn("getWallElement: Deprecated use of 'endRight' (please use 'end')"); 264 case "end": 265 if (wallset.end) 266 ret = clone(wallset.end); 267 break; 268 269 default: 270 if (g_CivList.indexOf(civ) == -1) 271 civ = FALLBACK_CIV; 272 // Is it a structure? 273 var entPath = "structures/"+civ+"_"+element; 274 if (RMS.TemplateExists(entPath)) 275 { 276 if (["outpost", "defense_tower"].indexOf(element) > -1) 277 ret.indent = ret.length * -3; 278 else 279 ret.indent = ret.length * 3.5; 280 ret.entPath = entPath; 281 ret.length = 0; 282 } 283 else if (element.slice(0, 3) === "gap") // A gap? 284 { 285 ret.entPath = undefined; 286 ret.angle = 0; 287 ret.length = +element.slice(3); 288 } 289 else if (element.slice(0, 4) === "turn") // A bend? 290 { 291 let dir = element.slice(4).toLowerCase(); 292 if (dir === "out" || dir === "in") 293 { 294 ret.entPath = undefined; 295 ret.angle = PI/2; 296 ret.length = 0; 297 if (dir === "out") 298 ret.angle -= ret.angle; 299 } 300 else 301 warn("Unrecognised turn direction given: '"+dir+"' ("+ style+")."); 302 } 303 else // Or... I give up. 304 warn("Unrecognised wall element: '"+element+"' ("+ style+"). Defaulting to 'tower'."); 305 } 306 307 // Cache to save having to calculate this element again 308 g_WallStyles[style][element] = ret; 309 310 return ret; 311 } 312 313 /** 314 * Set a wall element of a style. 315 * 316 * @param style The style to which this element belongs 317 * @param element The element to add 318 * @param path The template path to read values from 319 */ 320 function setWallElement(style, element, path) 324 321 { 325 // Graciously handle arguments 326 if (wall === undefined) 327 wall = []; 328 if (!wallStyles.hasOwnProperty(style)) 329 { 330 warn("Function getWallAlignment: Unknown style: " + style + ' (falling back to "athen")'); 331 style = "athen"; 332 } 333 orientation = (orientation || 0); 334 322 var template = RMS.GetTemplate(path); 323 template = GetTemplateDataHelper(template); 324 325 if (!g_WallStyles[style]) 326 g_WallStyles[style] = {}; 327 328 var length = (template.wallPiece) ? template.wallPiece.length : template.obstruction.shape.width; 329 g_WallStyles[style][element] = { 330 "entPath": path, 331 "angle": (template.wallPiece) ? template.wallPiece.angle : PI, 332 "length": length / CELL_SIZE, 333 "indent": (template.wallPiece) ? template.wallPiece.indent / CELL_SIZE : 0, 334 "bend": (template.wallPiece) ? template.wallPiece.bend : 0 335 }; 336 } 337 338 /** 339 * getWallAlignment 340 * 341 * Returns a list of objects containing all information to place all the wall elements entities with placeObject (but the player ID) 342 * Placing the first wall element at startX/startY placed with an angle given by orientation 343 * An alignment can be used to get the "center" of a "wall" (more likely used for fortresses) with getCenterToFirstElement 344 */ 345 function getWallAlignment(startX, startY, wall=[], style="athen_stone", orientation=0) 346 { 335 347 var alignment = []; 336 348 var wallX = startX; 337 349 var wallY = startY; 338 for (var i = 0; i < wall.length; i++) 350 351 for (var i = 0; i < wall.length; ++i) 339 352 { 340 var element = wallStyles[style][wall[i]];353 var element = getWallElement(style, wall[i]); 341 354 if (element === undefined && i == 0) 342 warn("No valid wall element: " + wall[i]); 355 { 356 warn("Not a valid wall element: style = " + style + ", wall[" +i+ "] = " +wall[i]+ "; .entPath = " +element.entPath+ ", .length = " +element.length+ ", .angle = " +element.angle+ ", .indent = " +element.indent+ ", .bend = " +element.bend); 357 continue; 358 } 359 343 360 // Indentation 344 361 var placeX = wallX - element.indent * cos(orientation); 345 362 var placeY = wallY - element.indent * sin(orientation); 363 346 364 // Add wall elements entity placement arguments to the alignment 347 alignment.push({"x": placeX, "y": placeY, "entity": element.entity, "angle":orientation + element.angle}); 365 alignment.push({"x": placeX, "y": placeY, "entPath": element.entPath, "angle":orientation + element.angle}); 366 348 367 // Preset vars for the next wall element 349 368 if (i+1 < wall.length) 350 369 { 351 orientation += element.bend ing;352 var nextElement = wallStyles[style][wall[i+1]];370 orientation += element.bend; 371 var nextElement = getWallElement(style, wall[i+1]); 353 372 if (nextElement === undefined) 354 warn("No valid wall element: " + wall[i+1]); 355 var distance = (element.width + nextElement.width)/2; 373 { 374 warn("Not a valid wall element: style = " + style + ", wall[" +(i+1)+ "] = " +wall[i+1]+ "; .entPath = " +nextElement.entPath+ ", .length = " +nextElement.length+ ", .angle = " +nextElement.angle+ ", .indent = " +nextElement.indent+ ", .bend = " +nextElement.bend); 375 continue; 376 } 377 378 var distance = (element.length + nextElement.length)/2 - getOverlap(style); 356 379 // Corrections for elements with indent AND bending 357 380 var indent = element.indent; 358 var bend ing = element.bending;359 if (bend ing!== 0 && indent !== 0)381 var bend = element.bend; 382 if (bend !== 0 && indent !== 0) 360 383 { 361 384 // Indent correction to adjust distance 362 distance += indent*sin(bend ing);385 distance += indent*sin(bend); 363 386 // Indent correction to normalize indentation 364 387 wallX += indent * cos(orientation); 365 388 wallY += indent * sin(orientation); 366 389 } 390 367 391 // Set the next coordinates of the next element in the wall without indentation adjustment 368 392 wallX -= distance * sin(orientation); 369 393 wallY += distance * cos(orientation); … … 372 396 return alignment; 373 397 } 374 398 375 / /////////////////////////////////////////////////////////////////////////////////////////////////////////////////376 //getCenterToFirstElement377 // 378 //Center calculation works like getting the center of mass assuming all wall elements have the same "weight"379 // 380 //It returns the vector from the center to the first wall element381 //Used to get centerToFirstElement of fortresses by default382 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////399 /** 400 * getCenterToFirstElement 401 * 402 * Center calculation works like getting the center of mass assuming all wall elements have the same "weight" 403 * 404 * It returns the vector from the center to the first wall element 405 * Used to get centerToFirstElement of fortresses by default 406 */ 383 407 function getCenterToFirstElement(alignment) 384 408 { 385 409 var centerToFirstElement = {"x": 0, "y": 0}; 386 for (var i = 0; i < alignment.length; i++)410 for (var i = 0; i < alignment.length; ++i) 387 411 { 388 412 centerToFirstElement.x -= alignment[i].x/alignment.length; 389 413 centerToFirstElement.y -= alignment[i].y/alignment.length; … … 391 415 return centerToFirstElement; 392 416 } 393 417 394 ////////////////////////////////////////////////////////////////// 395 // getWallLength 396 // 397 // NOTE: Does not support bending wall elements like corners! 398 // e.g. used by placeIrregularPolygonalWall 399 ////////////////////////////////////////////////////////////////// 400 function getWallLength(wall, style) 418 /** 419 * getWallLength 420 * 421 * NOTE: Does not support bending wall elements like corners! 422 */ 423 function getWallLength(style, wall=[]) 401 424 { 402 425 // Graciously handle arguments 403 if (wall === undefined) 404 wall = []; 405 if (!wallStyles.hasOwnProperty(style)) 426 if (g_WallStyleList.indexOf(style) < 0) 406 427 { 407 warn(" Function getWallLength: Unknown style: " + style + ' (falling back to "athen")');408 style = "athen";428 warn("getWallLength: Unknown style: '" + style + "'. (Falling back to '" + FALLBACK_CIV + "_stone')."); 429 style = FALLBACK_CIV +"_stone"; 409 430 } 410 431 411 432 var length = 0; 412 for (var i = 0; i < wall.length; i++)413 {414 length += wallStyles[style][wall[i]].width;415 } 433 var overlap = getOverlap(style); 434 for (let element of wall) 435 length += getWallElement(style, element).length - overlap; 436 416 437 return length; 417 438 } 418 439 440 function getOverlap(style) 441 { 442 if (!style || g_WallStyleList.indexOf(style) == -1) 443 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 444 return g_WallStyles[style]["@overlap"]; 445 } 419 446 420 /////////////////////////////////////////////421 // Define the different wall placer functions422 /////////////////////////////////////////////423 447 424 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 425 // placeWall 426 // 427 // Places a wall with wall elements attached to another like determined by WallElement properties. 428 // 429 // startX, startY Where the first wall element should be placed 430 // wall Array of wall element type strings. Example: ["endLeft", "wallLong", "tower", "wallLong", "endRight"] 431 // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 432 // playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia) 433 // orientation Optional. Angle the first wall element is placed. Default is 0 434 // 0 means "outside" or "front" of the wall is right (positive X) like placeObject 435 // It will then be build towards top/positive Y (if no bending wall elements like corners are used) 436 // Raising orientation means the wall is rotated counter-clockwise like placeObject 437 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 438 function placeWall(startX, startY, wall, style, playerId, orientation) 448 /** 449 * Define the different wall placer functions 450 */ 451 452 /** 453 * placeWall 454 * 455 * Places a wall with wall elements attached to another like determined by WallElement properties. 456 * 457 * startX, startY Where the first wall element should be placed 458 * wall Array of wall element types. Example: ["start", "long", "tower", "long", "end"] 459 * style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 460 * playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia) 461 * orientation Optional. Angle the first wall element is placed. Default is 0 462 * 0 means "outside" or "front" of the wall is right (positive X) like placeObject 463 * It will then be build towards top/positive Y (if no bending wall elements like corners are used) 464 * Raising orientation means the wall is rotated counter-clockwise like placeObject 465 */ 466 function placeWall(startX=0, startY=0, wall=[], style, playerId=0, orientation=0) 439 467 { 440 // Graciously handle arguments 441 if (wall === undefined) 442 wall = []; 443 playerId = (playerId || 0); 444 if (!wallStyles.hasOwnProperty(style)) 445 { 446 if (playerId == 0) 447 style = (style || "palisades"); 448 else 449 style = (getCivCode(playerId-1)); 450 } 451 orientation = (orientation || 0); 468 if (!style || g_WallStyleList.indexOf(style) == -1) 469 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 452 470 453 471 // Get wall alignment 454 472 var AM = getWallAlignment(startX, startY, wall, style, orientation); 473 455 474 // Place the wall 456 for (var iWall = 0; iWall < wall.length; iWall++)475 for (var iWall = 0; iWall < wall.length; ++iWall) 457 476 { 458 var ent ity = AM[iWall].entity;459 if (ent ity!== undefined)460 placeObject(AM[iWall].x, AM[iWall].y, ent ity, playerId, AM[iWall].angle);477 var entPath = AM[iWall].entPath; 478 if (entPath !== undefined) 479 placeObject(AM[iWall].x, AM[iWall].y, entPath, playerId, AM[iWall].angle); 461 480 } 462 481 } 463 482 464 / ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////465 //placeCustomFortress466 // 467 //Place a fortress (mainly a closed wall build like placeWall) centered at centerX/centerY468 //The fortress wall should always start with the main entrance (like "entry" or "gate") to get the orientation right (like placeObject)469 // 470 //fortress An instance of Fortress with a wall defined471 //style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia472 //playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia)473 //orientation Optional. Angle the first wall element (should be a gate or entrance) is placed. Default is 0474 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////475 function placeCustomFortress(centerX, centerY, fortress, style, playerId , orientation)483 /** 484 * placeCustomFortress 485 * 486 * Place a fortress (mainly a closed wall build like placeWall) centered at centerX/centerY 487 * The fortress wall should always start with the main entrance (like "entry" or "gate") to get the orientation right (like placeObject) 488 * 489 * fortress An instance of Fortress with a wall defined 490 * style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 491 * playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia) 492 * orientation Optional. Angle the first wall element (should be a gate or entrance) is placed. Default is 0 493 */ 494 function placeCustomFortress(centerX, centerY, fortress, style, playerId=0, orientation=0) 476 495 { 477 496 // Graciously handle arguments 478 fortress = (fortress || fortressTypes["medium"]); 479 playerId = (playerId || 0); 480 if (!wallStyles.hasOwnProperty(style)) 481 { 482 if (playerId == 0) 483 style = (style || "palisades"); 484 else 485 style = (getCivCode(playerId-1)); 486 } 487 orientation = (orientation || 0); 497 fortress = fortress || g_FortressTypes["medium"]; 498 if (!style || g_WallStyleList.indexOf(style) == -1) 499 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 488 500 489 501 // Calculate center if fortress.centerToFirstElement is undefined (default) 490 502 var centerToFirstElement = fortress.centerToFirstElement; … … 496 508 placeWall(startX, startY, fortress.wall, style, playerId, orientation) 497 509 } 498 510 499 / //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////500 //placeFortress501 // 502 //Like placeCustomFortress just it takes type (a fortress type string, has to be in fortressTypes) instead of an instance of Fortress503 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////504 function placeFortress(centerX, centerY, type , style, playerId, orientation)511 /** 512 * placeFortress 513 * 514 * Like placeCustomFortress just it takes type (a fortress type string, has to be in fortressTypes) instead of an instance of Fortress 515 */ 516 function placeFortress(centerX, centerY, type="medium", style, playerId=0, orientation=0) 505 517 { 506 518 // Graciously handle arguments 507 type = (type || "medium"); 508 playerId = (playerId || 0); 509 if (!wallStyles.hasOwnProperty(style)) 510 { 511 if (playerId == 0) 512 style = (style || "palisades"); 513 else 514 style = (getCivCode(playerId-1)); 515 } 516 orientation = (orientation || 0); 519 if (!style || g_WallStyleList.indexOf(style) == -1) 520 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 517 521 518 522 // Call placeCustomFortress with the given arguments 519 placeCustomFortress(centerX, centerY, fortressTypes[type], style, playerId, orientation);523 placeCustomFortress(centerX, centerY, g_FortressTypes[type], style, playerId, orientation); 520 524 } 521 525 522 / /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////523 //placeLinearWall524 // 525 //Places a straight wall from a given coordinate to an other repeatedly using the wall parts.526 // 527 //startX/startY Coordinate of the approximate beginning of the wall (Not the place of the first wall element)528 //targetX/targetY Coordinate of the approximate ending of the wall (Not the place of the last wall element)529 // wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["tower", "wallLong"]530 //style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia531 //playerId Optional. Integer number of the player. Default is 0 (gaia)532 //endWithFirst Optional. A boolean value. If true the 1st wall element in the wallPart array will finalize the wall. Default is true533 // 534 //TODO: Maybe add angle offset for more generic looking?535 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////536 function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId , endWithFirst)526 /** 527 * placeLinearWall 528 * 529 * Places a straight wall from a given coordinate to an other repeatedly using the wall parts. 530 * 531 * startX/startY Coordinate of the approximate beginning of the wall (Not the place of the first wall element) 532 * targetX/targetY Coordinate of the approximate ending of the wall (Not the place of the last wall element) 533 * wallPart Optional. An array of NON-BENDING wall element types. Default is ["tower", "wallLong"] 534 * style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 535 * playerId Optional. Integer number of the player. Default is 0 (gaia) 536 * endWithFirst Optional. A boolean value. If true the 1st wall element in the wallPart array will finalize the wall. Default is true 537 * 538 * TODO: Maybe add angle offset for more generic looking? 539 */ 540 function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId=0, endWithFirst=true) 537 541 { 538 542 // Setup optional arguments to the default 539 wallPart = (wallPart || ["tower", "wallLong"]); 540 playerId = (playerId || 0); 541 if (!wallStyles.hasOwnProperty(style)) 542 { 543 if (playerId == 0) 544 style = (style || "palisades"); 545 else 546 style = (getCivCode(playerId-1)); 547 } 548 endWithFirst = typeof endWithFirst == "undefined" ? true : endWithFirst; 543 wallPart = wallPart || ["tower", "long"]; 544 if (!style || g_WallStyleList.indexOf(style) == -1) 545 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 549 546 550 547 // Check arguments 551 for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) 552 { 553 var bending = wallStyles[style][wallPart[elementIndex]].bending; 554 if (bending != 0) 555 warn("Bending is not supported by placeLinearWall but a bending wall element is used: " + wallPart[elementIndex] + " -> wallStyles[style][wallPart[elementIndex]].entity"); 556 } 548 for (let element of wallPart) 549 if (getWallElement(style, element).bend != 0) 550 warn("Bending is not supported by placeLinearWall but the following bending wall element was used: " + element); 551 557 552 // Setup number of wall parts 558 553 var totalLength = getDistance(startX, startY, targetX, targetY); 559 var wallPartLength = 0; 560 for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) 561 wallPartLength += wallStyles[style][wallPart[elementIndex]].width; 554 var wallPartLength = getWallLength(style, wallPart); 562 555 var numParts = 0; 563 556 if (endWithFirst == true) 564 numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength);557 numParts = ceil((totalLength - getWallElement(style, wallPart[0]).length) / wallPartLength); 565 558 else 566 559 numParts = ceil(totalLength / wallPartLength); 560 567 561 // Setup scale factor 568 562 var scaleFactor = 1; 569 563 if (endWithFirst == true) 570 scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width);564 scaleFactor = totalLength / (numParts * wallPartLength + getWallElement(style, wallPart[0]).length); 571 565 else 572 566 scaleFactor = totalLength / (numParts * wallPartLength); 567 573 568 // Setup angle 574 569 var wallAngle = getAngle(startX, startY, targetX, targetY); // NOTE: function "getAngle()" is about to be changed... 575 570 var placeAngle = wallAngle - PI/2; 576 571 // Place wall entities 577 572 var x = startX; 578 573 var y = startY; 579 for (var partIndex = 0; partIndex < numParts; partIndex++)574 for (var partIndex = 0; partIndex < numParts; ++partIndex) 580 575 { 581 for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)576 for (var elementIndex = 0; elementIndex < wallPart.length; ++elementIndex) 582 577 { 583 var wallEle = wallStyles[style][wallPart[elementIndex]]; 584 // Width correction 585 x += scaleFactor * wallEle.width/2 * cos(wallAngle); 586 y += scaleFactor * wallEle.width/2 * sin(wallAngle); 578 let wallEle = getWallElement(style, wallPart[elementIndex]); 579 let wallLength = (wallEle.length - getOverlap(style)) / 2; 580 let distX = scaleFactor * wallLength * cos(wallAngle); 581 let distY = scaleFactor * wallLength * sin(wallAngle); 582 // Length correction 583 x += distX; 584 y += distY; 587 585 // Indent correction 588 varplaceX = x - wallEle.indent * sin(wallAngle);589 varplaceY = y + wallEle.indent * cos(wallAngle);586 let placeX = x - wallEle.indent * sin(wallAngle); 587 let placeY = y + wallEle.indent * cos(wallAngle); 590 588 // Placement 591 var entity = wallEle.entity; 592 if (entity !== undefined) 593 placeObject(placeX, placeY, entity, playerId, placeAngle + wallEle.angle); 594 x += scaleFactor * wallEle.width/2 * cos(wallAngle); 595 y += scaleFactor * wallEle.width/2 * sin(wallAngle); 589 let entPath = wallEle.entPath; 590 if (entPath !== undefined) 591 placeObject(placeX, placeY, entPath, playerId, placeAngle + wallEle.angle); 592 // Prep for next object 593 x += distX; 594 y += distY; 596 595 } 597 596 } 598 597 if (endWithFirst == true) 599 598 { 600 var wallEle = wallStyles[style][wallPart[0]]; 601 x += scaleFactor * wallEle.width/2 * cos(wallAngle); 602 y += scaleFactor * wallEle.width/2 * sin(wallAngle); 603 var entity = wallEle.entity; 604 if (entity !== undefined) 605 placeObject(x, y, entity, playerId, placeAngle + wallEle.angle); 599 var wallEle = getWallElement(style, wallPart[0]); 600 let wallLength = (wallEle.length - getOverlap(style)) / 2; 601 x += scaleFactor * wallLength * cos(wallAngle); 602 y += scaleFactor * wallLength * sin(wallAngle); 603 var entPath = wallEle.entPath; 604 if (entPath !== undefined) 605 placeObject(x, y, entPath, playerId, placeAngle + wallEle.angle); 606 606 } 607 607 } 608 608 609 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 610 // placeCircularWall 611 // 612 // Place a circular wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius 613 // The wall can be opened forming more an arc than a circle if maxAngle < 2*PI 614 // The orientation then determines where this open part faces (0 means right like unrotated building's drop-points) 615 // 616 // centerX/Y Coordinates of the circle's center 617 // radius How wide the circle should be (approximate, especially if maxBendOff != 0) 618 // wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["tower", "wallLong"] 619 // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 620 // playerId Optional. Integer number of the player. Default is 0 (gaia) 621 // orientation Optional. Where the open part of the (circular) arc should face (if maxAngle is < 2*PI). Default is 0 622 // maxAngle Optional. How far the wall should circumvent the center. Default is 2*PI (full circle) 623 // endWithFirst Optional. Boolean. If true the 1st wall element in the wallPart array will finalize the wall. Default is false for full circles, else true 624 // maxBendOff Optional. How irregular the circle should be. 0 means regular circle, PI/2 means very irregular. Default is 0 (regular circle) 625 // 626 // NOTE: Don't use wall elements with bending like corners! 627 // TODO: Perhaps add eccentricity and maxBendOff functionality (untill now an unused argument) 628 // TODO: Perhaps add functionality for spirals 629 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 630 function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle, endWithFirst, maxBendOff) 609 /** 610 * placeCircularWall 611 * 612 * Place a circular wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius 613 * The wall can be opened forming more an arc than a circle if maxAngle < 2*PI 614 * The orientation then determines where this open part faces (0 means right like unrotated building's drop-points) 615 * 616 * centerX/Y Coordinates of the circle's center 617 * radius How wide the circle should be (approximate, especially if maxBendOff != 0) 618 * wallPart Optional. An array of NON-BENDING wall element types. Default is ["tower", "wallLong"] 619 * style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 620 * playerId Optional. Integer number of the player. Default is 0 (gaia) 621 * orientation Optional. Where the open part of the (circular) arc should face (if maxAngle is < 2*PI). Default is 0 622 * maxAngle Optional. How far the wall should circumvent the center. Default is 2*PI (full circle) 623 * endWithFirst Optional. Boolean. If true the 1st wall element in the wallPart array will finalize the wall. Default is false for full circles, else true 624 * maxBendOff Optional. How irregular the circle should be. 0 means regular circle, PI/2 means very irregular. Default is 0 (regular circle) 625 * 626 * NOTE: Don't use wall elements with bending like corners! 627 * TODO: Perhaps add eccentricity 628 * TODO: Check if maxBendOff parameter works in all cases 629 * TODO: Perhaps add functionality for spirals 630 */ 631 function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId=0, orientation=0, maxAngle=TWO_PI, endWithFirst, maxBendOff=0) 631 632 { 632 633 // Setup optional arguments to the default 633 wallPart = (wallPart || ["tower", "wallLong"]); 634 playerId = (playerId || 0); 635 if (!wallStyles.hasOwnProperty(style)) 636 { 637 if (playerId == 0) 638 style = (style || "palisades"); 639 else 640 style = (getCivCode(playerId-1)); 641 } 642 orientation = (orientation || 0); 643 maxAngle = (maxAngle || 2*PI); 634 wallPart = wallPart || ["tower", "long"]; 635 if (!style || g_WallStyleList.indexOf(style) == -1) 636 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 644 637 if (endWithFirst === undefined) 645 638 { 646 if (maxAngle >= 2*PI - 0.001) // Can this be done better?639 if (maxAngle >= TWO_PI - 0.001) // Can this be done better? 647 640 endWithFirst = false; 648 641 else 649 642 endWithFirst = true; 650 643 } 651 maxBendOff = (maxBendOff || 0);652 644 653 645 // Check arguments 654 646 if (maxBendOff > PI/2 || maxBendOff < 0) 655 warn("placeCircularWall maxBendOff sould satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: " + maxBendOff); 656 for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) 657 { 658 var bending = wallStyles[style][wallPart[elementIndex]].bending; 659 if (bending != 0) 660 warn("Bending is not supported by placeCircularWall but a bending wall element is used: " + wallPart[elementIndex]); 661 } 647 warn("placeCircularWall maxBendOff should satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: " + maxBendOff); 648 for (let element of wallPart) 649 if (getWallElement(style, element).bend != 0) 650 warn("Bending is not supported by placeCircularWall but the following bending wall element was used: " + element); 651 662 652 // Setup number of wall parts 663 653 var totalLength = maxAngle * radius; 664 var wallPartLength = 0; 665 for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) 666 wallPartLength += wallStyles[style][wallPart[elementIndex]].width; 654 var wallPartLength = getWallLength(style, wallPart); 667 655 var numParts = 0; 668 656 if (endWithFirst == true) 669 657 { 670 numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength);658 numParts = ceil((totalLength - getWallElement(style, wallPart[0]).length) / wallPartLength); 671 659 } 672 660 else 673 661 { … … 676 664 // Setup scale factor 677 665 var scaleFactor = 1; 678 666 if (endWithFirst == true) 679 scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width);667 scaleFactor = totalLength / (numParts * wallPartLength + getWallElement(style, wallPart[0]).length); 680 668 else 681 669 scaleFactor = totalLength / (numParts * wallPartLength); 682 670 // Place wall entities 683 671 var actualAngle = orientation + (2*PI - maxAngle) / 2; 684 672 var x = centerX + radius*cos(actualAngle); 685 673 var y = centerY + radius*sin(actualAngle); 686 for ( var partIndex = 0; partIndex < numParts; partIndex++)674 for (let partIndex = 0; partIndex < numParts; ++partIndex) 687 675 { 688 for ( var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)676 for (let wallEle of wallPart) 689 677 { 690 var wallEle = wallStyles[style][wallPart[elementIndex]];678 wallEle = getWallElement(style, wallEle); 691 679 // Width correction 692 var addAngle = scaleFactor * wallEle.width/ radius;693 vartargetX = centerX + radius * cos(actualAngle + addAngle);694 vartargetY = centerY + radius * sin(actualAngle + addAngle);695 varplaceX = x + (targetX - x)/2;696 varplaceY = y + (targetY - y)/2;697 varplaceAngle = actualAngle + addAngle/2;680 let addAngle = scaleFactor * (wallEle.length - getOverlap(style)) / radius; 681 let targetX = centerX + radius * cos(actualAngle + addAngle); 682 let targetY = centerY + radius * sin(actualAngle + addAngle); 683 let placeX = x + (targetX - x)/2; 684 let placeY = y + (targetY - y)/2; 685 let placeAngle = actualAngle + addAngle/2; 698 686 // Indent correction 699 687 placeX -= wallEle.indent * cos(placeAngle); 700 688 placeY -= wallEle.indent * sin(placeAngle); 701 689 // Placement 702 var ent ity = wallEle.entity;703 if (ent ity!== undefined)704 placeObject(placeX, placeY, ent ity, playerId, placeAngle + wallEle.angle);690 var entPath = wallEle.entPath; 691 if (entPath !== undefined) 692 placeObject(placeX, placeY, entPath, playerId, placeAngle + wallEle.angle); 705 693 // Prepare for the next wall element 706 694 actualAngle += addAngle; 707 695 x = centerX + radius*cos(actualAngle); … … 710 698 } 711 699 if (endWithFirst == true) 712 700 { 713 var wallEle = wallStyles[style][wallPart[0]];714 var addAngle = scaleFactor * wallEle. width / radius;701 var wallEle = getWallElement(style, wallPart[0]); 702 var addAngle = scaleFactor * wallEle.length / radius; 715 703 var targetX = centerX + radius * cos(actualAngle + addAngle); 716 704 var targetY = centerY + radius * sin(actualAngle + addAngle); 717 705 var placeX = x + (targetX - x)/2; 718 706 var placeY = y + (targetY - y)/2; 719 707 var placeAngle = actualAngle + addAngle/2; 720 placeObject(placeX, placeY, wallEle.ent ity, playerId, placeAngle + wallEle.angle);708 placeObject(placeX, placeY, wallEle.entPath, playerId, placeAngle + wallEle.angle); 721 709 } 722 710 } 723 711 724 / ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////725 //placePolygonalWall726 // 727 //Place a polygonal wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius728 // 729 //centerX/Y Coordinates of the polygon's center730 //radius How wide the circle should be in which the polygon fits731 // wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["wallLong", "tower"]732 //cornerWallElement Optional. Wall element to be placed at the polygon's corners. Default is "tower"733 //style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia734 //playerId Optional. Integer number of the player. Default is 0 (gaia)735 //orientation Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right)736 //numCorners Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory)737 //skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true738 // 739 //NOTE: Don't use wall elements with bending like corners!740 //TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement741 //TODO: Check some arguments742 //TODO: Add eccentricity and perhaps make it just call placeIrregularPolygonalWall with irregularity = 0743 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////744 function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId , orientation, numCorners, skipFirstWall)712 /** 713 * placePolygonalWall 714 * 715 * Place a polygonal wall of repeated wall elements given in the argument wallPart around centerX/centerY with the given radius 716 * 717 * centerX/Y Coordinates of the polygon's center 718 * radius How wide the circle should be in which the polygon fits 719 * wallPart Optional. An array of NON-BENDING wall element types. Default is ["wallLong", "tower"] 720 * cornerWallElement Optional. Wall element to be placed at the polygon's corners. Default is "tower" 721 * style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 722 * playerId Optional. Integer number of the player. Default is 0 (gaia) 723 * orientation Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right) 724 * numCorners Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory) 725 * skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true 726 * 727 * NOTE: Don't use wall elements with bending like corners! 728 * TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement 729 * TODO: Check some arguments 730 * TODO: Add eccentricity and perhaps make it just call placeIrregularPolygonalWall with irregularity = 0 731 */ 732 function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId=0, orientation=0, numCorners=8, skipFirstWall=true) 745 733 { 746 734 // Setup optional arguments to the default 747 wallPart = (wallPart || ["wallLong", "tower"]); 748 cornerWallElement = (cornerWallElement || "tower"); // Don't use wide elements for this. Not supported well... 749 playerId = (playerId || 0); 750 if (!wallStyles.hasOwnProperty(style)) 751 { 752 if (playerId == 0) 753 style = (style || "palisades"); 754 else 755 style = (getCivCode(playerId-1)); 756 } 757 orientation = (orientation || 0); 758 numCorners = (numCorners || 8); 759 skipFirstWall = (skipFirstWall || true); 760 735 wallPart = wallPart || ["long", "tower"]; 736 cornerWallElement = cornerWallElement || "tower"; // Don't use wide elements for this. Not supported well... 737 if (!style || g_WallStyleList.indexOf(style) == -1) 738 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 739 761 740 // Setup angles 762 var angleAdd = 2*PI/numCorners;741 var angleAdd = TWO_PI/numCorners; 763 742 var angleStart = orientation - angleAdd/2; 743 764 744 // Setup corners 765 745 var corners = []; 766 for ( var i = 0; i < numCorners; i++)746 for (let i = 0; i < numCorners; ++i) 767 747 corners.push([centerX + radius*cos(angleStart + i*angleAdd), centerY + radius*sin(angleStart + i*angleAdd)]); 748 768 749 // Place Corners and walls 769 for ( var i = 0; i < numCorners; i++)750 for (let i = 0; i < numCorners; ++i) 770 751 { 771 varangleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);772 placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entity, playerId, angleToCorner);752 let angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY); 753 placeObject(corners[i][0], corners[i][1], getWallElement(style, cornerWallElement).entPath, playerId, angleToCorner); 773 754 if (!(skipFirstWall && i == 0)) 774 755 { 756 let cornerLength = getWallElement(style, cornerWallElement).length / 2; 757 let cornerAngle = angleToCorner + angleAdd / 2; 758 let cornerX = cornerLength * sin(cornerAngle); 759 let cornerY = cornerLength * cos(cornerAngle); 775 760 placeLinearWall( 776 761 // Adjustment to the corner element width (approximately) 777 corners[i][0] + wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // startX778 corners[i][1] - wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // startY779 corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2 * sin(angleToCorner + angleAdd/2), // targetX780 corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2 * cos(angleToCorner + angleAdd/2), // targetY762 corners[i][0] + cornerX, // startX 763 corners[i][1] - cornerY, // startY 764 corners[(i+1)%numCorners][0] - cornerX, // targetX 765 corners[(i+1)%numCorners][1] + cornerY, // targetY 781 766 wallPart, style, playerId); 782 767 } 783 768 } 784 769 } 785 770 786 / ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////787 //placeIrregularPolygonalWall788 // 789 //Place an irregular polygonal wall of some wall parts to choose from around centerX/centerY with the given radius790 // 791 //centerX/Y Coordinates of the polygon's center792 //radius How wide the circle should be in which the polygon fits793 //cornerWallElement Optional. Wall element to be placed at the polygon's corners. Default is "tower"794 //style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia795 //playerId Optional. Integer number of the player. Default is 0 (gaia)796 //orientation Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right)797 // numCorners Optional. How many corners the polygon will have. Default is 8 (matching a civ centers territory) 798 //irregularity Optional. How irregular the polygon will be. 0 means regular, 1 means VERY irregular. Default is 0.5799 // skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true800 //wallPartsAssortment Optional. An array of wall part arrays to choose from for each linear wall connecting the corners. Default is hard to describe ^^801 // 802 //NOTE: wallPartsAssortment is put to the end because it's hardest to set803 //NOTE: Don't use wall elements with bending like corners!804 //TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement805 //TODO: Check some arguments806 //TODO: Perhaps add eccentricity807 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////808 function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement , style, playerId, orientation, numCorners, irregularity, skipFirstWall, wallPartsAssortment)771 /** 772 * placeIrregularPolygonalWall 773 * 774 * Place an irregular polygonal wall of some wall parts to choose from around centerX/centerY with the given radius 775 * 776 * centerX/Y Coordinates of the polygon's center 777 * radius How wide the circle should be in which the polygon fits 778 * cornerWallElement Optional. Wall element to be placed at the polygon's corners. Default is "tower" 779 * style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 780 * playerId Optional. Integer number of the player. Default is 0 (gaia) 781 * orientation Optional. Angle from the center to the first linear wall part placed. Default is 0 (towards positive X/right) 782 * numCorners Optional. How many corners the polygon will have. Default is randomly chosen from 'tween 5 & 7 inclusive 783 * irregularity Optional. How irregular the polygon will be. 0 means regular, 1 means VERY irregular. Default is 0.5 784 * skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is false 785 * wallPartsAssortment Optional. An array of wall part arrays to choose from for each linear wall connecting the corners. Default is hard to describe ^^ 786 * 787 * NOTE: wallPartsAssortment is put to the end because it's hardest to set 788 * NOTE: Don't use wall elements with bending like corners! 789 * TODO: Replace skipFirstWall with firstWallPart to enable gate/defended entrance placement 790 * TODO: Check some arguments 791 * TODO: Perhaps add eccentricity 792 */ 793 function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement="tower", style, playerId=0, orientation=0, numCorners, irregularity=0.5, skipFirstWall=false, wallPartsAssortment) 809 794 { 810 795 // Setup optional arguments 811 playerId = (playerId || 0); 812 if (!wallStyles.hasOwnProperty(style)) 813 { 814 if (playerId == 0) 815 style = (style || "palisades"); 816 else 817 style = (getCivCode(playerId-1)); 818 } 819 796 if (!style || g_WallStyleList.indexOf(style) == -1) 797 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 798 numCorners = (numCorners || randInt(5, 7)); 799 820 800 // Generating a generic wall part assortment with each wall part including 1 gate lengthened by walls and towers 821 801 // NOTE: It might be a good idea to write an own function for that... 822 var defaultWallPartsAssortment = [[" wallShort"], ["wall"], ["wallLong"], ["gate", "tower", "wallShort"]];802 var defaultWallPartsAssortment = [["short"], ["medium"], ["long"], ["gate", "tower", "short"]]; 823 803 var centeredWallPart = ["gate"]; 824 var extandingWallPartAssortment = [["tower", " wallLong"], ["tower", "wall"]];804 var extandingWallPartAssortment = [["tower", "long"], ["tower", "medium"]]; 825 805 defaultWallPartsAssortment.push(centeredWallPart); 826 for (var i = 0; i < extandingWallPartAssortment.length; i++)806 for (var i = 0; i < extandingWallPartAssortment.length; ++i) 827 807 { 828 808 var wallPart = centeredWallPart; 829 for (var j = 0; j < radius; j++)809 for (var j = 0; j < radius; ++j) 830 810 { 831 811 if (j%2 == 0) 832 812 wallPart = wallPart.concat(extandingWallPartAssortment[i]); … … 841 821 } 842 822 // Setup optional arguments to the default 843 823 wallPartsAssortment = (wallPartsAssortment || defaultWallPartsAssortment); 844 cornerWallElement = (cornerWallElement || "tower"); // Don't use wide elements for this. Not supported well... 845 style = (style || "palisades"); 846 playerId = (playerId || 0); 847 orientation = (orientation || 0); 848 numCorners = (numCorners || randInt(5, 7)); 849 irregularity = (irregularity || 0.5); 850 skipFirstWall = (skipFirstWall || false); 824 851 825 // Setup angles 852 var angleToCover = 2*PI;826 var angleToCover = TWO_PI; 853 827 var angleAddList = []; 854 for (var i = 0; i < numCorners; i++)828 for (var i = 0; i < numCorners; ++i) 855 829 { 856 830 // Randomize covered angles. Variety scales down with raising angle though... 857 831 angleAddList.push(angleToCover/(numCorners-i) * (1 + randFloat(-irregularity, irregularity))); … … 860 834 // Setup corners 861 835 var corners = []; 862 836 var angleActual = orientation - angleAddList[0]/2; 863 for (var i = 0; i < numCorners; i++)837 for (var i = 0; i < numCorners; ++i) 864 838 { 865 839 corners.push([centerX + radius*cos(angleActual), centerY + radius*sin(angleActual)]); 866 840 if (i < numCorners - 1) … … 869 843 // Setup best wall parts for the different walls (a bit confusing naming...) 870 844 var wallPartLengths = []; 871 845 var maxWallPartLength = 0; 872 for ( var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++)846 for (let wallPart of wallPartsAssortment) 873 847 { 874 var length = wallPartLengths[partIndex];875 wallPartLengths.push( getWallLength(wallPartsAssortment[partIndex], style));848 var length = getWallLength(style, wallPart); 849 wallPartLengths.push(length); 876 850 if (length > maxWallPartLength) 877 851 maxWallPartLength = length; 878 852 } 853 879 854 var wallPartList = []; // This is the list of the wall parts to use for the walls between the corners, not to confuse with wallPartsAssortment! 880 for (var i = 0; i < numCorners; i++)855 for (var i = 0; i < numCorners; ++i) 881 856 { 882 var bestWallPart = []; // This is a simp elwall part not a wallPartsAssortment!883 var bestWallLength = 99999999;857 var bestWallPart = []; // This is a simple wall part not a wallPartsAssortment! 858 var bestWallLength = Number.MAX_VALUE; 884 859 // NOTE: This is not exactly like the length the wall will be in the end. Has to be tweaked... 885 860 var wallLength = getDistance(corners[i][0], corners[i][1], corners[(i+1)%numCorners][0], corners[(i+1)%numCorners][1]); 886 861 var numWallParts = ceil(wallLength/maxWallPartLength); 887 for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++)862 for (var partIndex = 0; partIndex < wallPartsAssortment.length; ++partIndex) 888 863 { 889 864 var linearWallLength = numWallParts*wallPartLengths[partIndex]; 890 865 if (linearWallLength < bestWallLength && linearWallLength > wallLength) … … 895 870 } 896 871 wallPartList.push(bestWallPart); 897 872 } 873 898 874 // Place Corners and walls 899 for (var i = 0; i < numCorners; i++)875 for (var i = 0; i < numCorners; ++i) 900 876 { 901 877 var angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY); 902 placeObject(corners[i][0], corners[i][1], wallStyles[style][cornerWallElement].entity, playerId, angleToCorner);878 placeObject(corners[i][0], corners[i][1], getWallElement(style, cornerWallElement).entPath, playerId, angleToCorner); 903 879 if (!(skipFirstWall && i == 0)) 904 880 { 881 let cornerLength = getWallElement(style, cornerWallElement).length / 2; 905 882 placeLinearWall( 906 883 // Adjustment to the corner element width (approximately) 907 corners[i][0] + wallStyles[style][cornerWallElement].width/2* sin(angleToCorner + angleAddList[i]/2), // startX908 corners[i][1] - wallStyles[style][cornerWallElement].width/2* cos(angleToCorner + angleAddList[i]/2), // startY909 corners[(i+1)%numCorners][0] - wallStyles[style][cornerWallElement].width/2* sin(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetX910 corners[(i+1)%numCorners][1] + wallStyles[style][cornerWallElement].width/2* cos(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetY884 corners[i][0] + cornerLength * sin(angleToCorner + angleAddList[i]/2), // startX 885 corners[i][1] - cornerLength * cos(angleToCorner + angleAddList[i]/2), // startY 886 corners[(i+1)%numCorners][0] - cornerLength * sin(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetX 887 corners[(i+1)%numCorners][1] + cornerLength * cos(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetY 911 888 wallPartList[i], style, playerId, false); 912 889 } 913 890 } 914 891 } 915 892 916 / /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////917 //placeGenericFortress918 // 919 //Places a generic fortress with towers at the edges connected with long walls and gates (entries until gates work)920 //This is the default Iberian civ bonus starting wall921 // 922 //centerX/Y The approximate center coordinates of the fortress923 // radius The approximate radius of the wall to be placed 924 //playerId Optional. Integer number of the player. Default is 0 (gaia)925 //style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia926 // irregularity Optional. Float between 0 (circle) and 1 (very spiky), default is 1/2 927 //gateOccurence Optional. Integer number, every n-th walls will be a gate instead. Default is 3928 //maxTrys Optional. How often the function tries to find a better fitting shape at max. Default is 100929 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////930 function placeGenericFortress(centerX, centerY, radius , playerId, style, irregularity, gateOccurence, maxTrys)893 /** 894 * placeGenericFortress 895 * 896 * Places a generic fortress with towers at the edges connected with long walls and gates (entries until gates work) 897 * This is the default Iberian civ bonus starting wall 898 * 899 * centerX/Y The approximate center coordinates of the fortress 900 * radius Optional. The approximate radius of the wall to be placed. Default is 20 901 * playerId Optional. Integer number of the player. Default is 0 (gaia) 902 * style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 903 * irregularity Optional. Float between 0 (circle) and 1 (very spiky), default is 0.5 904 * gateOccurence Optional. Integer number, every n-th walls will be a gate instead. Default is 3 905 * maxTrys Optional. How often the function tries to find a better fitting shape at max. Default is 100 906 */ 907 function placeGenericFortress(centerX, centerY, radius=20, playerId=0, style, irregularity=0.5, gateOccurence=3, maxTrys=100) 931 908 { 932 909 // Setup optional arguments 933 radius = (radius || 20); 934 playerId = (playerId || 0); 935 if (!wallStyles.hasOwnProperty(style)) 936 { 937 if (playerId == 0) 938 style = (style || "palisades"); 939 else 940 style = (getCivCode(playerId-1)); 941 } 942 irregularity = (irregularity || 1/2); 943 gateOccurence = (gateOccurence || 3); 944 maxTrys = (maxTrys || 100); 910 if (!style || g_WallStyleList.indexOf(style) == -1) 911 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 945 912 946 913 // Setup some vars 947 914 var startAngle = randFloat(0, 2*PI); 948 915 var actualOffX = radius*cos(startAngle); 949 916 var actualOffY = radius*sin(startAngle); 950 917 var actualAngle = startAngle; 951 var pointDistance = wallStyles[style]["wallLong"].width + wallStyles[style]["tower"].width;918 var pointDistance = getWallLength(style, ["long", "tower"]); 952 919 // Searching for a well fitting point derivation 953 920 var tries = 0; 954 921 var bestPointDerivation = undefined; 955 922 var minOverlap = 1000; 956 923 var overlap = undefined; 957 while (tries < maxTrys && minOverlap > wallStyles[style]["tower"].width / 10)924 while (tries < maxTrys && minOverlap > getOverlap(style)) 958 925 { 959 926 var pointDerivation = []; 960 927 var distanceToTarget = 1000; … … 963 930 { 964 931 var indent = randFloat(-irregularity*pointDistance, irregularity*pointDistance); 965 932 var tmpAngle = getAngle(actualOffX, actualOffY, 966 (radius + indent)*cos(actualAngle + (pointDistance / radius)),967 (radius + indent)*sin(actualAngle + (pointDistance / radius)));933 (radius + indent)*cos(actualAngle + pointDistance / radius), 934 (radius + indent)*sin(actualAngle + pointDistance / radius)); 968 935 actualOffX += pointDistance*cos(tmpAngle); 969 936 actualOffY += pointDistance*sin(tmpAngle); 970 937 actualAngle = getAngle(0, 0, actualOffX, actualOffY); … … 982 949 } 983 950 } 984 951 } 985 tries++;952 ++tries; 986 953 } 987 954 log("placeGenericFortress: Reduced overlap to " + minOverlap + " after " + tries + " tries"); 988 955 // Place wall 989 for (var pointIndex = 0; pointIndex < bestPointDerivation.length; pointIndex++)956 for (var pointIndex = 0; pointIndex < bestPointDerivation.length; ++pointIndex) 990 957 { 991 958 var startX = centerX + bestPointDerivation[pointIndex][0]; 992 959 var startY = centerY + bestPointDerivation[pointIndex][1]; 993 960 var targetX = centerX + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][0]; 994 961 var targetY = centerY + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][1]; 995 962 var angle = getAngle(startX, startY, targetX, targetY); 996 var wallElement = " wallLong";963 var wallElement = "long"; 997 964 if ((pointIndex + 1) % gateOccurence == 0) 998 965 wallElement = "gate"; 999 var entity = wallStyles[style][wallElement].entity; 1000 if (entity) 966 967 var entPath = getWallElement(style, wallElement).entPath; 968 if (entPath) 1001 969 { 1002 970 placeObject(startX + (getDistance(startX, startY, targetX, targetY)/2)*cos(angle), // placeX 1003 971 startY + (getDistance(startX, startY, targetX, targetY)/2)*sin(angle), // placeY 1004 ent ity, playerId, angle - PI/2 + wallStyles[style][wallElement].angle);972 entPath, playerId, angle - PI/2 + getWallElement(style, wallElement).angle); 1005 973 } 1006 974 // Place tower 1007 975 var startX = centerX + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][0]; 1008 976 var startY = centerY + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][1]; 1009 977 var angle = getAngle(startX, startY, targetX, targetY); 1010 placeObject(centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], wallStyles[style]["tower"].entity, playerId, angle - PI/2 + wallStyles[style]["tower"].angle); 978 979 var tower = getWallElement(style, "tower"); 980 placeObject(centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], tower.entPath, playerId, angle - PI/2 + tower.angle); 1011 981 } 1012 982 } -
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(); -
binaries/data/mods/public/maps/random/wall_demo.js
1 1 RMS.LoadLibrary("rmgen"); 2 2 3 // initialize map 3 /** 4 * initialize map 5 */ 4 6 log("Initializing map..."); 5 7 InitMap(); 6 8 7 8 // General map setup 9 /** 10 * General map setup 11 */ 9 12 var mapSize = getMapSize(); 10 13 var mapCenterX = mapSize/2; 11 14 var mapCenterY = mapSize/2; 12 15 const BUILDING_ANlE = -PI/4; 13 16 14 17 15 //////////////////////////////////////// 16 // Demonstration code for wall placement 17 //////////////////////////////////////// 18 /** 19 * Demonstration code for wall placement 20 * 21 * 22 *Some general notes to the arguments: 23 * 24 * First all the place functions take the coordinates needed to place the wall 25 * X and Y coordinate are taken in seperate arguments like in placeObject 26 * Their meaning differs for different placement methods but are mainly self explanatory 27 * placeLinearWall takes 4 arguments here (2 coordinates) for startX, startY, targetX and targetY 28 * 29 * The next argument is always the 'wall' definition, an array of wall element type strings in most cases 30 * That looks like ['endLeft', 'wall', 'tower', 'wall', 'endRight', 'entry', 'endLeft', 'wall', 'tower', 'wall', 'endRight'] 31 * For placeCircularWall and placeLinearWall only wall parts are needed like: ['tower', 'wall'] 32 * They will automatically end with the first wall element if that makes sense (e.g. the wall is not closed) 33 * NOTE: They take further optional arguments to adjust this behaviour (See the wall_builder.js for that) 34 * placeFortress just takes a fortress type string that includes the wall definition 35 * The default fortress type strings are made for easy placement of predefined fortresses 36 * They are chosen like map sizes: 'tiny', 'small', 'medium', 'normal', 'large', 'veryLarge' and 'giant' 37 * NOTE: To place a custom fortress use placeCustomFortress instead 38 * It takes an instance of the Fortress class instead of the default fortress type strings 39 * 40 * The next argument is always the wall style string 41 * Wall styles are chosen by strings so the civ strings got by getCivCode() can be used 42 * Other styles may be present as well but besides the civ styles only 'palisades' includes all wall element types (yet) 43 * 44 * The next argument is always the index of the player that owns the wall. 45 * 0 is Gaia, 1 is Player 1 (default color blue), 2 is Player 2 (default color red), ... 46 * 47 * The next argument is an angle defining the orientation of the wall 48 * placeLinearWall does not need an angle since it's defined by startX/Y and targetX/Y 49 * Orientation works like the angle argument in placeObject 50 * 0 is always right (towards positive X) 51 * Raising the angle will rotate the wall counter-clockwise (mathmatical positive in default 2D) 52 * PI/2 faces top (positive Y) 53 * Orientation might be a little confusing for placeWall since it defines where the wall has its 'front' or 'outside' not the direction it will be build to. 54 * It's because all other methods work like that and it's intuitive there 55 * That means the walls outside by default (orientation = 0) faces positive X and (without bending wall elements) will be build towards positive Y 56 * 57 * Some other arguments are taken but all of them are optional and in most cases not needed 58 * One example is maxAngle for placeCircularWall that defines how far the wall will circumvent the center. Default is 2*PI which makes a full circle 59 */ 18 60 19 // Some general notes to the arguments: 20 21 // First all the place functions take the coordinates needed to place the wall 22 // X and Y coordinate are taken in seperate arguments like in placeObject 23 // Their meaning differs for different placement methods but are mainly self explanatory 24 // placeLinearWall takes 4 arguments here (2 coordinates) for startX, startY, targetX and targetY 25 26 // The next argument is always the 'wall' definition, an array of wall element type strings in most cases 27 // That looks like ['endLeft', 'wall', 'tower', 'wall', 'endRight', 'entry', 'endLeft', 'wall', 'tower', 'wall', 'endRight'] 28 // For placeCircularWall and placeLinearWall only wall parts are needed like: ['tower', 'wall'] 29 // They will automatically end with the first wall element if that makes sense (e.g. the wall is not closed) 30 // NOTE: They take further optional arguments to adjust this behaviour (See the wall_builder.js for that) 31 // placeFortress just takes a fortress type string that includes the wall definition 32 // The default fortress type strings are made for easy placement of predefined fortresses 33 // They are chosen like map sizes: 'tiny', 'small', 'medium', 'normal', 'large', 'veryLarge' and 'giant' 34 // NOTE: To place a custom fortress use placeCustomFortress instead 35 // It takes an instance of the Fortress class instead of the default fortress type strings 36 37 // The next argument is always the wall style string 38 // Wall styles are chosen by strings so the civ strings got by getCivCode() can be used 39 // Other styles may be present as well but besides the civ styles only 'palisades' includes all wall element types (yet) 40 41 // The next argument is always the index of the player that owns the wall. 42 // 0 is Gaia, 1 is Player 1 (default color blue), 2 is Player 2 (default color red), ... 43 44 // The next argument is an angle defining the orientation of the wall 45 // placeLinearWall does not need an angle since it's defined by startX/Y and targetX/Y 46 // Orientation works like the angle argument in placeObject 47 // 0 is always right (towards positive X) 48 // Raising the angle will rotate the wall counter-clockwise (mathmatical positive in default 2D) 49 // PI/2 faces top (positive Y) 50 // Orientation might be a little confusing for placeWall since it defines where the wall has its 'front' or 'outside' not the direction it will be build to. 51 // It's because all other methods work like that and it's intuitive there 52 // That means the walls outside by default (orientation = 0) faces positive X and (without bending wall elements) will be build towards positive Y 53 54 // Some other arguments are taken but all of them are optional and in most cases not needed 55 // One example is maxAngle for placeCircularWall that defines how far the wall will circumvent the center. Default is 2*PI which makes a full circle 56 57 58 // General wall placement setup 61 /** 62 * General wall placement setup 63 */ 59 64 const distToMapBorder = 5; 60 65 const distToOtherWalls = 10; 61 66 var buildableMapSize = mapSize - 2 * distToMapBorder; 62 67 var actualX = distToMapBorder; 63 68 var actualY = distToMapBorder; 64 // Wall styles are chosen by strings so the civ strings got by getCivCode() can be used 65 // Other styles may be present as well but besides the civ styles only 'palisades' includes all wall element types (yet) 66 const wallStyleList = ["athen", "brit", "cart", "gaul", "iber", "mace", "maur", "pers", "ptol", "rome", "sele", "spart", "rome_siege", "palisades"]; 69 var wallStyleList = g_WallStyleList; 67 70 68 69 //////////////////////////////////////// 70 // Custom wall placement (element based) 71 //////////////////////////////////////// 72 var wall = ['endLeft', 'wallLong', 'tower', 'wall', 'outpost', 'wall', 'cornerOut', 'wall', 'cornerIn', 'wall', 'house', 'endRight', 'entryTower', 'endLeft', 'wallShort', 'barracks', 'gate', 'tower', 'wall', 'wallFort', 'wall', 'endRight']; 73 for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++) 71 /** 72 * Custom wall placement (element based) 73 */ 74 var wall = ['start', 'long', 'tower', 'tower', 'tower', 'medium', 'outpost', 'medium', 'cornerOut', 'medium', 'cornerIn', 'medium', 'house', 'end', 'entryTower', 'start', 'short', 'barracks', 'gate', 'tower', 'medium', 'fort', 'medium', 'end']; 75 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 74 76 { 75 77 var startX = actualX + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the first wall element 76 78 var startY = actualY; // Y coordinate of the first wall element 77 var style = wallStyleList[styleIndex]; // //The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades'78 var orientation = styleIndex * PI/64; // Orientation of the first wall element. 0 means 'outside' or 'front' is right (positive X, like object placement)79 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 80 var orientation = PI/16 * sin(styleIndex * PI/4); // Orientation of the first wall element. 0 means 'outside' or 'front' is right (positive X, like object placement in Atlas) 79 81 // That means the wall will be build towards top (positive Y) if no corners are used 80 82 var playerId = 0; // Owner of the wall (like in placeObject). 0 is Gaia, 1 is Player 1 (default color blue), ... 81 placeWall(startX, startY, wall, style, playerId, orientation); // Actually plac ingthe wall83 placeWall(startX, startY, wall, style, playerId, orientation); // Actually place the wall 82 84 } 83 85 actualX = distToMapBorder; // Reset actualX 84 86 actualY += 80 + distToOtherWalls; // Increase actualY for next wall placement method 85 87 86 ////////////////////////////////////////////////////////////// 87 // Default fortress placement (chosen by fortress type string) 88 ////////////////////////////////////////////////////////////// 88 89 /** 90 * Default fortress placement (chosen by fortress type string) 91 */ 89 92 var fortressRadius = 15; // The space the fortresses take in average. Just for design of this map 90 for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)93 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 91 94 { 92 95 var centerX = actualX + fortressRadius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the fortress 93 96 var centerY = actualY + fortressRadius; // Y coordinate of the center of the fortress … … 99 102 placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the fortress 100 103 } 101 104 actualX = distToMapBorder; // Reset actualX 102 actualY += 2 * fortressRadius + 2 *distToOtherWalls; // Increase actualY for next wall placement method105 actualY += 2 * fortressRadius + distToOtherWalls; // Increase actualY for next wall placement method 103 106 104 ////////////////////////// 105 // Circular wall placement 106 ////////////////////////// 107 // NOTE: Don't use bending wall elements like corners here! 107 /** 108 * 'generic' fortress placement (iberian wall circuit code) 109 */ 108 110 var radius = min((mapSize - actualY - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall circle 111 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 112 { 113 var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the fortress 114 var centerY = actualY + radius; // Y coordinate of the center of the fortress 115 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 116 var playerId = 0; // Owner of the wall. 0 is Gaia, 1 is Player 1 (default color blue), ... 117 placeGenericFortress(centerX, centerY, radius, playerId, style); // Actually place the fortress 118 placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the fortress 119 } 120 actualX = distToMapBorder; // Reset actualX 121 actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method 122 123 /** 124 * Circular wall placement 125 * 126 * NOTE: Don't use bending wall elements like corners here! 127 */ 128 var radius = min((mapSize - actualY - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall circle 109 129 var centerY = actualY + radius; // Y coordinate of the center of the wall circle 110 130 var orientation = 0; // Where the wall circle will be open if maxAngle < 2*PI, see below. Otherwise where the first wall element will be placed 111 for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)131 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 112 132 { 113 133 var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle 114 134 var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... 115 var wallPart = ['tower', ' wall', 'house']; // List of wall elements the wall will be build of. Optional, default id ['wall']135 var wallPart = ['tower', 'medium', 'house']; // List of wall elements the wall will be build of. Optional, default id ['wall'] 116 136 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 117 137 var maxAngle = PI/2 * (styleIndex%3 + 2); // How far the wall should circumvent the center 118 138 placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle); // Actually placing the wall … … 122 142 actualX = distToMapBorder; // Reset actualX 123 143 actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method 124 144 125 /////////////////////////// 126 // Polygonal wall placement 127 /////////////////////////// 128 // NOTE: Don't use bending wall elements like corners here! 145 /** 146 * Regular Polygonal wall placement 147 * 148 * NOTE: Don't use bending wall elements like corners here! 149 */ 129 150 var radius = min((mapSize - actualY - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons 130 151 var centerY = actualY + radius; // Y coordinate of the center of the wall polygon 131 152 var orientation = 0; // Where the wall circle will be open if ???, see below. Otherwise where the first wall will be placed 132 for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)153 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 133 154 { 134 155 var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle 135 156 var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... 136 157 var cornerWallElement = 'tower'; // With wall element type will be uset for the corners of the polygon 137 var wallPart = [' wall', 'tower']; // List of wall elements the wall will be build of. Optional, default id ['wall']158 var wallPart = ['medium', 'tower']; // List of wall elements the wall will be build of. Optional, default id ['wall'] 138 159 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 139 160 var numCorners = (styleIndex)%6 + 3; // How many corners the plogon will have 140 161 var skipFirstWall = true; // If the wall should be open towards orientation … … 145 166 actualX = distToMapBorder; // Reset actualX 146 167 actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method 147 168 148 //////////////////////// 149 // Linear wall placement 150 //////////////////////// 151 // NOTE: Don't use bending wall elements like corners here! 169 /** 170 * Irregular Polygonal wall placement 171 * 172 * NOTE: Don't use bending wall elements like corners here! 173 */ 174 var radius = min((mapSize - actualY - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons 175 var centerY = actualY + radius; // Y coordinate of the center of the wall polygon 176 var orientation = 0; // Where the wall circle will be open if ???, see below. Otherwise where the first wall will be placed 177 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 178 { 179 var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle 180 var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... 181 var cornerWallElement = 'tower'; // With wall element type will be uset for the corners of the polygon 182 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 183 var numCorners = (styleIndex)%6 + 3; // How many corners the plogon will have 184 var skipFirstWall = true; // If the wall should be open towards orientation 185 placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerId, orientation, numCorners, undefined, skipFirstWall); 186 placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the wall circle 187 orientation += PI/16; // Increasing orientation to see how rotation works (like for object placement) 188 } 189 actualX = distToMapBorder; // Reset actualX 190 actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method 191 192 /** 193 * Linear wall placement 194 * 195 * NOTE: Don't use bending wall elements like corners here! 196 */ 152 197 var maxWallLength = (mapSize - actualY - distToMapBorder - distToOtherWalls); // Just for this maps design. How long the longest wall will be 153 198 var numWallsPerStyle = floor(buildableMapSize / distToOtherWalls / wallStyleList.length); // Just for this maps design. How many walls of the same style will be placed 154 for (var styleIndex = 0; styleIndex < wallStyleList.length; styleIndex++)199 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 155 200 { 156 for (var wallIndex = 0; wallIndex < numWallsPerStyle; wallIndex++)201 for (var wallIndex = 0; wallIndex < numWallsPerStyle; ++wallIndex) 157 202 { 158 var startX = actualX + (styleIndex * numWallsPerStyle + wallIndex) * distToOtherWalls; // X coordinate the wall will start from203 var startX = actualX + (styleIndex * numWallsPerStyle + wallIndex) * buildableMapSize/wallStyleList.length/numWallsPerStyle; // X coordinate the wall will start from 159 204 var startY = actualY; // Y coordinate the wall will start from 160 205 var endX = startX; // X coordinate the wall will end 161 206 var endY = actualY + (wallIndex + 1) * maxWallLength/numWallsPerStyle; // Y coordinate the wall will end 162 207 var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... 163 var wallPart = ['tower', ' wall']; // List of wall elements the wall will be build of208 var wallPart = ['tower', 'medium']; // List of wall elements the wall will be build of 164 209 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 165 210 placeLinearWall(startX, startY, endX, endY, wallPart, style, playerId); // Actually placing the wall 166 211 // placeObject(startX, startY, 'other/obelisk', 0, 0*PI); // Place visual marker to see where exsactly the wall begins 167 212 // placeObject(endX, endY, 'other/obelisk', 0, 0*PI); // Place visual marker to see where exsactly the wall ends 168 213 } 169 214 } 170 actualX = distToMapBorder; // Reset actualX171 actualY += maxWallLength + distToOtherWalls; // Increase actualY for next wall placement method172 215 173 174 // Export map data 216 /** 217 * Export map data 218 */ 175 219 ExportMap(); -
binaries/data/mods/public/maps/random/wall_demo.json
2 2 "settings" : { 3 3 "Name" : "Wall Demo", 4 4 "Script" : "wall_demo.js", 5 "Description" : "A demonstration of wall placement methods/code in random maps. Very large map size is recommended.",5 "Description" : "A demonstration of wall placement methods/code in random maps. Giant map size is recommended!", 6 6 "BaseTerrain" : ["grass1"], 7 7 "BaseHeight" : 0, 8 8 "Keywords": ["demo"], 9 9 "CircularMap" : false, 10 "RevealMap": true, 10 11 "XXXXXX" : "Optionally define other things here, like we would for a scenario" 11 12 } 12 13 } 14 No newline at end of file -
binaries/data/mods/public/simulation/components/WallPiece.js
6 6 "</a:example>" + 7 7 "<element name='Length'>" + 8 8 "<ref name='nonNegativeDecimal'/>" + 9 "</element>"; 9 "</element>" + 10 "<optional>" + 11 "<element name='Orientation'>" + 12 "<ref name='nonNegativeDecimal'/>" + 13 "</element>" + 14 "</optional>" + 15 "<optional>" + 16 "<element name='Indent'>" + 17 "<data type='decimal'/>" + 18 "</element>" + 19 "</optional>" + 20 "<optional>" + 21 "<element name='Bend'>" + 22 "<data type='decimal'/>" + 23 "</element>" + 24 "</optional>"; 10 25 11 26 12 27 WallPiece.prototype.Init = function() -
binaries/data/mods/public/simulation/components/WallSet.js
21 21 "<element name='WallShort' a:help='Template name of the short wall segment'>" + 22 22 "<text/>" + 23 23 "</element>" + 24 "<optional>" + 25 "<element name='WallCurveQuarter'>" + 26 "<text/>" + 27 "</element>" + 28 "</optional>" + 29 "<optional>" + 30 "<element name='WallCurveEighth'>" + 31 "<text/>" + 32 "</element>" + 33 "</optional>" + 34 "<optional>" + 35 "<element name='WallEnd'>" + 36 "<text/>" + 37 "</element>" + 38 "</optional>" + 39 "<optional>" + 40 "<element name='Fort'>" + 41 "<text/>" + 42 "</element>" + 43 "</optional>" + 24 44 "</interleave>" + 25 45 "</element>" + 26 46 "<element name='MinTowerOverlap' a:help='Maximum fraction that wall segments are allowed to overlap towers, where 0 signifies no overlap and 1 full overlap'>" + -
binaries/data/mods/public/simulation/data/civs/athen.json
109 109 "Special":"Train heroes and research technology pertaining to heroes." 110 110 } 111 111 ], 112 "WallSets": 113 [ 114 "other/wallset_palisade", 115 "structures/athen_wallset_stone" 116 ], 112 117 "StartEntities": 113 118 [ 114 119 { -
binaries/data/mods/public/simulation/data/civs/brit.json
87 87 "Special": "" 88 88 } 89 89 ], 90 "WallSets": 91 [ 92 "other/wallset_palisade", 93 "structures/brit_wallset_stone" 94 ], 90 95 "StartEntities": 91 96 [ 92 97 { -
binaries/data/mods/public/simulation/data/civs/cart.json
112 112 "Special":"Hire Iberian mercenaries." 113 113 } 114 114 ], 115 "WallSets": 116 [ 117 "other/wallset_palisade", 118 "structures/cart_wallset_stone" 119 ], 115 120 "StartEntities": 116 121 [ 117 122 { -
binaries/data/mods/public/simulation/data/civs/gaul.json
87 87 "Special": "" 88 88 } 89 89 ], 90 "WallSets": 91 [ 92 "other/wallset_palisade", 93 "structures/gaul_wallset_stone" 94 ], 90 95 "StartEntities": 91 96 [ 92 97 { -
binaries/data/mods/public/simulation/data/civs/iber.json
85 85 "Special": "Defensive Aura - Gives all Iberian units and buildings within vision range of the monument a 10-15% attack boost. Build Limit: Only 5 may be built per map." 86 86 } 87 87 ], 88 "WallSets": 89 [ 90 "other/wallset_palisade", 91 "structures/iber_wallset_stone" 92 93 ], 88 94 "StartEntities": 89 95 [ 90 96 { -
binaries/data/mods/public/simulation/data/civs/mace.json
114 114 "Special":"Constructs and upgrades all Macedonian siege engines." 115 115 } 116 116 ], 117 "WallSets": 118 [ 119 "other/wallset_palisade", 120 "structures/mace_wallset_stone" 121 122 ], 117 123 "StartEntities": 118 124 [ 119 125 { -
binaries/data/mods/public/simulation/data/civs/maur.json
94 94 "Special":"Contentment: +10% Health and +10% resource gathering rates for all citizens and allied citizens within its range. Can be built anywhere except in enemy territory. Max Built: 10." 95 95 } 96 96 ], 97 "WallSets": 98 [ 99 "other/wallset_palisade", 100 "structures/maur_wallset_stone" 101 102 ], 97 103 "StartEntities": 98 104 [ 99 105 { -
binaries/data/mods/public/simulation/data/civs/pers.json
104 104 "Special": "Train heroes and Persian Immortals. Gives a slow trickle of all resources as 'Satrapy Tribute.'" 105 105 } 106 106 ], 107 "WallSets": 108 [ 109 "other/wallset_palisade", 110 "structures/pers_wallset_stone" 111 112 ], 107 113 "StartEntities": 108 114 [ 109 115 { -
binaries/data/mods/public/simulation/data/civs/ptol.json
113 113 "Special":"When built along the shoreline, removes shroud of darkness over all the water, revealing all the coast lines on the map. Limit: 1." 114 114 } 115 115 ], 116 "WallSets": 117 [ 118 "other/wallset_palisade", 119 "structures/ptol_wallset_stone" 120 121 ], 116 122 "StartEntities": 117 123 [ 118 124 { -
binaries/data/mods/public/simulation/data/civs/rome.json
89 89 "Special": "Can be built in neutral and enemy territory to strangle enemy towns." 90 90 } 91 91 ], 92 "WallSets": 93 [ 94 "structures/rome_wallset_stone", 95 "structures/rome_wallset_siege" 96 97 ], 92 98 "StartEntities": 93 99 [ 94 100 { -
binaries/data/mods/public/simulation/data/civs/sele.json
114 114 "Special":"This is the Seleucid expansion building, similar to Civic Centers for other factions. It is weaker and carries a smaller territory influence, but is cheaper and built faster." 115 115 } 116 116 ], 117 "WallSets": 118 [ 119 "other/wallset_palisade", 120 "structures/sele_wallset_stone" 121 122 ], 117 123 "StartEntities": 118 124 [ 119 125 { -
binaries/data/mods/public/simulation/data/civs/spart.json
105 105 "Special":"Train heroes and Spartiates and research technologies related to them." 106 106 } 107 107 ], 108 "WallSets": 109 [ 110 "other/wallset_palisade", 111 "structures/spart_wallset_stone" 112 113 ], 108 114 "StartEntities": 109 115 [ 110 116 { -
binaries/data/mods/public/simulation/templates/other/palisades_rocks_curve.xml
25 25 <VisualActor> 26 26 <Actor>props/special/palisade_rocks_curve.xml</Actor> 27 27 </VisualActor> 28 <WallPiece> 29 <Length>8.0</Length> 30 <Orientation>0.75</Orientation> 31 <Indent>2.8</Indent> 32 <Bend>0.5</Bend> 33 </WallPiece> 28 34 </Entity> -
binaries/data/mods/public/simulation/templates/other/palisades_rocks_end.xml
25 25 <VisualActor> 26 26 <Actor>props/special/palisade_rocks_end.xml</Actor> 27 27 </VisualActor> 28 <WallPiece> 29 <Length>0.8</Length> 30 <Orientation>1.5</Orientation> 31 </WallPiece> 28 32 </Entity> -
binaries/data/mods/public/simulation/templates/other/palisades_rocks_fort.xml
8 8 <Icon>structures/palisade_fort.png</Icon> 9 9 <Classes datatype="tokens">Palisade</Classes> 10 10 </Identity> 11 <WallPiece> 12 <Length>8.0</Length> 13 </WallPiece> 11 14 </Entity> -
binaries/data/mods/public/simulation/templates/other/palisades_rocks_long.xml
39 39 </VisualActor> 40 40 <TerritoryInfluence disable=""/> 41 41 <WallPiece> 42 <Length>1 1.0</Length>42 <Length>14.0</Length> 43 43 </WallPiece> 44 44 </Entity> -
binaries/data/mods/public/simulation/templates/other/palisades_rocks_medium.xml
38 38 </VisualActor> 39 39 <TerritoryInfluence disable=""/> 40 40 <WallPiece> 41 <Length> 8.0</Length>41 <Length>9.2</Length> 42 42 </WallPiece> 43 43 </Entity> -
binaries/data/mods/public/simulation/templates/other/palisades_rocks_short.xml
37 37 <FoundationActor>structures/fndn_1x1pal.xml</FoundationActor> 38 38 </VisualActor> 39 39 <WallPiece> 40 <Length>4. 0</Length>40 <Length>4.8</Length> 41 41 </WallPiece> 42 42 </Entity> -
binaries/data/mods/public/simulation/templates/other/wallset_palisade.xml
13 13 <Templates> 14 14 <Tower>other/palisades_rocks_tower</Tower> 15 15 <Gate>other/palisades_rocks_gate</Gate> 16 <Fort>other/palisades_rocks_fort</Fort> 16 17 <WallLong>other/palisades_rocks_long</WallLong> 17 18 <WallMedium>other/palisades_rocks_medium</WallMedium> 18 19 <WallShort>other/palisades_rocks_short</WallShort> 20 <WallCurveQuarter>other/palisades_rocks_curve</WallCurveQuarter> 21 <WallEnd>other/palisades_rocks_end</WallEnd> 19 22 </Templates> 20 23 </WallSet> 21 24 </Entity> -
binaries/data/mods/public/simulation/templates/structures/athen_fortress.xml
25 25 <VisualActor> 26 26 <Actor>structures/athenians/fortress_up.xml</Actor> 27 27 </VisualActor> 28 <WallPiece> 29 <Length>24.0</Length> 30 <Indent>7.6</Indent> 31 </WallPiece> 28 32 </Entity> -
binaries/data/mods/public/simulation/templates/structures/athen_wall_gate.xml
20 20 <Actor>structures/hellenes/wall_gate.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>3 8.0</Length>23 <Length>35.4</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/athen_wall_long.xml
17 17 <Actor>structures/hellenes/wall_long.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>3 7.0</Length>20 <Length>36.2</Length> 21 21 </WallPiece> 22 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/athen_wall_medium.xml
17 17 <Actor>structures/hellenes/wall_medium.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>24. 0</Length>20 <Length>24.2</Length> 21 21 </WallPiece> 22 </Entity> 23 No newline at end of file 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/athen_wall_short.xml
17 17 <Actor>structures/hellenes/wall_short.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>1 3.0</Length>20 <Length>12.3</Length> 21 21 </WallPiece> 22 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/athen_wall_tower.xml
16 16 <Actor>structures/hellenes/wall_tower.xml</Actor> 17 17 </VisualActor> 18 18 <WallPiece> 19 <Length>7. 5</Length>19 <Length>7.1</Length> 20 20 </WallPiece> 21 </Entity> 22 No newline at end of file 21 </Entity> -
binaries/data/mods/public/simulation/templates/structures/brit_fortress.xml
54 54 <Actor>structures/britons/fortress_briton.xml</Actor> 55 55 <FoundationActor>structures/fndn_5x5.xml</FoundationActor> 56 56 </VisualActor> 57 <WallPiece> 58 <Length>28</Length> 59 </WallPiece> 57 60 </Entity> -
binaries/data/mods/public/simulation/templates/structures/brit_wall_gate.xml
27 27 <Actor>structures/celts/wall_gate.xml</Actor> 28 28 </VisualActor> 29 29 <WallPiece> 30 <Length> 25.0</Length>30 <Length>37.0</Length> 31 31 </WallPiece> 32 32 </Entity> -
binaries/data/mods/public/simulation/templates/structures/brit_wall_long.xml
36 36 <Actor>structures/celts/wall_long.xml</Actor> 37 37 </VisualActor> 38 38 <WallPiece> 39 <Length>3 7.0</Length>39 <Length>36.6</Length> 40 40 </WallPiece> 41 41 </Entity> -
binaries/data/mods/public/simulation/templates/structures/brit_wall_medium.xml
33 33 <Actor>structures/celts/wall_medium.xml</Actor> 34 34 </VisualActor> 35 35 <WallPiece> 36 <Length>2 5.0</Length>36 <Length>24.6</Length> 37 37 </WallPiece> 38 38 </Entity> -
binaries/data/mods/public/simulation/templates/structures/brit_wall_short.xml
20 20 <Actor>structures/celts/wall_short.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>1 3.0</Length>23 <Length>12.5</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/brit_wall_tower.xml
20 20 <Actor>structures/celts/wall_tower.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length> 9.0</Length>23 <Length>8.7</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/cart_fortress.xml
31 31 <VisualActor> 32 32 <Actor>structures/carthaginians/fortress.xml</Actor> 33 33 </VisualActor> 34 <WallPiece> 35 <Length>25.0</Length> 36 <Indent>6.4</Indent> 37 </WallPiece> 34 38 </Entity> -
binaries/data/mods/public/simulation/templates/structures/cart_wall_gate.xml
20 20 <Actor>structures/carthaginians/wall_gate.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length> 25.0</Length>23 <Length>43.8</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/cart_wall_long.xml
36 36 <Actor>structures/carthaginians/wall_long.xml</Actor> 37 37 </VisualActor> 38 38 <WallPiece> 39 <Length>4 6.0</Length>39 <Length>43.7</Length> 40 40 </WallPiece> 41 41 </Entity> -
binaries/data/mods/public/simulation/templates/structures/cart_wall_medium.xml
30 30 <Actor>structures/carthaginians/wall_medium.xml</Actor> 31 31 </VisualActor> 32 32 <WallPiece> 33 <Length> 30.0</Length>33 <Length>29.3</Length> 34 34 </WallPiece> 35 35 </Entity> -
binaries/data/mods/public/simulation/templates/structures/cart_wall_short.xml
17 17 <Actor>structures/carthaginians/wall_short.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>1 6.0</Length>20 <Length>14.7</Length> 21 21 </WallPiece> 22 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/cart_wall_tower.xml
20 20 <FoundationActor>structures/fndn_3x3.xml</FoundationActor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>11. 0</Length>23 <Length>11.8</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/gaul_fortress.xml
34 34 <VisualActor> 35 35 <Actor>structures/gauls/fortress_gallic.xml</Actor> 36 36 </VisualActor> 37 <WallPiece> 38 <Length>16.8</Length> 39 <Indent>5.8</Indent> 40 </WallPiece> 37 41 </Entity> -
binaries/data/mods/public/simulation/templates/structures/gaul_wall_gate.xml
27 27 <Actor>structures/celts/wall_gate.xml</Actor> 28 28 </VisualActor> 29 29 <WallPiece> 30 <Length> 25.0</Length>30 <Length>37.0</Length> 31 31 </WallPiece> 32 32 </Entity> -
binaries/data/mods/public/simulation/templates/structures/gaul_wall_long.xml
36 36 <Actor>structures/celts/wall_long.xml</Actor> 37 37 </VisualActor> 38 38 <WallPiece> 39 <Length>3 7.0</Length>39 <Length>36.6</Length> 40 40 </WallPiece> 41 41 </Entity> -
binaries/data/mods/public/simulation/templates/structures/gaul_wall_medium.xml
33 33 <Actor>structures/celts/wall_medium.xml</Actor> 34 34 </VisualActor> 35 35 <WallPiece> 36 <Length>2 5.0</Length>36 <Length>24.6</Length> 37 37 </WallPiece> 38 38 </Entity> -
binaries/data/mods/public/simulation/templates/structures/gaul_wall_short.xml
20 20 <Actor>structures/celts/wall_short.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>1 3.0</Length>23 <Length>12.6</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/gaul_wall_tower.xml
20 20 <Actor>structures/celts/wall_tower.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length> 9.0</Length>23 <Length>8.7</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/iber_fortress.xml
37 37 <VisualActor> 38 38 <Actor>structures/iberians/fortress.xml</Actor> 39 39 </VisualActor> 40 <WallPiece> 41 <Length>24.5</Length> 42 </WallPiece> 40 43 </Entity> -
binaries/data/mods/public/simulation/templates/structures/iber_wall_long.xml
36 36 <Actor>structures/iberians/wall_long.xml</Actor> 37 37 </VisualActor> 38 38 <WallPiece> 39 <Length>36. 0</Length>39 <Length>36.4</Length> 40 40 </WallPiece> 41 41 </Entity> -
binaries/data/mods/public/simulation/templates/structures/iber_wall_medium.xml
33 33 <Actor>structures/iberians/wall_medium.xml</Actor> 34 34 </VisualActor> 35 35 <WallPiece> 36 <Length>24. 0</Length>36 <Length>24.4</Length> 37 37 </WallPiece> 38 38 </Entity> -
binaries/data/mods/public/simulation/templates/structures/iber_wall_short.xml
20 20 <Actor>structures/iberians/wall_short.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>12. 0</Length>23 <Length>12.4</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/iber_wall_tower.xml
21 21 <Actor>structures/iberians/wall_tower.xml</Actor> 22 22 </VisualActor> 23 23 <WallPiece> 24 <Length>10 </Length>24 <Length>10.8</Length> 25 25 </WallPiece> 26 26 </Entity> -
binaries/data/mods/public/simulation/templates/structures/mace_fortress.xml
40 40 <VisualActor> 41 41 <Actor>structures/macedonians/fortress_up.xml</Actor> 42 42 </VisualActor> 43 <WallPiece> 44 <Length>24.0</Length> 45 <Indent>7.6</Indent> 46 </WallPiece> 43 47 </Entity> -
binaries/data/mods/public/simulation/templates/structures/mace_wall_gate.xml
20 20 <Actor>structures/hellenes/wall_gate.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>3 8.0</Length>23 <Length>35.4</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/mace_wall_long.xml
17 17 <Actor>structures/hellenes/wall_long.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>3 7.0</Length>20 <Length>36.2</Length> 21 21 </WallPiece> 22 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/mace_wall_medium.xml
17 17 <Actor>structures/hellenes/wall_medium.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>24. 0</Length>20 <Length>24.2</Length> 21 21 </WallPiece> 22 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/mace_wall_short.xml
17 17 <Actor>structures/hellenes/wall_short.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>1 3.0</Length>20 <Length>12.3</Length> 21 21 </WallPiece> 22 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/mace_wall_tower.xml
16 16 <Actor>structures/hellenes/wall_tower.xml</Actor> 17 17 </VisualActor> 18 18 <WallPiece> 19 <Length>7. 5</Length>19 <Length>7.1</Length> 20 20 </WallPiece> 21 </Entity> 22 No newline at end of file 21 </Entity> -
binaries/data/mods/public/simulation/templates/structures/maur_fortress.xml
28 28 <VisualActor> 29 29 <Actor>structures/mauryans/fortress.xml</Actor> 30 30 </VisualActor> 31 <WallPiece> 32 <Length>22.0</Length> 33 </WallPiece> 31 34 </Entity> -
binaries/data/mods/public/simulation/templates/structures/maur_wall_gate.xml
20 20 <Actor>structures/mauryans/wall_gate.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>3 7.0</Length>23 <Length>36.7</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/maur_wall_long.xml
42 42 <Actor>structures/mauryans/wall_long.xml</Actor> 43 43 </VisualActor> 44 44 <WallPiece> 45 <Length>3 5.0</Length>45 <Length>36.6</Length> 46 46 </WallPiece> 47 47 </Entity> -
binaries/data/mods/public/simulation/templates/structures/maur_wall_medium.xml
36 36 <Actor>structures/mauryans/wall_medium.xml</Actor> 37 37 </VisualActor> 38 38 <WallPiece> 39 <Length>24. 0</Length>39 <Length>24.4</Length> 40 40 </WallPiece> 41 41 </Entity> -
binaries/data/mods/public/simulation/templates/structures/maur_wall_short.xml
23 23 <Actor>structures/mauryans/wall_short.xml</Actor> 24 24 </VisualActor> 25 25 <WallPiece> 26 <Length>1 3.0</Length>26 <Length>12.4</Length> 27 27 </WallPiece> 28 28 </Entity> -
binaries/data/mods/public/simulation/templates/structures/maur_wall_tower.xml
25 25 <Actor>structures/mauryans/wall_tower.xml</Actor> 26 26 </VisualActor> 27 27 <WallPiece> 28 <Length> 9.5</Length>28 <Length>7.8</Length> 29 29 </WallPiece> 30 30 </Entity> -
binaries/data/mods/public/simulation/templates/structures/pers_fortress.xml
20 20 <VisualActor> 21 21 <Actor>structures/persians/fortress.xml</Actor> 22 22 </VisualActor> 23 <WallPiece> 24 <Length>24.5</Length> 25 <Indent>7.6</Indent> 26 </WallPiece> 23 27 </Entity> -
binaries/data/mods/public/simulation/templates/structures/pers_wall_tower.xml
16 16 <Actor>structures/persians/wall_tower.xml</Actor> 17 17 </VisualActor> 18 18 <WallPiece> 19 <Length> 8.5</Length>19 <Length>7.5</Length> 20 20 </WallPiece> 21 21 </Entity> -
binaries/data/mods/public/simulation/templates/structures/ptol_fortress.xml
31 31 <VisualActor> 32 32 <Actor>structures/ptolemies/fortress.xml</Actor> 33 33 </VisualActor> 34 <WallPiece> 35 <Length>24.0</Length> 36 <Indent>8.7</Indent> 37 </WallPiece> 34 38 </Entity> -
binaries/data/mods/public/simulation/templates/structures/ptol_wall_gate.xml
20 20 <Actor>structures/ptolemies/wall_gate.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>38. 0</Length>23 <Length>38.8</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/ptol_wall_medium.xml
30 30 <Actor>structures/ptolemies/wall_medium.xml</Actor> 31 31 </VisualActor> 32 32 <WallPiece> 33 <Length>2 6.0</Length>33 <Length>25.0</Length> 34 34 </WallPiece> 35 35 </Entity> -
binaries/data/mods/public/simulation/templates/structures/ptol_wall_short.xml
17 17 <Actor>structures/ptolemies/wall_short.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>1 4.0</Length>20 <Length>16.0</Length> 21 21 </WallPiece> 22 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/ptol_wall_tower.xml
16 16 <Actor>structures/ptolemies/wall_tower.xml</Actor> 17 17 </VisualActor> 18 18 <WallPiece> 19 <Length> 10</Length>19 <Length>9.0</Length> 20 20 </WallPiece> 21 </Entity> 22 No newline at end of file 21 </Entity> -
binaries/data/mods/public/simulation/templates/structures/ptol_wallset_stone.xml
14 14 <WallShort>structures/ptol_wall_short</WallShort> 15 15 </Templates> 16 16 <MaxTowerOverlap>0.90</MaxTowerOverlap> 17 <MinTowerOverlap>0. 05</MinTowerOverlap>17 <MinTowerOverlap>0.10</MinTowerOverlap> 18 18 </WallSet> 19 19 </Entity> -
binaries/data/mods/public/simulation/templates/structures/rome_army_camp.xml
101 101 <Actor>structures/romans/camp.xml</Actor> 102 102 <FoundationActor>structures/fndn_8x8.xml</FoundationActor> 103 103 </VisualActor> 104 <WallPiece> 105 <Length>29.5</Length> 106 <Indent>8</Indent> 107 </WallPiece> 104 108 </Entity> -
binaries/data/mods/public/simulation/templates/structures/rome_fortress.xml
23 23 <VisualActor> 24 24 <Actor>structures/romans/fortress.xml</Actor> 25 25 </VisualActor> 26 <WallPiece> 27 <Length>25.0</Length> 28 <Indent>8.4</Indent> 29 </WallPiece> 26 30 </Entity> -
binaries/data/mods/public/simulation/templates/structures/rome_siege_wall_tower.xml
43 43 <Actor>structures/romans/siege_wall_tower.xml</Actor> 44 44 </VisualActor> 45 45 <WallPiece> 46 <Length> 6.0</Length>46 <Length>5.5</Length> 47 47 </WallPiece> 48 48 </Entity> -
binaries/data/mods/public/simulation/templates/structures/rome_wall_gate.xml
20 20 <Actor>structures/romans/wall_gate.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>3 7.0</Length>23 <Length>36.8</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/rome_wall_long.xml
36 36 <Actor>structures/romans/wall_long.xml</Actor> 37 37 </VisualActor> 38 38 <WallPiece> 39 <Length>3 7.0</Length>39 <Length>36.8</Length> 40 40 </WallPiece> 41 41 </Entity> -
binaries/data/mods/public/simulation/templates/structures/rome_wall_medium.xml
33 33 <Actor>structures/romans/wall_medium.xml</Actor> 34 34 </VisualActor> 35 35 <WallPiece> 36 <Length>2 5.0</Length>36 <Length>24.8</Length> 37 37 </WallPiece> 38 38 </Entity> -
binaries/data/mods/public/simulation/templates/structures/rome_wall_short.xml
20 20 <Actor>structures/romans/wall_short.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>1 3.0</Length>23 <Length>12.9</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/rome_wall_tower.xml
16 16 <Actor>structures/romans/wall_tower.xml</Actor> 17 17 </VisualActor> 18 18 <WallPiece> 19 <Length> 9.5</Length>19 <Length>10</Length> 20 20 </WallPiece> 21 21 </Entity> -
binaries/data/mods/public/simulation/templates/structures/rome_wallset_siege.xml
13 13 <Templates> 14 14 <Tower>structures/rome_siege_wall_tower</Tower> 15 15 <Gate>structures/rome_siege_wall_gate</Gate> 16 <Fort>structures/rome_army_camp</Fort> 16 17 <WallLong>structures/rome_siege_wall_long</WallLong> 17 18 <WallMedium>structures/rome_siege_wall_medium</WallMedium> 18 19 <WallShort>structures/rome_siege_wall_short</WallShort> -
binaries/data/mods/public/simulation/templates/structures/sele_fortress.xml
34 34 <VisualActor> 35 35 <Actor>structures/seleucids/fortress.xml</Actor> 36 36 </VisualActor> 37 <WallPiece> 38 <Length>23</Length> 39 <Indent>7.8</Indent> 40 </WallPiece> 37 41 </Entity> -
binaries/data/mods/public/simulation/templates/structures/sele_wall_gate.xml
20 20 <Actor>structures/hellenes/wall_gate.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>3 8.0</Length>23 <Length>35.4</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/sele_wall_long.xml
17 17 <Actor>structures/hellenes/wall_long.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>3 7.0</Length>20 <Length>36.2</Length> 21 21 </WallPiece> 22 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/sele_wall_medium.xml
17 17 <Actor>structures/hellenes/wall_medium.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>24. 0</Length>20 <Length>24.2</Length> 21 21 </WallPiece> 22 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/sele_wall_short.xml
17 17 <Actor>structures/hellenes/wall_short.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>1 3.0</Length>20 <Length>12.3</Length> 21 21 </WallPiece> 22 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/sele_wall_tower.xml
16 16 <Actor>structures/hellenes/wall_tower.xml</Actor> 17 17 </VisualActor> 18 18 <WallPiece> 19 <Length>7. 5</Length>19 <Length>7.1</Length> 20 20 </WallPiece> 21 </Entity> 22 No newline at end of file 21 </Entity> -
binaries/data/mods/public/simulation/templates/structures/spart_fortress.xml
25 25 <VisualActor> 26 26 <Actor>structures/spartans/fortress_up.xml</Actor> 27 27 </VisualActor> 28 <WallPiece> 29 <Length>24.0</Length> 30 <Indent>7.6</Indent> 31 </WallPiece> 28 32 </Entity> -
binaries/data/mods/public/simulation/templates/structures/spart_wall_gate.xml
20 20 <Actor>structures/hellenes/wall_gate.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>3 8.0</Length>23 <Length>35.4</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/spart_wall_long.xml
17 17 <Actor>structures/hellenes/wall_long.xml</Actor> 18 18 </VisualActor> 19 19 <WallPiece> 20 <Length>3 7.0</Length>20 <Length>36.2</Length> 21 21 </WallPiece> 22 22 </Entity> -
binaries/data/mods/public/simulation/templates/structures/spart_wall_medium.xml
20 20 <Actor>structures/hellenes/wall_medium.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>24. 0</Length>23 <Length>24.2</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/spart_wall_short.xml
20 20 <Actor>structures/hellenes/wall_short.xml</Actor> 21 21 </VisualActor> 22 22 <WallPiece> 23 <Length>1 3.0</Length>23 <Length>12.3</Length> 24 24 </WallPiece> 25 25 </Entity> -
binaries/data/mods/public/simulation/templates/structures/spart_wall_tower.xml
16 16 <Actor>structures/hellenes/wall_tower.xml</Actor> 17 17 </VisualActor> 18 18 <WallPiece> 19 <Length>7. 5</Length>19 <Length>7.1</Length> 20 20 </WallPiece> 21 </Entity> 22 No newline at end of file 21 </Entity>