diff --git a/binaries/data/mods/public/maps/random/caledonian_meadows.js b/binaries/data/mods/public/maps/random/caledonian_meadows.js index 14b1677419..db3c13ab26 100644 --- a/binaries/data/mods/public/maps/random/caledonian_meadows.js +++ b/binaries/data/mods/public/maps/random/caledonian_meadows.js @@ -15,11 +15,20 @@ const g_Map = new RandomMap(0, "whiteness"); */ // Mines const decorations = [ - "actor|geology/gray1.xml", "actor|geology/gray_rock1.xml", - "actor|geology/highland1.xml", "actor|geology/highland2.xml", "actor|geology/highland3.xml", - "actor|geology/highland_c.xml", "actor|geology/highland_d.xml", "actor|geology/highland_e.xml", - "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml", - "actor|props/flora/bush_tempe_a.xml", "actor|props/flora/bush_tempe_b.xml", "actor|props/flora/ferns.xml" + "actor|geology/gray1.xml", + "actor|geology/gray_rock1.xml", + "actor|geology/highland1.xml", + "actor|geology/highland2.xml", + "actor|geology/highland3.xml", + "actor|geology/highland_c.xml", + "actor|geology/highland_d.xml", + "actor|geology/highland_e.xml", + "actor|props/flora/bush.xml", + "actor|props/flora/bush_dry_a.xml", + "actor|props/flora/bush_highlands.xml", + "actor|props/flora/bush_tempe_a.xml", + "actor|props/flora/bush_tempe_b.xml", + "actor|props/flora/ferns.xml" ]; function placeMine(point, centerEntity) @@ -32,7 +41,8 @@ function placeMine(point, centerEntity) g_Map.placeEntityPassable( pickRandom(decorations), 0, - Vector2D.add(point, new Vector2D(randFloat(2, 5), 0).rotate(-dAngle * randFloat(i, i + 1))), + Vector2D.add(point, + new Vector2D(randFloat(2, 5), 0).rotate(-dAngle * randFloat(i, i + 1))), randomAngle()); } @@ -41,10 +51,34 @@ g_WallStyles.other = { "overlap": 0, "fence": readyWallElement("structures/fence_long", "gaia"), "fence_short": readyWallElement("structures/fence_short", "gaia"), - "bench": { "angle": Math.PI / 2, "length": 1.5, "indent": 0, "bend": 0, "templateName": "structures/bench" }, - "sheep": { "angle": 0, "length": 0, "indent": 0.75, "bend": 0, "templateName": "gaia/fauna_sheep" }, - "foodBin": { "angle": Math.PI / 2, "length": 1.5, "indent": 0, "bend": 0, "templateName": "gaia/treasure/food_bin" }, - "farmstead": { "angle": Math.PI, "length": 0, "indent": -3, "bend": 0, "templateName": "structures/brit/farmstead" } + "bench": { + "angle": Math.PI / 2, + "length": 1.5, + "indent": 0, + "bend": 0, + "templateName": "structures/bench" + }, + "sheep": { + "angle": 0, + "length": 0, + "indent": 0.75, + "bend": 0, + "templateName": "gaia/fauna_sheep" + }, + "foodBin": { + "angle": Math.PI / 2, + "length": 1.5, + "indent": 0, + "bend": 0, + "templateName": "gaia/treasure/food_bin" + }, + "farmstead": { + "angle": Math.PI, + "length": 0, + "indent": -3, + "bend": 0, + "templateName": "structures/brit/farmstead" + } }; const fences = [ @@ -78,17 +112,19 @@ const fences = [ "turn_0.25", "sheep", "turn_0.25", "fence_short", "sheep", "fence", "turn_0.25", "sheep", "turn_0.25", "fence_short", "sheep", "fence" ]) -]; -const num = fences.length; -for (let i = 0; i < num; ++i) - fences.push(new Fortress("fence", clone(fences[i].wall).reverse())); +].flatMap(fence => [fence, new Fortress("fence", clone(fence.wall).reverse())]); // Groves, only wood const groveEntities = ["gaia/tree/bush_temperate", "gaia/tree/euro_beech"]; const groveActors = [ - "actor|geology/highland1_moss.xml", "actor|geology/highland2_moss.xml", - "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml", - "actor|props/flora/bush_tempe_a.xml", "actor|props/flora/bush_tempe_b.xml", "actor|props/flora/ferns.xml" + "actor|geology/highland1_moss.xml", + "actor|geology/highland2_moss.xml", + "actor|props/flora/bush.xml", + "actor|props/flora/bush_dry_a.xml", + "actor|props/flora/bush_highlands.xml", + "actor|props/flora/bush_tempe_a.xml", + "actor|props/flora/bush_tempe_b.xml", + "actor|props/flora/ferns.xml" ]; function placeGrove(point) @@ -112,14 +148,27 @@ function placeGrove(point) } // Camps with fire and gold treasure -function placeCamp(point, - centerEntity = "actor|props/special/eyecandy/campfire.xml", - otherEntities = ["gaia/treasure/metal", "gaia/treasure/standing_stone", - "units/brit/infantry_slinger_b", "units/brit/infantry_javelineer_b", "units/gaul/infantry_slinger_b", "units/gaul/infantry_javelineer_b", "units/gaul/champion_fanatic", - "actor|props/special/common/waypoint_flag.xml", "actor|props/special/eyecandy/barrel_a.xml", "actor|props/special/eyecandy/basket_celt_a.xml", "actor|props/special/eyecandy/crate_a.xml", "actor|props/special/eyecandy/dummy_a.xml", "actor|props/special/eyecandy/handcart_1.xml", "actor|props/special/eyecandy/handcart_1_broken.xml", "actor|props/special/eyecandy/sack_1.xml", "actor|props/special/eyecandy/sack_1_rough.xml" - ] -) +function placeCamp(point) { + const centerEntity = "actor|props/special/eyecandy/campfire.xml"; + const otherEntities = [ + "gaia/treasure/metal", + "gaia/treasure/standing_stone", + "units/brit/infantry_slinger_b", + "units/brit/infantry_javelineer_b", + "units/gaul/infantry_slinger_b", + "units/gaul/infantry_javelineer_b", + "units/gaul/champion_fanatic", + "actor|props/special/common/waypoint_flag.xml", + "actor|props/special/eyecandy/barrel_a.xml", + "actor|props/special/eyecandy/basket_celt_a.xml", + "actor|props/special/eyecandy/crate_a.xml", + "actor|props/special/eyecandy/dummy_a.xml", + "actor|props/special/eyecandy/handcart_1.xml", + "actor|props/special/eyecandy/handcart_1_broken.xml", + "actor|props/special/eyecandy/sack_1.xml", + "actor|props/special/eyecandy/sack_1_rough.xml" + ]; g_Map.placeEntityPassable(centerEntity, 0, point, randomAngle()); const quantity = randIntInclusive(5, 11); const dAngle = 2 * Math.PI / quantity; @@ -127,12 +176,14 @@ function placeCamp(point, { const angle = dAngle * randFloat(i, i + 1); const dist = randFloat(1, 3); - g_Map.placeEntityPassable(pickRandom(otherEntities), 0, Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle)), randomAngle()); + g_Map.placeEntityPassable(pickRandom(otherEntities), 0, + Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle)), randomAngle()); } } -function placeStartLocationResources(point, foodEntities = ["gaia/fruit/berry_01", "gaia/fauna_chicken", "gaia/fauna_chicken"]) +function placeStartLocationResources(point) { + const foodEntities = ["gaia/fruit/berry_01", "gaia/fauna_chicken", "gaia/fauna_chicken"]; let currentAngle = randomAngle(); // Stone and chicken let dAngle = 4/9 * Math.PI; @@ -192,8 +243,12 @@ const heightScale = (g_Map.size + 256) / 768 / 4; const heightRange = { "min": MIN_HEIGHT * heightScale, "max": MAX_HEIGHT * heightScale }; // Water coverage -const averageWaterCoverage = 1/5; // NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with the same value -const heightSeaGround = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); // Water height in environment and the engine +// NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with the +// same value +const averageWaterCoverage = 1 / 5; +// Water height in environment and the engine +const heightSeaGround = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * + (heightRange.max - heightRange.min); const heightSeaGroundAdjusted = heightSeaGround + MIN_HEIGHT; // Water height in RMGEN setWaterHeight(heightSeaGround); @@ -211,80 +266,243 @@ rescaleHeightmap(heightRange.min, heightRange.max); Engine.SetProgress(25); const heighLimits = [ - heightRange.min + 1/3 * (heightSeaGroundAdjusted - heightRange.min), // 0 Deep water - heightRange.min + 2/3 * (heightSeaGroundAdjusted - heightRange.min), // 1 Medium Water - heightRange.min + (heightSeaGroundAdjusted - heightRange.min), // 2 Shallow water - heightSeaGroundAdjusted + 1/8 * (heightRange.max - heightSeaGroundAdjusted), // 3 Shore - heightSeaGroundAdjusted + 2/8 * (heightRange.max - heightSeaGroundAdjusted), // 4 Low ground - heightSeaGroundAdjusted + 3/8 * (heightRange.max - heightSeaGroundAdjusted), // 5 Player and path height - heightSeaGroundAdjusted + 4/8 * (heightRange.max - heightSeaGroundAdjusted), // 6 High ground - heightSeaGroundAdjusted + 5/8 * (heightRange.max - heightSeaGroundAdjusted), // 7 Lower forest border - heightSeaGroundAdjusted + 6/8 * (heightRange.max - heightSeaGroundAdjusted), // 8 Forest - heightSeaGroundAdjusted + 7/8 * (heightRange.max - heightSeaGroundAdjusted), // 9 Upper forest border - heightSeaGroundAdjusted + (heightRange.max - heightSeaGroundAdjusted)]; // 10 Hilltop + // 0 Deep water + [true, 1 / 3], + // 1 Medium Water + [true, 2 / 3], + // 2 Shallow water + [true, 3 / 3], + // 3 Shore + [false, 1 / 8], + // 4 Low ground + [false, 2 / 8], + // 5 Player and path height + [false, 3 / 8], + // 6 High ground + [false, 4 / 8], + // 7 Lower forest border + [false, 5 / 8], + // 8 Forest + [false, 6 / 8], + // 9 Upper forest border + [false, 7 / 8], + // 10 Hilltop + [false, 8 / 8] +].map(([underWater, ratio]) => { + const base = underWater ? heightRange.min : heightSeaGround; + const factor = underWater ? heightSeaGroundAdjusted - heightRange.min : + heightRange.max - heightSeaGroundAdjusted; + return base + ratio * factor; +}); const playerHeight = (heighLimits[4] + heighLimits[5]) / 2; // Average player height g_Map.log("Determining height-dependent biome"); // Texture and actor presets -const myBiome = []; -myBiome.push({ // 0 Deep water - "texture": ["shoreline_stoney_a"], - "entity": [["gaia/fish/generic", "actor|geology/stone_granite_boulder.xml"], 0.02], - "textureHS": ["alpine_mountainside"], "entityHS": [["gaia/fish/generic"], 0.1] -}); -myBiome.push({ // 1 Medium Water - "texture": ["shoreline_stoney_a", "alpine_shore_rocks"], - "entity": [["actor|geology/stone_granite_boulder.xml", "actor|geology/stone_granite_med.xml"], 0.03], - "textureHS": ["alpine_mountainside"], "entityHS": [["actor|geology/stone_granite_boulder.xml", "actor|geology/stone_granite_med.xml"], 0.0] -}); -myBiome.push({ // 2 Shallow water - "texture": ["alpine_shore_rocks"], - "entity": [["actor|props/flora/reeds_pond_dry.xml", "actor|geology/stone_granite_large.xml", "actor|geology/stone_granite_med.xml", "actor|props/flora/reeds_pond_lush_b.xml"], 0.2], - "textureHS": ["alpine_mountainside"], "entityHS": [["actor|props/flora/reeds_pond_dry.xml", "actor|geology/stone_granite_med.xml"], 0.1] -}); -myBiome.push({ // 3 Shore - "texture": ["alpine_shore_rocks_grass_50", "alpine_grass_rocky"], - "entity": [["gaia/tree/pine", "gaia/tree/bush_badlands", "actor|geology/highland1_moss.xml", "actor|props/flora/grass_soft_tuft_a.xml", "actor|props/flora/bush.xml"], 0.3], - "textureHS": ["alpine_mountainside"], "entityHS": [["actor|props/flora/grass_soft_tuft_a.xml"], 0.1] -}); -myBiome.push({ // 4 Low ground - "texture": ["alpine_dirt_grass_50", "alpine_grass_rocky"], - "entity": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_soft_tuft_a.xml", "actor|props/flora/bush.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], - "textureHS": ["alpine_grass_rocky"], "entityHS": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_soft_tuft_a.xml"], 0.1] -}); -myBiome.push({ // 5 Player and path height - "texture": ["new_alpine_grass_c", "new_alpine_grass_b", "new_alpine_grass_d"], - "entity": [["actor|geology/stone_granite_small.xml", "actor|props/flora/grass_soft_small.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], - "textureHS": ["alpine_grass_rocky"], "entityHS": [["actor|geology/stone_granite_small.xml", "actor|props/flora/grass_soft_small.xml"], 0.1] -}); -myBiome.push({ // 6 High ground - "texture": ["new_alpine_grass_a", "alpine_grass_rocky"], - "entity": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_tufts_a.xml", "actor|props/flora/bush_highlands.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], - "textureHS": ["alpine_grass_rocky"], "entityHS": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_tufts_a.xml"], 0.1] -}); -myBiome.push({ // 7 Lower forest border - "texture": ["new_alpine_grass_mossy", "alpine_grass_rocky"], - "entity": [["gaia/tree/pine", "gaia/tree/oak", "actor|props/flora/grass_tufts_a.xml", "gaia/fruit/berry_01", "actor|geology/highland2_moss.xml", "gaia/fauna_goat", "actor|props/flora/bush_tempe_underbrush.xml"], 0.3], - "textureHS": ["alpine_cliff_c"], "entityHS": [["actor|props/flora/grass_tufts_a.xml", "actor|geology/highland2_moss.xml"], 0.1] -}); -myBiome.push({ // 8 Forest - "texture": ["alpine_forrestfloor"], - "entity": [["gaia/tree/pine", "gaia/tree/pine", "gaia/tree/pine", "gaia/tree/pine", "actor|geology/highland2_moss.xml", "actor|props/flora/bush_highlands.xml"], 0.5], - "textureHS": ["alpine_cliff_c"], "entityHS": [["actor|geology/highland2_moss.xml", "actor|geology/stone_granite_med.xml"], 0.1] -}); -myBiome.push({ // 9 Upper forest border - "texture": ["alpine_forrestfloor_snow", "new_alpine_grass_dirt_a"], - "entity": [["gaia/tree/pine", "actor|geology/snow1.xml"], 0.3], - "textureHS": ["alpine_cliff_b"], "entityHS": [["actor|geology/stone_granite_med.xml", "actor|geology/snow1.xml"], 0.1] -}); -myBiome.push({ // 10 Hilltop - "texture": ["alpine_cliff_a", "alpine_cliff_snow"], - "entity": [["actor|geology/highland1.xml"], 0.05], - "textureHS": ["alpine_cliff_c"], "entityHS": [["actor|geology/highland1.xml"], 0.0] -}); +const myBiome = [ + // 0 Deep water + { + "flat": { + "texture": ["shoreline_stoney_a"], + "entity": ["gaia/fish/generic", "actor|geology/stone_granite_boulder.xml"], + "entityPropability": 0.02 + }, + "steep": { + "texture": ["alpine_mountainside"], + "entity": ["gaia/fish/generic"], + "entityPropability": 0.1 + } + }, -const [playerIDs, playerPosition] = groupPlayersCycle(getStartLocationsByHeightmap({ "min": heighLimits[4], "max": heighLimits[5] }, 1000, 30)); + // 1 Medium Water + { + "flat": { + "texture": ["shoreline_stoney_a", "alpine_shore_rocks"], + "entity": + ["actor|geology/stone_granite_boulder.xml", "actor|geology/stone_granite_med.xml"], + "entityPropability": 0.03 + }, + "steep": { + "texture": ["alpine_mountainside"], + "entity": + ["actor|geology/stone_granite_boulder.xml", "actor|geology/stone_granite_med.xml"], + "entityPropability": 0.0 + } + }, + + // 2 Shallow water + { + "flat": { + "texture": ["alpine_shore_rocks"], + "entity": [ + "actor|props/flora/reeds_pond_dry.xml", + "actor|geology/stone_granite_large.xml", + "actor|geology/stone_granite_med.xml", + "actor|props/flora/reeds_pond_lush_b.xml" + ], + "entityPropability": 0.2 + }, + "steep": { + "texture": ["alpine_mountainside"], + "entity": ["actor|props/flora/reeds_pond_dry.xml", "actor|geology/stone_granite_med.xml"], + "entityPropability": 0.1 + } + }, + + // 3 Shore + { + "flat": { + "texture": ["alpine_shore_rocks_grass_50", "alpine_grass_rocky"], + "entity": [ + "gaia/tree/pine", + "gaia/tree/bush_badlands", + "actor|geology/highland1_moss.xml", + "actor|props/flora/grass_soft_tuft_a.xml", + "actor|props/flora/bush.xml" + ], + "entityPropability": 0.3 + }, + "steep": { + "texture": ["alpine_mountainside"], + "entity": ["actor|props/flora/grass_soft_tuft_a.xml"], + "entityPropability": 0.1 + } + }, + + // 4 Low ground + { + "flat": { + "texture": ["alpine_dirt_grass_50", "alpine_grass_rocky"], + "entity": [ + "actor|geology/stone_granite_med.xml", + "actor|props/flora/grass_soft_tuft_a.xml", + "actor|props/flora/bush.xml", + "actor|props/flora/grass_medit_flowering_tall.xml" + ], + "entityPropability": 0.2 + }, + "steep": { + "texture": ["alpine_grass_rocky"], + "entity": + ["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_soft_tuft_a.xml"], + "entityPropability": 0.1 + } + }, + + // 5 Player and path height + { + "flat": { + "texture": ["new_alpine_grass_c", "new_alpine_grass_b", "new_alpine_grass_d"], + "entity": [ + "actor|geology/stone_granite_small.xml", + "actor|props/flora/grass_soft_small.xml", + "actor|props/flora/grass_medit_flowering_tall.xml" + ], + "entityPropability": 0.2 + }, + "steep": { + "texture": ["alpine_grass_rocky"], + "entity": + ["actor|geology/stone_granite_small.xml", "actor|props/flora/grass_soft_small.xml"], + "entityPropability": 0.1 + } + }, + + // 6 High ground + { + "flat": { + "texture": ["new_alpine_grass_a", "alpine_grass_rocky"], + "entity": [ + "actor|geology/stone_granite_med.xml", + "actor|props/flora/grass_tufts_a.xml", + "actor|props/flora/bush_highlands.xml", + "actor|props/flora/grass_medit_flowering_tall.xml" + ], + "entityPropability": 0.2 + }, + "steep": { + "texture": ["alpine_grass_rocky"], + "entity": ["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_tufts_a.xml"], + "entityPropability": 0.1 + } + }, + + // 7 Lower forest border + { + "flat": { + "texture": ["new_alpine_grass_mossy", "alpine_grass_rocky"], + "entity": [ + "gaia/tree/pine", + "gaia/tree/oak", + "actor|props/flora/grass_tufts_a.xml", + "gaia/fruit/berry_01", + "actor|geology/highland2_moss.xml", + "gaia/fauna_goat", + "actor|props/flora/bush_tempe_underbrush.xml" + ], + "entityPropability": 0.3 + }, + "steep": { + "texture": ["alpine_cliff_c"], + "entity": ["actor|props/flora/grass_tufts_a.xml", "actor|geology/highland2_moss.xml"], + "entityPropability": 0.1 + } + }, + + // 8 Forest + { + "flat": { + "texture": ["alpine_forrestfloor"], + "entity": [ + "gaia/tree/pine", + "gaia/tree/pine", + "gaia/tree/pine", + "gaia/tree/pine", + "actor|geology/highland2_moss.xml", + "actor|props/flora/bush_highlands.xml" + ], + "entityPropability": 0.5 + }, + "steep": { + "texture": ["alpine_cliff_c"], + "entity": [ + "actor|geology/highland2_moss.xml", "actor|geology/stone_granite_med.xml" + ], + "entityPropability": 0.1 + } + }, + + // 9 Upper forest border + { + "flat": { + "texture": ["alpine_forrestfloor_snow", "new_alpine_grass_dirt_a"], + "entity": ["gaia/tree/pine", "actor|geology/snow1.xml"], + "entityPropability": 0.3 + }, + "steep": { + "texture": ["alpine_cliff_b"], + "entity": ["actor|geology/stone_granite_med.xml", "actor|geology/snow1.xml"], + "entityPropability": 0.1 + } + }, + + // 10 Hilltop + { + "flat": { + "texture": ["alpine_cliff_a", "alpine_cliff_snow"], + "entity": ["actor|geology/highland1.xml"], + "entityPropability": 0.05 + }, + "steep": { + "texture": ["alpine_cliff_c"], + "entity": ["actor|geology/highland1.xml"], + "entityPropability": 0.0 + } + } +]; + +const [playerIDs, playerPosition] = groupPlayersCycle( + getStartLocationsByHeightmap({ "min": heighLimits[4], "max": heighLimits[5] }, 1000, 30)); Engine.SetProgress(30); g_Map.log("Smoothing player locations"); @@ -297,7 +515,8 @@ g_Map.log("Creating paths between players"); const clPath = g_Map.createTileClass(); for (let i = 0; i < playerPosition.length; ++i) createArea( - new RandomPathPlacer(playerPosition[i], playerPosition[(i + 1) % playerPosition.length], 4, 2, false), + new RandomPathPlacer(playerPosition[i], + playerPosition[(i + 1) % playerPosition.length], 4, 2, false), [ new TerrainPainter(tPath), new ElevationBlendingPainter(playerHeight, 0.4), @@ -314,9 +533,14 @@ Engine.SetProgress(45); g_Map.log("Determining resource locations"); const avoidPoints = playerPosition.map(pos => pos.clone()); -for (let i = 0; i < avoidPoints.length; ++i) - avoidPoints[i].dist = 30; -const resourceSpots = getPointsByHeight({ "min": (heighLimits[3] + heighLimits[4]) / 2, "max": (heighLimits[5] + heighLimits[6]) / 2 }, avoidPoints, clPath); +avoidPoints.forEach(point => { point.dist = 30; }); +const resourceSpots = getPointsByHeight( + { + "min": (heighLimits[3] + heighLimits[4]) / 2, + "max": (heighLimits[5] + heighLimits[6]) / 2 + }, + avoidPoints, + clPath); Engine.SetProgress(55); /** @@ -328,67 +552,35 @@ for (let x = 0; x < tchm.length; ++x) for (let y = 0; y < tchm[0].length; ++y) { const position = new Vector2D(x, y); - if (!avoidClasses(clPath, 0).allows(position)) + if (!avoidClasses(clPath, 0).allows(position) || tchm[x][y] < heightRange.min) continue; - let minHeight = heightRange.min; - for (let h = 0; h < heighLimits.length; ++h) - { - if (tchm[x][y] >= minHeight && tchm[x][y] <= heighLimits[h]) - { - areas[h].push(position); - break; - } - - minHeight = heighLimits[h]; - } + const index = heighLimits.findIndex(limit => tchm[x][y] <= limit); + if (index !== -1) + areas[index].push(position); } /** - * Get max slope of each area + * Get midpoint slope of each area */ const slopeMap = getSlopeMap(); -const minSlope = []; -const maxSlope = []; -for (let h = 0; h < heighLimits.length; ++h) -{ - minSlope[h] = Infinity; - maxSlope[h] = 0; - for (const point of areas[h]) - { - const slope = slopeMap[point.x][point.y]; - - if (slope > maxSlope[h]) - maxSlope[h] = slope; - - if (slope < minSlope[h]) - minSlope[h] = slope; - } -} +const slopeMidpoints = areas.map(area => { + const slopesInThisArea = area.map(({ x, y }) => slopeMap[x][y]); + return Math.min(...slopesInThisArea) + Math.max(...slopesInThisArea); +}); g_Map.log("Painting areas by height and slope"); for (let h = 0; h < heighLimits.length; ++h) for (const point of areas[h]) { - let entity; - let texture = pickRandom(myBiome[h].texture); + const isFlat = slopeMap[point.x][point.y] < 0.4 * slopeMidpoints[h]; + const selectedBiome = myBiome[h][isFlat? "flat" : "steep"]; - if (slopeMap[point.x][point.y] < 0.4 * (minSlope[h] + maxSlope[h])) - { - if (randBool(myBiome[h].entity[1])) - entity = pickRandom(myBiome[h].entity[0]); - } - else - { - texture = pickRandom(myBiome[h].textureHS); - if (randBool(myBiome[h].entityHS[1])) - entity = pickRandom(myBiome[h].entityHS[0]); - } + g_Map.setTexture(point, pickRandom(selectedBiome.texture)); - g_Map.setTexture(point, texture); - - if (entity) - g_Map.placeEntityPassable(entity, 0, randomPositionOnTile(point), randomAngle()); + if (randBool(selectedBiome.entityPropability)) + g_Map.placeEntityPassable(pickRandom(selectedBiome.entity), 0, + randomPositionOnTile(point), randomAngle()); } Engine.SetProgress(80);