Ticket #4275: optimize_caledonian_meadows2016_10_9b.patch

File optimize_caledonian_meadows2016_10_9b.patch, 14.9 KB (added by FeXoR, 8 years ago)

Fixes as proposed by elexis, fixes an issue with an optional argument

  • 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(
     147    start, target, targetHeight, tileClass = undefined, texture = "road_rome_a",
     148    width = 10, distance = 4, strength = 0.08, heightmap = g_Map.height)
    151149{
    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 = [];
    157151    let position = deepcopy(start);
    158     while (!targetReached)
     152    while (true)
    159153    {
    160154        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            {
     159                createArea(new ClumpPlacer(0.3 * width * width, 1, 1, 1, floor(position.x), floor(position.y)),
     160                    [new TerrainPainter(texture), paintClass(tileClass)]);
     161            }
     162            else
     163            {
     164                createArea(new ClumpPlacer(0.3 * width * width, 1, 1, 1, floor(position.x), floor(position.y)),
     165                    new TerrainPainter(texture));
     166            }
     167        }
     168        pathPoints.push({ "x": position.x, "y": position.y, "dist": distance });
     169        // Check for distance to target and setup for next loop if needed
     170        if (getDistance(position.x, position.y, target.x, target.y) < distance / 2)
     171            break;
    165172        let angleToTarget = getAngle(position.x, position.y, target.x, target.y);
    166173        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;
     174        position.x += distance * cos(angleToTarget + angleOff);
     175        position.y += distance * sin(angleToTarget + angleOff);
    171176    }
    172     return clTempPath;
     177    return pathPoints;
    173178}
    174179
    175180function getGrad(wrapped = true, scalarField = g_Map.height)
     
    240245/**
    241246 * Meant to place e.g. resource spots within a height range
    242247 * @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
     248 * @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
     249 * @param {object} [avoidClass=undefined] - TileClass to be avoided
    245250 * @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
    246251 * @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
     252 * @param {integer} [maxTries=2 * g_Map.size] - How often random player distributions are rolled to be compared (256 to 1024)
    248253 * @param {boolean} [isCircular=g_MapSettings.CircularMap] - If the map is circular or rectangular
    249254 */
    250 function getPointsByHeight(heightRange, avoidPoints, avoidArea, minDistance = 20, maxTries = 1000, heightmap = g_Map.height, isCircular = g_MapSettings.CircularMap)
     255function getPointsByHeight(heightRange, avoidPoints = [], avoidClass = undefined, minDistance = 20, maxTries = 2 * g_Map.size, heightmap = g_Map.height, isCircular = g_MapSettings.CircularMap)
    251256{
    252257    let points = [];
    253258    let placements = deepcopy(avoidPoints);
    254259    let validVertices = [];
    255260    let r = 0.5 * (heightmap.length - 1); // Map center x/y as well as radius
     261
    256262    for (let x = minDistance; x < heightmap.length - minDistance; ++x)
    257263    {
    258264        for (let y = minDistance; y < heightmap[0].length - minDistance; ++y)
    259265        {
    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)
     266            if (avoidClass !== undefined && // Avoid adjecting tiles in avoidClass
     267                (g_Map.tileClasses[avoidClass].inclusionCount[max(x - 1, 0)][y] > 0 || g_Map.tileClasses[avoidClass].inclusionCount[x][max(y - 1, 0)] > 0 ||
     268                g_Map.tileClasses[avoidClass].inclusionCount[min(x + 1, g_Map.tileClasses[avoidClass].inclusionCount.length - 1)][y] > 0 ||
     269                g_Map.tileClasses[avoidClass].inclusionCount[x][min(y + 1, g_Map.tileClasses[avoidClass].inclusionCount[0].length - 1)] > 0)
     270            )
    265271                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
     272
     273            if (heightmap[x][y] > heightRange.min && heightmap[x][y] < heightRange.max && // Has correct height
     274                (!isCircular || r - getDistance(x, y, r, r) >= minDistance)) // Enough distance to map border
    268275                validVertices.push({ "x": x, "y": y , "dist": minDistance});
    269276        }
    270277    }
    271    
     278
    272279    for (let tries = 0; tries < maxTries; ++tries)
    273280    {
    274281        let point = validVertices[randInt(validVertices.length)];
     
    277284            points.push(point);
    278285            placements.push(point);
    279286        }
     287        if ((tries != 0) && (tries % 100 == 0)) // Time Check
     288            log(points.length + " points found after " + tries + " tries after " + ((new Date().getTime() - genStartTime) / 1000) + "s");
    280289    }
    281    
     290
    282291    return points;
    283292}
    284293
     
    294303    "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml",
    295304    "actor|props/flora/bush_tempe_a.xml", "actor|props/flora/bush_tempe_b.xml", "actor|props/flora/ferns.xml"
    296305];
    297 
    298306function placeMine(point, centerEntity)
    299307{
    300308    placeObject(point.x, point.y, centerEntity, 0, randFloat(0, TWO_PI));
     
    334342    fences.push(new Fortress("fence", deepcopy(fences[i].wall).reverse()));
    335343
    336344// Groves, only Wood
    337 let groveEntities = [
    338     "gaia/flora_bush_temperate", "gaia/flora_tree_euro_beech"
    339 ];
     345let groveEntities = ["gaia/flora_bush_temperate", "gaia/flora_tree_euro_beech"];
    340346let groveActors = [
    341347    "actor|geology/highland1_moss.xml", "actor|geology/highland2_moss.xml",
    342348    "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml",
     
    383389    }
    384390}
    385391
    386 let foodEntities = ["gaia/flora_bush_berry", "gaia/fauna_chicken", "gaia/fauna_chicken"];
    387 // Start loaction resources
    388 function placeStartLocationResources(point)
     392
     393function placeStartLocationResources(point, foodEntities = ["gaia/flora_bush_berry", "gaia/fauna_chicken", "gaia/fauna_chicken"])
    389394{
    390395    let currentAngle = randFloat(0, TWO_PI);
    391396    // Stone and chicken
     
    438443    }
    439444}
    440445
     446log("Functions loaded after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
     447
    441448/**
    442  * Set height limits and water level by map size
     449 * Environment settings
    443450 */
     451setBiome(g_BiomeAlpine);
     452g_Environment.Fog.FogColor = { "r": 0.8, "g": 0.8, "b": 0.8, "a": 0.01 };
     453g_Environment.Water.WaterBody.Colour = { "r" : 0.3, "g" : 0.05, "b" : 0.1, "a" : 0.1 };
     454g_Environment.Water.WaterBody.Murkiness = 0.4;
     455
     456/**
     457 * Base terrain shape generation and settings
     458 */
     459 // Height range by map size
    444460let heightScale = (g_Map.size + 256) / 768 / 4;
    445461let heightRange = { "min": MIN_HEIGHT * heightScale, "max": MAX_HEIGHT * heightScale };
    446 
     462// Water coverage
    447463let averageWaterCoverage = 1/5; // NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with the same value
    448464let waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); // Water height in environment and the engine
    449465let waterHeightAdjusted = waterHeight + MIN_HEIGHT; // Water height in RMGEN
    450466setWaterHeight(waterHeight);
    451 
    452 
    453 /**
    454  * Generate base terrain
    455  */
     467// Generate base terrain shape
    456468let medH = (heightRange.min + heightRange.max) / 2;
    457469let initialHeightmap = [[medH, medH], [medH, medH]];
    458470setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, initialHeightmap, 0.8);
    459 
    460 /**
    461  * Apply simple erosion
    462  */
    463 // globalSmoothHeightmap(0.5);
     471// Apply simple erosion
    464472for (let i = 0; i < 5; ++i)
    465473    splashErodeMap(0.1);
    466 
     474// Final rescale
    467475rescaleHeightmap(heightRange.min, heightRange.max);
    468476
     477RMS.SetProgress(25);
     478
    469479/**
    470  * Height presets
     480 * Prepare terrain texture placement
    471481 */
    472482let heighLimits = [
    473483    heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), // 0 Deep water
     
    481491    waterHeightAdjusted + 6/8 * (heightRange.max - waterHeightAdjusted), // 8 Forest
    482492    waterHeightAdjusted + 7/8 * (heightRange.max - waterHeightAdjusted), // 9 Upper forest border
    483493    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";
     494let playerHeight = (heighLimits[4] + heighLimits[5]) / 2; // Average player height
     495// Texture and actor presets
    497496let myBiome = [];
    498497myBiome.push({ // 0 Deep water
    499498    "texture": ["shoreline_stoney_a"],
     
    551550    "textureHS": ["alpine_cliff_c"], "actorHS": [["actor|geology/highland1.xml"], 0.0]
    552551});
    553552
     553log("Terrain shape generation and texture presets after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
    554554
    555555/**
    556556 * Get start locations
     
    573573        teams.push(t);
    574574}
    575575playerIDs = sortPlayers(playerIDs);
    576 
    577576// Minimize maximum distance between players within a team
    578577if (teams.length)
    579578{
     
    616615    }
    617616}
    618617
    619 let playerHeight = (heighLimits[4] + heighLimits[5]) / 2;
     618log("Start location chosen after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
     619RMS.SetProgress(30);
    620620
    621621/**
    622  * Place start locations (resources later)
     622 * Add paths
    623623 */
    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 = [];
     624let tchm = getTileCenteredHeightmap(); // Calculate tileCenteredHeightMap (This has nothing to to with TILE_CENTERED_HEIGHT_MAP which should be false)
     625let pathPoints = [];
     626let clPath = createTileClass();
    640627for (let i = 0; i < startLocations.length; ++i)
    641628{
    642629    let start = startLocations[i];
    643630    let target = startLocations[(i + 1) % startLocations.length];
    644     pathTerrainClassIDs.push(placeRandomPathToHeight(start, ["road_rome_a"], target, playerHeight, 8, 3, 0.1));
     631    pathPoints = pathPoints.concat(placeRandomPathToHeight(start, target, playerHeight, clPath));
    645632}
    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 });
    652633
     634log("Paths placed after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
     635RMS.SetProgress(45);
     636
    653637/**
    654  * Get resource spots after players start locations after path are calculated but before they are placed!
     638 * Get resource spots after players start locations calculation
    655639 */
    656640let avoidPoints = deepcopy(startLocations);
    657641for (let i = 0; i < avoidPoints.length; ++i)
    658642    avoidPoints[i].dist = 30;
    659 let resourceSpots = getPointsByHeight({ "min": (heighLimits[3] + heighLimits[4]) / 2, "max": (heighLimits[5] + heighLimits[6]) / 2 }, avoidPoints, pathArea);
     643let resourceSpots = getPointsByHeight({ "min": (heighLimits[3] + heighLimits[4]) / 2, "max": (heighLimits[5] + heighLimits[6]) / 2 }, avoidPoints, clPath);
    660644
    661 /**
    662  * Calculate slope map
    663  */
    664 let slopeMap = getSlopeMap();
     645log("Resource spots chosen after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
     646RMS.SetProgress(55);
    665647
    666648/**
    667649 * Divide tiles in areas by height and avoid paths
     
    673655{
    674656    for (let y = 0; y < tchm[0].length; ++y)
    675657    {
    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)
     658        if (g_Map.tileClasses[clPath].inclusionCount[x][y] > 0) // Avoid paths
    681659            continue;
    682660       
    683661        let minHeight = heightRange.min;
     
    697675/**
    698676 * Get max slope of each area
    699677 */
     678let slopeMap = getSlopeMap(); // Calculate slope map
    700679let minSlope = [];
    701680let maxSlope = [];
    702681for (let h = 0; h < heighLimits.length; ++h)
     
    744723    }
    745724}
    746725
     726log("Terrain texture placement finished after " + ((new Date().getTime() - genStartTime) / 1000) + "s"); // Time Check
     727RMS.SetProgress(80);
     728
    747729/**
    748  * Add starting resources after terrain texture painting
     730 * Add start locations and resource spots after terrain texture and path painting
    749731 */
    750 for (let p = 0; p < g_MapSettings.PlayerData.length - 1; ++p)
     732for (let p = 0; p < playerIDs.length; ++p)
     733{
     734    let point = startLocations[p];
     735    rectangularSmoothToHeight(point, 40, 40, playerHeight, 0.7);
     736    placeCivDefaultEntities(point.x, point.y, playerIDs[p], { "iberWall": true });
    751737    placeStartLocationResources(startLocations[p]);
    752 
    753 /**
    754  * Add resource spots after terrain texture painting
    755  */
     738}
    756739for (let i = 0; i < resourceSpots.length; ++i)
    757740{
    758741    let choice = i % 5;
     
    771754/**
    772755 * Stop Timer
    773756 */
    774 log("Map generation finished after " + ((new Date().getTime() - genStartTime) / 1000) + "s")
     757log("Map generation finished after " + ((new Date().getTime() - genStartTime) / 1000) + "s");
    775758
    776759/**
    777760 * Export map data