Ticket #2944: gen_wall_builder2015-8-16b.patch
File gen_wall_builder2015-8-16b.patch, 133.6 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
21 21 // Heightmap functionality 22 22 ////////// 23 23 24 // Some general heightmap settings25 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 24 // Add random heightmap generation functionality 29 25 function getRandomReliefmap(minHeight, maxHeight) 30 26 { … … 35 31 if (maxHeight > MAX_HEIGHT) 36 32 warn("getRandomReliefmap: Argument maxHeight is smaler then the supported maximum height of " + MAX_HEIGHT + " (const MAX_HEIGHT): " + maxHeight) 37 33 var reliefmap = []; 38 for (var x = 0; x <= mapSize; x++)34 for (var x = 0; x <= mapSize; ++x) 39 35 { 40 36 reliefmap.push([]); 41 for (var y = 0; y <= mapSize; y++)37 for (var y = 0; y <= mapSize; ++y) 42 38 { 43 39 reliefmap[x].push(randFloat(minHeight, maxHeight)); 44 40 } … … 50 46 function setReliefmap(reliefmap) 51 47 { 52 48 // g_Map.height = reliefmap; 53 for (var x = 0; x <= mapSize; x++)49 for (var x = 0; x <= mapSize; ++x) 54 50 { 55 for (var y = 0; y <= mapSize; y++)51 for (var y = 0; y <= mapSize; ++y) 56 52 { 57 53 setHeight(x, y, reliefmap[x][y]); 58 54 } … … 65 61 var height = {}; 66 62 height.min = Infinity; 67 63 height.max = -Infinity; 68 for (var x = 0; x <= mapSize; x++)64 for (var x = 0; x <= mapSize; ++x) 69 65 { 70 for (var y = 0; y <= mapSize; y++)66 for (var y = 0; y <= mapSize; ++y) 71 67 { 72 68 if (reliefmap[x][y] < height.min) 73 69 height.min = reliefmap[x][y]; … … 89 85 if (maxHeight > MAX_HEIGHT) 90 86 warn("getRescaledReliefmap: Argument maxHeight is smaler then the supported maximum height of " + MAX_HEIGHT + " (const MAX_HEIGHT): " + maxHeight) 91 87 var oldHeightRange = getMinAndMaxHeight(reliefmap); 92 for (var x = 0; x <= mapSize; x++)88 for (var x = 0; x <= mapSize; ++x) 93 89 { 94 for (var y = 0; y <= mapSize; y++)90 for (var y = 0; y <= mapSize; ++y) 95 91 { 96 92 newReliefmap[x][y] = minHeight + (reliefmap[x][y] - oldHeightRange.min) / (oldHeightRange.max - oldHeightRange.min) * (maxHeight - minHeight); 97 93 } … … 105 101 var newReliefmap = deepcopy(reliefmap); 106 102 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 103 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++)104 for (var x = 0; x <= mapSize; ++x) 109 105 { 110 for (var y = 0; y <= mapSize; y++)106 for (var y = 0; y <= mapSize; ++y) 111 107 { 112 108 var div = 0; 113 for (var i = 0; i < map.length; i++)109 for (var i = 0; i < map.length; ++i) 114 110 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 111 } 116 112 } … … 173 169 "temp_grass_long|gaia/flora_tree_apple", "temp_grass_clovers|gaia/flora_bush_berry", "temp_grass_clovers_2|gaia/flora_bush_grapes", 174 170 "temp_grass_plants|gaia/fauna_deer", "temp_grass_long_b|gaia/fauna_rabbit"]; 175 171 var numTerreins = terreins.length; 176 for (var i = 0; i < numTerreins; i++)172 for (var i = 0; i < numTerreins; ++i) 177 173 terreins.push("temp_grass_plants"); 178 174 textueByHeight.push({"upperHeightLimit": waterHeightAdjusted + 5/6 * (heightRange.max - waterHeightAdjusted), "terrain": terreins}); 179 175 // Unpassable woods … … 200 196 var tries = 0; 201 197 while (!goodStartPositionsFound) 202 198 { 203 tries++;199 ++tries; 204 200 log("Starting giant while loop try " + tries); 205 201 // Generate reliefmap 206 202 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)203 for (var i = 0; i < 50 + mapSize/4; ++i) // Cycles depend on mapsize (more cycles -> bigger structures) 208 204 myReliefmap = getHeightErrosionedReliefmap(myReliefmap, 1); 209 205 myReliefmap = getRescaledReliefmap(myReliefmap, heightRange.min, heightRange.max); 210 206 setReliefmap(myReliefmap); … … 217 213 var lowerHeightLimit = textueByHeight[3].upperHeightLimit; 218 214 var upperHeightLimit = textueByHeight[6].upperHeightLimit; 219 215 // Check for valid points by height 220 for (var x = distToBorder + minTerrainDistToBorder; x < mapSize - distToBorder - minTerrainDistToBorder; x++)216 for (var x = distToBorder + minTerrainDistToBorder; x < mapSize - distToBorder - minTerrainDistToBorder; ++x) 221 217 { 222 for (var y = distToBorder + minTerrainDistToBorder; y < mapSize - distToBorder - minTerrainDistToBorder; y++)218 for (var y = distToBorder + minTerrainDistToBorder; y < mapSize - distToBorder - minTerrainDistToBorder; ++y) 223 219 { 224 220 var actualHeight = getHeight(x, y); 225 221 if (actualHeight > lowerHeightLimit && actualHeight < upperHeightLimit) 226 222 { 227 223 // Check for points within a valid area by height (rectangular since faster) 228 224 var isPossible = true; 229 for (var offX = - neededDistance; offX <= neededDistance; offX++)225 for (var offX = - neededDistance; offX <= neededDistance; ++offX) 230 226 { 231 for (var offY = - neededDistance; offY <= neededDistance; offY++)227 for (var offY = - neededDistance; offY <= neededDistance; ++offY) 232 228 { 233 229 var testHeight = getHeight(x + offX, y + offY); 234 230 if (testHeight <= lowerHeightLimit || testHeight >= upperHeightLimit) … … 252 248 // Reduce to tiles in a circle of mapSize / 2 distance to the center (to avoid players placed in corners) 253 249 var possibleStartPositionsTemp = []; 254 250 var maxDistToCenter = mapSize / 2; 255 for (var i = 0; i < possibleStartPositions.length; i++)251 for (var i = 0; i < possibleStartPositions.length; ++i) 256 252 { 257 253 var deltaX = possibleStartPositions[i][0] - mapSize / 2; 258 254 var deltaY = possibleStartPositions[i][1] - mapSize / 2; … … 270 266 var maxDistToResources = distToBorder; // Has to be <= distToBorder! 271 267 var minNumLowTiles = 10; 272 268 var minNumHighTiles = 10; 273 for (var i = 0; i < possibleStartPositions.length; i++)269 for (var i = 0; i < possibleStartPositions.length; ++i) 274 270 { 275 271 var numLowTiles = 0; 276 272 var numHighTiles = 0; 277 for (var dx = - maxDistToResources; dx < maxDistToResources; dx++)273 for (var dx = - maxDistToResources; dx < maxDistToResources; ++dx) 278 274 { 279 for (var dy = - maxDistToResources; dy < maxDistToResources; dy++)275 for (var dy = - maxDistToResources; dy < maxDistToResources; ++dy) 280 276 { 281 277 var testHeight = getHeight(possibleStartPositions[i][0] + dx, possibleStartPositions[i][1] + dy); 282 278 if (testHeight < lowerHeightLimit) 283 numLowTiles++;279 ++numLowTiles; 284 280 if (testHeight > upperHeightLimit) 285 numHighTiles++;281 ++numHighTiles; 286 282 if (numLowTiles > minNumLowTiles && numHighTiles > minNumHighTiles) 287 283 break; 288 284 } … … 311 307 // Get some random start location derivations. NOTE: Itterating over all possible derivations is just to much (valid points ** numPlayers) 312 308 var maxTries = 100000; // floor(800000 / (Math.pow(numPlayers, 2) / 2)); 313 309 var possibleDerivations = []; 314 for (var i = 0; i < maxTries; i++)310 for (var i = 0; i < maxTries; ++i) 315 311 { 316 312 var vector = []; 317 for (var p = 0; p < numPlayers; p++)313 for (var p = 0; p < numPlayers; ++p) 318 314 vector.push(randInt(possibleStartPositions.length)); 319 315 possibleDerivations.push(vector); 320 316 } 321 317 322 318 // Choose the start location derivation with the greatest minimum distance between players 323 319 var maxMinDist = 0; 324 for (var d = 0; d < possibleDerivations.length; d++)320 for (var d = 0; d < possibleDerivations.length; ++d) 325 321 { 326 322 var minDist = 2 * mapSize; 327 for (var p1 = 0; p1 < numPlayers - 1; p1++)323 for (var p1 = 0; p1 < numPlayers - 1; ++p1) 328 324 { 329 for (var p2 = p1 + 1; p2 < numPlayers; p2++)325 for (var p2 = p1 + 1; p2 < numPlayers; ++p2) 330 326 { 331 327 if (p1 != p2) 332 328 { … … 372 368 propDensity = 1/4; 373 369 else if (mapSize > 400) 374 370 propDensity = 3/4; 375 for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; x++)371 for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; ++x) 376 372 { 377 for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; y++)373 for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; ++y) 378 374 { 379 375 var textureMinHeight = heightRange.min; 380 for (var i = 0; i < textueByHeight.length; i++)376 for (var i = 0; i < textueByHeight.length; ++i) 381 377 { 382 378 if (getHeight(x, y) >= textureMinHeight && getHeight(x, y) <= textueByHeight[i].upperHeightLimit) 383 379 { … … 497 493 // Place players and start resources 498 494 //////// 499 495 500 for (var p = 0; p < numPlayers; p++)496 for (var p = 0; p < numPlayers; ++p) 501 497 { 502 498 var actualX = possibleStartPositions[bestDerivation[p]][0]; 503 499 var actualY = possibleStartPositions[bestDerivation[p]][1]; … … 509 505 { 510 506 var uAngle = BUILDING_ANGlE - PI * (2-j) / 2; 511 507 var count = 4; 512 for (var numberofentities = 0; numberofentities < count; numberofentities++)508 for (var numberofentities = 0; numberofentities < count; ++numberofentities) 513 509 { 514 510 var ux = actualX + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); 515 511 var uz = actualY + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); … … 531 527 // Calculate progress percentage with the time checks 532 528 var generationTime = timeArray[timeArray.length - 1] - timeArray[0]; 533 529 log("Total generation time (ms): " + generationTime); 534 for (var i = 0; i < timeArray.length; i++)530 for (var i = 0; i < timeArray.length; ++i) 535 531 { 536 532 var timeSinceStart = timeArray[i] - timeArray[0]; 537 533 var progressPercentage = 100 * timeSinceStart / generationTime; -
binaries/data/mods/public/maps/random/rmgen/library.js
1 2 1 ///////////////////////////////////////////////////////////////////////////////////////////// 3 2 // Constant definitions 4 3 ///////////////////////////////////////////////////////////////////////////////////////////// 5 4 6 5 const PI = Math.PI; 7 const TWO_PI = 2 * Math.PI; 6 const TWO_PI = 2 * Math.PI; // mathematically known as 'tau' 8 7 const TERRAIN_SEPARATOR = "|"; 9 const SEA_LEVEL = 20.0;8 const SEA_LEVEL = 160.0; 10 9 const CELL_SIZE = 4; 11 10 const HEIGHT_UNITS_PER_METRE = 92; 12 11 const MIN_MAP_SIZE = 128; 13 12 const MAX_MAP_SIZE = 512; 14 13 const FALLBACK_CIV = "athen"; 14 // Constants needed for heightmap_manipulation.js 15 const MAX_HEIGHT_RANGE = 0xFFFF / HEIGHT_UNITS_PER_METRE // Engine limit, Roughly 700 meters 16 const MIN_HEIGHT = - SEA_LEVEL; 17 const MAX_HEIGHT = MAX_HEIGHT_RANGE - SEA_LEVEL; 18 // Entity template structure keys that might change, for easier mod support 19 const STARTING_ENTITY_KEY = "StartEntities"; 20 const START_ENTITY_TEMPLATE_PATH_KEY = "Template" 21 const BUILDER_TEMPLATEPATH_KEYS = ["Builder", "Entities", "_string"]; 22 const PRODUCTION_TEMPLATEPATH_KEYS = ["ProductionQueue", "Entities", "_string"]; 23 const CIV_PLACEHOLDER_STRING = "{civ}"; 15 24 16 25 ///////////////////////////////////////////////////////////////////////////////////////////// 17 26 // Utility functions … … 103 112 if (numArgs != 1) 104 113 { 105 114 var ret = new Array(numArgs); 106 for (var i=0; i < numArgs; i++)115 for (var i=0; i < numArgs; ++i) 107 116 { 108 117 ret[i] = x[i]; 109 118 } … … 132 141 return []; 133 142 134 143 var result = [source[0]]; 135 for (var i = 1; i < source.length; i++)144 for (var i = 1; i < source.length; ++i) 136 145 { 137 146 var j = randInt(0, i); 138 147 result[i] = result[j]; … … 172 181 var area = g_Map.createArea(centeredPlacer, painter, constraint); 173 182 if (area !== undefined) 174 183 { 175 good++;184 ++good; 176 185 result.push(area); 177 186 } 178 187 else 179 188 { 180 bad++;189 ++bad; 181 190 } 182 191 } 183 192 return result; … … 208 217 var area = g_Map.createArea(centeredPlacer, painter, constraint); 209 218 if (area !== undefined) 210 219 { 211 good++;220 ++good; 212 221 result.push(area); 213 222 } 214 223 else 215 224 { 216 bad++;225 ++bad; 217 226 } 218 227 } 219 228 return result; … … 248 257 var result = createObjectGroup(placer, player, constraint); 249 258 if (result !== undefined) 250 259 { 251 good++;260 ++good; 252 261 } 253 262 else 254 263 { 255 bad++;264 ++bad; 256 265 } 257 266 } 258 267 return good; … … 282 291 var result = createObjectGroup(placer, player, constraint); 283 292 if (result !== undefined) 284 293 { 285 good++;294 ++good; 286 295 } 287 296 else 288 297 { 289 bad++;298 ++bad; 290 299 } 291 300 } 292 301 return good; … … 394 403 return g_MapSettings.PlayerData.length - 1; 395 404 } 396 405 406 // Takes nothing, returns an array of strings representing all available civilizations 407 function getCivList() 408 { 409 var raw_civData = RMS.GetCivData(); 410 var civList = []; 411 for (var i = 0; i < raw_civData.length; ++i) 412 civList.push(JSON.parse(raw_civData[i]).Code); 413 414 return civList; 415 } 416 417 // 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) 418 function getFullCivData() 419 { 420 var rawCivData = RMS.GetCivData(); 421 var unpackedCivData = {}; 422 for (var i = 0; i < rawCivData.length; ++i) 423 { 424 var singleCivData = JSON.parse(rawCivData[i]); 425 unpackedCivData[singleCivData.Code] = singleCivData; 426 } 427 428 return unpackedCivData; 429 } 430 431 // Takes a player number (0-7, so Gaia excluded). Returns this players civ string 432 // ToDo: If the player number is to high an error will occur (and the fallback won't be reached)! 397 433 function getCivCode(player) 398 434 { 399 435 if (g_MapSettings.PlayerData[player+1].Civ) 400 436 return g_MapSettings.PlayerData[player+1].Civ; 401 437 402 warn(" undefined civ specified for player " + (player + 1) + ", falling back to '" + FALLBACK_CIV + "'");438 warn("Undefined civ specified for player " + (player + 1) + ", falling back to '" + FALLBACK_CIV + "'"); 403 439 return FALLBACK_CIV; 404 440 } 405 441 442 // Takes an entity path and a key list to get the templates value 443 function getTemplateValue(entPath, key_list) 444 { 445 var subdata = RMS.GetTemplate(entPath); 446 for (var i = 0; i < key_list.length; ++i) 447 { 448 if (!subdata.key_list[i]) 449 {return false}; 450 subdata = subdata[key_list[i]]; 451 } 452 return subdata; 453 } 454 455 // Returns a list of all templates paths available to the given civ 456 function getTempatePathList(civ) 457 { 458 var templatePaths = getFullCivData(); 459 if (!templatePaths.civ) 460 { 461 warn("getTempatePathList: Unknown civ '" + civ + "' not in " + Object.keys(templatePaths)); 462 return false; 463 } 464 templatePaths = templatePaths[civ]; 465 466 if (!templatePaths.STARTING_ENTITY_KEY) 467 { 468 warn("getTempatePathList: Civ has no starting entities as defined in STARTING_ENTITY_KEY (" + STARTING_ENTITY_KEY + "): " + Object.keys(templatePaths)); 469 return false; 470 } 471 templatePaths = templatePaths[STARTING_ENTITY_KEY]; 472 473 for (var i = 0; i < templatePaths.length; ++i) 474 { 475 if (!templatePaths[i].START_ENTITY_TEMPLATE_PATH_KEY) 476 { 477 warn("getTempatePathList: Starting entity list item has no template as defined in START_ENTITY_TEMPLATE_PATH_KEY (" + START_ENTITY_TEMPLATE_PATH_KEY + "): " + Object.keys(templatePaths)); 478 return false; 479 } 480 templatePaths[i] = templatePaths[i][START_ENTITY_TEMPLATE_PATH_KEY]; 481 } 482 var foundNew = 1; 483 while (foundNew > 0) 484 { 485 foundNew = 0; 486 var methods = [BUILDER_TEMPLATEPATH_KEYS, PRODUCTION_TEMPLATEPATH_KEYS]; 487 for (var m = 0; m < methods.length; ++m) 488 { 489 for (var t = 0; t < templatePaths.length; ++t) 490 { 491 var pathsToCheck = getTemplateValue(templatePaths[t], methods[m]); 492 if (typeof(pathsToCheck) === typeof("")) 493 { 494 pathsToCheck = pathsToCheck.split(/\s+/); 495 for (var c = 0; c < pathsToCheck.length; ++c) 496 { 497 var actualPath = pathsToCheck[c].replace(CIV_PLACEHOLDER_STRING, civ); 498 if (templatePaths.indexOf(actualPath) == -1 && RMS.TemplateExists(actualPath)) 499 { 500 templatePaths.push(actualPath); 501 ++foundNew; 502 } 503 } 504 } 505 } 506 } 507 } 508 return templatePaths; 509 } 510 406 511 function areAllies(player1, player2) 407 512 { 408 513 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 539 435 540 var result = new Array(0); 436 541 var team = new Array(5); 437 for (var q = 0; q < 5; q++)542 for (var q = 0; q < 5; ++q) 438 543 { 439 544 team[q] = new Array(1); 440 545 } 441 546 442 for (var i = -1; i < 4; i++)547 for (var i = -1; i < 4; ++i) 443 548 { 444 for (var j = 0; j < source.length; j++)549 for (var j = 0; j < source.length; ++j) 445 550 { 446 551 if (getPlayerTeam(j) == i) 447 552 { … … 461 566 462 567 var prime = new Array(source.length); 463 568 464 for (var i = 0; i < round(source.length/2); i++)569 for (var i = 0; i < round(source.length/2); ++i) 465 570 { 466 571 prime[2*i]=source[i]; 467 572 prime[2*i+1]=source[source.length-1-i]; … … 535 640 function avoidClasses(/*class1, dist1, class2, dist2, etc*/) 536 641 { 537 642 var ar = new Array(arguments.length/2); 538 for (var i = 0; i < arguments.length/2; i++)643 for (var i = 0; i < arguments.length/2; ++i) 539 644 { 540 645 ar[i] = new AvoidTileClassConstraint(arguments[2*i], arguments[2*i+1]); 541 646 } … … 555 660 function stayClasses(/*class1, dist1, class2, dist2, etc*/) 556 661 { 557 662 var ar = new Array(arguments.length/2); 558 for (var i = 0; i < arguments.length/2; i++)663 for (var i = 0; i < arguments.length/2; ++i) 559 664 { 560 665 ar[i] = new StayInTileClassConstraint(arguments[2*i], arguments[2*i+1]); 561 666 } … … 575 680 function borderClasses(/*class1, idist1, odist1, class2, idist2, odist2, etc*/) 576 681 { 577 682 var ar = new Array(arguments.length/3); 578 for (var i = 0; i < arguments.length/3; i++)683 for (var i = 0; i < arguments.length/3; ++i) 579 684 { 580 685 ar[i] = new BorderTileClassConstraint(arguments[3*i], arguments[3*i+1], arguments[3*i+2]); 581 686 } … … 642 747 { 643 748 return g_Map.getTexture(x, y); 644 749 } 645 -
binaries/data/mods/public/maps/random/rmgen/misc.js
20 20 var tchm = TILE_CENTERED_HEIGHT_MAP; 21 21 TILE_CENTERED_HEIGHT_MAP = true; 22 22 var mapSize = g_Map.size; 23 for (var ix = 0; ix < mapSize; ix++)23 for (var ix = 0; ix < mapSize; ++ix) 24 24 { 25 for (var iz = 0; iz < mapSize; iz++)25 for (var iz = 0; iz < mapSize; ++iz) 26 26 { 27 27 var a = z1-z2; 28 28 var b = x2-x1; … … 92 92 var rndRe = 0; 93 93 var rndRr = f-floor(f); 94 94 var rndRa = 0; 95 for (var rndRx=0; rndRx<=floor(f); rndRx++)95 for (var rndRx=0; rndRx<=floor(f); ++rndRx) 96 96 { 97 97 rndRw = 10*(rndRw-floor(rndRw)); 98 98 } … … 148 148 { 149 149 var uAngle = BUILDING_ANGlE - PI * (2-j) / 2; 150 150 var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1); 151 for (var numberofentities = 0; numberofentities < count; numberofentities++)151 for (var numberofentities = 0; numberofentities < count; ++numberofentities) 152 152 { 153 153 var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); 154 154 var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); … … 157 157 } 158 158 } 159 159 160 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 160 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 161 161 // placeCivDefaultEntities 162 162 // 163 163 // Creates the default starting player entities depending on the players civ 164 164 // fx&fy: position of player base 165 165 // playerid: id of player 166 166 // angle: angle of main base building, optional, default is BUILDING_ANGlE 167 // kwargs: Takes some optional keyword arguments to tweek things168 // 'iberWall': may be false, 'walls' (default) or 'towers'. Determines the defensive structures Iberians get as civ bonus167 // kwargs: Optional. Takes an associative array with keyword arguments to tweak things: 168 // Known keys: 'iberWall': may be false, 'walls' (default) or 'towers'. Determines the defensive structures Iberians get as civ bonus 169 169 // 170 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 170 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 171 171 function placeCivDefaultEntities(fx, fz, playerid, angle, kwargs) 172 172 { 173 173 // Unpack kwargs … … 187 187 { 188 188 var uAngle = angle - PI * (2-j) / 2; 189 189 var count = (civEntities[j].Count !== undefined ? civEntities[j].Count : 1); 190 for (var numberofentities = 0; numberofentities < count; numberofentities++)190 for (var numberofentities = 0; numberofentities < count; ++numberofentities) 191 191 { 192 192 var ux = fx + uDist * cos(uAngle) + numberofentities * uSpace * cos(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * cos(uAngle + PI/2)); 193 193 var uz = fz + uDist * sin(uAngle) + numberofentities * uSpace * sin(uAngle + PI/2) - (0.75 * uSpace * floor(count / 2) * sin(uAngle + PI/2)); … … 221 221 function paintTerrainBasedOnHeight(minheight, maxheight, mode, terrain) 222 222 { 223 223 var mSize = g_Map.size; 224 for (var qx = 0; qx < mSize; qx++)224 for (var qx = 0; qx < mSize; ++qx) 225 225 { 226 for (var qz = 0; qz < mSize; qz++)226 for (var qz = 0; qz < mSize; ++qz) 227 227 { 228 228 if (mode == 0) 229 229 { … … 273 273 function paintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass) 274 274 { 275 275 var mSize = g_Map.size; 276 for (var qx = 0; qx < mSize; qx++)276 for (var qx = 0; qx < mSize; ++qx) 277 277 { 278 for (var qz = 0; qz < mSize; qz++)278 for (var qz = 0; qz < mSize; ++qz) 279 279 { 280 280 if (mode == 0) 281 281 { … … 313 313 function unPaintTileClassBasedOnHeight(minheight, maxheight, mode, tileclass) 314 314 { 315 315 var mSize = g_Map.size; 316 for (var qx = 0; qx < mSize; qx++)316 for (var qx = 0; qx < mSize; ++qx) 317 317 { 318 for (var qz = 0; qz < mSize; qz++)318 for (var qz = 0; qz < mSize; ++qz) 319 319 { 320 320 if (mode == 0) 321 321 { … … 617 617 618 618 for (var ix = sx; ix <= lx; ++ix) 619 619 { 620 for (var iz = sz; iz <= lz; ++ 620 for (var iz = sz; iz <= lz; ++iz) 621 621 { 622 622 dx = ix - cx; 623 623 dz = iz - cz; … … 666 666 667 667 for (var ix = sx; ix <= lx; ++ix) 668 668 { 669 for (var iz = sz; iz <= lz; ++ 669 for (var iz = sz; iz <= lz; ++iz) 670 670 { 671 671 if (fcc) 672 672 if ((x - ix) > fcc || (ix - x) > fcc || (z - iz) > fcc || (iz - z) > fcc) … … 737 737 738 738 for (var ix = sx; ix <= lx; ++ix) 739 739 { 740 for (var iz = sz; iz <= lz; ++ 740 for (var iz = sz; iz <= lz; ++iz) 741 741 { 742 742 dx = ix - cx; 743 743 dz = iz - cz; -
binaries/data/mods/public/maps/random/rmgen/wall_builder.js
3 3 //////////////////////////////////////////////////////////////////// 4 4 5 5 // To do: 6 // Check if all wall placement methods work with wall elements with ent ity=== undefined (some still might raise errors in that case)6 // Check if all wall placement methods work with wall elements with entPath === undefined (some still might raise errors in that case) 7 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 8 // Perhaps add Roman army camp to style palisades and add upgraded/balanced default palisade fortress types matching civ default fortresses strength 9 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 … … 27 27 // maxTrys 28 28 // Add treasures to wall style "others" 29 29 // Adjust documentation 30 // Perhaps rename "endLeft" to "start" and "endRight" to "end"31 30 // ?Use available civ-type wall elements rather than palisades: Remove "endLeft" and "endRight" as default wall elements and adjust default palisade fortress types? 32 31 // ?Remove "endRight", "endLeft" and adjust generic fortress types palisades? 33 32 // ?Think of something to enable splitting walls into two walls so more complex walls can be build and roads can have branches/crossroads? 34 33 // ?Readjust placement angle for wall elements with bending when used in linear/circular walls by their bending? 35 34 35 /** 36 * Set some globals for this module 37 */ 38 var g_WallStyles = {}; 39 var g_WallStyleList = []; 40 var g_CivData = getFullCivData(); 41 var g_CivList = Object.keys(g_CivData); 42 var g_FortressTypes = {}; 43 var g_FortressTypeKeys = ["tiny", "small", "medium", "normal", "large", "veryLarge", "giant"]; 36 44 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) 45 /** 46 * Basic Initialisation 47 * 48 * Fetches wallsets from {civ}.json files, and then uses them to load 49 * basic wall elements 50 */ 51 for (let civ of g_CivList) 52 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; 53 let civInfo = g_CivData[civ]; 54 if (!civInfo.WallSets) 55 continue; 56 57 for (let path of civInfo.WallSets) 58 { 59 let style = path.split("/")[1].split("_"); 60 style = (style[0]=="wallset") ? style[1] : style[0]+"_"+style[2]; 61 62 if (g_WallStyleList.indexOf(style) == -1) 63 { 64 g_WallStyleList.push(style); 65 g_WallStyles[style] = {}; 66 let wallset = GetTemplateDataHelper(RMS.GetTemplate(path)).wallSet; 67 for (let element in wallset.templates) 68 setWallElement(style, element, wallset.templates[element].replace("{civ}",civ)) 69 g_WallStyles[style]["@overlap"] = wallset.minTowerOverlap * getWallElement(style, "tower").length; 70 } 71 } 80 72 } 81 73 82 74 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// … … 86 78 // It's mainly the abstract shape defined in a Fortress instances wall because different styles can be used for it (see wallStyles) 87 79 // 88 80 // type Descriptive string, example: "tiny". Not really needed (WallTool.wallTypes["type string"] is used). Mainly for custom wall elements 89 // wall Optional. Array of wall element strings. Can be set afterwards. Default is an e pty array.81 // wall Optional. Array of wall element strings. Can be set afterwards. Default is an empty array. 90 82 // Example: ["entrance", "wall", "cornerIn", "wall", "gate", "wall", "entrance", "wall", "cornerIn", "wall", "gate", "wall", "cornerIn", "wall"] 91 83 // centerToFirstElement Optional. Object with properties "x" and "y" representing a vector from the visual center to the first wall element. Default is undefined 92 84 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 93 85 function Fortress(type, wall, centerToFirstElement) 94 86 { 95 this.type = type; // Only usefull to get the type of the actual fortress96 this.wall = (wall !== undefined) ? wall :[];97 this.centerToFirstElement = undefined;87 this.type = type; 88 this.wall = wall || []; 89 this.centerToFirstElement = centerToFirstElement || undefined; 98 90 } 99 91 100 92 101 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////102 // wallStyles data structure for default wall styles103 //104 // A wall style is an associative array with all wall elements of that style in it associated with the wall element type string105 // wallStyles holds all the wall styles within an associative array with the civ string or another descriptive strings as key106 // Examples: "athen", "rome_siege", "palisades", "fence", "road"107 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////108 var wallStyles = {};109 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)113 {114 var civ = style;115 if (style == "rome_siege")116 civ = "rome";117 wallStyles[style] = {};118 // Default wall elements119 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/3123 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/3124 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 elements129 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 wall135 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 wall138 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 elements148 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]);152 }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 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/corner200 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/corner201 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/corner202 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/corner203 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 93 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 237 // fortressTypes data structure for some default fortress types94 // g_FortressTypes data structure for some default fortress types (defined above) 238 95 // 239 96 // A fortress type is just an instance of the Fortress class with actually something in it 240 97 // fortressTypes holds all the fortresses within an associative array with a descriptive string as key (e.g. matching the map size) 241 98 // Examples: "tiny", "veryLarge" 242 99 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 243 var fortressTypes = {};244 // Setup some default fortress types245 // 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 100 101 // Set some default fortress types 102 for (let key of g_FortressTypeKeys) 103 g_FortressTypes[key] = new Fortress(key); 104 105 g_FortressTypes["tiny"].wall = ["gate", "tower", "short", "cornerIn", "short", "tower"]; 106 g_FortressTypes["small"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "tower"]; 107 g_FortressTypes["medium"].wall = ["gate", "tower", "long", "cornerIn", "long", "tower"]; 108 g_FortressTypes["normal"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "cornerOut", "medium", "cornerIn", "medium", "tower"]; 109 g_FortressTypes["large"].wall = ["gate", "tower", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "tower"]; 110 g_FortressTypes["veryLarge"].wall = ["gate", "tower", "medium", "cornerIn", "medium", "cornerOut", "long", "cornerIn", "long", "cornerOut", "medium", "cornerIn", "medium", "tower"]; 111 g_FortressTypes["giant"].wall = ["gate", "tower", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "cornerOut", "long", "cornerIn", "long", "tower"]; 112 113 for (let type in g_FortressTypes) 114 { 115 let wallPart = g_FortressTypes[type].wall; 116 g_FortressTypes[type].wall = wallPart.concat(wallPart, wallPart, wallPart); 117 } 118 274 119 // 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++) 120 for (let fortType of g_FortressTypeKeys) 277 121 { 278 var newKey = fort ressTypeKeys[i]+ "Palisades";279 var oldWall = fortressTypes[fortressTypeKeys[i]].wall;280 fortressTypes[newKey] = new Fortress(newKey);122 var newKey = fortType + "Palisades"; 123 var oldWall = g_FortressTypes[fortType].wall; 124 g_FortressTypes[newKey] = new Fortress(newKey); 281 125 var fillTowersBetween = ["wallShort", "wall", "wallLong", "endLeft", "endRight", "cornerIn", "cornerOut"]; 282 for (var j = 0; j < oldWall.length; j++)126 for (var j = 0; j < oldWall.length; ++j) 283 127 { 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)128 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 129 if (j+1 < oldWall.length) 286 130 if (fillTowersBetween.indexOf(oldWall[j]) > -1 && fillTowersBetween.indexOf(oldWall[j+1]) > -1) // ... > -1 means "exists" here 287 131 fortressTypes[newKey].wall.push("tower"); … … 291 135 // Setup some balanced (to civ type fortresses) semi default fortresses for "palisades" style 292 136 // TODO 293 137 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);310 138 311 312 139 /////////////////////////////// 313 140 // Define some helper functions 314 141 /////////////////////////////// 315 142 143 /** 144 * Get a wall element of a style. 145 * 146 * If the element requested is unknown, the function attempts to derive 147 * it either from another element, or from a template or whatever. 148 * 149 * @param style The style to which this element comes from 150 * @param element The element to fetch 151 * @return The wall element requested. Or a tower element. 152 */ 153 function getWallElement(style="athen_stone", element) 154 { 155 if (g_WallStyleList.indexOf(style) < 0) 156 { 157 error("getWallElement: Style '"+style+"' not recognised. (Falling back to '" + FALLBACK_CIV + "_stone'.)"); 158 style = FALLBACK_CIV + "_stone"; 159 } 160 if (g_WallStyles[style][element]) 161 return g_WallStyles[style][element]; 162 163 // Attempt to derive any unknown elements. 164 // Defaults to a wall tower piece 165 var wallset = g_WallStyles[style]; 166 var civ = style.split("_")[0]; 167 var ret = clone(wallset.tower); 168 169 // We use clone() so we don't change the attributes of the object we're referencing 170 switch (element) 171 { 172 173 case "quarterCurve": 174 ret.angle += PI/4; 175 ret.bend = PI/2; 176 break; 177 178 case "eighthCurve": 179 ret.angle += PI/8; 180 ret.bend = PI/4; 181 break; 182 183 case "cornerIn": 184 if (wallset.quarterCurve) 185 ret = clone(wallset.quarterCurve); 186 else 187 { 188 ret.angle += PI/4 189 ret.indent = ret.length * 0.25; 190 ret.length = 0; 191 } 192 ret.bend = PI/2; 193 break; 194 195 case "cornerOut": 196 if (wallset.quarterCurve) 197 { 198 ret = clone(wallset.quarterCurve); 199 ret.angle += PI/2; 200 ret.indent -= ret.indent*2; 201 } 202 else 203 { 204 ret.angle -= PI/4; 205 ret.length *= 0.71; 206 } 207 ret.bend = -PI/2; 208 break; 209 210 case "wallShort": 211 warn("getWallElement: Deprecated use of 'wallShort' (please use 'short')"); 212 ret = clone(wallset.short); 213 break; 214 215 case "wallMedium": 216 case "wall": 217 warn("getWallElement: Deprecated use of '"+element+"' (please use 'medium')"); 218 ret = clone(wallset.medium); 219 break; 220 221 case "wallLong": 222 warn("getWallElement: Deprecated use of 'wallLong' (please use 'long')"); 223 ret = clone(wallset.long); 224 break; 225 226 case "entry": 227 ret.entPath = undefined; 228 ret.length = clone(g_WallStyles[style].gate.length); 229 break; 230 231 case "entryTower": 232 ret.entPath = (g_CivList.indexOf(civ) > -1) ? "structures/"+civ+"_defense_tower" : "other/palisades_rocks_watchtower"; 233 ret.indent = ret.length * -3; 234 ret.length = clone(g_WallStyles[style].gate.length); 235 break; 236 237 case "entryFort": 238 ret = clone(g_WallStyles[style].fort); 239 ret.angle -= PI; 240 ret.length *= 1.5; 241 ret.indent = ret.length; 242 break; 243 244 case "endLeft": 245 warn("getWallElement: Deprecated use of 'endLeft' (please use 'start')"); 246 case "start": 247 if (wallset.end) 248 { 249 ret = clone(wallset.end); 250 ret.angle += PI; 251 } 252 break; 253 254 case "endRight": 255 warn("getWallElement: Deprecated use of 'endRight' (please use 'start')"); 256 case "end": 257 if (wallset.end) 258 ret = clone(wallset.end); 259 break; 260 261 default: 262 // See if it's a structure (ie. house, barracks) 263 if (g_CivList.indexOf(civ) == -1) 264 civ = FALLBACK_CIV; 265 var entPath = "structures/"+civ+"_"+element; 266 if (RMS.TemplateExists(entPath)) 267 { 268 if (["outpost", "defense_tower"].indexOf(element) > -1) 269 ret.indent = ret.length * -3; 270 else 271 ret.indent = ret.length * 3.5; 272 ret.entPath = entPath; 273 ret.length = 0; 274 } 275 else if (element.slice(0.3) === "gap") 276 { 277 ret.entPath = undefined; 278 ret.angle = 0; 279 ret.length = +element.slice(4); 280 } 281 else if (element.slice(0,4) === "turn") 282 { 283 ret.entPath = undefined; 284 ret.angle = PI/2; 285 ret.length = 0; 286 if (element.slice(5) === "out") 287 ret.angle -= ret.angle; 288 } 289 else 290 warn("Unrecognised wall element: "+element+" ("+ style+"). Defaulting to 'tower'."); 291 } 292 293 // cache to save having to calculate this element again 294 g_WallStyles[style][element] = ret; 295 296 return ret; 297 } 298 299 /** 300 * Set a wall element of a style. 301 * 302 * @param style The style to which this element belongs 303 * @param element The element to add 304 * @param path The template path to read values from 305 */ 306 function setWallElement(style, element, path) 307 { 308 var template = RMS.GetTemplate(path); 309 template = GetTemplateDataHelper(template); 310 311 if (!g_WallStyles[style]) 312 g_WallStyles[style] = {}; 313 314 var length = (template.wallPiece) ? template.wallPiece.length : template.obstruction.shape.width; 315 g_WallStyles[style][element] = { 316 "entPath": path, 317 "angle": (template.wallPiece) ? template.wallPiece.angle : PI, 318 "length": length / CELL_SIZE, 319 "indent": (template.wallPiece) ? template.wallPiece.indent / CELL_SIZE : 0, 320 "bend": (template.wallPiece) ? template.wallPiece.bend : 0 321 }; 322 } 323 316 324 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 317 325 // getWallAlignment 318 326 // … … 320 328 // Placing the first wall element at startX/startY placed with an angle given by orientation 321 329 // An alignment can be used to get the "center" of a "wall" (more likely used for fortresses) with getCenterToFirstElement 322 330 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 323 function getWallAlignment(startX, startY, wall , style, orientation)331 function getWallAlignment(startX, startY, wall=[], style="athen_stone", orientation=0) 324 332 { 325 // Graciously handle arguments326 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 335 333 var alignment = []; 336 334 var wallX = startX; 337 335 var wallY = startY; 338 for (var i = 0; i < wall.length; i++) 336 337 for (var i = 0; i < wall.length; ++i) 339 338 { 340 var element = wallStyles[style][wall[i]];339 var element = getWallElement(style, wall[i]); 341 340 if (element === undefined && i == 0) 342 warn("No valid wall element: " + wall[i]); 341 { 342 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); 343 continue; 344 } 345 343 346 // Indentation 344 347 var placeX = wallX - element.indent * cos(orientation); 345 348 var placeY = wallY - element.indent * sin(orientation); 349 346 350 // Add wall elements entity placement arguments to the alignment 347 alignment.push({"x": placeX, "y": placeY, "entity": element.entity, "angle":orientation + element.angle}); 351 alignment.push({"x": placeX, "y": placeY, "entPath": element.entPath, "angle":orientation + element.angle}); 352 348 353 // Preset vars for the next wall element 349 354 if (i+1 < wall.length) 350 355 { 351 orientation += element.bend ing;352 var nextElement = wallStyles[style][wall[i+1]];356 orientation += element.bend; 357 var nextElement = getWallElement(style, wall[i+1]); 353 358 if (nextElement === undefined) 354 warn("No valid wall element: " + wall[i+1]); 355 var distance = (element.width + nextElement.width)/2; 359 { 360 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); 361 continue; 362 } 363 364 var distance = (element.length + nextElement.length)/2 - getOverlap(style); 356 365 // Corrections for elements with indent AND bending 357 366 var indent = element.indent; 358 var bend ing = element.bending;359 if (bend ing!== 0 && indent !== 0)367 var bend = element.bend; 368 if (bend !== 0 && indent !== 0) 360 369 { 361 370 // Indent correction to adjust distance 362 distance += indent*sin(bend ing);371 distance += indent*sin(bend); 363 372 // Indent correction to normalize indentation 364 373 wallX += indent * cos(orientation); 365 374 wallY += indent * sin(orientation); 366 375 } 376 367 377 // Set the next coordinates of the next element in the wall without indentation adjustment 368 378 wallX -= distance * sin(orientation); 369 379 wallY += distance * cos(orientation); … … 383 393 function getCenterToFirstElement(alignment) 384 394 { 385 395 var centerToFirstElement = {"x": 0, "y": 0}; 386 for (var i = 0; i < alignment.length; i++)396 for (var i = 0; i < alignment.length; ++i) 387 397 { 388 398 centerToFirstElement.x -= alignment[i].x/alignment.length; 389 399 centerToFirstElement.y -= alignment[i].y/alignment.length; … … 395 405 // getWallLength 396 406 // 397 407 // NOTE: Does not support bending wall elements like corners! 398 // e.g. used by placeIrregularPolygonalWall399 408 ////////////////////////////////////////////////////////////////// 400 function getWallLength( wall, style)409 function getWallLength(style, wall=[]) 401 410 { 402 411 // Graciously handle arguments 403 if (wall === undefined) 404 wall = []; 405 if (!wallStyles.hasOwnProperty(style)) 412 if (g_WallStyleList.indexOf(style) < 0) 406 413 { 407 warn(" Function getWallLength: Unknown style: " + style + ' (falling back to "athen")');408 style = "athen";414 warn("getWallLength: Unknown style: '" + style + "'. (Falling back to '" + FALLBACK_CIV + "_stone')."); 415 style = FALLBACK_CIV +"_stone"; 409 416 } 410 417 411 418 var length = 0; 412 for (var i = 0; i < wall.length; i++)413 {414 length += wallStyles[style][wall[i]].width;415 } 419 var overlap = getOverlap(style); 420 for (let element of wall) 421 length += getWallElement(style, element).length - overlap; 422 416 423 return length; 417 424 } 418 425 426 function getOverlap(style) 427 { 428 if (!style || !g_WallStyles[style]) 429 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 430 return g_WallStyles[style]["@overlap"]; 431 } 419 432 433 420 434 ///////////////////////////////////////////// 421 435 // Define the different wall placer functions 422 436 ///////////////////////////////////////////// … … 427 441 // Places a wall with wall elements attached to another like determined by WallElement properties. 428 442 // 429 443 // startX, startY Where the first wall element should be placed 430 // wall Array of wall element type strings. Example: ["endLeft", "wallLong", "tower", "wallLong", "endRight"]444 // wall Array of wall element types. Example: ["endLeft", "wallLong", "tower", "wallLong", "endRight"] 431 445 // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 432 446 // playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia) 433 447 // orientation Optional. Angle the first wall element is placed. Default is 0 … … 435 449 // It will then be build towards top/positive Y (if no bending wall elements like corners are used) 436 450 // Raising orientation means the wall is rotated counter-clockwise like placeObject 437 451 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 438 function placeWall(startX, startY, wall , style, playerId, orientation)452 function placeWall(startX, startY, wall=[], style, playerId=0, orientation=0) 439 453 { 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); 454 if (!startX || !startY) 455 return; 452 456 457 if (!style || g_WallStyleList.indexOf(style) == -1) 458 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 459 453 460 // Get wall alignment 454 461 var AM = getWallAlignment(startX, startY, wall, style, orientation); 462 455 463 // Place the wall 456 for (var iWall = 0; iWall < wall.length; iWall++)464 for (var iWall = 0; iWall < wall.length; ++iWall) 457 465 { 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);466 var entPath = AM[iWall].entPath; 467 if (entPath !== undefined) 468 placeObject(AM[iWall].x, AM[iWall].y, entPath, playerId, AM[iWall].angle); 461 469 } 462 470 } 463 471 … … 472 480 // playerId Optional. Number of the player the wall will be placed for. Default is 0 (gaia) 473 481 // orientation Optional. Angle the first wall element (should be a gate or entrance) is placed. Default is 0 474 482 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 475 function placeCustomFortress(centerX, centerY, fortress, style, playerId , orientation)483 function placeCustomFortress(centerX, centerY, fortress, style, playerId=0, orientation=0) 476 484 { 477 485 // 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); 486 fortress = fortress || g_FortressTypes["medium"]; 487 if (!style || !g_WallStyles[style]) 488 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 488 489 489 490 // Calculate center if fortress.centerToFirstElement is undefined (default) 490 491 var centerToFirstElement = fortress.centerToFirstElement; … … 501 502 // 502 503 // Like placeCustomFortress just it takes type (a fortress type string, has to be in fortressTypes) instead of an instance of Fortress 503 504 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 504 function placeFortress(centerX, centerY, type , style, playerId, orientation)505 function placeFortress(centerX, centerY, type="medium", style, playerId=0, orientation=0) 505 506 { 506 507 // 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); 508 if (!style || !g_WallStyles[style]) 509 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 517 510 518 511 // Call placeCustomFortress with the given arguments 519 placeCustomFortress(centerX, centerY, fortressTypes[type], style, playerId, orientation);512 placeCustomFortress(centerX, centerY, g_FortressTypes[type], style, playerId, orientation); 520 513 } 521 514 522 515 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// … … 526 519 // 527 520 // startX/startY Coordinate of the approximate beginning of the wall (Not the place of the first wall element) 528 521 // 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"]522 // wallPart Optional. An array of NON-BENDING wall element types. Default is ["tower", "wallLong"] 530 523 // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 531 524 // playerId Optional. Integer number of the player. Default is 0 (gaia) 532 525 // endWithFirst Optional. A boolean value. If true the 1st wall element in the wallPart array will finalize the wall. Default is true 533 526 // 534 527 // TODO: Maybe add angle offset for more generic looking? 535 528 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 536 function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId , endWithFirst)529 function placeLinearWall(startX, startY, targetX, targetY, wallPart, style, playerId=0, endWithFirst=true) 537 530 { 538 531 // 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; 532 wallPart = wallPart || ["tower", "long"]; 533 if (!style || !g_WallStyles[style]) 534 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 549 535 550 536 // 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 } 537 for (let element of wallPart) 538 if (getWallElement(style, element).bend != 0) 539 warn("Bending is not supported by placeLinearWall but the following bending wall element was used: " + element); 540 557 541 // Setup number of wall parts 558 542 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; 543 var wallPartLength = getWallLength(style, wallPart); 562 544 var numParts = 0; 563 545 if (endWithFirst == true) 564 numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength);546 numParts = ceil((totalLength - getWallElement(style, wallPart[0]).length) / wallPartLength); 565 547 else 566 548 numParts = ceil(totalLength / wallPartLength); 549 567 550 // Setup scale factor 568 551 var scaleFactor = 1; 569 552 if (endWithFirst == true) 570 scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width);553 scaleFactor = totalLength / (numParts * wallPartLength + getWallElement(style, wallPart[0]).length); 571 554 else 572 555 scaleFactor = totalLength / (numParts * wallPartLength); 556 573 557 // Setup angle 574 558 var wallAngle = getAngle(startX, startY, targetX, targetY); // NOTE: function "getAngle()" is about to be changed... 575 559 var placeAngle = wallAngle - PI/2; 576 560 // Place wall entities 577 561 var x = startX; 578 562 var y = startY; 579 for (var partIndex = 0; partIndex < numParts; partIndex++)563 for (var partIndex = 0; partIndex < numParts; ++partIndex) 580 564 { 581 for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)565 for (var elementIndex = 0; elementIndex < wallPart.length; ++elementIndex) 582 566 { 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); 567 let wallEle = getWallElement(style, wallPart[elementIndex]); 568 let wallLength = (wallEle.length - getOverlap(style)) / 2; 569 let distX = scaleFactor * wallLength * cos(wallAngle); 570 let distY = scaleFactor * wallLength * sin(wallAngle); 571 // Length correction 572 x += distX; 573 y += distY; 587 574 // Indent correction 588 varplaceX = x - wallEle.indent * sin(wallAngle);589 varplaceY = y + wallEle.indent * cos(wallAngle);575 let placeX = x - wallEle.indent * sin(wallAngle); 576 let placeY = y + wallEle.indent * cos(wallAngle); 590 577 // 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); 578 let entPath = wallEle.entPath; 579 if (entPath !== undefined) 580 placeObject(placeX, placeY, entPath, playerId, placeAngle + wallEle.angle); 581 // Prep for next object 582 x += distX; 583 y += distY; 596 584 } 597 585 } 598 586 if (endWithFirst == true) 599 587 { 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); 588 var wallEle = getWallElement(style, wallPart[0]); 589 let wallLength = (wallEle.length - getOverlap(style)) / 2; 590 x += scaleFactor * wallLength * cos(wallAngle); 591 y += scaleFactor * wallLength * sin(wallAngle); 592 var entPath = wallEle.entPath; 593 if (entPath !== undefined) 594 placeObject(x, y, entPath, playerId, placeAngle + wallEle.angle); 606 595 } 607 596 } 608 597 … … 615 604 // 616 605 // centerX/Y Coordinates of the circle's center 617 606 // 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"]607 // wallPart Optional. An array of NON-BENDING wall element types. Default is ["tower", "wallLong"] 619 608 // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 620 609 // playerId Optional. Integer number of the player. Default is 0 (gaia) 621 610 // orientation Optional. Where the open part of the (circular) arc should face (if maxAngle is < 2*PI). Default is 0 … … 624 613 // maxBendOff Optional. How irregular the circle should be. 0 means regular circle, PI/2 means very irregular. Default is 0 (regular circle) 625 614 // 626 615 // NOTE: Don't use wall elements with bending like corners! 627 // TODO: Perhaps add eccentricity and maxBendOff functionality (untill now an unused argument) 616 // TODO: Perhaps add eccentricity 617 // TODO: Check if maxBendOff parameter works in all cases 628 618 // TODO: Perhaps add functionality for spirals 629 619 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 630 function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId , orientation, maxAngle, endWithFirst, maxBendOff)620 function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId=0, orientation=0, maxAngle=TWO_PI, endWithFirst, maxBendOff=0) 631 621 { 632 622 // 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); 623 wallPart = wallPart || ["tower", "long"]; 624 if (!style || !g_WallStyles[style]) 625 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 644 626 if (endWithFirst === undefined) 645 627 { 646 if (maxAngle >= 2*PI - 0.001) // Can this be done better?628 if (maxAngle >= TWO_PI - 0.001) // Can this be done better? 647 629 endWithFirst = false; 648 630 else 649 631 endWithFirst = true; 650 632 } 651 maxBendOff = (maxBendOff || 0);652 633 653 634 // Check arguments 654 635 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 } 636 warn("placeCircularWall maxBendOff should satisfy 0 < maxBendOff < PI/2 (~1.5) but it is: " + maxBendOff); 637 for (let element of wallPart) 638 if (getWallElement(style, element).bend != 0) 639 warn("Bending is not supported by placeCircularWall but the following bending wall element was used: " + element); 640 662 641 // Setup number of wall parts 663 642 var totalLength = maxAngle * radius; 664 var wallPartLength = 0; 665 for (var elementIndex = 0; elementIndex < wallPart.length; elementIndex++) 666 wallPartLength += wallStyles[style][wallPart[elementIndex]].width; 643 var wallPartLength = getWallLength(style, wallPart); 667 644 var numParts = 0; 668 645 if (endWithFirst == true) 669 646 { 670 numParts = ceil((totalLength - wallStyles[style][wallPart[0]].width) / wallPartLength);647 numParts = ceil((totalLength - getWallElement(style, wallPart[0]).length) / wallPartLength); 671 648 } 672 649 else 673 650 { … … 676 653 // Setup scale factor 677 654 var scaleFactor = 1; 678 655 if (endWithFirst == true) 679 scaleFactor = totalLength / (numParts * wallPartLength + wallStyles[style][wallPart[0]].width);656 scaleFactor = totalLength / (numParts * wallPartLength + getWallElement(style, wallPart[0]).length); 680 657 else 681 658 scaleFactor = totalLength / (numParts * wallPartLength); 682 659 // Place wall entities 683 660 var actualAngle = orientation + (2*PI - maxAngle) / 2; 684 661 var x = centerX + radius*cos(actualAngle); 685 662 var y = centerY + radius*sin(actualAngle); 686 for ( var partIndex = 0; partIndex < numParts; partIndex++)663 for (let partIndex = 0; partIndex < numParts; ++partIndex) 687 664 { 688 for ( var elementIndex = 0; elementIndex < wallPart.length; elementIndex++)665 for (let wallEle of wallPart) 689 666 { 690 var wallEle = wallStyles[style][wallPart[elementIndex]];667 wallEle = getWallElement(style, wallEle); 691 668 // 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;669 let addAngle = scaleFactor * (wallEle.length - getOverlap(style)) / radius; 670 let targetX = centerX + radius * cos(actualAngle + addAngle); 671 let targetY = centerY + radius * sin(actualAngle + addAngle); 672 let placeX = x + (targetX - x)/2; 673 let placeY = y + (targetY - y)/2; 674 let placeAngle = actualAngle + addAngle/2; 698 675 // Indent correction 699 676 placeX -= wallEle.indent * cos(placeAngle); 700 677 placeY -= wallEle.indent * sin(placeAngle); 701 678 // Placement 702 var ent ity = wallEle.entity;703 if (ent ity!== undefined)704 placeObject(placeX, placeY, ent ity, playerId, placeAngle + wallEle.angle);679 var entPath = wallEle.entPath; 680 if (entPath !== undefined) 681 placeObject(placeX, placeY, entPath, playerId, placeAngle + wallEle.angle); 705 682 // Prepare for the next wall element 706 683 actualAngle += addAngle; 707 684 x = centerX + radius*cos(actualAngle); … … 710 687 } 711 688 if (endWithFirst == true) 712 689 { 713 var wallEle = wallStyles[style][wallPart[0]];714 var addAngle = scaleFactor * wallEle. width / radius;690 var wallEle = getWallElement(style, wallPart[0]); 691 var addAngle = scaleFactor * wallEle.length / radius; 715 692 var targetX = centerX + radius * cos(actualAngle + addAngle); 716 693 var targetY = centerY + radius * sin(actualAngle + addAngle); 717 694 var placeX = x + (targetX - x)/2; 718 695 var placeY = y + (targetY - y)/2; 719 696 var placeAngle = actualAngle + addAngle/2; 720 placeObject(placeX, placeY, wallEle.ent ity, playerId, placeAngle + wallEle.angle);697 placeObject(placeX, placeY, wallEle.entPath, playerId, placeAngle + wallEle.angle); 721 698 } 722 699 } 723 700 … … 728 705 // 729 706 // centerX/Y Coordinates of the polygon's center 730 707 // radius How wide the circle should be in which the polygon fits 731 // wallPart Optional. An array of NON-BENDING wall element type strings. Default is ["wallLong", "tower"]708 // wallPart Optional. An array of NON-BENDING wall element types. Default is ["wallLong", "tower"] 732 709 // cornerWallElement Optional. Wall element to be placed at the polygon's corners. Default is "tower" 733 710 // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 734 711 // playerId Optional. Integer number of the player. Default is 0 (gaia) … … 741 718 // TODO: Check some arguments 742 719 // TODO: Add eccentricity and perhaps make it just call placeIrregularPolygonalWall with irregularity = 0 743 720 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 744 function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId , orientation, numCorners, skipFirstWall)721 function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement, style, playerId=0, orientation=0, numCorners=8, skipFirstWall=true) 745 722 { 746 723 // 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 724 wallPart = wallPart || ["long", "tower"]; 725 cornerWallElement = cornerWallElement || "tower"; // Don't use wide elements for this. Not supported well... 726 if (!style || !g_WallStyles[style]) 727 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 728 761 729 // Setup angles 762 var angleAdd = 2*PI/numCorners;730 var angleAdd = TWO_PI/numCorners; 763 731 var angleStart = orientation - angleAdd/2; 732 764 733 // Setup corners 765 734 var corners = []; 766 for ( var i = 0; i < numCorners; i++)735 for (let i = 0; i < numCorners; ++i) 767 736 corners.push([centerX + radius*cos(angleStart + i*angleAdd), centerY + radius*sin(angleStart + i*angleAdd)]); 737 768 738 // Place Corners and walls 769 for ( var i = 0; i < numCorners; i++)739 for (let i = 0; i < numCorners; ++i) 770 740 { 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);741 let angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY); 742 placeObject(corners[i][0], corners[i][1], getWallElement(style, cornerWallElement).entPath, playerId, angleToCorner); 773 743 if (!(skipFirstWall && i == 0)) 774 744 { 745 let cornerLength = getWallElement(style, cornerWallElement).length / 2; 746 let cornerAngle = angleToCorner + angleAdd / 2; 747 let cornerX = cornerLength * sin(cornerAngle); 748 let cornerY = cornerLength * cos(cornerAngle); 775 749 placeLinearWall( 776 750 // 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), // targetY751 corners[i][0] + cornerX, // startX 752 corners[i][1] - cornerY, // startY 753 corners[(i+1)%numCorners][0] - cornerX, // targetX 754 corners[(i+1)%numCorners][1] + cornerY, // targetY 781 755 wallPart, style, playerId); 782 756 } 783 757 } … … 794 768 // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 795 769 // playerId Optional. Integer number of the player. Default is 0 (gaia) 796 770 // 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)771 // numCorners Optional. How many corners the polygon will have. Default is randomly chosen from 'tween 5 & 7 inclusive 798 772 // irregularity Optional. How irregular the polygon will be. 0 means regular, 1 means VERY irregular. Default is 0.5 799 // skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is true773 // skipFirstWall Optional. Boolean. If the first linear wall part will be left opened as entrance. Default is false 800 774 // wallPartsAssortment Optional. An array of wall part arrays to choose from for each linear wall connecting the corners. Default is hard to describe ^^ 801 775 // 802 776 // NOTE: wallPartsAssortment is put to the end because it's hardest to set … … 805 779 // TODO: Check some arguments 806 780 // TODO: Perhaps add eccentricity 807 781 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 808 function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement , style, playerId, orientation, numCorners, irregularity, skipFirstWall, wallPartsAssortment)782 function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement="tower", style, playerId=0, orientation=0, numCorners, irregularity=0.5, skipFirstWall=false, wallPartsAssortment) 809 783 { 810 784 // 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 785 if (!style || !g_WallStyles[style]) 786 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 787 numCorners = (numCorners || randInt(5, 7)); 788 820 789 // Generating a generic wall part assortment with each wall part including 1 gate lengthened by walls and towers 821 790 // NOTE: It might be a good idea to write an own function for that... 822 var defaultWallPartsAssortment = [[" wallShort"], ["wall"], ["wallLong"], ["gate", "tower", "wallShort"]];791 var defaultWallPartsAssortment = [["short"], ["medium"], ["long"], ["gate", "tower", "short"]]; 823 792 var centeredWallPart = ["gate"]; 824 var extandingWallPartAssortment = [["tower", " wallLong"], ["tower", "wall"]];793 var extandingWallPartAssortment = [["tower", "long"], ["tower", "medium"]]; 825 794 defaultWallPartsAssortment.push(centeredWallPart); 826 for (var i = 0; i < extandingWallPartAssortment.length; i++)795 for (var i = 0; i < extandingWallPartAssortment.length; ++i) 827 796 { 828 797 var wallPart = centeredWallPart; 829 for (var j = 0; j < radius; j++)798 for (var j = 0; j < radius; ++j) 830 799 { 831 800 if (j%2 == 0) 832 801 wallPart = wallPart.concat(extandingWallPartAssortment[i]); … … 841 810 } 842 811 // Setup optional arguments to the default 843 812 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); 813 851 814 // Setup angles 852 var angleToCover = 2*PI;815 var angleToCover = TWO_PI; 853 816 var angleAddList = []; 854 for (var i = 0; i < numCorners; i++)817 for (var i = 0; i < numCorners; ++i) 855 818 { 856 819 // Randomize covered angles. Variety scales down with raising angle though... 857 820 angleAddList.push(angleToCover/(numCorners-i) * (1 + randFloat(-irregularity, irregularity))); … … 860 823 // Setup corners 861 824 var corners = []; 862 825 var angleActual = orientation - angleAddList[0]/2; 863 for (var i = 0; i < numCorners; i++)826 for (var i = 0; i < numCorners; ++i) 864 827 { 865 828 corners.push([centerX + radius*cos(angleActual), centerY + radius*sin(angleActual)]); 866 829 if (i < numCorners - 1) … … 869 832 // Setup best wall parts for the different walls (a bit confusing naming...) 870 833 var wallPartLengths = []; 871 834 var maxWallPartLength = 0; 872 for ( var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++)835 for (let wallPart of wallPartsAssortment) 873 836 { 874 var length = wallPartLengths[partIndex];875 wallPartLengths.push( getWallLength(wallPartsAssortment[partIndex], style));837 var length = getWallLength(style, wallPart); 838 wallPartLengths.push(length); 876 839 if (length > maxWallPartLength) 877 840 maxWallPartLength = length; 878 841 } 842 879 843 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++)844 for (var i = 0; i < numCorners; ++i) 881 845 { 882 var bestWallPart = []; // This is a simp elwall part not a wallPartsAssortment!883 var bestWallLength = 99999999;846 var bestWallPart = []; // This is a simple wall part not a wallPartsAssortment! 847 var bestWallLength = Number.MAX_VALUE; 884 848 // NOTE: This is not exactly like the length the wall will be in the end. Has to be tweaked... 885 849 var wallLength = getDistance(corners[i][0], corners[i][1], corners[(i+1)%numCorners][0], corners[(i+1)%numCorners][1]); 886 850 var numWallParts = ceil(wallLength/maxWallPartLength); 887 for (var partIndex = 0; partIndex < wallPartsAssortment.length; partIndex++)851 for (var partIndex = 0; partIndex < wallPartsAssortment.length; ++partIndex) 888 852 { 889 853 var linearWallLength = numWallParts*wallPartLengths[partIndex]; 890 854 if (linearWallLength < bestWallLength && linearWallLength > wallLength) … … 895 859 } 896 860 wallPartList.push(bestWallPart); 897 861 } 862 898 863 // Place Corners and walls 899 for (var i = 0; i < numCorners; i++)864 for (var i = 0; i < numCorners; ++i) 900 865 { 901 866 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);867 placeObject(corners[i][0], corners[i][1], getWallElement(style, cornerWallElement).entPath, playerId, angleToCorner); 903 868 if (!(skipFirstWall && i == 0)) 904 869 { 870 let cornerLength = getWallElement(style, cornerWallElement).length / 2; 905 871 placeLinearWall( 906 872 // 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), // targetY873 corners[i][0] + cornerLength * sin(angleToCorner + angleAddList[i]/2), // startX 874 corners[i][1] - cornerLength * cos(angleToCorner + angleAddList[i]/2), // startY 875 corners[(i+1)%numCorners][0] - cornerLength * sin(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetX 876 corners[(i+1)%numCorners][1] + cornerLength * cos(angleToCorner + angleAddList[(i+1)%numCorners]/2), // targetY 911 877 wallPartList[i], style, playerId, false); 912 878 } 913 879 } … … 920 886 // This is the default Iberian civ bonus starting wall 921 887 // 922 888 // centerX/Y The approximate center coordinates of the fortress 923 // radius The approximate radius of the wall to be placed889 // radius Optional. The approximate radius of the wall to be placed. Default is 20 924 890 // playerId Optional. Integer number of the player. Default is 0 (gaia) 925 891 // style Optional. Wall style string. Default is the civ of the given player, "palisades" for gaia 926 // irregularity Optional. Float between 0 (circle) and 1 (very spiky), default is 1/2892 // irregularity Optional. Float between 0 (circle) and 1 (very spiky), default is 0.5 927 893 // gateOccurence Optional. Integer number, every n-th walls will be a gate instead. Default is 3 928 894 // maxTrys Optional. How often the function tries to find a better fitting shape at max. Default is 100 929 895 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 930 function placeGenericFortress(centerX, centerY, radius , playerId, style, irregularity, gateOccurence, maxTrys)896 function placeGenericFortress(centerX, centerY, radius=20, playerId=0, style, irregularity=0.5, gateOccurence=3, maxTrys=100) 931 897 { 932 898 // 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); 899 if (!style || !g_WallStyles[style]) 900 style = (playerId == 0) ? "palisade" : getCivCode(playerId-1)+"_stone"; 945 901 946 902 // Setup some vars 947 903 var startAngle = randFloat(0, 2*PI); 948 904 var actualOffX = radius*cos(startAngle); 949 905 var actualOffY = radius*sin(startAngle); 950 906 var actualAngle = startAngle; 951 var pointDistance = wallStyles[style]["wallLong"].width + wallStyles[style]["tower"].width;907 var pointDistance = getWallLength(style, ["long", "tower"]); 952 908 // Searching for a well fitting point derivation 953 909 var tries = 0; 954 910 var bestPointDerivation = undefined; 955 911 var minOverlap = 1000; 956 912 var overlap = undefined; 957 while (tries < maxTrys && minOverlap > wallStyles[style]["tower"].width / 10)913 while (tries < maxTrys && minOverlap > getOverlap(style)) 958 914 { 959 915 var pointDerivation = []; 960 916 var distanceToTarget = 1000; … … 963 919 { 964 920 var indent = randFloat(-irregularity*pointDistance, irregularity*pointDistance); 965 921 var tmpAngle = getAngle(actualOffX, actualOffY, 966 (radius + indent)*cos(actualAngle + (pointDistance / radius)),967 (radius + indent)*sin(actualAngle + (pointDistance / radius)));922 (radius + indent)*cos(actualAngle + pointDistance / radius), 923 (radius + indent)*sin(actualAngle + pointDistance / radius)); 968 924 actualOffX += pointDistance*cos(tmpAngle); 969 925 actualOffY += pointDistance*sin(tmpAngle); 970 926 actualAngle = getAngle(0, 0, actualOffX, actualOffY); … … 982 938 } 983 939 } 984 940 } 985 tries++;941 ++tries; 986 942 } 987 943 log("placeGenericFortress: Reduced overlap to " + minOverlap + " after " + tries + " tries"); 988 944 // Place wall 989 for (var pointIndex = 0; pointIndex < bestPointDerivation.length; pointIndex++)945 for (var pointIndex = 0; pointIndex < bestPointDerivation.length; ++pointIndex) 990 946 { 991 947 var startX = centerX + bestPointDerivation[pointIndex][0]; 992 948 var startY = centerY + bestPointDerivation[pointIndex][1]; 993 949 var targetX = centerX + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][0]; 994 950 var targetY = centerY + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][1]; 995 951 var angle = getAngle(startX, startY, targetX, targetY); 996 var wallElement = " wallLong";952 var wallElement = "long"; 997 953 if ((pointIndex + 1) % gateOccurence == 0) 998 954 wallElement = "gate"; 999 var entity = wallStyles[style][wallElement].entity; 1000 if (entity) 955 956 var entPath = getWallElement(style, wallElement).entPath; 957 if (entPath) 1001 958 { 1002 959 placeObject(startX + (getDistance(startX, startY, targetX, targetY)/2)*cos(angle), // placeX 1003 960 startY + (getDistance(startX, startY, targetX, targetY)/2)*sin(angle), // placeY 1004 ent ity, playerId, angle - PI/2 + wallStyles[style][wallElement].angle);961 entPath, playerId, angle - PI/2 + getWallElement(style, wallElement).angle); 1005 962 } 1006 963 // Place tower 1007 964 var startX = centerX + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][0]; 1008 965 var startY = centerY + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][1]; 1009 966 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); 967 968 var tower = getWallElement(style, "tower"); 969 placeObject(centerX + bestPointDerivation[pointIndex][0], centerY + bestPointDerivation[pointIndex][1], tower.entPath, playerId, angle - PI/2 + tower.angle); 1011 970 } 1012 971 } -
binaries/data/mods/public/maps/random/schwarzwald.js
131 131 // Setup paths 132 132 var pathSucsessRadius = baseRadius/2; 133 133 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 path134 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 135 136 136 // Setup additional resources 137 137 var resourceRadius = 2*mapRadius/3; // 3*mapRadius/8; … … 159 159 constraint = (constraint || new NullConstraint()); 160 160 161 161 var ret = []; 162 for (var x = 0; x < g_Map.size; x++) {163 for (var y = 0; y < g_Map.size; y++) {162 for (var x = 0; x < g_Map.size; ++x) { 163 for (var y = 0; y < g_Map.size; ++y) { 164 164 if (g_Map.height[x][y] >= this.lowerBound && g_Map.height[x][y] <= this.upperBound && constraint.allows(x, y)) { 165 165 ret.push(new PointXZ(x, y)); 166 166 } … … 179 179 var distances = []; 180 180 if (points.length <= 3) 181 181 { 182 for (var i = 0; i < points.length; i++)182 for (var i = 0; i < points.length; ++i) 183 183 order.push(i); 184 184 185 185 return order; … … 187 187 188 188 // Just add the first 3 points 189 189 var pointsToAdd = deepcopy(points); 190 for (var i = 0; i < min(points.length, 3); i ++)190 for (var i = 0; i < min(points.length, 3); i) 191 191 { 192 192 order.push(i); 193 193 pointsToAdd.shift(i); … … 198 198 199 199 // Add remaining points so the path lengthens the least 200 200 var numPointsToAdd = pointsToAdd.length; 201 for (var i = 0; i < numPointsToAdd; i++)201 for (var i = 0; i < numPointsToAdd; ++i) 202 202 { 203 203 var indexToAddTo = undefined; 204 204 var minEnlengthen = Infinity; 205 205 var minDist1 = 0; 206 206 var minDist2 = 0; 207 for (var k = 0; k < order.length; k++)207 for (var k = 0; k < order.length; ++k) 208 208 { 209 209 var dist1 = getDistance(pointsToAdd[0][0], pointsToAdd[0][1], points[order[k]][0], points[order[k]][1]); 210 210 var dist2 = getDistance(pointsToAdd[0][0], pointsToAdd[0][1], points[order[(k + 1) % order.length]][0], points[order[(k + 1) % order.length]][1]); … … 232 232 // 233 233 //////////////// 234 234 235 // Some heightmap constants236 const MIN_HEIGHT = - SEA_LEVEL; // -20237 const MAX_HEIGHT = 0xFFFF/HEIGHT_UNITS_PER_METRE - SEA_LEVEL; // A bit smaller than 90238 239 235 // Get the diferrence between minimum and maxumum height 240 236 function getMinAndMaxHeight(reliefmap) 241 237 { 242 238 var height = {}; 243 239 height.min = Infinity; 244 240 height.max = - Infinity; 245 for (var x = 0; x < reliefmap.length; x++)241 for (var x = 0; x < reliefmap.length; ++x) 246 242 { 247 for (var y = 0; y < reliefmap[x].length; y++)243 for (var y = 0; y < reliefmap[x].length; ++y) 248 244 { 249 245 if (reliefmap[x][y] < height.min) 250 246 height.min = reliefmap[x][y]; … … 264 260 var oldHeightRange = getMinAndMaxHeight(heightmap); 265 261 var max_x = heightmap.length; 266 262 var max_y = heightmap[0].length; 267 for (var x = 0; x < max_x; x++)268 for (var y = 0; y < max_y; y++)263 for (var x = 0; x < max_x; ++x) 264 for (var y = 0; y < max_y; ++y) 269 265 heightmap[x][y] = minHeight + (heightmap[x][y] - oldHeightRange.min) / (oldHeightRange.max - oldHeightRange.min) * (maxHeight - minHeight); 270 266 } 271 267 … … 288 284 heightmap = (heightmap || g_Map.height); 289 285 290 286 var validStartLocTiles = []; 291 for (var x = minDistToBorder; x < heightmap.length - minDistToBorder; x++)292 for (var y = minDistToBorder; y < heightmap[0].length - minDistToBorder; y++)287 for (var x = minDistToBorder; x < heightmap.length - minDistToBorder; ++x) 288 for (var y = minDistToBorder; y < heightmap[0].length - minDistToBorder; ++y) 293 289 if (heightmap[x][y] > hightRange.min && heightmap[x][y] < hightRange.max) // Has the right hight 294 290 validStartLocTiles.push([x, y]); 295 291 296 292 var maxMinDist = 0; 297 for (var tries = 0; tries < maxTries; tries++)293 for (var tries = 0; tries < maxTries; ++tries) 298 294 { 299 295 var startLoc = []; 300 296 var minDist = heightmap.length; 301 for (var p = 0; p < numberOfPlayers; p++)297 for (var p = 0; p < numberOfPlayers; ++p) 302 298 startLoc.push(validStartLocTiles[randInt(validStartLocTiles.length)]); 303 for (var p1 = 0; p1 < numberOfPlayers - 1; p1++)299 for (var p1 = 0; p1 < numberOfPlayers - 1; ++p1) 304 300 { 305 for (var p2 = p1 + 1; p2 < numberOfPlayers; p2++)301 for (var p2 = p1 + 1; p2 < numberOfPlayers; ++p2) 306 302 { 307 303 var dist = getDistance(startLoc[p1][0], startLoc[p1][1], startLoc[p2][0], startLoc[p2][1]); 308 304 if (dist < minDist) … … 340 336 341 337 var placements = deepcopy(startLoc); 342 338 var validTiles = []; 343 for (var x = minDistance; x < heightmap.length - minDistance; x++)344 for (var y = minDistance; y < heightmap[0].length - minDistance; y++)339 for (var x = minDistance; x < heightmap.length - minDistance; ++x) 340 for (var y = minDistance; y < heightmap[0].length - minDistance; ++y) 345 341 if (heightmap[x][y] > hightRange.min && heightmap[x][y] < hightRange.max) // Has the right hight 346 342 validTiles.push([x, y]); 347 343 348 344 if (!validTiles.length) 349 345 return; 350 346 351 for (var tries = 0; tries < maxTries; tries++)347 for (var tries = 0; tries < maxTries; ++tries) 352 348 { 353 349 var tile = validTiles[randInt(validTiles.length)]; 354 350 var isValid = true; 355 for (var p = 0; p < placements.length; p++)351 for (var p = 0; p < placements.length; ++p) 356 352 { 357 353 if (getDistance(placements[p][0], placements[p][1], tile[0], tile[1]) < minDistance) 358 354 { … … 395 391 var newHeightmap = []; 396 392 var oldWidth = initialHeightmap.length; 397 393 // Square 398 for (var x = 0; x < 2 * oldWidth - 1; x++)394 for (var x = 0; x < 2 * oldWidth - 1; ++x) 399 395 { 400 396 newHeightmap.push([]); 401 for (var y = 0; y < 2 * oldWidth - 1; y++)397 for (var y = 0; y < 2 * oldWidth - 1; ++y) 402 398 { 403 399 if (x % 2 === 0 && y % 2 === 0) // Old tile 404 400 newHeightmap[x].push(initialHeightmap[x/2][y/2]); … … 412 408 } 413 409 } 414 410 // Diamond 415 for (var x = 0; x < 2 * oldWidth - 1; x++)411 for (var x = 0; x < 2 * oldWidth - 1; ++x) 416 412 { 417 for (var y = 0; y < 2 * oldWidth - 1; y++)413 for (var y = 0; y < 2 * oldWidth - 1; ++y) 418 414 { 419 415 if (newHeightmap[x][y] === undefined) 420 416 { … … 452 448 453 449 // Cut initialHeightmap to fit target width 454 450 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++)451 for (var x = 0; x < heightmap.length; ++x) 452 for (var y = 0; y < heightmap[0].length; ++y) 457 453 heightmap[x][y] = newHeightmap[x][y]; 458 454 } 459 455 … … 474 470 var map = [[1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1]]; // smoother 475 471 var max_x = heightmap.length; 476 472 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++)473 for (var x = 0; x < max_x; ++x) 474 for (var y = 0; y < max_y; ++y) 475 for (var i = 0; i < map.length; ++i) 480 476 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 477 } 482 478 … … 490 486 heightmap = (heightmap || g_Map.height); 491 487 492 488 var heightmapWin = []; 493 for (var wx = 0; wx < 2 * dx + 1; wx++)489 for (var wx = 0; wx < 2 * dx + 1; ++wx) 494 490 { 495 491 heightmapWin.push([]); 496 for (var wy = 0; wy < 2 * dy + 1; wy++)492 for (var wy = 0; wy < 2 * dy + 1; ++wy) 497 493 { 498 494 var actualX = x - dx + wx; 499 495 var actualY = y - dy + wy; … … 503 499 heightmapWin[wx].push(targetHeight); 504 500 } 505 501 } 506 for (var wx = 0; wx < 2 * dx + 1; wx++)502 for (var wx = 0; wx < 2 * dx + 1; ++wx) 507 503 { 508 for (var wy = 0; wy < 2 * dy + 1; wy++)504 for (var wy = 0; wy < 2 * dy + 1; ++wy) 509 505 { 510 506 var actualX = x - dx + wx; 511 507 var actualY = y - dy + wy; … … 550 546 551 547 setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, 0.5, initialReliefmap, g_Map.height); 552 548 // Apply simple erosion 553 for (var i = 0; i < 5; i++)549 for (var i = 0; i < 5; ++i) 554 550 decayErrodeHeightmap(0.5); 555 551 rescaleHeightmap(heightRange.min, heightRange.max); 556 552 … … 582 578 var startLocations = getStartLocationsByHeightmap({'min': heighLimits[4], 'max': heighLimits[5]}); 583 579 var playerHeight = (heighLimits[4] + heighLimits[5]) / 2; 584 580 585 for (var i=0; i < numPlayers; i++)581 for (var i=0; i < numPlayers; ++i) 586 582 { 587 583 playerAngle[i] = (playerAngleStart + i*playerAngleAddAvrg + randFloat(0, playerAngleMaxOff))%(2*PI); 588 584 var x = round(mapCenterX + randFloat(minPlayerRadius, maxPlayerRadius)*cos(playerAngle[i])); … … 604 600 var distToSL = 15; 605 601 var resStartAngle = playerAngle[i] + PI; 606 602 var resAddAngle = 2*PI / startingResources.length; 607 for (var rIndex = 0; rIndex < startingResources.length; rIndex++)603 for (var rIndex = 0; rIndex < startingResources.length; ++rIndex) 608 604 { 609 605 var angleOff = randFloat(-resAddAngle/2, resAddAngle/2); 610 606 var placeX = x + distToSL*cos(resStartAngle + rIndex*resAddAngle + angleOff); … … 644 640 var maxI = numPlayers+1; 645 641 else 646 642 var maxI = numPlayers; 647 for (var i = 0; i < maxI; i++)643 for (var i = 0; i < maxI; ++i) 648 644 { 649 645 if (doublePaths === true) 650 646 var minJ = 0; 651 647 else 652 648 var minJ = i+1; 653 for (var j = minJ; j < numPlayers+1; j++)649 for (var j = minJ; j < numPlayers+1; ++j) 654 650 { 655 651 // Setup start and target coordinates 656 652 if (i < numPlayers) … … 700 696 } 701 697 if (getDistance(x, z, targetX, targetZ) < pathSucsessRadius) 702 698 targetReached = true; 703 tries++;699 ++tries; 704 700 705 701 } 706 702 } … … 761 757 762 758 // place trees 763 759 log("Planting trees..."); 764 for (var x = 0; x < mapSize; x++)760 for (var x = 0; x < mapSize; ++x) 765 761 { 766 for (var z = 0; z < mapSize;z++)762 for (var z = 0; z < mapSize; ++z) 767 763 { 768 764 // Some variables 769 765 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 766 var minDistToSL = mapSize; 771 for (var i=0; i < numPlayers; i++)767 for (var i=0; i < numPlayers; ++i) 772 768 minDistToSL = min(minDistToSL, getDistance(playerStartLocX[i], playerStartLocZ[i], x, z)); 773 769 // Woods tile based 774 770 var tDensFactSL = max(min((minDistToSL - baseRadius) / baseRadius, 1), 0); -
binaries/data/mods/public/maps/random/wall_demo.js
61 61 var buildableMapSize = mapSize - 2 * distToMapBorder; 62 62 var actualX = distToMapBorder; 63 63 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"]; 64 var wallStyleList = g_WallStyleList; 67 65 68 69 66 //////////////////////////////////////// 70 67 // Custom wall placement (element based) 71 68 //////////////////////////////////////// 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++)69 var wall = ['start', 'long', 'tower', 'medium', 'outpost', 'medium', 'cornerOut', 'medium', 'cornerIn', 'medium', 'house', 'end', 'entryTower', 'start', 'short', 'barracks', 'gate', 'tower', 'medium', 'fort', 'medium', 'end']; 70 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 74 71 { 75 72 var startX = actualX + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the first wall element 76 73 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)74 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 75 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 76 // That means the wall will be build towards top (positive Y) if no corners are used 80 77 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 wall78 placeWall(startX, startY, wall, style, playerId, orientation); // Actually place the wall 82 79 } 83 80 actualX = distToMapBorder; // Reset actualX 84 81 actualY += 80 + distToOtherWalls; // Increase actualY for next wall placement method 85 82 83 86 84 ////////////////////////////////////////////////////////////// 87 85 // Default fortress placement (chosen by fortress type string) 88 86 ////////////////////////////////////////////////////////////// 89 87 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++)88 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 91 89 { 92 90 var centerX = actualX + fortressRadius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the fortress 93 91 var centerY = actualY + fortressRadius; // Y coordinate of the center of the fortress … … 99 97 placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the fortress 100 98 } 101 99 actualX = distToMapBorder; // Reset actualX 102 actualY += 2 * fortressRadius + 2 *distToOtherWalls; // Increase actualY for next wall placement method100 actualY += 2 * fortressRadius + distToOtherWalls; // Increase actualY for next wall placement method 103 101 102 ////////////////////////////////////////////////////////////// 103 // 'generic' fortress placement (iberian wall circuit code) 104 ////////////////////////////////////////////////////////////// 105 var radius = min((mapSize - actualY - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall circle 106 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 107 { 108 var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the fortress 109 var centerY = actualY + radius; // Y coordinate of the center of the fortress 110 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 111 var playerId = 0; // Owner of the wall. 0 is Gaia, 1 is Player 1 (default color blue), ... 112 placeGenericFortress(centerX, centerY, radius, playerId, style); // Actually place the fortress 113 placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the fortress 114 } 115 actualX = distToMapBorder; // Reset actualX 116 actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method 117 104 118 ////////////////////////// 105 119 // Circular wall placement 106 120 ////////////////////////// … … 108 122 var radius = min((mapSize - actualY - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall circle 109 123 var centerY = actualY + radius; // Y coordinate of the center of the wall circle 110 124 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++)125 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 112 126 { 113 127 var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle 114 128 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']129 var wallPart = ['tower', 'medium', 'house']; // List of wall elements the wall will be build of. Optional, default id ['wall'] 116 130 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 117 131 var maxAngle = PI/2 * (styleIndex%3 + 2); // How far the wall should circumvent the center 118 132 placeCircularWall(centerX, centerY, radius, wallPart, style, playerId, orientation, maxAngle); // Actually placing the wall … … 122 136 actualX = distToMapBorder; // Reset actualX 123 137 actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method 124 138 125 /////////////////////////// 126 // Polygonal wall placement127 /////////////////////////// 139 /////////////////////////////////// 140 // Regular Polygonal wall placement 141 /////////////////////////////////// 128 142 // NOTE: Don't use bending wall elements like corners here! 129 143 var radius = min((mapSize - actualY - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons 130 144 var centerY = actualY + radius; // Y coordinate of the center of the wall polygon 131 145 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++)146 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 133 147 { 134 148 var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle 135 149 var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... 136 150 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']151 var wallPart = ['medium', 'tower']; // List of wall elements the wall will be build of. Optional, default id ['wall'] 138 152 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 139 153 var numCorners = (styleIndex)%6 + 3; // How many corners the plogon will have 140 154 var skipFirstWall = true; // If the wall should be open towards orientation … … 145 159 actualX = distToMapBorder; // Reset actualX 146 160 actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method 147 161 162 ///////////////////////////////////// 163 // Irregular Polygonal wall placement 164 ///////////////////////////////////// 165 // NOTE: Don't use bending wall elements like corners here! 166 var radius = min((mapSize - actualY - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons 167 var centerY = actualY + radius; // Y coordinate of the center of the wall polygon 168 var orientation = 0; // Where the wall circle will be open if ???, see below. Otherwise where the first wall will be placed 169 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 170 { 171 var centerX = actualX + radius + styleIndex * buildableMapSize/wallStyleList.length; // X coordinate of the center of the wall circle 172 var playerId = 0; // Player ID of the player owning the wall, 0 is Gaia, 1 is the first player (default blue), ... 173 var cornerWallElement = 'tower'; // With wall element type will be uset for the corners of the polygon 174 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 175 var numCorners = (styleIndex)%6 + 3; // How many corners the plogon will have 176 var skipFirstWall = true; // If the wall should be open towards orientation 177 placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerId, orientation, numCorners, undefined, skipFirstWall); 178 placeObject(centerX, centerY, 'other/obelisk', 0, 0*PI); // Place visual marker to see the center of the wall circle 179 orientation += PI/16; // Increasing orientation to see how rotation works (like for object placement) 180 } 181 actualX = distToMapBorder; // Reset actualX 182 actualY += 2 * radius + distToOtherWalls; // Increase actualY for next wall placement method 183 184 148 185 //////////////////////// 149 186 // Linear wall placement 150 187 //////////////////////// 151 188 // NOTE: Don't use bending wall elements like corners here! 152 189 var maxWallLength = (mapSize - actualY - distToMapBorder - distToOtherWalls); // Just for this maps design. How long the longest wall will be 153 190 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++)191 for (var styleIndex = 0; styleIndex < wallStyleList.length; ++styleIndex) 155 192 { 156 for (var wallIndex = 0; wallIndex < numWallsPerStyle; wallIndex++)193 for (var wallIndex = 0; wallIndex < numWallsPerStyle; ++wallIndex) 157 194 { 158 var startX = actualX + (styleIndex * numWallsPerStyle + wallIndex) * distToOtherWalls; // X coordinate the wall will start from195 var startX = actualX + (styleIndex * numWallsPerStyle + wallIndex) * buildableMapSize/wallStyleList.length/numWallsPerStyle; // X coordinate the wall will start from 159 196 var startY = actualY; // Y coordinate the wall will start from 160 197 var endX = startX; // X coordinate the wall will end 161 198 var endY = actualY + (wallIndex + 1) * maxWallLength/numWallsPerStyle; // Y coordinate the wall will end 162 199 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 of200 var wallPart = ['tower', 'medium']; // List of wall elements the wall will be build of 164 201 var style = wallStyleList[styleIndex]; // The wall's style like 'cart', 'iber', 'pers', 'rome', 'romeSiege' or 'palisades' 165 202 placeLinearWall(startX, startY, endX, endY, wallPart, style, playerId); // Actually placing the wall 166 203 // placeObject(startX, startY, 'other/obelisk', 0, 0*PI); // Place visual marker to see where exsactly the wall begins 167 204 // placeObject(endX, endY, 'other/obelisk', 0, 0*PI); // Place visual marker to see where exsactly the wall ends 168 205 } 169 206 } 170 actualX = distToMapBorder; // Reset actualX171 actualY += maxWallLength + distToOtherWalls; // Increase actualY for next wall placement method172 207 173 208 174 209 // Export map data -
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/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.0</Length> 20 20 </WallPiece> 21 21 </Entity> 22 No newline at end of file -
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>7.0</Length> 24 24 </WallPiece> 25 25 </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>1 1.0</Length>23 <Length>10.5</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>7.0</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>8.5</Length> 25 25 </WallPiece> 26 26 </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.0</Length> 20 20 </WallPiece> 21 21 </Entity> 22 No newline at end of file -
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.0</Length> 29 29 </WallPiece> 30 30 </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_wall_tower.xml
16 16 <Actor>structures/ptolemies/wall_tower.xml</Actor> 17 17 </VisualActor> 18 18 <WallPiece> 19 <Length> 10</Length>19 <Length>6.5</Length> 20 20 </WallPiece> 21 21 </Entity> 22 No newline at end of file -
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_tower.xml
16 16 <Actor>structures/romans/wall_tower.xml</Actor> 17 17 </VisualActor> 18 18 <WallPiece> 19 <Length> 9.5</Length>19 <Length>8.0</Length> 20 20 </WallPiece> 21 21 </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.0</Length> 20 20 </WallPiece> 21 21 </Entity> 22 No newline at end of file -
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.0</Length> 20 20 </WallPiece> 21 21 </Entity> 22 No newline at end of file