Ticket #4275: optimize_caledonian_meadows2016_10_9.patch

File optimize_caledonian_meadows2016_10_9.patch, 14.8 KB (added by FeXoR, 8 years ago)

Patch as in ticket description

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

     
    142142
    143143/**
    144144 * 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 arguments
    148  * Adding painted tiles to a tile class
    149145 */
    150 function placeRandomPathToHeight(start, pathTexture, target, targetHeight, width = 10, occurrence = 2, strength = 0.1, heightmap = g_Map.height)
     146function placeRandomPathToHeight(start, target, targetHeight, tileClass = undefined, texture = "road_rome_a", width = 10, distance = 4, strength = 0.08, heightmap = g_Map.height)
    151147{
    152     if (pathTexture === true)
    153         pathTexture = ['temp_road', "temp_road_overgrown", 'temp_grass_b'];
    154    
    155     let clTempPath = createTileClass();
     148    let pathPoints = [];
    156149    let targetReached = false;
    157150    let position = deepcopy(start);
    158151    while (!targetReached)
    159152    {
    160153        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
    165         let angleToTarget = getAngle(position.x, position.y, target.x, target.y);
    166         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)
     154        if (texture)
     155            createArea(new ClumpPlacer(0.3 * width * width, 1, 1, 1, floor(position.x), floor(position.y)), [new TerrainPainter(texture), paintClass(tileClass)]);
     156        pathPoints.push({"x" : position.x, "y" : position.y, "dist" : distance});
     157        // Setup for next loop
     158        if (getDistance(position.x, position.y, target.x, target.y) < distance / 2)
    170159            targetReached = true;
     160        else
     161        {
     162            let angleToTarget = getAngle(position.x, position.y, target.x, target.y);
     163            let angleOff = PI * (randFloat() - 0.5);
     164            position.x += distance * cos(angleToTarget + angleOff);
     165            position.y += distance * sin(angleToTarget + angleOff);
     166        }
    171167    }
    172     return clTempPath;
     168    return pathPoints;
    173169}
    174170
    175171function getGrad(wrapped = true, scalarField = g_Map.height)
     
    240236/**
    241237 * Meant to place e.g. resource spots within a height range
    242238 * @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 locations
    244  * @param {array} [avoidArea] - List of tiles to avoid
     239 * @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
     240 * @param {object} [avoidClass=undefined] - TileClass to be avoided
    245241 * @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
    246242 * @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 compared
     243 * @param {integer} [maxTries=2 * g_Map.size] - How often random player distributions are rolled to be compared (256 to 1024)
    248244 * @param {boolean} [isCircular=g_MapSettings.CircularMap] - If the map is circular or rectangular
    249245 */
    250 function getPointsByHeight(heightRange, avoidPoints, avoidArea, minDistance = 20, maxTries = 1000, heightmap = g_Map.height, isCircular = g_MapSettings.CircularMap)
     246function getPointsByHeight(heightRange, avoidPoints = [], avoidClass = undefined, minDistance = 20, maxTries = 2 * g_Map.size, heightmap = g_Map.height, isCircular = g_MapSettings.CircularMap)
    251247{
    252248    let points = [];
    253249    let placements = deepcopy(avoidPoints);
    254250    let validVertices = [];
    255251    let r = 0.5 * (heightmap.length - 1); // Map center x/y as well as radius
     252
    256253    for (let x = minDistance; x < heightmap.length - minDistance; ++x)
    257254    {
    258255        for (let y = minDistance; y < heightmap[0].length - minDistance; ++y)
    259256        {
    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)
     257            if (avoidClass !== undefined && // Avoid adjecting tiles in avoidClass
     258                (g_Map.tileClasses[avoidClass].inclusionCount[max(x - 1, 0)][y] > 0 || g_Map.tileClasses[avoidClass].inclusionCount[x][max(y - 1, 0)] > 0 ||
     259                g_Map.tileClasses[avoidClass].inclusionCount[min(x + 1, g_Map.tileClasses[avoidClass].inclusionCount.length - 1)][y] > 0 ||
     260                g_Map.tileClasses[avoidClass].inclusionCount[x][min(y + 1, g_Map.tileClasses[avoidClass].inclusionCount[0].length - 1)] > 0)
     261            )
    265262                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
     263
     264            if (heightmap[x][y] > heightRange.min && heightmap[x][y] < heightRange.max && // Has correct height
     265                (!isCircular || r - getDistance(x, y, r, r) >= minDistance) // Enough distance to map border
     266            )
    268267                validVertices.push({ "x": x, "y": y , "dist": minDistance});
    269268        }
    270269    }
    271    
     270
    272271    for (let tries = 0; tries < maxTries; ++tries)
    273272    {
    274273        let point = validVertices[randInt(validVertices.length)];
     
    277276            points.push(point);
    278277            placements.push(point);
    279278        }
     279        if ((tries != 0) && (tries % 100 == 0)) // Time Check
     280            log(points.length + " points found after " + tries + " tries after " + ((new Date().getTime() - genStartTime) / 1000) + "s");
    280281    }
    281    
     282
    282283    return points;
    283284}
    284285
     
    294295    "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml",
    295296    "actor|props/flora/bush_tempe_a.xml", "actor|props/flora/bush_tempe_b.xml", "actor|props/flora/ferns.xml"
    296297];
    297 
    298298function placeMine(point, centerEntity)
    299299{
    300300    placeObject(point.x, point.y, centerEntity, 0, randFloat(0, TWO_PI));
     
    334334    fences.push(new Fortress("fence", deepcopy(fences[i].wall).reverse()));
    335335
    336336// Groves, only Wood
    337 let groveEntities = [
    338     "gaia/flora_bush_temperate", "gaia/flora_tree_euro_beech"
    339 ];
     337let groveEntities = ["gaia/flora_bush_temperate", "gaia/flora_tree_euro_beech"];
    340338let groveActors = [
    341339    "actor|geology/highland1_moss.xml", "actor|geology/highland2_moss.xml",
    342340    "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml",
     
    383381    }
    384382}
    385383
    386 let foodEntities = ["gaia/flora_bush_berry", "gaia/fauna_chicken", "gaia/fauna_chicken"];
    387 // Start loaction resources
    388 function placeStartLocationResources(point)
     384
     385function placeStartLocationResources(point, foodEntities = ["gaia/flora_bush_berry", "gaia/fauna_chicken", "gaia/fauna_chicken"])
    389386{
    390387    let currentAngle = randFloat(0, TWO_PI);
    391388    // Stone and chicken
     
    438435    }
    439436}
    440437
     438log("Functions loaded after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
     439
    441440/**
    442  * Set height limits and water level by map size
     441 * Environment settings
    443442 */
     443setBiome(g_BiomeAlpine);
     444g_Environment.Fog.FogColor = { "r": 0.8, "g": 0.8, "b": 0.8, "a": 0.01 };
     445g_Environment.Water.WaterBody.Colour = { "r" : 0.3, "g" : 0.05, "b" : 0.1, "a" : 0.1 };
     446g_Environment.Water.WaterBody.Murkiness = 0.4;
     447
     448/**
     449 * Base terrain shape generation and settings
     450 */
     451 // Height range by map size
    444452let heightScale = (g_Map.size + 256) / 768 / 4;
    445453let heightRange = { "min": MIN_HEIGHT * heightScale, "max": MAX_HEIGHT * heightScale };
    446 
     454// Water coverage
    447455let averageWaterCoverage = 1/5; // NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with the same value
    448456let waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); // Water height in environment and the engine
    449457let waterHeightAdjusted = waterHeight + MIN_HEIGHT; // Water height in RMGEN
    450458setWaterHeight(waterHeight);
    451 
    452 
    453 /**
    454  * Generate base terrain
    455  */
     459// Generate base terrain shape
    456460let medH = (heightRange.min + heightRange.max) / 2;
    457461let initialHeightmap = [[medH, medH], [medH, medH]];
    458462setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, initialHeightmap, 0.8);
    459 
    460 /**
    461  * Apply simple erosion
    462  */
    463 // globalSmoothHeightmap(0.5);
     463// Apply simple erosion
    464464for (let i = 0; i < 5; ++i)
    465465    splashErodeMap(0.1);
    466 
     466// Final rescale
    467467rescaleHeightmap(heightRange.min, heightRange.max);
    468468
     469RMS.SetProgress(25);
     470
    469471/**
    470  * Height presets
     472 * Prepare terrain texture placement
    471473 */
    472474let heighLimits = [
    473475    heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), // 0 Deep water
     
    481483    waterHeightAdjusted + 6/8 * (heightRange.max - waterHeightAdjusted), // 8 Forest
    482484    waterHeightAdjusted + 7/8 * (heightRange.max - waterHeightAdjusted), // 9 Upper forest border
    483485    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";
     486let playerHeight = (heighLimits[4] + heighLimits[5]) / 2; // Average player height
     487// Texture and actor presets
    497488let myBiome = [];
    498489myBiome.push({ // 0 Deep water
    499490    "texture": ["shoreline_stoney_a"],
     
    551542    "textureHS": ["alpine_cliff_c"], "actorHS": [["actor|geology/highland1.xml"], 0.0]
    552543});
    553544
     545log("Terrain shape generation and texture presets after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
    554546
    555547/**
    556548 * Get start locations
     
    573565        teams.push(t);
    574566}
    575567playerIDs = sortPlayers(playerIDs);
    576 
    577568// Minimize maximum distance between players within a team
    578569if (teams.length)
    579570{
     
    616607    }
    617608}
    618609
    619 let playerHeight = (heighLimits[4] + heighLimits[5]) / 2;
     610log("Start location chosen after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
     611RMS.SetProgress(30);
    620612
    621613/**
    622  * Place start locations (resources later)
     614 * Add paths
    623615 */
    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 = [];
     616let tchm = getTileCenteredHeightmap(); // Calculate tileCenteredHeightMap (This has nothing to to with TILE_CENTERED_HEIGHT_MAP which should be false)
     617let pathPoints = [];
     618let clPath = createTileClass();
    640619for (let i = 0; i < startLocations.length; ++i)
    641620{
    642621    let start = startLocations[i];
    643622    let target = startLocations[(i + 1) % startLocations.length];
    644     pathTerrainClassIDs.push(placeRandomPathToHeight(start, ["road_rome_a"], target, playerHeight, 8, 3, 0.1));
     623    let points = placeRandomPathToHeight(start, target, playerHeight, clPath);
     624    for (let pi = 0; pi < points.length; ++pi)
     625        pathPoints.push(points[pi]);
    645626}
    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 });
    652627
     628log("Paths placed after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
     629RMS.SetProgress(45);
     630
    653631/**
    654  * Get resource spots after players start locations after path are calculated but before they are placed!
     632 * Get resource spots after players start locations calculation
    655633 */
    656634let avoidPoints = deepcopy(startLocations);
    657635for (let i = 0; i < avoidPoints.length; ++i)
    658636    avoidPoints[i].dist = 30;
    659 let resourceSpots = getPointsByHeight({ "min": (heighLimits[3] + heighLimits[4]) / 2, "max": (heighLimits[5] + heighLimits[6]) / 2 }, avoidPoints, pathArea);
     637let resourceSpots = getPointsByHeight({ "min": (heighLimits[3] + heighLimits[4]) / 2, "max": (heighLimits[5] + heighLimits[6]) / 2 }, avoidPoints, clPath);
    660638
    661 /**
    662  * Calculate slope map
    663  */
    664 let slopeMap = getSlopeMap();
     639log("Resource spots chosen after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
     640RMS.SetProgress(55);
    665641
    666642/**
    667643 * Divide tiles in areas by height and avoid paths
     
    673649{
    674650    for (let y = 0; y < tchm[0].length; ++y)
    675651    {
    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)
     652        if (g_Map.tileClasses[clPath].inclusionCount[x][y] > 0) // Avoid paths
    681653            continue;
    682654       
    683655        let minHeight = heightRange.min;
     
    697669/**
    698670 * Get max slope of each area
    699671 */
     672let slopeMap = getSlopeMap(); // Calculate slope map
    700673let minSlope = [];
    701674let maxSlope = [];
    702675for (let h = 0; h < heighLimits.length; ++h)
     
    744717    }
    745718}
    746719
     720log("Terrain texture placement finished after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
     721RMS.SetProgress(80);
     722
    747723/**
    748  * Add starting resources after terrain texture painting
     724 * Add start locations and resource spots after terrain texture and path painting
    749725 */
    750 for (let p = 0; p < g_MapSettings.PlayerData.length - 1; ++p)
     726for (let p = 0; p < playerIDs.length; ++p)
     727{
     728    let point = startLocations[p];
     729    rectangularSmoothToHeight(point, 40, 40, playerHeight, 0.7);
     730    placeCivDefaultEntities(point.x, point.y, playerIDs[p], { "iberWall": true });
    751731    placeStartLocationResources(startLocations[p]);
    752 
    753 /**
    754  * Add resource spots after terrain texture painting
    755  */
     732}
    756733for (let i = 0; i < resourceSpots.length; ++i)
    757734{
    758735    let choice = i % 5;
     
    771748/**
    772749 * Stop Timer
    773750 */
    774 log("Map generation finished after " + ((new Date().getTime() - genStartTime) / 1000) + "s")
     751log("Map generation finished after " + ((new Date().getTime() - genStartTime) / 1000) + "s");
    775752
    776753/**
    777754 * Export map data