Ticket #4275: optimize_caledonian_meadows2016_10_9d.2.patch
File optimize_caledonian_meadows2016_10_9d.2.patch, 14.7 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/maps/random/caledonian_meadows.js
142 142 143 143 /** 144 144 * Drags a path to a target height smoothing it at the edges and return some points along the path. 145 *146 * TODO:147 * Would be nice to tell the function what to do and how often in the arguments148 * Adding painted tiles to a tile class149 145 */ 150 function placeRandomPathToHeight(start, pathTexture, target, targetHeight, width = 10, occurrence = 2, strength = 0.1, heightmap = g_Map.height) 146 function placeRandomPathToHeight( 147 start, target, targetHeight, tileClass = undefined, texture = "road_rome_a", 148 width = 10, distance = 4, strength = 0.08, heightmap = g_Map.height) 151 149 { 152 if (pathTexture === true) 153 pathTexture = ['temp_road', "temp_road_overgrown", 'temp_grass_b']; 154 155 let clTempPath = createTileClass(); 156 let targetReached = false; 150 let pathPoints = []; 157 151 let position = deepcopy(start); 158 while ( !targetReached)152 while (true) 159 153 { 160 154 rectangularSmoothToHeight(position, width, width, targetHeight, strength, heightmap); 161 if (pathTexture) 162 createArea(new ClumpPlacer(0.2 * width * width, 1, 1, 1, floor(position.x), floor(position.y)), [new TerrainPainter(pathTexture), paintClass(clTempPath)]); 163 164 // Set lets for next loop 155 if (texture) 156 { 157 if (tileClass !== undefined) 158 createArea(new ClumpPlacer(0.3 * width * width, 1, 1, 1, floor(position.x), floor(position.y)), 159 [new TerrainPainter(texture), paintClass(tileClass)]); 160 else 161 createArea(new ClumpPlacer(0.3 * width * width, 1, 1, 1, floor(position.x), floor(position.y)), 162 new TerrainPainter(texture)); 163 } 164 pathPoints.push({ "x": position.x, "y": position.y, "dist": distance }); 165 // Check for distance to target and setup for next loop if needed 166 if (getDistance(position.x, position.y, target.x, target.y) < distance / 2) 167 break; 165 168 let angleToTarget = getAngle(position.x, position.y, target.x, target.y); 166 169 let angleOff = PI * (randFloat() - 0.5); 167 position.x += occurrence * cos(angleToTarget + angleOff); 168 position.y += occurrence * sin(angleToTarget + angleOff); 169 if (getDistance(position.x, position.y, target.x, target.y) < occurrence / 2) 170 targetReached = true; 170 position.x += distance * cos(angleToTarget + angleOff); 171 position.y += distance * sin(angleToTarget + angleOff); 171 172 } 172 return clTempPath;173 return pathPoints; 173 174 } 174 175 175 176 function getGrad(wrapped = true, scalarField = g_Map.height) … … 240 241 /** 241 242 * Meant to place e.g. resource spots within a height range 242 243 * @param {array} [heightRange] - The height range in which to place the entities (An associative array with keys "min" and "max" each containing a float) 243 * @param {array} [avoidPoints ] - An array of objects of the form {"x": int, "y": int, "dist": int}, points that will be avoided in the given dist e.g. start locations244 * @param { array} [avoidArea] - List of tiles to avoid244 * @param {array} [avoidPoints=[]] - An array of objects of the form {"x": int, "y": int, "dist": int}, points that will be avoided in the given dist e.g. start locations 245 * @param {object} [avoidClass=undefined] - TileClass to be avoided 245 246 * @param {integer} [minDistance=30] - How many tile widths the entities to place have to be away from each other, start locations and the map border 246 247 * @param {array} [heightmap=g_Map.height] - The reliefmap the entities should be distributed on 247 * @param {integer} [maxTries= 1000] - How often random player distributions are rolled to be compared248 * @param {integer} [maxTries=2 * g_Map.size] - How often random player distributions are rolled to be compared (256 to 1024) 248 249 * @param {boolean} [isCircular=g_MapSettings.CircularMap] - If the map is circular or rectangular 249 250 */ 250 function getPointsByHeight(heightRange, avoidPoints , avoidArea, minDistance = 20, maxTries = 1000, heightmap = g_Map.height, isCircular = g_MapSettings.CircularMap)251 function getPointsByHeight(heightRange, avoidPoints = [], avoidClass = undefined, minDistance = 20, maxTries = 2 * g_Map.size, heightmap = g_Map.height, isCircular = g_MapSettings.CircularMap) 251 252 { 252 253 let points = []; 253 254 let placements = deepcopy(avoidPoints); 254 255 let validVertices = []; 255 256 let r = 0.5 * (heightmap.length - 1); // Map center x/y as well as radius 257 let avoidMap = g_Map.tileClasses[avoidClass].inclusionCount; 256 258 for (let x = minDistance; x < heightmap.length - minDistance; ++x) 257 259 { 258 260 for (let y = minDistance; y < heightmap[0].length - minDistance; ++y) 259 261 { 260 let isValid = true;261 for (let i = 0; i < pathArea.length; ++i)262 if (pathArea[i].x == x && pathArea[i].y == y)263 isValid = false;264 if (!isValid)262 if (avoidClass !== undefined && // Avoid adjecting tiles in avoidClass 263 (avoidMap[max(x - 1, 0)][y] > 0 || 264 avoidMap[x][max(y - 1, 0)] > 0 || 265 avoidMap[min(x + 1, avoidMap.length - 1)][y] > 0 || 266 avoidMap[x][min(y + 1, avoidMap[0].length - 1)] > 0)) 265 267 continue; 266 267 if (heightmap[x][y] > heightRange.min && heightmap[x][y] < heightRange.max && (!isCircular || r - getDistance(x, y, r, r) >= minDistance)) // Has correct height and enough distance to map border 268 269 if (heightmap[x][y] > heightRange.min && heightmap[x][y] < heightRange.max && // Has correct height 270 (!isCircular || r - getDistance(x, y, r, r) >= minDistance)) // Enough distance to map border 268 271 validVertices.push({ "x": x, "y": y , "dist": minDistance}); 269 272 } 270 273 } 271 274 272 275 for (let tries = 0; tries < maxTries; ++tries) 273 276 { 274 277 let point = validVertices[randInt(validVertices.length)]; … … 277 280 points.push(point); 278 281 placements.push(point); 279 282 } 283 if ((tries != 0) && (tries % 100 == 0)) // Time Check 284 log(points.length + " points found after " + tries + " tries after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); 280 285 } 281 286 282 287 return points; 283 288 } 284 289 … … 294 299 "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml", 295 300 "actor|props/flora/bush_tempe_a.xml", "actor|props/flora/bush_tempe_b.xml", "actor|props/flora/ferns.xml" 296 301 ]; 297 298 302 function placeMine(point, centerEntity) 299 303 { 300 304 placeObject(point.x, point.y, centerEntity, 0, randFloat(0, TWO_PI)); … … 334 338 fences.push(new Fortress("fence", deepcopy(fences[i].wall).reverse())); 335 339 336 340 // Groves, only Wood 337 let groveEntities = [ 338 "gaia/flora_bush_temperate", "gaia/flora_tree_euro_beech" 339 ]; 341 let groveEntities = ["gaia/flora_bush_temperate", "gaia/flora_tree_euro_beech"]; 340 342 let groveActors = [ 341 343 "actor|geology/highland1_moss.xml", "actor|geology/highland2_moss.xml", 342 344 "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml", … … 383 385 } 384 386 } 385 387 386 let foodEntities = ["gaia/flora_bush_berry", "gaia/fauna_chicken", "gaia/fauna_chicken"]; 387 // Start loaction resources 388 function placeStartLocationResources(point) 388 389 function placeStartLocationResources(point, foodEntities = ["gaia/flora_bush_berry", "gaia/fauna_chicken", "gaia/fauna_chicken"]) 389 390 { 390 391 let currentAngle = randFloat(0, TWO_PI); 391 392 // Stone and chicken … … 438 439 } 439 440 } 440 441 442 log("Functions loaded after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check 443 441 444 /** 442 * Set height limits and water level by map size445 * Environment settings 443 446 */ 447 setBiome(g_BiomeAlpine); 448 g_Environment.Fog.FogColor = { "r": 0.8, "g": 0.8, "b": 0.8, "a": 0.01 }; 449 g_Environment.Water.WaterBody.Colour = { "r" : 0.3, "g" : 0.05, "b" : 0.1, "a" : 0.1 }; 450 g_Environment.Water.WaterBody.Murkiness = 0.4; 451 452 /** 453 * Base terrain shape generation and settings 454 */ 455 // Height range by map size 444 456 let heightScale = (g_Map.size + 256) / 768 / 4; 445 457 let heightRange = { "min": MIN_HEIGHT * heightScale, "max": MAX_HEIGHT * heightScale }; 446 458 // Water coverage 447 459 let averageWaterCoverage = 1/5; // NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with the same value 448 460 let waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); // Water height in environment and the engine 449 461 let waterHeightAdjusted = waterHeight + MIN_HEIGHT; // Water height in RMGEN 450 462 setWaterHeight(waterHeight); 451 452 453 /** 454 * Generate base terrain 455 */ 463 // Generate base terrain shape 456 464 let medH = (heightRange.min + heightRange.max) / 2; 457 465 let initialHeightmap = [[medH, medH], [medH, medH]]; 458 466 setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, initialHeightmap, 0.8); 459 460 /** 461 * Apply simple erosion 462 */ 463 // globalSmoothHeightmap(0.5); 467 // Apply simple erosion 464 468 for (let i = 0; i < 5; ++i) 465 469 splashErodeMap(0.1); 466 470 // Final rescale 467 471 rescaleHeightmap(heightRange.min, heightRange.max); 468 472 473 RMS.SetProgress(25); 474 469 475 /** 470 * Height presets476 * Prepare terrain texture placement 471 477 */ 472 478 let heighLimits = [ 473 479 heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), // 0 Deep water … … 481 487 waterHeightAdjusted + 6/8 * (heightRange.max - waterHeightAdjusted), // 8 Forest 482 488 waterHeightAdjusted + 7/8 * (heightRange.max - waterHeightAdjusted), // 9 Upper forest border 483 489 waterHeightAdjusted + (heightRange.max - waterHeightAdjusted)]; // 10 Hilltop 484 485 /** 486 * Set environment 487 */ 488 setBiome(g_BiomeAlpine); 489 g_Environment.Fog.FogColor = { "r": 0.8, "g": 0.8, "b": 0.8, "a": 0.01 }; 490 g_Environment.Water.WaterBody.Colour = { "r" : 0.3, "g" : 0.05, "b" : 0.1, "a" : 0.1 }; 491 g_Environment.Water.WaterBody.Murkiness = 0.4; 492 493 /** 494 * Add tile painting presets 495 */ 496 let dummyActor = "actor|props/special/common/waypoint_flag.xml"; 490 let playerHeight = (heighLimits[4] + heighLimits[5]) / 2; // Average player height 491 // Texture and actor presets 497 492 let myBiome = []; 498 493 myBiome.push({ // 0 Deep water 499 494 "texture": ["shoreline_stoney_a"], … … 551 546 "textureHS": ["alpine_cliff_c"], "actorHS": [["actor|geology/highland1.xml"], 0.0] 552 547 }); 553 548 549 log("Terrain shape generation and texture presets after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check 554 550 555 551 /** 556 552 * Get start locations … … 573 569 teams.push(t); 574 570 } 575 571 playerIDs = sortPlayers(playerIDs); 576 577 572 // Minimize maximum distance between players within a team 578 573 if (teams.length) 579 574 { … … 616 611 } 617 612 } 618 613 619 let playerHeight = (heighLimits[4] + heighLimits[5]) / 2; 614 log("Start location chosen after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check 615 RMS.SetProgress(30); 620 616 621 617 /** 622 * Place start locations (resources later)618 * Add paths 623 619 */ 624 for (let p = 0; p < playerIDs.length; ++p) 625 { 626 let point = startLocations[p]; 627 rectangularSmoothToHeight(point, 35, 35, playerHeight, 0.7); 628 placeCivDefaultEntities(point.x, point.y, playerIDs[p], { "iberWall": true }); 629 } 630 631 /** 632 * Calculate tileCenteredHeightMap (This has nothing to to with TILE_CENTERED_HEIGHT_MAP which should be false (default) for this map to work properly) 633 */ 634 let tchm = getTileCenteredHeightmap(); 635 636 /** 637 * Add paths class and area but don't paint before resource spots are chosen! 638 */ 639 let pathTerrainClassIDs = []; 620 let tchm = getTileCenteredHeightmap(); // Calculate tileCenteredHeightMap (This has nothing to to with TILE_CENTERED_HEIGHT_MAP which should be false) 621 let pathPoints = []; 622 let clPath = createTileClass(); 640 623 for (let i = 0; i < startLocations.length; ++i) 641 624 { 642 625 let start = startLocations[i]; 643 626 let target = startLocations[(i + 1) % startLocations.length]; 644 path TerrainClassIDs.push(placeRandomPathToHeight(start, ["road_rome_a"], target, playerHeight, 8, 3, 0.1));627 pathPoints = pathPoints.concat(placeRandomPathToHeight(start, target, playerHeight, clPath)); 645 628 } 646 let pathArea = [];647 for (let x = 0; x < tchm.length; ++x)648 for (let y = 0; y < tchm[0].length; ++y)649 for (let i = 0; i < pathTerrainClassIDs.length; ++i)650 if (getTileClass(pathTerrainClassIDs[i]).countMembersInRadius(x, y, 0.5))651 pathArea.push({ "x": x, "y": y });652 629 630 log("Paths placed after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check 631 RMS.SetProgress(45); 632 653 633 /** 654 * Get resource spots after players start locations after path are calculated but before they are placed!634 * Get resource spots after players start locations calculation 655 635 */ 656 636 let avoidPoints = deepcopy(startLocations); 657 637 for (let i = 0; i < avoidPoints.length; ++i) 658 638 avoidPoints[i].dist = 30; 659 let resourceSpots = getPointsByHeight({ "min": (heighLimits[3] + heighLimits[4]) / 2, "max": (heighLimits[5] + heighLimits[6]) / 2 }, avoidPoints, pathArea);639 let resourceSpots = getPointsByHeight({ "min": (heighLimits[3] + heighLimits[4]) / 2, "max": (heighLimits[5] + heighLimits[6]) / 2 }, avoidPoints, clPath); 660 640 661 /** 662 * Calculate slope map 663 */ 664 let slopeMap = getSlopeMap(); 641 log("Resource spots chosen after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check 642 RMS.SetProgress(55); 665 643 666 644 /** 667 645 * Divide tiles in areas by height and avoid paths … … 673 651 { 674 652 for (let y = 0; y < tchm[0].length; ++y) 675 653 { 676 let isPath = false; 677 for (let i = 0; i < pathArea.length; ++i) 678 if (pathArea[i].x == x && pathArea[i].y == y) 679 isPath = true; 680 if (isPath) 654 if (g_Map.tileClasses[clPath].inclusionCount[x][y] > 0) // Avoid paths 681 655 continue; 682 656 683 657 let minHeight = heightRange.min; … … 697 671 /** 698 672 * Get max slope of each area 699 673 */ 674 let slopeMap = getSlopeMap(); // Calculate slope map 700 675 let minSlope = []; 701 676 let maxSlope = []; 702 677 for (let h = 0; h < heighLimits.length; ++h) … … 744 719 } 745 720 } 746 721 722 log("Terrain texture placement finished after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check 723 RMS.SetProgress(80); 724 747 725 /** 748 * Add start ing resources after terrain texturepainting726 * Add start locations and resource spots after terrain texture and path painting 749 727 */ 750 for (let p = 0; p < g_MapSettings.PlayerData.length - 1; ++p) 728 for (let p = 0; p < playerIDs.length; ++p) 729 { 730 let point = startLocations[p]; 731 rectangularSmoothToHeight(point, 40, 40, playerHeight, 0.7); 732 placeCivDefaultEntities(point.x, point.y, playerIDs[p], { "iberWall": true }); 751 733 placeStartLocationResources(startLocations[p]); 752 753 /** 754 * Add resource spots after terrain texture painting 755 */ 734 } 756 735 for (let i = 0; i < resourceSpots.length; ++i) 757 736 { 758 737 let choice = i % 5; … … 771 750 /** 772 751 * Stop Timer 773 752 */ 774 log("Map generation finished after " + ((new Date().getTime() - genStartTime) / 1000) + "s") 753 log("Map generation finished after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); 775 754 776 755 /** 777 756 * Export map data