Index: ps/trunk/binaries/data/mods/public/maps/random/corsica.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/corsica.js (revision 20904) +++ ps/trunk/binaries/data/mods/public/maps/random/corsica.js (revision 20905) @@ -1,541 +1,541 @@ Engine.LoadLibrary("rmgen"); var tGrass = ["medit_grass_field", "medit_grass_field_b", "temp_grass_c"]; var tLushGrass = ["medit_grass_field","medit_grass_field_a"]; var tSteepCliffs = ["temp_cliff_b", "temp_cliff_a"]; var tCliffs = ["temp_cliff_b", "medit_cliff_italia", "medit_cliff_italia_grass"]; var tHill = ["medit_cliff_italia_grass","medit_cliff_italia_grass", "medit_grass_field", "medit_grass_field", "temp_grass"]; var tMountain = ["medit_cliff_italia_grass","medit_cliff_italia"]; var tRoad = ["medit_city_tile","medit_rocks_grass","medit_grass_field_b"]; var tRoadWild = ["medit_rocks_grass","medit_grass_field_b"]; var tShoreBlend = ["medit_sand_wet","medit_rocks_wet"]; var tShore = ["medit_rocks","medit_sand","medit_sand"]; var tSandTransition = ["medit_sand","medit_rocks_grass","medit_rocks_grass","medit_rocks_grass"]; var tVeryDeepWater = ["medit_sea_depths","medit_sea_coral_deep"]; var tDeepWater = ["medit_sea_coral_deep","tropic_ocean_coral"]; var tCreekWater = "medit_sea_coral_plants"; var ePine = "gaia/flora_tree_aleppo_pine"; var ePalmTall = "gaia/flora_tree_cretan_date_palm_tall"; var eFanPalm = "gaia/flora_tree_medit_fan_palm"; var eApple = "gaia/flora_tree_apple"; var eBush = "gaia/flora_bush_berry"; var eFish = "gaia/fauna_fish"; var ePig = "gaia/fauna_pig"; var eStoneMine = "gaia/geology_stonemine_medit_quarry"; var eMetalMine = "gaia/geology_metal_mediterranean_slabs"; var aRock = "actor|geology/stone_granite_med.xml"; var aLargeRock = "actor|geology/stone_granite_large.xml"; var aBushA = "actor|props/flora/bush_medit_sm_lush.xml"; var aBushB = "actor|props/flora/bush_medit_me_lush.xml"; var aPlantA = "actor|props/flora/plant_medit_artichoke.xml"; var aPlantB = "actor|props/flora/grass_tufts_a.xml"; var aPlantC = "actor|props/flora/grass_soft_tuft_a.xml"; var aStandingStone = "actor|props/special/eyecandy/standing_stones.xml"; var heightSeaGround = -8; var heightCreeks = -5; var heightBeaches = -1; var heightMain = 5; var heightOffsetMainRelief = 30; var heightOffsetLevel1 = 9; var heightOffsetLevel2 = 8; var heightOffsetBumps = 2; var heightOffsetAntiBumps = -5; InitMap(heightSeaGround, tVeryDeepWater); var numPlayers = getNumPlayers(); var mapSize = getMapSize(); var mapCenter = getMapCenter(); var clIsland = createTileClass(); var clCreek = createTileClass(); var clWater = createTileClass(); var clCliffs = createTileClass(); var clForest = createTileClass(); var clShore = createTileClass(); var clPlayer = createTileClass(); var clBaseResource = createTileClass(); var clPassage = createTileClass(); var clSettlement = createTileClass(); var radiusBeach = fractionToTiles(0.57); var radiusCreeks = fractionToTiles(0.52); var radiusIsland = fractionToTiles(0.4); var radiusLevel1 = fractionToTiles(0.35); var radiusPlayer = fractionToTiles(0.25); var radiusLevel2 = fractionToTiles(0.2); var creeksArea = () => randBool() ? randFloat(10, 50) : scaleByMapSize(75, 100) + randFloat(0, 20); var nbCreeks = scaleByMapSize(6, 15); var nbSubIsland = 5; var nbBeaches = scaleByMapSize(2, 5); var nbPassagesLevel1 = scaleByMapSize(4, 8); var nbPassagesLevel2 = scaleByMapSize(2, 4); log("Creating Corsica and Sardinia..."); var swapAngle = randBool() ? Math.PI / 2 : 0; var islandLocations = [new Vector2D(0.05, 0.05), new Vector2D(0.95, 0.95)].map(v => v.mult(mapSize).rotateAround(-swapAngle, mapCenter)); for (let island = 0; island < 2; ++island) { log("Creating island area..."); createArea( new ClumpPlacer(diskArea(radiusIsland), 1, 0.5, 10, islandLocations[island].x, islandLocations[island].y), [ new LayeredPainter([tCliffs, tGrass], [2]), new SmoothElevationPainter(ELEVATION_SET, heightMain, 0), paintClass(clIsland) ]); log("Creating subislands..."); for (let i = 0; i < nbSubIsland + 1; ++i) { let angle = Math.PI * (island + i / (nbSubIsland * 2)) + swapAngle; let location = Vector2D.add(islandLocations[island], new Vector2D(radiusIsland, 0).rotate(-angle)); createArea( - new ClumpPlacer(fractionToSize(0.05) / 2, 0.6, 0.03, 10, location.x, location.y), + new ClumpPlacer(diskArea(fractionToTiles(0.09)), 0.6, 0.03, 10, location.x, location.y), [ new LayeredPainter([tCliffs, tGrass], [2]), new SmoothElevationPainter(ELEVATION_SET, heightMain, 1), paintClass(clIsland) ]); } log("Creating creeks..."); for (let i = 0; i < nbCreeks + 1; ++i) { let angle = Math.PI * (island + i * (1 / (nbCreeks * 2))) + swapAngle; let location = Vector2D.add(islandLocations[island], new Vector2D(radiusCreeks, 0).rotate(-angle)); createArea( new ClumpPlacer(creeksArea(), 0.4, 0.01, 10, location.x, location.y), [ new TerrainPainter(tSteepCliffs), new SmoothElevationPainter(ELEVATION_SET, heightCreeks, 0), paintClass(clCreek) ]); } log("Creating beaches..."); for (let i = 0; i < nbBeaches + 1; ++i) { let angle = Math.PI * (island + (i / (nbBeaches * 2.5)) + 1 / (nbBeaches * 6) + randFloat(-1, 1) / (nbBeaches * 7)) + swapAngle; let start = Vector2D.add(islandLocations[island], new Vector2D(radiusIsland, 0).rotate(-angle)); let end = Vector2D.add(islandLocations[island], new Vector2D(radiusBeach, 0).rotate(-angle)); createArea( new ClumpPlacer(130, 0.7, 0.8, 10, Math.round((start.x + end.x * 3) / 4), Math.round((start.y + end.y * 3) / 4)), new SmoothElevationPainter(ELEVATION_SET, heightBeaches, 5)); createPassage({ "start": start, "end": end, "startWidth": 18, "endWidth": 25, "smoothWidth": 4, "tileClass": clShore }); } log("Creating main relief..."); createArea( new ClumpPlacer(diskArea(radiusIsland), 1, 0.2, 10, islandLocations[island].x, islandLocations[island].y), new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetMainRelief, fractionToTiles(0.45))); log("Creating first level plateau..."); createArea( new ClumpPlacer(diskArea(radiusLevel1), 0.95, 0.02, 10, islandLocations[island].x, islandLocations[island].y), new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLevel1, 1)); log("Creating first level passages..."); for (let i = 0; i <= nbPassagesLevel1; ++i) { let angle = Math.PI * (i / 7 + 1 / 9 + island) + swapAngle; createPassage({ "start": Vector2D.add(islandLocations[island], new Vector2D(radiusLevel1 + 10, 0).rotate(-angle)), "end": Vector2D.add(islandLocations[island], new Vector2D(radiusLevel1 - 4, 0).rotate(-angle)), "startWidth": 10, "endWidth": 6, "smoothWidth": 3, "tileClass": clPassage }); } if (mapSize > 150) { log("Creating second level plateau..."); createArea( new ClumpPlacer(diskArea(radiusLevel2), 0.98, 0.04, 10, islandLocations[island].x, islandLocations[island].y), [ new LayeredPainter([tCliffs, tGrass], [2]), new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLevel2, 1) ]); log("Creating second level passages..."); for (let i = 0; i < nbPassagesLevel2; ++i) { let angle = Math.PI * (i / (2 * nbPassagesLevel2) + 1 / (4 * nbPassagesLevel2) + island) + swapAngle; createPassage({ "start": Vector2D.add(islandLocations[island], new Vector2D(radiusLevel2 + 3, 0).rotate(-angle)), "end": Vector2D.add(islandLocations[island], new Vector2D(radiusLevel2 - 6, 0).rotate(-angle)), "startWidth": 4, "endWidth": 6, "smoothWidth": 2, "tileClass": clPassage }); } } } Engine.SetProgress(30); log("Determining player locations..."); var playerIDs = sortAllPlayers(); var playerPosition = []; var playerAngle = []; var p = 0; for (let island = 0; island < 2; ++island) { let playersPerIsland = island == 0 ? Math.ceil(numPlayers / 2) : Math.floor(numPlayers / 2); for (let i = 0; i < playersPerIsland; ++i) { playerAngle[p] = Math.PI * ((i + 0.5) / (2 * playersPerIsland) + island) + swapAngle; playerPosition[p] = Vector2D.add(islandLocations[island], new Vector2D(radiusPlayer).rotate(-playerAngle[p])); ++p; } } placePlayerBases({ "PlayerPlacement": [sortAllPlayers(), playerPosition], "PlayerTileClass": clPlayer, "BaseResourceClass": clBaseResource, "Walls": false, "CityPatch": { "outerTerrain": tRoadWild, "innerTerrain": tRoad, "coherence": 0.8, "radius": 6, "painters": [ paintClass(clSettlement) ] }, "Chicken": { }, "Berries": { "template": eBush }, "Mines": { "types": [ { "template": eMetalMine }, { "template": eStoneMine } ] } // Sufficient starting trees around, no decoratives }); Engine.SetProgress(40); log("Creating bumps..."); createAreas( new ClumpPlacer(70, 0.6, 0.1, 4), [new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBumps, 3)], [ stayClasses(clIsland, 2), avoidClasses(clPlayer, 6, clPassage, 2) ], scaleByMapSize(20, 100), 5); log("Creating anti bumps..."); createAreas( new ClumpPlacer(120, 0.3, 0.1, 4), new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetAntiBumps, 6), avoidClasses(clPlayer, 6, clPassage, 2, clIsland, 2), scaleByMapSize(20, 100), 5); log("Painting water..."); paintTileClassBasedOnHeight(-Infinity, 0, Elevation_ExcludeMin_ExcludeMax, clWater); log("Painting land..."); for (let mapX = 0; mapX < mapSize; ++mapX) for (let mapZ = 0; mapZ < mapSize; ++mapZ) { let terrain = getCosricaSardiniaTerrain(mapX, mapZ); if (!terrain) continue; createTerrain(terrain).place(mapX, mapZ); if (terrain == tCliffs || terrain == tSteepCliffs) addToClass(mapX, mapZ, clCliffs); } function getCosricaSardiniaTerrain(mapX, mapZ) { let isWater = getTileClass(clWater).countMembersInRadius(mapX, mapZ, 3); let isShore = getTileClass(clShore).countMembersInRadius(mapX, mapZ, 2); let isPassage = getTileClass(clPassage).countMembersInRadius(mapX, mapZ, 2); let isSettlement = getTileClass(clSettlement).countMembersInRadius(mapX, mapZ, 2); if (isSettlement) return undefined; let height = getHeight(mapX, mapZ); let heightDiff = getHeightDiff(mapX, mapZ); if (height >= 0.5 && height < 1.5 && isShore) return tSandTransition; // Paint land cliffs and grass if (height >= 1 && !isWater) { if (isPassage) return tGrass; if (heightDiff >= 10) return height > 25 ? tSteepCliffs : tCliffs; if (height < 17) return tGrass; if (heightDiff < 5) return tHill; return tMountain; } if (heightDiff >= 9) return tCliffs; if (height >= 1.5) return undefined; if (height >= -0.75) return tShore; if (height >= -3) return tShoreBlend; if (height >= -6) return tCreekWater; if (height > -10 && heightDiff < 6) return tDeepWater; return undefined; } Engine.SetProgress(65); log("Creating mines..."); for (let mine of [eMetalMine, eStoneMine]) createObjectGroupsDeprecated( new SimpleGroup( [ new SimpleObject(mine, 1,1, 0,0), new SimpleObject(aBushB, 1,1, 2,2), new SimpleObject(aBushA, 0,2, 1,3) ], true, clBaseResource), 0, [ stayClasses(clIsland, 1), avoidClasses( clWater, 3, clPlayer, 6, clBaseResource, 4, clPassage, 2, clCliffs, 1) ], scaleByMapSize(6, 25), 1000); log("Creating grass patches..."); createAreas( new ClumpPlacer(20, 0.3, 0.06, 0.5), [ new TerrainPainter(tLushGrass), paintClass(clForest) ], avoidClasses( clWater, 1, clPlayer, 6, clBaseResource, 3, clCliffs, 1), scaleByMapSize(10, 40)); log("Creating forests..."); createObjectGroupsDeprecated( new SimpleGroup( [ new SimpleObject(ePine, 3, 6, 1, 3), new SimpleObject(ePalmTall, 1, 3, 1, 3), new SimpleObject(eFanPalm, 0, 2, 0, 2), new SimpleObject(eApple, 0, 1, 1, 2) ], true, clForest), 0, [ stayClasses(clIsland, 3), avoidClasses( clWater, 1, clForest, 0, clPlayer, 3, clBaseResource, 4, clPassage, 2, clCliffs, 2) ], scaleByMapSize(350, 2500), 100); Engine.SetProgress(75); log("Creating small decorative rocks..."); createObjectGroupsDeprecated( new SimpleGroup( [ new SimpleObject(aRock, 1, 3, 0, 1), new SimpleObject(aStandingStone, 0, 2, 0, 3) ], true), 0, avoidClasses( clWater, 0, clForest, 0, clPlayer, 6, clBaseResource, 4, clPassage, 2), scaleByMapSize(16, 262), 50); log("Creating large decorative rocks..."); var rocksGroup = new SimpleGroup( [ new SimpleObject(aLargeRock, 1, 2, 0, 1), new SimpleObject(aRock, 1, 3, 0, 2) ], true); createObjectGroupsDeprecated( rocksGroup, 0, avoidClasses( clWater, 0, clForest, 0, clPlayer, 6, clBaseResource, 4, clPassage, 2), scaleByMapSize(8, 131), 50); createObjectGroupsDeprecated( rocksGroup, 0, borderClasses(clWater, 5, 10), scaleByMapSize(100, 800), 500); log("Creating decorative plants..."); var plantGroups = [ new SimpleGroup( [ new SimpleObject(aPlantA, 3, 7, 0, 3), new SimpleObject(aPlantB, 3,6, 0, 3), new SimpleObject(aPlantC, 1,4, 0, 4) ], true), new SimpleGroup( [ new SimpleObject(aPlantB, 5, 20, 0, 5), new SimpleObject(aPlantC, 4,10, 0,4) ], true) ]; for (let group of plantGroups) createObjectGroupsDeprecated( group, 0, avoidClasses( clWater, 0, clBaseResource, 4, clShore, 3), scaleByMapSize(100, 600), 50); Engine.SetProgress(80); log("Creating animals..."); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(ePig, 2,4, 0,3)]), 0, avoidClasses( clWater, 3, clBaseResource, 4, clPlayer, 6), scaleByMapSize(20, 100), 50); log("Creating fish..."); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(eFish, 1,2, 0,3)]), 0, [ stayClasses(clWater, 3), avoidClasses(clCreek, 3, clShore, 3) ], scaleByMapSize(50, 150), 100); Engine.SetProgress(95); placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clBaseResource, 4, clCliffs, 4)); setSkySet(pickRandom(["cumulus", "sunny"])); setSunColor(0.8, 0.66, 0.48); setSunElevation(0.828932); setSunRotation((swapAngle ? 0.288 : 0.788) * Math.PI); setTerrainAmbientColor(0.564706,0.543726,0.419608); setUnitsAmbientColor(0.53,0.55,0.45); setWaterColor(0.2,0.294,0.49); setWaterTint(0.208, 0.659, 0.925); setWaterMurkiness(0.72); setWaterWaviness(2.0); setWaterType("ocean"); ExportMap(); // no need for preliminary rounding function getHeightDiff(x1, z1) { var height = getHeight(Math.round(x1),Math.round(z1)); var diff = 0; if (z1 + 1 < mapSize) diff += Math.abs(getHeight(Math.round(x1),Math.round(z1+1)) - height); if (x1 + 1 < mapSize && z1 + 1 < mapSize) diff += Math.abs(getHeight(Math.round(x1+1),Math.round(z1+1)) - height); if (x1 + 1 < mapSize) diff += Math.abs(getHeight(Math.round(x1+1),Math.round(z1)) - height); if (x1 + 1 < mapSize && z1 - 1 >= 0) diff += Math.abs(getHeight(Math.round(x1+1),Math.round(z1-1)) - height); if (z1 - 1 >= 0) diff += Math.abs(getHeight(Math.round(x1),Math.round(z1-1)) - height); if (x1 - 1 >= 0 && z1 - 1 >= 0) diff += Math.abs(getHeight(Math.round(x1-1),Math.round(z1-1)) - height); if (x1 - 1 >= 0) diff += Math.abs(getHeight(Math.round(x1-1),Math.round(z1)) - height); if (x1 - 1 >= 0 && z1 + 1 < mapSize) diff += Math.abs(getHeight(Math.round(x1-1),Math.round(z1+1)) - height); return diff; } Index: ps/trunk/binaries/data/mods/public/maps/random/deep_forest.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/deep_forest.js (revision 20904) +++ ps/trunk/binaries/data/mods/public/maps/random/deep_forest.js (revision 20905) @@ -1,202 +1,201 @@ Engine.LoadLibrary("rmgen"); var templateStone = "gaia/geology_stone_temperate"; var templateStoneMine = "gaia/geology_stonemine_temperate_quarry"; var templateMetalMine = "gaia/geology_metal_temperate_slabs"; var templateTemple = "other/unfinished_greek_temple"; var terrainWood = ['temp_grass_mossy|gaia/flora_tree_oak', 'temp_forestfloor_pine|gaia/flora_tree_pine', 'temp_mud_plants|gaia/flora_tree_dead', 'temp_plants_bog|gaia/flora_tree_oak_large', "temp_dirt_gravel_plants|gaia/flora_tree_aleppo_pine", 'temp_forestfloor_autumn|gaia/flora_tree_carob']; //'temp_forestfloor_autumn|gaia/flora_tree_fig' var terrainWoodBorder = ['temp_grass_plants|gaia/flora_tree_euro_beech', 'temp_grass_mossy|gaia/flora_tree_poplar', 'temp_grass_mossy|gaia/flora_tree_poplar_lombardy', 'temp_grass_long|gaia/flora_bush_temperate', 'temp_mud_plants|gaia/flora_bush_temperate', 'temp_mud_plants|gaia/flora_bush_badlands', 'temp_grass_long|gaia/flora_tree_apple', 'temp_grass_clovers|gaia/flora_bush_berry', 'temp_grass_clovers_2|gaia/flora_bush_grapes', 'temp_grass_plants|gaia/fauna_deer', "temp_grass_long_b|gaia/fauna_rabbit", "temp_grass_plants"]; var terrainBase = ['temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_grass_b|gaia/fauna_pig', 'temp_dirt_gravel|gaia/fauna_chicken']; var terrainBaseBorder = ["temp_grass_b", "temp_grass_b", "temp_grass", "temp_grass_c", "temp_grass_mossy"]; var terrainBaseCenter = ['temp_dirt_gravel', 'temp_dirt_gravel', 'temp_grass_b']; var terrainPath = ['temp_road', "temp_road_overgrown", 'temp_grass_b']; var terrainHill = ["temp_highlands", "temp_highlands", "temp_highlands", "temp_dirt_gravel_b", "temp_cliff_a"]; var terrainHillBorder = ["temp_highlands", "temp_highlands", "temp_highlands", "temp_dirt_gravel_b", "temp_dirt_gravel_plants", "temp_highlands", "temp_highlands", "temp_highlands", "temp_dirt_gravel_b", "temp_dirt_gravel_plants", "temp_highlands", "temp_highlands", "temp_highlands", "temp_cliff_b", "temp_dirt_gravel_plants", "temp_highlands", "temp_highlands", "temp_highlands", "temp_cliff_b", "temp_dirt_gravel_plants", "temp_highlands|gaia/fauna_goat"]; var heightPath = -2; var heightLand = 0; var heightOffsetRandomPath = 1; InitMap(heightLand, g_MapSettings.BaseTerrain); var mapSize = getMapSize(); -var mapArea = getMapArea(); var mapRadius = mapSize/2; var mapCenter = getMapCenter(); var clPlayer = createTileClass(); var clPath = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clBaseResource = createTileClass(); var numPlayers = getNumPlayers(); var baseRadius = 20; var minPlayerRadius = Math.min(mapRadius - 1.5 * baseRadius, 5/8 * mapRadius); var maxPlayerRadius = Math.min(mapRadius - baseRadius, 3/4 * mapRadius); var playerPosition = []; var playerAngle = []; var playerAngleStart = randomAngle(); var playerAngleAddAvrg = 2 * Math.PI / numPlayers; var playerAngleMaxOff = playerAngleAddAvrg/4; var radiusEC = Math.max(mapRadius/8, baseRadius/2); var resourceRadius = fractionToTiles(1/3); var resourcePerPlayer = [templateStone, templateMetalMine]; // For large maps there are memory errors with too many trees. A density of 256*192/mapArea works with 0 players. // Around each player there is an area without trees so with more players the max density can increase a bit. -var maxTreeDensity = Math.min(256 * (192 + 8 * numPlayers) / mapArea, 1); // Has to be tweeked but works ok +var maxTreeDensity = Math.min(256 * (192 + 8 * numPlayers) / Math.square(mapSize), 1); // Has to be tweeked but works ok var bushChance = 1/3; // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood var playerIDs = sortAllPlayers(); for (var i=0; i < numPlayers; i++) { playerAngle[i] = (playerAngleStart + i * playerAngleAddAvrg + randFloat(0, playerAngleMaxOff)) % (2 * Math.PI); playerPosition[i] = Vector2D.add(mapCenter, new Vector2D(randFloat(minPlayerRadius, maxPlayerRadius), 0).rotate(-playerAngle[i]).round()); } Engine.SetProgress(10); placePlayerBases({ "PlayerPlacement": [playerIDs, playerPosition], "BaseResourceClass": clBaseResource, // player class painted below "CityPatch": { "radius": 0.8 * baseRadius, "smoothness": 1/8, "painters": [ new LayeredPainter([terrainBaseBorder, terrainBase, terrainBaseCenter], [baseRadius/4, baseRadius/4]), paintClass(clPlayer) ] }, // Chicken already placed at the base terrain "Berries": { "template": "gaia/flora_bush_grapes", "minCount": 2, "maxCount": 2, "minDist": 10, "maxDist": 10 }, "Mines": { "types": [ { "template": templateMetalMine }, { "template": templateStoneMine } ], "minAngle": Math.PI / 2, "maxAngle": Math.PI }, "Trees": { "template": "gaia/flora_tree_oak_large", "count": 2 } }); Engine.SetProgress(10); log("Painting paths..."); var pathBlending = numPlayers <= 4; for (let i = 0; i < numPlayers + (pathBlending ? 1 : 0); ++i) for (let j = pathBlending ? 0 : i + 1; j < numPlayers + 1; ++j) { let pathStart = i < numPlayers ? playerPosition[i] : mapCenter; let pathEnd = j < numPlayers ? playerPosition[j] : mapCenter; createArea( new RandomPathPlacer(pathStart, pathEnd, 1.25, baseRadius / 2, pathBlending), [ new TerrainPainter(terrainPath), new SmoothElevationPainter(ELEVATION_SET, heightPath, 2, heightOffsetRandomPath), paintClass(clPath) ], avoidClasses(clHill, 0, clBaseResource, 4)); } Engine.SetProgress(50); log("Placing expansion resources..."); for (let i = 0; i < numPlayers; ++i) for (let rIndex = 0; rIndex < resourcePerPlayer.length; ++rIndex) { let angleDist = numPlayers > 1 ? (playerAngle[(i + 1) % numPlayers] - playerAngle[i] + 2 * Math.PI) % (2 * Math.PI) : 2 * Math.PI; // they are supposed to be in between players on the same radius let angle = playerAngle[i] + angleDist * (rIndex + 1) / (resourcePerPlayer.length + 1); let position = Vector2D.add(mapCenter, new Vector2D(resourceRadius, 0).rotate(-angle)).round(); placeObject(position.x, position.y, resourcePerPlayer[rIndex], 0, randomAngle()); createArea( new ClumpPlacer(40, 1/2, 1/8, 1, position.x, position.y), [ new LayeredPainter([terrainHillBorder, terrainHill], [1]), new ElevationPainter(randFloat(1, 2)), paintClass(clHill) ]); } Engine.SetProgress(60); log("Placing temple..."); placeObject(mapCenter.x, mapCenter.y, templateTemple, 0, randomAngle()); addToClass(mapCenter.x, mapCenter.y, clBaseResource); log("Creating central mountain..."); createArea( new ClumpPlacer(Math.square(radiusEC), 1/2, 1/8, 1, mapCenter.x, mapCenter.y), [ new LayeredPainter([terrainHillBorder, terrainHill], [radiusEC/4]), new ElevationPainter(randFloat(1, 2)), paintClass(clHill) ]); // Woods and general hight map for (var x = 0; x < mapSize; x++) for (var z = 0;z < mapSize;z++) { // The 0.5 is a correction for the entities placed on the center of tiles var radius = Math.euclidDistance2D(x + 0.5, z + 0.5, mapCenter.x, mapCenter.y); var minDistToSL = mapSize; for (var i=0; i < numPlayers; i++) minDistToSL = Math.min(minDistToSL, Math.euclidDistance2D(x, z, playerPosition[i].x, playerPosition[i].y)); // Woods tile based var tDensFactSL = Math.max(Math.min((minDistToSL - baseRadius) / baseRadius, 1), 0); var tDensFactRad = Math.abs((resourceRadius - radius) / resourceRadius); var tDensFactEC = Math.max(Math.min((radius - radiusEC) / radiusEC, 1), 0); var tDensActual = maxTreeDensity * tDensFactSL * tDensFactRad * tDensFactEC; if (randBool(tDensActual) && g_Map.validT(x, z)) { let border = tDensActual < randFloat(0, bushChance * maxTreeDensity); createArea( new ClumpPlacer(1, 1, 1, 1, x, z), [ new TerrainPainter(border ? terrainWoodBorder : terrainWood), new ElevationPainter(randFloat(0, 1)), paintClass(clForest) ], avoidClasses(clPath, 1, clHill, border ? 0 : 1)); } // General hight map var hVarMiddleHill = mapSize / 64 * (1 + Math.cos(3/2 * Math.PI * radius / mapRadius)); var hVarHills = 5 * (1 + Math.sin(x / 10) * Math.sin(z / 10)); setHeight(x, z, getHeight(x, z) + hVarMiddleHill + hVarHills + 1); } Engine.SetProgress(95); placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clBaseResource, 4)); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/flood.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/flood.js (revision 20904) +++ ps/trunk/binaries/data/mods/public/maps/random/flood.js (revision 20905) @@ -1,321 +1,312 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmbiome"); setSelectedBiome(); const tMainTerrain = g_Terrains.mainTerrain; const tForestFloor1 = g_Terrains.forestFloor1; const tForestFloor2 = g_Terrains.forestFloor2; const tCliff = g_Terrains.cliff; const tTier1Terrain = g_Terrains.tier1Terrain; const tTier2Terrain = g_Terrains.tier2Terrain; const tTier3Terrain = g_Terrains.tier3Terrain; const tRoad = g_Terrains.road; const tRoadWild = g_Terrains.roadWild; const tTier4Terrain = g_Terrains.tier4Terrain; const tShore = g_Terrains.shore; const tWater = g_Terrains.water; var tHill = g_Terrains.hill; var tDirt = g_Terrains.dirt; if (currentBiome() == "temperate") { tDirt = ["medit_shrubs_a", "grass_field"]; tHill = ["grass_field", "peat_temp"]; } const oTree1 = g_Gaia.tree1; const oTree2 = g_Gaia.tree2; const oTree3 = g_Gaia.tree3; const oTree4 = g_Gaia.tree4; const oTree5 = g_Gaia.tree5; const oFruitBush = g_Gaia.fruitBush; const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal; const oFish = g_Gaia.fish; const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; const oStoneLarge = g_Gaia.stoneLarge; const oMetalLarge = g_Gaia.metalLarge; const aGrass = g_Decoratives.grass; const aGrassShort = g_Decoratives.grassShort; const aRockLarge = g_Decoratives.rockLarge; const aRockMedium = g_Decoratives.rockMedium; const aBushMedium = g_Decoratives.bushMedium; const aBushSmall = g_Decoratives.bushSmall; const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; const heightSeaGround = -2; const heightLand = 2; const shoreRadius = 6; InitMap(heightSeaGround, tWater); const clPlayer = createTileClass(); const clHill = createTileClass(); const clMountain = createTileClass(); const clForest = createTileClass(); const clDirt = createTileClass(); const clRock = createTileClass(); const clMetal = createTileClass(); const clFood = createTileClass(); const clBaseResource = createTileClass(); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); const mapCenter = getMapCenter(); -log("Creating the water..."); -createArea( - new ClumpPlacer(getMapArea(), 1, 1, 1, mapCenter.x, mapCenter.y), - [ - new LayeredPainter([tWater, tWater, tShore], [1, 4]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 2) - ], - avoidClasses(clPlayer, 5)); - log("Creating player islands...") var [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.38)); for (let i = 0; i < numPlayers; ++i) createArea( new ClumpPlacer( 2 * diskArea(defaultPlayerBaseRadius()), 0.8, 0.1, 10, playerPosition[i].x, playerPosition[i].y), [ new LayeredPainter([tShore, tMainTerrain], [shoreRadius]), new SmoothElevationPainter(ELEVATION_SET, heightLand, shoreRadius), paintClass(clHill) ]); placePlayerBases({ "PlayerPlacement": [playerIDs, playerPosition], "PlayerTileClass": clPlayer, "BaseResourceClass": clBaseResource, "Walls": false, "CityPatch": { "outerTerrain": tRoadWild, "innerTerrain": tRoad }, "Chicken": { }, "Berries": { "template": oFruitBush }, "Mines": { "types": [ { "template": oMetalLarge }, { "template": oStoneLarge } ] }, "Trees": { "template": oTree2, "count": 50, "maxDist": 16, "maxDistGroup": 7 }, "Decoratives": { "template": aGrassShort } }); Engine.SetProgress(40); log("Creating central island..."); createArea( new ChainPlacer( 6, Math.floor(scaleByMapSize(10, 15)), Math.floor(scaleByMapSize(200, 300)), 1, mapCenter.x, mapCenter.y, 0, [Math.floor(mapSize * 0.01)]), [ new LayeredPainter([tShore, tMainTerrain], [shoreRadius, 100]), new SmoothElevationPainter(ELEVATION_SET, heightLand, shoreRadius), paintClass(clHill) ], avoidClasses(clPlayer, 40)); for (let m = 0; m < randIntInclusive(20, 34); ++m) { let elevRand = randIntInclusive(6, 20); createArea( new ChainPlacer( 7, 15, Math.floor(scaleByMapSize(15, 20)), 1, randIntExclusive(0, mapSize), randIntExclusive(0, mapSize), 0, [Math.floor(mapSize * 0.01)]), [ new LayeredPainter([tDirt, tHill], [Math.floor(elevRand / 3), 40]), new SmoothElevationPainter(ELEVATION_SET, elevRand, Math.floor(elevRand / 3)), paintClass(clHill) ], [avoidClasses(clBaseResource, 2, clPlayer, 40), stayClasses(clHill, 6)]); } for (let m = 0; m < randIntInclusive(8, 17); ++m) { let elevRand = randIntInclusive(15, 29); createArea( new ChainPlacer( 5, 8, Math.floor(scaleByMapSize(15, 20)), 1, randIntExclusive(0, mapSize), randIntExclusive(0, mapSize), 0, [Math.floor(mapSize * 0.01)]), [ new LayeredPainter([tCliff, tForestFloor2], [Math.floor(elevRand / 3), 40]), new SmoothElevationPainter(ELEVATION_MODIFY, elevRand, Math.floor(elevRand / 3)), paintClass(clMountain) ], [avoidClasses(clBaseResource, 2, clPlayer, 40), stayClasses(clHill, 6)]); } log("Creating center bounty..."); createObjectGroup( new SimpleGroup( [new SimpleObject(oMetalLarge, 3, 6, 25, Math.floor(mapSize * 0.25))], true, clBaseResource, mapCenter.x, mapCenter.y), 0, [avoidClasses(clBaseResource, 20, clPlayer, 40, clMountain, 4), stayClasses(clHill, 10)]); createObjectGroup( new SimpleGroup( [new SimpleObject(oStoneLarge, 3, 6, 25, Math.floor(mapSize * 0.25))], true, clBaseResource, mapCenter.x, mapCenter.y), 0, [avoidClasses(clBaseResource, 20, clPlayer, 40, clMountain, 4), stayClasses(clHill, 10)]); log("Creating fish..."); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood), 0, avoidClasses(clHill, 10, clFood, 20), 10 * numPlayers, 60); var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(0.7)); createForests( [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], [avoidClasses(clPlayer, 25, clForest, 10, clBaseResource, 3, clMetal, 6, clRock, 3, clMountain, 2), stayClasses(clHill, 6)], clForest, forestTrees); let types = [oTree1, oTree2, oTree4, oTree3]; createStragglerTrees( types, [avoidClasses(clBaseResource, 2, clMetal, 6, clRock, 3, clMountain, 2, clPlayer, 25), stayClasses(clHill, 6)], clForest, stragglerTrees); Engine.SetProgress(65); log("Creating dirt patches..."); var numb = currentBiome() == "savanna" ? 3 : 1; for (let size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) createAreas( new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), [ new LayeredPainter([[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]), paintClass(clDirt) ], avoidClasses(clForest, 0, clMountain, 0, clDirt, 5, clPlayer, 10), numb * scaleByMapSize(15, 45)); log("Painting shorelines..."); paintTerrainBasedOnHeight(1, heightLand, 0, tMainTerrain); paintTerrainBasedOnHeight(heightSeaGround, 1, 3, tTier1Terrain); log("Creating grass patches..."); for (let size of [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]) createAreas( new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), new TerrainPainter(tTier4Terrain), avoidClasses(clForest, 0, clMountain, 0, clDirt, 5, clPlayer, 10), numb * scaleByMapSize(15, 45)); log("Creating food..."); createFood( [ [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] ], [3 * numPlayers, 3 * numPlayers], [avoidClasses(clForest, 0, clPlayer, 20, clMountain, 1, clFood, 4, clRock, 6, clMetal, 6), stayClasses(clHill, 6)], clFood); Engine.SetProgress(75); createFood( [ [new SimpleObject(oFruitBush, 5, 7, 0, 4)] ], [3 * numPlayers], [avoidClasses(clForest, 0, clPlayer, 15, clMountain, 1, clFood, 4, clRock, 6, clMetal, 6), stayClasses(clHill, 6)], clFood); Engine.SetProgress(85); log("Creating decoration..."); var planetm = currentBiome() == "tropic" ? 8 : 1; createDecoration( [ [new SimpleObject(aRockMedium, 1, 3, 0, 1)], [new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)], [new SimpleObject(aGrassShort, 2, 15, 0, 1)], [new SimpleObject(aGrass, 2, 10, 0, 1.8), new SimpleObject(aGrassShort, 3, 10, 1.2, 2.5)], [new SimpleObject(aBushMedium, 1, 5, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)] ], [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), planetm * scaleByMapSize(13, 200), planetm * scaleByMapSize(13, 200), planetm * scaleByMapSize(13, 200) ], avoidClasses(clForest, 2, clPlayer, 20, clMountain, 5, clFood, 1, clBaseResource, 2)); log("Creating water forests..."); var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(0.1)); createForests( [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], avoidClasses(clPlayer, 30, clHill, 10, clFood, 5), clForest, forestTrees); log("Creating small grass tufts..."); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(aGrassShort, 1, 2, 0, 1)]), 0, [avoidClasses(clMountain, 2, clPlayer, 2, clDirt, 0), stayClasses(clHill, 8)], planetm * scaleByMapSize(13, 200)); placePlayersNomad( clPlayer, new AndConstraint([ stayClasses(clHill, 2), avoidClasses(clMountain, 2, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)])); setSkySet(pickRandom(["cloudless", "cumulus", "overcast"])); setWaterMurkiness(0.4); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/gear.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/gear.js (revision 20904) +++ ps/trunk/binaries/data/mods/public/maps/random/gear.js (revision 20905) @@ -1,305 +1,312 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmbiome"); TILE_CENTERED_HEIGHT_MAP = true; setSelectedBiome(); const tMainTerrain = g_Terrains.mainTerrain; const tForestFloor1 = g_Terrains.forestFloor1; const tForestFloor2 = g_Terrains.forestFloor2; const tCliff = g_Terrains.cliff; const tTier1Terrain = g_Terrains.tier1Terrain; const tTier2Terrain = g_Terrains.tier2Terrain; const tTier3Terrain = g_Terrains.tier3Terrain; const tHill = g_Terrains.mainTerrain; const tRoad = g_Terrains.road; const tRoadWild = g_Terrains.roadWild; const tTier4Terrain = g_Terrains.tier4Terrain; const tShore = g_Terrains.shore; const tWater = g_Terrains.water; const oTree1 = g_Gaia.tree1; const oTree2 = g_Gaia.tree2; const oTree3 = g_Gaia.tree3; const oTree4 = g_Gaia.tree4; const oTree5 = g_Gaia.tree5; const oFruitBush = g_Gaia.fruitBush; const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal; const oFish = g_Gaia.fish; const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; const oStoneLarge = g_Gaia.stoneLarge; const oStoneSmall = g_Gaia.stoneSmall; const oMetalLarge = g_Gaia.metalLarge; const aGrass = g_Decoratives.grass; const aGrassShort = g_Decoratives.grassShort; const aRockLarge = g_Decoratives.rockLarge; const aRockMedium = g_Decoratives.rockMedium; const aBushMedium = g_Decoratives.bushMedium; const aBushSmall = g_Decoratives.bushSmall; const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; var heightSeaGround = -4; var heightShallow = -2; var heightLand = 3; -var heighRing = 4; +var heightRing = 4; var heightHill = 20; InitMap(heightLand, tMainTerrain); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); -const mapArea = getMapArea(); const mapCenter = getMapCenter(); var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); -var [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); +var radiusPlayers = fractionToTiles(0.35); +var radiusCentralLake = fractionToTiles(0.27); +var radiusCentralRingLand = fractionToTiles(0.21); +var radiusCentralWaterRing = fractionToTiles(0.17); +var radiusCentralIsland = fractionToTiles(0.14); +var radiusCentralHill = fractionToTiles(0.12); + +var [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(radiusPlayers); log("Determining number of rivers between players..."); var split = 1; if (mapSize == 128 && numPlayers <= 2) split = 2; else if (mapSize == 192 && numPlayers <= 3) split = 2; else if (mapSize == 256) { if (numPlayers <= 3) split = 3; else if (numPlayers == 4) split = 2; } else if (mapSize == 320) { if (numPlayers <= 3) split = 3; else if (numPlayers == 4) split = 2; } else if (mapSize == 384) { if (numPlayers <= 3) split = 4; else if (numPlayers == 4) split = 3; else if (numPlayers == 5) split = 2; } else if (mapSize == 448) { if (numPlayers <= 2) split = 5; else if (numPlayers <= 4) split = 4; else if (numPlayers == 5) split = 3; else if (numPlayers == 6) split = 2; } log("Creating big circular lake..."); createArea( - new ClumpPlacer(mapArea * 0.23, 1, 1, 10, mapCenter.x, mapCenter.y), + new ClumpPlacer(diskArea(radiusCentralLake), 1, 1, 10, mapCenter.x, mapCenter.y), new SmoothElevationPainter(ELEVATION_SET, heightShallow, 4)); for (let m = 0; m < numPlayers * split; ++m) { log("Creating rivers between players..."); let angle = startAngle + (m + 0.5) * 2 * Math.PI / (numPlayers * split); let position1 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.15), 0).rotate(-angle)); let position2 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.6), 0).rotate(-angle)); createArea( new PathPlacer(position1.x, position1.y, position2.x, position2.y, scaleByMapSize(14, 40), 0, scaleByMapSize(3, 9), 0.2, 0.05), new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), avoidClasses(clPlayer, 5)); log("Create path from the island to the center..."); angle = startAngle + m * 2 * Math.PI / (numPlayers * split); position1 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.05), 0).rotate(-angle)); position2 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.49), 0).rotate(-angle)); createArea( new PathPlacer(position1.x, position1.y, position2.x, position2.y, scaleByMapSize(10, 40), 0, scaleByMapSize(3, 9), 0.2, 0.05), new SmoothElevationPainter(ELEVATION_SET, heightLand, 4)); } log("Creating ring of land connecting players..."); createArea( - new ClumpPlacer(mapArea * 0.15, 1, 1, 10, mapCenter.x, mapCenter.y), - new SmoothElevationPainter(ELEVATION_SET, heighRing, 4)); + new ClumpPlacer(diskArea(radiusCentralRingLand), 1, 1, 10, mapCenter.x, mapCenter.y), + new SmoothElevationPainter(ELEVATION_SET, heightRing, 4)); log("Creating ring of water separating the central hill from the ring..."); createArea( - new ClumpPlacer(mapArea * 0.09, 1, 1, 10, mapCenter.x, mapCenter.y), + new ClumpPlacer(diskArea(radiusCentralWaterRing), 1, 1, 10, mapCenter.x, mapCenter.y), new SmoothElevationPainter(ELEVATION_SET, heightShallow, 3)); log("Creating central island..."); createArea( - new ClumpPlacer(Math.square(mapSize - 50) * 0.09, 1, 1, 10, mapCenter.x, mapCenter.y), - new SmoothElevationPainter(ELEVATION_SET, heighRing, 3)); + new ClumpPlacer(diskArea(radiusCentralIsland), 1, 1, 10, mapCenter.x, mapCenter.y), + new SmoothElevationPainter(ELEVATION_SET, heightRing, 3)); log("Creating hill on the central island..."); createArea( - new ClumpPlacer(diskArea(scaleByMapSize(6, 18)) * 7, 1, 1, 10, mapCenter.x, mapCenter.y), + new ClumpPlacer(diskArea(radiusCentralHill), 1, 1, 10, mapCenter.x, mapCenter.y), new SmoothElevationPainter(ELEVATION_SET, heightHill, 8)); paintTerrainBasedOnHeight(-6, 1, 1, tWater); paintTerrainBasedOnHeight(1, 2, 1, tShore); paintTerrainBasedOnHeight(2, 21, 1, tMainTerrain); paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); placePlayerBases({ "PlayerPlacement": [playerIDs, playerPosition], "PlayerTileClass": clPlayer, "BaseResourceClass": clBaseResource, + "baseResourceConstraint": avoidClasses(clWater, 2), "Walls": "towers", "CityPatch": { "outerTerrain": tRoadWild, "innerTerrain": tRoad }, "Chicken": { }, "Berries": { "template": oFruitBush }, "Mines": { "types": [ { "template": oMetalLarge }, { "template": oStoneLarge } ] }, "Trees": { "template": oTree1, "count": 2 }, "Decoratives": { "template": aGrassShort } }); if (randBool()) createHills([tMainTerrain, tCliff, tHill], avoidClasses(clPlayer, 20, clHill, 15, clWater, 2), clHill, scaleByMapSize(1, 4) * numPlayers); else createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 15, clWater, 2), clHill, scaleByMapSize(1, 4) * numPlayers); var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); createForests( [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 2), clForest, forestTrees); Engine.SetProgress(50); log("Creating dirt patches..."); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [[tMainTerrain,tTier1Terrain],[tTier1Terrain,tTier2Terrain], [tTier2Terrain,tTier3Terrain]], [1,1], avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), scaleByMapSize(15, 45), clDirt); log("Creating grass patches..."); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tTier4Terrain, avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), scaleByMapSize(15, 45), clDirt); Engine.SetProgress(55); log("Creating stone mines..."); createMines( [ [new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], [new SimpleObject(oStoneSmall, 2,5, 1,3)] ], avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), clRock); log("Creating metal mines..."); createMines( [ [new SimpleObject(oMetalLarge, 1,1, 0,4)] ], avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), clMetal ); log("Creating fish..."); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(oFish, 1,1, 0,3)], true, clFood), 0, [stayClasses(clWater, 8), avoidClasses(clFood, 14)], scaleByMapSize(400, 2000), 100); Engine.SetProgress(65); var planetm = 1; if (currentBiome() == "tropic") planetm = 8; createDecoration( [ [new SimpleObject(aRockMedium, 1, 3, 0, 1)], [new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)], [new SimpleObject(aGrassShort, 1, 2, 0, 1)], [new SimpleObject(aGrass, 2, 4, 0, 1.8), new SimpleObject(aGrassShort, 3, 6, 1.2, 2.5)], [new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)] ], [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), planetm * scaleByMapSize(13, 200), planetm * scaleByMapSize(13, 200), planetm * scaleByMapSize(13, 200) ], avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); Engine.SetProgress(70); createFood( [ [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] ], [ 3 * numPlayers, 3 * numPlayers ], avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), clFood); createFood( [ [new SimpleObject(oFruitBush, 5, 7, 0, 4)] ], [ 3 * numPlayers ], avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), clFood); createStragglerTrees( [oTree1, oTree2, oTree4, oTree3], avoidClasses(clWater, 5, clForest, 7, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), clForest, stragglerTrees); placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/lions_den.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/lions_den.js (revision 20904) +++ ps/trunk/binaries/data/mods/public/maps/random/lions_den.js (revision 20905) @@ -1,567 +1,566 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); setSelectedBiome(); const topTerrain = g_Terrains.tier2Terrain; const heightValley = 0; const heightPath = 10; const heightDen = 15; const heightHill = 50; InitMap(heightHill, topTerrain); -const mapArea = getMapArea(); const mapCenter = getMapCenter(); const numPlayers = getNumPlayers(); const startAngle = randomAngle(); initTileClasses(["step"]); createArea( new MapBoundsPlacer(), paintClass(g_TileClasses.land)); Engine.SetProgress(10); addBases("radial", fractionToTiles(0.4), fractionToTiles(randFloat(0.05, 0.1)), startAngle); Engine.SetProgress(20); createSunkenTerrain(); Engine.SetProgress(30); addElements([ { "func": addLayeredPatches, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.dirt, 5, g_TileClasses.forest, 2, g_TileClasses.mountain, 2, g_TileClasses.player, 12, g_TileClasses.step, 5 ], "stay": [g_TileClasses.valley, 7], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] }, { "func": addLayeredPatches, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.dirt, 5, g_TileClasses.forest, 2, g_TileClasses.mountain, 2, g_TileClasses.player, 12 ], "stay": [g_TileClasses.settlement, 7], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] }, { "func": addLayeredPatches, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.dirt, 5, g_TileClasses.forest, 2 ], "stay": [g_TileClasses.player, 1], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] }, { "func": addDecoration, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.forest, 2 ], "stay": [g_TileClasses.player, 1], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] }, { "func": addDecoration, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.forest, 2, g_TileClasses.mountain, 2, g_TileClasses.player, 12, g_TileClasses.step, 2 ], "stay": [g_TileClasses.valley, 7], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] }, { "func": addDecoration, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.forest, 2, g_TileClasses.mountain, 2, g_TileClasses.player, 12 ], "stay": [g_TileClasses.settlement, 7], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["normal"] }, { "func": addDecoration, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.forest, 2, g_TileClasses.mountain, 2, g_TileClasses.player, 12 ], "stay": [g_TileClasses.step, 7], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["scarce"] } ]); Engine.SetProgress(40); addElements(shuffleArray([ { "func": addMetal, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.berries, 5, g_TileClasses.forest, 3, g_TileClasses.player, 30, g_TileClasses.rock, 10, g_TileClasses.metal, 20 ], "stay": [g_TileClasses.settlement, 7], "sizes": ["normal"], "mixes": ["same"], "amounts": ["tons"] }, { "func": addMetal, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.berries, 5, g_TileClasses.forest, 3, g_TileClasses.player, 10, g_TileClasses.rock, 10, g_TileClasses.metal, 20, g_TileClasses.mountain, 5, g_TileClasses.step, 5 ], "stay": [g_TileClasses.valley, 7], "sizes": ["normal"], "mixes": ["same"], "amounts": g_AllAmounts }, { "func": addStone, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.berries, 5, g_TileClasses.forest, 3, g_TileClasses.player, 30, g_TileClasses.rock, 20, g_TileClasses.metal, 10 ], "stay": [g_TileClasses.settlement, 7], "sizes": ["normal"], "mixes": ["same"], "amounts": ["tons"] }, { "func": addStone, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.berries, 5, g_TileClasses.forest, 3, g_TileClasses.player, 10, g_TileClasses.rock, 20, g_TileClasses.metal, 10, g_TileClasses.mountain, 5, g_TileClasses.step, 5 ], "stay": [g_TileClasses.valley, 7], "sizes": ["normal"], "mixes": ["same"], "amounts": g_AllAmounts }, { "func": addForests, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.berries, 5, g_TileClasses.forest, 18, g_TileClasses.metal, 3, g_TileClasses.player, 20, g_TileClasses.rock, 3 ], "stay": [g_TileClasses.settlement, 7], "sizes": ["normal", "big"], "mixes": ["same"], "amounts": ["tons"] }, { "func": addForests, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.berries, 3, g_TileClasses.forest, 18, g_TileClasses.metal, 3, g_TileClasses.mountain, 5, g_TileClasses.player, 5, g_TileClasses.rock, 3, g_TileClasses.step, 1 ], "stay": [g_TileClasses.valley, 7], "sizes": ["normal", "big"], "mixes": ["same"], "amounts": ["tons"] } ])); Engine.SetProgress(60); addElements(shuffleArray([ { "func": addBerries, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.berries, 30, g_TileClasses.forest, 5, g_TileClasses.metal, 10, g_TileClasses.player, 20, g_TileClasses.rock, 10 ], "stay": [g_TileClasses.settlement, 7], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": ["tons"] }, { "func": addBerries, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.berries, 30, g_TileClasses.forest, 5, g_TileClasses.metal, 10, g_TileClasses.mountain, 5, g_TileClasses.player, 10, g_TileClasses.rock, 10, g_TileClasses.step, 5 ], "stay": [g_TileClasses.valley, 7], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts }, { "func": addAnimals, "avoid": [ g_TileClasses.animals, 20, g_TileClasses.baseResource, 5, g_TileClasses.forest, 0, g_TileClasses.metal, 1, g_TileClasses.player, 20, g_TileClasses.rock, 1 ], "stay": [g_TileClasses.settlement, 7], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": ["tons"] }, { "func": addAnimals, "avoid": [ g_TileClasses.animals, 20, g_TileClasses.baseResource, 5, g_TileClasses.forest, 0, g_TileClasses.metal, 1, g_TileClasses.mountain, 5, g_TileClasses.player, 10, g_TileClasses.rock, 1, g_TileClasses.step, 5 ], "stay": [g_TileClasses.valley, 7], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": g_AllAmounts }, { "func": addStragglerTrees, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.berries, 5, g_TileClasses.forest, 7, g_TileClasses.metal, 3, g_TileClasses.player, 12, g_TileClasses.rock, 3 ], "stay": [g_TileClasses.settlement, 7], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": ["tons"] }, { "func": addStragglerTrees, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.berries, 5, g_TileClasses.forest, 7, g_TileClasses.metal, 3, g_TileClasses.mountain, 5, g_TileClasses.player, 10, g_TileClasses.rock, 3, g_TileClasses.step, 5 ], "stay": [g_TileClasses.valley, 7], "sizes": g_AllSizes, "mixes": g_AllMixes, "amounts": ["normal", "many", "tons"] }, { "func": addStragglerTrees, "avoid": [ g_TileClasses.player, 10, g_TileClasses.baseResource, 5, g_TileClasses.berries, 5, g_TileClasses.forest, 3, g_TileClasses.metal, 5, g_TileClasses.rock, 5 ], "stay": [g_TileClasses.player, 1], "sizes": ["huge"], "mixes": ["same"], "amounts": ["tons"] } ])); Engine.SetProgress(75); addElements([ { "func": addDecoration, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.valley, 4, g_TileClasses.player, 4, g_TileClasses.settlement, 4, g_TileClasses.step, 4 ], "stay": [g_TileClasses.land, 2], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["tons"] } ]); Engine.SetProgress(80); addElements([ { "func": addProps, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.valley, 4, g_TileClasses.player, 4, g_TileClasses.settlement, 4, g_TileClasses.step, 4 ], "stay": [g_TileClasses.land, 2], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["scarce"] } ]); Engine.SetProgress(85); addElements([ { "func": addDecoration, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.player, 4, g_TileClasses.settlement, 4, g_TileClasses.step, 4 ], "stay": [g_TileClasses.mountain, 2], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["tons"] } ]); Engine.SetProgress(90); addElements([ { "func": addProps, "avoid": [ g_TileClasses.baseResource, 5, g_TileClasses.player, 4, g_TileClasses.settlement, 4, g_TileClasses.step, 4 ], "stay": [g_TileClasses.mountain, 2], "sizes": ["normal"], "mixes": ["normal"], "amounts": ["scarce"] } ]); Engine.SetProgress(95); placePlayersNomad( g_TileClasses.player, [ new HeightConstraint(heightValley, heightPath), avoidClasses( g_TileClasses.forest, 1, g_TileClasses.metal, 4, g_TileClasses.rock, 4, g_TileClasses.animals, 2) ]); ExportMap(); function createSunkenTerrain() { var base = g_Terrains.mainTerrain; var middle = g_Terrains.dirt; var lower = g_Terrains.tier2Terrain; var road = g_Terrains.road; if (currentBiome() == "snowy") { middle = g_Terrains.tier2Terrain; lower = g_Terrains.tier1Terrain; } if (currentBiome() == "alpine") { middle = g_Terrains.shore; lower = g_Terrains.tier4Terrain; } if (currentBiome() == "mediterranean") { middle = g_Terrains.tier1Terrain; lower = g_Terrains.forestFloor1; } if (currentBiome() == "savanna") { middle = g_Terrains.tier2Terrain; lower = g_Terrains.tier4Terrain; } if (currentBiome() == "tropic" || currentBiome() == "autumn") road = g_Terrains.roadWild; if (currentBiome() == "autumn") middle = g_Terrains.shore; - var expSize = mapArea * 0.015 / (numPlayers / 4); + var expSize = diskArea(fractionToTiles(0.14)) / numPlayers; var expDist = 0.1 + numPlayers / 200; var expAngle = 0.75; - if (numPlayers == 2) + if (numPlayers <= 2) { - expSize = mapArea * 0.015 / 0.8; + expSize = diskArea(fractionToTiles(0.075)); expAngle = 0.72; } var nRoad = 0.44; var nExp = 0.425; if (numPlayers < 4) { nRoad = 0.42; nExp = 0.4; } log("Creating central valley..."); createArea( - new ClumpPlacer(mapArea * 0.26, 1, 1, 1, mapCenter.x, mapCenter.y), + new ClumpPlacer(diskArea(fractionToTiles(0.29)), 1, 1, 1, mapCenter.x, mapCenter.y), [ new LayeredPainter([g_Terrains.cliff, lower], [3]), new SmoothElevationPainter(ELEVATION_SET, heightValley, 3), paintClass(g_TileClasses.valley) ]); log("Creating central hill..."); createArea( - new ClumpPlacer(mapArea * 0.14, 1, 1, 1, mapCenter.x, mapCenter.y), + new ClumpPlacer(diskArea(fractionToTiles(0.21)), 1, 1, 1, mapCenter.x, mapCenter.y), [ new LayeredPainter([g_Terrains.cliff, topTerrain], [3]), new SmoothElevationPainter(ELEVATION_SET, heightHill, 3), paintClass(g_TileClasses.mountain) ]); let getCoords = (distance, playerID, playerIDOffset) => { let angle = startAngle + (playerID + playerIDOffset) * 2 * Math.PI / numPlayers; return Vector2D.add(mapCenter, new Vector2D(fractionToTiles(distance), 0).rotate(-angle)).round(); }; for (let i = 0; i < numPlayers; ++i) { let playerPosition = getCoords(0.4, i, 0); log("Creating path from player to expansion..."); let expansionPosition = getCoords(expDist, i, expAngle); createArea( new PathPlacer(playerPosition.x, playerPosition.y, expansionPosition.x, expansionPosition.y, 12, 0.7, 0.5, 0.1, -1), [ new LayeredPainter([g_Terrains.cliff, middle, road], [3, 4]), new SmoothElevationPainter(ELEVATION_SET, heightPath, 3), paintClass(g_TileClasses.step) ]); log("Creating path from player to the neighbor..."); for (let neighborOffset of [-0.5, 0.5]) { let neighborPosition = getCoords(nRoad, i, neighborOffset); let pathPosition = getCoords(0.47, i, 0); createArea( new PathPlacer(pathPosition.x, pathPosition.y, neighborPosition.x, neighborPosition.y, 19, 0.4, 0.5, 0.1, -0.6), [ new LayeredPainter([g_Terrains.cliff, middle, road], [3, 6]), new SmoothElevationPainter(ELEVATION_SET, heightPath, 3), paintClass(g_TileClasses.step) ]); } log("Creating the den of the player..."); createArea( - new ClumpPlacer(mapArea * 0.03 / (isNomad() ? 2 : 1), 0.9, 0.3, 1, playerPosition.x, playerPosition.y), + new ClumpPlacer(diskArea(fractionToTiles(0.1)) / (isNomad() ? 2 : 1), 0.9, 0.3, 1, playerPosition.x, playerPosition.y), [ new LayeredPainter([g_Terrains.cliff, base], [3]), new SmoothElevationPainter(ELEVATION_SET, heightDen, 3), paintClass(g_TileClasses.valley) ]); log("Creating the expansion of the player..."); createArea( new ClumpPlacer(expSize, 0.9, 0.3, 1, expansionPosition.x, expansionPosition.y), [ new LayeredPainter([g_Terrains.cliff, base], [3]), new SmoothElevationPainter(ELEVATION_SET, heightDen, 3), paintClass(g_TileClasses.settlement) ], [avoidClasses(g_TileClasses.settlement, 2)]); } log("Creating the expansions between players after the paths were created..."); for (let i = 0; i < numPlayers; ++i) { let position = getCoords(nExp, i, 0.5); createArea( new ClumpPlacer(expSize, 0.9, 0.3, 1, position.x, position.y), [ new LayeredPainter([g_Terrains.cliff, lower], [3]), new SmoothElevationPainter(ELEVATION_SET, heightValley, 3), paintClass(g_TileClasses.settlement) ]); } } Index: ps/trunk/binaries/data/mods/public/maps/random/migration.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/migration.js (revision 20904) +++ ps/trunk/binaries/data/mods/public/maps/random/migration.js (revision 20905) @@ -1,372 +1,372 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmbiome"); setSelectedBiome(); const tMainTerrain = g_Terrains.mainTerrain; const tForestFloor1 = g_Terrains.forestFloor1; const tForestFloor2 = g_Terrains.forestFloor2; const tCliff = g_Terrains.cliff; const tTier1Terrain = g_Terrains.tier1Terrain; const tTier2Terrain = g_Terrains.tier2Terrain; const tTier3Terrain = g_Terrains.tier3Terrain; const tHill = g_Terrains.hill; const tRoad = g_Terrains.road; const tRoadWild = g_Terrains.roadWild; const tTier4Terrain = g_Terrains.tier4Terrain; const tShore = g_Terrains.shore; const tWater = g_Terrains.water; const oTree1 = g_Gaia.tree1; const oTree2 = g_Gaia.tree2; const oTree3 = g_Gaia.tree3; const oTree4 = g_Gaia.tree4; const oTree5 = g_Gaia.tree5; const oFruitBush = g_Gaia.fruitBush; const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal; const oFish = g_Gaia.fish; const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; const oStoneLarge = g_Gaia.stoneLarge; const oStoneSmall = g_Gaia.stoneSmall; const oMetalLarge = g_Gaia.metalLarge; const oWoodTreasure = "gaia/special_treasure_wood"; const oDock = "skirmish/structures/default_dock"; const aGrass = g_Decoratives.grass; const aGrassShort = g_Decoratives.grassShort; const aRockLarge = g_Decoratives.rockLarge; const aRockMedium = g_Decoratives.rockMedium; const aBushMedium = g_Decoratives.bushMedium; const aBushSmall = g_Decoratives.bushSmall; const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; const heightSeaGround = -5; const heightLand = 3; const heightHill = 18; const heightOffsetBump = 2; InitMap(heightSeaGround, g_MapSettings.BaseTerrain); const numPlayers = getNumPlayers(); const mapSize = getMapSize(); -const mapArea = getMapArea(); const mapCenter = getMapCenter(); var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); var clMetal = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clLand = createTileClass(); var clIsland = createTileClass(); var startAngle = 4/7 * Math.PI; var playerIDs = sortAllPlayers(); var [playerPosition, playerAngle] = playerPlacementCustomAngle( fractionToTiles(0.35), mapCenter, i => startAngle - 8/7 * Math.PI * (i + 1) / (numPlayers + 1)); log("Creating player islands and docks..."); for (let i = 0; i < numPlayers; ++i) { createArea( new ClumpPlacer(diskArea(defaultPlayerBaseRadius()), 0.8, 0.1, 10, playerPosition[i].x, playerPosition[i].y), [ new LayeredPainter([tWater, tShore, tMainTerrain], [1, 4]), new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), paintClass(clIsland), paintClass(isNomad() ? clLand : clPlayer) ]); if (isNomad()) continue; let dockLocation = findLocationInDirectionBasedOnHeight(playerPosition[i], mapCenter, -3 , 2.6, 3); placeObject(dockLocation.x, dockLocation.y, oDock, playerIDs[i], playerAngle[i] + Math.PI); } Engine.SetProgress(10); placePlayerBases({ "PlayerPlacement": [playerIDs, playerPosition], "PlayerTileClass": clPlayer, "BaseResourceClass": clBaseResource, "Walls": false, // No city patch "Chicken": { }, "Berries": { "template": oFruitBush }, "Mines": { "types": [ { "template": oMetalLarge }, { "template": oStoneLarge } ] }, "Treasures": { "types": [ { "template": oWoodTreasure, "count": 14 } ] }, "Trees": { "template": oTree1, "count": scaleByMapSize(12, 30) }, "Decoratives": { "template": aGrassShort } }); Engine.SetProgress(15); log("Create the continent body..."); +var continentPosition = new Vector2D(fractionToTiles(0.12), mapCenter.y).round() createArea( - new ClumpPlacer(mapArea * 0.50, 0.8, 0.08, 10, Math.round(fractionToTiles(0.12)), Math.round(fractionToTiles(0.5))), + new ClumpPlacer(diskArea(fractionToTiles(0.4)), 0.8, 0.08, 10, continentPosition.x, continentPosition.y), [ new LayeredPainter([tWater, tShore, tMainTerrain], [4, 2]), new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), paintClass(clLand) ], avoidClasses(clIsland, 8)); Engine.SetProgress(20); log("Creating shore jaggedness..."); createAreas( new ClumpPlacer(scaleByMapSize(15, 80), 0.2, 0.1, 1), [ new LayeredPainter([tMainTerrain, tMainTerrain], [2]), new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), paintClass(clLand) ], [ borderClasses(clLand, 6, 3), avoidClasses(clIsland, 8) ], scaleByMapSize(2, 15) * 20, 150); paintTerrainBasedOnHeight(1, 3, 0, tShore); paintTerrainBasedOnHeight(-8, 1, 2, tWater); Engine.SetProgress(25); log("Creating bumps..."); createAreas( new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1), new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), [avoidClasses(clIsland, 10), stayClasses(clLand, 3)], scaleByMapSize(100, 200) ); Engine.SetProgress(30); log("Creating hills..."); createAreas( new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, 1), [ new LayeredPainter([tCliff, tHill], [2]), new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), paintClass(clHill) ], [avoidClasses(clIsland, 10, clHill, 15), stayClasses(clLand, 7)], scaleByMapSize(1, 4) * numPlayers ); Engine.SetProgress(34); log("Creating forests..."); var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); var types = [ [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] ]; var size = forestTrees / (scaleByMapSize(2,8) * numPlayers) * (currentBiome() == "savanna" ? 2 : 1); var num = Math.floor(size / types.length); for (let type of types) createAreas( new ClumpPlacer(forestTrees / num, 0.1, 0.1, 1), [ new LayeredPainter(type, [2]), paintClass(clForest) ], [avoidClasses(clPlayer, 6, clForest, 10, clHill, 0), stayClasses(clLand, 7)], num); Engine.SetProgress(38); log("Creating dirt patches..."); for (let size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) createAreas( new ClumpPlacer(size, 0.3, 0.06, 0.5), [ new LayeredPainter( [[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]), paintClass(clDirt) ], [ avoidClasses( clForest, 0, clHill, 0, clDirt, 5, clIsland, 0), stayClasses(clLand, 7) ], scaleByMapSize(15, 45)); Engine.SetProgress(42); log("Creating grass patches..."); for (let size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) createAreas( new ClumpPlacer(size, 0.3, 0.06, 0.5), new TerrainPainter(tTier4Terrain), [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clIsland, 0), stayClasses(clLand, 7)], scaleByMapSize(15, 45)); Engine.SetProgress(46); log("Creating stone mines..."); var group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), stayClasses(clLand, 7)], scaleByMapSize(4,16), 100 ); Engine.SetProgress(50); log("Creating small stone quarries..."); group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), stayClasses(clLand, 7)], scaleByMapSize(4,16), 100 ); Engine.SetProgress(54); log("Creating metal mines..."); group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 1), stayClasses(clLand, 7)], scaleByMapSize(4,16), 100 ); Engine.SetProgress(58); log("Creating small decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroupsDeprecated( group, 0, [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 6)], scaleByMapSize(16, 262), 50 ); Engine.SetProgress(62); log("Creating large decorative rocks..."); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroupsDeprecated( group, 0, [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 6)], scaleByMapSize(8, 131), 50 ); Engine.SetProgress(66); log("Creating deer..."); group = new SimpleGroup( [new SimpleObject(oMainHuntableAnimal, 5,7, 0,4)], true, clFood ); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), stayClasses(clLand, 7)], 3 * numPlayers, 50 ); Engine.SetProgress(70); log("Creating sheep..."); group = new SimpleGroup( [new SimpleObject(oSecondaryHuntableAnimal, 2,3, 0,2)], true, clFood ); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), stayClasses(clLand, 7)], 3 * numPlayers, 50 ); Engine.SetProgress(74); log("Creating fruit bush..."); group = new SimpleGroup( [new SimpleObject(oFruitBush, 5,7, 0,4)], true, clFood ); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 0, clPlayer, 8, clHill, 1, clFood, 20), stayClasses(clLand, 7)], randIntInclusive(1, 4) * numPlayers + 2, 50 ); Engine.SetProgress(78); log("Creating fish..."); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(oFish, 2,3, 0,2)], true, clFood), 0, avoidClasses(clLand, 2, clPlayer, 2, clHill, 0, clFood, 20), 25 * numPlayers, 60 ); Engine.SetProgress(82); createStragglerTrees( [oTree1, oTree2, oTree4, oTree3], [avoidClasses(clForest, 1, clHill, 1, clPlayer, 9, clMetal, 6, clRock, 6), stayClasses(clLand, 9)], clForest, stragglerTrees); Engine.SetProgress(86); var planetm = currentBiome() == "tropic" ? 8 : 1; log("Creating small grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrassShort, 1,2, 0,1, -Math.PI / 8, Math.PI / 8)] ); createObjectGroupsDeprecated(group, 0, [avoidClasses(clHill, 2, clPlayer, 2, clDirt, 0), stayClasses(clLand, 6)], planetm * scaleByMapSize(13, 200) ); Engine.SetProgress(90); log("Creating large grass tufts..."); group = new SimpleGroup( [new SimpleObject(aGrass, 2,4, 0,1.8, -Math.PI / 8, Math.PI / 8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -Math.PI / 8, Math.PI / 8)] ); createObjectGroupsDeprecated(group, 0, [avoidClasses(clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), stayClasses(clLand, 6)], planetm * scaleByMapSize(13, 200) ); Engine.SetProgress(94); log("Creating bushes..."); group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ); createObjectGroupsDeprecated(group, 0, [avoidClasses(clHill, 1, clPlayer, 1, clDirt, 1), stayClasses(clLand, 6)], planetm * scaleByMapSize(13, 200), 50 ); Engine.SetProgress(98); setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); setSunRotation(randomAngle()); setSunElevation(randFloat(1/5, 1/3) * Math.PI); setWaterWaviness(2); placePlayersNomad(clPlayer, [stayClasses(clIsland, 4), avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)]); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/gaia_terrain.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/gaia_terrain.js (revision 20904) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/gaia_terrain.js (revision 20905) @@ -1,609 +1,608 @@ /** * @file These functions are often used to create a landscape, for instance shaping mountains, hills, rivers or grass and dirt patches. */ /** * Bumps add slight, diverse elevation differences to otherwise completely level terrain. */ function createBumps(constraint, count, minSize, maxSize, spread, failFraction = 0, elevation = 2) { log("Creating bumps..."); createAreas( new ChainPlacer( minSize || 1, maxSize || Math.floor(scaleByMapSize(4, 6)), spread || Math.floor(scaleByMapSize(2, 5)), failFraction), new SmoothElevationPainter(ELEVATION_MODIFY, elevation, 2), constraint, count || scaleByMapSize(100, 200)); } /** * Hills are elevated, planar, impassable terrain areas. */ function createHills(terrainset, constraint, tileClass, count, minSize, maxSize, spread, failFraction = 0.5, elevation = 18, elevationSmoothing = 2) { log("Creating hills..."); createAreas( new ChainPlacer( minSize || 1, maxSize || Math.floor(scaleByMapSize(4, 6)), spread || Math.floor(scaleByMapSize(16, 40)), failFraction), [ new LayeredPainter(terrainset, [1, elevationSmoothing]), new SmoothElevationPainter(ELEVATION_SET, elevation, elevationSmoothing), paintClass(tileClass) ], constraint, count || scaleByMapSize(1, 4) * getNumPlayers()); } /** * Mountains are impassable smoothened cones. */ function createMountains(terrain, constraint, tileClass, count, maxHeight, minRadius, maxRadius, numCircles) { log("Creating mountains..."); let mapSize = getMapSize(); for (let i = 0; i < (count || scaleByMapSize(1, 4) * getNumPlayers()); ++i) createMountain( maxHeight !== undefined ? maxHeight : Math.floor(scaleByMapSize(30, 50)), minRadius || Math.floor(scaleByMapSize(3, 4)), maxRadius || Math.floor(scaleByMapSize(6, 12)), numCircles || Math.floor(scaleByMapSize(4, 10)), constraint, randIntExclusive(0, mapSize), randIntExclusive(0, mapSize), terrain, tileClass, 14); } /** * Create a mountain using a technique very similar to ChainPlacer. */ function createMountain(maxHeight, minRadius, maxRadius, numCircles, constraints, x, z, terrain, tileClass, fcc = 0, q = []) { let constraint = new AndConstraint(constraints); if (!g_Map.inMapBounds(x, z) || !constraint.allows(x, z)) return; let mapSize = getMapSize(); let queueEmpty = !q.length; let gotRet = []; for (let i = 0; i < mapSize; ++i) { gotRet[i] = []; for (let j = 0; j < mapSize; ++j) gotRet[i][j] = -1; } --mapSize; minRadius = Math.max(1, Math.min(minRadius, maxRadius)); let edges = [[x, z]]; let circles = []; for (let i = 0; i < numCircles; ++i) { let badPoint = false; let [cx, cz] = pickRandom(edges); let radius; if (queueEmpty) radius = randIntInclusive(minRadius, maxRadius); else { radius = q.pop(); queueEmpty = !q.length; } let sx = Math.max(0, cx - radius); let sz = Math.max(0, cz - radius); let lx = Math.min(cx + radius, mapSize); let lz = Math.min(cz + radius, mapSize); let radius2 = Math.square(radius); for (let ix = sx; ix <= lx; ++ix) { for (let iz = sz; iz <= lz; ++iz) { if (Math.euclidDistance2D(ix, iz, cx, cz) > radius2 || !g_Map.inMapBounds(ix, iz)) continue; if (!constraint.allows(ix, iz)) { badPoint = true; break; } let state = gotRet[ix][iz]; if (state == -1) { gotRet[ix][iz] = -2; } else if (state >= 0) { edges.splice(state, 1); gotRet[ix][iz] = -2; for (let k = state; k < edges.length; ++k) --gotRet[edges[k][0]][edges[k][1]]; } } if (badPoint) break; } if (badPoint) continue; circles.push([cx, cz, radius]); for (let ix = sx; ix <= lx; ++ix) for (let iz = sz; iz <= lz; ++iz) { if (gotRet[ix][iz] != -2 || fcc && (x - ix > fcc || ix - x > fcc || z - iz > fcc || iz - z > fcc) || ix > 0 && gotRet[ix-1][iz] == -1 || iz > 0 && gotRet[ix][iz-1] == -1 || ix < mapSize && gotRet[ix+1][iz] == -1 || iz < mapSize && gotRet[ix][iz+1] == -1) continue; edges.push([ix, iz]); gotRet[ix][iz] = edges.length - 1; } } for (let [cx, cz, radius] of circles) { let sx = Math.max(0, cx - radius); let sz = Math.max(0, cz - radius); let lx = Math.min(cx + radius, mapSize); let lz = Math.min(cz + radius, mapSize); let clumpHeight = radius / maxRadius * maxHeight * randFloat(0.8, 1.2); for (let ix = sx; ix <= lx; ++ix) for (let iz = sz; iz <= lz; ++iz) { let distance = Math.euclidDistance2D(ix, iz, cx, cz); let newHeight = randIntInclusive(0, 2) + Math.round(2/3 * clumpHeight * (Math.sin(Math.PI * 2/3 * (3/4 - distance / radius)) + 0.5)); if (distance > radius) continue; if (getHeight(ix, iz) < newHeight) setHeight(ix, iz, newHeight); else if (getHeight(ix, iz) >= newHeight && getHeight(ix, iz) < newHeight + 4) setHeight(ix, iz, newHeight + 4); if (terrain !== undefined) createTerrain(terrain).place(ix, iz); if (tileClass !== undefined) addToClass(ix, iz, tileClass); } } } /** * Generates a volcano mountain. Smoke and lava are optional. * * @param {number} center - Vector2D location on the tilemap. * @param {number} tileClass - Painted onto every tile that is occupied by the volcano. * @param {string} terrainTexture - The texture painted onto the volcano hill. * @param {array} lavaTextures - Three different textures for the interior, from the outside to the inside. * @param {boolean} smoke - Whether to place smoke particles. * @param {number} elevationType - Elevation painter type, ELEVATION_SET = absolute or ELEVATION_MODIFY = relative. */ function createVolcano(position, tileClass, terrainTexture, lavaTextures, smoke, elevationType) { log("Creating volcano"); - let baseSize = getMapArea() / scaleByMapSize(1, 8); - let coherence = 0.7; - let smoothness = 0.05; - let failFraction = 100; - let steepness = 3; + let baseSize = diskArea(scaleByMapSize(72, 102)); let clLava = createTileClass(); - let layers = [ { "clumps": 0.067, "elevation": 15, - "tileClass": tileClass + "tileClass": tileClass, + "steepness": 3 }, { "clumps": 0.05, "elevation": 25, - "tileClass": createTileClass() + "tileClass": createTileClass(), + "steepness": 3 }, { "clumps": 0.02, "elevation": 45, - "tileClass": createTileClass() + "tileClass": createTileClass(), + "steepness": 3 }, { "clumps": 0.011, "elevation": 62, - "tileClass": createTileClass() + "tileClass": createTileClass(), + "steepness": 3 }, { "clumps": 0.003, "elevation": 42, "tileClass": clLava, "painter": lavaTextures && new LayeredPainter([terrainTexture, ...lavaTextures], [1, 1, 1]), "steepness": 1 } ]; for (let i = 0; i < layers.length; ++i) createArea( - new ClumpPlacer(baseSize * layers[i].clumps, coherence, smoothness, failFraction, position.x, position.y), + new ClumpPlacer(baseSize * layers[i].clumps, 0.7, 0.05, 100, position.x, position.y), [ layers[i].painter || new LayeredPainter([terrainTexture, terrainTexture], [3]), - new SmoothElevationPainter(elevationType, layers[i].elevation, layers[i].steepness || steepness), + new SmoothElevationPainter(elevationType, layers[i].elevation, layers[i].steepness), paintClass(layers[i].tileClass) ], i == 0 ? null : stayClasses(layers[i - 1].tileClass, 1)); if (smoke) { let num = Math.floor(baseSize * 0.002); createObjectGroup( new SimpleGroup( [new SimpleObject("actor|particle/smoke.xml", num, num, 0, 7)], false, clLava, position.x, position.y), 0, stayClasses(tileClass, 1)); } } /** * Paint the given terrain texture in the given sizes at random places of the map to diversify monotone land texturing. */ function createPatches(sizes, terrain, constraint, count, tileClass, failFraction = 0.5) { for (let size of sizes) createAreas( new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, failFraction), [ new TerrainPainter(terrain), paintClass(tileClass) ], constraint, count); } /** * Same as createPatches, but each patch consists of a set of textures drawn depending to the distance of the patch border. */ function createLayeredPatches(sizes, terrains, terrainWidths, constraint, count, tileClass, failFraction = 0.5) { for (let size of sizes) createAreas( new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, failFraction), [ new LayeredPainter(terrains, terrainWidths), paintClass(tileClass) ], constraint, count); } /** * Creates a meandering river at the given location and width. * Optionally calls a function on the affected tiles. * Horizontal locations and widths (including fadeDist, meandering) are fractions of the mapsize. * * @property start - A Vector2D in tile coordinates stating where the river starts. * @property end - A Vector2D in tile coordinates stating where the river ends. * @property parallel - Whether the shorelines should be parallel or meander separately. * @property width - Size between the two shorelines. * @property fadeDist - Size of the shoreline. * @property deviation - Fuzz effect on the shoreline if greater than 0. * @property heightRiverbed - Ground height of the riverbed. * @proeprty heightLand - Ground height of the end of the shoreline. * @property meanderShort - Strength of frequent meanders. * @property meanderLong - Strength of less frequent meanders. * @property [constraint] - If given, ignores any tiles that don't satisfy the given Constraint. * @property [waterFunc] - Optional function called on tiles within the river. * Provides location on the tilegrid, new elevation and * the location on the axis parallel to the river as a fraction of the river length. * @property [landFunc] - Optional function called on land tiles, providing ix, iz, shoreDist1, shoreDist2. * @property [minHeight] - If given, only changes the elevation below this height while still calling the given functions. */ function paintRiver(args) { log("Creating the river"); // Model the river meandering as the sum of two sine curves. let meanderShort = fractionToTiles(args.meanderShort / scaleByMapSize(35, 160)); let meanderLong = fractionToTiles(args.meanderLong / scaleByMapSize(35, 100)); // Unless the river is parallel, each riverside will receive an own random seed and starting angle. let seed1 = randFloat(2, 3); let seed2 = randFloat(2, 3); let startingAngle1 = randFloat(0, 1); let startingAngle2 = randFloat(0, 1); // Computes the deflection of the river at a given point. let riverCurve = (riverFraction, startAngle, seed) => meanderShort * rndRiver(startAngle + fractionToTiles(riverFraction) / 128, seed) + meanderLong * rndRiver(startAngle + fractionToTiles(riverFraction) / 256, seed); // Describe river location in vectors. let riverLength = args.start.distanceTo(args.end); let unitVecRiver = Vector2D.sub(args.start, args.end).normalize(); // Describe river boundaries. let riverMinX = Math.min(args.start.x, args.end.x); let riverMinZ = Math.min(args.start.y, args.end.y); let riverMaxX = Math.max(args.start.x, args.end.x); let riverMaxZ = Math.max(args.start.y, args.end.y); let mapSize = getMapSize(); for (let ix = 0; ix < mapSize; ++ix) for (let iz = 0; iz < mapSize; ++iz) { if (args.constraint && !args.constraint.allows(ix, iz)) continue; let vecPoint = new Vector2D(ix, iz); // Compute the shortest distance to the river. let distanceToRiver = distanceOfPointFromLine(args.start, args.end, vecPoint); // Closest point on the river (i.e the foot of the perpendicular). let river = Vector2D.sub(vecPoint, unitVecRiver.perpendicular().mult(distanceToRiver)); // Only process points that actually are perpendicular with the river. if (river.x < riverMinX || river.x > riverMaxX || river.y < riverMinZ || river.y > riverMaxZ) continue; // Coordinate between 0 and 1 on the axis parallel to the river. let riverFraction = river.distanceTo(args.start) / riverLength; // Amplitude of the river at this location. let riverCurve1 = riverCurve(riverFraction, startingAngle1, seed1); let riverCurve2 = args.parallel ? riverCurve1 : riverCurve(riverFraction, startingAngle2, seed2); // Add noise. let deviation = args.deviation * randFloat(-1, 1); // Compute the distance to the shoreline. let sign = Math.sign(distanceToRiver || 1); let shoreDist1 = sign * riverCurve1 + Math.abs(distanceToRiver) - deviation - args.width / 2; let shoreDist2 = sign * riverCurve2 + Math.abs(distanceToRiver) - deviation + args.width / 2; // Create the elevation for the water and the slopy shoreline and call the user functions. if (shoreDist1 < 0 && shoreDist2 > 0) { let height = args.heightRiverbed; if (shoreDist1 > -args.fadeDist) height += (args.heightLand - args.heightRiverbed) * (1 + shoreDist1 / args.fadeDist); else if (shoreDist2 < args.fadeDist) height += (args.heightLand - args.heightRiverbed) * (1 - shoreDist2 / args.fadeDist); if (args.minHeight === undefined || height < args.minHeight) setHeight(ix, iz, height); if (args.waterFunc) args.waterFunc(ix, iz, height, riverFraction); } else if (args.landFunc) args.landFunc(ix, iz, shoreDist1, shoreDist2); } } /** * Helper function to create a meandering river. * It works the same as sin or cos function with the difference that it's period is 1 instead of 2 pi. */ function rndRiver(f, seed) { let rndRw = seed; for (let i = 0; i <= f; ++i) rndRw = 10 * (rndRw % 1); let rndRr = f % 1; let retVal = (Math.floor(f) % 2 ? -1 : 1) * rndRr * (rndRr - 1); let rndRe = Math.floor(rndRw) % 5; if (rndRe == 0) retVal *= 2.3 * (rndRr - 0.5) * (rndRr - 0.5); else if (rndRe == 1) retVal *= 2.6 * (rndRr - 0.3) * (rndRr - 0.7); else if (rndRe == 2) retVal *= 22 * (rndRr - 0.2) * (rndRr - 0.3) * (rndRr - 0.3) * (rndRr - 0.8); else if (rndRe == 3) retVal *= 180 * (rndRr - 0.2) * (rndRr - 0.2) * (rndRr - 0.4) * (rndRr - 0.6) * (rndRr - 0.6) * (rndRr - 0.8); else if (rndRe == 4) retVal *= 2.6 * (rndRr - 0.5) * (rndRr - 0.7); return retVal; } /** * Add small rivers with shallows starting at a central river ending at the map border, if the given Constraint is met. */ function createTributaryRivers(horizontal, riverCount, riverWidth, heightRiverbed, heightRange, maxAngle, tributaryRiverTileClass, shallowTileClass, constraint) { log("Creating tributary rivers..."); let waviness = 0.4; let smoothness = scaleByMapSize(3, 12); let offset = 0.1; let tapering = 0.05; let heightShallow = -2; let riverAngle = horizontal ? 0 : Math.PI / 2; let mapSize = getMapSize(); let mapCenter = getMapCenter(); let riverConstraint = avoidClasses(tributaryRiverTileClass, 3); if (shallowTileClass) riverConstraint = new AndConstraint([riverConstraint, avoidClasses(shallowTileClass, 2)]); for (let i = 0; i < riverCount; ++i) { // Determining tributary river location let searchCenter = new Vector2D(randFloat(tapering, 1 - tapering), 0.5); let sign = randBool() ? 1 : -1; let distanceVec = new Vector2D(0, sign * tapering); let searchStart = Vector2D.add(searchCenter, distanceVec).mult(mapSize).rotateAround(riverAngle, mapCenter); let searchEnd = Vector2D.sub(searchCenter, distanceVec).mult(mapSize).rotateAround(riverAngle, mapCenter); let start = findLocationInDirectionBasedOnHeight(searchStart, searchEnd, heightRange[0], heightRange[1], 4); if (!start) continue; start.round(); let end = Vector2D.add(mapCenter, new Vector2D(mapSize, 0).rotate(riverAngle - sign * randFloat(maxAngle, 2 * Math.PI - maxAngle))).round(); // Create river if (!createArea( new PathPlacer( start.x, start.y, end.x, end.y, riverWidth, waviness, smoothness, offset, tapering), [ new SmoothElevationPainter(ELEVATION_SET, heightRiverbed, 4), paintClass(tributaryRiverTileClass) ], new AndConstraint([constraint, riverConstraint]))) continue; // Create small puddles at the map border to ensure players being separated createArea( new ClumpPlacer(Math.floor(diskArea(riverWidth / 2)), 0.95, 0.6, 10, end.x, end.y), new SmoothElevationPainter(ELEVATION_SET, heightRiverbed, 3), constraint); } // Create shallows if (shallowTileClass) for (let z of [0.25, 0.75]) createPassage({ "start": new Vector2D(0, z).mult(mapSize).rotateAround(riverAngle, mapCenter), "end": new Vector2D(1, z).mult(mapSize).rotateAround(riverAngle, mapCenter), "startWidth": scaleByMapSize(8, 12), "endWidth": scaleByMapSize(8, 12), "smoothWidth": 2, "startHeight": heightShallow, "endHeight": heightShallow, "maxHeight": heightShallow, "tileClass": shallowTileClass }); } /** * Creates a smooth, passable path between between start and end with the given startWidth and endWidth. * Paints the given tileclass and terrain. * * @property {Vector2D} start - Location of the passage. * @property {Vector2D} end * @property {number} startWidth - Size of the passage (perpendicular to the direction of the passage). * @property {number} endWidth * @property {number} [startHeight] - Fixed height to be used if the height at the location shouldn't be used. * @property {number} [endHeight] * @property {number} [maxHeight] - If given, do not touch any terrain above this height. * @property {number} smoothWidth - Number of tiles at the passage border to apply height interpolation. * @property {number} [tileClass] - Marks the passage with this tile class. * @property {string} [terrain] - Texture to be painted on the passage area. * @property {string} [edgeTerrain] - Texture to be painted on the borders of the passage. */ function createPassage(args) { let bound = x => Math.max(0, Math.min(Math.round(x), getMapSize())); let startHeight = args.startHeight !== undefined ? args.startHeight : getHeight(bound(args.start.x), bound(args.start.y)); let endHeight = args.endHeight !== undefined ? args.endHeight : getHeight(bound(args.end.x), bound(args.end.y)); let passageVec = Vector2D.sub(args.end, args.start); let widthDirection = passageVec.perpendicular().normalize(); let lengthStep = 1 / (2 * passageVec.length()); for (let lengthFraction = 0; lengthFraction <= 1; lengthFraction += lengthStep) { let locationLength = Vector2D.add(args.start, Vector2D.mult(passageVec, lengthFraction)); let halfPassageWidth = (args.startWidth + (args.endWidth - args.startWidth) * lengthFraction) / 2; let passageHeight = startHeight + (endHeight - startHeight) * lengthFraction; for (let stepWidth = -halfPassageWidth; stepWidth <= halfPassageWidth; stepWidth += 0.5) { let location = Vector2D.add(locationLength, Vector2D.mult(widthDirection, stepWidth)).round(); if (!g_Map.inMapBounds(location.x, location.y) || args.maxHeight !== undefined && getHeight(location.x, location.y) > args.maxHeight) continue; let smoothDistance = args.smoothWidth + Math.abs(stepWidth) - halfPassageWidth; g_Map.setHeight( location.x, location.y, smoothDistance > 0 ? (getHeight(location.x, location.y) * smoothDistance + passageHeight / smoothDistance) / (smoothDistance + 1 / smoothDistance) : passageHeight); if (args.tileClass !== undefined) addToClass(location.x, location.y, args.tileClass); if (args.edgeTerrain && smoothDistance > 0) createTerrain(args.edgeTerrain).place(location.x, location.y); else if (args.terrain) createTerrain(args.terrain).place(location.x, location.y); } } } /** * Returns the first location between startPoint and endPoint that lies within the given heightrange. */ function findLocationInDirectionBasedOnHeight(startPoint, endPoint, minHeight, maxHeight, offset = 0) { let stepVec = Vector2D.sub(endPoint, startPoint); let distance = Math.ceil(stepVec.length()); stepVec.normalize(); for (let i = 0; i < distance; ++i) { let pos = Vector2D.add(startPoint, Vector2D.mult(stepVec, i)); let ipos = pos.clone().round(); if (g_Map.validH(ipos.x, ipos.y) && getHeight(ipos.x, ipos.y) >= minHeight && getHeight(ipos.x, ipos.y) <= maxHeight) return pos.add(stepVec.mult(offset)); } return undefined; } Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/library.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/library.js (revision 20904) +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/library.js (revision 20905) @@ -1,440 +1,425 @@ const TERRAIN_SEPARATOR = "|"; const SEA_LEVEL = 20.0; const HEIGHT_UNITS_PER_METRE = 92; const MAP_BORDER_WIDTH = 3; const g_DamageTypes = new DamageTypes(); /** * Constants needed for heightmap_manipulation.js */ const MAX_HEIGHT_RANGE = 0xFFFF / HEIGHT_UNITS_PER_METRE; // Engine limit, Roughly 700 meters const MIN_HEIGHT = - SEA_LEVEL; /** * Length of one tile of the terrain grid in metres. * Useful to transform footprint sizes of templates to the coordinate system used by getMapSize. */ const TERRAIN_TILE_SIZE = Engine.GetTerrainTileSize(); const MAX_HEIGHT = MAX_HEIGHT_RANGE - SEA_LEVEL; /** * Default angle for buildings. */ const BUILDING_ORIENTATION = -1/4 * Math.PI; const g_CivData = deepfreeze(loadCivFiles(false)); function fractionToTiles(f) { return g_Map.size * f; } function tilesToFraction(t) { return t / g_Map.size; } -function fractionToSize(f) -{ - return getMapArea() * f; -} - -function sizeToFraction(s) -{ - return s / getMapArea(); -} - function scaleByMapSize(min, max, minMapSize = 128, maxMapSize = 512) { return min + (max - min) * (g_Map.size - minMapSize) / (maxMapSize - minMapSize); } /** * Retries the given function with those arguments as often as specified. */ function retryPlacing(placeFunc, retryFactor, amount, getResult, behaveDeprecated = false) { let maxFail = amount * retryFactor; let results = []; let good = 0; let bad = 0; while (good < amount && bad <= maxFail) { let result = placeFunc(); if (result !== undefined || behaveDeprecated) { ++good; if (getResult) results.push(result); } else ++bad; } return getResult ? results : good; } /** * Sets the x and z property of the given object (typically a Placer or Group) to a random point on the map. * @param passableOnly - Should be true for entity placement and false for terrain or elevation operations. */ function randomizeCoordinates(obj, passableOnly) { let border = passableOnly ? MAP_BORDER_WIDTH : 0; if (g_MapSettings.CircularMap) { // Polar coordinates // Uniformly distributed on the disk let halfMapSize = g_Map.size / 2 - border; let r = halfMapSize * Math.sqrt(randFloat(0, 1)); let theta = randomAngle(); obj.x = Math.floor(r * Math.cos(theta)) + halfMapSize; obj.z = Math.floor(r * Math.sin(theta)) + halfMapSize; } else { // Rectangular coordinates obj.x = randIntExclusive(border, g_Map.size - border); obj.z = randIntExclusive(border, g_Map.size - border); } } /** * Sets the x and z property of the given JS object (typically a Placer or Group) to a random point of the area. */ function randomizeCoordinatesFromAreas(obj, areas) { let pt = pickRandom(pickRandom(areas).points); obj.x = pt.x; obj.z = pt.z; } // TODO this is a hack to simulate the old behaviour of those functions // until all old maps are changed to use the correct version of these functions function createObjectGroupsDeprecated(group, player, constraint, amount, retryFactor = 10) { return createObjectGroups(group, player, constraint, amount, retryFactor, true); } function createObjectGroupsByAreasDeprecated(group, player, constraint, amount, retryFactor, areas) { return createObjectGroupsByAreas(group, player, constraint, amount, retryFactor, areas, true); } /** * Attempts to place the given number of areas in random places of the map. * Returns actually placed areas. */ function createAreas(centeredPlacer, painter, constraint, amount, retryFactor = 10) { let placeFunc = function() { randomizeCoordinates(centeredPlacer, false); return createArea(centeredPlacer, painter, constraint); }; return retryPlacing(placeFunc, retryFactor, amount, true, false); } /** * Attempts to place the given number of areas in random places of the given areas. * Returns actually placed areas. */ function createAreasInAreas(centeredPlacer, painter, constraint, amount, retryFactor, areas) { let placeFunc = function() { randomizeCoordinatesFromAreas(centeredPlacer, areas); return createArea(centeredPlacer, painter, constraint); }; return retryPlacing(placeFunc, retryFactor, amount, true, false); } /** * Attempts to place the given number of groups in random places of the map. * Returns the number of actually placed groups. */ function createObjectGroups(group, player, constraint, amount, retryFactor = 10, behaveDeprecated = false) { let placeFunc = function() { randomizeCoordinates(group, true); return createObjectGroup(group, player, constraint); }; return retryPlacing(placeFunc, retryFactor, amount, false, behaveDeprecated); } /** * Attempts to place the given number of groups in random places of the given areas. * Returns the number of actually placed groups. */ function createObjectGroupsByAreas(group, player, constraint, amount, retryFactor, areas, behaveDeprecated = false) { let placeFunc = function() { randomizeCoordinatesFromAreas(group, areas); return createObjectGroup(group, player, constraint); }; return retryPlacing(placeFunc, retryFactor, amount, false, behaveDeprecated); } function createTerrain(terrain) { return typeof terrain == "string" ? new SimpleTerrain(...terrain.split(TERRAIN_SEPARATOR)) : new RandomTerrain(terrain.map(t => createTerrain(t))); } function placeObject(x, z, type, player, angle) { if (g_Map.validT(x, z)) g_Map.addObject(new Entity(type, player, x, z, angle)); } function isCircularMap() { return !!g_MapSettings.CircularMap; } function createTileClass() { return g_Map.createTileClass(); } function getTileClass(id) { if (!g_Map.validClass(id)) return undefined; return g_Map.tileClasses[id]; } /** * Constructs a new Area shaped by the Placer meeting the Constraints and calls the Painters there. * Supports both Centered and Non-Centered Placers. */ function createArea(placer, painter, constraints) { let points = placer.place(new AndConstraint(constraints)); if (!points) return undefined; let area = g_Map.createArea(points); if (painter instanceof Array) painter = new MultiPainter(painter); painter.paint(area); return area; } /** * @param mode is one of the HeightPlacer constants determining whether to exclude the min/max elevation. */ function paintTerrainBasedOnHeight(minHeight, maxHeight, mode, terrain) { createArea( new HeightPlacer(mode, minHeight, maxHeight), new TerrainPainter(terrain)); } function paintTileClassBasedOnHeight(minHeight, maxHeight, mode, tileClass) { createArea( new HeightPlacer(mode, minHeight, maxHeight), new TileClassPainter(getTileClass(tileClass))); } function unPaintTileClassBasedOnHeight(minHeight, maxHeight, mode, tileClass) { createArea( new HeightPlacer(mode, minHeight, maxHeight), new TileClassUnPainter(getTileClass(tileClass))); } /** * Places the Entities of the given Group if they meet the Constraints * and sets the given player as the owner. */ function createObjectGroup(group, player, constraints) { return group.place(player, new AndConstraint(constraints)); } function getMapSize() { return g_Map.size; } -function getMapArea() -{ - return Math.square(g_Map.size); -} - function getMapCenter() { return deepfreeze(new Vector2D(g_Map.size / 2, g_Map.size / 2)); } function getMapBounds() { return deepfreeze({ "left": fractionToTiles(0), "right": fractionToTiles(1), "top": fractionToTiles(1), "bottom": fractionToTiles(0) }); } function isNomad() { return !!g_MapSettings.Nomad; } function getNumPlayers() { return g_MapSettings.PlayerData.length - 1; } function getCivCode(playerID) { return g_MapSettings.PlayerData[playerID].Civ; } function areAllies(playerID1, playerID2) { return ( g_MapSettings.PlayerData[playerID1].Team !== undefined && g_MapSettings.PlayerData[playerID2].Team !== undefined && g_MapSettings.PlayerData[playerID1].Team != -1 && g_MapSettings.PlayerData[playerID2].Team != -1 && g_MapSettings.PlayerData[playerID1].Team === g_MapSettings.PlayerData[playerID2].Team); } function getPlayerTeam(playerID) { if (g_MapSettings.PlayerData[playerID].Team === undefined) return -1; return g_MapSettings.PlayerData[playerID].Team; } function getHeight(x, z) { return g_Map.getHeight(x, z); } function setHeight(x, z, height) { g_Map.setHeight(x, z, height); } /** * Utility functions for classes */ /** * Add point to given class by id */ function addToClass(x, z, id) { let tileClass = getTileClass(id); if (tileClass !== null) tileClass.add(x, z); } /** * Remove point from the given class by id */ function removeFromClass(x, z, id) { let tileClass = getTileClass(id); if (tileClass !== null) tileClass.remove(x, z); } /** * Create a painter for the given class */ function paintClass(id) { return new TileClassPainter(getTileClass(id)); } /** * Create a painter for the given class */ function unPaintClass(id) { return new TileClassUnPainter(getTileClass(id)); } /** * Create an avoid constraint for the given classes by the given distances */ function avoidClasses(/*class1, dist1, class2, dist2, etc*/) { let ar = []; for (let i = 0; i < arguments.length/2; ++i) ar.push(new AvoidTileClassConstraint(arguments[2*i], arguments[2*i+1])); // Return single constraint if (ar.length == 1) return ar[0]; return new AndConstraint(ar); } /** * Create a stay constraint for the given classes by the given distances */ function stayClasses(/*class1, dist1, class2, dist2, etc*/) { let ar = []; for (let i = 0; i < arguments.length/2; ++i) ar.push(new StayInTileClassConstraint(arguments[2*i], arguments[2*i+1])); // Return single constraint if (ar.length == 1) return ar[0]; return new AndConstraint(ar); } /** * Create a border constraint for the given classes by the given distances */ function borderClasses(/*class1, idist1, odist1, class2, idist2, odist2, etc*/) { let ar = []; for (let i = 0; i < arguments.length/3; ++i) ar.push(new BorderTileClassConstraint(arguments[3*i], arguments[3*i+1], arguments[3*i+2])); // Return single constraint if (ar.length == 1) return ar[0]; return new AndConstraint(ar); } /** * Checks if the given tile is in class "id" */ function checkIfInClass(x, z, id) { let tileClass = getTileClass(id); if (tileClass === null) return 0; let members = tileClass.countMembersInRadius(x, z, 1); if (members === null) return 0; return members; } Index: ps/trunk/binaries/data/mods/public/maps/random/schwarzwald.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/schwarzwald.js (revision 20904) +++ ps/trunk/binaries/data/mods/public/maps/random/schwarzwald.js (revision 20905) @@ -1,325 +1,324 @@ Engine.LoadLibrary('rmgen'); Engine.LoadLibrary("heightmap"); log('Initializing map...'); const heightLand = 1; const heightOffsetPath = -0.1; InitMap(heightLand, g_MapSettings.BaseTerrain); setSkySet("fog"); setFogFactor(0.35); setFogThickness(0.19); setWaterColor(0.501961, 0.501961, 0.501961); setWaterTint(0.25098, 0.501961, 0.501961); setWaterWaviness(0.5); setWaterType("clap"); setWaterMurkiness(0.75); setPPSaturation(0.37); setPPContrast(0.4); setPPBrightness(0.4); setPPEffect("hdr"); setPPBloom(0.4); var clPlayer = createTileClass(); var clPath = createTileClass(); var clForest = createTileClass(); var clWater = createTileClass(); var clMetal = createTileClass(); var clRock = createTileClass(); var clFood = createTileClass(); var clBaseResource = createTileClass(); var clOpen = createTileClass(); var templateStoneMine = 'gaia/geology_stonemine_alpine_quarry'; var templateMetalMine = 'gaia/geology_metal_alpine_slabs'; var aGrass = 'actor|props/flora/grass_soft_small_tall.xml'; var aGrassShort = 'actor|props/flora/grass_soft_large.xml'; var aRockLarge = 'actor|geology/stone_granite_med.xml'; var aRockMedium = 'actor|geology/stone_granite_med.xml'; var aBushMedium = 'actor|props/flora/bush_medit_me.xml'; var aBushSmall = 'actor|props/flora/bush_medit_sm.xml'; var aReeds = 'actor|props/flora/reeds_pond_lush_b.xml'; var oFish = "gaia/fauna_fish"; var terrainWood = ['alpine_forrestfloor|gaia/flora_tree_oak', 'alpine_forrestfloor|gaia/flora_tree_pine']; var terrainWoodBorder = ['new_alpine_grass_mossy|gaia/flora_tree_oak', 'alpine_forrestfloor|gaia/flora_tree_pine', 'temp_grass_long|gaia/flora_bush_temperate', 'temp_grass_clovers|gaia/flora_bush_berry', 'temp_grass_clovers_2|gaia/flora_bush_grapes', 'temp_grass_plants|gaia/fauna_deer', 'temp_grass_plants|gaia/fauna_rabbit', 'new_alpine_grass_dirt_a']; var terrainBase = ['temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants', 'temp_grass_plants|gaia/fauna_sheep']; var terrainBaseBorder = ['temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_d', 'temp_grass_plants', 'temp_plants_bog', 'temp_grass_plants', 'temp_grass_plants']; var baseTex = ['temp_road', 'temp_road_overgrown']; var terrainPath = ['temp_road', 'temp_road_overgrown']; var tWater = ['dirt_brown_d']; var tWaterBorder = ['dirt_brown_d']; var mapSize = getMapSize(); -var mapArea = getMapArea(); var mapCenter = getMapCenter(); var mapRadius = mapSize/2; var numPlayers = getNumPlayers(); var baseRadius = 15; var minPlayerRadius = Math.min(mapRadius - 1.5 * baseRadius, 5/8 * mapRadius); var maxPlayerRadius = Math.min(mapRadius - baseRadius, 3/4 * mapRadius); var playerPosition = []; var playerAngleStart = randomAngle(); var playerAngleAddAvrg = 2 * Math.PI / numPlayers; var playerAngleMaxOff = playerAngleAddAvrg/4; var resourceRadius = fractionToTiles(1/3); // Setup woods // For large maps there are memory errors with too many trees. A density of 256*192/mapArea works with 0 players. // Around each player there is an area without trees so with more players the max density can increase a bit. -var maxTreeDensity = Math.min(256 * (192 + 8 * numPlayers) / mapArea, 1); // Has to be tweeked but works ok +var maxTreeDensity = Math.min(256 * (192 + 8 * numPlayers) / Math.square(mapSize), 1); // Has to be tweeked but works ok var bushChance = 1/3; // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood // Set height limits and water level by map size // Set target min and max height depending on map size to make average steepness about the same on all map sizes var heightRange = {'min': MIN_HEIGHT * (g_Map.size + 512) / 8192, 'max': MAX_HEIGHT * (g_Map.size + 512) / 8192, 'avg': (MIN_HEIGHT * (g_Map.size + 512) +MAX_HEIGHT * (g_Map.size + 512))/16384}; // Set average water coverage var averageWaterCoverage = 1/5; // NOTE: Since erosion is not predictable actual water coverage might vary much with the same values var heightSeaGround = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); var heightSeaGroundAdjusted = heightSeaGround + MIN_HEIGHT; setWaterHeight(heightSeaGround); // Setting a 3x3 Grid as initial heightmap var initialReliefmap = [[heightRange.max, heightRange.max, heightRange.max], [heightRange.max, heightRange.min, heightRange.max], [heightRange.max, heightRange.max, heightRange.max]]; setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, initialReliefmap); for (var i = 0; i < 5; i++) globalSmoothHeightmap(); rescaleHeightmap(heightRange.min, heightRange.max); var 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 var startLocations = getStartLocationsByHeightmap({'min': heighLimits[4], 'max': heighLimits[5]}); var playerHeight = (heighLimits[4] + heighLimits[5]) / 2; for (let i = 0; i < numPlayers; ++i) { playerPosition[i] = Vector2D.add( mapCenter, new Vector2D(randFloat(minPlayerRadius, maxPlayerRadius), 0).rotate( -((playerAngleStart + i * playerAngleAddAvrg + randFloat(0, playerAngleMaxOff)) % (2 * Math.PI)))).round(); rectangularSmoothToHeight(playerPosition[i], 20, 20, playerHeight, 0.8); } placePlayerBases({ "PlayerPlacement": [sortAllPlayers(), playerPosition], "BaseResourceClass": clBaseResource, "Walls": false, // player class painted below "CityPatch": { "radius": 0.8 * baseRadius, "smoothness": 1/8, "painters": [ new TerrainPainter([baseTex], [baseRadius/4, baseRadius/4]), paintClass(clPlayer) ] }, // No chicken "Berries": { "template": "gaia/flora_bush_berry", "minCount": 2, "maxCount": 2, "minDist": 10, "maxDist": 10 }, "Mines": { "types": [ { "template": templateMetalMine }, { "template": templateStoneMine } ], "distance": 15, "minAngle": Math.PI / 2, "maxAngle": Math.PI }, "Trees": { "template": "gaia/flora_tree_oak_large", "count": 2 } }); log("Creating mines..."); for (let [minHeight, maxHeight] of [[heighLimits[3], (heighLimits[4] + heighLimits[3]) / 2], [(heighLimits[5] + heighLimits[6]) / 2, heighLimits[7]]]) for (let [template, tileClass] of [[templateStoneMine, clRock], [templateMetalMine, clMetal]]) createObjectGroups( new SimpleGroup([new SimpleObject(template, 1, 1, 0, 4)], true, tileClass), 0, [ new HeightConstraint(minHeight, maxHeight), avoidClasses(clForest, 4, clPlayer, 20, clMetal, 40, clRock, 40) ], scaleByMapSize(2, 8), 100, false); Engine.SetProgress(50); log("Painting textures..."); var betweenShallowAndShore = (heighLimits[3] + heighLimits[2]) / 2; createArea( new HeightPlacer(Elevation_IncludeMin_IncludeMax, heighLimits[2], betweenShallowAndShore), new LayeredPainter([terrainBase, terrainBaseBorder], [5])); paintTileClassBasedOnHeight(heighLimits[2], betweenShallowAndShore, 1, clOpen); createArea( new HeightPlacer(Elevation_IncludeMin_IncludeMax, heightRange.min, heighLimits[2]), new LayeredPainter([tWaterBorder, tWater], [2])); paintTileClassBasedOnHeight(heightRange.min, heighLimits[2], 1, clWater); Engine.SetProgress(60); log("Painting paths..."); var pathBlending = numPlayers <= 4; for (let i = 0; i < numPlayers + (pathBlending ? 1 : 0); ++i) for (let j = pathBlending ? 0 : i + 1; j < numPlayers + 1; ++j) { let pathStart = i < numPlayers ? playerPosition[i] : mapCenter; let pathEnd = j < numPlayers ? playerPosition[j] : mapCenter; createArea( new RandomPathPlacer(pathStart, pathEnd, 1.75, baseRadius / 2, pathBlending), [ new TerrainPainter(terrainPath), new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetPath, 1), paintClass(clPath) ], avoidClasses(clPath, 0, clOpen, 0 ,clWater, 4, clBaseResource, 4)); } Engine.SetProgress(75); log("Creating decoration..."); createDecoration( [ [new SimpleObject(aRockMedium, 1, 3, 0, 1)], [new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)], [new SimpleObject(aGrassShort, 1, 2, 0, 1)], [new SimpleObject(aGrass, 2, 4, 0, 1.8), new SimpleObject(aGrassShort, 3, 6, 1.2, 2.5)], [new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)] ], [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), scaleByMapSize(13, 200), scaleByMapSize(13, 200), scaleByMapSize(13, 200) ], avoidClasses(clForest, 1, clPlayer, 0, clPath, 3, clWater, 3)); Engine.SetProgress(80); log("Growing fish..."); createFood( [ [new SimpleObject(oFish, 2, 3, 0, 2)] ], [ 100 * numPlayers ], [avoidClasses(clFood, 5), stayClasses(clWater, 4)], clFood); Engine.SetProgress(85); log("Planting reeds..."); var types = [aReeds]; for (let type of types) createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(type, 1, 1, 0, 0)], true), 0, borderClasses(clWater, 0, 6), scaleByMapSize(1, 2) * 1000, 1000); Engine.SetProgress(90); log("Planting trees..."); for (var x = 0; x < mapSize; x++) for (var z = 0;z < mapSize;z++) { if (!g_Map.validT(x, z)) continue; // The 0.5 is a correction for the entities placed on the center of tiles var radius = Math.euclidDistance2D(x + 0.5, z + 0.5, mapCenter.x, mapCenter.y); var minDistToSL = mapSize; for (var i=0; i < numPlayers; i++) minDistToSL = Math.min(minDistToSL, Math.euclidDistance2D(x, z, playerPosition[i].x, playerPosition[i].x)); // Woods tile based var tDensFactSL = Math.max(Math.min((minDistToSL - baseRadius) / baseRadius, 1), 0); var tDensFactRad = Math.abs((resourceRadius - radius) / resourceRadius); var tDensActual = (maxTreeDensity * tDensFactSL * tDensFactRad)*0.75; if (!randBool(tDensActual)) continue; let border = tDensActual < randFloat(0, bushChance * maxTreeDensity); createArea( new RectPlacer(x, z, x, z), [ new TerrainPainter(border ? terrainWoodBorder : terrainWood), paintClass(clForest) ], border ? avoidClasses(clPath, 1, clOpen, 2, clWater, 3, clMetal, 4, clRock, 4) : avoidClasses(clPath, 2, clOpen, 3, clWater, 4, clMetal, 4, clRock, 4)); } placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clFood, 2, clMetal, 4, clRock, 4)); Engine.SetProgress(100); ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/survivalofthefittest.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/survivalofthefittest.js (revision 20904) +++ ps/trunk/binaries/data/mods/public/maps/random/survivalofthefittest.js (revision 20905) @@ -1,204 +1,203 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmbiome"); setSelectedBiome(); const tMainTerrain = g_Terrains.mainTerrain; const tForestFloor1 = g_Terrains.forestFloor1; const tForestFloor2 = g_Terrains.forestFloor2; const tCliff = g_Terrains.cliff; const tHill = g_Terrains.hill; const tTier1Terrain = g_Terrains.tier1Terrain; const tTier2Terrain = g_Terrains.tier2Terrain; const tTier3Terrain = g_Terrains.tier3Terrain; const tTier4Terrain = g_Terrains.tier4Terrain; const oTree1 = g_Gaia.tree1; const oTree2 = g_Gaia.tree2; const oTree3 = g_Gaia.tree3; const oTree4 = g_Gaia.tree4; const oTree5 = g_Gaia.tree5; const aGrass = g_Decoratives.grass; const aGrassShort = g_Decoratives.grassShort; const aRockLarge = g_Decoratives.rockLarge; const aRockMedium = g_Decoratives.rockMedium; const aBushMedium = g_Decoratives.bushMedium; const aBushSmall = g_Decoratives.bushSmall; const aWaypointFlag = "actor|props/special/common/waypoint_flag.xml"; const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; const oTreasureSeeker = "undeletable|skirmish/units/default_support_female_citizen"; const triggerPointAttacker = "trigger/trigger_point_A"; const triggerPointTreasures = [ "trigger/trigger_point_B", "trigger/trigger_point_C", "trigger/trigger_point_D" ]; const heightLand = 3; const heightHill = 30; InitMap(heightHill, tMainTerrain); var numPlayers = getNumPlayers(); var mapSize = getMapSize(); -var mapArea = getMapArea(); var mapCenter = getMapCenter(); var clPlayer = createTileClass(); var clHill = createTileClass(); var clForest = createTileClass(); var clDirt = createTileClass(); var clBaseResource = createTileClass(); var clLand = createTileClass(); var clWomen = createTileClass(); -// Create the main treasure area in the middle of the map +log("Creating central area..."); createArea( - new ClumpPlacer(mapArea * scaleByMapSize(0.065, 0.09), 0.7, 0.1, 10, mapCenter.x, mapCenter.y), + new ClumpPlacer(diskArea(fractionToTiles(0.15)), 0.7, 0.1, 10, mapCenter.x, mapCenter.y), [ new LayeredPainter([tMainTerrain, tMainTerrain], [3]), new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), paintClass(clLand) ]); Engine.SetProgress(10); var [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.3)); var halfway = distributePointsOnCircle(numPlayers, startAngle, fractionToTiles(0.375), mapCenter)[0].map(v => v.round()); var attacker = distributePointsOnCircle(numPlayers, startAngle, fractionToTiles(0.45), mapCenter)[0].map(v => v.round()); var passage = distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.5), mapCenter)[0]; log("Creating player bases and attacker points..."); for (let i = 0; i < numPlayers; ++i) { placeStartingEntities(playerPosition[i], playerIDs[i], getStartingEntities(playerIDs[i]).filter(ent => ent.Template.indexOf("civil_centre") != -1 || ent.Template.indexOf("infantry") != -1)); placePlayerBaseDecoratives({ "playerPosition": playerPosition[i], "template": aGrassShort, "BaseResourceClass": clBaseResource }); log("Creating passage separating players..."); createArea( new PathPlacer(mapCenter.x, mapCenter.y, passage[i].x, passage[i].y, scaleByMapSize(14, 24), 0.4, scaleByMapSize(3, 9), 0.2, 0.05), [ new LayeredPainter([tMainTerrain, tMainTerrain], [1]), new SmoothElevationPainter(ELEVATION_SET, heightLand, 4) ]); log("Placing treasure seeker woman..."); let femaleLocation = findLocationInDirectionBasedOnHeight(playerPosition[i], mapCenter, -3 , 3.5, 3).round(); addToClass(femaleLocation.x, femaleLocation.y, clWomen); placeObject(femaleLocation.x, femaleLocation.y, oTreasureSeeker, playerIDs[i], playerAngle[i] + Math.PI); log("Placing attacker spawn point...."); placeObject(attacker[i].x, attacker[i].y, aWaypointFlag, 0, Math.PI / 2); placeObject(attacker[i].x, attacker[i].y, triggerPointAttacker, playerIDs[i], Math.PI / 2); log("Preventing mountains in the area between player and attackers..."); addCivicCenterAreaToClass(playerPosition[i], clPlayer); addToClass(attacker[i].x, attacker[i].y, clPlayer); addToClass(halfway[i].x, halfway[i].y, clPlayer); } Engine.SetProgress(20); paintTerrainBasedOnHeight(3.12, 29, 1, tCliff); paintTileClassBasedOnHeight(3.12, 29, 1, clHill); for (let triggerPointTreasure of triggerPointTreasures) createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(triggerPointTreasure, 1, 1, 0, 0)], true, clWomen), 0, [avoidClasses(clForest, 5, clPlayer, 5, clHill, 5), stayClasses(clLand, 5)], scaleByMapSize(40, 140), 100 ); Engine.SetProgress(25); createBumps(stayClasses(clLand, 5)); var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); createForests( [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], [avoidClasses(clPlayer, 20, clForest, 5, clHill, 0, clBaseResource,2, clWomen, 5), stayClasses(clLand, 4)], clForest, forestTrees); Engine.SetProgress(30); if (randBool()) createHills( [tMainTerrain, tCliff, tHill], [avoidClasses(clPlayer, 20, clHill, 5, clBaseResource, 3, clWomen, 5), stayClasses(clLand, 5)], clHill, scaleByMapSize(10, 60) * numPlayers); else createMountains( tCliff, [avoidClasses(clPlayer, 20, clHill, 5, clBaseResource, 3, clWomen, 5), stayClasses(clLand, 5)], clHill, scaleByMapSize(10, 60) * numPlayers); Engine.SetProgress(40); createHills( [tCliff, tCliff, tHill], avoidClasses(clPlayer, 20, clHill, 5, clBaseResource, 3, clWomen, 5, clLand, 5), clHill, scaleByMapSize(15, 90) * numPlayers, undefined, undefined, undefined, undefined, 55); Engine.SetProgress(50); log("Creating dirt patches..."); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1], [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWomen, 5), stayClasses(clLand, 5)], scaleByMapSize(15, 45), clDirt); log("Creating grass patches..."); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tTier4Terrain, [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12, clWomen, 5), stayClasses(clLand, 5)], scaleByMapSize(15, 45), clDirt); var planetm = 1; if (currentBiome() == "tropic") planetm = 8; createDecoration( [ [new SimpleObject(aRockMedium, 1, 3, 0, 1)], [new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)], [new SimpleObject(aGrassShort, 1, 2, 0, 1)], [new SimpleObject(aGrass, 2,4, 0, 1.8), new SimpleObject(aGrassShort, 3, 6, 1.2, 2.5)], [new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)] ], [ scaleByMapSize(16, 262), scaleByMapSize(8, 131), planetm * scaleByMapSize(13, 200), planetm * scaleByMapSize(13, 200), planetm * scaleByMapSize(13, 200) ], [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 5)]); createStragglerTrees( [oTree1, oTree2, oTree4, oTree3], [avoidClasses(clForest, 7, clHill, 1, clPlayer, 9), stayClasses(clLand, 7)], clForest, stragglerTrees); ExportMap();