Index: binaries/data/mods/public/maps/random/aegean_sea.js =================================================================== --- binaries/data/mods/public/maps/random/aegean_sea.js +++ binaries/data/mods/public/maps/random/aegean_sea.js @@ -3,308 +3,325 @@ TILE_CENTERED_HEIGHT_MAP = true; -const tCity = "medit_city_pavement"; -const tCityPlaza = "medit_city_pavement"; -const tHill = ["medit_grass_shrubs", "medit_rocks_grass_shrubs", "medit_rocks_shrubs", "medit_rocks_grass", "medit_shrubs"]; -const tMainDirt = "medit_dirt"; -const tCliff = "medit_cliff_aegean"; -const tForestFloor = "medit_grass_shrubs"; -const tGrass = "medit_grass_field"; -const tGrassSand50 = "medit_grass_field_a"; -const tGrassSand25 = "medit_grass_field_b"; -const tDirt = "medit_dirt_b"; -const tDirt2 = "medit_rocks_grass"; -const tDirt3 = "medit_rocks_shrubs"; -const tDirtCracks = "medit_dirt_c"; -const tShoreUpper = "medit_sand"; -const tShoreLower = "medit_sand_wet"; -const tCoralsUpper = "medit_sea_coral_plants"; -const tCoralsLower = "medit_sea_coral_deep"; -const tSeaDepths = "medit_sea_depths"; - -const oBerryBush = "gaia/fruit/berry_01"; -const oDeer = "gaia/fauna_deer"; -const oFish = "gaia/fish/generic"; -const oSheep = "gaia/fauna_sheep"; -const oGoat = "gaia/fauna_goat"; -const oStoneLarge = "gaia/rock/mediterranean_large"; -const oStoneSmall = "gaia/rock/mediterranean_small"; -const oMetalLarge = "gaia/ore/mediterranean_large"; -const oDatePalm = "gaia/tree/cretan_date_palm_short"; -const oSDatePalm = "gaia/tree/cretan_date_palm_tall"; -const oCarob = "gaia/tree/carob"; -const oFanPalm = "gaia/tree/medit_fan_palm"; -const oPoplar = "gaia/tree/poplar_lombardy"; -const oCypress = "gaia/tree/cypress"; - -const aBush1 = "actor|props/flora/bush_medit_sm.xml"; -const aBush2 = "actor|props/flora/bush_medit_me.xml"; -const aBush3 = "actor|props/flora/bush_medit_la.xml"; -const aBush4 = "actor|props/flora/bush_medit_me.xml"; -const aDecorativeRock = "actor|geology/stone_granite_med.xml"; - -const pForest = [tForestFloor, tForestFloor + TERRAIN_SEPARATOR + oCarob, tForestFloor + TERRAIN_SEPARATOR + oDatePalm, tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, tForestFloor]; - -const heightSeaGround = -3; -const heightSeaBump = -2.5; -const heightCorralsLower = -2; -const heightCorralsUpper = -1.5; -const heightShore = 1; -const heightLand = 2; -const heightIsland = 6; - -const g_Map = new RandomMap(heightShore, tHill); - -const numPlayers = getNumPlayers(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clGrass = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clIsland = g_Map.createTileClass(); - -const startAngle = randomAngle(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementRiver(startAngle , fractionToTiles(0.6)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tCityPlaza, - "innerTerrain": tCity - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oCarob, - "count": 2 - }, - "Decoratives": { - "template": aBush1 - } -}); -Engine.SetProgress(30); - -paintRiver({ - "parallel": false, - "start": new Vector2D(mapCenter.x, mapBounds.top).rotateAround(startAngle, mapCenter), - "end": new Vector2D(mapCenter.x, mapBounds.bottom).rotateAround(startAngle, mapCenter), - "width": fractionToTiles(0.35), - "fadeDist": scaleByMapSize(6, 25), - "deviation": 0, - "heightRiverbed": heightSeaGround, - "heightLand": heightLand, - "meanderShort": 20, - "meanderLong": 0 -}); - -paintTileClassBasedOnHeight(-Infinity, 0.7, Elevation_ExcludeMin_ExcludeMax, clWater); - -paintTerrainBasedOnHeight(-Infinity, heightShore, Elevation_ExcludeMin_ExcludeMax, tShoreLower); -paintTerrainBasedOnHeight(heightShore, heightLand, Elevation_ExcludeMin_ExcludeMax, tShoreUpper); -Engine.SetProgress(40); - -createBumps(avoidClasses(clWater, 2, clPlayer, 20)); - -const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); -createForests( - [tForestFloor, tForestFloor, tForestFloor, pForest, pForest], - avoidClasses(clPlayer, 20, clForest, 17, clWater, 2, clBaseResource, 3), - clForest, - forestTrees); - -Engine.SetProgress(50); - -if (randBool()) - createHills([tGrass, tCliff, tHill], avoidClasses(clPlayer, 20, clForest, 1, clHill, 15, clWater, 3), clHill, scaleByMapSize(3, 15)); -else - createMountains(tCliff, avoidClasses(clPlayer, 20, clForest, 1, clHill, 15, clWater, 3), clHill, scaleByMapSize(3, 15)); - -g_Map.log("Creating grass patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tGrass,tGrassSand50],[tGrassSand50,tGrassSand25], [tGrassSand25,tGrass]], - [1,1], - avoidClasses(clForest, 0, clGrass, 2, clPlayer, 10, clWater, 2, clDirt, 2, clHill, 1), - scaleByMapSize(15, 45), - clDirt); - -Engine.SetProgress(55); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [tDirt3, tDirt2,[tDirt,tMainDirt], [tDirtCracks,tMainDirt]], - [1,1,1], - avoidClasses(clForest, 0, clDirt, 2, clPlayer, 10, clWater, 2, clGrass, 2, clHill, 1), - scaleByMapSize(15, 45), - clDirt); - -Engine.SetProgress(60); - -g_Map.log("Creating undersea bumps"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), - new SmoothElevationPainter(ELEVATION_SET, heightSeaBump, 3), - stayClasses(clWater, 6), - scaleByMapSize(10, 50)); - -g_Map.log("Creating islands"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(30, 80)), 0.5), - [ - new LayeredPainter([tShoreLower, tShoreUpper, tHill], [2 ,1]), - new SmoothElevationPainter(ELEVATION_SET, heightIsland, 4), - new TileClassPainter(clIsland) - ], - [avoidClasses(clPlayer, 8, clForest, 1, clIsland, 15), stayClasses (clWater, 6)], - scaleByMapSize(1, 4) * numPlayers -); - -paintTerrainBasedOnHeight(-Infinity, heightSeaGround, Elevation_IncludeMin_IncludeMax, tSeaDepths); -paintTerrainBasedOnHeight(heightSeaGround, heightCorralsLower, Elevation_ExcludeMin_IncludeMax, tCoralsLower); -paintTerrainBasedOnHeight(heightCorralsLower, heightCorralsUpper, Elevation_ExcludeMin_IncludeMax, tCoralsUpper); - -g_Map.log("Creating island stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2,5, 1,3)] - ], - stayClasses(clIsland, 4), - clRock); - -g_Map.log("Creating island metal mines"); -createMines( - [ - [new SimpleObject(oMetalLarge, 1,1, 0,4)] - ], - stayClasses(clIsland, 4), - clMetal -); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2,5, 1,3)] - ], - avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 1, clHill, 1), - clRock); - -g_Map.log("Creating metal mines"); -createMines( - [ - [new SimpleObject(oMetalLarge, 1,1, 0,4)] - ], - avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clWater, 1, clHill, 1), - clMetal -); - -Engine.SetProgress(65); - -createDecoration( - [ +function* GenerateMap() +{ + const tCity = "medit_city_pavement"; + const tCityPlaza = "medit_city_pavement"; + const tHill = ["medit_grass_shrubs", "medit_rocks_grass_shrubs", "medit_rocks_shrubs", + "medit_rocks_grass", "medit_shrubs"]; + const tMainDirt = "medit_dirt"; + const tCliff = "medit_cliff_aegean"; + const tForestFloor = "medit_grass_shrubs"; + const tGrass = "medit_grass_field"; + const tGrassSand50 = "medit_grass_field_a"; + const tGrassSand25 = "medit_grass_field_b"; + const tDirt = "medit_dirt_b"; + const tDirt2 = "medit_rocks_grass"; + const tDirt3 = "medit_rocks_shrubs"; + const tDirtCracks = "medit_dirt_c"; + const tShoreUpper = "medit_sand"; + const tShoreLower = "medit_sand_wet"; + const tCoralsUpper = "medit_sea_coral_plants"; + const tCoralsLower = "medit_sea_coral_deep"; + const tSeaDepths = "medit_sea_depths"; + + const oBerryBush = "gaia/fruit/berry_01"; + const oDeer = "gaia/fauna_deer"; + const oFish = "gaia/fish/generic"; + const oSheep = "gaia/fauna_sheep"; + const oGoat = "gaia/fauna_goat"; + const oStoneLarge = "gaia/rock/mediterranean_large"; + const oStoneSmall = "gaia/rock/mediterranean_small"; + const oMetalLarge = "gaia/ore/mediterranean_large"; + const oDatePalm = "gaia/tree/cretan_date_palm_short"; + const oSDatePalm = "gaia/tree/cretan_date_palm_tall"; + const oCarob = "gaia/tree/carob"; + const oFanPalm = "gaia/tree/medit_fan_palm"; + const oPoplar = "gaia/tree/poplar_lombardy"; + const oCypress = "gaia/tree/cypress"; + + const aBush1 = "actor|props/flora/bush_medit_sm.xml"; + const aBush2 = "actor|props/flora/bush_medit_me.xml"; + const aBush3 = "actor|props/flora/bush_medit_la.xml"; + const aBush4 = "actor|props/flora/bush_medit_me.xml"; + const aDecorativeRock = "actor|geology/stone_granite_med.xml"; + + const pForest = [tForestFloor, tForestFloor + TERRAIN_SEPARATOR + oCarob, + tForestFloor + TERRAIN_SEPARATOR + oDatePalm, tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, tForestFloor]; + + const heightSeaGround = -3; + const heightSeaBump = -2.5; + const heightCorralsLower = -2; + const heightCorralsUpper = -1.5; + const heightShore = 1; + const heightLand = 2; + const heightIsland = 6; + + global.g_Map = new RandomMap(heightShore, tHill); + + const numPlayers = getNumPlayers(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clGrass = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clIsland = g_Map.createTileClass(); + + const startAngle = randomAngle(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementRiver(startAngle , fractionToTiles(0.6)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tCityPlaza, + "innerTerrain": tCity + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oCarob, + "count": 2 + }, + "Decoratives": { + "template": aBush1 + } + }); + yield 30; + + paintRiver({ + "parallel": false, + "start": new Vector2D(mapCenter.x, mapBounds.top).rotateAround(startAngle, mapCenter), + "end": new Vector2D(mapCenter.x, mapBounds.bottom).rotateAround(startAngle, mapCenter), + "width": fractionToTiles(0.35), + "fadeDist": scaleByMapSize(6, 25), + "deviation": 0, + "heightRiverbed": heightSeaGround, + "heightLand": heightLand, + "meanderShort": 20, + "meanderLong": 0 + }); + + paintTileClassBasedOnHeight(-Infinity, 0.7, Elevation_ExcludeMin_ExcludeMax, clWater); + + paintTerrainBasedOnHeight(-Infinity, heightShore, Elevation_ExcludeMin_ExcludeMax, tShoreLower); + paintTerrainBasedOnHeight(heightShore, heightLand, Elevation_ExcludeMin_ExcludeMax, tShoreUpper); + yield 40; + + createBumps(avoidClasses(clWater, 2, clPlayer, 20)); + + const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); + createForests( + [tForestFloor, tForestFloor, tForestFloor, pForest, pForest], + avoidClasses(clPlayer, 20, clForest, 17, clWater, 2, clBaseResource, 3), + clForest, + forestTrees); + + yield 50; + + if (randBool()) + createHills([tGrass, tCliff, tHill], + avoidClasses(clPlayer, 20, clForest, 1, clHill, 15, clWater, 3), clHill, + scaleByMapSize(3, 15)); + else + createMountains(tCliff, avoidClasses(clPlayer, 20, clForest, 1, clHill, 15, clWater, 3), clHill, + scaleByMapSize(3, 15)); + + g_Map.log("Creating grass patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tGrass,tGrassSand50],[tGrassSand50,tGrassSand25], [tGrassSand25,tGrass]], + [1,1], + avoidClasses(clForest, 0, clGrass, 2, clPlayer, 10, clWater, 2, clDirt, 2, clHill, 1), + scaleByMapSize(15, 45), + clDirt); + + yield 55; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [tDirt3, tDirt2,[tDirt,tMainDirt], [tDirtCracks,tMainDirt]], + [1,1,1], + avoidClasses(clForest, 0, clDirt, 2, clPlayer, 10, clWater, 2, clGrass, 2, clHill, 1), + scaleByMapSize(15, 45), + clDirt); + + yield 60; + + g_Map.log("Creating undersea bumps"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), + new SmoothElevationPainter(ELEVATION_SET, heightSeaBump, 3), + stayClasses(clWater, 6), + scaleByMapSize(10, 50)); + + g_Map.log("Creating islands"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(30, 80)), 0.5), [ - new SimpleObject(aDecorativeRock, 1, 3, 0, 1) + new LayeredPainter([tShoreLower, tShoreUpper, tHill], [2 ,1]), + new SmoothElevationPainter(ELEVATION_SET, heightIsland, 4), + new TileClassPainter(clIsland) ], + [avoidClasses(clPlayer, 8, clForest, 1, clIsland, 15), stayClasses (clWater, 6)], + scaleByMapSize(1, 4) * numPlayers + ); + + paintTerrainBasedOnHeight(-Infinity, heightSeaGround, Elevation_IncludeMin_IncludeMax, tSeaDepths); + paintTerrainBasedOnHeight(heightSeaGround, heightCorralsLower, Elevation_ExcludeMin_IncludeMax, + tCoralsLower); + paintTerrainBasedOnHeight(heightCorralsLower, heightCorralsUpper, Elevation_ExcludeMin_IncludeMax, + tCoralsUpper); + + g_Map.log("Creating island stone mines"); + createMines( [ - new SimpleObject(aBush2, 1, 2, 0, 1), - new SimpleObject(aBush1, 1, 3, 0, 2), - new SimpleObject(aBush4, 1, 2, 0, 1), - new SimpleObject(aBush3, 1, 3, 0, 2) - ] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapSize(40, 360) - ], - avoidClasses(clWater, 2, clForest, 0, clPlayer, 0, clHill, 1)); - -Engine.SetProgress(70); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 3 * scaleByMapSize(5, 20) - ], - [avoidClasses(clIsland, 2, clFood, 10), stayClasses(clWater, 5)], - clFood); - -createFood( - [ - [new SimpleObject(oSheep, 5, 7, 0, 4)], - [new SimpleObject(oGoat, 2, 4, 0, 3)], - [new SimpleObject(oDeer, 2, 4, 0, 2)] - ], - [ - scaleByMapSize(5, 20), - scaleByMapSize(5, 20), - scaleByMapSize(5, 20) - ], - avoidClasses(clForest, 0, clPlayer, 8, clBaseResource, 4, clWater, 1, clFood, 10, clHill, 1), - clFood); - -createFood( - [ - [new SimpleObject(oBerryBush, 5, 7, 0, 4)] - ], - [ - 3 * numPlayers - ], - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - clFood); - -Engine.SetProgress(90); - -const types = [oDatePalm, oSDatePalm, oCarob, oFanPalm, oPoplar, oCypress]; -createStragglerTrees( - types, - avoidClasses(clForest, 1, clWater, 2, clPlayer, 12, clMetal, 6, clHill, 1), - clForest, - stragglerTrees); - -createStragglerTrees( - types, - stayClasses(clIsland, 4), - clForest, - stragglerTrees * 10); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clIsland, 10, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setSkySet("cumulus"); -setSunColor(0.866667, 0.776471, 0.486275); -setWaterColor(0, 0.501961, 1); -setWaterTint(0.501961, 1, 1); -setWaterWaviness(4.0); -setWaterType("ocean"); -setWaterMurkiness(0.49); - -setFogFactor(0.3); -setFogThickness(0.25); - -setPPEffect("hdr"); -setPPContrast(0.62); -setPPSaturation(0.51); -setPPBloom(0.12); - -g_Map.ExportMap(); + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4) + ], + [new SimpleObject(oStoneSmall, 2,5, 1,3)] + ], + stayClasses(clIsland, 4), + clRock); + + g_Map.log("Creating island metal mines"); + createMines( + [ + [new SimpleObject(oMetalLarge, 1,1, 0,4)] + ], + stayClasses(clIsland, 4), + clMetal + ); + + g_Map.log("Creating stone mines"); + createMines( + [ + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4) + ], + [new SimpleObject(oStoneSmall, 2,5, 1,3)] + ], + avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 1, clHill, 1), + clRock); + + g_Map.log("Creating metal mines"); + createMines( + [ + [new SimpleObject(oMetalLarge, 1,1, 0,4)] + ], + avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clWater, 1, clHill, 1), + clMetal + ); + + yield 65; + + createDecoration( + [ + [ + new SimpleObject(aDecorativeRock, 1, 3, 0, 1) + ], + [ + new SimpleObject(aBush2, 1, 2, 0, 1), + new SimpleObject(aBush1, 1, 3, 0, 2), + new SimpleObject(aBush4, 1, 2, 0, 1), + new SimpleObject(aBush3, 1, 3, 0, 2) + ] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapSize(40, 360) + ], + avoidClasses(clWater, 2, clForest, 0, clPlayer, 0, clHill, 1)); + + yield 70; + + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 3 * scaleByMapSize(5, 20) + ], + [avoidClasses(clIsland, 2, clFood, 10), stayClasses(clWater, 5)], + clFood); + + createFood( + [ + [new SimpleObject(oSheep, 5, 7, 0, 4)], + [new SimpleObject(oGoat, 2, 4, 0, 3)], + [new SimpleObject(oDeer, 2, 4, 0, 2)] + ], + [ + scaleByMapSize(5, 20), + scaleByMapSize(5, 20), + scaleByMapSize(5, 20) + ], + avoidClasses(clForest, 0, clPlayer, 8, clBaseResource, 4, clWater, 1, clFood, 10, clHill, 1), + clFood); + + createFood( + [ + [new SimpleObject(oBerryBush, 5, 7, 0, 4)] + ], + [ + 3 * numPlayers + ], + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), + clFood); + + yield 90; + + const types = [oDatePalm, oSDatePalm, oCarob, oFanPalm, oPoplar, oCypress]; + createStragglerTrees( + types, + avoidClasses(clForest, 1, clWater, 2, clPlayer, 12, clMetal, 6, clHill, 1), + clForest, + stragglerTrees); + + createStragglerTrees( + types, + stayClasses(clIsland, 4), + clForest, + stragglerTrees * 10); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clIsland, 10, clForest, 1, clMetal, 4, clRock, 4, + clHill, 4, clFood, 2)); + + setSkySet("cumulus"); + setSunColor(0.866667, 0.776471, 0.486275); + setWaterColor(0, 0.501961, 1); + setWaterTint(0.501961, 1, 1); + setWaterWaviness(4.0); + setWaterType("ocean"); + setWaterMurkiness(0.49); + + setFogFactor(0.3); + setFogThickness(0.25); + + setPPEffect("hdr"); + setPPContrast(0.62); + setPPSaturation(0.51); + setPPBloom(0.12); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/african_plains.js =================================================================== --- binaries/data/mods/public/maps/random/african_plains.js +++ binaries/data/mods/public/maps/random/african_plains.js @@ -2,306 +2,312 @@ Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); -if (g_MapSettings.Biome) - setSelectedBiome(); -else - setBiome("generic/savanna"); - - -// Pick some biome defaults and overload a few settings. -const tPrimary = g_Terrains.mainTerrain; -const tForestFloor = g_Terrains.tier3Terrain; -const tCliff = ["savanna_cliff_a", "savanna_cliff_a_red", "savanna_cliff_b", "savanna_cliff_b_red"]; -const tSecondary = g_Terrains.tier1Terrain; -const tGrassShrubs = g_Terrains.tier2Terrain; -const tDirt = g_Terrains.tier3Terrain; -const tDirt2 = g_Terrains.tier4Terrain; -const tDirt3 = g_Terrains.dirt; -const tDirt4 = g_Terrains.dirt; -const tCitytiles = "savanna_tile_a"; -const tShore = g_Terrains.shore; -const tWater = g_Terrains.water; - -const oBaobab = pickRandom(["gaia/tree/baobab", "gaia/tree/baobab_3_mature", "gaia/tree/acacia"]); -const oPalm = "gaia/tree/bush_tropic"; -const oPalm2 = "gaia/tree/cretan_date_palm_short"; -const oBerryBush = "gaia/fruit/berry_01"; -const oWildebeest = "gaia/fauna_wildebeest"; -const oZebra = "gaia/fauna_zebra"; -const oRhino = "gaia/fauna_rhinoceros_white"; -const oLion = "gaia/fauna_lion"; -const oLioness = "gaia/fauna_lioness"; -const oHawk = "birds/buzzard"; -const oGiraffe = "gaia/fauna_giraffe"; -const oGiraffe2 = "gaia/fauna_giraffe_infant"; -const oGazelle = "gaia/fauna_gazelle"; -const oElephant = "gaia/fauna_elephant_african_bush"; -const oElephant2 = "gaia/fauna_elephant_african_infant"; -const oCrocodile = "gaia/fauna_crocodile_nile"; -const oFish = g_Gaia.fish; -const oStoneLarge = g_Gaia.stoneLarge; -const oStoneSmall = g_Gaia.stoneSmall; -const oMetalLarge = g_Gaia.metalLarge; -const oMetalSmall = g_Gaia.metalSmall; - -const aBush = g_Decoratives.bushMedium; -const aRock = g_Decoratives.rockMedium; - -const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPalm, tForestFloor + TERRAIN_SEPARATOR + oPalm2, tForestFloor]; - -const heightSeaGround = -5; -const heightLand = 2; -const heightCliff = 3; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tPrimary, - "innerTerrain": tCitytiles - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { - "template": oMetalLarge - }, - { - "type": "stone_formation", - "template": oStoneSmall, - "terrain": tDirt4 - } - ] - }, - "Trees": { - "template": oBaobab, - "count": scaleByMapSize(3, 12), - "minDistGroup": 2, - "maxDistGroup": 6, - "minDist": 15, - "maxDist": 16 +function* GenerateMap(mapSettings) +{ + setBiome(mapSettings.Biome ?? "generic/savanna"); + + // Pick some biome defaults and overload a few settings. + const tPrimary = g_Terrains.mainTerrain; + const tForestFloor = g_Terrains.tier3Terrain; + const tCliff = ["savanna_cliff_a", "savanna_cliff_a_red", "savanna_cliff_b", "savanna_cliff_b_red"]; + const tSecondary = g_Terrains.tier1Terrain; + const tGrassShrubs = g_Terrains.tier2Terrain; + const tDirt = g_Terrains.tier3Terrain; + const tDirt2 = g_Terrains.tier4Terrain; + const tDirt3 = g_Terrains.dirt; + const tDirt4 = g_Terrains.dirt; + const tCitytiles = "savanna_tile_a"; + const tShore = g_Terrains.shore; + const tWater = g_Terrains.water; + + const oBaobab = pickRandom(["gaia/tree/baobab", "gaia/tree/baobab_3_mature", "gaia/tree/acacia"]); + const oPalm = "gaia/tree/bush_tropic"; + const oPalm2 = "gaia/tree/cretan_date_palm_short"; + const oBerryBush = "gaia/fruit/berry_01"; + const oWildebeest = "gaia/fauna_wildebeest"; + const oZebra = "gaia/fauna_zebra"; + const oRhino = "gaia/fauna_rhinoceros_white"; + const oLion = "gaia/fauna_lion"; + const oLioness = "gaia/fauna_lioness"; + const oHawk = "birds/buzzard"; + const oGiraffe = "gaia/fauna_giraffe"; + const oGiraffe2 = "gaia/fauna_giraffe_infant"; + const oGazelle = "gaia/fauna_gazelle"; + const oElephant = "gaia/fauna_elephant_african_bush"; + const oElephant2 = "gaia/fauna_elephant_african_infant"; + const oCrocodile = "gaia/fauna_crocodile_nile"; + const oFish = g_Gaia.fish; + const oStoneLarge = g_Gaia.stoneLarge; + const oStoneSmall = g_Gaia.stoneSmall; + const oMetalLarge = g_Gaia.metalLarge; + const oMetalSmall = g_Gaia.metalSmall; + + const aBush = g_Decoratives.bushMedium; + const aRock = g_Decoratives.rockMedium; + + const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPalm, tForestFloor + TERRAIN_SEPARATOR + oPalm2, + tForestFloor]; + + const heightSeaGround = -5; + const heightLand = 2; + const heightCliff = 3; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tPrimary, + "innerTerrain": tCitytiles + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { + "template": oMetalLarge + }, + { + "type": "stone_formation", + "template": oStoneSmall, + "terrain": tDirt4 + } + ] + }, + "Trees": { + "template": oBaobab, + "count": scaleByMapSize(3, 12), + "minDistGroup": 2, + "maxDistGroup": 6, + "minDist": 15, + "maxDist": 16 + } + // No decoratives + }); + yield 20; + + // The specificity of this map is a bunch of watering holes & hills making it somewhat cluttered. + const nbHills = scaleByMapSize(6, 16); + const nbWateringHoles = scaleByMapSize(4, 10); + { + g_Map.log("Creating hills"); + createHills([tDirt2, tCliff, tGrassShrubs], avoidClasses(clPlayer, 30, clHill, 15), clHill, + nbHills); + yield 30; + + g_Map.log("Creating water holes"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), Math.floor(scaleByMapSize(60, 100)), + Infinity), + [ + new LayeredPainter([tShore, tWater], [1]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 7), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 22, clWater, 8, clHill, 2), + nbWateringHoles); + + yield 45; + + paintTerrainBasedOnHeight(heightCliff, Infinity, 0, tCliff); } - // No decoratives -}); -Engine.SetProgress(20); -// The specificity of this map is a bunch of watering holes & hills making it somewhat cluttered. -const nbHills = scaleByMapSize(6, 16); -const nbWateringHoles = scaleByMapSize(4, 10); -{ - g_Map.log("Creating hills"); - createHills([tDirt2, tCliff, tGrassShrubs], avoidClasses(clPlayer, 30, clHill, 15), clHill, nbHills); - Engine.SetProgress(30); + createBumps(avoidClasses(clWater, 2, clPlayer, 20)); + + g_Map.log("Creating forests"); + + createDefaultForests( + [tPrimary, pForest, tForestFloor, pForest, pForest], + avoidClasses(clPlayer, 20, clForest, 15, clHill, 0, clWater, 2), + clForest, + scaleByMapSize(200, 1000)); + yield 50; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tDirt, tDirt3], [tDirt2, tDirt4]], + [2], + avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + yield 55; + + g_Map.log("Creating shrubs"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tGrassShrubs, + avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + yield 60; + + g_Map.log("Creating grass patches"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tSecondary, + avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + yield 65; + + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + avoidClasses(clWater, 4, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1) + ); - g_Map.log("Creating water holes"); - createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), Math.floor(scaleByMapSize(60, 100)), Infinity), + g_Map.log("Creating stone mines"); + createBalancedStoneMines( + oStoneSmall, + oStoneLarge, + clRock, + avoidClasses(clWater, 4, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1, clMetal, 10) + ); + + yield 70; + + createDecoration( [ - new LayeredPainter([tShore, tWater], [1]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 7), - new TileClassPainter(clWater) + [new SimpleObject(aBush, 1,3, 0,1)], + [new SimpleObject(aRock, 1,2, 0,1)] ], - avoidClasses(clPlayer, 22, clWater, 8, clHill, 2), - nbWateringHoles); - - Engine.SetProgress(45); + [ + scaleByMapAreaAbsolute(8), + scaleByMapAreaAbsolute(8) + ], + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); + yield 75; - paintTerrainBasedOnHeight(heightCliff, Infinity, 0, tCliff); -} + // Roaming animals + { + var placeRoaming = function(name, objs) + { + g_Map.log("Creating roaming " + name); + const group = new SimpleGroup(objs, true, clFood); + createObjectGroups(group, 0, + avoidClasses(clWater, 3, clPlayer, 20, clFood, 11, clHill, 4), + scaleByMapSize(3, 9), 50 + ); + }; + + placeRoaming("giraffes", [new SimpleObject(oGiraffe, 2, 4, 0, 4), + new SimpleObject(oGiraffe2, 0, 2, 0, 4)]); + placeRoaming("elephants", [new SimpleObject(oElephant, 2, 4, 0, 4), + new SimpleObject(oElephant2, 0, 2, 0, 4)]); + placeRoaming("lions", [new SimpleObject(oLion, 0, 1, 0, 4), + new SimpleObject(oLioness, 2, 3, 0, 4)]); + + // Other roaming animals + createFood( + [ + [new SimpleObject(oHawk, 1, 1, 0, 3)], + [new SimpleObject(oGazelle, 3, 5, 0, 3)], + [new SimpleObject(oZebra, 3, 5, 0, 3)], + [new SimpleObject(oWildebeest, 4, 6, 0, 3)], + [new SimpleObject(oRhino, 1, 1, 0, 3)] + ], + [ + 3 * numPlayers, + 3 * numPlayers, + 3 * numPlayers, + 3 * numPlayers, + 3 * numPlayers, + ], + avoidClasses(clFood, 20, clWater, 5, clHill, 2, clPlayer, 16), + clFood); + } -createBumps(avoidClasses(clWater, 2, clPlayer, 20)); - -g_Map.log("Creating forests"); - -createDefaultForests( - [tPrimary, pForest, tForestFloor, pForest, pForest], - avoidClasses(clPlayer, 20, clForest, 15, clHill, 0, clWater, 2), - clForest, - scaleByMapSize(200, 1000)); -Engine.SetProgress(50); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tDirt, tDirt3], [tDirt2, tDirt4]], - [2], - avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(55); - -g_Map.log("Creating shrubs"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tGrassShrubs, - avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(60); - -g_Map.log("Creating grass patches"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tSecondary, - avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(65); - -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - avoidClasses(clWater, 4, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1) -); - -g_Map.log("Creating stone mines"); -createBalancedStoneMines( - oStoneSmall, - oStoneLarge, - clRock, - avoidClasses(clWater, 4, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1, clMetal, 10) -); - -Engine.SetProgress(70); - -createDecoration( - [ - [new SimpleObject(aBush, 1,3, 0,1)], - [new SimpleObject(aRock, 1,2, 0,1)] - ], - [ - scaleByMapAreaAbsolute(8), - scaleByMapAreaAbsolute(8) - ], - avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); -Engine.SetProgress(75); - -// Roaming animals -{ - var placeRoaming = function(name, objs) + // Animals that hang around watering holes { - g_Map.log("Creating roaming " + name); - const group = new SimpleGroup(objs, true, clFood); - createObjectGroups(group, 0, - avoidClasses(clWater, 3, clPlayer, 20, clFood, 11, clHill, 4), - scaleByMapSize(3, 9), 50 + // TODO: these have a high retry factor because our mapgen constraint logic is bad. + var placeWateringHoleAnimals = function(name, objs, numberOfGroups) + { + g_Map.log("Creating " + name + " around watering holes"); + const group = new SimpleGroup(objs, true, clFood); + createObjectGroups(group, 0, + borderClasses(clWater, 6, 3), + numberOfGroups, 50 + ); + }; + placeWateringHoleAnimals( + "crocodiles", + [new SimpleObject(oCrocodile, 2, 3, 0, 3)], + nbWateringHoles * 0.8 ); - }; + placeWateringHoleAnimals( + "zebras", + [new SimpleObject(oZebra, 2, 5, 0, 3)], + nbWateringHoles + ); + placeWateringHoleAnimals( + "gazelles", + [new SimpleObject(oGazelle, 2, 5, 0, 3)], + nbWateringHoles + ); + } - placeRoaming("giraffes", [new SimpleObject(oGiraffe, 2, 4, 0, 4), new SimpleObject(oGiraffe2, 0, 2, 0, 4)]); - placeRoaming("elephants", [new SimpleObject(oElephant, 2, 4, 0, 4), new SimpleObject(oElephant2, 0, 2, 0, 4)]); - placeRoaming("lions", [new SimpleObject(oLion, 0, 1, 0, 4), new SimpleObject(oLioness, 2, 3, 0, 4)]); - // Other roaming animals + g_Map.log("Creating other food sources"); createFood( [ - [new SimpleObject(oHawk, 1, 1, 0, 3)], - [new SimpleObject(oGazelle, 3, 5, 0, 3)], - [new SimpleObject(oZebra, 3, 5, 0, 3)], - [new SimpleObject(oWildebeest, 4, 6, 0, 3)], - [new SimpleObject(oRhino, 1, 1, 0, 3)] + [new SimpleObject(oBerryBush, 5, 7, 0, 4)] ], [ - 3 * numPlayers, - 3 * numPlayers, - 3 * numPlayers, - 3 * numPlayers, - 3 * numPlayers, + randIntInclusive(1, 4) * numPlayers + 2 ], - avoidClasses(clFood, 20, clWater, 5, clHill, 2, clPlayer, 16), + avoidClasses(clWater, 3, clForest, 2, clPlayer, 20, clHill, 3, clFood, 10), clFood); -} -// Animals that hang around watering holes -{ - // TODO: these have a high retry factor because our mapgen constraint logic is bad. - var placeWateringHoleAnimals = function(name, objs, numberOfGroups) - { - g_Map.log("Creating " + name + " around watering holes"); - const group = new SimpleGroup(objs, true, clFood); - createObjectGroups(group, 0, - borderClasses(clWater, 6, 3), - numberOfGroups, 50 - ); - }; - placeWateringHoleAnimals( - "crocodiles", - [new SimpleObject(oCrocodile, 2, 3, 0, 3)], - nbWateringHoles * 0.8 - ); - placeWateringHoleAnimals( - "zebras", - [new SimpleObject(oZebra, 2, 5, 0, 3)], - nbWateringHoles - ); - placeWateringHoleAnimals( - "gazelles", - [new SimpleObject(oGazelle, 2, 5, 0, 3)], - nbWateringHoles - ); -} - - -g_Map.log("Creating other food sources"); -createFood( - [ - [new SimpleObject(oBerryBush, 5, 7, 0, 4)] - ], - [ - randIntInclusive(1, 4) * numPlayers + 2 - ], - avoidClasses(clWater, 3, clForest, 2, clPlayer, 20, clHill, 3, clFood, 10), - clFood); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 15 * numPlayers - ], - [avoidClasses(clFood, 20), stayClasses(clWater, 6)], - clFood); -Engine.SetProgress(85); + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 15 * numPlayers + ], + [avoidClasses(clFood, 20), stayClasses(clWater, 6)], + clFood); + yield 85; -g_Map.log("Creating straggler baobabs"); -const group = new SimpleGroup([new SimpleObject(oBaobab, 1, 1, 0, 3)], true, clForest); -createObjectGroups( - group, - 0, - avoidClasses(clWater, 0, clForest, 2, clHill, 3, clPlayer, 12, clMetal, 4, clRock, 4), - scaleByMapSize(15, 75) -); + g_Map.log("Creating straggler baobabs"); + const group = new SimpleGroup([new SimpleObject(oBaobab, 1, 1, 0, 3)], true, clForest); + createObjectGroups( + group, + 0, + avoidClasses(clWater, 0, clForest, 2, clHill, 3, clPlayer, 12, clMetal, 4, clRock, 4), + scaleByMapSize(15, 75) + ); -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + placePlayersNomad(clPlayer, + avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); -// Adjust some biome settings; + // Adjust some biome settings; -setSkySet("sunny"); -setWaterType("clap"); + setSkySet("sunny"); + setWaterType("clap"); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/alpine_lakes.js =================================================================== --- binaries/data/mods/public/maps/random/alpine_lakes.js +++ binaries/data/mods/public/maps/random/alpine_lakes.js @@ -1,269 +1,277 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -if (randBool()) +function* GenerateMap() { - RandomMapLogger.prototype.printDirectly("Setting late spring biome.\n"); - - setFogThickness(0.26); - setFogFactor(0.4); - - setPPEffect("hdr"); - setPPSaturation(0.48); - setPPContrast(0.53); - setPPBloom(0.12); - - var tPrimary = ["alpine_dirt_grass_50"]; - var tForestFloor = "alpine_forrestfloor"; - var tCliff = ["alpine_cliff_a", "alpine_cliff_b", "alpine_cliff_c"]; - var tSecondary = "alpine_grass_rocky"; - var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; - var tSnowLimited = ["alpine_snow_rocky"]; - var tDirt = "alpine_dirt"; - var tRoad = "new_alpine_citytile"; - var tRoadWild = "new_alpine_citytile"; - var tShore = "alpine_shore_rocks_grass_50"; - var tWater = "alpine_shore_rocks"; - - var oPine = "gaia/tree/pine"; - var oBerryBush = "gaia/fruit/berry_01"; - var oDeer = "gaia/fauna_deer"; - var oFish = "gaia/fish/generic"; - var oRabbit = "gaia/fauna_rabbit"; - var oStoneLarge = "gaia/rock/alpine_large"; - var oStoneSmall = "gaia/rock/alpine_small"; - var oMetalLarge = "gaia/ore/alpine_large"; - - 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"; -} -else -{ - RandomMapLogger.prototype.printDirectly("Setting winter spring biome.\n"); - - setFogFactor(0.35); - setFogThickness(0.19); - setPPSaturation(0.37); - setPPEffect("hdr"); - - var tPrimary = ["alpine_snow_a", "alpine_snow_b"]; - var tForestFloor = "alpine_forrestfloor_snow"; - var tCliff = ["alpine_cliff_snow"]; - var tSecondary = "alpine_grass_snow_50"; - var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; - var tSnowLimited = ["alpine_snow_a", "alpine_snow_b"]; - var tDirt = "alpine_dirt"; - var tRoad = "new_alpine_citytile"; - var tRoadWild = "new_alpine_citytile"; - var tShore = "alpine_shore_rocks_icy"; - var tWater = "alpine_shore_rocks"; - - var oPine = "gaia/tree/pine_w"; - var oBerryBush = "gaia/fruit/berry_01"; - var oDeer = "gaia/fauna_deer"; - var oFish = "gaia/fish/generic"; - var oRabbit = "gaia/fauna_rabbit"; - var oStoneLarge = "gaia/rock/alpine_large"; - var oStoneSmall = "gaia/rock/alpine_small"; - var oMetalLarge = "gaia/ore/alpine_large"; - - var aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; - var aGrassShort = "actor|props/flora/grass_soft_dry_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_dry.xml"; - var aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; -} - -const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; - -const heightSeaGround = -5; -const heightLand = 3; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oPine, - "count": scaleByMapSize(3, 12) - }, - "Decoratives": { - "template": aGrassShort + if (randBool()) + { + RandomMapLogger.prototype.printDirectly("Setting late spring biome.\n"); + + setFogThickness(0.26); + setFogFactor(0.4); + + setPPEffect("hdr"); + setPPSaturation(0.48); + setPPContrast(0.53); + setPPBloom(0.12); + + var tPrimary = ["alpine_dirt_grass_50"]; + var tForestFloor = "alpine_forrestfloor"; + var tCliff = ["alpine_cliff_a", "alpine_cliff_b", "alpine_cliff_c"]; + var tSecondary = "alpine_grass_rocky"; + var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; + var tSnowLimited = ["alpine_snow_rocky"]; + var tDirt = "alpine_dirt"; + var tRoad = "new_alpine_citytile"; + var tRoadWild = "new_alpine_citytile"; + var tShore = "alpine_shore_rocks_grass_50"; + var tWater = "alpine_shore_rocks"; + + var oPine = "gaia/tree/pine"; + var oBerryBush = "gaia/fruit/berry_01"; + var oDeer = "gaia/fauna_deer"; + var oFish = "gaia/fish/generic"; + var oRabbit = "gaia/fauna_rabbit"; + var oStoneLarge = "gaia/rock/alpine_large"; + var oStoneSmall = "gaia/rock/alpine_small"; + var oMetalLarge = "gaia/ore/alpine_large"; + + 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"; } -}); -Engine.SetProgress(20); - -createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 8), clHill, scaleByMapSize(10, 40) * numPlayers, Math.floor(scaleByMapSize(40, 60)), Math.floor(scaleByMapSize(4, 5)), Math.floor(scaleByMapSize(7, 15)), Math.floor(scaleByMapSize(5, 15))); - -Engine.SetProgress(30); - -g_Map.log("Creating lakes"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 8)), Math.floor(scaleByMapSize(40, 180)), 0.7), - [ - new LayeredPainter([tShore, tWater], [1]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 5), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 20, clWater, 8), - scaleByMapSize(5, 16), - 1); - -paintTerrainBasedOnHeight(3, Math.floor(scaleByMapSize(20, 40)), 0, tCliff); -paintTerrainBasedOnHeight(Math.floor(scaleByMapSize(20, 40)), 100, 3, tSnowLimited); - -createBumps(avoidClasses(clWater, 2, clPlayer, 20)); - -const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); -createForests( - [tPrimary, tForestFloor, tForestFloor, pForest, pForest], - avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 2), - clForest, - forestTrees); - -Engine.SetProgress(60); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tDirt,tHalfSnow], [tHalfSnow,tSnowLimited]], - [2], - avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); - -g_Map.log("Creating grass patches"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tSecondary, - avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(65); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2,5, 1,3)] - ], - avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - clRock); - -g_Map.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 -); - -Engine.SetProgress(70); - -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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13) - ], - avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); - -Engine.SetProgress(75); - -createFood( - [ - [new SimpleObject(oDeer, 5, 7, 0, 4)], - [new SimpleObject(oRabbit, 2, 3, 0, 2)] - ], - [ - 3 * numPlayers, - 3 * numPlayers - ], - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), - clFood); - -createFood( - [ - [new SimpleObject(oBerryBush, 5, 7, 0, 4)] - ], - [ - randIntInclusive(1, 4) * numPlayers + 2 - ], - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - clFood); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 15 * numPlayers - ], - [avoidClasses(clFood, 20), stayClasses(clWater, 6)], - clFood); - -Engine.SetProgress(85); - -createStragglerTrees( - [oPine], - avoidClasses(clWater, 5, clForest, 3, 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)); - -setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); -setSunRotation(randomAngle()); -setSunElevation(Math.PI * randFloat(1/5, 1/3)); -setWaterColor(0.0, 0.047, 0.286); // dark majestic blue -setWaterTint(0.471, 0.776, 0.863); // light blue -setWaterMurkiness(0.82); -setWaterWaviness(3.0); -setWaterType("clap"); - -g_Map.ExportMap(); + else + { + RandomMapLogger.prototype.printDirectly("Setting winter spring biome.\n"); + + setFogFactor(0.35); + setFogThickness(0.19); + setPPSaturation(0.37); + setPPEffect("hdr"); + + var tPrimary = ["alpine_snow_a", "alpine_snow_b"]; + var tForestFloor = "alpine_forrestfloor_snow"; + var tCliff = ["alpine_cliff_snow"]; + var tSecondary = "alpine_grass_snow_50"; + var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; + var tSnowLimited = ["alpine_snow_a", "alpine_snow_b"]; + var tDirt = "alpine_dirt"; + var tRoad = "new_alpine_citytile"; + var tRoadWild = "new_alpine_citytile"; + var tShore = "alpine_shore_rocks_icy"; + var tWater = "alpine_shore_rocks"; + + var oPine = "gaia/tree/pine_w"; + var oBerryBush = "gaia/fruit/berry_01"; + var oDeer = "gaia/fauna_deer"; + var oFish = "gaia/fish/generic"; + var oRabbit = "gaia/fauna_rabbit"; + var oStoneLarge = "gaia/rock/alpine_large"; + var oStoneSmall = "gaia/rock/alpine_small"; + var oMetalLarge = "gaia/ore/alpine_large"; + + var aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; + var aGrassShort = "actor|props/flora/grass_soft_dry_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_dry.xml"; + var aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; + } + + const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; + + const heightSeaGround = -5; + const heightLand = 3; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oPine, + "count": scaleByMapSize(3, 12) + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 20; + + createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 8), clHill, + scaleByMapSize(10, 40) * numPlayers, Math.floor(scaleByMapSize(40, 60)), + Math.floor(scaleByMapSize(4, 5)), Math.floor(scaleByMapSize(7, 15)), + Math.floor(scaleByMapSize(5, 15))); + + yield 30; + + g_Map.log("Creating lakes"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 8)), Math.floor(scaleByMapSize(40, 180)), 0.7), + [ + new LayeredPainter([tShore, tWater], [1]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 5), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 20, clWater, 8), + scaleByMapSize(5, 16), + 1); + + paintTerrainBasedOnHeight(3, Math.floor(scaleByMapSize(20, 40)), 0, tCliff); + paintTerrainBasedOnHeight(Math.floor(scaleByMapSize(20, 40)), 100, 3, tSnowLimited); + + createBumps(avoidClasses(clWater, 2, clPlayer, 20)); + + const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); + createForests( + [tPrimary, tForestFloor, tForestFloor, pForest, pForest], + avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 2), + clForest, + forestTrees); + + yield 60; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tDirt,tHalfSnow], [tHalfSnow,tSnowLimited]], + [2], + avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + + g_Map.log("Creating grass patches"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tSecondary, + avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + yield 65; + + g_Map.log("Creating stone mines"); + createMines( + [ + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oStoneSmall, 2,5, 1,3)] + ], + avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + clRock); + + g_Map.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 + ); + + yield 70; + + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13) + ], + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); + + yield 75; + + createFood( + [ + [new SimpleObject(oDeer, 5, 7, 0, 4)], + [new SimpleObject(oRabbit, 2, 3, 0, 2)] + ], + [ + 3 * numPlayers, + 3 * numPlayers + ], + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), + clFood); + + createFood( + [ + [new SimpleObject(oBerryBush, 5, 7, 0, 4)] + ], + [ + randIntInclusive(1, 4) * numPlayers + 2 + ], + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), + clFood); + + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 15 * numPlayers + ], + [avoidClasses(clFood, 20), stayClasses(clWater, 6)], + clFood); + + yield 85; + + createStragglerTrees( + [oPine], + avoidClasses(clWater, 5, clForest, 3, 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)); + + setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); + setSunRotation(randomAngle()); + setSunElevation(Math.PI * randFloat(1/5, 1/3)); + setWaterColor(0.0, 0.047, 0.286); // dark majestic blue + setWaterTint(0.471, 0.776, 0.863); // light blue + setWaterMurkiness(0.82); + setWaterWaviness(3.0); + setWaterType("clap"); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/alpine_valley.js =================================================================== --- binaries/data/mods/public/maps/random/alpine_valley.js +++ binaries/data/mods/public/maps/random/alpine_valley.js @@ -50,7 +50,7 @@ * The algorithm adds possible edges consecutively and removes subsequently invalid edges. */ this.possibleEdges = []; - this.InitPossibleEdges(); + this.InitPossibleEdges(args.numPlayers); /** * A two-dimensional array of booleans that are true if the two corresponding vertices may be connected by a new edge (mountainrange). @@ -58,7 +58,7 @@ * The purpose is to rule out any cycles in the graph, i.e. prevent any territory enclosed by mountainranges. */ this.verticesConnectable = []; - this.InitConnectable(); + this.InitConnectable(args.numPlayers); /** * Currently iterated item of possibleEdges that is either used as a mountainrange or removed from the possibleEdges. @@ -73,7 +73,7 @@ this.currentEdgeEnd = undefined; } -MountainRangeBuilder.prototype.InitPossibleEdges = function() +MountainRangeBuilder.prototype.InitPossibleEdges = function(numPlayers) { for (let i = 0; i < this.vertices.length; ++i) for (let j = numPlayers; j < this.vertices.length; ++j) @@ -81,7 +81,7 @@ this.possibleEdges.push([i, j]); }; -MountainRangeBuilder.prototype.InitConnectable = function() +MountainRangeBuilder.prototype.InitConnectable = function(numPlayers) { for (let i = 0; i < this.vertices.length; ++i) { @@ -226,319 +226,331 @@ } }; -if (randBool()) +function* GenerateMap() { - RandomMapLogger.prototype.printDirectly("Setting late spring biome.\n"); - var tPrimary = ["alpine_dirt_grass_50"]; - var tForestFloor = "alpine_forrestfloor"; - var tCliff = ["alpine_cliff_a", "alpine_cliff_b", "alpine_cliff_c"]; - var tSecondary = "alpine_grass_rocky"; - var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; - var tSnowLimited = ["alpine_snow_rocky"]; - var tDirt = "alpine_dirt"; - var tRoad = "new_alpine_citytile"; - var tRoadWild = "new_alpine_citytile"; - - var oPine = "gaia/tree/pine"; - var oBerryBush = "gaia/fruit/berry_01"; - var oDeer = "gaia/fauna_deer"; - var oRabbit = "gaia/fauna_rabbit"; - var oStoneLarge = "gaia/rock/alpine_large"; - var oStoneSmall = "gaia/rock/alpine_small"; - var oMetalLarge = "gaia/ore/alpine_large"; - - 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"; -} -else -{ - RandomMapLogger.prototype.printDirectly("Setting winter biome.\n"); - var tPrimary = ["alpine_snow_a", "alpine_snow_b"]; - var tForestFloor = "alpine_forrestfloor_snow"; - var tCliff = ["alpine_cliff_snow"]; - var tSecondary = "alpine_grass_snow_50"; - var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; - var tSnowLimited = ["alpine_snow_a", "alpine_snow_b"]; - var tDirt = "alpine_dirt"; - var tRoad = "new_alpine_citytile"; - var tRoadWild = "new_alpine_citytile"; - - var oPine = "gaia/tree/pine_w"; - var oBerryBush = "gaia/fruit/berry_01"; - var oDeer = "gaia/fauna_deer"; - var oRabbit = "gaia/fauna_rabbit"; - var oStoneLarge = "gaia/rock/alpine_large"; - var oStoneSmall = "gaia/rock/alpine_small"; - var oMetalLarge = "gaia/ore/alpine_large"; - - var aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; - var aGrassShort = "actor|props/flora/grass_soft_dry_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_dry.xml"; - var aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; -} - -var heightLand = 3; -var heightOffsetBump = 2; -var snowlineHeight = 29; -var heightMountain = 30; - -const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -var [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oPine - }, - "Decoratives": { - "template": aGrassShort + if (randBool()) + { + RandomMapLogger.prototype.printDirectly("Setting late spring biome.\n"); + var tPrimary = ["alpine_dirt_grass_50"]; + var tForestFloor = "alpine_forrestfloor"; + var tCliff = ["alpine_cliff_a", "alpine_cliff_b", "alpine_cliff_c"]; + var tSecondary = "alpine_grass_rocky"; + var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; + var tSnowLimited = ["alpine_snow_rocky"]; + var tDirt = "alpine_dirt"; + var tRoad = "new_alpine_citytile"; + var tRoadWild = "new_alpine_citytile"; + + var oPine = "gaia/tree/pine"; + var oBerryBush = "gaia/fruit/berry_01"; + var oDeer = "gaia/fauna_deer"; + var oRabbit = "gaia/fauna_rabbit"; + var oStoneLarge = "gaia/rock/alpine_large"; + var oStoneSmall = "gaia/rock/alpine_small"; + var oMetalLarge = "gaia/ore/alpine_large"; + + 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"; } -}); -Engine.SetProgress(20); - -new MountainRangeBuilder({ - "pathplacer": new PathPlacer(undefined, undefined, undefined, 0.4, scaleByMapSize(3, 12), 0.1, 0.1, 0.1), - "painters":[ - new LayeredPainter([tCliff, tPrimary], [3]), - new SmoothElevationPainter(ELEVATION_SET, heightMountain, 2), - new TileClassPainter(clHill) - ], - "constraint": avoidClasses(clPlayer, 20), - "passageWidth": scaleByMapSize(10, 15), - "mountainWidth": scaleByMapSize(9, 15), - "maxDegree": 3, - "points": [ - // Four points near each player - ...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.49), mapCenter)[0], - ...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers * 1.4, fractionToTiles(0.34), mapCenter)[0], - ...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers * 0.6, fractionToTiles(0.34), mapCenter)[0], - ...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.18), mapCenter)[0], - mapCenter - ] -}).CreateMountainRanges(); - -Engine.SetProgress(35); - -paintTerrainBasedOnHeight(heightLand + 0.1, snowlineHeight, 0, tCliff); -paintTerrainBasedOnHeight(snowlineHeight, heightMountain, 3, tSnowLimited); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - avoidClasses(clPlayer, 10), - scaleByMapSize(100, 200)); -Engine.SetProgress(40); - -g_Map.log("Creating hills"); -createAreas( - new ClumpPlacer(scaleByMapSize(40, 150), 0.2, 0.1, Infinity), - [ - new LayeredPainter([tCliff, tSnowLimited], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightMountain, 2), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 20, clHill, 14), - scaleByMapSize(10, 80) * numPlayers -); -Engine.SetProgress(50); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); -const types = [ - [[tForestFloor, tPrimary, pForest], [tForestFloor, pForest]] -]; - -var size = forestTrees / (scaleByMapSize(2,8) * numPlayers); - -const num = Math.floor(size / types.length); -for (const type of types) - createAreas( - new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) + else + { + RandomMapLogger.prototype.printDirectly("Setting winter biome.\n"); + var tPrimary = ["alpine_snow_a", "alpine_snow_b"]; + var tForestFloor = "alpine_forrestfloor_snow"; + var tCliff = ["alpine_cliff_snow"]; + var tSecondary = "alpine_grass_snow_50"; + var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; + var tSnowLimited = ["alpine_snow_a", "alpine_snow_b"]; + var tDirt = "alpine_dirt"; + var tRoad = "new_alpine_citytile"; + var tRoadWild = "new_alpine_citytile"; + + var oPine = "gaia/tree/pine_w"; + var oBerryBush = "gaia/fruit/berry_01"; + var oDeer = "gaia/fauna_deer"; + var oRabbit = "gaia/fauna_rabbit"; + var oStoneLarge = "gaia/rock/alpine_large"; + var oStoneSmall = "gaia/rock/alpine_small"; + var oMetalLarge = "gaia/ore/alpine_large"; + + var aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; + var aGrassShort = "actor|props/flora/grass_soft_dry_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_dry.xml"; + var aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; + } + + var heightLand = 3; + var heightOffsetBump = 2; + var snowlineHeight = 29; + var heightMountain = 30; + + const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + var [playerIDs, playerPosition, playerAngle, startAngle] = + playerPlacementCircle(fractionToTiles(0.35)); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oPine + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 20; + + new MountainRangeBuilder({ + "pathplacer": new PathPlacer(undefined, undefined, undefined, 0.4, scaleByMapSize(3, 12), 0.1, + 0.1, 0.1), + "painters":[ + new LayeredPainter([tCliff, tPrimary], [3]), + new SmoothElevationPainter(ELEVATION_SET, heightMountain, 2), + new TileClassPainter(clHill) + ], + "constraint": avoidClasses(clPlayer, 20), + "passageWidth": scaleByMapSize(10, 15), + "mountainWidth": scaleByMapSize(9, 15), + "maxDegree": 3, + "points": [ + // Four points near each player + ...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, + fractionToTiles(0.49), mapCenter)[0], + ...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers * 1.4, + fractionToTiles(0.34), mapCenter)[0], + ...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers * 0.6, + fractionToTiles(0.34), mapCenter)[0], + ...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, + fractionToTiles(0.18), mapCenter)[0], + mapCenter ], - avoidClasses(clPlayer, 12, clForest, 10, clHill, 0), - num); -Engine.SetProgress(60); + "numPlayers": numPlayers + }).CreateMountainRanges(); + + yield 35; -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + paintTerrainBasedOnHeight(heightLand + 0.1, snowlineHeight, 0, tCliff); + paintTerrainBasedOnHeight(snowlineHeight, heightMountain, 3, tSnowLimited); + + g_Map.log("Creating bumps"); createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - [ - new LayeredPainter([[tDirt, tHalfSnow], [tHalfSnow, tSnowLimited]], [2]), - new TileClassPainter(clDirt) - ], - avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), - scaleByMapSize(15, 45)); + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + avoidClasses(clPlayer, 10), + scaleByMapSize(100, 200)); + yield 40; -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) + g_Map.log("Creating hills"); createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - new TerrainPainter(tSecondary), - avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), - scaleByMapSize(15, 45)); - -Engine.SetProgress(65); - -g_Map.log("Creating stone mines"); -var group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone mines"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), - scaleByMapSize(4,16), 100 -); -Engine.SetProgress(70); - -g_Map.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), - scaleByMapSize(16, 262), 50 -); - -g_Map.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), - scaleByMapSize(8, 131), 50 -); -Engine.SetProgress(75); - -g_Map.log("Creating deer"); -group = new SimpleGroup( - [new SimpleObject(oDeer, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), - 3 * numPlayers, 50 -); - -g_Map.log("Creating berry bush"); -group = new SimpleGroup( - [new SimpleObject(oBerryBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - randIntInclusive(1, 4) * numPlayers + 2, 50 -); - -g_Map.log("Creating rabbit"); -group = new SimpleGroup( - [new SimpleObject(oRabbit, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), - 3 * numPlayers, 50 -); -Engine.SetProgress(85); - -createStragglerTrees( - [oPine], - avoidClasses(clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); - -g_Map.log("Creating small grass tufts"); -var planetm = 1; - -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), - planetm * scaleByMapSize(13, 200) -); -Engine.SetProgress(90); - -g_Map.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), - planetm * scaleByMapSize(13, 200) -); -Engine.SetProgress(95); - -g_Map.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), - planetm * scaleByMapSize(13, 200), 50 -); - -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); -setSunRotation(randomAngle()); -setSunElevation(Math.PI * randFloat(1/5, 1/3)); - -g_Map.ExportMap(); + new ClumpPlacer(scaleByMapSize(40, 150), 0.2, 0.1, Infinity), + [ + new LayeredPainter([tCliff, tSnowLimited], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightMountain, 2), + new TileClassPainter(clHill) + ], + avoidClasses(clPlayer, 20, clHill, 14), + scaleByMapSize(10, 80) * numPlayers + ); + yield 50; + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); + const types = [ + [[tForestFloor, tPrimary, pForest], [tForestFloor, pForest]] + ]; + + var size = forestTrees / (scaleByMapSize(2,8) * numPlayers); + + const num = Math.floor(size / types.length); + for (const type of types) + createAreas( + new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 12, clForest, 10, clHill, 0), + num); + yield 60; + + g_Map.log("Creating dirt patches"); + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new LayeredPainter([[tDirt, tHalfSnow], [tHalfSnow, tSnowLimited]], [2]), + new TileClassPainter(clDirt) + ], + avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), + scaleByMapSize(15, 45)); + + g_Map.log("Creating grass patches"); + for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + new TerrainPainter(tSecondary), + avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), + scaleByMapSize(15, 45)); + + yield 65; + + g_Map.log("Creating stone mines"); + var group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating small stone mines"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), + scaleByMapSize(4,16), 100 + ); + yield 70; + + g_Map.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), + scaleByMapSize(16, 262), 50 + ); + + g_Map.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), + scaleByMapSize(8, 131), 50 + ); + yield 75; + + g_Map.log("Creating deer"); + group = new SimpleGroup( + [new SimpleObject(oDeer, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating berry bush"); + group = new SimpleGroup( + [new SimpleObject(oBerryBush, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + + g_Map.log("Creating rabbit"); + group = new SimpleGroup( + [new SimpleObject(oRabbit, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), + 3 * numPlayers, 50 + ); + yield 85; + + createStragglerTrees( + [oPine], + avoidClasses(clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + + g_Map.log("Creating small grass tufts"); + var planetm = 1; + + 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), + planetm * scaleByMapSize(13, 200) + ); + yield 90; + + g_Map.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), + planetm * scaleByMapSize(13, 200) + ); + yield 95; + + g_Map.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), + planetm * scaleByMapSize(13, 200), 50 + ); + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + + setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); + setSunRotation(randomAngle()); + setSunElevation(Math.PI * randFloat(1/5, 1/3)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/ambush.js =================================================================== --- binaries/data/mods/public/maps/random/ambush.js +++ binaries/data/mods/public/maps/random/ambush.js @@ -3,241 +3,245 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setSelectedBiome(); - -const heightLand = 2; - -const g_Map = new RandomMap(heightLand, g_Terrains.mainTerrain); -const mapCenter = g_Map.getCenter(); -const mapSize = g_Map.getSize(); - -initTileClasses(["bluffsPassage", "nomadArea"]); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land)); - -Engine.SetProgress(10); - -const pattern = g_MapSettings.TeamPlacement || pickRandom(["line", "radial", "randomGroup", "stronghold"]); -let [playerIDs, playerPosition] = - createBases( - ...playerPlacementByPattern( - pattern, - fractionToTiles(randFloat(0.2, 0.35)), - fractionToTiles(randFloat(0.08, 0.1)), - randomAngle(), - undefined), - g_PlayerbaseTypes[pattern].walls); - -if (!isNomad()) - markPlayerAvoidanceArea(playerPosition, defaultPlayerBaseRadius()); - -Engine.SetProgress(20); - -addElements([ - { - "func": addBluffs, - "baseHeight": heightLand, - "avoid": [g_TileClasses.bluffIgnore, 0], - "sizes": ["normal", "big", "huge"], - "mixes": ["same"], - "amounts": ["many"] - }, - { - "func": addHills, - "avoid": [ - g_TileClasses.bluff, 5, - g_TileClasses.hill, 15, - g_TileClasses.player, 20 - ], - "sizes": ["normal", "big"], - "mixes": ["normal"], - "amounts": ["tons"] - } -]); -Engine.SetProgress(30); - -if (!isNomad()) - createBluffsPassages(playerPosition); +function* GenerateMap(mapSettings) +{ + setSelectedBiome(); -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.bluffsPassage, 4, - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.bluffsPassage, 4, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - } -]); -Engine.SetProgress(50); + const heightLand = 2; -addElements(shuffleArray([ - { - "func": addMetal, - "avoid": [ - g_TileClasses.bluffsPassage, 4, - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.metal, 20, - g_TileClasses.water, 3 - ], - "stay": [g_TileClasses.bluff, 5], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["tons"] - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.bluffsPassage, 4, - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 10, - g_TileClasses.water, 3 - ], - "stay": [g_TileClasses.bluff, 5], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["tons"] - }, - // Forests on bluffs - { - "func": addForests, - "avoid": [ - g_TileClasses.bluffsPassage, 4, - g_TileClasses.forest, 6, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 5, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.water, 2 - ], - "stay": [g_TileClasses.bluff, 5], - "sizes": ["big"], - "mixes": ["normal"], - "amounts": ["tons"] - }, - // Forests on mainland - { - "func": addForests, - "avoid": [ - g_TileClasses.bluffsPassage, 4, - g_TileClasses.bluff, 10, - g_TileClasses.forest, 10, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 5, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.water, 2 - ], - "sizes": ["small"], - "mixes": ["same"], - "amounts": ["normal"] - } -])); -Engine.SetProgress(70); + global.g_Map = new RandomMap(heightLand, g_Terrains.mainTerrain); + const mapCenter = g_Map.getCenter(); + const mapSize = g_Map.getSize(); -addElements(shuffleArray([ - { - "func": addBerries, - "avoid": [ - g_TileClasses.bluff, 5, - g_TileClasses.bluffsPassage, 4, - g_TileClasses.forest, 5, - g_TileClasses.metal, 10, - g_TileClasses.mountain, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 10, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["few"] - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.bluff, 5, - g_TileClasses.bluffsPassage, 4, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.water, 3 - ], - "sizes": ["small"], - "mixes": ["similar"], - "amounts": ["few"] - }, + initTileClasses(["bluffsPassage", "nomadArea"]); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land)); + + yield 10; + + const pattern = mapSettings.TeamPlacement || + pickRandom(["line", "radial", "randomGroup", "stronghold"]); + let [playerIDs, playerPosition] = + createBases( + ...playerPlacementByPattern( + pattern, + fractionToTiles(randFloat(0.2, 0.35)), + fractionToTiles(randFloat(0.08, 0.1)), + randomAngle(), + undefined), + g_PlayerbaseTypes[pattern].walls); + + if (!isNomad()) + markPlayerAvoidanceArea(playerPosition, defaultPlayerBaseRadius()); + + yield 20; + + addElements([ + { + "func": addBluffs, + "baseHeight": heightLand, + "avoid": [g_TileClasses.bluffIgnore, 0], + "sizes": ["normal", "big", "huge"], + "mixes": ["same"], + "amounts": ["many"] + }, + { + "func": addHills, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.hill, 15, + g_TileClasses.player, 20 + ], + "sizes": ["normal", "big"], + "mixes": ["normal"], + "amounts": ["tons"] + } + ]); + yield 30; + + if (!isNomad()) + createBluffsPassages(playerPosition); + + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.bluffsPassage, 4, + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.bluffsPassage, 4, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + } + ]); + yield 50; + + addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.bluffsPassage, 4, + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 20, + g_TileClasses.water, 3 + ], + "stay": [g_TileClasses.bluff, 5], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.bluffsPassage, 4, + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10, + g_TileClasses.water, 3 + ], + "stay": [g_TileClasses.bluff, 5], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + }, + // Forests on bluffs + { + "func": addForests, + "avoid": [ + g_TileClasses.bluffsPassage, 4, + g_TileClasses.forest, 6, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2 + ], + "stay": [g_TileClasses.bluff, 5], + "sizes": ["big"], + "mixes": ["normal"], + "amounts": ["tons"] + }, + // Forests on mainland + { + "func": addForests, + "avoid": [ + g_TileClasses.bluffsPassage, 4, + g_TileClasses.bluff, 10, + g_TileClasses.forest, 10, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2 + ], + "sizes": ["small"], + "mixes": ["same"], + "amounts": ["normal"] + } + ])); + yield 70; + + addElements(shuffleArray([ + { + "func": addBerries, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.bluffsPassage, 4, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 10, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["few"] + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.bluffsPassage, 4, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.water, 3 + ], + "sizes": ["small"], + "mixes": ["similar"], + "amounts": ["few"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.bluffsPassage, 4, + g_TileClasses.forest, 7, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.water, 5 + ], + "sizes": ["tiny"], + "mixes": ["same"], + "amounts": ["many"] + } + ])); + yield 90; + + if (isNomad()) { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.bluffsPassage, 4, - g_TileClasses.forest, 7, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.water, 5 - ], - "sizes": ["tiny"], - "mixes": ["same"], - "amounts": ["many"] + g_Map.log("Preventing units to be spawned at the map border"); + createArea( + new DiskPlacer(mapSize / 2 - scaleByMapSize(15, 35), mapCenter), + new TileClassPainter(g_TileClasses.nomadArea)); + + placePlayersNomad( + g_TileClasses.player, + [ + stayClasses(g_TileClasses.nomadArea, 0), + avoidClasses( + g_TileClasses.bluff, 2, + g_TileClasses.water, 4, + g_TileClasses.forest, 1, + g_TileClasses.metal, 4, + g_TileClasses.rock, 4, + g_TileClasses.mountain, 4, + g_TileClasses.animals, 2) + ]); } -])); -Engine.SetProgress(90); -if (isNomad()) -{ - g_Map.log("Preventing units to be spawned at the map border"); - createArea( - new DiskPlacer(mapSize / 2 - scaleByMapSize(15, 35), mapCenter), - new TileClassPainter(g_TileClasses.nomadArea)); - - placePlayersNomad( - g_TileClasses.player, - [ - stayClasses(g_TileClasses.nomadArea, 0), - avoidClasses( - g_TileClasses.bluff, 2, - g_TileClasses.water, 4, - g_TileClasses.forest, 1, - g_TileClasses.metal, 4, - g_TileClasses.rock, 4, - g_TileClasses.mountain, 4, - g_TileClasses.animals, 2) - ]); + return g_Map; } - -g_Map.ExportMap(); Index: binaries/data/mods/public/maps/random/anatolian_plateau.js =================================================================== --- binaries/data/mods/public/maps/random/anatolian_plateau.js +++ binaries/data/mods/public/maps/random/anatolian_plateau.js @@ -1,251 +1,256 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tPrimary = ["steppe_grass_a", "steppe_grass_c", "steppe_grass_d"]; -const tGrass = ["steppe_grass_a", "steppe_grass_b", "steppe_grass_c", "steppe_grass_d"]; -const tForestFloor = "steppe_grass_c"; -const tGrassA = "steppe_grass_b"; -const tGrassB = "steppe_grass_c"; -const tGrassC = ["steppe_grass_b", "steppe_grass_c", "steppe_grass_d"]; -const tGrassD = "steppe_grass_a"; -const tDirt = ["steppe_dirt_a", "steppe_dirt_b"]; -const tRoad = "road_stones"; -const tRoadWild = "road_stones"; - -const oPoplar = "gaia/tree/poplar_lombardy"; -const oBush = "gaia/tree/bush_temperate"; -const oBerryBush = "gaia/fruit/berry_01"; -const oRabbit = "gaia/fauna_rabbit"; -const oAnimal = "gaia/fauna_sheep"; -const oSheep = "gaia/fauna_sheep"; -const oStoneLarge = "gaia/rock/mediterranean_large"; -const oStoneSmall = "gaia/rock/mediterranean_small"; -const oMetalLarge = "gaia/ore/mediterranean_large"; - -const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; -const aGrassShort = "actor|props/flora/grass_soft_large.xml"; -const aRockLarge = "actor|geology/stone_granite_med.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aBushMedium = "actor|props/flora/bush_medit_me.xml"; -const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; - -const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPoplar, tForestFloor]; - -const heightLand = 1; -const heightOffsetBump = 2; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - "template": oAnimal - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oPoplar - }, - "Decoratives": { - "template": aGrassShort - } -}); - -Engine.SetProgress(20); - -g_Map.log("Creating bumps"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(2, 5)), 0.5), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - avoidClasses(clPlayer, 13), - scaleByMapSize(300, 800)); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(220, 1000, 0.65); -const types = [[[tForestFloor, tGrass, pForest], [tForestFloor, pForest]]]; -const size = forestTrees / (scaleByMapSize(2,8) * numPlayers); -const num = 4 * Math.floor(size / types.length); -for (const type of types) +function* GenerateMap() +{ + const tPrimary = ["steppe_grass_a", "steppe_grass_c", "steppe_grass_d"]; + const tGrass = ["steppe_grass_a", "steppe_grass_b", "steppe_grass_c", "steppe_grass_d"]; + const tForestFloor = "steppe_grass_c"; + const tGrassA = "steppe_grass_b"; + const tGrassB = "steppe_grass_c"; + const tGrassC = ["steppe_grass_b", "steppe_grass_c", "steppe_grass_d"]; + const tGrassD = "steppe_grass_a"; + const tDirt = ["steppe_dirt_a", "steppe_dirt_b"]; + const tRoad = "road_stones"; + const tRoadWild = "road_stones"; + + const oPoplar = "gaia/tree/poplar_lombardy"; + const oBush = "gaia/tree/bush_temperate"; + const oBerryBush = "gaia/fruit/berry_01"; + const oRabbit = "gaia/fauna_rabbit"; + const oAnimal = "gaia/fauna_sheep"; + const oSheep = "gaia/fauna_sheep"; + const oStoneLarge = "gaia/rock/mediterranean_large"; + const oStoneSmall = "gaia/rock/mediterranean_small"; + const oMetalLarge = "gaia/ore/mediterranean_large"; + + const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; + const aGrassShort = "actor|props/flora/grass_soft_large.xml"; + const aRockLarge = "actor|geology/stone_granite_med.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aBushMedium = "actor|props/flora/bush_medit_me.xml"; + const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; + + const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPoplar, tForestFloor]; + + const heightLand = 1; + const heightOffsetBump = 2; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + "template": oAnimal + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oPoplar + }, + "Decoratives": { + "template": aGrassShort + } + }); + + yield 20; + + g_Map.log("Creating bumps"); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(2, 3)), 4, Infinity), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) - ], - avoidClasses(clPlayer, 13, clForest, 20, clHill, 1), - num); -Engine.SetProgress(50); - -g_Map.log("Creating grass patches"); -createLayeredPatches( - [scaleByMapSize(5, 48), scaleByMapSize(6, 84), scaleByMapSize(8, 128)], - [[tGrass,tGrassA,tGrassC],[tGrass,tGrassA,tGrassC], [tGrass,tGrassA,tGrassC]], - [1,1], - avoidClasses(clForest, 0, clHill, 0, clDirt, 2, clPlayer, 10), - scaleByMapSize(50, 70), - clDirt); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(5, 32), scaleByMapSize(6, 48), scaleByMapSize(7, 80)], - [tGrassD ,tDirt], - [1], - avoidClasses(clForest, 0, clHill, 0, clDirt, 2, clPlayer, 10), - scaleByMapSize(50, 90), - clDirt); - -Engine.SetProgress(55); - -g_Map.log("Creating big patches"); -createLayeredPatches( - [scaleByMapSize(10, 60), scaleByMapSize(15, 90), scaleByMapSize(20, 120)], - [tGrassB ,tGrassA], - [1], - avoidClasses(clHill, 0, clPlayer, 8), - scaleByMapSize(30, 90), - clDirt); - -Engine.SetProgress(60); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - scaleByMapSize(1,4), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - scaleByMapSize(1,4), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), - scaleByMapSize(2,8), 100 -); - -Engine.SetProgress(65); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aRockMedium, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clForest, 0, clPlayer, 10, clHill, 0), - scaleByMapSize(16, 262), 50 -); - -g_Map.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, 10, clHill, 0), - scaleByMapSize(8, 131), 50 -); - -Engine.SetProgress(70); - -g_Map.log("Creating rabbits"); -group = new SimpleGroup( - [new SimpleObject(oRabbit, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), - 6 * numPlayers, 50 -); - -g_Map.log("Creating berry bush"); -group = new SimpleGroup( - [new SimpleObject(oBerryBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), - randIntInclusive(1, 4) * numPlayers + 2, 50 -); - -Engine.SetProgress(75); - -g_Map.log("Creating sheep"); -group = new SimpleGroup( - [new SimpleObject(oSheep, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), - 3 * numPlayers, 50 -); - -Engine.SetProgress(85); - -createStragglerTrees( - [oBush, oPoplar], - avoidClasses(clForest, 1, clHill, 1, clPlayer, 13, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); - -g_Map.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, 10, clDirt, 1, clForest, 0), - scaleByMapSize(13, 200) -); - -Engine.SetProgress(95); - -g_Map.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), - scaleByMapSize(13, 200), 50 -); - -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setFogThickness(0.1); -setFogFactor(0.2); - -setPPEffect("hdr"); -setPPSaturation(0.45); -setPPContrast(0.62); -setPPBloom(0.2); - -g_Map.ExportMap(); + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(2, 5)), 0.5), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + avoidClasses(clPlayer, 13), + scaleByMapSize(300, 800)); + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(220, 1000, 0.65); + const types = [[[tForestFloor, tGrass, pForest], [tForestFloor, pForest]]]; + const size = forestTrees / (scaleByMapSize(2,8) * numPlayers); + const num = 4 * Math.floor(size / types.length); + for (const type of types) + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(2, 3)), 4, Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 13, clForest, 20, clHill, 1), + num); + yield 50; + + g_Map.log("Creating grass patches"); + createLayeredPatches( + [scaleByMapSize(5, 48), scaleByMapSize(6, 84), scaleByMapSize(8, 128)], + [[tGrass,tGrassA,tGrassC],[tGrass,tGrassA,tGrassC], [tGrass,tGrassA,tGrassC]], + [1,1], + avoidClasses(clForest, 0, clHill, 0, clDirt, 2, clPlayer, 10), + scaleByMapSize(50, 70), + clDirt); + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(5, 32), scaleByMapSize(6, 48), scaleByMapSize(7, 80)], + [tGrassD ,tDirt], + [1], + avoidClasses(clForest, 0, clHill, 0, clDirt, 2, clPlayer, 10), + scaleByMapSize(50, 90), + clDirt); + + yield 55; + + g_Map.log("Creating big patches"); + createLayeredPatches( + [scaleByMapSize(10, 60), scaleByMapSize(15, 90), scaleByMapSize(20, 120)], + [tGrassB ,tGrassA], + [1], + avoidClasses(clHill, 0, clPlayer, 8), + scaleByMapSize(30, 90), + clDirt); + + yield 60; + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + scaleByMapSize(1,4), 100 + ); + + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + scaleByMapSize(1,4), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), + scaleByMapSize(2,8), 100 + ); + + yield 65; + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aRockMedium, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clForest, 0, clPlayer, 10, clHill, 0), + scaleByMapSize(16, 262), 50 + ); + + g_Map.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, 10, clHill, 0), + scaleByMapSize(8, 131), 50 + ); + + yield 70; + + g_Map.log("Creating rabbits"); + group = new SimpleGroup( + [new SimpleObject(oRabbit, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), + 6 * numPlayers, 50 + ); + + g_Map.log("Creating berry bush"); + group = new SimpleGroup( + [new SimpleObject(oBerryBush, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + + yield 75; + + g_Map.log("Creating sheep"); + group = new SimpleGroup( + [new SimpleObject(oSheep, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), + 3 * numPlayers, 50 + ); + + yield 85; + + createStragglerTrees( + [oBush, oPoplar], + avoidClasses(clForest, 1, clHill, 1, clPlayer, 13, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + + g_Map.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, 10, clDirt, 1, clForest, 0), + scaleByMapSize(13, 200) + ); + + yield 95; + + g_Map.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), + scaleByMapSize(13, 200), 50 + ); + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + + setFogThickness(0.1); + setFogFactor(0.2); + + setPPEffect("hdr"); + setPPSaturation(0.45); + setPPContrast(0.62); + setPPBloom(0.2); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/archipelago.js =================================================================== --- binaries/data/mods/public/maps/random/archipelago.js +++ binaries/data/mods/public/maps/random/archipelago.js @@ -4,274 +4,279 @@ TILE_CENTERED_HEIGHT_MAP = true; -setSelectedBiome(); - -const biomeTweaks = Engine.ReadJSONFile("maps/random/archipelago_biome_tweaks.json"); - -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 tTier4Terrain = g_Terrains.dirt; -const tRoad = g_Terrains.road; -const tRoadWild = g_Terrains.roadWild; -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/treasure/wood"; - -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 heightShore = 1; - -const g_Map = new RandomMap(heightSeaGround, tWater); - -const numPlayers = getNumPlayers(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clLand = g_Map.createTileClass(); - -const islandRadius = scaleByMapSize(22, 31); - -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - -g_Map.log("Creating player islands"); -for (let i = 0; i < numPlayers; ++i) - createArea( +function* GenerateMap() +{ + setSelectedBiome(); + + const biomeTweaks = Engine.ReadJSONFile("maps/random/archipelago_biome_tweaks.json"); + + 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 tTier4Terrain = g_Terrains.dirt; + const tRoad = g_Terrains.road; + const tRoadWild = g_Terrains.roadWild; + 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/treasure/wood"; + + 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 heightShore = 1; + + global.g_Map = new RandomMap(heightSeaGround, tWater); + + const numPlayers = getNumPlayers(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clLand = g_Map.createTileClass(); + + const islandRadius = scaleByMapSize(22, 31); + + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + + g_Map.log("Creating player islands"); + for (let i = 0; i < numPlayers; ++i) + createArea( + new ChainPlacer( + 2, + Math.floor(scaleByMapSize(5, 10)), + Math.floor(scaleByMapSize(25, 60)), + Infinity, + playerPosition[i], + 0, + [Math.floor(islandRadius)]), + [ + new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), + new TileClassPainter(clLand) + ]); + + g_Map.log("Creating random islands"); + createAreas( new ChainPlacer( - 2, - Math.floor(scaleByMapSize(5, 10)), + Math.floor(scaleByMapSize(4, 8)), + Math.floor(scaleByMapSize(8, 14)), Math.floor(scaleByMapSize(25, 60)), - Infinity, - playerPosition[i], - 0, - [Math.floor(islandRadius)]), + 0.07, + undefined, + scaleByMapSize(30, 70)), [ new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), new TileClassPainter(clLand) - ]); - -g_Map.log("Creating random islands"); -createAreas( - new ChainPlacer( - Math.floor(scaleByMapSize(4, 8)), - Math.floor(scaleByMapSize(8, 14)), - Math.floor(scaleByMapSize(25, 60)), - 0.07, - undefined, - scaleByMapSize(30, 70)), - [ - new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), - new TileClassPainter(clLand) - ], - null, - scaleByMapSize(1, 5) * randIntInclusive(5, 10)); - -paintTerrainBasedOnHeight(heightLand - 0.6, heightLand + 0.4, 3, tMainTerrain); -paintTerrainBasedOnHeight(heightShore, heightLand, 0, tShore); -paintTerrainBasedOnHeight(heightSeaGround, heightShore, 2, tWater); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - // PlayerTileClass marked below - "BaseResourceClass": clBaseResource, - "Walls": "towers", - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad, - "radius": islandRadius / 3, - "painters": [ - new TileClassPainter(clPlayer) - ] - }, - "StartingAnimal": { - }, - "Berries": { - "template": oFruitBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Treasures": { - "types": [ - { - "template": oWoodTreasure, - "count": 14 - } - ] - }, - "Trees": { - "template": oTree1, - "count": scaleByMapSize(15, 30) - }, - "Decoratives": { - "template": aGrassShort, - } -}); - -createBumps([avoidClasses(clPlayer, 10), stayClasses(clLand, 5)]); - -if (randBool()) - createHills([tMainTerrain, tCliff, tHill], [avoidClasses(clPlayer, 2, clHill, 15), stayClasses(clLand, 0)], clHill, scaleByMapSize(1, 4) * numPlayers); -else - createMountains(tCliff, [avoidClasses(clPlayer, 2, clHill, 15), stayClasses(clLand, 0)], clHill, scaleByMapSize(1, 4) * numPlayers); - -// adjust biomes (especially wood) -const biomeSpecifics = biomeTweaks[currentBiome()] || biomeTweaks.baseline; - -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(biomeSpecifics.treeAmount)); -createForests( - [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], - [avoidClasses(clPlayer, biomeSpecifics.forestPlayerSpacing, clForest, biomeSpecifics.forestForestSpacing, clHill, 0), stayClasses(clLand, 3)], - clForest, - forestTrees -); -Engine.SetProgress(50); - -g_Map.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, 3, clPlayer, 12), stayClasses(clLand, 7)], - scaleByMapSize(15, 45), - clDirt -); - -g_Map.log("Creating grass patches"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tTier4Terrain, - [avoidClasses(clForest, 0, clHill, 0, clDirt, 3, clPlayer, 12), stayClasses(clLand, 7)], - scaleByMapSize(15, 45), - clDirt -); -Engine.SetProgress(55); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4)], - [new SimpleObject(oStoneSmall, 2, 5, 1, 3)] - ], - [avoidClasses(clForest, 1, clPlayer, 7, clRock, 10, clHill, 1), stayClasses(clLand, 6)], - clRock -); - -g_Map.log("Creating metal mines"); -createMines( - [[new SimpleObject(oMetalLarge, 1, 1, 0, 4)]], - [avoidClasses(clForest, 1, clPlayer, 7, clMetal, 10, clRock, 5, clHill, 1), stayClasses(clLand, 6)], - clMetal -); -Engine.SetProgress(65); - -const planetm = currentBiome() == "generic/india" ? 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, 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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13) - ], - [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 5)]); -Engine.SetProgress(70); - -createFood( - [ - [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], - [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] - ], - [ - 3 * numPlayers, - 3 * numPlayers - ], - [avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20), stayClasses(clLand, 3)], - clFood); - -Engine.SetProgress(75); - -createFood( - [ - [new SimpleObject(oFruitBush, 5, 7, 0, 4)] - ], - [ - 3 * numPlayers - ], - [avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 10), stayClasses(clLand, 3)], - clFood); - -Engine.SetProgress(80); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 25 * numPlayers - ], - avoidClasses(clLand, 3, clPlayer, 2, clFood, 20), - clFood); - -Engine.SetProgress(85); - -createStragglerTrees( - [oTree1, oTree2, oTree4, oTree3], - [avoidClasses(clForest, 7, clHill, 1, clPlayer, 3, clMetal, 6, clRock, 6), stayClasses(clLand, 7)], - clForest, - stragglerTrees); - -placePlayersNomad( - clPlayer, - new AndConstraint([ - stayClasses(clLand, 4), - avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)])); - -setWaterWaviness(4.0); -setWaterType("ocean"); - -g_Map.ExportMap(); + ], + null, + scaleByMapSize(1, 5) * randIntInclusive(5, 10)); + + paintTerrainBasedOnHeight(heightLand - 0.6, heightLand + 0.4, 3, tMainTerrain); + paintTerrainBasedOnHeight(heightShore, heightLand, 0, tShore); + paintTerrainBasedOnHeight(heightSeaGround, heightShore, 2, tWater); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + // PlayerTileClass marked below + "BaseResourceClass": clBaseResource, + "Walls": "towers", + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad, + "radius": islandRadius / 3, + "painters": [ + new TileClassPainter(clPlayer) + ] + }, + "StartingAnimal": { + }, + "Berries": { + "template": oFruitBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Treasures": { + "types": [ + { + "template": oWoodTreasure, + "count": 14 + } + ] + }, + "Trees": { + "template": oTree1, + "count": scaleByMapSize(15, 30) + }, + "Decoratives": { + "template": aGrassShort, + } + }); + + createBumps([avoidClasses(clPlayer, 10), stayClasses(clLand, 5)]); + + if (randBool()) + createHills([tMainTerrain, tCliff, tHill], [avoidClasses(clPlayer, 2, clHill, 15), stayClasses(clLand, 0)], clHill, scaleByMapSize(1, 4) * numPlayers); + else + createMountains(tCliff, [avoidClasses(clPlayer, 2, clHill, 15), stayClasses(clLand, 0)], clHill, scaleByMapSize(1, 4) * numPlayers); + + // adjust biomes (especially wood) + const biomeSpecifics = biomeTweaks[currentBiome()] || biomeTweaks.baseline; + + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(biomeSpecifics.treeAmount)); + createForests( + [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], + [avoidClasses(clPlayer, biomeSpecifics.forestPlayerSpacing, clForest, biomeSpecifics.forestForestSpacing, clHill, 0), stayClasses(clLand, 3)], + clForest, + forestTrees + ); + yield 50; + + g_Map.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, 3, clPlayer, 12), stayClasses(clLand, 7)], + scaleByMapSize(15, 45), + clDirt + ); + + g_Map.log("Creating grass patches"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tTier4Terrain, + [avoidClasses(clForest, 0, clHill, 0, clDirt, 3, clPlayer, 12), stayClasses(clLand, 7)], + scaleByMapSize(15, 45), + clDirt + ); + yield 55; + + g_Map.log("Creating stone mines"); + createMines( + [ + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4)], + [new SimpleObject(oStoneSmall, 2, 5, 1, 3)] + ], + [avoidClasses(clForest, 1, clPlayer, 7, clRock, 10, clHill, 1), stayClasses(clLand, 6)], + clRock + ); + + g_Map.log("Creating metal mines"); + createMines( + [[new SimpleObject(oMetalLarge, 1, 1, 0, 4)]], + [avoidClasses(clForest, 1, clPlayer, 7, clMetal, 10, clRock, 5, clHill, 1), stayClasses(clLand, 6)], + clMetal + ); + yield 65; + + const planetm = currentBiome() == "generic/india" ? 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, 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13) + ], + [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 5)]); + yield 70; + + createFood( + [ + [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], + [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] + ], + [ + 3 * numPlayers, + 3 * numPlayers + ], + [avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20), stayClasses(clLand, 3)], + clFood); + + yield 75; + + createFood( + [ + [new SimpleObject(oFruitBush, 5, 7, 0, 4)] + ], + [ + 3 * numPlayers + ], + [avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 10), stayClasses(clLand, 3)], + clFood); + + yield 80; + + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 25 * numPlayers + ], + avoidClasses(clLand, 3, clPlayer, 2, clFood, 20), + clFood); + + yield 85; + + createStragglerTrees( + [oTree1, oTree2, oTree4, oTree3], + [avoidClasses(clForest, 7, clHill, 1, clPlayer, 3, clMetal, 6, clRock, 6), stayClasses(clLand, 7)], + clForest, + stragglerTrees); + + placePlayersNomad( + clPlayer, + new AndConstraint([ + stayClasses(clLand, 4), + avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)])); + + setWaterWaviness(4.0); + setWaterType("ocean"); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/arctic_summer.js =================================================================== --- binaries/data/mods/public/maps/random/arctic_summer.js +++ binaries/data/mods/public/maps/random/arctic_summer.js @@ -1,323 +1,331 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -setFogThickness(0.46); -setFogFactor(0.5); - -setPPEffect("hdr"); -setPPSaturation(0.48); -setPPContrast(0.53); -setPPBloom(0.12); - -const tPrimary = ["alpine_grass_rocky"]; -const tForestFloor = "alpine_grass"; -const tCliff = ["polar_cliff_a", "polar_cliff_b", "polar_cliff_snow"]; -const tSecondary = "alpine_grass"; -const tHalfSnow = ["polar_grass_snow", "ice_dirt"]; -const tSnowLimited = ["polar_snow_rocks", "polar_ice"]; -const tDirt = "ice_dirt"; -const tShore = "alpine_shore_rocks"; -const tWater = "polar_ice_b"; -const tHill = "polar_ice_cracked"; - -const oBush = "gaia/tree/bush_badlands"; -const oBush2 = "gaia/tree/bush_temperate"; -const oBerryBush = "gaia/fruit/berry_01"; -const oRabbit = "gaia/fauna_rabbit"; -const oMuskox = "gaia/fauna_muskox"; -const oDeer = "gaia/fauna_deer"; -const oWolf = "gaia/fauna_wolf"; -const oWhaleFin = "gaia/fauna_whale_fin"; -const oWhaleHumpback = "gaia/fauna_whale_humpback"; -const oFish = "gaia/fish/generic"; -const oStoneLarge = "gaia/rock/alpine_large"; -const oStoneSmall = "gaia/rock/alpine_small"; -const oMetalLarge = "gaia/ore/alpine_large"; -const oWoodTreasure = "gaia/treasure/wood"; - -const aRockLarge = "actor|geology/stone_granite_med.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; - -const pForest = [tForestFloor + TERRAIN_SEPARATOR + oBush, tForestFloor + TERRAIN_SEPARATOR + oBush2, tForestFloor]; - -const heightSeaGround = -5; -const heightLand = 2; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tPrimary, - "innerTerrain": tSecondary - }, - "StartingAnimal": { - "template": oRabbit - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Treasures": { - "types": [ - { - "template": oWoodTreasure, - "count": 10 - } - ] - }, - "Trees": { - "template": oBush, - "count": 20, - "maxDistGroup": 3 - } - // No decoratives -}); -Engine.SetProgress(20); - -createHills( - [tPrimary, tCliff, tHill], - avoidClasses( - clPlayer, 35, - clForest, 20, - clHill, 50, - clWater, 2), - clHill, - scaleByMapSize(1, 240)); - -Engine.SetProgress(30); - -g_Map.log("Creating lakes"); -createAreas( - new ChainPlacer( - 1, - Math.floor(scaleByMapSize(4, 8)), - Math.floor(scaleByMapSize(40, 180)), - Infinity), - [ - new LayeredPainter([tShore, tWater], [1]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 5), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 15), - scaleByMapSize(1, 20)); - -Engine.SetProgress(45); - -createBumps(avoidClasses(clPlayer, 6, clWater, 2), scaleByMapSize(30, 300), 1, 8, 4, 0, 3); - -paintTerrainBasedOnHeight(4, 15, 0, tCliff); -paintTerrainBasedOnHeight(15, 100, 3, tSnowLimited); - -const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); -createForests( - [tSecondary, tForestFloor, tForestFloor, pForest, pForest], - avoidClasses( - clPlayer, 20, - clForest, 14, - clHill, 20, - clWater, 2), - clForest, - forestTrees); -Engine.SetProgress(60); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tDirt,tHalfSnow], [tHalfSnow,tSnowLimited]], - [2], - avoidClasses( - clWater, 3, - clForest, 0, - clHill, 0, - clDirt, 5, - clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); - -g_Map.log("Creating shrubs"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tSecondary, - avoidClasses( - clWater, 3, - clForest, 0, - clHill, 0, - clDirt, 5, - clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); - -g_Map.log("Creating grass patches"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tSecondary, - avoidClasses( - clWater, 3, - clForest, 0, - clHill, 0, - clDirt, 5, - clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(65); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2, 5, 1, 3)] - ], - avoidClasses( - clWater, 3, - clForest, 1, - clPlayer, 20, - clRock, 18, - clHill, 1), - clRock); - -g_Map.log("Creating metal mines"); -createMines( - [ - [new SimpleObject(oMetalLarge, 1, 1, 0, 4)] - ], - avoidClasses( - clWater, 3, - clForest, 1, - clPlayer, 20, - clMetal, 18, - clRock, 5, - clHill, 1), - clMetal); -Engine.SetProgress(70); - -createDecoration( - [ +function* GenerateMap() +{ + setFogThickness(0.46); + setFogFactor(0.5); + + setPPEffect("hdr"); + setPPSaturation(0.48); + setPPContrast(0.53); + setPPBloom(0.12); + + const tPrimary = ["alpine_grass_rocky"]; + const tForestFloor = "alpine_grass"; + const tCliff = ["polar_cliff_a", "polar_cliff_b", "polar_cliff_snow"]; + const tSecondary = "alpine_grass"; + const tHalfSnow = ["polar_grass_snow", "ice_dirt"]; + const tSnowLimited = ["polar_snow_rocks", "polar_ice"]; + const tDirt = "ice_dirt"; + const tShore = "alpine_shore_rocks"; + const tWater = "polar_ice_b"; + const tHill = "polar_ice_cracked"; + + const oBush = "gaia/tree/bush_badlands"; + const oBush2 = "gaia/tree/bush_temperate"; + const oBerryBush = "gaia/fruit/berry_01"; + const oRabbit = "gaia/fauna_rabbit"; + const oMuskox = "gaia/fauna_muskox"; + const oDeer = "gaia/fauna_deer"; + const oWolf = "gaia/fauna_wolf"; + const oWhaleFin = "gaia/fauna_whale_fin"; + const oWhaleHumpback = "gaia/fauna_whale_humpback"; + const oFish = "gaia/fish/generic"; + const oStoneLarge = "gaia/rock/alpine_large"; + const oStoneSmall = "gaia/rock/alpine_small"; + const oMetalLarge = "gaia/ore/alpine_large"; + const oWoodTreasure = "gaia/treasure/wood"; + + const aRockLarge = "actor|geology/stone_granite_med.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + + const pForest = [tForestFloor + TERRAIN_SEPARATOR + oBush, tForestFloor + TERRAIN_SEPARATOR + oBush2, + tForestFloor]; + + const heightSeaGround = -5; + const heightLand = 2; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tPrimary, + "innerTerrain": tSecondary + }, + "StartingAnimal": { + "template": oRabbit + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Treasures": { + "types": [ + { + "template": oWoodTreasure, + "count": 10 + } + ] + }, + "Trees": { + "template": oBush, + "count": 20, + "maxDistGroup": 3 + } + // No decoratives + }); + yield 20; + + createHills( + [tPrimary, tCliff, tHill], + avoidClasses( + clPlayer, 35, + clForest, 20, + clHill, 50, + clWater, 2), + clHill, + scaleByMapSize(1, 240)); + + yield 30; + + g_Map.log("Creating lakes"); + createAreas( + new ChainPlacer( + 1, + Math.floor(scaleByMapSize(4, 8)), + Math.floor(scaleByMapSize(40, 180)), + Infinity), [ - new SimpleObject(aRockMedium, 1, 3, 0, 1) + new LayeredPainter([tShore, tWater], [1]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 5), + new TileClassPainter(clWater) ], + avoidClasses(clPlayer, 15), + scaleByMapSize(1, 20)); + + yield 45; + + createBumps(avoidClasses(clPlayer, 6, clWater, 2), scaleByMapSize(30, 300), 1, 8, 4, 0, 3); + + paintTerrainBasedOnHeight(4, 15, 0, tCliff); + paintTerrainBasedOnHeight(15, 100, 3, tSnowLimited); + + const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); + createForests( + [tSecondary, tForestFloor, tForestFloor, pForest, pForest], + avoidClasses( + clPlayer, 20, + clForest, 14, + clHill, 20, + clWater, 2), + clForest, + forestTrees); + yield 60; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tDirt,tHalfSnow], [tHalfSnow,tSnowLimited]], + [2], + avoidClasses( + clWater, 3, + clForest, 0, + clHill, 0, + clDirt, 5, + clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + + g_Map.log("Creating shrubs"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tSecondary, + avoidClasses( + clWater, 3, + clForest, 0, + clHill, 0, + clDirt, 5, + clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + + g_Map.log("Creating grass patches"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tSecondary, + avoidClasses( + clWater, 3, + clForest, 0, + clHill, 0, + clDirt, 5, + clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + yield 65; + + g_Map.log("Creating stone mines"); + createMines( [ - new SimpleObject(aRockLarge, 1, 2, 0, 1), - new SimpleObject(aRockMedium, 1, 3, 0, 1) - ] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - ], - avoidClasses( - clWater, 0, - clForest, 0, - clPlayer, 0, - clHill, 0)); -Engine.SetProgress(75); - -createFood( - [ - [new SimpleObject(oWolf, 3, 5, 0, 3)], - [new SimpleObject(oRabbit, 6, 8, 0, 6)], - [new SimpleObject(oDeer, 3, 4, 0, 3)], - [new SimpleObject(oMuskox, 3, 4, 0, 3)] - ], - [ - 3 * numPlayers, - 3 * numPlayers, - 3 * numPlayers, - 3 * numPlayers - ], - avoidClasses( - clFood, 20, - clHill, 5, - clWater, 5), - clFood); - -createFood( - [ - [new SimpleObject(oWhaleFin, 1, 1, 0, 3)], - [new SimpleObject(oWhaleHumpback, 1, 1, 0, 3)] - ], - [ - 3 * numPlayers, - 3 * numPlayers - ], - [ - avoidClasses(clFood, 20), - stayClasses(clWater, 6) - ], - clFood); - -createFood( - [ - [new SimpleObject(oBerryBush, 5, 7, 0, 4)] - ], - [ - randIntInclusive(1, 4) * numPlayers + 2 - ], - avoidClasses( - clWater, 3, - clForest, 0, - clPlayer, 20, - clHill, 1, - clFood, 10), - clFood); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 15 * numPlayers - ], - [ - avoidClasses(clFood, 20), - stayClasses(clWater, 6) - ], - clFood); - -Engine.SetProgress(85); - -createStragglerTrees( - [oBush, oBush2], - avoidClasses( - clWater, 5, - clForest, 3, - clHill, 1, - clPlayer, 12, - clMetal, 4, - clRock, 4), - clForest, - stragglerTrees); - -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clWater, 4, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setSkySet("sunset 1"); -setSunRotation(randomAngle()); -setSunColor(0.8, 0.7, 0.6); -setAmbientColor(0.6, 0.5, 0.6); -setSunElevation(Math.PI * randFloat(1/12, 1/7)); -setWaterColor(0, 0.047, 0.286); -setWaterTint(0.462, 0.756, 0.866); -setWaterMurkiness(0.92); -setWaterWaviness(1); -setWaterType("clap"); - -g_Map.ExportMap(); + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4) + ], + [new SimpleObject(oStoneSmall, 2, 5, 1, 3)] + ], + avoidClasses( + clWater, 3, + clForest, 1, + clPlayer, 20, + clRock, 18, + clHill, 1), + clRock); + + g_Map.log("Creating metal mines"); + createMines( + [ + [new SimpleObject(oMetalLarge, 1, 1, 0, 4)] + ], + avoidClasses( + clWater, 3, + clForest, 1, + clPlayer, 20, + clMetal, 18, + clRock, 5, + clHill, 1), + clMetal); + yield 70; + + createDecoration( + [ + [ + new SimpleObject(aRockMedium, 1, 3, 0, 1) + ], + [ + new SimpleObject(aRockLarge, 1, 2, 0, 1), + new SimpleObject(aRockMedium, 1, 3, 0, 1) + ] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + ], + avoidClasses( + clWater, 0, + clForest, 0, + clPlayer, 0, + clHill, 0)); + yield 75; + + createFood( + [ + [new SimpleObject(oWolf, 3, 5, 0, 3)], + [new SimpleObject(oRabbit, 6, 8, 0, 6)], + [new SimpleObject(oDeer, 3, 4, 0, 3)], + [new SimpleObject(oMuskox, 3, 4, 0, 3)] + ], + [ + 3 * numPlayers, + 3 * numPlayers, + 3 * numPlayers, + 3 * numPlayers + ], + avoidClasses( + clFood, 20, + clHill, 5, + clWater, 5), + clFood); + + createFood( + [ + [new SimpleObject(oWhaleFin, 1, 1, 0, 3)], + [new SimpleObject(oWhaleHumpback, 1, 1, 0, 3)] + ], + [ + 3 * numPlayers, + 3 * numPlayers + ], + [ + avoidClasses(clFood, 20), + stayClasses(clWater, 6) + ], + clFood); + + createFood( + [ + [new SimpleObject(oBerryBush, 5, 7, 0, 4)] + ], + [ + randIntInclusive(1, 4) * numPlayers + 2 + ], + avoidClasses( + clWater, 3, + clForest, 0, + clPlayer, 20, + clHill, 1, + clFood, 10), + clFood); + + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 15 * numPlayers + ], + [ + avoidClasses(clFood, 20), + stayClasses(clWater, 6) + ], + clFood); + + yield 85; + + createStragglerTrees( + [oBush, oBush2], + avoidClasses( + clWater, 5, + clForest, 3, + clHill, 1, + clPlayer, 12, + clMetal, 4, + clRock, 4), + clForest, + stragglerTrees); + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clWater, 4, clMetal, 4, clRock, 4, clHill, 4, + clFood, 2)); + + setSkySet("sunset 1"); + setSunRotation(randomAngle()); + setSunColor(0.8, 0.7, 0.6); + setAmbientColor(0.6, 0.5, 0.6); + setSunElevation(Math.PI * randFloat(1/12, 1/7)); + setWaterColor(0, 0.047, 0.286); + setWaterTint(0.462, 0.756, 0.866); + setWaterMurkiness(0.92); + setWaterWaviness(1); + setWaterType("clap"); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/ardennes_forest.js =================================================================== --- binaries/data/mods/public/maps/random/ardennes_forest.js +++ binaries/data/mods/public/maps/random/ardennes_forest.js @@ -2,461 +2,471 @@ Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); -setBiome("generic/temperate"); - -const tPrimary = ["steppe_grass_03", "steppe_grass_03", "alpine_cliff_c", "temperate_grass_mud_01"]; -const tGrass = ["steppe_grass_04", "steppe_grass_04", "aegean_grass_dirt_03"]; -const tPineForestFloor = "steppe_grass_03"; -const tForestFloor = [tPineForestFloor, tPineForestFloor, "temperate_grass_mud_01"]; -const tCliff = ["alpine_cliff_c", "alpine_cliff_c", "temperate_cliff_01"]; -const tCity = ["new_alpine_citytile", "new_alpine_grass_dirt_a"]; -const tGrassPatch = ["alpine_grass_d"]; - -const oBoar = "gaia/fauna_boar"; -const oDeer = "gaia/fauna_deer"; -const oBear = "gaia/fauna_bear_brown"; -const oPig = "gaia/fauna_pig"; -const oBerryBush = "gaia/fruit/berry_01"; -const oMetalSmall = "gaia/ore/alpine_small"; -const oMetalLarge = "gaia/ore/temperate_large"; -const oStoneSmall = "gaia/rock/alpine_small"; -const oStoneLarge = "gaia/rock/temperate_large"; - -const oOak = "gaia/tree/oak"; -const oOakLarge = "gaia/tree/oak_large"; -const oPine = "gaia/tree/pine"; -const oAleppoPine = "gaia/tree/fir"; - -const aTreeA = "actor|flora/trees/oak.xml"; -const aTreeB = "actor|flora/trees/oak_large.xml"; -const aTreeC = "actor|flora/trees/pine.xml"; -const aTreeD = "actor|flora/trees/fir_tree.xml"; - -const aTrees = [aTreeA, aTreeB, aTreeC, aTreeD]; - -const aGrassLarge = "actor|props/flora/grass_soft_large.xml"; -const aWoodLarge = "actor|props/special/eyecandy/wood_pile_1_b.xml"; -const aWoodA = "actor|props/special/eyecandy/wood_sm_pile_a.xml"; -const aWoodB = "actor|props/special/eyecandy/wood_sm_pile_b.xml"; -const aBarrel = "actor|props/special/eyecandy/barrel_a.xml"; -const aWheel = "actor|props/special/eyecandy/wheel_laying.xml"; -const aCeltHomestead = "actor|structures/celts/homestead.xml"; -const aCeltHouse = "actor|structures/celts/house.xml"; -const aCeltLongHouse = "actor|structures/celts/longhouse.xml"; - -const pForest = [ - tPineForestFloor+TERRAIN_SEPARATOR+oOak, tForestFloor, - tPineForestFloor+TERRAIN_SEPARATOR+oPine, tForestFloor, - tPineForestFloor+TERRAIN_SEPARATOR+oAleppoPine, tForestFloor, - tForestFloor - ]; - -const heightRavineValley = 2; -const heightLand = 30; -const heightRavineHill = 40; -const heightHill = 50; -const heightOffsetRavine = 10; - -const g_Map = new RandomMap(heightHill, tPrimary); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clForestJoin = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clHillDeco = g_Map.createTileClass(); -const clExplorable = g_Map.createTileClass(); - -g_Map.log("Creating the central dip"); -createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.44)), 0.94, 0.05, 0.1, mapCenter), - [ - new LayeredPainter([tCliff, tGrass], [3]), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 3) - ]); -Engine.SetProgress(5); - -g_Map.log("Finding hills"); -const noise0 = new Noise2D(20); -for (let ix = 0; ix < mapSize; ix++) - for (let iz = 0; iz < mapSize; iz++) - { - const position = new Vector2D(ix, iz); - const h = g_Map.getHeight(position); - if (h > heightRavineHill) +function* GenerateMap() +{ + setBiome("generic/temperate"); + + const tPrimary = ["steppe_grass_03", "steppe_grass_03", "alpine_cliff_c", "temperate_grass_mud_01"]; + const tGrass = ["steppe_grass_04", "steppe_grass_04", "aegean_grass_dirt_03"]; + const tPineForestFloor = "steppe_grass_03"; + const tForestFloor = [tPineForestFloor, tPineForestFloor, "temperate_grass_mud_01"]; + const tCliff = ["alpine_cliff_c", "alpine_cliff_c", "temperate_cliff_01"]; + const tCity = ["new_alpine_citytile", "new_alpine_grass_dirt_a"]; + const tGrassPatch = ["alpine_grass_d"]; + + const oBoar = "gaia/fauna_boar"; + const oDeer = "gaia/fauna_deer"; + const oBear = "gaia/fauna_bear_brown"; + const oPig = "gaia/fauna_pig"; + const oBerryBush = "gaia/fruit/berry_01"; + const oMetalSmall = "gaia/ore/alpine_small"; + const oMetalLarge = "gaia/ore/temperate_large"; + const oStoneSmall = "gaia/rock/alpine_small"; + const oStoneLarge = "gaia/rock/temperate_large"; + + const oOak = "gaia/tree/oak"; + const oOakLarge = "gaia/tree/oak_large"; + const oPine = "gaia/tree/pine"; + const oAleppoPine = "gaia/tree/fir"; + + const aTreeA = "actor|flora/trees/oak.xml"; + const aTreeB = "actor|flora/trees/oak_large.xml"; + const aTreeC = "actor|flora/trees/pine.xml"; + const aTreeD = "actor|flora/trees/fir_tree.xml"; + + const aTrees = [aTreeA, aTreeB, aTreeC, aTreeD]; + + const aGrassLarge = "actor|props/flora/grass_soft_large.xml"; + const aWoodLarge = "actor|props/special/eyecandy/wood_pile_1_b.xml"; + const aWoodA = "actor|props/special/eyecandy/wood_sm_pile_a.xml"; + const aWoodB = "actor|props/special/eyecandy/wood_sm_pile_b.xml"; + const aBarrel = "actor|props/special/eyecandy/barrel_a.xml"; + const aWheel = "actor|props/special/eyecandy/wheel_laying.xml"; + const aCeltHomestead = "actor|structures/celts/homestead.xml"; + const aCeltHouse = "actor|structures/celts/house.xml"; + const aCeltLongHouse = "actor|structures/celts/longhouse.xml"; + + const pForest = [ + tPineForestFloor+TERRAIN_SEPARATOR+oOak, tForestFloor, + tPineForestFloor+TERRAIN_SEPARATOR+oPine, tForestFloor, + tPineForestFloor+TERRAIN_SEPARATOR+oAleppoPine, tForestFloor, + tForestFloor + ]; + + const heightRavineValley = 2; + const heightLand = 30; + const heightRavineHill = 40; + const heightHill = 50; + const heightOffsetRavine = 10; + + global.g_Map = new RandomMap(heightHill, tPrimary); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clForestJoin = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clHillDeco = g_Map.createTileClass(); + const clExplorable = g_Map.createTileClass(); + + g_Map.log("Creating the central dip"); + createArea( + new ClumpPlacer(diskArea(fractionToTiles(0.44)), 0.94, 0.05, 0.1, mapCenter), + [ + new LayeredPainter([tCliff, tGrass], [3]), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 3) + ]); + yield 5; + + g_Map.log("Finding hills"); + const noise0 = new Noise2D(20); + for (let ix = 0; ix < mapSize; ix++) + for (let iz = 0; iz < mapSize; iz++) { - clHill.add(position); - - // Add hill noise - const x = ix / (mapSize + 1.0); - const z = iz / (mapSize + 1.0); - const n = (noise0.get(x, z) - 0.5) * heightRavineHill; - g_Map.setHeight(position, h + n); + const position = new Vector2D(ix, iz); + const h = g_Map.getHeight(position); + if (h > heightRavineHill) + { + clHill.add(position); + + // Add hill noise + const x = ix / (mapSize + 1.0); + const z = iz / (mapSize + 1.0); + const n = (noise0.get(x, z) - 0.5) * heightRavineHill; + g_Map.setHeight(position, h + n); + } } - } -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.3)); + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.3)); -function distanceToPlayers(x, z) -{ - let r = 10000; - for (let i = 0; i < numPlayers; i++) + function distanceToPlayers(x, z) { - let dx = x - tilesToFraction(playerPosition[i].x); - let dz = z - tilesToFraction(playerPosition[i].y); - r = Math.min(r, Math.square(dx) + Math.square(dz)); + let r = 10000; + for (let i = 0; i < numPlayers; i++) + { + let dx = x - tilesToFraction(playerPosition[i].x); + let dz = z - tilesToFraction(playerPosition[i].y); + r = Math.min(r, Math.square(dx) + Math.square(dz)); + } + return Math.sqrt(r); } - return Math.sqrt(r); -} - -function playerNearness(x, z) -{ - let d = fractionToTiles(distanceToPlayers(x,z)); - if (d < 13) - return 0; + function playerNearness(x, z) + { + let d = fractionToTiles(distanceToPlayers(x,z)); - if (d < 19) - return (d-13)/(19-13); + if (d < 13) + return 0; - return 1; -} + if (d < 19) + return (d-13)/(19-13); -Engine.SetProgress(10); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "BaseResourceClass": clBaseResource, - // Playerclass marked below - "CityPatch": { - "outerTerrain": tCity, - "innerTerrain": tCity, - "radius": scaleByMapSize(5, 6), - "smoothness": 0.05 - }, - "StartingAnimal": { - "template": oPig - }, - "Berries": { - "template": oBerryBush, - "minCount": 3, - "maxCount": 3 - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ], - "distance": 16 - }, - "Trees": { - "template": oOak, - "count": 2 + return 1; } - // No decoratives -}); -g_Map.log("Marking player territory"); -for (let i = 0; i < numPlayers; ++i) - createArea( - new ClumpPlacer(250, 0.95, 0.3, 0.1, playerPosition[i]), - new TileClassPainter(clPlayer)); + yield 10; + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "BaseResourceClass": clBaseResource, + // Playerclass marked below + "CityPatch": { + "outerTerrain": tCity, + "innerTerrain": tCity, + "radius": scaleByMapSize(5, 6), + "smoothness": 0.05 + }, + "StartingAnimal": { + "template": oPig + }, + "Berries": { + "template": oBerryBush, + "minCount": 3, + "maxCount": 3 + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ], + "distance": 16 + }, + "Trees": { + "template": oOak, + "count": 2 + } + // No decoratives + }); -Engine.SetProgress(30); + g_Map.log("Marking player territory"); + for (let i = 0; i < numPlayers; ++i) + createArea( + new ClumpPlacer(250, 0.95, 0.3, 0.1, playerPosition[i]), + new TileClassPainter(clPlayer)); -g_Map.log("Creating hills"); -for (const size of [scaleByMapSize(50, 800), scaleByMapSize(50, 400), scaleByMapSize(10, 30), scaleByMapSize(10, 30)]) -{ - const mountains = createAreas( - new ClumpPlacer(size, 0.1, 0.2, 0.1), - [ - new LayeredPainter([tCliff, [tForestFloor, tForestFloor, tCliff]], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, size < 50 ? 2 : 4), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 8, clBaseResource, 2, clHill, 5), - scaleByMapSize(1, 4)); + yield 30; - if (size > 100 && mountains.length) - createAreasInAreas( - new ClumpPlacer(size * 0.3, 0.94, 0.05, 0.1), + g_Map.log("Creating hills"); + for (const size of [scaleByMapSize(50, 800), scaleByMapSize(50, 400), scaleByMapSize(10, 30), + scaleByMapSize(10, 30)]) + { + const mountains = createAreas( + new ClumpPlacer(size, 0.1, 0.2, 0.1), [ - new LayeredPainter([tCliff, tForestFloor], [2]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetRavine, 3) + new LayeredPainter([tCliff, [tForestFloor, tForestFloor, tCliff]], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, size < 50 ? 2 : 4), + new TileClassPainter(clHill) ], - stayClasses(clHill, 4), - mountains.length * 2, - 20, - mountains); - - const ravine = createAreas( - new ClumpPlacer(size, 0.1, 0.2, 0.1), - [ - new LayeredPainter([tCliff, tForestFloor], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightRavineValley, 2), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 6, clBaseResource, 2, clHill, 5), - scaleByMapSize(1, 3)); + avoidClasses(clPlayer, 8, clBaseResource, 2, clHill, 5), + scaleByMapSize(1, 4)); - if (size > 150 && ravine.length) - { - g_Map.log("Placing huts in ravines"); - createObjectGroupsByAreasDeprecated( - new RandomGroup( + if (size > 100 && mountains.length) + createAreasInAreas( + new ClumpPlacer(size * 0.3, 0.94, 0.05, 0.1), [ - new SimpleObject(aCeltHouse, 0, 1, 4, 5), - new SimpleObject(aCeltLongHouse, 1, 1, 4, 5) + new LayeredPainter([tCliff, tForestFloor], [2]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetRavine, 3) ], - true, - clHillDeco), - 0, - [avoidClasses(clHillDeco, 3), stayClasses(clHill, 3)], - ravine.length * 5, 20, - ravine); - - createObjectGroupsByAreasDeprecated( - new RandomGroup([new SimpleObject(aCeltHomestead, 1, 1, 1, 1)], true, clHillDeco), - 0, - [avoidClasses(clHillDeco, 5), stayClasses(clHill, 4)], - ravine.length * 2, 100, - ravine); - - // Place noise - createAreasInAreas( - new ClumpPlacer(size * 0.3, 0.94, 0.05, 0.1), - [ - new LayeredPainter([tCliff, tForestFloor], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightRavineValley, 2) - ], - [avoidClasses(clHillDeco, 2), stayClasses(clHill, 0)], - ravine.length * 2, - 20, - ravine); + stayClasses(clHill, 4), + mountains.length * 2, + 20, + mountains); - createAreasInAreas( - new ClumpPlacer(size * 0.1, 0.3, 0.05, 0.1), + const ravine = createAreas( + new ClumpPlacer(size, 0.1, 0.2, 0.1), [ new LayeredPainter([tCliff, tForestFloor], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightRavineHill, 2), + new SmoothElevationPainter(ELEVATION_SET, heightRavineValley, 2), new TileClassPainter(clHill) ], - [avoidClasses(clHillDeco, 2), borderClasses(clHill, 15, 1)], - ravine.length * 2, - 50, - ravine); - } -} + avoidClasses(clPlayer, 6, clBaseResource, 2, clHill, 5), + scaleByMapSize(1, 3)); -Engine.SetProgress(50); - -for (let ix = 0; ix < mapSize; ix++) - for (let iz = 0; iz < mapSize; iz++) - { - const position = new Vector2D(ix, iz); - const h = g_Map.getHeight(position); + if (size > 150 && ravine.length) + { + g_Map.log("Placing huts in ravines"); + createObjectGroupsByAreasDeprecated( + new RandomGroup( + [ + new SimpleObject(aCeltHouse, 0, 1, 4, 5), + new SimpleObject(aCeltLongHouse, 1, 1, 4, 5) + ], + true, + clHillDeco), + 0, + [avoidClasses(clHillDeco, 3), stayClasses(clHill, 3)], + ravine.length * 5, 20, + ravine); - if (h > 35 && randBool(0.1) || - h < 15 && randBool(0.05) && clHillDeco.countMembersInRadius(position, 1) == 0) - g_Map.placeEntityAnywhere( - pickRandom(aTrees), + createObjectGroupsByAreasDeprecated( + new RandomGroup([new SimpleObject(aCeltHomestead, 1, 1, 1, 1)], true, clHillDeco), 0, - randomPositionOnTile(position), - randomAngle()); + [avoidClasses(clHillDeco, 5), stayClasses(clHill, 4)], + ravine.length * 2, 100, + ravine); + + // Place noise + createAreasInAreas( + new ClumpPlacer(size * 0.3, 0.94, 0.05, 0.1), + [ + new LayeredPainter([tCliff, tForestFloor], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightRavineValley, 2) + ], + [avoidClasses(clHillDeco, 2), stayClasses(clHill, 0)], + ravine.length * 2, + 20, + ravine); + + createAreasInAreas( + new ClumpPlacer(size * 0.1, 0.3, 0.05, 0.1), + [ + new LayeredPainter([tCliff, tForestFloor], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightRavineHill, 2), + new TileClassPainter(clHill) + ], + [avoidClasses(clHillDeco, 2), borderClasses(clHill, 15, 1)], + ravine.length * 2, + 50, + ravine); + } } -const explorableArea = createArea( - new MapBoundsPlacer(), - undefined, - [ - new HeightConstraint(15, 45), - avoidClasses(clPlayer, 1) - ]); + yield 50; -new TileClassPainter(clExplorable).paint(explorableArea); + for (let ix = 0; ix < mapSize; ix++) + for (let iz = 0; iz < mapSize; iz++) + { + const position = new Vector2D(ix, iz); + const h = g_Map.getHeight(position); + + if (h > 35 && randBool(0.1) || + h < 15 && randBool(0.05) && clHillDeco.countMembersInRadius(position, 1) == 0) + g_Map.placeEntityAnywhere( + pickRandom(aTrees), + 0, + randomPositionOnTile(position), + randomAngle()); + } + + const explorableArea = createArea( + new MapBoundsPlacer(), + undefined, + [ + new HeightConstraint(15, 45), + avoidClasses(clPlayer, 1) + ]); -Engine.SetProgress(55); + new TileClassPainter(clExplorable).paint(explorableArea); -// Add some general noise - after placing height dependant trees -for (let ix = 0; ix < mapSize; ix++) -{ - const x = ix / (mapSize + 1.0); - for (let iz = 0; iz < mapSize; iz++) + yield 55; + + // Add some general noise - after placing height dependant trees + for (let ix = 0; ix < mapSize; ix++) { - const position = new Vector2D(ix, iz); - const z = iz / (mapSize + 1.0); - const h = g_Map.getHeight(position); - const pn = playerNearness(x,z); - const n = (noise0.get(x,z) - 0.5) * 10; - g_Map.setHeight(position, h + (n * pn)); + const x = ix / (mapSize + 1.0); + for (let iz = 0; iz < mapSize; iz++) + { + const position = new Vector2D(ix, iz); + const z = iz / (mapSize + 1.0); + const h = g_Map.getHeight(position); + const pn = playerNearness(x,z); + const n = (noise0.get(x,z) - 0.5) * 10; + g_Map.setHeight(position, h + (n * pn)); + } } -} -Engine.SetProgress(60); - -g_Map.log("Creating forests"); -var [forestTrees, stragglerTrees] = getTreeCounts(1300, 8000, 0.8); -var [forestTreesJoin, forestTrees] = getTreeCounts(forestTrees, forestTrees, 0.25); - -var num = forestTrees / scaleByMapSize(20, 70); -createAreasInAreas( - new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), - [ - new TerrainPainter(pForest), - new TileClassPainter(clForest) - ], - avoidClasses(clPlayer, 5, clBaseResource, 4, clForest, 5, clHill, 4), - num, - 100, - [explorableArea] -); - -var num = forestTreesJoin / (scaleByMapSize(4, 6) * numPlayers); -createAreasInAreas( - new ClumpPlacer(forestTreesJoin / num, 0.1, 0.1, Infinity), - [ - new TerrainPainter(pForest), - new TileClassPainter(clForest), - new TileClassPainter(clForestJoin) - ], - [avoidClasses(clPlayer, 5, clBaseResource, 4, clForestJoin, 5, clHill, 4), borderClasses(clForest, 1, 4)], - num, - 100, - [explorableArea] -); - -Engine.SetProgress(70); - -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - new TerrainPainter([tGrass, tGrassPatch]), - avoidClasses(clForest, 0, clHill, 2, clPlayer, 5), - scaleByMapSize(15, 45)); - -g_Map.log("Creating chopped forest patches"); -for (const size of [scaleByMapSize(20, 120)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - new TerrainPainter(tForestFloor), - avoidClasses(clForest, 1, clHill, 2, clPlayer, 5), - scaleByMapSize(4, 12)); - -Engine.SetProgress(75); - -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - [stayClasses(clExplorable, 1), avoidClasses(clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1)] -); - - -g_Map.log("Creating stone mines"); -createBalancedStoneMines( - oStoneSmall, - oStoneLarge, - clRock, - [stayClasses(clExplorable, 1), avoidClasses(clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1, clMetal, 10)] -); - -Engine.SetProgress(80); - -g_Map.log("Creating wildlife"); -let group = new SimpleGroup( - [new SimpleObject(oDeer, 5,7, 0,4)], - true, clFood -); -createObjectGroupsByAreasDeprecated(group, 0, - avoidClasses(clHill, 4, clForest, 0, clPlayer, 0, clBaseResource, 20), - 3 * numPlayers, 100, - [explorableArea] -); - -group = new SimpleGroup( - [new SimpleObject(oBoar, 2,3, 0,5)], - true, clFood -); -createObjectGroupsByAreasDeprecated(group, 0, - avoidClasses(clHill, 4, clForest, 0, clPlayer, 0, clBaseResource, 15), - numPlayers, 50, - [explorableArea] -); - -group = new SimpleGroup( - [new SimpleObject(oBear, 1,1, 0,4)], - false, clFood -); -createObjectGroupsByAreasDeprecated(group, 0, - avoidClasses(clHill, 4, clForest, 0, clPlayer, 20), - scaleByMapSize(3, 12), 200, - [explorableArea] -); - -Engine.SetProgress(85); - -g_Map.log("Creating berry bush"); -group = new SimpleGroup( - [new SimpleObject(oBerryBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 20, clHill, 4, clFood, 20), - randIntInclusive(3, 12) * numPlayers + 2, 50 -); - -g_Map.log("Creating decorative props"); -group = new SimpleGroup( - [ - new SimpleObject(aWoodA, 1,2, 0,1), - new SimpleObject(aWoodB, 1,3, 0,1), - new SimpleObject(aWheel, 0,2, 0,1), - new SimpleObject(aWoodLarge, 0,1, 0,1), - new SimpleObject(aBarrel, 0,2, 0,1) - ], - true -); -createObjectGroupsByAreasDeprecated( - group, 0, - avoidClasses(clForest, 0), - scaleByMapSize(5, 50), 50, - [explorableArea] -); - -Engine.SetProgress(90); - -g_Map.log("Creating straggler trees"); -const types = [oOak, oOakLarge, oPine, oAleppoPine]; -var num = Math.floor(stragglerTrees / types.length); -for (const type of types) + yield 60; + + g_Map.log("Creating forests"); + var [forestTrees, stragglerTrees] = getTreeCounts(1300, 8000, 0.8); + var [forestTreesJoin, forestTrees] = getTreeCounts(forestTrees, forestTrees, 0.25); + + var num = forestTrees / scaleByMapSize(20, 70); + createAreasInAreas( + new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), + [ + new TerrainPainter(pForest), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 5, clBaseResource, 4, clForest, 5, clHill, 4), + num, + 100, + [explorableArea] + ); + + var num = forestTreesJoin / (scaleByMapSize(4, 6) * numPlayers); + createAreasInAreas( + new ClumpPlacer(forestTreesJoin / num, 0.1, 0.1, Infinity), + [ + new TerrainPainter(pForest), + new TileClassPainter(clForest), + new TileClassPainter(clForestJoin) + ], + [ + avoidClasses(clPlayer, 5, clBaseResource, 4, clForestJoin, 5, clHill, 4), + borderClasses(clForest, 1, 4) + ], + num, + 100, + [explorableArea] + ); + + yield 70; + + g_Map.log("Creating grass patches"); + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + new TerrainPainter([tGrass, tGrassPatch]), + avoidClasses(clForest, 0, clHill, 2, clPlayer, 5), + scaleByMapSize(15, 45)); + + g_Map.log("Creating chopped forest patches"); + for (const size of [scaleByMapSize(20, 120)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + new TerrainPainter(tForestFloor), + avoidClasses(clForest, 1, clHill, 2, clPlayer, 5), + scaleByMapSize(4, 12)); + + yield 75; + + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + [stayClasses(clExplorable, 1), + avoidClasses(clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1)] + ); + + + g_Map.log("Creating stone mines"); + createBalancedStoneMines( + oStoneSmall, + oStoneLarge, + clRock, + [stayClasses(clExplorable, 1), + avoidClasses(clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1, clMetal, 10)] + ); + + yield 80; + + g_Map.log("Creating wildlife"); + let group = new SimpleGroup( + [new SimpleObject(oDeer, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsByAreasDeprecated(group, 0, + avoidClasses(clHill, 4, clForest, 0, clPlayer, 0, clBaseResource, 20), + 3 * numPlayers, 100, + [explorableArea] + ); + + group = new SimpleGroup( + [new SimpleObject(oBoar, 2,3, 0,5)], + true, clFood + ); + createObjectGroupsByAreasDeprecated(group, 0, + avoidClasses(clHill, 4, clForest, 0, clPlayer, 0, clBaseResource, 15), + numPlayers, 50, + [explorableArea] + ); + + group = new SimpleGroup( + [new SimpleObject(oBear, 1,1, 0,4)], + false, clFood + ); + createObjectGroupsByAreasDeprecated(group, 0, + avoidClasses(clHill, 4, clForest, 0, clPlayer, 20), + scaleByMapSize(3, 12), 200, + [explorableArea] + ); + + yield 85; + + g_Map.log("Creating berry bush"); + group = new SimpleGroup( + [new SimpleObject(oBerryBush, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 20, clHill, 4, clFood, 20), + randIntInclusive(3, 12) * numPlayers + 2, 50 + ); + + g_Map.log("Creating decorative props"); + group = new SimpleGroup( + [ + new SimpleObject(aWoodA, 1,2, 0,1), + new SimpleObject(aWoodB, 1,3, 0,1), + new SimpleObject(aWheel, 0,2, 0,1), + new SimpleObject(aWoodLarge, 0,1, 0,1), + new SimpleObject(aBarrel, 0,2, 0,1) + ], + true + ); createObjectGroupsByAreasDeprecated( - new SimpleGroup([new SimpleObject(type, 1, 1, 0, 3)], true, clForest), - 0, - avoidClasses(clForest, 4, clHill, 5, clPlayer, 10, clBaseResource, 2, clMetal, 5, clRock, 5), - num, 20, - [explorableArea]); - -Engine.SetProgress(95); - -g_Map.log("Creating grass tufts"); -group = new SimpleGroup( - [new SimpleObject(aGrassLarge, 1,2, 0,1, -Math.PI / 8, Math.PI / 8)] -); -createObjectGroupsByAreasDeprecated(group, 0, - avoidClasses(clHill, 2, clPlayer, 2), - scaleByMapSize(50, 300), 20, - [explorableArea] -); - -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -g_Map.ExportMap(); + group, 0, + avoidClasses(clForest, 0), + scaleByMapSize(5, 50), 50, + [explorableArea] + ); + + yield 90; + + g_Map.log("Creating straggler trees"); + const types = [oOak, oOakLarge, oPine, oAleppoPine]; + var num = Math.floor(stragglerTrees / types.length); + for (const type of types) + createObjectGroupsByAreasDeprecated( + new SimpleGroup([new SimpleObject(type, 1, 1, 0, 3)], true, clForest), + 0, + avoidClasses(clForest, 4, clHill, 5, clPlayer, 10, clBaseResource, 2, clMetal, 5, clRock, + 5), + num, 20, + [explorableArea]); + + yield 95; + + g_Map.log("Creating grass tufts"); + group = new SimpleGroup( + [new SimpleObject(aGrassLarge, 1,2, 0,1, -Math.PI / 8, Math.PI / 8)] + ); + createObjectGroupsByAreasDeprecated(group, 0, + avoidClasses(clHill, 2, clPlayer, 2), + scaleByMapSize(50, 300), 20, + [explorableArea] + ); + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/atlas_mountains.js =================================================================== --- binaries/data/mods/public/maps/random/atlas_mountains.js +++ binaries/data/mods/public/maps/random/atlas_mountains.js @@ -1,224 +1,230 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tPrimary = ["medit_rocks_grass", "medit_rocks_grass", "medit_rocks_grass", - "medit_rocks_grass", "medit_rocks_grass_shrubs", "medit_rocks_shrubs"]; -const tGrass = ["medit_rocks_grass_shrubs", "medit_rocks_shrubs"]; -const tForestFloor = "medit_grass_field_dry"; -const tCliff = "medit_cliff_italia"; -const tGrassDirt = "medit_rocks_grass"; -const tDirt = "medit_dirt"; -const tRoad = "medit_city_tile"; -const tRoadWild = "medit_city_tile"; -const tGrass2 = "medit_rocks_grass_shrubs"; -const tGrassPatch = "medit_grass_wild"; - -const oCarob = "gaia/tree/carob"; -const oAleppoPine = "gaia/tree/aleppo_pine"; -const oBerryBush = "gaia/fruit/berry_01"; -const oDeer = "gaia/fauna_deer"; -const oSheep = "gaia/fauna_sheep"; -const oStoneLarge = "gaia/rock/mediterranean_large"; -const oStoneSmall = "gaia/rock/mediterranean_small"; -const oMetalLarge = "gaia/ore/mediterranean_large"; -const oWoodTreasure = "gaia/treasure/wood"; -const oFoodTreasure = "gaia/treasure/food_bin"; - -const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; -const aGrassShort = "actor|props/flora/grass_soft_large.xml"; -const aRockLarge = "actor|geology/stone_granite_large.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aBushMedium = "actor|props/flora/bush_medit_me.xml"; -const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; -const aCarob = "actor|flora/trees/carob.xml"; -const aAleppoPine = "actor|flora/trees/aleppo_pine.xml"; - -const pForest1 = [tForestFloor + TERRAIN_SEPARATOR + oCarob, tForestFloor]; -const pForest2 = [tForestFloor + TERRAIN_SEPARATOR + oAleppoPine, tForestFloor]; - -const heightLand = 3; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clTreasure = g_Map.createTileClass(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oCarob, - "count": scaleByMapSize(2, 8) - }, - "Decoratives": { - "template": aGrassShort - } -}); -Engine.SetProgress(10); - -createBumps(avoidClasses(clPlayer, 9)); - -createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 8), clHill, scaleByMapSize(20, 120)); - -Engine.SetProgress(25); - -const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); -createForests( - [tGrass, tForestFloor, tForestFloor, pForest1, pForest2], - avoidClasses(clPlayer, 20, clForest, 14, clHill, 1), - clForest, - forestTrees); - -Engine.SetProgress(40); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [tGrassDirt,tDirt], - [2], - avoidClasses(clForest, 0, clHill, 0, clDirt, 3, clPlayer, 10), - scaleByMapSize(15, 45), - clDirt); - -g_Map.log("Creating grass patches"); -createLayeredPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - [tGrass2,tGrassPatch], - [1], - avoidClasses(clForest, 0, clHill, 0, clDirt, 3, clPlayer, 10), - scaleByMapSize(15, 45), - clDirt); - -Engine.SetProgress(50); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2,5, 1,3)] - ], - avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 2), - clRock); - -g_Map.log("Creating metal mines"); -createMines( - [ - [new SimpleObject(oMetalLarge, 1,1, 0,4)] - ], - avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 2), - clMetal -); - -Engine.SetProgress(60); - -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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13) - ], - avoidClasses(clForest, 0, clPlayer, 0, clHill, 0)); - -Engine.SetProgress(75); - -createFood( - [ - [new SimpleObject(oSheep, 5, 7, 0, 4)], - [new SimpleObject(oDeer, 2, 3, 0, 2)] - ], - [ - 3 * numPlayers, - 3 * numPlayers - ], - avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), - clFood); - -createFood( - [ - [new SimpleObject(oBerryBush, 5, 7, 0, 4)] - ], - [ - randIntInclusive(3, 12) * numPlayers + 2 - ], - avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - clFood); - -g_Map.log("Creating food treasures"); -let group = new SimpleGroup( - [new SimpleObject(oFoodTreasure, 2,3, 0,2)], - true, clTreasure -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 18, clHill, 1, clFood, 5), - 3 * numPlayers, 50 -); - -g_Map.log("Creating food treasures"); -group = new SimpleGroup( - [new SimpleObject(oWoodTreasure, 2,3, 0,2)], - true, clTreasure -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 18, clHill, 1), - 3 * numPlayers, 50 -); - -Engine.SetProgress(80); - -createStragglerTrees( - [oCarob, oAleppoPine], - avoidClasses(clForest, 1, clHill, 1, clPlayer, 10, clMetal, 6, clRock, 6, clTreasure, 4), - clForest, - stragglerTrees); - -createStragglerTrees( - [aCarob, aAleppoPine], - stayClasses(clHill, 2), - clForest, - stragglerTrees / 5); - -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setFogFactor(0.2); -setFogThickness(0.14); - -setPPEffect("hdr"); -setPPContrast(0.45); -setPPSaturation(0.56); -setPPBloom(0.1); - -g_Map.ExportMap(); +function* GenerateMap() +{ + const tPrimary = ["medit_rocks_grass", "medit_rocks_grass", "medit_rocks_grass", + "medit_rocks_grass", "medit_rocks_grass_shrubs", "medit_rocks_shrubs"]; + const tGrass = ["medit_rocks_grass_shrubs", "medit_rocks_shrubs"]; + const tForestFloor = "medit_grass_field_dry"; + const tCliff = "medit_cliff_italia"; + const tGrassDirt = "medit_rocks_grass"; + const tDirt = "medit_dirt"; + const tRoad = "medit_city_tile"; + const tRoadWild = "medit_city_tile"; + const tGrass2 = "medit_rocks_grass_shrubs"; + const tGrassPatch = "medit_grass_wild"; + + const oCarob = "gaia/tree/carob"; + const oAleppoPine = "gaia/tree/aleppo_pine"; + const oBerryBush = "gaia/fruit/berry_01"; + const oDeer = "gaia/fauna_deer"; + const oSheep = "gaia/fauna_sheep"; + const oStoneLarge = "gaia/rock/mediterranean_large"; + const oStoneSmall = "gaia/rock/mediterranean_small"; + const oMetalLarge = "gaia/ore/mediterranean_large"; + const oWoodTreasure = "gaia/treasure/wood"; + const oFoodTreasure = "gaia/treasure/food_bin"; + + const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; + const aGrassShort = "actor|props/flora/grass_soft_large.xml"; + const aRockLarge = "actor|geology/stone_granite_large.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aBushMedium = "actor|props/flora/bush_medit_me.xml"; + const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; + const aCarob = "actor|flora/trees/carob.xml"; + const aAleppoPine = "actor|flora/trees/aleppo_pine.xml"; + + const pForest1 = [tForestFloor + TERRAIN_SEPARATOR + oCarob, tForestFloor]; + const pForest2 = [tForestFloor + TERRAIN_SEPARATOR + oAleppoPine, tForestFloor]; + + const heightLand = 3; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clTreasure = g_Map.createTileClass(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oCarob, + "count": scaleByMapSize(2, 8) + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 10; + + createBumps(avoidClasses(clPlayer, 9)); + + createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 8), clHill, scaleByMapSize(20, 120)); + + yield 25; + + const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); + createForests( + [tGrass, tForestFloor, tForestFloor, pForest1, pForest2], + avoidClasses(clPlayer, 20, clForest, 14, clHill, 1), + clForest, + forestTrees); + + yield 40; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [tGrassDirt,tDirt], + [2], + avoidClasses(clForest, 0, clHill, 0, clDirt, 3, clPlayer, 10), + scaleByMapSize(15, 45), + clDirt); + + g_Map.log("Creating grass patches"); + createLayeredPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + [tGrass2,tGrassPatch], + [1], + avoidClasses(clForest, 0, clHill, 0, clDirt, 3, clPlayer, 10), + scaleByMapSize(15, 45), + clDirt); + + yield 50; + + g_Map.log("Creating stone mines"); + createMines( + [ + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4) + ], + [new SimpleObject(oStoneSmall, 2,5, 1,3)] + ], + avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 2), + clRock); + + g_Map.log("Creating metal mines"); + createMines( + [ + [new SimpleObject(oMetalLarge, 1,1, 0,4)] + ], + avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 2), + clMetal + ); + + yield 60; + + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13) + ], + avoidClasses(clForest, 0, clPlayer, 0, clHill, 0)); + + yield 75; + + createFood( + [ + [new SimpleObject(oSheep, 5, 7, 0, 4)], + [new SimpleObject(oDeer, 2, 3, 0, 2)] + ], + [ + 3 * numPlayers, + 3 * numPlayers + ], + avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), + clFood); + + createFood( + [ + [new SimpleObject(oBerryBush, 5, 7, 0, 4)] + ], + [ + randIntInclusive(3, 12) * numPlayers + 2 + ], + avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), + clFood); + + g_Map.log("Creating food treasures"); + let group = new SimpleGroup( + [new SimpleObject(oFoodTreasure, 2,3, 0,2)], + true, clTreasure + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 18, clHill, 1, clFood, 5), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating food treasures"); + group = new SimpleGroup( + [new SimpleObject(oWoodTreasure, 2,3, 0,2)], + true, clTreasure + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 18, clHill, 1), + 3 * numPlayers, 50 + ); + + yield 80; + + createStragglerTrees( + [oCarob, oAleppoPine], + avoidClasses(clForest, 1, clHill, 1, clPlayer, 10, clMetal, 6, clRock, 6, clTreasure, 4), + clForest, + stragglerTrees); + + createStragglerTrees( + [aCarob, aAleppoPine], + stayClasses(clHill, 2), + clForest, + stragglerTrees / 5); + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + + setFogFactor(0.2); + setFogThickness(0.14); + + setPPEffect("hdr"); + setPPContrast(0.45); + setPPSaturation(0.56); + setPPBloom(0.1); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/bahrain.js =================================================================== --- binaries/data/mods/public/maps/random/bahrain.js +++ binaries/data/mods/public/maps/random/bahrain.js @@ -21,459 +21,468 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setBiome("generic/sahara"); -setLandBiome(); - -function setLandBiome() +function* GenerateMap() { - g_Terrains.mainTerrain = new Array(3).fill("desert_dirt_rough_2").concat(["desert_dirt_rocks_3", "desert_sand_stones"]); - g_Terrains.forestFloor1 = "grass_dead"; - g_Terrains.forestFloor2 = "desert_dirt_persia_1"; - g_Terrains.tier1Terrain = "desert_sand_dunes_stones"; - g_Terrains.tier2Terrain = "desert_sand_scrub"; - g_Terrains.tier3Terrain = "desert_plants_b"; - g_Terrains.tier4Terrain = "medit_dirt_dry"; -} - -function setIslandBiome() -{ - g_Terrains.mainTerrain = "sand"; - g_Terrains.forestFloor1 = "desert_wave"; - g_Terrains.forestFloor2 = "desert_sahara"; - g_Terrains.tier1Terrain = "sand_scrub_25"; - g_Terrains.tier2Terrain = "sand_scrub_75"; - g_Terrains.tier3Terrain = "sand_scrub_50"; - g_Terrains.tier4Terrain = "sand"; -} + setBiome("generic/sahara"); + setLandBiome(); -g_Terrains.roadWild = "desert_city_tile_pers_dirt"; -g_Terrains.road = "desert_city_tile_pers"; - -g_Gaia.mainHuntableAnimal = "gaia/fauna_camel"; -g_Gaia.secondaryHuntableAnimal = "gaia/fauna_gazelle"; -g_Gaia.fish = "gaia/fish/generic"; -g_Gaia.tree1 = "gaia/tree/cretan_date_palm_tall"; -g_Gaia.tree2 = "gaia/tree/cretan_date_palm_short"; -g_Gaia.tree3 = "gaia/tree/cretan_date_palm_patch"; -g_Gaia.tree4 = "gaia/tree/cretan_date_palm_tall"; -g_Gaia.tree5 = "gaia/tree/cretan_date_palm_short"; -g_Gaia.fruitBush = "gaia/fruit/grapes"; -g_Gaia.woodTreasure = "gaia/treasure/wood"; -g_Gaia.foodTreasure = "gaia/treasure/food_bin"; -g_Gaia.shipWreck = "gaia/treasure/shipwreck_sail_boat_cut"; - -g_Decoratives.grass = "actor|props/flora/grass_field_parched_short.xml"; -g_Decoratives.grassShort = "actor|props/flora/grass_field_parched_short.xml"; -g_Decoratives.rockLarge = "actor|geology/stone_savanna_med.xml"; -g_Decoratives.rockMedium = "actor|geology/stone_granite_greek_small.xml"; -g_Decoratives.bushMedium = "actor|props/flora/bush_desert_dry_a.xml"; -g_Decoratives.bushSmall = "actor|props/flora/bush_medit_la_dry"; - -const heightScale = num => num * g_MapSettings.Size / 320; - -const heightSeaGround = heightScale(-6); -const heightWaterLevel = heightScale(0); -const heightShoreline = heightScale(0.5); - -const g_Map = new RandomMap(0, g_Terrains.mainTerrain); -const mapBounds = g_Map.getBounds(); -const mapCenter = g_Map.getCenter(); -const numPlayers = getNumPlayers(); - -g_Map.LoadHeightmapImage("bahrain.png", 0, 15); -Engine.SetProgress(15); - -initTileClasses(["island", "shoreline"]); - -g_Map.log("Lowering sea ground"); -createArea( - new MapBoundsPlacer(), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 2), - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(20); - -g_Map.log("Smoothing heightmap"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, scaleByMapSize(0.1, 0.5), 1)); -Engine.SetProgress(25); - -g_Map.log("Marking water"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.water), - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(30); - -g_Map.log("Marking land"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land), - avoidClasses(g_TileClasses.water, 0)); -Engine.SetProgress(35); - -g_Map.log("Marking island"); -const areaIsland = createArea( - new RectPlacer(new Vector2D(fractionToTiles(0.4), mapBounds.top), new Vector2D(fractionToTiles(0.6), mapCenter.y), Infinity), - new TileClassPainter(g_TileClasses.island), - avoidClasses(g_TileClasses.water, 0)); -Engine.SetProgress(37); - -g_Map.log("Painting shoreline"); -createArea( - new MapBoundsPlacer(), - [ - new TerrainPainter(g_Terrains.water), - new TileClassPainter(g_TileClasses.shoreline) - ], - new HeightConstraint(-Infinity, heightShoreline)); -Engine.SetProgress(40); - -g_Map.log("Painting cliffs"); -createArea( - new MapBoundsPlacer(), - [ - new TerrainPainter(g_Terrains.cliff), - new TileClassPainter(g_TileClasses.mountain), - ], - [ - avoidClasses(g_TileClasses.water, 2), - new SlopeConstraint(2, Infinity) - ]); -Engine.SetProgress(45); - -if (!isNomad()) -{ - g_Map.log("Placing players"); - const [playerIDs, playerPosition] = createBases( - ...playerPlacementRandom( - sortAllPlayers(), - [ - avoidClasses(g_TileClasses.island, 5), - stayClasses(g_TileClasses.land, defaultPlayerBaseRadius() / 2) - ]), - "towers"); - - g_Map.log("Flatten the initial CC area"); - for (const position of playerPosition) - createArea( - new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, position), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); -} - -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3, - g_TileClasses.island, 2 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] - }, + function setLandBiome() { - "func": addDecoration, - "avoid": [ - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3, - g_TileClasses.island, 2 - ], - "sizes": ["small"], - "mixes": ["same"], - "amounts": ["many"] + g_Terrains.mainTerrain = new Array(3).fill("desert_dirt_rough_2").concat(["desert_dirt_rocks_3", + "desert_sand_stones"]); + g_Terrains.forestFloor1 = "grass_dead"; + g_Terrains.forestFloor2 = "desert_dirt_persia_1"; + g_Terrains.tier1Terrain = "desert_sand_dunes_stones"; + g_Terrains.tier2Terrain = "desert_sand_scrub"; + g_Terrains.tier3Terrain = "desert_plants_b"; + g_Terrains.tier4Terrain = "medit_dirt_dry"; } -]); -addElements(shuffleArray([ - { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 30, - g_TileClasses.water, 3, - g_TileClasses.island, 2 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal"] - }, + function setIslandBiome() { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.player, 30, - g_TileClasses.rock, 30, - g_TileClasses.metal, 20, - g_TileClasses.water, 3, - g_TileClasses.island, 2 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal"] + g_Terrains.mainTerrain = "sand"; + g_Terrains.forestFloor1 = "desert_wave"; + g_Terrains.forestFloor2 = "desert_sahara"; + g_Terrains.tier1Terrain = "sand_scrub_25"; + g_Terrains.tier2Terrain = "sand_scrub_75"; + g_Terrains.tier3Terrain = "sand_scrub_50"; + g_Terrains.tier4Terrain = "sand"; } -])); -addElements([ - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 35, - g_TileClasses.metal, 3, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.water, 2, - g_TileClasses.island, 2 - ], - "sizes": ["big"], - "mixes": ["similar"], - "amounts": ["few"] - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 18, - g_TileClasses.metal, 3, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.water, 2, - g_TileClasses.island, 2 + g_Terrains.roadWild = "desert_city_tile_pers_dirt"; + g_Terrains.road = "desert_city_tile_pers"; + + g_Gaia.mainHuntableAnimal = "gaia/fauna_camel"; + g_Gaia.secondaryHuntableAnimal = "gaia/fauna_gazelle"; + g_Gaia.fish = "gaia/fish/generic"; + g_Gaia.tree1 = "gaia/tree/cretan_date_palm_tall"; + g_Gaia.tree2 = "gaia/tree/cretan_date_palm_short"; + g_Gaia.tree3 = "gaia/tree/cretan_date_palm_patch"; + g_Gaia.tree4 = "gaia/tree/cretan_date_palm_tall"; + g_Gaia.tree5 = "gaia/tree/cretan_date_palm_short"; + g_Gaia.fruitBush = "gaia/fruit/grapes"; + g_Gaia.woodTreasure = "gaia/treasure/wood"; + g_Gaia.foodTreasure = "gaia/treasure/food_bin"; + g_Gaia.shipWreck = "gaia/treasure/shipwreck_sail_boat_cut"; + + g_Decoratives.grass = "actor|props/flora/grass_field_parched_short.xml"; + g_Decoratives.grassShort = "actor|props/flora/grass_field_parched_short.xml"; + g_Decoratives.rockLarge = "actor|geology/stone_savanna_med.xml"; + g_Decoratives.rockMedium = "actor|geology/stone_granite_greek_small.xml"; + g_Decoratives.bushMedium = "actor|props/flora/bush_desert_dry_a.xml"; + g_Decoratives.bushSmall = "actor|props/flora/bush_medit_la_dry"; + + const heightScale = num => num * g_MapSettings.Size / 320; + + const heightSeaGround = heightScale(-6); + const heightWaterLevel = heightScale(0); + const heightShoreline = heightScale(0.5); + + global.g_Map = new RandomMap(0, g_Terrains.mainTerrain); + const mapBounds = g_Map.getBounds(); + const mapCenter = g_Map.getCenter(); + const numPlayers = getNumPlayers(); + + g_Map.LoadHeightmapImage("bahrain.png", 0, 15); + yield 15; + + initTileClasses(["island", "shoreline"]); + + g_Map.log("Lowering sea ground"); + createArea( + new MapBoundsPlacer(), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 2), + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 20; + + g_Map.log("Smoothing heightmap"); + createArea( + new MapBoundsPlacer(), + new SmoothingPainter(1, scaleByMapSize(0.1, 0.5), 1)); + yield 25; + + g_Map.log("Marking water"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.water), + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 30; + + g_Map.log("Marking land"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land), + avoidClasses(g_TileClasses.water, 0)); + yield 35; + + g_Map.log("Marking island"); + const areaIsland = createArea( + new RectPlacer(new Vector2D(fractionToTiles(0.4), mapBounds.top), + new Vector2D(fractionToTiles(0.6), mapCenter.y), Infinity), + new TileClassPainter(g_TileClasses.island), + avoidClasses(g_TileClasses.water, 0)); + yield 37; + + g_Map.log("Painting shoreline"); + createArea( + new MapBoundsPlacer(), + [ + new TerrainPainter(g_Terrains.water), + new TileClassPainter(g_TileClasses.shoreline) ], - "sizes": ["normal"], - "mixes": ["similar"], - "amounts": ["many"] - }, -]); + new HeightConstraint(-Infinity, heightShoreline)); + yield 40; -addElements(shuffleArray([ - { - "func": addBerries, - "avoid": [ - g_TileClasses.berries, 30, - g_TileClasses.forest, 5, - g_TileClasses.metal, 10, - g_TileClasses.player, 20, - g_TileClasses.rock, 10, - g_TileClasses.water, 3, - g_TileClasses.island, 2 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["few"] - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.water, 3, - g_TileClasses.island, 2 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["tons"] - }, - { - "func": addFish, - "avoid": [ - g_TileClasses.fish, 18, - g_TileClasses.player, 8 - ], - "stay": [g_TileClasses.water, 4], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal"] - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 7, - g_TileClasses.metal, 2, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.water, 5, - g_TileClasses.island, 2 + g_Map.log("Painting cliffs"); + createArea( + new MapBoundsPlacer(), + [ + new TerrainPainter(g_Terrains.cliff), + new TileClassPainter(g_TileClasses.mountain), ], - "sizes": ["small"], - "mixes": ["same"], - "amounts": ["normal"] - } -])); -Engine.SetProgress(65); - -g_Map.log("Painting island"); -setIslandBiome(); + [ + avoidClasses(g_TileClasses.water, 2), + new SlopeConstraint(2, Infinity) + ]); + yield 45; -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "stay": [g_TileClasses.island, 2], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["few"] - }, + if (!isNomad()) { - "func": addDecoration, - "avoid": [ - g_TileClasses.forest, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "stay": [g_TileClasses.island, 2], - "sizes": ["tiny"], - "mixes": ["same"], - "amounts": ["scarce"] + g_Map.log("Placing players"); + const [playerIDs, playerPosition] = createBases( + ...playerPlacementRandom( + sortAllPlayers(), + [ + avoidClasses(g_TileClasses.island, 5), + stayClasses(g_TileClasses.land, defaultPlayerBaseRadius() / 2) + ]), + "towers"); + + g_Map.log("Flatten the initial CC area"); + for (const position of playerPosition) + createArea( + new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, + position), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); } -]); - -g_Map.log("Creating island mines"); -for (let i = 0; i < scaleByMapSize(4, 10); ++i) - createObjectGroupsByAreas( - randBool() ? - new SimpleGroup([new SimpleObject(g_Gaia.metalLarge, 1, 1, 0, 4)], true, g_TileClasses.metal) : - new SimpleGroup([new SimpleObject(g_Gaia.stoneLarge, 1, 1, 0, 4)], true, g_TileClasses.rock), - 0, - [avoidClasses(g_TileClasses.rock, 8, g_TileClasses.metal, 8), stayClasses(g_TileClasses.island, 4)], - 1, - 40, - [areaIsland]); -addElements(shuffleArray([ - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 10, - g_TileClasses.metal, 3, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.water, 2 - ], - "stay": [g_TileClasses.island, 2], - "sizes": ["normal"], - "mixes": ["similar"], - "amounts": ["normal"] - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 7, - g_TileClasses.metal, 2, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.water, 5 - ], - "stay": [g_TileClasses.island, 2], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - } -])); + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3, + g_TileClasses.island, 2 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3, + g_TileClasses.island, 2 + ], + "sizes": ["small"], + "mixes": ["same"], + "amounts": ["many"] + } + ]); -Engine.SetProgress(80); + addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 30, + g_TileClasses.water, 3, + g_TileClasses.island, 2 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.player, 30, + g_TileClasses.rock, 30, + g_TileClasses.metal, 20, + g_TileClasses.water, 3, + g_TileClasses.island, 2 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal"] + } + ])); + + addElements([ + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 35, + g_TileClasses.metal, 3, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2, + g_TileClasses.island, 2 + ], + "sizes": ["big"], + "mixes": ["similar"], + "amounts": ["few"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 18, + g_TileClasses.metal, 3, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2, + g_TileClasses.island, 2 + ], + "sizes": ["normal"], + "mixes": ["similar"], + "amounts": ["many"] + }, + ]); -g_Map.log("Adding more decoratives"); -createObjectGroups( - new SimpleGroup( - [ - new SimpleObject("actor|props/special/eyecandy/awning_wood_small.xml", 1, 1, 1, 7), - new SimpleObject("actor|props/special/eyecandy/barrels_buried.xml", 1, 2, 1, 7) - ], - true, - g_TileClasses.dirt), - 0, - avoidClasses( - g_TileClasses.water, 2, - g_TileClasses.player, 10, - g_TileClasses.mountain, 2, - g_TileClasses.forest, 2), - 2 * scaleByMapSize(1, 4), - 20); -Engine.SetProgress(85); - -g_Map.log("Creating treasures"); -for (const treasure of [g_Gaia.woodTreasure, g_Gaia.foodTreasure]) + addElements(shuffleArray([ + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.player, 20, + g_TileClasses.rock, 10, + g_TileClasses.water, 3, + g_TileClasses.island, 2 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["few"] + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.water, 3, + g_TileClasses.island, 2 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + }, + { + "func": addFish, + "avoid": [ + g_TileClasses.fish, 18, + g_TileClasses.player, 8 + ], + "stay": [g_TileClasses.water, 4], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 7, + g_TileClasses.metal, 2, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.water, 5, + g_TileClasses.island, 2 + ], + "sizes": ["small"], + "mixes": ["same"], + "amounts": ["normal"] + } + ])); + yield 65; + + g_Map.log("Painting island"); + setIslandBiome(); + + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "stay": [g_TileClasses.island, 2], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["few"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "stay": [g_TileClasses.island, 2], + "sizes": ["tiny"], + "mixes": ["same"], + "amounts": ["scarce"] + } + ]); + + g_Map.log("Creating island mines"); + for (let i = 0; i < scaleByMapSize(4, 10); ++i) + createObjectGroupsByAreas( + randBool() ? + new SimpleGroup([new SimpleObject(g_Gaia.metalLarge, 1, 1, 0, 4)], true, + g_TileClasses.metal) : + new SimpleGroup([new SimpleObject(g_Gaia.stoneLarge, 1, 1, 0, 4)], true, + g_TileClasses.rock), + 0, + [avoidClasses(g_TileClasses.rock, 8, g_TileClasses.metal, 8), + stayClasses(g_TileClasses.island, 4)], + 1, + 40, + [areaIsland]); + + addElements(shuffleArray([ + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 10, + g_TileClasses.metal, 3, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2 + ], + "stay": [g_TileClasses.island, 2], + "sizes": ["normal"], + "mixes": ["similar"], + "amounts": ["normal"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 7, + g_TileClasses.metal, 2, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.water, 5 + ], + "stay": [g_TileClasses.island, 2], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + } + ])); + + yield 80; + + g_Map.log("Adding more decoratives"); createObjectGroups( - new SimpleGroup([new SimpleObject(treasure, 1, 1, 0, 2)], true), + new SimpleGroup( + [ + new SimpleObject("actor|props/special/eyecandy/awning_wood_small.xml", 1, 1, 1, 7), + new SimpleObject("actor|props/special/eyecandy/barrels_buried.xml", 1, 2, 1, 7) + ], + true, + g_TileClasses.dirt), 0, avoidClasses( g_TileClasses.water, 2, - g_TileClasses.player, 25, + g_TileClasses.player, 10, + g_TileClasses.mountain, 2, g_TileClasses.forest, 2), - randIntInclusive(1, numPlayers), + 2 * scaleByMapSize(1, 4), 20); -Engine.SetProgress(90); - -g_Map.log("Creating shipwrecks"); -createObjectGroups( - new SimpleGroup([new SimpleObject(g_Gaia.shipWreck, 1, 1, 0, 1)], true), - 0, - stayClasses(g_TileClasses.water, 2), - randIntInclusive(0, 1), - 20); -Engine.SetProgress(95); - -placePlayersNomad( - g_Map.createTileClass(), - [ - stayClasses(g_TileClasses.land, 5), - avoidClasses( - g_TileClasses.island, 0, - g_TileClasses.forest, 2, - g_TileClasses.rock, 4, - g_TileClasses.metal, 4, - g_TileClasses.berries, 1, - g_TileClasses.animals, 1) - ]); - -setSunColor(0.733, 0.746, 0.574); -setSkySet("cloudless"); - -// Prevent the water from disappearing on the tiny mapsize while maximizing land on greater sizes -setWaterHeight(scaleByMapSize(20, 18)); -setWaterTint(0.37, 0.67, 0.73); -setWaterColor(0.24, 0.44, 0.56); -setWaterWaviness(9); -setWaterMurkiness(0.8); -setWaterType("lake"); - -setAmbientColor(0.521, 0.475, 0.322); - -setSunRotation(Math.PI); -setSunElevation(Math.PI / 6.25); - -setFogFactor(0); -setFogThickness(0); -setFogColor(0.69, 0.616, 0.541); - -setPPEffect("hdr"); -setPPContrast(0.67); -setPPSaturation(0.42); -setPPBloom(0.23); + yield 85; + + g_Map.log("Creating treasures"); + for (const treasure of [g_Gaia.woodTreasure, g_Gaia.foodTreasure]) + createObjectGroups( + new SimpleGroup([new SimpleObject(treasure, 1, 1, 0, 2)], true), + 0, + avoidClasses( + g_TileClasses.water, 2, + g_TileClasses.player, 25, + g_TileClasses.forest, 2), + randIntInclusive(1, numPlayers), + 20); + yield 90; + + g_Map.log("Creating shipwrecks"); + createObjectGroups( + new SimpleGroup([new SimpleObject(g_Gaia.shipWreck, 1, 1, 0, 1)], true), + 0, + stayClasses(g_TileClasses.water, 2), + randIntInclusive(0, 1), + 20); + yield 95; -g_Map.ExportMap(); + placePlayersNomad( + g_Map.createTileClass(), + [ + stayClasses(g_TileClasses.land, 5), + avoidClasses( + g_TileClasses.island, 0, + g_TileClasses.forest, 2, + g_TileClasses.rock, 4, + g_TileClasses.metal, 4, + g_TileClasses.berries, 1, + g_TileClasses.animals, 1) + ]); + + setSunColor(0.733, 0.746, 0.574); + setSkySet("cloudless"); + + // Prevent the water from disappearing on the tiny mapsize while maximizing land on greater sizes + setWaterHeight(scaleByMapSize(20, 18)); + setWaterTint(0.37, 0.67, 0.73); + setWaterColor(0.24, 0.44, 0.56); + setWaterWaviness(9); + setWaterMurkiness(0.8); + setWaterType("lake"); + + setAmbientColor(0.521, 0.475, 0.322); + + setSunRotation(Math.PI); + setSunElevation(Math.PI / 6.25); + + setFogFactor(0); + setFogThickness(0); + setFogColor(0.69, 0.616, 0.541); + + setPPEffect("hdr"); + setPPContrast(0.67); + setPPSaturation(0.42); + setPPBloom(0.23); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/belgian_uplands.js =================================================================== --- binaries/data/mods/public/maps/random/belgian_uplands.js +++ binaries/data/mods/public/maps/random/belgian_uplands.js @@ -2,282 +2,337 @@ Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("heightmap"); -const tPrimary = ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_d", - "temp_grass_long_b", "temp_grass_clovers_2", "temp_grass_mossy", "temp_grass_plants"]; - -const heightLand = 0; -const g_Map = new RandomMap(heightLand, tPrimary); -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -// Set target min and max height depending on map size to make average stepness the same on all map sizes -const heightRange = {"min": MIN_HEIGHT * mapSize / 8192, "max": MAX_HEIGHT * mapSize / 8192}; - -// Since erosion is not predictable, actual water coverage can differ much with the same value -const averageWaterCoverage = scaleByMapSize(1/5, 1/3); - -const heightSeaGround = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); -const heightSeaGroundAdjusted = heightSeaGround + MIN_HEIGHT; -setWaterHeight(heightSeaGround); - -const textueByHeight = []; - -// Deep water -textueByHeight.push({"upperHeightLimit": heightRange.min + 1/3 * (heightSeaGroundAdjusted - heightRange.min), "terrain": "temp_sea_rocks"}); - -// Medium deep water (with fish) -var terrains = ["temp_sea_weed"]; -terrains = terrains.concat(terrains, terrains, terrains, terrains); -terrains = terrains.concat(terrains, terrains, terrains, terrains); -terrains.push("temp_sea_weed|gaia/fish/generic"); -textueByHeight.push({"upperHeightLimit": heightRange.min + 2/3 * (heightSeaGroundAdjusted - heightRange.min), "terrain": terrains}); - -// Flat Water -textueByHeight.push({"upperHeightLimit": heightRange.min + 3/3 * (heightSeaGroundAdjusted - heightRange.min), "terrain": "temp_mud_a"}); - -// Water surroundings/bog (with stone/metal some rabits and bushes) -var terrains = ["temp_plants_bog", "temp_plants_bog_aut", "temp_dirt_gravel_plants", "temp_grass_d"]; -terrains = terrains.concat(terrains, terrains, terrains, terrains, terrains); -terrains = ["temp_plants_bog|gaia/tree/bush_temperate"].concat(terrains, terrains); -terrains = ["temp_dirt_gravel_plants|gaia/ore/temperate_small", "temp_dirt_gravel_plants|gaia/rock/temperate_small", "temp_plants_bog|gaia/fauna_rabbit"].concat(terrains, terrains); -terrains = ["temp_plants_bog_aut|gaia/tree/dead"].concat(terrains, terrains); -textueByHeight.push({"upperHeightLimit": heightSeaGroundAdjusted + 1/6 * (heightRange.max - heightSeaGroundAdjusted), "terrain": terrains}); - -// Juicy grass near bog -textueByHeight.push({"upperHeightLimit": heightSeaGroundAdjusted + 2/6 * (heightRange.max - heightSeaGroundAdjusted), - "terrain": ["temp_grass", "temp_grass_d", "temp_grass_long_b", "temp_grass_plants"]}); - -// Medium level grass -// const testActor = "actor|geology/decal_stone_medit_a.xml"; -textueByHeight.push({"upperHeightLimit": heightSeaGroundAdjusted + 3/6 * (heightRange.max - heightSeaGroundAdjusted), - "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_mossy"]}); - -// Long grass near forest border -textueByHeight.push({"upperHeightLimit": heightSeaGroundAdjusted + 4/6 * (heightRange.max - heightSeaGroundAdjusted), - "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_d", "temp_grass_long_b", "temp_grass_clovers_2", "temp_grass_mossy", "temp_grass_plants"]}); - -// Forest border (With wood/food plants/deer/rabits) -var terrains = ["temp_grass_plants|gaia/tree/euro_beech", "temp_grass_mossy|gaia/tree/poplar", "temp_grass_mossy|gaia/tree/poplar_lombardy", - "temp_grass_long|gaia/tree/bush_temperate", "temp_mud_plants|gaia/tree/bush_temperate", "temp_mud_plants|gaia/tree/bush_badlands", - "temp_grass_long|gaia/fruit/apple", "temp_grass_clovers|gaia/fruit/berry_01", "temp_grass_clovers_2|gaia/fruit/grapes", - "temp_grass_plants|gaia/fauna_deer", "temp_grass_long_b|gaia/fauna_rabbit"]; - -const numTerrains = terrains.length; -for (let i = 0; i < numTerrains; i++) - terrains.push("temp_grass_plants"); -textueByHeight.push({"upperHeightLimit": heightSeaGroundAdjusted + 5/6 * (heightRange.max - heightSeaGroundAdjusted), "terrain": terrains}); - -// Unpassable woods -textueByHeight.push({"upperHeightLimit": heightSeaGroundAdjusted + 6/6 * (heightRange.max - heightSeaGroundAdjusted), - "terrain": ["temp_grass_mossy|gaia/tree/oak", "temp_forestfloor_pine|gaia/tree/pine", - "temp_grass_mossy|gaia/tree/oak", "temp_forestfloor_pine|gaia/tree/pine", - "temp_mud_plants|gaia/tree/dead", "temp_plants_bog|gaia/tree/oak_large", - "temp_dirt_gravel_plants|gaia/tree/aleppo_pine", "temp_forestfloor_autumn|gaia/tree/carob"]}); - -Engine.SetProgress(5); - -const lowerHeightLimit = textueByHeight[3].upperHeightLimit; -const upperHeightLimit = textueByHeight[6].upperHeightLimit; - -let playerPosition; -let playerIDs; - -while (true) +function* GenerateMap() { - g_Map.log("Randomizing heightmap"); - createArea( - new MapBoundsPlacer(), - new RandomElevationPainter(heightRange.min, heightRange.max)); - - // More cycles yield bigger structures - g_Map.log("Smoothing map"); - createArea( - new MapBoundsPlacer(), - new SmoothingPainter(2, 1, 20)); - - g_Map.log("Rescaling map"); - rescaleHeightmap(heightRange.min, heightRange.max, g_Map.height); - - g_Map.log("Mark valid heightrange for player starting positions"); - const tHeightRange = g_Map.createTileClass(); - const area = createArea( - new DiskPlacer(fractionToTiles(0.5) - MAP_BORDER_WIDTH, mapCenter), - new TileClassPainter(tHeightRange), - new HeightConstraint(lowerHeightLimit, upperHeightLimit)); - - const players = area && playerPlacementRandom(sortAllPlayers(), stayClasses(tHeightRange, 15), true); - if (players) - { - [playerIDs, playerPosition] = players; - break; - } + const tPrimary = ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_d", + "temp_grass_long_b", "temp_grass_clovers_2", "temp_grass_mossy", "temp_grass_plants"]; - g_Map.log("Too few starting locations"); -} -Engine.SetProgress(60); + const heightLand = 0; + global.g_Map = new RandomMap(heightLand, tPrimary); + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); -g_Map.log("Painting terrain by height and add props"); -let propDensity = 1; // 1 means as determined in the loop, less for large maps as set below -if (mapSize > 500) - propDensity = 1/4; -else if (mapSize > 400) - propDensity = 3/4; + // Set target min and max height depending on map size to make average stepness the same on all map + // sizes + const heightRange = {"min": MIN_HEIGHT * mapSize / 8192, "max": MAX_HEIGHT * mapSize / 8192}; -for (let x = 0; x < mapSize; ++x) - for (let y = 0; y < mapSize; ++y) - { - const position = new Vector2D(x, y); - if (!g_Map.validHeight(position)) - continue; + // Since erosion is not predictable, actual water coverage can differ much with the same value + const averageWaterCoverage = scaleByMapSize(1/5, 1/3); - let textureMinHeight = heightRange.min; - for (let i = 0; i < textueByHeight.length; i++) + const heightSeaGround = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * + (heightRange.max - heightRange.min); + const heightSeaGroundAdjusted = heightSeaGround + MIN_HEIGHT; + setWaterHeight(heightSeaGround); + + const textueByHeight = []; + + // Deep water + textueByHeight.push( { - if (g_Map.getHeight(position) >= textureMinHeight && g_Map.getHeight(position) <= textueByHeight[i].upperHeightLimit) - { - createTerrain(textueByHeight[i].terrain).place(position); + "upperHeightLimit": heightRange.min + 1/3 * (heightSeaGroundAdjusted - heightRange.min), + "terrain": "temp_sea_rocks" + }); + + // Medium deep water (with fish) + var terrains = ["temp_sea_weed"]; + terrains = terrains.concat(terrains, terrains, terrains, terrains); + terrains = terrains.concat(terrains, terrains, terrains, terrains); + terrains.push("temp_sea_weed|gaia/fish/generic"); + textueByHeight.push( + { + "upperHeightLimit": heightRange.min + 2/3 * (heightSeaGroundAdjusted - heightRange.min), + "terrain": terrains + }); - let template; + // Flat Water + textueByHeight.push( + { + "upperHeightLimit": heightRange.min + 3/3 * (heightSeaGroundAdjusted - heightRange.min), + "terrain": "temp_mud_a" + }); + + // Water surroundings/bog (with stone/metal some rabits and bushes) + var terrains = ["temp_plants_bog", "temp_plants_bog_aut", "temp_dirt_gravel_plants", "temp_grass_d"]; + terrains = terrains.concat(terrains, terrains, terrains, terrains, terrains); + terrains = ["temp_plants_bog|gaia/tree/bush_temperate"].concat(terrains, terrains); + terrains = ["temp_dirt_gravel_plants|gaia/ore/temperate_small", + "temp_dirt_gravel_plants|gaia/rock/temperate_small", "temp_plants_bog|gaia/fauna_rabbit"] + .concat(terrains, terrains); + terrains = ["temp_plants_bog_aut|gaia/tree/dead"].concat(terrains, terrains); + textueByHeight.push( + { + "upperHeightLimit": heightSeaGroundAdjusted + 1/6 * + (heightRange.max - heightSeaGroundAdjusted), + "terrain": terrains + }); - if (i == 0) // ...deep water - { - if (randBool(propDensity / 100)) - template = "actor|props/flora/pond_lillies_large.xml"; - else if (randBool(propDensity / 40)) - template = "actor|props/flora/water_lillies.xml"; - } - if (i == 1) // ...medium water (with fish) - { - if (randBool(propDensity / 200)) - template = "actor|props/flora/pond_lillies_large.xml"; - else if (randBool(propDensity / 100)) - template = "actor|props/flora/water_lillies.xml"; - } - if (i == 2) // ...low water/mud - { - if (randBool(propDensity / 200)) - template = "actor|props/flora/water_log.xml"; - else if (randBool(propDensity / 100)) - template = "actor|props/flora/water_lillies.xml"; - else if (randBool(propDensity / 40)) - template = "actor|geology/highland_c.xml"; - else if (randBool(propDensity / 20)) - template = "actor|props/flora/reeds_pond_lush_b.xml"; - else if (randBool(propDensity / 10)) - template = "actor|props/flora/reeds_pond_lush_a.xml"; - } - if (i == 3) // ...water suroundings/bog - { - if (randBool(propDensity / 200)) - template = "actor|props/flora/water_log.xml"; - else if (randBool(propDensity / 100)) - template = "actor|geology/highland_c.xml"; - else if (randBool(propDensity / 40)) - template = "actor|props/flora/reeds_pond_lush_a.xml"; - } - if (i == 4) // ...low height grass - { - if (randBool(propDensity / 800)) - template = "actor|props/flora/grass_field_flowering_tall.xml"; - else if (randBool(propDensity / 400)) - template = "actor|geology/gray_rock1.xml"; - else if (randBool(propDensity / 200)) - template = "actor|props/flora/bush_tempe_sm_lush.xml"; - else if (randBool(propDensity / 100)) - template = "actor|props/flora/bush_tempe_b.xml"; - else if (randBool(propDensity / 40)) - template = "actor|props/flora/grass_soft_small_tall.xml"; - } - if (i == 5) // ...medium height grass - { - if (randBool(propDensity / 800)) - template = "actor|geology/decal_stone_medit_a.xml"; - else if (randBool(propDensity / 400)) - template = "actor|props/flora/decals_flowers_daisies.xml"; - else if (randBool(propDensity / 200)) - template = "actor|props/flora/bush_tempe_underbrush.xml"; - else if (randBool(propDensity / 100)) - template = "actor|props/flora/grass_soft_small_tall.xml"; - else if (randBool(propDensity / 40)) - template = "actor|props/flora/grass_temp_field.xml"; - } - if (i == 6) // ...high height grass - { - if (randBool(propDensity / 400)) - template = "actor|geology/stone_granite_boulder.xml"; - else if (randBool(propDensity / 200)) - template = "actor|props/flora/foliagebush.xml"; - else if (randBool(propDensity / 100)) - template = "actor|props/flora/bush_tempe_underbrush.xml"; - else if (randBool(propDensity / 40)) - template = "actor|props/flora/grass_soft_small_tall.xml"; - else if (randBool(propDensity / 20)) - template = "actor|props/flora/ferns.xml"; - } - if (i == 7) // ...forest border (with wood/food plants/deer/rabits) - { - if (randBool(propDensity / 400)) - template = "actor|geology/highland_c.xml"; - else if (randBool(propDensity / 200)) - template = "actor|props/flora/bush_tempe_a.xml"; - else if (randBool(propDensity / 100)) - template = "actor|props/flora/ferns.xml"; - else if (randBool(propDensity / 40)) - template = "actor|props/flora/grass_soft_tuft_a.xml"; - } - if (i == 8) // ...woods - { - if (randBool(propDensity / 200)) - template = "actor|geology/highland2_moss.xml"; - else if (randBool(propDensity / 100)) - template = "actor|props/flora/grass_soft_tuft_a.xml"; - else if (randBool(propDensity / 40)) - template = "actor|props/flora/ferns.xml"; - } + // Juicy grass near bog + textueByHeight.push( + { + "upperHeightLimit": heightSeaGroundAdjusted + 2/6 * + (heightRange.max - heightSeaGroundAdjusted), + "terrain": ["temp_grass", "temp_grass_d", "temp_grass_long_b", "temp_grass_plants"] + }); + + // Medium level grass + // const testActor = "actor|geology/decal_stone_medit_a.xml"; + textueByHeight.push( + { + "upperHeightLimit": heightSeaGroundAdjusted + 3/6 * + (heightRange.max - heightSeaGroundAdjusted), + "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_mossy"] + }); - if (template) - g_Map.placeEntityAnywhere(template, 0, position, randomAngle()); + // Long grass near forest border + textueByHeight.push( + { + "upperHeightLimit": heightSeaGroundAdjusted + 4/6 * + (heightRange.max - heightSeaGroundAdjusted), + "terrain": ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_d", + "temp_grass_long_b", "temp_grass_clovers_2", "temp_grass_mossy", + "temp_grass_plants"] + }); + + // Forest border (With wood/food plants/deer/rabits) + var terrains = ["temp_grass_plants|gaia/tree/euro_beech", "temp_grass_mossy|gaia/tree/poplar", + "temp_grass_mossy|gaia/tree/poplar_lombardy", "temp_grass_long|gaia/tree/bush_temperate", + "temp_mud_plants|gaia/tree/bush_temperate", "temp_mud_plants|gaia/tree/bush_badlands", + "temp_grass_long|gaia/fruit/apple", "temp_grass_clovers|gaia/fruit/berry_01", + "temp_grass_clovers_2|gaia/fruit/grapes", "temp_grass_plants|gaia/fauna_deer", + "temp_grass_long_b|gaia/fauna_rabbit"]; + + const numTerrains = terrains.length; + for (let i = 0; i < numTerrains; i++) + terrains.push("temp_grass_plants"); + textueByHeight.push( + { + "upperHeightLimit": heightSeaGroundAdjusted + 5/6 * + (heightRange.max - heightSeaGroundAdjusted), + "terrain": terrains + }); - break; - } - else - textureMinHeight = textueByHeight[i].upperHeightLimit; + // Unpassable woods + textueByHeight.push( + { + "upperHeightLimit": heightSeaGroundAdjusted + 6/6 * + (heightRange.max - heightSeaGroundAdjusted), + "terrain": ["temp_grass_mossy|gaia/tree/oak", "temp_forestfloor_pine|gaia/tree/pine", + "temp_grass_mossy|gaia/tree/oak", "temp_forestfloor_pine|gaia/tree/pine", + "temp_mud_plants|gaia/tree/dead", "temp_plants_bog|gaia/tree/oak_large", + "temp_dirt_gravel_plants|gaia/tree/aleppo_pine", + "temp_forestfloor_autumn|gaia/tree/carob"] + }); + + Engine.SetProgress(5); + + const lowerHeightLimit = textueByHeight[3].upperHeightLimit; + const upperHeightLimit = textueByHeight[6].upperHeightLimit; + + let playerPosition; + let playerIDs; + + while (true) + { + g_Map.log("Randomizing heightmap"); + createArea( + new MapBoundsPlacer(), + new RandomElevationPainter(heightRange.min, heightRange.max)); + + // More cycles yield bigger structures + g_Map.log("Smoothing map"); + createArea( + new MapBoundsPlacer(), + new SmoothingPainter(2, 1, 20)); + + g_Map.log("Rescaling map"); + rescaleHeightmap(heightRange.min, heightRange.max, g_Map.height); + + g_Map.log("Mark valid heightrange for player starting positions"); + const tHeightRange = g_Map.createTileClass(); + const area = createArea( + new DiskPlacer(fractionToTiles(0.5) - MAP_BORDER_WIDTH, mapCenter), + new TileClassPainter(tHeightRange), + new HeightConstraint(lowerHeightLimit, upperHeightLimit)); + + const players = area && + playerPlacementRandom(sortAllPlayers(), stayClasses(tHeightRange, 15), true); + if (players) + { + [playerIDs, playerPosition] = players; + break; } + + g_Map.log("Too few starting locations"); } + Engine.SetProgress(60); -Engine.SetProgress(90); + g_Map.log("Painting terrain by height and add props"); + let propDensity = 1; // 1 means as determined in the loop, less for large maps as set below + if (mapSize > 500) + propDensity = 1/4; + else if (mapSize > 400) + propDensity = 3/4; -if (isNomad()) - placePlayersNomad(g_Map.createTileClass(), new HeightConstraint(lowerHeightLimit, upperHeightLimit)); -else -{ - g_Map.log("Placing players and starting resources"); + for (let x = 0; x < mapSize; ++x) + for (let y = 0; y < mapSize; ++y) + { + const position = new Vector2D(x, y); + if (!g_Map.validHeight(position)) + continue; + + let textureMinHeight = heightRange.min; + for (let i = 0; i < textueByHeight.length; i++) + { + if (g_Map.getHeight(position) >= textureMinHeight && + g_Map.getHeight(position) <= textueByHeight[i].upperHeightLimit) + { + createTerrain(textueByHeight[i].terrain).place(position); + + let template; + + if (i == 0) // ...deep water + { + if (randBool(propDensity / 100)) + template = "actor|props/flora/pond_lillies_large.xml"; + else if (randBool(propDensity / 40)) + template = "actor|props/flora/water_lillies.xml"; + } + if (i == 1) // ...medium water (with fish) + { + if (randBool(propDensity / 200)) + template = "actor|props/flora/pond_lillies_large.xml"; + else if (randBool(propDensity / 100)) + template = "actor|props/flora/water_lillies.xml"; + } + if (i == 2) // ...low water/mud + { + if (randBool(propDensity / 200)) + template = "actor|props/flora/water_log.xml"; + else if (randBool(propDensity / 100)) + template = "actor|props/flora/water_lillies.xml"; + else if (randBool(propDensity / 40)) + template = "actor|geology/highland_c.xml"; + else if (randBool(propDensity / 20)) + template = "actor|props/flora/reeds_pond_lush_b.xml"; + else if (randBool(propDensity / 10)) + template = "actor|props/flora/reeds_pond_lush_a.xml"; + } + if (i == 3) // ...water suroundings/bog + { + if (randBool(propDensity / 200)) + template = "actor|props/flora/water_log.xml"; + else if (randBool(propDensity / 100)) + template = "actor|geology/highland_c.xml"; + else if (randBool(propDensity / 40)) + template = "actor|props/flora/reeds_pond_lush_a.xml"; + } + if (i == 4) // ...low height grass + { + if (randBool(propDensity / 800)) + template = "actor|props/flora/grass_field_flowering_tall.xml"; + else if (randBool(propDensity / 400)) + template = "actor|geology/gray_rock1.xml"; + else if (randBool(propDensity / 200)) + template = "actor|props/flora/bush_tempe_sm_lush.xml"; + else if (randBool(propDensity / 100)) + template = "actor|props/flora/bush_tempe_b.xml"; + else if (randBool(propDensity / 40)) + template = "actor|props/flora/grass_soft_small_tall.xml"; + } + if (i == 5) // ...medium height grass + { + if (randBool(propDensity / 800)) + template = "actor|geology/decal_stone_medit_a.xml"; + else if (randBool(propDensity / 400)) + template = "actor|props/flora/decals_flowers_daisies.xml"; + else if (randBool(propDensity / 200)) + template = "actor|props/flora/bush_tempe_underbrush.xml"; + else if (randBool(propDensity / 100)) + template = "actor|props/flora/grass_soft_small_tall.xml"; + else if (randBool(propDensity / 40)) + template = "actor|props/flora/grass_temp_field.xml"; + } + if (i == 6) // ...high height grass + { + if (randBool(propDensity / 400)) + template = "actor|geology/stone_granite_boulder.xml"; + else if (randBool(propDensity / 200)) + template = "actor|props/flora/foliagebush.xml"; + else if (randBool(propDensity / 100)) + template = "actor|props/flora/bush_tempe_underbrush.xml"; + else if (randBool(propDensity / 40)) + template = "actor|props/flora/grass_soft_small_tall.xml"; + else if (randBool(propDensity / 20)) + template = "actor|props/flora/ferns.xml"; + } + if (i == 7) // ...forest border (with wood/food plants/deer/rabits) + { + if (randBool(propDensity / 400)) + template = "actor|geology/highland_c.xml"; + else if (randBool(propDensity / 200)) + template = "actor|props/flora/bush_tempe_a.xml"; + else if (randBool(propDensity / 100)) + template = "actor|props/flora/ferns.xml"; + else if (randBool(propDensity / 40)) + template = "actor|props/flora/grass_soft_tuft_a.xml"; + } + if (i == 8) // ...woods + { + if (randBool(propDensity / 200)) + template = "actor|geology/highland2_moss.xml"; + else if (randBool(propDensity / 100)) + template = "actor|props/flora/grass_soft_tuft_a.xml"; + else if (randBool(propDensity / 40)) + template = "actor|props/flora/ferns.xml"; + } + + if (template) + g_Map.placeEntityAnywhere(template, 0, position, randomAngle()); + + break; + } + else + textureMinHeight = textueByHeight[i].upperHeightLimit; + } + } - const resourceDistance = 8; - const resourceSpacing = 1; - const resourceCount = 4; + Engine.SetProgress(90); - for (let i = 0; i < numPlayers; ++i) + if (isNomad()) + placePlayersNomad(g_Map.createTileClass(), + new HeightConstraint(lowerHeightLimit, upperHeightLimit)); + else { - placeCivDefaultStartingEntities(playerPosition[i], playerIDs[i], false); + g_Map.log("Placing players and starting resources"); - for (let j = 1; j <= 4; ++j) + const resourceDistance = 8; + const resourceSpacing = 1; + const resourceCount = 4; + + for (let i = 0; i < numPlayers; ++i) { - const uAngle = BUILDING_ORIENTATION - Math.PI * (2-j) / 2; - for (let k = 0; k < resourceCount; ++k) + placeCivDefaultStartingEntities(playerPosition[i], playerIDs[i], false); + + for (let j = 1; j <= 4; ++j) { - const pos = Vector2D.sum([ - playerPosition[i], - new Vector2D(resourceDistance, 0).rotate(-uAngle), - new Vector2D(k * resourceSpacing, 0).rotate(-uAngle - Math.PI/2), - new Vector2D(-0.75 * resourceSpacing * Math.floor(resourceCount / 2), 0).rotate(-uAngle - Math.PI/2) - ]); - - g_Map.placeEntityPassable(j % 2 ? "gaia/tree/cypress" : "gaia/fruit/berry_01", 0, pos, randomAngle()); + const uAngle = BUILDING_ORIENTATION - Math.PI * (2-j) / 2; + for (let k = 0; k < resourceCount; ++k) + { + const pos = Vector2D.sum([ + playerPosition[i], + new Vector2D(resourceDistance, 0).rotate(-uAngle), + new Vector2D(k * resourceSpacing, 0).rotate(-uAngle - Math.PI/2), + new Vector2D(-0.75 * resourceSpacing * Math.floor(resourceCount / 2), 0) + .rotate(-uAngle - Math.PI/2) + ]); + + g_Map.placeEntityPassable(j % 2 ? "gaia/tree/cypress" : "gaia/fruit/berry_01", + 0, pos, randomAngle()); + } } } } -} -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/botswanan_haven.js =================================================================== --- binaries/data/mods/public/maps/random/botswanan_haven.js +++ binaries/data/mods/public/maps/random/botswanan_haven.js @@ -1,398 +1,404 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tGrassA = "savanna_shrubs_a_wetseason"; -const tGrassB = "savanna_shrubs_a"; -const tCliff = "savanna_cliff_a"; -const tHill = "savanna_grass_a_wetseason"; -const tMud = "savanna_mud_a"; -const tShoreBlend = "savanna_grass_b_wetseason"; -const tShore = "savanna_riparian_wet"; -const tWater = "savanna_mud_a"; -const tCityTile = "savanna_tile_a"; - -const oBush = "gaia/tree/bush_temperate"; -const oBaobab = "gaia/tree/baobab"; -const oToona = "gaia/tree/toona"; -const oBerryBush = "gaia/fruit/berry_01"; -const oGazelle = "gaia/fauna_gazelle"; -const oZebra = "gaia/fauna_zebra"; -const oWildebeest = "gaia/fauna_wildebeest"; -const oLion = "gaia/fauna_lion"; -const oRhino = "gaia/fauna_rhinoceros_white"; -const oCrocodile = "gaia/fauna_crocodile_nile"; -const oElephant = "gaia/fauna_elephant_north_african"; -const oElephantInfant = "gaia/fauna_elephant_african_infant"; -const oLioness = "gaia/fauna_lioness"; -const oRabbit = "gaia/fauna_rabbit"; -const oStoneLarge = "gaia/rock/temperate_large"; -const oStoneSmall = "gaia/rock/savanna_small"; -const oMetalLarge = "gaia/ore/savanna_large"; - -const aGrass = "actor|props/flora/grass_field_lush_tall.xml"; -const aGrass2 = "actor|props/flora/grass_tropic_field_tall.xml"; -const aGrassShort = "actor|props/flora/grass_soft_large.xml"; -const aRockLarge = "actor|geology/stone_granite_med.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; -const aReeds2 = "actor|props/flora/reeds_pond_lush_b.xml"; -const aLillies = "actor|props/flora/water_lillies.xml"; -const aBushMedium = "actor|props/flora/bush_tropic_b.xml"; -const aBushSmall = "actor|props/flora/bush_tropic_a.xml"; -const aShrub = "actor|props/flora/shrub_tropic_plant_flower.xml"; -const aFlower = "actor|props/flora/flower_bright.xml"; -const aPalm = "actor|props/flora/shrub_fanpalm.xml"; - -const heightMarsh = -2; -const heightLand = 3; -const heightHill = 15; - -const heightOffsetBump1 = 2; -const heightOffsetBump2 = 1; - -const g_Map = new RandomMap(heightLand, tShoreBlend); - -const numPlayers = getNumPlayers(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tCityTile, - "innerTerrain": tCityTile - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oBaobab - }, - "Decoratives": { - "template": aGrassShort - } -}); -Engine.SetProgress(15); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.6, 0.1, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump1, 2), - avoidClasses(clPlayer, 13), - scaleByMapSize(300, 800)); - -g_Map.log("Creating hills"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), - [ - new LayeredPainter([tCliff, tHill], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 20, clHill, 15, clWater, 0), - scaleByMapSize(1, 4) * numPlayers * 3); - -g_Map.log("Creating marshes"); -for (let i = 0; i < 2; ++i) +function* GenerateMap() +{ + const tGrassA = "savanna_shrubs_a_wetseason"; + const tGrassB = "savanna_shrubs_a"; + const tCliff = "savanna_cliff_a"; + const tHill = "savanna_grass_a_wetseason"; + const tMud = "savanna_mud_a"; + const tShoreBlend = "savanna_grass_b_wetseason"; + const tShore = "savanna_riparian_wet"; + const tWater = "savanna_mud_a"; + const tCityTile = "savanna_tile_a"; + + const oBush = "gaia/tree/bush_temperate"; + const oBaobab = "gaia/tree/baobab"; + const oToona = "gaia/tree/toona"; + const oBerryBush = "gaia/fruit/berry_01"; + const oGazelle = "gaia/fauna_gazelle"; + const oZebra = "gaia/fauna_zebra"; + const oWildebeest = "gaia/fauna_wildebeest"; + const oLion = "gaia/fauna_lion"; + const oRhino = "gaia/fauna_rhinoceros_white"; + const oCrocodile = "gaia/fauna_crocodile_nile"; + const oElephant = "gaia/fauna_elephant_north_african"; + const oElephantInfant = "gaia/fauna_elephant_african_infant"; + const oLioness = "gaia/fauna_lioness"; + const oRabbit = "gaia/fauna_rabbit"; + const oStoneLarge = "gaia/rock/temperate_large"; + const oStoneSmall = "gaia/rock/savanna_small"; + const oMetalLarge = "gaia/ore/savanna_large"; + + const aGrass = "actor|props/flora/grass_field_lush_tall.xml"; + const aGrass2 = "actor|props/flora/grass_tropic_field_tall.xml"; + const aGrassShort = "actor|props/flora/grass_soft_large.xml"; + const aRockLarge = "actor|geology/stone_granite_med.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; + const aReeds2 = "actor|props/flora/reeds_pond_lush_b.xml"; + const aLillies = "actor|props/flora/water_lillies.xml"; + const aBushMedium = "actor|props/flora/bush_tropic_b.xml"; + const aBushSmall = "actor|props/flora/bush_tropic_a.xml"; + const aShrub = "actor|props/flora/shrub_tropic_plant_flower.xml"; + const aFlower = "actor|props/flora/flower_bright.xml"; + const aPalm = "actor|props/flora/shrub_fanpalm.xml"; + + const heightMarsh = -2; + const heightLand = 3; + const heightHill = 15; + + const heightOffsetBump1 = 2; + const heightOffsetBump2 = 1; + + global.g_Map = new RandomMap(heightLand, tShoreBlend); + + const numPlayers = getNumPlayers(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tCityTile, + "innerTerrain": tCityTile + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oBaobab + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 15; + + g_Map.log("Creating bumps"); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(6, 12)), Math.floor(scaleByMapSize(15, 60)), 0.8), - [ - new LayeredPainter([tShoreBlend, tShore, tWater], [1, 1]), - new SmoothElevationPainter(ELEVATION_SET, heightMarsh, 3), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 25, clWater, Math.round(scaleByMapSize(7, 16) * randFloat(0.8, 1.35))), - scaleByMapSize(4, 20)); + new ClumpPlacer(scaleByMapSize(20, 50), 0.6, 0.1, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump1, 2), + avoidClasses(clPlayer, 13), + scaleByMapSize(300, 800)); -g_Map.log("Creating reeds"); -createObjectGroupsDeprecated( - new SimpleGroup( - [ - new SimpleObject(aReeds, 20, 40, 0, 4), - new SimpleObject(aReeds2, 20, 40, 0, 4), - new SimpleObject(aLillies, 10, 30, 0, 4) - ], - true), - 0, - stayClasses(clWater, 1), - scaleByMapSize(400, 1000), - 100); -Engine.SetProgress(40); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump2, 2), - stayClasses(clWater, 2), - scaleByMapSize(50, 100)); - -g_Map.log("Creating mud patches"); -for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) + g_Map.log("Creating hills"); createAreas( - new ChainPlacer(2, Math.floor(scaleByMapSize(3, 6)), size, Infinity), - [ - new LayeredPainter([tGrassA, tGrassB, tMud], [1, 1]), - new TileClassPainter(clDirt) - ], - avoidClasses(clWater, 1, clHill, 0, clDirt, 5, clPlayer, 8), - scaleByMapSize(15, 45)); -Engine.SetProgress(50); - -g_Map.log("Creating stone mines"); -createObjectGroupsDeprecated( - new SimpleGroup( - [ - new SimpleObject(oStoneSmall, 0, 2, 0, 4), - new SimpleObject(oStoneLarge, 1, 1, 0, 4) - ], - true, - clRock), - 0, - [avoidClasses(clWater, 0, clPlayer, 20, clRock, 10, clHill, 1)], - scaleByMapSize(4, 16), - 100); - -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock), - 0, - [avoidClasses(clWater, 0, clPlayer, 20, clRock, 10, clHill, 1)], - scaleByMapSize(4, 16), - 100); - -g_Map.log("Creating metal mines"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), - 0, - [avoidClasses(clWater, 0, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1)], - scaleByMapSize(4, 16), - 100); -Engine.SetProgress(60); - -g_Map.log("Creating small decorative rocks"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aRockMedium, 1, 3, 0, 1)], true), - 0, - avoidClasses(clPlayer, 1), - scaleByMapSize(16, 262), - 50); -Engine.SetProgress(65); - -g_Map.log("Creating large decorative rocks"); -createObjectGroupsDeprecated( - new SimpleGroup( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), [ - new SimpleObject(aRockLarge, 1, 2, 0, 1), - new SimpleObject(aRockMedium, 1, 3, 0, 2) + new LayeredPainter([tCliff, tHill], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) ], - true), - 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), - scaleByMapSize(8, 131), - 50); -Engine.SetProgress(70); - -g_Map.log("Creating lions"); -createObjectGroupsDeprecated( - new SimpleGroup( - [ - new SimpleObject(oLion, 0, 1, 0, 4), - new SimpleObject(oLioness, 2, 3, 0, 4) - ], - true, - clFood), - 0, - avoidClasses(clWater, 1, clPlayer, 20, clFood, 11, clHill, 1), - scaleByMapSize(4, 12), - 50); - -g_Map.log("Creating zebras"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oZebra, 4, 6, 0, 4)], - true, - clFood), - 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), - 3 * numPlayers, - 50); - -g_Map.log("Creating wildebeest"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oWildebeest, 2, 4, 0, 4)], - true, - clFood), - 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), - 3 * numPlayers, - 50); - -g_Map.log("Creating crocodiles"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oCrocodile, 2, 3, 0, 4)], - true, - clFood), - 0, - [avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), stayClasses(clWater, 3)], - 5 * numPlayers, - 200); - -g_Map.log("Creating gazelles"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oGazelle, 4, 6, 0, 4)], - true, - clFood), - 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), - 3 * numPlayers, - 50); -Engine.SetProgress(75); - -g_Map.log("Creating rabbits"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oRabbit, 6, 8, 0, 2)], - true, - clFood), - 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), - 6 * numPlayers, - 50); - -g_Map.log("Creating rhinos"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oRhino, 1, 1, 0, 2)], - true, - clFood), - 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), - 3 * numPlayers, - 50); - -g_Map.log("Creating elephants"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oElephant, 2, 3, 0, 4), new SimpleObject(oElephantInfant, 1, 1, 0, 4)], - true, - clFood), - 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), - 3 * numPlayers, - 50); - -g_Map.log("Creating berry bushes"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oBerryBush, 5, 7, 0, 4)], - true, - clFood), - 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - randIntInclusive(1, 4) * numPlayers + 2, - 50); -Engine.SetProgress(80); - -createStragglerTrees( - [oToona, oBaobab, oBush, oBush], - avoidClasses(clForest, 1, clWater, 1, clHill, 1, clPlayer, 13, clMetal, 4, clRock, 4), - clForest, - scaleByMapSize(60, 500)); -Engine.SetProgress(85); - -g_Map.log("Creating small grass tufts"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aGrassShort, 1, 2, 0, 1, -Math.PI / 8, Math.PI / 8)]), - 0, - avoidClasses(clWater, 2, clPlayer, 13, clDirt, 0), - scaleByMapSize(13, 200)); -Engine.SetProgress(90); - -g_Map.log("Creating large grass tufts"); -createObjectGroupsDeprecated( - 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) - ]), - 0, - avoidClasses(clWater, 3, clPlayer, 13, clDirt, 1, clForest, 0), - scaleByMapSize(13, 200)); -Engine.SetProgress(95); - -g_Map.log("Creating bushes"); -createObjectGroupsDeprecated( - new SimpleGroup( - [ - new SimpleObject(aBushMedium, 1, 2, 0, 2), - new SimpleObject(aBushSmall, 2, 4, 0, 2) - ]), - 0, - avoidClasses(clWater, 1, clPlayer, 13, clDirt, 1), - scaleByMapSize(13, 200), - 50); - -g_Map.log("Creating flowering shrubs"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aShrub, 1, 1, 0, 2)]), - 0, - avoidClasses(clWater, 1, clPlayer, 13, clDirt, 1), - scaleByMapSize(13, 200), - 50); - -g_Map.log("Creating decorative palms"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aPalm, 1, 3, 0, 2)]), - 0, - avoidClasses(clWater, 2, clPlayer, 12, clDirt, 1), - scaleByMapSize(13, 200), - 50); - -g_Map.log("Creating shrubs,flowers and other decorations"); -createObjectGroupsDeprecated( - new SimpleGroup( + avoidClasses(clPlayer, 20, clHill, 15, clWater, 0), + scaleByMapSize(1, 4) * numPlayers * 3); + + g_Map.log("Creating marshes"); + for (let i = 0; i < 2; ++i) + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(6, 12)), Math.floor(scaleByMapSize(15, 60)), + 0.8), + [ + new LayeredPainter([tShoreBlend, tShore, tWater], [1, 1]), + new SmoothElevationPainter(ELEVATION_SET, heightMarsh, 3), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 25, clWater, + Math.round(scaleByMapSize(7, 16) * randFloat(0.8, 1.35))), + scaleByMapSize(4, 20)); + + g_Map.log("Creating reeds"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(aReeds, 20, 40, 0, 4), + new SimpleObject(aReeds2, 20, 40, 0, 4), + new SimpleObject(aLillies, 10, 30, 0, 4) + ], + true), + 0, + stayClasses(clWater, 1), + scaleByMapSize(400, 1000), + 100); + yield 40; + + g_Map.log("Creating bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump2, 2), + stayClasses(clWater, 2), + scaleByMapSize(50, 100)); + + g_Map.log("Creating mud patches"); + for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) + createAreas( + new ChainPlacer(2, Math.floor(scaleByMapSize(3, 6)), size, Infinity), + [ + new LayeredPainter([tGrassA, tGrassB, tMud], [1, 1]), + new TileClassPainter(clDirt) + ], + avoidClasses(clWater, 1, clHill, 0, clDirt, 5, clPlayer, 8), + scaleByMapSize(15, 45)); + yield 50; + + g_Map.log("Creating stone mines"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4), + new SimpleObject(oStoneLarge, 1, 1, 0, 4) + ], + true, + clRock), + 0, + [avoidClasses(clWater, 0, clPlayer, 20, clRock, 10, clHill, 1)], + scaleByMapSize(4, 16), + 100); + + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock), + 0, + [avoidClasses(clWater, 0, clPlayer, 20, clRock, 10, clHill, 1)], + scaleByMapSize(4, 16), + 100); + + g_Map.log("Creating metal mines"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), + 0, + [avoidClasses(clWater, 0, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1)], + scaleByMapSize(4, 16), + 100); + yield 60; + + g_Map.log("Creating small decorative rocks"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aRockMedium, 1, 3, 0, 1)], true), + 0, + avoidClasses(clPlayer, 1), + scaleByMapSize(16, 262), + 50); + yield 65; + + g_Map.log("Creating large decorative rocks"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(aRockLarge, 1, 2, 0, 1), + new SimpleObject(aRockMedium, 1, 3, 0, 2) + ], + true), + 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), + scaleByMapSize(8, 131), + 50); + yield 70; + + g_Map.log("Creating lions"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(oLion, 0, 1, 0, 4), + new SimpleObject(oLioness, 2, 3, 0, 4) + ], + true, + clFood), + 0, + avoidClasses(clWater, 1, clPlayer, 20, clFood, 11, clHill, 1), + scaleByMapSize(4, 12), + 50); + + g_Map.log("Creating zebras"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oZebra, 4, 6, 0, 4)], + true, + clFood), + 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), + 3 * numPlayers, + 50); + + g_Map.log("Creating wildebeest"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oWildebeest, 2, 4, 0, 4)], + true, + clFood), + 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), + 3 * numPlayers, + 50); + + g_Map.log("Creating crocodiles"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oCrocodile, 2, 3, 0, 4)], + true, + clFood), + 0, + [avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), stayClasses(clWater, 3)], + 5 * numPlayers, + 200); + + g_Map.log("Creating gazelles"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oGazelle, 4, 6, 0, 4)], + true, + clFood), + 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), + 3 * numPlayers, + 50); + yield 75; + + g_Map.log("Creating rabbits"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oRabbit, 6, 8, 0, 2)], + true, + clFood), + 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), + 6 * numPlayers, + 50); + + g_Map.log("Creating rhinos"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oRhino, 1, 1, 0, 2)], + true, + clFood), + 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), + 3 * numPlayers, + 50); + + g_Map.log("Creating elephants"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oElephant, 2, 3, 0, 4), new SimpleObject(oElephantInfant, 1, 1, 0, 4)], + true, + clFood), + 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 1, clFood, 13), + 3 * numPlayers, + 50); + + g_Map.log("Creating berry bushes"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oBerryBush, 5, 7, 0, 4)], + true, + clFood), + 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), + randIntInclusive(1, 4) * numPlayers + 2, + 50); + yield 80; + + createStragglerTrees( + [oToona, oBaobab, oBush, oBush], + avoidClasses(clForest, 1, clWater, 1, clHill, 1, clPlayer, 13, clMetal, 4, clRock, 4), + clForest, + scaleByMapSize(60, 500)); + yield 85; + + g_Map.log("Creating small grass tufts"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aGrassShort, 1, 2, 0, 1, -Math.PI / 8, Math.PI / 8)]), + 0, + avoidClasses(clWater, 2, clPlayer, 13, clDirt, 0), + scaleByMapSize(13, 200)); + yield 90; + + g_Map.log("Creating large grass tufts"); + createObjectGroupsDeprecated( + 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) + ]), + 0, + avoidClasses(clWater, 3, clPlayer, 13, clDirt, 1, clForest, 0), + scaleByMapSize(13, 200)); + yield 95; + + g_Map.log("Creating bushes"); + createObjectGroupsDeprecated( + new SimpleGroup( [ - new SimpleObject(aFlower, 0, 6, 0, 2), - new SimpleObject(aGrass2, 2, 5, 0, 2) + new SimpleObject(aBushMedium, 1, 2, 0, 2), + new SimpleObject(aBushSmall, 2, 4, 0, 2) ]), - 0, - avoidClasses(clWater, 1, clHill, 1, clPlayer, 13, clDirt, 1), - scaleByMapSize(13, 200), - 50); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setSkySet("cirrus"); -setWaterColor(0.553, 0.635, 0.345); -setWaterTint(0.161, 0.514, 0.635); -setWaterMurkiness(0.8); -setWaterWaviness(1.0); -setWaterType("clap"); - -setFogThickness(0.25); -setFogFactor(0.6); - -setPPEffect("hdr"); -setPPSaturation(0.44); -setPPBloom(0.3); - -g_Map.ExportMap(); + 0, + avoidClasses(clWater, 1, clPlayer, 13, clDirt, 1), + scaleByMapSize(13, 200), + 50); + + g_Map.log("Creating flowering shrubs"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aShrub, 1, 1, 0, 2)]), + 0, + avoidClasses(clWater, 1, clPlayer, 13, clDirt, 1), + scaleByMapSize(13, 200), + 50); + + g_Map.log("Creating decorative palms"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aPalm, 1, 3, 0, 2)]), + 0, + avoidClasses(clWater, 2, clPlayer, 12, clDirt, 1), + scaleByMapSize(13, 200), + 50); + + g_Map.log("Creating shrubs,flowers and other decorations"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(aFlower, 0, 6, 0, 2), + new SimpleObject(aGrass2, 2, 5, 0, 2) + ]), + 0, + avoidClasses(clWater, 1, clHill, 1, clPlayer, 13, clDirt, 1), + scaleByMapSize(13, 200), + 50); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, + clFood, 2)); + + setSkySet("cirrus"); + setWaterColor(0.553, 0.635, 0.345); + setWaterTint(0.161, 0.514, 0.635); + setWaterMurkiness(0.8); + setWaterWaviness(1.0); + setWaterType("clap"); + + setFogThickness(0.25); + setFogFactor(0.6); + + setPPEffect("hdr"); + setPPSaturation(0.44); + setPPBloom(0.3); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/caledonian_meadows.js =================================================================== --- binaries/data/mods/public/maps/random/caledonian_meadows.js +++ binaries/data/mods/public/maps/random/caledonian_meadows.js @@ -3,420 +3,504 @@ Engine.LoadLibrary("rmbiome"); Engine.LoadLibrary("heightmap"); -const tGrove = "temp_grass_plants"; -const tPath = "road_rome_a"; - -const oGroveEntities = ["structures/gaul/outpost", "gaia/tree/oak_new"]; - -const g_Map = new RandomMap(0, "whiteness"); - -/** - * Design resource spots - */ -// Mines -const decorations = [ - "actor|geology/gray1.xml", "actor|geology/gray_rock1.xml", - "actor|geology/highland1.xml", "actor|geology/highland2.xml", "actor|geology/highland3.xml", - "actor|geology/highland_c.xml", "actor|geology/highland_d.xml", "actor|geology/highland_e.xml", - "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml", - "actor|props/flora/bush_tempe_a.xml", "actor|props/flora/bush_tempe_b.xml", "actor|props/flora/ferns.xml" -]; - -function placeMine(point, centerEntity) +function* GenerateMap() { - g_Map.placeEntityPassable(centerEntity, 0, point, randomAngle()); - const quantity = randIntInclusive(11, 23); - const dAngle = 2 * Math.PI / quantity; - - for (let i = 0; i < quantity; ++i) - g_Map.placeEntityPassable( - pickRandom(decorations), - 0, - Vector2D.add(point, new Vector2D(randFloat(2, 5), 0).rotate(-dAngle * randFloat(i, i + 1))), - randomAngle()); -} + const tGrove = "temp_grass_plants"; + const tPath = "road_rome_a"; -// Food, fences with domestic animals -g_WallStyles.other = { - "overlap": 0, - "fence": readyWallElement("structures/fence_long", "gaia"), - "fence_short": readyWallElement("structures/fence_short", "gaia"), - "bench": { "angle": Math.PI / 2, "length": 1.5, "indent": 0, "bend": 0, "templateName": "structures/bench" }, - "sheep": { "angle": 0, "length": 0, "indent": 0.75, "bend": 0, "templateName": "gaia/fauna_sheep" }, - "foodBin": { "angle": Math.PI / 2, "length": 1.5, "indent": 0, "bend": 0, "templateName": "gaia/treasure/food_bin" }, - "farmstead": { "angle": Math.PI, "length": 0, "indent": -3, "bend": 0, "templateName": "structures/brit/farmstead" } -}; - -const fences = [ - new Fortress("fence", [ - "foodBin", "farmstead", "bench", - "turn_0.25", "sheep", "turn_0.25", "fence", - "turn_0.25", "sheep", "turn_0.25", "fence", - "turn_0.25", "sheep", "turn_0.25", "fence" - ]), - new Fortress("fence", [ - "foodBin", "farmstead", "fence", - "turn_0.25", "sheep", "turn_0.25", "fence", - "turn_0.25", "sheep", "turn_0.25", "bench", "sheep", "fence", - "turn_0.25", "sheep", "turn_0.25", "fence" - ]), - new Fortress("fence", [ - "foodBin", "farmstead", "turn_0.5", "bench", "turn_-0.5", "fence_short", - "turn_0.25", "sheep", "turn_0.25", "fence", - "turn_0.25", "sheep", "turn_0.25", "fence", - "turn_0.25", "sheep", "turn_0.25", "fence_short", "sheep", "fence" - ]), - new Fortress("fence", [ - "foodBin", "farmstead", "turn_0.5", "fence_short", "turn_-0.5", "bench", - "turn_0.25", "sheep", "turn_0.25", "fence", - "turn_0.25", "sheep", "turn_0.25", "fence", - "turn_0.25", "sheep", "turn_0.25", "fence_short", "sheep", "fence" - ]), - new Fortress("fence", [ - "foodBin", "farmstead", "fence", - "turn_0.25", "sheep", "turn_0.25", "bench", "sheep", "fence", - "turn_0.25", "sheep", "turn_0.25", "fence_short", "sheep", "fence", - "turn_0.25", "sheep", "turn_0.25", "fence_short", "sheep", "fence" - ]) -]; -const num = fences.length; -for (let i = 0; i < num; ++i) - fences.push(new Fortress("fence", clone(fences[i].wall).reverse())); - -// Groves, only wood -const groveEntities = ["gaia/tree/bush_temperate", "gaia/tree/euro_beech"]; -const groveActors = [ - "actor|geology/highland1_moss.xml", "actor|geology/highland2_moss.xml", - "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", "actor|props/flora/bush_highlands.xml", - "actor|props/flora/bush_tempe_a.xml", "actor|props/flora/bush_tempe_b.xml", "actor|props/flora/ferns.xml" -]; - -function placeGrove(point) -{ - g_Map.placeEntityPassable(pickRandom(oGroveEntities), 0, point, randomAngle()); - const quantity = randIntInclusive(20, 30); - const dAngle = 2 * Math.PI / quantity; - for (let i = 0; i < quantity; ++i) + const oGroveEntities = ["structures/gaul/outpost", "gaia/tree/oak_new"]; + + global.g_Map = new RandomMap(0, "whiteness"); + + /** + * Design resource spots + */ + // Mines + const decorations = ["actor|geology/gray1.xml", "actor|geology/gray_rock1.xml", + "actor|geology/highland1.xml", "actor|geology/highland2.xml", "actor|geology/highland3.xml", + "actor|geology/highland_c.xml", "actor|geology/highland_d.xml", "actor|geology/highland_e.xml", + "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", + "actor|props/flora/bush_highlands.xml", "actor|props/flora/bush_tempe_a.xml", + "actor|props/flora/bush_tempe_b.xml", "actor|props/flora/ferns.xml"]; + + function placeMine(point, centerEntity) { - const angle = dAngle * randFloat(i, i + 1); - const dist = randFloat(2, 5); - let objectList = groveEntities; - if (i % 3 == 0) - objectList = groveActors; - const position = Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle)); - g_Map.placeEntityPassable(pickRandom(objectList), 0, position, randomAngle()); - createArea( - new ClumpPlacer(5, 1, 1, Infinity, position), - new TerrainPainter(tGrove)); + g_Map.placeEntityPassable(centerEntity, 0, point, randomAngle()); + const quantity = randIntInclusive(11, 23); + const dAngle = 2 * Math.PI / quantity; + + for (let i = 0; i < quantity; ++i) + g_Map.placeEntityPassable( + pickRandom(decorations), + 0, + Vector2D.add(point, + new Vector2D(randFloat(2, 5), 0).rotate(-dAngle * randFloat(i, i + 1))), + randomAngle()); } -} -// Camps with fire and gold treasure -function placeCamp(point, - centerEntity = "actor|props/special/eyecandy/campfire.xml", - otherEntities = ["gaia/treasure/metal", "gaia/treasure/standing_stone", - "units/brit/infantry_slinger_b", "units/brit/infantry_javelineer_b", "units/gaul/infantry_slinger_b", "units/gaul/infantry_javelineer_b", "units/gaul/champion_fanatic", - "actor|props/special/common/waypoint_flag.xml", "actor|props/special/eyecandy/barrel_a.xml", "actor|props/special/eyecandy/basket_celt_a.xml", "actor|props/special/eyecandy/crate_a.xml", "actor|props/special/eyecandy/dummy_a.xml", "actor|props/special/eyecandy/handcart_1.xml", "actor|props/special/eyecandy/handcart_1_broken.xml", "actor|props/special/eyecandy/sack_1.xml", "actor|props/special/eyecandy/sack_1_rough.xml" - ] -) -{ - g_Map.placeEntityPassable(centerEntity, 0, point, randomAngle()); - const quantity = randIntInclusive(5, 11); - const dAngle = 2 * Math.PI / quantity; - for (let i = 0; i < quantity; ++i) + // Food, fences with domestic animals + g_WallStyles.other = { + "overlap": 0, + "fence": readyWallElement("structures/fence_long", "gaia"), + "fence_short": readyWallElement("structures/fence_short", "gaia"), + "bench": { + "angle": Math.PI / 2, + "length": 1.5, + "indent": 0, + "bend": 0, + "templateName": "structures/bench" }, + "sheep": { + "angle": 0, + "length": 0, + "indent": 0.75, + "bend": 0, + "templateName": "gaia/fauna_sheep" }, + "foodBin": { + "angle": Math.PI / 2, + "length": 1.5, + "indent": 0, + "bend": 0, + "templateName": "gaia/treasure/food_bin" }, + "farmstead": { + "angle": Math.PI, + "length": 0, + "indent": -3, + "bend": 0, + "templateName": "structures/brit/farmstead" } + }; + + const fences = [ + new Fortress("fence", [ + "foodBin", "farmstead", "bench", + "turn_0.25", "sheep", "turn_0.25", "fence", + "turn_0.25", "sheep", "turn_0.25", "fence", + "turn_0.25", "sheep", "turn_0.25", "fence" + ]), + new Fortress("fence", [ + "foodBin", "farmstead", "fence", + "turn_0.25", "sheep", "turn_0.25", "fence", + "turn_0.25", "sheep", "turn_0.25", "bench", "sheep", "fence", + "turn_0.25", "sheep", "turn_0.25", "fence" + ]), + new Fortress("fence", [ + "foodBin", "farmstead", "turn_0.5", "bench", "turn_-0.5", "fence_short", + "turn_0.25", "sheep", "turn_0.25", "fence", + "turn_0.25", "sheep", "turn_0.25", "fence", + "turn_0.25", "sheep", "turn_0.25", "fence_short", "sheep", "fence" + ]), + new Fortress("fence", [ + "foodBin", "farmstead", "turn_0.5", "fence_short", "turn_-0.5", "bench", + "turn_0.25", "sheep", "turn_0.25", "fence", + "turn_0.25", "sheep", "turn_0.25", "fence", + "turn_0.25", "sheep", "turn_0.25", "fence_short", "sheep", "fence" + ]), + new Fortress("fence", [ + "foodBin", "farmstead", "fence", + "turn_0.25", "sheep", "turn_0.25", "bench", "sheep", "fence", + "turn_0.25", "sheep", "turn_0.25", "fence_short", "sheep", "fence", + "turn_0.25", "sheep", "turn_0.25", "fence_short", "sheep", "fence" + ]) + ]; + const num = fences.length; + for (let i = 0; i < num; ++i) + fences.push(new Fortress("fence", clone(fences[i].wall).reverse())); + + // Groves, only wood + const groveEntities = ["gaia/tree/bush_temperate", "gaia/tree/euro_beech"]; + const groveActors = ["actor|geology/highland1_moss.xml", "actor|geology/highland2_moss.xml", + "actor|props/flora/bush.xml", "actor|props/flora/bush_dry_a.xml", + "actor|props/flora/bush_highlands.xml", "actor|props/flora/bush_tempe_a.xml", + "actor|props/flora/bush_tempe_b.xml", "actor|props/flora/ferns.xml"]; + + function placeGrove(point) { - const angle = dAngle * randFloat(i, i + 1); - const dist = randFloat(1, 3); - g_Map.placeEntityPassable(pickRandom(otherEntities), 0, Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle)), randomAngle()); + g_Map.placeEntityPassable(pickRandom(oGroveEntities), 0, point, randomAngle()); + const quantity = randIntInclusive(20, 30); + const dAngle = 2 * Math.PI / quantity; + for (let i = 0; i < quantity; ++i) + { + const angle = dAngle * randFloat(i, i + 1); + const dist = randFloat(2, 5); + let objectList = groveEntities; + if (i % 3 == 0) + objectList = groveActors; + const position = Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle)); + g_Map.placeEntityPassable(pickRandom(objectList), 0, position, randomAngle()); + createArea( + new ClumpPlacer(5, 1, 1, Infinity, position), + new TerrainPainter(tGrove)); + } } -} -function placeStartLocationResources(point, foodEntities = ["gaia/fruit/berry_01", "gaia/fauna_chicken", "gaia/fauna_chicken"]) -{ - let currentAngle = randomAngle(); - // Stone and chicken - let dAngle = 4/9 * Math.PI; - let angle = currentAngle + randFloat(1, 3) * dAngle / 4; - const stonePosition = Vector2D.add(point, new Vector2D(12, 0).rotate(-angle)); - placeMine(stonePosition, "gaia/rock/temperate_large"); - currentAngle += dAngle; - - // Wood - let quantity = 80; - dAngle = 2 * Math.PI / quantity / 3; - for (let i = 0; i < quantity; ++i) + // Camps with fire and gold treasure + function placeCamp(point, + centerEntity = "actor|props/special/eyecandy/campfire.xml", + otherEntities = ["gaia/treasure/metal", "gaia/treasure/standing_stone", + "units/brit/infantry_slinger_b", "units/brit/infantry_javelineer_b", + "units/gaul/infantry_slinger_b", "units/gaul/infantry_javelineer_b", + "units/gaul/champion_fanatic", "actor|props/special/common/waypoint_flag.xml", + "actor|props/special/eyecandy/barrel_a.xml", + "actor|props/special/eyecandy/basket_celt_a.xml", + "actor|props/special/eyecandy/crate_a.xml", "actor|props/special/eyecandy/dummy_a.xml", + "actor|props/special/eyecandy/handcart_1.xml", + "actor|props/special/eyecandy/handcart_1_broken.xml", + "actor|props/special/eyecandy/sack_1.xml", + "actor|props/special/eyecandy/sack_1_rough.xml"] + ) { - angle = currentAngle + randFloat(0, dAngle); - let objectList = groveEntities; - if (i % 2 == 0) - objectList = groveActors; - const woodPosition = Vector2D.add(point, new Vector2D(randFloat(10, 15), 0).rotate(-angle)); - g_Map.placeEntityPassable(pickRandom(objectList), 0, woodPosition, randomAngle()); - createArea( - new ClumpPlacer(5, 1, 1, Infinity, woodPosition), - new TerrainPainter("temp_grass_plants")); - currentAngle += dAngle; + g_Map.placeEntityPassable(centerEntity, 0, point, randomAngle()); + const quantity = randIntInclusive(5, 11); + const dAngle = 2 * Math.PI / quantity; + for (let i = 0; i < quantity; ++i) + { + const angle = dAngle * randFloat(i, i + 1); + const dist = randFloat(1, 3); + g_Map.placeEntityPassable(pickRandom(otherEntities), 0, + Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle)), randomAngle()); + } } - // Metal and chicken - dAngle = 2 * Math.PI * 2 / 9; - angle = currentAngle + dAngle * randFloat(1, 3) / 4; - const metalPosition = Vector2D.add(point, new Vector2D(13, 0).rotate(-angle)); - placeMine(metalPosition, "gaia/ore/temperate_large"); - currentAngle += dAngle; - - // Berries - quantity = 15; - dAngle = 2 * Math.PI / quantity * 2 / 9; - for (let i = 0; i < quantity; ++i) + function placeStartLocationResources(point, + foodEntities = ["gaia/fruit/berry_01", "gaia/fauna_chicken", "gaia/fauna_chicken"]) { - angle = currentAngle + randFloat(0, dAngle); - const berriesPosition = Vector2D.add(point, new Vector2D(randFloat(10, 15), 0).rotate(-angle)); - g_Map.placeEntityPassable(pickRandom(foodEntities), 0, berriesPosition, randomAngle()); + let currentAngle = randomAngle(); + // Stone and chicken + let dAngle = 4/9 * Math.PI; + let angle = currentAngle + randFloat(1, 3) * dAngle / 4; + const stonePosition = Vector2D.add(point, new Vector2D(12, 0).rotate(-angle)); + placeMine(stonePosition, "gaia/rock/temperate_large"); + currentAngle += dAngle; + + // Wood + let quantity = 80; + dAngle = 2 * Math.PI / quantity / 3; + for (let i = 0; i < quantity; ++i) + { + angle = currentAngle + randFloat(0, dAngle); + let objectList = groveEntities; + if (i % 2 == 0) + objectList = groveActors; + const woodPosition = Vector2D.add(point, + new Vector2D(randFloat(10, 15), 0).rotate(-angle)); + g_Map.placeEntityPassable(pickRandom(objectList), 0, woodPosition, randomAngle()); + createArea( + new ClumpPlacer(5, 1, 1, Infinity, woodPosition), + new TerrainPainter("temp_grass_plants")); + currentAngle += dAngle; + } + + // Metal and chicken + dAngle = 2 * Math.PI * 2 / 9; + angle = currentAngle + dAngle * randFloat(1, 3) / 4; + const metalPosition = Vector2D.add(point, new Vector2D(13, 0).rotate(-angle)); + placeMine(metalPosition, "gaia/ore/temperate_large"); currentAngle += dAngle; + + // Berries + quantity = 15; + dAngle = 2 * Math.PI / quantity * 2 / 9; + for (let i = 0; i < quantity; ++i) + { + angle = currentAngle + randFloat(0, dAngle); + const berriesPosition = Vector2D.add(point, + new Vector2D(randFloat(10, 15), 0).rotate(-angle)); + g_Map.placeEntityPassable(pickRandom(foodEntities), 0, berriesPosition, randomAngle()); + currentAngle += dAngle; + } } -} -/** - * Environment settings - */ -setBiome("generic/alpine"); -g_Environment.Fog.FogColor = { "r": 0.8, "g": 0.8, "b": 0.8, "a": 0.01 }; -g_Environment.Water.WaterBody.Colour = { "r": 0.3, "g": 0.05, "b": 0.1, "a": 0.1 }; -g_Environment.Water.WaterBody.Murkiness = 0.4; - -/** - * Base terrain shape generation and settings - */ -const heightScale = (g_Map.size + 256) / 768 / 4; -const heightRange = { "min": MIN_HEIGHT * heightScale, "max": MAX_HEIGHT * heightScale }; - -// Water coverage -const averageWaterCoverage = 1/5; // NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with the same value -const heightSeaGround = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); // Water height in environment and the engine -const heightSeaGroundAdjusted = heightSeaGround + MIN_HEIGHT; // Water height in RMGEN -setWaterHeight(heightSeaGround); - -g_Map.log("Generating terrain using diamon-square"); -const medH = (heightRange.min + heightRange.max) / 2; -const initialHeightmap = [[medH, medH], [medH, medH]]; -setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, initialHeightmap, 0.8); - -g_Map.log("Apply erosion"); -for (let i = 0; i < 5; ++i) - splashErodeMap(0.1); - -rescaleHeightmap(heightRange.min, heightRange.max); - -Engine.SetProgress(25); - -const heighLimits = [ - heightRange.min + 1/3 * (heightSeaGroundAdjusted - heightRange.min), // 0 Deep water - heightRange.min + 2/3 * (heightSeaGroundAdjusted - heightRange.min), // 1 Medium Water - heightRange.min + (heightSeaGroundAdjusted - heightRange.min), // 2 Shallow water - heightSeaGroundAdjusted + 1/8 * (heightRange.max - heightSeaGroundAdjusted), // 3 Shore - heightSeaGroundAdjusted + 2/8 * (heightRange.max - heightSeaGroundAdjusted), // 4 Low ground - heightSeaGroundAdjusted + 3/8 * (heightRange.max - heightSeaGroundAdjusted), // 5 Player and path height - heightSeaGroundAdjusted + 4/8 * (heightRange.max - heightSeaGroundAdjusted), // 6 High ground - heightSeaGroundAdjusted + 5/8 * (heightRange.max - heightSeaGroundAdjusted), // 7 Lower forest border - heightSeaGroundAdjusted + 6/8 * (heightRange.max - heightSeaGroundAdjusted), // 8 Forest - heightSeaGroundAdjusted + 7/8 * (heightRange.max - heightSeaGroundAdjusted), // 9 Upper forest border - heightSeaGroundAdjusted + (heightRange.max - heightSeaGroundAdjusted)]; // 10 Hilltop - -const playerHeight = (heighLimits[4] + heighLimits[5]) / 2; // Average player height - -g_Map.log("Determining height-dependent biome"); -// Texture and actor presets -const myBiome = []; -myBiome.push({ // 0 Deep water - "texture": ["shoreline_stoney_a"], - "entity": [["gaia/fish/generic", "actor|geology/stone_granite_boulder.xml"], 0.02], - "textureHS": ["alpine_mountainside"], "entityHS": [["gaia/fish/generic"], 0.1] -}); -myBiome.push({ // 1 Medium Water - "texture": ["shoreline_stoney_a", "alpine_shore_rocks"], - "entity": [["actor|geology/stone_granite_boulder.xml", "actor|geology/stone_granite_med.xml"], 0.03], - "textureHS": ["alpine_mountainside"], "entityHS": [["actor|geology/stone_granite_boulder.xml", "actor|geology/stone_granite_med.xml"], 0.0] -}); -myBiome.push({ // 2 Shallow water - "texture": ["alpine_shore_rocks"], - "entity": [["actor|props/flora/reeds_pond_dry.xml", "actor|geology/stone_granite_large.xml", "actor|geology/stone_granite_med.xml", "actor|props/flora/reeds_pond_lush_b.xml"], 0.2], - "textureHS": ["alpine_mountainside"], "entityHS": [["actor|props/flora/reeds_pond_dry.xml", "actor|geology/stone_granite_med.xml"], 0.1] -}); -myBiome.push({ // 3 Shore - "texture": ["alpine_shore_rocks_grass_50", "alpine_grass_rocky"], - "entity": [["gaia/tree/pine", "gaia/tree/bush_badlands", "actor|geology/highland1_moss.xml", "actor|props/flora/grass_soft_tuft_a.xml", "actor|props/flora/bush.xml"], 0.3], - "textureHS": ["alpine_mountainside"], "entityHS": [["actor|props/flora/grass_soft_tuft_a.xml"], 0.1] -}); -myBiome.push({ // 4 Low ground - "texture": ["alpine_dirt_grass_50", "alpine_grass_rocky"], - "entity": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_soft_tuft_a.xml", "actor|props/flora/bush.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], - "textureHS": ["alpine_grass_rocky"], "entityHS": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_soft_tuft_a.xml"], 0.1] -}); -myBiome.push({ // 5 Player and path height - "texture": ["new_alpine_grass_c", "new_alpine_grass_b", "new_alpine_grass_d"], - "entity": [["actor|geology/stone_granite_small.xml", "actor|props/flora/grass_soft_small.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], - "textureHS": ["alpine_grass_rocky"], "entityHS": [["actor|geology/stone_granite_small.xml", "actor|props/flora/grass_soft_small.xml"], 0.1] -}); -myBiome.push({ // 6 High ground - "texture": ["new_alpine_grass_a", "alpine_grass_rocky"], - "entity": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_tufts_a.xml", "actor|props/flora/bush_highlands.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], - "textureHS": ["alpine_grass_rocky"], "entityHS": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_tufts_a.xml"], 0.1] -}); -myBiome.push({ // 7 Lower forest border - "texture": ["new_alpine_grass_mossy", "alpine_grass_rocky"], - "entity": [["gaia/tree/pine", "gaia/tree/oak", "actor|props/flora/grass_tufts_a.xml", "gaia/fruit/berry_01", "actor|geology/highland2_moss.xml", "gaia/fauna_goat", "actor|props/flora/bush_tempe_underbrush.xml"], 0.3], - "textureHS": ["alpine_cliff_c"], "entityHS": [["actor|props/flora/grass_tufts_a.xml", "actor|geology/highland2_moss.xml"], 0.1] -}); -myBiome.push({ // 8 Forest - "texture": ["alpine_forrestfloor"], - "entity": [["gaia/tree/pine", "gaia/tree/pine", "gaia/tree/pine", "gaia/tree/pine", "actor|geology/highland2_moss.xml", "actor|props/flora/bush_highlands.xml"], 0.5], - "textureHS": ["alpine_cliff_c"], "entityHS": [["actor|geology/highland2_moss.xml", "actor|geology/stone_granite_med.xml"], 0.1] -}); -myBiome.push({ // 9 Upper forest border - "texture": ["alpine_forrestfloor_snow", "new_alpine_grass_dirt_a"], - "entity": [["gaia/tree/pine", "actor|geology/snow1.xml"], 0.3], - "textureHS": ["alpine_cliff_b"], "entityHS": [["actor|geology/stone_granite_med.xml", "actor|geology/snow1.xml"], 0.1] -}); -myBiome.push({ // 10 Hilltop - "texture": ["alpine_cliff_a", "alpine_cliff_snow"], - "entity": [["actor|geology/highland1.xml"], 0.05], - "textureHS": ["alpine_cliff_c"], "entityHS": [["actor|geology/highland1.xml"], 0.0] -}); - -const [playerIDs, playerPosition] = groupPlayersCycle(getStartLocationsByHeightmap({ "min": heighLimits[4], "max": heighLimits[5] }, 1000, 30)); -Engine.SetProgress(30); - -g_Map.log("Smoothing player locations"); -for (const position of playerPosition) - createArea( - new DiskPlacer(35, position), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 35)); + /** + * Environment settings + */ + setBiome("generic/alpine"); + g_Environment.Fog.FogColor = { "r": 0.8, "g": 0.8, "b": 0.8, "a": 0.01 }; + g_Environment.Water.WaterBody.Colour = { "r": 0.3, "g": 0.05, "b": 0.1, "a": 0.1 }; + g_Environment.Water.WaterBody.Murkiness = 0.4; + + /** + * Base terrain shape generation and settings + */ + const heightScale = (g_Map.size + 256) / 768 / 4; + const heightRange = { "min": MIN_HEIGHT * heightScale, "max": MAX_HEIGHT * heightScale }; + + // Water coverage + // NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with + // the same value + const averageWaterCoverage = 1/5; + // Water height in environment and the engine + const heightSeaGround = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * + (heightRange.max - heightRange.min); + // Water height in RMGEN + const heightSeaGroundAdjusted = heightSeaGround + MIN_HEIGHT; + setWaterHeight(heightSeaGround); + + g_Map.log("Generating terrain using diamon-square"); + const medH = (heightRange.min + heightRange.max) / 2; + const initialHeightmap = [[medH, medH], [medH, medH]]; + setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, initialHeightmap, 0.8); + + g_Map.log("Apply erosion"); + for (let i = 0; i < 5; ++i) + splashErodeMap(0.1); + + rescaleHeightmap(heightRange.min, heightRange.max); + + yield 25; + + const heighLimits = [ + // 0 Deep water + heightRange.min + 1/3 * (heightSeaGroundAdjusted - heightRange.min), + // 1 Medium Water + heightRange.min + 2/3 * (heightSeaGroundAdjusted - heightRange.min), + // 2 Shallow water + heightRange.min + (heightSeaGroundAdjusted - heightRange.min), + // 3 Shore + heightSeaGroundAdjusted + 1/8 * (heightRange.max - heightSeaGroundAdjusted), + // 4 Low ground + heightSeaGroundAdjusted + 2/8 * (heightRange.max - heightSeaGroundAdjusted), + // 5 Player and path height + heightSeaGroundAdjusted + 3/8 * (heightRange.max - heightSeaGroundAdjusted), + // 6 High ground + heightSeaGroundAdjusted + 4/8 * (heightRange.max - heightSeaGroundAdjusted), + // 7 Lower forest border + heightSeaGroundAdjusted + 5/8 * (heightRange.max - heightSeaGroundAdjusted), + // 8 Forest + heightSeaGroundAdjusted + 6/8 * (heightRange.max - heightSeaGroundAdjusted), + // 9 Upper forest border + heightSeaGroundAdjusted + 7/8 * (heightRange.max - heightSeaGroundAdjusted), + // 10 Hilltop + heightSeaGroundAdjusted + (heightRange.max - heightSeaGroundAdjusted)]; + + const playerHeight = (heighLimits[4] + heighLimits[5]) / 2; // Average player height + + g_Map.log("Determining height-dependent biome"); + // Texture and actor presets + const myBiome = []; + myBiome.push({ // 0 Deep water + "texture": ["shoreline_stoney_a"], + "entity": [["gaia/fish/generic", "actor|geology/stone_granite_boulder.xml"], 0.02], + "textureHS": ["alpine_mountainside"], + "entityHS": [["gaia/fish/generic"], 0.1] + }); + myBiome.push({ // 1 Medium Water + "texture": ["shoreline_stoney_a", "alpine_shore_rocks"], + "entity": [["actor|geology/stone_granite_boulder.xml", "actor|geology/stone_granite_med.xml"], + 0.03], + "textureHS": ["alpine_mountainside"], + "entityHS": [["actor|geology/stone_granite_boulder.xml", "actor|geology/stone_granite_med.xml"], + 0.0] + }); + myBiome.push({ // 2 Shallow water + "texture": ["alpine_shore_rocks"], + "entity": [["actor|props/flora/reeds_pond_dry.xml", "actor|geology/stone_granite_large.xml", + "actor|geology/stone_granite_med.xml", "actor|props/flora/reeds_pond_lush_b.xml"], 0.2], + "textureHS": ["alpine_mountainside"], + "entityHS": [["actor|props/flora/reeds_pond_dry.xml", "actor|geology/stone_granite_med.xml"], + 0.1] + }); + myBiome.push({ // 3 Shore + "texture": ["alpine_shore_rocks_grass_50", "alpine_grass_rocky"], + "entity": [["gaia/tree/pine", "gaia/tree/bush_badlands", "actor|geology/highland1_moss.xml", + "actor|props/flora/grass_soft_tuft_a.xml", "actor|props/flora/bush.xml"], 0.3], + "textureHS": ["alpine_mountainside"], + "entityHS": [["actor|props/flora/grass_soft_tuft_a.xml"], 0.1] + }); + myBiome.push({ // 4 Low ground + "texture": ["alpine_dirt_grass_50", "alpine_grass_rocky"], + "entity": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_soft_tuft_a.xml", + "actor|props/flora/bush.xml", "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], + "textureHS": ["alpine_grass_rocky"], + "entityHS": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_soft_tuft_a.xml"], + 0.1] + }); + myBiome.push({ // 5 Player and path height + "texture": ["new_alpine_grass_c", "new_alpine_grass_b", "new_alpine_grass_d"], + "entity": [["actor|geology/stone_granite_small.xml", "actor|props/flora/grass_soft_small.xml", + "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], + "textureHS": ["alpine_grass_rocky"], + "entityHS": [["actor|geology/stone_granite_small.xml", + "actor|props/flora/grass_soft_small.xml"], 0.1] + }); + myBiome.push({ // 6 High ground + "texture": ["new_alpine_grass_a", "alpine_grass_rocky"], + "entity": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_tufts_a.xml", + "actor|props/flora/bush_highlands.xml", + "actor|props/flora/grass_medit_flowering_tall.xml"], 0.2], + "textureHS": ["alpine_grass_rocky"], + "entityHS": [["actor|geology/stone_granite_med.xml", "actor|props/flora/grass_tufts_a.xml"], + 0.1] + }); + myBiome.push({ // 7 Lower forest border + "texture": ["new_alpine_grass_mossy", "alpine_grass_rocky"], + "entity": [["gaia/tree/pine", "gaia/tree/oak", "actor|props/flora/grass_tufts_a.xml", + "gaia/fruit/berry_01", "actor|geology/highland2_moss.xml", "gaia/fauna_goat", + "actor|props/flora/bush_tempe_underbrush.xml"], 0.3], + "textureHS": ["alpine_cliff_c"], + "entityHS": [["actor|props/flora/grass_tufts_a.xml", "actor|geology/highland2_moss.xml"], 0.1] + }); + myBiome.push({ // 8 Forest + "texture": ["alpine_forrestfloor"], + "entity": [["gaia/tree/pine", "gaia/tree/pine", "gaia/tree/pine", "gaia/tree/pine", + "actor|geology/highland2_moss.xml", "actor|props/flora/bush_highlands.xml"], 0.5], + "textureHS": ["alpine_cliff_c"], + "entityHS": [["actor|geology/highland2_moss.xml", "actor|geology/stone_granite_med.xml"], 0.1] + }); + myBiome.push({ // 9 Upper forest border + "texture": ["alpine_forrestfloor_snow", "new_alpine_grass_dirt_a"], + "entity": [["gaia/tree/pine", "actor|geology/snow1.xml"], 0.3], + "textureHS": ["alpine_cliff_b"], + "entityHS": [["actor|geology/stone_granite_med.xml", "actor|geology/snow1.xml"], 0.1] + }); + myBiome.push({ // 10 Hilltop + "texture": ["alpine_cliff_a", "alpine_cliff_snow"], + "entity": [["actor|geology/highland1.xml"], 0.05], + "textureHS": ["alpine_cliff_c"], "entityHS": [["actor|geology/highland1.xml"], 0.0] + }); + + const [playerIDs, playerPosition] = groupPlayersCycle(getStartLocationsByHeightmap( + { + "min": heighLimits[4], + "max": heighLimits[5] + }, 1000, 30)); + yield 30; -g_Map.log("Creating paths between players"); -const clPath = g_Map.createTileClass(); -for (let i = 0; i < playerPosition.length; ++i) + g_Map.log("Smoothing player locations"); + for (const position of playerPosition) + createArea( + new DiskPlacer(35, position), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 35)); + + g_Map.log("Creating paths between players"); + const clPath = g_Map.createTileClass(); + for (let i = 0; i < playerPosition.length; ++i) + createArea( + new RandomPathPlacer(playerPosition[i], playerPosition[(i + 1) % playerPosition.length], + 4, 2, false), + [ + new TerrainPainter(tPath), + new ElevationBlendingPainter(playerHeight, 0.4), + new TileClassPainter(clPath) + ]); + + g_Map.log("Smoothing paths"); createArea( - new RandomPathPlacer(playerPosition[i], playerPosition[(i + 1) % playerPosition.length], 4, 2, false), - [ - new TerrainPainter(tPath), - new ElevationBlendingPainter(playerHeight, 0.4), - new TileClassPainter(clPath) - ]); - -g_Map.log("Smoothing paths"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(5, 1, 1), - new NearTileClassConstraint(clPath, 5)); - -Engine.SetProgress(45); - -g_Map.log("Determining resource locations"); -const avoidPoints = playerPosition.map(pos => pos.clone()); -for (let i = 0; i < avoidPoints.length; ++i) - avoidPoints[i].dist = 30; -const resourceSpots = getPointsByHeight({ "min": (heighLimits[3] + heighLimits[4]) / 2, "max": (heighLimits[5] + heighLimits[6]) / 2 }, avoidPoints, clPath); -Engine.SetProgress(55); - -/** - * Divide tiles in areas by height and avoid paths - */ -const tchm = getTileCenteredHeightmap(); -const areas = heighLimits.map(heightLimit => []); -for (let x = 0; x < tchm.length; ++x) - for (let y = 0; y < tchm[0].length; ++y) - { - const position = new Vector2D(x, y); - if (!avoidClasses(clPath, 0).allows(position)) - continue; + new MapBoundsPlacer(), + new SmoothingPainter(5, 1, 1), + new NearTileClassConstraint(clPath, 5)); + + yield 45; - let minHeight = heightRange.min; - for (let h = 0; h < heighLimits.length; ++h) + g_Map.log("Determining resource locations"); + const avoidPoints = playerPosition.map(pos => pos.clone()); + for (let i = 0; i < avoidPoints.length; ++i) + avoidPoints[i].dist = 30; + const resourceSpots = getPointsByHeight( { - if (tchm[x][y] >= minHeight && tchm[x][y] <= heighLimits[h]) + "min": (heighLimits[3] + heighLimits[4]) / 2, + "max": (heighLimits[5] + heighLimits[6]) / 2 + }, avoidPoints, clPath); + yield 55; + + /** + * Divide tiles in areas by height and avoid paths + */ + const tchm = getTileCenteredHeightmap(); + const areas = heighLimits.map(heightLimit => []); + for (let x = 0; x < tchm.length; ++x) + for (let y = 0; y < tchm[0].length; ++y) + { + const position = new Vector2D(x, y); + if (!avoidClasses(clPath, 0).allows(position)) + continue; + + let minHeight = heightRange.min; + for (let h = 0; h < heighLimits.length; ++h) { - areas[h].push(position); - break; - } + if (tchm[x][y] >= minHeight && tchm[x][y] <= heighLimits[h]) + { + areas[h].push(position); + break; + } - minHeight = heighLimits[h]; + minHeight = heighLimits[h]; + } } - } -/** - * Get max slope of each area - */ -const slopeMap = getSlopeMap(); -const minSlope = []; -const maxSlope = []; -for (let h = 0; h < heighLimits.length; ++h) -{ - minSlope[h] = Infinity; - maxSlope[h] = 0; - for (const point of areas[h]) + /** + * Get max slope of each area + */ + const slopeMap = getSlopeMap(); + const minSlope = []; + const maxSlope = []; + for (let h = 0; h < heighLimits.length; ++h) { - const slope = slopeMap[point.x][point.y]; + minSlope[h] = Infinity; + maxSlope[h] = 0; + for (const point of areas[h]) + { + const slope = slopeMap[point.x][point.y]; - if (slope > maxSlope[h]) - maxSlope[h] = slope; + if (slope > maxSlope[h]) + maxSlope[h] = slope; - if (slope < minSlope[h]) - minSlope[h] = slope; + if (slope < minSlope[h]) + minSlope[h] = slope; + } } -} -g_Map.log("Painting areas by height and slope"); -for (let h = 0; h < heighLimits.length; ++h) - for (const point of areas[h]) - { - let entity; - let texture = pickRandom(myBiome[h].texture); - - if (slopeMap[point.x][point.y] < 0.4 * (minSlope[h] + maxSlope[h])) + g_Map.log("Painting areas by height and slope"); + for (let h = 0; h < heighLimits.length; ++h) + for (const point of areas[h]) { - if (randBool(myBiome[h].entity[1])) - entity = pickRandom(myBiome[h].entity[0]); + let entity; + let texture = pickRandom(myBiome[h].texture); + + if (slopeMap[point.x][point.y] < 0.4 * (minSlope[h] + maxSlope[h])) + { + if (randBool(myBiome[h].entity[1])) + entity = pickRandom(myBiome[h].entity[0]); + } + else + { + texture = pickRandom(myBiome[h].textureHS); + if (randBool(myBiome[h].entityHS[1])) + entity = pickRandom(myBiome[h].entityHS[0]); + } + + g_Map.setTexture(point, texture); + + if (entity) + g_Map.placeEntityPassable(entity, 0, randomPositionOnTile(point), randomAngle()); } - else + yield 80; + + g_Map.log("Placing players"); + if (isNomad()) + placePlayersNomad(g_Map.createTileClass(), + new HeightConstraint(heighLimits[4], heighLimits[5])); + else + for (let p = 0; p < playerIDs.length; ++p) { - texture = pickRandom(myBiome[h].textureHS); - if (randBool(myBiome[h].entityHS[1])) - entity = pickRandom(myBiome[h].entityHS[0]); + placeCivDefaultStartingEntities(playerPosition[p], playerIDs[p], true); + placeStartLocationResources(playerPosition[p]); } - g_Map.setTexture(point, texture); - - if (entity) - g_Map.placeEntityPassable(entity, 0, randomPositionOnTile(point), randomAngle()); - } -Engine.SetProgress(80); - -g_Map.log("Placing players"); -if (isNomad()) - placePlayersNomad(g_Map.createTileClass(), new HeightConstraint(heighLimits[4], heighLimits[5])); -else - for (let p = 0; p < playerIDs.length; ++p) + g_Map.log("Placing resources, farmsteads, groves and camps"); + for (let i = 0; i < resourceSpots.length; ++i) { - placeCivDefaultStartingEntities(playerPosition[p], playerIDs[p], true); - placeStartLocationResources(playerPosition[p]); + const pos = new Vector2D(resourceSpots[i].x, resourceSpots[i].y); + const choice = i % (isNomad() ? 4 : 5); + if (choice == 0) + placeMine(pos, "gaia/rock/temperate_large_02"); + if (choice == 1) + placeMine(pos, "gaia/ore/temperate_large"); + if (choice == 2) + placeCustomFortress(pos, pickRandom(fences), "other", 0, randomAngle()); + if (choice == 3) + placeGrove(pos); + if (choice == 4) + placeCamp(pos); } -g_Map.log("Placing resources, farmsteads, groves and camps"); -for (let i = 0; i < resourceSpots.length; ++i) -{ - const pos = new Vector2D(resourceSpots[i].x, resourceSpots[i].y); - const choice = i % (isNomad() ? 4 : 5); - if (choice == 0) - placeMine(pos, "gaia/rock/temperate_large_02"); - if (choice == 1) - placeMine(pos, "gaia/ore/temperate_large"); - if (choice == 2) - placeCustomFortress(pos, pickRandom(fences), "other", 0, randomAngle()); - if (choice == 3) - placeGrove(pos); - if (choice == 4) - placeCamp(pos); + return g_Map; } - -g_Map.ExportMap(); Index: binaries/data/mods/public/maps/random/cantabrian_highlands.js =================================================================== --- binaries/data/mods/public/maps/random/cantabrian_highlands.js +++ binaries/data/mods/public/maps/random/cantabrian_highlands.js @@ -2,278 +2,287 @@ Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); -setSelectedBiome(); - -const tPrimary = g_Terrains.mainTerrain; -const tGrass = [g_Terrains.tier1Terrain, g_Terrains.tier2Terrain]; -const tGrassPForest = g_Terrains.forestFloor1; -const tGrassDForest = g_Terrains.forestFloor2; -const tGrassA = g_Terrains.tier2Terrain; -const tGrassB = g_Terrains.tier3Terrain; -const tGrassC = g_Terrains.tier4Terrain; -const tHill = g_Terrains.hill; -const tCliff = g_Terrains.cliff; -const tRoad = g_Terrains.road; -const tRoadWild = g_Terrains.roadWild; -const tGrassPatchBlend = g_Terrains.tier2Terrain; -const tGrassPatch = g_Terrains.tier1Terrain; -const tShoreBlend = g_Terrains.shoreBlend; -const tShore = g_Terrains.shore; -const tWater = g_Terrains.water; - -const oOak = g_Gaia.tree1; -const oOakLarge = g_Gaia.tree2; -const oApple = g_Gaia.tree3; -const oPine = g_Gaia.tree4; -const oAleppoPine = g_Gaia.tree5; -const oBerryBush = g_Gaia.fruitBush; -const oDeer = g_Gaia.mainHuntableAnimal; -const oFish = g_Gaia.fish; -const oSheep = g_Gaia.secondaryHuntableAnimal; -const oStoneLarge = g_Gaia.stoneLarge; -const oStoneSmall = g_Gaia.stoneSmall; -const oMetalLarge = g_Gaia.metalLarge; -const oMetalSmall = g_Gaia.metalSmall; - -const aGrass = g_Decoratives.grass; -const aGrassShort = g_Decoratives.grassShort; -const aReeds = g_Decoratives.reeds; -const aLillies = g_Decoratives.lillies; -const aRockLarge = g_Decoratives.rockLarge; -const aRockMedium = g_Decoratives.rockMedium; -const aBushMedium = g_Decoratives.bushMedium; -const aBushSmall = g_Decoratives.bushSmall; - -const pForestD = [tGrassDForest + TERRAIN_SEPARATOR + oOak, tGrassDForest + TERRAIN_SEPARATOR + oOakLarge, tGrassDForest]; -const pForestP = [tGrassPForest + TERRAIN_SEPARATOR + oPine, tGrassPForest + TERRAIN_SEPARATOR + oAleppoPine, tGrassPForest]; - -const heightSeaGround = -7; -const heightLand = 3; -const heightHill = 20; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -const playerHillRadius = defaultPlayerBaseRadius() / (isNomad() ? 1.5 : 1); - -const [playerIDs, playerPosition, playerAngle] = playerPlacementCircle(fractionToTiles(0.35)); - -g_Map.log("Creating player hills and ramps"); -for (let i = 0; i < numPlayers; ++i) +function* GenerateMap() { - createArea( - new ClumpPlacer(diskArea(playerHillRadius), 0.95, 0.6, Infinity, playerPosition[i]), - [ - new LayeredPainter([tCliff, tHill], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clPlayer) - ]); - - const angle = playerAngle[i] + Math.PI * (1 + randFloat(-1, 1) / 8); - createPassage({ - "start": Vector2D.add(playerPosition[i], new Vector2D(playerHillRadius + 15, 0).rotate(-angle)), - "end": Vector2D.add(playerPosition[i], new Vector2D(playerHillRadius - 3, 0).rotate(-angle)), - "startWidth": 10, - "endWidth": 10, - "smoothWidth": 2, - "tileClass": clPlayer, - "terrain": tHill, - "edgeTerrain": tCliff + setSelectedBiome(); + + const tPrimary = g_Terrains.mainTerrain; + const tGrass = [g_Terrains.tier1Terrain, g_Terrains.tier2Terrain]; + const tGrassPForest = g_Terrains.forestFloor1; + const tGrassDForest = g_Terrains.forestFloor2; + const tGrassA = g_Terrains.tier2Terrain; + const tGrassB = g_Terrains.tier3Terrain; + const tGrassC = g_Terrains.tier4Terrain; + const tHill = g_Terrains.hill; + const tCliff = g_Terrains.cliff; + const tRoad = g_Terrains.road; + const tRoadWild = g_Terrains.roadWild; + const tGrassPatchBlend = g_Terrains.tier2Terrain; + const tGrassPatch = g_Terrains.tier1Terrain; + const tShoreBlend = g_Terrains.shoreBlend; + const tShore = g_Terrains.shore; + const tWater = g_Terrains.water; + + const oOak = g_Gaia.tree1; + const oOakLarge = g_Gaia.tree2; + const oApple = g_Gaia.tree3; + const oPine = g_Gaia.tree4; + const oAleppoPine = g_Gaia.tree5; + const oBerryBush = g_Gaia.fruitBush; + const oDeer = g_Gaia.mainHuntableAnimal; + const oFish = g_Gaia.fish; + const oSheep = g_Gaia.secondaryHuntableAnimal; + const oStoneLarge = g_Gaia.stoneLarge; + const oStoneSmall = g_Gaia.stoneSmall; + const oMetalLarge = g_Gaia.metalLarge; + const oMetalSmall = g_Gaia.metalSmall; + + const aGrass = g_Decoratives.grass; + const aGrassShort = g_Decoratives.grassShort; + const aReeds = g_Decoratives.reeds; + const aLillies = g_Decoratives.lillies; + const aRockLarge = g_Decoratives.rockLarge; + const aRockMedium = g_Decoratives.rockMedium; + const aBushMedium = g_Decoratives.bushMedium; + const aBushSmall = g_Decoratives.bushSmall; + + const pForestD = [tGrassDForest + TERRAIN_SEPARATOR + oOak, + tGrassDForest + TERRAIN_SEPARATOR + oOakLarge, tGrassDForest]; + const pForestP = [tGrassPForest + TERRAIN_SEPARATOR + oPine, + tGrassPForest + TERRAIN_SEPARATOR + oAleppoPine, tGrassPForest]; + + const heightSeaGround = -7; + const heightLand = 3; + const heightHill = 20; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + const playerHillRadius = defaultPlayerBaseRadius() / (isNomad() ? 1.5 : 1); + + const [playerIDs, playerPosition, playerAngle] = playerPlacementCircle(fractionToTiles(0.35)); + + g_Map.log("Creating player hills and ramps"); + for (let i = 0; i < numPlayers; ++i) + { + createArea( + new ClumpPlacer(diskArea(playerHillRadius), 0.95, 0.6, Infinity, playerPosition[i]), + [ + new LayeredPainter([tCliff, tHill], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clPlayer) + ]); + + const angle = playerAngle[i] + Math.PI * (1 + randFloat(-1, 1) / 8); + createPassage({ + "start": Vector2D.add(playerPosition[i], + new Vector2D(playerHillRadius + 15, 0).rotate(-angle)), + "end": Vector2D.add(playerPosition[i], + new Vector2D(playerHillRadius - 3, 0).rotate(-angle)), + "startWidth": 10, + "endWidth": 10, + "smoothWidth": 2, + "tileClass": clPlayer, + "terrain": tHill, + "edgeTerrain": tCliff + }); + } + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "Walls": false, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oOak, + "count": 2 + }, + "Decoratives": { + "template": aGrassShort + } }); -} + yield 10; -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "Walls": false, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oOak, - "count": 2 - }, - "Decoratives": { - "template": aGrassShort - } -}); -Engine.SetProgress(10); - -g_Map.log("Creating lakes"); -const numLakes = Math.round(scaleByMapSize(1,4) * numPlayers); -const waterAreas = createAreas( - new ClumpPlacer(scaleByMapSize(100, 250), 0.8, 0.1, Infinity), - [ - new LayeredPainter([tShoreBlend, tShore, tWater], [1, 1]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 6), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 2, clWater, 20), - numLakes -); -Engine.SetProgress(15); - -g_Map.log("Creating reeds"); -const group = new SimpleGroup( - [new SimpleObject(aReeds, 5,10, 0,4), new SimpleObject(aLillies, 0,1, 0,4)], true -); -createObjectGroupsByAreas(group, 0, - [borderClasses(clWater, 3, 0), stayClasses(clWater, 1)], - numLakes, 100, - waterAreas -); -Engine.SetProgress(20); - -g_Map.log("Creating fish"); -createObjectGroupsByAreas( - new SimpleGroup( - [new SimpleObject(oFish, 1,1, 0,1)], - true, clFood - ), - 0, - [stayClasses(clWater, 4), avoidClasses(clFood, 8)], - numLakes / 4, - 50, - waterAreas -); -Engine.SetProgress(25); - -createBumps(avoidClasses(clWater, 2, clPlayer, 0)); -Engine.SetProgress(30); - -createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 2, clWater, 5, clHill, 15), clHill, scaleByMapSize(1, 4) * numPlayers); -Engine.SetProgress(35); - -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); -createDefaultForests( - [tGrass, tGrassDForest, tGrassPForest, pForestP, pForestD], - avoidClasses(clPlayer, 1, clWater, 3, clForest, 17, clHill, 1), - clForest, - forestTrees); -Engine.SetProgress(40); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tGrass,tGrassA],[tGrassA,tGrassB], [tGrassB,tGrassC]], - [1,1], - avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(45); - -g_Map.log("Creating grass patches"); -createLayeredPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - [tGrassPatchBlend, tGrassPatch], - [1], - avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(50); - -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - avoidClasses(clWater, 0, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1) -); - -g_Map.log("Creating stone mines"); -createBalancedStoneMines( - oStoneSmall, - oStoneLarge, - clRock, - avoidClasses(clWater, 0, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1, clMetal, 10) -); - -Engine.SetProgress(60); - -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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13) - ], - avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); -Engine.SetProgress(70); - -createFood( - [ - [new SimpleObject(oSheep, 2, 3, 0, 2)], - [new SimpleObject(oDeer, 5, 7, 0, 4)] - ], - [ - 3 * numPlayers, - 3 * numPlayers - ], - avoidClasses(clWater, 0, clForest, 0, clPlayer, 1, clHill, 1, clFood, 20), - clFood); -Engine.SetProgress(80); - -createFood( - [ - [new SimpleObject(oBerryBush, 5, 7, 0, 4)] - ], - [ - randIntInclusive(1, 4) * numPlayers + 2 - ], - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - clFood); -Engine.SetProgress(85); - -createStragglerTrees( - [oOak, oOakLarge, oPine, oApple], - avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 1, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); -Engine.SetProgress(90); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setSkySet("cirrus"); -setWaterColor(0.447, 0.412, 0.322); // muddy brown -setWaterTint(0.447, 0.412, 0.322); -setWaterMurkiness(1.0); -setWaterWaviness(3.0); -setWaterType("lake"); - -setFogThickness(0.25); -setFogFactor(0.4); - -g_Map.ExportMap(); + g_Map.log("Creating lakes"); + const numLakes = Math.round(scaleByMapSize(1,4) * numPlayers); + const waterAreas = createAreas( + new ClumpPlacer(scaleByMapSize(100, 250), 0.8, 0.1, Infinity), + [ + new LayeredPainter([tShoreBlend, tShore, tWater], [1, 1]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 6), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 2, clWater, 20), + numLakes + ); + yield 15; + + g_Map.log("Creating reeds"); + const group = new SimpleGroup( + [new SimpleObject(aReeds, 5,10, 0,4), new SimpleObject(aLillies, 0,1, 0,4)], true + ); + createObjectGroupsByAreas(group, 0, + [borderClasses(clWater, 3, 0), stayClasses(clWater, 1)], + numLakes, 100, + waterAreas + ); + yield 20; + + g_Map.log("Creating fish"); + createObjectGroupsByAreas( + new SimpleGroup( + [new SimpleObject(oFish, 1,1, 0,1)], + true, clFood + ), + 0, + [stayClasses(clWater, 4), avoidClasses(clFood, 8)], + numLakes / 4, + 50, + waterAreas + ); + yield 25; + + createBumps(avoidClasses(clWater, 2, clPlayer, 0)); + yield 30; + + createHills([tCliff, tCliff, tHill], + avoidClasses(clPlayer, 2, clWater, 5, clHill, 15), clHill, scaleByMapSize(1, 4) * numPlayers); + yield 35; + + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + createDefaultForests( + [tGrass, tGrassDForest, tGrassPForest, pForestP, pForestD], + avoidClasses(clPlayer, 1, clWater, 3, clForest, 17, clHill, 1), + clForest, + forestTrees); + yield 40; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tGrass,tGrassA],[tGrassA,tGrassB], [tGrassB,tGrassC]], + [1,1], + avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), + scaleByMapSize(15, 45), + clDirt); + yield 45; + + g_Map.log("Creating grass patches"); + createLayeredPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + [tGrassPatchBlend, tGrassPatch], + [1], + avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), + scaleByMapSize(15, 45), + clDirt); + yield 50; + + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + avoidClasses(clWater, 0, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1) + ); + + g_Map.log("Creating stone mines"); + createBalancedStoneMines( + oStoneSmall, + oStoneLarge, + clRock, + avoidClasses(clWater, 0, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1, clMetal, 10) + ); + + yield 60; + + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13) + ], + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); + yield 70; + + createFood( + [ + [new SimpleObject(oSheep, 2, 3, 0, 2)], + [new SimpleObject(oDeer, 5, 7, 0, 4)] + ], + [ + 3 * numPlayers, + 3 * numPlayers + ], + avoidClasses(clWater, 0, clForest, 0, clPlayer, 1, clHill, 1, clFood, 20), + clFood); + yield 80; + + createFood( + [ + [new SimpleObject(oBerryBush, 5, 7, 0, 4)] + ], + [ + randIntInclusive(1, 4) * numPlayers + 2 + ], + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), + clFood); + yield 85; + + createStragglerTrees( + [oOak, oOakLarge, oPine, oApple], + avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 1, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + yield 90; + + placePlayersNomad(clPlayer, + avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + + setSkySet("cirrus"); + setWaterColor(0.447, 0.412, 0.322); // muddy brown + setWaterTint(0.447, 0.412, 0.322); + setWaterMurkiness(1.0); + setWaterWaviness(3.0); + setWaterType("lake"); + + setFogThickness(0.25); + setFogFactor(0.4); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/canyon.js =================================================================== --- binaries/data/mods/public/maps/random/canyon.js +++ binaries/data/mods/public/maps/random/canyon.js @@ -2,351 +2,367 @@ Engine.LoadLibrary("rmgen-common"); 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 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 oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; -const oStoneLarge = g_Gaia.stoneLarge; -const oStoneSmall = g_Gaia.stoneSmall; -const oMetalLarge = g_Gaia.metalLarge; -const oWoodTreasure = "gaia/treasure/wood"; -const oFoodTreasure = "gaia/treasure/food_bin"; - -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 aTree = g_Decoratives.tree; - -const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; -const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; - -const heightLand = 3; -const heightHill = 30; - -const g_Map = new RandomMap(heightHill, tMainTerrain); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clHill2 = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clLand = g_Map.createTileClass(); - -const playerCanyonRadius = scaleByMapSize(18, 32); - -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - -g_Map.log("Reserving space for the players, their initial forests and some less space therein without trees"); -for (let i = 0; i < numPlayers; ++i) - for (let j = 1; j <= 2; ++j) +function* GenerateMap() +{ + 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 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 oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; + const oStoneLarge = g_Gaia.stoneLarge; + const oStoneSmall = g_Gaia.stoneSmall; + const oMetalLarge = g_Gaia.metalLarge; + const oWoodTreasure = "gaia/treasure/wood"; + const oFoodTreasure = "gaia/treasure/food_bin"; + + 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 aTree = g_Decoratives.tree; + + const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, + tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; + const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, + tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; + + const heightLand = 3; + const heightHill = 30; + + global.g_Map = new RandomMap(heightHill, tMainTerrain); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clHill2 = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clLand = g_Map.createTileClass(); + + const playerCanyonRadius = scaleByMapSize(18, 32); + + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + + g_Map.log("Reserving space for the players, their initial forests and some less space therein " + + "without trees"); + for (let i = 0; i < numPlayers; ++i) + for (let j = 1; j <= 2; ++j) + createArea( + new ClumpPlacer(diskArea(playerCanyonRadius / j), 0.65, 0.1, Infinity, playerPosition[i]), + [ + new TerrainPainter(tMainTerrain), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 2), + new TileClassPainter(j == 1 || isNomad() ? clLand : clPlayer) + ]); + + g_Map.log("Creating center area"); createArea( - new ClumpPlacer(diskArea(playerCanyonRadius / j), 0.65, 0.1, Infinity, playerPosition[i]), + new ClumpPlacer(diskArea(fractionToTiles(0.16)), 0.7, 0.1, Infinity, mapCenter), [ new TerrainPainter(tMainTerrain), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 2), - new TileClassPainter(j == 1 || isNomad() ? clLand : clPlayer) + new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), + new TileClassPainter(clLand) ]); -g_Map.log("Creating center area"); -createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.16)), 0.7, 0.1, Infinity, mapCenter), - [ - new TerrainPainter(tMainTerrain), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), - new TileClassPainter(clLand) - ]); - -createArea( - new ClumpPlacer(150, 0.6, 0.3, Infinity, mapCenter), - new TileClassPainter(clHill)); - -g_Map.log("Creating hills"); -for (let i = 0; i < scaleByMapSize(9, 16); ++i) createArea( - new PathPlacer( - new Vector2D(randIntExclusive(1, mapSize), randIntExclusive(1, mapSize)), - new Vector2D(randIntExclusive(1, mapSize), randIntExclusive(1, mapSize)), - scaleByMapSize(11, 16), - 0.4, - 3 * scaleByMapSize(1, 4), - 0.1, - 0), - [ - new SmoothElevationPainter(ELEVATION_SET, heightHill, 3), - new TileClassPainter(clHill2) - ], - avoidClasses(clPlayer, 6, clHill2, 3, clHill, 2)); - -for (let g = 0; g < scaleByMapSize(5, 30); ++g) -{ - const position = new Vector2D(randIntInclusive(1, mapSize - 1), randIntInclusive(1, mapSize - 1)); + new ClumpPlacer(150, 0.6, 0.3, Infinity, mapCenter), + new TileClassPainter(clHill)); - const newarea = createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.06)), 0.7, 0.1, Infinity, position), - [ - new TerrainPainter(tMainTerrain), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), - new TileClassPainter(clLand) - ], - avoidClasses(clLand, 6)); + g_Map.log("Creating hills"); + for (let i = 0; i < scaleByMapSize(9, 16); ++i) + createArea( + new PathPlacer( + new Vector2D(randIntExclusive(1, mapSize), randIntExclusive(1, mapSize)), + new Vector2D(randIntExclusive(1, mapSize), randIntExclusive(1, mapSize)), + scaleByMapSize(11, 16), + 0.4, + 3 * scaleByMapSize(1, 4), + 0.1, + 0), + [ + new SmoothElevationPainter(ELEVATION_SET, heightHill, 3), + new TileClassPainter(clHill2) + ], + avoidClasses(clPlayer, 6, clHill2, 3, clHill, 2)); - if (newarea !== null) + for (let g = 0; g < scaleByMapSize(5, 30); ++g) { - let distances = []; - let d1 = 9999; - let d2 = 9999; - let p1 = -1; - let p2 = 0; + const position = + new Vector2D(randIntInclusive(1, mapSize - 1), randIntInclusive(1, mapSize - 1)); - for (let i = 0; i < numPlayers; ++i) - distances.push(position.distanceTo(playerPosition[i])); + const newarea = createArea( + new ClumpPlacer(diskArea(fractionToTiles(0.06)), 0.7, 0.1, Infinity, position), + [ + new TerrainPainter(tMainTerrain), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), + new TileClassPainter(clLand) + ], + avoidClasses(clLand, 6)); - for (let a = 0; a < numPlayers; ++a) + if (newarea !== null) { - if (d1 >= distances[a]) - { - d2 = d1; - d1 = distances[a]; - p2 = p1; - p1 = a; - } - else if (d2 >= distances[a]) + let distances = []; + let d1 = 9999; + let d2 = 9999; + let p1 = -1; + let p2 = 0; + + for (let i = 0; i < numPlayers; ++i) + distances.push(position.distanceTo(playerPosition[i])); + + for (let a = 0; a < numPlayers; ++a) { - d2 = distances[a]; - p2 = a; + if (d1 >= distances[a]) + { + d2 = d1; + d1 = distances[a]; + p2 = p1; + p1 = a; + } + else if (d2 >= distances[a]) + { + d2 = distances[a]; + p2 = a; + } } + + for (const playerID of [p1, p2]) + if (playerPosition[playerID]) + createArea( + new PathPlacer(position, playerPosition[playerID], + scaleByMapSize(11, 17), 0.4, scaleByMapSize(3, 12), 0.1, 0.1), + [ + new TerrainPainter(tMainTerrain), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), + new TileClassPainter(clLand) + ]); } + } - for (const playerID of [p1, p2]) - if (playerPosition[playerID]) - createArea( - new PathPlacer(position, playerPosition[playerID], scaleByMapSize(11, 17), 0.4, scaleByMapSize(3, 12), 0.1, 0.1), - [ - new TerrainPainter(tMainTerrain), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), - new TileClassPainter(clLand) - ]); + g_Map.log("Creating paths from players to neighbor and center"); + for (let i = 0; i < numPlayers; ++i) + { + const neighbor = i + 1 < numPlayers ? i + 1 : 0; + for (const position of [playerPosition[neighbor], mapCenter]) + createArea( + new PathPlacer( + playerPosition[i], + position, + scaleByMapSize(8, 13), + 0.4, + 3 * scaleByMapSize(1, 4), + 0.1, + 0), + [ + new LayeredPainter([tRoadWild, tRoad], [1]), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 2), + new TileClassPainter(clLand), + new TileClassPainter(clHill) + ]); } -} -g_Map.log("Creating paths from players to neighbor and center"); -for (let i = 0; i < numPlayers; ++i) -{ - const neighbor = i + 1 < numPlayers ? i + 1 : 0; - for (const position of [playerPosition[neighbor], mapCenter]) - createArea( - new PathPlacer( - playerPosition[i], - position, - scaleByMapSize(8, 13), - 0.4, - 3 * scaleByMapSize(1, 4), - 0.1, - 0), - [ - new LayeredPainter([tRoadWild, tRoad], [1]), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 2), - new TileClassPainter(clLand), - new TileClassPainter(clHill) - ]); -} + g_Map.log("Painting center place"); + createArea( + new ClumpPlacer(150, 0.6, 0.3, Infinity, mapCenter), + new TerrainPainter(tRoad)); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + // PlayerTileClass already marked above + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoad, + "innerTerrain": tRoad, + "radius": playerCanyonRadius / 3 + }, + "StartingAnimal": { + }, + "Berries": { + "template": oFruitBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ], + "distance": 11 + }, + "Trees": { + "template": oTree1 + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 20; + + paintTerrainBasedOnHeight(3.1, 29, 0, tCliff); + paintTileClassBasedOnHeight(3.1, 32, 0, clHill2); + + createBumps([avoidClasses(clPlayer, 2), stayClasses(clLand, 2)]); + + createHills([tCliff, tCliff, tHill], [avoidClasses(clPlayer, 2, clHill, 8, clHill2, 8), + stayClasses(clLand, 5)], clHill, scaleByMapSize(10, 40)); + + // create hills outside the canyon + createHills([tCliff, tCliff, tMainTerrain], avoidClasses(clLand, 1, clHill, 1), clHill, + scaleByMapSize(20, 150), undefined, undefined, undefined, undefined, 40); + + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + createForests( + [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], + [avoidClasses(clPlayer, 1, clForest, 15, clHill, 1, clHill2, 0), stayClasses(clLand, 4)], + clForest, + forestTrees); + + yield 50; + + g_Map.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, 4, clHill2, 0), stayClasses(clLand, 3)], + scaleByMapSize(15, 45), + clDirt); + + g_Map.log("Creating grass patches"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tTier4Terrain, + [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 4, clHill2, 0), stayClasses(clLand, 3)], + scaleByMapSize(15, 45), + clDirt); + + g_Map.log("Creating stone mines"); + createMines( + [ + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oStoneSmall, 2,5, 1,3)] + ], + [avoidClasses(clForest, 1, clPlayer, 3, clRock, 10, clHill, 1, clHill2, 1), stayClasses(clLand, 2)], + clRock); + + g_Map.log("Creating metal mines"); + createMines( + [ + [new SimpleObject(oMetalLarge, 1,1, 0,4)] + ], + [avoidClasses(clForest, 1, clPlayer, 3, clMetal, 10, clRock, 5, clHill, 1, clHill2, 1), + stayClasses(clLand, 2)], + clMetal + ); + + yield 65; + + let planetm = 1; + + if (currentBiome() == "generic/india") + 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)] + ], + [ + 3 * scaleByMapAreaAbsolute(16), + 3 * scaleByMapAreaAbsolute(8), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13) + ], + avoidClasses(clForest, 0, clPlayer, 0, clHill, 0)); + + g_Map.log("Creating actor trees"); + const group = new SimpleGroup( + [new SimpleObject(aTree, 1,1, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clLand, 5), + scaleByMapSize(200, 800), 50 + ); + + yield 70; + + createFood( + [ + [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], + [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] + ], + [ + 3 * numPlayers, + 3 * numPlayers + ], + [avoidClasses(clForest, 0, clPlayer, 4, clHill, 1, clFood, 20, clHill2, 1), + stayClasses(clLand, 3)], + clFood); -g_Map.log("Painting center place"); -createArea( - new ClumpPlacer(150, 0.6, 0.3, Infinity, mapCenter), - new TerrainPainter(tRoad)); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - // PlayerTileClass already marked above - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoad, - "innerTerrain": tRoad, - "radius": playerCanyonRadius / 3 - }, - "StartingAnimal": { - }, - "Berries": { - "template": oFruitBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } + createFood( + [ + [new SimpleObject(oFruitBush, 5, 7, 0, 4)] ], - "distance": 11 - }, - "Trees": { - "template": oTree1 - }, - "Decoratives": { - "template": aGrassShort - } -}); -Engine.SetProgress(20); - -paintTerrainBasedOnHeight(3.1, 29, 0, tCliff); -paintTileClassBasedOnHeight(3.1, 32, 0, clHill2); - -createBumps([avoidClasses(clPlayer, 2), stayClasses(clLand, 2)]); - -createHills([tCliff, tCliff, tHill], [avoidClasses(clPlayer, 2, clHill, 8, clHill2, 8), stayClasses(clLand, 5)], clHill, scaleByMapSize(10, 40)); - -// create hills outside the canyon -createHills([tCliff, tCliff, tMainTerrain], avoidClasses(clLand, 1, clHill, 1), clHill, scaleByMapSize(20, 150), undefined, undefined, undefined, undefined, 40); - -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); -createForests( - [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], - [avoidClasses(clPlayer, 1, clForest, 15, clHill, 1, clHill2, 0), stayClasses(clLand, 4)], - clForest, - forestTrees); - -Engine.SetProgress(50); - -g_Map.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, 4, clHill2, 0), stayClasses(clLand, 3)], - scaleByMapSize(15, 45), - clDirt); - -g_Map.log("Creating grass patches"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tTier4Terrain, - [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 4, clHill2, 0), stayClasses(clLand, 3)], - scaleByMapSize(15, 45), - clDirt); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2,5, 1,3)] - ], - [avoidClasses(clForest, 1, clPlayer, 3, clRock, 10, clHill, 1, clHill2, 1), stayClasses(clLand, 2)], - clRock); - -g_Map.log("Creating metal mines"); -createMines( - [ - [new SimpleObject(oMetalLarge, 1,1, 0,4)] - ], - [avoidClasses(clForest, 1, clPlayer, 3, clMetal, 10, clRock, 5, clHill, 1, clHill2, 1), stayClasses(clLand, 2)], - clMetal -); - -Engine.SetProgress(65); - -let planetm = 1; - -if (currentBiome() == "generic/india") - 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)] - ], - [ - 3 * scaleByMapAreaAbsolute(16), - 3 * scaleByMapAreaAbsolute(8), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13) - ], - avoidClasses(clForest, 0, clPlayer, 0, clHill, 0)); - -g_Map.log("Creating actor trees"); -const group = new SimpleGroup( - [new SimpleObject(aTree, 1,1, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clLand, 5), - scaleByMapSize(200, 800), 50 -); - -Engine.SetProgress(70); - -createFood( - [ - [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], - [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] - ], - [ - 3 * numPlayers, - 3 * numPlayers - ], - [avoidClasses(clForest, 0, clPlayer, 4, clHill, 1, clFood, 20, clHill2, 1), stayClasses(clLand, 3)], - clFood); - -createFood( - [ - [new SimpleObject(oFruitBush, 5, 7, 0, 4)] - ], - [ - 3 * numPlayers - ], - [avoidClasses(clForest, 0, clPlayer, 4, clHill, 1, clFood, 10, clHill2, 1), stayClasses(clLand, 3)], - clFood); - -Engine.SetProgress(85); - -createStragglerTrees( - [oTree1, oTree2, oTree4, oTree3], - [avoidClasses(clForest, 1, clHill, 1, clPlayer, 9, clMetal, 6, clRock, 6, clHill2, 1), stayClasses(clLand, 3)], - clForest, - stragglerTrees); - -g_Map.log("Creating treasures"); -for (let i = 0; i < randIntInclusive(3, 8); ++i) - for (const template of [oFoodTreasure, oWoodTreasure]) - g_Map.placeEntityPassable( - template, - 0, - Vector2D.add(mapCenter, new Vector2D(randFloat(0, 7), 0).rotate(randomAngle())), - randomAngle()); - -placePlayersNomad( - clPlayer, - [stayClasses(clLand, 4), avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clHill2, 4, clFood, 2)]); - -g_Map.ExportMap(); + [ + 3 * numPlayers + ], + [avoidClasses(clForest, 0, clPlayer, 4, clHill, 1, clFood, 10, clHill2, 1), + stayClasses(clLand, 3)], + clFood); + + yield 85; + + createStragglerTrees( + [oTree1, oTree2, oTree4, oTree3], + [avoidClasses(clForest, 1, clHill, 1, clPlayer, 9, clMetal, 6, clRock, 6, clHill2, 1), + stayClasses(clLand, 3)], + clForest, + stragglerTrees); + + g_Map.log("Creating treasures"); + for (let i = 0; i < randIntInclusive(3, 8); ++i) + for (const template of [oFoodTreasure, oWoodTreasure]) + g_Map.placeEntityPassable( + template, + 0, + Vector2D.add(mapCenter, new Vector2D(randFloat(0, 7), 0).rotate(randomAngle())), + randomAngle()); + + placePlayersNomad( + clPlayer, + [stayClasses(clLand, 4), avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clHill2, 4, + clFood, 2)]); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/continent.js =================================================================== --- binaries/data/mods/public/maps/random/continent.js +++ binaries/data/mods/public/maps/random/continent.js @@ -2,255 +2,268 @@ Engine.LoadLibrary("rmgen-common"); 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 oMetalSmall = g_Gaia.metalSmall; - -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 g_Map = new RandomMap(heightSeaGround, tWater); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clLand = g_Map.createTileClass(); - -g_Map.log("Creating continent"); -createArea( - new ChainPlacer( - 2, - Math.floor(scaleByMapSize(5, 12)), - Math.floor(scaleByMapSize(60, 700)), - Infinity, - mapCenter, - 0, - [Math.floor(fractionToTiles(0.33))]), - [ - new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), - new TileClassPainter(clLand) - ]); - -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.25)); - -g_Map.log("Ensuring initial player land"); -for (let i = 0; i < numPlayers; ++i) +function* GenerateMap() +{ + 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 oMetalSmall = g_Gaia.metalSmall; + + 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; + + global.g_Map = new RandomMap(heightSeaGround, tWater); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clLand = g_Map.createTileClass(); + + g_Map.log("Creating continent"); createArea( new ChainPlacer( 2, - Math.floor(scaleByMapSize(5, 9)), - Math.floor(scaleByMapSize(5, 20)), + Math.floor(scaleByMapSize(5, 12)), + Math.floor(scaleByMapSize(60, 700)), Infinity, - playerPosition[i], + mapCenter, 0, - [Math.floor(scaleByMapSize(23, 50))]), + [Math.floor(fractionToTiles(0.33))]), [ new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), new TileClassPainter(clLand) ]); -Engine.SetProgress(20); - -paintTerrainBasedOnHeight(3, 4, 3, tMainTerrain); -paintTerrainBasedOnHeight(1, 3, 0, tShore); -paintTerrainBasedOnHeight(-8, 1, 2, tWater); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oFruitBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oTree1, - "count": 2 - }, - "Decoratives": { - "template": aGrassShort - } -}); -Engine.SetProgress(30); - -createBumps([avoidClasses(clPlayer, 10), stayClasses(clLand, 5)]); - -if (randBool()) - createHills([tMainTerrain, tCliff, tHill], [avoidClasses(clPlayer, 20, clHill, 15, clBaseResource, 3), stayClasses(clLand, 5)], clHill, scaleByMapSize(1, 4) * numPlayers); -else - createMountains(tCliff, [avoidClasses(clPlayer, 20, clHill, 15, clBaseResource, 3), stayClasses(clLand, 5)], clHill, scaleByMapSize(1, 4) * numPlayers); - -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); -createDefaultForests( - [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], - [avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clBaseResource,2), stayClasses(clLand, 4)], - clForest, - forestTrees); - -Engine.SetProgress(50); - -g_Map.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), stayClasses(clLand, 5)], - scaleByMapSize(15, 45), - clDirt); - -g_Map.log("Creating grass patches"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tTier4Terrain, - [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)], - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(55); - -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - [stayClasses(clLand, 6), avoidClasses(clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1)], -); - -g_Map.log("Creating stone mines"); -createBalancedStoneMines( - oStoneSmall, - oStoneLarge, - clRock, - [stayClasses(clLand, 6), avoidClasses(clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1, clMetal, 10)] -); - -Engine.SetProgress(65); - -// create decoration -let planetm = 1; - -if (currentBiome() == "generic/india") - 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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13) - ], - [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 5)]); - -Engine.SetProgress(70); - -createFood( - [ - [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], - [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] - ], - [ - 3 * numPlayers, - 3 * numPlayers - ], - [avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), stayClasses(clLand, 5)], - clFood); - -createFood( - [ - [new SimpleObject(oFruitBush, 5, 7, 0, 4)] - ], - [ - 3 * numPlayers - ], - [avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), stayClasses(clLand, 5)], - clFood); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 25 * numPlayers - ], - avoidClasses(clLand, 2, clFood, 20), - clFood); - -Engine.SetProgress(85); - -createStragglerTrees( - [oTree1, oTree2, oTree4, oTree3], - [avoidClasses(clForest, 7, clHill, 1, clPlayer, 9, clMetal, 6, clRock, 6), stayClasses(clLand, 7)], - clForest, - stragglerTrees); - -placePlayersNomad( - clPlayer, - [stayClasses(clLand, 4), avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)]); - -setWaterWaviness(1.0); -setWaterType("ocean"); - -g_Map.ExportMap(); + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.25)); + + g_Map.log("Ensuring initial player land"); + for (let i = 0; i < numPlayers; ++i) + createArea( + new ChainPlacer( + 2, + Math.floor(scaleByMapSize(5, 9)), + Math.floor(scaleByMapSize(5, 20)), + Infinity, + playerPosition[i], + 0, + [Math.floor(scaleByMapSize(23, 50))]), + [ + new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), + new TileClassPainter(clLand) + ]); + + yield 20; + + paintTerrainBasedOnHeight(3, 4, 3, tMainTerrain); + paintTerrainBasedOnHeight(1, 3, 0, tShore); + paintTerrainBasedOnHeight(-8, 1, 2, tWater); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oFruitBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oTree1, + "count": 2 + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 30; + + createBumps([avoidClasses(clPlayer, 10), stayClasses(clLand, 5)]); + + if (randBool()) + createHills([tMainTerrain, tCliff, tHill], + [avoidClasses(clPlayer, 20, clHill, 15, clBaseResource, 3), stayClasses(clLand, 5)], + clHill, scaleByMapSize(1, 4) * numPlayers); + else + createMountains(tCliff, + [avoidClasses(clPlayer, 20, clHill, 15, clBaseResource, 3), stayClasses(clLand, 5)], + clHill, scaleByMapSize(1, 4) * numPlayers); + + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + createDefaultForests( + [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], + [avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clBaseResource,2), stayClasses(clLand, 4)], + clForest, + forestTrees); + + yield 50; + + g_Map.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), stayClasses(clLand, 5)], + scaleByMapSize(15, 45), + clDirt); + + g_Map.log("Creating grass patches"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tTier4Terrain, + [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)], + scaleByMapSize(15, 45), + clDirt); + yield 55; + + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + [stayClasses(clLand, 6), + avoidClasses(clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1)] + ); + + g_Map.log("Creating stone mines"); + createBalancedStoneMines( + oStoneSmall, + oStoneLarge, + clRock, + [stayClasses(clLand, 6), + avoidClasses(clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1, clMetal, 10)] + ); + + yield 65; + + // create decoration + let planetm = 1; + + if (currentBiome() == "generic/india") + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13) + ], + [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), stayClasses(clLand, 5)]); + + yield 70; + + createFood( + [ + [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], + [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] + ], + [ + 3 * numPlayers, + 3 * numPlayers + ], + [avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), stayClasses(clLand, 5)], + clFood); + + createFood( + [ + [new SimpleObject(oFruitBush, 5, 7, 0, 4)] + ], + [ + 3 * numPlayers + ], + [avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), stayClasses(clLand, 5)], + clFood); + + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 25 * numPlayers + ], + avoidClasses(clLand, 2, clFood, 20), + clFood); + + yield 85; + + createStragglerTrees( + [oTree1, oTree2, oTree4, oTree3], + [avoidClasses(clForest, 7, clHill, 1, clPlayer, 9, clMetal, 6, clRock, 6), + stayClasses(clLand, 7)], + clForest, + stragglerTrees); + + placePlayersNomad( + clPlayer, + [stayClasses(clLand, 4), + avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)]); + + setWaterWaviness(1.0); + setWaterType("ocean"); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/corinthian_isthmus.js =================================================================== --- binaries/data/mods/public/maps/random/corinthian_isthmus.js +++ binaries/data/mods/public/maps/random/corinthian_isthmus.js @@ -2,332 +2,345 @@ Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); -setSelectedBiome(); - -TILE_CENTERED_HEIGHT_MAP = true; - -const tCity = g_Terrains.road; -const tCityPlaza = g_Terrains.roadWild; -const tHill = g_Terrains.hill; -const tMainDirt = g_Terrains.dirt; -const tCliff = g_Terrains.cliff; -const tForestFloor = g_Terrains.forestFloor1; -const tGrass = g_Terrains.mainTerrain; -const tGrassSand50 = g_Terrains.tier1Terrain; -const tGrassSand25 = g_Terrains.tier3Terrain; -const tDirt = g_Terrains.dirt; -const tDirt2 = g_Terrains.dirt; -const tDirt3 = g_Terrains.tier2Terrain; -const tDirtCracks = g_Terrains.dirt; -const tShore = g_Terrains.shore; -const tWater = g_Terrains.water; - -const oBerryBush = g_Gaia.fruitBush; -const oDeer = g_Gaia.mainHuntableAnimal; -const oFish = g_Gaia.fish; -const oSheep = g_Gaia.secondaryHuntableAnimal; -const oGoat = "gaia/fauna_goat"; -const oStoneLarge = g_Gaia.stoneLarge; -const oStoneSmall = g_Gaia.stoneSmall; -const oMetalLarge = g_Gaia.metalLarge; -const oMetalSmall = g_Gaia.metalSmall; -const oDatePalm = g_Gaia.tree1; -const oSDatePalm = g_Gaia.tree2; -const oCarob = g_Gaia.tree3; -const oFanPalm = g_Gaia.tree4; -const oPoplar = g_Gaia.tree5; -const oCypress = pickRandom([g_Gaia.tree1, g_Gaia.tree2, g_Gaia.tree3, g_Gaia.tree4, g_Gaia.tree5]); - -const aBush1 = g_Decoratives.bushSmall; -const aBush2 = g_Decoratives.bushMedium; -const aBush3 = g_Decoratives.grassShort; -const aBush4 = g_Decoratives.tree; -const aDecorativeRock = g_Decoratives.rockMedium; - -const aLillies = g_Decoratives.lillies; -const aReeds = g_Decoratives.reeds; - -const pForest = [ - tForestFloor, tForestFloor + TERRAIN_SEPARATOR + oCarob, - tForestFloor + TERRAIN_SEPARATOR + oDatePalm, - tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, - tForestFloor -]; - -const heightSeaGround = -7; -const heightShallow = -0.8; -const heightLand = 3; - -const g_Map = new RandomMap(heightLand, tHill); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -let clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clGrass = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clPassageway = g_Map.createTileClass(); -const clShallow = g_Map.createTileClass(); - -g_Map.log("Creating the main river"); -const riverAngle = randomAngle(); -const riverWidth = scaleByMapSize(20, 90); -const riverStart = new Vector2D(mapCenter.x, 0).rotateAround(riverAngle, mapCenter); -const riverEnd = new Vector2D(mapCenter.x, mapSize).rotateAround(riverAngle, mapCenter); - -createArea( - new PathPlacer(riverStart, riverEnd, riverWidth, 0.2, scaleByMapSize(0.3, 1), 0.04, 0.01), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4)); - -g_Map.log("Creating small puddles at the map border to ensure players being separated"); -for (const point of [riverStart, riverEnd]) +function* GenerateMap() +{ + setSelectedBiome(); + + TILE_CENTERED_HEIGHT_MAP = true; + + const tCity = g_Terrains.road; + const tCityPlaza = g_Terrains.roadWild; + const tHill = g_Terrains.hill; + const tMainDirt = g_Terrains.dirt; + const tCliff = g_Terrains.cliff; + const tForestFloor = g_Terrains.forestFloor1; + const tGrass = g_Terrains.mainTerrain; + const tGrassSand50 = g_Terrains.tier1Terrain; + const tGrassSand25 = g_Terrains.tier3Terrain; + const tDirt = g_Terrains.dirt; + const tDirt2 = g_Terrains.dirt; + const tDirt3 = g_Terrains.tier2Terrain; + const tDirtCracks = g_Terrains.dirt; + const tShore = g_Terrains.shore; + const tWater = g_Terrains.water; + + const oBerryBush = g_Gaia.fruitBush; + const oDeer = g_Gaia.mainHuntableAnimal; + const oFish = g_Gaia.fish; + const oSheep = g_Gaia.secondaryHuntableAnimal; + const oGoat = "gaia/fauna_goat"; + const oStoneLarge = g_Gaia.stoneLarge; + const oStoneSmall = g_Gaia.stoneSmall; + const oMetalLarge = g_Gaia.metalLarge; + const oMetalSmall = g_Gaia.metalSmall; + const oDatePalm = g_Gaia.tree1; + const oSDatePalm = g_Gaia.tree2; + const oCarob = g_Gaia.tree3; + const oFanPalm = g_Gaia.tree4; + const oPoplar = g_Gaia.tree5; + const oCypress = pickRandom([g_Gaia.tree1, g_Gaia.tree2, g_Gaia.tree3, g_Gaia.tree4, g_Gaia.tree5]); + + const aBush1 = g_Decoratives.bushSmall; + const aBush2 = g_Decoratives.bushMedium; + const aBush3 = g_Decoratives.grassShort; + const aBush4 = g_Decoratives.tree; + const aDecorativeRock = g_Decoratives.rockMedium; + + const aLillies = g_Decoratives.lillies; + const aReeds = g_Decoratives.reeds; + + const pForest = [ + tForestFloor, tForestFloor + TERRAIN_SEPARATOR + oCarob, + tForestFloor + TERRAIN_SEPARATOR + oDatePalm, + tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, + tForestFloor + ]; + + const heightSeaGround = -7; + const heightShallow = -0.8; + const heightLand = 3; + + global.g_Map = new RandomMap(heightLand, tHill); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + let clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clGrass = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clPassageway = g_Map.createTileClass(); + const clShallow = g_Map.createTileClass(); + + g_Map.log("Creating the main river"); + const riverAngle = randomAngle(); + const riverWidth = scaleByMapSize(20, 90); + const riverStart = new Vector2D(mapCenter.x, 0).rotateAround(riverAngle, mapCenter); + const riverEnd = new Vector2D(mapCenter.x, mapSize).rotateAround(riverAngle, mapCenter); + createArea( - new ClumpPlacer(diskArea(riverWidth / 2), 0.95, 0.6, Infinity, point), + new PathPlacer(riverStart, riverEnd, riverWidth, 0.2, scaleByMapSize(0.3, 1), 0.04, 0.01), new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4)); -// Paint water so we now where to lay passageway. -paintTileClassBasedOnHeight(heightSeaGround - 1, 0.5, 1, clWater); - -g_Map.log("Creating passage connecting the two riversides"); -// Add some leeway to make sure things are connected. -const fraction = randFloat(0.38, 0.62); -const middlePoint = riverStart.clone().mult(fraction).add(riverEnd.clone().mult(1 - fraction)); -let passageStart = new Vector2D(middlePoint.x, middlePoint.y - riverWidth * 1.1).rotateAround(riverAngle, middlePoint); -let passageEnd = new Vector2D(middlePoint.x, middlePoint.y + riverWidth * 1.1).rotateAround(riverAngle, middlePoint); -passageStart = passageStart.rotateAround(Math.PI / 2, middlePoint); -passageEnd = passageEnd.rotateAround(Math.PI / 2, middlePoint); -// First create a shallow (walkable) area. -const passageWidth = scaleByMapSize(15, 40); -createArea( - new PathPlacer( - passageStart, - passageEnd, - passageWidth * 2, - 0.2, - scaleByMapSize(0.2, 0.4), - 0.1, - 0.01, - 100.0), - new MultiPainter([ - new SmoothElevationPainter(ELEVATION_SET, heightShallow, 3), - new TileClassPainter(clShallow)]), - new OrConstraint([ - stayClasses(clWater, 0), - borderClasses(clWater, 0, 3), - ]) -); - -// Then create the proper passageway. -createArea( - new PathPlacer( - passageStart, - passageEnd, - passageWidth, - 0.5, - scaleByMapSize(0.2, 0.4), - 0.1, - 0.01), - new MultiPainter([ - new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), - new TileClassPainter(clPassageway)]) -); - -paintTerrainBasedOnHeight(heightSeaGround - 1, 1, 1, tWater); -paintTerrainBasedOnHeight(1, 2, 1, tShore); -paintTerrainBasedOnHeight(2, 5, 1, tGrass); - -// Reset water class. -clWater = g_Map.createTileClass(); -paintTileClassBasedOnHeight(heightSeaGround - 1, 0.5, 1, clWater); - -placePlayerBases({ - "PlayerPlacement": playerPlacementRiver(riverAngle, fractionToTiles(0.6)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "Walls": "towers", - "CityPatch": { - "outerTerrain": tCityPlaza, - "innerTerrain": tCity - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneSmall }, - { "template": oStoneSmall }, - ] - }, - "Trees": { - "template": oCarob, - "count": 2 - }, - "Decoratives": { - "template": aBush1 - } -}); -Engine.SetProgress(40); - -createBumps(avoidClasses(clWater, 2, clPlayer, 20)); - -const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); -createDefaultForests( - [tForestFloor, tForestFloor, pForest, pForest, pForest], - avoidClasses(clPlayer, 20, clPassageway, 5, clForest, 17, clWater, 2, clBaseResource, 3), - clForest, - forestTrees); - -Engine.SetProgress(50); - -if (randBool()) - createHills([tGrass, tCliff, tHill], avoidClasses(clPlayer, 20, clPassageway, 10, clForest, 1, clHill, 15, clWater, 3), clHill, scaleByMapSize(3, 15)); -else - createMountains(tCliff, avoidClasses(clPlayer, 20, clPassageway, 10, clForest, 1, clHill, 15, clWater, 3), clHill, scaleByMapSize(3, 15)); - -g_Map.log("Creating grass patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tGrass, tGrassSand50], [tGrassSand50, tGrassSand25], [tGrassSand25, tGrass]], - [1, 1], - avoidClasses(clForest, 0, clGrass, 2, clPlayer, 10, clWater, 2, clDirt, 2, clHill, 1), - scaleByMapSize(15, 45), - clDirt); - -Engine.SetProgress(55); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [tDirt3, tDirt2, [tDirt, tMainDirt], [tDirtCracks, tMainDirt]], - [1, 1, 1], - avoidClasses(clForest, 0, clDirt, 2, clPlayer, 10, clWater, 2, clGrass, 2, clHill, 1), - scaleByMapSize(15, 45), - clDirt); - -Engine.SetProgress(60); - -g_Map.log("Creating stone mines in the middle"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oStoneSmall, 1, 4, 0, 4)], true, clRock), - 0, - [ - avoidClasses(clForest, 4, clPlayer, 15, clRock, 6, clWater, 0, clHill, 4), - stayClasses(clPassageway, 2) - ], - scaleByMapSize(4, 15), - 80 -); - -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - avoidClasses(clPassageway, 1, clWater, 0, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1, clRock, 10), - 0.9 // less available area -> slightly less metal -); - -Engine.SetProgress(65); - -createDecoration( - [ + g_Map.log("Creating small puddles at the map border to ensure players being separated"); + for (const point of [riverStart, riverEnd]) + createArea( + new ClumpPlacer(diskArea(riverWidth / 2), 0.95, 0.6, Infinity, point), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4)); + + // Paint water so we now where to lay passageway. + paintTileClassBasedOnHeight(heightSeaGround - 1, 0.5, 1, clWater); + + g_Map.log("Creating passage connecting the two riversides"); + // Add some leeway to make sure things are connected. + const fraction = randFloat(0.38, 0.62); + const middlePoint = riverStart.clone().mult(fraction).add(riverEnd.clone().mult(1 - fraction)); + let passageStart = new Vector2D(middlePoint.x, middlePoint.y - riverWidth * 1.1) + .rotateAround(riverAngle, middlePoint); + let passageEnd = new Vector2D(middlePoint.x, middlePoint.y + riverWidth * 1.1) + .rotateAround(riverAngle, middlePoint); + passageStart = passageStart.rotateAround(Math.PI / 2, middlePoint); + passageEnd = passageEnd.rotateAround(Math.PI / 2, middlePoint); + // First create a shallow (walkable) area. + const passageWidth = scaleByMapSize(15, 40); + createArea( + new PathPlacer( + passageStart, + passageEnd, + passageWidth * 2, + 0.2, + scaleByMapSize(0.2, 0.4), + 0.1, + 0.01, + 100.0), + new MultiPainter([ + new SmoothElevationPainter(ELEVATION_SET, heightShallow, 3), + new TileClassPainter(clShallow)]), + new OrConstraint([ + stayClasses(clWater, 0), + borderClasses(clWater, 0, 3), + ]) + ); + + // Then create the proper passageway. + createArea( + new PathPlacer( + passageStart, + passageEnd, + passageWidth, + 0.5, + scaleByMapSize(0.2, 0.4), + 0.1, + 0.01), + new MultiPainter([ + new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), + new TileClassPainter(clPassageway)]) + ); + + paintTerrainBasedOnHeight(heightSeaGround - 1, 1, 1, tWater); + paintTerrainBasedOnHeight(1, 2, 1, tShore); + paintTerrainBasedOnHeight(2, 5, 1, tGrass); + + // Reset water class. + clWater = g_Map.createTileClass(); + paintTileClassBasedOnHeight(heightSeaGround - 1, 0.5, 1, clWater); + + placePlayerBases({ + "PlayerPlacement": playerPlacementRiver(riverAngle, fractionToTiles(0.6)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "Walls": "towers", + "CityPatch": { + "outerTerrain": tCityPlaza, + "innerTerrain": tCity + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneSmall }, + { "template": oStoneSmall }, + ] + }, + "Trees": { + "template": oCarob, + "count": 2 + }, + "Decoratives": { + "template": aBush1 + } + }); + yield 40; + + createBumps(avoidClasses(clWater, 2, clPlayer, 20)); + + const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); + createDefaultForests( + [tForestFloor, tForestFloor, pForest, pForest, pForest], + avoidClasses(clPlayer, 20, clPassageway, 5, clForest, 17, clWater, 2, clBaseResource, 3), + clForest, + forestTrees); + + yield 50; + + if (randBool()) + createHills([tGrass, tCliff, tHill], avoidClasses(clPlayer, 20, clPassageway, 10, clForest, 1, + clHill, 15, clWater, 3), clHill, scaleByMapSize(3, 15)); + else + createMountains(tCliff, avoidClasses(clPlayer, 20, clPassageway, 10, clForest, 1, clHill, 15, + clWater, 3), clHill, scaleByMapSize(3, 15)); + + g_Map.log("Creating grass patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tGrass, tGrassSand50], [tGrassSand50, tGrassSand25], [tGrassSand25, tGrass]], + [1, 1], + avoidClasses(clForest, 0, clGrass, 2, clPlayer, 10, clWater, 2, clDirt, 2, clHill, 1), + scaleByMapSize(15, 45), + clDirt); + + yield 55; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [tDirt3, tDirt2, [tDirt, tMainDirt], [tDirtCracks, tMainDirt]], + [1, 1, 1], + avoidClasses(clForest, 0, clDirt, 2, clPlayer, 10, clWater, 2, clGrass, 2, clHill, 1), + scaleByMapSize(15, 45), + clDirt); + + yield 60; + + g_Map.log("Creating stone mines in the middle"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oStoneSmall, 1, 4, 0, 4)], true, clRock), + 0, + [ + avoidClasses(clForest, 4, clPlayer, 15, clRock, 6, clWater, 0, clHill, 4), + stayClasses(clPassageway, 2) + ], + scaleByMapSize(4, 15), + 80 + ); + + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + avoidClasses(clPassageway, 1, clWater, 0, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, + 1, clRock, 10), + 0.9 // less available area -> slightly less metal + ); + + yield 65; + + createDecoration( + [ + [ + new SimpleObject(aDecorativeRock, 1, 3, 0, 1) + ], + [ + new SimpleObject(aBush2, 1, 2, 0, 1), + new SimpleObject(aBush1, 1, 3, 0, 2), + new SimpleObject(aBush4, 1, 2, 0, 1), + new SimpleObject(aBush3, 1, 3, 0, 2) + ] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapSize(40, 360) + ], + avoidClasses(clWater, 2, clForest, 0, clPlayer, 5, clBaseResource, 6, clHill, 1, clRock, 6, + clMetal, 6)); + + yield 70; + + createFood( [ - new SimpleObject(aDecorativeRock, 1, 3, 0, 1) + [new SimpleObject(oFish, 2, 3, 0, 2)] ], [ - new SimpleObject(aBush2, 1, 2, 0, 1), - new SimpleObject(aBush1, 1, 3, 0, 2), - new SimpleObject(aBush4, 1, 2, 0, 1), - new SimpleObject(aBush3, 1, 3, 0, 2) - ] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapSize(40, 360) - ], - avoidClasses(clWater, 2, clForest, 0, clPlayer, 5, clBaseResource, 6, clHill, 1, clRock, 6, clMetal, 6)); - -Engine.SetProgress(70); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 3 * scaleByMapSize(5, 20) - ], - [avoidClasses(clFood, 8, clShallow, 2), stayClasses(clWater, 4)], - clFood); - -createFood( - [ - [new SimpleObject(oSheep, 5, 7, 0, 4)], - [new SimpleObject(oGoat, 2, 4, 0, 3)], - [new SimpleObject(oDeer, 2, 4, 0, 2)] - ], - [ - scaleByMapSize(5, 20), - scaleByMapSize(5, 20), - scaleByMapSize(5, 20) - ], - avoidClasses(clForest, 0, clPlayer, 10, clPassageway, 0, clBaseResource, 6, clWater, 1, clFood, 10, clHill, 1, clRock, 6, clMetal, 6), - clFood); - -createFood( - [ - [new SimpleObject(oBerryBush, 5, 7, 0, 4)] - ], - [ - 3 * numPlayers - ], - avoidClasses(clWater, 3, clForest, 0, clPassageway, 0, clPlayer, 20, clHill, 1, clFood, 10, clRock, 6, clMetal, 6), - clFood); - -Engine.SetProgress(90); - -createStragglerTrees( - [oDatePalm, oSDatePalm, oCarob, oFanPalm, oPoplar, oCypress], - avoidClasses(clForest, 1, clWater, 2, clPlayer, 8, clBaseResource, 6, clMetal, 6, clRock, 6, clHill, 1), - clForest, - stragglerTrees); - - -g_Map.log("Placing decorations on shallows"); - -createObjectGroups( - new SimpleGroup([ - new SimpleObject(aDecorativeRock, 1, 2, 0, 1), - new SimpleObject(aReeds, 0, 4, 0, 1), - ], true, clRock), - 0, - [stayClasses(clShallow, 2), avoidClasses(clPassageway, 0)], - scaleByMapSize(30, 100), - 50 -); - -createObjectGroups( - new SimpleGroup([new SimpleObject(aLillies, 1, 2, 0, 1)], true, clRock), - 0, - [stayClasses(clShallow, 2), avoidClasses(clPassageway, 0)], - scaleByMapSize(6, 36), - 50 -); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setWaterWaviness(2.5); -setWaterType("ocean"); -setWaterMurkiness(0.49); - -g_Map.ExportMap(); + 3 * scaleByMapSize(5, 20) + ], + [avoidClasses(clFood, 8, clShallow, 2), stayClasses(clWater, 4)], + clFood); + + createFood( + [ + [new SimpleObject(oSheep, 5, 7, 0, 4)], + [new SimpleObject(oGoat, 2, 4, 0, 3)], + [new SimpleObject(oDeer, 2, 4, 0, 2)] + ], + [ + scaleByMapSize(5, 20), + scaleByMapSize(5, 20), + scaleByMapSize(5, 20) + ], + avoidClasses(clForest, 0, clPlayer, 10, clPassageway, 0, clBaseResource, 6, clWater, 1, clFood, + 10, clHill, 1, clRock, 6, clMetal, 6), + clFood); + + createFood( + [ + [new SimpleObject(oBerryBush, 5, 7, 0, 4)] + ], + [ + 3 * numPlayers + ], + avoidClasses(clWater, 3, clForest, 0, clPassageway, 0, clPlayer, 20, clHill, 1, clFood, 10, + clRock, 6, clMetal, 6), + clFood); + + yield 90; + + createStragglerTrees( + [oDatePalm, oSDatePalm, oCarob, oFanPalm, oPoplar, oCypress], + avoidClasses(clForest, 1, clWater, 2, clPlayer, 8, clBaseResource, 6, clMetal, 6, clRock, 6, + clHill, 1), + clForest, + stragglerTrees); + + + g_Map.log("Placing decorations on shallows"); + + createObjectGroups( + new SimpleGroup([ + new SimpleObject(aDecorativeRock, 1, 2, 0, 1), + new SimpleObject(aReeds, 0, 4, 0, 1), + ], true, clRock), + 0, + [stayClasses(clShallow, 2), avoidClasses(clPassageway, 0)], + scaleByMapSize(30, 100), + 50 + ); + + createObjectGroups( + new SimpleGroup([new SimpleObject(aLillies, 1, 2, 0, 1)], true, clRock), + 0, + [stayClasses(clShallow, 2), avoidClasses(clPassageway, 0)], + scaleByMapSize(6, 36), + 50 + ); + + placePlayersNomad(clPlayer, + avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + + setWaterWaviness(2.5); + setWaterType("ocean"); + setWaterMurkiness(0.49); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/corsica.js =================================================================== --- binaries/data/mods/public/maps/random/corsica.js +++ binaries/data/mods/public/maps/random/corsica.js @@ -1,519 +1,522 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tGrass = ["medit_grass_field", "medit_grass_field_b", "temp_grass_c"]; -const tLushGrass = ["medit_grass_field","medit_grass_field_a"]; - -const tSteepCliffs = ["temp_cliff_b", "temp_cliff_a"]; -const tCliffs = ["temp_cliff_b", "medit_cliff_italia", "medit_cliff_italia_grass"]; -const tHill = ["medit_cliff_italia_grass","medit_cliff_italia_grass", "medit_grass_field", "medit_grass_field", "temp_grass"]; -const tMountain = ["medit_cliff_italia_grass","medit_cliff_italia"]; - -const tRoad = ["medit_city_tile","medit_rocks_grass","medit_grass_field_b"]; -const tRoadWild = ["medit_rocks_grass","medit_grass_field_b"]; - -const tShoreBlend = ["medit_sand_wet","medit_rocks_wet"]; -const tShore = ["medit_rocks","medit_sand","medit_sand"]; -const tSandTransition = ["medit_sand","medit_rocks_grass","medit_rocks_grass","medit_rocks_grass"]; -const tVeryDeepWater = ["medit_sea_depths","medit_sea_coral_deep"]; -const tDeepWater = ["medit_sea_coral_deep","tropic_ocean_coral"]; -const tCreekWater = "medit_sea_coral_plants"; - -const ePine = "gaia/tree/aleppo_pine"; -const ePalmTall = "gaia/tree/cretan_date_palm_tall"; -const eFanPalm = "gaia/tree/medit_fan_palm"; -const eApple = "gaia/fruit/apple"; -const eBush = "gaia/fruit/berry_01"; -const eFish = "gaia/fish/generic"; -const ePig = "gaia/fauna_pig"; -const eStoneMine = "gaia/rock/mediterranean_large"; -const eMetalMine = "gaia/ore/mediterranean_large"; - -const aRock = "actor|geology/stone_granite_med.xml"; -const aLargeRock = "actor|geology/stone_granite_large.xml"; -const aBushA = "actor|props/flora/bush_medit_sm_lush.xml"; -const aBushB = "actor|props/flora/bush_medit_me_lush.xml"; -const aPlantA = "actor|props/flora/plant_medit_artichoke.xml"; -const aPlantB = "actor|props/flora/grass_tufts_a.xml"; -const aPlantC = "actor|props/flora/grass_soft_tuft_a.xml"; - -const aStandingStone = "actor|props/special/eyecandy/standing_stones.xml"; - -const heightSeaGround = -8; -const heightCreeks = -5; -const heightBeaches = -1; -const heightMain = 5; - -const heightOffsetMainRelief = 30; -const heightOffsetLevel1 = 9; -const heightOffsetLevel2 = 8; -const heightOffsetBumps = 2; -const heightOffsetAntiBumps = -5; - -const g_Map = new RandomMap(heightSeaGround, tVeryDeepWater); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clIsland = g_Map.createTileClass(); -const clCreek = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clCliffs = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clShore = g_Map.createTileClass(); -const clPlayer = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clPassage = g_Map.createTileClass(); -const clSettlement = g_Map.createTileClass(); - -const radiusBeach = fractionToTiles(0.57); -const radiusCreeks = fractionToTiles(0.52); -const radiusIsland = fractionToTiles(0.4); -const radiusLevel1 = fractionToTiles(0.35); -const radiusPlayer = fractionToTiles(0.25); -const radiusLevel2 = fractionToTiles(0.2); - -const creeksArea = () => randBool() ? randFloat(10, 50) : scaleByMapSize(75, 100) + randFloat(0, 20); - -const nbCreeks = scaleByMapSize(6, 15); -const nbSubIsland = 5; -const nbBeaches = scaleByMapSize(2, 5); -const nbPassagesLevel1 = scaleByMapSize(4, 8); -const nbPassagesLevel2 = scaleByMapSize(2, 4); - -g_Map.log("Creating Corsica and Sardinia"); -const swapAngle = randBool() ? Math.PI / 2 : 0; -const 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) +function* GenerateMap() { - g_Map.log("Creating island area"); - createArea( - new ClumpPlacer(diskArea(radiusIsland), 1, 0.5, Infinity, islandLocations[island]), - [ - new LayeredPainter([tCliffs, tGrass], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightMain, 0), - new TileClassPainter(clIsland) - ]); - - g_Map.log("Creating subislands"); - for (let i = 0; i < nbSubIsland + 1; ++i) + const tGrass = ["medit_grass_field", "medit_grass_field_b", "temp_grass_c"]; + const tLushGrass = ["medit_grass_field","medit_grass_field_a"]; + + const tSteepCliffs = ["temp_cliff_b", "temp_cliff_a"]; + const tCliffs = ["temp_cliff_b", "medit_cliff_italia", "medit_cliff_italia_grass"]; + const tHill = ["medit_cliff_italia_grass","medit_cliff_italia_grass", "medit_grass_field", "medit_grass_field", "temp_grass"]; + const tMountain = ["medit_cliff_italia_grass","medit_cliff_italia"]; + + const tRoad = ["medit_city_tile","medit_rocks_grass","medit_grass_field_b"]; + const tRoadWild = ["medit_rocks_grass","medit_grass_field_b"]; + + const tShoreBlend = ["medit_sand_wet","medit_rocks_wet"]; + const tShore = ["medit_rocks","medit_sand","medit_sand"]; + const tSandTransition = ["medit_sand","medit_rocks_grass","medit_rocks_grass","medit_rocks_grass"]; + const tVeryDeepWater = ["medit_sea_depths","medit_sea_coral_deep"]; + const tDeepWater = ["medit_sea_coral_deep","tropic_ocean_coral"]; + const tCreekWater = "medit_sea_coral_plants"; + + const ePine = "gaia/tree/aleppo_pine"; + const ePalmTall = "gaia/tree/cretan_date_palm_tall"; + const eFanPalm = "gaia/tree/medit_fan_palm"; + const eApple = "gaia/fruit/apple"; + const eBush = "gaia/fruit/berry_01"; + const eFish = "gaia/fish/generic"; + const ePig = "gaia/fauna_pig"; + const eStoneMine = "gaia/rock/mediterranean_large"; + const eMetalMine = "gaia/ore/mediterranean_large"; + + const aRock = "actor|geology/stone_granite_med.xml"; + const aLargeRock = "actor|geology/stone_granite_large.xml"; + const aBushA = "actor|props/flora/bush_medit_sm_lush.xml"; + const aBushB = "actor|props/flora/bush_medit_me_lush.xml"; + const aPlantA = "actor|props/flora/plant_medit_artichoke.xml"; + const aPlantB = "actor|props/flora/grass_tufts_a.xml"; + const aPlantC = "actor|props/flora/grass_soft_tuft_a.xml"; + + const aStandingStone = "actor|props/special/eyecandy/standing_stones.xml"; + + const heightSeaGround = -8; + const heightCreeks = -5; + const heightBeaches = -1; + const heightMain = 5; + + const heightOffsetMainRelief = 30; + const heightOffsetLevel1 = 9; + const heightOffsetLevel2 = 8; + const heightOffsetBumps = 2; + const heightOffsetAntiBumps = -5; + + global.g_Map = new RandomMap(heightSeaGround, tVeryDeepWater); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clIsland = g_Map.createTileClass(); + const clCreek = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clCliffs = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clShore = g_Map.createTileClass(); + const clPlayer = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clPassage = g_Map.createTileClass(); + const clSettlement = g_Map.createTileClass(); + + const radiusBeach = fractionToTiles(0.57); + const radiusCreeks = fractionToTiles(0.52); + const radiusIsland = fractionToTiles(0.4); + const radiusLevel1 = fractionToTiles(0.35); + const radiusPlayer = fractionToTiles(0.25); + const radiusLevel2 = fractionToTiles(0.2); + + const creeksArea = () => randBool() ? randFloat(10, 50) : scaleByMapSize(75, 100) + randFloat(0, 20); + + const nbCreeks = scaleByMapSize(6, 15); + const nbSubIsland = 5; + const nbBeaches = scaleByMapSize(2, 5); + const nbPassagesLevel1 = scaleByMapSize(4, 8); + const nbPassagesLevel2 = scaleByMapSize(2, 4); + + g_Map.log("Creating Corsica and Sardinia"); + const swapAngle = randBool() ? Math.PI / 2 : 0; + const 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) { - const angle = Math.PI * (island + i / (nbSubIsland * 2)) + swapAngle; - const location = Vector2D.add(islandLocations[island], new Vector2D(radiusIsland, 0).rotate(-angle)); + g_Map.log("Creating island area"); createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.09)), 0.6, 0.03, Infinity, location), + new ClumpPlacer(diskArea(radiusIsland), 1, 0.5, Infinity, islandLocations[island]), [ new LayeredPainter([tCliffs, tGrass], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightMain, 1), + new SmoothElevationPainter(ELEVATION_SET, heightMain, 0), new TileClassPainter(clIsland) ]); - } - g_Map.log("Creating creeks"); - for (let i = 0; i < nbCreeks + 1; ++i) - { - const angle = Math.PI * (island + i * (1 / (nbCreeks * 2))) + swapAngle; - const location = Vector2D.add(islandLocations[island], new Vector2D(radiusCreeks, 0).rotate(-angle)); - createArea( - new ClumpPlacer(creeksArea(), 0.4, 0.01, Infinity, location), - [ - new TerrainPainter(tSteepCliffs), - new SmoothElevationPainter(ELEVATION_SET, heightCreeks, 0), - new TileClassPainter(clCreek) - ]); - } + g_Map.log("Creating subislands"); + for (let i = 0; i < nbSubIsland + 1; ++i) + { + const angle = Math.PI * (island + i / (nbSubIsland * 2)) + swapAngle; + const location = Vector2D.add(islandLocations[island], new Vector2D(radiusIsland, 0).rotate(-angle)); + createArea( + new ClumpPlacer(diskArea(fractionToTiles(0.09)), 0.6, 0.03, Infinity, location), + [ + new LayeredPainter([tCliffs, tGrass], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightMain, 1), + new TileClassPainter(clIsland) + ]); + } - g_Map.log("Creating beaches"); - for (let i = 0; i < nbBeaches + 1; ++i) - { - const angle = Math.PI * (island + (i / (nbBeaches * 2.5)) + 1 / (nbBeaches * 6) + randFloat(-1, 1) / (nbBeaches * 7)) + swapAngle; - const start = Vector2D.add(islandLocations[island], new Vector2D(radiusIsland, 0).rotate(-angle)); - const end = Vector2D.add(islandLocations[island], new Vector2D(radiusBeach, 0).rotate(-angle)); + g_Map.log("Creating creeks"); + for (let i = 0; i < nbCreeks + 1; ++i) + { + const angle = Math.PI * (island + i * (1 / (nbCreeks * 2))) + swapAngle; + const location = Vector2D.add(islandLocations[island], new Vector2D(radiusCreeks, 0).rotate(-angle)); + createArea( + new ClumpPlacer(creeksArea(), 0.4, 0.01, Infinity, location), + [ + new TerrainPainter(tSteepCliffs), + new SmoothElevationPainter(ELEVATION_SET, heightCreeks, 0), + new TileClassPainter(clCreek) + ]); + } - createArea( - new ClumpPlacer(130, 0.7, 0.8, Infinity, Vector2D.add(start, Vector2D.mult(end, 3)).div(4)), - new SmoothElevationPainter(ELEVATION_SET, heightBeaches, 5)); - - createPassage({ - "start": start, - "end": end, - "startWidth": 18, - "endWidth": 25, - "smoothWidth": 4, - "tileClass": clShore - }); - } + g_Map.log("Creating beaches"); + for (let i = 0; i < nbBeaches + 1; ++i) + { + const angle = Math.PI * (island + (i / (nbBeaches * 2.5)) + 1 / (nbBeaches * 6) + randFloat(-1, 1) / (nbBeaches * 7)) + swapAngle; + const start = Vector2D.add(islandLocations[island], new Vector2D(radiusIsland, 0).rotate(-angle)); + const end = Vector2D.add(islandLocations[island], new Vector2D(radiusBeach, 0).rotate(-angle)); - g_Map.log("Creating main relief"); - createArea( - new ClumpPlacer(diskArea(radiusIsland), 1, 0.2, Infinity, islandLocations[island]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetMainRelief, fractionToTiles(0.45))); + createArea( + new ClumpPlacer(130, 0.7, 0.8, Infinity, Vector2D.add(start, Vector2D.mult(end, 3)).div(4)), + new SmoothElevationPainter(ELEVATION_SET, heightBeaches, 5)); - g_Map.log("Creating first level plateau"); - createArea( - new ClumpPlacer(diskArea(radiusLevel1), 0.95, 0.02, Infinity, islandLocations[island]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLevel1, 1)); + createPassage({ + "start": start, + "end": end, + "startWidth": 18, + "endWidth": 25, + "smoothWidth": 4, + "tileClass": clShore + }); + } - g_Map.log("Creating first level passages"); - for (let i = 0; i <= nbPassagesLevel1; ++i) - { - const 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 - }); - } + g_Map.log("Creating main relief"); + createArea( + new ClumpPlacer(diskArea(radiusIsland), 1, 0.2, Infinity, islandLocations[island]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetMainRelief, fractionToTiles(0.45))); - if (mapSize > 150) - { - g_Map.log("Creating second level plateau"); + g_Map.log("Creating first level plateau"); createArea( - new ClumpPlacer(diskArea(radiusLevel2), 0.98, 0.04, Infinity, islandLocations[island]), - [ - new LayeredPainter([tCliffs, tGrass], [2]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLevel2, 1) - ]); + new ClumpPlacer(diskArea(radiusLevel1), 0.95, 0.02, Infinity, islandLocations[island]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLevel1, 1)); - g_Map.log("Creating second level passages"); - for (let i = 0; i < nbPassagesLevel2; ++i) + g_Map.log("Creating first level passages"); + for (let i = 0; i <= nbPassagesLevel1; ++i) { - const angle = Math.PI * (i / (2 * nbPassagesLevel2) + 1 / (4 * nbPassagesLevel2) + island) + swapAngle; + const angle = Math.PI * (i / 7 + 1 / 9 + 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, + "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": 2, + "smoothWidth": 3, "tileClass": clPassage }); } - } -} -Engine.SetProgress(30); - -g_Map.log("Determining player locations"); -const playerIDs = sortAllPlayers(); -let playerPosition = []; -let playerAngle = []; -let p = 0; -for (let island = 0; island < 2; ++island) -{ - const 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])); - addCivicCenterAreaToClass(playerPosition[p], clPlayer); - ++p; + if (mapSize > 150) + { + g_Map.log("Creating second level plateau"); + createArea( + new ClumpPlacer(diskArea(radiusLevel2), 0.98, 0.04, Infinity, islandLocations[island]), + [ + new LayeredPainter([tCliffs, tGrass], [2]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLevel2, 1) + ]); + + g_Map.log("Creating second level passages"); + for (let i = 0; i < nbPassagesLevel2; ++i) + { + const 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 + }); + } + } } -} + yield 30; + + g_Map.log("Determining player locations"); + const playerIDs = sortAllPlayers(); + let playerPosition = []; + let playerAngle = []; + let p = 0; + for (let island = 0; island < 2; ++island) + { + const playersPerIsland = island == 0 ? Math.ceil(numPlayers / 2) : Math.floor(numPlayers / 2); -placePlayerBases({ - "PlayerPlacement": [sortAllPlayers(), playerPosition], - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": avoidClasses(clPlayer, 2), - "Walls": false, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad, - "coherence": 0.8, - "radius": 6, - "painters": [ - new TileClassPainter(clSettlement) - ] - }, - "StartingAnimal": { - }, - "Berries": { - "template": eBush - }, - "Mines": { - "types": [ - { "template": eMetalMine }, - { "template": eStoneMine } - ] + 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])); + addCivicCenterAreaToClass(playerPosition[p], clPlayer); + ++p; + } } - // Sufficient starting trees around, no decoratives -}); -Engine.SetProgress(40); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(70, 0.6, 0.1, Infinity), - [new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBumps, 3)], - [ - stayClasses(clIsland, 2), - avoidClasses(clPlayer, 6, clPassage, 2) - ], - scaleByMapSize(20, 100), - 5); - -g_Map.log("Creating anti bumps"); -createAreas( - new ClumpPlacer(120, 0.3, 0.1, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetAntiBumps, 6), - avoidClasses(clPlayer, 6, clPassage, 2, clIsland, 2), - scaleByMapSize(20, 100), - 5); - -g_Map.log("Painting water"); -paintTileClassBasedOnHeight(-Infinity, 0, Elevation_ExcludeMin_ExcludeMax, clWater); - -g_Map.log("Painting land"); -for (let mapX = 0; mapX < mapSize; ++mapX) - for (let mapZ = 0; mapZ < mapSize; ++mapZ) - { - const position = new Vector2D(mapX, mapZ); - const terrain = getCosricaSardiniaTerrain(position); - if (!terrain) - continue; - createTerrain(terrain).place(position); + placePlayerBases({ + "PlayerPlacement": [sortAllPlayers(), playerPosition], + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": avoidClasses(clPlayer, 2), + "Walls": false, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad, + "coherence": 0.8, + "radius": 6, + "painters": [ + new TileClassPainter(clSettlement) + ] + }, + "StartingAnimal": { + }, + "Berries": { + "template": eBush + }, + "Mines": { + "types": [ + { "template": eMetalMine }, + { "template": eStoneMine } + ] + } + // Sufficient starting trees around, no decoratives + }); + yield 40; + + g_Map.log("Creating bumps"); + createAreas( + new ClumpPlacer(70, 0.6, 0.1, Infinity), + [new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBumps, 3)], + [ + stayClasses(clIsland, 2), + avoidClasses(clPlayer, 6, clPassage, 2) + ], + scaleByMapSize(20, 100), + 5); + + g_Map.log("Creating anti bumps"); + createAreas( + new ClumpPlacer(120, 0.3, 0.1, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetAntiBumps, 6), + avoidClasses(clPlayer, 6, clPassage, 2, clIsland, 2), + scaleByMapSize(20, 100), + 5); + + g_Map.log("Painting water"); + paintTileClassBasedOnHeight(-Infinity, 0, Elevation_ExcludeMin_ExcludeMax, clWater); + + g_Map.log("Painting land"); + for (let mapX = 0; mapX < mapSize; ++mapX) + for (let mapZ = 0; mapZ < mapSize; ++mapZ) + { + const position = new Vector2D(mapX, mapZ); + const terrain = getCosricaSardiniaTerrain(position); + if (!terrain) + continue; - if (terrain == tCliffs || terrain == tSteepCliffs) - clCliffs.add(position); - } + createTerrain(terrain).place(position); -function getCosricaSardiniaTerrain(position) -{ - const isWater = clWater.countMembersInRadius(position, 3); - const isShore = clShore.countMembersInRadius(position, 2); - const isPassage = clPassage.countMembersInRadius(position, 2); - const isSettlement = clSettlement.countMembersInRadius(position, 2); + if (terrain == tCliffs || terrain == tSteepCliffs) + clCliffs.add(position); + } - if (isSettlement) - return undefined; + function getCosricaSardiniaTerrain(position) + { + const isWater = clWater.countMembersInRadius(position, 3); + const isShore = clShore.countMembersInRadius(position, 2); + const isPassage = clPassage.countMembersInRadius(position, 2); + const isSettlement = clSettlement.countMembersInRadius(position, 2); - const height = g_Map.getHeight(position); - const slope = g_Map.getSlope(position); + if (isSettlement) + return undefined; - if (height >= 0.5 && height < 1.5 && isShore) - return tSandTransition; + const height = g_Map.getHeight(position); + const slope = g_Map.getSlope(position); - // Paint land cliffs and grass - if (height >= 1 && !isWater) - { - if (isPassage) - return tGrass; + if (height >= 0.5 && height < 1.5 && isShore) + return tSandTransition; - if (slope >= 1.25) - return height > 25 ? tSteepCliffs : tCliffs; + // Paint land cliffs and grass + if (height >= 1 && !isWater) + { + if (isPassage) + return tGrass; - if (height < 17) - return tGrass; + if (slope >= 1.25) + return height > 25 ? tSteepCliffs : tCliffs; - if (slope < 0.625) - return tHill; + if (height < 17) + return tGrass; - return tMountain; - } + if (slope < 0.625) + return tHill; - if (slope >= 1.125) - return tCliffs; + return tMountain; + } - if (height >= 1.5) - return undefined; + if (slope >= 1.125) + return tCliffs; - if (height >= -0.75) - return tShore; + if (height >= 1.5) + return undefined; - if (height >= -3) - return tShoreBlend; + if (height >= -0.75) + return tShore; - if (height >= -6) - return tCreekWater; + if (height >= -3) + return tShoreBlend; - if (height > -10 && slope < 0.75) - return tDeepWater; + if (height >= -6) + return tCreekWater; - return undefined; -} + if (height > -10 && slope < 0.75) + return tDeepWater; -Engine.SetProgress(65); + return undefined; + } -g_Map.log("Creating mines"); -for (const mine of [eMetalMine, eStoneMine]) + yield 65; + + g_Map.log("Creating mines"); + for (const 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); + + g_Map.log("Creating grass patches"); + createAreas( + new ClumpPlacer(20, 0.3, 0.06, 0.5), + [ + new TerrainPainter(tLushGrass), + new TileClassPainter(clForest) + ], + avoidClasses( + clWater, 1, + clPlayer, 6, + clBaseResource, 3, + clCliffs, 1), + scaleByMapSize(10, 40)); + + g_Map.log("Creating forests"); createObjectGroupsDeprecated( new SimpleGroup( [ - new SimpleObject(mine, 1,1, 0,0), - new SimpleObject(aBushB, 1,1, 2,2), - new SimpleObject(aBushA, 0,2, 1,3) + 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, - clBaseResource), + clForest), 0, [ - stayClasses(clIsland, 1), + stayClasses(clIsland, 3), avoidClasses( - clWater, 3, - clPlayer, 6, + clWater, 1, + clForest, 0, + clPlayer, 3, clBaseResource, 4, clPassage, 2, - clCliffs, 1) - ], - scaleByMapSize(6, 25), - 1000); - -g_Map.log("Creating grass patches"); -createAreas( - new ClumpPlacer(20, 0.3, 0.06, 0.5), - [ - new TerrainPainter(tLushGrass), - new TileClassPainter(clForest) - ], - avoidClasses( - clWater, 1, - clPlayer, 6, - clBaseResource, 3, - clCliffs, 1), - scaleByMapSize(10, 40)); - -g_Map.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) + clCliffs, 2) ], - true, - clForest), - 0, - [ - stayClasses(clIsland, 3), + scaleByMapSize(350, 2500), + 100); + + yield 75; + + g_Map.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, 1, + clWater, 0, clForest, 0, - clPlayer, 3, + clPlayer, 6, clBaseResource, 4, - clPassage, 2, - clCliffs, 2) - ], - scaleByMapSize(350, 2500), - 100); - -Engine.SetProgress(75); + clPassage, 2), + scaleByMapSize(16, 262), + 50); -g_Map.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); - -g_Map.log("Creating large decorative rocks"); -const 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); - -g_Map.log("Creating decorative plants"); -const plantGroups = [ - new SimpleGroup( + g_Map.log("Creating large decorative rocks"); + const rocksGroup = new SimpleGroup( [ - new SimpleObject(aPlantA, 3, 7, 0, 3), - new SimpleObject(aPlantB, 3,6, 0, 3), - new SimpleObject(aPlantC, 1,4, 0, 4) + new SimpleObject(aLargeRock, 1, 2, 0, 1), + new SimpleObject(aRock, 1, 3, 0, 2) ], - true), - new SimpleGroup( - [ - new SimpleObject(aPlantB, 5, 20, 0, 5), - new SimpleObject(aPlantC, 4,10, 0,4) - ], - true) -]; -for (const group of plantGroups) + true); + createObjectGroupsDeprecated( - group, + rocksGroup, 0, avoidClasses( clWater, 0, + clForest, 0, + clPlayer, 6, clBaseResource, 4, - clShore, 3), - scaleByMapSize(100, 600), + clPassage, 2), + scaleByMapSize(8, 131), 50); -Engine.SetProgress(80); - -g_Map.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); - -g_Map.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); - -setAmbientColor(0.564706,0.543726,0.419608); -setWaterColor(0.2,0.294,0.49); -setWaterTint(0.208, 0.659, 0.925); -setWaterMurkiness(0.72); -setWaterWaviness(2.0); -setWaterType("ocean"); - -g_Map.ExportMap(); + createObjectGroupsDeprecated( + rocksGroup, + 0, + borderClasses(clWater, 5, 10), + scaleByMapSize(100, 800), + 500); + + g_Map.log("Creating decorative plants"); + const 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 (const group of plantGroups) + createObjectGroupsDeprecated( + group, + 0, + avoidClasses( + clWater, 0, + clBaseResource, 4, + clShore, 3), + scaleByMapSize(100, 600), + 50); + + yield 80; + + g_Map.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); + + g_Map.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); + + yield 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); + + setAmbientColor(0.564706,0.543726,0.419608); + setWaterColor(0.2,0.294,0.49); + setWaterTint(0.208, 0.659, 0.925); + setWaterMurkiness(0.72); + setWaterWaviness(2.0); + setWaterType("ocean"); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/cycladic_archipelago.js =================================================================== --- binaries/data/mods/public/maps/random/cycladic_archipelago.js +++ binaries/data/mods/public/maps/random/cycladic_archipelago.js @@ -1,364 +1,378 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tOceanRockDeep = "medit_sea_coral_deep"; -const tOceanCoral = "medit_sea_coral_plants"; -const tBeachWet = "medit_sand_wet"; -const tBeachDry = "medit_sand"; -const tBeach = ["medit_rocks_grass","medit_sand", "medit_rocks_grass_shrubs"]; -const tBeachBlend = ["medit_rocks_grass", "medit_rocks_grass_shrubs"]; -const tCity = "medit_city_tile"; -const tGrassDry = ["medit_grass_field_dry", "medit_grass_field_b"]; -const tGrass = ["medit_rocks_grass", "medit_rocks_grass","medit_dirt","medit_rocks_grass_shrubs"]; -const tGrassShrubs = "medit_shrubs"; -const tCliffShrubs = ["medit_cliff_aegean_shrubs", "medit_cliff_italia_grass","medit_cliff_italia"]; -const tCliff = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"]; -const tForestFloor = "medit_forestfloor_a"; -const tWater = "medit_sea_depths"; - -const oBeech = "gaia/tree/euro_beech"; -const oBerryBush = "gaia/fruit/berry_01"; -const oCarob = "gaia/tree/carob"; -const oCypress1 = "gaia/tree/cypress"; -const oCypress2 = "gaia/tree/cypress"; -const oLombardyPoplar = "gaia/tree/poplar_lombardy"; -const oPalm = "gaia/tree/medit_fan_palm"; -const oPine = "gaia/tree/aleppo_pine"; -const oDateT = "gaia/tree/cretan_date_palm_tall"; -const oDateS = "gaia/tree/cretan_date_palm_short"; -const oDeer = "gaia/fauna_deer"; -const oFish = "gaia/fish/generic"; -const oWhale = "gaia/fauna_whale_humpback"; -const oStoneLarge = "gaia/rock/mediterranean_large"; -const oStoneSmall = "gaia/rock/mediterranean_small"; -const oMetalLarge = "gaia/ore/mediterranean_large"; -const oShipwreck = "gaia/treasure/shipwreck"; -const oShipDebris = "gaia/treasure/shipwreck_debris"; - -const aRockLarge = "actor|geology/stone_granite_large.xml"; -const aRockMed = "actor|geology/stone_granite_med.xml"; -const aRockSmall = "actor|geology/stone_granite_small.xml"; - -const pPalmForest = [tForestFloor+TERRAIN_SEPARATOR+oPalm, tGrass]; -const pPineForest = [tForestFloor+TERRAIN_SEPARATOR+oPine, tGrass]; -const pPoplarForest = [tForestFloor+TERRAIN_SEPARATOR+oLombardyPoplar, tGrass]; -const pMainForest = [tForestFloor+TERRAIN_SEPARATOR+oCarob, tForestFloor+TERRAIN_SEPARATOR+oBeech, tGrass, tGrass]; - -const heightSeaGround = -5; -const heightLand = 3; -const heightHill = 12; -const heightOffsetBump = 2; - -const g_Map = new RandomMap(heightSeaGround, tWater); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clCoral = g_Map.createTileClass(); -const clPlayer = g_Map.createTileClass(); -const clIsland = g_Map.createTileClass(); -const clCity = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -//array holding starting islands based on number of players -const startingPlaces=[[0],[0,3],[0,2,4],[0,1,3,4],[0,1,2,3,4],[0,1,2,3,4,5]]; - -const startAngle = randomAngle(); - -const islandRadius = scaleByMapSize(15, 40); -const islandCount = Math.max(6, numPlayers); -const islandPosition = distributePointsOnCircle(islandCount, startAngle, fractionToTiles(0.39), mapCenter)[0].map(position => position.round()); - -const centralIslandRadius = scaleByMapSize(15, 30); -const centralIslandCount = Math.floor(scaleByMapSize(1, 4)); -const centralIslandPosition = new Array(numPlayers).fill(0).map((v, i) => - Vector2D.add(mapCenter, new Vector2D(fractionToTiles(randFloat(0.1, 0.16)), 0).rotate( - -startAngle - Math.PI * (i * 2 / centralIslandCount + randFloat(-1, 1) / 8)).round())); - -const areas = []; - -var nPlayer = 0; -var playerPosition = []; - -function createCycladicArchipelagoIsland(position, tileClass, radius, coralRadius) +function* GenerateMap() { - // Deep ocean rocks - createArea( - new ClumpPlacer(diskArea(radius + coralRadius), 0.7, 0.1, Infinity, position), - [ - new LayeredPainter([tOceanRockDeep, tOceanCoral], [5]), - new TileClassPainter(clCoral) - ], - avoidClasses(clCoral, 0, clPlayer, 0)); - - // Island - areas.push( + const tOceanRockDeep = "medit_sea_coral_deep"; + const tOceanCoral = "medit_sea_coral_plants"; + const tBeachWet = "medit_sand_wet"; + const tBeachDry = "medit_sand"; + const tBeach = ["medit_rocks_grass","medit_sand", "medit_rocks_grass_shrubs"]; + const tBeachBlend = ["medit_rocks_grass", "medit_rocks_grass_shrubs"]; + const tCity = "medit_city_tile"; + const tGrassDry = ["medit_grass_field_dry", "medit_grass_field_b"]; + const tGrass = ["medit_rocks_grass", "medit_rocks_grass","medit_dirt","medit_rocks_grass_shrubs"]; + const tGrassShrubs = "medit_shrubs"; + const tCliffShrubs = ["medit_cliff_aegean_shrubs", "medit_cliff_italia_grass","medit_cliff_italia"]; + const tCliff = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"]; + const tForestFloor = "medit_forestfloor_a"; + const tWater = "medit_sea_depths"; + + const oBeech = "gaia/tree/euro_beech"; + const oBerryBush = "gaia/fruit/berry_01"; + const oCarob = "gaia/tree/carob"; + const oCypress1 = "gaia/tree/cypress"; + const oCypress2 = "gaia/tree/cypress"; + const oLombardyPoplar = "gaia/tree/poplar_lombardy"; + const oPalm = "gaia/tree/medit_fan_palm"; + const oPine = "gaia/tree/aleppo_pine"; + const oDateT = "gaia/tree/cretan_date_palm_tall"; + const oDateS = "gaia/tree/cretan_date_palm_short"; + const oDeer = "gaia/fauna_deer"; + const oFish = "gaia/fish/generic"; + const oWhale = "gaia/fauna_whale_humpback"; + const oStoneLarge = "gaia/rock/mediterranean_large"; + const oStoneSmall = "gaia/rock/mediterranean_small"; + const oMetalLarge = "gaia/ore/mediterranean_large"; + const oShipwreck = "gaia/treasure/shipwreck"; + const oShipDebris = "gaia/treasure/shipwreck_debris"; + + const aRockLarge = "actor|geology/stone_granite_large.xml"; + const aRockMed = "actor|geology/stone_granite_med.xml"; + const aRockSmall = "actor|geology/stone_granite_small.xml"; + + const pPalmForest = [tForestFloor+TERRAIN_SEPARATOR+oPalm, tGrass]; + const pPineForest = [tForestFloor+TERRAIN_SEPARATOR+oPine, tGrass]; + const pPoplarForest = [tForestFloor+TERRAIN_SEPARATOR+oLombardyPoplar, tGrass]; + const pMainForest = + [tForestFloor+TERRAIN_SEPARATOR+oCarob, tForestFloor+TERRAIN_SEPARATOR+oBeech, tGrass, tGrass]; + + const heightSeaGround = -5; + const heightLand = 3; + const heightHill = 12; + const heightOffsetBump = 2; + + global.g_Map = new RandomMap(heightSeaGround, tWater); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clCoral = g_Map.createTileClass(); + const clPlayer = g_Map.createTileClass(); + const clIsland = g_Map.createTileClass(); + const clCity = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + //array holding starting islands based on number of players + const startingPlaces=[[0],[0,3],[0,2,4],[0,1,3,4],[0,1,2,3,4],[0,1,2,3,4,5]]; + + const startAngle = randomAngle(); + + const islandRadius = scaleByMapSize(15, 40); + const islandCount = Math.max(6, numPlayers); + const islandPosition = + distributePointsOnCircle(islandCount, startAngle, fractionToTiles(0.39), mapCenter)[0] + .map(position => position.round()); + + const centralIslandRadius = scaleByMapSize(15, 30); + const centralIslandCount = Math.floor(scaleByMapSize(1, 4)); + const centralIslandPosition = new Array(numPlayers).fill(0).map((v, i) => + Vector2D.add(mapCenter, new Vector2D(fractionToTiles(randFloat(0.1, 0.16)), 0).rotate( + -startAngle - Math.PI * (i * 2 / centralIslandCount + randFloat(-1, 1) / 8)).round())); + + const areas = []; + + var nPlayer = 0; + var playerPosition = []; + + function createCycladicArchipelagoIsland(position, tileClass, radius, coralRadius) + { + // Deep ocean rocks createArea( - new ClumpPlacer(diskArea(radius), 0.7, 0.1, Infinity, position), + new ClumpPlacer(diskArea(radius + coralRadius), 0.7, 0.1, Infinity, position), [ - new LayeredPainter([tOceanCoral, tBeachWet, tBeachDry, tBeach, tBeachBlend, tGrass], [1, 3, 1, 1, 2]), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 5), - new TileClassPainter(tileClass) + new LayeredPainter([tOceanRockDeep, tOceanCoral], [5]), + new TileClassPainter(clCoral) ], - avoidClasses(clPlayer, 0))); -} + avoidClasses(clCoral, 0, clPlayer, 0)); + + // Island + areas.push( + createArea( + new ClumpPlacer(diskArea(radius), 0.7, 0.1, Infinity, position), + [ + new LayeredPainter( + [tOceanCoral, tBeachWet, tBeachDry, tBeach, tBeachBlend, tGrass], + [1, 3, 1, 1, 2]), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 5), + new TileClassPainter(tileClass) + ], + avoidClasses(clPlayer, 0))); + } -g_Map.log("Creating player islands"); -for (let i = 0; i < islandCount; ++i) -{ - const isPlayerIsland = numPlayers >= 6 || i == startingPlaces[numPlayers - 1][nPlayer]; - if (isPlayerIsland) + g_Map.log("Creating player islands"); + for (let i = 0; i < islandCount; ++i) { - playerPosition[nPlayer] = islandPosition[i]; - ++nPlayer; + const isPlayerIsland = numPlayers >= 6 || i == startingPlaces[numPlayers - 1][nPlayer]; + if (isPlayerIsland) + { + playerPosition[nPlayer] = islandPosition[i]; + ++nPlayer; + } + createCycladicArchipelagoIsland(islandPosition[i], isPlayerIsland ? clPlayer : clIsland, + islandRadius, scaleByMapSize(1, 5)); } - createCycladicArchipelagoIsland(islandPosition[i], isPlayerIsland ? clPlayer : clIsland, islandRadius, scaleByMapSize(1, 5)); -} -g_Map.log("Creating central islands"); -for (const position of centralIslandPosition) - createCycladicArchipelagoIsland(position, clIsland, centralIslandRadius, 2); - -placePlayerBases({ - "PlayerPlacement": [sortAllPlayers(), playerPosition], - // PlayerTileClass is clCity here and painted below - "BaseResourceClass": clBaseResource, - "Walls": "towers", - "CityPatch": { - "radius": 6, - "outerTerrain": tGrass, - "innerTerrain": tCity, - "painters": [ - new TileClassPainter(clCity) - ] - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oPalm, - "count": 2 - } - // No decoratives -}); -Engine.SetProgress(20); - -g_Map.log("Creating bumps"); -createAreasInAreas( - new ClumpPlacer(scaleByMapSize(20, 60), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 3), - avoidClasses(clCity, 0), - scaleByMapSize(25, 75),15, - areas); - -Engine.SetProgress(34); - -g_Map.log("Creating hills"); -createAreasInAreas( - new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), - [ - new LayeredPainter([tCliff, tCliffShrubs], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - avoidClasses(clCity, 15, clHill, 15), - scaleByMapSize(5, 30), 15, - areas); - -Engine.SetProgress(38); - -paintTileClassBasedOnHeight(-Infinity, 0, Elevation_ExcludeMin_ExcludeMax, clWater); - -g_Map.log("Creating forests"); -var forestTypes = [ - [[tForestFloor, tGrass, pPalmForest], [tForestFloor, pPalmForest]], - [[tForestFloor, tGrass, pPineForest], [tForestFloor, pPineForest]], - [[tForestFloor, tGrass, pPoplarForest], [tForestFloor, pPoplarForest]], - [[tForestFloor, tGrass, pMainForest], [tForestFloor, pMainForest]] -]; - -for (const type of forestTypes) + g_Map.log("Creating central islands"); + for (const position of centralIslandPosition) + createCycladicArchipelagoIsland(position, clIsland, centralIslandRadius, 2); + + placePlayerBases({ + "PlayerPlacement": [sortAllPlayers(), playerPosition], + // PlayerTileClass is clCity here and painted below + "BaseResourceClass": clBaseResource, + "Walls": "towers", + "CityPatch": { + "radius": 6, + "outerTerrain": tGrass, + "innerTerrain": tCity, + "painters": [ + new TileClassPainter(clCity) + ] + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oPalm, + "count": 2 + } + // No decoratives + }); + yield 20; + + g_Map.log("Creating bumps"); createAreasInAreas( - new ClumpPlacer(randIntInclusive(6, 17), 0.1, 0.1, Infinity), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) - ], - avoidClasses(clCity, 1, clWater, 3, clForest, 3, clHill, 1, clBaseResource, 4), - scaleByMapSize(10, 64), - 20, - areas); -Engine.SetProgress(42); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsByAreasDeprecated(group, 0, - [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clRock, 6)], - scaleByMapSize(4,16), 200, areas -); -Engine.SetProgress(46); - -g_Map.log("Creating small stone mines"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsByAreasDeprecated(group, 0, - [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clRock, 6)], - scaleByMapSize(4,16), 200, areas -); -Engine.SetProgress(50); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsByAreasDeprecated(group, 0, - [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clMetal, 6, clRock, 6)], - scaleByMapSize(4,16), 200, areas -); -Engine.SetProgress(54); - -g_Map.log("Creating shrub patches"); -for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) - createAreasInAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - [ - new LayeredPainter([tBeachBlend, tGrassShrubs], [1]), - new TileClassPainter(clDirt) - ], - avoidClasses(clWater, 3, clHill, 0, clDirt, 6, clCity, 0, clBaseResource, 4), - scaleByMapSize(4, 16), - 20, + new ClumpPlacer(scaleByMapSize(20, 60), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 3), + avoidClasses(clCity, 0), + scaleByMapSize(25, 75),15, areas); -Engine.SetProgress(58); -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) + yield 34; + + g_Map.log("Creating hills"); createAreasInAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), + new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), [ - new LayeredPainter([tGrassDry], []), - new TileClassPainter(clDirt) + new LayeredPainter([tCliff, tCliffShrubs], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) ], - avoidClasses(clWater, 3, clHill, 0, clDirt, 6, clCity, 0, clBaseResource, 4), - scaleByMapSize(4, 16), - 20, + avoidClasses(clCity, 15, clHill, 15), + scaleByMapSize(5, 30), 15, areas); -Engine.SetProgress(62); - -g_Map.log("Creating straggler trees"); -for (const tree of [oCarob, oBeech, oLombardyPoplar, oLombardyPoplar, oPine]) - createObjectGroupsByAreasDeprecated( - new SimpleGroup([new SimpleObject(tree, 1,1, 0,1)], true, clForest), - 0, - avoidClasses(clWater, 2, clForest, 2, clCity, 3, clBaseResource, 4, clRock, 6, clMetal, 6, clPlayer, 1, clHill, 1), - scaleByMapSize(2, 38), 50, areas + + yield 38; + + paintTileClassBasedOnHeight(-Infinity, 0, Elevation_ExcludeMin_ExcludeMax, clWater); + + g_Map.log("Creating forests"); + var forestTypes = [ + [[tForestFloor, tGrass, pPalmForest], [tForestFloor, pPalmForest]], + [[tForestFloor, tGrass, pPineForest], [tForestFloor, pPineForest]], + [[tForestFloor, tGrass, pPoplarForest], [tForestFloor, pPoplarForest]], + [[tForestFloor, tGrass, pMainForest], [tForestFloor, pMainForest]] + ]; + + for (const type of forestTypes) + createAreasInAreas( + new ClumpPlacer(randIntInclusive(6, 17), 0.1, 0.1, Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses(clCity, 1, clWater, 3, clForest, 3, clHill, 1, clBaseResource, 4), + scaleByMapSize(10, 64), + 20, + areas); + yield 42; + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsByAreasDeprecated(group, 0, + [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clRock, 6)], + scaleByMapSize(4,16), 200, areas + ); + yield 46; + + g_Map.log("Creating small stone mines"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsByAreasDeprecated(group, 0, + [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clRock, 6)], + scaleByMapSize(4,16), 200, areas + ); + yield 50; + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsByAreasDeprecated(group, 0, + [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clMetal, 6, clRock, 6)], + scaleByMapSize(4,16), 200, areas + ); + yield 54; + + g_Map.log("Creating shrub patches"); + for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) + createAreasInAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new LayeredPainter([tBeachBlend, tGrassShrubs], [1]), + new TileClassPainter(clDirt) + ], + avoidClasses(clWater, 3, clHill, 0, clDirt, 6, clCity, 0, clBaseResource, 4), + scaleByMapSize(4, 16), + 20, + areas); + yield 58; + + g_Map.log("Creating grass patches"); + for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) + createAreasInAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new LayeredPainter([tGrassDry], []), + new TileClassPainter(clDirt) + ], + avoidClasses(clWater, 3, clHill, 0, clDirt, 6, clCity, 0, clBaseResource, 4), + scaleByMapSize(4, 16), + 20, + areas); + yield 62; + + g_Map.log("Creating straggler trees"); + for (const tree of [oCarob, oBeech, oLombardyPoplar, oLombardyPoplar, oPine]) + createObjectGroupsByAreasDeprecated( + new SimpleGroup([new SimpleObject(tree, 1,1, 0,1)], true, clForest), + 0, + avoidClasses(clWater, 2, clForest, 2, clCity, 3, clBaseResource, 4, clRock, 6, clMetal, 6, + clPlayer, 1, clHill, 1), + scaleByMapSize(2, 38), 50, areas + ); + yield 66; + + g_Map.log("Create straggler cypresses"); + group = new SimpleGroup( + [new SimpleObject(oCypress2, 1,3, 0,3), new SimpleObject(oCypress1, 0,2, 0,2)], + true + ); + createObjectGroupsByAreasDeprecated(group, 0, + avoidClasses(clWater, 2, clForest, 2, clCity, 3, clBaseResource, 4, clRock, 6, clMetal, 6, + clPlayer, 1, clHill, 1), + scaleByMapSize(5, 75), 50, areas + ); + yield 70; + + g_Map.log("Create straggler date palms"); + group = new SimpleGroup( + [new SimpleObject(oDateS, 1,3, 0,3), new SimpleObject(oDateT, 0,2, 0,2)], + true + ); + createObjectGroupsByAreasDeprecated(group, 0, + avoidClasses(clWater, 2, clForest, 1, clCity, 0, clBaseResource, 4, clRock, 6, clMetal, 6, + clPlayer, 1, clHill, 1), + scaleByMapSize(5, 75), 50, areas + ); + yield 74; + + g_Map.log("Creating rocks"); + group = new SimpleGroup( + [new SimpleObject(aRockSmall, 0,3, 0,2), new SimpleObject(aRockMed, 0,2, 0,2), + new SimpleObject(aRockLarge, 0,1, 0,2)] + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 0, clCity, 0), + scaleByMapSize(30, 180), 50 + ); + yield 78; + + g_Map.log("Creating deer"); + group = new SimpleGroup( + [new SimpleObject(oDeer, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 5, clForest, 1, clHill, 1, clCity, 10, clMetal, 6, clRock, 4, clFood, 8), + 3 * numPlayers, 50 ); -Engine.SetProgress(66); - -g_Map.log("Create straggler cypresses"); -group = new SimpleGroup( - [new SimpleObject(oCypress2, 1,3, 0,3), new SimpleObject(oCypress1, 0,2, 0,2)], - true -); -createObjectGroupsByAreasDeprecated(group, 0, - avoidClasses(clWater, 2, clForest, 2, clCity, 3, clBaseResource, 4, clRock, 6, clMetal, 6, clPlayer, 1, clHill, 1), - scaleByMapSize(5, 75), 50, areas -); -Engine.SetProgress(70); - -g_Map.log("Create straggler date palms"); -group = new SimpleGroup( - [new SimpleObject(oDateS, 1,3, 0,3), new SimpleObject(oDateT, 0,2, 0,2)], - true -); -createObjectGroupsByAreasDeprecated(group, 0, - avoidClasses(clWater, 2, clForest, 1, clCity, 0, clBaseResource, 4, clRock, 6, clMetal, 6, clPlayer, 1, clHill, 1), - scaleByMapSize(5, 75), 50, areas -); -Engine.SetProgress(74); - -g_Map.log("Creating rocks"); -group = new SimpleGroup( - [new SimpleObject(aRockSmall, 0,3, 0,2), new SimpleObject(aRockMed, 0,2, 0,2), - new SimpleObject(aRockLarge, 0,1, 0,2)] -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 0, clCity, 0), - scaleByMapSize(30, 180), 50 -); -Engine.SetProgress(78); - -g_Map.log("Creating deer"); -group = new SimpleGroup( - [new SimpleObject(oDeer, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 5, clForest, 1, clHill, 1, clCity, 10, clMetal, 6, clRock, 4, clFood, 8), - 3 * numPlayers, 50 -); -Engine.SetProgress(82); - -g_Map.log("Creating berry bushes"); -group = new SimpleGroup([new SimpleObject(oBerryBush, 5,7, 0,3)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 2, clForest, 1, clHill, 1, clCity, 10, clMetal, 6, clRock, 4, clFood, 8), - 1.5 * numPlayers, 100 -); -Engine.SetProgress(86); - -g_Map.log("Creating Fish"); -group = new SimpleGroup([new SimpleObject(oFish, 1,1, 0,3)], true, clFood); -createObjectGroupsDeprecated(group, 0, - [stayClasses(clWater,1),avoidClasses(clFood, 8)], - scaleByMapSize(40,200), 100 -); -Engine.SetProgress(90); - -g_Map.log("Creating Whales"); -group = new SimpleGroup([new SimpleObject(oWhale, 1,1, 0,3)], true, clFood); -createObjectGroupsDeprecated(group, 0, - [stayClasses(clWater,1),avoidClasses(clFood, 8, clPlayer,4,clIsland,4)], - scaleByMapSize(10,40), 100 -); -Engine.SetProgress(94); - -g_Map.log("Creating shipwrecks"); -group = new SimpleGroup([new SimpleObject(oShipwreck, 1,1, 0,3)], true, clFood); -createObjectGroupsDeprecated(group, 0, - [stayClasses(clWater,1),avoidClasses(clFood, 8)], - scaleByMapSize(6,16), 100 -); -Engine.SetProgress(98); - -g_Map.log("Creating shipwreck debris"); -group = new SimpleGroup([new SimpleObject(oShipDebris, 1,2, 0,4)], true, clFood); -createObjectGroupsDeprecated(group, 0, - [stayClasses(clWater,1),avoidClasses(clFood, 8)], - scaleByMapSize(10,20), 100 -); -Engine.SetProgress(99); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clBaseResource, 4, clHill, 4, clMetal, 4, clRock, 4, clFood, 1)); - -setSkySet("sunny"); -setWaterColor(0.2,0.294,0.49); -setWaterTint(0.208, 0.659, 0.925); -setWaterMurkiness(0.72); -setWaterWaviness(3.0); -setWaterType("ocean"); - -g_Map.ExportMap(); + yield 82; + + g_Map.log("Creating berry bushes"); + group = new SimpleGroup([new SimpleObject(oBerryBush, 5,7, 0,3)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 2, clForest, 1, clHill, 1, clCity, 10, clMetal, 6, clRock, 4, clFood, 8), + 1.5 * numPlayers, 100 + ); + yield 86; + + g_Map.log("Creating Fish"); + group = new SimpleGroup([new SimpleObject(oFish, 1,1, 0,3)], true, clFood); + createObjectGroupsDeprecated(group, 0, + [stayClasses(clWater,1),avoidClasses(clFood, 8)], + scaleByMapSize(40,200), 100 + ); + yield 90; + + g_Map.log("Creating Whales"); + group = new SimpleGroup([new SimpleObject(oWhale, 1,1, 0,3)], true, clFood); + createObjectGroupsDeprecated(group, 0, + [stayClasses(clWater,1),avoidClasses(clFood, 8, clPlayer,4,clIsland,4)], + scaleByMapSize(10,40), 100 + ); + yield 94; + + g_Map.log("Creating shipwrecks"); + group = new SimpleGroup([new SimpleObject(oShipwreck, 1,1, 0,3)], true, clFood); + createObjectGroupsDeprecated(group, 0, + [stayClasses(clWater,1),avoidClasses(clFood, 8)], + scaleByMapSize(6,16), 100 + ); + yield 98; + + g_Map.log("Creating shipwreck debris"); + group = new SimpleGroup([new SimpleObject(oShipDebris, 1,2, 0,4)], true, clFood); + createObjectGroupsDeprecated(group, 0, + [stayClasses(clWater,1),avoidClasses(clFood, 8)], + scaleByMapSize(10,20), 100 + ); + yield 99; + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clBaseResource, 4, clHill, 4, + clMetal, 4, clRock, 4, clFood, 1)); + + setSkySet("sunny"); + setWaterColor(0.2,0.294,0.49); + setWaterTint(0.208, 0.659, 0.925); + setWaterMurkiness(0.72); + setWaterWaviness(3.0); + setWaterType("ocean"); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/danubius.js =================================================================== --- binaries/data/mods/public/maps/random/danubius.js +++ binaries/data/mods/public/maps/random/danubius.js @@ -1,844 +1,907 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const day = g_MapSettings.Daytime !== undefined ? g_MapSettings.Daytime == "day" : randBool(2/3); - -// Spawn ships away from the shoreline, but patrol close to the shoreline -const triggerPointShipSpawn = "trigger/trigger_point_A"; -const triggerPointShipPatrol = "trigger/trigger_point_B"; -const triggerPointShipUnloadLeft = "trigger/trigger_point_C"; -const triggerPointShipUnloadRight = "trigger/trigger_point_D"; -const triggerPointLandPatrolLeft = "trigger/trigger_point_E"; -const triggerPointLandPatrolRight = "trigger/trigger_point_F"; -const triggerPointCCAttackerPatrolLeft = "trigger/trigger_point_G"; -const triggerPointCCAttackerPatrolRight = "trigger/trigger_point_H"; -const triggerPointRiverDirection = "trigger/trigger_point_I"; - -const tPrimary = ["temp_grass_aut", "temp_grass_plants_aut", "temp_grass_c_aut", "temp_grass_d_aut"]; -const tRoad = "steppe_river_rocks"; -const tIsland = ["temp_grass_long_b_aut", "temp_grass_plants_aut", "temp_forestfloor_aut"]; -const tCliff = "temp_cliff_a"; -const tForestFloor = "temp_forestfloor_aut"; -const tGrass = "medit_shrubs_golden"; -const tGrass2 ="grass_mediterranean_dry_1024test"; -const tGrass3 = "medit_grass_field_b"; -const tShore = "temp_dirt_gravel_b"; -const tWater = "steppe_river_rocks_wet"; -const tSeaDepths = "medit_sea_depths"; - -const oBerryBush = "gaia/fruit/berry_01"; -const oDeer = "gaia/fauna_deer"; -const oFish = "gaia/fish/generic"; -const oSheep = "gaia/fauna_sheep"; -const oGoat = "gaia/fauna_goat"; -const oWolf = "gaia/fauna_wolf"; -const oHawk = "birds/buzzard"; -const oRabbit = "gaia/fauna_rabbit"; -const oBoar = "gaia/fauna_boar"; -const oBear = "gaia/fauna_bear_brown"; -const oStoneLarge = "gaia/rock/temperate_large"; -const oStoneRuins = "gaia/ruins/standing_stone"; -const oMetalLarge = "gaia/ore/mediterranean_large"; -const oApple = "gaia/fruit/apple"; -const oAcacia = "gaia/tree/acacia"; -const oOak = "gaia/tree/oak_aut"; -const oOak2 = "gaia/tree/oak_aut_new"; -const oOak3 = "gaia/tree/oak_dead"; -const oOak4 = "gaia/tree/oak"; -const oPopolar = "gaia/tree/poplar_lombardy"; -const oBeech = "gaia/tree/euro_beech_aut"; -const oBeech2 = "gaia/tree/euro_beech"; -const oTreasures = [ - "gaia/treasure/food_barrel", - "gaia/treasure/food_bin", - "gaia/treasure/stone", - "gaia/treasure/wood", - "gaia/treasure/metal" -]; - -// Disable capturing on all parts of the village except the -// civic center and buildings occurring outside of the village -const oCivicCenter = "structures/gaul/civil_centre"; -const oTower = "structures/gaul/defense_tower"; -const oOutpost = "structures/gaul/outpost"; - -const oTemple = "uncapturable|structures/gaul/temple"; -const oTavern = "uncapturable|structures/gaul/tavern"; -const oHouse = "uncapturable|structures/gaul/house"; -const oLongHouse = "uncapturable|structures/celt_longhouse"; -const oHut = "uncapturable|structures/celt_hut"; -const oSentryTower = "uncapturable|structures/gaul/sentry_tower"; -const oWatchTower = "uncapturable|structures/palisades_watchtower"; - -const oPalisadeTallSpikes = "uncapturable|structures/palisades_spikes_tall"; -const oPalisadeAngleSpikes = "uncapturable|structures/palisades_spike_angle"; -const oPalisadeCurve = "uncapturable|structures/palisades_curve"; -const oPalisadeShort = "uncapturable|structures/palisades_short"; -const oPalisadeMedium = "uncapturable|structures/palisades_medium"; -const oPalisadeLong = "uncapturable|structures/palisades_long"; -const oPalisadeGate = "uncapturable|structures/palisades_gate"; -const oPalisadePillar = "uncapturable|structures/palisades_tower"; - -const oFemale = "units/gaul/support_female_citizen"; -const oHealer = "units/gaul/support_healer_b"; -const oSkirmisher = "units/gaul/infantry_javelineer_b"; -const oNakedFanatic = "units/gaul/champion_fanatic"; - -const aBush1 = "actor|props/flora/bush_tempe_sm.xml"; -const aBush2 = "actor|props/flora/bush_tempe_me.xml"; -const aBush3 = "actor|props/flora/bush_tempe_la.xml"; -const aBush4 = "actor|props/flora/bush_tempe_me.xml"; -const aRock1 = "actor|geology/stone_granite_med.xml"; -const aRock2 = "actor|geology/stone_granite_boulder.xml"; -const aRock3 = "actor|geology/stone_granite_greek_boulder.xml"; -const aRock4 = "actor|geology/stonemine_alpine_a.xml"; -const aFerns = "actor|props/flora/ferns.xml"; -const aBucket = "actor|props/structures/celts/blacksmith_bucket"; -const aBarrel = "actor|props/structures/gauls/storehouse_barrel_b"; -const aTartan = "actor|props/structures/celts/tartan_a"; -const aWheel = "actor|props/special/eyecandy/wheel_laying"; -const aWell = "actor|props/special/eyecandy/well_1_b"; -const aWoodcord = "actor|props/special/eyecandy/woodcord"; -const aWaterLog = "actor|props/flora/water_log.xml"; -const aCampfire = "actor|props/special/eyecandy/campfire"; -const aBench = "actor|props/special/eyecandy/bench_1"; -const aRug = "actor|props/special/eyecandy/rug_stand_iber"; - -const treeTypes = [oOak, oOak2, oOak3, oOak4, oBeech, oBeech2, oAcacia]; - -const pForest1 = [ - tForestFloor, - tForestFloor + TERRAIN_SEPARATOR + oOak, - tForestFloor + TERRAIN_SEPARATOR + oOak2, - tForestFloor + TERRAIN_SEPARATOR + oOak3, - tForestFloor + TERRAIN_SEPARATOR + oOak4, - tForestFloor -]; - -const pForest2 = [ - tForestFloor, - tForestFloor + TERRAIN_SEPARATOR + oPopolar, - tForestFloor + TERRAIN_SEPARATOR + oBeech, - tForestFloor + TERRAIN_SEPARATOR + oBeech2, - tForestFloor + TERRAIN_SEPARATOR + oAcacia, - tForestFloor -]; - -const smallMapSize = 192; -const mediumMapSize = 256; -const normalMapSize = 320; - -// Minimum distance from the map border to ship ungarrison points -const ShorelineDistance = 15; - -const heightSeaGround = -3; -const heightShore = 1; -const heightLand = 3; -const heightPath = 1.5; -const heightIsland = 6; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clLand = [g_Map.createTileClass(), g_Map.createTileClass()]; -const clPatrolPointSiegeEngine = [g_Map.createTileClass(), g_Map.createTileClass()]; -const clPatrolPointSoldier = [g_Map.createTileClass(), g_Map.createTileClass()]; -const clShore = [g_Map.createTileClass(), g_Map.createTileClass()]; -const clShoreUngarrisonPoint = [g_Map.createTileClass(), g_Map.createTileClass()]; -const clShip = g_Map.createTileClass(); -const clShipPatrol = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clIsland = g_Map.createTileClass(); -const clTreasure = g_Map.createTileClass(); -const clWaterLog = g_Map.createTileClass(); -const clGauls = g_Map.createTileClass(); -const clTower = g_Map.createTileClass(); -const clOutpost = g_Map.createTileClass(); -const clPath = g_Map.createTileClass(); -const clRitualPlace = g_Map.createTileClass(); - -const startAngle = randomAngle(); -const waterWidth = fractionToTiles(0.3); - -// How many treasures will be placed near the gallic civic centers -const gallicCCTreasureCount = randIntInclusive(8, 12); - -// How many treasures will be placed randomly on the map at most -const randomTreasureCount = randIntInclusive(0, scaleByMapSize(0, 2)); - -const ritualParticipants = [ - { - "radius": 0.6, - "templates": [oFemale], - "count": 9, - "angle": Math.PI - }, - { - "radius": 0.8, - "templates": [oSkirmisher, oHealer, oNakedFanatic], - "count": 15, - "angle": Math.PI - }, - { - "radius": 1, - "templates": [aBench], - "count": 10, - "angle": Math.PI / 2 - }, - { - "radius": 1.1, - "templates": [oGoat], - "count": 7, - "angle": 0 - }, - { - "radius": 1.2, - "templates": [aRug], - "count": 8, - "angle": Math.PI - } -]; - -g_WallStyles.danubius_village = { - "house": { "angle": Math.PI, "length": 0, "indent": 4, "bend": 0, "templateName": oHouse }, - "hut": { "angle": Math.PI, "length": 0, "indent": 4, "bend": 0, "templateName": oHut }, - "longhouse": { "angle": Math.PI, "length": 0, "indent": 4, "bend": 0, "templateName": oLongHouse }, - "tavern": { "angle": Math.PI * 3/2, "length": 0, "indent": 4, "bend": 0, "templateName": oTavern }, - "temple": { "angle": Math.PI * 3/2, "length": 0, "indent": 4, "bend": 0, "templateName": oTemple }, - "defense_tower": { "angle": Math.PI / 2, "length": 0, "indent": 4, "bend": 0, "templateName": mapSize >= normalMapSize ? (isNomad() ? oSentryTower : oTower) : oWatchTower }, - "pillar": readyWallElement(oPalisadePillar), - "gate": readyWallElement(oPalisadeGate), - "long": readyWallElement(oPalisadeLong), - "medium": readyWallElement(oPalisadeMedium), - "short": readyWallElement(oPalisadeShort), - "cornerIn": readyWallElement(oPalisadeCurve), - "overlap": 0.05 -}; - -g_WallStyles.danubius_spikes = { - "spikes_tall": readyWallElement(oPalisadeTallSpikes, "gaia"), - "spike_single": readyWallElement(oPalisadeAngleSpikes, "gaia"), - "overlap": 0 -}; - -const fortressDanubiusVillage = new Fortress( - "Geto-Dacian Tribal Confederation", - new Array(2).fill([ - "gate", "pillar", "hut", "long", "long", - "cornerIn", "defense_tower", "long", "temple", "long", - "pillar", "house", "long", "short", "pillar", "gate", "pillar", "longhouse", "long", "long", - "cornerIn", "defense_tower", "long", "tavern", "long", "pillar" - ]).reduce((result, items) => result.concat(items), [])); - -const palisadeCorner = ["turn_0.25", "spike_single", "turn_0.25"]; -const palisadeGate = ["spike_single", "gap_3.6", "spike_single"]; -const palisadeWallShort = new Array(3).fill("spikes_tall"); -const palisadeWallLong = new Array(5).fill("spikes_tall"); -const palisadeSideShort = [...palisadeGate, ...palisadeWallShort, ...palisadeCorner, ...palisadeWallShort]; -const palisadeSideLong = [...palisadeGate, ...palisadeWallShort, ...palisadeCorner, ...palisadeWallLong]; -const fortressDanubiusSpikes = new Fortress( - "Spikes Of The Geto-Dacian Tribal Confederation", - [...palisadeSideLong, ...palisadeSideShort, ...palisadeSideLong, ...palisadeSideShort]); - -// Place a gallic village on small maps and larger -const gallicCC = mapSize >= smallMapSize; -if (gallicCC) +function* GenerateMap(mapSettings) { - g_Map.log("Creating gallic villages"); - const gaulCityRadius = 12; - const gaulCityBorderDistance = mapSize < mediumMapSize ? 10 : 18; - - // Whether to add a celtic ritual and a path from the gallic city leading to it - const addCelticRitual = randBool(0.9); + const day = mapSettings.Daytime !== undefined ? mapSettings.Daytime == "day" : randBool(2/3); + + // Spawn ships away from the shoreline, but patrol close to the shoreline + const triggerPointShipSpawn = "trigger/trigger_point_A"; + const triggerPointShipPatrol = "trigger/trigger_point_B"; + const triggerPointShipUnloadLeft = "trigger/trigger_point_C"; + const triggerPointShipUnloadRight = "trigger/trigger_point_D"; + const triggerPointLandPatrolLeft = "trigger/trigger_point_E"; + const triggerPointLandPatrolRight = "trigger/trigger_point_F"; + const triggerPointCCAttackerPatrolLeft = "trigger/trigger_point_G"; + const triggerPointCCAttackerPatrolRight = "trigger/trigger_point_H"; + const triggerPointRiverDirection = "trigger/trigger_point_I"; + + const tPrimary = ["temp_grass_aut", "temp_grass_plants_aut", "temp_grass_c_aut", "temp_grass_d_aut"]; + const tRoad = "steppe_river_rocks"; + const tIsland = ["temp_grass_long_b_aut", "temp_grass_plants_aut", "temp_forestfloor_aut"]; + const tCliff = "temp_cliff_a"; + const tForestFloor = "temp_forestfloor_aut"; + const tGrass = "medit_shrubs_golden"; + const tGrass2 ="grass_mediterranean_dry_1024test"; + const tGrass3 = "medit_grass_field_b"; + const tShore = "temp_dirt_gravel_b"; + const tWater = "steppe_river_rocks_wet"; + const tSeaDepths = "medit_sea_depths"; + + const oBerryBush = "gaia/fruit/berry_01"; + const oDeer = "gaia/fauna_deer"; + const oFish = "gaia/fish/generic"; + const oSheep = "gaia/fauna_sheep"; + const oGoat = "gaia/fauna_goat"; + const oWolf = "gaia/fauna_wolf"; + const oHawk = "birds/buzzard"; + const oRabbit = "gaia/fauna_rabbit"; + const oBoar = "gaia/fauna_boar"; + const oBear = "gaia/fauna_bear_brown"; + const oStoneLarge = "gaia/rock/temperate_large"; + const oStoneRuins = "gaia/ruins/standing_stone"; + const oMetalLarge = "gaia/ore/mediterranean_large"; + const oApple = "gaia/fruit/apple"; + const oAcacia = "gaia/tree/acacia"; + const oOak = "gaia/tree/oak_aut"; + const oOak2 = "gaia/tree/oak_aut_new"; + const oOak3 = "gaia/tree/oak_dead"; + const oOak4 = "gaia/tree/oak"; + const oPopolar = "gaia/tree/poplar_lombardy"; + const oBeech = "gaia/tree/euro_beech_aut"; + const oBeech2 = "gaia/tree/euro_beech"; + const oTreasures = [ + "gaia/treasure/food_barrel", + "gaia/treasure/food_bin", + "gaia/treasure/stone", + "gaia/treasure/wood", + "gaia/treasure/metal" + ]; + + // Disable capturing on all parts of the village except the + // civic center and buildings occurring outside of the village + const oCivicCenter = "structures/gaul/civil_centre"; + const oTower = "structures/gaul/defense_tower"; + const oOutpost = "structures/gaul/outpost"; + + const oTemple = "uncapturable|structures/gaul/temple"; + const oTavern = "uncapturable|structures/gaul/tavern"; + const oHouse = "uncapturable|structures/gaul/house"; + const oLongHouse = "uncapturable|structures/celt_longhouse"; + const oHut = "uncapturable|structures/celt_hut"; + const oSentryTower = "uncapturable|structures/gaul/sentry_tower"; + const oWatchTower = "uncapturable|structures/palisades_watchtower"; + + const oPalisadeTallSpikes = "uncapturable|structures/palisades_spikes_tall"; + const oPalisadeAngleSpikes = "uncapturable|structures/palisades_spike_angle"; + const oPalisadeCurve = "uncapturable|structures/palisades_curve"; + const oPalisadeShort = "uncapturable|structures/palisades_short"; + const oPalisadeMedium = "uncapturable|structures/palisades_medium"; + const oPalisadeLong = "uncapturable|structures/palisades_long"; + const oPalisadeGate = "uncapturable|structures/palisades_gate"; + const oPalisadePillar = "uncapturable|structures/palisades_tower"; + + const oFemale = "units/gaul/support_female_citizen"; + const oHealer = "units/gaul/support_healer_b"; + const oSkirmisher = "units/gaul/infantry_javelineer_b"; + const oNakedFanatic = "units/gaul/champion_fanatic"; + + const aBush1 = "actor|props/flora/bush_tempe_sm.xml"; + const aBush2 = "actor|props/flora/bush_tempe_me.xml"; + const aBush3 = "actor|props/flora/bush_tempe_la.xml"; + const aBush4 = "actor|props/flora/bush_tempe_me.xml"; + const aRock1 = "actor|geology/stone_granite_med.xml"; + const aRock2 = "actor|geology/stone_granite_boulder.xml"; + const aRock3 = "actor|geology/stone_granite_greek_boulder.xml"; + const aRock4 = "actor|geology/stonemine_alpine_a.xml"; + const aFerns = "actor|props/flora/ferns.xml"; + const aBucket = "actor|props/structures/celts/blacksmith_bucket"; + const aBarrel = "actor|props/structures/gauls/storehouse_barrel_b"; + const aTartan = "actor|props/structures/celts/tartan_a"; + const aWheel = "actor|props/special/eyecandy/wheel_laying"; + const aWell = "actor|props/special/eyecandy/well_1_b"; + const aWoodcord = "actor|props/special/eyecandy/woodcord"; + const aWaterLog = "actor|props/flora/water_log.xml"; + const aCampfire = "actor|props/special/eyecandy/campfire"; + const aBench = "actor|props/special/eyecandy/bench_1"; + const aRug = "actor|props/special/eyecandy/rug_stand_iber"; + + const treeTypes = [oOak, oOak2, oOak3, oOak4, oBeech, oBeech2, oAcacia]; + + const pForest1 = [ + tForestFloor, + tForestFloor + TERRAIN_SEPARATOR + oOak, + tForestFloor + TERRAIN_SEPARATOR + oOak2, + tForestFloor + TERRAIN_SEPARATOR + oOak3, + tForestFloor + TERRAIN_SEPARATOR + oOak4, + tForestFloor + ]; + + const pForest2 = [ + tForestFloor, + tForestFloor + TERRAIN_SEPARATOR + oPopolar, + tForestFloor + TERRAIN_SEPARATOR + oBeech, + tForestFloor + TERRAIN_SEPARATOR + oBeech2, + tForestFloor + TERRAIN_SEPARATOR + oAcacia, + tForestFloor + ]; + + const smallMapSize = 192; + const mediumMapSize = 256; + const normalMapSize = 320; + + // Minimum distance from the map border to ship ungarrison points + const ShorelineDistance = 15; + + const heightSeaGround = -3; + const heightShore = 1; + const heightLand = 3; + const heightPath = 1.5; + const heightIsland = 6; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clLand = [g_Map.createTileClass(), g_Map.createTileClass()]; + const clPatrolPointSiegeEngine = [g_Map.createTileClass(), g_Map.createTileClass()]; + const clPatrolPointSoldier = [g_Map.createTileClass(), g_Map.createTileClass()]; + const clShore = [g_Map.createTileClass(), g_Map.createTileClass()]; + const clShoreUngarrisonPoint = [g_Map.createTileClass(), g_Map.createTileClass()]; + const clShip = g_Map.createTileClass(); + const clShipPatrol = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clIsland = g_Map.createTileClass(); + const clTreasure = g_Map.createTileClass(); + const clWaterLog = g_Map.createTileClass(); + const clGauls = g_Map.createTileClass(); + const clTower = g_Map.createTileClass(); + const clOutpost = g_Map.createTileClass(); + const clPath = g_Map.createTileClass(); + const clRitualPlace = g_Map.createTileClass(); + + const startAngle = randomAngle(); + const waterWidth = fractionToTiles(0.3); + + // How many treasures will be placed near the gallic civic centers + const gallicCCTreasureCount = randIntInclusive(8, 12); + + // How many treasures will be placed randomly on the map at most + const randomTreasureCount = randIntInclusive(0, scaleByMapSize(0, 2)); + + const ritualParticipants = [ + { + "radius": 0.6, + "templates": [oFemale], + "count": 9, + "angle": Math.PI + }, + { + "radius": 0.8, + "templates": [oSkirmisher, oHealer, oNakedFanatic], + "count": 15, + "angle": Math.PI + }, + { + "radius": 1, + "templates": [aBench], + "count": 10, + "angle": Math.PI / 2 + }, + { + "radius": 1.1, + "templates": [oGoat], + "count": 7, + "angle": 0 + }, + { + "radius": 1.2, + "templates": [aRug], + "count": 8, + "angle": Math.PI + } + ]; - // One village left and right of the river - for (let i = 0; i < 2; ++i) + g_WallStyles.danubius_village = { + "house": { "angle": Math.PI, "length": 0, "indent": 4, "bend": 0, "templateName": oHouse }, + "hut": { "angle": Math.PI, "length": 0, "indent": 4, "bend": 0, "templateName": oHut }, + "longhouse": + { + "angle": Math.PI, + "length": 0, + "indent": 4, + "bend": 0, + "templateName": oLongHouse }, + "tavern": + { + "angle": Math.PI * 3/2, + "length": 0, + "indent": 4, + "bend": 0, + "templateName": oTavern + }, + "temple": + { + "angle": Math.PI * 3/2, + "length": 0, + "indent": 4, + "bend": 0, + "templateName": oTemple + }, + "defense_tower": + { + "angle": Math.PI / 2, + "length": 0, + "indent": 4, + "bend": 0, + "templateName": mapSize >= normalMapSize ? (isNomad() ? oSentryTower : oTower) : + oWatchTower + }, + "pillar": readyWallElement(oPalisadePillar), + "gate": readyWallElement(oPalisadeGate), + "long": readyWallElement(oPalisadeLong), + "medium": readyWallElement(oPalisadeMedium), + "short": readyWallElement(oPalisadeShort), + "cornerIn": readyWallElement(oPalisadeCurve), + "overlap": 0.05 + }; + + g_WallStyles.danubius_spikes = { + "spikes_tall": readyWallElement(oPalisadeTallSpikes, "gaia"), + "spike_single": readyWallElement(oPalisadeAngleSpikes, "gaia"), + "overlap": 0 + }; + + const fortressDanubiusVillage = new Fortress( + "Geto-Dacian Tribal Confederation", + new Array(2).fill(["gate", "pillar", "hut", "long", "long", "cornerIn", "defense_tower", "long", + "temple", "long", "pillar", "house", "long", "short", "pillar", "gate", "pillar", + "longhouse", "long", "long", "cornerIn", "defense_tower", "long", "tavern", "long", + "pillar" + ]).reduce((result, items) => result.concat(items), [])); + + const palisadeCorner = ["turn_0.25", "spike_single", "turn_0.25"]; + const palisadeGate = ["spike_single", "gap_3.6", "spike_single"]; + const palisadeWallShort = new Array(3).fill("spikes_tall"); + const palisadeWallLong = new Array(5).fill("spikes_tall"); + const palisadeSideShort = + [...palisadeGate, ...palisadeWallShort, ...palisadeCorner, ...palisadeWallShort]; + const palisadeSideLong = + [...palisadeGate, ...palisadeWallShort, ...palisadeCorner, ...palisadeWallLong]; + const fortressDanubiusSpikes = new Fortress( + "Spikes Of The Geto-Dacian Tribal Confederation", + [...palisadeSideLong, ...palisadeSideShort, ...palisadeSideLong, ...palisadeSideShort]); + + // Place a gallic village on small maps and larger + const gallicCC = mapSize >= smallMapSize; + if (gallicCC) { - const civicCenterPosition = new Vector2D( - i == 0 ? mapBounds.left + gaulCityBorderDistance : mapBounds.right - gaulCityBorderDistance, - mapCenter.y).rotateAround(startAngle, mapCenter); + g_Map.log("Creating gallic villages"); + const gaulCityRadius = 12; + const gaulCityBorderDistance = mapSize < mediumMapSize ? 10 : 18; + + // Whether to add a celtic ritual and a path from the gallic city leading to it + const addCelticRitual = randBool(0.9); - if (addCelticRitual) + // One village left and right of the river + for (let i = 0; i < 2; ++i) { - // Don't position the meeting place at the center of the map - const meetingPlacePosition = new Vector2D( - i == 0 ? mapBounds.left + waterWidth : mapBounds.right - waterWidth, - mapCenter.y + fractionToTiles(randFloat(0.1, 0.4)) * (randBool() ? 1 : -1)).rotateAround(startAngle, mapCenter); + const civicCenterPosition = new Vector2D( + i == 0 ? mapBounds.left + gaulCityBorderDistance : + mapBounds.right - gaulCityBorderDistance, mapCenter.y) + .rotateAround(startAngle, mapCenter); - // Radius of the meeting place - const mRadius = scaleByMapSize(4, 6); + if (addCelticRitual) + { + // Don't position the meeting place at the center of the map + const meetingPlacePosition = new Vector2D( + i == 0 ? mapBounds.left + waterWidth : mapBounds.right - waterWidth, + mapCenter.y + fractionToTiles(randFloat(0.1, 0.4)) * (randBool() ? 1 : -1)) + .rotateAround(startAngle, mapCenter); + + // Radius of the meeting place + const mRadius = scaleByMapSize(4, 6); + + // Create a path connecting the gallic city with a meeting place at the shoreline. + // To avoid the path going through the palisade wall, start it at the gate, not at + // the city center. + const pathStart = Vector2D.add(civicCenterPosition, + new Vector2D(gaulCityRadius * (i == 0 ? 1 : -1), 0).rotate(startAngle)); + createArea( + new PathPlacer(pathStart, meetingPlacePosition, 4, 0.4, 4, 0.2, 0.05), + [ + new LayeredPainter([tShore, tRoad], [1]), + new SmoothElevationPainter(ELEVATION_SET, heightPath, 4), + new TileClassPainter(clPath) + ]); + + // Create the meeting place near the shoreline at the end of the path + createArea( + new ClumpPlacer(diskArea(mRadius), 0.6, 0.3, Infinity, meetingPlacePosition), + [ + new TerrainPainter(tShore), + new TileClassPainter(clPath), + new TileClassPainter(clRitualPlace) + ]); + + g_Map.placeEntityAnywhere(aCampfire, 0, meetingPlacePosition, randomAngle()); + + for (const participants of ritualParticipants) + { + const [positions, angles] = distributePointsOnCircle(participants.count, + startAngle, participants.radius * mRadius, meetingPlacePosition); + for (let j = 0; j < positions.length; ++j) + g_Map.placeEntityPassable(pickRandom(participants.templates), 0, + positions[j], angles[j] + participants.angle); + } + } - // Create a path connecting the gallic city with a meeting place at the shoreline. - // To avoid the path going through the palisade wall, start it at the gate, not at the city center. - const pathStart = Vector2D.add(civicCenterPosition, new Vector2D(gaulCityRadius * (i == 0 ? 1 : -1), 0).rotate(startAngle)); - createArea( - new PathPlacer(pathStart, meetingPlacePosition, 4, 0.4, 4, 0.2, 0.05), - [ - new LayeredPainter([tShore, tRoad], [1]), - new SmoothElevationPainter(ELEVATION_SET, heightPath, 4), - new TileClassPainter(clPath) - ]); + g_Map.placeEntityPassable(oCivicCenter, 0, civicCenterPosition, + startAngle + BUILDING_ORIENTATION + Math.PI * 3/2 * i); - // Create the meeting place near the shoreline at the end of the path + // Create the city patch createArea( - new ClumpPlacer(diskArea(mRadius), 0.6, 0.3, Infinity, meetingPlacePosition), + new ClumpPlacer(diskArea(gaulCityRadius), 0.6, 0.3, Infinity, civicCenterPosition), [ new TerrainPainter(tShore), - new TileClassPainter(clPath), - new TileClassPainter(clRitualPlace) + new TileClassPainter(clGauls) ]); - g_Map.placeEntityAnywhere(aCampfire, 0, meetingPlacePosition, randomAngle()); - - for (const participants of ritualParticipants) - { - const [positions, angles] = distributePointsOnCircle(participants.count, startAngle, participants.radius * mRadius, meetingPlacePosition); - for (let j = 0; j < positions.length; ++j) - g_Map.placeEntityPassable(pickRandom(participants.templates), 0, positions[j], angles[j] + participants.angle); - } + // Place walls and buildings + placeCustomFortress(civicCenterPosition, fortressDanubiusVillage, "danubius_village", 0, + startAngle + Math.PI); + placeCustomFortress(civicCenterPosition, fortressDanubiusSpikes, "danubius_spikes", 0, + startAngle + Math.PI); + + // Place treasure, potentially inside buildings + for (let j = 0; j < gallicCCTreasureCount; ++j) + g_Map.placeEntityPassable( + pickRandom(oTreasures), + 0, + Vector2D.add(civicCenterPosition, + new Vector2D(randFloat(-0.8, 0.8) * gaulCityRadius, 0) + .rotate(randomAngle())), + randomAngle()); + } + } + yield 10; + + placePlayerBases({ + "PlayerPlacement": playerPlacementRiver(startAngle, fractionToTiles(0.6)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "Walls": false, + "CityPatch": { + "outerTerrain": tShore, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ], + "distance": scaleByMapSize(9, 14) + }, + "Trees": { + "template": oOak, + "count": 20, + "minDist": 10, + "maxDist": 14 + }, + "Decoratives": { + "template": aBush1 } + }); + yield 20; + + paintRiver({ + "parallel": true, + "start": new Vector2D(mapCenter.x, mapBounds.top).rotateAround(startAngle, mapCenter), + "end": new Vector2D(mapCenter.x, mapBounds.bottom).rotateAround(startAngle, mapCenter), + "width": waterWidth, + "fadeDist": scaleByMapSize(6, 25), + "deviation": 0, + "heightRiverbed": heightSeaGround, + "heightLand": heightLand, + "meanderShort": 30, + "meanderLong": 0, + "waterFunc": (position, height, riverFraction) => { + const origPos = position.clone().rotateAround(-startAngle, mapCenter); + // Distinguish left and right shoreline + if (0 < height && height < 1 && + origPos.y > ShorelineDistance && origPos.y < mapSize - ShorelineDistance) + clShore[origPos.x < mapCenter.x ? 0 : 1].add(position); + }, + "landFunc": (position, shoreDist1, shoreDist2) => { + + if (shoreDist1 > 0) + clLand[0].add(position); + + if (shoreDist2 < 0) + clLand[1].add(position); + } + }); + yield 30; - g_Map.placeEntityPassable(oCivicCenter, 0, civicCenterPosition, startAngle + BUILDING_ORIENTATION + Math.PI * 3/2 * i); + paintTileClassBasedOnHeight(-Infinity, 0.7, Elevation_ExcludeMin_ExcludeMax, clWater); - // Create the city patch + const areasLand = [0, 1].map(i => createArea( - new ClumpPlacer(diskArea(gaulCityRadius), 0.6, 0.3, Infinity, civicCenterPosition), + new MapBoundsPlacer(), + undefined, + stayClasses(clLand[i], 0))); + + const areasWater = + [createArea( + new MapBoundsPlacer(), + undefined, + new HeightConstraint(-Infinity, heightLand))]; + + g_Map.log("Creating shores"); + paintTerrainBasedOnHeight(-Infinity, heightShore, 0, tWater); + paintTerrainBasedOnHeight(heightShore, heightLand, 0, tShore); + yield 35; + + createBumps(avoidClasses(clPlayer, 6, clWater, 2, clPath, 1, clGauls, 1), + scaleByMapSize(30, 300), 1, 8, 4, 0, 3); + yield 40; + + if (randBool()) + createHills( + [tCliff, tCliff, tCliff], + avoidClasses(clPlayer, 18, clHill, 20, clWater, 2, clGauls, 5, clPath, 1), + clHill, + scaleByMapSize(3, 15)); + else + createMountains( + tCliff, + avoidClasses(clPlayer, 18, clHill, 20, clWater, 2, clGauls, 5, clPath, 1), + clHill, + scaleByMapSize(3, 15)); + + yield 45; + + const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); + createForests( + [tForestFloor, tForestFloor, tForestFloor, pForest1, pForest2], + avoidClasses(clPlayer, 16, clForest, 17, clWater, 5, clHill, 2, clGauls, 5, clPath, 1), + clForest, + forestTrees); + + yield 50; + + g_Map.log("Creating grass patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tGrass, tGrass2], [tGrass2, tGrass3], [tGrass3, tGrass]], + [1, 1], + avoidClasses(clForest, 0, clPlayer, 10, clWater, 2, clDirt, 2, clHill, 1, clGauls, 5, clPath, + 1), + scaleByMapSize(15, 45), + clDirt); + + yield 55; + + g_Map.log("Creating islands"); + const areaIslands = createAreas( + new ChainPlacer(Math.floor(scaleByMapSize(3, 4)), Math.floor(scaleByMapSize(4, 8)), + Math.floor(scaleByMapSize(50, 80)), 0.5), + [ + new LayeredPainter([tWater, tShore, tIsland], [2, 1]), + new SmoothElevationPainter(ELEVATION_SET, heightIsland, 4), + new TileClassPainter(clIsland) + ], + [avoidClasses(clIsland, 30), stayClasses(clWater, 10)], + scaleByMapSize(1, 4) * numPlayers); + + yield 60; + + createBumps(stayClasses(clIsland, 2), scaleByMapSize(50, 400), 1, 8, 4, 0, 3); + + g_Map.log("Painting seabed"); + paintTerrainBasedOnHeight(-20, -3, 3, tSeaDepths); + + g_Map.log("Creating island metal mines"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), + 0, + [avoidClasses(clMetal, 50, clRock, 10), stayClasses(clIsland, 5)], + scaleByMapSize(3, 10), + 20, + areaIslands); + + g_Map.log("Creating island stone mines"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oStoneLarge, 1, 1, 0, 4)], true, clRock), + 0, + [avoidClasses(clMetal, 10, clRock, 50), stayClasses(clIsland, 5)], + scaleByMapSize(3, 10), + 20, + areaIslands); + yield 65; + + g_Map.log("Creating island towers"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oTower, 1, 1, 0, 4)], true, clTower), + 0, + [avoidClasses(clMetal, 4, clRock, 4, clTower, 20), stayClasses(clIsland, 7)], + scaleByMapSize(3, 10), + 20, + areaIslands); + + g_Map.log("Creating island outposts"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oOutpost, 1, 1, 0, 4)], true, clOutpost), + 0, + [avoidClasses(clMetal, 4, clRock, 4, clTower, 5, clOutpost, 20), stayClasses(clIsland, 7)], + scaleByMapSize(3, 10), + 20, + areaIslands); + + g_Map.log("Creating metal mines"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), + 0, + avoidClasses(clForest, 4, clBaseResource, 20, clMetal, 50, clRock, 20, clWater, 4, clHill, 4, + clGauls, 5, clPath, 5), + scaleByMapSize(4, 20), + 50, + areasLand); + + g_Map.log("Creating stone mines"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oStoneLarge, 1, 1, 0, 4)], true, clRock), + 0, + avoidClasses(clForest, 4, clBaseResource, 20, clMetal, 20, clRock, 50, clWater, 4, clHill, 4, + clGauls, 5, clPath, 5), + scaleByMapSize(4, 20), + 50, + areasLand); + + g_Map.log("Creating stone ruins"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oStoneRuins, 1, 1, 0, 4)], true, clRock), + 0, + avoidClasses(clForest, 2, clPlayer, 12, clMetal, 6, clRock, 25, clWater, 4, clHill, 4, clGauls, + 5, clPath, 1), + scaleByMapSize(2, 10), + 20, + areasLand); + yield 70; + + g_Map.log("Creating decoratives"); + for (let i = 0; i < 2; ++i) + createDecoration( [ - new TerrainPainter(tShore), - new TileClassPainter(clGauls) - ]); - - // Place walls and buildings - placeCustomFortress(civicCenterPosition, fortressDanubiusVillage, "danubius_village", 0, startAngle + Math.PI); - placeCustomFortress(civicCenterPosition, fortressDanubiusSpikes, "danubius_spikes", 0, startAngle + Math.PI); - - // Place treasure, potentially inside buildings - for (let j = 0; j < gallicCCTreasureCount; ++j) - g_Map.placeEntityPassable( - pickRandom(oTreasures), - 0, - Vector2D.add(civicCenterPosition, new Vector2D(randFloat(-0.8, 0.8) * gaulCityRadius, 0).rotate(randomAngle())), - randomAngle()); - } -} -Engine.SetProgress(10); - -placePlayerBases({ - "PlayerPlacement": playerPlacementRiver(startAngle, fractionToTiles(0.6)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "Walls": false, - "CityPatch": { - "outerTerrain": tShore, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } + [new SimpleObject(aRock1, 1, 1, 0, 1)], + [new SimpleObject(aRock2, 1, 1, 0, 1)], + [new SimpleObject(aRock3, 1, 1, 0, 1)], + [new SimpleObject(aRock4, 1, 1, 0, 1)], + + [new SimpleObject(aBush1, 1, 3, 0, 2)], + [new SimpleObject(aBush2, 1, 2, 0, 1)], + [new SimpleObject(aBush3, 1, 3, 0, 2)], + [new SimpleObject(aBush4, 1, 2, 0, 1)], + + [new SimpleObject(aFerns, 2, 5, 2, 4)] + ], + [ + scaleByMapAreaAbsolute(5), + scaleByMapAreaAbsolute(5), + scaleByMapAreaAbsolute(5), + scaleByMapAreaAbsolute(5), + + scaleByMapAreaAbsolute(5), + scaleByMapAreaAbsolute(5), + scaleByMapAreaAbsolute(5), + scaleByMapAreaAbsolute(5), + + scaleByMapSize(20, 80) + ], + i == 0 ? + avoidClasses(clWater, 4, clForest, 1, clPlayer, 16, clRock, 4, clMetal, 4, clHill, + 4, clGauls, 5, clPath, 1) : + [stayClasses(clIsland, 4), avoidClasses(clForest, 1, clRock, 4, clMetal, 4)]); + yield 75; + + g_Map.log("Creating fish"); + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] ], - "distance": scaleByMapSize(9, 14) - }, - "Trees": { - "template": oOak, - "count": 20, - "minDist": 10, - "maxDist": 14 - }, - "Decoratives": { - "template": aBush1 - } -}); -Engine.SetProgress(20); - -paintRiver({ - "parallel": true, - "start": new Vector2D(mapCenter.x, mapBounds.top).rotateAround(startAngle, mapCenter), - "end": new Vector2D(mapCenter.x, mapBounds.bottom).rotateAround(startAngle, mapCenter), - "width": waterWidth, - "fadeDist": scaleByMapSize(6, 25), - "deviation": 0, - "heightRiverbed": heightSeaGround, - "heightLand": heightLand, - "meanderShort": 30, - "meanderLong": 0, - "waterFunc": (position, height, riverFraction) => { - const origPos = position.clone().rotateAround(-startAngle, mapCenter); - // Distinguish left and right shoreline - if (0 < height && height < 1 && - origPos.y > ShorelineDistance && origPos.y < mapSize - ShorelineDistance) - clShore[origPos.x < mapCenter.x ? 0 : 1].add(position); - }, - "landFunc": (position, shoreDist1, shoreDist2) => { - - if (shoreDist1 > 0) - clLand[0].add(position); - - if (shoreDist2 < 0) - clLand[1].add(position); - } -}); -Engine.SetProgress(30); - -paintTileClassBasedOnHeight(-Infinity, 0.7, Elevation_ExcludeMin_ExcludeMax, clWater); - -const areasLand = [0, 1].map(i => - createArea( - new MapBoundsPlacer(), - undefined, - stayClasses(clLand[i], 0))); - -const areasWater = - [createArea( - new MapBoundsPlacer(), - undefined, - new HeightConstraint(-Infinity, heightLand))]; - -g_Map.log("Creating shores"); -paintTerrainBasedOnHeight(-Infinity, heightShore, 0, tWater); -paintTerrainBasedOnHeight(heightShore, heightLand, 0, tShore); -Engine.SetProgress(35); - -createBumps(avoidClasses(clPlayer, 6, clWater, 2, clPath, 1, clGauls, 1), scaleByMapSize(30, 300), 1, 8, 4, 0, 3); -Engine.SetProgress(40); - -if (randBool()) - createHills( - [tCliff, tCliff, tCliff], - avoidClasses(clPlayer, 18, clHill, 20, clWater, 2, clGauls, 5, clPath, 1), - clHill, - scaleByMapSize(3, 15)); -else - createMountains( - tCliff, - avoidClasses(clPlayer, 18, clHill, 20, clWater, 2, clGauls, 5, clPath, 1), - clHill, - scaleByMapSize(3, 15)); - -Engine.SetProgress(45); - -const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); -createForests( - [tForestFloor, tForestFloor, tForestFloor, pForest1, pForest2], - avoidClasses(clPlayer, 16, clForest, 17, clWater, 5, clHill, 2, clGauls, 5, clPath, 1), - clForest, - forestTrees); - -Engine.SetProgress(50); - -g_Map.log("Creating grass patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tGrass, tGrass2], [tGrass2, tGrass3], [tGrass3, tGrass]], - [1, 1], - avoidClasses(clForest, 0, clPlayer, 10, clWater, 2, clDirt, 2, clHill, 1, clGauls, 5, clPath, 1), - scaleByMapSize(15, 45), - clDirt); - -Engine.SetProgress(55); - -g_Map.log("Creating islands"); -const areaIslands = createAreas( - new ChainPlacer(Math.floor(scaleByMapSize(3, 4)), Math.floor(scaleByMapSize(4, 8)), Math.floor(scaleByMapSize(50, 80)), 0.5), - [ - new LayeredPainter([tWater, tShore, tIsland], [2, 1]), - new SmoothElevationPainter(ELEVATION_SET, heightIsland, 4), - new TileClassPainter(clIsland) - ], - [avoidClasses(clIsland, 30), stayClasses(clWater, 10)], - scaleByMapSize(1, 4) * numPlayers); - -Engine.SetProgress(60); - -createBumps(stayClasses(clIsland, 2), scaleByMapSize(50, 400), 1, 8, 4, 0, 3); - -g_Map.log("Painting seabed"); -paintTerrainBasedOnHeight(-20, -3, 3, tSeaDepths); - -g_Map.log("Creating island metal mines"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), - 0, - [avoidClasses(clMetal, 50, clRock, 10), stayClasses(clIsland, 5)], - scaleByMapSize(3, 10), - 20, - areaIslands); - -g_Map.log("Creating island stone mines"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oStoneLarge, 1, 1, 0, 4)], true, clRock), - 0, - [avoidClasses(clMetal, 10, clRock, 50), stayClasses(clIsland, 5)], - scaleByMapSize(3, 10), - 20, - areaIslands); -Engine.SetProgress(65); - -g_Map.log("Creating island towers"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oTower, 1, 1, 0, 4)], true, clTower), - 0, - [avoidClasses(clMetal, 4, clRock, 4, clTower, 20), stayClasses(clIsland, 7)], - scaleByMapSize(3, 10), - 20, - areaIslands); - -g_Map.log("Creating island outposts"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oOutpost, 1, 1, 0, 4)], true, clOutpost), - 0, - [avoidClasses(clMetal, 4, clRock, 4, clTower, 5, clOutpost, 20), stayClasses(clIsland, 7)], - scaleByMapSize(3, 10), - 20, - areaIslands); - -g_Map.log("Creating metal mines"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), - 0, - avoidClasses(clForest, 4, clBaseResource, 20, clMetal, 50, clRock, 20, clWater, 4, clHill, 4, clGauls, 5, clPath, 5), - scaleByMapSize(4, 20), - 50, - areasLand); - -g_Map.log("Creating stone mines"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oStoneLarge, 1, 1, 0, 4)], true, clRock), - 0, - avoidClasses(clForest, 4, clBaseResource, 20, clMetal, 20, clRock, 50, clWater, 4, clHill, 4, clGauls, 5, clPath, 5), - scaleByMapSize(4, 20), - 50, - areasLand); - -g_Map.log("Creating stone ruins"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oStoneRuins, 1, 1, 0, 4)], true, clRock), - 0, - avoidClasses(clForest, 2, clPlayer, 12, clMetal, 6, clRock, 25, clWater, 4, clHill, 4, clGauls, 5, clPath, 1), - scaleByMapSize(2, 10), - 20, - areasLand); -Engine.SetProgress(70); - -g_Map.log("Creating decoratives"); -for (let i = 0; i < 2; ++i) - createDecoration( [ - [new SimpleObject(aRock1, 1, 1, 0, 1)], - [new SimpleObject(aRock2, 1, 1, 0, 1)], - [new SimpleObject(aRock3, 1, 1, 0, 1)], - [new SimpleObject(aRock4, 1, 1, 0, 1)], + 20 * scaleByMapSize(5, 20) + ], + [avoidClasses(clIsland, 2, clFood, 10, clPath, 1), stayClasses(clWater, 5)], + clFood); - [new SimpleObject(aBush1, 1, 3, 0, 2)], - [new SimpleObject(aBush2, 1, 2, 0, 1)], - [new SimpleObject(aBush3, 1, 3, 0, 2)], - [new SimpleObject(aBush4, 1, 2, 0, 1)], + yield 80; - [new SimpleObject(aFerns, 2, 5, 2, 4)] + g_Map.log("Creating huntable animals"); + createFood( + [ + [new SimpleObject(oSheep, 5, 5, 0, 4)], + [new SimpleObject(oGoat, 5, 5, 0, 4)], + [new SimpleObject(oRabbit, 5, 8, 0, 4)], + [new SimpleObject(oDeer, 4, 6, 0, 2)], + [new SimpleObject(oHawk, 1, 1, 0, 4)] ], [ - scaleByMapAreaAbsolute(5), - scaleByMapAreaAbsolute(5), - scaleByMapAreaAbsolute(5), - scaleByMapAreaAbsolute(5), + scaleByMapSize(5, 20), + scaleByMapSize(5, 20), + scaleByMapSize(5, 20), + scaleByMapSize(5, 20), + scaleByMapSize(5, 10) + ], + avoidClasses(clIsland, 2, clFood, 10, clWater, 5, clPlayer, 16, clHill, 2, clGauls, 5, clPath, + 1), + clFood); - scaleByMapAreaAbsolute(5), - scaleByMapAreaAbsolute(5), - scaleByMapAreaAbsolute(5), - scaleByMapAreaAbsolute(5), + g_Map.log("Creating violent animals"); + if (!isNomad()) + createFood( + [ + [new SimpleObject(oWolf, 1, 3, 0, 4)], + [new SimpleObject(oBoar, 1, 1, 0, 4)], + [new SimpleObject(oBear, 1, 1, 0, 4)] + ], + [ + scaleByMapSize(5, 20), + scaleByMapSize(5, 20), + scaleByMapSize(5, 20) + ], + avoidClasses(clIsland, 2, clFood, 10, clWater, 5, clPlayer, 24, clHill, 2, clGauls, 5, + clPath, 1), + clFood); - scaleByMapSize(20, 80) - ], - i == 0 ? - avoidClasses(clWater, 4, clForest, 1, clPlayer, 16, clRock, 4, clMetal, 4, clHill, 4, clGauls, 5, clPath, 1) : - [stayClasses(clIsland, 4), avoidClasses(clForest, 1, clRock, 4, clMetal, 4)]); -Engine.SetProgress(75); - -g_Map.log("Creating fish"); -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 20 * scaleByMapSize(5, 20) - ], - [avoidClasses(clIsland, 2, clFood, 10, clPath, 1), stayClasses(clWater, 5)], - clFood); - -Engine.SetProgress(80); - -g_Map.log("Creating huntable animals"); -createFood( - [ - [new SimpleObject(oSheep, 5, 5, 0, 4)], - [new SimpleObject(oGoat, 5, 5, 0, 4)], - [new SimpleObject(oRabbit, 5, 8, 0, 4)], - [new SimpleObject(oDeer, 4, 6, 0, 2)], - [new SimpleObject(oHawk, 1, 1, 0, 4)] - ], - [ - scaleByMapSize(5, 20), - scaleByMapSize(5, 20), - scaleByMapSize(5, 20), - scaleByMapSize(5, 20), - scaleByMapSize(5, 10) - ], - avoidClasses(clIsland, 2, clFood, 10, clWater, 5, clPlayer, 16, clHill, 2, clGauls, 5, clPath, 1), - clFood); - -g_Map.log("Creating violent animals"); -if (!isNomad()) + yield 85; + + g_Map.log("Creating fruits"); createFood( [ - [new SimpleObject(oWolf, 1, 3, 0, 4)], - [new SimpleObject(oBoar, 1, 1, 0, 4)], - [new SimpleObject(oBear, 1, 1, 0, 4)] + [new SimpleObject(oApple, 3, 5, 4, 7)], + [new SimpleObject(oBerryBush, 4, 6, 0, 4)] ], [ - scaleByMapSize(5, 20), scaleByMapSize(5, 20), scaleByMapSize(5, 20) ], - avoidClasses(clIsland, 2, clFood, 10, clWater, 5, clPlayer, 24, clHill, 2, clGauls, 5, clPath, 1), + avoidClasses(clWater, 5, clForest, 2, clPlayer, 16, clHill, 4, clFood, 10, clMetal, 4, clRock, + 4, clGauls, 5, clPath, 1), clFood); -Engine.SetProgress(85); - -g_Map.log("Creating fruits"); -createFood( - [ - [new SimpleObject(oApple, 3, 5, 4, 7)], - [new SimpleObject(oBerryBush, 4, 6, 0, 4)] - ], - [ - scaleByMapSize(5, 20), - scaleByMapSize(5, 20) - ], - avoidClasses(clWater, 5, clForest, 2, clPlayer, 16, clHill, 4, clFood, 10, clMetal, 4, clRock, 4, clGauls, 5, clPath, 1), - clFood); - -Engine.SetProgress(90); - -createStragglerTrees( - treeTypes, - avoidClasses(clForest, 2, clWater, 8, clPlayer, 16, clMetal, 4, clRock, 4, clFood, 1, clHill, 2, clGauls, 5, clPath, 5), - clForest, - stragglerTrees); - -createStragglerTrees( - treeTypes, - [stayClasses(clIsland, 4), avoidClasses(clMetal, 4, clRock, 4, clTower, 4, clOutpost, 4)], - clForest, - stragglerTrees * 7); - -Engine.SetProgress(95); - -g_Map.log("Creating animals on islands"); -createFood( - [ - [new SimpleObject(oSheep, 4, 6, 0, 4)], - [new SimpleObject(oGoat, 4, 6, 0, 4)], - [new SimpleObject(oRabbit, 5, 8, 0, 4)] - ], - [ - 10 * scaleByMapSize(5, 20), - 10 * scaleByMapSize(5, 20), - 10 * scaleByMapSize(5, 20) - ], - [avoidClasses(clRock, 4, clMetal, 4, clFood, 3, clForest, 1, clOutpost, 2, clTower, 2), stayClasses(clIsland, 4)], - clFood); - -Engine.SetProgress(98); - -g_Map.log("Creating treasures"); -createObjectGroupsByAreas( - new SimpleGroup( - [new SimpleObject(pickRandom(oTreasures), 1, 1, 0, 2)], - true, clTreasure - ), - 0, - avoidClasses(clForest, 1, clPlayer, 15, clHill, 1, clWater, 5, clFood, 1, clRock, 4, clMetal, 4, clTreasure, 10, clGauls, 5), - randomTreasureCount, - 50, - areasLand); - -g_Map.log("Creating gallic decoratives"); -createDecoration( - [ - [new SimpleObject(aBucket, 1, 1, 0, 1)], - [new SimpleObject(aBarrel, 1, 1, 0, 1)], - [new SimpleObject(aTartan, 3, 3, 4, 4, Math.PI/4, Math.PI/2)], - [new SimpleObject(aWheel, 2, 4, 1, 2)], - [new SimpleObject(aWell, 1, 1, 0, 2)], - [new SimpleObject(aWoodcord, 1, 2, 2, 2, Math.PI/2, Math.PI/2)] - ], - [ - scaleByMapSize(2, 10), - scaleByMapSize(2, 10), - scaleByMapSize(2, 10), - scaleByMapSize(2, 10), - scaleByMapSize(3, 4), - scaleByMapSize(2, 10) - ], - avoidClasses(clForest, 1, clPlayer, 10, clBaseResource, 5, clHill, 1, clFood, 1, clWater, 5, clRock, 4, clMetal, 4, clGauls, 5, clPath, 1)); - -g_Map.log("Creating spawn points for ships"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(triggerPointShipSpawn, 1, 1, 0, 0)], true, clShip), - 0, - [avoidClasses(clShip, 5, clIsland, 4), stayClasses(clWater, 10)], - scaleByMapSize(10, 75), - 10, - areasWater); - -g_Map.log("Creating patrol points for ships"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(triggerPointShipPatrol, 1, 1, 0, 0)], true, clShipPatrol), - 0, - [avoidClasses(clShipPatrol, 5, clIsland, 3), stayClasses(clWater, 4)], - scaleByMapSize(20, 150), - 10, - areasWater); - -g_Map.log("Creating ungarrison points for ships"); -for (let i = 0; i < 2; ++i) -{ - const areaShore = [createArea( - new MapBoundsPlacer(), - undefined, - stayClasses(clShore[i], 0))]; + yield 90; + + createStragglerTrees( + treeTypes, + avoidClasses(clForest, 2, clWater, 8, clPlayer, 16, clMetal, 4, clRock, 4, clFood, 1, clHill, + 2, clGauls, 5, clPath, 5), + clForest, + stragglerTrees); + createStragglerTrees( + treeTypes, + [stayClasses(clIsland, 4), avoidClasses(clMetal, 4, clRock, 4, clTower, 4, clOutpost, 4)], + clForest, + stragglerTrees * 7); + + yield 95; + + g_Map.log("Creating animals on islands"); + createFood( + [ + [new SimpleObject(oSheep, 4, 6, 0, 4)], + [new SimpleObject(oGoat, 4, 6, 0, 4)], + [new SimpleObject(oRabbit, 5, 8, 0, 4)] + ], + [ + 10 * scaleByMapSize(5, 20), + 10 * scaleByMapSize(5, 20), + 10 * scaleByMapSize(5, 20) + ], + [avoidClasses(clRock, 4, clMetal, 4, clFood, 3, clForest, 1, clOutpost, 2, clTower, 2), + stayClasses(clIsland, 4)], + clFood); + + yield 98; + + g_Map.log("Creating treasures"); createObjectGroupsByAreas( new SimpleGroup( - [new SimpleObject( - i == 0 ? triggerPointShipUnloadLeft : triggerPointShipUnloadRight, - 1, 1, - 0, 0)], - true, - clShoreUngarrisonPoint[i]), + [new SimpleObject(pickRandom(oTreasures), 1, 1, 0, 2)], + true, clTreasure + ), 0, - avoidClasses(clShoreUngarrisonPoint[i], 4), - scaleByMapSize(60, 200), - 20, - areaShore); -} + avoidClasses(clForest, 1, clPlayer, 15, clHill, 1, clWater, 5, clFood, 1, clRock, 4, clMetal, 4, + clTreasure, 10, clGauls, 5), + randomTreasureCount, + 50, + areasLand); -g_Map.log("Creating riverdirection triggerpoint"); -g_Map.placeEntityAnywhere(triggerPointRiverDirection, 0, Vector2D.add(mapCenter, new Vector2D(0, 1).rotate(startAngle)), randomAngle()); + g_Map.log("Creating gallic decoratives"); + createDecoration( + [ + [new SimpleObject(aBucket, 1, 1, 0, 1)], + [new SimpleObject(aBarrel, 1, 1, 0, 1)], + [new SimpleObject(aTartan, 3, 3, 4, 4, Math.PI/4, Math.PI/2)], + [new SimpleObject(aWheel, 2, 4, 1, 2)], + [new SimpleObject(aWell, 1, 1, 0, 2)], + [new SimpleObject(aWoodcord, 1, 2, 2, 2, Math.PI/2, Math.PI/2)] + ], + [ + scaleByMapSize(2, 10), + scaleByMapSize(2, 10), + scaleByMapSize(2, 10), + scaleByMapSize(2, 10), + scaleByMapSize(3, 4), + scaleByMapSize(2, 10) + ], + avoidClasses(clForest, 1, clPlayer, 10, clBaseResource, 5, clHill, 1, clFood, 1, clWater, 5, + clRock, 4, clMetal, 4, clGauls, 5, clPath, 1)); -g_Map.log("Creating patrol points for siege engines"); -for (let i = 0; i < 2; ++i) - // Patrol points for siege engines + g_Map.log("Creating spawn points for ships"); createObjectGroupsByAreas( - new SimpleGroup( - [new SimpleObject( - i == 0 ? triggerPointLandPatrolLeft : triggerPointLandPatrolRight, - 1, 1, - 0, 0)], - true, - clPatrolPointSiegeEngine[i]), + new SimpleGroup([new SimpleObject(triggerPointShipSpawn, 1, 1, 0, 0)], true, clShip), 0, - avoidClasses(clWater, 5, clForest, 3, clHill, 3, clFood, 1, clRock, 5, clMetal, 5, clPlayer, 10, clGauls, 5, clPatrolPointSiegeEngine[i], 5), + [avoidClasses(clShip, 5, clIsland, 4), stayClasses(clWater, 10)], + scaleByMapSize(10, 75), + 10, + areasWater); + + g_Map.log("Creating patrol points for ships"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(triggerPointShipPatrol, 1, 1, 0, 0)], true, clShipPatrol), + 0, + [avoidClasses(clShipPatrol, 5, clIsland, 3), stayClasses(clWater, 4)], scaleByMapSize(20, 150), 10, - [areasLand[i]]); + areasWater); -if (gallicCC) -{ - g_Map.log("Creating patrol points for soldiers"); + g_Map.log("Creating ungarrison points for ships"); for (let i = 0; i < 2; ++i) + { + const areaShore = [createArea( + new MapBoundsPlacer(), + undefined, + stayClasses(clShore[i], 0))]; + createObjectGroupsByAreas( new SimpleGroup( [new SimpleObject( - i == 0 ? triggerPointCCAttackerPatrolLeft : triggerPointCCAttackerPatrolRight, + i == 0 ? triggerPointShipUnloadLeft : triggerPointShipUnloadRight, 1, 1, 0, 0)], true, - clPatrolPointSoldier[i]), + clShoreUngarrisonPoint[i]), 0, - // Don't avoid the forest, so that as many places as possible on the border are visited - avoidClasses( - clWater, 5, - clHill, 3, - clFood, 1, - clRock, 4, - clMetal, 4, - clPlayer, 15, - clGauls, 0, - clPatrolPointSoldier[i], 5), - scaleByMapSize(20, 150), + avoidClasses(clShoreUngarrisonPoint[i], 4), + scaleByMapSize(60, 200), 20, + areaShore); + } + + g_Map.log("Creating riverdirection triggerpoint"); + g_Map.placeEntityAnywhere(triggerPointRiverDirection, 0, + Vector2D.add(mapCenter, new Vector2D(0, 1).rotate(startAngle)), randomAngle()); + + g_Map.log("Creating patrol points for siege engines"); + for (let i = 0; i < 2; ++i) + // Patrol points for siege engines + createObjectGroupsByAreas( + new SimpleGroup( + [new SimpleObject( + i == 0 ? triggerPointLandPatrolLeft : triggerPointLandPatrolRight, + 1, 1, + 0, 0)], + true, + clPatrolPointSiegeEngine[i]), + 0, + avoidClasses(clWater, 5, clForest, 3, clHill, 3, clFood, 1, clRock, 5, clMetal, 5, + clPlayer, 10, clGauls, 5, clPatrolPointSiegeEngine[i], 5), + scaleByMapSize(20, 150), + 10, [areasLand[i]]); -} -g_Map.log("Creating water logs"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(aWaterLog, 1, 1, 0, 0, startAngle, startAngle)], true, clWaterLog), - 0, - [avoidClasses(clShip, 3, clIsland, 4), stayClasses(clWater, 4)], - scaleByMapSize(1, 4), - 10, - areasWater); + if (gallicCC) + { + g_Map.log("Creating patrol points for soldiers"); + for (let i = 0; i < 2; ++i) + createObjectGroupsByAreas( + new SimpleGroup( + [new SimpleObject( + i == 0 ? triggerPointCCAttackerPatrolLeft : + triggerPointCCAttackerPatrolRight, + 1, 1, + 0, 0)], + true, + clPatrolPointSoldier[i]), + 0, + // Don't avoid the forest, so that as many places as possible on the border are + // visited + avoidClasses( + clWater, 5, + clHill, 3, + clFood, 1, + clRock, 4, + clMetal, 4, + clPlayer, 15, + clGauls, 0, + clPatrolPointSoldier[i], 5), + scaleByMapSize(20, 150), + 20, + [areasLand[i]]); + } -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clMetal, 4, clRock, 4, clIsland, 4, clGauls, 20, clRitualPlace, 20, clForest, 1, clBaseResource, 4, clHill, 4, clFood, 2)); + g_Map.log("Creating water logs"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(aWaterLog, 1, 1, 0, 0, startAngle, startAngle)], true, + clWaterLog), + 0, + [avoidClasses(clShip, 3, clIsland, 4), stayClasses(clWater, 4)], + scaleByMapSize(1, 4), + 10, + areasWater); -if (day) -{ - g_Map.log("Setting day theme"); - setSkySet("cumulus"); + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clMetal, 4, clRock, 4, clIsland, 4, clGauls, 20, + clRitualPlace, 20, clForest, 1, clBaseResource, 4, clHill, 4, clFood, 2)); - setSunColor(0.9, 0.8, 0.5); + if (day) + { + g_Map.log("Setting day theme"); + setSkySet("cumulus"); - setFogFactor(0.05); - setFogThickness(0.25); + setSunColor(0.9, 0.8, 0.5); - setWaterColor(0.317, 0.396, 0.294); - setWaterTint(0.439, 0.403, 0.262); + setFogFactor(0.05); + setFogThickness(0.25); - setPPContrast(0.62); - setPPSaturation(0.51); - setPPBloom(0.12); -} -else -{ - g_Map.log("Setting night theme"); - setSkySet("dark"); + setWaterColor(0.317, 0.396, 0.294); + setWaterTint(0.439, 0.403, 0.262); - setSunColor(0.4, 0.9, 1.2); - setSunElevation(0.13499); - setSunRotation(-2.5); + setPPContrast(0.62); + setPPSaturation(0.51); + setPPBloom(0.12); + } + else + { + g_Map.log("Setting night theme"); + setSkySet("dark"); - setAmbientColor(0.25, 0.3, 0.45); + setSunColor(0.4, 0.9, 1.2); + setSunElevation(0.13499); + setSunRotation(-2.5); - setFogFactor(0.004); - setFogThickness(0.25); - setFogColor(0.35, 0.45, 0.5); + setAmbientColor(0.25, 0.3, 0.45); - setWaterColor(0.074, 0.101, 0.090); - setWaterTint(0.129, 0.160, 0.137); -} + setFogFactor(0.004); + setFogThickness(0.25); + setFogColor(0.35, 0.45, 0.5); + + setWaterColor(0.074, 0.101, 0.090); + setWaterTint(0.129, 0.160, 0.137); + } -setPPEffect("hdr"); -setWaterWaviness(2.0); -setWaterType("lake"); -setWaterMurkiness(0.97); -setWaterHeight(21); + setPPEffect("hdr"); + setWaterWaviness(2.0); + setWaterType("lake"); + setWaterMurkiness(0.97); + setWaterHeight(21); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/deep_forest.js =================================================================== --- binaries/data/mods/public/maps/random/deep_forest.js +++ binaries/data/mods/public/maps/random/deep_forest.js @@ -1,201 +1,220 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const templateStone = "gaia/rock/temperate_small"; -const templateStoneMine = "gaia/rock/temperate_large"; -const templateMetalMine = "gaia/ore/temperate_large"; -const templateTemple = "gaia/ruins/unfinished_greek_temple"; - -const terrainPrimary = ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_d", "temp_grass_long_b", "temp_grass_clovers_2", "temp_grass_mossy", "temp_grass_plants"]; -const terrainWood = ['temp_grass_mossy|gaia/tree/oak', 'temp_forestfloor_pine|gaia/tree/pine', 'temp_mud_plants|gaia/tree/dead', - 'temp_plants_bog|gaia/tree/oak_large', "temp_dirt_gravel_plants|gaia/tree/aleppo_pine", 'temp_forestfloor_autumn|gaia/tree/carob']; -const terrainWoodBorder = ['temp_grass_plants|gaia/tree/euro_beech', 'temp_grass_mossy|gaia/tree/poplar', 'temp_grass_mossy|gaia/tree/poplar_lombardy', - 'temp_grass_long|gaia/tree/bush_temperate', 'temp_mud_plants|gaia/tree/bush_temperate', 'temp_mud_plants|gaia/tree/bush_badlands', - 'temp_grass_long|gaia/fruit/apple', 'temp_grass_clovers|gaia/fruit/berry_01', 'temp_grass_clovers_2|gaia/fruit/grapes', - 'temp_grass_plants|gaia/fauna_deer', "temp_grass_long_b|gaia/fauna_rabbit", "temp_grass_plants"]; -const terrainBase = ["temp_dirt_gravel", "temp_grass_b"]; -const terrainBaseBorder = ["temp_grass_b", "temp_grass_b", "temp_grass", "temp_grass_c", "temp_grass_mossy"]; -const terrainBaseCenter = ['temp_dirt_gravel', 'temp_dirt_gravel', 'temp_grass_b']; -const terrainPath = ['temp_road', "temp_road_overgrown", 'temp_grass_b']; -const terrainHill = ["temp_highlands", "temp_highlands", "temp_highlands", "temp_dirt_gravel_b", "temp_cliff_a"]; -const 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"]; - -const heightPath = -2; -const heightLand = 0; -const heightOffsetRandomPath = 1; - -const g_Map = new RandomMap(heightLand, terrainPrimary); - -const mapSize = g_Map.getSize(); -const mapRadius = mapSize/2; -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clPath = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -const numPlayers = getNumPlayers(); -const baseRadius = 20; -const minPlayerRadius = Math.min(mapRadius - 1.5 * baseRadius, 5/8 * mapRadius); -const maxPlayerRadius = Math.min(mapRadius - baseRadius, 3/4 * mapRadius); -let playerPosition = []; -let playerAngle = []; -const playerAngleStart = randomAngle(); -const playerAngleAddAvrg = 2 * Math.PI / numPlayers; -const playerAngleMaxOff = playerAngleAddAvrg/4; - -const radiusEC = Math.max(mapRadius/8, baseRadius/2); -const resourceRadius = fractionToTiles(1/3); -const resourcePerPlayer = [templateStone, templateMetalMine]; - -// For large maps there are memory errors with too many trees. A density of 256x192/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. -const maxTreeDensity = Math.min(256 * (192 + 8 * numPlayers) / Math.square(mapSize), 1); // Has to be tweeked but works ok -const bushChance = 1/3; // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood - -const playerIDs = sortAllPlayers(); -for (let i=0; i < numPlayers; i++) +function* GenerateMap() { - 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]), - new TileClassPainter(clPlayer) - ] - }, - "StartingAnimal": { - }, - "Berries": { - "template": "gaia/fruit/grapes", - "minCount": 2, - "maxCount": 2, - "distance": 12, - "minDist": 5, - "maxDist": 8 - }, - "Mines": { - "types": [ - { "template": templateMetalMine }, - { "template": templateStoneMine } - ], - "minAngle": Math.PI / 2, - "maxAngle": Math.PI - }, - "Trees": { - "template": "gaia/tree/oak_large", - "count": 2 - } -}); -Engine.SetProgress(30); - -g_Map.log("Painting paths"); -const pathBlending = numPlayers <= 4; -for (let i = 0; i < numPlayers + (pathBlending ? 1 : 0); ++i) - for (let j = pathBlending ? 0 : i + 1; j < numPlayers + 1; ++j) + const templateStone = "gaia/rock/temperate_small"; + const templateStoneMine = "gaia/rock/temperate_large"; + const templateMetalMine = "gaia/ore/temperate_large"; + const templateTemple = "gaia/ruins/unfinished_greek_temple"; + + const terrainPrimary = ["temp_grass", "temp_grass_b", "temp_grass_c", "temp_grass_d", + "temp_grass_long_b", "temp_grass_clovers_2", "temp_grass_mossy", "temp_grass_plants"]; + const terrainWood = ['temp_grass_mossy|gaia/tree/oak', 'temp_forestfloor_pine|gaia/tree/pine', + 'temp_mud_plants|gaia/tree/dead', 'temp_plants_bog|gaia/tree/oak_large', + "temp_dirt_gravel_plants|gaia/tree/aleppo_pine", 'temp_forestfloor_autumn|gaia/tree/carob']; + const terrainWoodBorder = ['temp_grass_plants|gaia/tree/euro_beech', + 'temp_grass_mossy|gaia/tree/poplar', 'temp_grass_mossy|gaia/tree/poplar_lombardy', + 'temp_grass_long|gaia/tree/bush_temperate', 'temp_mud_plants|gaia/tree/bush_temperate', + 'temp_mud_plants|gaia/tree/bush_badlands', 'temp_grass_long|gaia/fruit/apple', + 'temp_grass_clovers|gaia/fruit/berry_01', 'temp_grass_clovers_2|gaia/fruit/grapes', + 'temp_grass_plants|gaia/fauna_deer', "temp_grass_long_b|gaia/fauna_rabbit", + "temp_grass_plants"]; + const terrainBase = ["temp_dirt_gravel", "temp_grass_b"]; + const terrainBaseBorder = ["temp_grass_b", "temp_grass_b", "temp_grass", "temp_grass_c", + "temp_grass_mossy"]; + const terrainBaseCenter = ['temp_dirt_gravel', 'temp_dirt_gravel', 'temp_grass_b']; + const terrainPath = ['temp_road', "temp_road_overgrown", 'temp_grass_b']; + const terrainHill = ["temp_highlands", "temp_highlands", "temp_highlands", "temp_dirt_gravel_b", + "temp_cliff_a"]; + const 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"]; + + const heightPath = -2; + const heightLand = 0; + const heightOffsetRandomPath = 1; + + global.g_Map = new RandomMap(heightLand, terrainPrimary); + + const mapSize = g_Map.getSize(); + const mapRadius = mapSize/2; + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clPath = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + const numPlayers = getNumPlayers(); + const baseRadius = 20; + const minPlayerRadius = Math.min(mapRadius - 1.5 * baseRadius, 5/8 * mapRadius); + const maxPlayerRadius = Math.min(mapRadius - baseRadius, 3/4 * mapRadius); + let playerPosition = []; + let playerAngle = []; + const playerAngleStart = randomAngle(); + const playerAngleAddAvrg = 2 * Math.PI / numPlayers; + const playerAngleMaxOff = playerAngleAddAvrg/4; + + const radiusEC = Math.max(mapRadius/8, baseRadius/2); + const resourceRadius = fractionToTiles(1/3); + const resourcePerPlayer = [templateStone, templateMetalMine]; + + // For large maps there are memory errors with too many trees. A density of 256x192/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. + // Has to be tweeked but works ok + const maxTreeDensity = Math.min(256 * (192 + 8 * numPlayers) / Math.square(mapSize), 1); + // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood + const bushChance = 1/3; + + const playerIDs = sortAllPlayers(); + for (let i=0; i < numPlayers; i++) { - const pathStart = i < numPlayers ? playerPosition[i] : mapCenter; - const 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), - new TileClassPainter(clPath) - ], - avoidClasses(clBaseResource, 4)); + 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(50); + yield 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]), + new TileClassPainter(clPlayer) + ] + }, + "StartingAnimal": { + }, + "Berries": { + "template": "gaia/fruit/grapes", + "minCount": 2, + "maxCount": 2, + "distance": 12, + "minDist": 5, + "maxDist": 8 + }, + "Mines": { + "types": [ + { "template": templateMetalMine }, + { "template": templateStoneMine } + ], + "minAngle": Math.PI / 2, + "maxAngle": Math.PI + }, + "Trees": { + "template": "gaia/tree/oak_large", + "count": 2 + } + }); + yield 30; -g_Map.log("Placing expansion resources"); -for (let i = 0; i < numPlayers; ++i) - for (let rIndex = 0; rIndex < resourcePerPlayer.length; ++rIndex) - { - const 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 - const angle = playerAngle[i] + angleDist * (rIndex + 1) / (resourcePerPlayer.length + 1); - const position = Vector2D.add(mapCenter, new Vector2D(resourceRadius, 0).rotate(-angle)).round(); - - g_Map.placeEntityPassable(resourcePerPlayer[rIndex], 0, position, randomAngle()); - - createArea( - new ClumpPlacer(40, 1/2, 1/8, Infinity, position), - [ - new LayeredPainter([terrainHillBorder, terrainHill], [1]), - new ElevationPainter(randFloat(1, 2)), - new TileClassPainter(clHill) - ]); - } -Engine.SetProgress(60); - -g_Map.log("Placing temple"); -g_Map.placeEntityPassable(templateTemple, 0, mapCenter, randomAngle()); -clBaseResource.add(mapCenter); - -g_Map.log("Creating central mountain"); -createArea( - new ClumpPlacer(Math.square(radiusEC), 1/2, 1/8, Infinity, mapCenter), - [ - new LayeredPainter([terrainHillBorder, terrainHill], [radiusEC/4]), - new ElevationPainter(randFloat(1, 2)), - new TileClassPainter(clHill) - ]); - -// Woods and general height map -for (let x = 0; x < mapSize; x++) - for (let z = 0; z < mapSize; z++) - { - const position = new Vector2D(x, z); + g_Map.log("Painting paths"); + const pathBlending = numPlayers <= 4; + for (let i = 0; i < numPlayers + (pathBlending ? 1 : 0); ++i) + for (let j = pathBlending ? 0 : i + 1; j < numPlayers + 1; ++j) + { + const pathStart = i < numPlayers ? playerPosition[i] : mapCenter; + const 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), + new TileClassPainter(clPath) + ], + avoidClasses(clBaseResource, 4)); + } + yield 50; - // The 0.5 is a correction for the entities placed on the center of tiles - const radius = mapCenter.distanceTo(Vector2D.add(position, new Vector2D(0.5, 0.5))); - let minDistToSL = mapSize; - for (let i=0; i < numPlayers; i++) - minDistToSL = Math.min(minDistToSL, position.distanceTo(playerPosition[i])); + g_Map.log("Placing expansion resources"); + for (let i = 0; i < numPlayers; ++i) + for (let rIndex = 0; rIndex < resourcePerPlayer.length; ++rIndex) + { + const 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 + const angle = playerAngle[i] + angleDist * (rIndex + 1) / (resourcePerPlayer.length + 1); + const position = Vector2D.add(mapCenter, + new Vector2D(resourceRadius, 0).rotate(-angle)).round(); + + g_Map.placeEntityPassable(resourcePerPlayer[rIndex], 0, position, randomAngle()); + + createArea( + new ClumpPlacer(40, 1/2, 1/8, Infinity, position), + [ + new LayeredPainter([terrainHillBorder, terrainHill], [1]), + new ElevationPainter(randFloat(1, 2)), + new TileClassPainter(clHill) + ]); + } + yield 60; + + g_Map.log("Placing temple"); + g_Map.placeEntityPassable(templateTemple, 0, mapCenter, randomAngle()); + clBaseResource.add(mapCenter); + + g_Map.log("Creating central mountain"); + createArea( + new ClumpPlacer(Math.square(radiusEC), 1/2, 1/8, Infinity, mapCenter), + [ + new LayeredPainter([terrainHillBorder, terrainHill], [radiusEC/4]), + new ElevationPainter(randFloat(1, 2)), + new TileClassPainter(clHill) + ]); + + // Woods and general height map + for (let x = 0; x < mapSize; x++) + for (let z = 0; z < mapSize; z++) + { + const position = new Vector2D(x, z); - // Woods tile based - const tDensFactSL = Math.max(Math.min((minDistToSL - baseRadius) / baseRadius, 1), 0); - const tDensFactRad = Math.abs((resourceRadius - radius) / resourceRadius); - const tDensFactEC = Math.max(Math.min((radius - radiusEC) / radiusEC, 1), 0); - const tDensActual = maxTreeDensity * tDensFactSL * tDensFactRad * tDensFactEC; + // The 0.5 is a correction for the entities placed on the center of tiles + const radius = mapCenter.distanceTo(Vector2D.add(position, new Vector2D(0.5, 0.5))); + let minDistToSL = mapSize; + for (let i=0; i < numPlayers; i++) + minDistToSL = Math.min(minDistToSL, position.distanceTo(playerPosition[i])); - if (randBool(tDensActual) && g_Map.validTile(position)) - { - const border = tDensActual < randFloat(0, bushChance * maxTreeDensity); - if (avoidClasses(clPath, 1, clHill, border ? 0 : 1).allows(position)) + // Woods tile based + const tDensFactSL = Math.max(Math.min((minDistToSL - baseRadius) / baseRadius, 1), 0); + const tDensFactRad = Math.abs((resourceRadius - radius) / resourceRadius); + const tDensFactEC = Math.max(Math.min((radius - radiusEC) / radiusEC, 1), 0); + const tDensActual = maxTreeDensity * tDensFactSL * tDensFactRad * tDensFactEC; + + if (randBool(tDensActual) && g_Map.validTile(position)) { - createTerrain(border ? terrainWoodBorder : terrainWood).place(position); - g_Map.setHeight(position, randFloat(0, 1)); - clForest.add(position); + const border = tDensActual < randFloat(0, bushChance * maxTreeDensity); + if (avoidClasses(clPath, 1, clHill, border ? 0 : 1).allows(position)) + { + createTerrain(border ? terrainWoodBorder : terrainWood).place(position); + g_Map.setHeight(position, randFloat(0, 1)); + clForest.add(position); + } } - } - // General height map - const hVarMiddleHill = fractionToTiles(1 / 64) * (1 + Math.cos(3/2 * Math.PI * radius / mapRadius)); - const hVarHills = 5 * (1 + Math.sin(x / 10) * Math.sin(z / 10)); - g_Map.setHeight(position, g_Map.getHeight(position) + hVarMiddleHill + hVarHills + 1); - } -Engine.SetProgress(95); + // General height map + const hVarMiddleHill = + fractionToTiles(1 / 64) * (1 + Math.cos(3/2 * Math.PI * radius / mapRadius)); + const hVarHills = 5 * (1 + Math.sin(x / 10) * Math.sin(z / 10)); + g_Map.setHeight(position, g_Map.getHeight(position) + hVarMiddleHill + hVarHills + 1); + } + yield 95; -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clBaseResource, 4, clHill, 4)); + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clBaseResource, 4, clHill, 4)); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/dodecanese.js =================================================================== --- binaries/data/mods/public/maps/random/dodecanese.js +++ binaries/data/mods/public/maps/random/dodecanese.js @@ -3,428 +3,445 @@ TILE_CENTERED_HEIGHT_MAP = true; -const tCity = "medit_city_pavement"; -const tCityPlaza = "medit_city_pavement"; -const tHill = ["medit_grass_shrubs", "medit_rocks_grass_shrubs", "medit_rocks_shrubs", "medit_rocks_grass", "medit_shrubs"]; -const tMainDirt = "medit_dirt"; -const tCliff = "medit_cliff_aegean"; -const tForestFloor = "medit_grass_wild"; -const tPrimary = ["medit_grass_shrubs", "medit_grass_wild", "medit_rocks_grass_shrubs", "medit_dirt_b", "medit_plants_dirt", "medit_grass_flowers"]; -const tDirt = "medit_dirt_b"; -const tDirt2 = "medit_rocks_grass"; -const tDirt3 = "medit_rocks_shrubs"; -const tDirtCracks = "medit_dirt_c"; -const tShoreLower = "medit_sand_wet"; -const tShoreUpper = "medit_sand"; -const tCoralsLower = "medit_sea_coral_deep"; -const tCoralsUpper = "medit_sea_coral_plants"; -const tWater = "medit_sea_depths"; -const tLavaOuter = "LavaTest06"; -const tLavaInner = "LavaTest05"; - -const oBerryBush = "gaia/fruit/berry_01"; -const oDeer = "gaia/fauna_deer"; -const oFish = "gaia/fish/generic"; -const oSheep = "gaia/fauna_sheep"; -const oGoat = "gaia/fauna_goat"; -const oRabbit = "gaia/fauna_rabbit"; -const oStoneLarge = "gaia/rock/mediterranean_large"; -const oStoneSmall = "gaia/rock/mediterranean_small"; -const oMetalLarge = "gaia/ore/mediterranean_large"; -const oMetalSmall = "gaia/ore/mediterranean_small"; -const oDatePalm = "gaia/tree/cretan_date_palm_short"; -const oSDatePalm = "gaia/tree/cretan_date_palm_tall"; -const oCarob = "gaia/tree/carob"; -const oFanPalm = "gaia/tree/medit_fan_palm"; -const oPoplar = "gaia/tree/poplar_lombardy"; -const oCypress = "gaia/tree/cypress"; -const oBush = "gaia/tree/bush_temperate"; - -const aBush1 = actorTemplate("props/flora/bush_medit_sm"); -const aBush2 = actorTemplate("props/flora/bush_medit_me"); -const aBush3 = actorTemplate("props/flora/bush_medit_la"); -const aBush4 = actorTemplate("props/flora/bush_medit_me"); -const aDecorativeRock = actorTemplate("geology/stone_granite_med"); -const aBridge = actorTemplate("props/special/eyecandy/bridge_edge_wooden"); -const aSmokeBig = actorTemplate("particle/smoke_volcano"); -const aSmokeSmall = actorTemplate("particle/smoke_curved"); - -const pForest1 = [ - tForestFloor, - tForestFloor + TERRAIN_SEPARATOR + oCarob, - tForestFloor + TERRAIN_SEPARATOR + oDatePalm, - tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, - tForestFloor]; - -const pForest2 = [ - tForestFloor, - tForestFloor + TERRAIN_SEPARATOR + oFanPalm, - tForestFloor + TERRAIN_SEPARATOR + oPoplar, - tForestFloor + TERRAIN_SEPARATOR + oCypress]; - -const heightSeaGround = -8; -const heightCoralsLower = -6; -const heightCoralsUpper = -4; -const heightSeaBump = -2.5; -const heightShoreLower = -2; -const heightBridge = -0.5; -const heightShoreUpper = 1; -const heightLand = 3; -const heightOffsetBump = 2; -const heightHill = 8; -const heightVolano = 25; - -const g_Map = new RandomMap(heightSeaGround, tWater); -const numPlayers = getNumPlayers(); - -const clIsland = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clPlayer = g_Map.createTileClass(); -const clPlayerIsland = g_Map.createTileClass(); -const clShore = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clGrass = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clVolcano = g_Map.createTileClass(); -const clBridge = g_Map.createTileClass(); - -const playerIslandRadius = scaleByMapSize(20, 29); -const bridgeLength = 16; -const maxBridges = scaleByMapSize(2, 12); - -const [playerIDs, playerPosition] = playerPlacementRandom(sortAllPlayers()); - -g_Map.log("Creating player islands"); -for (const position of playerPosition) - createArea( - new ChainPlacer(2, 6, scaleByMapSize(15, 50), Infinity, position, 0, [playerIslandRadius]), +function* GenerateMap() +{ + const tCity = "medit_city_pavement"; + const tCityPlaza = "medit_city_pavement"; + const tHill = ["medit_grass_shrubs", "medit_rocks_grass_shrubs", "medit_rocks_shrubs", "medit_rocks_grass", "medit_shrubs"]; + const tMainDirt = "medit_dirt"; + const tCliff = "medit_cliff_aegean"; + const tForestFloor = "medit_grass_wild"; + const tPrimary = ["medit_grass_shrubs", "medit_grass_wild", "medit_rocks_grass_shrubs", "medit_dirt_b", "medit_plants_dirt", "medit_grass_flowers"]; + const tDirt = "medit_dirt_b"; + const tDirt2 = "medit_rocks_grass"; + const tDirt3 = "medit_rocks_shrubs"; + const tDirtCracks = "medit_dirt_c"; + const tShoreLower = "medit_sand_wet"; + const tShoreUpper = "medit_sand"; + const tCoralsLower = "medit_sea_coral_deep"; + const tCoralsUpper = "medit_sea_coral_plants"; + const tWater = "medit_sea_depths"; + const tLavaOuter = "LavaTest06"; + const tLavaInner = "LavaTest05"; + + const oBerryBush = "gaia/fruit/berry_01"; + const oDeer = "gaia/fauna_deer"; + const oFish = "gaia/fish/generic"; + const oSheep = "gaia/fauna_sheep"; + const oGoat = "gaia/fauna_goat"; + const oRabbit = "gaia/fauna_rabbit"; + const oStoneLarge = "gaia/rock/mediterranean_large"; + const oStoneSmall = "gaia/rock/mediterranean_small"; + const oMetalLarge = "gaia/ore/mediterranean_large"; + const oMetalSmall = "gaia/ore/mediterranean_small"; + const oDatePalm = "gaia/tree/cretan_date_palm_short"; + const oSDatePalm = "gaia/tree/cretan_date_palm_tall"; + const oCarob = "gaia/tree/carob"; + const oFanPalm = "gaia/tree/medit_fan_palm"; + const oPoplar = "gaia/tree/poplar_lombardy"; + const oCypress = "gaia/tree/cypress"; + const oBush = "gaia/tree/bush_temperate"; + + const aBush1 = actorTemplate("props/flora/bush_medit_sm"); + const aBush2 = actorTemplate("props/flora/bush_medit_me"); + const aBush3 = actorTemplate("props/flora/bush_medit_la"); + const aBush4 = actorTemplate("props/flora/bush_medit_me"); + const aDecorativeRock = actorTemplate("geology/stone_granite_med"); + const aBridge = actorTemplate("props/special/eyecandy/bridge_edge_wooden"); + const aSmokeBig = actorTemplate("particle/smoke_volcano"); + const aSmokeSmall = actorTemplate("particle/smoke_curved"); + + const pForest1 = [ + tForestFloor, + tForestFloor + TERRAIN_SEPARATOR + oCarob, + tForestFloor + TERRAIN_SEPARATOR + oDatePalm, + tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, + tForestFloor]; + + const pForest2 = [ + tForestFloor, + tForestFloor + TERRAIN_SEPARATOR + oFanPalm, + tForestFloor + TERRAIN_SEPARATOR + oPoplar, + tForestFloor + TERRAIN_SEPARATOR + oCypress]; + + const heightSeaGround = -8; + const heightCoralsLower = -6; + const heightCoralsUpper = -4; + const heightSeaBump = -2.5; + const heightShoreLower = -2; + const heightBridge = -0.5; + const heightShoreUpper = 1; + const heightLand = 3; + const heightOffsetBump = 2; + const heightHill = 8; + const heightVolano = 25; + + global.g_Map = new RandomMap(heightSeaGround, tWater); + const numPlayers = getNumPlayers(); + + const clIsland = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clPlayer = g_Map.createTileClass(); + const clPlayerIsland = g_Map.createTileClass(); + const clShore = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clGrass = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clVolcano = g_Map.createTileClass(); + const clBridge = g_Map.createTileClass(); + + const playerIslandRadius = scaleByMapSize(20, 29); + const bridgeLength = 16; + const maxBridges = scaleByMapSize(2, 12); + + const [playerIDs, playerPosition] = playerPlacementRandom(sortAllPlayers()); + + g_Map.log("Creating player islands"); + for (const position of playerPosition) + createArea( + new ChainPlacer(2, 6, scaleByMapSize(15, 50), Infinity, position, 0, + [playerIslandRadius]), + [ + new TerrainPainter(tPrimary), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), + new TileClassPainter(clIsland) + ].concat(isNomad() ? [] : [new TileClassPainter(clPlayerIsland)])); + yield 10; + + g_Map.log("Creating islands"); + createAreas( + new ChainPlacer(6, Math.floor(scaleByMapSize(8, 10)), Math.floor(scaleByMapSize(10, 35)), 0.2), [ new TerrainPainter(tPrimary), new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), new TileClassPainter(clIsland) - ].concat(isNomad() ? [] : [new TileClassPainter(clPlayerIsland)])); -Engine.SetProgress(10); - -g_Map.log("Creating islands"); -createAreas( - new ChainPlacer(6, Math.floor(scaleByMapSize(8, 10)), Math.floor(scaleByMapSize(10, 35)), 0.2), - [ - new TerrainPainter(tPrimary), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), - new TileClassPainter(clIsland) - ], - avoidClasses(clIsland, 6), - scaleByMapSize(25, 80)); -Engine.SetProgress(20); - -// Notice that the Constraints become much shorter when avoiding water rather than staying on islands -g_Map.log("Marking water"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(clWater), - new HeightConstraint(-Infinity, heightShoreLower)); -Engine.SetProgress(30); - -g_Map.log("Creating undersea bumps"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), - new SmoothElevationPainter(ELEVATION_SET, heightSeaBump, 3), - avoidClasses(clIsland, 2), - scaleByMapSize(10, 50)); -Engine.SetProgress(35); - -g_Map.log("Creating volcano"); -const areasVolcano = createAreas( - new ClumpPlacer(diskArea(scaleByMapSize(4, 8)), 0.5, 0.5, 0.1), - [ - new LayeredPainter([tLavaOuter, tLavaInner], [4]), - new SmoothElevationPainter(ELEVATION_SET, heightVolano, 6), - new TileClassPainter(clVolcano) - ], - [ - new NearTileClassConstraint(clIsland, 8), - avoidClasses(clHill, 5, clPlayerIsland, 0), - ], - 1, - 200); - -createBumps(avoidClasses(clWater, 0, clPlayer, 10, clVolcano, 0)); -Engine.SetProgress(40); - -g_Map.log("Creating large bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 3), - avoidClasses(clWater, 2, clVolcano, 0, clPlayer, 10), - scaleByMapSize(20, 200)); -Engine.SetProgress(45); - -g_Map.log("Creating hills"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), - [ - new LayeredPainter([tCliff, tHill], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - avoidClasses(clWater, 1, clPlayer, 12, clVolcano, 0, clHill, 15), - scaleByMapSize(4, 13)); -Engine.SetProgress(50); - -g_Map.log("Painting corals"); -paintTerrainBasedOnHeight(-Infinity, heightCoralsLower, Elevation_IncludeMin_ExcludeMax, tWater); -paintTerrainBasedOnHeight(heightCoralsLower, heightCoralsUpper, Elevation_IncludeMin_ExcludeMax, tCoralsLower); -paintTerrainBasedOnHeight(heightCoralsUpper, heightShoreLower, Elevation_IncludeMin_ExcludeMax, tCoralsUpper); - -g_Map.log("Painting shoreline"); -const areaShoreline = createArea( - new HeightPlacer(Elevation_IncludeMin_ExcludeMax, heightShoreLower, heightShoreUpper), - [ - new TerrainPainter(tShoreLower), - new TileClassPainter(clShore) - ], - avoidClasses(clVolcano, 0)); - -createArea( - new HeightPlacer(Elevation_IncludeMin_ExcludeMax, heightShoreUpper, heightLand), - new TerrainPainter(tShoreUpper), - avoidClasses(clVolcano, 0)); -Engine.SetProgress(60); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [tDirt3, tDirt2, [tDirt, tMainDirt], [tDirtCracks, tMainDirt]], - [1, 1, 1], - avoidClasses(clWater, 4, clVolcano, 2, clForest, 1, clDirt, 2, clGrass, 2, clHill, 1), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(65); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "BaseResourceClass": clBaseResource, - "PlayerTileClass": clPlayer, - "Walls": "towers", - "CityPatch": { - "radius": playerIslandRadius / 4, - "outerTerrain": tCityPlaza, - "innerTerrain": tCity - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - // sufficient trees around - "Decoratives": { - "template": aBush1 - } -}); -Engine.SetProgress(70); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2, 5, 1, 3)] - ], - avoidClasses(clWater, 4, clVolcano, 4, clPlayerIsland, 0, clBaseResource, 4, clForest, 3, clMetal, 4, clRock, 4), - clRock, - scaleByMapSize(4, 16)); -Engine.SetProgress(75); - -g_Map.log("Creating metal mines"); -createMines( - [ - [new SimpleObject(oMetalSmall, 0, 1, 0, 4), new SimpleObject(oMetalLarge, 1, 1, 0, 4)], - [new SimpleObject(oMetalSmall, 2, 5, 1, 3)] - ], - avoidClasses(clWater, 4, clPlayerIsland, 0, clVolcano, 4, clBaseResource, 4, clForest, 3, clMetal, 4, clRock, 4), - clMetal, - scaleByMapSize(4, 16)); -Engine.SetProgress(80); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 12, clVolcano, 4, clMetal, 4, clRock, 4, clHill, 4)); - -const [forestTrees, stragglerTrees] = getTreeCounts(800, 4000, 0.7); -createForests( - [tForestFloor, tForestFloor, tForestFloor, pForest1, pForest2], - avoidClasses(clWater, 2, clPlayer, 4, clVolcano, 2, clForest, 1, clBaseResource, 4, clMetal, 4, clRock, 4), - clForest, - forestTrees, - 200); -Engine.SetProgress(85); - -createFood( - [ - [new SimpleObject(oSheep, 5, 7, 0, 4)], - [new SimpleObject(oGoat, 2, 4, 0, 3)], - [new SimpleObject(oDeer, 2, 4, 0, 2)], - [new SimpleObject(oRabbit, 3, 9, 0, 4)], - [new SimpleObject(oBerryBush, 3, 5, 0, 4)] - ], - [ - scaleByMapSize(5, 20), - scaleByMapSize(5, 20), - scaleByMapSize(5, 20), - scaleByMapSize(5, 20), - 3 * numPlayers - ], - avoidClasses(clWater, 1, clPlayer, 15, clVolcano, 4, clBaseResource, 4, clHill, 2, clMetal, 4, clRock, 4), - clFood); - -Engine.SetProgress(87); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 3 * numPlayers - ], - avoidClasses(clIsland, 8, clFood, 10, clVolcano, 4), - clFood); - -createStragglerTrees( - [oPoplar, oCypress, oFanPalm, oDatePalm, oSDatePalm], - avoidClasses(clWater, 1, clVolcano, 4, clPlayer, 12, clForest, 1, clMetal, 4, clRock, 4), - clForest, - stragglerTrees, - 200); - -g_Map.log("Creating bushes"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oBush, 3, 5, 0, 4)], true), - 0, - [avoidClasses(clWater, 1, clVolcano, 4, clPlayer, 5, clForest, 1, clBaseResource, 4, clMetal, 4, clRock, 4)], - scaleByMapSize(20, 50)); - -createDecoration( - [ + ], + avoidClasses(clIsland, 6), + scaleByMapSize(25, 80)); + yield 20; + + // Notice that the Constraints become much shorter when avoiding water rather than staying on islands + g_Map.log("Marking water"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(clWater), + new HeightConstraint(-Infinity, heightShoreLower)); + yield 30; + + g_Map.log("Creating undersea bumps"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), + new SmoothElevationPainter(ELEVATION_SET, heightSeaBump, 3), + avoidClasses(clIsland, 2), + scaleByMapSize(10, 50)); + yield 35; + + g_Map.log("Creating volcano"); + const areasVolcano = createAreas( + new ClumpPlacer(diskArea(scaleByMapSize(4, 8)), 0.5, 0.5, 0.1), [ - new SimpleObject(aDecorativeRock, 1, 3, 0, 1) + new LayeredPainter([tLavaOuter, tLavaInner], [4]), + new SmoothElevationPainter(ELEVATION_SET, heightVolano, 6), + new TileClassPainter(clVolcano) ], [ - new SimpleObject(aBush2, 1, 2, 0, 1), - new SimpleObject(aBush1, 1, 3, 0, 2), - new SimpleObject(aBush4, 1, 2, 0, 1), - new SimpleObject(aBush3, 1, 3, 0, 2) - ] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapSize(40, 360) - ], - avoidClasses(clWater, 4, clPlayer, 5, clVolcano, 4, clForest, 1, clBaseResource, 4, clRock, 4, clMetal, 4, clHill, 1)); - -g_Map.log("Creating bridges"); -let bridges = 0; -for (const bridgeStart of shuffleArray(areaShoreline.getPoints())) -{ - if (new NearTileClassConstraint(clBridge, bridgeLength * 8).allows(bridgeStart)) - continue; + new NearTileClassConstraint(clIsland, 8), + avoidClasses(clHill, 5, clPlayerIsland, 0), + ], + 1, + 200); + + createBumps(avoidClasses(clWater, 0, clPlayer, 10, clVolcano, 0)); + yield 40; + + g_Map.log("Creating large bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 3), + avoidClasses(clWater, 2, clVolcano, 0, clPlayer, 10), + scaleByMapSize(20, 200)); + yield 45; + + g_Map.log("Creating hills"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), + [ + new LayeredPainter([tCliff, tHill], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) + ], + avoidClasses(clWater, 1, clPlayer, 12, clVolcano, 0, clHill, 15), + scaleByMapSize(4, 13)); + yield 50; + + g_Map.log("Painting corals"); + paintTerrainBasedOnHeight(-Infinity, heightCoralsLower, Elevation_IncludeMin_ExcludeMax, tWater); + paintTerrainBasedOnHeight(heightCoralsLower, heightCoralsUpper, Elevation_IncludeMin_ExcludeMax, + tCoralsLower); + paintTerrainBasedOnHeight(heightCoralsUpper, heightShoreLower, Elevation_IncludeMin_ExcludeMax, + tCoralsUpper); + + g_Map.log("Painting shoreline"); + const areaShoreline = createArea( + new HeightPlacer(Elevation_IncludeMin_ExcludeMax, heightShoreLower, heightShoreUpper), + [ + new TerrainPainter(tShoreLower), + new TileClassPainter(clShore) + ], + avoidClasses(clVolcano, 0)); - for (let direction = 0; direction < 4; ++direction) - { - const bridgeAngle = direction * Math.PI / 2; - const bridgeDirection = new Vector2D(1, 0).rotate(bridgeAngle); + createArea( + new HeightPlacer(Elevation_IncludeMin_ExcludeMax, heightShoreUpper, heightLand), + new TerrainPainter(tShoreUpper), + avoidClasses(clVolcano, 0)); + yield 60; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [tDirt3, tDirt2, [tDirt, tMainDirt], [tDirtCracks, tMainDirt]], + [1, 1, 1], + avoidClasses(clWater, 4, clVolcano, 2, clForest, 1, clDirt, 2, clGrass, 2, clHill, 1), + scaleByMapSize(15, 45), + clDirt); + yield 65; + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "BaseResourceClass": clBaseResource, + "PlayerTileClass": clPlayer, + "Walls": "towers", + "CityPatch": { + "radius": playerIslandRadius / 4, + "outerTerrain": tCityPlaza, + "innerTerrain": tCity + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + // sufficient trees around + "Decoratives": { + "template": aBush1 + } + }); + yield 70; + + g_Map.log("Creating stone mines"); + createMines( + [ + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oStoneSmall, 2, 5, 1, 3)] + ], + avoidClasses(clWater, 4, clVolcano, 4, clPlayerIsland, 0, clBaseResource, 4, clForest, 3, + clMetal, 4, clRock, 4), + clRock, + scaleByMapSize(4, 16)); + yield 75; + + g_Map.log("Creating metal mines"); + createMines( + [ + [new SimpleObject(oMetalSmall, 0, 1, 0, 4), new SimpleObject(oMetalLarge, 1, 1, 0, 4)], + [new SimpleObject(oMetalSmall, 2, 5, 1, 3)] + ], + avoidClasses(clWater, 4, clPlayerIsland, 0, clVolcano, 4, clBaseResource, 4, clForest, 3, + clMetal, 4, clRock, 4), + clMetal, + scaleByMapSize(4, 16)); + yield 80; + + placePlayersNomad(clPlayer, avoidClasses(clWater, 12, clVolcano, 4, clMetal, 4, clRock, 4, clHill, 4)); + + const [forestTrees, stragglerTrees] = getTreeCounts(800, 4000, 0.7); + createForests( + [tForestFloor, tForestFloor, tForestFloor, pForest1, pForest2], + avoidClasses(clWater, 2, clPlayer, 4, clVolcano, 2, clForest, 1, clBaseResource, 4, clMetal, 4, + clRock, 4), + clForest, + forestTrees, + 200); + yield 85; + + createFood( + [ + [new SimpleObject(oSheep, 5, 7, 0, 4)], + [new SimpleObject(oGoat, 2, 4, 0, 3)], + [new SimpleObject(oDeer, 2, 4, 0, 2)], + [new SimpleObject(oRabbit, 3, 9, 0, 4)], + [new SimpleObject(oBerryBush, 3, 5, 0, 4)] + ], + [ + scaleByMapSize(5, 20), + scaleByMapSize(5, 20), + scaleByMapSize(5, 20), + scaleByMapSize(5, 20), + 3 * numPlayers + ], + avoidClasses(clWater, 1, clPlayer, 15, clVolcano, 4, clBaseResource, 4, clHill, 2, clMetal, 4, + clRock, 4), + clFood); - const areaOffset = new Vector2D(1, 1); + yield 87; - const bridgeOffset = new Vector2D(direction % 2 ? 2 : 0, direction % 2 ? 0 : 2); - const bridgeCenter1 = Vector2D.add(bridgeStart, Vector2D.mult(bridgeDirection, bridgeLength / 2)); - const bridgeCenter2 = Vector2D.add(bridgeCenter1, bridgeOffset); - if (avoidClasses(clWater, 0).allows(bridgeCenter1) && avoidClasses(clWater, 0).allows(bridgeCenter2)) - continue; + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 3 * numPlayers + ], + avoidClasses(clIsland, 8, clFood, 10, clVolcano, 4), + clFood); + + createStragglerTrees( + [oPoplar, oCypress, oFanPalm, oDatePalm, oSDatePalm], + avoidClasses(clWater, 1, clVolcano, 4, clPlayer, 12, clForest, 1, clMetal, 4, clRock, 4), + clForest, + stragglerTrees, + 200); + + g_Map.log("Creating bushes"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oBush, 3, 5, 0, 4)], true), + 0, + [avoidClasses(clWater, 1, clVolcano, 4, clPlayer, 5, clForest, 1, clBaseResource, 4, clMetal, 4, + clRock, 4)], + scaleByMapSize(20, 50)); - const bridgeEnd1 = Vector2D.add(bridgeStart, Vector2D.mult(bridgeDirection, bridgeLength)); - const bridgeEnd2 = Vector2D.add(bridgeEnd1, bridgeOffset); - if (avoidClasses(clShore, 0).allows(bridgeEnd1) && avoidClasses(clShore, 0).allows(bridgeEnd2)) - continue; + createDecoration( + [ + [ + new SimpleObject(aDecorativeRock, 1, 3, 0, 1) + ], + [ + new SimpleObject(aBush2, 1, 2, 0, 1), + new SimpleObject(aBush1, 1, 3, 0, 2), + new SimpleObject(aBush4, 1, 2, 0, 1), + new SimpleObject(aBush3, 1, 3, 0, 2) + ] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapSize(40, 360) + ], + avoidClasses(clWater, 4, clPlayer, 5, clVolcano, 4, clForest, 1, clBaseResource, 4, clRock, 4, + clMetal, 4, clHill, 1)); - const bridgePerpendicular = bridgeDirection.perpendicular(); - const bridgeP = Vector2D.mult(bridgePerpendicular, bridgeLength / 2).round(); - if (avoidClasses(clWater, 0).allows(Vector2D.add(bridgeCenter1, bridgeP)) || - avoidClasses(clWater, 0).allows(Vector2D.sub(bridgeCenter2, bridgeP))) + g_Map.log("Creating bridges"); + let bridges = 0; + for (const bridgeStart of shuffleArray(areaShoreline.getPoints())) + { + if (new NearTileClassConstraint(clBridge, bridgeLength * 8).allows(bridgeStart)) continue; - ++bridges; + for (let direction = 0; direction < 4; ++direction) + { + const bridgeAngle = direction * Math.PI / 2; + const bridgeDirection = new Vector2D(1, 0).rotate(bridgeAngle); - // This bridge model is not centered on the horizontal plane, so the angle is messy - // TILE_CENTERED_HEIGHT_MAP also influences the outcome of the placement. - const bridgeOrientation = direction % 2 ? 0 : Math.PI / 2; - bridgeCenter1[direction % 2 ? "y" : "x"] += 0.25; - bridgeCenter2[direction % 2 ? "y" : "x"] -= 0.25; + const areaOffset = new Vector2D(1, 1); - g_Map.placeEntityAnywhere(aBridge, 0, bridgeCenter1, bridgeOrientation); - g_Map.placeEntityAnywhere(aBridge, 0, bridgeCenter2, bridgeOrientation + Math.PI); + const bridgeOffset = new Vector2D(direction % 2 ? 2 : 0, direction % 2 ? 0 : 2); + const bridgeCenter1 = Vector2D.add(bridgeStart, + Vector2D.mult(bridgeDirection, bridgeLength / 2)); + const bridgeCenter2 = Vector2D.add(bridgeCenter1, bridgeOffset); + if (avoidClasses(clWater, 0).allows(bridgeCenter1) && + avoidClasses(clWater, 0).allows(bridgeCenter2)) + continue; - createArea( - new RectPlacer(Vector2D.sub(bridgeStart, areaOffset), Vector2D.add(bridgeEnd1, areaOffset)), - [ - new ElevationPainter(heightBridge), - new TileClassPainter(clBridge) - ]); + const bridgeEnd1 = Vector2D.add(bridgeStart, Vector2D.mult(bridgeDirection, bridgeLength)); + const bridgeEnd2 = Vector2D.add(bridgeEnd1, bridgeOffset); + if (avoidClasses(clShore, 0).allows(bridgeEnd1) && + avoidClasses(clShore, 0).allows(bridgeEnd2)) + continue; - for (const center of [bridgeStart, bridgeEnd2]) - createArea( - new DiskPlacer(2, center), - new SmoothingPainter(1, 1, 1)); + const bridgePerpendicular = bridgeDirection.perpendicular(); + const bridgeP = Vector2D.mult(bridgePerpendicular, bridgeLength / 2).round(); + if (avoidClasses(clWater, 0).allows(Vector2D.add(bridgeCenter1, bridgeP)) || + avoidClasses(clWater, 0).allows(Vector2D.sub(bridgeCenter2, bridgeP))) + continue; - break; - } + ++bridges; - if (bridges >= maxBridges) - break; -} + // This bridge model is not centered on the horizontal plane, so the angle is messy + // TILE_CENTERED_HEIGHT_MAP also influences the outcome of the placement. + const bridgeOrientation = direction % 2 ? 0 : Math.PI / 2; + bridgeCenter1[direction % 2 ? "y" : "x"] += 0.25; + bridgeCenter2[direction % 2 ? "y" : "x"] -= 0.25; -g_Map.log("Creating smoke"); -if (areasVolcano.length) -{ - createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(aSmokeBig, 1, 1, 0, 4)], false), - 0, - stayClasses(clVolcano, 6), - scaleByMapSize(4, 12), - 20, - areasVolcano); + g_Map.placeEntityAnywhere(aBridge, 0, bridgeCenter1, bridgeOrientation); + g_Map.placeEntityAnywhere(aBridge, 0, bridgeCenter2, bridgeOrientation + Math.PI); - createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(aSmokeSmall, 2, 2, 0, 4)], false), - 0, - stayClasses(clVolcano, 4), - scaleByMapSize(4, 12), - 20, - areasVolcano); -} -Engine.SetProgress(90); + createArea( + new RectPlacer(Vector2D.sub(bridgeStart, areaOffset), + Vector2D.add(bridgeEnd1, areaOffset)), + [ + new ElevationPainter(heightBridge), + new TileClassPainter(clBridge) + ]); + + for (const center of [bridgeStart, bridgeEnd2]) + createArea( + new DiskPlacer(2, center), + new SmoothingPainter(1, 1, 1)); + + break; + } + + if (bridges >= maxBridges) + break; + } + + g_Map.log("Creating smoke"); + if (areasVolcano.length) + { + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(aSmokeBig, 1, 1, 0, 4)], false), + 0, + stayClasses(clVolcano, 6), + scaleByMapSize(4, 12), + 20, + areasVolcano); + + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(aSmokeSmall, 2, 2, 0, 4)], false), + 0, + stayClasses(clVolcano, 4), + scaleByMapSize(4, 12), + 20, + areasVolcano); + } + yield 90; -setSkySet("cumulus"); -setSunColor(0.87, 0.78, 0.49); -setWaterColor(0, 0.501961, 1); -setWaterTint(0.5, 1, 1); -setWaterWaviness(4.0); -setWaterType("ocean"); -setWaterMurkiness(0.49); + setSkySet("cumulus"); + setSunColor(0.87, 0.78, 0.49); + setWaterColor(0, 0.501961, 1); + setWaterTint(0.5, 1, 1); + setWaterWaviness(4.0); + setWaterType("ocean"); + setWaterMurkiness(0.49); -setFogFactor(0.3); -setFogThickness(0.25); + setFogFactor(0.3); + setFogThickness(0.25); -setPPEffect("hdr"); -setPPContrast(0.62); -setPPSaturation(0.51); -setPPBloom(0.12); + setPPEffect("hdr"); + setPPContrast(0.62); + setPPSaturation(0.51); + setPPBloom(0.12); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/elephantine.js =================================================================== --- binaries/data/mods/public/maps/random/elephantine.js +++ binaries/data/mods/public/maps/random/elephantine.js @@ -20,581 +20,603 @@ TILE_CENTERED_HEIGHT_MAP = true; -const tPrimary = ["savanna_dirt_rocks_a_red", "savanna_dirt_a_red", "savanna_dirt_b_red"]; -const tDirt = ["new_savanna_dirt_c", "new_savanna_dirt_d", "savanna_dirt_b_red", "savanna_dirt_plants_cracked"]; -const tWater = "desert_sand_wet"; -const tRoad = "savanna_tile_a_red"; -const tRoadIsland = "savanna_tile_a"; -const tRoadWildIsland = "savanna_dirt_rocks_a"; -const tGrass = ["savanna_shrubs_a_wetseason", "alpine_grass_b_wild", "medit_shrubs_a", "steppe_grass_green_a"]; -const tForestFloorLand = "savanna_forestfloor_b_red"; -const tForestFloorIsland = pickRandom(tGrass); - -const oAcacia = "gaia/tree/acacia"; -const oPalms = [ - "gaia/tree/cretan_date_palm_tall", - "gaia/tree/cretan_date_palm_short", - "gaia/tree/palm_tropic", - "gaia/tree/date_palm", - "gaia/tree/senegal_date_palm", - "gaia/tree/medit_fan_palm" -]; -const oStoneLarge = "gaia/rock/savanna_large"; -const oStoneSmall = "gaia/rock/desert_small"; -const oMetalLarge = "gaia/ore/savanna_large"; -const oMetalSmall = "gaia/ore/desert_small"; - -const oTreasure = [ - "gaia/treasure/food_barrel", - "gaia/treasure/food_bin", - "gaia/treasure/wood", - "gaia/treasure/metal", - "gaia/treasure/stone" -]; -const oBerryBush = "gaia/fruit/berry_05"; -const oGazelle = "gaia/fauna_gazelle"; -const oRhino = "gaia/fauna_rhinoceros_white"; -const oWarthog = "gaia/fauna_boar"; -const oGiraffe = "gaia/fauna_giraffe"; -const oGiraffeInfant = "gaia/fauna_giraffe_infant"; -const oElephant = "gaia/fauna_elephant_african_bush"; -const oElephantInfant = "gaia/fauna_elephant_african_infant"; -const oLion = "gaia/fauna_lion"; -const oLioness = "gaia/fauna_lioness"; -const oCrocodile = "gaia/fauna_crocodile_nile"; -const oFish = "gaia/fish/tilapia"; -const oHawk = "birds/buzzard"; - -// The main temple on elephantine was very similar looking (Greco-Roman-Egyptian): -const oWonder = "structures/ptol/wonder"; -const oTemples = ["structures/kush/temple_amun", "structures/kush/temple"]; -const oPyramid = "structures/kush/pyramid_large"; -const oTowers = new Array(2).fill("uncapturable|structures/kush/sentry_tower").concat(["uncapturable|structures/kush/defense_tower"]); - -const oHeroes = Engine.FindTemplates("units/kush/", true).filter(templateName => templateName.startsWith("units/kush/hero_")); -const oUnits = Engine.FindTemplates("units/kush/", false).filter(templateName => - templateName.startsWith("units/kush/") && - oHeroes.every(heroTemplateName => heroTemplateName != templateName) && - Engine.GetTemplate(templateName).Identity.VisibleClasses._string.split(" ").some(type => ["Soldier", "Healer", "Female"].indexOf(type) != -1)); - -const aRock = actorTemplate("geology/stone_savanna_med"); - -const aStatues = [ - "props/structures/kushites/statue_bird", - "props/structures/kushites/statue_lion", - "props/structures/kushites/statue_ram" -].map(actorTemplate); - -const aBushesShoreline = [ - ...new Array(4).fill("props/flora/ferns"), - "props/flora/bush", - "props/flora/bush_medit_la", - "props/flora/bush_medit_la_lush", - "props/flora/bush_medit_me_lush", - "props/flora/bush_medit_sm", - "props/flora/bush_medit_sm_lush", - "props/flora/bush_tempe_la_lush" -].map(actorTemplate); - -const aBushesIslands = aBushesShoreline.concat(new Array(3).fill(actorTemplate("props/flora/foliagebush"))); - -const aBushesDesert = [ - "props/flora/bush_dry_a", - "props/flora/bush_medit_la_dry", - "props/flora/bush_medit_me_dry", - "props/flora/bush_medit_sm", - "props/flora/bush_medit_sm_dry", - "props/flora/bush_tempe_me_dry", - "props/flora/grass_soft_dry_large_tall", - "props/flora/grass_soft_dry_small_tall" -].map(actorTemplate); - -const pForestPalmsLand = [ - tForestFloorLand, - ...oPalms.map(tree => tForestFloorLand + TERRAIN_SEPARATOR + tree), - tForestFloorLand]; - -const pForest2Land = [ - tForestFloorLand, - tForestFloorLand + TERRAIN_SEPARATOR + oAcacia, - tForestFloorLand -]; - -const pForestPalmsIsland = [ - tForestFloorIsland, - ...oPalms.map(tree => tForestFloorIsland + TERRAIN_SEPARATOR + tree), - tForestFloorIsland]; - -const pForest2Island = [ - tForestFloorIsland, - tForestFloorIsland + TERRAIN_SEPARATOR + oAcacia, - tForestFloorIsland -]; - -const heightSeaGround = -6; -const heightWaterLevel = 0; -const heightShore = 0.5; -const heightOffsetPath = -g_MapSettings.Size / 80; -const minHeight = -1; -const maxHeight = 2; - -const g_Map = new RandomMap(0, tPrimary); -const mapBounds = g_Map.getBounds(); -const mapCenter = g_Map.getCenter(); - -const clWater = g_Map.createTileClass(); -const clIsland = g_Map.createTileClass(); -const clCliff = g_Map.createTileClass(); -const clPlayer = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clTemple = g_Map.createTileClass(); -const clTower = g_Map.createTileClass(); -const clStatue = g_Map.createTileClass(); -const clSoldier = g_Map.createTileClass(); -const clTreasure = g_Map.createTileClass(); -const clPath = g_Map.createTileClass(); - -const riverAngle = 0.22 * Math.PI; -const riverWidthBorder = fractionToTiles(0.27); -const riverWidthCenter = fractionToTiles(0.35); - -const avoidCollisions = avoidClasses( - clPlayer, 15, clWater, 1, clForest, 1, clRock, 4, clMetal, 4, clFood, 6, clPath, 1, - clTemple, 11, clCliff, 0, clStatue, 2, clSoldier, 3, clTower, 2, clTreasure, 1); - -g_Map.LoadHeightmapImage("elephantine.png", minHeight, maxHeight); -Engine.SetProgress(3); - -g_Map.log("Lowering sea ground"); -createArea( - new MapBoundsPlacer(), - [ - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), - new TileClassPainter(clWater) - ], - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(6); - -g_Map.log("Smoothing heightmap"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, scaleByMapSize(0.1, 0.5), 1)); -Engine.SetProgress(10); - -g_Map.log("Marking islands"); -const areaIsland = createArea( - new ConvexPolygonPlacer( +function* GenerateMap(mapSettings) +{ + const tPrimary = ["savanna_dirt_rocks_a_red", "savanna_dirt_a_red", "savanna_dirt_b_red"]; + const tDirt = ["new_savanna_dirt_c", "new_savanna_dirt_d", "savanna_dirt_b_red", + "savanna_dirt_plants_cracked"]; + const tWater = "desert_sand_wet"; + const tRoad = "savanna_tile_a_red"; + const tRoadIsland = "savanna_tile_a"; + const tRoadWildIsland = "savanna_dirt_rocks_a"; + const tGrass = ["savanna_shrubs_a_wetseason", "alpine_grass_b_wild", "medit_shrubs_a", + "steppe_grass_green_a"]; + const tForestFloorLand = "savanna_forestfloor_b_red"; + const tForestFloorIsland = pickRandom(tGrass); + + const oAcacia = "gaia/tree/acacia"; + const oPalms = [ + "gaia/tree/cretan_date_palm_tall", + "gaia/tree/cretan_date_palm_short", + "gaia/tree/palm_tropic", + "gaia/tree/date_palm", + "gaia/tree/senegal_date_palm", + "gaia/tree/medit_fan_palm" + ]; + const oStoneLarge = "gaia/rock/savanna_large"; + const oStoneSmall = "gaia/rock/desert_small"; + const oMetalLarge = "gaia/ore/savanna_large"; + const oMetalSmall = "gaia/ore/desert_small"; + + const oTreasure = [ + "gaia/treasure/food_barrel", + "gaia/treasure/food_bin", + "gaia/treasure/wood", + "gaia/treasure/metal", + "gaia/treasure/stone" + ]; + const oBerryBush = "gaia/fruit/berry_05"; + const oGazelle = "gaia/fauna_gazelle"; + const oRhino = "gaia/fauna_rhinoceros_white"; + const oWarthog = "gaia/fauna_boar"; + const oGiraffe = "gaia/fauna_giraffe"; + const oGiraffeInfant = "gaia/fauna_giraffe_infant"; + const oElephant = "gaia/fauna_elephant_african_bush"; + const oElephantInfant = "gaia/fauna_elephant_african_infant"; + const oLion = "gaia/fauna_lion"; + const oLioness = "gaia/fauna_lioness"; + const oCrocodile = "gaia/fauna_crocodile_nile"; + const oFish = "gaia/fish/tilapia"; + const oHawk = "birds/buzzard"; + + // The main temple on elephantine was very similar looking (Greco-Roman-Egyptian): + const oWonder = "structures/ptol/wonder"; + const oTemples = ["structures/kush/temple_amun", "structures/kush/temple"]; + const oPyramid = "structures/kush/pyramid_large"; + const oTowers = new Array(2).fill("uncapturable|structures/kush/sentry_tower").concat( + ["uncapturable|structures/kush/defense_tower"]); + + const oHeroes = Engine.FindTemplates("units/kush/", true).filter( + templateName => templateName.startsWith("units/kush/hero_")); + const oUnits = Engine.FindTemplates("units/kush/", false).filter(templateName => + templateName.startsWith("units/kush/") && + oHeroes.every(heroTemplateName => heroTemplateName != templateName) && + Engine.GetTemplate(templateName).Identity.VisibleClasses._string.split(" ").some( + type => ["Soldier", "Healer", "Female"].indexOf(type) != -1)); + + const aRock = actorTemplate("geology/stone_savanna_med"); + + const aStatues = [ + "props/structures/kushites/statue_bird", + "props/structures/kushites/statue_lion", + "props/structures/kushites/statue_ram" + ].map(actorTemplate); + + const aBushesShoreline = [ + ...new Array(4).fill("props/flora/ferns"), + "props/flora/bush", + "props/flora/bush_medit_la", + "props/flora/bush_medit_la_lush", + "props/flora/bush_medit_me_lush", + "props/flora/bush_medit_sm", + "props/flora/bush_medit_sm_lush", + "props/flora/bush_tempe_la_lush" + ].map(actorTemplate); + + const aBushesIslands = aBushesShoreline.concat( + new Array(3).fill(actorTemplate("props/flora/foliagebush"))); + + const aBushesDesert = [ + "props/flora/bush_dry_a", + "props/flora/bush_medit_la_dry", + "props/flora/bush_medit_me_dry", + "props/flora/bush_medit_sm", + "props/flora/bush_medit_sm_dry", + "props/flora/bush_tempe_me_dry", + "props/flora/grass_soft_dry_large_tall", + "props/flora/grass_soft_dry_small_tall" + ].map(actorTemplate); + + const pForestPalmsLand = [ + tForestFloorLand, + ...oPalms.map(tree => tForestFloorLand + TERRAIN_SEPARATOR + tree), + tForestFloorLand]; + + const pForest2Land = [ + tForestFloorLand, + tForestFloorLand + TERRAIN_SEPARATOR + oAcacia, + tForestFloorLand + ]; + + const pForestPalmsIsland = [ + tForestFloorIsland, + ...oPalms.map(tree => tForestFloorIsland + TERRAIN_SEPARATOR + tree), + tForestFloorIsland]; + + const pForest2Island = [ + tForestFloorIsland, + tForestFloorIsland + TERRAIN_SEPARATOR + oAcacia, + tForestFloorIsland + ]; + + const heightSeaGround = -6; + const heightWaterLevel = 0; + const heightShore = 0.5; + const heightOffsetPath = -mapSettings.Size / 80; + const minHeight = -1; + const maxHeight = 2; + + global.g_Map = new RandomMap(0, tPrimary); + const mapBounds = g_Map.getBounds(); + const mapCenter = g_Map.getCenter(); + + const clWater = g_Map.createTileClass(); + const clIsland = g_Map.createTileClass(); + const clCliff = g_Map.createTileClass(); + const clPlayer = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clTemple = g_Map.createTileClass(); + const clTower = g_Map.createTileClass(); + const clStatue = g_Map.createTileClass(); + const clSoldier = g_Map.createTileClass(); + const clTreasure = g_Map.createTileClass(); + const clPath = g_Map.createTileClass(); + + const riverAngle = 0.22 * Math.PI; + const riverWidthBorder = fractionToTiles(0.27); + const riverWidthCenter = fractionToTiles(0.35); + + const avoidCollisions = avoidClasses( + clPlayer, 15, clWater, 1, clForest, 1, clRock, 4, clMetal, 4, clFood, 6, clPath, 1, + clTemple, 11, clCliff, 0, clStatue, 2, clSoldier, 3, clTower, 2, clTreasure, 1); + + g_Map.LoadHeightmapImage("elephantine.png", minHeight, maxHeight); + Engine.SetProgress(3); + + g_Map.log("Lowering sea ground"); + createArea( + new MapBoundsPlacer(), [ - new Vector2D(mapCenter.x - riverWidthBorder / 2, mapBounds.top), - new Vector2D(mapCenter.x - riverWidthBorder / 2, mapBounds.bottom), - new Vector2D(mapCenter.x - riverWidthCenter / 2, mapCenter.y), - new Vector2D(mapCenter.x + riverWidthCenter / 2, mapCenter.y), - new Vector2D(mapCenter.x + riverWidthBorder / 2, mapBounds.top), - new Vector2D(mapCenter.x + riverWidthBorder / 2, mapBounds.bottom) - ].map(v => v.rotateAround(riverAngle, mapCenter)), - Infinity), - new TileClassPainter(clIsland), - avoidClasses(clPlayer, 0, clWater, 0)); -Engine.SetProgress(13); - -g_Map.log("Painting islands"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(tGrass), - stayClasses(clIsland, 0)); -Engine.SetProgress(16); - -g_Map.log("Painting water and shoreline"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(tWater), - new HeightConstraint(-Infinity, heightShore)); -Engine.SetProgress(19); - -placePlayerBases({ - "PlayerPlacement": playerPlacementRiver(riverAngle, fractionToTiles(0.62)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": avoidClasses(clWater, 4), - "Walls": "towers", - "CityPatch": { - "outerTerrain": tRoad, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oAcacia, - "count": 2 - }, - "Decoratives": { - "template": pickRandom(aBushesDesert) - } -}); -Engine.SetProgress(22); - -g_Map.log("Creating temple"); -const groupTemple = createObjectGroupsByAreas( - new SimpleGroup([new RandomObject(g_Map.getSize() >= 320 ? [oWonder] : oTemples, 1, 1, 0, 1, riverAngle, riverAngle)], true, clTemple), - 0, - stayClasses(clIsland, scaleByMapSize(10, 20)), - 1, - 200, - [areaIsland]); -Engine.SetProgress(34); - -g_Map.log("Creating pyramid"); -const groupPyramid = createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oPyramid, 1, 1, 0, 1, riverAngle, riverAngle)], true, clTemple), - 0, - [stayClasses(clIsland, scaleByMapSize(10, 20)), avoidClasses(clTemple, scaleByMapSize(20, 50)), avoidCollisions], - 1, - 200, - [areaIsland]); -Engine.SetProgress(37); - -g_Map.log("Painting city patches"); -const cityCenters = [ - groupTemple[0] && groupTemple[0][0] && { "pos": Vector2D.from3D(groupTemple[0][0].position), "radius": 10 }, - groupPyramid[0] && groupPyramid[0][0] && { "pos": Vector2D.from3D(groupPyramid[0][0].position), "radius": 6 },].filter(pos => !!pos); - -const areaCityPatch = cityCenters.map(cityCenter => + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), + new TileClassPainter(clWater) + ], + new HeightConstraint(-Infinity, heightWaterLevel)); + Engine.SetProgress(6); + + g_Map.log("Smoothing heightmap"); createArea( - new DiskPlacer(cityCenter.radius, cityCenter.pos), - new LayeredPainter([tRoadWildIsland, tRoadIsland], [2]), - stayClasses(clIsland, 2))); -Engine.SetProgress(40); + new MapBoundsPlacer(), + new SmoothingPainter(1, scaleByMapSize(0.1, 0.5), 1)); + Engine.SetProgress(10); -g_Map.log("Painting city path"); -if (cityCenters.length == 2) + g_Map.log("Marking islands"); + const areaIsland = createArea( + new ConvexPolygonPlacer( + [ + new Vector2D(mapCenter.x - riverWidthBorder / 2, mapBounds.top), + new Vector2D(mapCenter.x - riverWidthBorder / 2, mapBounds.bottom), + new Vector2D(mapCenter.x - riverWidthCenter / 2, mapCenter.y), + new Vector2D(mapCenter.x + riverWidthCenter / 2, mapCenter.y), + new Vector2D(mapCenter.x + riverWidthBorder / 2, mapBounds.top), + new Vector2D(mapCenter.x + riverWidthBorder / 2, mapBounds.bottom) + ].map(v => v.rotateAround(riverAngle, mapCenter)), + Infinity), + new TileClassPainter(clIsland), + avoidClasses(clPlayer, 0, clWater, 0)); + Engine.SetProgress(13); + + g_Map.log("Painting islands"); createArea( - new PathPlacer(cityCenters[0].pos, cityCenters[1].pos, 4, 0.3, 4, 0.2, 0.05), + new MapBoundsPlacer(), + new TerrainPainter(tGrass), + stayClasses(clIsland, 0)); + Engine.SetProgress(16); + + g_Map.log("Painting water and shoreline"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(tWater), + new HeightConstraint(-Infinity, heightShore)); + Engine.SetProgress(19); + + placePlayerBases({ + "PlayerPlacement": playerPlacementRiver(riverAngle, fractionToTiles(0.62)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": avoidClasses(clWater, 4), + "Walls": "towers", + "CityPatch": { + "outerTerrain": tRoad, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oAcacia, + "count": 2 + }, + "Decoratives": { + "template": pickRandom(aBushesDesert) + } + }); + Engine.SetProgress(22); + + g_Map.log("Creating temple"); + const groupTemple = createObjectGroupsByAreas( + new SimpleGroup([new RandomObject(g_Map.getSize() >= 320 ? [oWonder] : oTemples, 1, 1, 0, 1, + riverAngle, riverAngle)], true, clTemple), + 0, + stayClasses(clIsland, scaleByMapSize(10, 20)), + 1, + 200, + [areaIsland]); + Engine.SetProgress(34); + + g_Map.log("Creating pyramid"); + const groupPyramid = createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oPyramid, 1, 1, 0, 1, riverAngle, riverAngle)], true, + clTemple), + 0, + [stayClasses(clIsland, scaleByMapSize(10, 20)), avoidClasses(clTemple, scaleByMapSize(20, 50)), + avoidCollisions], + 1, + 200, + [areaIsland]); + Engine.SetProgress(37); + + g_Map.log("Painting city patches"); + const cityCenters = [ + groupTemple[0] && groupTemple[0][0] && + { "pos": Vector2D.from3D(groupTemple[0][0].position), "radius": 10 }, + groupPyramid[0] && groupPyramid[0][0] && + { "pos": Vector2D.from3D(groupPyramid[0][0].position), "radius": 6 },] + .filter(pos => !!pos); + + const areaCityPatch = cityCenters.map(cityCenter => + createArea( + new DiskPlacer(cityCenter.radius, cityCenter.pos), + new LayeredPainter([tRoadWildIsland, tRoadIsland], [2]), + stayClasses(clIsland, 2))); + Engine.SetProgress(40); + + g_Map.log("Painting city path"); + if (cityCenters.length == 2) + createArea( + new PathPlacer(cityCenters[0].pos, cityCenters[1].pos, 4, 0.3, 4, 0.2, 0.05), + [ + new LayeredPainter([tRoadWildIsland, tRoadIsland], [1]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetPath, 4), + new TileClassPainter(clPath) + ]); + Engine.SetProgress(42); + + createBumps(avoidClasses(clPlayer, 10, clWater, 2, clTemple, 10, clPath, 1), + scaleByMapSize(10, 500), 1, 8, 4, 0.2, 3); + Engine.SetProgress(43); + + g_Map.log("Marking cliffs"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(clCliff), [ - new LayeredPainter([tRoadWildIsland, tRoadIsland], [1]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetPath, 4), - new TileClassPainter(clPath) + avoidClasses(clWater, 2), + new SlopeConstraint(2, Infinity) ]); -Engine.SetProgress(42); - -createBumps(avoidClasses(clPlayer, 10, clWater, 2, clTemple, 10, clPath, 1), scaleByMapSize(10, 500), 1, 8, 4, 0.2, 3); -Engine.SetProgress(43); - -g_Map.log("Marking cliffs"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(clCliff), - [ - avoidClasses(clWater, 2), - new SlopeConstraint(2, Infinity) - ]); -Engine.SetProgress(44); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2, 5, 1, 3, 0, 2 * Math.PI, 1)] - ], - avoidClasses(clWater, 4, clCliff, 4, clPlayer, 20, clRock, 10, clPath, 1), - clRock, - scaleByMapSize(6, 24)); -Engine.SetProgress(45); - -g_Map.log("Creating metal mines"); -createMines( - [ - [new SimpleObject(oMetalSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oMetalLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oMetalSmall, 2, 5, 1, 3, 0, 2 * Math.PI, 1)] - ], - avoidClasses(clWater, 4, clCliff, 4, clPlayer, 20, clMetal, 10, clRock, 5, clPath, 1), - clMetal, - scaleByMapSize(6, 24)); -Engine.SetProgress(46); - -g_Map.log("Creating kushite towers"); -createObjectGroups( - new SimpleGroup([new RandomObject(oTowers, 1, 1, 0, 1)], true, clTower), - 0, - [ - stayClasses(clIsland, scaleByMapSize(4, 8)), - new NearTileClassConstraint(clTemple, 25), - avoidClasses(clTower, 12, clPlayer, 30), - avoidCollisions - ], - scaleByMapSize(4, 12), - 200); -Engine.SetProgress(49); - -const [forestTrees, stragglerTrees] = getTreeCounts(400, 3000, 0.7); -createForests( - [tForestFloorLand, tForestFloorLand, tForestFloorLand, pForestPalmsLand, pForest2Land], - [avoidCollisions, avoidClasses(clIsland, 0, clPlayer, 20, clForest, 18, clWater, 2)], - clForest, - forestTrees / 2); -Engine.SetProgress(52); - -createForests( - [tForestFloorIsland, tForestFloorIsland, tForestFloorIsland, pForestPalmsIsland, pForest2Island], - [stayClasses(clIsland, 0), avoidClasses(clForest, 15, clWater, 2), avoidCollisions], - clForest, - forestTrees / 2); -Engine.SetProgress(55); - -g_Map.log("Creating dirt patches"); -createPatches( - [scaleByMapSize(5, 15)], - tDirt, - avoidClasses(clWater, 0, clIsland, 0, clForest, 0, clDirt, 5, clPlayer, 12), - scaleByMapSize(5, 30), - clDirt); -Engine.SetProgress(58); - -g_Map.log("Creating statues"); -createObjectGroupsByAreas( - new SimpleGroup([new RandomObject(aStatues, 1, 1, 0, 1)], true, clStatue), - 0, - [ - stayClasses(clIsland, scaleByMapSize(8, 24)), - new NearTileClassConstraint(clTemple, 10), - avoidCollisions - ], - scaleByMapSize(2, 10), - 400, - [areaIsland]); -Engine.SetProgress(61); - -g_Map.log("Creating treasure"); -createObjectGroupsByAreas( - new SimpleGroup([new RandomObject(oTreasure, 1, 2, 0, 1)], true, clTreasure), - 0, - avoidCollisions, - scaleByMapSize(4, 10), - 100, - areaCityPatch); -Engine.SetProgress(62); - -g_Map.log("Creating hero"); -createObjectGroups( - new SimpleGroup([new RandomObject(oHeroes, 1, 1, 0, 1)], true, clSoldier), - 0, - [ - stayClasses(clIsland, scaleByMapSize(2, 24)), - new NearTileClassConstraint(clTemple, 14), - avoidCollisions - ], - 1, - 500); -Engine.SetProgress(64); - -g_Map.log("Creating soldiers"); -createObjectGroups( - new SimpleGroup([new RandomObject(oUnits, 1, 1, 0, 1)], true, clSoldier), - 0, - [ - new StaticConstraint( - [ - stayClasses(clIsland, scaleByMapSize(2, 24)), - new NearTileClassConstraint(clTemple, 20) - ]), - avoidCollisions - ], - scaleByMapSize(12, 60), - 200); -Engine.SetProgress(67); - -g_Map.log("Creating berries"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oBerryBush, 3, 5, 1, 2)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(4, 12), - 250); -Engine.SetProgress(70); - -g_Map.log("Creating rhinos"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oRhino, 1, 1, 0, 1)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(2, 10), - 50); -Engine.SetProgress(73); - -g_Map.log("Creating warthog"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oWarthog, 1, 1, 0, 1)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(2, 10), - 50); -Engine.SetProgress(77); - -g_Map.log("Creating gazelles"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oGazelle, 5, 7, 2, 4)], true, clFood), - 0, - [avoidClasses(clIsland, 1), avoidCollisions], - scaleByMapSize(2, 10), - 50); -Engine.SetProgress(80); - -g_Map.log("Creating giraffes"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oGiraffe, 2, 3, 2, 4), new SimpleObject(oGiraffeInfant, 2, 3, 2, 4)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(2, 10), - 50); -Engine.SetProgress(83); - -if (!isNomad()) -{ - g_Map.log("Creating lions"); + Engine.SetProgress(44); + + g_Map.log("Creating stone mines"); + createMines( + [ + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oStoneSmall, 2, 5, 1, 3, 0, 2 * Math.PI, 1)] + ], + avoidClasses(clWater, 4, clCliff, 4, clPlayer, 20, clRock, 10, clPath, 1), + clRock, + scaleByMapSize(6, 24)); + Engine.SetProgress(45); + + g_Map.log("Creating metal mines"); + createMines( + [ + [new SimpleObject(oMetalSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oMetalLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oMetalSmall, 2, 5, 1, 3, 0, 2 * Math.PI, 1)] + ], + avoidClasses(clWater, 4, clCliff, 4, clPlayer, 20, clMetal, 10, clRock, 5, clPath, 1), + clMetal, + scaleByMapSize(6, 24)); + Engine.SetProgress(46); + + g_Map.log("Creating kushite towers"); createObjectGroups( - new SimpleGroup([new SimpleObject(oLion, 1, 2, 2, 4), new SimpleObject(oLioness, 2, 3, 2, 4)], true, clFood), + new SimpleGroup([new RandomObject(oTowers, 1, 1, 0, 1)], true, clTower), + 0, + [ + stayClasses(clIsland, scaleByMapSize(4, 8)), + new NearTileClassConstraint(clTemple, 25), + avoidClasses(clTower, 12, clPlayer, 30), + avoidCollisions + ], + scaleByMapSize(4, 12), + 200); + Engine.SetProgress(49); + + const [forestTrees, stragglerTrees] = getTreeCounts(400, 3000, 0.7); + createForests( + [tForestFloorLand, tForestFloorLand, tForestFloorLand, pForestPalmsLand, pForest2Land], + [avoidCollisions, avoidClasses(clIsland, 0, clPlayer, 20, clForest, 18, clWater, 2)], + clForest, + forestTrees / 2); + Engine.SetProgress(52); + + createForests( + [tForestFloorIsland, tForestFloorIsland, tForestFloorIsland, pForestPalmsIsland, + pForest2Island], + [stayClasses(clIsland, 0), avoidClasses(clForest, 15, clWater, 2), avoidCollisions], + clForest, + forestTrees / 2); + Engine.SetProgress(55); + + g_Map.log("Creating dirt patches"); + createPatches( + [scaleByMapSize(5, 15)], + tDirt, + avoidClasses(clWater, 0, clIsland, 0, clForest, 0, clDirt, 5, clPlayer, 12), + scaleByMapSize(5, 30), + clDirt); + Engine.SetProgress(58); + + g_Map.log("Creating statues"); + createObjectGroupsByAreas( + new SimpleGroup([new RandomObject(aStatues, 1, 1, 0, 1)], true, clStatue), + 0, + [ + stayClasses(clIsland, scaleByMapSize(8, 24)), + new NearTileClassConstraint(clTemple, 10), + avoidCollisions + ], + scaleByMapSize(2, 10), + 400, + [areaIsland]); + Engine.SetProgress(61); + + g_Map.log("Creating treasure"); + createObjectGroupsByAreas( + new SimpleGroup([new RandomObject(oTreasure, 1, 2, 0, 1)], true, clTreasure), + 0, + avoidCollisions, + scaleByMapSize(4, 10), + 100, + areaCityPatch); + Engine.SetProgress(62); + + g_Map.log("Creating hero"); + createObjectGroups( + new SimpleGroup([new RandomObject(oHeroes, 1, 1, 0, 1)], true, clSoldier), + 0, + [ + stayClasses(clIsland, scaleByMapSize(2, 24)), + new NearTileClassConstraint(clTemple, 14), + avoidCollisions + ], + 1, + 500); + Engine.SetProgress(64); + + g_Map.log("Creating soldiers"); + createObjectGroups( + new SimpleGroup([new RandomObject(oUnits, 1, 1, 0, 1)], true, clSoldier), + 0, + [ + new StaticConstraint( + [ + stayClasses(clIsland, scaleByMapSize(2, 24)), + new NearTileClassConstraint(clTemple, 20) + ]), + avoidCollisions + ], + scaleByMapSize(12, 60), + 200); + Engine.SetProgress(67); + + g_Map.log("Creating berries"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oBerryBush, 3, 5, 1, 2)], true, clFood), + 0, + avoidCollisions, + scaleByMapSize(4, 12), + 250); + Engine.SetProgress(70); + + g_Map.log("Creating rhinos"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oRhino, 1, 1, 0, 1)], true, clFood), 0, avoidCollisions, scaleByMapSize(2, 10), 50); - Engine.SetProgress(87); -} + Engine.SetProgress(73); -g_Map.log("Creating elephants"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oElephant, 2, 3, 2, 4), new SimpleObject(oElephantInfant, 2, 3, 2, 4)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(2, 10), - 50); -Engine.SetProgress(88); - -g_Map.log("Creating crocodiles"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oCrocodile, 2, 3, 3, 5)], true, clFood), - 0, - [ - new NearTileClassConstraint(clWater, 3), - avoidCollisions - ], - scaleByMapSize(2, 10), - 50); -Engine.SetProgress(89); - -g_Map.log("Creating hawk"); -for (let i = 0; i < scaleByMapSize(0, 2); ++i) - g_Map.placeEntityAnywhere(oHawk, 0, mapCenter, randomAngle()); -Engine.SetProgress(90); - -g_Map.log("Creating fish"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oFish, 1, 2, 0, 1)], true, clFood), - 0, - [stayClasses(clWater, 8), avoidClasses(clFood, 16)], - scaleByMapSize(15, 80), - 50); -Engine.SetProgress(91); - -createStragglerTrees( - [oAcacia], - avoidCollisions, - clForest, - stragglerTrees); -Engine.SetProgress(93); - -placePlayersNomad(clPlayer, [avoidCollisions, avoidClasses(clIsland, 0)]); -Engine.SetProgress(95); - -createDecoration( - aBushesDesert.map(bush => [new SimpleObject(bush, 0, 3, 2, 4)]), - aBushesDesert.map(bush => scaleByMapSize(20, 150) * randIntInclusive(1, 3)), - [avoidClasses(clIsland, 0), avoidCollisions]); -Engine.SetProgress(96); - -createDecoration( - aBushesIslands.map(bush => [new SimpleObject(bush, 0, 4, 2, 4)]), - aBushesIslands.map(bush => scaleByMapSize(20, 150) * randIntInclusive(1, 3)), - [stayClasses(clIsland, 0), avoidCollisions]); -Engine.SetProgress(97); - -createDecoration( - [[new SimpleObject(aRock, 0, 4, 2, 4)]], - [[scaleByMapSize(80, 500)]], - [avoidClasses(clIsland, 0), avoidCollisions]); -Engine.SetProgress(98); - -createDecoration( - aBushesShoreline.map(bush => [new SimpleObject(bush, 0, 3, 2, 4)]), - aBushesShoreline.map(bush => scaleByMapSize(200, 1000)), - [new HeightConstraint(heightWaterLevel, heightShore), avoidCollisions]); -Engine.SetProgress(99); - -g_Environment = { - "SkySet": "cloudless", - "SunColor": { - "r": 1, - "g": 0.964706, - "b": 0.909804, - "a": 0 - }, - "SunElevation": 0.908117, - "SunRotation": -0.558369, - "AmbientColor": { - "r": 0.54902, - "g": 0.419608, - "b": 0.352941, - "a": 0 - }, - "Fog": { - "FogFactor": 0.00195313, - "FogThickness": 0, - "FogColor": { - "r": 0.941176, - "g": 0.917647, - "b": 0.807843, + g_Map.log("Creating warthog"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oWarthog, 1, 1, 0, 1)], true, clFood), + 0, + avoidCollisions, + scaleByMapSize(2, 10), + 50); + Engine.SetProgress(77); + + g_Map.log("Creating gazelles"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oGazelle, 5, 7, 2, 4)], true, clFood), + 0, + [avoidClasses(clIsland, 1), avoidCollisions], + scaleByMapSize(2, 10), + 50); + Engine.SetProgress(80); + + g_Map.log("Creating giraffes"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oGiraffe, 2, 3, 2, 4), + new SimpleObject(oGiraffeInfant, 2, 3, 2, 4)], true, clFood), + 0, + avoidCollisions, + scaleByMapSize(2, 10), + 50); + Engine.SetProgress(83); + + if (!isNomad()) + { + g_Map.log("Creating lions"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oLion, 1, 2, 2, 4), + new SimpleObject(oLioness, 2, 3, 2, 4)], true, clFood), + 0, + avoidCollisions, + scaleByMapSize(2, 10), + 50); + Engine.SetProgress(87); + } + + g_Map.log("Creating elephants"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oElephant, 2, 3, 2, 4), + new SimpleObject(oElephantInfant, 2, 3, 2, 4)], true, clFood), + 0, + avoidCollisions, + scaleByMapSize(2, 10), + 50); + Engine.SetProgress(88); + + g_Map.log("Creating crocodiles"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oCrocodile, 2, 3, 3, 5)], true, clFood), + 0, + [ + new NearTileClassConstraint(clWater, 3), + avoidCollisions + ], + scaleByMapSize(2, 10), + 50); + Engine.SetProgress(89); + + g_Map.log("Creating hawk"); + for (let i = 0; i < scaleByMapSize(0, 2); ++i) + g_Map.placeEntityAnywhere(oHawk, 0, mapCenter, randomAngle()); + Engine.SetProgress(90); + + g_Map.log("Creating fish"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oFish, 1, 2, 0, 1)], true, clFood), + 0, + [stayClasses(clWater, 8), avoidClasses(clFood, 16)], + scaleByMapSize(15, 80), + 50); + Engine.SetProgress(91); + + createStragglerTrees( + [oAcacia], + avoidCollisions, + clForest, + stragglerTrees); + Engine.SetProgress(93); + + placePlayersNomad(clPlayer, [avoidCollisions, avoidClasses(clIsland, 0)]); + Engine.SetProgress(95); + + createDecoration( + aBushesDesert.map(bush => [new SimpleObject(bush, 0, 3, 2, 4)]), + aBushesDesert.map(bush => scaleByMapSize(20, 150) * randIntInclusive(1, 3)), + [avoidClasses(clIsland, 0), avoidCollisions]); + Engine.SetProgress(96); + + createDecoration( + aBushesIslands.map(bush => [new SimpleObject(bush, 0, 4, 2, 4)]), + aBushesIslands.map(bush => scaleByMapSize(20, 150) * randIntInclusive(1, 3)), + [stayClasses(clIsland, 0), avoidCollisions]); + Engine.SetProgress(97); + + createDecoration( + [[new SimpleObject(aRock, 0, 4, 2, 4)]], + [[scaleByMapSize(80, 500)]], + [avoidClasses(clIsland, 0), avoidCollisions]); + Engine.SetProgress(98); + + createDecoration( + aBushesShoreline.map(bush => [new SimpleObject(bush, 0, 3, 2, 4)]), + aBushesShoreline.map(bush => scaleByMapSize(200, 1000)), + [new HeightConstraint(heightWaterLevel, heightShore), avoidCollisions]); + Engine.SetProgress(99); + + g_Environment = { + "SkySet": "cloudless", + "SunColor": { + "r": 1, + "g": 0.964706, + "b": 0.909804, "a": 0 - } - }, - "Water": { - "WaterBody": { - "Type": "lake", - "Color": { - "r": 0.443137, - "g": 0.341176, - "b": 0.14902, - "a": 0 - }, - "Tint": { - "r": 0.705882, - "g": 0.67451, - "b": 0.454902, + }, + "SunElevation": 0.908117, + "SunRotation": -0.558369, + "AmbientColor": { + "r": 0.54902, + "g": 0.419608, + "b": 0.352941, + "a": 0 + }, + "Fog": { + "FogFactor": 0.00195313, + "FogThickness": 0, + "FogColor": { + "r": 0.941176, + "g": 0.917647, + "b": 0.807843, "a": 0 - }, - "Waviness": 8.4668, - "Murkiness": 0.92, - "WindAngle": 0.625864 + } + }, + "Water": { + "WaterBody": { + "Type": "lake", + "Color": { + "r": 0.443137, + "g": 0.341176, + "b": 0.14902, + "a": 0 + }, + "Tint": { + "r": 0.705882, + "g": 0.67451, + "b": 0.454902, + "a": 0 + }, + "Waviness": 8.4668, + "Murkiness": 0.92, + "WindAngle": 0.625864 + } + }, + "Postproc": { + "Brightness": 0.0234375, + "Contrast": 1.09961, + "Saturation": 0.828125, + "Bloom": 0.142969, + "PostprocEffect": "hdr" } - }, - "Postproc": { - "Brightness": 0.0234375, - "Contrast": 1.09961, - "Saturation": 0.828125, - "Bloom": 0.142969, - "PostprocEffect": "hdr" - } -}; + }; -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/empire.js =================================================================== --- binaries/data/mods/public/maps/random/empire.js +++ binaries/data/mods/public/maps/random/empire.js @@ -3,246 +3,249 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setSelectedBiome(); - -const g_Map = new RandomMap(2, g_Terrains.mainTerrain); - -initTileClasses(); - -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land)); - -Engine.SetProgress(10); - -const teamsArray = getTeamsArray(); -const startAngle = randomAngle(); -createBases( - ...playerPlacementByPattern( - "stronghold", - fractionToTiles(0.37), - fractionToTiles(0.04), - startAngle, - undefined), - false); -Engine.SetProgress(20); - -// Change the starting angle and add the players again -let rotation = Math.PI; - -if (teamsArray.length == 2) - rotation = Math.PI / 2; - -if (teamsArray.length == 4) - rotation = 5/4 * Math.PI; - -createBases( - ...playerPlacementByPattern( - "stronghold", - fractionToTiles(0.15), - fractionToTiles(0.04), - startAngle + rotation, - undefined), - false); -Engine.SetProgress(40); - -addElements(shuffleArray([ - { - "func": addHills, - "avoid": [ - g_TileClasses.bluff, 5, - g_TileClasses.hill, 15, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 5, - g_TileClasses.player, 20, - g_TileClasses.valley, 2, - g_TileClasses.water, 2 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": ["tons"] - }, - { - "func": addMountains, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.mountain, 25, - g_TileClasses.plateau, 20, - g_TileClasses.player, 20, - g_TileClasses.valley, 10, - g_TileClasses.water, 15 - ], - "sizes": ["huge"], - "mixes": ["same", "similar"], - "amounts": ["tons"] - }, - { - "func": addPlateaus, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.mountain, 25, - g_TileClasses.plateau, 20, - g_TileClasses.player, 40, - g_TileClasses.valley, 10, - g_TileClasses.water, 15 - ], - "sizes": ["huge"], - "mixes": ["same", "similar"], - "amounts": ["tons"] - } -])); -Engine.SetProgress(50); - -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - } -]); -Engine.SetProgress(60); - -addElements(shuffleArray([ - { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.metal, 20, - g_TileClasses.plateau, 2, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": g_AllAmounts - }, - { - "func": addStone, - "avoid": [g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 10, - g_TileClasses.plateau, 2, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": g_AllAmounts - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 18, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 5, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.water, 2 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": ["few", "normal", "many", "tons"] - } -])); -Engine.SetProgress(80); - -addElements(shuffleArray([ - { - "func": addBerries, - "avoid": [ - g_TileClasses.berries, 30, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 5, - g_TileClasses.metal, 10, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 10, - g_TileClasses.water, 3 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.water, 3 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 7, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.water, 5 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - } -])); -Engine.SetProgress(90); - -placePlayersNomad( - g_TileClasses.player, - avoidClasses( - g_TileClasses.plateau, 4, - g_TileClasses.forest, 1, - g_TileClasses.metal, 4, - g_TileClasses.rock, 4, - g_TileClasses.mountain, 4, - g_TileClasses.animals, 2)); - -g_Map.ExportMap(); +function* GenerateMap() +{ + setSelectedBiome(); + + const g_Map = new RandomMap(2, g_Terrains.mainTerrain); + + initTileClasses(); + + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land)); + + yield 10; + + const teamsArray = getTeamsArray(); + const startAngle = randomAngle(); + createBases( + ...playerPlacementByPattern( + "stronghold", + fractionToTiles(0.37), + fractionToTiles(0.04), + startAngle, + undefined), + false); + yield 20; + + // Change the starting angle and add the players again + let rotation = Math.PI; + + if (teamsArray.length == 2) + rotation = Math.PI / 2; + + if (teamsArray.length == 4) + rotation = 5/4 * Math.PI; + + createBases( + ...playerPlacementByPattern( + "stronghold", + fractionToTiles(0.15), + fractionToTiles(0.04), + startAngle + rotation, + undefined), + false); + yield 40; + + addElements(shuffleArray([ + { + "func": addHills, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.hill, 15, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 5, + g_TileClasses.player, 20, + g_TileClasses.valley, 2, + g_TileClasses.water, 2 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": ["tons"] + }, + { + "func": addMountains, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 20, + g_TileClasses.player, 20, + g_TileClasses.valley, 10, + g_TileClasses.water, 15 + ], + "sizes": ["huge"], + "mixes": ["same", "similar"], + "amounts": ["tons"] + }, + { + "func": addPlateaus, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 20, + g_TileClasses.player, 40, + g_TileClasses.valley, 10, + g_TileClasses.water, 15 + ], + "sizes": ["huge"], + "mixes": ["same", "similar"], + "amounts": ["tons"] + } + ])); + yield 50; + + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + } + ]); + yield 60; + + addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 20, + g_TileClasses.plateau, 2, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": g_AllAmounts + }, + { + "func": addStone, + "avoid": [g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10, + g_TileClasses.plateau, 2, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": g_AllAmounts + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 18, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": ["few", "normal", "many", "tons"] + } + ])); + yield 80; + + addElements(shuffleArray([ + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 10, + g_TileClasses.water, 3 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.water, 3 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 7, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.water, 5 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + } + ])); + yield 90; + + placePlayersNomad( + g_TileClasses.player, + avoidClasses( + g_TileClasses.plateau, 4, + g_TileClasses.forest, 1, + g_TileClasses.metal, 4, + g_TileClasses.rock, 4, + g_TileClasses.mountain, 4, + g_TileClasses.animals, 2)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/english_channel.js =================================================================== --- binaries/data/mods/public/maps/random/english_channel.js +++ binaries/data/mods/public/maps/random/english_channel.js @@ -1,267 +1,273 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tPrimary = "temp_grass_long"; -const tGrass = ["temp_grass", "temp_grass", "temp_grass_d"]; -const tGrassDForest = "temp_plants_bog"; -const tGrassA = "temp_grass_plants"; -const tGrassB = "temp_plants_bog"; -const tGrassC = "temp_mud_a"; -const tHill = ["temp_highlands", "temp_grass_long_b"]; -const tCliff = ["temp_cliff_a", "temp_cliff_b"]; -const tRoad = "temp_road"; -const tRoadWild = "temp_road_overgrown"; -const tGrassPatchBlend = "temp_grass_long_b"; -const tGrassPatch = ["temp_grass_d", "temp_grass_clovers"]; -const tShore = "temp_dirt_gravel"; -const tWater = "temp_dirt_gravel_b"; - -const oBeech = "gaia/tree/euro_beech"; -const oPoplar = "gaia/tree/poplar"; -const oApple = "gaia/fruit/apple"; -const oOak = "gaia/tree/oak"; -const oBerryBush = "gaia/fruit/berry_01"; -const oDeer = "gaia/fauna_deer"; -const oFish = "gaia/fish/generic"; -const oGoat = "gaia/fauna_goat"; -const oBoar = "gaia/fauna_boar"; -const oStoneLarge = "gaia/rock/temperate_large"; -const oStoneSmall = "gaia/rock/temperate_small"; -const oMetalLarge = "gaia/ore/temperate_large"; - -const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; -const aGrassShort = "actor|props/flora/grass_soft_large.xml"; -const aRockLarge = "actor|geology/stone_granite_large.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aBushMedium = "actor|props/flora/bush_medit_me_lush.xml"; -const aBushSmall = "actor|props/flora/bush_medit_sm_lush.xml"; -const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; -const aLillies = "actor|props/flora/water_lillies.xml"; - -const pForestD = [tGrassDForest + TERRAIN_SEPARATOR + oBeech, tGrassDForest]; - -const heightSeaGround = -4; -const heightShore = 1; -const heightLand = 3; - -const g_Map = new RandomMap(heightShore, tPrimary); - -const numPlayers = getNumPlayers(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clShallow = g_Map.createTileClass(); - -const startAngle = randomAngle(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.6)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oOak, - "count": 2 - }, - "Decoratives": { - "template": aGrassShort - } -}); -Engine.SetProgress(10); - -paintRiver({ - "parallel": false, - "start": new Vector2D(mapBounds.left, mapCenter.y).rotateAround(startAngle, mapCenter), - "end": new Vector2D(mapBounds.right, mapCenter.y).rotateAround(startAngle, mapCenter), - "width": fractionToTiles(0.25), - "fadeDist": scaleByMapSize(3, 10), - "deviation": 0, - "heightRiverbed": heightSeaGround, - "heightLand": heightLand, - "meanderShort": 20, - "meanderLong": 0, - "waterFunc": (position, height, riverFraction) => { - createTerrain(height < -1.5 ? tWater : tShore).place(position); - }, - "landFunc": (position, shoreDist1, shoreDist2) => { - g_Map.setHeight(position, heightLand + 0.1); - } -}); - -Engine.SetProgress(20); - -createTributaryRivers( - startAngle, - randIntInclusive(9, scaleByMapSize(13, 21)), - scaleByMapSize(10, 20), - heightSeaGround, - [-6, -1.5], - Math.PI / 5, - clWater, - clShallow, - avoidClasses(clPlayer, 8, clBaseResource, 4)); - -paintTerrainBasedOnHeight(-5, 1, 1, tWater); -paintTerrainBasedOnHeight(1, heightLand, 1, tShore); -paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); -Engine.SetProgress(25); - -createBumps(avoidClasses(clWater, 5, clPlayer, 20)); -Engine.SetProgress(30); - -createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 20, clHill, 15, clWater, 5), clHill, scaleByMapSize(1, 4) * numPlayers); -Engine.SetProgress(50); - -const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); -createForests( - [tGrass, tGrassDForest, tGrassDForest, pForestD, pForestD], - avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 6), - clForest, - forestTrees); -Engine.SetProgress(70); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tGrass,tGrassA], tGrassB, [tGrassB,tGrassC]], - [1,1], - avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6), - scaleByMapSize(15, 45), - clDirt); - -g_Map.log("Creating grass patches"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - [tGrassPatchBlend, tGrassPatch], - [1], - avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(80); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2,5, 1,3)] - ], - avoidClasses(clWater, 2, clForest, 1, clPlayer, 20, clRock, 10, clHill, 2), - clRock); - -g_Map.log("Creating metal mines"); -createMines( - [ - [new SimpleObject(oMetalLarge, 1,1, 0,4)] - ], - avoidClasses(clWater, 2, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 2), - clMetal -); -Engine.SetProgress(85); - -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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13) - ], - avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 0)); - -createDecoration( - [ - [new SimpleObject(aReeds, 1, 3, 0, 1)], - [new SimpleObject(aLillies, 1, 2, 0, 1)] - ], - [ - scaleByMapSize(800, 12800), - scaleByMapSize(800, 12800) - ], - stayClasses(clShallow, 0)); - -createFood( - [ - [new SimpleObject(oDeer, 5, 7, 0, 4)], - [new SimpleObject(oGoat, 2, 3, 0, 2)], - [new SimpleObject(oBoar, 2, 3, 0, 2)] - ], - [ - 3 * numPlayers, - 3 * numPlayers, - 3 * numPlayers - ], - avoidClasses(clWater, 1, clForest, 0, clPlayer, 20, clHill, 0, clFood, 15), - clFood); - -createFood( - [ - [new SimpleObject(oBerryBush, 5, 7, 0, 4)] - ], - [ - randIntInclusive(1, 4) * numPlayers + 2 - ], - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - clFood); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [scaleByMapSize(3, 25) * numPlayers], - [avoidClasses(clFood, 6), stayClasses(clWater, 4)], - clFood); - -createStragglerTrees( - [oBeech, oPoplar, oApple], - avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 8, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); - -setSkySet("cirrus"); -setWaterColor(0.114, 0.192, 0.463); -setWaterTint(0.255, 0.361, 0.651); -setWaterWaviness(3.0); -setWaterType("ocean"); -setWaterMurkiness(0.83); - -setFogThickness(0.35); -setFogFactor(0.55); - -setPPEffect("hdr"); -setPPSaturation(0.62); -setPPContrast(0.62); -setPPBloom(0.37); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -g_Map.ExportMap(); +function* GenerateMap() +{ + const tPrimary = "temp_grass_long"; + const tGrass = ["temp_grass", "temp_grass", "temp_grass_d"]; + const tGrassDForest = "temp_plants_bog"; + const tGrassA = "temp_grass_plants"; + const tGrassB = "temp_plants_bog"; + const tGrassC = "temp_mud_a"; + const tHill = ["temp_highlands", "temp_grass_long_b"]; + const tCliff = ["temp_cliff_a", "temp_cliff_b"]; + const tRoad = "temp_road"; + const tRoadWild = "temp_road_overgrown"; + const tGrassPatchBlend = "temp_grass_long_b"; + const tGrassPatch = ["temp_grass_d", "temp_grass_clovers"]; + const tShore = "temp_dirt_gravel"; + const tWater = "temp_dirt_gravel_b"; + + const oBeech = "gaia/tree/euro_beech"; + const oPoplar = "gaia/tree/poplar"; + const oApple = "gaia/fruit/apple"; + const oOak = "gaia/tree/oak"; + const oBerryBush = "gaia/fruit/berry_01"; + const oDeer = "gaia/fauna_deer"; + const oFish = "gaia/fish/generic"; + const oGoat = "gaia/fauna_goat"; + const oBoar = "gaia/fauna_boar"; + const oStoneLarge = "gaia/rock/temperate_large"; + const oStoneSmall = "gaia/rock/temperate_small"; + const oMetalLarge = "gaia/ore/temperate_large"; + + const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; + const aGrassShort = "actor|props/flora/grass_soft_large.xml"; + const aRockLarge = "actor|geology/stone_granite_large.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aBushMedium = "actor|props/flora/bush_medit_me_lush.xml"; + const aBushSmall = "actor|props/flora/bush_medit_sm_lush.xml"; + const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; + const aLillies = "actor|props/flora/water_lillies.xml"; + + const pForestD = [tGrassDForest + TERRAIN_SEPARATOR + oBeech, tGrassDForest]; + + const heightSeaGround = -4; + const heightShore = 1; + const heightLand = 3; + + global.g_Map = new RandomMap(heightShore, tPrimary); + + const numPlayers = getNumPlayers(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clShallow = g_Map.createTileClass(); + + const startAngle = randomAngle(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.6)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oOak, + "count": 2 + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 10; + + paintRiver({ + "parallel": false, + "start": new Vector2D(mapBounds.left, mapCenter.y).rotateAround(startAngle, mapCenter), + "end": new Vector2D(mapBounds.right, mapCenter.y).rotateAround(startAngle, mapCenter), + "width": fractionToTiles(0.25), + "fadeDist": scaleByMapSize(3, 10), + "deviation": 0, + "heightRiverbed": heightSeaGround, + "heightLand": heightLand, + "meanderShort": 20, + "meanderLong": 0, + "waterFunc": (position, height, riverFraction) => { + createTerrain(height < -1.5 ? tWater : tShore).place(position); + }, + "landFunc": (position, shoreDist1, shoreDist2) => { + g_Map.setHeight(position, heightLand + 0.1); + } + }); + + yield 20; + + createTributaryRivers( + startAngle, + randIntInclusive(9, scaleByMapSize(13, 21)), + scaleByMapSize(10, 20), + heightSeaGround, + [-6, -1.5], + Math.PI / 5, + clWater, + clShallow, + avoidClasses(clPlayer, 8, clBaseResource, 4)); + + paintTerrainBasedOnHeight(-5, 1, 1, tWater); + paintTerrainBasedOnHeight(1, heightLand, 1, tShore); + paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); + yield 25; + + createBumps(avoidClasses(clWater, 5, clPlayer, 20)); + yield 30; + + createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 20, clHill, 15, clWater, 5), clHill, + scaleByMapSize(1, 4) * numPlayers); + yield 50; + + const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); + createForests( + [tGrass, tGrassDForest, tGrassDForest, pForestD, pForestD], + avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 6), + clForest, + forestTrees); + yield 70; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tGrass,tGrassA], tGrassB, [tGrassB,tGrassC]], + [1,1], + avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6), + scaleByMapSize(15, 45), + clDirt); + + g_Map.log("Creating grass patches"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + [tGrassPatchBlend, tGrassPatch], + [1], + avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6), + scaleByMapSize(15, 45), + clDirt); + yield(80); + + g_Map.log("Creating stone mines"); + createMines( + [ + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oStoneSmall, 2,5, 1,3)] + ], + avoidClasses(clWater, 2, clForest, 1, clPlayer, 20, clRock, 10, clHill, 2), + clRock); + + g_Map.log("Creating metal mines"); + createMines( + [ + [new SimpleObject(oMetalLarge, 1,1, 0,4)] + ], + avoidClasses(clWater, 2, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 2), + clMetal + ); + yield 85; + + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13) + ], + avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 0)); + + createDecoration( + [ + [new SimpleObject(aReeds, 1, 3, 0, 1)], + [new SimpleObject(aLillies, 1, 2, 0, 1)] + ], + [ + scaleByMapSize(800, 12800), + scaleByMapSize(800, 12800) + ], + stayClasses(clShallow, 0)); + + createFood( + [ + [new SimpleObject(oDeer, 5, 7, 0, 4)], + [new SimpleObject(oGoat, 2, 3, 0, 2)], + [new SimpleObject(oBoar, 2, 3, 0, 2)] + ], + [ + 3 * numPlayers, + 3 * numPlayers, + 3 * numPlayers + ], + avoidClasses(clWater, 1, clForest, 0, clPlayer, 20, clHill, 0, clFood, 15), + clFood); + + createFood( + [ + [new SimpleObject(oBerryBush, 5, 7, 0, 4)] + ], + [ + randIntInclusive(1, 4) * numPlayers + 2 + ], + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), + clFood); + + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [scaleByMapSize(3, 25) * numPlayers], + [avoidClasses(clFood, 6), stayClasses(clWater, 4)], + clFood); + + createStragglerTrees( + [oBeech, oPoplar, oApple], + avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 8, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + + setSkySet("cirrus"); + setWaterColor(0.114, 0.192, 0.463); + setWaterTint(0.255, 0.361, 0.651); + setWaterWaviness(3.0); + setWaterType("ocean"); + setWaterMurkiness(0.83); + + setFogThickness(0.35); + setFogFactor(0.55); + + setPPEffect("hdr"); + setPPSaturation(0.62); + setPPContrast(0.62); + setPPBloom(0.37); + + placePlayersNomad(clPlayer, + avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/extinct_volcano.js =================================================================== --- binaries/data/mods/public/maps/random/extinct_volcano.js +++ binaries/data/mods/public/maps/random/extinct_volcano.js @@ -1,466 +1,469 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tHillDark = "cliff volcanic light"; -const tHillMedium1 = "ocean_rock_a"; -const tHillMedium2 = "ocean_rock_b"; -const tHillVeryDark = ["cliff volcanic coarse", "cave_walls"]; -const tRoad = "road1"; -const tRoadWild = "road1"; -const tForestFloor1 = tHillMedium1; -const tForestFloor2 = tHillMedium2; -const tGrassA = "cliff volcanic light"; -const tGrassB = "ocean_rock_a"; -const tGrassPatchBlend = "temp_grass_long_b"; -const tGrassPatch = ["temp_grass_d", "temp_grass_clovers"]; -const tShoreBlend = "cliff volcanic light"; -const tShore = "ocean_rock_a"; -const tWater = "ocean_rock_b"; - -const oTree = "gaia/tree/dead"; -const oTree2 = "gaia/tree/euro_beech"; -const oTree3 = "gaia/tree/oak"; -const oTree4 = "gaia/tree/oak_dead"; -const oBush = "gaia/tree/bush_temperate"; -const oFruitBush = "gaia/fruit/berry_01"; -const oRabbit = "gaia/fauna_rabbit"; -const oGoat = "gaia/fauna_goat"; -const oBear = "gaia/fauna_bear_brown"; -const oStoneLarge = "gaia/rock/temperate_large"; -const oStoneSmall = "gaia/rock/temperate_small"; -const oMetalLarge = "gaia/ore/temperate_large"; -const oTower = "structures/palisades_fort"; - -const aRockLarge = "actor|geology/stone_granite_med.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aBushMedium = "actor|props/flora/bush_tempe_me.xml"; -const aBushSmall = "actor|props/flora/bush_tempe_sm.xml"; -const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; -const aGrassShort = "actor|props/flora/grass_soft_large.xml"; -const aRain = "actor|particle/rain_shower.xml"; - -const pForestD = [ - tForestFloor1 + TERRAIN_SEPARATOR + oTree, - tForestFloor2 + TERRAIN_SEPARATOR + oTree2, - tForestFloor1 -]; - -const pForestP = [ - tForestFloor1 + TERRAIN_SEPARATOR + oTree3, - tForestFloor2 + TERRAIN_SEPARATOR + oTree4, - tForestFloor1 -]; - -const heightSeaGround = -4; -const heightLand = 1; -const heightHill = 18; -const heightPlayerHill = 25; - -const g_Map = new RandomMap(heightLand, tHillMedium1); - -const numPlayers = getNumPlayers(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clGrass = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clBumps = g_Map.createTileClass(); -const clTower = g_Map.createTileClass(); -const clRain = g_Map.createTileClass(); - -const playerMountainSize = defaultPlayerBaseRadius(); - -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - -g_Map.log("Creating CC mountains"); -if (!isNomad()) - for (let i = 0; i < numPlayers; ++i) - { - // This one consists of many bumps, creating an omnidirectional ramp - createMountain( - heightPlayerHill, - playerMountainSize, - playerMountainSize, - Math.floor(scaleByMapSize(4, 10)), - undefined, - playerPosition[i].x, - playerPosition[i].y, - tHillDark, - clPlayer, - 14); - - // Flatten the initial CC area - createArea( - new ClumpPlacer(diskArea(playerMountainSize), 0.95, 0.6, Infinity, playerPosition[i]), - [ - new LayeredPainter([tHillVeryDark, tHillMedium1], [playerMountainSize]), - new SmoothElevationPainter(ELEVATION_SET, heightPlayerHill, playerMountainSize), - new TileClassPainter(clPlayer) - ]); - } - -Engine.SetProgress(8); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - // PlayerTileClass already marked above - "BaseResourceClass": clBaseResource, - "Walls": "towers", - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oFruitBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oTree2 - } - // No decoratives -}); -Engine.SetProgress(15); - -createVolcano(mapCenter, clHill, tHillVeryDark, undefined, false, ELEVATION_SET); -Engine.SetProgress(20); - -g_Map.log("Creating lakes"); -createAreas( - new ChainPlacer(5, 6, Math.floor(scaleByMapSize(10, 14)), 0.1), - [ - new LayeredPainter([tShoreBlend, tShore, tWater], [1, 1]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 3), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 0, clHill, 2, clWater, 12), - Math.round(scaleByMapSize(6, 12))); -Engine.SetProgress(25); - -createBumps(avoidClasses(clPlayer, 0, clHill, 0), scaleByMapSize(50, 300), 1, 10, 3, 0, scaleByMapSize(4, 10)); -paintTileClassBasedOnHeight(10, 100, 0, clBumps); -Engine.SetProgress(30); - -g_Map.log("Creating hills"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), - [ - new LayeredPainter([tHillDark, tHillDark, tHillDark], [2, 2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 0, clHill, 15, clWater, 2, clBaseResource, 2), - scaleByMapSize(2, 8) * numPlayers); -Engine.SetProgress(35); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(1200, 3000, 0.7); -const types = [ - [[tGrassB, tGrassA, pForestD], [tGrassB, pForestD]], - [[tGrassB, tGrassA, pForestP], [tGrassB, pForestP]] -]; -const size = forestTrees / (scaleByMapSize(4, 12) * numPlayers); -const num = Math.floor(size / types.length); -for (const type of types) +function* GenerateMap() +{ + const tHillDark = "cliff volcanic light"; + const tHillMedium1 = "ocean_rock_a"; + const tHillMedium2 = "ocean_rock_b"; + const tHillVeryDark = ["cliff volcanic coarse", "cave_walls"]; + const tRoad = "road1"; + const tRoadWild = "road1"; + const tForestFloor1 = tHillMedium1; + const tForestFloor2 = tHillMedium2; + const tGrassA = "cliff volcanic light"; + const tGrassB = "ocean_rock_a"; + const tGrassPatchBlend = "temp_grass_long_b"; + const tGrassPatch = ["temp_grass_d", "temp_grass_clovers"]; + const tShoreBlend = "cliff volcanic light"; + const tShore = "ocean_rock_a"; + const tWater = "ocean_rock_b"; + + const oTree = "gaia/tree/dead"; + const oTree2 = "gaia/tree/euro_beech"; + const oTree3 = "gaia/tree/oak"; + const oTree4 = "gaia/tree/oak_dead"; + const oBush = "gaia/tree/bush_temperate"; + const oFruitBush = "gaia/fruit/berry_01"; + const oRabbit = "gaia/fauna_rabbit"; + const oGoat = "gaia/fauna_goat"; + const oBear = "gaia/fauna_bear_brown"; + const oStoneLarge = "gaia/rock/temperate_large"; + const oStoneSmall = "gaia/rock/temperate_small"; + const oMetalLarge = "gaia/ore/temperate_large"; + const oTower = "structures/palisades_fort"; + + const aRockLarge = "actor|geology/stone_granite_med.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aBushMedium = "actor|props/flora/bush_tempe_me.xml"; + const aBushSmall = "actor|props/flora/bush_tempe_sm.xml"; + const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; + const aGrassShort = "actor|props/flora/grass_soft_large.xml"; + const aRain = "actor|particle/rain_shower.xml"; + + const pForestD = [ + tForestFloor1 + TERRAIN_SEPARATOR + oTree, + tForestFloor2 + TERRAIN_SEPARATOR + oTree2, + tForestFloor1 + ]; + + const pForestP = [ + tForestFloor1 + TERRAIN_SEPARATOR + oTree3, + tForestFloor2 + TERRAIN_SEPARATOR + oTree4, + tForestFloor1 + ]; + + const heightSeaGround = -4; + const heightLand = 1; + const heightHill = 18; + const heightPlayerHill = 25; + + global.g_Map = new RandomMap(heightLand, tHillMedium1); + + const numPlayers = getNumPlayers(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clGrass = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clBumps = g_Map.createTileClass(); + const clTower = g_Map.createTileClass(); + const clRain = g_Map.createTileClass(); + + const playerMountainSize = defaultPlayerBaseRadius(); + + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + + g_Map.log("Creating CC mountains"); + if (!isNomad()) + for (let i = 0; i < numPlayers; ++i) + { + // This one consists of many bumps, creating an omnidirectional ramp + createMountain( + heightPlayerHill, + playerMountainSize, + playerMountainSize, + Math.floor(scaleByMapSize(4, 10)), + undefined, + playerPosition[i].x, + playerPosition[i].y, + tHillDark, + clPlayer, + 14); + + // Flatten the initial CC area + createArea( + new ClumpPlacer(diskArea(playerMountainSize), 0.95, 0.6, Infinity, playerPosition[i]), + [ + new LayeredPainter([tHillVeryDark, tHillMedium1], [playerMountainSize]), + new SmoothElevationPainter(ELEVATION_SET, heightPlayerHill, playerMountainSize), + new TileClassPainter(clPlayer) + ]); + } + + yield 8; + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + // PlayerTileClass already marked above + "BaseResourceClass": clBaseResource, + "Walls": "towers", + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oFruitBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oTree2 + } + // No decoratives + }); + yield 15; + + createVolcano(mapCenter, clHill, tHillVeryDark, undefined, false, ELEVATION_SET); + yield 20; + + g_Map.log("Creating lakes"); createAreas( - new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), + new ChainPlacer(5, 6, Math.floor(scaleByMapSize(10, 14)), 0.1), [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) + new LayeredPainter([tShoreBlend, tShore, tWater], [1, 1]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 3), + new TileClassPainter(clWater) ], - avoidClasses( - clPlayer, 4, - clForest, 10, - clHill, 0, - clWater, 2), - num); -Engine.SetProgress(40); + avoidClasses(clPlayer, 0, clHill, 2, clWater, 12), + Math.round(scaleByMapSize(6, 12))); + yield 25; -g_Map.log("Creating hill patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - for (const type of [[tHillMedium1, tHillDark], [tHillDark, tHillMedium2], [tHillMedium1, tHillMedium2]]) + createBumps(avoidClasses(clPlayer, 0, clHill, 0), scaleByMapSize(50, 300), 1, 10, 3, 0, scaleByMapSize(4, 10)); + paintTileClassBasedOnHeight(10, 100, 0, clBumps); + yield 30; + + g_Map.log("Creating hills"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), + [ + new LayeredPainter([tHillDark, tHillDark, tHillDark], [2, 2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) + ], + avoidClasses(clPlayer, 0, clHill, 15, clWater, 2, clBaseResource, 2), + scaleByMapSize(2, 8) * numPlayers); + yield 35; + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(1200, 3000, 0.7); + const types = [ + [[tGrassB, tGrassA, pForestD], [tGrassB, pForestD]], + [[tGrassB, tGrassA, pForestP], [tGrassB, pForestP]] + ]; + const size = forestTrees / (scaleByMapSize(4, 12) * numPlayers); + const num = Math.floor(size / types.length); + for (const type of types) createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), + new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), [ - new LayeredPainter(type, [1]), - new TileClassPainter(clGrass) + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) ], avoidClasses( - clWater, 3, - clForest, 0, + clPlayer, 4, + clForest, 10, clHill, 0, - clBumps, 0, - clPlayer, 0), - scaleByMapSize(20, 80)); -Engine.SetProgress(45); - -g_Map.log("Creating grass patches"); -createLayeredPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - [tGrassPatchBlend, tGrassPatch], - [1], - avoidClasses( - clWater, 1, - clForest, 0, - clHill, 0, - clGrass, 5, - clBumps, 0, - clPlayer, 0), - scaleByMapSize(3, 8), - clDirt); -Engine.SetProgress(50); - -g_Map.log("Creating stone mines"); -createObjectGroupsDeprecated( - new SimpleGroup( + clWater, 2), + num); + yield 40; + + g_Map.log("Creating hill patches"); + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + for (const type of [[tHillMedium1, tHillDark], [tHillDark, tHillMedium2], [tHillMedium1, tHillMedium2]]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new LayeredPainter(type, [1]), + new TileClassPainter(clGrass) + ], + avoidClasses( + clWater, 3, + clForest, 0, + clHill, 0, + clBumps, 0, + clPlayer, 0), + scaleByMapSize(20, 80)); + yield 45; + + g_Map.log("Creating grass patches"); + createLayeredPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + [tGrassPatchBlend, tGrassPatch], + [1], + avoidClasses( + clWater, 1, + clForest, 0, + clHill, 0, + clGrass, 5, + clBumps, 0, + clPlayer, 0), + scaleByMapSize(3, 8), + clDirt); + yield 50; + + g_Map.log("Creating stone mines"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4), + new SimpleObject(oStoneLarge, 1, 1, 0, 4) + ], + true, + clRock), + 0, [ - new SimpleObject(oStoneSmall, 0, 2, 0, 4), - new SimpleObject(oStoneLarge, 1, 1, 0, 4) + stayClasses(clBumps, 1), + avoidClasses( + clWater, 3, + clForest, 1, + clPlayer, 0, + clRock, 15, + clHill, 0) ], - true, - clRock), - 0, - [ - stayClasses(clBumps, 1), - avoidClasses( - clWater, 3, - clForest, 1, - clPlayer, 0, - clRock, 15, - clHill, 0) - ], - 100, - 100); -Engine.SetProgress(55); - -g_Map.log("Creating small stone quarries"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock), - 0, - [ - stayClasses(clBumps, 1), - avoidClasses( - clWater, 3, - clForest, 1, - clPlayer, 0, - clRock, 15, - clHill, 0) - ], - 100, - 100); -Engine.SetProgress(60); - -g_Map.log("Creating metal mines"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), - 0, - [ - stayClasses(clBumps, 1), - avoidClasses( - clWater, 3, - clForest, 1, - clPlayer, 0, - clMetal, 15, - clRock, 10, - clHill, 0) - ], - 100, - 100); -Engine.SetProgress(65); - -if (!isNomad()) -{ - g_Map.log("Creating towers"); + 100, + 100); + yield 55; + + g_Map.log("Creating small stone quarries"); createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oTower, 1, 1, 0, 4)], true, clTower), + new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock), 0, [ - stayClasses(clBumps, 3), + stayClasses(clBumps, 1), avoidClasses( - clMetal, 5, - clRock, 5, - clHill, 0, - clTower, 60, - clPlayer, 10, - clForest, 2) + clWater, 3, + clForest, 1, + clPlayer, 0, + clRock, 15, + clHill, 0) ], - 500, - 1); -} -Engine.SetProgress(67); + 100, + 100); + yield 60; -createDecoration( + g_Map.log("Creating metal mines"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), + 0, [ + stayClasses(clBumps, 1), + avoidClasses( + clWater, 3, + clForest, 1, + clPlayer, 0, + clMetal, 15, + clRock, 10, + clHill, 0) + ], + 100, + 100); + yield 65; + + if (!isNomad()) + { + g_Map.log("Creating towers"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oTower, 1, 1, 0, 4)], true, clTower), + 0, [ - new SimpleObject(aGrassShort, 1, 2, 0, 1) + stayClasses(clBumps, 3), + avoidClasses( + clMetal, 5, + clRock, 5, + clHill, 0, + clTower, 60, + clPlayer, 10, + clForest, 2) ], + 500, + 1); + } + yield 67; + + createDecoration( [ - new SimpleObject(aGrass, 2, 4, 0, 1.8), - new SimpleObject(aGrassShort, 3, 6, 1.2, 2.5) + [ + 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) + ] ], [ - new SimpleObject(aBushMedium, 1, 2, 0, 2), - new SimpleObject(aBushSmall, 2, 4, 0, 2) - ] + scaleByMapAreaAbsolute(15), + scaleByMapAreaAbsolute(15), + scaleByMapAreaAbsolute(15) + ], + [ + stayClasses(clGrass, 0), + avoidClasses( + clWater, 0, + clForest, 0, + clPlayer, 0, + clHill, 0) + ]); + yield 70; + + createDecoration( + [ + [ + new SimpleObject(aRockMedium, 1, 3, 0, 1) + ], + [ + new SimpleObject(aRockLarge, 1, 2, 0, 1), + new SimpleObject(aRockMedium, 1, 3, 0, 2) + ] + ], + [ + scaleByMapSize(15, 250), + scaleByMapSize(15, 150) + ], + avoidClasses( + clWater, 0, + clForest, 0, + clPlayer, 0, + clHill, 0 + )); + yield 75; + + createFood( + [ + [new SimpleObject(oRabbit, 5, 7, 2, 4)], + [new SimpleObject(oGoat, 3, 5, 2, 4)] ], [ - scaleByMapAreaAbsolute(15), - scaleByMapAreaAbsolute(15), - scaleByMapAreaAbsolute(15) + scaleByMapSize(1, 6) * numPlayers, + scaleByMapSize(3, 10) * numPlayers ], [ - stayClasses(clGrass, 0), avoidClasses( - clWater, 0, + clWater, 1, clForest, 0, clPlayer, 0, - clHill, 0) - ]); -Engine.SetProgress(70); + clHill, 1, + clFood, 20) + ], + clFood); + yield 78; -createDecoration( + createFood( [ - [ - new SimpleObject(aRockMedium, 1, 3, 0, 1) - ], - [ - new SimpleObject(aRockLarge, 1, 2, 0, 1), - new SimpleObject(aRockMedium, 1, 3, 0, 2) - ] + [new SimpleObject(oBear, 1, 1, 0, 2)] ], [ - scaleByMapSize(15, 250), - scaleByMapSize(15, 150) + 3 * numPlayers ], - avoidClasses( - clWater, 0, - clForest, 0, - clPlayer, 0, - clHill, 0 - )); -Engine.SetProgress(75); - -createFood( - [ - [new SimpleObject(oRabbit, 5, 7, 2, 4)], - [new SimpleObject(oGoat, 3, 5, 2, 4)] - ], - [ - scaleByMapSize(1, 6) * numPlayers, - scaleByMapSize(3, 10) * numPlayers - ], - [ - avoidClasses( - clWater, 1, - clForest, 0, - clPlayer, 0, - clHill, 1, - clFood, 20) - ], - clFood); -Engine.SetProgress(78); - -createFood( - [ - [new SimpleObject(oBear, 1, 1, 0, 2)] - ], - [ - 3 * numPlayers - ], - [ - avoidClasses( - clWater, 1, - clForest, 0, - clPlayer, 0, - clHill, 1, - clFood, 20 + [ + avoidClasses( + clWater, 1, + clForest, 0, + clPlayer, 0, + clHill, 1, + clFood, 20 + ), + stayClasses(clForest, 2) + ], + clFood); + yield 81; + + createFood( + [ + [new SimpleObject(oFruitBush, 1, 2, 0, 4)] + ], + [ + 3 * numPlayers + ], + [stayClasses(clGrass, 1), avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 1, clFood, 10)], + clFood); + yield 85; + + createStragglerTrees( + [oTree, oTree2, oTree3, oTree4, oBush], + [ + stayClasses(clGrass, 1), + avoidClasses( + clWater, 5, + clForest, 1, + clHill, 1, + clPlayer, 0, + clMetal, 4, + clRock, 4) + ], + clForest, + stragglerTrees); + + yield 90; + + g_Map.log("Creating straggler bushes"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oBush, 1, 3, 0, 3)], + true, + clForest ), - stayClasses(clForest, 2) - ], - clFood); -Engine.SetProgress(81); - -createFood( - [ - [new SimpleObject(oFruitBush, 1, 2, 0, 4)] - ], - [ - 3 * numPlayers - ], - [stayClasses(clGrass, 1), avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 1, clFood, 10)], - clFood); -Engine.SetProgress(85); - -createStragglerTrees( - [oTree, oTree2, oTree3, oTree4, oBush], - [ - stayClasses(clGrass, 1), - avoidClasses( - clWater, 5, - clForest, 1, - clHill, 1, - clPlayer, 0, - clMetal, 4, - clRock, 4) - ], - clForest, - stragglerTrees); - -Engine.SetProgress(90); - -g_Map.log("Creating straggler bushes"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oBush, 1, 3, 0, 3)], - true, - clForest - ), - 0, - [ - stayClasses(clGrass, 3), - avoidClasses( - clWater, 1, - clForest, 1, - clPlayer, 0, - clMetal, 4, - clRock, 4) - ], - stragglerTrees); -Engine.SetProgress(95); - -g_Map.log("Creating rain drops"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(aRain, 2, 2, 1, 4)], - true, - clRain), - 0, - avoidClasses(clRain, 5), - scaleByMapSize(80, 250)); -Engine.SetProgress(98); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clHill, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setSkySet("rain"); -setWaterType("lake"); -setWaterWaviness(2); -setWaterColor(0.1, 0.13, 0.15); -setWaterTint(0.058, 0.05, 0.035); -setWaterMurkiness(0.9); - -setPPEffect("hdr"); - -g_Map.ExportMap(); + 0, + [ + stayClasses(clGrass, 3), + avoidClasses( + clWater, 1, + clForest, 1, + clPlayer, 0, + clMetal, 4, + clRock, 4) + ], + stragglerTrees); + yield 95; + + g_Map.log("Creating rain drops"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(aRain, 2, 2, 1, 4)], + true, + clRain), + 0, + avoidClasses(clRain, 5), + scaleByMapSize(80, 250)); + yield 98; + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clHill, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + + setSkySet("rain"); + setWaterType("lake"); + setWaterWaviness(2); + setWaterColor(0.1, 0.13, 0.15); + setWaterTint(0.058, 0.05, 0.035); + setWaterMurkiness(0.9); + + setPPEffect("hdr"); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/fields_of_meroe.js =================================================================== --- binaries/data/mods/public/maps/random/fields_of_meroe.js +++ binaries/data/mods/public/maps/random/fields_of_meroe.js @@ -2,450 +2,469 @@ Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); -if (g_MapSettings.Biome) - setSelectedBiome(); -else - setBiome("fields_of_meroe/dry"); - -const tMainDirt = g_Terrains.mainDirt; -const tSecondaryDirt = g_Terrains.secondaryDirt; -const tDirt = g_Terrains.dirt; -const tLush = "desert_grass_a"; -const tSLush = "desert_grass_a_sand"; -const tFarmland = "desert_farmland"; -const tRoad = "savanna_tile_a"; -const tRoadWild = "desert_city_tile"; -const tRiverBank = "savanna_riparian_wet"; -const tForestFloor = "savanna_forestfloor_b"; - -const oBush = g_Gaia.berry; -const oBaobab = "gaia/tree/baobab"; -const oAcacia = "gaia/tree/acacia"; -const oDatePalm = "gaia/tree/date_palm"; -const oSDatePalm = "gaia/tree/cretan_date_palm_short"; -const oGazelle = "gaia/fauna_gazelle"; -const oGiraffe = "gaia/fauna_giraffe"; -const oLion = "gaia/fauna_lion"; -const oFish = "gaia/fish/generic"; -const oHawk = "birds/buzzard"; -const oStoneLarge = "gaia/rock/savanna_large"; -const oStoneSmall = "gaia/rock/desert_small"; -const oMetalLarge = "gaia/ore/savanna_large"; -const oMetalSmall = "gaia/ore/desert_small"; - -const oHouse = "structures/kush/house"; -const oFarmstead = "structures/kush/farmstead"; -const oField = "structures/kush/field"; -const oPyramid = "structures/kush/pyramid_small"; -const oPyramidLarge = "structures/kush/pyramid_large"; -const oKushUnits = isNomad() ? - "units/kush/support_female_citizen" : - "units/kush/infantry_javelineer_merc_e"; - -const aRain = g_Decoratives.rain; -const aBushA = g_Decoratives.bushA; -const aBushB = g_Decoratives.bushB; -const aBushes = [aBushA, aBushB]; -const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; -const aRockA = g_Decoratives.rock; -const aRockB = "actor|geology/shoreline_large.xml"; -const aRockC = "actor|geology/shoreline_small.xml"; - -const pForestP = [tForestFloor + TERRAIN_SEPARATOR + oAcacia, tForestFloor]; - -const heightSeaGround = g_Heights.seaGround; -const heightReedsDepth = -2.5; -const heightCataract = -1; -const heightShore = 1; -const heightLand = 2; -const heightDunes = 11; -const heightOffsetBump = 1.4; -const heightOffsetBumpPassage = 4; - -const g_Map = new RandomMap(heightLand, tMainDirt); - -const numPlayers = getNumPlayers(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clKushiteVillages = g_Map.createTileClass(); -const clRiver = g_Map.createTileClass(); -const clShore = g_Map.createTileClass(); -const clDunes = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clRain = g_Map.createTileClass(); -const clCataract = g_Map.createTileClass(); - -const kushVillageBuildings = { - "houseA": { "template": oHouse, "offset": new Vector2D(5, 5) }, - "houseB": { "template": oHouse, "offset": new Vector2D(5, 0) }, - "houseC": { "template": oHouse, "offset": new Vector2D(5, -5) }, - "farmstead": { "template": oFarmstead, "offset": new Vector2D(-5, 0) }, - "fieldA": { "template": oField, "offset": new Vector2D(-5, 5) }, - "fieldB": { "template": oField, "offset": new Vector2D(-5, -5) }, - "pyramid": { "template": oPyramid, "offset": new Vector2D(0, -5) } -}; - -const riverTextures = [ - { - "left": fractionToTiles(0), - "right": fractionToTiles(0.04), - "terrain": tLush, - "tileClass": clShore - }, +function* GenerateMap(mapSettings) +{ + setBiome(mapSettings.Biome ?? "fields_of_meroe/dry"); + + const tMainDirt = g_Terrains.mainDirt; + const tSecondaryDirt = g_Terrains.secondaryDirt; + const tDirt = g_Terrains.dirt; + const tLush = "desert_grass_a"; + const tSLush = "desert_grass_a_sand"; + const tFarmland = "desert_farmland"; + const tRoad = "savanna_tile_a"; + const tRoadWild = "desert_city_tile"; + const tRiverBank = "savanna_riparian_wet"; + const tForestFloor = "savanna_forestfloor_b"; + + const oBush = g_Gaia.berry; + const oBaobab = "gaia/tree/baobab"; + const oAcacia = "gaia/tree/acacia"; + const oDatePalm = "gaia/tree/date_palm"; + const oSDatePalm = "gaia/tree/cretan_date_palm_short"; + const oGazelle = "gaia/fauna_gazelle"; + const oGiraffe = "gaia/fauna_giraffe"; + const oLion = "gaia/fauna_lion"; + const oFish = "gaia/fish/generic"; + const oHawk = "birds/buzzard"; + const oStoneLarge = "gaia/rock/savanna_large"; + const oStoneSmall = "gaia/rock/desert_small"; + const oMetalLarge = "gaia/ore/savanna_large"; + const oMetalSmall = "gaia/ore/desert_small"; + + const oHouse = "structures/kush/house"; + const oFarmstead = "structures/kush/farmstead"; + const oField = "structures/kush/field"; + const oPyramid = "structures/kush/pyramid_small"; + const oPyramidLarge = "structures/kush/pyramid_large"; + const oKushUnits = isNomad() ? + "units/kush/support_female_citizen" : + "units/kush/infantry_javelineer_merc_e"; + + const aRain = g_Decoratives.rain; + const aBushA = g_Decoratives.bushA; + const aBushB = g_Decoratives.bushB; + const aBushes = [aBushA, aBushB]; + const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; + const aRockA = g_Decoratives.rock; + const aRockB = "actor|geology/shoreline_large.xml"; + const aRockC = "actor|geology/shoreline_small.xml"; + + const pForestP = [tForestFloor + TERRAIN_SEPARATOR + oAcacia, tForestFloor]; + + const heightSeaGround = g_Heights.seaGround; + const heightReedsDepth = -2.5; + const heightCataract = -1; + const heightShore = 1; + const heightLand = 2; + const heightDunes = 11; + const heightOffsetBump = 1.4; + const heightOffsetBumpPassage = 4; + + global.g_Map = new RandomMap(heightLand, tMainDirt); + + const numPlayers = getNumPlayers(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clKushiteVillages = g_Map.createTileClass(); + const clRiver = g_Map.createTileClass(); + const clShore = g_Map.createTileClass(); + const clDunes = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clRain = g_Map.createTileClass(); + const clCataract = g_Map.createTileClass(); + + const kushVillageBuildings = { + "houseA": { "template": oHouse, "offset": new Vector2D(5, 5) }, + "houseB": { "template": oHouse, "offset": new Vector2D(5, 0) }, + "houseC": { "template": oHouse, "offset": new Vector2D(5, -5) }, + "farmstead": { "template": oFarmstead, "offset": new Vector2D(-5, 0) }, + "fieldA": { "template": oField, "offset": new Vector2D(-5, 5) }, + "fieldB": { "template": oField, "offset": new Vector2D(-5, -5) }, + "pyramid": { "template": oPyramid, "offset": new Vector2D(0, -5) } + }; + + const riverTextures = [ + { + "left": fractionToTiles(0), + "right": fractionToTiles(0.04), + "terrain": tLush, + "tileClass": clShore + }, + { + "left": fractionToTiles(0.04), + "right": fractionToTiles(0.06), + "terrain": tSLush, + "tileClass": clShore + } + ]; + + const riverAngle = Math.PI/5; + + paintRiver({ + "parallel": false, + "start": new Vector2D(fractionToTiles(0.25), mapBounds.top).rotateAround(riverAngle, mapCenter), + "end": new Vector2D(fractionToTiles(0.25), mapBounds.bottom) + .rotateAround(riverAngle, mapCenter), + "width": scaleByMapSize(12, 36), + "fadeDist": scaleByMapSize(3, 12), + "deviation": 1, + "heightRiverbed": heightSeaGround, + "heightLand": heightShore, + "meanderShort": 14, + "meanderLong": 18, + "waterFunc": (position, height, z) => { + clRiver.add(position); + createTerrain(tRiverBank).place(position); + }, + "landFunc": (position, shoreDist1, shoreDist2) => { + for (const riv of riverTextures) + if (riv.left < +shoreDist1 && +shoreDist1 < riv.right || riv.left < -shoreDist2 && + -shoreDist2 < riv.right) + { + riv.tileClass.add(position); + if (riv.terrain) + createTerrain(riv.terrain).place(position); + } + } + }); + yield 10; + + g_Map.log("Creating cataracts"); + for (const x of [fractionToTiles(randFloat(0.15, 0.25)), fractionToTiles(randFloat(0.75, 0.85))]) { - "left": fractionToTiles(0.04), - "right": fractionToTiles(0.06), - "terrain": tSLush, - "tileClass": clShore + const anglePassage = riverAngle + Math.PI / 2 * randFloat(0.8, 1.2); + + const areaPassage = createArea( + new PathPlacer( + new Vector2D(x, mapBounds.bottom).rotateAround(anglePassage, mapCenter), + new Vector2D(x, mapBounds.top).rotateAround(anglePassage, mapCenter), + scaleByMapSize(20, 30), + 0, + 1, + 0, + 0, + Infinity), + [ + new SmoothElevationPainter(ELEVATION_SET, heightCataract, 2), + new TileClassPainter(clCataract) + ], + new HeightConstraint(-Infinity, 0)); + + createAreasInAreas( + new ClumpPlacer(4, 0.4, 0.6, 0.5), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBumpPassage, 2), + undefined, + scaleByMapSize(15, 30), + 20, + [areaPassage]); + + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(aReeds, 2, 4, 0, 1)], true), + 0, + undefined, + scaleByMapSize(20, 50), + 20, + [areaPassage]); } -]; - -const riverAngle = Math.PI/5; - -paintRiver({ - "parallel": false, - "start": new Vector2D(fractionToTiles(0.25), mapBounds.top).rotateAround(riverAngle, mapCenter), - "end": new Vector2D(fractionToTiles(0.25), mapBounds.bottom).rotateAround(riverAngle, mapCenter), - "width": scaleByMapSize(12, 36), - "fadeDist": scaleByMapSize(3, 12), - "deviation": 1, - "heightRiverbed": heightSeaGround, - "heightLand": heightShore, - "meanderShort": 14, - "meanderLong": 18, - "waterFunc": (position, height, z) => { - clRiver.add(position); - createTerrain(tRiverBank).place(position); - }, - "landFunc": (position, shoreDist1, shoreDist2) => { - for (const riv of riverTextures) - if (riv.left < +shoreDist1 && +shoreDist1 < riv.right || riv.left < -shoreDist2 && -shoreDist2 < riv.right) + + const [playerIDs, playerPosition] = playerPlacementRandom(sortAllPlayers(), + avoidClasses(clRiver, 15, clPlayer, 30)); + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad, + "radius": 10, + "width": 3, + "painters": [new TileClassPainter(clPlayer)] + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, { - riv.tileClass.add(position); - if (riv.terrain) - createTerrain(riv.terrain).place(position); + "type": "stone_formation", + "template": oStoneSmall, + "terrain": tSecondaryDirt } + ], + "groupElements": [new RandomObject(aBushes, 2, 4, 2, 3)] + }, + "Trees": { + "template": pickRandom([oBaobab, oAcacia]), + "count": 3 + } + }); + yield 15; + + g_Map.log("Getting random coordinates for Kushite settlements"); + let kushiteTownPositions = []; + for (let retryCount = 0; retryCount < scaleByMapSize(3, 10); ++retryCount) + { + const coordinate = g_Map.randomCoordinate(true); + if (new AndConstraint(avoidClasses(clPlayer, 40, clForest, 5, clKushiteVillages, 50, clRiver, + 15)).allows(coordinate)) + { + kushiteTownPositions.push(coordinate); + createArea( + new ClumpPlacer(40, 0.6, 0.3, Infinity, coordinate), + [ + new TerrainPainter(tRoad), + new TileClassPainter(clKushiteVillages) + ]); + } } -}); -Engine.SetProgress(10); -g_Map.log("Creating cataracts"); -for (const x of [fractionToTiles(randFloat(0.15, 0.25)), fractionToTiles(randFloat(0.75, 0.85))]) -{ - const anglePassage = riverAngle + Math.PI / 2 * randFloat(0.8, 1.2); + g_Map.log("Placing the Kushite buildings"); + for (const coordinate of kushiteTownPositions) + { + for (const building in kushVillageBuildings) + g_Map.placeEntityPassable(kushVillageBuildings[building].template, 0, + Vector2D.add(coordinate, kushVillageBuildings[building].offset), Math.PI); - const areaPassage = createArea( - new PathPlacer( - new Vector2D(x, mapBounds.bottom).rotateAround(anglePassage, mapCenter), - new Vector2D(x, mapBounds.top).rotateAround(anglePassage, mapCenter), - scaleByMapSize(20, 30), - 0, - 1, - 0, - 0, - Infinity), + createObjectGroup(new SimpleGroup([new SimpleObject(oKushUnits, 5, 7, 1, 2)], true, + clKushiteVillages, coordinate), 0); + } + + g_Map.log("Creating kushite pyramids"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oPyramidLarge, 1, 1, 0, 1)], true, clKushiteVillages), + 0, + avoidClasses(clPlayer, 20, clForest, 5, clKushiteVillages, 30, clRiver, 10), + scaleByMapSize(1, 7), + 200); + yield 20; + + g_Map.log("Creating bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + new StaticConstraint(avoidClasses(clPlayer, 5, clKushiteVillages, 10, clRiver, 20)), + scaleByMapSize(300, 800)); + + g_Map.log("Creating dunes"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(5, 15)), 0.5), [ - new SmoothElevationPainter(ELEVATION_SET, heightCataract, 2), - new TileClassPainter(clCataract) + new SmoothElevationPainter(ELEVATION_SET, heightDunes, 2), + new TileClassPainter(clDunes) ], - new HeightConstraint(-Infinity, 0)); - - createAreasInAreas( - new ClumpPlacer(4, 0.4, 0.6, 0.5), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBumpPassage, 2), - undefined, - scaleByMapSize(15, 30), - 20, - [areaPassage]); - - createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(aReeds, 2, 4, 0, 1)], true), + avoidClasses(clPlayer, 3, clRiver, 20, clDunes, 10, clKushiteVillages, 10), + scaleByMapSize(1, 3) * numPlayers * 3); + + yield 25; + + const [forestTrees, stragglerTrees] = getTreeCounts(400, 2000, 0.7); + createForests( + [tMainDirt[0], tForestFloor, tForestFloor, pForestP, pForestP], + avoidClasses(clPlayer, 20, clForest, 20, clDunes, 2, clRiver, 20, clKushiteVillages, 10), + clForest, + forestTrees); + yield 40; + + g_Map.log("Creating dirt patches"); + for (const 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([tSecondaryDirt, tDirt], [1]), + avoidClasses(clDunes, 0, clForest, 0, clPlayer, 5, clRiver, 10), + scaleByMapSize(50, 90)); + + g_Map.log("Creating patches of farmland"); + for (const size of [scaleByMapSize(30, 40), scaleByMapSize(35, 50)]) + createAreas( + new ClumpPlacer(size, 0.4, 0.6), + new TerrainPainter(tFarmland), + avoidClasses(clDunes, 3, clForest, 3, clPlayer, 5, clKushiteVillages, 5, clRiver, 10), + scaleByMapSize(1, 10)); + yield 60; + + g_Map.log("Creating stone mines"); + createObjectGroups( + new SimpleGroup( + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4) + ], true, clRock), 0, - undefined, - scaleByMapSize(20, 50), - 20, - [areaPassage]); -} + avoidClasses(clRiver, 4, clCataract, 4, clPlayer, 20, clRock, 15, clKushiteVillages, 5, clDunes, + 2, clForest, 4), + scaleByMapSize(2, 8), + 50); -const [playerIDs, playerPosition] = playerPlacementRandom(sortAllPlayers(), avoidClasses(clRiver, 15, clPlayer, 30)); -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad, - "radius": 10, - "width": 3, - "painters": [new TileClassPainter(clPlayer)] - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { - "type": "stone_formation", - "template": oStoneSmall, - "terrain": tSecondaryDirt - } - ], - "groupElements": [new RandomObject(aBushes, 2, 4, 2, 3)] - }, - "Trees": { - "template": pickRandom([oBaobab, oAcacia]), - "count": 3 - } -}); -Engine.SetProgress(15); + g_Map.log("Creating small stone quarries"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3, 0, 2 * Math.PI, 1)], true, clRock), + 0, + avoidClasses(clRiver, 4, clCataract, 4, clPlayer, 20, clRock, 15, clKushiteVillages, 5, clDunes, + 2, clForest, 4), + scaleByMapSize(2, 8), + 50); -g_Map.log("Getting random coordinates for Kushite settlements"); -let kushiteTownPositions = []; -for (let retryCount = 0; retryCount < scaleByMapSize(3, 10); ++retryCount) -{ - const coordinate = g_Map.randomCoordinate(true); - if (new AndConstraint(avoidClasses(clPlayer, 40, clForest, 5, clKushiteVillages, 50, clRiver, 15)).allows(coordinate)) - { - kushiteTownPositions.push(coordinate); - createArea( - new ClumpPlacer(40, 0.6, 0.3, Infinity, coordinate), + g_Map.log("Creating metal mines"); + createObjectGroups( + new SimpleGroup( [ - new TerrainPainter(tRoad), - new TileClassPainter(clKushiteVillages) - ]); - } -} + new SimpleObject(oMetalSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oMetalLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4) + ], true, clMetal), + 0, + avoidClasses(clRiver, 4, clCataract, 4, clPlayer, 20, clRock, 10, clMetal, 15, + clKushiteVillages, 5, clDunes, 2, clForest, 4), + scaleByMapSize(2, 8), + 50); -g_Map.log("Placing the Kushite buildings"); -for (const coordinate of kushiteTownPositions) -{ - for (const building in kushVillageBuildings) - g_Map.placeEntityPassable(kushVillageBuildings[building].template, 0, Vector2D.add(coordinate, kushVillageBuildings[building].offset), Math.PI); + g_Map.log("Creating small metal quarries"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oMetalSmall, 2, 5, 1, 3, 0, 2 * Math.PI, 1)], true, clMetal), + 0, + avoidClasses(clRiver, 4, clCataract, 4, clPlayer, 20, clRock, 10, clMetal, 15, + clKushiteVillages, 5, clDunes, 2, clForest, 4), + scaleByMapSize(2, 8), + 50); + yield 70; - createObjectGroup(new SimpleGroup([new SimpleObject(oKushUnits, 5, 7, 1, 2)], true, clKushiteVillages, coordinate), 0); -} + g_Map.log("Creating gazelle"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oGazelle, 4, 6, 1, 4)], true, clFood), + 0, + avoidClasses(clForest, 0, clKushiteVillages, 10, clPlayer, 5, clDunes, 1, clFood, 25, clRiver, + 2, clMetal, 4, clRock, 4), + 2 * numPlayers, + 50); -g_Map.log("Creating kushite pyramids"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oPyramidLarge, 1, 1, 0, 1)], true, clKushiteVillages), - 0, - avoidClasses(clPlayer, 20, clForest, 5, clKushiteVillages, 30, clRiver, 10), - scaleByMapSize(1, 7), - 200); -Engine.SetProgress(20); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 1), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - new StaticConstraint(avoidClasses(clPlayer, 5, clKushiteVillages, 10, clRiver, 20)), - scaleByMapSize(300, 800)); - -g_Map.log("Creating dunes"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(5, 15)), 0.5), - [ - new SmoothElevationPainter(ELEVATION_SET, heightDunes, 2), - new TileClassPainter(clDunes) - ], - avoidClasses(clPlayer, 3, clRiver, 20, clDunes, 10, clKushiteVillages, 10), - scaleByMapSize(1, 3) * numPlayers * 3); - -Engine.SetProgress(25); - -const [forestTrees, stragglerTrees] = getTreeCounts(400, 2000, 0.7); -createForests( - [tMainDirt[0], tForestFloor, tForestFloor, pForestP, pForestP], - avoidClasses(clPlayer, 20, clForest, 20, clDunes, 2, clRiver, 20, clKushiteVillages, 10), - clForest, - forestTrees); -Engine.SetProgress(40); - -g_Map.log("Creating dirt patches"); -for (const 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([tSecondaryDirt, tDirt], [1]), - avoidClasses(clDunes, 0, clForest, 0, clPlayer, 5, clRiver, 10), - scaleByMapSize(50, 90)); + g_Map.log("Creating giraffe"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oGiraffe, 4, 6, 1, 4)], true, clFood), + 0, + avoidClasses(clForest, 0, clKushiteVillages, 10, clPlayer, 5, clDunes, 1, clFood, 25, clRiver, + 2, clMetal, 4, clRock, 4), + 2 * numPlayers, + 50); -g_Map.log("Creating patches of farmland"); -for (const size of [scaleByMapSize(30, 40), scaleByMapSize(35, 50)]) - createAreas( - new ClumpPlacer(size, 0.4, 0.6), - new TerrainPainter(tFarmland), - avoidClasses(clDunes, 3, clForest, 3, clPlayer, 5, clKushiteVillages, 5, clRiver, 10), - scaleByMapSize(1, 10)); -Engine.SetProgress(60); - -g_Map.log("Creating stone mines"); -createObjectGroups( - new SimpleGroup( - [ - new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), - new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4) - ], true, clRock), - 0, - avoidClasses(clRiver, 4, clCataract, 4, clPlayer, 20, clRock, 15, clKushiteVillages, 5, clDunes, 2, clForest, 4), - scaleByMapSize(2, 8), - 50); - -g_Map.log("Creating small stone quarries"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3, 0, 2 * Math.PI, 1)], true, clRock), - 0, - avoidClasses(clRiver, 4, clCataract, 4, clPlayer, 20, clRock, 15, clKushiteVillages, 5, clDunes, 2, clForest, 4), - scaleByMapSize(2, 8), - 50); - -g_Map.log("Creating metal mines"); -createObjectGroups( - new SimpleGroup( + g_Map.log("Creating lions"); + if (!isNomad()) + createObjectGroups( + new SimpleGroup([new SimpleObject(oLion, 2, 3, 0, 2)], true, clFood), + 0, + avoidClasses(clForest, 0, clKushiteVillages, 10, clPlayer, 5, clDunes, 1, clFood, 25, + clRiver, 2, clMetal, 4, clRock, 4), + 3 * numPlayers, + 50); + + g_Map.log("Creating hawk"); + for (let i = 0; i < scaleByMapSize(1, 3); ++i) + g_Map.placeEntityAnywhere(oHawk, 0, mapCenter, randomAngle()); + + g_Map.log("Creating fish"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oFish, 1, 2, 0, 1)], true, clFood), + 0, + [stayClasses(clRiver, 4), avoidClasses(clFood, 16, clCataract, 10)], + scaleByMapSize(15, 80), + 50); + yield 80; + + createStragglerTrees( + [oBaobab, oAcacia], + avoidClasses(clForest, 3, clFood, 1, clDunes, 1, clPlayer, 1, clMetal, 6, clRock, 6, clRiver, + 15, clKushiteVillages, 15), + clForest, + stragglerTrees); + + createStragglerTrees( + [oBaobab, oAcacia], + avoidClasses(clForest, 1, clFood, 1, clDunes, 3, clPlayer, 1, clMetal, 6, clRock, 6, clRiver, + 15, clKushiteVillages, 15), + clForest, + stragglerTrees * (isNomad() ? 3 : 1)); + + createStragglerTrees( + [oDatePalm, oSDatePalm], + [avoidClasses(clPlayer, 5, clFood, 1), stayClasses(clShore, 2)], + clForest, + stragglerTrees * 10); + + yield 90; + + g_Map.log("Creating reeds on the shore"); + createObjectGroups( + new SimpleGroup([new SimpleObject(aReeds, 3, 5, 0, 1)], true), + 0, [ - new SimpleObject(oMetalSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), - new SimpleObject(oMetalLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4) - ], true, clMetal), - 0, - avoidClasses(clRiver, 4, clCataract, 4, clPlayer, 20, clRock, 10, clMetal, 15, clKushiteVillages, 5, clDunes, 2, clForest, 4), - scaleByMapSize(2, 8), - 50); - -g_Map.log("Creating small metal quarries"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oMetalSmall, 2, 5, 1, 3, 0, 2 * Math.PI, 1)], true, clMetal), - 0, - avoidClasses(clRiver, 4, clCataract, 4, clPlayer, 20, clRock, 10, clMetal, 15, clKushiteVillages, 5, clDunes, 2, clForest, 4), - scaleByMapSize(2, 8), - 50); -Engine.SetProgress(70); - -g_Map.log("Creating gazelle"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oGazelle, 4, 6, 1, 4)], true, clFood), - 0, - avoidClasses(clForest, 0, clKushiteVillages, 10, clPlayer, 5, clDunes, 1, clFood, 25, clRiver, 2, clMetal, 4, clRock, 4), - 2 * numPlayers, - 50); - -g_Map.log("Creating giraffe"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oGiraffe, 4, 6, 1, 4)], true, clFood), - 0, - avoidClasses(clForest, 0, clKushiteVillages, 10, clPlayer, 5, clDunes, 1, clFood, 25, clRiver, 2, clMetal, 4, clRock, 4), - 2 * numPlayers, - 50); - -g_Map.log("Creating lions"); -if (!isNomad()) + new HeightConstraint(heightReedsDepth, heightShore), + avoidClasses(clCataract, 2) + ], + scaleByMapSize(500, 1000), + 50); + + g_Map.log("Creating small decorative rocks"); createObjectGroups( - new SimpleGroup([new SimpleObject(oLion, 2, 3, 0, 2)], true, clFood), + new SimpleGroup([new SimpleObject(aRockA, 2, 4, 0, 1)], true), 0, - avoidClasses(clForest, 0, clKushiteVillages, 10, clPlayer, 5, clDunes, 1, clFood, 25, clRiver, 2, clMetal, 4, clRock, 4), - 3 * numPlayers, + avoidClasses(clForest, 0, clPlayer, 0, clDunes, 0, clRiver, 5, clCataract, 5, clMetal, 4, + clRock, 4), + scaleByMapSize(16, 262), + 50); + createObjectGroups( + new SimpleGroup([new SimpleObject(aRockB, 1, 2, 0, 1), + new SimpleObject(aRockC, 1, 3, 0, 1)], true), + 0, + [ + new NearTileClassConstraint(clCataract, 5), + new HeightConstraint(-Infinity, heightShore) + ], + scaleByMapSize(30, 50), 50); -g_Map.log("Creating hawk"); -for (let i = 0; i < scaleByMapSize(1, 3); ++i) - g_Map.placeEntityAnywhere(oHawk, 0, mapCenter, randomAngle()); - -g_Map.log("Creating fish"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oFish, 1, 2, 0, 1)], true, clFood), - 0, - [stayClasses(clRiver, 4), avoidClasses(clFood, 16, clCataract, 10)], - scaleByMapSize(15, 80), - 50); -Engine.SetProgress(80); - -createStragglerTrees( - [oBaobab, oAcacia], - avoidClasses(clForest, 3, clFood, 1, clDunes, 1, clPlayer, 1, clMetal, 6, clRock, 6, clRiver, 15, clKushiteVillages, 15), - clForest, - stragglerTrees); - -createStragglerTrees( - [oBaobab, oAcacia], - avoidClasses(clForest, 1, clFood, 1, clDunes, 3, clPlayer, 1, clMetal, 6, clRock, 6, clRiver, 15, clKushiteVillages, 15), - clForest, - stragglerTrees * (isNomad() ? 3 : 1)); - -createStragglerTrees( - [oDatePalm, oSDatePalm], - [avoidClasses(clPlayer, 5, clFood, 1), stayClasses(clShore, 2)], - clForest, - stragglerTrees * 10); - -Engine.SetProgress(90); - -g_Map.log("Creating reeds on the shore"); -createObjectGroups( - new SimpleGroup([new SimpleObject(aReeds, 3, 5, 0, 1)], true), - 0, - [ - new HeightConstraint(heightReedsDepth, heightShore), - avoidClasses(clCataract, 2) - ], - scaleByMapSize(500, 1000), - 50); - -g_Map.log("Creating small decorative rocks"); -createObjectGroups( - new SimpleGroup([new SimpleObject(aRockA, 2, 4, 0, 1)], true), - 0, - avoidClasses(clForest, 0, clPlayer, 0, clDunes, 0, clRiver, 5, clCataract, 5, clMetal, 4, clRock, 4), - scaleByMapSize(16, 262), - 50); -createObjectGroups( - new SimpleGroup([new SimpleObject(aRockB, 1, 2, 0, 1), new SimpleObject(aRockC, 1, 3, 0, 1)], true), - 0, - [ - new NearTileClassConstraint(clCataract, 5), - new HeightConstraint(-Infinity, heightShore) - ], - scaleByMapSize(30, 50), - 50); - -g_Map.log("Creating bushes"); -createObjectGroups( - new SimpleGroup([new SimpleObject(aBushB, 1, 2, 0, 1), new SimpleObject(aBushA, 1, 3, 0, 2)], true), - 0, - avoidClasses(clForest, 0, clPlayer, 0, clDunes, 0, clRiver, 15, clMetal, 4, clRock, 4), - scaleByMapSize(50, 500), - 50); -Engine.SetProgress(95); - -g_Map.log("Creating rain drops"); -if (aRain) + g_Map.log("Creating bushes"); createObjectGroups( - new SimpleGroup([new SimpleObject(aRain, 1, 1, 1, 4)], true, clRain), + new SimpleGroup([new SimpleObject(aBushB, 1, 2, 0, 1), new SimpleObject(aBushA, 1, 3, 0, 2)], + true), 0, - avoidClasses(clRain, 5), - scaleByMapSize(60, 200)); -Engine.SetProgress(98); + avoidClasses(clForest, 0, clPlayer, 0, clDunes, 0, clRiver, 15, clMetal, 4, clRock, 4), + scaleByMapSize(50, 500), + 50); + yield 95; + + g_Map.log("Creating rain drops"); + if (aRain) + createObjectGroups( + new SimpleGroup([new SimpleObject(aRain, 1, 1, 1, 4)], true, clRain), + 0, + avoidClasses(clRain, 5), + scaleByMapSize(60, 200)); + yield 98; -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clKushiteVillages, 18, clMetal, 4, clRock, 4, clDunes, 4, clFood, 2, clRiver, 5)); + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clKushiteVillages, 18, clMetal, 4, clRock, 4, + clDunes, 4, clFood, 2, clRiver, 5)); -setSunElevation(Math.PI / 8); -setSunRotation(randomAngle()); -setSunColor(0.746, 0.718, 0.539); -setWaterColor(0.292, 0.347, 0.691); -setWaterTint(0.550, 0.543, 0.437); + setSunElevation(Math.PI / 8); + setSunRotation(randomAngle()); + setSunColor(0.746, 0.718, 0.539); + setWaterColor(0.292, 0.347, 0.691); + setWaterTint(0.550, 0.543, 0.437); -setFogColor(0.8, 0.76, 0.61); -setFogThickness(0.2); -setFogFactor(0.2); + setFogColor(0.8, 0.76, 0.61); + setFogThickness(0.2); + setFogFactor(0.2); -setPPEffect("hdr"); -setPPContrast(0.65); -setPPSaturation(0.42); -setPPBloom(0.6); + setPPEffect("hdr"); + setPPContrast(0.65); + setPPSaturation(0.42); + setPPBloom(0.6); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/flood.js =================================================================== --- binaries/data/mods/public/maps/random/flood.js +++ binaries/data/mods/public/maps/random/flood.js @@ -2,299 +2,310 @@ Engine.LoadLibrary("rmgen-common"); 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; - -let tHill = g_Terrains.hill; -let tDirt = g_Terrains.dirt; -if (currentBiome() == "generic/temperate") +function* GenerateMap() { - 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 = 6; -const heightStartingIslands = 2; -const shoreRadius = 6; - -const g_Map = new RandomMap(heightSeaGround, tWater); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clMountain = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -g_Map.log("Creating player islands..."); -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.38)); - -for (let i = 0; i < numPlayers; ++i) - createArea( - new ClumpPlacer(diskArea(1.4 * defaultPlayerBaseRadius()), 0.8, 0.1, Infinity, playerPosition[i]), - [ - new LayeredPainter([tShore, tMainTerrain], [shoreRadius]), - new SmoothElevationPainter(ELEVATION_SET, heightStartingIslands, shoreRadius), - new TileClassPainter(clHill) - ]); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "Walls": false, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oFruitBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oTree2, - "count": 50, - "maxDist": 16, - "maxDistGroup": 7 - }, - "Decoratives": { - "template": aGrassShort + 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; + + let tHill = g_Terrains.hill; + let tDirt = g_Terrains.dirt; + if (currentBiome() == "generic/temperate") + { + tDirt = ["medit_shrubs_a", "grass_field"]; + tHill = ["grass_field", "peat_temp"]; } -}); -Engine.SetProgress(40); - -g_Map.log("Creating central island"); -createArea( - new ChainPlacer( - 6, - Math.floor(scaleByMapSize(10, 15)), - Math.floor(scaleByMapSize(200, 300)), - Infinity, - mapCenter, - 0, - [Math.floor(fractionToTiles(0.01))]), - [ - new LayeredPainter([tShore, tMainTerrain], [shoreRadius, 100]), - new SmoothElevationPainter(ELEVATION_SET, heightLand, shoreRadius), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 40)); - -for (let m = 0; m < randIntInclusive(20, 34); ++m) -{ - const elevRand = randIntInclusive(6, 20); + + 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 = 6; + const heightStartingIslands = 2; + const shoreRadius = 6; + + global.g_Map = new RandomMap(heightSeaGround, tWater); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clMountain = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + g_Map.log("Creating player islands..."); + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.38)); + + for (let i = 0; i < numPlayers; ++i) + createArea( + new ClumpPlacer(diskArea(1.4 * defaultPlayerBaseRadius()), 0.8, 0.1, Infinity, + playerPosition[i]), + [ + new LayeredPainter([tShore, tMainTerrain], [shoreRadius]), + new SmoothElevationPainter(ELEVATION_SET, heightStartingIslands, shoreRadius), + new TileClassPainter(clHill) + ]); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "Walls": false, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oFruitBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oTree2, + "count": 50, + "maxDist": 16, + "maxDistGroup": 7 + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 40; + + g_Map.log("Creating central island"); createArea( new ChainPlacer( - 7, - 15, - Math.floor(scaleByMapSize(15, 20)), + 6, + Math.floor(scaleByMapSize(10, 15)), + Math.floor(scaleByMapSize(200, 300)), Infinity, - new Vector2D(fractionToTiles(randFloat(0, 1)), fractionToTiles(randFloat(0, 1))), + mapCenter, 0, [Math.floor(fractionToTiles(0.01))]), [ - new LayeredPainter([tDirt, tHill], [Math.floor(elevRand / 3), 40]), - new SmoothElevationPainter(ELEVATION_SET, elevRand, Math.floor(elevRand / 3)), + new LayeredPainter([tShore, tMainTerrain], [shoreRadius, 100]), + new SmoothElevationPainter(ELEVATION_SET, heightLand, shoreRadius), new TileClassPainter(clHill) ], - [avoidClasses(clBaseResource, 2, clPlayer, 40), stayClasses(clHill, 6)]); -} - -for (let m = 0; m < randIntInclusive(8, 17); ++m) -{ - const elevRand = randIntInclusive(15, 29); - createArea( - new ChainPlacer( - 5, - 8, + avoidClasses(clPlayer, 40)); + + for (let m = 0; m < randIntInclusive(20, 34); ++m) + { + const elevRand = randIntInclusive(6, 20); + createArea( + new ChainPlacer( + 7, + 15, Math.floor(scaleByMapSize(15, 20)), Infinity, - new Vector2D(randIntExclusive(0, mapSize), randIntExclusive(0, mapSize)), + new Vector2D(fractionToTiles(randFloat(0, 1)), fractionToTiles(randFloat(0, 1))), 0, [Math.floor(fractionToTiles(0.01))]), - [ - new LayeredPainter([tCliff, tForestFloor2], [Math.floor(elevRand / 3), 40]), - new SmoothElevationPainter(ELEVATION_MODIFY, elevRand, Math.floor(elevRand / 3)), - new TileClassPainter(clMountain) - ], - [avoidClasses(clBaseResource, 2, clPlayer, 40), stayClasses(clHill, 6)]); -} + [ + new LayeredPainter([tDirt, tHill], [Math.floor(elevRand / 3), 40]), + new SmoothElevationPainter(ELEVATION_SET, elevRand, Math.floor(elevRand / 3)), + new TileClassPainter(clHill) + ], + [avoidClasses(clBaseResource, 2, clPlayer, 40), stayClasses(clHill, 6)]); + } + + for (let m = 0; m < randIntInclusive(8, 17); ++m) + { + const elevRand = randIntInclusive(15, 29); + createArea( + new ChainPlacer( + 5, + 8, + Math.floor(scaleByMapSize(15, 20)), + Infinity, + new Vector2D(randIntExclusive(0, mapSize), randIntExclusive(0, mapSize)), + 0, + [Math.floor(fractionToTiles(0.01))]), + [ + new LayeredPainter([tCliff, tForestFloor2], [Math.floor(elevRand / 3), 40]), + new SmoothElevationPainter(ELEVATION_MODIFY, elevRand, Math.floor(elevRand / 3)), + new TileClassPainter(clMountain) + ], + [avoidClasses(clBaseResource, 2, clPlayer, 40), stayClasses(clHill, 6)]); + } -g_Map.log("Creating center bounty"); -createObjectGroup( - new SimpleGroup( - [new SimpleObject(oMetalLarge, 3, 6, 25, Math.floor(fractionToTiles(0.25)))], - true, - clBaseResource, - mapCenter), - 0, - [avoidClasses(clBaseResource, 20, clPlayer, 40, clMountain, 4), stayClasses(clHill, 10)]); - -createObjectGroup( - new SimpleGroup( - [new SimpleObject(oStoneLarge, 3, 6, 25, Math.floor(fractionToTiles(0.25)))], - true, - clBaseResource, - mapCenter), + g_Map.log("Creating center bounty"); + createObjectGroup( + new SimpleGroup( + [new SimpleObject(oMetalLarge, 3, 6, 25, Math.floor(fractionToTiles(0.25)))], + true, + clBaseResource, + mapCenter), 0, [avoidClasses(clBaseResource, 20, clPlayer, 40, clMountain, 4), stayClasses(clHill, 10)]); -g_Map.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, 6, clMountain, 2), stayClasses(clHill, 6)], - clForest, - forestTrees); - -const types = [oTree1, oTree2, oTree4, oTree3]; -createStragglerTrees( - types, - [avoidClasses(clBaseResource, 2, clMetal, 6, clRock, 6, clMountain, 2, clPlayer, 25), stayClasses(clHill, 6)], - clForest, - stragglerTrees); -Engine.SetProgress(65); - -g_Map.log("Creating dirt patches"); -const numb = currentBiome() == "generic/savanna" ? 3 : 1; -for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) - createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), + createObjectGroup( + new SimpleGroup( + [new SimpleObject(oStoneLarge, 3, 6, 25, Math.floor(fractionToTiles(0.25)))], + true, + clBaseResource, + mapCenter), + 0, + [avoidClasses(clBaseResource, 20, clPlayer, 40, clMountain, 4), stayClasses(clHill, 10)]); + + g_Map.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, 6, clMountain, + 2), stayClasses(clHill, 6)], + clForest, + forestTrees); + + const types = [oTree1, oTree2, oTree4, oTree3]; + createStragglerTrees( + types, + [avoidClasses(clBaseResource, 2, clMetal, 6, clRock, 6, clMountain, 2, clPlayer, 25), + stayClasses(clHill, 6)], + clForest, + stragglerTrees); + yield 65; + + g_Map.log("Creating dirt patches"); + const numb = currentBiome() == "generic/savanna" ? 3 : 1; + for (const 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]), + new TileClassPainter(clDirt) + ], + avoidClasses(clForest, 0, clMountain, 0, clDirt, 5, clPlayer, 10), + numb * scaleByMapSize(15, 45)); + + g_Map.log("Painting shorelines"); + paintTerrainBasedOnHeight(1, heightStartingIslands, 0, tMainTerrain); + paintTerrainBasedOnHeight(heightSeaGround, 1, 3, tTier1Terrain); + + g_Map.log("Creating grass patches"); + for (const 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)); + + 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); + + yield 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); + + yield 85; + + var planetm = currentBiome() == "generic/india" ? 8 : 1; + createDecoration( [ - new LayeredPainter([[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]), - new TileClassPainter(clDirt) + [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)] ], - avoidClasses(clForest, 0, clMountain, 0, clDirt, 5, clPlayer, 10), - numb * scaleByMapSize(15, 45)); - -g_Map.log("Painting shorelines"); -paintTerrainBasedOnHeight(1, heightStartingIslands, 0, tMainTerrain); -paintTerrainBasedOnHeight(heightSeaGround, 1, 3, tTier1Terrain); - -g_Map.log("Creating grass patches"); -for (const 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)); - -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); - -var planetm = currentBiome() == "generic/india" ? 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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13) - ], - avoidClasses(clForest, 2, clPlayer, 20, clMountain, 5, clFood, 1, clBaseResource, 2)); - -var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(0.1)); -createForests( - [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], - avoidClasses(clPlayer, 30, clHill, 10, clFood, 5), - clForest, - forestTrees); - -g_Map.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); - -g_Map.ExportMap(); + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13) + ], + avoidClasses(clForest, 2, clPlayer, 20, clMountain, 5, clFood, 1, clBaseResource, 2)); + + var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(0.1)); + createForests( + [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], + avoidClasses(clPlayer, 30, clHill, 10, clFood, 5), + clForest, + forestTrees); + + g_Map.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); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/fortress.js =================================================================== --- binaries/data/mods/public/maps/random/fortress.js +++ binaries/data/mods/public/maps/random/fortress.js @@ -1,289 +1,302 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tGrass = ["temperate_grass_04", "temperate_grass_03", "temperate_grass_04"]; -const tForestFloor = "temperate_forestfloor_01"; -const tGrassA = "temperate_grass_05"; -const tGrassB = "temperate_grass_02"; -const tGrassC = "temperate_grass_mud_01"; -const tHill = "temperate_rocks_dirt_01"; -const tCliff = ["temperate_cliff_01", "temperate_cliff_02"]; -const tRoad = "temperate_paving_03"; -const tGrassPatch = "temperate_grass_dirt_01"; -const tShore = "temperate_grass_mud_01"; -const tWater = "temperate_mud_01"; - -const oBeech = "gaia/tree/euro_beech_aut"; -const oOak = "gaia/tree/oak_aut"; -const oPine = "gaia/tree/pine"; -const oDeer = "gaia/fauna_deer"; -const oFish = "gaia/fish/generic"; -const oSheep = "gaia/fauna_rabbit"; -const oBerryBush = "gaia/fruit/berry_01"; -const oStoneLarge = "gaia/rock/temperate_large"; -const oStoneSmall = "gaia/rock/temperate_small"; -const oMetalLarge = "gaia/ore/temperate_01"; -const oMetalSmall = "gaia/ore/temperate_small"; -const oFoodTreasure = "gaia/treasure/food_bin"; -const oWoodTreasure = "gaia/treasure/wood"; -const oStoneTreasure = "gaia/treasure/stone"; -const oMetalTreasure = "gaia/treasure/metal"; - -const aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; -const aGrassShort = "actor|props/flora/grass_soft_dry_large.xml"; -const aRockLarge = "actor|geology/stone_granite_med.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aReeds = "actor|props/flora/reeds_pond_dry.xml"; -const aLillies = "actor|props/flora/water_lillies.xml"; -const aBushMedium = "actor|props/flora/bush_medit_me_dry.xml"; -const aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; - -const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oBeech, tForestFloor]; -const pForestO = [tForestFloor + TERRAIN_SEPARATOR + oOak, tForestFloor]; -const pForestP = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; - -const heightSeaGround = -4; -const heightLand = 3; - -const g_Map = new RandomMap(heightLand, tGrass); - -const numPlayers = getNumPlayers(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -const treasures = [ - { "template": oFoodTreasure, "count": 5 }, - { "template": oWoodTreasure, "count": 5 }, - { "template": oMetalTreasure, "count": 4 }, - { "template": oStoneTreasure, "count": 2 } -]; - -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - -g_Map.log("Creating playerbases"); -const playerAngle = BUILDING_ORIENTATION; -for (let i = 0; i < numPlayers; ++i) +function* GenerateMap() { - if (isNomad()) - break; - - // CC and units - for (const dist of [6, 8]) + const tGrass = ["temperate_grass_04", "temperate_grass_03", "temperate_grass_04"]; + const tForestFloor = "temperate_forestfloor_01"; + const tGrassA = "temperate_grass_05"; + const tGrassB = "temperate_grass_02"; + const tGrassC = "temperate_grass_mud_01"; + const tHill = "temperate_rocks_dirt_01"; + const tCliff = ["temperate_cliff_01", "temperate_cliff_02"]; + const tRoad = "temperate_paving_03"; + const tGrassPatch = "temperate_grass_dirt_01"; + const tShore = "temperate_grass_mud_01"; + const tWater = "temperate_mud_01"; + + const oBeech = "gaia/tree/euro_beech_aut"; + const oOak = "gaia/tree/oak_aut"; + const oPine = "gaia/tree/pine"; + const oDeer = "gaia/fauna_deer"; + const oFish = "gaia/fish/generic"; + const oSheep = "gaia/fauna_rabbit"; + const oBerryBush = "gaia/fruit/berry_01"; + const oStoneLarge = "gaia/rock/temperate_large"; + const oStoneSmall = "gaia/rock/temperate_small"; + const oMetalLarge = "gaia/ore/temperate_01"; + const oMetalSmall = "gaia/ore/temperate_small"; + const oFoodTreasure = "gaia/treasure/food_bin"; + const oWoodTreasure = "gaia/treasure/wood"; + const oStoneTreasure = "gaia/treasure/stone"; + const oMetalTreasure = "gaia/treasure/metal"; + + const aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; + const aGrassShort = "actor|props/flora/grass_soft_dry_large.xml"; + const aRockLarge = "actor|geology/stone_granite_med.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aReeds = "actor|props/flora/reeds_pond_dry.xml"; + const aLillies = "actor|props/flora/water_lillies.xml"; + const aBushMedium = "actor|props/flora/bush_medit_me_dry.xml"; + const aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; + + const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oBeech, tForestFloor]; + const pForestO = [tForestFloor + TERRAIN_SEPARATOR + oOak, tForestFloor]; + const pForestP = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; + + const heightSeaGround = -4; + const heightLand = 3; + + global.g_Map = new RandomMap(heightLand, tGrass); + + const numPlayers = getNumPlayers(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + const treasures = [ + { "template": oFoodTreasure, "count": 5 }, + { "template": oWoodTreasure, "count": 5 }, + { "template": oMetalTreasure, "count": 4 }, + { "template": oStoneTreasure, "count": 2 } + ]; + + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + + g_Map.log("Creating playerbases"); + const playerAngle = BUILDING_ORIENTATION; + for (let i = 0; i < numPlayers; ++i) { - let ents = getStartingEntities(playerIDs[i]); - - if (dist == 8) - ents = ents.filter(ent => ent.Template.indexOf("female") != -1 || ent.Template.indexOf("infantry") != -1); - - placeStartingEntities(playerPosition[i], playerIDs[i], ents, dist); + if (isNomad()) + break; + + // CC and units + for (const dist of [6, 8]) + { + let ents = getStartingEntities(playerIDs[i]); + + if (dist == 8) + ents = ents.filter(ent => ent.Template.indexOf("female") != -1 || + ent.Template.indexOf("infantry") != -1); + + placeStartingEntities(playerPosition[i], playerIDs[i], ents, dist); + } + + // Treasure + for (let j = 0; j < treasures.length; ++j) + createObjectGroup( + new SimpleGroup( + [new SimpleObject(treasures[j].template, treasures[j].count, + treasures[j].count, 0, 2)], + false, + clBaseResource, + Vector2D.add(playerPosition[i], + new Vector2D(10, 0).rotate(-j * Math.PI / 2 - playerAngle))), + 0); + + // Ground texture + const civ = getCivCode(playerIDs[i]); + const tilesSize = civ == "cart" ? 23 : 21; + createArea( + new ConvexPolygonPlacer( + new Array(4).fill(0).map((zero, j) => + new Vector2D(tilesSize, 0).rotate(j * Math.PI / 2 - playerAngle - Math.PI/4) + .add(playerPosition[i])), + Infinity), + [ + new TerrainPainter(tRoad), + new TileClassPainter(clPlayer) + ]); + + // Fortress + const wall = ["gate", "tower", "long", + "cornerIn", "long", "barracks", "tower", "long", "tower", "long", + "cornerIn", "long", "stable", "tower", "gate", "tower", "long", + "cornerIn", "long", "temple", "tower", "long", "tower", "long", + "cornerIn", "long", "market", "tower"]; + + placeCustomFortress(playerPosition[i], + new Fortress("Spahbod", wall), civ, playerIDs[i], playerAngle); } - // Treasure - for (let j = 0; j < treasures.length; ++j) - createObjectGroup( - new SimpleGroup( - [new SimpleObject(treasures[j].template, treasures[j].count, treasures[j].count, 0, 2)], - false, - clBaseResource, - Vector2D.add(playerPosition[i], new Vector2D(10, 0).rotate(-j * Math.PI / 2 - playerAngle))), - 0); - - // Ground texture - const civ = getCivCode(playerIDs[i]); - const tilesSize = civ == "cart" ? 23 : 21; - createArea( - new ConvexPolygonPlacer( - new Array(4).fill(0).map((zero, j) => new Vector2D(tilesSize, 0).rotate(j * Math.PI / 2 - playerAngle - Math.PI/4).add(playerPosition[i])), - Infinity), + g_Map.log("Creating lakes"); + const numLakes = Math.round(scaleByMapSize(1,4) * numPlayers); + const waterAreas = createAreas( + new ClumpPlacer(scaleByMapSize(100,250), 0.8, 0.1, Infinity), [ - new TerrainPainter(tRoad), - new TileClassPainter(clPlayer) - ]); - - // Fortress - const wall = ["gate", "tower", "long", - "cornerIn", "long", "barracks", "tower", "long", "tower", "long", - "cornerIn", "long", "stable", "tower", "gate", "tower", "long", - "cornerIn", "long", "temple", "tower", "long", "tower", "long", - "cornerIn", "long", "market", "tower"]; - - placeCustomFortress(playerPosition[i], new Fortress("Spahbod", wall), civ, playerIDs[i], playerAngle); -} + new LayeredPainter([tShore, tWater], [1]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 3), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 7, clWater, 20), + numLakes); + + yield 15; + + g_Map.log("Creating reeds"); + createObjectGroupsByAreasDeprecated( + new SimpleGroup([new SimpleObject(aReeds, 5,10, 0,4), + new SimpleObject(aLillies, 0,1, 0,4)], true), + 0, + [borderClasses(clWater, 3, 0), stayClasses(clWater, 1)], + numLakes, 100, + waterAreas); + + yield 25; + + g_Map.log("Creating fish"); + createObjectGroupsByAreasDeprecated( + new SimpleGroup( + [new SimpleObject(oFish, 1,1, 0,1)], + true, clFood + ), + 0, + [stayClasses(clWater, 4), avoidClasses(clFood, 8)], + numLakes / 4, + 50, + waterAreas); + yield 30; + + createBumps(avoidClasses(clWater, 2, clPlayer, 5)); + yield 35; + + createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 5, clWater, 5, clHill, 15), clHill, + scaleByMapSize(1, 4) * numPlayers); + yield 40; + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.7); + const types = [ + [[tForestFloor, tGrass, pForestD], [tForestFloor, pForestD]], + [[tForestFloor, tGrass, pForestO], [tForestFloor, pForestO]], + [[tForestFloor, tGrass, pForestP], [tForestFloor, pForestP]] + ]; + const size = forestTrees / (scaleByMapSize(3,6) * numPlayers); + const num = Math.floor(size / types.length); + for (const type of types) + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), forestTrees / num, 0.5), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 5, clWater, 3, clForest, 15, clHill, 1), + num); + yield 50; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tGrass,tGrassA],[tGrassA,tGrassB], [tGrassB,tGrassC]], + [1,1], + avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 1), + scaleByMapSize(15, 45), + clDirt); + yield 55; + + g_Map.log("Creating grass patches"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tGrassPatch, + avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 1), + scaleByMapSize(15, 45), + clDirt); + yield 60; + + g_Map.log("Creating stone mines"); + createMines( + [ + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oStoneSmall, 2,5, 1,3)] + ], + avoidClasses(clWater, 0, clForest, 1, clPlayer, 5, clRock, 10, clHill, 1), + clRock); + yield 65; + + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + avoidClasses(clWater, 0, clForest, 1, clPlayer, 5, clMetal, 10, clRock, 5, clHill, 1) + ); + yield 70; + + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13) + ], + avoidClasses(clWater, 0, clForest, 0, clPlayer, 1, clHill, 0)); + yield 80; -g_Map.log("Creating lakes"); -const numLakes = Math.round(scaleByMapSize(1,4) * numPlayers); -const waterAreas = createAreas( - new ClumpPlacer(scaleByMapSize(100,250), 0.8, 0.1, Infinity), - [ - new LayeredPainter([tShore, tWater], [1]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 3), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 7, clWater, 20), - numLakes); - -Engine.SetProgress(15); - -g_Map.log("Creating reeds"); -createObjectGroupsByAreasDeprecated( - new SimpleGroup([new SimpleObject(aReeds, 5,10, 0,4), new SimpleObject(aLillies, 0,1, 0,4)], true), - 0, - [borderClasses(clWater, 3, 0), stayClasses(clWater, 1)], - numLakes, 100, - waterAreas); - -Engine.SetProgress(25); - -g_Map.log("Creating fish"); -createObjectGroupsByAreasDeprecated( - new SimpleGroup( - [new SimpleObject(oFish, 1,1, 0,1)], - true, clFood - ), - 0, - [stayClasses(clWater, 4), avoidClasses(clFood, 8)], - numLakes / 4, - 50, - waterAreas); -Engine.SetProgress(30); - -createBumps(avoidClasses(clWater, 2, clPlayer, 5)); -Engine.SetProgress(35); - -createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 5, clWater, 5, clHill, 15), clHill, scaleByMapSize(1, 4) * numPlayers); -Engine.SetProgress(40); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.7); -const types = [ - [[tForestFloor, tGrass, pForestD], [tForestFloor, pForestD]], - [[tForestFloor, tGrass, pForestO], [tForestFloor, pForestO]], - [[tForestFloor, tGrass, pForestP], [tForestFloor, pForestP]] -]; -const size = forestTrees / (scaleByMapSize(3,6) * numPlayers); -const num = Math.floor(size / types.length); -for (const type of types) - createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), forestTrees / num, 0.5), + createFood( [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) + [new SimpleObject(oSheep, 2, 3, 0, 2)], + [new SimpleObject(oDeer, 5, 7, 0, 4)] ], - avoidClasses(clPlayer, 5, clWater, 3, clForest, 15, clHill, 1), - num); -Engine.SetProgress(50); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tGrass,tGrassA],[tGrassA,tGrassB], [tGrassB,tGrassC]], - [1,1], - avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 1), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(55); - -g_Map.log("Creating grass patches"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tGrassPatch, - avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 1), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(60); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2,5, 1,3)] - ], - avoidClasses(clWater, 0, clForest, 1, clPlayer, 5, clRock, 10, clHill, 1), - clRock); -Engine.SetProgress(65); - -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - avoidClasses(clWater, 0, clForest, 1, clPlayer, 5, clMetal, 10, clRock, 5, clHill, 1) -); -Engine.SetProgress(70); - -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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13) - ], - avoidClasses(clWater, 0, clForest, 0, clPlayer, 1, clHill, 0)); -Engine.SetProgress(80); - -createFood( - [ - [new SimpleObject(oSheep, 2, 3, 0, 2)], - [new SimpleObject(oDeer, 5, 7, 0, 4)] - ], - [ - 3 * numPlayers, - 3 * numPlayers - ], - avoidClasses(clWater, 0, clForest, 0, clPlayer, 6, clHill, 1, clFood, 20), - clFood); -Engine.SetProgress(85); - -createFood( - [ - [new SimpleObject(oBerryBush, 5, 7, 0, 4)] - ], - [ - randIntInclusive(1, 4) * numPlayers + 2 - ], - avoidClasses(clWater, 2, clForest, 0, clPlayer, 6, clHill, 1, clFood, 10), - clFood); - -Engine.SetProgress(90); - -createStragglerTrees( - [oOak, oBeech, oPine], - avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 1, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); -Engine.SetProgress(95); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 2, clHill, 2, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setSkySet("sunny"); -setWaterColor(0.157, 0.149, 0.443); -setWaterTint(0.443,0.42,0.824); -setWaterWaviness(2.0); -setWaterType("lake"); -setWaterMurkiness(0.83); - -setFogFactor(0.35); -setFogThickness(0.22); -setFogColor(0.82,0.82, 0.73); -setPPSaturation(0.56); -setPPContrast(0.56); -setPPBloom(0.38); -setPPEffect("hdr"); - -g_Map.ExportMap(); + [ + 3 * numPlayers, + 3 * numPlayers + ], + avoidClasses(clWater, 0, clForest, 0, clPlayer, 6, clHill, 1, clFood, 20), + clFood); + yield 85; + + createFood( + [ + [new SimpleObject(oBerryBush, 5, 7, 0, 4)] + ], + [ + randIntInclusive(1, 4) * numPlayers + 2 + ], + avoidClasses(clWater, 2, clForest, 0, clPlayer, 6, clHill, 1, clFood, 10), + clFood); + + yield 90; + + createStragglerTrees( + [oOak, oBeech, oPine], + avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 1, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + yield 95; + + placePlayersNomad(clPlayer, avoidClasses(clWater, 2, clHill, 2, clForest, 1, clMetal, 4, clRock, 4, + clHill, 4, clFood, 2)); + + setSkySet("sunny"); + setWaterColor(0.157, 0.149, 0.443); + setWaterTint(0.443,0.42,0.824); + setWaterWaviness(2.0); + setWaterType("lake"); + setWaterMurkiness(0.83); + + setFogFactor(0.35); + setFogThickness(0.22); + setFogColor(0.82,0.82, 0.73); + setPPSaturation(0.56); + setPPContrast(0.56); + setPPBloom(0.38); + setPPEffect("hdr"); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/frontier.js =================================================================== --- binaries/data/mods/public/maps/random/frontier.js +++ binaries/data/mods/public/maps/random/frontier.js @@ -3,291 +3,295 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setSelectedBiome(); +function* GenerateMap(mapSettings) +{ + setSelectedBiome(); -// Random elevation with a bias towards lower elevations -let randElevation = randIntInclusive(0, 29); -if (randElevation < 25) - randElevation = randIntInclusive(1, 4); + // Random elevation with a bias towards lower elevations + let randElevation = randIntInclusive(0, 29); + if (randElevation < 25) + randElevation = randIntInclusive(1, 4); -const g_Map = new RandomMap(randElevation, g_Terrains.mainTerrain); + global.g_Map = new RandomMap(randElevation, g_Terrains.mainTerrain); -initTileClasses(); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land)); + initTileClasses(); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land)); -Engine.SetProgress(20); + yield 20; -if (!isNomad()) -{ - // Note: `|| pickRandom(...)` is needed for atlas. - const pattern = g_MapSettings.TeamPlacement || pickRandom(["line", "radial", "randomGroup", "stronghold"]); - createBases( - ...playerPlacementByPattern( - pattern, - fractionToTiles(randFloat(0.2, 0.35)), - fractionToTiles(randFloat(0.08, 0.1)), - randomAngle(), - undefined), - g_PlayerbaseTypes[pattern].walls); -} -Engine.SetProgress(40); - -let features = [ - { - "func": addBluffs, - "baseHeight": randElevation, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.hill, 10, - g_TileClasses.mountain, 20, - g_TileClasses.plateau, 15, - g_TileClasses.player, 30, - g_TileClasses.valley, 5, - g_TileClasses.water, 7 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, + if (!isNomad()) { - "func": addHills, - "avoid": [ - g_TileClasses.bluff, 5, - g_TileClasses.hill, 15, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 15, - g_TileClasses.player, 20, - g_TileClasses.valley, 2, - g_TileClasses.water, 2 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addMountains, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.mountain, 25, - g_TileClasses.plateau, 15, - g_TileClasses.player, 20, - g_TileClasses.valley, 10, - g_TileClasses.water, 15 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addPlateaus, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.mountain, 25, - g_TileClasses.plateau, 25, - g_TileClasses.plateau, 25, - g_TileClasses.player, 40, - g_TileClasses.valley, 10, - g_TileClasses.water, 15 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts + // Note: `|| pickRandom(...)` is needed for atlas. + const pattern = mapSettings.TeamPlacement || + pickRandom(["line", "radial", "randomGroup", "stronghold"]); + createBases( + ...playerPlacementByPattern( + pattern, + fractionToTiles(randFloat(0.2, 0.35)), + fractionToTiles(randFloat(0.08, 0.1)), + randomAngle(), + undefined), + g_PlayerbaseTypes[pattern].walls); } -]; + yield 40; -if (randElevation < 4) - features.push({ - "func": addLakes, - "avoid": [ - g_TileClasses.bluff, 7, - g_TileClasses.hill, 2, - g_TileClasses.mountain, 15, - g_TileClasses.plateau, 10, - g_TileClasses.player, 20, - g_TileClasses.valley, 10, - g_TileClasses.water, 25 - ], - "sizes": ["small"], - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }); + let features = [ + { + "func": addBluffs, + "baseHeight": randElevation, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.hill, 10, + g_TileClasses.mountain, 20, + g_TileClasses.plateau, 15, + g_TileClasses.player, 30, + g_TileClasses.valley, 5, + g_TileClasses.water, 7 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addHills, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.hill, 15, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 15, + g_TileClasses.player, 20, + g_TileClasses.valley, 2, + g_TileClasses.water, 2 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addMountains, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 15, + g_TileClasses.player, 20, + g_TileClasses.valley, 10, + g_TileClasses.water, 15 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addPlateaus, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 25, + g_TileClasses.plateau, 25, + g_TileClasses.player, 40, + g_TileClasses.valley, 10, + g_TileClasses.water, 15 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + } + ]; -if (randElevation > 20) - features.push({ - "func": addValleys, - "baseHeight": randElevation, - "avoid": [ - g_TileClasses.bluff, 5, - g_TileClasses.hill, 5, - g_TileClasses.mountain, 25, - g_TileClasses.plateau, 20, - g_TileClasses.player, 40, - g_TileClasses.valley, 15, - g_TileClasses.water, 10 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }); + if (randElevation < 4) + features.push({ + "func": addLakes, + "avoid": [ + g_TileClasses.bluff, 7, + g_TileClasses.hill, 2, + g_TileClasses.mountain, 15, + g_TileClasses.plateau, 10, + g_TileClasses.player, 20, + g_TileClasses.valley, 10, + g_TileClasses.water, 25 + ], + "sizes": ["small"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }); -addElements(shuffleArray(features)); -Engine.SetProgress(50); + if (randElevation > 20) + features.push({ + "func": addValleys, + "baseHeight": randElevation, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.hill, 5, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 20, + g_TileClasses.player, 40, + g_TileClasses.valley, 15, + g_TileClasses.water, 10 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }); -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - } -]); -Engine.SetProgress(60); + addElements(shuffleArray(features)); + yield 50; -addElements(shuffleArray([ - { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.metal, 20, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": g_AllAmounts - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 10, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": g_AllAmounts - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 18, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 5, - g_TileClasses.plateau, 5, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.water, 2 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": ["few", "normal", "many", "tons"] - } -])); -Engine.SetProgress(70); + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + } + ]); + yield 60; -addElements(shuffleArray([ - { - "func": addBerries, - "avoid": [ - g_TileClasses.berries, 30, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 5, - g_TileClasses.metal, 10, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 10, - g_TileClasses.water, 3 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.water, 3 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 7, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.water, 5 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - } -])); -Engine.SetProgress(90); + addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 20, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": g_AllAmounts + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": g_AllAmounts + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 18, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.plateau, 5, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": ["few", "normal", "many", "tons"] + } + ])); + yield 70; -placePlayersNomad( - g_TileClasses.player, - avoidClasses( - g_TileClasses.bluff, 4, - g_TileClasses.water, 4, - g_TileClasses.forest, 1, - g_TileClasses.metal, 4, - g_TileClasses.rock, 4, - g_TileClasses.mountain, 4, - g_TileClasses.plateau, 4, - g_TileClasses.animals, 2)); + addElements(shuffleArray([ + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 10, + g_TileClasses.water, 3 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.water, 3 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 7, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.water, 5 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + } + ])); + yield 90; -g_Map.ExportMap(); + placePlayersNomad( + g_TileClasses.player, + avoidClasses( + g_TileClasses.bluff, 4, + g_TileClasses.water, 4, + g_TileClasses.forest, 1, + g_TileClasses.metal, 4, + g_TileClasses.rock, 4, + g_TileClasses.mountain, 4, + g_TileClasses.plateau, 4, + g_TileClasses.animals, 2)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/gear.js =================================================================== --- binaries/data/mods/public/maps/random/gear.js +++ binaries/data/mods/public/maps/random/gear.js @@ -4,313 +4,327 @@ 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]; - -const heightSeaGround = -4; -const heightShallow = -2; -const heightLand = 3; -const heightRing = 4; -const heightHill = 20; - -const g_Map = new RandomMap(heightLand, tMainTerrain); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -const radiusPlayers = fractionToTiles(0.35); -const radiusCentralLake = fractionToTiles(0.27); -const radiusCentralRingLand = fractionToTiles(0.21); -const radiusCentralWaterRing = fractionToTiles(0.17); -const radiusCentralIsland = fractionToTiles(0.14); -const radiusCentralHill = fractionToTiles(0.12); - -const [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(radiusPlayers); - -g_Map.log("Determining number of rivers between players"); -let split = 1; -if (mapSize == 128 && numPlayers <= 2) - split = 2; -else if (mapSize == 192 && numPlayers <= 3) - split = 2; -else if (mapSize == 256) +function* GenerateMap() { - if (numPlayers <= 3) - split = 3; - else if (numPlayers == 4) + 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]; + + const heightSeaGround = -4; + const heightShallow = -2; + const heightLand = 3; + const heightRing = 4; + const heightHill = 20; + + global.g_Map = new RandomMap(heightLand, tMainTerrain); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + const radiusPlayers = fractionToTiles(0.35); + const radiusCentralLake = fractionToTiles(0.27); + const radiusCentralRingLand = fractionToTiles(0.21); + const radiusCentralWaterRing = fractionToTiles(0.17); + const radiusCentralIsland = fractionToTiles(0.14); + const radiusCentralHill = fractionToTiles(0.12); + + const [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(radiusPlayers); + + g_Map.log("Determining number of rivers between players"); + let split = 1; + if (mapSize == 128 && numPlayers <= 2) split = 2; -} -else if (mapSize == 320) -{ - if (numPlayers <= 3) - split = 3; - else if (numPlayers == 4) + else if (mapSize == 192 && numPlayers <= 3) 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; -} + 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; + } -g_Map.log("Creating big circular lake"); -createArea( - new DiskPlacer(radiusCentralLake, mapCenter), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4)); + g_Map.log("Creating big circular lake"); + createArea( + new DiskPlacer(radiusCentralLake, mapCenter), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4)); + + g_Map.log("Creating rivers between players"); + for (let m = 0; m < numPlayers * split; ++m) + { + const angle = startAngle + (m + 0.5) * 2 * Math.PI / (numPlayers * split); + const position1 = Vector2D.add(mapCenter, + new Vector2D(fractionToTiles(0.15), 0).rotate(-angle)); + const position2 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.6), 0).rotate(-angle)); + createArea( + new PathPlacer(position1, position2, scaleByMapSize(14, 40), 0, scaleByMapSize(3, 9), 0.2, + 0.05), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), + avoidClasses(clPlayer, 5)); + } -g_Map.log("Creating rivers between players"); -for (let m = 0; m < numPlayers * split; ++m) -{ - const angle = startAngle + (m + 0.5) * 2 * Math.PI / (numPlayers * split); - const position1 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.15), 0).rotate(-angle)); - const position2 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.6), 0).rotate(-angle)); + g_Map.log("Create path from the island to the center"); + for (let m = 0; m < numPlayers * split; ++m) + { + const angle = startAngle + m * 2 * Math.PI / (numPlayers * split); + const position1 = + Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.05), 0).rotate(-angle)); + const position2 = + Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.49), 0).rotate(-angle)); + createArea( + new PathPlacer(position1, position2, scaleByMapSize(10, 40), 0, scaleByMapSize(3, 9), 0.2, + 0.05), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 4)); + } + + g_Map.log("Creating ring of land connecting players"); createArea( - new PathPlacer(position1, position2, scaleByMapSize(14, 40), 0, scaleByMapSize(3, 9), 0.2, 0.05), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), - avoidClasses(clPlayer, 5)); -} + new DiskPlacer(radiusCentralRingLand, mapCenter), + new SmoothElevationPainter(ELEVATION_SET, heightRing, 4)); -g_Map.log("Create path from the island to the center"); -for (let m = 0; m < numPlayers * split; ++m) -{ - const angle = startAngle + m * 2 * Math.PI / (numPlayers * split); - const position1 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.05), 0).rotate(-angle)); - const position2 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.49), 0).rotate(-angle)); + g_Map.log("Creating inner ring of water"); createArea( - new PathPlacer(position1, position2, scaleByMapSize(10, 40), 0, scaleByMapSize(3, 9), 0.2, 0.05), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 4)); -} + new DiskPlacer(radiusCentralWaterRing, mapCenter), + new SmoothElevationPainter(ELEVATION_SET, heightShallow, 3)); -g_Map.log("Creating ring of land connecting players"); -createArea( - new DiskPlacer(radiusCentralRingLand, mapCenter), - new SmoothElevationPainter(ELEVATION_SET, heightRing, 4)); - -g_Map.log("Creating inner ring of water"); -createArea( - new DiskPlacer(radiusCentralWaterRing, mapCenter), - new SmoothElevationPainter(ELEVATION_SET, heightShallow, 3)); - -g_Map.log("Creating central island"); -createArea( - new DiskPlacer(radiusCentralIsland, mapCenter), - new SmoothElevationPainter(ELEVATION_SET, heightRing, 3)); - -g_Map.log("Creating hill on the central island"); -createArea( - new DiskPlacer(radiusCentralHill, mapCenter), - 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 - }, - "StartingAnimal": { - }, - "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); - -const [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); - -g_Map.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); - -g_Map.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); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2,5, 1,3)] - ], - avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - clRock); - -g_Map.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 -); - -g_Map.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); - -let planetm = 1; - -if (currentBiome() == "generic/india") - 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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13) - ], - 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)); - -g_Map.ExportMap(); + g_Map.log("Creating central island"); + createArea( + new DiskPlacer(radiusCentralIsland, mapCenter), + new SmoothElevationPainter(ELEVATION_SET, heightRing, 3)); + + g_Map.log("Creating hill on the central island"); + createArea( + new DiskPlacer(radiusCentralHill, mapCenter), + 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 + }, + "StartingAnimal": { + }, + "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); + + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + createForests( + [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], + avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 2), + clForest, + forestTrees); + + yield 50; + + g_Map.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); + + g_Map.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); + yield 55; + + g_Map.log("Creating stone mines"); + createMines( + [ + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oStoneSmall, 2,5, 1,3)] + ], + avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + clRock); + + g_Map.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 + ); + + g_Map.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); + + yield 65; + + let planetm = 1; + + if (currentBiome() == "generic/india") + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13) + ], + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); + + yield 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)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/guadalquivir_river.js =================================================================== --- binaries/data/mods/public/maps/random/guadalquivir_river.js +++ binaries/data/mods/public/maps/random/guadalquivir_river.js @@ -1,290 +1,297 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tGrass = ["medit_grass_field_a", "medit_grass_field_b"]; -const tForestFloorC = "medit_plants_dirt"; -const tForestFloorP = "medit_grass_shrubs"; -const tGrassA = "medit_grass_field_b"; -const tGrassB = "medit_grass_field_brown"; -const tGrassC = "medit_grass_field_dry"; -const tRoad = "medit_city_tile"; -const tRoadWild = "medit_city_tile"; -const tGrassPatch = "medit_grass_shrubs"; -const tShore = "sand_grass_25"; -const tWater = "medit_sand_wet"; - -const oPoplar = "gaia/tree/poplar"; -const oApple = "gaia/fruit/apple"; -const oCarob = "gaia/tree/carob"; -const oBerryBush = "gaia/fruit/berry_01"; -const oDeer = "gaia/fauna_deer"; -const oFish = "gaia/fish/generic"; -const oSheep = "gaia/fauna_sheep"; -const oStoneLarge = "gaia/rock/mediterranean_large"; -const oStoneSmall = "gaia/rock/mediterranean_small"; -const oMetalLarge = "gaia/ore/mediterranean_large"; - -const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; -const aGrassShort = "actor|props/flora/grass_soft_large.xml"; -const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; -const aLillies = "actor|props/flora/water_lillies.xml"; -const aRockLarge = "actor|geology/stone_granite_large.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aBushMedium = "actor|props/flora/bush_medit_me.xml"; -const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; - -const pForestP = [tForestFloorP + TERRAIN_SEPARATOR + oPoplar, tForestFloorP]; -const pForestC = [tForestFloorC + TERRAIN_SEPARATOR + oCarob, tForestFloorC]; - -const heightSeaGround = -3; -const heightShallow = -1.5; -const heightShore = 2; -const heightLand = 3; - -const g_Map = new RandomMap(heightSeaGround, tWater); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clLand = g_Map.createTileClass(); -const clRiver = g_Map.createTileClass(); -const clShallow = g_Map.createTileClass(); - -g_Map.log("Create the continent body"); -const startAngle = randomAngle(); -const continentCenter = new Vector2D(fractionToTiles(0.5), fractionToTiles(0.7)).rotateAround(startAngle, mapCenter).round(); - -createArea( - new ChainPlacer( - 2, - Math.floor(scaleByMapSize(5, 12)), - Math.floor(scaleByMapSize(60, 700)), - Infinity, +function* GenerateMap() +{ + const tGrass = ["medit_grass_field_a", "medit_grass_field_b"]; + const tForestFloorC = "medit_plants_dirt"; + const tForestFloorP = "medit_grass_shrubs"; + const tGrassA = "medit_grass_field_b"; + const tGrassB = "medit_grass_field_brown"; + const tGrassC = "medit_grass_field_dry"; + const tRoad = "medit_city_tile"; + const tRoadWild = "medit_city_tile"; + const tGrassPatch = "medit_grass_shrubs"; + const tShore = "sand_grass_25"; + const tWater = "medit_sand_wet"; + + const oPoplar = "gaia/tree/poplar"; + const oApple = "gaia/fruit/apple"; + const oCarob = "gaia/tree/carob"; + const oBerryBush = "gaia/fruit/berry_01"; + const oDeer = "gaia/fauna_deer"; + const oFish = "gaia/fish/generic"; + const oSheep = "gaia/fauna_sheep"; + const oStoneLarge = "gaia/rock/mediterranean_large"; + const oStoneSmall = "gaia/rock/mediterranean_small"; + const oMetalLarge = "gaia/ore/mediterranean_large"; + + const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; + const aGrassShort = "actor|props/flora/grass_soft_large.xml"; + const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; + const aLillies = "actor|props/flora/water_lillies.xml"; + const aRockLarge = "actor|geology/stone_granite_large.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aBushMedium = "actor|props/flora/bush_medit_me.xml"; + const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; + + const pForestP = [tForestFloorP + TERRAIN_SEPARATOR + oPoplar, tForestFloorP]; + const pForestC = [tForestFloorC + TERRAIN_SEPARATOR + oCarob, tForestFloorC]; + + const heightSeaGround = -3; + const heightShallow = -1.5; + const heightShore = 2; + const heightLand = 3; + + global.g_Map = new RandomMap(heightSeaGround, tWater); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clLand = g_Map.createTileClass(); + const clRiver = g_Map.createTileClass(); + const clShallow = g_Map.createTileClass(); + + g_Map.log("Create the continent body"); + const startAngle = randomAngle(); + const continentCenter = new Vector2D(fractionToTiles(0.5), fractionToTiles(0.7)) + .rotateAround(startAngle, mapCenter).round(); + + createArea( + new ChainPlacer( + 2, + Math.floor(scaleByMapSize(5, 12)), + Math.floor(scaleByMapSize(60, 700)), + Infinity, + continentCenter, + 0, + [Math.floor(fractionToTiles(0.49))]), + [ + new TerrainPainter(tGrass), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), + new TileClassPainter(clLand) + ]); + + const playerIDs = sortAllPlayers(); + const playerPosition = playerPlacementArcs( + playerIDs, continentCenter, + fractionToTiles(0.35), + -startAngle - 0.5 * Math.PI, 0, - [Math.floor(fractionToTiles(0.49))]), - [ - new TerrainPainter(tGrass), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), - new TileClassPainter(clLand) - ]); - -const playerIDs = sortAllPlayers(); -const playerPosition = playerPlacementArcs( - playerIDs, - continentCenter, - fractionToTiles(0.35), - -startAngle - 0.5 * Math.PI, - 0, - 0.65 * Math.PI); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "Walls": false, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oPoplar, - "count": 2 - }, - "Decoratives": { - "template": aGrassShort - } -}); -Engine.SetProgress(20); - -paintRiver({ - "parallel": true, - "constraint": stayClasses(clLand, 0), - "start": new Vector2D(mapCenter.x, mapBounds.top).rotateAround(startAngle, mapCenter), - "end": new Vector2D(mapCenter.x, mapBounds.bottom).rotateAround(startAngle, mapCenter), - "width": fractionToTiles(0.07), - "fadeDist": scaleByMapSize(3, 12), - "deviation": 1, - "heightRiverbed": heightSeaGround, - "heightLand": heightShore, - "meanderShort": 12, - "meanderLong": 0, - "waterFunc": (position, height, z) => { - clRiver.add(position); - createTerrain(tWater).place(position); - - if (height < heightShallow && ( - z > 0.3 && z < 0.4 || - z > 0.5 && z < 0.6 || - z > 0.7 && z < 0.8)) - { - g_Map.setHeight(position, heightShallow); - clShallow.add(position); + 0.65 * Math.PI); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "Walls": false, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oPoplar, + "count": 2 + }, + "Decoratives": { + "template": aGrassShort } - } -}); - -paintTerrainBasedOnHeight(1, 3, 0, tShore); -paintTerrainBasedOnHeight(-8, 1, 2, tWater); - -createBumps([avoidClasses(clPlayer, 20, clRiver, 1), stayClasses(clLand, 3)]); - -const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); -createForests( - [tGrass, tForestFloorP, tForestFloorC, pForestC, pForestP], - [avoidClasses(clPlayer, 20, clForest, 17, clRiver, 1), stayClasses(clLand, 7)], - clForest, - forestTrees); - -Engine.SetProgress(50); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tGrass,tGrassA],[tGrassA,tGrassB], [tGrassB,tGrassC]], - [1,1], - [avoidClasses(clForest, 0, clDirt, 3, clPlayer, 8, clRiver, 1), stayClasses(clLand, 7)], - scaleByMapSize(15, 45), - clDirt); - -g_Map.log("Creating grass patches"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tGrassPatch, - [avoidClasses(clForest, 0, clDirt, 3, clPlayer, 8, clRiver, 1), stayClasses(clLand, 7)], - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(55); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2,5, 1,3)] - ], - [avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clRiver, 1), stayClasses(clLand, 5)], - clRock); - -g_Map.log("Creating metal mines"); -createMines( - [ - [new SimpleObject(oMetalLarge, 1,1, 0,4)] - ], - [avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clRiver, 1), stayClasses(clLand, 5)], - clMetal -); -Engine.SetProgress(65); - -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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13) - ], - [avoidClasses(clPlayer, 1, clDirt, 1, clRiver, 1), stayClasses(clLand, 6)]); - -g_Map.log("Create water decoration in the shallow parts"); -createDecoration( - [ - [new SimpleObject(aReeds, 1, 3, 0, 1)], - [new SimpleObject(aLillies, 1, 2, 0, 1)] - ], - [ - scaleByMapAreaAbsolute(800), - scaleByMapAreaAbsolute(800) - ], - stayClasses(clShallow, 0)); - -Engine.SetProgress(70); - -createFood( - [ - [new SimpleObject(oDeer, 5, 7, 0, 4)], - [new SimpleObject(oSheep, 2, 3, 0, 2)] - ], - [ - 3 * numPlayers, - 3 * numPlayers - ], - [avoidClasses(clForest, 0, clPlayer, 20, clFood, 20, clRiver, 1), stayClasses(clLand, 3)], - clFood); - -createFood( - [ - [new SimpleObject(oBerryBush, 5, 7, 0, 4)] - ], - [ - randIntInclusive(1, 4) * numPlayers + 2 - ], - [avoidClasses(clForest, 0, clPlayer, 20, clFood, 10, clRiver, 1), stayClasses(clLand, 3)], - clFood); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 25 * numPlayers - ], - avoidClasses(clLand, 2, clRiver, 1), - clFood); - -Engine.SetProgress(85); - -createStragglerTrees( - [oPoplar, oCarob, oApple], - [avoidClasses(clForest, 1, clPlayer, 9, clMetal, 6, clRock, 6, clRiver, 1), stayClasses(clLand, 7)], - clForest, - stragglerTrees); - -placePlayersNomad( - clPlayer, - new AndConstraint([ - stayClasses(clLand, 4), - avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clFood, 2)])); - -setSkySet("cumulus"); -setWaterColor(0.2,0.312,0.522); -setWaterTint(0.1,0.1,0.8); -setWaterWaviness(4.0); -setWaterType("lake"); -setWaterMurkiness(0.73); - -setFogFactor(0.3); -setFogThickness(0.25); - -setPPEffect("hdr"); -setPPContrast(0.62); -setPPSaturation(0.51); -setPPBloom(0.12); - -g_Map.ExportMap(); + }); + yield 20; + + paintRiver({ + "parallel": true, + "constraint": stayClasses(clLand, 0), + "start": new Vector2D(mapCenter.x, mapBounds.top).rotateAround(startAngle, mapCenter), + "end": new Vector2D(mapCenter.x, mapBounds.bottom).rotateAround(startAngle, mapCenter), + "width": fractionToTiles(0.07), + "fadeDist": scaleByMapSize(3, 12), + "deviation": 1, + "heightRiverbed": heightSeaGround, + "heightLand": heightShore, + "meanderShort": 12, + "meanderLong": 0, + "waterFunc": (position, height, z) => { + clRiver.add(position); + createTerrain(tWater).place(position); + + if (height < heightShallow && ( + z > 0.3 && z < 0.4 || + z > 0.5 && z < 0.6 || + z > 0.7 && z < 0.8)) + { + g_Map.setHeight(position, heightShallow); + clShallow.add(position); + } + } + }); + + paintTerrainBasedOnHeight(1, 3, 0, tShore); + paintTerrainBasedOnHeight(-8, 1, 2, tWater); + + createBumps([avoidClasses(clPlayer, 20, clRiver, 1), stayClasses(clLand, 3)]); + + const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); + createForests( + [tGrass, tForestFloorP, tForestFloorC, pForestC, pForestP], + [avoidClasses(clPlayer, 20, clForest, 17, clRiver, 1), stayClasses(clLand, 7)], + clForest, + forestTrees); + + yield 50; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tGrass,tGrassA],[tGrassA,tGrassB], [tGrassB,tGrassC]], + [1,1], + [avoidClasses(clForest, 0, clDirt, 3, clPlayer, 8, clRiver, 1), stayClasses(clLand, 7)], + scaleByMapSize(15, 45), + clDirt); + + g_Map.log("Creating grass patches"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tGrassPatch, + [avoidClasses(clForest, 0, clDirt, 3, clPlayer, 8, clRiver, 1), stayClasses(clLand, 7)], + scaleByMapSize(15, 45), + clDirt); + Engine.SetProgress(55); + + g_Map.log("Creating stone mines"); + createMines( + [ + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oStoneSmall, 2,5, 1,3)] + ], + [avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clRiver, 1), stayClasses(clLand, 5)], + clRock); + + g_Map.log("Creating metal mines"); + createMines( + [ + [new SimpleObject(oMetalLarge, 1,1, 0,4)] + ], + [avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clRiver, 1), + stayClasses(clLand, 5)], + clMetal + ); + yield 65; + + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13) + ], + [avoidClasses(clPlayer, 1, clDirt, 1, clRiver, 1), stayClasses(clLand, 6)]); + + g_Map.log("Create water decoration in the shallow parts"); + createDecoration( + [ + [new SimpleObject(aReeds, 1, 3, 0, 1)], + [new SimpleObject(aLillies, 1, 2, 0, 1)] + ], + [ + scaleByMapAreaAbsolute(800), + scaleByMapAreaAbsolute(800) + ], + stayClasses(clShallow, 0)); + + yield 70; + + createFood( + [ + [new SimpleObject(oDeer, 5, 7, 0, 4)], + [new SimpleObject(oSheep, 2, 3, 0, 2)] + ], + [ + 3 * numPlayers, + 3 * numPlayers + ], + [avoidClasses(clForest, 0, clPlayer, 20, clFood, 20, clRiver, 1), stayClasses(clLand, 3)], + clFood); + + createFood( + [ + [new SimpleObject(oBerryBush, 5, 7, 0, 4)] + ], + [ + randIntInclusive(1, 4) * numPlayers + 2 + ], + [avoidClasses(clForest, 0, clPlayer, 20, clFood, 10, clRiver, 1), stayClasses(clLand, 3)], + clFood); + + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 25 * numPlayers + ], + avoidClasses(clLand, 2, clRiver, 1), + clFood); + + yield 85; + + createStragglerTrees( + [oPoplar, oCarob, oApple], + [avoidClasses(clForest, 1, clPlayer, 9, clMetal, 6, clRock, 6, clRiver, 1), + stayClasses(clLand, 7)], + clForest, + stragglerTrees); + + placePlayersNomad( + clPlayer, + new AndConstraint([ + stayClasses(clLand, 4), + avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clFood, 2)])); + + setSkySet("cumulus"); + setWaterColor(0.2,0.312,0.522); + setWaterTint(0.1,0.1,0.8); + setWaterWaviness(4.0); + setWaterType("lake"); + setWaterMurkiness(0.73); + + setFogFactor(0.3); + setFogThickness(0.25); + + setPPEffect("hdr"); + setPPContrast(0.62); + setPPSaturation(0.51); + setPPBloom(0.12); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/gulf_of_bothnia.js =================================================================== --- binaries/data/mods/public/maps/random/gulf_of_bothnia.js +++ binaries/data/mods/public/maps/random/gulf_of_bothnia.js @@ -4,290 +4,295 @@ TILE_CENTERED_HEIGHT_MAP = true; -if (g_MapSettings.Biome) - setSelectedBiome(); -else +function* GenerateMap(mapSettings) +{ // TODO: Replace ugly default for atlas by a dropdown - setBiome("gulf_of_bothnia/winter"); - -const isLakeFrozen = g_Environment.Water.Frozen; - -const tPrimary = g_Terrains.mainTerrain; -const tForestFloor = g_Terrains.forestFloor1; -const tCliff = g_Terrains.cliff; -const tSecondary = g_Terrains.tier1Terrain; -const tPatch1 = g_Terrains.tier2Terrain; -const tPatch2 = g_Terrains.tier3Terrain; -const tRoad = g_Terrains.road; -const tRoadWild = g_Terrains.roadWild; -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 oBerryBush = g_Gaia.fruitBush; -const oStoneLarge = g_Gaia.stoneLarge; -const oStoneSmall = g_Gaia.stoneSmall; -const oMetalLarge = g_Gaia.metalLarge; -const oMetalSmall = g_Gaia.metalSmall; -const oMainHunt = g_Gaia.mainHuntableAnimal; -const oSecHunt = g_Gaia.secondaryHuntableAnimal; -const oFish = g_Gaia.fish; - -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 heightSeaGround = g_Heights.seaGround; -const heightShore = g_Heights.shore; -const heightLand = g_Heights.land; - -const fishCount = g_ResourceCounts.fish; -const huntCount = g_ResourceCounts.hunt; -const berriesCount = g_ResourceCounts.berries; -const bushCount = g_ResourceCounts.bush; - - -const pForest1 = [ - tForestFloor + TERRAIN_SEPARATOR + oTree1, - tForestFloor + TERRAIN_SEPARATOR + oTree2, tForestFloor]; - -const pForest2 = [ - tForestFloor + TERRAIN_SEPARATOR + oTree4, - tForestFloor + TERRAIN_SEPARATOR + oTree5, tForestFloor]; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clLake = g_Map.createTileClass(); -const clWater = isLakeFrozen ? g_Map.createTileClass() : clLake; -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -const startAngle = randomAngle(); - -placePlayerBases({ - "PlayerPlacement": [sortAllPlayers(), ...playerPlacementCustomAngle( - fractionToTiles(0.35), - mapCenter, - i => startAngle + 1/3 * Math.PI * (1 + 2 * (numPlayers == 1 ? 1 : 2 * i / (numPlayers - 1))))], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oTree1, - "count": 2 - }, - "Decoratives": { - "template": aRockMedium + setBiome(mapSettings.Biome ?? "gulf_of_bothnia/winter"); + + const isLakeFrozen = g_Environment.Water.Frozen; + + const tPrimary = g_Terrains.mainTerrain; + const tForestFloor = g_Terrains.forestFloor1; + const tCliff = g_Terrains.cliff; + const tSecondary = g_Terrains.tier1Terrain; + const tPatch1 = g_Terrains.tier2Terrain; + const tPatch2 = g_Terrains.tier3Terrain; + const tRoad = g_Terrains.road; + const tRoadWild = g_Terrains.roadWild; + 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 oBerryBush = g_Gaia.fruitBush; + const oStoneLarge = g_Gaia.stoneLarge; + const oStoneSmall = g_Gaia.stoneSmall; + const oMetalLarge = g_Gaia.metalLarge; + const oMetalSmall = g_Gaia.metalSmall; + const oMainHunt = g_Gaia.mainHuntableAnimal; + const oSecHunt = g_Gaia.secondaryHuntableAnimal; + const oFish = g_Gaia.fish; + + 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 heightSeaGround = g_Heights.seaGround; + const heightShore = g_Heights.shore; + const heightLand = g_Heights.land; + + const fishCount = g_ResourceCounts.fish; + const huntCount = g_ResourceCounts.hunt; + const berriesCount = g_ResourceCounts.berries; + const bushCount = g_ResourceCounts.bush; + + + const pForest1 = [ + tForestFloor + TERRAIN_SEPARATOR + oTree1, + tForestFloor + TERRAIN_SEPARATOR + oTree2, tForestFloor]; + + const pForest2 = [ + tForestFloor + TERRAIN_SEPARATOR + oTree4, + tForestFloor + TERRAIN_SEPARATOR + oTree5, tForestFloor]; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clLake = g_Map.createTileClass(); + const clWater = isLakeFrozen ? g_Map.createTileClass() : clLake; + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + const startAngle = randomAngle(); + + placePlayerBases({ + "PlayerPlacement": [sortAllPlayers(), ...playerPlacementCustomAngle( + fractionToTiles(0.35), + mapCenter, + i => startAngle + 1/3 * Math.PI * + (1 + 2 * (numPlayers == 1 ? 1 : 2 * i / (numPlayers - 1))))], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oTree1, + "count": 2 + }, + "Decoratives": { + "template": aRockMedium + } + }); + yield 20; + + g_Map.log("Creating the gulf"); + const gulfLakePositions = [ + { "numCircles": 200, "x": fractionToTiles(0), "radius": fractionToTiles(0.175) }, + { "numCircles": 120, "x": fractionToTiles(0.3), "radius": fractionToTiles(0.2) }, + { "numCircles": 100, "x": fractionToTiles(0.5), "radius": fractionToTiles(0.225) } + ]; + + for (const gulfLake of gulfLakePositions) + { + const position = + Vector2D.add(mapCenter, new Vector2D(gulfLake.x, 0).rotate(-startAngle)).round(); + + createArea( + new ChainPlacer( + 2, + Math.floor(scaleByMapSize(5, 16)), + Math.floor(scaleByMapSize(35, gulfLake.numCircles)), + Infinity, + position, + 0, + [Math.floor(gulfLake.radius)]), + [ + new TerrainPainter(tPrimary), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), + new TileClassPainter(clLake) + ], + avoidClasses(clPlayer,scaleByMapSize(20, 28))); } -}); -Engine.SetProgress(20); - -g_Map.log("Creating the gulf"); -const gulfLakePositions = [ - { "numCircles": 200, "x": fractionToTiles(0), "radius": fractionToTiles(0.175) }, - { "numCircles": 120, "x": fractionToTiles(0.3), "radius": fractionToTiles(0.2) }, - { "numCircles": 100, "x": fractionToTiles(0.5), "radius": fractionToTiles(0.225) } -]; -for (const gulfLake of gulfLakePositions) -{ - const position = Vector2D.add(mapCenter, new Vector2D(gulfLake.x, 0).rotate(-startAngle)).round(); - - createArea( - new ChainPlacer( - 2, - Math.floor(scaleByMapSize(5, 16)), - Math.floor(scaleByMapSize(35, gulfLake.numCircles)), - Infinity, - position, + if (isLakeFrozen) + { + const areas = createAreas( + new ChainPlacer( + 1, + 4, + scaleByMapSize(16, 40), + 0.3), + [ + new ElevationPainter(-6), + new TileClassPainter(clWater) + ], + stayClasses(clLake, 2), + scaleByMapSize(10, 40)); + + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oFish, 1, 2, 0, 2)], true, clFood), 0, - [Math.floor(gulfLake.radius)]), + stayClasses(clWater, 2), + scaleByMapSize(fishCount.min, fishCount.max), + 20, + areas); + } + + paintTerrainBasedOnHeight(heightShore, heightLand, Elevation_ExcludeMin_ExcludeMax, tShore); + paintTerrainBasedOnHeight(-Infinity, heightShore, Elevation_ExcludeMin_IncludeMax, tWater); + + createBumps(avoidClasses(clLake, 2, clPlayer, 10)); + + if (randBool()) + createHills( + [tPrimary, tCliff, tCliff], + avoidClasses(clPlayer, 20, clHill, 15, clLake, 0), + clHill, + scaleByMapSize(1, 4) * numPlayers, + undefined, + undefined, + undefined, + 0.5, + 18, + 4); + else + createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 15, clLake, 0), clHill, + scaleByMapSize(1, 4) * numPlayers, Math.floor(scaleByMapSize(20, 40))); + + const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); + createDefaultForests( + [tForestFloor, tForestFloor, tForestFloor, pForest1, pForest2], + avoidClasses(clPlayer, 20, clForest, 16, clHill, 0, clLake, 2), + clForest, + forestTrees); + + yield 60; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tPrimary, tSecondary], [tSecondary, tPatch1], [tPatch1, tPatch2]], + [1, 1], + avoidClasses(clLake, 6, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + + g_Map.log("Creating grass patches"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tPatch1, + avoidClasses(clLake, 6, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + yield 65; + + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + avoidClasses(clLake, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1), + 0.9 + ); + + g_Map.log("Creating stone mines"); + createBalancedStoneMines( + oStoneSmall, + oStoneLarge, + clRock, + avoidClasses(clLake, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1, clMetal, 10), + 0.9 + ); + yield 70; + + createDecoration( [ - new TerrainPainter(tPrimary), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), - new TileClassPainter(clLake) + [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)] ], - avoidClasses(clPlayer,scaleByMapSize(20, 28))); -} + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + scaleByMapSize(bushCount.min, bushCount.max), + scaleByMapSize(bushCount.min, bushCount.max), + scaleByMapSize(bushCount.min, bushCount.max) + ], + avoidClasses(clLake, 0, clForest, 0, clPlayer, 5, clHill, 0, clBaseResource, 5)); + yield 75; -if (isLakeFrozen) -{ - const areas = createAreas( - new ChainPlacer( - 1, - 4, - scaleByMapSize(16, 40), - 0.3), + createFood( [ - new ElevationPainter(-6), - new TileClassPainter(clWater) + [new SimpleObject(oMainHunt, 5, 7, 0, 4)], + [new SimpleObject(oSecHunt, 2, 3, 0, 2)] ], - stayClasses(clLake, 2), - scaleByMapSize(10, 40)); - - createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oFish, 1, 2, 0, 2)], true, clFood), - 0, - stayClasses(clWater, 2), - scaleByMapSize(fishCount.min, fishCount.max), - 20, - areas); -} + [ + scaleByMapSize(huntCount.min / 2, huntCount.max / 2), + scaleByMapSize(huntCount.min / 2, huntCount.max / 2) + ], + avoidClasses(clLake, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), + clFood); -paintTerrainBasedOnHeight(heightShore, heightLand, Elevation_ExcludeMin_ExcludeMax, tShore); -paintTerrainBasedOnHeight(-Infinity, heightShore, Elevation_ExcludeMin_IncludeMax, tWater); - -createBumps(avoidClasses(clLake, 2, clPlayer, 10)); - -if (randBool()) - createHills( - [tPrimary, tCliff, tCliff], - avoidClasses(clPlayer, 20, clHill, 15, clLake, 0), - clHill, - scaleByMapSize(1, 4) * numPlayers, - undefined, - undefined, - undefined, - 0.5, - 18, - 4); -else - createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 15, clLake, 0), clHill, scaleByMapSize(1, 4) * numPlayers, Math.floor(scaleByMapSize(20, 40))); - -const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); -createDefaultForests( - [tForestFloor, tForestFloor, tForestFloor, pForest1, pForest2], - avoidClasses(clPlayer, 20, clForest, 16, clHill, 0, clLake, 2), - clForest, - forestTrees); - -Engine.SetProgress(60); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tPrimary, tSecondary], [tSecondary, tPatch1], [tPatch1, tPatch2]], - [1, 1], - avoidClasses(clLake, 6, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); - -g_Map.log("Creating grass patches"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tPatch1, - avoidClasses(clLake, 6, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(65); - -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - avoidClasses(clLake, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1), - 0.9 -); - -g_Map.log("Creating stone mines"); -createBalancedStoneMines( - oStoneSmall, - oStoneLarge, - clRock, - avoidClasses(clLake, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1, clMetal, 10), - 0.9 -); -Engine.SetProgress(70); - -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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - scaleByMapSize(bushCount.min, bushCount.max), - scaleByMapSize(bushCount.min, bushCount.max), - scaleByMapSize(bushCount.min, bushCount.max) - ], - avoidClasses(clLake, 0, clForest, 0, clPlayer, 5, clHill, 0, clBaseResource, 5)); -Engine.SetProgress(75); - -createFood( - [ - [new SimpleObject(oMainHunt, 5, 7, 0, 4)], - [new SimpleObject(oSecHunt, 2, 3, 0, 2)] - ], - [ - scaleByMapSize(huntCount.min / 2, huntCount.max / 2), - scaleByMapSize(huntCount.min / 2, huntCount.max / 2) - ], - avoidClasses(clLake, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), - clFood); - -createFood( - [[new SimpleObject(oBerryBush, 5, 7, 0, 4)]], - [scaleByMapSize(berriesCount.min, berriesCount.max)], - avoidClasses(clLake, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - clFood); - -if (!isLakeFrozen) -{ - // actually it would work without an error without this if statement - // but since this placer would fail most of the time on the frozen lake -> save some time by just skipping it - // fish are already placed when creating the holes in the ice createFood( - [[new SimpleObject(oFish, 2, 3, 0, 2)]], - [scaleByMapSize(fishCount.min, fishCount.max)], - [avoidClasses(clFood, 20), stayClasses(clWater, 6)], + [[new SimpleObject(oBerryBush, 5, 7, 0, 4)]], + [scaleByMapSize(berriesCount.min, berriesCount.max)], + avoidClasses(clLake, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), clFood); -} -Engine.SetProgress(85); + if (!isLakeFrozen) + { + // actually it would work without an error without this if statement + // but since this placer would fail most of the time on the frozen lake -> save some time by + // just skipping it + // fish are already placed when creating the holes in the ice + createFood( + [[new SimpleObject(oFish, 2, 3, 0, 2)]], + [scaleByMapSize(fishCount.min, fishCount.max)], + [avoidClasses(clFood, 20), stayClasses(clWater, 6)], + clFood); + } + + yield 85; -createStragglerTrees( - [oTree3], - avoidClasses(clLake, 3, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); + createStragglerTrees( + [oTree3], + avoidClasses(clLake, 3, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); -// Avoid the lake, even if frozen -placePlayersNomad(clPlayer, avoidClasses(clLake, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + // Avoid the lake, even if frozen + placePlayersNomad(clPlayer, + avoidClasses(clLake, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/harbor.js =================================================================== --- binaries/data/mods/public/maps/random/harbor.js +++ binaries/data/mods/public/maps/random/harbor.js @@ -3,305 +3,308 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setSelectedBiome(); - -const heightSeaGround = -18; -const heightLand = 2; -const heightOffsetHarbor = -11; - -const g_Map = new RandomMap(heightLand, g_Terrains.mainTerrain); - -initTileClasses(); +function* GenerateMap() +{ + setSelectedBiome(); -setFogFactor(0.04); + const heightLand = 2; -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land)); + global.g_Map = new RandomMap(heightLand, g_Terrains.mainTerrain); -Engine.SetProgress(10); + initTileClasses(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); + setFogFactor(0.04); -const startAngle = randomAngle(); -const [playerIDs, playerPosition] = - createBases( - ...playerPlacementByPattern( - "radial", - fractionToTiles(0.38), - fractionToTiles(0.05), - startAngle, - undefined), - true); -Engine.SetProgress(20); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land)); + + yield 10; + + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const startAngle = randomAngle(); + const [playerIDs, playerPosition] = + createBases( + ...playerPlacementByPattern( + "radial", + fractionToTiles(0.38), + fractionToTiles(0.05), + startAngle, + undefined), + true); + yield 20; + + addCenterLake(mapCenter, mapSize); + yield 30; + + if (mapSize >= 192) + { + addHarbors(mapCenter, playerPosition); + yield 40; + } -addCenterLake(); -Engine.SetProgress(30); + addSpines(mapCenter, mapSize, startAngle); + yield 50; -if (mapSize >= 192) -{ - addHarbors(); - Engine.SetProgress(40); -} + addElements([ + { + "func": addFish, + "avoid": [ + g_TileClasses.fish, 12, + g_TileClasses.hill, 8, + g_TileClasses.mountain, 8, + g_TileClasses.player, 8, + g_TileClasses.spine, 4 + ], + "stay": [g_TileClasses.water, 7], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": ["many"] + } + ]); -addSpines(); -Engine.SetProgress(50); + addElements(shuffleArray([ + { + "func": addHills, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.hill, 15, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 5, + g_TileClasses.player, 20, + g_TileClasses.spine, 5, + g_TileClasses.valley, 2, + g_TileClasses.water, 2 + ], + "sizes": ["tiny", "small"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addMountains, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 20, + g_TileClasses.player, 20, + g_TileClasses.spine, 20, + g_TileClasses.valley, 10, + g_TileClasses.water, 15 + ], + "sizes": ["small"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addPlateaus, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 20, + g_TileClasses.player, 40, + g_TileClasses.spine, 20, + g_TileClasses.valley, 10, + g_TileClasses.water, 15 + ], + "sizes": ["small"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addBluffs, + "baseHeight": heightLand, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 20, + g_TileClasses.player, 40, + g_TileClasses.spine, 20, + g_TileClasses.valley, 10, + g_TileClasses.water, 15 + ], + "sizes": ["normal"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + } + ])); + yield 60; -addElements([ - { - "func": addFish, - "avoid": [ - g_TileClasses.fish, 12, - g_TileClasses.hill, 8, - g_TileClasses.mountain, 8, - g_TileClasses.player, 8, - g_TileClasses.spine, 4 - ], - "stay": [g_TileClasses.water, 7], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": ["many"] - } -]); + addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.spine, 5, + g_TileClasses.metal, 20, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal", "many"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.spine, 5, + g_TileClasses.metal, 10, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal", "many"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 8, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.plateau, 5, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.spine, 5, + g_TileClasses.water, 2 + ], + "sizes": ["normal"], + "mixes": ["similar"], + "amounts": ["many"] + } + ])); -addElements(shuffleArray([ - { - "func": addHills, - "avoid": [ - g_TileClasses.bluff, 5, - g_TileClasses.hill, 15, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 5, - g_TileClasses.player, 20, - g_TileClasses.spine, 5, - g_TileClasses.valley, 2, - g_TileClasses.water, 2 - ], - "sizes": ["tiny", "small"], - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addMountains, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.mountain, 25, - g_TileClasses.plateau, 20, - g_TileClasses.player, 20, - g_TileClasses.spine, 20, - g_TileClasses.valley, 10, - g_TileClasses.water, 15 - ], - "sizes": ["small"], - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addPlateaus, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.mountain, 25, - g_TileClasses.plateau, 20, - g_TileClasses.player, 40, - g_TileClasses.spine, 20, - g_TileClasses.valley, 10, - g_TileClasses.water, 15 - ], - "sizes": ["small"], - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addBluffs, - "baseHeight": heightLand, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.mountain, 25, - g_TileClasses.plateau, 20, - g_TileClasses.player, 40, - g_TileClasses.spine, 20, - g_TileClasses.valley, 10, - g_TileClasses.water, 15 - ], - "sizes": ["normal"], - "mixes": g_AllMixes, - "amounts": g_AllAmounts - } -])); -Engine.SetProgress(60); + yield 70; -addElements(shuffleArray([ - { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.spine, 5, - g_TileClasses.metal, 20, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal", "many"] - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.spine, 5, - g_TileClasses.metal, 10, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal", "many"] - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 8, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 5, - g_TileClasses.plateau, 5, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.spine, 5, - g_TileClasses.water, 2 - ], - "sizes": ["normal"], - "mixes": ["similar"], - "amounts": ["many"] - } -])); + addElements(shuffleArray([ + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 10, + g_TileClasses.spine, 2, + g_TileClasses.water, 3 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.spine, 2, + g_TileClasses.water, 3 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 7, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.spine, 2, + g_TileClasses.water, 5 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + } + ])); -Engine.SetProgress(70); + yield 80; -addElements(shuffleArray([ - { - "func": addBerries, - "avoid": [ - g_TileClasses.berries, 30, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 5, - g_TileClasses.metal, 10, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 10, - g_TileClasses.spine, 2, - g_TileClasses.water, 3 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.spine, 2, - g_TileClasses.water, 3 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 7, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.spine, 2, - g_TileClasses.water, 5 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - } -])); + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.spine, 5, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.spine, 5, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + } + ]); -Engine.SetProgress(80); + yield 90; + + placePlayersNomad( + g_TileClasses.player, + avoidClasses( + g_TileClasses.bluff, 4, + g_TileClasses.water, 4, + g_TileClasses.spine, 4, + g_TileClasses.plateau, 4, + g_TileClasses.forest, 1, + g_TileClasses.metal, 4, + g_TileClasses.rock, 4, + g_TileClasses.mountain, 4, + g_TileClasses.animals, 2)); + + return g_Map; +} -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.spine, 5, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.spine, 5, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - } -]); - -Engine.SetProgress(90); - -placePlayersNomad( - g_TileClasses.player, - avoidClasses( - g_TileClasses.bluff, 4, - g_TileClasses.water, 4, - g_TileClasses.spine, 4, - g_TileClasses.plateau, 4, - g_TileClasses.forest, 1, - g_TileClasses.metal, 4, - g_TileClasses.rock, 4, - g_TileClasses.mountain, 4, - g_TileClasses.animals, 2)); - -g_Map.ExportMap(); - -function addCenterLake() +function addCenterLake(mapCenter, mapSize) { + const heightSeaGround = -18; + createArea( new ChainPlacer( 2, @@ -323,8 +326,10 @@ fDist = 20; } -function addHarbors() +function addHarbors(mapCenter, playerPosition) { + const heightOffsetHarbor = -11; + for (const position of playerPosition) { const harborPosition = Vector2D.add(position, Vector2D.sub(mapCenter, position).div(2.5).round()); @@ -343,7 +348,7 @@ } } -function addSpines() +function addSpines(mapCenter, mapSize, startAngle) { const smallSpines = mapSize <= 192; const spineSize = smallSpines ? 0.02 : 0.5; Index: binaries/data/mods/public/maps/random/hellas.js =================================================================== --- binaries/data/mods/public/maps/random/hellas.js +++ binaries/data/mods/public/maps/random/hellas.js @@ -20,545 +20,571 @@ TILE_CENTERED_HEIGHT_MAP = true; -const mapStyles = [ - // mainland - { - "minMapSize": 0, - "enabled": randBool(0.15), - "landRatio": [0.95, 1] - }, - // lots of water - { - "minMapSize": 384, - "enabled": randBool(1/4), - "landRatio": [0.3, 0.5] - }, - // few water - { - "minMapSize": 192, - "enabled": true, - "landRatio": [0.65, 0.9] - } -]; - -const heightmapHellas = convertHeightmap1Dto2D(Engine.LoadHeightmapImage("maps/random/hellas.png")); -const biomes = Engine.ReadJSONFile("maps/random/hellas_biomes.json"); - -const heightScale = num => num * g_MapSettings.Size / 320; - -const heightSeaGround = heightScale(-6); -const heightReedsMin = heightScale(-2); -const heightReedsMax = heightScale(-0.5); -const heightShoreline = heightScale(1); -const heightLowlands = heightScale(30); -const heightHighlands = heightScale(60); - -const heightmapMin = 0; -const heightmapMax = 100; - -const g_Map = new RandomMap(0, biomes.lowlands.terrains.main); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const numPlayers = getNumPlayers(); - -let clWater = g_Map.createTileClass(); -let clCliffs = g_Map.createTileClass(); -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clDock = g_Map.createTileClass(); - -const constraintLowlands = new HeightConstraint(heightShoreline, heightLowlands); -const constraintHighlands = new HeightConstraint(heightLowlands, heightHighlands); -const constraintMountains = new HeightConstraint(heightHighlands, Infinity); - -const [minLandRatio, maxLandRatio] = mapStyles.filter(mapStyle => mapSize >= mapStyle.minMapSize).sort((a, b) => a.enabled - b.enabled).pop().landRatio; -const [minCliffRatio, maxCliffRatio] = [maxLandRatio < 0.75 ? 0 : 0.08, 0.18]; - -let playerIDs = sortAllPlayers(); -let playerPosition; - -// Pick a random subset of the heightmap that meets the mapStyle and has space for all players -let subAreaSize; -let subAreaTopLeft; -while (true) +function* GenerateMap(mapSettings) { - subAreaSize = Math.floor(randFloat(0.01, 0.2) * heightmapHellas.length); - subAreaTopLeft = new Vector2D(randFloat(0, 1), randFloat(0, 1)).mult(heightmapHellas.length - subAreaSize).floor(); - - const heightmap = extractHeightmap(heightmapHellas, subAreaTopLeft, subAreaSize); - const heightmapPainter = new HeightmapPainter(heightmap, heightmapMin, heightmapMax); - - // Quick area test - const points = new DiskPlacer(heightmap.length / 2 - MAP_BORDER_WIDTH, new Vector2D(1, 1).mult(heightmap.length / 2)).place(new NullConstraint()); - let landArea = 0; - for (const point of points) - if (heightmapPainter.scaleHeight(heightmap[point.x][point.y]) > heightShoreline) - ++landArea; - - let landRatio = landArea / points.length; - g_Map.log("Chosen heightmap at " + uneval(subAreaTopLeft) + " of size " + subAreaSize + ", land-ratio: " + landRatio.toFixed(3)); - if (landRatio < minLandRatio || landRatio > maxLandRatio) - continue; - - g_Map.log("Copying heightmap"); - createArea( - new MapBoundsPlacer(), - heightmapPainter); - - g_Map.log("Measuring land area"); - const passableLandArea = createArea( - new DiskPlacer(fractionToTiles(0.5), mapCenter), - undefined, - new HeightConstraint(heightShoreline, Infinity)); - - if (!passableLandArea) - continue; - - landRatio = passableLandArea.getPoints().length / diskArea(fractionToTiles(0.5)); - g_Map.log("Land ratio: " + landRatio.toFixed(3)); - if (landRatio < minLandRatio || landRatio > maxLandRatio) - continue; - - g_Map.log("Lowering sea ground"); - clWater = g_Map.createTileClass(); - createArea( - new MapBoundsPlacer(), - [ - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 5), - new TileClassPainter(clWater) - ], - new HeightConstraint(-Infinity, heightShoreline)); - - let cliffsRatio; + const mapStyles = [ + // mainland + { + "minMapSize": 0, + "enabled": randBool(0.15), + "landRatio": [0.95, 1] + }, + // lots of water + { + "minMapSize": 384, + "enabled": randBool(1/4), + "landRatio": [0.3, 0.5] + }, + // few water + { + "minMapSize": 192, + "enabled": true, + "landRatio": [0.65, 0.9] + } + ]; + + const heightmapHellas = convertHeightmap1Dto2D(Engine.LoadHeightmapImage("maps/random/hellas.png")); + const biomes = Engine.ReadJSONFile("maps/random/hellas_biomes.json"); + + const heightScale = num => num * mapSettings.Size / 320; + + const heightSeaGround = heightScale(-6); + const heightReedsMin = heightScale(-2); + const heightReedsMax = heightScale(-0.5); + const heightShoreline = heightScale(1); + const heightLowlands = heightScale(30); + const heightHighlands = heightScale(60); + + const heightmapMin = 0; + const heightmapMax = 100; + + global.g_Map = new RandomMap(0, biomes.lowlands.terrains.main); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const numPlayers = getNumPlayers(); + + let clWater = g_Map.createTileClass(); + let clCliffs = g_Map.createTileClass(); + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clDock = g_Map.createTileClass(); + + const constraintLowlands = new HeightConstraint(heightShoreline, heightLowlands); + const constraintHighlands = new HeightConstraint(heightLowlands, heightHighlands); + const constraintMountains = new HeightConstraint(heightHighlands, Infinity); + + const [minLandRatio, maxLandRatio] = mapStyles.filter(mapStyle => mapSize >= mapStyle.minMapSize) + .sort((a, b) => a.enabled - b.enabled).pop().landRatio; + const [minCliffRatio, maxCliffRatio] = [maxLandRatio < 0.75 ? 0 : 0.08, 0.18]; + + let playerIDs = sortAllPlayers(); + let playerPosition; + + // Pick a random subset of the heightmap that meets the mapStyle and has space for all players + let subAreaSize; + let subAreaTopLeft; while (true) { + subAreaSize = Math.floor(randFloat(0.01, 0.2) * heightmapHellas.length); + subAreaTopLeft = new Vector2D(randFloat(0, 1), randFloat(0, 1)) + .mult(heightmapHellas.length - subAreaSize).floor(); + + const heightmap = extractHeightmap(heightmapHellas, subAreaTopLeft, subAreaSize); + const heightmapPainter = new HeightmapPainter(heightmap, heightmapMin, heightmapMax); + + // Quick area test + const points = new DiskPlacer(heightmap.length / 2 - MAP_BORDER_WIDTH, + new Vector2D(1, 1).mult(heightmap.length / 2)).place(new NullConstraint()); + let landArea = 0; + for (const point of points) + if (heightmapPainter.scaleHeight(heightmap[point.x][point.y]) > heightShoreline) + ++landArea; + + let landRatio = landArea / points.length; + g_Map.log("Chosen heightmap at " + uneval(subAreaTopLeft) + " of size " + subAreaSize + + ", land-ratio: " + landRatio.toFixed(3)); + if (landRatio < minLandRatio || landRatio > maxLandRatio) + continue; + + g_Map.log("Copying heightmap"); createArea( - new DiskPlacer(fractionToTiles(0.5) - MAP_BORDER_WIDTH, mapCenter), - new SmoothingPainter(1, 0.5, 1)); - Engine.SetProgress(25); + new MapBoundsPlacer(), + heightmapPainter); + + g_Map.log("Measuring land area"); + const passableLandArea = createArea( + new DiskPlacer(fractionToTiles(0.5), mapCenter), + undefined, + new HeightConstraint(heightShoreline, Infinity)); - clCliffs = g_Map.createTileClass(); + if (!passableLandArea) + continue; - // Marking cliffs - const cliffsArea = createArea( + landRatio = passableLandArea.getPoints().length / diskArea(fractionToTiles(0.5)); + g_Map.log("Land ratio: " + landRatio.toFixed(3)); + if (landRatio < minLandRatio || landRatio > maxLandRatio) + continue; + + g_Map.log("Lowering sea ground"); + clWater = g_Map.createTileClass(); + createArea( new MapBoundsPlacer(), - new TileClassPainter(clCliffs), [ - avoidClasses(clWater, 2), - new SlopeConstraint(2, Infinity) - ]); + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 5), + new TileClassPainter(clWater) + ], + new HeightConstraint(-Infinity, heightShoreline)); + + let cliffsRatio; + while (true) + { + createArea( + new DiskPlacer(fractionToTiles(0.5) - MAP_BORDER_WIDTH, mapCenter), + new SmoothingPainter(1, 0.5, 1)); + yield 25; + + clCliffs = g_Map.createTileClass(); + + // Marking cliffs + const cliffsArea = createArea( + new MapBoundsPlacer(), + new TileClassPainter(clCliffs), + [ + avoidClasses(clWater, 2), + new SlopeConstraint(2, Infinity) + ]); + + cliffsRatio = cliffsArea.getPoints().length / Math.square(g_Map.getSize()); + g_Map.log("Smoothing heightmap, cliff ratio: " + cliffsRatio.toFixed(3)); + if (cliffsRatio < maxCliffRatio) + break; + } + + if (cliffsRatio < minCliffRatio) + { + g_Map.log("Too few cliffs: " + cliffsRatio); + continue; + } - cliffsRatio = cliffsArea.getPoints().length / Math.square(g_Map.getSize()); - g_Map.log("Smoothing heightmap, cliff ratio: " + cliffsRatio.toFixed(3)); - if (cliffsRatio < maxCliffRatio) + if (isNomad()) break; + + g_Map.log("Finding player locations"); + const players = playerPlacementRandom( + playerIDs, + avoidClasses( + clCliffs, scaleByMapSize(6, 15), + clWater, scaleByMapSize(10, 20))); + + if (players) + { + [playerIDs, playerPosition] = players; + break; + } + + g_Map.log("Too few player locations, starting over"); } + yield 35; - if (cliffsRatio < minCliffRatio) + if (!isNomad()) { - g_Map.log("Too few cliffs: " + cliffsRatio); - continue; + g_Map.log("Flattening initial CC area"); + const playerRadius = defaultPlayerBaseRadius() * 0.8; + for (const position of playerPosition) + createArea( + new ClumpPlacer(diskArea(playerRadius), 0.95, 0.6, Infinity, position), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), + playerRadius / 2)); + yield 38; } - if (isNomad()) - break; + g_Map.log("Painting lowlands"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(biomes.lowlands.terrains.main), + constraintLowlands); + yield 40; + + g_Map.log("Painting highlands"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(biomes.highlands.terrains.main), + constraintHighlands); + yield 45; + + g_Map.log("Painting mountains"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(biomes.common.terrains.cliffs), + [ + avoidClasses(clWater, 2), + constraintMountains + ]); + yield 48; + + g_Map.log("Painting water and shoreline"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(biomes.water.terrains.main), + new HeightConstraint(-Infinity, heightShoreline)); + yield 50; - g_Map.log("Finding player locations"); - const players = playerPlacementRandom( - playerIDs, - avoidClasses( - clCliffs, scaleByMapSize(6, 15), - clWater, scaleByMapSize(10, 20))); + g_Map.log("Painting cliffs"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(biomes.common.terrains.cliffs), + [ + avoidClasses(clWater, 2), + new SlopeConstraint(2, Infinity) + ]); + yield 55; - if (players) + for (let i = 0; i < numPlayers; ++i) { - [playerIDs, playerPosition] = players; - break; - } + if (isNomad()) + break; - g_Map.log("Too few player locations, starting over"); -} -Engine.SetProgress(35); + const localBiome = constraintHighlands.allows(playerPosition[i]) ? biomes.highlands : + biomes.lowlands; + placePlayerBase({ + "playerID": playerIDs[i], + "playerPosition": playerPosition[i], + "PlayerTileClass": clPlayer, + "Walls": "towers", + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": avoidClasses(clPlayer, 4, clWater, 1, clCliffs, 1), + "CityPatch": { + "outerTerrain": biomes.common.terrains.roadWild, + "innerTerrain": biomes.common.terrains.road + }, + "StartingAnimal": { + "template": localBiome.gaia.fauna.startingAnimal, + "groupCount": 1, + "minGroupCount": 4, + "maxGroupCount": 4 + }, + "Berries": { + "template": localBiome.gaia.flora.fruitBush, + "minCount": 3, + "maxCount": 3 + }, + "Mines": { + "types": [ + { "template": biomes.common.gaia.mines.metalLarge }, + { "template": biomes.common.gaia.mines.stoneLarge } + ], + "minAngle": Math.PI / 2, + "maxAngle": Math.PI + }, + "Trees": { + "template": pickRandom(localBiome.gaia.flora.trees), + "count": 15 + } + // No decoratives + }); + } + yield 60; -if (!isNomad()) -{ - g_Map.log("Flattening initial CC area"); - const playerRadius = defaultPlayerBaseRadius() * 0.8; - for (const position of playerPosition) - createArea( - new ClumpPlacer(diskArea(playerRadius), 0.95, 0.6, Infinity, position), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), playerRadius / 2)); - Engine.SetProgress(38); -} + g_Map.log("Placing docks"); + placeDocks( + biomes.shoreline.gaia.dock, + 0, + scaleByMapSize(1, 2) * 100, + clWater, + clDock, + heightReedsMax, + heightShoreline, + [avoidClasses(clDock, 50), new StaticConstraint(avoidClasses(clPlayer, 30, clCliffs, 8))], + 0, + 50); + yield 65; -g_Map.log("Painting lowlands"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(biomes.lowlands.terrains.main), - constraintLowlands); -Engine.SetProgress(40); - -g_Map.log("Painting highlands"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(biomes.highlands.terrains.main), - constraintHighlands); -Engine.SetProgress(45); - -g_Map.log("Painting mountains"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(biomes.common.terrains.cliffs), - [ - avoidClasses(clWater, 2), - constraintMountains - ]); -Engine.SetProgress(48); - -g_Map.log("Painting water and shoreline"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(biomes.water.terrains.main), - new HeightConstraint(-Infinity, heightShoreline)); -Engine.SetProgress(50); - -g_Map.log("Painting cliffs"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(biomes.common.terrains.cliffs), - [ - avoidClasses(clWater, 2), - new SlopeConstraint(2, Infinity) - ]); -Engine.SetProgress(55); - -for (let i = 0; i < numPlayers; ++i) -{ - if (isNomad()) - break; - - const localBiome = constraintHighlands.allows(playerPosition[i]) ? biomes.highlands : biomes.lowlands; - placePlayerBase({ - "playerID": playerIDs[i], - "playerPosition": playerPosition[i], - "PlayerTileClass": clPlayer, - "Walls": "towers", - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": avoidClasses(clPlayer, 4, clWater, 1, clCliffs, 1), - "CityPatch": { - "outerTerrain": biomes.common.terrains.roadWild, - "innerTerrain": biomes.common.terrains.road - }, - "StartingAnimal": { - "template": localBiome.gaia.fauna.startingAnimal, - "groupCount": 1, - "minGroupCount": 4, - "maxGroupCount": 4 - }, - "Berries": { - "template": localBiome.gaia.flora.fruitBush, - "minCount": 3, - "maxCount": 3 - }, - "Mines": { - "types": [ - { "template": biomes.common.gaia.mines.metalLarge }, - { "template": biomes.common.gaia.mines.stoneLarge } + const [forestTrees, stragglerTrees] = getTreeCounts(600, 4000, 0.7); + const biomeTreeRatioHighlands = 0.4; + for (const biome of ["lowlands", "highlands"]) + createForests( + [ + biomes[biome].terrains.main, + biomes[biome].terrains.forestFloors[0], + biomes[biome].terrains.forestFloors[1], + biomes[biome].terrains.forests[0], + biomes[biome].terrains.forests[1] ], - "minAngle": Math.PI / 2, - "maxAngle": Math.PI - }, - "Trees": { - "template": pickRandom(localBiome.gaia.flora.trees), - "count": 15 - } - // No decoratives - }); -} -Engine.SetProgress(60); - -g_Map.log("Placing docks"); -placeDocks( - biomes.shoreline.gaia.dock, - 0, - scaleByMapSize(1, 2) * 100, - clWater, - clDock, - heightReedsMax, - heightShoreline, - [avoidClasses(clDock, 50), new StaticConstraint(avoidClasses(clPlayer, 30, clCliffs, 8))], - 0, - 50); -Engine.SetProgress(65); - -const [forestTrees, stragglerTrees] = getTreeCounts(600, 4000, 0.7); -const biomeTreeRatioHighlands = 0.4; -for (const biome of ["lowlands", "highlands"]) - createForests( + [ + biome == "highlands" ? constraintHighlands : constraintLowlands, + avoidClasses(clPlayer, 20, clForest, 18, clCliffs, 1, clWater, 2) + ], + clForest, + forestTrees * (biome == "highlands" ? biomeTreeRatioHighlands : + 1 - biomeTreeRatioHighlands)); + yield 70; + + g_Map.log("Creating stone mines"); + const minesStone = [ + [new SimpleObject(biomes.common.gaia.mines.stoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(biomes.common.gaia.mines.stoneSmall, 2, 3, 1, 3, 0, 2 * Math.PI, 1)] + ]; + for (const mine of minesStone) + createObjectGroups( + new SimpleGroup(mine, true, clRock), + 0, + [avoidClasses(clForest, 1, clPlayer, 20, clRock, 18, clCliffs, 2, clWater, 2, clDock, 6)], + scaleByMapSize(2, 12), + 50); + yield 75; + + g_Map.log("Creating metal mines"); + const minesMetal = [ + [new SimpleObject(biomes.common.gaia.mines.metalLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(biomes.common.gaia.mines.metalSmall, 2, 3, 1, 3, 0, 2 * Math.PI, 1)] + ]; + for (const mine of minesMetal) + createObjectGroups( + new SimpleGroup(mine, true, clMetal), + 0, + [avoidClasses(clForest, 1, clPlayer, 20, clRock, 8, clMetal, 18, clCliffs, 2, clWater, 2, + clDock, 6)], + scaleByMapSize(2, 12), + 50); + yield 80; + + for (const biome of ["lowlands", "highlands"]) + createStragglerTrees( + biomes[biome].gaia.flora.trees, + [ + biome == "highlands" ? constraintHighlands : constraintLowlands, + avoidClasses(clForest, 8, clCliffs, 1, clPlayer, 12, clMetal, 6, clRock, 6, + clCliffs, 2, clWater, 2, clDock, 6) + ], + clForest, + stragglerTrees * (biome == "highlands" ? biomeTreeRatioHighlands * 4 : + 1 - biomeTreeRatioHighlands)); + yield 85; + + createFood( [ - biomes[biome].terrains.main, - biomes[biome].terrains.forestFloors[0], - biomes[biome].terrains.forestFloors[1], - biomes[biome].terrains.forests[0], - biomes[biome].terrains.forests[1] + [new SimpleObject(biomes.highlands.gaia.fauna.horse, 3, 5, 0, 4)], + [new SimpleObject(biomes.highlands.gaia.fauna.pony, 2, 3, 0, 4)], + [new SimpleObject(biomes.highlands.gaia.flora.fruitBush, 5, 7, 0, 4)] ], [ - biome == "highlands" ? constraintHighlands : constraintLowlands, - avoidClasses(clPlayer, 20, clForest, 18, clCliffs, 1, clWater, 2) + scaleByMapSize(2, 16), + scaleByMapSize(2, 12), + scaleByMapSize(2, 20) ], - clForest, - forestTrees * (biome == "highlands" ? biomeTreeRatioHighlands : 1 - biomeTreeRatioHighlands)); -Engine.SetProgress(70); - -g_Map.log("Creating stone mines"); -const minesStone = [ - [new SimpleObject(biomes.common.gaia.mines.stoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(biomes.common.gaia.mines.stoneSmall, 2, 3, 1, 3, 0, 2 * Math.PI, 1)] -]; -for (const mine of minesStone) - createObjectGroups( - new SimpleGroup(mine, true, clRock), - 0, - [avoidClasses(clForest, 1, clPlayer, 20, clRock, 18, clCliffs, 2, clWater, 2, clDock, 6)], - scaleByMapSize(2, 12), - 50); -Engine.SetProgress(75); - -g_Map.log("Creating metal mines"); -const minesMetal = [ - [new SimpleObject(biomes.common.gaia.mines.metalLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(biomes.common.gaia.mines.metalSmall, 2, 3, 1, 3, 0, 2 * Math.PI, 1)] -]; -for (const mine of minesMetal) - createObjectGroups( - new SimpleGroup(mine, true, clMetal), - 0, - [avoidClasses(clForest, 1, clPlayer, 20, clRock, 8, clMetal, 18, clCliffs, 2, clWater, 2, clDock, 6)], - scaleByMapSize(2, 12), - 50); -Engine.SetProgress(80); + [ + avoidClasses(clForest, 0, clPlayer, 20, clFood, 16, clCliffs, 2, clWater, 2, clRock, 4, + clMetal, 4, clDock, 6), + constraintHighlands + ], + clFood); + yield 90; -for (const biome of ["lowlands", "highlands"]) - createStragglerTrees( - biomes[biome].gaia.flora.trees, + createFood( [ - biome == "highlands" ? constraintHighlands : constraintLowlands, - avoidClasses(clForest, 8, clCliffs, 1, clPlayer, 12, clMetal, 6, clRock, 6, clCliffs, 2, clWater, 2, clDock, 6) + [new SimpleObject(biomes.lowlands.gaia.fauna.sheep, 2, 3, 0, 2)], + [new SimpleObject(biomes.lowlands.gaia.fauna.rabbit, 2, 3, 0, 2)], + [new SimpleObject(biomes.lowlands.gaia.flora.fruitBush, 5, 7, 0, 4)] ], - clForest, - stragglerTrees * (biome == "highlands" ? biomeTreeRatioHighlands * 4 : 1 - biomeTreeRatioHighlands)); -Engine.SetProgress(85); - -createFood( - [ - [new SimpleObject(biomes.highlands.gaia.fauna.horse, 3, 5, 0, 4)], - [new SimpleObject(biomes.highlands.gaia.fauna.pony, 2, 3, 0, 4)], - [new SimpleObject(biomes.highlands.gaia.flora.fruitBush, 5, 7, 0, 4)] - ], - [ - scaleByMapSize(2, 16), - scaleByMapSize(2, 12), - scaleByMapSize(2, 20) - ], - [ - avoidClasses(clForest, 0, clPlayer, 20, clFood, 16, clCliffs, 2, clWater, 2, clRock, 4, clMetal, 4, clDock, 6), - constraintHighlands - ], - clFood); -Engine.SetProgress(90); - -createFood( - [ - [new SimpleObject(biomes.lowlands.gaia.fauna.sheep, 2, 3, 0, 2)], - [new SimpleObject(biomes.lowlands.gaia.fauna.rabbit, 2, 3, 0, 2)], - [new SimpleObject(biomes.lowlands.gaia.flora.fruitBush, 5, 7, 0, 4)] - ], - [ - scaleByMapSize(2, 16), - scaleByMapSize(2, 12), - scaleByMapSize(1, 20) - ], - [ - avoidClasses(clForest, 0, clPlayer, 20, clFood, 16, clCliffs, 2, clWater, 2, clRock, 4, clMetal, 4, clDock, 6), - constraintLowlands - ], - clFood); -Engine.SetProgress(93); - -createFood( - [ - [new SimpleObject(biomes.highlands.gaia.fauna.goat, 3, 5, 0, 4)] - ], - [ - 3 * numPlayers - ], - [ - avoidClasses(clForest, 1, clPlayer, 20, clFood, 20, clCliffs, 1, clRock, 4, clMetal, 4, clDock, 6), - constraintMountains - ], - clFood); - -g_Map.log("Creating hawk"); -for (let i = 0; i < scaleByMapSize(0, 2); ++i) - g_Map.placeEntityAnywhere(biomes.highlands.gaia.fauna.hawk, 0, mapCenter, randomAngle()); - -g_Map.log("Creating fish"); -createObjectGroups( - new SimpleGroup([new SimpleObject(biomes.water.gaia.fauna.fish, 1, 1, 0, 3)], true, clFood), - 0, - [stayClasses(clWater, 8), avoidClasses(clFood, 8, clDock, 6)], - scaleByMapSize(15, 50), - 100); -Engine.SetProgress(95); - -g_Map.log("Creating grass patches"); -for (const biome of ["lowlands", "highlands"]) - for (const patch of biomes[biome].terrains.patches) - createPatches( - [scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - patch, - [ - biome == "highlands" ? constraintHighlands : constraintLowlands, - avoidClasses(clForest, 0, clDirt, 5, clPlayer, 12, clCliffs, 2, clWater, 2), - ], - scaleByMapSize(15, 45) / biomes[biome].terrains.patches.length, - clDirt); -Engine.SetProgress(96); + [ + scaleByMapSize(2, 16), + scaleByMapSize(2, 12), + scaleByMapSize(1, 20) + ], + [ + avoidClasses(clForest, 0, clPlayer, 20, clFood, 16, clCliffs, 2, clWater, 2, clRock, 4, + clMetal, 4, clDock, 6), + constraintLowlands + ], + clFood); + yield 93; -for (const biome of ["lowlands", "highlands"]) -{ - createDecoration( + createFood( [ - [new SimpleObject(actorTemplate(biomes[biome].actors.mushroom), 1, 4, 1, 2)], - [ - new SimpleObject(actorTemplate(biomes.common.actors.grass), 2, 4, 0, 1.8), - new SimpleObject(actorTemplate(biomes.common.actors.grassShort), 3,6, 1.2, 2.5) - ], - [ - new SimpleObject(actorTemplate(biomes.common.actors.bushMedium), 1, 2, 0, 2), - new SimpleObject(actorTemplate(biomes.common.actors.bushSmall), 2, 4, 0, 2) - ] + [new SimpleObject(biomes.highlands.gaia.fauna.goat, 3, 5, 0, 4)] ], [ - scaleByMapAreaAbsolute(20), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13) + 3 * numPlayers ], [ - biome == "highlands" ? constraintHighlands : constraintLowlands, - avoidClasses(clCliffs, 1, clPlayer, 15, clForest, 1, clRock, 4, clMetal, 4), - ]); + avoidClasses(clForest, 1, clPlayer, 20, clFood, 20, clCliffs, 1, clRock, 4, clMetal, 4, + clDock, 6), + constraintMountains + ], + clFood); - createDecoration( + g_Map.log("Creating hawk"); + for (let i = 0; i < scaleByMapSize(0, 2); ++i) + g_Map.placeEntityAnywhere(biomes.highlands.gaia.fauna.hawk, 0, mapCenter, randomAngle()); + + g_Map.log("Creating fish"); + createObjectGroups( + new SimpleGroup([new SimpleObject(biomes.water.gaia.fauna.fish, 1, 1, 0, 3)], true, clFood), + 0, + [stayClasses(clWater, 8), avoidClasses(clFood, 8, clDock, 6)], + scaleByMapSize(15, 50), + 100); + yield 95; + + g_Map.log("Creating grass patches"); + for (const biome of ["lowlands", "highlands"]) + for (const patch of biomes[biome].terrains.patches) + createPatches( + [scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + patch, + [ + biome == "highlands" ? constraintHighlands : constraintLowlands, + avoidClasses(clForest, 0, clDirt, 5, clPlayer, 12, clCliffs, 2, clWater, 2), + ], + scaleByMapSize(15, 45) / biomes[biome].terrains.patches.length, + clDirt); + yield 96; + + for (const biome of ["lowlands", "highlands"]) + { + createDecoration( [ - biomes[biome].actors.stones.map(template => new SimpleObject(actorTemplate(template), 1, 3, 0, 1)) + [new SimpleObject(actorTemplate(biomes[biome].actors.mushroom), 1, 4, 1, 2)], + [ + new SimpleObject(actorTemplate(biomes.common.actors.grass), 2, 4, 0, 1.8), + new SimpleObject(actorTemplate(biomes.common.actors.grassShort), 3,6, 1.2, + 2.5) + ], + [ + new SimpleObject(actorTemplate(biomes.common.actors.bushMedium), 1, 2, 0, 2), + new SimpleObject(actorTemplate(biomes.common.actors.bushSmall), 2, 4, 0, 2) + ] ], [ - biomes[biome].actors.stones.map(template => scaleByMapAreaAbsolute(2) * randIntInclusive(1, 3)) + scaleByMapAreaAbsolute(20), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13) ], [ biome == "highlands" ? constraintHighlands : constraintLowlands, - avoidClasses(clWater, 4, clPlayer, 15, clForest, 1, clRock, 4, clMetal, 4), + avoidClasses(clCliffs, 1, clPlayer, 15, clForest, 1, clRock, 4, clMetal, 4), ]); -} -Engine.SetProgress(98); - -g_Map.log("Creating temple"); -createObjectGroups( - new SimpleGroup([new SimpleObject(biomes.highlands.gaia.athen.temple, 1, 1, 0, 0)], true), - 0, - [ - avoidClasses(clCliffs, 4, clWater, 4, clPlayer, 40, clForest, 4, clRock, 4, clMetal, 4), - constraintHighlands - ], - 1, - 200); - -g_Map.log("Creating statues"); -createObjectGroups( - new SimpleGroup([new SimpleObject(actorTemplate(biomes.lowlands.actors.athen.statue), 1, 1, 0, 0)], true), - 0, - [ - avoidClasses(clCliffs, 2, clWater, 4, clPlayer, 30, clForest, 1, clRock, 8, clMetal, 8, clDock, 6), - constraintLowlands - ], - scaleByMapSize(1, 2), - 50); - -g_Map.log("Creating campfire"); -createObjectGroups( - new SimpleGroup([new SimpleObject(actorTemplate(biomes.common.actors.campfire), 1, 1, 0, 0)], true), - 0, - [avoidClasses(clCliffs, 2, clWater, 4, clPlayer, 30, clForest, 1, clRock, 8, clMetal, 8, clDock, 6)], - scaleByMapSize(0, 2), - 50); - -g_Map.log("Creating oxybeles"); -createObjectGroups( - new SimpleGroup([new SimpleObject(biomes.highlands.gaia.athen.oxybeles, 1, 1, 0, 0)], true), - 0, - [ - avoidClasses(clCliffs, 2, clPlayer, 30, clForest, 1, clRock, 4, clMetal, 4), - constraintHighlands - ], - scaleByMapSize(0, 2), - 100); - -g_Map.log("Creating handcart"); -createObjectGroups( - new SimpleGroup([new SimpleObject(actorTemplate(biomes.highlands.actors.handcart), 1, 1, 0, 0)], true), - 0, - [ - avoidClasses(clCliffs, 1, clPlayer, 15, clForest, 1, clRock, 4, clMetal, 4), - constraintHighlands - ], - scaleByMapSize(1, 4), - 50); - -g_Map.log("Creating water log"); -createObjectGroups( - new SimpleGroup([new SimpleObject(actorTemplate(biomes.water.actors.waterlog), 1, 1, 0, 0)], true), - 0, - [stayClasses(clWater, 4)], - scaleByMapSize(1, 2), - 10); - -g_Map.log("Creating reeds"); -createObjectGroups( - new SimpleGroup( + + createDecoration( + [ + biomes[biome].actors.stones.map( + template => new SimpleObject(actorTemplate(template), 1, 3, 0, 1)) + ], + [ + biomes[biome].actors.stones.map( + template => scaleByMapAreaAbsolute(2) * randIntInclusive(1, 3)) + ], + [ + biome == "highlands" ? constraintHighlands : constraintLowlands, + avoidClasses(clWater, 4, clPlayer, 15, clForest, 1, clRock, 4, clMetal, 4), + ]); + } + yield 98; + + g_Map.log("Creating temple"); + createObjectGroups( + new SimpleGroup([new SimpleObject(biomes.highlands.gaia.athen.temple, 1, 1, 0, 0)], true), + 0, + [ + avoidClasses(clCliffs, 4, clWater, 4, clPlayer, 40, clForest, 4, clRock, 4, clMetal, 4), + constraintHighlands + ], + 1, + 200); + + g_Map.log("Creating statues"); + createObjectGroups( + new SimpleGroup([ + new SimpleObject(actorTemplate(biomes.lowlands.actors.athen.statue), 1, 1, 0, 0)], true), + 0, [ - new SimpleObject(actorTemplate(biomes.shoreline.actors.reeds), 5, 12, 1, 4), - new SimpleObject(actorTemplate(biomes.shoreline.actors.lillies), 1, 2, 1, 5) + avoidClasses(clCliffs, 2, clWater, 4, clPlayer, 30, clForest, 1, clRock, 8, clMetal, 8, + clDock, 6), + constraintLowlands ], - false, - clDirt), - 0, - new HeightConstraint(heightReedsMin, heightReedsMax), - scaleByMapSize(10, 25), - 20); - -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clFood, 2, clCliffs, 2, clWater, 15)); -Engine.SetProgress(99); - -setSkySet("sunny"); -setSunColor(0.988166, 0.929297, 0.693819); -setSunElevation(0.579592); -setSunRotation(-0.566729); -setAmbientColor(0.372549,0.376471,0.459608); -setWaterColor(0.024, 0.212, 0.024); -setWaterTint(0.133, 0.725, 0.855); -setWaterMurkiness(0.8); -setWaterWaviness(3); -setFogFactor(0); -setPPEffect("hdr"); -setPPSaturation(0.45); -setPPContrast(0.62); -setPPBloom(0.12); - -g_Map.ExportMap(); + scaleByMapSize(1, 2), + 50); + + g_Map.log("Creating campfire"); + createObjectGroups( + new SimpleGroup([new SimpleObject(actorTemplate(biomes.common.actors.campfire), 1, 1, 0, 0)], + true), + 0, + [avoidClasses(clCliffs, 2, clWater, 4, clPlayer, 30, clForest, 1, clRock, 8, clMetal, 8, clDock, + 6)], + scaleByMapSize(0, 2), + 50); + + g_Map.log("Creating oxybeles"); + createObjectGroups( + new SimpleGroup([new SimpleObject(biomes.highlands.gaia.athen.oxybeles, 1, 1, 0, 0)], true), + 0, + [ + avoidClasses(clCliffs, 2, clPlayer, 30, clForest, 1, clRock, 4, clMetal, 4), + constraintHighlands + ], + scaleByMapSize(0, 2), + 100); + + g_Map.log("Creating handcart"); + createObjectGroups( + new SimpleGroup([new SimpleObject(actorTemplate(biomes.highlands.actors.handcart), 1, 1, 0, 0)], + true), + 0, + [ + avoidClasses(clCliffs, 1, clPlayer, 15, clForest, 1, clRock, 4, clMetal, 4), + constraintHighlands + ], + scaleByMapSize(1, 4), + 50); + + g_Map.log("Creating water log"); + createObjectGroups( + new SimpleGroup([new SimpleObject(actorTemplate(biomes.water.actors.waterlog), 1, 1, 0, 0)], + true), + 0, + [stayClasses(clWater, 4)], + scaleByMapSize(1, 2), + 10); + + g_Map.log("Creating reeds"); + createObjectGroups( + new SimpleGroup( + [ + new SimpleObject(actorTemplate(biomes.shoreline.actors.reeds), 5, 12, 1, 4), + new SimpleObject(actorTemplate(biomes.shoreline.actors.lillies), 1, 2, 1, 5) + ], + false, + clDirt), + 0, + new HeightConstraint(heightReedsMin, heightReedsMax), + scaleByMapSize(10, 25), + 20); + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clFood, 2, clCliffs, 2, + clWater, 15)); + yield 99; + + setSkySet("sunny"); + setSunColor(0.988166, 0.929297, 0.693819); + setSunElevation(0.579592); + setSunRotation(-0.566729); + setAmbientColor(0.372549,0.376471,0.459608); + setWaterColor(0.024, 0.212, 0.024); + setWaterTint(0.133, 0.725, 0.855); + setWaterMurkiness(0.8); + setWaterWaviness(3); + setFogFactor(0); + setPPEffect("hdr"); + setPPSaturation(0.45); + setPPContrast(0.62); + setPPBloom(0.12); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/hells_pass.js =================================================================== --- binaries/data/mods/public/maps/random/hells_pass.js +++ binaries/data/mods/public/maps/random/hells_pass.js @@ -3,259 +3,264 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setSelectedBiome(); +// teamsArray -const heightLand = 1; -const heightBarrier = 30; +function* GenerateMap() +{ + setSelectedBiome(); -const g_Map = new RandomMap(heightLand, g_Terrains.mainTerrain); + const heightLand = 1; -initTileClasses(); + global.g_Map = new RandomMap(heightLand, g_Terrains.mainTerrain); -const mapCenter = g_Map.getCenter(); + initTileClasses(); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land)); + const mapCenter = g_Map.getCenter(); -Engine.SetProgress(10); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land)); -const teamsArray = getTeamsArray(); -const startAngle = randomAngle(); -createBases( - ...playerPlacementByPattern( - "line", - fractionToTiles(0.2), - fractionToTiles(0.08), - startAngle, - undefined), - false); -Engine.SetProgress(20); + yield 10; -placeBarriers(); -Engine.SetProgress(40); + const startAngle = randomAngle(); + createBases( + ...playerPlacementByPattern( + "line", + fractionToTiles(0.2), + fractionToTiles(0.08), + startAngle, + undefined), + false); + yield 20; -addElements(shuffleArray([ - { - "func": addBluffs, - "baseHeight": heightLand, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.hill, 5, - g_TileClasses.mountain, 20, - g_TileClasses.plateau, 20, - g_TileClasses.player, 30, - g_TileClasses.spine, 15, - g_TileClasses.valley, 5, - g_TileClasses.water, 7 - ], - "sizes": ["normal", "big"], - "mixes": ["varied"], - "amounts": ["few"] - }, - { - "func": addHills, - "avoid": [ - g_TileClasses.bluff, 5, - g_TileClasses.hill, 15, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 5, - g_TileClasses.player, 20, - g_TileClasses.spine, 15, - g_TileClasses.valley, 2, - g_TileClasses.water, 2 - ], - "sizes": ["normal", "big"], - "mixes": ["varied"], - "amounts": ["few"] - }, - { - "func": addLakes, - "avoid": [ - g_TileClasses.bluff, 7, - g_TileClasses.hill, 2, - g_TileClasses.mountain, 15, - g_TileClasses.plateau, 10, - g_TileClasses.player, 20, - g_TileClasses.spine, 15, - g_TileClasses.valley, 10, - g_TileClasses.water, 25 - ], - "sizes": ["big", "huge"], - "mixes": ["varied", "unique"], - "amounts": ["few"] - } -])); -Engine.SetProgress(50); + placeBarriers(startAngle, mapCenter); + yield 40; -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.spine, 5, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.spine, 5, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - } -]); -Engine.SetProgress(60); + addElements(shuffleArray([ + { + "func": addBluffs, + "baseHeight": heightLand, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.hill, 5, + g_TileClasses.mountain, 20, + g_TileClasses.plateau, 20, + g_TileClasses.player, 30, + g_TileClasses.spine, 15, + g_TileClasses.valley, 5, + g_TileClasses.water, 7 + ], + "sizes": ["normal", "big"], + "mixes": ["varied"], + "amounts": ["few"] + }, + { + "func": addHills, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.hill, 15, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 5, + g_TileClasses.player, 20, + g_TileClasses.spine, 15, + g_TileClasses.valley, 2, + g_TileClasses.water, 2 + ], + "sizes": ["normal", "big"], + "mixes": ["varied"], + "amounts": ["few"] + }, + { + "func": addLakes, + "avoid": [ + g_TileClasses.bluff, 7, + g_TileClasses.hill, 2, + g_TileClasses.mountain, 15, + g_TileClasses.plateau, 10, + g_TileClasses.player, 20, + g_TileClasses.spine, 15, + g_TileClasses.valley, 10, + g_TileClasses.water, 25 + ], + "sizes": ["big", "huge"], + "mixes": ["varied", "unique"], + "amounts": ["few"] + } + ])); + yield 50; -addElements(shuffleArray([ - { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.metal, 20, - g_TileClasses.spine, 5, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": g_AllAmounts - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 10, - g_TileClasses.spine, 5, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": g_AllAmounts - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 18, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 5, - g_TileClasses.plateau, 5, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.spine, 5, - g_TileClasses.water, 2 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": ["few", "normal", "many", "tons"] - } -])); -Engine.SetProgress(80); + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.spine, 5, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.spine, 5, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + } + ]); + yield 60; -addElements(shuffleArray([ - { - "func": addBerries, - "avoid": [ - g_TileClasses.berries, 30, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 5, - g_TileClasses.metal, 10, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 10, - g_TileClasses.spine, 2, - g_TileClasses.water, 3 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.spine, 2, - g_TileClasses.water, 3 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 7, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.spine, 2, - g_TileClasses.water, 5 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - } -])); -Engine.SetProgress(90); + addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 20, + g_TileClasses.spine, 5, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": g_AllAmounts + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10, + g_TileClasses.spine, 5, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": g_AllAmounts + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 18, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.plateau, 5, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.spine, 5, + g_TileClasses.water, 2 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": ["few", "normal", "many", "tons"] + } + ])); + yield 80; -placePlayersNomad( - g_TileClasses.player, - avoidClasses( - g_TileClasses.bluff, 4, - g_TileClasses.water, 4, - g_TileClasses.spine, 4, - g_TileClasses.plateau, 4, - g_TileClasses.forest, 1, - g_TileClasses.metal, 4, - g_TileClasses.rock, 4, - g_TileClasses.mountain, 4, - g_TileClasses.animals, 2)); + addElements(shuffleArray([ + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 10, + g_TileClasses.spine, 2, + g_TileClasses.water, 3 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.spine, 2, + g_TileClasses.water, 3 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 7, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.spine, 2, + g_TileClasses.water, 5 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + } + ])); + yield 90; -g_Map.ExportMap(); + placePlayersNomad( + g_TileClasses.player, + avoidClasses( + g_TileClasses.bluff, 4, + g_TileClasses.water, 4, + g_TileClasses.spine, 4, + g_TileClasses.plateau, 4, + g_TileClasses.forest, 1, + g_TileClasses.metal, 4, + g_TileClasses.rock, 4, + g_TileClasses.mountain, 4, + g_TileClasses.animals, 2)); -function placeBarriers() + return g_Map; +} + +function placeBarriers(startAngle, mapCenter) { + const heightBarrier = 30; + let spineTerrain = g_Terrains.dirt; if (currentBiome() == "generic/arctic") @@ -267,7 +272,7 @@ if (currentBiome() == "generic/autumn") spineTerrain = g_Terrains.tier4Terrain; - const spineCount = isNomad() ? randIntInclusive(1, 4) : teamsArray.length; + const spineCount = isNomad() ? randIntInclusive(1, 4) : getTeamsArray().length; for (let i = 0; i < spineCount; ++i) { Index: binaries/data/mods/public/maps/random/hyrcanian_shores.js =================================================================== --- binaries/data/mods/public/maps/random/hyrcanian_shores.js +++ binaries/data/mods/public/maps/random/hyrcanian_shores.js @@ -2,357 +2,370 @@ Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); -setSelectedBiome(); - -const tPrimary = g_Terrains.mainTerrain; -const tGrass = g_Terrains.tier1Terrain; -const tGrassPForest = g_Terrains.forestFloor1; -const tGrassDForest = g_Terrains.forestFloor2; -const tCliff = g_Terrains.cliff; -const tGrassA = g_Terrains.tier2Terrain; -const tGrassB = g_Terrains.tier3Terrain; -const tGrassC = g_Terrains.tier4Terrain; -const tHill = g_Terrains.hill; -const tRoad = g_Terrains.road; -const tRoadWild = g_Terrains.roadWild; -const tGrassPatch = g_Terrains.dirt; -const tShore = g_Terrains.shoreBlend; -const tWater = g_Terrains.shore; - -const oPoplar = g_Gaia.tree1; -const oPalm = g_Gaia.tree2; -const oApple = g_Gaia.tree3; -const oOak = g_Gaia.tree4; -const oBerryBush = g_Gaia.fruitBush; -const oDeer = g_Gaia.mainHuntableAnimal; -const oFish = g_Gaia.fish; -const oGoat = "gaia/fauna_goat"; -const oBoar = "gaia/fauna_boar"; -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 pForestD = [tGrassDForest + TERRAIN_SEPARATOR + oPoplar, tGrassDForest]; -const pForestP = [tGrassPForest + TERRAIN_SEPARATOR + oOak, tGrassPForest]; - -const heightSeaGround1 = -3; -const heightShore1 = -1.5; -const heightShore2 = 0; -const heightLand = 1; -const heightOffsetBump = 4; -const heightHill = 15; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); -const numPlayers = getNumPlayers(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clHighlands = g_Map.createTileClass(); - -const waterPosition = fractionToTiles(0.25); -const highlandsPosition = fractionToTiles(0.75); - -const startAngle = randomAngle(); - -placePlayerBases({ - "PlayerPlacement": [sortAllPlayers(), playerPlacementLine(startAngle, mapCenter, fractionToTiles(0.2))], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oOak, - "count": 2 - }, - "Decoratives": { - "template": aGrassShort +function* GenerateMap() +{ + setSelectedBiome(); + + const tPrimary = g_Terrains.mainTerrain; + const tGrass = g_Terrains.tier1Terrain; + const tGrassPForest = g_Terrains.forestFloor1; + const tGrassDForest = g_Terrains.forestFloor2; + const tCliff = g_Terrains.cliff; + const tGrassA = g_Terrains.tier2Terrain; + const tGrassB = g_Terrains.tier3Terrain; + const tGrassC = g_Terrains.tier4Terrain; + const tHill = g_Terrains.hill; + const tRoad = g_Terrains.road; + const tRoadWild = g_Terrains.roadWild; + const tGrassPatch = g_Terrains.dirt; + const tShore = g_Terrains.shoreBlend; + const tWater = g_Terrains.shore; + + const oPoplar = g_Gaia.tree1; + const oPalm = g_Gaia.tree2; + const oApple = g_Gaia.tree3; + const oOak = g_Gaia.tree4; + const oBerryBush = g_Gaia.fruitBush; + const oDeer = g_Gaia.mainHuntableAnimal; + const oFish = g_Gaia.fish; + const oGoat = "gaia/fauna_goat"; + const oBoar = "gaia/fauna_boar"; + 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 pForestD = [tGrassDForest + TERRAIN_SEPARATOR + oPoplar, tGrassDForest]; + const pForestP = [tGrassPForest + TERRAIN_SEPARATOR + oOak, tGrassPForest]; + + const heightSeaGround1 = -3; + const heightShore1 = -1.5; + const heightShore2 = 0; + const heightLand = 1; + const heightOffsetBump = 4; + const heightHill = 15; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + const numPlayers = getNumPlayers(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clHighlands = g_Map.createTileClass(); + + const waterPosition = fractionToTiles(0.25); + const highlandsPosition = fractionToTiles(0.75); + + const startAngle = randomAngle(); + + placePlayerBases({ + "PlayerPlacement": [sortAllPlayers(), + playerPlacementLine(startAngle, mapCenter, fractionToTiles(0.2))], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oOak, + "count": 2 + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 10; + + paintRiver({ + "parallel": true, + "start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(startAngle, mapCenter), + "end": new Vector2D(mapBounds.right, mapBounds.top).rotateAround(startAngle, mapCenter), + "width": 2 * waterPosition, + "fadeDist": scaleByMapSize(6, 25), + "deviation": 0, + "heightRiverbed": heightSeaGround1, + "heightLand": heightLand, + "meanderShort": 20, + "meanderLong": 0, + "waterFunc": (position, height, riverFraction) => { + + if (height < heightShore2) + clWater.add(position); + + createTerrain(height < heightShore1 ? tWater : tShore).place(position); + } + }); + yield 20; + + g_Map.log("Marking highlands area"); + createArea( + new ConvexPolygonPlacer( + [ + new Vector2D(mapBounds.left, mapBounds.top - highlandsPosition), + new Vector2D(mapBounds.right, mapBounds.top - highlandsPosition), + new Vector2D(mapBounds.left, mapBounds.bottom), + new Vector2D(mapBounds.right, mapBounds.bottom) + ].map(pos => pos.rotateAround(startAngle, mapCenter)), + Infinity), + new TileClassPainter(clHighlands)); + + g_Map.log("Creating fish"); + for (let i = 0; i < scaleByMapSize(10, 20); ++i) + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood), + 0, + [stayClasses(clWater, 2), avoidClasses(clFood, 3)], + numPlayers, + 50); + yield 25; + + g_Map.log("Creating bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(10, 60), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 3), + stayClasses(clHighlands, 1), + scaleByMapSize(300, 600)); + + yield 30; + + g_Map.log("Creating hills"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), + [ + new LayeredPainter([tCliff, tHill], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) + ], + avoidClasses(clPlayer, 20, clWater, 5, clHill, 15, clHighlands, 5), + scaleByMapSize(1, 4) * numPlayers); + + yield 35; + + g_Map.log("Creating mainland forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(1000, 3500, 0.85); + const highlandShare = 0.4; + { + const types = [ + [[tGrassDForest, tGrass, pForestD], [tGrassDForest, pForestD]] + ]; + const numberOfForests = scaleByMapSize(20, 100) / types[0].length; + for (const type of types) + createAreas( + new ClumpPlacer(forestTrees * (1.0 - highlandShare) / numberOfForests, 0.1, 0.1, + Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 20, clWater, 3, clForest, 10, clHill, 0, clBaseResource, 3, + clHighlands, 2), + numberOfForests); + yield 45; } -}); -Engine.SetProgress(10); - -paintRiver({ - "parallel": true, - "start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(startAngle, mapCenter), - "end": new Vector2D(mapBounds.right, mapBounds.top).rotateAround(startAngle, mapCenter), - "width": 2 * waterPosition, - "fadeDist": scaleByMapSize(6, 25), - "deviation": 0, - "heightRiverbed": heightSeaGround1, - "heightLand": heightLand, - "meanderShort": 20, - "meanderLong": 0, - "waterFunc": (position, height, riverFraction) => { - - if (height < heightShore2) - clWater.add(position); - - createTerrain(height < heightShore1 ? tWater : tShore).place(position); + + g_Map.log("Creating highland forests"); + { + const types = [ + [[tGrassDForest, tGrass, pForestP], [tGrassDForest, pForestP]] + ]; + const numberOfForests = scaleByMapSize(8, 50) / types[0].length; + for (const type of types) + createAreas( + new ClumpPlacer(forestTrees * (highlandShare) / numberOfForests, 0.1, 0.1, + Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + [ + avoidClasses(clPlayer, 20, clWater, 3, clForest, 10, clHill, 0, + clBaseResource, 3), + stayClasses(clHighlands, 2) + ], + numberOfForests, + 30); } -}); -Engine.SetProgress(20); -g_Map.log("Marking highlands area"); -createArea( - new ConvexPolygonPlacer( - [ - new Vector2D(mapBounds.left, mapBounds.top - highlandsPosition), - new Vector2D(mapBounds.right, mapBounds.top - highlandsPosition), - new Vector2D(mapBounds.left, mapBounds.bottom), - new Vector2D(mapBounds.right, mapBounds.bottom) - ].map(pos => pos.rotateAround(startAngle, mapCenter)), - Infinity), - new TileClassPainter(clHighlands)); - -g_Map.log("Creating fish"); -for (let i = 0; i < scaleByMapSize(10, 20); ++i) - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood), - 0, - [stayClasses(clWater, 2), avoidClasses(clFood, 3)], - numPlayers, - 50); -Engine.SetProgress(25); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(10, 60), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 3), - stayClasses(clHighlands, 1), - scaleByMapSize(300, 600)); - -Engine.SetProgress(30); - -g_Map.log("Creating hills"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), - [ - new LayeredPainter([tCliff, tHill], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 20, clWater, 5, clHill, 15, clHighlands, 5), - scaleByMapSize(1, 4) * numPlayers); - -Engine.SetProgress(35); - -g_Map.log("Creating mainland forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(1000, 3500, 0.85); -const highlandShare = 0.4; -{ - const types = [ - [[tGrassDForest, tGrass, pForestD], [tGrassDForest, pForestD]] - ]; - const numberOfForests = scaleByMapSize(20, 100) / types[0].length; - for (const type of types) + yield 70; + + g_Map.log("Creating dirt patches"); + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) createAreas( - new ClumpPlacer(forestTrees * (1.0 - highlandShare) / numberOfForests, 0.1, 0.1, Infinity), + new ClumpPlacer(size, 0.3, 0.06, 0.5), [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) + new LayeredPainter([[tGrass, tGrassA], [tGrassA, tGrassB], [tGrassB, tGrassC]], + [1, 1]), + new TileClassPainter(clDirt) ], - avoidClasses(clPlayer, 20, clWater, 3, clForest, 10, clHill, 0, clBaseResource, 3, clHighlands, 2), - numberOfForests); - Engine.SetProgress(45); -} + avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 4), + scaleByMapSize(15, 45)); + yield 75; -g_Map.log("Creating highland forests"); -{ - const types = [ - [[tGrassDForest, tGrass, pForestP], [tGrassDForest, pForestP]] - ]; - const numberOfForests = scaleByMapSize(8, 50) / types[0].length; - for (const type of types) + g_Map.log("Creating grass patches"); + for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) createAreas( - new ClumpPlacer(forestTrees * (highlandShare) / numberOfForests, 0.1, 0.1, Infinity), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) - ], - [ - avoidClasses(clPlayer, 20, clWater, 3, clForest, 10, clHill, 0, clBaseResource, 3), - stayClasses(clHighlands, 2) - ], - numberOfForests, - 30); + new ClumpPlacer(size, 0.3, 0.06, 0.5), + new LayeredPainter([tGrassC, tGrassPatch], [2]), + avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6, clBaseResource, + 6), + scaleByMapSize(15, 45)); + + yield 80; + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10, clHill, 2)], + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10, clHill, 2)], + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 2)], + scaleByMapSize(5, 20), 100 + ); + + yield 85; + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aRockMedium, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), + scaleByMapSize(16, 262), 50 + ); + yield 90; + + g_Map.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(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), + scaleByMapSize(8, 131), 50 + ); + + g_Map.log("Creating deer"); + group = new SimpleGroup( + [new SimpleObject(oDeer, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 0, clFood, 5), + 6 * numPlayers, 50 + ); + + g_Map.log("Creating sheep"); + group = new SimpleGroup( + [new SimpleObject(oGoat, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 0, clFood, 20), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating berry bush"); + group = new SimpleGroup( + [new SimpleObject(oBerryBush, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 6, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + + g_Map.log("Creating boar"); + group = new SimpleGroup( + [new SimpleObject(oBoar, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 0, clFood, 20), + 2 * numPlayers, 50 + ); + + createStragglerTrees( + [oPoplar, oPalm, oApple], + avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 10, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + + g_Map.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(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), + scaleByMapSize(13, 200) + ); + + g_Map.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(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), + scaleByMapSize(13, 200) + ); + yield 95; + + g_Map.log("Creating bushes"); + group = new SimpleGroup( + [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 1, clHill, 1, clPlayer, 1, clDirt, 1), + scaleByMapSize(13, 200), 50 + ); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, + clFood, 2)); + + setWaterWaviness(2.0); + setWaterType("ocean"); + + return g_Map; } - -Engine.SetProgress(70); - -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - [ - new LayeredPainter([[tGrass, tGrassA], [tGrassA, tGrassB], [tGrassB, tGrassC]], [1, 1]), - new TileClassPainter(clDirt) - ], - avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 4), - scaleByMapSize(15, 45)); -Engine.SetProgress(75); - -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - new LayeredPainter([tGrassC, tGrassPatch], [2]), - avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6, clBaseResource, 6), - scaleByMapSize(15, 45)); - -Engine.SetProgress(80); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10, clHill, 2)], - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10, clHill, 2)], - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 2)], - scaleByMapSize(5, 20), 100 -); - -Engine.SetProgress(85); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aRockMedium, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), - scaleByMapSize(16, 262), 50 -); -Engine.SetProgress(90); - -g_Map.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(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), - scaleByMapSize(8, 131), 50 -); - -g_Map.log("Creating deer"); -group = new SimpleGroup( - [new SimpleObject(oDeer, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 0, clFood, 5), - 6 * numPlayers, 50 -); - -g_Map.log("Creating sheep"); -group = new SimpleGroup( - [new SimpleObject(oGoat, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 0, clFood, 20), - 3 * numPlayers, 50 -); - -g_Map.log("Creating berry bush"); -group = new SimpleGroup( - [new SimpleObject(oBerryBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 6, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - randIntInclusive(1, 4) * numPlayers + 2, 50 -); - -g_Map.log("Creating boar"); -group = new SimpleGroup( - [new SimpleObject(oBoar, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clHill, 0, clFood, 20), - 2 * numPlayers, 50 -); - -createStragglerTrees( - [oPoplar, oPalm, oApple], - avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 10, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); - -g_Map.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(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), - scaleByMapSize(13, 200) -); - -g_Map.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(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), - scaleByMapSize(13, 200) -); -Engine.SetProgress(95); - -g_Map.log("Creating bushes"); -group = new SimpleGroup( - [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 1, clHill, 1, clPlayer, 1, clDirt, 1), - scaleByMapSize(13, 200), 50 -); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setWaterWaviness(2.0); -setWaterType("ocean"); - -g_Map.ExportMap(); Index: binaries/data/mods/public/maps/random/india.js =================================================================== --- binaries/data/mods/public/maps/random/india.js +++ binaries/data/mods/public/maps/random/india.js @@ -1,271 +1,274 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tGrass1 = "savanna_grass_a"; -const tDirt1 = "savanna_dirt_a"; -const tDirt4 = "savanna_dirt_b"; -const tCityTiles = "savanna_tile_a_dirt_red"; -const tShore = "savanna_riparian_bank"; -const tWater = "savanna_riparian_wet"; +function* GenerateMap() +{ + const tGrass1 = "savanna_grass_a"; + const tDirt1 = "savanna_dirt_a"; + const tDirt4 = "savanna_dirt_b"; + const tCityTiles = "savanna_tile_a_dirt_red"; + const tShore = "savanna_riparian_bank"; + const tWater = "savanna_riparian_wet"; -const oTree = "gaia/tree/palm_tropic"; -const oBerryBush = "gaia/fruit/berry_01"; -const oRabbit = "gaia/fauna_rabbit"; -const oTiger = "gaia/fauna_tiger"; -const oCrocodile = "gaia/fauna_crocodile_nile"; -const oFish = "gaia/fish/generic"; -const oElephant = "gaia/fauna_elephant_asian"; -const oElephantInfant = "gaia/fauna_elephant_asian_infant"; -const oBoar = "gaia/fauna_boar"; -const oStoneSmall = "gaia/rock/savanna_small"; -const oMetalLarge = "gaia/ore/savanna_large"; + const oTree = "gaia/tree/palm_tropic"; + const oBerryBush = "gaia/fruit/berry_01"; + const oRabbit = "gaia/fauna_rabbit"; + const oTiger = "gaia/fauna_tiger"; + const oCrocodile = "gaia/fauna_crocodile_nile"; + const oFish = "gaia/fish/generic"; + const oElephant = "gaia/fauna_elephant_asian"; + const oElephantInfant = "gaia/fauna_elephant_asian_infant"; + const oBoar = "gaia/fauna_boar"; + const oStoneSmall = "gaia/rock/savanna_small"; + const oMetalLarge = "gaia/ore/savanna_large"; -const aBush = "actor|props/flora/bush_medit_sm_dry.xml"; -const aRock = "actor|geology/stone_savanna_med.xml"; + const aBush = "actor|props/flora/bush_medit_sm_dry.xml"; + const aRock = "actor|geology/stone_savanna_med.xml"; -const heightSeaGround = -3; -const heightLand = 1; -const heightShore = 3; -const heightOffsetBump = 2; + const heightSeaGround = -3; + const heightLand = 1; + const heightShore = 3; + const heightOffsetBump = 2; -const g_Map = new RandomMap(heightLand, tGrass1); + global.g_Map = new RandomMap(heightLand, tGrass1); -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - // No city patch - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { - "template": oMetalLarge - }, - { - "type": "stone_formation", - "template": oStoneSmall, - "terrain": tDirt1 - } - ] - }, - "Trees": { - "template": oTree, - "count": scaleByMapSize(3, 7), - "minDist": 13, - "maxDist": 15, - "minDistGroup": 4, - "maxDistGroup": 6 - } - // No decoratives -}); -Engine.SetProgress(20); + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + // No city patch + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { + "template": oMetalLarge + }, + { + "type": "stone_formation", + "template": oStoneSmall, + "terrain": tDirt1 + } + ] + }, + "Trees": { + "template": oTree, + "count": scaleByMapSize(3, 7), + "minDist": 13, + "maxDist": 15, + "minDistGroup": 4, + "maxDistGroup": 6 + } + // No decoratives + }); + yield 20; -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.5, 0.08, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - avoidClasses(clPlayer, 13), - scaleByMapSize(300, 800) -); + g_Map.log("Creating bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 50), 0.5, 0.08, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + avoidClasses(clPlayer, 13), + scaleByMapSize(300, 800) + ); -g_Map.log("Creating the half dried-up lake"); -createArea( - new ChainPlacer( - 2, - Math.floor(scaleByMapSize(2, 16)), - Math.floor(scaleByMapSize(35, 200)), - Infinity, - mapCenter, - 0, - [Math.floor(scaleByMapSize(15, 40))]), - [ - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 2)); + g_Map.log("Creating the half dried-up lake"); + createArea( + new ChainPlacer( + 2, + Math.floor(scaleByMapSize(2, 16)), + Math.floor(scaleByMapSize(35, 200)), + Infinity, + mapCenter, + 0, + [Math.floor(scaleByMapSize(15, 40))]), + [ + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 2)); -g_Map.log("Creating more shore jaggedness"); -createAreas( - new ChainPlacer(2, Math.floor(scaleByMapSize(4, 6)), 3, Infinity), - [ - new SmoothElevationPainter(ELEVATION_SET, heightShore, 4), - new TileClassUnPainter(clWater) - ], - borderClasses(clWater, 4, 7), - scaleByMapSize(12, 130) * 2, 150 -); + g_Map.log("Creating more shore jaggedness"); + createAreas( + new ChainPlacer(2, Math.floor(scaleByMapSize(4, 6)), 3, Infinity), + [ + new SmoothElevationPainter(ELEVATION_SET, heightShore, 4), + new TileClassUnPainter(clWater) + ], + borderClasses(clWater, 4, 7), + scaleByMapSize(12, 130) * 2, 150 + ); -paintTerrainBasedOnHeight(2.4, 3.4, 3, tGrass1); -paintTerrainBasedOnHeight(1, 2.4, 0, tShore); -paintTerrainBasedOnHeight(-8, 1, 2, tWater); -paintTileClassBasedOnHeight(-6, 0, 1, clWater); -Engine.SetProgress(55); + paintTerrainBasedOnHeight(2.4, 3.4, 3, tGrass1); + paintTerrainBasedOnHeight(1, 2.4, 0, tShore); + paintTerrainBasedOnHeight(-8, 1, 2, tWater); + paintTileClassBasedOnHeight(-6, 0, 1, clWater); + yield 55; -g_Map.log("Creating stone mines"); -for (let i = 0; i < scaleByMapSize(12, 30); ++i) -{ - const position = new Vector2D(randIntInclusive(1, mapSize - 1), randIntInclusive(1, mapSize - 1)); - if (avoidClasses(clPlayer, 30, clRock, 25, clWater, 10).allows(position)) + g_Map.log("Creating stone mines"); + for (let i = 0; i < scaleByMapSize(12, 30); ++i) { - createStoneMineFormation(position, oStoneSmall, tDirt4); - clRock.add(position); + const position = new Vector2D(randIntInclusive(1, mapSize - 1), randIntInclusive(1, mapSize - 1)); + if (avoidClasses(clPlayer, 30, clRock, 25, clWater, 10).allows(position)) + { + createStoneMineFormation(position, oStoneSmall, tDirt4); + clRock.add(position); + } } -} -g_Map.log("Creating metal mines"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), - 0, - avoidClasses(clPlayer, 20, clMetal, 10, clRock, 8, clWater, 4), - scaleByMapSize(2, 12), 100 -); -Engine.SetProgress(65); + g_Map.log("Creating metal mines"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), + 0, + avoidClasses(clPlayer, 20, clMetal, 10, clRock, 8, clWater, 4), + scaleByMapSize(2, 12), 100 + ); + yield 65; -g_Map.log("Creating small decorative rocks"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(aRock, 1, 3, 0, 3)], - true - ), - 0, - avoidClasses(clPlayer, 7, clWater, 1), - scaleByMapSize(200, 1200), 1 -); -Engine.SetProgress(70); + g_Map.log("Creating small decorative rocks"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(aRock, 1, 3, 0, 3)], + true + ), + 0, + avoidClasses(clPlayer, 7, clWater, 1), + scaleByMapSize(200, 1200), 1 + ); + yield 70; -g_Map.log("Creating boar"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oBoar, 1, 2, 0, 4)], - true, clFood - ), - 0, - avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), - scaleByMapSize(4, 12), 50 -); + g_Map.log("Creating boar"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oBoar, 1, 2, 0, 4)], + true, clFood + ), + 0, + avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), + scaleByMapSize(4, 12), 50 + ); -g_Map.log("Creating tigers"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oTiger, 2, 2, 0, 4)], - true, clFood - ), - 0, - avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), - scaleByMapSize(4, 12), 50 -); + g_Map.log("Creating tigers"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oTiger, 2, 2, 0, 4)], + true, clFood + ), + 0, + avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), + scaleByMapSize(4, 12), 50 + ); -g_Map.log("Creating crocodiles"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oCrocodile, 2, 4, 0, 4)], - true, clFood - ), 0, - stayClasses(clWater, 1), - scaleByMapSize(4, 12), 50 -); + g_Map.log("Creating crocodiles"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oCrocodile, 2, 4, 0, 4)], + true, clFood + ), 0, + stayClasses(clWater, 1), + scaleByMapSize(4, 12), 50 + ); -g_Map.log("Creating elephants"); -createObjectGroupsDeprecated( - new SimpleGroup( - [ - new SimpleObject(oElephant, 2, 4, 0, 4), - new SimpleObject(oElephantInfant, 1, 2, 0, 4) - ], - true, clFood - ), - 0, - avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), - scaleByMapSize(4, 12), 50 -); + g_Map.log("Creating elephants"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(oElephant, 2, 4, 0, 4), + new SimpleObject(oElephantInfant, 1, 2, 0, 4) + ], + true, clFood + ), + 0, + avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), + scaleByMapSize(4, 12), 50 + ); -g_Map.log("Creating rabbits"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oRabbit, 5, 6, 0, 4)], - true, clFood - ), - 0, - avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), - scaleByMapSize(4, 12), 50 -); + g_Map.log("Creating rabbits"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oRabbit, 5, 6, 0, 4)], + true, clFood + ), + 0, + avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), + scaleByMapSize(4, 12), 50 + ); -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 25 * numPlayers - ], - [avoidClasses(clFood, 20), stayClasses(clWater, 2)], - clFood); + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 25 * numPlayers + ], + [avoidClasses(clFood, 20), stayClasses(clWater, 2)], + clFood); -g_Map.log("Creating berry bush"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oBerryBush, 5, 7, 0, 4)], - true, clFood - ), - 0, - avoidClasses(clWater, 3, clPlayer, 20, clFood, 12, clRock, 4, clMetal, 4), - randIntInclusive(1, 4) * numPlayers + 2, 50 -); -Engine.SetProgress(85); + g_Map.log("Creating berry bush"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oBerryBush, 5, 7, 0, 4)], + true, clFood + ), + 0, + avoidClasses(clWater, 3, clPlayer, 20, clFood, 12, clRock, 4, clMetal, 4), + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + yield 85; -g_Map.log("Creating trees"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(oTree, 1, 7, 0, 3)], - true, clForest - ), - 0, - avoidClasses(clForest, 1, clPlayer, 20, clMetal, 4, clRock, 4, clWater, 1), - scaleByMapSize(70, 500) -); + g_Map.log("Creating trees"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(oTree, 1, 7, 0, 3)], + true, clForest + ), + 0, + avoidClasses(clForest, 1, clPlayer, 20, clMetal, 4, clRock, 4, clWater, 1), + scaleByMapSize(70, 500) + ); -g_Map.log("Creating large grass tufts"); -createObjectGroupsDeprecated( - new SimpleGroup( - [new SimpleObject(aBush, 2, 4, 0, 1.8, -Math.PI/8, Math.PI/8)] - ), - 0, - avoidClasses(clWater, 3, clPlayer, 2, clForest, 0), - scaleByMapSize(100, 1200) -); + g_Map.log("Creating large grass tufts"); + createObjectGroupsDeprecated( + new SimpleGroup( + [new SimpleObject(aBush, 2, 4, 0, 1.8, -Math.PI/8, Math.PI/8)] + ), + 0, + avoidClasses(clWater, 3, clPlayer, 2, clForest, 0), + scaleByMapSize(100, 1200) + ); -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); -setSunColor(0.87451, 0.847059, 0.647059); -setWaterColor(0.741176, 0.592157, 0.27451); -setWaterTint(0.741176, 0.592157, 0.27451); -setWaterWaviness(2.0); -setWaterType("clap"); -setWaterMurkiness(0.835938); + setSunColor(0.87451, 0.847059, 0.647059); + setWaterColor(0.741176, 0.592157, 0.27451); + setWaterTint(0.741176, 0.592157, 0.27451); + setWaterWaviness(2.0); + setWaterType("clap"); + setWaterMurkiness(0.835938); -setAmbientColor(0.57, 0.58, 0.55); + setAmbientColor(0.57, 0.58, 0.55); -setFogFactor(0.25); -setFogThickness(0.15); -setFogColor(0.847059, 0.737255, 0.482353); + setFogFactor(0.25); + setFogThickness(0.15); + setFogColor(0.847059, 0.737255, 0.482353); -setPPEffect("hdr"); -setPPContrast(0.57031); -setPPBloom(0.34); + setPPEffect("hdr"); + setPPContrast(0.57031); + setPPBloom(0.34); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/island_stronghold.js =================================================================== --- binaries/data/mods/public/maps/random/island_stronghold.js +++ binaries/data/mods/public/maps/random/island_stronghold.js @@ -3,409 +3,434 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -const g_InitialMineDistance = 14; -const g_InitialTrees = 50; - -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 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 oWhale = "gaia/fauna_whale_humpback"; -const oShipwreck = "gaia/treasure/shipwreck"; -const oShipDebris = "gaia/treasure/shipwreck_debris"; -const oObelisk = "structures/obelisk"; - -const aGrass = g_Decoratives.grass; -const aGrassShort = g_Decoratives.grassShort; -const aRockLarge = g_Decoratives.rockLarge; -const aRockMedium = g_Decoratives.rockMedium; - -const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; -const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; - -const heightSeaGround = -10; -const heightLand = 3; -const heightHill = 18; - -const g_Map = new RandomMap(heightSeaGround, tWater); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clLand = g_Map.createTileClass(); - -const startAngle = randomAngle(); - -const teams = getTeamsArray(); -const numTeams = teams.filter(team => team).length; -const teamPosition = distributePointsOnCircle(numTeams, startAngle, fractionToTiles(0.3), mapCenter)[0]; -const teamRadius = fractionToTiles(0.05); - -let teamNo = 0; - -g_Map.log("Creating player islands and bases"); - -for (let i = 0; i < teams.length; ++i) +function* GenerateMap() { - if (!teams[i] || isNomad()) - continue; - - ++teamNo; - - const [playerPosition, playerAngle] = distributePointsOnCircle(teams[i].length, startAngle + 2 * Math.PI / teams[i].length, teamRadius, teamPosition[i]); - playerPosition.forEach(position => position.round()); - - for (let p = 0; p < teams[i].length; ++p) + const initialMineDistance = 14; + const initialTrees = 50; + + 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 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 oWhale = "gaia/fauna_whale_humpback"; + const oShipwreck = "gaia/treasure/shipwreck"; + const oShipDebris = "gaia/treasure/shipwreck_debris"; + const oObelisk = "structures/obelisk"; + + const aGrass = g_Decoratives.grass; + const aGrassShort = g_Decoratives.grassShort; + const aRockLarge = g_Decoratives.rockLarge; + const aRockMedium = g_Decoratives.rockMedium; + + const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, + tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; + const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, + tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; + + const heightSeaGround = -10; + const heightLand = 3; + const heightHill = 18; + + global.g_Map = new RandomMap(heightSeaGround, tWater); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clLand = g_Map.createTileClass(); + + const startAngle = randomAngle(); + + const teams = getTeamsArray(); + const numTeams = teams.filter(team => team).length; + const teamPosition = + distributePointsOnCircle(numTeams, startAngle, fractionToTiles(0.3), mapCenter)[0]; + const teamRadius = fractionToTiles(0.05); + + let teamNo = 0; + + g_Map.log("Creating player islands and bases"); + + for (let i = 0; i < teams.length; ++i) { - addCivicCenterAreaToClass(playerPosition[p], clPlayer); + if (!teams[i] || isNomad()) + continue; - createArea( - new ChainPlacer(2, Math.floor(scaleByMapSize(5, 11)), Math.floor(scaleByMapSize(60, 250)), Infinity, playerPosition[p], Infinity, [defaultPlayerBaseRadius() * 3/4]), - [ - new TerrainPainter(tMainTerrain), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 2), - new TileClassPainter(clLand) - ]); + ++teamNo; - placeCivDefaultStartingEntities(playerPosition[p], teams[i][p], false); - } + const [playerPosition, playerAngle] = distributePointsOnCircle(teams[i].length, + startAngle + 2 * Math.PI / teams[i].length, teamRadius, teamPosition[i]); + playerPosition.forEach(position => position.round()); - const mineAngle = randFloat(-1, 1) * Math.PI / teams[i].length; - const mines = [ - { "template": oMetalLarge, "angle": mineAngle }, - { "template": oStoneLarge, "angle": mineAngle + Math.PI / 4 } - ]; + for (let p = 0; p < teams[i].length; ++p) + { + addCivicCenterAreaToClass(playerPosition[p], clPlayer); + + createArea( + new ChainPlacer(2, Math.floor(scaleByMapSize(5, 11)), + Math.floor(scaleByMapSize(60, 250)), Infinity, playerPosition[p], Infinity, + [defaultPlayerBaseRadius() * 3/4]), + [ + new TerrainPainter(tMainTerrain), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 2), + new TileClassPainter(clLand) + ]); + + placeCivDefaultStartingEntities(playerPosition[p], teams[i][p], false); + } - // Mines - for (let p = 0; p < teams[i].length; ++p) - for (const mine of mines) + const mineAngle = randFloat(-1, 1) * Math.PI / teams[i].length; + const mines = [ + { "template": oMetalLarge, "angle": mineAngle }, + { "template": oStoneLarge, "angle": mineAngle + Math.PI / 4 } + ]; + + // Mines + for (let p = 0; p < teams[i].length; ++p) + for (const mine of mines) + { + const position = Vector2D.add(playerPosition[p], + new Vector2D(initialMineDistance, 0).rotate(-playerAngle[p] - mine.angle)); + createObjectGroup( + new SimpleGroup([new SimpleObject(mine.template, 1, 1, 0, 4)], true, + clBaseResource, position), + 0, + [avoidClasses(clBaseResource, 4, clPlayer, 4), stayClasses(clLand, 5)]); + } + + // Trees + for (let p = 0; p < teams[i].length; ++p) { - const position = Vector2D.add(playerPosition[p], new Vector2D(g_InitialMineDistance, 0).rotate(-playerAngle[p] - mine.angle)); - createObjectGroup( - new SimpleGroup([new SimpleObject(mine.template, 1, 1, 0, 4)], true, clBaseResource, position), - 0, - [avoidClasses(clBaseResource, 4, clPlayer, 4), stayClasses(clLand, 5)]); + const tries = 10; + for (let x = 0; x < tries; ++x) + { + const tAngle = playerAngle[p] + randFloat(-1, 1) * 2 * Math.PI / teams[i].length; + const treePosition = Vector2D.add(playerPosition[p], + new Vector2D(16, 0).rotate(-tAngle)).round(); + if (createObjectGroup( + new SimpleGroup([new SimpleObject(oTree2, initialTrees, initialTrees, 0, + 7)], true, clBaseResource, treePosition), + 0, + [avoidClasses(clBaseResource, 4, clPlayer, 4), stayClasses(clLand, 4)])) + break; + } } - // Trees - for (let p = 0; p < teams[i].length; ++p) - { - const tries = 10; - for (let x = 0; x < tries; ++x) + for (let p = 0; p < teams[i].length; ++p) + placePlayerBaseBerries({ + "template": oFruitBush, + "playerID": teams[i][p], + "playerPosition": playerPosition[p], + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": new AndConstraint([avoidClasses(clPlayer, 4), + stayClasses(clLand, 5)]) + }); + + for (let p = 0; p < teams[i].length; ++p) + placePlayerBaseStartingAnimal({ + "playerID": teams[i][p], + "playerPosition": playerPosition[p], + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": new AndConstraint([avoidClasses(clPlayer, 4), + stayClasses(clLand, 5)]) + }); + + // Huntable animals + for (let p = 0; p < teams[i].length; ++p) { - const tAngle = playerAngle[p] + randFloat(-1, 1) * 2 * Math.PI / teams[i].length; - const treePosition = Vector2D.add(playerPosition[p], new Vector2D(16, 0).rotate(-tAngle)).round(); - if (createObjectGroup( - new SimpleGroup([new SimpleObject(oTree2, g_InitialTrees, g_InitialTrees, 0, 7)], true, clBaseResource, treePosition), + createObjectGroup( + new SimpleGroup([new SimpleObject(oMainHuntableAnimal, 2 * numPlayers / numTeams, + 2 * numPlayers / numTeams, 0, Math.floor(fractionToTiles(0.2)))], true, + clBaseResource, teamPosition[i]), 0, - [avoidClasses(clBaseResource, 4, clPlayer, 4), stayClasses(clLand, 4)])) - break; + [avoidClasses(clBaseResource, 2, clPlayer, 10), stayClasses(clLand, 5)]); + + createObjectGroup( + new SimpleGroup( + [new SimpleObject(oSecondaryHuntableAnimal, 4 * numPlayers / numTeams, + 4 * numPlayers / numTeams, 0, Math.floor(fractionToTiles(0.2)))], + true, clBaseResource, teamPosition[i]), + 0, + [avoidClasses(clBaseResource, 2, clPlayer, 10), stayClasses(clLand, 5)]); } } - for (let p = 0; p < teams[i].length; ++p) - placePlayerBaseBerries({ - "template": oFruitBush, - "playerID": teams[i][p], - "playerPosition": playerPosition[p], - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": new AndConstraint([avoidClasses(clPlayer, 4), stayClasses(clLand, 5)]) - }); - - for (let p = 0; p < teams[i].length; ++p) - placePlayerBaseStartingAnimal({ - "playerID": teams[i][p], - "playerPosition": playerPosition[p], - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": new AndConstraint([avoidClasses(clPlayer, 4), stayClasses(clLand, 5)]) - }); - - // Huntable animals - for (let p = 0; p < teams[i].length; ++p) + yield 40; + + g_Map.log("Creating big islands"); + createAreas( + new ChainPlacer( + Math.floor(scaleByMapSize(4, 8) * (isNomad() ? 2 : 1)), + Math.floor(scaleByMapSize(8, 16) * (isNomad() ? 2 : 1)), + Math.floor(scaleByMapSize(25, 60)), + 0.07, + undefined, + scaleByMapSize(30, 70)), + [ + new TerrainPainter(tMainTerrain), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), + new TileClassPainter(clLand) + ], + avoidClasses(clLand, 3, clPlayer, 3), + scaleByMapSize(4, 14) * (isNomad() ? 2 : 1), + 1); + + g_Map.log("Creating small islands"); + createAreas( + new ChainPlacer(Math.floor(scaleByMapSize(4, 7)), Math.floor(scaleByMapSize(7, 10)), + Math.floor(scaleByMapSize(16, 40)), 0.07, undefined, scaleByMapSize(22, 40)), + [ + new LayeredPainter([tMainTerrain, tMainTerrain], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), + new TileClassPainter(clLand) + ], + avoidClasses(clLand, 3, clPlayer, 3), + scaleByMapSize(6, 55), + 1); + + yield 70; + + g_Map.log("Smoothing heightmap"); + createArea( + new MapBoundsPlacer(), + new SmoothingPainter(1, 0.8, 5)); + + // repaint clLand to compensate for smoothing + unPaintTileClassBasedOnHeight(-10, 10, 3, clLand); + paintTileClassBasedOnHeight(0, 5, 3, clLand); + + yield 85; + + createBumps(avoidClasses(clPlayer, 20)); + + createMines( + [ + [new SimpleObject(oMetalLarge, 1, 1, 0, 4)] + ], + [avoidClasses(clForest, 1, clPlayer, 40, clRock, 20), stayClasses(clLand, 4)], + clMetal); + + createMines( + [ + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)] + ], + [avoidClasses(clForest, 1, clPlayer, 40, clMetal, 20), stayClasses(clLand, 4)], + clRock); + + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + createForests( + [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], + [avoidClasses(clPlayer, 10, clForest, 20, clBaseResource, 5, clRock, 6, clMetal, 6), + stayClasses(clLand, 3)], + clForest, + forestTrees); + + g_Map.log("Creating hills"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), + [ + new LayeredPainter([tCliff, tHill], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) + ], + [avoidClasses(clBaseResource, 20, clHill, 15, clRock, 6, clMetal, 6), stayClasses(clLand, 0)], + scaleByMapSize(4, 13) + ); + + g_Map.log("Smoothing heightmap"); + createArea( + new MapBoundsPlacer(), + new SmoothingPainter(1, 0.8, 3)); + + createStragglerTrees( + [oTree1, oTree2, oTree4, oTree3], + [ + avoidClasses(clForest, 10, clPlayer, 20, clMetal, 6, clRock, 6, clHill, 1), + stayClasses(clLand, 4) + ], + clForest, + stragglerTrees); + + createFood( + [ + [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], + [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] + ], + [3 * numPlayers, 3 * numPlayers], + [avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clRock, 6, clMetal, 6), + stayClasses(clLand, 2)], + clFood); + + createFood( + [ + [new SimpleObject(oFruitBush, 5, 7, 0, 4)] + ], + [3 * numPlayers], + [avoidClasses(clForest, 0, clPlayer, 15, clHill, 1, clFood, 4, clRock, 6, clMetal, 6), + stayClasses(clLand, 2)], + clFood); + + if (currentBiome() == "generic/sahara") { - createObjectGroup( - new SimpleGroup([new SimpleObject(oMainHuntableAnimal, 2 * numPlayers / numTeams, 2 * numPlayers / numTeams, 0, Math.floor(fractionToTiles(0.2)))], true, clBaseResource, teamPosition[i]), - 0, - [avoidClasses(clBaseResource, 2, clPlayer, 10), stayClasses(clLand, 5)]); - - createObjectGroup( - new SimpleGroup( - [new SimpleObject(oSecondaryHuntableAnimal, 4 * numPlayers / numTeams, 4 * numPlayers / numTeams, 0, Math.floor(fractionToTiles(0.2)))], - true, clBaseResource, teamPosition[i]), - 0, - [avoidClasses(clBaseResource, 2, clPlayer, 10), stayClasses(clLand, 5)]); + g_Map.log("Creating obelisks"); + const group = new SimpleGroup( + [new SimpleObject(oObelisk, 1, 1, 0, 1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + [avoidClasses(clBaseResource, 0, clHill, 0, clRock, 0, clMetal, 0, clFood, 0), + stayClasses(clLand, 1)], + scaleByMapSize(3, 8), 1000 + ); } -} -Engine.SetProgress(40); - -g_Map.log("Creating big islands"); -createAreas( - new ChainPlacer( - Math.floor(scaleByMapSize(4, 8) * (isNomad() ? 2 : 1)), - Math.floor(scaleByMapSize(8, 16) * (isNomad() ? 2 : 1)), - Math.floor(scaleByMapSize(25, 60)), - 0.07, - undefined, - scaleByMapSize(30, 70)), - [ - new TerrainPainter(tMainTerrain), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), - new TileClassPainter(clLand) - ], - avoidClasses(clLand, 3, clPlayer, 3), - scaleByMapSize(4, 14) * (isNomad() ? 2 : 1), - 1); - -g_Map.log("Creating small islands"); -createAreas( - new ChainPlacer(Math.floor(scaleByMapSize(4, 7)), Math.floor(scaleByMapSize(7, 10)), Math.floor(scaleByMapSize(16, 40)), 0.07, undefined, scaleByMapSize(22, 40)), - [ - new LayeredPainter([tMainTerrain, tMainTerrain], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), - new TileClassPainter(clLand) - ], - avoidClasses(clLand, 3, clPlayer, 3), - scaleByMapSize(6, 55), - 1); - -Engine.SetProgress(70); - -g_Map.log("Smoothing heightmap"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, 0.8, 5)); - -// repaint clLand to compensate for smoothing -unPaintTileClassBasedOnHeight(-10, 10, 3, clLand); -paintTileClassBasedOnHeight(0, 5, 3, clLand); - -Engine.SetProgress(85); - -createBumps(avoidClasses(clPlayer, 20)); - -createMines( - [ - [new SimpleObject(oMetalLarge, 1, 1, 0, 4)] - ], - [avoidClasses(clForest, 1, clPlayer, 40, clRock, 20), stayClasses(clLand, 4)], - clMetal); - -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)] - ], - [avoidClasses(clForest, 1, clPlayer, 40, clMetal, 20), stayClasses(clLand, 4)], - clRock); - -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); -createForests( - [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], - [avoidClasses(clPlayer, 10, clForest, 20, clBaseResource, 5, clRock, 6, clMetal, 6), stayClasses(clLand, 3)], - clForest, - forestTrees); - -g_Map.log("Creating hills"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), - [ - new LayeredPainter([tCliff, tHill], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - [avoidClasses(clBaseResource, 20, clHill, 15, clRock, 6, clMetal, 6), stayClasses(clLand, 0)], - scaleByMapSize(4, 13) -); - -g_Map.log("Smoothing heightmap"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, 0.8, 3)); - -createStragglerTrees( - [oTree1, oTree2, oTree4, oTree3], - [ - avoidClasses(clForest, 10, clPlayer, 20, clMetal, 6, clRock, 6, clHill, 1), - stayClasses(clLand, 4) - ], - clForest, - stragglerTrees); - -createFood( - [ - [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], - [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] - ], - [3 * numPlayers, 3 * numPlayers], - [avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clRock, 6, clMetal, 6), stayClasses(clLand, 2)], - clFood); - -createFood( - [ - [new SimpleObject(oFruitBush, 5, 7, 0, 4)] - ], - [3 * numPlayers], - [avoidClasses(clForest, 0, clPlayer, 15, clHill, 1, clFood, 4, clRock, 6, clMetal, 6), stayClasses(clLand, 2)], - clFood); - -if (currentBiome() == "generic/sahara") -{ - g_Map.log("Creating obelisks"); - const group = new SimpleGroup( - [new SimpleObject(oObelisk, 1, 1, 0, 1)], + g_Map.log("Creating dirt patches"); + const numb = currentBiome() == "generic/savanna" ? 3 : 1; + for (const 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]), + new TileClassPainter(clDirt) + ], + [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 4)], + numb*scaleByMapSize(15, 45)); + + g_Map.log("Creating grass patches"); + for (const 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, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 4)], + numb * scaleByMapSize(15, 45)); + + g_Map.log("Creating small decorative rocks"); + let group = new SimpleGroup( + [new SimpleObject(aRockMedium, 1, 3, 0, 1)], true ); createObjectGroupsDeprecated( group, 0, - [avoidClasses(clBaseResource, 0, clHill, 0, clRock, 0, clMetal, 0, clFood, 0), stayClasses(clLand, 1)], - scaleByMapSize(3, 8), 1000 + [avoidClasses(clForest, 0, clHill, 0), stayClasses(clLand, 2)], + scaleByMapSize(16, 262), 50 ); -} -g_Map.log("Creating dirt patches"); -const numb = currentBiome() == "generic/savanna" ? 3 : 1; -for (const 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]), - new TileClassPainter(clDirt) - ], - [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 4)], - numb*scaleByMapSize(15, 45)); + g_Map.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, clHill, 0), stayClasses(clLand, 2)], + scaleByMapSize(8, 131), 50 + ); -g_Map.log("Creating grass patches"); -for (const 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, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 4)], - numb * scaleByMapSize(15, 45)); - -g_Map.log("Creating small decorative rocks"); -let group = new SimpleGroup( - [new SimpleObject(aRockMedium, 1, 3, 0, 1)], - true -); -createObjectGroupsDeprecated( - group, 0, - [avoidClasses(clForest, 0, clHill, 0), stayClasses(clLand, 2)], - scaleByMapSize(16, 262), 50 -); - -g_Map.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, clHill, 0), stayClasses(clLand, 2)], - scaleByMapSize(8, 131), 50 -); - -g_Map.log("Creating fish"); -group = new SimpleGroup( - [new SimpleObject(oFish, 2, 3, 0, 2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clLand, 4, clFood, 20), - 25 * numPlayers, 60 -); - -g_Map.log("Creating Whales"); -group = new SimpleGroup( - [new SimpleObject(oWhale, 1, 1, 0, 3)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clLand, 4),avoidClasses(clFood, 8)], - scaleByMapSize(5, 20), 100 -); - -g_Map.log("Creating shipwrecks"); -group = new SimpleGroup( - [new SimpleObject(oShipwreck, 1, 1, 0, 1)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clLand, 4),avoidClasses(clFood, 8)], - scaleByMapSize(12, 16), 100 -); - -g_Map.log("Creating shipwreck debris"); -group = new SimpleGroup( - [new SimpleObject(oShipDebris, 1, 1, 0, 1)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clLand, 4),avoidClasses(clFood, 8)], - scaleByMapSize(10, 20), 100 -); - -g_Map.log("Creating small grass tufts"); -const planetm = currentBiome() == "generic/india" ? 8 : 1; -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, 3)], - planetm * scaleByMapSize(13, 200) -); - -Engine.SetProgress(95); - -g_Map.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, 5)], - planetm * scaleByMapSize(13, 200) -); - -paintTerrainBasedOnHeight(1, 2, 0, tShore); -paintTerrainBasedOnHeight(heightSeaGround, 1, 3, tWater); - -placePlayersNomad(clPlayer, [stayClasses(clLand, 4), avoidClasses(clHill, 2, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)]); - -setSkySet(pickRandom(["cloudless", "cumulus", "overcast"])); -setSunRotation(randomAngle()); -setSunElevation(randFloat(1/5, 1/3) * Math.PI); -setWaterWaviness(2); - -Engine.SetProgress(100); - -g_Map.ExportMap(); + g_Map.log("Creating fish"); + group = new SimpleGroup( + [new SimpleObject(oFish, 2, 3, 0, 2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clLand, 4, clFood, 20), + 25 * numPlayers, 60 + ); + + g_Map.log("Creating Whales"); + group = new SimpleGroup( + [new SimpleObject(oWhale, 1, 1, 0, 3)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clLand, 4),avoidClasses(clFood, 8)], + scaleByMapSize(5, 20), 100 + ); + + g_Map.log("Creating shipwrecks"); + group = new SimpleGroup( + [new SimpleObject(oShipwreck, 1, 1, 0, 1)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clLand, 4),avoidClasses(clFood, 8)], + scaleByMapSize(12, 16), 100 + ); + + g_Map.log("Creating shipwreck debris"); + group = new SimpleGroup( + [new SimpleObject(oShipDebris, 1, 1, 0, 1)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clLand, 4),avoidClasses(clFood, 8)], + scaleByMapSize(10, 20), 100 + ); + + g_Map.log("Creating small grass tufts"); + const planetm = currentBiome() == "generic/india" ? 8 : 1; + 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, 3)], + planetm * scaleByMapSize(13, 200) + ); + + yield 95; + + g_Map.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, 5)], + planetm * scaleByMapSize(13, 200) + ); + + paintTerrainBasedOnHeight(1, 2, 0, tShore); + paintTerrainBasedOnHeight(heightSeaGround, 1, 3, tWater); + + placePlayersNomad(clPlayer, [stayClasses(clLand, 4), avoidClasses(clHill, 2, clForest, 1, clMetal, 4, + clRock, 4, clFood, 2)]); + + setSkySet(pickRandom(["cloudless", "cumulus", "overcast"])); + setSunRotation(randomAngle()); + setSunElevation(randFloat(1/5, 1/3) * Math.PI); + setWaterWaviness(2); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/islands.js =================================================================== --- binaries/data/mods/public/maps/random/islands.js +++ binaries/data/mods/public/maps/random/islands.js @@ -4,362 +4,365 @@ 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.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/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 heightOffsetBump = 2; -const heightHill = 18; - -const g_Map = new RandomMap(heightSeaGround, tWater); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clLand = g_Map.createTileClass(); - -const playerIslandRadius = scaleByMapSize(20, 29); - -const [playerIDs, playerPosition, playerAngle] = playerPlacementCircle(fractionToTiles(0.35)); - -if (!isNomad()) +function* GenerateMap() { - g_Map.log("Creating player islands and docks"); - for (let i = 0; i < numPlayers; i++) + 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/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 heightOffsetBump = 2; + const heightHill = 18; + + global.g_Map = new RandomMap(heightSeaGround, tWater); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clLand = g_Map.createTileClass(); + + const playerIslandRadius = scaleByMapSize(20, 29); + + const [playerIDs, playerPosition, playerAngle] = playerPlacementCircle(fractionToTiles(0.35)); + + if (!isNomad()) { - createArea( - new ClumpPlacer(diskArea(playerIslandRadius), 0.8, 0.1, Infinity, playerPosition[i]), - [ - new LayeredPainter([tMainTerrain , tMainTerrain, tMainTerrain], [1, 6]), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), - new TileClassPainter(clLand), - new TileClassPainter(clPlayer) - ]); - - const dockLocation = findLocationInDirectionBasedOnHeight(playerPosition[i], mapCenter, -3 , heightLand - 0.5, heightLand); - g_Map.placeEntityPassable(oDock, playerIDs[i], dockLocation, playerAngle[i] + Math.PI); + g_Map.log("Creating player islands and docks"); + for (let i = 0; i < numPlayers; i++) + { + createArea( + new ClumpPlacer(diskArea(playerIslandRadius), 0.8, 0.1, Infinity, playerPosition[i]), + [ + new LayeredPainter([tMainTerrain , tMainTerrain, tMainTerrain], [1, 6]), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), + new TileClassPainter(clLand), + new TileClassPainter(clPlayer) + ]); + + const dockLocation = findLocationInDirectionBasedOnHeight(playerPosition[i], mapCenter, -3 , heightLand - 0.5, heightLand); + g_Map.placeEntityPassable(oDock, playerIDs[i], dockLocation, playerAngle[i] + Math.PI); + } } -} -g_Map.log("Creating big islands"); -createAreas( - new ChainPlacer( - Math.floor(scaleByMapSize(4, 8)), - Math.floor(scaleByMapSize(8, 14)), - Math.floor(scaleByMapSize(25, 60)), - 0.07), - [ - new TerrainPainter(tMainTerrain), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), - new TileClassPainter(clLand) - ], - avoidClasses(clLand, scaleByMapSize(8, 12)), - scaleByMapSize(4, 14)); - -g_Map.log("Creating small islands"); -createAreas( - new ChainPlacer( - Math.floor(scaleByMapSize(4, 7)), - Math.floor(scaleByMapSize(7, 10)), - Math.floor(scaleByMapSize(16, 40)), - 0.07), - [ - new TerrainPainter(tMainTerrain), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), - new TileClassPainter(clLand) - ], - avoidClasses(clLand, scaleByMapSize(8, 12)), - scaleByMapSize(6, 54)); - -paintTerrainBasedOnHeight(1, 3, 0, tShore); -paintTerrainBasedOnHeight(-8, 1, 2, tWater); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - // PlayerTileClass marked above - "BaseResourceClass": clBaseResource, - "Walls": "towers", - "CityPatch": { - "radius": playerIslandRadius / 3, - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oFruitBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Treasures": { - "types": [ - { - "template": oWoodTreasure, - "count": 14 - } - ] - }, - "Trees": { - "template": oTree1, - "count": 5 - }, - "Decoratives": { - "template": aGrassShort - } -}); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - [avoidClasses(clPlayer, 0), stayClasses(clLand, 3)], - scaleByMapSize(20, 100)); - -g_Map.log("Creating hills"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), - [ - new LayeredPainter([tCliff, tHill], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - [avoidClasses(clPlayer, 2, clHill, 15), stayClasses(clLand, 0)], - scaleByMapSize(4, 13)); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); -const types = [ - [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], - [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] -]; - -if (currentBiome() != "generic/savanna") -{ - const size = forestTrees / (scaleByMapSize(3,6) * numPlayers); - const num = Math.floor(size / types.length); - for (const type of types) - createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), forestTrees / (num * Math.floor(scaleByMapSize(2, 5))), 0.5), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) - ], - [avoidClasses(clPlayer, 0, clForest, 10, clHill, 0), stayClasses(clLand, 6)], - num); -} + g_Map.log("Creating big islands"); + createAreas( + new ChainPlacer( + Math.floor(scaleByMapSize(4, 8)), + Math.floor(scaleByMapSize(8, 14)), + Math.floor(scaleByMapSize(25, 60)), + 0.07), + [ + new TerrainPainter(tMainTerrain), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), + new TileClassPainter(clLand) + ], + avoidClasses(clLand, scaleByMapSize(8, 12)), + scaleByMapSize(4, 14)); -Engine.SetProgress(50); -g_Map.log("Creating dirt patches"); -const numberOfPatches = scaleByMapSize(15, 45) * (currentBiome() == "generic/savanna" ? 3 : 1); -for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) + g_Map.log("Creating small islands"); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), + new ChainPlacer( + Math.floor(scaleByMapSize(4, 7)), + Math.floor(scaleByMapSize(7, 10)), + Math.floor(scaleByMapSize(16, 40)), + 0.07), [ - new LayeredPainter([[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]), - new TileClassPainter(clDirt) + new TerrainPainter(tMainTerrain), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), + new TileClassPainter(clLand) ], - [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 6)], - numberOfPatches); + avoidClasses(clLand, scaleByMapSize(8, 12)), + scaleByMapSize(6, 54)); + + paintTerrainBasedOnHeight(1, 3, 0, tShore); + paintTerrainBasedOnHeight(-8, 1, 2, tWater); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + // PlayerTileClass marked above + "BaseResourceClass": clBaseResource, + "Walls": "towers", + "CityPatch": { + "radius": playerIslandRadius / 3, + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oFruitBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Treasures": { + "types": [ + { + "template": oWoodTreasure, + "count": 14 + } + ] + }, + "Trees": { + "template": oTree1, + "count": 5 + }, + "Decoratives": { + "template": aGrassShort + } + }); + + g_Map.log("Creating bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + [avoidClasses(clPlayer, 0), stayClasses(clLand, 3)], + scaleByMapSize(20, 100)); -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]) + g_Map.log("Creating hills"); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), - new TerrainPainter(tTier4Terrain), - [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 6)], - numberOfPatches); - -Engine.SetProgress(55); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 1, clPlayer, 0, clRock, 10, clHill, 1), stayClasses(clLand, 5)], - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 1, clPlayer, 0, clRock, 10, clHill, 1), stayClasses(clLand, 5)], - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 1, clPlayer, 0, clMetal, 10, clRock, 5, clHill, 1), stayClasses(clLand, 5)], - scaleByMapSize(4,16), 100 -); - -Engine.SetProgress(65); - -g_Map.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, 5)], - scaleByMapSize(16, 262), 50 -); - -g_Map.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, 5)], - scaleByMapSize(8, 131), 50 -); - -Engine.SetProgress(70); - -g_Map.log("Creating deer"); -group = new SimpleGroup( - [new SimpleObject(oMainHuntableAnimal, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 0, clPlayer, 0, clHill, 1, clFood, 20), stayClasses(clLand, 5)], - 3 * numPlayers, 50 -); - -Engine.SetProgress(75); - -g_Map.log("Creating sheep"); -group = new SimpleGroup( - [new SimpleObject(oSecondaryHuntableAnimal, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 0, clPlayer, 0, clHill, 1, clFood, 20), stayClasses(clLand, 5)], - 3 * numPlayers, 50 -); - -g_Map.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, 5)], - randIntInclusive(1, 4) * numPlayers + 2, 50 -); - -g_Map.log("Creating fish"); -group = new SimpleGroup( - [new SimpleObject(oFish, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clLand, 4, clForest, 2, clPlayer, 2, clHill, 2, clFood, 20), - 25 * numPlayers, 60 -); - -Engine.SetProgress(85); - -createStragglerTrees( - [oTree1, oTree2, oTree4, oTree3], - [avoidClasses(clForest, 1, clHill, 1, clPlayer, 0, clMetal, 6, clRock, 6), stayClasses(clLand, 6)], - clForest, - stragglerTrees); - -let planetm = 1; -if (currentBiome() == "generic/india") - planetm = 8; - -g_Map.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); - -g_Map.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, 5)], - planetm * scaleByMapSize(13, 200) -); - -Engine.SetProgress(95); - -g_Map.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 -); - -placePlayersNomad(clPlayer, [stayClasses(clLand, 4), avoidClasses(clHill, 2, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)]); - -setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); -setSunRotation(randomAngle()); -setSunElevation(randFloat(1/5, 1/3) * Math.PI); -setWaterWaviness(2); - -g_Map.ExportMap(); + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), + [ + new LayeredPainter([tCliff, tHill], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) + ], + [avoidClasses(clPlayer, 2, clHill, 15), stayClasses(clLand, 0)], + scaleByMapSize(4, 13)); + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + const types = [ + [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], + [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] + ]; + + if (currentBiome() != "generic/savanna") + { + const size = forestTrees / (scaleByMapSize(3,6) * numPlayers); + const num = Math.floor(size / types.length); + for (const type of types) + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), forestTrees / (num * Math.floor(scaleByMapSize(2, 5))), 0.5), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + [avoidClasses(clPlayer, 0, clForest, 10, clHill, 0), stayClasses(clLand, 6)], + num); + } + + yield 50; + g_Map.log("Creating dirt patches"); + const numberOfPatches = scaleByMapSize(15, 45) * (currentBiome() == "generic/savanna" ? 3 : 1); + for (const 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]), + new TileClassPainter(clDirt) + ], + [avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 6)], + numberOfPatches); + + g_Map.log("Creating grass patches"); + for (const 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, clHill, 0, clDirt, 5, clPlayer, 0), stayClasses(clLand, 6)], + numberOfPatches); + + yield 55; + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 1, clPlayer, 0, clRock, 10, clHill, 1), stayClasses(clLand, 5)], + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 1, clPlayer, 0, clRock, 10, clHill, 1), stayClasses(clLand, 5)], + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 1, clPlayer, 0, clMetal, 10, clRock, 5, clHill, 1), stayClasses(clLand, 5)], + scaleByMapSize(4,16), 100 + ); + + yield 65; + + g_Map.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, 5)], + scaleByMapSize(16, 262), 50 + ); + + g_Map.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, 5)], + scaleByMapSize(8, 131), 50 + ); + + yield 70; + + g_Map.log("Creating deer"); + group = new SimpleGroup( + [new SimpleObject(oMainHuntableAnimal, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 0, clPlayer, 0, clHill, 1, clFood, 20), stayClasses(clLand, 5)], + 3 * numPlayers, 50 + ); + + yield 75; + + g_Map.log("Creating sheep"); + group = new SimpleGroup( + [new SimpleObject(oSecondaryHuntableAnimal, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 0, clPlayer, 0, clHill, 1, clFood, 20), stayClasses(clLand, 5)], + 3 * numPlayers, 50 + ); + + g_Map.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, 5)], + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + + g_Map.log("Creating fish"); + group = new SimpleGroup( + [new SimpleObject(oFish, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clLand, 4, clForest, 2, clPlayer, 2, clHill, 2, clFood, 20), + 25 * numPlayers, 60 + ); + + yield 85; + + createStragglerTrees( + [oTree1, oTree2, oTree4, oTree3], + [avoidClasses(clForest, 1, clHill, 1, clPlayer, 0, clMetal, 6, clRock, 6), stayClasses(clLand, 6)], + clForest, + stragglerTrees); + + let planetm = 1; + if (currentBiome() == "generic/india") + planetm = 8; + + g_Map.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) + ); + + yield 90; + + g_Map.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, 5)], + planetm * scaleByMapSize(13, 200) + ); + + yield 95; + + g_Map.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 + ); + + placePlayersNomad(clPlayer, [stayClasses(clLand, 4), avoidClasses(clHill, 2, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)]); + + setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); + setSunRotation(randomAngle()); + setSunElevation(randFloat(1/5, 1/3) * Math.PI); + setWaterWaviness(2); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/jebel_barkal.js =================================================================== --- binaries/data/mods/public/maps/random/jebel_barkal.js +++ binaries/data/mods/public/maps/random/jebel_barkal.js @@ -8,1498 +8,1548 @@ TILE_CENTERED_HEIGHT_MAP = true; -const tSand = "desert_sand_dunes_100"; -const tHilltop = ["new_savanna_dirt_c", "new_savanna_dirt_d"]; -const tHillGround = ["savanna_dirt_rocks_a", "savanna_dirt_rocks_b", "savanna_dirt_rocks_c"]; -const tHillCliff = ["savanna_cliff_a_red", "savanna_cliff_b_red"]; -const tRoadDesert = "savanna_tile_a"; -const tRoadFertileLand = "savanna_tile_a"; -const tWater = "desert_sand_wet"; -const tGrass = ["savanna_shrubs_a_wetseason", "alpine_grass_b_wild", "medit_shrubs_a", "steppe_grass_green_a"]; -const tForestFloorFertile = pickRandom(tGrass); -const tGrassTransition1 = "desert_grass_a"; -const tGrassTransition2 = "steppe_grass_dirt_66"; -const tPath = "road2"; -const tPathWild = "road_med"; - -const oAcacia = "gaia/tree/acacia"; -const oPalmPath = "gaia/tree/cretan_date_palm_tall"; -const oPalms = [ - "gaia/tree/cretan_date_palm_tall", - "gaia/tree/cretan_date_palm_short", - "gaia/tree/palm_tropic", - "gaia/tree/date_palm", - "gaia/tree/senegal_date_palm", - "gaia/tree/medit_fan_palm" -]; -const oBerryBushGrapes = "gaia/fruit/grapes"; -const oBerryBushDesert = "gaia/fruit/berry_05"; -const oStoneLargeDesert = "gaia/rock/desert_large"; -const oStoneSmallDesert = "gaia/rock/desert_small"; -const oMetalLargeDesert = "gaia/ore/desert_large"; -const oMetalSmallDesert = "gaia/ore/desert_small"; -const oStoneLargeFertileLand = "gaia/rock/desert_large"; -const oStoneSmallFertileLand = "gaia/rock/greece_small"; -const oMetalLargeFertileLand = "gaia/ore/desert_large"; -const oMetalSmallFertileLand = "gaia/ore/temperate_small"; -const oFoodTreasureBin = "gaia/treasure/food_bin"; -const oFoodTreasureCrate = "gaia/treasure/food_crate"; -const oFoodTreasureJars = "gaia/treasure/food_jars"; -const oWoodTreasure = "gaia/treasure/wood"; -const oStoneTreasure = "gaia/treasure/stone"; -const oMetalTreasure = "gaia/treasure/metal"; -const oTreasuresHill = [oWoodTreasure, oStoneTreasure, oMetalTreasure]; -const oTreasuresCity = [oFoodTreasureBin, oFoodTreasureCrate, oFoodTreasureJars].concat(oTreasuresHill); -const oGiraffe = "gaia/fauna_giraffe"; -const oGiraffeInfant = "gaia/fauna_giraffe_infant"; -const oGazelle = "gaia/fauna_gazelle"; -const oRhino = "gaia/fauna_rhinoceros_white"; -const oWarthog = "gaia/fauna_boar"; -const oElephant = "gaia/fauna_elephant_african_bush"; -const oElephantInfant = "gaia/fauna_elephant_african_infant"; -const oLion = "gaia/fauna_lion"; -const oLioness = "gaia/fauna_lioness"; -const oCrocodile = "gaia/fauna_crocodile_nile"; -const oFish = "gaia/fish/tilapia"; -const oHawk = "birds/buzzard"; -const oTempleApedemak = "structures/kush/temple"; -const oTempleAmun = "structures/kush/temple_amun"; -const oPyramidLarge = "structures/kush/pyramid_large"; -const oPyramidSmall = "structures/kush/pyramid_small"; -const oWonderPtol = "structures/ptol/wonder"; -const oFortress = "structures/kush/fortress"; -const oTower = g_MapSettings.Size >= 256 && getDifficulty() >= 3 ? "structures/kush/defense_tower" : "structures/kush/sentry_tower"; -const oHouse = "structures/kush/house"; -const oMarket = "structures/kush/market"; -const oForge = "structures/kush/forge"; -const oBlemmyeCamp = "structures/kush/camp_blemmye"; -const oNobaCamp = "structures/kush/camp_noba"; -const oCivicCenter = "structures/kush/civil_centre"; -const oBarracks = "structures/kush/barracks"; -const oStable = "structures/kush/stable"; -const oElephantStable = "structures/kush/elephant_stable"; -const oWallMedium = "structures/kush/wall_medium"; -const oWallGate = "structures/kush/wall_gate"; -const oWallTower = "structures/kush/wall_tower"; -const oPalisadeMedium = "structures/palisades_medium"; -const oPalisadeGate = "structures/palisades_gate"; -const oPalisadeTower = "structures/palisades_tower"; -const oKushCitizenArcher = "units/kush/infantry_archer_b"; -const oKushHealer = "units/kush/support_healer_b"; -const oKushChampionArcher = "units/kush/champion_infantry_archer"; -const oKushChampions = [ - oKushChampionArcher, - "units/kush/champion_infantry_amun", - "units/kush/champion_infantry_apedemak" -]; -const oPtolSiege = ["units/ptol/siege_lithobolos_unpacked", "units/ptol/siege_polybolos_unpacked"]; -const oTriggerPointCityPath = "trigger/trigger_point_A"; -const oTriggerPointAttackerPatrol = "trigger/trigger_point_B"; - -const aPalmPath = actorTemplate("flora/trees/palm_cretan_date_tall"); -const aRock = actorTemplate("geology/stone_savanna_med"); -const aHandcart = actorTemplate("props/special/eyecandy/handcart_1"); -const aPlotFence = actorTemplate("props/special/common/plot_fence"); -const aStatueKush = actorTemplate("props/special/eyecandy/statues_kush"); -const aStatues = [ - "props/structures/kushites/statue_pedestal_rectangular", - "props/structures/kushites/statue_pedestal_rectangular_lion" -].map(actorTemplate); -const aBushesFertileLand = [ - ...new Array(3).fill("props/flora/shrub_spikes"), - ...new Array(3).fill("props/flora/ferns"), - "props/flora/shrub_tropic_plant_a", - "props/flora/shrub_tropic_plant_b", - "props/flora/shrub_tropic_plant_flower", - "props/flora/foliagebush", - "props/flora/bush", - "props/flora/bush_medit_la", - "props/flora/bush_medit_la_lush", - "props/flora/bush_medit_me_lush", - "props/flora/bush_medit_sm", - "props/flora/bush_medit_sm_lush", - "props/flora/bush_tempe_la_lush" -].map(actorTemplate); -const aBushesCity = [ - "props/flora/bush_dry_a", - "props/flora/bush_medit_la_dry", - "props/flora/bush_medit_me_dry", - "props/flora/bush_medit_sm", - "props/flora/bush_medit_sm_dry", -].map(actorTemplate); -const aBushesDesert = [ - "props/flora/bush_tempe_me_dry", - "props/flora/grass_soft_dry_large_tall", - "props/flora/grass_soft_dry_small_tall" -].map(actorTemplate).concat(aBushesCity); -const aWaterDecoratives = ["props/flora/reeds_pond_lush_a"].map(actorTemplate); - -const pForestPalms = [ - tForestFloorFertile, - ...oPalms.map(tree => tForestFloorFertile + TERRAIN_SEPARATOR + tree), - tForestFloorFertile]; - -const heightScale = num => num * g_MapSettings.Size / 320; - -const minHeightSource = 3; -const maxHeightSource = 800; - -const g_Map = new RandomMap(0, tSand); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); -const numPlayers = getNumPlayers(); - -const clHill = g_Map.createTileClass(); -const clCliff = g_Map.createTileClass(); -const clDesert = g_Map.createTileClass(); -const clFertileLand = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clIrrigationCanal = g_Map.createTileClass(); -const clPassage = g_Map.createTileClass(); -const clPlayer = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clTreasure = g_Map.createTileClass(); -const clCity = g_Map.createTileClass(); -const clPath = g_Map.createTileClass(); -const clPathStatues = g_Map.createTileClass(); -const clPathCrossing = g_Map.createTileClass(); -const clStatue = g_Map.createTileClass(); -const clWall = g_Map.createTileClass(); -const clGate = g_Map.createTileClass(); -const clRoad = g_Map.createTileClass(); -const clTriggerPointCityPath = g_Map.createTileClass(); -const clTriggerPointMap = g_Map.createTileClass(); -const clSoldier = g_Map.createTileClass(); -const clTower = g_Map.createTileClass(); -const clFortress = g_Map.createTileClass(); -const clTemple = g_Map.createTileClass(); -const clRitualPlace = g_Map.createTileClass(); -const clPyramid = g_Map.createTileClass(); -const clHouse = g_Map.createTileClass(); -const clForge = g_Map.createTileClass(); -const clStable = g_Map.createTileClass(); -const clElephantStable = g_Map.createTileClass(); -const clCivicCenter = g_Map.createTileClass(); -const clBarracks = g_Map.createTileClass(); -const clBlemmyeCamp = g_Map.createTileClass(); -const clNobaCamp = g_Map.createTileClass(); -const clMarket = g_Map.createTileClass(); -const clDecorative = g_Map.createTileClass(); - -const riverAngle = 0.05 * Math.PI; - -const hillRadius = scaleByMapSize(40, 120); -const positionPyramids = new Vector2D(fractionToTiles(0.15), fractionToTiles(0.75)); - -const pathWidth = 4; -const pathWidthCenter = 10; -const pathWidthSecondary = 6; - -const placeNapataWall = mapSize < 192 || getDifficulty() < 2 ? false : getDifficulty() < 3 ? "napata_palisade" : "napata_wall"; - -const layoutFertileLandTextures = [ - { - "left": fractionToTiles(0), - "right": fractionToTiles(0.04), - "terrain": createTerrain(tGrassTransition1), - "tileClass": clFertileLand - }, - { - "left": fractionToTiles(0.04), - "right": fractionToTiles(0.08), - "terrain": createTerrain(tGrassTransition2), - "tileClass": clDesert - } -]; - -const layoutKushTemples = [ - ...new Array(2).fill(0).map((v, i) => - ({ - "template": oTempleApedemak, - "pathOffset": new Vector2D(0, 9), - "minMapSize": i == 0 ? 320 : 0 - })), - { - "template": oTempleAmun, - "pathOffset": new Vector2D(0, 12), - "minMapSize": 256 - }, - { - "template": oWonderPtol, - "pathOffset": new Vector2D(0, scaleByMapSize(9, 14)), - "minMapSize": 0 - }, - { - "template": oTempleAmun, - "pathOffset": new Vector2D(0, 12), - "minMapSize": 256 - }, - ...new Array(2).fill(0).map((v, i) => - ({ - "template": oTempleApedemak, - "pathOffset": new Vector2D(0, 9), - "minMapSize": i == 0 ? 320 : 0 - })) -].filter(temple => mapSize >= temple.minMapSize); +function* GenerateMap(mapSettings) +{ + const tSand = "desert_sand_dunes_100"; + const tHilltop = ["new_savanna_dirt_c", "new_savanna_dirt_d"]; + const tHillGround = ["savanna_dirt_rocks_a", "savanna_dirt_rocks_b", "savanna_dirt_rocks_c"]; + const tHillCliff = ["savanna_cliff_a_red", "savanna_cliff_b_red"]; + const tRoadDesert = "savanna_tile_a"; + const tRoadFertileLand = "savanna_tile_a"; + const tWater = "desert_sand_wet"; + const tGrass = ["savanna_shrubs_a_wetseason", "alpine_grass_b_wild", "medit_shrubs_a", + "steppe_grass_green_a"]; + const tForestFloorFertile = pickRandom(tGrass); + const tGrassTransition1 = "desert_grass_a"; + const tGrassTransition2 = "steppe_grass_dirt_66"; + const tPath = "road2"; + const tPathWild = "road_med"; + + const oAcacia = "gaia/tree/acacia"; + const oPalmPath = "gaia/tree/cretan_date_palm_tall"; + const oPalms = [ + "gaia/tree/cretan_date_palm_tall", + "gaia/tree/cretan_date_palm_short", + "gaia/tree/palm_tropic", + "gaia/tree/date_palm", + "gaia/tree/senegal_date_palm", + "gaia/tree/medit_fan_palm" + ]; + const oBerryBushGrapes = "gaia/fruit/grapes"; + const oBerryBushDesert = "gaia/fruit/berry_05"; + const oStoneLargeDesert = "gaia/rock/desert_large"; + const oStoneSmallDesert = "gaia/rock/desert_small"; + const oMetalLargeDesert = "gaia/ore/desert_large"; + const oMetalSmallDesert = "gaia/ore/desert_small"; + const oStoneLargeFertileLand = "gaia/rock/desert_large"; + const oStoneSmallFertileLand = "gaia/rock/greece_small"; + const oMetalLargeFertileLand = "gaia/ore/desert_large"; + const oMetalSmallFertileLand = "gaia/ore/temperate_small"; + const oFoodTreasureBin = "gaia/treasure/food_bin"; + const oFoodTreasureCrate = "gaia/treasure/food_crate"; + const oFoodTreasureJars = "gaia/treasure/food_jars"; + const oWoodTreasure = "gaia/treasure/wood"; + const oStoneTreasure = "gaia/treasure/stone"; + const oMetalTreasure = "gaia/treasure/metal"; + const oTreasuresHill = [oWoodTreasure, oStoneTreasure, oMetalTreasure]; + const oTreasuresCity = [oFoodTreasureBin, oFoodTreasureCrate, oFoodTreasureJars] + .concat(oTreasuresHill); + const oGiraffe = "gaia/fauna_giraffe"; + const oGiraffeInfant = "gaia/fauna_giraffe_infant"; + const oGazelle = "gaia/fauna_gazelle"; + const oRhino = "gaia/fauna_rhinoceros_white"; + const oWarthog = "gaia/fauna_boar"; + const oElephant = "gaia/fauna_elephant_african_bush"; + const oElephantInfant = "gaia/fauna_elephant_african_infant"; + const oLion = "gaia/fauna_lion"; + const oLioness = "gaia/fauna_lioness"; + const oCrocodile = "gaia/fauna_crocodile_nile"; + const oFish = "gaia/fish/tilapia"; + const oHawk = "birds/buzzard"; + const oTempleApedemak = "structures/kush/temple"; + const oTempleAmun = "structures/kush/temple_amun"; + const oPyramidLarge = "structures/kush/pyramid_large"; + const oPyramidSmall = "structures/kush/pyramid_small"; + const oWonderPtol = "structures/ptol/wonder"; + const oFortress = "structures/kush/fortress"; + const oTower = mapSettings.Size >= 256 && getDifficulty() >= 3 ? "structures/kush/defense_tower" : + "structures/kush/sentry_tower"; + const oHouse = "structures/kush/house"; + const oMarket = "structures/kush/market"; + const oForge = "structures/kush/forge"; + const oBlemmyeCamp = "structures/kush/camp_blemmye"; + const oNobaCamp = "structures/kush/camp_noba"; + const oCivicCenter = "structures/kush/civil_centre"; + const oBarracks = "structures/kush/barracks"; + const oStable = "structures/kush/stable"; + const oElephantStable = "structures/kush/elephant_stable"; + const oWallMedium = "structures/kush/wall_medium"; + const oWallGate = "structures/kush/wall_gate"; + const oWallTower = "structures/kush/wall_tower"; + const oPalisadeMedium = "structures/palisades_medium"; + const oPalisadeGate = "structures/palisades_gate"; + const oPalisadeTower = "structures/palisades_tower"; + const oKushCitizenArcher = "units/kush/infantry_archer_b"; + const oKushHealer = "units/kush/support_healer_b"; + const oKushChampionArcher = "units/kush/champion_infantry_archer"; + const oKushChampions = [ + oKushChampionArcher, + "units/kush/champion_infantry_amun", + "units/kush/champion_infantry_apedemak" + ]; + const oPtolSiege = ["units/ptol/siege_lithobolos_unpacked", "units/ptol/siege_polybolos_unpacked"]; + const oTriggerPointCityPath = "trigger/trigger_point_A"; + const oTriggerPointAttackerPatrol = "trigger/trigger_point_B"; + + const aPalmPath = actorTemplate("flora/trees/palm_cretan_date_tall"); + const aRock = actorTemplate("geology/stone_savanna_med"); + const aHandcart = actorTemplate("props/special/eyecandy/handcart_1"); + const aPlotFence = actorTemplate("props/special/common/plot_fence"); + const aStatueKush = actorTemplate("props/special/eyecandy/statues_kush"); + const aStatues = [ + "props/structures/kushites/statue_pedestal_rectangular", + "props/structures/kushites/statue_pedestal_rectangular_lion" + ].map(actorTemplate); + const aBushesFertileLand = [ + ...new Array(3).fill("props/flora/shrub_spikes"), + ...new Array(3).fill("props/flora/ferns"), + "props/flora/shrub_tropic_plant_a", + "props/flora/shrub_tropic_plant_b", + "props/flora/shrub_tropic_plant_flower", + "props/flora/foliagebush", + "props/flora/bush", + "props/flora/bush_medit_la", + "props/flora/bush_medit_la_lush", + "props/flora/bush_medit_me_lush", + "props/flora/bush_medit_sm", + "props/flora/bush_medit_sm_lush", + "props/flora/bush_tempe_la_lush" + ].map(actorTemplate); + const aBushesCity = [ + "props/flora/bush_dry_a", + "props/flora/bush_medit_la_dry", + "props/flora/bush_medit_me_dry", + "props/flora/bush_medit_sm", + "props/flora/bush_medit_sm_dry", + ].map(actorTemplate); + const aBushesDesert = [ + "props/flora/bush_tempe_me_dry", + "props/flora/grass_soft_dry_large_tall", + "props/flora/grass_soft_dry_small_tall" + ].map(actorTemplate).concat(aBushesCity); + const aWaterDecoratives = ["props/flora/reeds_pond_lush_a"].map(actorTemplate); + + const pForestPalms = [ + tForestFloorFertile, + ...oPalms.map(tree => tForestFloorFertile + TERRAIN_SEPARATOR + tree), + tForestFloorFertile]; + + const heightScale = num => num * mapSettings.Size / 320; + + const minHeightSource = 3; + const maxHeightSource = 800; + + global.g_Map = new RandomMap(0, tSand); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + const numPlayers = getNumPlayers(); + + const clHill = g_Map.createTileClass(); + const clCliff = g_Map.createTileClass(); + const clDesert = g_Map.createTileClass(); + const clFertileLand = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clIrrigationCanal = g_Map.createTileClass(); + const clPassage = g_Map.createTileClass(); + const clPlayer = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clTreasure = g_Map.createTileClass(); + const clCity = g_Map.createTileClass(); + const clPath = g_Map.createTileClass(); + const clPathStatues = g_Map.createTileClass(); + const clPathCrossing = g_Map.createTileClass(); + const clStatue = g_Map.createTileClass(); + const clWall = g_Map.createTileClass(); + const clGate = g_Map.createTileClass(); + const clRoad = g_Map.createTileClass(); + const clTriggerPointCityPath = g_Map.createTileClass(); + const clTriggerPointMap = g_Map.createTileClass(); + const clSoldier = g_Map.createTileClass(); + const clTower = g_Map.createTileClass(); + const clFortress = g_Map.createTileClass(); + const clTemple = g_Map.createTileClass(); + const clRitualPlace = g_Map.createTileClass(); + const clPyramid = g_Map.createTileClass(); + const clHouse = g_Map.createTileClass(); + const clForge = g_Map.createTileClass(); + const clStable = g_Map.createTileClass(); + const clElephantStable = g_Map.createTileClass(); + const clCivicCenter = g_Map.createTileClass(); + const clBarracks = g_Map.createTileClass(); + const clBlemmyeCamp = g_Map.createTileClass(); + const clNobaCamp = g_Map.createTileClass(); + const clMarket = g_Map.createTileClass(); + const clDecorative = g_Map.createTileClass(); + + const riverAngle = 0.05 * Math.PI; + + const hillRadius = scaleByMapSize(40, 120); + const positionPyramids = new Vector2D(fractionToTiles(0.15), fractionToTiles(0.75)); + + const pathWidth = 4; + const pathWidthCenter = 10; + const pathWidthSecondary = 6; + + const placeNapataWall = mapSize < 192 || getDifficulty() < 2 ? false : getDifficulty() < 3 ? + "napata_palisade" : "napata_wall"; + + const layoutFertileLandTextures = [ + { + "left": fractionToTiles(0), + "right": fractionToTiles(0.04), + "terrain": createTerrain(tGrassTransition1), + "tileClass": clFertileLand + }, + { + "left": fractionToTiles(0.04), + "right": fractionToTiles(0.08), + "terrain": createTerrain(tGrassTransition2), + "tileClass": clDesert + } + ]; + + const layoutKushTemples = [ + ...new Array(2).fill(0).map((v, i) => + ({ + "template": oTempleApedemak, + "pathOffset": new Vector2D(0, 9), + "minMapSize": i == 0 ? 320 : 0 + })), + { + "template": oTempleAmun, + "pathOffset": new Vector2D(0, 12), + "minMapSize": 256 + }, + { + "template": oWonderPtol, + "pathOffset": new Vector2D(0, scaleByMapSize(9, 14)), + "minMapSize": 0 + }, + { + "template": oTempleAmun, + "pathOffset": new Vector2D(0, 12), + "minMapSize": 256 + }, + ...new Array(2).fill(0).map((v, i) => + ({ + "template": oTempleApedemak, + "pathOffset": new Vector2D(0, 9), + "minMapSize": i == 0 ? 320 : 0 + })) + ].filter(temple => mapSize >= temple.minMapSize); + + /** + * The buildings are set as uncapturable, otherwise the player would gain the buildings via root + * territory and can delete them without effort. + * Keep the entire city uncapturable as a consistent property of the city. + */ + const layoutKushCity = [ + { + "templateName": "uncapturable|" + oHouse, + "difficulty": "Very Easy", + "painters": new TileClassPainter(clHouse) + }, + { + "templateName": oFortress, + "difficulty": "Medium", + "constraints": [avoidClasses(clFortress, 25), new NearTileClassConstraint(clPath, 8)], + "painters": new TileClassPainter(clFortress) + }, + { + "templateName": oCivicCenter, + "difficulty": "Easy", + "constraints": [avoidClasses(clCivicCenter, 60), new NearTileClassConstraint(clPath, 8)], + "painters": new TileClassPainter(clCivicCenter) + }, + { + "templateName": oElephantStable, + "difficulty": "Easy", + "constraints": avoidClasses(clElephantStable, 10), + "painters": new TileClassPainter(clElephantStable) + }, + { + "templateName": oStable, + "difficulty": "Easy", + "constraints": avoidClasses(clStable, 20), + "painters": new TileClassPainter(clStable) + }, + { + "templateName": oBarracks, + "difficulty": "Easy", + "constraints": avoidClasses(clBarracks, 12), + "painters": new TileClassPainter(clBarracks) + }, + { + "templateName": oTower, + "difficulty": "Easy", + "constraints": avoidClasses(clTower, 17), + "painters": new TileClassPainter(clTower) + }, + { + "templateName": "uncapturable|" + oMarket, + "difficulty": "Very Easy", + "constraints": avoidClasses(clMarket, 15), + "painters": new TileClassPainter(clMarket) + }, + { + "templateName": "uncapturable|" + oForge, + "difficulty": "Very Easy", + "constraints": avoidClasses(clForge, 30), + "painters": new TileClassPainter(clForge) + }, + { + "templateName": oNobaCamp, + "difficulty": "Easy", + "constraints": avoidClasses(clNobaCamp, 30), + "painters": new TileClassPainter(clNobaCamp) + }, + { + "templateName": oBlemmyeCamp, + "difficulty": "Easy", + "constraints": avoidClasses(clBlemmyeCamp, 30), + "painters": new TileClassPainter(clBlemmyeCamp) + } + ].filter(building => getDifficulty() >= getDifficulties().find( + difficulty => difficulty.Name == building.difficulty).Difficulty); + + g_WallStyles.napata_wall = { + "short": readyWallElement("uncapturable|" + oWallMedium), + "medium": readyWallElement("uncapturable|" + oWallMedium), + "tower": readyWallElement("uncapturable|" + oWallTower), + "gate": readyWallElement("uncapturable|" + oWallGate), + "overlap": 0.05 + }; + + g_WallStyles.napata_palisade = { + "short": readyWallElement("uncapturable|" + oPalisadeMedium), + "medium": readyWallElement("uncapturable|" + oPalisadeMedium), + "tower": readyWallElement("uncapturable|" + oPalisadeTower), + "gate": readyWallElement("uncapturable|" + oPalisadeGate), + "overlap": 0.05 + }; + + yield 10; + + g_Map.log("Loading hill heightmap"); + createArea( + new MapBoundsPlacer(), + new HeightmapPainter( + translateHeightmap( + new Vector2D(-12, scaleByMapSize(-12, -25)), + undefined, + convertHeightmap1Dto2D( + Engine.LoadMapTerrain("maps/random/jebel_barkal.pmp").height)), + minHeightSource, + maxHeightSource)); + + const heightDesert = g_Map.getHeight(mapCenter); + const heightFertileLand = heightDesert - heightScale(2); + const heightShoreline = heightFertileLand - heightScale(0.5); + const heightWaterLevel = heightFertileLand - heightScale(3); + const heightPassage = heightWaterLevel - heightScale(1.5); + const heightIrrigationCanal = heightWaterLevel - heightScale(4); + const heightSeaGround = heightWaterLevel - heightScale(8); + const heightHill = heightDesert + heightScale(4); + const heightHilltop = heightHill + heightScale(90); + const heightHillArchers = (heightHilltop + heightHill) / 2; + const heightOffsetPath = heightScale(-2.5); + const heightOffsetRoad = heightScale(-1.5); + const heightOffsetWalls = heightScale(2.5); + const heightOffsetStatue = heightScale(2.5); + + g_Map.log("Flattening land"); + createArea( + new MapBoundsPlacer(), + new ElevationPainter(heightDesert), + new HeightConstraint(-Infinity, heightDesert)); + + // Fertile land + const widthFertileLand = fractionToTiles(0.33); + paintRiver({ + "parallel": true, + "start": new Vector2D(mapBounds.left, mapBounds.bottom).rotateAround(-riverAngle, mapCenter), + "end": new Vector2D(mapBounds.right, mapBounds.bottom).rotateAround(-riverAngle, mapCenter), + "width": 2 * widthFertileLand, + "fadeDist": 8, + "deviation": 0, + "heightLand": heightDesert, + "heightRiverbed": heightFertileLand, + "meanderShort": 40, + "meanderLong": 0, + "waterFunc": (position, height, riverFraction) => { + createTerrain(tGrass).place(position); + clFertileLand.add(position); + }, + "landFunc": (position, shoreDist1, shoreDist2) => { -/** - * The buildings are set as uncapturable, otherwise the player would gain the buildings via root territory and can delete them without effort. - * Keep the entire city uncapturable as a consistent property of the city. - */ -const layoutKushCity = [ - { - "templateName": "uncapturable|" + oHouse, - "difficulty": "Very Easy", - "painters": new TileClassPainter(clHouse) - }, - { - "templateName": oFortress, - "difficulty": "Medium", - "constraints": [avoidClasses(clFortress, 25), new NearTileClassConstraint(clPath, 8)], - "painters": new TileClassPainter(clFortress) - }, - { - "templateName": oCivicCenter, - "difficulty": "Easy", - "constraints": [avoidClasses(clCivicCenter, 60), new NearTileClassConstraint(clPath, 8)], - "painters": new TileClassPainter(clCivicCenter) - }, - { - "templateName": oElephantStable, - "difficulty": "Easy", - "constraints": avoidClasses(clElephantStable, 10), - "painters": new TileClassPainter(clElephantStable) - }, - { - "templateName": oStable, - "difficulty": "Easy", - "constraints": avoidClasses(clStable, 20), - "painters": new TileClassPainter(clStable) - }, - { - "templateName": oBarracks, - "difficulty": "Easy", - "constraints": avoidClasses(clBarracks, 12), - "painters": new TileClassPainter(clBarracks) - }, - { - "templateName": oTower, - "difficulty": "Easy", - "constraints": avoidClasses(clTower, 17), - "painters": new TileClassPainter(clTower) - }, - { - "templateName": "uncapturable|" + oMarket, - "difficulty": "Very Easy", - "constraints": avoidClasses(clMarket, 15), - "painters": new TileClassPainter(clMarket) - }, - { - "templateName": "uncapturable|" + oForge, - "difficulty": "Very Easy", - "constraints": avoidClasses(clForge, 30), - "painters": new TileClassPainter(clForge) - }, - { - "templateName": oNobaCamp, - "difficulty": "Easy", - "constraints": avoidClasses(clNobaCamp, 30), - "painters": new TileClassPainter(clNobaCamp) - }, + for (const riv of layoutFertileLandTextures) + if (riv.left < +shoreDist1 && +shoreDist1 < riv.right || + riv.left < -shoreDist2 && -shoreDist2 < riv.right) + { + riv.tileClass.add(position); + riv.terrain.place(position); + } + } + }); + + // Nile + paintRiver({ + "parallel": true, + "start": new Vector2D(mapBounds.left, mapBounds.bottom).rotateAround(-riverAngle, mapCenter), + "end": new Vector2D(mapBounds.right, mapBounds.bottom).rotateAround(-riverAngle, mapCenter), + "width": fractionToTiles(0.2), + "fadeDist": 4, + "deviation": 0, + "heightLand": heightFertileLand, + "heightRiverbed": heightSeaGround, + "meanderShort": 40, + "meanderLong": 0 + }); + yield 30; + + g_Map.log("Computing player locations"); + const playerIDs = sortAllPlayers(); + const playerPosition = playerPlacementArcs( + playerIDs, + mapCenter, + fractionToTiles(0.38), + riverAngle - 0.5 * Math.PI, + 0.05 * Math.PI, + 0.55 * Math.PI); + + if (!isNomad()) { - "templateName": oBlemmyeCamp, - "difficulty": "Easy", - "constraints": avoidClasses(clBlemmyeCamp, 30), - "painters": new TileClassPainter(clBlemmyeCamp) - } -].filter(building => getDifficulty() >= getDifficulties().find(difficulty => difficulty.Name == building.difficulty).Difficulty); - -g_WallStyles.napata_wall = { - "short": readyWallElement("uncapturable|" + oWallMedium), - "medium": readyWallElement("uncapturable|" + oWallMedium), - "tower": readyWallElement("uncapturable|" + oWallTower), - "gate": readyWallElement("uncapturable|" + oWallGate), - "overlap": 0.05 -}; - -g_WallStyles.napata_palisade = { - "short": readyWallElement("uncapturable|" + oPalisadeMedium), - "medium": readyWallElement("uncapturable|" + oPalisadeMedium), - "tower": readyWallElement("uncapturable|" + oPalisadeTower), - "gate": readyWallElement("uncapturable|" + oPalisadeGate), - "overlap": 0.05 -}; - -Engine.SetProgress(10); - -g_Map.log("Loading hill heightmap"); -createArea( - new MapBoundsPlacer(), - new HeightmapPainter( - translateHeightmap( - new Vector2D(-12, scaleByMapSize(-12, -25)), - undefined, - convertHeightmap1Dto2D(Engine.LoadMapTerrain("maps/random/jebel_barkal.pmp").height)), - minHeightSource, - maxHeightSource)); - -const heightDesert = g_Map.getHeight(mapCenter); -const heightFertileLand = heightDesert - heightScale(2); -const heightShoreline = heightFertileLand - heightScale(0.5); -const heightWaterLevel = heightFertileLand - heightScale(3); -const heightPassage = heightWaterLevel - heightScale(1.5); -const heightIrrigationCanal = heightWaterLevel - heightScale(4); -const heightSeaGround = heightWaterLevel - heightScale(8); -const heightHill = heightDesert + heightScale(4); -const heightHilltop = heightHill + heightScale(90); -const heightHillArchers = (heightHilltop + heightHill) / 2; -const heightOffsetPath = heightScale(-2.5); -const heightOffsetRoad = heightScale(-1.5); -const heightOffsetWalls = heightScale(2.5); -const heightOffsetStatue = heightScale(2.5); - -g_Map.log("Flattening land"); -createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightDesert), - new HeightConstraint(-Infinity, heightDesert)); - -// Fertile land -const widthFertileLand = fractionToTiles(0.33); -paintRiver({ - "parallel": true, - "start": new Vector2D(mapBounds.left, mapBounds.bottom).rotateAround(-riverAngle, mapCenter), - "end": new Vector2D(mapBounds.right, mapBounds.bottom).rotateAround(-riverAngle, mapCenter), - "width": 2 * widthFertileLand, - "fadeDist": 8, - "deviation": 0, - "heightLand": heightDesert, - "heightRiverbed": heightFertileLand, - "meanderShort": 40, - "meanderLong": 0, - "waterFunc": (position, height, riverFraction) => { - createTerrain(tGrass).place(position); - clFertileLand.add(position); - }, - "landFunc": (position, shoreDist1, shoreDist2) => { - - for (const riv of layoutFertileLandTextures) - if (riv.left < +shoreDist1 && +shoreDist1 < riv.right || - riv.left < -shoreDist2 && -shoreDist2 < riv.right) - { - riv.tileClass.add(position); - riv.terrain.place(position); - } + g_Map.log("Marking player positions"); + for (const position of playerPosition) + addCivicCenterAreaToClass(position, clPlayer); } -}); - -// Nile -paintRiver({ - "parallel": true, - "start": new Vector2D(mapBounds.left, mapBounds.bottom).rotateAround(-riverAngle, mapCenter), - "end": new Vector2D(mapBounds.right, mapBounds.bottom).rotateAround(-riverAngle, mapCenter), - "width": fractionToTiles(0.2), - "fadeDist": 4, - "deviation": 0, - "heightLand": heightFertileLand, - "heightRiverbed": heightSeaGround, - "meanderShort": 40, - "meanderLong": 0 -}); -Engine.SetProgress(30); - -g_Map.log("Computing player locations"); -const playerIDs = sortAllPlayers(); -const playerPosition = playerPlacementArcs( - playerIDs, - mapCenter, - fractionToTiles(0.38), - riverAngle - 0.5 * Math.PI, - 0.05 * Math.PI, - 0.55 * Math.PI); - -if (!isNomad()) -{ - g_Map.log("Marking player positions"); - for (const position of playerPosition) - addCivicCenterAreaToClass(position, clPlayer); -} -g_Map.log("Marking water"); -createArea( + g_Map.log("Marking water"); + createArea( + new MapBoundsPlacer(), + [ + new TileClassPainter(clWater), + new TileClassUnPainter(clFertileLand) + ], + new HeightConstraint(-Infinity, heightWaterLevel)); + + g_Map.log("Marking desert"); + const avoidWater = new StaticConstraint(avoidClasses(clWater, 0)); + createArea( new MapBoundsPlacer(), + new TileClassPainter(clDesert), [ - new TileClassPainter(clWater), - new TileClassUnPainter(clFertileLand) - ], - new HeightConstraint(-Infinity, heightWaterLevel)); + new HeightConstraint(-Infinity, heightHill), + avoidWater, + avoidClasses(clFertileLand, 0) + ]); -g_Map.log("Marking desert"); -const avoidWater = new StaticConstraint(avoidClasses(clWater, 0)); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(clDesert), - [ - new HeightConstraint(-Infinity, heightHill), - avoidWater, - avoidClasses(clFertileLand, 0) - ]); + const stayDesert = new StaticConstraint(stayClasses(clDesert, 0)); + const stayFertileLand = new StaticConstraint(stayClasses(clFertileLand, 0)); -const stayDesert = new StaticConstraint(stayClasses(clDesert, 0)); -const stayFertileLand = new StaticConstraint(stayClasses(clFertileLand, 0)); + g_Map.log("Finding possible irrigation canal locations"); + let irrigationCanalAreas = []; + for (let i = 0; i < 30; ++i) + { + const x = fractionToTiles(randFloat(0, 1)); + irrigationCanalAreas.push( + createArea( + new PathPlacer( + new Vector2D(x, mapBounds.bottom).rotateAround(-riverAngle, mapCenter), + new Vector2D(x, mapBounds.top).rotateAround(-riverAngle, mapCenter), + 3, + 0, + 10, + 0.1, + 0.01, + Infinity), + undefined, + avoidClasses(clDesert, 2))); + } -g_Map.log("Finding possible irrigation canal locations"); -let irrigationCanalAreas = []; -for (let i = 0; i < 30; ++i) -{ - const x = fractionToTiles(randFloat(0, 1)); - irrigationCanalAreas.push( - createArea( - new PathPlacer( - new Vector2D(x, mapBounds.bottom).rotateAround(-riverAngle, mapCenter), - new Vector2D(x, mapBounds.top).rotateAround(-riverAngle, mapCenter), - 3, - 0, - 10, - 0.1, - 0.01, - Infinity), - undefined, - avoidClasses(clDesert, 2))); -} + g_Map.log("Creating irrigation canals"); + let irrigationCanalLocations = []; + for (const area of irrigationCanalAreas) + { + if (!area.getPoints().length || + area.getPoints().some(point => !avoidClasses(clPlayer, scaleByMapSize(8, 13), + clIrrigationCanal, scaleByMapSize(15, 25)).allows(point))) + continue; + + irrigationCanalLocations.push(pickRandom(area.getPoints()).clone() + .rotateAround(riverAngle, mapCenter).x); + createArea( + new MapBoundsPlacer(), + [ + new SmoothElevationPainter(ELEVATION_SET, heightIrrigationCanal, 1), + new TileClassPainter(clIrrigationCanal) + ], + [new StayAreasConstraint([area]), + new HeightConstraint(heightIrrigationCanal, heightDesert)]); + } -g_Map.log("Creating irrigation canals"); -let irrigationCanalLocations = []; -for (const area of irrigationCanalAreas) + g_Map.log("Creating passages"); + let previousPassageY = randIntInclusive(0, widthFertileLand); + let areasPassages = []; + irrigationCanalLocations.sort((a, b) => a - b); + for (let i = 0; i < irrigationCanalLocations.length; ++i) { - if (!area.getPoints().length || - area.getPoints().some(point => !avoidClasses(clPlayer, scaleByMapSize(8, 13), clIrrigationCanal, scaleByMapSize(15, 25)).allows(point))) - continue; + const previous = i == 0 ? mapBounds.left : irrigationCanalLocations[i - 1]; + const next = i == irrigationCanalLocations.length - 1 ? mapBounds.right : + irrigationCanalLocations[i + 1]; - irrigationCanalLocations.push(pickRandom(area.getPoints()).clone().rotateAround(riverAngle, mapCenter).x); - createArea( - new MapBoundsPlacer(), - [ - new SmoothElevationPainter(ELEVATION_SET, heightIrrigationCanal, 1), - new TileClassPainter(clIrrigationCanal) - ], - [new StayAreasConstraint([area]), new HeightConstraint(heightIrrigationCanal, heightDesert)]); - } + const x1 = (irrigationCanalLocations[i] + previous) / 2; + const x2 = (irrigationCanalLocations[i] + next) / 2; + let y; -g_Map.log("Creating passages"); -let previousPassageY = randIntInclusive(0, widthFertileLand); -let areasPassages = []; -irrigationCanalLocations.sort((a, b) => a - b); -for (let i = 0; i < irrigationCanalLocations.length; ++i) -{ - const previous = i == 0 ? mapBounds.left : irrigationCanalLocations[i - 1]; - const next = i == irrigationCanalLocations.length - 1 ? mapBounds.right : irrigationCanalLocations[i + 1]; + // The passages should be at different locations, so that enemies can't attack each other easily + for (let tries = 0; tries < 100; ++tries) + { + y = (previousPassageY + randIntInclusive(0.2 * widthFertileLand, + 0.8 * widthFertileLand)) % widthFertileLand; - const x1 = (irrigationCanalLocations[i] + previous) / 2; - const x2 = (irrigationCanalLocations[i] + next) / 2; - let y; + const pos = new Vector2D((x1 + x2) / 2, y).rotateAround(-riverAngle, mapCenter).round(); - // The passages should be at different locations, so that enemies can't attack each other easily - for (let tries = 0; tries < 100; ++tries) - { - y = (previousPassageY + randIntInclusive(0.2 * widthFertileLand, 0.8 * widthFertileLand)) % widthFertileLand; + if (g_Map.validTilePassable(new Vector2D(pos.x, pos.y)) && + avoidClasses(clDesert, 12).allows(pos) && + new HeightConstraint(heightIrrigationCanal, heightFertileLand).allows(pos)) + break; + } - const pos = new Vector2D((x1 + x2) / 2, y).rotateAround(-riverAngle, mapCenter).round(); + const area = + createArea( + new PathPlacer( + new Vector2D(x1, y).rotateAround(-riverAngle, mapCenter), + new Vector2D(x2, y).rotateAround(-riverAngle, mapCenter), + 10, + 0, + 1, + 0, + 0, + Infinity), + [ + new ElevationPainter(heightPassage), + new TileClassPainter(clPassage) + ], + [ + new HeightConstraint(-Infinity, heightPassage), + stayClasses(clFertileLand, 2) + ]); + + if (!area || !area.getPoints().length) + continue; - if (g_Map.validTilePassable(new Vector2D(pos.x, pos.y)) && - avoidClasses(clDesert, 12).allows(pos) && - new HeightConstraint(heightIrrigationCanal, heightFertileLand).allows(pos)) - break; + previousPassageY = y; + areasPassages.push(area); } + yield 40; - const area = - createArea( - new PathPlacer( - new Vector2D(x1, y).rotateAround(-riverAngle, mapCenter), - new Vector2D(x2, y).rotateAround(-riverAngle, mapCenter), - 10, - 0, - 1, - 0, - 0, - Infinity), - [ - new ElevationPainter(heightPassage), - new TileClassPainter(clPassage) - ], - [ - new HeightConstraint(-Infinity, heightPassage), - stayClasses(clFertileLand, 2) - ]); + g_Map.log("Marking hill"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(clHill), + new HeightConstraint(heightHill, Infinity)); - if (!area || !area.getPoints().length) - continue; + g_Map.log("Marking water"); + const areaWater = createArea( + new MapBoundsPlacer(), + new TileClassPainter(clWater), + new HeightConstraint(-Infinity, heightWaterLevel)); - previousPassageY = y; - areasPassages.push(area); -} -Engine.SetProgress(40); - -g_Map.log("Marking hill"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(clHill), - new HeightConstraint(heightHill, Infinity)); - -g_Map.log("Marking water"); -const areaWater = createArea( - new MapBoundsPlacer(), - new TileClassPainter(clWater), - new HeightConstraint(-Infinity, heightWaterLevel)); - -g_Map.log("Painting water and shoreline"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(tWater), - new HeightConstraint(-Infinity, heightShoreline)); - -g_Map.log("Painting hill"); -const areaHill = createArea( - new MapBoundsPlacer(), - new TerrainPainter(tHillGround), - new HeightConstraint(heightHill, Infinity)); - -g_Map.log("Painting hilltop"); -const areaHilltop = createArea( - new MapBoundsPlacer(), - new TerrainPainter(tHilltop), - [ - new HeightConstraint(heightHilltop, Infinity), - new SlopeConstraint(-Infinity, 2) - ]); + g_Map.log("Painting water and shoreline"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(tWater), + new HeightConstraint(-Infinity, heightShoreline)); -Engine.SetProgress(50); + g_Map.log("Painting hill"); + const areaHill = createArea( + new MapBoundsPlacer(), + new TerrainPainter(tHillGround), + new HeightConstraint(heightHill, Infinity)); -for (let i = 0; i < numPlayers; ++i) -{ - const isDesert = clDesert.has(playerPosition[i]); - placePlayerBase({ - "playerID": playerIDs[i], - "playerPosition": playerPosition[i], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": avoidClasses(clPlayer, 4, clWater, 4), - "Walls": mapSize <= 256 || getDifficulty() >= 3 ? "towers" : "walls", - "CityPatch": { - "outerTerrain": isDesert ? tRoadDesert : tRoadFertileLand, - "innerTerrain": isDesert ? tRoadDesert : tRoadFertileLand - }, - "StartingAnimal": { - "template": oGazelle, - "distance": 15, - "minGroupDistance": 2, - "maxGroupDistance": 4, - "minGroupCount": 2, - "maxGroupCount": 3 - }, - "Berries": { - "template": isDesert ? oBerryBushDesert : oBerryBushGrapes - }, - "Mines": { - "types": [ - { "template": isDesert ? oMetalLargeDesert : oMetalLargeFertileLand }, - { "template": isDesert ? oStoneLargeDesert : oStoneLargeFertileLand } - ] - }, - "Trees": { - "template": isDesert ? oAcacia : pickRandom(oPalms), - "count": isDesert ? scaleByMapSize(5, 10) : scaleByMapSize(15, 30) - }, - "Treasures": { - "types": - [ - { - "template": oWoodTreasure, - "count": isDesert ? 4 : 0 - }, - { - "template": oStoneTreasure, - "count": isDesert ? 1 : 0 - }, - { - "template": oMetalTreasure, - "count": isDesert ? 1 : 0 - } - ] - }, - "Decoratives": { - "template": isDesert ? aRock : pickRandom(aBushesFertileLand) - } - }); -} + g_Map.log("Painting hilltop"); + const areaHilltop = createArea( + new MapBoundsPlacer(), + new TerrainPainter(tHilltop), + [ + new HeightConstraint(heightHilltop, Infinity), + new SlopeConstraint(-Infinity, 2) + ]); -g_Map.log("Placing pyramids"); -const areaPyramids = createArea(new DiskPlacer(scaleByMapSize(5, 14), positionPyramids)); -// Retry loops are needed due to the self-avoidance -createObjectGroupsByAreas( - new SimpleGroup( - [new RandomObject( - [oPyramidLarge, oPyramidSmall], - scaleByMapSize(1, 6), - scaleByMapSize(2, 8), - scaleByMapSize(6, 8), - scaleByMapSize(6, 14), - Math.PI * 1.35, - Math.PI * 1.5, - scaleByMapSize(6, 8))], - true, - clPyramid), - 0, - undefined, - 1, - 50, - [areaPyramids]); - -Engine.SetProgress(60); - -// The city is a circle segment of this maximum size -g_Map.log("Computing city grid"); -const gridCenter = new Vector2D(0, fractionToTiles(0.3)).rotate(-riverAngle).add(mapCenter).round(); -const gridMaxAngle = Math.min(scaleByMapSize(1/3, 1), 2/3) * Math.PI; -const gridStartAngle = -Math.PI / 2 -gridMaxAngle / 2 + riverAngle; -const gridRadius = y => hillRadius + 18 * y; - -const gridPointsX = layoutKushTemples.length; -const gridPointsY = Math.floor(scaleByMapSize(2, 5)); -const gridPointXCenter = Math.floor(gridPointsX / 2); -const gridPointYCenter = Math.floor(gridPointsY / 2); - -// Maps from grid position to map position -let cityGridPosition = []; -let cityGridAngle = []; -for (let y = 0; y < gridPointsY; ++y) - [cityGridPosition[y], cityGridAngle[y]] = distributePointsOnCircularSegment( - gridPointsX, gridMaxAngle, gridStartAngle, gridRadius(y), gridCenter); - -g_Map.log("Marking city path crossings"); -for (const y in cityGridPosition) - for (const x in cityGridPosition[y]) + yield 50; + + for (let i = 0; i < numPlayers; ++i) { - cityGridPosition[y][x].round(); - createArea( - new DiskPlacer(pathWidth, cityGridPosition[y][x]), - [ - new TileClassPainter(clPath), - new TileClassPainter(clPathCrossing) - ]); + const isDesert = clDesert.has(playerPosition[i]); + placePlayerBase({ + "playerID": playerIDs[i], + "playerPosition": playerPosition[i], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": avoidClasses(clPlayer, 4, clWater, 4), + "Walls": mapSize <= 256 || getDifficulty() >= 3 ? "towers" : "walls", + "CityPatch": { + "outerTerrain": isDesert ? tRoadDesert : tRoadFertileLand, + "innerTerrain": isDesert ? tRoadDesert : tRoadFertileLand + }, + "StartingAnimal": { + "template": oGazelle, + "distance": 15, + "minGroupDistance": 2, + "maxGroupDistance": 4, + "minGroupCount": 2, + "maxGroupCount": 3 + }, + "Berries": { + "template": isDesert ? oBerryBushDesert : oBerryBushGrapes + }, + "Mines": { + "types": [ + { "template": isDesert ? oMetalLargeDesert : oMetalLargeFertileLand }, + { "template": isDesert ? oStoneLargeDesert : oStoneLargeFertileLand } + ] + }, + "Trees": { + "template": isDesert ? oAcacia : pickRandom(oPalms), + "count": isDesert ? scaleByMapSize(5, 10) : scaleByMapSize(15, 30) + }, + "Treasures": { + "types": + [ + { + "template": oWoodTreasure, + "count": isDesert ? 4 : 0 + }, + { + "template": oStoneTreasure, + "count": isDesert ? 1 : 0 + }, + { + "template": oMetalTreasure, + "count": isDesert ? 1 : 0 + } + ] + }, + "Decoratives": { + "template": isDesert ? aRock : pickRandom(aBushesFertileLand) + } + }); } -g_Map.log("Marking horizontal city paths"); -const areasCityPaths = []; -for (let y = 0; y < gridPointsY; ++y) - for (let x = 1; x < gridPointsX; ++x) - { - const width = y == gridPointYCenter ? pathWidthSecondary : pathWidth; - areasCityPaths.push( + g_Map.log("Placing pyramids"); + const areaPyramids = createArea(new DiskPlacer(scaleByMapSize(5, 14), positionPyramids)); + // Retry loops are needed due to the self-avoidance + createObjectGroupsByAreas( + new SimpleGroup( + [new RandomObject( + [oPyramidLarge, oPyramidSmall], + scaleByMapSize(1, 6), + scaleByMapSize(2, 8), + scaleByMapSize(6, 8), + scaleByMapSize(6, 14), + Math.PI * 1.35, + Math.PI * 1.5, + scaleByMapSize(6, 8))], + true, + clPyramid), + 0, + undefined, + 1, + 50, + [areaPyramids]); + + yield 60; + + // The city is a circle segment of this maximum size + g_Map.log("Computing city grid"); + const gridCenter = new Vector2D(0, fractionToTiles(0.3)).rotate(-riverAngle).add(mapCenter).round(); + const gridMaxAngle = Math.min(scaleByMapSize(1/3, 1), 2/3) * Math.PI; + const gridStartAngle = -Math.PI / 2 -gridMaxAngle / 2 + riverAngle; + const gridRadius = y => hillRadius + 18 * y; + + const gridPointsX = layoutKushTemples.length; + const gridPointsY = Math.floor(scaleByMapSize(2, 5)); + const gridPointXCenter = Math.floor(gridPointsX / 2); + const gridPointYCenter = Math.floor(gridPointsY / 2); + + // Maps from grid position to map position + let cityGridPosition = []; + let cityGridAngle = []; + for (let y = 0; y < gridPointsY; ++y) + [cityGridPosition[y], cityGridAngle[y]] = distributePointsOnCircularSegment( + gridPointsX, gridMaxAngle, gridStartAngle, gridRadius(y), gridCenter); + + g_Map.log("Marking city path crossings"); + for (const y in cityGridPosition) + for (const x in cityGridPosition[y]) + { + cityGridPosition[y][x].round(); createArea( - new PathPlacer(cityGridPosition[y][x - 1], cityGridPosition[y][x], width, 0, 8, 0, 0, Infinity), - new TileClassPainter(clPath))); - } + new DiskPlacer(pathWidth, cityGridPosition[y][x]), + [ + new TileClassPainter(clPath), + new TileClassPainter(clPathCrossing) + ]); + } -g_Map.log("Marking vertical city paths"); -for (let y = 1; y < gridPointsY; ++y) - for (let x = 0; x < gridPointsX; ++x) + g_Map.log("Marking horizontal city paths"); + const areasCityPaths = []; + for (let y = 0; y < gridPointsY; ++y) + for (let x = 1; x < gridPointsX; ++x) + { + const width = y == gridPointYCenter ? pathWidthSecondary : pathWidth; + areasCityPaths.push( + createArea( + new PathPlacer(cityGridPosition[y][x - 1], cityGridPosition[y][x], width, 0, + 8, 0, 0, Infinity), + new TileClassPainter(clPath))); + } + + g_Map.log("Marking vertical city paths"); + for (let y = 1; y < gridPointsY; ++y) + for (let x = 0; x < gridPointsX; ++x) + { + const width = + Math.abs(x - gridPointXCenter) == 0 ? + pathWidthCenter : + Math.abs(x - gridPointXCenter) == 1 ? + pathWidthSecondary : + pathWidth; + + areasCityPaths.push( + createArea( + new PathPlacer(cityGridPosition[y - 1][x], cityGridPosition[y][x], width, 0, + 8, 0, 0, Infinity), + new TileClassPainter(clPath))); + } + yield 70; + + g_Map.log("Placing kushite temples"); + let entitiesTemples = []; + const templePosition = []; + for (let i = 0; i < layoutKushTemples.length; ++i) { - const width = - Math.abs(x - gridPointXCenter) == 0 ? - pathWidthCenter : - Math.abs(x - gridPointXCenter) == 1 ? - pathWidthSecondary : - pathWidth; - - areasCityPaths.push( - createArea( - new PathPlacer(cityGridPosition[y - 1][x], cityGridPosition[y][x], width, 0, 8, 0, 0, Infinity), - new TileClassPainter(clPath))); + const x = i + (gridPointsX - layoutKushTemples.length) / 2; + templePosition[i] = Vector2D.add(cityGridPosition[0][x], layoutKushTemples[i].pathOffset.rotate( + -Math.PI / 2 - cityGridAngle[0][x])); + entitiesTemples[i] = g_Map.placeEntityPassable(layoutKushTemples[i].template, 0, + templePosition[i], cityGridAngle[0][x]); } -Engine.SetProgress(70); -g_Map.log("Placing kushite temples"); -let entitiesTemples = []; -const templePosition = []; -for (let i = 0; i < layoutKushTemples.length; ++i) -{ - const x = i + (gridPointsX - layoutKushTemples.length) / 2; - templePosition[i] = Vector2D.add(cityGridPosition[0][x], layoutKushTemples[i].pathOffset.rotate(-Math.PI / 2 - cityGridAngle[0][x])); - entitiesTemples[i] = g_Map.placeEntityPassable(layoutKushTemples[i].template, 0, templePosition[i], cityGridAngle[0][x]); -} + g_Map.log("Marking temple area"); + createArea( + new EntitiesObstructionPlacer(entitiesTemples, 0, Infinity), + new TileClassPainter(clTemple)); -g_Map.log("Marking temple area"); -createArea( - new EntitiesObstructionPlacer(entitiesTemples, 0, Infinity), - new TileClassPainter(clTemple)); - -g_Map.log("Smoothing temple ground"); -createArea( - new MapBoundsPlacer(), - new ElevationBlendingPainter(heightDesert, 0.8), - new NearTileClassConstraint(clTemple, 0)); - -g_Map.log("Painting cliffs"); -createArea( - new MapBoundsPlacer(), - [ - new TerrainPainter(tHillCliff), - new TileClassPainter(clCliff) - ], - [ - stayClasses(clHill, 0), - new SlopeConstraint(2, Infinity) - ]); + g_Map.log("Smoothing temple ground"); + createArea( + new MapBoundsPlacer(), + new ElevationBlendingPainter(heightDesert, 0.8), + new NearTileClassConstraint(clTemple, 0)); -g_Map.log("Painting temple ground"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(tPathWild), - [ - new NearTileClassConstraint(clTemple, 1), - avoidClasses(clPath, 0, clCliff, 1) - ]); + g_Map.log("Painting cliffs"); + createArea( + new MapBoundsPlacer(), + [ + new TerrainPainter(tHillCliff), + new TileClassPainter(clCliff) + ], + [ + stayClasses(clHill, 0), + new SlopeConstraint(2, Infinity) + ]); -g_Map.log("Placing lion statues in the central path"); -const statueCount = scaleByMapSize(10, 40); -const centralPathStart = cityGridPosition[0][gridPointXCenter]; -const centralPathLength = centralPathStart.distanceTo(cityGridPosition[gridPointsY - 1][gridPointXCenter]); -const centralPathAngle = cityGridAngle[0][gridPointXCenter]; -for (let i = 0; i < 2; ++i) - for (let stat = 0; stat < statueCount; ++stat) - { - const start = new Vector2D(0, pathWidthCenter * 3/4 * (i - 0.5)).rotate(centralPathAngle).add(centralPathStart); - const position = new Vector2D(centralPathLength, 0).mult(stat / statueCount).rotate(-centralPathAngle).add(start).add(new Vector2D(0.5, 0.5)); + g_Map.log("Painting temple ground"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(tPathWild), + [ + new NearTileClassConstraint(clTemple, 1), + avoidClasses(clPath, 0, clCliff, 1) + ]); - if (!avoidClasses(clPathCrossing, 2).allows(position)) - continue; + g_Map.log("Placing lion statues in the central path"); + const statueCount = scaleByMapSize(10, 40); + const centralPathStart = cityGridPosition[0][gridPointXCenter]; + const centralPathLength = centralPathStart.distanceTo( + cityGridPosition[gridPointsY - 1][gridPointXCenter]); + const centralPathAngle = cityGridAngle[0][gridPointXCenter]; + for (let i = 0; i < 2; ++i) + for (let stat = 0; stat < statueCount; ++stat) + { + const start = new Vector2D(0, pathWidthCenter * 3/4 * (i - 0.5)).rotate(centralPathAngle) + .add(centralPathStart); + const position = new Vector2D(centralPathLength, 0).mult(stat / statueCount) + .rotate(-centralPathAngle).add(start).add(new Vector2D(0.5, 0.5)); - g_Map.placeEntityPassable(pickRandom(aStatues), 0, position, centralPathAngle - Math.PI * (i + 0.5)); - clPathStatues.add(position.round()); - } + if (!avoidClasses(clPathCrossing, 2).allows(position)) + continue; -g_Map.log("Placing guardian infantry in the central path"); -const centralChampionsCount = scaleByMapSize(2, 40); -for (let i = 0; i < 2; ++i) - for (let champ = 0; champ < centralChampionsCount; ++champ) - { - const start = new Vector2D(0, pathWidthCenter * 1/2 * (i - 0.5)).rotate(-centralPathAngle).add(centralPathStart); - const position = new Vector2D(centralPathLength, 0).mult(champ / centralChampionsCount).rotate(-centralPathAngle).add(start).add(new Vector2D(0.5, 0.5)); + g_Map.placeEntityPassable(pickRandom(aStatues), 0, position, + centralPathAngle - Math.PI * (i + 0.5)); + clPathStatues.add(position.round()); + } - if (!avoidClasses(clPathCrossing, 2).allows(position)) - continue; + g_Map.log("Placing guardian infantry in the central path"); + const centralChampionsCount = scaleByMapSize(2, 40); + for (let i = 0; i < 2; ++i) + for (let champ = 0; champ < centralChampionsCount; ++champ) + { + const start = new Vector2D(0, pathWidthCenter * 1/2 * (i - 0.5)).rotate(-centralPathAngle) + .add(centralPathStart); + const position = new Vector2D(centralPathLength, 0).mult(champ / centralChampionsCount) + .rotate(-centralPathAngle).add(start).add(new Vector2D(0.5, 0.5)); - g_Map.placeEntityPassable(pickRandom(oKushChampions), 0, position, centralPathAngle - Math.PI * (i - 0.5)); - clPathStatues.add(position.round()); - } + if (!avoidClasses(clPathCrossing, 2).allows(position)) + continue; -g_Map.log("Placing kushite statues in the secondary paths"); -for (const x of [gridPointXCenter - 1, gridPointXCenter + 1]) -{ - g_Map.placeEntityAnywhere(aStatueKush, 0, cityGridPosition[gridPointYCenter][x], cityGridAngle[gridPointYCenter][x]); - clPathStatues.add(cityGridPosition[gridPointYCenter][x]); -} + g_Map.placeEntityPassable(pickRandom(oKushChampions), 0, position, + centralPathAngle - Math.PI * (i - 0.5)); + clPathStatues.add(position.round()); + } -g_Map.log("Creating ritual place near the wonder"); -const ritualPosition = Vector2D.average([ - templePosition[Math.floor(templePosition.length / 2) - 1], - templePosition[Math.ceil(templePosition.length / 2) - 1], - cityGridPosition[0][gridPointXCenter], - cityGridPosition[0][gridPointXCenter - 1] -]).round(); - -const ritualAngle = (cityGridAngle[0][gridPointXCenter] + cityGridAngle[0][gridPointXCenter - 1]) / 2 + Math.PI / 2; - -g_Map.placeEntityPassable(aStatueKush, 0, ritualPosition, ritualAngle - Math.PI / 2); - -createArea( - new DiskPlacer(scaleByMapSize(4, 6), ritualPosition), - [ - new LayeredPainter([tPathWild, tPath], [1]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetPath, 2), - new TileClassPainter(clRitualPlace) - ], - avoidClasses(clCliff, 1)); - -createArea( - new DiskPlacer(0, new Vector2D(-1, -1).add(ritualPosition)), - new ElevationPainter(heightDesert + heightOffsetStatue)); - -g_Map.log("Placing healers at the ritual place"); -const [healerPosition, healerAngle] = distributePointsOnCircularSegment( - scaleByMapSize(2, 10), Math.PI, ritualAngle, scaleByMapSize(2, 3), ritualPosition); -for (let i = 0; i < healerPosition.length; ++i) - g_Map.placeEntityPassable(oKushHealer, 0, healerPosition[i], healerAngle[i] + Math.PI); - -g_Map.log("Placing statues at the ritual place"); -const [statuePosition, statueAngle] = distributePointsOnCircularSegment( - scaleByMapSize(4, 8), Math.PI, ritualAngle, scaleByMapSize(3, 4), ritualPosition); -for (let i = 0; i < statuePosition.length; ++i) - g_Map.placeEntityPassable(pickRandom(aStatues), 0, statuePosition[i], statueAngle[i] + Math.PI); - -g_Map.log("Placing palms at the ritual place"); -const palmPosition = distributePointsOnCircularSegment( - scaleByMapSize(6, 16), Math.PI, ritualAngle, scaleByMapSize(4, 5), ritualPosition)[0]; -for (let i = 0; i < palmPosition.length; ++i) - if (avoidClasses(clTemple, 1).allows(palmPosition[i])) - g_Map.placeEntityPassable(oPalmPath, 0, palmPosition[i], randomAngle()); - -g_Map.log("Painting city paths"); -const areaPaths = createArea( - new MapBoundsPlacer(), - [ - new LayeredPainter([tPathWild, tPath], [1]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetPath, 1) - ], - stayClasses(clPath, 0)); - -g_Map.log("Placing triggerpoints on city paths"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oTriggerPointCityPath, 1, 1, 0, 0)], true, clTriggerPointCityPath), - 0, - [avoidClasses(clTriggerPointCityPath, 8), stayClasses(clPathCrossing, 2)], - scaleByMapSize(20, 100), - 30, - [areaPaths]); - -g_Map.log("Placing city districts"); -for (let y = 1; y < gridPointsY; ++y) - for (let x = 1; x < gridPointsX; ++x) - createArea( - new ConvexPolygonPlacer([cityGridPosition[y - 1][x - 1], cityGridPosition[y - 1][x], cityGridPosition[y][x - 1], cityGridPosition[y][x]], Infinity), - [ - new TerrainPainter(tRoadDesert), - new CityPainter(layoutKushCity, (-cityGridAngle[y][x - 1] - cityGridAngle[y][x]) / 2, 0), - new TileClassPainter(clCity) - ], - new StaticConstraint(avoidClasses(clPath, 0))); + g_Map.log("Placing kushite statues in the secondary paths"); + for (const x of [gridPointXCenter - 1, gridPointXCenter + 1]) + { + g_Map.placeEntityAnywhere(aStatueKush, 0, cityGridPosition[gridPointYCenter][x], + cityGridAngle[gridPointYCenter][x]); + clPathStatues.add(cityGridPosition[gridPointYCenter][x]); + } -let entitiesGates; -if (placeNapataWall) -{ - g_Map.log("Placing front walls"); - const wallGridMaxAngleSummand = scaleByMapSize(0.04, 0.03) * Math.PI; - const wallGridStartAngle = gridStartAngle - wallGridMaxAngleSummand / 2; - const wallGridRadiusFront = gridRadius(gridPointsY - 1) + pathWidth - 1; - const wallGridMaxAngleFront = gridMaxAngle + wallGridMaxAngleSummand; - let entitiesWalls = placeCircularWall( - gridCenter, - wallGridRadiusFront, - ["tower", "short", "tower", "gate", "tower", "medium", "tower", "short"], - placeNapataWall, - 0, - wallGridStartAngle, - wallGridMaxAngleFront, - true, - 0, - 0); - - g_Map.log("Placing side and back walls"); - const wallGridRadiusBack = hillRadius - scaleByMapSize(15, 25); - const wallGridMaxAngleBack = gridMaxAngle + wallGridMaxAngleSummand; - const wallGridPositionFront = distributePointsOnCircularSegment(gridPointsX, wallGridMaxAngleBack, wallGridStartAngle, wallGridRadiusFront, gridCenter)[0]; - const wallGridPositionBack = distributePointsOnCircularSegment(gridPointsX, wallGridMaxAngleBack, wallGridStartAngle, wallGridRadiusBack, gridCenter)[0]; - const wallGridPosition = [wallGridPositionFront[0], ...wallGridPositionBack, wallGridPositionFront[wallGridPositionFront.length - 1]]; - for (let x = 1; x < wallGridPosition.length; ++x) - entitiesWalls = entitiesWalls.concat( - placeLinearWall( - wallGridPosition[x - 1], - wallGridPosition[x], - ["tower", "gate", "tower", "short", "tower", "short", "tower"], - placeNapataWall, - 0, - false, - avoidClasses(clHill, 0, clTemple, 0))); + g_Map.log("Creating ritual place near the wonder"); + const ritualPosition = Vector2D.average([ + templePosition[Math.floor(templePosition.length / 2) - 1], + templePosition[Math.ceil(templePosition.length / 2) - 1], + cityGridPosition[0][gridPointXCenter], + cityGridPosition[0][gridPointXCenter - 1] + ]).round(); - g_Map.log("Marking walls"); - createArea( - new EntitiesObstructionPlacer(entitiesWalls, 0, Infinity), - new TileClassPainter(clWall)); + const ritualAngle = (cityGridAngle[0][gridPointXCenter] + cityGridAngle[0][gridPointXCenter - 1]) / + 2 + Math.PI / 2; + + g_Map.placeEntityPassable(aStatueKush, 0, ritualPosition, ritualAngle - Math.PI / 2); - g_Map.log("Marking gates"); - entitiesGates = entitiesWalls.filter(entity => entity.templateName.endsWith(oWallGate)); createArea( - new EntitiesObstructionPlacer(entitiesGates, 0, Infinity), - new TileClassPainter(clGate)); + new DiskPlacer(scaleByMapSize(4, 6), ritualPosition), + [ + new LayeredPainter([tPathWild, tPath], [1]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetPath, 2), + new TileClassPainter(clRitualPlace) + ], + avoidClasses(clCliff, 1)); - g_Map.log("Painting wall terrain"); createArea( + new DiskPlacer(0, new Vector2D(-1, -1).add(ritualPosition)), + new ElevationPainter(heightDesert + heightOffsetStatue)); + + g_Map.log("Placing healers at the ritual place"); + const [healerPosition, healerAngle] = distributePointsOnCircularSegment( + scaleByMapSize(2, 10), Math.PI, ritualAngle, scaleByMapSize(2, 3), ritualPosition); + for (let i = 0; i < healerPosition.length; ++i) + g_Map.placeEntityPassable(oKushHealer, 0, healerPosition[i], healerAngle[i] + Math.PI); + + g_Map.log("Placing statues at the ritual place"); + const [statuePosition, statueAngle] = distributePointsOnCircularSegment( + scaleByMapSize(4, 8), Math.PI, ritualAngle, scaleByMapSize(3, 4), ritualPosition); + for (let i = 0; i < statuePosition.length; ++i) + g_Map.placeEntityPassable(pickRandom(aStatues), 0, statuePosition[i], statueAngle[i] + Math.PI); + + g_Map.log("Placing palms at the ritual place"); + const palmPosition = distributePointsOnCircularSegment( + scaleByMapSize(6, 16), Math.PI, ritualAngle, scaleByMapSize(4, 5), ritualPosition)[0]; + for (let i = 0; i < palmPosition.length; ++i) + if (avoidClasses(clTemple, 1).allows(palmPosition[i])) + g_Map.placeEntityPassable(oPalmPath, 0, palmPosition[i], randomAngle()); + + g_Map.log("Painting city paths"); + const areaPaths = createArea( new MapBoundsPlacer(), [ - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetWalls, 2), - new TerrainPainter(tPathWild) + new LayeredPainter([tPathWild, tPath], [1]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetPath, 1) ], - [ - new NearTileClassConstraint(clWall, 1), - avoidClasses(clCliff, 0) - ]); + stayClasses(clPath, 0)); + + g_Map.log("Placing triggerpoints on city paths"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oTriggerPointCityPath, 1, 1, 0, 0)], true, + clTriggerPointCityPath), + 0, + [avoidClasses(clTriggerPointCityPath, 8), stayClasses(clPathCrossing, 2)], + scaleByMapSize(20, 100), + 30, + [areaPaths]); + + g_Map.log("Placing city districts"); + for (let y = 1; y < gridPointsY; ++y) + for (let x = 1; x < gridPointsX; ++x) + createArea( + new ConvexPolygonPlacer([cityGridPosition[y - 1][x - 1], cityGridPosition[y - 1][x], + cityGridPosition[y][x - 1], cityGridPosition[y][x]], Infinity), + [ + new TerrainPainter(tRoadDesert), + new CityPainter(layoutKushCity, + (-cityGridAngle[y][x - 1] - cityGridAngle[y][x]) / 2, 0), + new TileClassPainter(clCity) + ], + new StaticConstraint(avoidClasses(clPath, 0))); + + let entitiesGates; + if (placeNapataWall) + { + g_Map.log("Placing front walls"); + const wallGridMaxAngleSummand = scaleByMapSize(0.04, 0.03) * Math.PI; + const wallGridStartAngle = gridStartAngle - wallGridMaxAngleSummand / 2; + const wallGridRadiusFront = gridRadius(gridPointsY - 1) + pathWidth - 1; + const wallGridMaxAngleFront = gridMaxAngle + wallGridMaxAngleSummand; + let entitiesWalls = placeCircularWall( + gridCenter, + wallGridRadiusFront, + ["tower", "short", "tower", "gate", "tower", "medium", "tower", "short"], + placeNapataWall, + 0, + wallGridStartAngle, + wallGridMaxAngleFront, + true, + 0, + 0); + + g_Map.log("Placing side and back walls"); + const wallGridRadiusBack = hillRadius - scaleByMapSize(15, 25); + const wallGridMaxAngleBack = gridMaxAngle + wallGridMaxAngleSummand; + const wallGridPositionFront = distributePointsOnCircularSegment(gridPointsX, + wallGridMaxAngleBack, wallGridStartAngle, wallGridRadiusFront, gridCenter)[0]; + const wallGridPositionBack = distributePointsOnCircularSegment(gridPointsX, + wallGridMaxAngleBack, wallGridStartAngle, wallGridRadiusBack, gridCenter)[0]; + const wallGridPosition = [wallGridPositionFront[0], ...wallGridPositionBack, + wallGridPositionFront[wallGridPositionFront.length - 1]]; + for (let x = 1; x < wallGridPosition.length; ++x) + entitiesWalls = entitiesWalls.concat( + placeLinearWall( + wallGridPosition[x - 1], + wallGridPosition[x], + ["tower", "gate", "tower", "short", "tower", "short", "tower"], + placeNapataWall, + 0, + false, + avoidClasses(clHill, 0, clTemple, 0))); + + g_Map.log("Marking walls"); + createArea( + new EntitiesObstructionPlacer(entitiesWalls, 0, Infinity), + new TileClassPainter(clWall)); + + g_Map.log("Marking gates"); + entitiesGates = entitiesWalls.filter(entity => entity.templateName.endsWith(oWallGate)); + createArea( + new EntitiesObstructionPlacer(entitiesGates, 0, Infinity), + new TileClassPainter(clGate)); - g_Map.log("Painting gate terrain"); - for (const entity of entitiesGates) + g_Map.log("Painting wall terrain"); createArea( - new DiskPlacer(pathWidth, entity.GetPosition2D()), + new MapBoundsPlacer(), [ - new LayeredPainter([tPathWild, tPath], [1]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetPath, 2), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetWalls, 2), + new TerrainPainter(tPathWild) ], [ - avoidClasses(clCliff, 0, clPath, 0, clCity, 0), - new NearTileClassConstraint(clPath, pathWidth + 1) + new NearTileClassConstraint(clWall, 1), + avoidClasses(clCliff, 0) ]); -} -Engine.SetProgress(70); -g_Map.log("Finding road starting points"); -const roadStartLocations = shuffleArray( - entitiesGates ? - entitiesGates.map(entity => entity.GetPosition2D()) : - [ - ...cityGridPosition.map(gridPos => gridPos[0]), - ...cityGridPosition.map(gridPos => gridPos[gridPos.length - 1]), - ...cityGridPosition[cityGridPosition.length - 1] - ]); + g_Map.log("Painting gate terrain"); + for (const entity of entitiesGates) + createArea( + new DiskPlacer(pathWidth, entity.GetPosition2D()), + [ + new LayeredPainter([tPathWild, tPath], [1]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetPath, 2), + ], + [ + avoidClasses(clCliff, 0, clPath, 0, clCity, 0), + new NearTileClassConstraint(clPath, pathWidth + 1) + ]); + } + yield 70; -g_Map.log("Finding possible roads"); -let roadConstraint = new StaticConstraint( - [ - stayDesert, - avoidClasses(clHill, 0, clCity, 0, clPyramid, 6, clPlayer, 16) - ]); + g_Map.log("Finding road starting points"); + const roadStartLocations = shuffleArray( + entitiesGates ? + entitiesGates.map(entity => entity.GetPosition2D()) : + [ + ...cityGridPosition.map(gridPos => gridPos[0]), + ...cityGridPosition.map(gridPos => gridPos[gridPos.length - 1]), + ...cityGridPosition[cityGridPosition.length - 1] + ]); -const areaCityPaths = new Area(areasCityPaths.reduce((points, area) => points.concat(area.getPoints()), [])); -const areaRoads = []; -for (const roadStart of roadStartLocations) -{ - if (areaRoads.length >= scaleByMapSize(2, 5)) - break; + g_Map.log("Finding possible roads"); + let roadConstraint = new StaticConstraint( + [ + stayDesert, + avoidClasses(clHill, 0, clCity, 0, clPyramid, 6, clPlayer, 16) + ]); - const closestPoint = areaCityPaths.getClosestPointTo(roadStart); - roadConstraint = new StaticConstraint([roadConstraint, avoidClasses(clRoad, 20)]); - for (let tries = 0; tries < 30; ++tries) + const areaCityPaths = + new Area(areasCityPaths.reduce((points, area) => points.concat(area.getPoints()), [])); + const areaRoads = []; + for (const roadStart of roadStartLocations) { - const area = createArea( - new PathPlacer( - Vector2D.add(closestPoint, new Vector2D(0, 3/4 * mapSize).rotate(closestPoint.angleTo(roadStart))), - roadStart, - scaleByMapSize(5, 3), - 0.1, - 5, - 0.5, - 0, - 0), - new TileClassPainter(clRoad), - roadConstraint); + if (areaRoads.length >= scaleByMapSize(2, 5)) + break; - if (area && area.getPoints().length) + const closestPoint = areaCityPaths.getClosestPointTo(roadStart); + roadConstraint = new StaticConstraint([roadConstraint, avoidClasses(clRoad, 20)]); + for (let tries = 0; tries < 30; ++tries) { - areaRoads.push(area); - break; + const area = createArea( + new PathPlacer( + Vector2D.add(closestPoint, new Vector2D(0, 3/4 * mapSize).rotate( + closestPoint.angleTo(roadStart))), + roadStart, + scaleByMapSize(5, 3), + 0.1, + 5, + 0.5, + 0, + 0), + new TileClassPainter(clRoad), + roadConstraint); + + if (area && area.getPoints().length) + { + areaRoads.push(area); + break; + } } } -} -g_Map.log("Painting roads"); -createArea( - new MapBoundsPlacer(), - [ - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetRoad, 1), - new LayeredPainter([tPathWild, tPath], [1]), - ], - [stayClasses(clRoad, 0), avoidClasses(clPath, 0)]); - -g_Map.log("Marking road palm area"); -const areaRoadPalms = createArea( - new MapBoundsPlacer(), - undefined, - [ - new NearTileClassConstraint(clRoad, 1), - avoidClasses(clRoad, 0, clPath, 1, clWall, 4, clGate, 4) - ]); + g_Map.log("Painting roads"); + createArea( + new MapBoundsPlacer(), + [ + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetRoad, 1), + new LayeredPainter([tPathWild, tPath], [1]), + ], + [stayClasses(clRoad, 0), avoidClasses(clPath, 0)]); -if (areaRoadPalms && areaRoadPalms.getPoints().length) -{ - g_Map.log("Placing road palms"); + g_Map.log("Marking road palm area"); + const areaRoadPalms = createArea( + new MapBoundsPlacer(), + undefined, + [ + new NearTileClassConstraint(clRoad, 1), + avoidClasses(clRoad, 0, clPath, 1, clWall, 4, clGate, 4) + ]); + + if (areaRoadPalms && areaRoadPalms.getPoints().length) + { + g_Map.log("Placing road palms"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oPalmPath, 1, 1, 0, 0)], true, clForest), + 0, + avoidClasses(clForest, 2, clGate, 7), + scaleByMapSize(40, 250), + 20, + [areaRoadPalms]); + + g_Map.log("Placing road bushes"); + createObjectGroupsByAreas( + new SimpleGroup([new RandomObject(aBushesCity, 1, 1, 0, 0)], true, clForest), + 0, + avoidClasses(clForest, 1), + scaleByMapSize(40, 200), + 20, + [areaRoadPalms]); + } + yield 75; + + g_Map.log("Marking city bush area"); + const areaCityBushes = + createArea( + new MapBoundsPlacer(), + undefined, + [ + new NearTileClassConstraint(clPath, 1), + avoidClasses( + clPath, 0, + clRoad, 0, + clPyramid, 20, + clRitualPlace, 8, + clTemple, 3, + clWall, 3, + clTower, 1, + clFortress, 1, + clHouse, 1, + clForge, 1, + clElephantStable, 1, + clStable, 1, + clCivicCenter, 1, + clBarracks, 1, + clBlemmyeCamp, 1, + clNobaCamp, 1, + clMarket, 1) + ]); + + g_Map.log("Marking city palm area"); + const areaCityPalms = + createArea( + new MapBoundsPlacer(), + undefined, + [ + new StayAreasConstraint([areaCityBushes]), + avoidClasses(clElephantStable, 3) + ]); + + g_Map.log("Placing city palms"); createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oPalmPath, 1, 1, 0, 0)], true, clForest), + new SimpleGroup([new SimpleObject(aPalmPath, 1, 1, 0, 0)], true, clForest), 0, - avoidClasses(clForest, 2, clGate, 7), - scaleByMapSize(40, 250), - 20, - [areaRoadPalms]); + avoidClasses(clForest, 3), + scaleByMapSize(40, 400), + 15, + [areaCityPalms]); - g_Map.log("Placing road bushes"); + g_Map.log("Placing city bushes"); createObjectGroupsByAreas( new SimpleGroup([new RandomObject(aBushesCity, 1, 1, 0, 0)], true, clForest), 0, avoidClasses(clForest, 1), - scaleByMapSize(40, 200), - 20, - [areaRoadPalms]); -} -Engine.SetProgress(75); + scaleByMapSize(20, 200), + 15, + [areaCityBushes]); -g_Map.log("Marking city bush area"); -const areaCityBushes = - createArea( - new MapBoundsPlacer(), - undefined, + if (placeNapataWall) + { + g_Map.log("Marking wall palm area"); + const areaWallPalms = createArea( + new MapBoundsPlacer(), + undefined, + new StaticConstraint([ + new NearTileClassConstraint(clWall, 2), + avoidClasses(clPath, 1, clRoad, 1, clWall, 1, clGate, 3, clTemple, 2, clHill, 6) + ])); + + g_Map.log("Placing wall palms"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oPalmPath, 1, 1, 0, 0)], true, clForest), + 0, + avoidClasses(clForest, 2), + scaleByMapSize(40, 250), + 50, + [areaWallPalms]); + } + + createBumps( + new StaticConstraint(avoidClasses(clPlayer, 6, clCity, 0, clWater, 2, clHill, 0, clPath, 0, + clRoad, 0, clTemple, 4, clPyramid, 8, clWall, 0, clGate, 4)), + scaleByMapSize(30, 300), + 1, + 8, + 4, + 0, + 3); + yield 80; + + g_Map.log("Setting up common constraints and areas"); + const nearWater = new NearTileClassConstraint(clWater, 3); + const avoidCollisionsNomad = new AndConstraint( [ - new NearTileClassConstraint(clPath, 1), - avoidClasses( - clPath, 0, - clRoad, 0, - clPyramid, 20, - clRitualPlace, 8, - clTemple, 3, - clWall, 3, - clTower, 1, - clFortress, 1, - clHouse, 1, - clForge, 1, - clElephantStable, 1, - clStable, 1, - clCivicCenter, 1, - clBarracks, 1, - clBlemmyeCamp, 1, - clNobaCamp, 1, - clMarket, 1) + new StaticConstraint(avoidClasses( + clCliff, 0, clHill, 0, clPlayer, 15, clWater, 1, clPath, 2, clRitualPlace, 10, + clTemple, 4, clPyramid, 7, clCity, 4, clWall, 4, clGate, 8)), + avoidClasses(clForest, 1, clRock, 4, clMetal, 4, clFood, 2, clSoldier, 1, clTreasure, 1) ]); -g_Map.log("Marking city palm area"); -const areaCityPalms = - createArea( - new MapBoundsPlacer(), - undefined, + let avoidCollisions = new AndConstraint( [ - new StayAreasConstraint([areaCityBushes]), - avoidClasses(clElephantStable, 3) + avoidCollisionsNomad, + new StaticConstraint(avoidClasses(clRoad, 6, clFood, 6)) ]); -g_Map.log("Placing city palms"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(aPalmPath, 1, 1, 0, 0)], true, clForest), - 0, - avoidClasses(clForest, 3), - scaleByMapSize(40, 400), - 15, - [areaCityPalms]); - -g_Map.log("Placing city bushes"); -createObjectGroupsByAreas( - new SimpleGroup([new RandomObject(aBushesCity, 1, 1, 0, 0)], true, clForest), - 0, - avoidClasses(clForest, 1), - scaleByMapSize(20, 200), - 15, - [areaCityBushes]); - -if (placeNapataWall) -{ - g_Map.log("Marking wall palm area"); - const areaWallPalms = createArea( - new MapBoundsPlacer(), - undefined, - new StaticConstraint([ - new NearTileClassConstraint(clWall, 2), - avoidClasses(clPath, 1, clRoad, 1, clWall, 1, clGate, 3, clTemple, 2, clHill, 6) - ])); + const areaDesert = createArea(new MapBoundsPlacer(), undefined, stayDesert); + const areaFertileLand = createArea(new MapBoundsPlacer(), undefined, stayFertileLand); - g_Map.log("Placing wall palms"); - createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oPalmPath, 1, 1, 0, 0)], true, clForest), - 0, - avoidClasses(clForest, 2), - scaleByMapSize(40, 250), - 50, - [areaWallPalms]); -} + createForests( + [tForestFloorFertile, tForestFloorFertile, tForestFloorFertile, pForestPalms, pForestPalms], + [stayFertileLand, avoidClasses(clForest, 15), + new StaticConstraint([avoidClasses(clWater, 2), avoidCollisions])], + clForest, + scaleByMapSize(250, 2000)); -createBumps( - new StaticConstraint(avoidClasses(clPlayer, 6, clCity, 0, clWater, 2, clHill, 0, clPath, 0, clRoad, 0, clTemple, 4, clPyramid, 8, clWall, 0, clGate, 4)), - scaleByMapSize(30, 300), - 1, - 8, - 4, - 0, - 3); -Engine.SetProgress(80); - -g_Map.log("Setting up common constraints and areas"); -const nearWater = new NearTileClassConstraint(clWater, 3); -const avoidCollisionsNomad = new AndConstraint( - [ + g_Map.log("Creating mines"); + const avoidCollisionsMines = [ + avoidClasses(clRock, 10, clMetal, 10), new StaticConstraint(avoidClasses( - clCliff, 0, clHill, 0, clPlayer, 15, clWater, 1, clPath, 2, clRitualPlace, 10, - clTemple, 4, clPyramid, 7, clCity, 4, clWall, 4, clGate, 8)), - avoidClasses(clForest, 1, clRock, 4, clMetal, 4, clFood, 2, clSoldier, 1, clTreasure, 1) - ]); + clWater, 4, clCliff, 4, clCity, 4, clRitualPlace, 10, clPlayer, 20, clForest, 4, + clPyramid, 6, clTemple, 4, clPath, 4, clRoad, 4, clGate, 8)) + ]; + + const mineObjects = (templateSmall, templateLarge) => ({ + "large": [ + new SimpleObject(templateSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(templateLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4) + ], + "small": [ + new SimpleObject(templateSmall, 3, 4, 1, 3, 0, 2 * Math.PI, 1) + ] + }); -let avoidCollisions = new AndConstraint( - [ - avoidCollisionsNomad, - new StaticConstraint(avoidClasses(clRoad, 6, clFood, 6)) - ]); + const mineObjectsPerBiome = [ + { + "desert": mineObjects(oMetalSmallDesert, oMetalLargeDesert), + "fertileLand": mineObjects(oMetalSmallFertileLand, oMetalLargeFertileLand), + "tileClass": clMetal + }, + { + "desert": mineObjects(oStoneSmallDesert, oStoneLargeDesert), + "fertileLand": mineObjects(oStoneSmallFertileLand, oStoneLargeFertileLand), + "tileClass": clRock + } + ]; -const areaDesert = createArea(new MapBoundsPlacer(), undefined, stayDesert); -const areaFertileLand = createArea(new MapBoundsPlacer(), undefined, stayFertileLand); - -createForests( - [tForestFloorFertile, tForestFloorFertile, tForestFloorFertile, pForestPalms, pForestPalms], - [stayFertileLand, avoidClasses(clForest, 15), new StaticConstraint([avoidClasses(clWater, 2), avoidCollisions])], - clForest, - scaleByMapSize(250, 2000)); - -g_Map.log("Creating mines"); -const avoidCollisionsMines = [ - avoidClasses(clRock, 10, clMetal, 10), - new StaticConstraint(avoidClasses( - clWater, 4, clCliff, 4, clCity, 4, clRitualPlace, 10, clPlayer, 20, clForest, 4, - clPyramid, 6, clTemple, 4, clPath, 4, clRoad, 4, clGate, 8)) -]; - -const mineObjects = (templateSmall, templateLarge) => ({ - "large": [ - new SimpleObject(templateSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), - new SimpleObject(templateLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4) - ], - "small": [ - new SimpleObject(templateSmall, 3, 4, 1, 3, 0, 2 * Math.PI, 1) - ] -}); - -const mineObjectsPerBiome = [ + for (let i = 0; i < scaleByMapSize(6, 22); ++i) { - "desert": mineObjects(oMetalSmallDesert, oMetalLargeDesert), - "fertileLand": mineObjects(oMetalSmallFertileLand, oMetalLargeFertileLand), - "tileClass": clMetal - }, - { - "desert": mineObjects(oStoneSmallDesert, oStoneLargeDesert), - "fertileLand": mineObjects(oStoneSmallFertileLand, oStoneLargeFertileLand), - "tileClass": clRock + const mineObjectsBiome = pickRandom(mineObjectsPerBiome); + for (const i in mineObjectsBiome.desert) + createObjectGroupsByAreas( + new SimpleGroup(mineObjectsBiome.desert[i], true, mineObjectsBiome.tileClass), + 0, + avoidCollisionsMines.concat([avoidClasses(clFertileLand, 12, + mineObjectsBiome.tileClass, 15)]), + 1, + 60, + [areaDesert]); } -]; -for (let i = 0; i < scaleByMapSize(6, 22); ++i) -{ - const mineObjectsBiome = pickRandom(mineObjectsPerBiome); - for (const i in mineObjectsBiome.desert) + for (let i = 0; i < (isNomad() ? scaleByMapSize(6, 16) : scaleByMapSize(0, 8)); ++i) + { + const mineObjectsBiome = pickRandom(mineObjectsPerBiome); createObjectGroupsByAreas( - new SimpleGroup(mineObjectsBiome.desert[i], true, mineObjectsBiome.tileClass), + new SimpleGroup(mineObjectsBiome.fertileLand.small, true, mineObjectsBiome.tileClass), 0, - avoidCollisionsMines.concat([avoidClasses(clFertileLand, 12, mineObjectsBiome.tileClass, 15)]), + avoidCollisionsMines.concat([avoidClasses(clDesert, 5, clMetal, 15, clRock, 15, + mineObjectsBiome.tileClass, 20)]), 1, - 60, - [areaDesert]); -} + 80, + [areaFertileLand]); + } -for (let i = 0; i < (isNomad() ? scaleByMapSize(6, 16) : scaleByMapSize(0, 8)); ++i) -{ - const mineObjectsBiome = pickRandom(mineObjectsPerBiome); + g_Map.log("Placing triggerpoints for attackers"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oTriggerPointAttackerPatrol, 1, 1, 0, 0)], true, + clTriggerPointMap), + 0, + [avoidClasses(clCity, 8, clCliff, 4, clHill, 4, clWater, 0, clWall, 2, clForest, 1, clRock, 4, + clMetal, 4, clTriggerPointMap, 15)], + scaleByMapSize(20, 100), + 30); + + g_Map.log("Creating berries"); createObjectGroupsByAreas( - new SimpleGroup(mineObjectsBiome.fertileLand.small, true, mineObjectsBiome.tileClass), + new SimpleGroup([new SimpleObject(oBerryBushGrapes, 4, 6, 1, 2)], true, clFood), 0, - avoidCollisionsMines.concat([avoidClasses(clDesert, 5, clMetal, 15, clRock, 15, mineObjectsBiome.tileClass, 20)]), - 1, - 80, + avoidCollisions, + scaleByMapSize(3, 15), + 50, [areaFertileLand]); -} -g_Map.log("Placing triggerpoints for attackers"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oTriggerPointAttackerPatrol, 1, 1, 0, 0)], true, clTriggerPointMap), - 0, - [avoidClasses(clCity, 8, clCliff, 4, clHill, 4, clWater, 0, clWall, 2, clForest, 1, clRock, 4, clMetal, 4, clTriggerPointMap, 15)], - scaleByMapSize(20, 100), - 30); - -g_Map.log("Creating berries"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oBerryBushGrapes, 4, 6, 1, 2)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(3, 15), - 50, - [areaFertileLand]); - -g_Map.log("Creating rhinos"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oRhino, 1, 1, 0, 1)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(2, 10), - 50, - [areaDesert]); - -g_Map.log("Creating warthogs"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oWarthog, 1, 1, 0, 1)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(2, 10), - 50, - [areaFertileLand]); - -g_Map.log("Creating giraffes"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oGiraffe, 2, 3, 2, 4), new SimpleObject(oGiraffeInfant, 2, 3, 2, 4)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(2, 10), - 50); - -g_Map.log("Creating gazelles"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oGazelle, 5, 7, 2, 4)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(2, 10), - 50, - [areaDesert]); - -if (!isNomad()) -{ - g_Map.log("Creating lions"); + g_Map.log("Creating rhinos"); createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oLion, 1, 2, 2, 4), new SimpleObject(oLioness, 2, 3, 2, 4)], true, clFood), + new SimpleGroup([new SimpleObject(oRhino, 1, 1, 0, 1)], true, clFood), 0, - [avoidCollisions, avoidClasses(clPlayer, 20)], + avoidCollisions, scaleByMapSize(2, 10), 50, [areaDesert]); -} -g_Map.log("Creating elephants"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oElephant, 2, 3, 2, 4), new SimpleObject(oElephantInfant, 2, 3, 2, 4)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(2, 10), - 50, - [areaDesert]); - -g_Map.log("Creating crocodiles"); -if (!isNomad()) + g_Map.log("Creating warthogs"); createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oCrocodile, 2, 3, 3, 5)], true, clFood), + new SimpleGroup([new SimpleObject(oWarthog, 1, 1, 0, 1)], true, clFood), 0, - [nearWater, avoidCollisions], - scaleByMapSize(1, 6), + avoidCollisions, + scaleByMapSize(2, 10), 50, [areaFertileLand]); -Engine.SetProgress(85); + g_Map.log("Creating giraffes"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oGiraffe, 2, 3, 2, 4), + new SimpleObject(oGiraffeInfant, 2, 3, 2, 4)], true, clFood), + 0, + avoidCollisions, + scaleByMapSize(2, 10), + 50); -g_Map.log("Marking irrigation canal tree area"); -const areaIrrigationCanalTrees = createArea( - new MapBoundsPlacer(), - undefined, - [ - nearWater, - avoidClasses(clPassage, 3), - avoidCollisions - ]); + g_Map.log("Creating gazelles"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oGazelle, 5, 7, 2, 4)], true, clFood), + 0, + avoidCollisions, + scaleByMapSize(2, 10), + 50, + [areaDesert]); -g_Map.log("Creating irrigation canal trees"); -createObjectGroupsByAreas( - new SimpleGroup([new RandomObject(oPalms, 1, 1, 1, 1)], true, clForest), - 0, - avoidClasses(clForest, 1), - scaleByMapSize(100, 600), - 50, - [areaIrrigationCanalTrees]); - -createStragglerTrees( - oPalms, - [stayFertileLand, avoidCollisions], - clForest, - scaleByMapSize(50, 400), - 200); - -createStragglerTrees( - [oAcacia], - [stayDesert, avoidCollisions], - clForest, - scaleByMapSize(50, 400), - 200); - -g_Map.log("Placing archer groups on the hilltop"); -createObjectGroupsByAreas( - new SimpleGroup([new RandomObject([oKushCitizenArcher, oKushChampionArcher], scaleByMapSize(4, 10), scaleByMapSize(6, 20), 1, 4)], true, clSoldier), - 0, - new StaticConstraint([avoidClasses(clCliff, 1), new NearTileClassConstraint(clCliff, 5)]), - scaleByMapSize(1, 5) / 3 * getDifficulty(), - 250, - [areaHilltop]); - -g_Map.log("Placing individual archers on the hill"); -createObjectGroupsByAreas( - new SimpleGroup([new RandomObject([oKushCitizenArcher, oKushChampionArcher], 1, 1, 1, 3)], true, clSoldier), - 0, - new StaticConstraint([ - new HeightConstraint(heightHillArchers, heightHilltop), - avoidClasses(clCliff, 1, clSoldier, 1), - new NearTileClassConstraint(clCliff, 5) - ]), - scaleByMapSize(8, 100) / 3 * getDifficulty(), - 250, - [areaHill]); - -g_Map.log("Placing siege engines on the hilltop"); -createObjectGroupsByAreas( - new SimpleGroup([new RandomObject(oPtolSiege, 1, 1, 1, 3)], true, clSoldier), - 0, - new StaticConstraint([new NearTileClassConstraint(clCliff, 5), avoidClasses(clCliff, 1, clSoldier, 1)]), - scaleByMapSize(1, 6) / 3 * getDifficulty(), - 250, - [areaHilltop]); - -const avoidCollisionsPyramids = new StaticConstraint([avoidCollisions, new NearTileClassConstraint(clPyramid, 10)]); -if (!isNomad()) -{ - g_Map.log("Placing soldiers near pyramids"); + if (!isNomad()) + { + g_Map.log("Creating lions"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oLion, 1, 2, 2, 4), + new SimpleObject(oLioness, 2, 3, 2, 4)], true, clFood), + 0, + [avoidCollisions, avoidClasses(clPlayer, 20)], + scaleByMapSize(2, 10), + 50, + [areaDesert]); + } + + g_Map.log("Creating elephants"); createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oKushCitizenArcher, 1, 1, 1, 1)], true, clSoldier), + new SimpleGroup([new SimpleObject(oElephant, 2, 3, 2, 4), + new SimpleObject(oElephantInfant, 2, 3, 2, 4)], true, clFood), 0, - avoidCollisionsPyramids, - scaleByMapSize(3, 8), + avoidCollisions, + scaleByMapSize(2, 10), + 50, + [areaDesert]); + + g_Map.log("Creating crocodiles"); + if (!isNomad()) + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oCrocodile, 2, 3, 3, 5)], true, clFood), + 0, + [nearWater, avoidCollisions], + scaleByMapSize(1, 6), + 50, + [areaFertileLand]); + + yield 85; + + g_Map.log("Marking irrigation canal tree area"); + const areaIrrigationCanalTrees = createArea( + new MapBoundsPlacer(), + undefined, + [ + nearWater, + avoidClasses(clPassage, 3), + avoidCollisions + ]); + + g_Map.log("Creating irrigation canal trees"); + createObjectGroupsByAreas( + new SimpleGroup([new RandomObject(oPalms, 1, 1, 1, 1)], true, clForest), + 0, + avoidClasses(clForest, 1), + scaleByMapSize(100, 600), + 50, + [areaIrrigationCanalTrees]); + + createStragglerTrees( + oPalms, + [stayFertileLand, avoidCollisions], + clForest, + scaleByMapSize(50, 400), + 200); + + createStragglerTrees( + [oAcacia], + [stayDesert, avoidCollisions], + clForest, + scaleByMapSize(50, 400), + 200); + + g_Map.log("Placing archer groups on the hilltop"); + createObjectGroupsByAreas( + new SimpleGroup([new RandomObject([oKushCitizenArcher, oKushChampionArcher], + scaleByMapSize(4, 10), scaleByMapSize(6, 20), 1, 4)], true, clSoldier), + 0, + new StaticConstraint([avoidClasses(clCliff, 1), new NearTileClassConstraint(clCliff, 5)]), + scaleByMapSize(1, 5) / 3 * getDifficulty(), 250, - [areaPyramids]); + [areaHilltop]); - g_Map.log("Placing treasures at the pyramid"); + g_Map.log("Placing individual archers on the hill"); + createObjectGroupsByAreas( + new SimpleGroup([new RandomObject([oKushCitizenArcher, oKushChampionArcher], 1, 1, 1, 3)], true, + clSoldier), + 0, + new StaticConstraint([ + new HeightConstraint(heightHillArchers, heightHilltop), + avoidClasses(clCliff, 1, clSoldier, 1), + new NearTileClassConstraint(clCliff, 5) + ]), + scaleByMapSize(8, 100) / 3 * getDifficulty(), + 250, + [areaHill]); + + g_Map.log("Placing siege engines on the hilltop"); + createObjectGroupsByAreas( + new SimpleGroup([new RandomObject(oPtolSiege, 1, 1, 1, 3)], true, clSoldier), + 0, + new StaticConstraint([new NearTileClassConstraint(clCliff, 5), + avoidClasses(clCliff, 1, clSoldier, 1)]), + scaleByMapSize(1, 6) / 3 * getDifficulty(), + 250, + [areaHilltop]); + + const avoidCollisionsPyramids = + new StaticConstraint([avoidCollisions, new NearTileClassConstraint(clPyramid, 10)]); + if (!isNomad()) + { + g_Map.log("Placing soldiers near pyramids"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oKushCitizenArcher, 1, 1, 1, 1)], true, clSoldier), + 0, + avoidCollisionsPyramids, + scaleByMapSize(3, 8), + 250, + [areaPyramids]); + + g_Map.log("Placing treasures at the pyramid"); + createObjectGroupsByAreas( + new SimpleGroup([new RandomObject(oTreasuresHill, 1, 1, 2, 2)], true, clTreasure), + 0, + avoidCollisionsPyramids, + scaleByMapSize(1, 10), + 250, + [areaPyramids]); + } + + g_Map.log("Placing treasures on the hilltop"); createObjectGroupsByAreas( new SimpleGroup([new RandomObject(oTreasuresHill, 1, 1, 2, 2)], true, clTreasure), 0, - avoidCollisionsPyramids, + avoidClasses(clCliff, 1, clTreasure, 1), + scaleByMapSize(8, 35), + 250, + [areaHilltop]); + + g_Map.log("Placing treasures in the city"); + const pathBorderConstraint = new AndConstraint([ + new StaticConstraint([new NearTileClassConstraint(clCity, 1)]), + avoidClasses(clTreasure, 2, clStatue, 10, clPathStatues, 4, clWall, 2, clForest, 1) + ]); + createObjectGroupsByAreas( + new SimpleGroup([new RandomObject(oTreasuresCity, 1, 1, 0, 2)], true, clTreasure), + 0, + pathBorderConstraint, + scaleByMapSize(2, 60), + 500, + [areaPaths]); + + g_Map.log("Placing handcarts on the paths"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(aHandcart, 1, 1, 1, 1)], true, clDecorative), + 0, + [pathBorderConstraint, avoidClasses(clDecorative, 10)], + scaleByMapSize(0, 5), + 250, + [areaPaths]); + + g_Map.log("Placing fence in fertile land"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(aPlotFence, 1, 1, 1, 1)], true, clDecorative), + 0, + new StaticConstraint([avoidCollisions, avoidClasses(clWater, 6, clDecorative, 10)]), scaleByMapSize(1, 10), 250, - [areaPyramids]); -} + [areaFertileLand]); + + g_Map.log("Creating fish"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oFish, 3, 4, 2, 3)], true, clFood), + 0, + [new StaticConstraint(stayClasses(clWater, 6)), avoidClasses(clFood, 12)], + scaleByMapSize(20, 120), + 50); + + yield 95; -g_Map.log("Placing treasures on the hilltop"); -createObjectGroupsByAreas( - new SimpleGroup([new RandomObject(oTreasuresHill, 1, 1, 2, 2)], true, clTreasure), - 0, - avoidClasses(clCliff, 1, clTreasure, 1), - scaleByMapSize(8, 35), - 250, - [areaHilltop]); - -g_Map.log("Placing treasures in the city"); -const pathBorderConstraint = new AndConstraint([ - new StaticConstraint([new NearTileClassConstraint(clCity, 1)]), - avoidClasses(clTreasure, 2, clStatue, 10, clPathStatues, 4, clWall, 2, clForest, 1) -]); -createObjectGroupsByAreas( - new SimpleGroup([new RandomObject(oTreasuresCity, 1, 1, 0, 2)], true, clTreasure), - 0, - pathBorderConstraint, - scaleByMapSize(2, 60), - 500, - [areaPaths]); - -g_Map.log("Placing handcarts on the paths"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(aHandcart, 1, 1, 1, 1)], true, clDecorative), - 0, - [pathBorderConstraint, avoidClasses(clDecorative, 10)], - scaleByMapSize(0, 5), - 250, - [areaPaths]); - -g_Map.log("Placing fence in fertile land"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(aPlotFence, 1, 1, 1, 1)], true, clDecorative), - 0, - new StaticConstraint([avoidCollisions, avoidClasses(clWater, 6, clDecorative, 10)]), - scaleByMapSize(1, 10), - 250, - [areaFertileLand]); - -g_Map.log("Creating fish"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oFish, 3, 4, 2, 3)], true, clFood), - 0, - [new StaticConstraint(stayClasses(clWater, 6)), avoidClasses(clFood, 12)], - scaleByMapSize(20, 120), - 50); - -Engine.SetProgress(95); - -avoidCollisions = new StaticConstraint(avoidCollisions); - -createDecoration( - aBushesDesert.map(bush => [new SimpleObject(bush, 0, 3, 2, 4)]), - aBushesDesert.map(bush => scaleByMapSize(20, 120) * randIntInclusive(1, 3)), - [stayDesert, avoidCollisions]); - -createDecoration( - aBushesFertileLand.map(bush => [new SimpleObject(bush, 0, 4, 2, 4)]), - aBushesFertileLand.map(bush => scaleByMapSize(20, 120) * randIntInclusive(1, 3)), - [stayFertileLand, avoidCollisions]); - -createDecoration( - [[new SimpleObject(aRock, 0, 4, 2, 4)]], - [[scaleByMapSize(80, 500)]], - [stayDesert, avoidCollisions]); - -createDecoration( - aBushesFertileLand.map(bush => [new SimpleObject(bush, 0, 3, 2, 4)]), - aBushesFertileLand.map(bush => scaleByMapSize(100, 800)), - [new HeightConstraint(heightWaterLevel, heightShoreline), avoidCollisions]); - -g_Map.log("Creating reeds"); -createObjectGroupsByAreas( - new SimpleGroup([new RandomObject(aWaterDecoratives, 2, 4, 1, 2)], true), - 0, - new StaticConstraint(new NearTileClassConstraint(clFertileLand, 4)), - scaleByMapSize(50, 400), - 20, - [areaWater]); - -g_Map.log("Creating reeds at the irrigation canals"); -for (const area of areasPassages) + avoidCollisions = new StaticConstraint(avoidCollisions); + + createDecoration( + aBushesDesert.map(bush => [new SimpleObject(bush, 0, 3, 2, 4)]), + aBushesDesert.map(bush => scaleByMapSize(20, 120) * randIntInclusive(1, 3)), + [stayDesert, avoidCollisions]); + + createDecoration( + aBushesFertileLand.map(bush => [new SimpleObject(bush, 0, 4, 2, 4)]), + aBushesFertileLand.map(bush => scaleByMapSize(20, 120) * randIntInclusive(1, 3)), + [stayFertileLand, avoidCollisions]); + + createDecoration( + [[new SimpleObject(aRock, 0, 4, 2, 4)]], + [[scaleByMapSize(80, 500)]], + [stayDesert, avoidCollisions]); + + createDecoration( + aBushesFertileLand.map(bush => [new SimpleObject(bush, 0, 3, 2, 4)]), + aBushesFertileLand.map(bush => scaleByMapSize(100, 800)), + [new HeightConstraint(heightWaterLevel, heightShoreline), avoidCollisions]); + + g_Map.log("Creating reeds"); createObjectGroupsByAreas( new SimpleGroup([new RandomObject(aWaterDecoratives, 2, 4, 1, 2)], true), 0, - undefined, - 15, + new StaticConstraint(new NearTileClassConstraint(clFertileLand, 4)), + scaleByMapSize(50, 400), 20, - [area]); + [areaWater]); + + g_Map.log("Creating reeds at the irrigation canals"); + for (const area of areasPassages) + createObjectGroupsByAreas( + new SimpleGroup([new RandomObject(aWaterDecoratives, 2, 4, 1, 2)], true), + 0, + undefined, + 15, + 20, + [area]); -g_Map.log("Creating hawk"); -for (let i = 0; i < scaleByMapSize(0, 2); ++i) - g_Map.placeEntityAnywhere(oHawk, 0, mapCenter, randomAngle()); + g_Map.log("Creating hawk"); + for (let i = 0; i < scaleByMapSize(0, 2); ++i) + g_Map.placeEntityAnywhere(oHawk, 0, mapCenter, randomAngle()); -placePlayersNomad(clPlayer, [avoidClasses(clHill, 15, clSoldier, 20, clCity, 15, clWall, 20), avoidCollisionsNomad]); + placePlayersNomad(clPlayer, [avoidClasses(clHill, 15, clSoldier, 20, clCity, 15, clWall, 20), + avoidCollisionsNomad]); -setWindAngle(-0.43); -setWaterHeight(heightWaterLevel + SEA_LEVEL); -setWaterTint(0.161, 0.286, 0.353); -setWaterColor(0.129, 0.176, 0.259); -setWaterWaviness(8); -setWaterMurkiness(0.87); -setWaterType("lake"); + setWindAngle(-0.43); + setWaterHeight(heightWaterLevel + SEA_LEVEL); + setWaterTint(0.161, 0.286, 0.353); + setWaterColor(0.129, 0.176, 0.259); + setWaterWaviness(8); + setWaterMurkiness(0.87); + setWaterType("lake"); -setAmbientColor(0.58, 0.443, 0.353); + setAmbientColor(0.58, 0.443, 0.353); -setSunColor(0.733, 0.746, 0.574); -setSunRotation(Math.PI / 2 * randFloat(-1, 1)); -setSunElevation(Math.PI / 7); + setSunColor(0.733, 0.746, 0.574); + setSunRotation(Math.PI / 2 * randFloat(-1, 1)); + setSunElevation(Math.PI / 7); -setFogFactor(0); -setFogThickness(0); -setFogColor(0.69, 0.616, 0.541); + setFogFactor(0); + setFogThickness(0); + setFogColor(0.69, 0.616, 0.541); -setPPEffect("hdr"); -setPPContrast(0.67); -setPPSaturation(0.42); -setPPBloom(0.23); + setPPEffect("hdr"); + setPPContrast(0.67); + setPPSaturation(0.42); + setPPBloom(0.23); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/kerala.js =================================================================== --- binaries/data/mods/public/maps/random/kerala.js +++ binaries/data/mods/public/maps/random/kerala.js @@ -1,345 +1,357 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tGrass = ["tropic_grass_c", "tropic_grass_c", "tropic_grass_c", "tropic_grass_c", "tropic_grass_plants", "tropic_plants", "tropic_plants_b"]; -const tGrassA = "tropic_plants_c"; -const tGrassB = "tropic_plants_c"; -const tGrassC = "tropic_grass_c"; -const tForestFloor = "tropic_grass_plants"; -const tCliff = ["tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a_plants"]; -const tPlants = "tropic_plants"; -const tRoad = "tropic_citytile_a"; -const tRoadWild = "tropic_citytile_plants"; -const tShoreBlend = "tropic_beach_dry_plants"; -const tShore = "tropic_beach_dry"; -const tWater = "tropic_beach_wet"; - -const oTree = "gaia/tree/toona"; -const oPalm = "gaia/tree/palm_tropic"; -const oStoneLarge = "gaia/rock/tropical_large"; -const oStoneSmall = "gaia/rock/tropical_small"; -const oMetalLarge = "gaia/ore/tropical_large"; -const oFish = "gaia/fish/generic"; -const oDeer = "gaia/fauna_deer"; -const oSheep = "gaia/fauna_tiger"; -const oBush = "gaia/fruit/berry_01"; - -const aRockLarge = "actor|geology/stone_granite_large.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aBush1 = "actor|props/flora/plant_tropic_a.xml"; -const aBush2 = "actor|props/flora/plant_lg.xml"; -const aBush3 = "actor|props/flora/plant_tropic_large.xml"; - -const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oTree, tForestFloor]; -const pForestP = [tForestFloor + TERRAIN_SEPARATOR + oPalm, tForestFloor]; - -const heightSeaGround = -5; -const heightLand = 3; -const heightHill = 25; - -const g_Map = new RandomMap(heightLand, tGrass); - -const numPlayers = getNumPlayers(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -const waterPosition = fractionToTiles(0.31); -const playerPosition = fractionToTiles(0.55); -const mountainPosition = fractionToTiles(0.69); - -const startAngle = randomAngle(); - -placePlayerBases({ - "PlayerPlacement": [ - sortAllPlayers(), - playerPlacementLine(0, new Vector2D(mapCenter.x, playerPosition), fractionToTiles(0.2)).map(pos => pos.rotateAround(startAngle, mapCenter)) - ], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oTree, - "count": scaleByMapSize(12, 30), - "minDist": 12, - "maxDist": 14, - "minDistGroup": 1, - "maxDistGroup": 3 - } - // No decoratives -}); -Engine.SetProgress(15); - -paintRiver({ - "parallel": true, - "start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(startAngle - Math.PI / 2, mapCenter), - "end": new Vector2D(mapBounds.left, mapBounds.bottom).rotateAround(startAngle - Math.PI / 2, mapCenter), - "width": 2 * waterPosition, - "fadeDist": 8, - "deviation": 0, - "heightRiverbed": heightSeaGround, - "heightLand": heightLand, - "meanderShort": 20, - "meanderLong": 0, - "waterFunc": (position, height, riverFraction) => { - clWater.add(position); - } -}); - -g_Map.log("Marking mountain area"); -const areaMountains = createArea( - new ConvexPolygonPlacer( - [ - new Vector2D(mountainPosition, mapBounds.top), - new Vector2D(mountainPosition, mapBounds.bottom), - new Vector2D(mapBounds.right, mapBounds.top), - new Vector2D(mapBounds.right, mapBounds.bottom) - ].map(pos => pos.rotateAround(startAngle - Math.PI / 2, mapCenter)), - Infinity)); - -g_Map.log("Creating shores"); -for (let i = 0; i < scaleByMapSize(20, 120); ++i) +function* GenerateMap() { - const position = new Vector2D(fractionToTiles(randFloat(0.28, 0.34)), fractionToTiles(randFloat(0.1, 0.9))).rotateAround(startAngle - Math.PI / 2, mapCenter).round(); - createArea( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 30)), Infinity, position), - [ - new LayeredPainter([tGrass, tGrass], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), - new TileClassUnPainter(clWater) - ]); -} - -paintTerrainBasedOnHeight(-6, 1, 1, tWater); -paintTerrainBasedOnHeight(1, 2.8, 1, tShoreBlend); -paintTerrainBasedOnHeight(0, 1, 1, tShore); -paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); - -Engine.SetProgress(45); - -g_Map.log("Creating hills"); -createAreasInAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.1), - [ - new LayeredPainter([tCliff, tGrass], [3]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 3), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 20, clHill, 5, clWater, 2, clBaseResource, 2), - scaleByMapSize(5, 100), - 3, - [areaMountains]); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(1000, 6000, 0.7); -const types = [ - [[tGrass, tGrass, tGrass, tGrass, pForestD], [tGrass, tGrass, tGrass, pForestD]], - [[tGrass, tGrass, tGrass, tGrass, pForestP], [tGrass, tGrass, tGrass, pForestP]] -]; -const forestSize = forestTrees / (scaleByMapSize(3,6) * numPlayers); -const num = Math.floor(forestSize / types.length); -for (const type of types) - createAreas( - new ChainPlacer( - 1, - Math.floor(scaleByMapSize(3, 5)), - forestTrees / (num * Math.floor(scaleByMapSize(2, 4))), - 0.5), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) + const tGrass = ["tropic_grass_c", "tropic_grass_c", "tropic_grass_c", "tropic_grass_c", + "tropic_grass_plants", "tropic_plants", "tropic_plants_b"]; + const tGrassA = "tropic_plants_c"; + const tGrassB = "tropic_plants_c"; + const tGrassC = "tropic_grass_c"; + const tForestFloor = "tropic_grass_plants"; + const tCliff = ["tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a_plants"]; + const tPlants = "tropic_plants"; + const tRoad = "tropic_citytile_a"; + const tRoadWild = "tropic_citytile_plants"; + const tShoreBlend = "tropic_beach_dry_plants"; + const tShore = "tropic_beach_dry"; + const tWater = "tropic_beach_wet"; + + const oTree = "gaia/tree/toona"; + const oPalm = "gaia/tree/palm_tropic"; + const oStoneLarge = "gaia/rock/tropical_large"; + const oStoneSmall = "gaia/rock/tropical_small"; + const oMetalLarge = "gaia/ore/tropical_large"; + const oFish = "gaia/fish/generic"; + const oDeer = "gaia/fauna_deer"; + const oSheep = "gaia/fauna_tiger"; + const oBush = "gaia/fruit/berry_01"; + + const aRockLarge = "actor|geology/stone_granite_large.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aBush1 = "actor|props/flora/plant_tropic_a.xml"; + const aBush2 = "actor|props/flora/plant_lg.xml"; + const aBush3 = "actor|props/flora/plant_tropic_large.xml"; + + const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oTree, tForestFloor]; + const pForestP = [tForestFloor + TERRAIN_SEPARATOR + oPalm, tForestFloor]; + + const heightSeaGround = -5; + const heightLand = 3; + const heightHill = 25; + + global.g_Map = new RandomMap(heightLand, tGrass); + + const numPlayers = getNumPlayers(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + const waterPosition = fractionToTiles(0.31); + const playerPosition = fractionToTiles(0.55); + const mountainPosition = fractionToTiles(0.69); + + const startAngle = randomAngle(); + + placePlayerBases({ + "PlayerPlacement": [ + sortAllPlayers(), + playerPlacementLine(0, new Vector2D(mapCenter.x, playerPosition), fractionToTiles(0.2)) + .map(pos => pos.rotateAround(startAngle, mapCenter)) ], - avoidClasses(clPlayer, 20, clForest, 10, clHill, 0, clWater, 8), - num); + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oTree, + "count": scaleByMapSize(12, 30), + "minDist": 12, + "maxDist": 14, + "minDistGroup": 1, + "maxDistGroup": 3 + } + // No decoratives + }); + yield 15; + + paintRiver({ + "parallel": true, + "start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(startAngle - Math.PI / 2, + mapCenter), + "end": new Vector2D(mapBounds.left, mapBounds.bottom).rotateAround(startAngle - Math.PI / 2, + mapCenter), + "width": 2 * waterPosition, + "fadeDist": 8, + "deviation": 0, + "heightRiverbed": heightSeaGround, + "heightLand": heightLand, + "meanderShort": 20, + "meanderLong": 0, + "waterFunc": (position, height, riverFraction) => { + clWater.add(position); + } + }); + + g_Map.log("Marking mountain area"); + const areaMountains = createArea( + new ConvexPolygonPlacer( + [ + new Vector2D(mountainPosition, mapBounds.top), + new Vector2D(mountainPosition, mapBounds.bottom), + new Vector2D(mapBounds.right, mapBounds.top), + new Vector2D(mapBounds.right, mapBounds.bottom) + ].map(pos => pos.rotateAround(startAngle - Math.PI / 2, mapCenter)), + Infinity)); + + g_Map.log("Creating shores"); + for (let i = 0; i < scaleByMapSize(20, 120); ++i) + { + const position = new Vector2D(fractionToTiles(randFloat(0.28, 0.34)), + fractionToTiles(randFloat(0.1, 0.9))).rotateAround(startAngle - Math.PI / 2, mapCenter) + .round(); + createArea( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 30)), + Infinity, position), + [ + new LayeredPainter([tGrass, tGrass], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), + new TileClassUnPainter(clWater) + ]); + } -Engine.SetProgress(70); + paintTerrainBasedOnHeight(-6, 1, 1, tWater); + paintTerrainBasedOnHeight(1, 2.8, 1, tShoreBlend); + paintTerrainBasedOnHeight(0, 1, 1, tShore); + paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); -g_Map.log("Creating grass patches"); -for (const 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([tGrassC, tGrassA, tGrassB], [2, 1]), - new TileClassPainter(clDirt) - ], - avoidClasses(clWater, 8, clForest, 0, clHill, 0, clPlayer, 12, clDirt, 16), - scaleByMapSize(20, 80)); + yield 45; -for (const size of [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]) - createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), + g_Map.log("Creating hills"); + createAreasInAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.1), [ - new TerrainPainter(tPlants), - new TileClassPainter(clDirt) + new LayeredPainter([tCliff, tGrass], [3]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 3), + new TileClassPainter(clHill) ], - avoidClasses(clWater, 8, clForest, 0, clHill, 0, clPlayer, 12, clDirt, 16), - scaleByMapSize(20, 80)); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aRockMedium, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), - 3*scaleByMapSize(16, 262), 50 -); - -g_Map.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(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), - 3*scaleByMapSize(8, 131), 50 -); - -g_Map.log("Creating small grass tufts"); -group = new SimpleGroup( - [new SimpleObject(aBush1, 1,2, 0,1, -Math.PI / 8, Math.PI / 8)] -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), - 8 * scaleByMapSize(13, 200) -); - -Engine.SetProgress(90); - -g_Map.log("Creating large grass tufts"); -group = new SimpleGroup( - [new SimpleObject(aBush2, 2,4, 0,1.8, -Math.PI / 8, Math.PI / 8), new SimpleObject(aBush1, 3,6, 1.2,2.5, -Math.PI / 8, Math.PI / 8)] -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), - 8 * scaleByMapSize(13, 200) -); - -Engine.SetProgress(95); - -g_Map.log("Creating bushes"); -group = new SimpleGroup( - [new SimpleObject(aBush3, 1,2, 0,2), new SimpleObject(aBush2, 2,4, 0,2)] -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 1, clHill, 1, clPlayer, 1, clDirt, 1), - 8 * scaleByMapSize(13, 200), 50 -); - -Engine.SetProgress(96); - -createStragglerTrees( - [oTree, oPalm], - avoidClasses(clWater, 5, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); - -g_Map.log("Creating deer"); -group = new SimpleGroup( - [new SimpleObject(oDeer, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), - 3 * numPlayers, 50 -); - -Engine.SetProgress(97); - -g_Map.log("Creating berry bush"); -group = new SimpleGroup( - [new SimpleObject(oBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 6, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - randIntInclusive(1, 4) * numPlayers + 2, 50 -); - -g_Map.log("Creating sheep"); -group = new SimpleGroup( - [new SimpleObject(oSheep, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 22, clHill, 1, clFood, 20), - 3 * numPlayers, 50 -); - -g_Map.log("Creating fish"); -group = new SimpleGroup( - [new SimpleObject(oFish, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clFood, 20), stayClasses(clWater, 6)], - 25 * numPlayers, 60 -); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clHill, 2, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); - -setSunColor(0.6, 0.6, 0.6); -setSunElevation(Math.PI / 3); - -setWaterColor(0.524,0.734,0.839); -setWaterTint(0.369,0.765,0.745); -setWaterWaviness(1.0); -setWaterType("ocean"); -setWaterMurkiness(0.35); - -setFogFactor(0.4); -setFogThickness(0.2); - -setPPEffect("hdr"); -setPPContrast(0.7); -setPPSaturation(0.65); -setPPBloom(0.6); - -setSkySet("cirrus"); -g_Map.ExportMap(); + avoidClasses(clPlayer, 20, clHill, 5, clWater, 2, clBaseResource, 2), + scaleByMapSize(5, 100), + 3, + [areaMountains]); + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(1000, 6000, 0.7); + const types = [ + [[tGrass, tGrass, tGrass, tGrass, pForestD], [tGrass, tGrass, tGrass, pForestD]], + [[tGrass, tGrass, tGrass, tGrass, pForestP], [tGrass, tGrass, tGrass, pForestP]] + ]; + const forestSize = forestTrees / (scaleByMapSize(3,6) * numPlayers); + const num = Math.floor(forestSize / types.length); + for (const type of types) + createAreas( + new ChainPlacer( + 1, + Math.floor(scaleByMapSize(3, 5)), + forestTrees / (num * Math.floor(scaleByMapSize(2, 4))), + 0.5), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 20, clForest, 10, clHill, 0, clWater, 8), + num); + + yield 70; + + g_Map.log("Creating grass patches"); + for (const 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([tGrassC, tGrassA, tGrassB], [2, 1]), + new TileClassPainter(clDirt) + ], + avoidClasses(clWater, 8, clForest, 0, clHill, 0, clPlayer, 12, clDirt, 16), + scaleByMapSize(20, 80)); + + for (const 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(tPlants), + new TileClassPainter(clDirt) + ], + avoidClasses(clWater, 8, clForest, 0, clHill, 0, clPlayer, 12, clDirt, 16), + scaleByMapSize(20, 80)); + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aRockMedium, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), + 3*scaleByMapSize(16, 262), 50 + ); + + g_Map.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(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), + 3*scaleByMapSize(8, 131), 50 + ); + + g_Map.log("Creating small grass tufts"); + group = new SimpleGroup( + [new SimpleObject(aBush1, 1,2, 0,1, -Math.PI / 8, Math.PI / 8)] + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), + 8 * scaleByMapSize(13, 200) + ); + + yield 90; + + g_Map.log("Creating large grass tufts"); + group = new SimpleGroup([new SimpleObject(aBush2, 2,4, 0,1.8, -Math.PI / 8, Math.PI / 8), + new SimpleObject(aBush1, 3,6, 1.2,2.5, -Math.PI / 8, Math.PI / 8)] + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), + 8 * scaleByMapSize(13, 200) + ); + + yield 95; + + g_Map.log("Creating bushes"); + group = new SimpleGroup( + [new SimpleObject(aBush3, 1,2, 0,2), new SimpleObject(aBush2, 2,4, 0,2)] + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 1, clHill, 1, clPlayer, 1, clDirt, 1), + 8 * scaleByMapSize(13, 200), 50 + ); + + yield 96; + + createStragglerTrees( + [oTree, oPalm], + avoidClasses(clWater, 5, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + + g_Map.log("Creating deer"); + group = new SimpleGroup( + [new SimpleObject(oDeer, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), + 3 * numPlayers, 50 + ); + + yield 97; + + g_Map.log("Creating berry bush"); + group = new SimpleGroup( + [new SimpleObject(oBush, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 6, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + + g_Map.log("Creating sheep"); + group = new SimpleGroup( + [new SimpleObject(oSheep, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 22, clHill, 1, clFood, 20), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating fish"); + group = new SimpleGroup( + [new SimpleObject(oFish, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clFood, 20), stayClasses(clWater, 6)], + 25 * numPlayers, 60 + ); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clHill, 2, clForest, 1, clMetal, 4, clRock, 4, + clFood, 2)); + + setSunColor(0.6, 0.6, 0.6); + setSunElevation(Math.PI / 3); + + setWaterColor(0.524,0.734,0.839); + setWaterTint(0.369,0.765,0.745); + setWaterWaviness(1.0); + setWaterType("ocean"); + setWaterMurkiness(0.35); + + setFogFactor(0.4); + setFogThickness(0.2); + + setPPEffect("hdr"); + setPPContrast(0.7); + setPPSaturation(0.65); + setPPBloom(0.6); + + setSkySet("cirrus"); + return g_Map; +} Index: binaries/data/mods/public/maps/random/lake.js =================================================================== --- binaries/data/mods/public/maps/random/lake.js +++ binaries/data/mods/public/maps/random/lake.js @@ -2,251 +2,259 @@ Engine.LoadLibrary("rmgen-common"); 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 oMetalSmall = g_Gaia.metalSmall; - -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 = -3; -const heightLand = 3; - -const g_Map = new RandomMap(heightLand, tMainTerrain); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - -g_Map.log("Preventing water in player territory"); -for (let i = 0; i < numPlayers; ++i) - addCivicCenterAreaToClass(playerPosition[i], clPlayer); - -g_Map.log("Creating the lake..."); -createArea( - new ChainPlacer( - 2, - Math.floor(scaleByMapSize(5, 16)), - Math.floor(scaleByMapSize(35, 200)), - Infinity, - mapCenter, - 0, - [Math.floor(fractionToTiles(0.2))]), - [ - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 20)); - -g_Map.log("Creating more shore jaggedness"); -createAreas( - new ChainPlacer(2, Math.floor(scaleByMapSize(4, 6)), 3, Infinity), - [ - new LayeredPainter([tCliff, tHill], [2]), - new TileClassUnPainter(clWater) - ], - borderClasses(clWater, 4, 7), - scaleByMapSize(12, 130) * 2, - 150); - -paintTerrainBasedOnHeight(2.4, 3.4, 3, tMainTerrain); -paintTerrainBasedOnHeight(1, 2.4, 0, tShore); -paintTerrainBasedOnHeight(-8, 1, 2, tWater); -paintTileClassBasedOnHeight(-6, 0, 1, clWater); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - // PlayerTileClass marked above - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oFruitBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oTree1, - "count": 5 - }, - "Decoratives": { - "template": aGrassShort - } -}); -Engine.SetProgress(20); - -createBumps(avoidClasses(clWater, 2, clPlayer, 20)); - -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); - -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); -createDefaultForests( - [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], - avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 2), - clForest, - forestTrees); - -Engine.SetProgress(50); - -g_Map.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); - -g_Map.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); - -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - avoidClasses(clWater, 3, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1) -); - -g_Map.log("Creating stone mines"); -createBalancedStoneMines( - oStoneSmall, - oStoneLarge, - clRock, - avoidClasses(clWater, 3, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1, clMetal, 10) -); - -Engine.SetProgress(65); - -let planetm = 1; - -if (currentBiome() == "generic/india") - 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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13) - ], - 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); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 25 * numPlayers - ], - [avoidClasses(clFood, 20), stayClasses(clWater, 6)], - clFood); - -Engine.SetProgress(85); - -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, clHill, 2, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); - -setWaterWaviness(4.0); -setWaterType("lake"); - -g_Map.ExportMap(); +function* GenerateMap() +{ + 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 oMetalSmall = g_Gaia.metalSmall; + + 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 = -3; + const heightLand = 3; + + global.g_Map = new RandomMap(heightLand, tMainTerrain); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + + g_Map.log("Preventing water in player territory"); + for (let i = 0; i < numPlayers; ++i) + addCivicCenterAreaToClass(playerPosition[i], clPlayer); + + g_Map.log("Creating the lake..."); + createArea( + new ChainPlacer( + 2, + Math.floor(scaleByMapSize(5, 16)), + Math.floor(scaleByMapSize(35, 200)), + Infinity, + mapCenter, + 0, + [Math.floor(fractionToTiles(0.2))]), + [ + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 20)); + + g_Map.log("Creating more shore jaggedness"); + createAreas( + new ChainPlacer(2, Math.floor(scaleByMapSize(4, 6)), 3, Infinity), + [ + new LayeredPainter([tCliff, tHill], [2]), + new TileClassUnPainter(clWater) + ], + borderClasses(clWater, 4, 7), + scaleByMapSize(12, 130) * 2, + 150); + + paintTerrainBasedOnHeight(2.4, 3.4, 3, tMainTerrain); + paintTerrainBasedOnHeight(1, 2.4, 0, tShore); + paintTerrainBasedOnHeight(-8, 1, 2, tWater); + paintTileClassBasedOnHeight(-6, 0, 1, clWater); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + // PlayerTileClass marked above + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oFruitBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oTree1, + "count": 5 + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 20; + + createBumps(avoidClasses(clWater, 2, clPlayer, 20)); + + 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); + + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + createDefaultForests( + [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], + avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 2), + clForest, + forestTrees); + + yield 50; + + g_Map.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); + + g_Map.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); + yield 55; + + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + avoidClasses(clWater, 3, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1) + ); + + g_Map.log("Creating stone mines"); + createBalancedStoneMines( + oStoneSmall, + oStoneLarge, + clRock, + avoidClasses(clWater, 3, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1, clMetal, 10) + ); + + yield 65; + + let planetm = 1; + + if (currentBiome() == "generic/india") + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13) + ], + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); + + yield 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); + + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 25 * numPlayers + ], + [avoidClasses(clFood, 20), stayClasses(clWater, 6)], + clFood); + + yield 85; + + 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, clHill, 2, clForest, 1, clMetal, 4, clRock, 4, + clFood, 2)); + + setWaterWaviness(4.0); + setWaterType("lake"); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/latium.js =================================================================== --- binaries/data/mods/public/maps/random/latium.js +++ binaries/data/mods/public/maps/random/latium.js @@ -1,469 +1,483 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tOceanDepths = "medit_sea_depths"; -const tOceanRockDeep = "medit_sea_coral_deep"; -const tOceanRockShallow = "medit_rocks_wet"; -const tOceanCoral = "medit_sea_coral_plants"; -const tBeachWet = "medit_sand_wet"; -const tBeachDry = "medit_sand"; -const tBeachGrass = "medit_rocks_grass"; -const tBeachCliff = "medit_dirt"; -const tCity = "medit_city_tile"; -const tGrassDry = ["medit_grass_field_brown", "medit_grass_field_dry", "medit_grass_field_b"]; -const tGrass = ["medit_grass_field_dry", "medit_grass_field_brown", "medit_grass_field_b"]; -const tGrassShrubs = ["medit_grass_shrubs", "medit_grass_flowers"]; -const tGrassRock = ["medit_rocks_grass"]; -const tDirt = "medit_dirt"; -const tDirtCliff = "medit_cliff_italia"; -const tGrassCliff = "medit_cliff_italia_grass"; -const tCliff = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"]; -const tForestFloor = "medit_grass_wild"; - -const oBeech = "gaia/tree/euro_beech"; -const oBerryBush = "gaia/fruit/berry_01"; -const oCarob = "gaia/tree/carob"; -const oCypress1 = "gaia/tree/cypress"; -const oCypress2 = "gaia/tree/cypress"; -const oLombardyPoplar = "gaia/tree/poplar_lombardy"; -const oPalm = "gaia/tree/medit_fan_palm"; -const oPine = "gaia/tree/aleppo_pine"; -const oDeer = "gaia/fauna_deer"; -const oFish = "gaia/fish/generic"; -const oSheep = "gaia/fauna_sheep"; -const oStoneLarge = "gaia/rock/mediterranean_large"; -const oStoneSmall = "gaia/rock/mediterranean_small"; -const oMetalLarge = "gaia/ore/mediterranean_large"; - -const aBushMedDry = "actor|props/flora/bush_medit_me_dry.xml"; -const aBushMed = "actor|props/flora/bush_medit_me.xml"; -const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; -const aBushSmallDry = "actor|props/flora/bush_medit_sm_dry.xml"; -const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; -const aGrassDry = "actor|props/flora/grass_soft_dry_large_tall.xml"; -const aRockLarge = "actor|geology/stone_granite_large.xml"; -const aRockMed = "actor|geology/stone_granite_med.xml"; -const aRockSmall = "actor|geology/stone_granite_small.xml"; - -const pPalmForest = [tForestFloor+TERRAIN_SEPARATOR+oPalm, tGrass]; -const pPineForest = [tForestFloor+TERRAIN_SEPARATOR+oPine, tGrass]; -const pPoplarForest = [tForestFloor+TERRAIN_SEPARATOR+oLombardyPoplar, tGrass]; -const pMainForest = [tForestFloor+TERRAIN_SEPARATOR+oCarob, tForestFloor+TERRAIN_SEPARATOR+oBeech, tGrass, tGrass]; - -const heightSeaGround = -16; -const heightLand = 0; -const heightPlayer = 5; -const heightHill = 12; - -const g_Map = new RandomMap(heightLand, tGrass); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clWater = g_Map.createTileClass(); -const clCliff = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clPlayer = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -var WATER_WIDTH = 0.1; -var horizontal = randBool(); - -g_Map.log("Creating players"); -var startAngle = randBool() ? 0 : Math.PI / 2; -var playerPosition = playerPlacementLine(startAngle + Math.PI / 2, mapCenter, fractionToTiles(randFloat(0.42, 0.46))); - -function distanceToPlayers(x, z) +function* GenerateMap() { - let r = Infinity; - for (let i = 0; i < numPlayers; ++i) + const tOceanDepths = "medit_sea_depths"; + const tOceanRockDeep = "medit_sea_coral_deep"; + const tOceanRockShallow = "medit_rocks_wet"; + const tOceanCoral = "medit_sea_coral_plants"; + const tBeachWet = "medit_sand_wet"; + const tBeachDry = "medit_sand"; + const tBeachGrass = "medit_rocks_grass"; + const tBeachCliff = "medit_dirt"; + const tCity = "medit_city_tile"; + const tGrassDry = ["medit_grass_field_brown", "medit_grass_field_dry", "medit_grass_field_b"]; + const tGrass = ["medit_grass_field_dry", "medit_grass_field_brown", "medit_grass_field_b"]; + const tGrassShrubs = ["medit_grass_shrubs", "medit_grass_flowers"]; + const tGrassRock = ["medit_rocks_grass"]; + const tDirt = "medit_dirt"; + const tDirtCliff = "medit_cliff_italia"; + const tGrassCliff = "medit_cliff_italia_grass"; + const tCliff = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"]; + const tForestFloor = "medit_grass_wild"; + + const oBeech = "gaia/tree/euro_beech"; + const oBerryBush = "gaia/fruit/berry_01"; + const oCarob = "gaia/tree/carob"; + const oCypress1 = "gaia/tree/cypress"; + const oCypress2 = "gaia/tree/cypress"; + const oLombardyPoplar = "gaia/tree/poplar_lombardy"; + const oPalm = "gaia/tree/medit_fan_palm"; + const oPine = "gaia/tree/aleppo_pine"; + const oDeer = "gaia/fauna_deer"; + const oFish = "gaia/fish/generic"; + const oSheep = "gaia/fauna_sheep"; + const oStoneLarge = "gaia/rock/mediterranean_large"; + const oStoneSmall = "gaia/rock/mediterranean_small"; + const oMetalLarge = "gaia/ore/mediterranean_large"; + + const aBushMedDry = "actor|props/flora/bush_medit_me_dry.xml"; + const aBushMed = "actor|props/flora/bush_medit_me.xml"; + const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; + const aBushSmallDry = "actor|props/flora/bush_medit_sm_dry.xml"; + const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; + const aGrassDry = "actor|props/flora/grass_soft_dry_large_tall.xml"; + const aRockLarge = "actor|geology/stone_granite_large.xml"; + const aRockMed = "actor|geology/stone_granite_med.xml"; + const aRockSmall = "actor|geology/stone_granite_small.xml"; + + const pPalmForest = [tForestFloor+TERRAIN_SEPARATOR+oPalm, tGrass]; + const pPineForest = [tForestFloor+TERRAIN_SEPARATOR+oPine, tGrass]; + const pPoplarForest = [tForestFloor+TERRAIN_SEPARATOR+oLombardyPoplar, tGrass]; + const pMainForest = [tForestFloor+TERRAIN_SEPARATOR+oCarob, tForestFloor+TERRAIN_SEPARATOR+oBeech, + tGrass, tGrass]; + + const heightSeaGround = -16; + const heightLand = 0; + const heightPlayer = 5; + const heightHill = 12; + + global.g_Map = new RandomMap(heightLand, tGrass); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clWater = g_Map.createTileClass(); + const clCliff = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clPlayer = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + var WATER_WIDTH = 0.1; + var horizontal = randBool(); + + g_Map.log("Creating players"); + var startAngle = randBool() ? 0 : Math.PI / 2; + var playerPosition = playerPlacementLine(startAngle + Math.PI / 2, mapCenter, + fractionToTiles(randFloat(0.42, 0.46))); + + function distanceToPlayers(x, z) { - let dx = x - tilesToFraction(playerPosition[i].x); - let dz = z - tilesToFraction(playerPosition[i].y); - r = Math.min(r, Math.square(dx) + Math.square(dz)); + let r = Infinity; + for (let i = 0; i < numPlayers; ++i) + { + let dx = x - tilesToFraction(playerPosition[i].x); + let dz = z - tilesToFraction(playerPosition[i].y); + r = Math.min(r, Math.square(dx) + Math.square(dz)); + } + return Math.sqrt(r); } - return Math.sqrt(r); -} - -function playerNearness(x, z) -{ - let d = fractionToTiles(distanceToPlayers(x,z)); - - if (d < 13) - return 0; - if (d < 19) - return (d-13)/(19-13); - - return 1; -} + function playerNearness(x, z) + { + let d = fractionToTiles(distanceToPlayers(x,z)); -for (const x of [mapBounds.left, mapBounds.right]) - paintRiver({ - "parallel": true, - "start": new Vector2D(x, mapBounds.top).rotateAround(startAngle, mapCenter), - "end": new Vector2D(x, mapBounds.bottom).rotateAround(startAngle, mapCenter), - "width": 2 * fractionToTiles(WATER_WIDTH), - "fadeDist": 16, - "deviation": 0, - "heightRiverbed": heightSeaGround, - "heightLand": heightLand, - "meanderShort": 0, - "meanderLong": 0, - "waterFunc": (position, height, z) => { - clWater.add(position); - } - }); -Engine.SetProgress(10); + if (d < 13) + return 0; -g_Map.log("Painting elevation"); -var noise0 = new Noise2D(scaleByMapSize(4, 16)); -var noise1 = new Noise2D(scaleByMapSize(8, 32)); -var noise2 = new Noise2D(scaleByMapSize(15, 60)); + if (d < 19) + return (d-13)/(19-13); -var noise2a = new Noise2D(scaleByMapSize(20, 80)); -var noise2b = new Noise2D(scaleByMapSize(35, 140)); + return 1; + } -var noise3 = new Noise2D(scaleByMapSize(4, 16)); -var noise4 = new Noise2D(scaleByMapSize(6, 24)); -var noise5 = new Noise2D(scaleByMapSize(11, 44)); + for (const x of [mapBounds.left, mapBounds.right]) + paintRiver({ + "parallel": true, + "start": new Vector2D(x, mapBounds.top).rotateAround(startAngle, mapCenter), + "end": new Vector2D(x, mapBounds.bottom).rotateAround(startAngle, mapCenter), + "width": 2 * fractionToTiles(WATER_WIDTH), + "fadeDist": 16, + "deviation": 0, + "heightRiverbed": heightSeaGround, + "heightLand": heightLand, + "meanderShort": 0, + "meanderLong": 0, + "waterFunc": (position, height, z) => { + clWater.add(position); + } + }); + yield 10; -for (var ix = 0; ix <= mapSize; ix++) - for (var iz = 0; iz <= mapSize; iz++) - { - const position = new Vector2D(ix, iz); + g_Map.log("Painting elevation"); + var noise0 = new Noise2D(scaleByMapSize(4, 16)); + var noise1 = new Noise2D(scaleByMapSize(8, 32)); + var noise2 = new Noise2D(scaleByMapSize(15, 60)); - var x = ix / (mapSize + 1.0); - var z = iz / (mapSize + 1.0); - var pn = playerNearness(x, z); + var noise2a = new Noise2D(scaleByMapSize(20, 80)); + var noise2b = new Noise2D(scaleByMapSize(35, 140)); - const c = startAngle ? z : x; - const distToWater = clWater.has(position) ? 0 : (0.5 - WATER_WIDTH - Math.abs(c - 0.5)); - let h = distToWater ? heightHill * (1 - Math.abs(c - 0.5) / (0.5 - WATER_WIDTH)) : g_Map.getHeight(position); + var noise3 = new Noise2D(scaleByMapSize(4, 16)); + var noise4 = new Noise2D(scaleByMapSize(6, 24)); + var noise5 = new Noise2D(scaleByMapSize(11, 44)); - // add some base noise - var baseNoise = 16*noise0.get(x,z) + 8*noise1.get(x,z) + 4*noise2.get(x,z) - (16+8+4)/2; - if ( baseNoise < 0 ) + for (var ix = 0; ix <= mapSize; ix++) + for (var iz = 0; iz <= mapSize; iz++) { - baseNoise *= pn; - baseNoise *= Math.max(0.1, distToWater / (0.5 - WATER_WIDTH)); - } - const oldH = h; - h += baseNoise; + const position = new Vector2D(ix, iz); - // add some higher-frequency noise on land - if ( oldH > 0 ) - h += (0.4 * noise2a.get(x,z) + 0.2 * noise2b.get(x,z)) * Math.min(oldH / 10, 1); + var x = ix / (mapSize + 1.0); + var z = iz / (mapSize + 1.0); + var pn = playerNearness(x, z); - // create cliff noise - if ( h > -10 ) - { - let cliffNoise = (noise3.get(x,z) + 0.5*noise4.get(x,z)) / 1.5; - if (h < 1) + const c = startAngle ? z : x; + const distToWater = clWater.has(position) ? 0 : (0.5 - WATER_WIDTH - Math.abs(c - 0.5)); + let h = distToWater ? heightHill * (1 - Math.abs(c - 0.5) / (0.5 - WATER_WIDTH)) : + g_Map.getHeight(position); + + // add some base noise + var baseNoise = 16*noise0.get(x,z) + 8*noise1.get(x,z) + 4*noise2.get(x,z) - (16+8+4)/2; + if ( baseNoise < 0 ) { - var u = 1 - 0.3*((h-1)/-10); - cliffNoise *= u; + baseNoise *= pn; + baseNoise *= Math.max(0.1, distToWater / (0.5 - WATER_WIDTH)); } - cliffNoise += 0.05 * distToWater / (0.5 - WATER_WIDTH); - if (cliffNoise > 0.6) + const oldH = h; + h += baseNoise; + + // add some higher-frequency noise on land + if ( oldH > 0 ) + h += (0.4 * noise2a.get(x,z) + 0.2 * noise2b.get(x,z)) * Math.min(oldH / 10, 1); + + // create cliff noise + if ( h > -10 ) { - var u = 0.8 * (cliffNoise - 0.6); - cliffNoise += u * noise5.get(x,z); - cliffNoise /= (1 + u); + let cliffNoise = (noise3.get(x,z) + 0.5*noise4.get(x,z)) / 1.5; + if (h < 1) + { + var u = 1 - 0.3*((h-1)/-10); + cliffNoise *= u; + } + cliffNoise += 0.05 * distToWater / (0.5 - WATER_WIDTH); + if (cliffNoise > 0.6) + { + var u = 0.8 * (cliffNoise - 0.6); + cliffNoise += u * noise5.get(x,z); + cliffNoise /= (1 + u); + } + cliffNoise -= 0.59; + cliffNoise *= pn; + if (cliffNoise > 0) + h += 19 * Math.min(cliffNoise, 0.045) / 0.045; } - cliffNoise -= 0.59; - cliffNoise *= pn; - if (cliffNoise > 0) - h += 19 * Math.min(cliffNoise, 0.045) / 0.045; + g_Map.setHeight(position, h); } - g_Map.setHeight(position, h); - } -Engine.SetProgress(20); + yield 20; -g_Map.log("Painting terrain"); -var noise6 = new Noise2D(scaleByMapSize(10, 40)); -var noise7 = new Noise2D(scaleByMapSize(20, 80)); -var noise8 = new Noise2D(scaleByMapSize(13, 52)); -var noise9 = new Noise2D(scaleByMapSize(26, 104)); -var noise10 = new Noise2D(scaleByMapSize(50, 200)); + g_Map.log("Painting terrain"); + var noise6 = new Noise2D(scaleByMapSize(10, 40)); + var noise7 = new Noise2D(scaleByMapSize(20, 80)); + var noise8 = new Noise2D(scaleByMapSize(13, 52)); + var noise9 = new Noise2D(scaleByMapSize(26, 104)); + var noise10 = new Noise2D(scaleByMapSize(50, 200)); -for (var ix = 0; ix < mapSize; ix++) - for (var iz = 0; iz < mapSize; iz++) - { - const position = new Vector2D(ix, iz); - var x = ix / (mapSize + 1.0); - var z = iz / (mapSize + 1.0); - var pn = playerNearness(x, z); - - // Compute height difference - let minH = +Infinity; - let maxH = -Infinity; - for (const vertex of g_TileVertices) + for (var ix = 0; ix < mapSize; ix++) + for (var iz = 0; iz < mapSize; iz++) { - const height = g_Map.getHeight(Vector2D.add(position, vertex)); - minH = Math.min(minH, height); - maxH = Math.max(maxH, height); - } - var diffH = maxH - minH; + const position = new Vector2D(ix, iz); + var x = ix / (mapSize + 1.0); + var z = iz / (mapSize + 1.0); + var pn = playerNearness(x, z); + + // Compute height difference + let minH = +Infinity; + let maxH = -Infinity; + for (const vertex of g_TileVertices) + { + const height = g_Map.getHeight(Vector2D.add(position, vertex)); + minH = Math.min(minH, height); + maxH = Math.max(maxH, height); + } + var diffH = maxH - minH; - // figure out if we're at the top of a cliff using min adjacent height - var minAdjHeight = minH; - if (maxH > 15) - { - var maxNx = Math.min(ix + 2, mapSize); - var maxNz = Math.min(iz + 2, mapSize); - for (let nx = Math.max(ix - 1, 0); nx <= maxNx; ++nx) - for (let nz = Math.max(iz - 1, 0); nz <= maxNz; ++nz) - minAdjHeight = Math.min(minAdjHeight, g_Map.getHeight(new Vector2D(nx, nz))); - } + // figure out if we're at the top of a cliff using min adjacent height + var minAdjHeight = minH; + if (maxH > 15) + { + var maxNx = Math.min(ix + 2, mapSize); + var maxNz = Math.min(iz + 2, mapSize); + for (let nx = Math.max(ix - 1, 0); nx <= maxNx; ++nx) + for (let nz = Math.max(iz - 1, 0); nz <= maxNz; ++nz) + minAdjHeight = + Math.min(minAdjHeight, g_Map.getHeight(new Vector2D(nx, nz))); + } - // choose a terrain based on elevation - let t = tGrass; - - // water - if (maxH < -12) - t = tOceanDepths; - else if (maxH < -8.8) - t = tOceanRockDeep; - else if (maxH < -4.7) - t = tOceanCoral; - else if (maxH < -2.8) - t = tOceanRockShallow; - else if (maxH < 0.9 && minH < 0.35) - t = tBeachWet; - else if (maxH < 1.5 && minH < 0.9) - t = tBeachDry; - else if (maxH < 2.3 && minH < 1.3) - t = tBeachGrass; - - if (minH < 0) - clWater.add(position); - - // cliffs - if (diffH > 2.9 && minH > -7) - { - t = tCliff; - clCliff.add(position); - } - else if (diffH > 2.5 && minH > -5 || maxH - minAdjHeight > 2.9 && minH > 0) - { - if (minH < -1) + // choose a terrain based on elevation + let t = tGrass; + + // water + if (maxH < -12) + t = tOceanDepths; + else if (maxH < -8.8) + t = tOceanRockDeep; + else if (maxH < -4.7) + t = tOceanCoral; + else if (maxH < -2.8) + t = tOceanRockShallow; + else if (maxH < 0.9 && minH < 0.35) + t = tBeachWet; + else if (maxH < 1.5 && minH < 0.9) + t = tBeachDry; + else if (maxH < 2.3 && minH < 1.3) + t = tBeachGrass; + + if (minH < 0) + clWater.add(position); + + // cliffs + if (diffH > 2.9 && minH > -7) + { t = tCliff; - else if (minH < 0.5) - t = tBeachCliff; - else - t = [tDirtCliff, tGrassCliff, tGrassCliff, tGrassRock, tCliff]; + clCliff.add(position); + } + else if (diffH > 2.5 && minH > -5 || maxH - minAdjHeight > 2.9 && minH > 0) + { + if (minH < -1) + t = tCliff; + else if (minH < 0.5) + t = tBeachCliff; + else + t = [tDirtCliff, tGrassCliff, tGrassCliff, tGrassRock, tCliff]; + + clCliff.add(position); + } - clCliff.add(position); - } + // Don't place resources onto potentially impassable mountains + if (minH >= 20) + clCliff.add(position); - // Don't place resources onto potentially impassable mountains - if (minH >= 20) - clCliff.add(position); + // forests + if (g_Map.getHeight(position) < 11 && diffH < 2 && minH > 1) + { + var forestNoise = (noise6.get(x,z) + 0.5*noise7.get(x,z)) / 1.5 * pn - 0.59; - // forests - if (g_Map.getHeight(position) < 11 && diffH < 2 && minH > 1) - { - var forestNoise = (noise6.get(x,z) + 0.5*noise7.get(x,z)) / 1.5 * pn - 0.59; + // Thin out trees a bit + if (forestNoise > 0 && randBool()) + { + if (minH < 11 && minH >= 4) + { + const typeNoise = noise10.get(x,z); + + if (typeNoise < 0.43 && forestNoise < 0.05) + t = pPoplarForest; + else if (typeNoise < 0.63) + t = pMainForest; + else + t = pPineForest; + + clForest.add(position); + } + else if (minH < 4) + { + t = pPalmForest; + clForest.add(position); + } + } + } - // Thin out trees a bit - if (forestNoise > 0 && randBool()) + // grass variations + if (t == tGrass) { - if (minH < 11 && minH >= 4) + var grassNoise = (noise8.get(x,z) + 0.6*noise9.get(x,z)) / 1.6; + if (grassNoise < 0.3) + t = (diffH > 1.2) ? tDirtCliff : tDirt; + else if (grassNoise < 0.34) { - const typeNoise = noise10.get(x,z); - - if (typeNoise < 0.43 && forestNoise < 0.05) - t = pPoplarForest; - else if (typeNoise < 0.63) - t = pMainForest; - else - t = pPineForest; - - clForest.add(position); + t = (diffH > 1.2) ? tGrassCliff : tGrassDry; + if (diffH < 0.5 && randBool(0.02)) + g_Map.placeEntityAnywhere(aGrassDry, 0, randomPositionOnTile(position), + randomAngle()); } - else if (minH < 4) + else if (grassNoise > 0.61) { - t = pPalmForest; - clForest.add(position); + t = (diffH > 1.2 ? tGrassRock : tGrassShrubs); } + else if (diffH < 0.5 && randBool(0.02)) + g_Map.placeEntityAnywhere(aGrass, 0, randomPositionOnTile(position), + randomAngle()); } - } - // grass variations - if (t == tGrass) - { - var grassNoise = (noise8.get(x,z) + 0.6*noise9.get(x,z)) / 1.6; - if (grassNoise < 0.3) - t = (diffH > 1.2) ? tDirtCliff : tDirt; - else if (grassNoise < 0.34) - { - t = (diffH > 1.2) ? tGrassCliff : tGrassDry; - if (diffH < 0.5 && randBool(0.02)) - g_Map.placeEntityAnywhere(aGrassDry, 0, randomPositionOnTile(position), randomAngle()); - } - else if (grassNoise > 0.61) - { - t = (diffH > 1.2 ? tGrassRock : tGrassShrubs); - } - else if (diffH < 0.5 && randBool(0.02)) - g_Map.placeEntityAnywhere(aGrass, 0, randomPositionOnTile(position), randomAngle()); + createTerrain(t).place(position); } - createTerrain(t).place(position); - } - -Engine.SetProgress(30); - -placePlayerBases({ - "PlayerPlacement": [primeSortAllPlayers(), playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": avoidClasses(clCliff, 4), - "CityPatch": { - "radius": 11, - "outerTerrain": tGrass, - "innerTerrain": tCity, - "width": 4, - "painters": [ - new SmoothElevationPainter(ELEVATION_SET, heightPlayer, 2) - ] - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush, - "distance": 9 - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oPalm, - "count": 5, - "minDist": 10, - "maxDist": 11 - } - // No decoratives -}); -Engine.SetProgress(40); - -g_Map.log("Creating bushes"); -var group = new SimpleGroup( - [new SimpleObject(aBushSmall, 0,2, 0,2), new SimpleObject(aBushSmallDry, 0,2, 0,2), - new SimpleObject(aBushMed, 0,1, 0,2), new SimpleObject(aBushMedDry, 0,1, 0,2)] -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 4, clCliff, 2), - scaleByMapSize(9, 146), 50 -); -Engine.SetProgress(45); - -g_Map.log("Creating rocks"); -group = new SimpleGroup( - [new SimpleObject(aRockSmall, 0,3, 0,2), new SimpleObject(aRockMed, 0,2, 0,2), - new SimpleObject(aRockLarge, 0,1, 0,2)] -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 2, clCliff, 1), - scaleByMapSize(9, 146), 50 -); -Engine.SetProgress(50); - -g_Map.log("Creating large stone mines"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 1, clForest, 4, clPlayer, 40, clRock, 60, clMetal, 10, clCliff, 3), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone mines"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroups(group, 0, - avoidClasses(clForest, 4, clWater, 1, clPlayer, 40, clRock, 30, clMetal, 10, clCliff, 3), - scaleByMapSize(4,16), 100 -); -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,2)], true, clMetal); -createObjectGroups(group, 0, - avoidClasses(clForest, 4, clWater, 1, clPlayer, 40, clMetal, 50, clCliff, 3), - scaleByMapSize(4,16), 100 -); -Engine.SetProgress(60); - -createStragglerTrees( - [oCarob, oBeech, oLombardyPoplar, oLombardyPoplar, oPine], - avoidClasses(clWater, 5, clCliff, 4, clForest, 2, clPlayer, 15, clMetal, 6, clRock, 6), - clForest, - scaleByMapSize(10, 190)); - -Engine.SetProgress(70); - -g_Map.log("Creating straggler cypresses"); -group = new SimpleGroup( - [new SimpleObject(oCypress2, 1,3, 0,3), new SimpleObject(oCypress1, 0,2, 0,2)], - true -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 5, clCliff, 4, clForest, 2, clPlayer, 15, clMetal, 6, clRock, 6), - scaleByMapSize(5, 75), 50 -); -Engine.SetProgress(80); - -g_Map.log("Creating sheep"); -group = new SimpleGroup([new SimpleObject(oSheep, 2,4, 0,2)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8), - 3 * numPlayers, 50 -); -Engine.SetProgress(85); - -g_Map.log("Creating fish"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oFish, 1, 1, 0, 1)], true, clFood), - 0, - [ - avoidClasses(clFood, 10), - stayClasses(clWater, 4), - new HeightConstraint(-Infinity, heightLand) - ], - scaleByMapSize(8, 32)); - -Engine.SetProgress(90); - -g_Map.log("Creating deer"); -group = new SimpleGroup( - [new SimpleObject(oDeer, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8), - 3 * numPlayers, 50 -); -Engine.SetProgress(95); - -g_Map.log("Creating berry bushes"); -group = new SimpleGroup([new SimpleObject(oBerryBush, 5,7, 0,3)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8), - 1.5 * numPlayers, 100 -); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clCliff, 2, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); - -setSkySet("sunny"); -setWaterColor(0.024,0.262,0.224); -setWaterTint(0.133, 0.325,0.255); -setWaterWaviness(2.5); -setWaterType("ocean"); -setWaterMurkiness(0.8); - -g_Map.ExportMap(); + yield 30; + + placePlayerBases({ + "PlayerPlacement": [primeSortAllPlayers(), playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": avoidClasses(clCliff, 4), + "CityPatch": { + "radius": 11, + "outerTerrain": tGrass, + "innerTerrain": tCity, + "width": 4, + "painters": [ + new SmoothElevationPainter(ELEVATION_SET, heightPlayer, 2) + ] + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush, + "distance": 9 + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oPalm, + "count": 5, + "minDist": 10, + "maxDist": 11 + } + // No decoratives + }); + yield 40; + + g_Map.log("Creating bushes"); + var group = new SimpleGroup( + [new SimpleObject(aBushSmall, 0,2, 0,2), new SimpleObject(aBushSmallDry, 0,2, 0,2), + new SimpleObject(aBushMed, 0,1, 0,2), new SimpleObject(aBushMedDry, 0,1, 0,2)] + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 4, clCliff, 2), + scaleByMapSize(9, 146), 50 + ); + yield 45; + + g_Map.log("Creating rocks"); + group = new SimpleGroup( + [new SimpleObject(aRockSmall, 0,3, 0,2), new SimpleObject(aRockMed, 0,2, 0,2), + new SimpleObject(aRockLarge, 0,1, 0,2)] + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 2, clCliff, 1), + scaleByMapSize(9, 146), 50 + ); + yield 50; + + g_Map.log("Creating large stone mines"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 1, clForest, 4, clPlayer, 40, clRock, 60, clMetal, 10, clCliff, 3), + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating small stone mines"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroups(group, 0, + avoidClasses(clForest, 4, clWater, 1, clPlayer, 40, clRock, 30, clMetal, 10, clCliff, 3), + scaleByMapSize(4,16), 100 + ); + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,2)], true, clMetal); + createObjectGroups(group, 0, + avoidClasses(clForest, 4, clWater, 1, clPlayer, 40, clMetal, 50, clCliff, 3), + scaleByMapSize(4,16), 100 + ); + yield 60; + + createStragglerTrees( + [oCarob, oBeech, oLombardyPoplar, oLombardyPoplar, oPine], + avoidClasses(clWater, 5, clCliff, 4, clForest, 2, clPlayer, 15, clMetal, 6, clRock, 6), + clForest, + scaleByMapSize(10, 190)); + + yield 70; + + g_Map.log("Creating straggler cypresses"); + group = new SimpleGroup( + [new SimpleObject(oCypress2, 1,3, 0,3), new SimpleObject(oCypress1, 0,2, 0,2)], + true + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 5, clCliff, 4, clForest, 2, clPlayer, 15, clMetal, 6, clRock, 6), + scaleByMapSize(5, 75), 50 + ); + yield 80; + + g_Map.log("Creating sheep"); + group = new SimpleGroup([new SimpleObject(oSheep, 2,4, 0,2)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, + 8), + 3 * numPlayers, 50 + ); + yield 85; + + g_Map.log("Creating fish"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oFish, 1, 1, 0, 1)], true, clFood), + 0, + [ + avoidClasses(clFood, 10), + stayClasses(clWater, 4), + new HeightConstraint(-Infinity, heightLand) + ], + scaleByMapSize(8, 32)); + + yield 90; + + g_Map.log("Creating deer"); + group = new SimpleGroup( + [new SimpleObject(oDeer, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, + 8), + 3 * numPlayers, 50 + ); + yield 95; + + g_Map.log("Creating berry bushes"); + group = new SimpleGroup([new SimpleObject(oBerryBush, 5,7, 0,3)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, + 8), + 1.5 * numPlayers, 100 + ); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clCliff, 2, clForest, 1, clMetal, 4, clRock, 4, + clFood, 2)); + + setSkySet("sunny"); + setWaterColor(0.024,0.262,0.224); + setWaterTint(0.133, 0.325,0.255); + setWaterWaviness(2.5); + setWaterType("ocean"); + setWaterMurkiness(0.8); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/lions_den.js =================================================================== --- binaries/data/mods/public/maps/random/lions_den.js +++ binaries/data/mods/public/maps/random/lions_den.js @@ -3,436 +3,437 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setSelectedBiome(); - -const topTerrain = g_Terrains.tier2Terrain; - const heightValley = 0; const heightPath = 10; const heightDen = 15; const heightHill = 50; -const g_Map = new RandomMap(heightHill, topTerrain); +function* GenerateMap() +{ + setSelectedBiome(); -const mapCenter = g_Map.getCenter(); -const numPlayers = getNumPlayers(); -const startAngle = randomAngle(); + const topTerrain = g_Terrains.tier2Terrain; -initTileClasses(["step"]); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land)); + global.g_Map = new RandomMap(heightHill, topTerrain); -Engine.SetProgress(10); + const startAngle = randomAngle(); -createBases( - ...playerPlacementByPattern( - "radial", - fractionToTiles(0.4), - fractionToTiles(randFloat(0.05, 0.1)), - startAngle, - undefined), - true); -Engine.SetProgress(20); + initTileClasses(["step"]); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land)); -createSunkenTerrain(); -Engine.SetProgress(30); + yield 10; -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); + createBases( + ...playerPlacementByPattern( + "radial", + fractionToTiles(0.4), + fractionToTiles(randFloat(0.05, 0.1)), + startAngle, + undefined), + true); + yield 20; -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); + createSunkenTerrain(topTerrain, startAngle); + yield 30; -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": 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"] + } + ]); + yield 40; -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(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"] + } + ])); + yield 60; -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(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"] + } + ])); + yield 75; -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": 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"] + } + ]); + yield 80; -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) + 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"] + } + ]); + yield 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"] + } + ]); + yield 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"] + } ]); + yield 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) + ]); -g_Map.ExportMap(); + return g_Map; +} -function createSunkenTerrain() +function createSunkenTerrain(topTerrain, startAngle) { let base = g_Terrains.mainTerrain; let middle = g_Terrains.dirt; @@ -469,6 +470,7 @@ if (currentBiome() == "generic/autumn") middle = g_Terrains.shore; + const numPlayers = getNumPlayers(); let expSize = diskArea(fractionToTiles(0.14)) / numPlayers; let expDist = 0.1 + numPlayers / 200; let expAngle = 0.75; @@ -489,6 +491,7 @@ } g_Map.log("Creating central valley"); + const mapCenter = g_Map.getCenter(); createArea( new DiskPlacer(fractionToTiles(0.29), mapCenter), [ Index: binaries/data/mods/public/maps/random/lorraine_plain.js =================================================================== --- binaries/data/mods/public/maps/random/lorraine_plain.js +++ binaries/data/mods/public/maps/random/lorraine_plain.js @@ -1,322 +1,329 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tPrimary = "temp_grass_long"; -const tGrass = ["temp_grass", "temp_grass", "temp_grass_d"]; -const tGrassPForest = "temp_plants_bog"; -const tGrassDForest = "temp_plants_bog"; -const tGrassA = "temp_grass_plants"; -const tGrassB = "temp_plants_bog"; -const tGrassC = "temp_mud_a"; -const tRoad = "temp_road"; -const tRoadWild = "temp_road_overgrown"; -const tGrassPatchBlend = "temp_grass_long_b"; -const tGrassPatch = ["temp_grass_d", "temp_grass_clovers"]; -const tShore = "temp_plants_bog"; -const tWater = "temp_mud_a"; - -const oBeech = "gaia/tree/euro_beech"; -const oOak = "gaia/tree/oak"; -const oBerryBush = "gaia/fruit/berry_01"; -const oDeer = "gaia/fauna_deer"; -const oRabbit = "gaia/fauna_rabbit"; -const oStoneLarge = "gaia/rock/temperate_large"; -const oStoneSmall = "gaia/rock/temperate_small"; -const oMetalLarge = "gaia/ore/temperate_large"; - -const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; -const aGrassShort = "actor|props/flora/grass_soft_large.xml"; -const aRockLarge = "actor|geology/stone_granite_med.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; -const aLillies = "actor|props/flora/water_lillies.xml"; -const aBushMedium = "actor|props/flora/bush_medit_me.xml"; -const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; - -const pForestB = [tGrassDForest + TERRAIN_SEPARATOR + oBeech, tGrassDForest]; -const pForestO = [tGrassPForest + TERRAIN_SEPARATOR + oOak, tGrassPForest]; -const pForestR = [tGrassDForest + TERRAIN_SEPARATOR + oBeech, tGrassDForest, tGrassDForest + TERRAIN_SEPARATOR + oOak, tGrassDForest, tGrassDForest, tGrassDForest]; - -const heightSeaGround = -4; -const heightShallows = -2; -const heightLand = 3; -const heightOffsetBump = 2; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clShallow = g_Map.createTileClass(); - -const shallowWidth = scaleByMapSize(8, 12); - -const startAngle = randomAngle(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.5)), - // PlayerTileClass marked below - "BaseResourceClass": clBaseResource, - "Walls": "towers", - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad, - "painters": [ - new TileClassPainter(clPlayer) - ] - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oOak, - "count": 3 - }, - "Decoratives": { - "template": aGrassShort - } -}); -Engine.SetProgress(20); - -const riverPositions = [ - new Vector2D(mapBounds.left + 1, mapCenter.y), - new Vector2D(mapBounds.right - 1, mapCenter.y) -].map(v => v.rotateAround(startAngle, mapCenter)); - -g_Map.log("Creating the main river"); -createArea( - new PathPlacer(riverPositions[0], riverPositions[1], scaleByMapSize(10, 20), 0.5, scaleByMapSize(0.5, 2), 0.1, 0.01), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), - avoidClasses(clPlayer, 4)); -Engine.SetProgress(25); - -g_Map.log("Creating small puddles at the map border to ensure players being separated"); -for (const riverPosition of riverPositions) - createArea( - new ClumpPlacer(diskArea(scaleByMapSize(5, 10)), 0.95, 0.6, Infinity, riverPosition), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 2), - avoidClasses(clPlayer, 8)); -Engine.SetProgress(30); - -g_Map.log("Creating the shallows of the main river"); -for (let i = 0; i <= randIntInclusive(3, scaleByMapSize(4, 6)); ++i) +function* GenerateMap() { - const location = fractionToTiles(randFloat(0.15, 0.85)); - createPassage({ - "start": new Vector2D(location, mapBounds.top).rotateAround(startAngle, mapCenter), - "end": new Vector2D(location, mapBounds.bottom).rotateAround(startAngle, mapCenter), - "startWidth": shallowWidth, - "endWidth": shallowWidth, - "smoothWidth": 2, - "startHeight": heightShallows, - "endHeight": heightShallows, - "constraints": new HeightConstraint(-Infinity, heightShallows), - "tileClass": clShallow + const tPrimary = "temp_grass_long"; + const tGrass = ["temp_grass", "temp_grass", "temp_grass_d"]; + const tGrassPForest = "temp_plants_bog"; + const tGrassDForest = "temp_plants_bog"; + const tGrassA = "temp_grass_plants"; + const tGrassB = "temp_plants_bog"; + const tGrassC = "temp_mud_a"; + const tRoad = "temp_road"; + const tRoadWild = "temp_road_overgrown"; + const tGrassPatchBlend = "temp_grass_long_b"; + const tGrassPatch = ["temp_grass_d", "temp_grass_clovers"]; + const tShore = "temp_plants_bog"; + const tWater = "temp_mud_a"; + + const oBeech = "gaia/tree/euro_beech"; + const oOak = "gaia/tree/oak"; + const oBerryBush = "gaia/fruit/berry_01"; + const oDeer = "gaia/fauna_deer"; + const oRabbit = "gaia/fauna_rabbit"; + const oStoneLarge = "gaia/rock/temperate_large"; + const oStoneSmall = "gaia/rock/temperate_small"; + const oMetalLarge = "gaia/ore/temperate_large"; + + const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; + const aGrassShort = "actor|props/flora/grass_soft_large.xml"; + const aRockLarge = "actor|geology/stone_granite_med.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; + const aLillies = "actor|props/flora/water_lillies.xml"; + const aBushMedium = "actor|props/flora/bush_medit_me.xml"; + const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; + + const pForestB = [tGrassDForest + TERRAIN_SEPARATOR + oBeech, tGrassDForest]; + const pForestO = [tGrassPForest + TERRAIN_SEPARATOR + oOak, tGrassPForest]; + const pForestR = [tGrassDForest + TERRAIN_SEPARATOR + oBeech, tGrassDForest, + tGrassDForest + TERRAIN_SEPARATOR + oOak, tGrassDForest, tGrassDForest, tGrassDForest]; + + const heightSeaGround = -4; + const heightShallows = -2; + const heightLand = 3; + const heightOffsetBump = 2; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clShallow = g_Map.createTileClass(); + + const shallowWidth = scaleByMapSize(8, 12); + + const startAngle = randomAngle(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.5)), + // PlayerTileClass marked below + "BaseResourceClass": clBaseResource, + "Walls": "towers", + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad, + "painters": [ + new TileClassPainter(clPlayer) + ] + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oOak, + "count": 3 + }, + "Decoratives": { + "template": aGrassShort + } }); -} -Engine.SetProgress(35); - -createTributaryRivers( - startAngle, - randIntInclusive(9, scaleByMapSize(13, 21)), - scaleByMapSize(10, 20), - heightSeaGround, - [-6, -1.5], - Math.PI / 5, - clWater, - clShallow, - avoidClasses(clPlayer, 3, clBaseResource, 4)); - -Engine.SetProgress(40); - -paintTerrainBasedOnHeight(-5, 1, 1, tWater); -paintTerrainBasedOnHeight(1, 2, 1, pForestR); -paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); - -Engine.SetProgress(50); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - avoidClasses(clWater, 2, clPlayer, 15), - scaleByMapSize(100, 200) -); -Engine.SetProgress(55); - -const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.7); -createForests( - [tGrass, tGrassDForest, tGrassPForest, pForestB, pForestO], - avoidClasses(clPlayer, 15, clWater, 3, clForest, 16, clHill, 1), - clForest, - forestTrees); -Engine.SetProgress(70); - -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) + yield 20; + + const riverPositions = [ + new Vector2D(mapBounds.left + 1, mapCenter.y), + new Vector2D(mapBounds.right - 1, mapCenter.y) + ].map(v => v.rotateAround(startAngle, mapCenter)); + + g_Map.log("Creating the main river"); + createArea( + new PathPlacer(riverPositions[0], riverPositions[1], scaleByMapSize(10, 20), 0.5, + scaleByMapSize(0.5, 2), 0.1, 0.01), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), + avoidClasses(clPlayer, 4)); + yield 25; + + g_Map.log("Creating small puddles at the map border to ensure players being separated"); + for (const riverPosition of riverPositions) + createArea( + new ClumpPlacer(diskArea(scaleByMapSize(5, 10)), 0.95, 0.6, Infinity, riverPosition), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 2), + avoidClasses(clPlayer, 8)); + yield 30; + + g_Map.log("Creating the shallows of the main river"); + for (let i = 0; i <= randIntInclusive(3, scaleByMapSize(4, 6)); ++i) + { + const location = fractionToTiles(randFloat(0.15, 0.85)); + createPassage({ + "start": new Vector2D(location, mapBounds.top).rotateAround(startAngle, mapCenter), + "end": new Vector2D(location, mapBounds.bottom).rotateAround(startAngle, mapCenter), + "startWidth": shallowWidth, + "endWidth": shallowWidth, + "smoothWidth": 2, + "startHeight": heightShallows, + "endHeight": heightShallows, + "constraints": new HeightConstraint(-Infinity, heightShallows), + "tileClass": clShallow + }); + } + yield 35; + + createTributaryRivers( + startAngle, + randIntInclusive(9, scaleByMapSize(13, 21)), + scaleByMapSize(10, 20), + heightSeaGround, + [-6, -1.5], + Math.PI / 5, + clWater, + clShallow, + avoidClasses(clPlayer, 3, clBaseResource, 4)); + + yield 40; + + paintTerrainBasedOnHeight(-5, 1, 1, tWater); + paintTerrainBasedOnHeight(1, 2, 1, pForestR); + paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); + + yield 50; + + g_Map.log("Creating bumps"); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), - [ - new LayeredPainter([[tGrass,tGrassA], tGrassB, [tGrassB,tGrassC]], [1, 1]), - new TileClassPainter(clDirt) - ], - avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6), - scaleByMapSize(15, 45) + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + avoidClasses(clWater, 2, clPlayer, 15), + scaleByMapSize(100, 200) + ); + yield 55; + + const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.7); + createForests( + [tGrass, tGrassDForest, tGrassPForest, pForestB, pForestO], + avoidClasses(clPlayer, 15, clWater, 3, clForest, 16, clHill, 1), + clForest, + forestTrees); + yield 70; + + g_Map.log("Creating dirt patches"); + for (const 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([[tGrass,tGrassA], tGrassB, [tGrassB,tGrassC]], [1, 1]), + new TileClassPainter(clDirt) + ], + avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6), + scaleByMapSize(15, 45) + ); + + g_Map.log("Creating grass patches"); + for (const size of [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]) + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), + new LayeredPainter([tGrassPatchBlend, tGrassPatch], [1]), + avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6), + scaleByMapSize(15, 45) + ); + yield 80; + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clWater, 0, clForest, 1, clPlayer, 15, clRock, 10, clHill, 1)], + scaleByMapSize(4,16), 100 ); -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]) - createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), - new LayeredPainter([tGrassPatchBlend, tGrassPatch], [1]), - avoidClasses(clWater, 1, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 6), - scaleByMapSize(15, 45) + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clWater, 0, clForest, 1, clPlayer, 15, clRock, 10, clHill, 1)], + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clWater, 0, clForest, 1, clPlayer, 15, clMetal, 10, clRock, 5, clHill, 1)], + scaleByMapSize(4,16), 100 + ); + + yield 86; + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aRockMedium, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), + scaleByMapSize(16, 262), 50 + ); + + g_Map.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(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), + scaleByMapSize(8, 131), 50 + ); + + g_Map.log("Creating deer"); + group = new SimpleGroup( + [new SimpleObject(oDeer, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 15, clHill, 1, clFood, 20), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating rabbits"); + group = new SimpleGroup( + [new SimpleObject(oRabbit, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 15, clHill, 1, clFood, 20), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating berry bush"); + group = new SimpleGroup( + [new SimpleObject(oBerryBush, 5,7, 0,4)], + true, clFood ); -Engine.SetProgress(80); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clWater, 0, clForest, 1, clPlayer, 15, clRock, 10, clHill, 1)], - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clWater, 0, clForest, 1, clPlayer, 15, clRock, 10, clHill, 1)], - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clWater, 0, clForest, 1, clPlayer, 15, clMetal, 10, clRock, 5, clHill, 1)], - scaleByMapSize(4,16), 100 -); - -Engine.SetProgress(86); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aRockMedium, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), - scaleByMapSize(16, 262), 50 -); - -g_Map.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(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), - scaleByMapSize(8, 131), 50 -); - -g_Map.log("Creating deer"); -group = new SimpleGroup( - [new SimpleObject(oDeer, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 15, clHill, 1, clFood, 20), - 3 * numPlayers, 50 -); - -g_Map.log("Creating rabbits"); -group = new SimpleGroup( - [new SimpleObject(oRabbit, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 15, clHill, 1, clFood, 20), - 3 * numPlayers, 50 -); - -g_Map.log("Creating berry bush"); -group = new SimpleGroup( - [new SimpleObject(oBerryBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 15, clHill, 1, clFood, 10), - randIntInclusive(1, 4) * numPlayers + 2, 50 -); - -createStragglerTrees( - [oOak, oBeech], - avoidClasses(clWater, 1, clForest, 7, clHill, 1, clPlayer, 5, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); - -g_Map.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(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), - scaleByMapSize(13, 200) -); - -g_Map.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(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), - scaleByMapSize(13, 200) -); - -g_Map.log("Creating bushes"); -group = new SimpleGroup( - [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 1, clHill, 1, clPlayer, 1, clDirt, 1), - scaleByMapSize(13, 200), 50 -); - -g_Map.log("Creating shallow flora"); -group = new SimpleGroup( - [new SimpleObject(aLillies, 1,2, 0,2), new SimpleObject(aReeds, 2,4, 0,2)] -); -createObjectGroupsDeprecated(group, 0, - stayClasses(clShallow, 1), - 60 * scaleByMapSize(13, 200), 80 -); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setSkySet("cirrus"); -setWaterColor(0.1,0.212,0.422); -setWaterTint(0.3,0.1,0.949); -setWaterWaviness(3.0); -setWaterType("lake"); -setWaterMurkiness(0.80); - -g_Map.ExportMap(); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 15, clHill, 1, clFood, 10), + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + + createStragglerTrees( + [oOak, oBeech], + avoidClasses(clWater, 1, clForest, 7, clHill, 1, clPlayer, 5, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + + g_Map.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(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), + scaleByMapSize(13, 200) + ); + + g_Map.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(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), + scaleByMapSize(13, 200) + ); + + g_Map.log("Creating bushes"); + group = new SimpleGroup( + [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 1, clHill, 1, clPlayer, 1, clDirt, 1), + scaleByMapSize(13, 200), 50 + ); + + g_Map.log("Creating shallow flora"); + group = new SimpleGroup( + [new SimpleObject(aLillies, 1,2, 0,2), new SimpleObject(aReeds, 2,4, 0,2)] + ); + createObjectGroupsDeprecated(group, 0, + stayClasses(clShallow, 1), + 60 * scaleByMapSize(13, 200), 80 + ); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, + clFood, 2)); + + setSkySet("cirrus"); + setWaterColor(0.1,0.212,0.422); + setWaterTint(0.3,0.1,0.949); + setWaterWaviness(3.0); + setWaterType("lake"); + setWaterMurkiness(0.80); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/lower_nubia.js =================================================================== --- binaries/data/mods/public/maps/random/lower_nubia.js +++ binaries/data/mods/public/maps/random/lower_nubia.js @@ -34,386 +34,403 @@ TILE_CENTERED_HEIGHT_MAP = true; -const tSand = "desert_sand_dunes_100"; -const tPlateau = ["savanna_dirt_a", "savanna_dirt_b"]; -const tNilePlants = "desert_plants_a"; -const tCliffUpper = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"]; -const tRoad = "savanna_tile_a"; -const tWater = "desert_sand_wet"; - -const oAcacia = "gaia/tree/acacia"; -const oTreeDead = "gaia/tree/dead"; -const oBushBadlands = "gaia/tree/bush_badlands"; -const oBerryBush = "gaia/fruit/berry_05"; -const oPalms = [ - "gaia/tree/cretan_date_palm_tall", - "gaia/tree/cretan_date_palm_short", - "gaia/tree/palm_tropic", - "gaia/tree/date_palm", - "gaia/tree/senegal_date_palm", - "gaia/tree/medit_fan_palm" -]; -const oStoneLarge = "gaia/rock/savanna_large"; -const oStoneSmall = "gaia/rock/desert_small"; -const oMetalLarge = "gaia/ore/savanna_large"; -const oMetalSmall = "gaia/ore/desert_small"; -const oWoodTreasure = "gaia/treasure/wood"; -const oGazelle = "gaia/fauna_gazelle"; -const oElephant = "gaia/fauna_elephant_african_bush"; -const oElephantInfant = "gaia/fauna_elephant_african_infant"; -const oLion = "gaia/fauna_lion"; -const oLioness = "gaia/fauna_lioness"; -const oHawk = "birds/buzzard"; -const oPyramid = "structures/kush/pyramid_large"; - -const aRock = actorTemplate("geology/stone_savanna_med"); -const aBushes = [ - "props/flora/bush_dry_a", - "props/flora/bush_medit_la_dry", - "props/flora/bush_medit_me_dry", - "props/flora/bush_medit_sm", - "props/flora/bush_medit_sm_dry", - "props/flora/bush_tempe_me_dry", - "props/flora/grass_soft_dry_large_tall", - "props/flora/grass_soft_dry_small_tall" -].map(actorTemplate); - -const heightScale = num => num * g_MapSettings.Size / 320; - -const heightSeaGround = heightScale(-3); -const heightWaterLevel = heightScale(0); -const heightNileForests = heightScale(15); -const heightPlateau2 = heightScale(38); -const minHeight = -3; -const maxHeight = 150; - -const g_Map = new RandomMap(0, tSand); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clWater = g_Map.createTileClass(); -const clCliff = g_Map.createTileClass(); -const clPlayer = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clPyramid = g_Map.createTileClass(); -const clPassage = g_Map.createTileClass(); - -g_Map.log("Loading heightmaps"); -const heightmapLand = convertHeightmap1Dto2D(Engine.LoadHeightmapImage("maps/random/lower_nubia_heightmap.png")); -const heightmapLandThreshold = convertHeightmap1Dto2D(Engine.LoadHeightmapImage("maps/random/lower_nubia_land_threshold.png")); -const heightmapWaterThreshold = convertHeightmap1Dto2D(Engine.LoadHeightmapImage("maps/random/lower_nubia_water_threshold.png")); -Engine.SetProgress(3); - -g_Map.log("Composing heightmap"); -let heightmapCombined = []; -for (let x = 0; x < heightmapLand.length; ++x) +function* GenerateMap() { - heightmapCombined[x] = new Float32Array(heightmapLand.length); - for (let y = 0; y < heightmapLand.length; ++y) - // Reduce ahistorical Lake Nasser and lakes in the valleys west of the Nile. - // The heightmap does not correlate with water distribution in this arid climate at all. - heightmapCombined[x][y] = heightmapLandThreshold[x][y] || heightmapWaterThreshold[x][y] ? heightmapLand[x][y] : minHeight; -} -Engine.SetProgress(6); - -g_Map.log("Applying heightmap"); -createArea( - new MapBoundsPlacer(), - new HeightmapPainter(heightmapCombined, minHeight, maxHeight)); -Engine.SetProgress(9); - -g_Map.log("Lowering sea ground"); -createArea( - new MapBoundsPlacer(), - [ - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 3), - new TileClassPainter(clWater) - ], - new HeightConstraint(-Infinity, heightSeaGround)); -Engine.SetProgress(15); - -g_Map.log("Creating Nile passages"); -const riverAngle = Math.PI * 3 / 4; -for (let i = 0; i < scaleByMapSize(8, 15); ++i) -{ - const x = fractionToTiles(randFloat(0, 1)); + const tSand = "desert_sand_dunes_100"; + const tPlateau = ["savanna_dirt_a", "savanna_dirt_b"]; + const tNilePlants = "desert_plants_a"; + const tCliffUpper = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"]; + const tRoad = "savanna_tile_a"; + const tWater = "desert_sand_wet"; + + const oAcacia = "gaia/tree/acacia"; + const oTreeDead = "gaia/tree/dead"; + const oBushBadlands = "gaia/tree/bush_badlands"; + const oBerryBush = "gaia/fruit/berry_05"; + const oPalms = [ + "gaia/tree/cretan_date_palm_tall", + "gaia/tree/cretan_date_palm_short", + "gaia/tree/palm_tropic", + "gaia/tree/date_palm", + "gaia/tree/senegal_date_palm", + "gaia/tree/medit_fan_palm" + ]; + const oStoneLarge = "gaia/rock/savanna_large"; + const oStoneSmall = "gaia/rock/desert_small"; + const oMetalLarge = "gaia/ore/savanna_large"; + const oMetalSmall = "gaia/ore/desert_small"; + const oWoodTreasure = "gaia/treasure/wood"; + const oGazelle = "gaia/fauna_gazelle"; + const oElephant = "gaia/fauna_elephant_african_bush"; + const oElephantInfant = "gaia/fauna_elephant_african_infant"; + const oLion = "gaia/fauna_lion"; + const oLioness = "gaia/fauna_lioness"; + const oHawk = "birds/buzzard"; + const oPyramid = "structures/kush/pyramid_large"; + + const aRock = actorTemplate("geology/stone_savanna_med"); + const aBushes = [ + "props/flora/bush_dry_a", + "props/flora/bush_medit_la_dry", + "props/flora/bush_medit_me_dry", + "props/flora/bush_medit_sm", + "props/flora/bush_medit_sm_dry", + "props/flora/bush_tempe_me_dry", + "props/flora/grass_soft_dry_large_tall", + "props/flora/grass_soft_dry_small_tall" + ].map(actorTemplate); + + const heightScale = num => num * g_MapSettings.Size / 320; + + const heightSeaGround = heightScale(-3); + const heightWaterLevel = heightScale(0); + const heightNileForests = heightScale(15); + const heightPlateau2 = heightScale(38); + const minHeight = -3; + const maxHeight = 150; + + global.g_Map = new RandomMap(0, tSand); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clWater = g_Map.createTileClass(); + const clCliff = g_Map.createTileClass(); + const clPlayer = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clPyramid = g_Map.createTileClass(); + const clPassage = g_Map.createTileClass(); + + g_Map.log("Loading heightmaps"); + const heightmapLand = convertHeightmap1Dto2D(Engine.LoadHeightmapImage( + "maps/random/lower_nubia_heightmap.png")); + const heightmapLandThreshold = convertHeightmap1Dto2D(Engine.LoadHeightmapImage( + "maps/random/lower_nubia_land_threshold.png")); + const heightmapWaterThreshold = convertHeightmap1Dto2D(Engine.LoadHeightmapImage( + "maps/random/lower_nubia_water_threshold.png")); + yield 3; + + g_Map.log("Composing heightmap"); + let heightmapCombined = []; + for (let x = 0; x < heightmapLand.length; ++x) + { + heightmapCombined[x] = new Float32Array(heightmapLand.length); + for (let y = 0; y < heightmapLand.length; ++y) + // Reduce ahistorical Lake Nasser and lakes in the valleys west of the Nile. + // The heightmap does not correlate with water distribution in this arid climate at all. + heightmapCombined[x][y] = heightmapLandThreshold[x][y] || heightmapWaterThreshold[x][y] ? + heightmapLand[x][y] : minHeight; + } + yield 6; + + g_Map.log("Applying heightmap"); createArea( - new PathPlacer( - new Vector2D(x, mapBounds.bottom).rotateAround(riverAngle, mapCenter), - new Vector2D(x, mapBounds.top).rotateAround(riverAngle, mapCenter), - scaleByMapSize(5, 7), - 0.2, - 5, - 0.2, - 0, - Infinity), + new MapBoundsPlacer(), + new HeightmapPainter(heightmapCombined, minHeight, maxHeight)); + yield 9; + + g_Map.log("Lowering sea ground"); + createArea( + new MapBoundsPlacer(), [ - new ElevationBlendingPainter(heightNileForests, 0.5), - new SmoothingPainter(2, 1, 2), - new TileClassPainter(clPassage) + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 3), + new TileClassPainter(clWater) ], + new HeightConstraint(-Infinity, heightSeaGround)); + yield 15; + + g_Map.log("Creating Nile passages"); + const riverAngle = Math.PI * 3 / 4; + for (let i = 0; i < scaleByMapSize(8, 15); ++i) + { + const x = fractionToTiles(randFloat(0, 1)); + createArea( + new PathPlacer( + new Vector2D(x, mapBounds.bottom).rotateAround(riverAngle, mapCenter), + new Vector2D(x, mapBounds.top).rotateAround(riverAngle, mapCenter), + scaleByMapSize(5, 7), + 0.2, + 5, + 0.2, + 0, + Infinity), + [ + new ElevationBlendingPainter(heightNileForests, 0.5), + new SmoothingPainter(2, 1, 2), + new TileClassPainter(clPassage) + ], + [ + new NearTileClassConstraint(clWater, 4), + avoidClasses(clPassage, scaleByMapSize(15, 25)) + ]); + } + yield 18; + + g_Map.log("Smoothing heightmap"); + createArea( + new MapBoundsPlacer(), + new SmoothingPainter(1, scaleByMapSize(0.5, 1), 1)); + yield 22; + + g_Map.log("Marking water"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(clWater), + new HeightConstraint(-Infinity, heightSeaGround)); + yield 28; + + g_Map.log("Marking cliffs"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(clCliff), + new SlopeConstraint(2, Infinity)); + yield 32; + + g_Map.log("Painting water and shoreline"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(tWater), + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 35; + + g_Map.log("Painting plateau"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(tPlateau), + new HeightConstraint(heightPlateau2, Infinity)); + yield 38; + + let playerIDs = []; + let playerPosition = []; + if (!isNomad()) + { + g_Map.log("Finding player locations"); + [playerIDs, playerPosition] = playerPlacementRandom(sortAllPlayers(), + avoidClasses(clWater, scaleByMapSize(8, 12), clCliff, scaleByMapSize(8, 12))); + + g_Map.log("Flatten the initial CC area"); + for (const position of playerPosition) + createArea( + new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, + position), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); + } + yield 43; + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": avoidClasses(clCliff, 0, clWater, 0), + "CityPatch": { + "outerTerrain": tRoad, + "innerTerrain": tRoad + }, + "StartingAnimal": { + "template": oGazelle, + "distance": 18, + "minGroupDistance": 2, + "maxGroupDistance": 4, + "minGroupCount": 2, + "maxGroupCount": 3 + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oAcacia, + "count": scaleByMapSize(3, 12), + "minDistGroup": 2, + "maxDistGroup": 6, + "minDist": 15, + "maxDist": 16 + }, + "Treasures": { + "types": [ + { + "template": oWoodTreasure, + "count": 14 + } + ] + }, + "Decoratives": { + "template": pickRandom(aBushes) + } + }); + yield 50; + + g_Map.log("Painting lower cliffs"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(tNilePlants), [ - new NearTileClassConstraint(clWater, 4), - avoidClasses(clPassage, scaleByMapSize(15, 25)) + new SlopeConstraint(2, Infinity), + new NearTileClassConstraint(clWater, 2) ]); -} -Engine.SetProgress(18); - -g_Map.log("Smoothing heightmap"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, scaleByMapSize(0.5, 1), 1)); -Engine.SetProgress(22); - -g_Map.log("Marking water"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(clWater), - new HeightConstraint(-Infinity, heightSeaGround)); -Engine.SetProgress(28); - -g_Map.log("Marking cliffs"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(clCliff), - new SlopeConstraint(2, Infinity)); -Engine.SetProgress(32); - -g_Map.log("Painting water and shoreline"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(tWater), - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(35); - -g_Map.log("Painting plateau"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(tPlateau), - new HeightConstraint(heightPlateau2, Infinity)); -Engine.SetProgress(38); - -let playerIDs = []; -let playerPosition = []; -if (!isNomad()) -{ - g_Map.log("Finding player locations"); - [playerIDs, playerPosition] = playerPlacementRandom(sortAllPlayers(), avoidClasses(clWater, scaleByMapSize(8, 12), clCliff, scaleByMapSize(8, 12))); + yield 55; - g_Map.log("Flatten the initial CC area"); - for (const position of playerPosition) - createArea( - new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, position), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); -} -Engine.SetProgress(43); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": avoidClasses(clCliff, 0, clWater, 0), - "CityPatch": { - "outerTerrain": tRoad, - "innerTerrain": tRoad - }, - "StartingAnimal": { - "template": oGazelle, - "distance": 18, - "minGroupDistance": 2, - "maxGroupDistance": 4, - "minGroupCount": 2, - "maxGroupCount": 3 - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oAcacia, - "count": scaleByMapSize(3, 12), - "minDistGroup": 2, - "maxDistGroup": 6, - "minDist": 15, - "maxDist": 16 - }, - "Treasures": { - "types": [ - { - "template": oWoodTreasure, - "count": 14 - } - ] - }, - "Decoratives": { - "template": pickRandom(aBushes) - } -}); -Engine.SetProgress(50); - -g_Map.log("Painting lower cliffs"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(tNilePlants), - [ - new SlopeConstraint(2, Infinity), - new NearTileClassConstraint(clWater, 2) - ]); -Engine.SetProgress(55); - -g_Map.log("Painting upper cliffs"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(tCliffUpper), - [ - avoidClasses(clWater, 2), - new SlopeConstraint(2, Infinity) - ]); -Engine.SetProgress(60); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 3, 6, 1, 3, 0, 2 * Math.PI, 1)] - ], - avoidClasses(clWater, 4, clCliff, 4, clPlayer, 20, clRock, 10), - clRock, - scaleByMapSize(10, 30)); -Engine.SetProgress(63); - -g_Map.log("Creating metal mines"); -createMines( - [ - [new SimpleObject(oMetalSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oMetalLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oMetalSmall, 3, 6, 1, 3, 0, 2 * Math.PI, 1)] - ], - avoidClasses(clWater, 4, clCliff, 4, clPlayer, 20, clMetal, 10, clRock, 5), - clMetal, - scaleByMapSize(10, 30)); -Engine.SetProgress(67); - -g_Map.log("Creating pyramid"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oPyramid, 1, 1, 1, 1)], true, clPyramid), - 0, - [new NearTileClassConstraint(clWater, 10), avoidClasses(clWater, 6, clCliff, 6, clPlayer, 40, clMetal, 6, clRock, 6)], - 1, - 500); -Engine.SetProgress(70); - -g_Map.log("Creating trees near the Nile"); -createObjectGroups( - new SimpleGroup([new RandomObject(oPalms, 1, 2, 1, 1)], true, clForest), - 0, - [ - new NearTileClassConstraint(clWater, scaleByMapSize(1, 8)), - new HeightConstraint(heightNileForests, Infinity), - avoidClasses(clWater, 0, clCliff, 0, clForest, 1, clPlayer, 12, clBaseResource, 5, clMetal, 4, clRock, 4, clPyramid, 6) - ], - scaleByMapSize(100, 1000), - 200); -Engine.SetProgress(73); - -const avoidCollisions = avoidClasses(clPlayer, 12, clBaseResource, 5, clWater, 1, clForest, 1, clRock, 4, clMetal, 4, clFood, 6, clCliff, 0, clPyramid, 6); - -g_Map.log("Creating straggler trees and bushes"); -const stragglerTreeObjects = [ - [new SimpleObject(oAcacia, 1, 1, 0, 0), new SimpleObject(oBushBadlands, 0, 1, 2, 2)], - [new SimpleObject(oTreeDead, 1, 1, 0, 0), new SimpleObject(oBushBadlands, 0, 1, 2, 2)] -]; -for (const objects of stragglerTreeObjects) + g_Map.log("Painting upper cliffs"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(tCliffUpper), + [ + avoidClasses(clWater, 2), + new SlopeConstraint(2, Infinity) + ]); + yield 60; + + g_Map.log("Creating stone mines"); + createMines( + [ + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oStoneSmall, 3, 6, 1, 3, 0, 2 * Math.PI, 1)] + ], + avoidClasses(clWater, 4, clCliff, 4, clPlayer, 20, clRock, 10), + clRock, + scaleByMapSize(10, 30)); + yield 63; + + g_Map.log("Creating metal mines"); + createMines( + [ + [new SimpleObject(oMetalSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oMetalLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oMetalSmall, 3, 6, 1, 3, 0, 2 * Math.PI, 1)] + ], + avoidClasses(clWater, 4, clCliff, 4, clPlayer, 20, clMetal, 10, clRock, 5), + clMetal, + scaleByMapSize(10, 30)); + yield 67; + + g_Map.log("Creating pyramid"); createObjectGroups( - new SimpleGroup(objects, true, clForest), + new SimpleGroup([new SimpleObject(oPyramid, 1, 1, 1, 1)], true, clPyramid), 0, - [avoidCollisions, avoidClasses(clWater, 10, clForest, 4)], - scaleByMapSize(10, 180), - 10); -Engine.SetProgress(77); - -g_Map.log("Creating gazelles"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oGazelle, 5, 7, 2, 4)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(2, 10), - 50); -Engine.SetProgress(80); - -if (!isNomad()) -{ - g_Map.log("Creating lions"); + [new NearTileClassConstraint(clWater, 10), avoidClasses(clWater, 6, clCliff, 6, clPlayer, 40, + clMetal, 6, clRock, 6)], + 1, + 500); + yield 70; + + g_Map.log("Creating trees near the Nile"); + createObjectGroups( + new SimpleGroup([new RandomObject(oPalms, 1, 2, 1, 1)], true, clForest), + 0, + [ + new NearTileClassConstraint(clWater, scaleByMapSize(1, 8)), + new HeightConstraint(heightNileForests, Infinity), + avoidClasses(clWater, 0, clCliff, 0, clForest, 1, clPlayer, 12, clBaseResource, 5, + clMetal, 4, clRock, 4, clPyramid, 6) + ], + scaleByMapSize(100, 1000), + 200); + yield 73; + + const avoidCollisions = avoidClasses(clPlayer, 12, clBaseResource, 5, clWater, 1, clForest, 1, clRock, + 4, clMetal, 4, clFood, 6, clCliff, 0, clPyramid, 6); + + g_Map.log("Creating straggler trees and bushes"); + const stragglerTreeObjects = [ + [new SimpleObject(oAcacia, 1, 1, 0, 0), new SimpleObject(oBushBadlands, 0, 1, 2, 2)], + [new SimpleObject(oTreeDead, 1, 1, 0, 0), new SimpleObject(oBushBadlands, 0, 1, 2, 2)] + ]; + for (const objects of stragglerTreeObjects) + createObjectGroups( + new SimpleGroup(objects, true, clForest), + 0, + [avoidCollisions, avoidClasses(clWater, 10, clForest, 4)], + scaleByMapSize(10, 180), + 10); + yield 77; + + g_Map.log("Creating gazelles"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oGazelle, 5, 7, 2, 4)], true, clFood), + 0, + avoidCollisions, + scaleByMapSize(2, 10), + 50); + yield 80; + + if (!isNomad()) + { + g_Map.log("Creating lions"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oLion, 1, 2, 2, 4), + new SimpleObject(oLioness, 2, 3, 2, 4)], true, clFood), + 0, + avoidCollisions, + scaleByMapSize(2, 10), + 50); + } + yield 83; + + g_Map.log("Creating elephants"); createObjectGroups( - new SimpleGroup([new SimpleObject(oLion, 1, 2, 2, 4), new SimpleObject(oLioness, 2, 3, 2, 4)], true, clFood), + new SimpleGroup([new SimpleObject(oElephant, 2, 3, 2, 4), + new SimpleObject(oElephantInfant, 2, 3, 2, 4)], true, clFood), 0, avoidCollisions, scaleByMapSize(2, 10), 50); + yield 86; + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 2, clRock, 4, clMetal, 4, clFood, 2, + clCliff, 2, clPyramid, 6)); + yield 90; + + g_Map.log("Creating hawk"); + for (let i = 0; i < scaleByMapSize(0, 2); ++i) + g_Map.placeEntityAnywhere(oHawk, 0, mapCenter, randomAngle()); + yield 91; + + createDecoration( + aBushes.map(bush => [new SimpleObject(bush, 0, 3, 2, 4)]), + aBushes.map(bush => scaleByMapSize(100, 800) * randIntInclusive(1, 3)), + [ + new NearTileClassConstraint(clWater, 2), + new HeightConstraint(heightWaterLevel, Infinity), + avoidClasses(clForest, 0) + ]); + yield 92; + + createDecoration( + [[new SimpleObject(aRock, 0, 4, 2, 4)]], + [[scaleByMapSize(100, 600)]], + avoidClasses(clWater, 0)); + yield 95; + + setWindAngle(-0.43); + setWaterTint(0.161, 0.286, 0.353); + setWaterColor(0.129, 0.176, 0.259); + setWaterWaviness(8); + setWaterMurkiness(0.87); + setWaterType("lake"); + + setAmbientColor(0.58, 0.443, 0.353); + + setSunColor(0.733, 0.746, 0.574); + setSunRotation(Math.PI * 1.1); + setSunElevation(Math.PI / 7); + + setFogFactor(0); + setFogThickness(0); + setFogColor(0.69, 0.616, 0.541); + + setPPEffect("hdr"); + setPPContrast(0.67); + setPPSaturation(0.42); + setPPBloom(0.23); + + return g_Map; } -Engine.SetProgress(83); - -g_Map.log("Creating elephants"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oElephant, 2, 3, 2, 4), new SimpleObject(oElephantInfant, 2, 3, 2, 4)], true, clFood), - 0, - avoidCollisions, - scaleByMapSize(2, 10), - 50); -Engine.SetProgress(86); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 2, clRock, 4, clMetal, 4, clFood, 2, clCliff, 2, clPyramid, 6)); -Engine.SetProgress(90); - -g_Map.log("Creating hawk"); -for (let i = 0; i < scaleByMapSize(0, 2); ++i) - g_Map.placeEntityAnywhere(oHawk, 0, mapCenter, randomAngle()); -Engine.SetProgress(91); - -createDecoration( - aBushes.map(bush => [new SimpleObject(bush, 0, 3, 2, 4)]), - aBushes.map(bush => scaleByMapSize(100, 800) * randIntInclusive(1, 3)), - [ - new NearTileClassConstraint(clWater, 2), - new HeightConstraint(heightWaterLevel, Infinity), - avoidClasses(clForest, 0) - ]); -Engine.SetProgress(92); - -createDecoration( - [[new SimpleObject(aRock, 0, 4, 2, 4)]], - [[scaleByMapSize(100, 600)]], - avoidClasses(clWater, 0)); -Engine.SetProgress(95); - -setWindAngle(-0.43); -setWaterTint(0.161, 0.286, 0.353); -setWaterColor(0.129, 0.176, 0.259); -setWaterWaviness(8); -setWaterMurkiness(0.87); -setWaterType("lake"); - -setAmbientColor(0.58, 0.443, 0.353); - -setSunColor(0.733, 0.746, 0.574); -setSunRotation(Math.PI * 1.1); -setSunElevation(Math.PI / 7); - -setFogFactor(0); -setFogThickness(0); -setFogColor(0.69, 0.616, 0.541); - -setPPEffect("hdr"); -setPPContrast(0.67); -setPPSaturation(0.42); -setPPBloom(0.23); - -g_Map.ExportMap(); Index: binaries/data/mods/public/maps/random/mainland.js =================================================================== --- binaries/data/mods/public/maps/random/mainland.js +++ binaries/data/mods/public/maps/random/mainland.js @@ -2,193 +2,197 @@ Engine.LoadLibrary("rmgen-common"); 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 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 oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; -const oStoneLarge = g_Gaia.stoneLarge; -const oStoneSmall = g_Gaia.stoneSmall; -const oMetalLarge = g_Gaia.metalLarge; -const oMetalSmall = g_Gaia.metalSmall; - -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 heightLand = 3; - -const g_Map = new RandomMap(heightLand, tMainTerrain); - -const numPlayers = getNumPlayers(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oFruitBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oTree1, - "count": 5 - } - // No decoratives -}); -Engine.SetProgress(20); - -createBumps(avoidClasses(clPlayer, 20)); - -if (randBool()) - createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 20, clHill, 15), clHill, scaleByMapSize(3, 15)); -else - createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 15), clHill, scaleByMapSize(3, 15)); - -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); -createDefaultForests( - [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], - avoidClasses(clPlayer, 20, clForest, 18, clHill, 0), - clForest, - forestTrees); - -Engine.SetProgress(50); - -g_Map.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), - scaleByMapSize(15, 45), - clDirt); - -g_Map.log("Creating grass patches"); -createPatches( - [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], - tTier4Terrain, - avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(55); - -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - avoidClasses(clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1) -); - -g_Map.log("Creating stone mines"); -createBalancedStoneMines( - oStoneSmall, - oStoneLarge, - clRock, - avoidClasses(clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1, clMetal, 10) -); - -Engine.SetProgress(65); - -let planetm = 1; - -if (currentBiome() == "generic/india") - 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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13) - ], - avoidClasses(clForest, 0, clPlayer, 10, 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(clForest, 0, clPlayer, 20, clHill, 1, clMetal, 4, clRock, 4, clFood, 20), - clFood); - -Engine.SetProgress(75); - -createFood( - [ - [new SimpleObject(oFruitBush, 5, 7, 0, 4)] - ], - [ - 3 * numPlayers - ], - avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clMetal, 4, clRock, 4, clFood, 10), - clFood); - -Engine.SetProgress(85); - -createStragglerTrees( - [oTree1, oTree2, oTree4, oTree3], - avoidClasses(clForest, 8, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6, clFood, 1), - clForest, - stragglerTrees); - -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -g_Map.ExportMap(); +function* GenerateMap() +{ + 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 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 oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; + const oStoneLarge = g_Gaia.stoneLarge; + const oStoneSmall = g_Gaia.stoneSmall; + const oMetalLarge = g_Gaia.metalLarge; + const oMetalSmall = g_Gaia.metalSmall; + + 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 heightLand = 3; + + global.g_Map = new RandomMap(heightLand, tMainTerrain); + + const numPlayers = getNumPlayers(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oFruitBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oTree1, + "count": 5 + } + // No decoratives + }); + yield 20; + + createBumps(avoidClasses(clPlayer, 20)); + + if (randBool()) + createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 20, clHill, 15), clHill, + scaleByMapSize(3, 15)); + else + createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 15), clHill, scaleByMapSize(3, 15)); + + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + createDefaultForests( + [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], + avoidClasses(clPlayer, 20, clForest, 18, clHill, 0), + clForest, + forestTrees); + + yield 50; + + g_Map.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), + scaleByMapSize(15, 45), + clDirt); + + g_Map.log("Creating grass patches"); + createPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + tTier4Terrain, + avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + yield 55; + + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + avoidClasses(clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1) + ); + + g_Map.log("Creating stone mines"); + createBalancedStoneMines( + oStoneSmall, + oStoneLarge, + clRock, + avoidClasses(clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1, clMetal, 10) + ); + + yield 65; + + let planetm = 1; + + if (currentBiome() == "generic/india") + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13) + ], + avoidClasses(clForest, 0, clPlayer, 10, clHill, 0)); + + yield 70; + + createFood( + [ + [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], + [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] + ], + [ + 3 * numPlayers, + 3 * numPlayers + ], + avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clMetal, 4, clRock, 4, clFood, 20), + clFood); + + yield 75; + + createFood( + [ + [new SimpleObject(oFruitBush, 5, 7, 0, 4)] + ], + [ + 3 * numPlayers + ], + avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clMetal, 4, clRock, 4, clFood, 10), + clFood); + + yield 85; + + createStragglerTrees( + [oTree1, oTree2, oTree4, oTree3], + avoidClasses(clForest, 8, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6, clFood, 1), + clForest, + stragglerTrees); + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/marmara.js =================================================================== --- binaries/data/mods/public/maps/random/marmara.js +++ binaries/data/mods/public/maps/random/marmara.js @@ -20,350 +20,354 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setBiome("generic/aegean"); - -g_Terrains.mainTerrain = ["grass_mediterranean_dry_1024test", "grass_field_dry","new_savanna_grass_b"]; -g_Terrains.forestFloor1 = "steppe_grass_dirt_66"; -g_Terrains.forestFloor2 = "steppe_dirt_a"; -g_Terrains.tier1Terrain = "medit_grass_field_b"; -g_Terrains.tier2Terrain = "medit_grass_field_dry"; -g_Terrains.tier3Terrain = "medit_shrubs_golden"; -g_Terrains.tier4Terrain = "steppe_dirt_b"; -g_Terrains.cliff = "medit_cliff_a"; -g_Terrains.roadWild = "road_med_a"; -g_Terrains.road = "road2"; -g_Terrains.water = "medit_sand_messy"; - -g_Gaia.mainHuntableAnimal = "gaia/fauna_horse"; -g_Gaia.secondaryHuntableAnimal = "gaia/fauna_boar"; -g_Gaia.fish = "gaia/fish/generic"; -g_Gaia.tree1 = "gaia/tree/carob"; -g_Gaia.tree2 = "gaia/tree/poplar_lombardy"; -g_Gaia.tree3 = "gaia/tree/dead"; -g_Gaia.tree4 = "gaia/tree/dead"; -g_Gaia.tree5 = "gaia/tree/carob"; -g_Gaia.fruitBush = "gaia/fruit/grapes"; -g_Gaia.metalSmall = "gaia/ore/desert_small"; - -g_Decoratives.grass = "actor|props/special/eyecandy/block_limestone.xml"; -g_Decoratives.grassShort = "actor|props/special/eyecandy/blocks_sandstone_pile_a.xml"; -g_Decoratives.rockLarge = "actor|geology/stone_savanna_med.xml"; -g_Decoratives.rockMedium = "actor|geology/stone_granite_small.xml"; -g_Decoratives.bushMedium = "actor|props/flora/bush_medit_me_dry.xml"; -g_Decoratives.bushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; -g_Decoratives.reeds = "actor|props/flora/reeds_pond_lush_a.xml"; - -const heightScale = num => num * g_MapSettings.Size / 320; +function* GenerateMap() +{ + setBiome("generic/aegean"); -const heightSeaGround = heightScale(scaleByMapSize(-6, -4)); -const heightWaterLevel = heightScale(0); -const heightShoreline = heightScale(0); + g_Terrains.mainTerrain = ["grass_mediterranean_dry_1024test", "grass_field_dry","new_savanna_grass_b"]; + g_Terrains.forestFloor1 = "steppe_grass_dirt_66"; + g_Terrains.forestFloor2 = "steppe_dirt_a"; + g_Terrains.tier1Terrain = "medit_grass_field_b"; + g_Terrains.tier2Terrain = "medit_grass_field_dry"; + g_Terrains.tier3Terrain = "medit_shrubs_golden"; + g_Terrains.tier4Terrain = "steppe_dirt_b"; + g_Terrains.cliff = "medit_cliff_a"; + g_Terrains.roadWild = "road_med_a"; + g_Terrains.road = "road2"; + g_Terrains.water = "medit_sand_messy"; -const g_Map = new RandomMap(0, g_Terrains.mainTerrain); -const mapCenter = g_Map.getCenter(); + g_Gaia.mainHuntableAnimal = "gaia/fauna_horse"; + g_Gaia.secondaryHuntableAnimal = "gaia/fauna_boar"; + g_Gaia.fish = "gaia/fish/generic"; + g_Gaia.tree1 = "gaia/tree/carob"; + g_Gaia.tree2 = "gaia/tree/poplar_lombardy"; + g_Gaia.tree3 = "gaia/tree/dead"; + g_Gaia.tree4 = "gaia/tree/dead"; + g_Gaia.tree5 = "gaia/tree/carob"; + g_Gaia.fruitBush = "gaia/fruit/grapes"; + g_Gaia.metalSmall = "gaia/ore/desert_small"; -initTileClasses(["shoreline"]); + g_Decoratives.grass = "actor|props/special/eyecandy/block_limestone.xml"; + g_Decoratives.grassShort = "actor|props/special/eyecandy/blocks_sandstone_pile_a.xml"; + g_Decoratives.rockLarge = "actor|geology/stone_savanna_med.xml"; + g_Decoratives.rockMedium = "actor|geology/stone_granite_small.xml"; + g_Decoratives.bushMedium = "actor|props/flora/bush_medit_me_dry.xml"; + g_Decoratives.bushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; + g_Decoratives.reeds = "actor|props/flora/reeds_pond_lush_a.xml"; -g_Map.LoadHeightmapImage("marmara.png", 0, 10); -Engine.SetProgress(15); + const heightScale = num => num * g_MapSettings.Size / 320; -g_Map.log("Lowering sea ground"); -createArea( - new MapBoundsPlacer(), - // Keep water impassable on all mapsizes - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, scaleByMapSize(1, 3)), - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(20); + const heightSeaGround = heightScale(scaleByMapSize(-6, -4)); + const heightWaterLevel = heightScale(0); + const heightShoreline = heightScale(0); -g_Map.log("Smoothing heightmap"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, scaleByMapSize(0.1, 0.2), 1)); -Engine.SetProgress(25); + global.g_Map = new RandomMap(0, g_Terrains.mainTerrain); + const mapCenter = g_Map.getCenter(); -g_Map.log("Marking water"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.water), - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(30); + initTileClasses(["shoreline"]); -g_Map.log("Marking land"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land), - avoidClasses(g_TileClasses.water, 0)); -Engine.SetProgress(35); + g_Map.LoadHeightmapImage("marmara.png", 0, 10); + yield 15; -g_Map.log("Painting shoreline"); -createArea( - new MapBoundsPlacer(), - [ - new TerrainPainter(g_Terrains.water), - new TileClassPainter(g_TileClasses.shoreline) - ], - new HeightConstraint(-Infinity, heightShoreline)); -Engine.SetProgress(40); + g_Map.log("Lowering sea ground"); + createArea( + new MapBoundsPlacer(), + // Keep water impassable on all mapsizes + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, scaleByMapSize(1, 3)), + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 20; -g_Map.log("Painting cliffs"); -createArea( - new MapBoundsPlacer(), - [ - new TerrainPainter(g_Terrains.cliff), - new TileClassPainter(g_TileClasses.mountain), - ], - [ - avoidClasses(g_TileClasses.water, 2), - new SlopeConstraint(2, Infinity) - ]); -Engine.SetProgress(45); + g_Map.log("Smoothing heightmap"); + createArea( + new MapBoundsPlacer(), + new SmoothingPainter(1, scaleByMapSize(0.1, 0.2), 1)); + yield 25; -if (!isNomad()) -{ - g_Map.log("Placing players"); - const [playerIDs, playerPosition] = createBases( - ...playerPlacementRandom( - sortAllPlayers(), - [ - avoidClasses(g_TileClasses.mountain, 5), - stayClasses(g_TileClasses.land, scaleByMapSize(6, 25)) - ]), - true); + g_Map.log("Marking water"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.water), + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 30; - g_Map.log("Flatten the initial CC area"); - for (const position of playerPosition) - createArea( - new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, position), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); -} -Engine.SetProgress(50); + g_Map.log("Marking land"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land), + avoidClasses(g_TileClasses.water, 0)); + yield 35; -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 + g_Map.log("Painting shoreline"); + createArea( + new MapBoundsPlacer(), + [ + new TerrainPainter(g_Terrains.water), + new TileClassPainter(g_TileClasses.shoreline) ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] - } -]); -Engine.SetProgress(60); + new HeightConstraint(-Infinity, heightShoreline)); + yield 40; -addElements(shuffleArray([ - { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 30, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal", "many"] - }, - { - "func": addSmallMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 30, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal", "many"] - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 30, - g_TileClasses.metal, 20, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal", "many"] - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 10, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 5, - g_TileClasses.plateau, 5, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.water, 2 + g_Map.log("Painting cliffs"); + createArea( + new MapBoundsPlacer(), + [ + new TerrainPainter(g_Terrains.cliff), + new TileClassPainter(g_TileClasses.mountain), ], - "sizes": ["normal"], - "mixes": ["similar"], - "amounts": ["many"] - } -])); -Engine.SetProgress(70); + [ + avoidClasses(g_TileClasses.water, 2), + new SlopeConstraint(2, Infinity) + ]); + yield 45; -addElements(shuffleArray([ - { - "func": addBerries, - "avoid": [ - g_TileClasses.berries, 30, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 5, - g_TileClasses.metal, 10, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 10, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal", "many"] - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.water, 3 - ], - "sizes": ["huge"], - "mixes": ["unique"], - "amounts": ["tons"] - }, - { - "func": addFish, - "avoid": [ - g_TileClasses.fish, 12, - g_TileClasses.player, 8 - ], - "stay": [g_TileClasses.water, 4], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - }, + if (!isNomad()) { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 5, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.water, 5 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["tons"] + g_Map.log("Placing players"); + const [playerIDs, playerPosition] = createBases( + ...playerPlacementRandom( + sortAllPlayers(), + [ + avoidClasses(g_TileClasses.mountain, 5), + stayClasses(g_TileClasses.land, scaleByMapSize(6, 25)) + ]), + true); + + g_Map.log("Flatten the initial CC area"); + for (const position of playerPosition) + createArea( + new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, + position), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); } -])); -Engine.SetProgress(80); + yield 50; + + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + } + ]); + yield 60; + + addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 30, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal", "many"] + }, + { + "func": addSmallMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 30, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal", "many"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 30, + g_TileClasses.metal, 20, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal", "many"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 10, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.plateau, 5, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2 + ], + "sizes": ["normal"], + "mixes": ["similar"], + "amounts": ["many"] + } + ])); + yield 70; -g_Map.log("Adding reeds"); -createObjectGroups( - new SimpleGroup( + addElements(shuffleArray([ + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 10, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal", "many"] + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.water, 3 + ], + "sizes": ["huge"], + "mixes": ["unique"], + "amounts": ["tons"] + }, + { + "func": addFish, + "avoid": [ + g_TileClasses.fish, 12, + g_TileClasses.player, 8 + ], + "stay": [g_TileClasses.water, 4], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 5, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.water, 5 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + } + ])); + yield 80; + + g_Map.log("Adding reeds"); + createObjectGroups( + new SimpleGroup( + [ + new SimpleObject(g_Decoratives.reeds, 5, 12, 1, 2), + new SimpleObject(g_Decoratives.rockMedium, 1, 2, 1, 3) + ], + true, + g_TileClasses.dirt + ), + 0, [ - new SimpleObject(g_Decoratives.reeds, 5, 12, 1, 2), - new SimpleObject(g_Decoratives.rockMedium, 1, 2, 1, 3) + stayClasses(g_TileClasses.water, 0), + borderClasses(g_TileClasses.water, scaleByMapSize(2,8), scaleByMapSize(2,8)) ], - true, - g_TileClasses.dirt - ), - 0, - [ - stayClasses(g_TileClasses.water, 0), - borderClasses(g_TileClasses.water, scaleByMapSize(2,8), scaleByMapSize(2,8)) - ], - scaleByMapSize(50, 400), - 2); -Engine.SetProgress(85); + scaleByMapSize(50, 400), + 2); + yield 85; -placePlayersNomad( - g_Map.createTileClass(), - [ - stayClasses(g_TileClasses.land, 5), - avoidClasses( - g_TileClasses.forest, 2, - g_TileClasses.rock, 4, - g_TileClasses.metal, 4, - g_TileClasses.berries, 2, - g_TileClasses.animals, 2, - g_TileClasses.mountain, 2) - ]); + placePlayersNomad( + g_Map.createTileClass(), + [ + stayClasses(g_TileClasses.land, 5), + avoidClasses( + g_TileClasses.forest, 2, + g_TileClasses.rock, 4, + g_TileClasses.metal, 4, + g_TileClasses.berries, 2, + g_TileClasses.animals, 2, + g_TileClasses.mountain, 2) + ]); -setSunColor(0.753, 0.586, 0.584); -setSkySet("sunset"); + setSunColor(0.753, 0.586, 0.584); + setSkySet("sunset"); -// Inverted so that water appears on tiny maps and passages are maximized on larger maps -setWaterHeight(scaleByMapSize(20, 18)); -setWaterTint(0.25, 0.67, 0.65); -setWaterColor(0.18, 0.36, 0.39); -setWaterWaviness(8); -setWaterMurkiness(0.99); -setWaterType("lake"); + // Inverted so that water appears on tiny maps and passages are maximized on larger maps + setWaterHeight(scaleByMapSize(20, 18)); + setWaterTint(0.25, 0.67, 0.65); + setWaterColor(0.18, 0.36, 0.39); + setWaterWaviness(8); + setWaterMurkiness(0.99); + setWaterType("lake"); -setAmbientColor(0.521, 0.475, 0.322); + setAmbientColor(0.521, 0.475, 0.322); -setSunRotation(Math.PI * 0.85); -setSunElevation(Math.PI / 14); + setSunRotation(Math.PI * 0.85); + setSunElevation(Math.PI / 14); -setFogFactor(0.15); -setFogThickness(0); -setFogColor(0.64, 0.5, 0.35); + setFogFactor(0.15); + setFogThickness(0); + setFogColor(0.64, 0.5, 0.35); -setPPEffect("hdr"); -setPPContrast(0.67); -setPPSaturation(0.42); -setPPBloom(0.23); + setPPEffect("hdr"); + setPPContrast(0.67); + setPPSaturation(0.42); + setPPBloom(0.23); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/mediterranean.js =================================================================== --- binaries/data/mods/public/maps/random/mediterranean.js +++ binaries/data/mods/public/maps/random/mediterranean.js @@ -23,446 +23,451 @@ TILE_CENTERED_HEIGHT_MAP = true; -const tWater = "medit_sand_wet"; -const tSnowedRocks = ["alpine_cliff_b", "alpine_cliff_snow"]; -setBiome("generic/aegean"); +function* GenerateMap() +{ + const tWater = "medit_sand_wet"; + const tSnowedRocks = ["alpine_cliff_b", "alpine_cliff_snow"]; + setBiome("generic/aegean"); -const heightScale = num => num * g_MapSettings.Size / 320; + const heightScale = num => num * g_MapSettings.Size / 320; -const heightSeaGround = heightScale(-6); -const heightWaterLevel = heightScale(0); -const heightShoreline = heightScale(0.5); -const heightSnow = heightScale(10); + const heightSeaGround = heightScale(-6); + const heightWaterLevel = heightScale(0); + const heightShoreline = heightScale(0.5); + const heightSnow = heightScale(10); -const g_Map = new RandomMap(heightWaterLevel, g_Terrains.mainTerrain); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); + global.g_Map = new RandomMap(heightWaterLevel, g_Terrains.mainTerrain); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); -g_Map.LoadHeightmapImage("mediterranean.png", 0, 40); -Engine.SetProgress(15); + g_Map.LoadHeightmapImage("mediterranean.png", 0, 40); + yield 15; -initTileClasses(["autumn", "desert", "medit", "polar", "steppe", "temp", "shoreline", "africa", "northern_europe", "southern_europe", "western_europe", "eastern_europe"]); + initTileClasses(["autumn", "desert", "medit", "polar", "steppe", "temp", "shoreline", "africa", + "northern_europe", "southern_europe", "western_europe", "eastern_europe"]); -const northernTopLeft = new Vector2D(fractionToTiles(0.3), fractionToTiles(0.7)); -const westernTopLeft = new Vector2D(fractionToTiles(0.7), fractionToTiles(0.47)); -const africaTop = fractionToTiles(0.33); + const northernTopLeft = new Vector2D(fractionToTiles(0.3), fractionToTiles(0.7)); + const westernTopLeft = new Vector2D(fractionToTiles(0.7), fractionToTiles(0.47)); + const africaTop = fractionToTiles(0.33); -const climateZones = [ - { - "tileClass": g_TileClasses.northern_europe, - "position1": new Vector2D(northernTopLeft.x, mapBounds.top), - "position2": new Vector2D(mapBounds.right, northernTopLeft.y), - "biome": "generic/arctic", - "constraint": new NullConstraint() - }, - { - "tileClass": g_TileClasses.western_europe, - "position1": new Vector2D(mapBounds.left, mapBounds.top), - "position2": westernTopLeft, - "biome": "generic/temperate", - "constraint": avoidClasses(g_TileClasses.northern_europe, 0) - }, - { - "tileClass": g_TileClasses.eastern_europe, - "position1": new Vector2D(westernTopLeft.x, mapBounds.top), - "position2": new Vector2D(mapBounds.right, westernTopLeft.y), - "biome": "generic/autumn", - "constraint": avoidClasses(g_TileClasses.northern_europe, 0) - }, - { - "tileClass": g_TileClasses.southern_europe, - "position1": new Vector2D(mapBounds.left, africaTop), - "position2": new Vector2D(mapBounds.right, westernTopLeft.y), - "biome": "generic/aegean", - "constraint": new NullConstraint() - }, - { - "tileClass": g_TileClasses.africa, - "position1": new Vector2D(mapBounds.left, africaTop), - "position2": new Vector2D(mapBounds.right, mapBounds.bottom), - "biome": "generic/sahara", - "constraint": new NullConstraint() - } -]; - -g_Map.log("Lowering sea ground"); -createArea( - new MapBoundsPlacer(), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 2), - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(20); - -g_Map.log("Smoothing heightmap"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, scaleByMapSize(0.3, 0.8), 1)); -Engine.SetProgress(25); - -g_Map.log("Marking water"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.water), - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(30); - -g_Map.log("Marking land"); -createArea( - new DiskPlacer(fractionToTiles(0.5), mapCenter), - new TileClassPainter(g_TileClasses.land), - avoidClasses(g_TileClasses.water, 0)); -Engine.SetProgress(35); - -g_Map.log("Marking climate zones"); -for (const zone of climateZones) -{ - setBiome(zone.biome); + const climateZones = [ + { + "tileClass": g_TileClasses.northern_europe, + "position1": new Vector2D(northernTopLeft.x, mapBounds.top), + "position2": new Vector2D(mapBounds.right, northernTopLeft.y), + "biome": "generic/arctic", + "constraint": new NullConstraint() + }, + { + "tileClass": g_TileClasses.western_europe, + "position1": new Vector2D(mapBounds.left, mapBounds.top), + "position2": westernTopLeft, + "biome": "generic/temperate", + "constraint": avoidClasses(g_TileClasses.northern_europe, 0) + }, + { + "tileClass": g_TileClasses.eastern_europe, + "position1": new Vector2D(westernTopLeft.x, mapBounds.top), + "position2": new Vector2D(mapBounds.right, westernTopLeft.y), + "biome": "generic/autumn", + "constraint": avoidClasses(g_TileClasses.northern_europe, 0) + }, + { + "tileClass": g_TileClasses.southern_europe, + "position1": new Vector2D(mapBounds.left, africaTop), + "position2": new Vector2D(mapBounds.right, westernTopLeft.y), + "biome": "generic/aegean", + "constraint": new NullConstraint() + }, + { + "tileClass": g_TileClasses.africa, + "position1": new Vector2D(mapBounds.left, africaTop), + "position2": new Vector2D(mapBounds.right, mapBounds.bottom), + "biome": "generic/sahara", + "constraint": new NullConstraint() + } + ]; + + g_Map.log("Lowering sea ground"); createArea( - new RectPlacer(zone.position1, zone.position2, Infinity), - new TileClassPainter(zone.tileClass), - zone.constraint); + new MapBoundsPlacer(), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 2), + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 20; + g_Map.log("Smoothing heightmap"); createArea( + new MapBoundsPlacer(), + new SmoothingPainter(1, scaleByMapSize(0.3, 0.8), 1)); + yield 25; + + g_Map.log("Marking water"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.water), + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 30; + + g_Map.log("Marking land"); + createArea( + new DiskPlacer(fractionToTiles(0.5), mapCenter), + new TileClassPainter(g_TileClasses.land), + avoidClasses(g_TileClasses.water, 0)); + yield 35; + + g_Map.log("Marking climate zones"); + for (const zone of climateZones) + { + setBiome(zone.biome); + createArea( new RectPlacer(zone.position1, zone.position2, Infinity), - new TerrainPainter(g_Terrains.mainTerrain), + new TileClassPainter(zone.tileClass), + zone.constraint); + + createArea( + new RectPlacer(zone.position1, zone.position2, Infinity), + new TerrainPainter(g_Terrains.mainTerrain), + [ + new HeightConstraint(heightWaterLevel, Infinity), + zone.constraint + ]); + } + yield 40; + + g_Map.log("Fuzzing biome borders"); + for (const zone of climateZones) + { + setBiome(zone.biome); + + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [ - new HeightConstraint(heightWaterLevel, Infinity), - zone.constraint - ]); -} -Engine.SetProgress(40); + [g_Terrains.mainTerrain, g_Terrains.tier1Terrain], + [g_Terrains.tier1Terrain, g_Terrains.tier2Terrain], + [g_Terrains.tier2Terrain, g_Terrains.tier3Terrain] + ], + [1, 1], + [ + avoidClasses( + g_TileClasses.forest, 2, + g_TileClasses.water, 2, + g_TileClasses.mountain, 2, + g_TileClasses.dirt, 5, + g_TileClasses.player, 8), + borderClasses(zone.tileClass, 3, 3), + ], + scaleByMapSize(20, 60), + g_TileClasses.dirt); + } + yield 45; -g_Map.log("Fuzzing biome borders"); -for (const zone of climateZones) -{ - setBiome(zone.biome); + if (!isNomad()) + { + g_Map.log("Finding player positions"); - createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [ - [g_Terrains.mainTerrain, g_Terrains.tier1Terrain], - [g_Terrains.tier1Terrain, g_Terrains.tier2Terrain], - [g_Terrains.tier2Terrain, g_Terrains.tier3Terrain] - ], - [1, 1], - [ - avoidClasses( - g_TileClasses.forest, 2, - g_TileClasses.water, 2, - g_TileClasses.mountain, 2, - g_TileClasses.dirt, 5, - g_TileClasses.player, 8), - borderClasses(zone.tileClass, 3, 3), - ], - scaleByMapSize(20, 60), - g_TileClasses.dirt); -} -Engine.SetProgress(45); + const [playerIDs, playerPosition] = playerPlacementRandom( + sortAllPlayers(), + [ + avoidClasses(g_TileClasses.mountain, 5), + stayClasses(g_TileClasses.land, scaleByMapSize(8, 25)) + ]); -if (!isNomad()) -{ - g_Map.log("Finding player positions"); + g_Map.log("Flatten the initial CC area and placing playerbases"); + for (let i = 0; i < getNumPlayers(); ++i) + { + g_Map.logger.printDuration(); + setBiome(climateZones.find(zone => zone.tileClass.has(playerPosition[i])).biome); - const [playerIDs, playerPosition] = playerPlacementRandom( - sortAllPlayers(), - [ - avoidClasses(g_TileClasses.mountain, 5), - stayClasses(g_TileClasses.land, scaleByMapSize(8, 25)) - ]); + createArea( + new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, + playerPosition[i]), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(playerPosition[i]), 6)); - g_Map.log("Flatten the initial CC area and placing playerbases"); - for (let i = 0; i < getNumPlayers(); ++i) + createBase(playerIDs[i], playerPosition[i], mapSize >= 384); + } + } + yield 50; + + for (const zone of climateZones) { - g_Map.logger.printDuration(); - setBiome(climateZones.find(zone => zone.tileClass.has(playerPosition[i])).biome); + setBiome(zone.biome); + g_Map.log("Painting shoreline"); createArea( - new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, playerPosition[i]), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(playerPosition[i]), 6)); + new MapBoundsPlacer(), + [ + new TerrainPainter(g_Terrains.shore), + new TileClassPainter(g_TileClasses.shoreline) + ], + [ + stayClasses(zone.tileClass, 0), + new HeightConstraint(-Infinity, heightShoreline) + ]); - createBase(playerIDs[i], playerPosition[i], mapSize >= 384); - } -} -Engine.SetProgress(50); + g_Map.log("Painting cliffs"); + createArea( + new MapBoundsPlacer(), + [ + new TerrainPainter(g_Terrains.cliff), + new TileClassPainter(g_TileClasses.mountain), + ], + [ + stayClasses(zone.tileClass, 0), + avoidClasses(g_TileClasses.water, 2), + new SlopeConstraint(2, Infinity) + ]); -for (const zone of climateZones) -{ - setBiome(zone.biome); + g_Map.log("Placing resources"); + addElements([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 25, + g_TileClasses.water, 4 + ], + "stay": [zone.tileClass, 0], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 25, + g_TileClasses.water, 4 + ], + "stay": [zone.tileClass, 0], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 3, + g_TileClasses.forest, 15, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.water, 2 + ], + "stay": [zone.tileClass, 0], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addSmallMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 15, + g_TileClasses.water, 4 + ], + "stay": [zone.tileClass, 0], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["few", "normal", "many"] + }, + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.forest, 2, + g_TileClasses.metal, 4, + g_TileClasses.mountain, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 4, + g_TileClasses.water, 2 + ], + "stay": [zone.tileClass, 0], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 10, + g_TileClasses.forest, 1, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.player, 15, + g_TileClasses.rock, 2, + g_TileClasses.water, 3 + ], + "stay": [zone.tileClass, 0], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 10, + g_TileClasses.forest, 1, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.player, 15, + g_TileClasses.rock, 2, + g_TileClasses.water, 1 + ], + "stay": [zone.tileClass, 0], + "sizes": ["small"], + "mixes": ["normal"], + "amounts": ["tons"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 5, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.water, 3 + ], + "stay": [zone.tileClass, 0], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["some"] + }, + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "stay": [zone.tileClass, 0], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["tons"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 4 + ], + "stay": [zone.tileClass, 0], + "sizes": ["small"], + "mixes": ["same"], + "amounts": ["normal"] + } + ]); + } + yield 60; - g_Map.log("Painting shoreline"); + g_Map.log("Painting water"); createArea( new MapBoundsPlacer(), - [ - new TerrainPainter(g_Terrains.shore), - new TileClassPainter(g_TileClasses.shoreline) - ], - [ - stayClasses(zone.tileClass, 0), - new HeightConstraint(-Infinity, heightShoreline) - ]); + new TerrainPainter(tWater), + new HeightConstraint(-Infinity, heightWaterLevel)); - g_Map.log("Painting cliffs"); + g_Map.log("Painting snow on mountains"); createArea( new MapBoundsPlacer(), + new TerrainPainter(tSnowedRocks), [ - new TerrainPainter(g_Terrains.cliff), - new TileClassPainter(g_TileClasses.mountain), - ], - [ - stayClasses(zone.tileClass, 0), - avoidClasses(g_TileClasses.water, 2), - new SlopeConstraint(2, Infinity) + new HeightConstraint(heightSnow, Infinity), + avoidClasses( + g_TileClasses.africa, 0, + g_TileClasses.southern_europe, 0, + g_TileClasses.player, 6) ]); - g_Map.log("Placing resources"); + yield 70; + + g_Map.log("Placing fish"); + g_Gaia.fish = "gaia/fish/generic"; addElements([ { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.metal, 25, - g_TileClasses.water, 4 - ], - "stay": [zone.tileClass, 0], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.metal, 25, - g_TileClasses.water, 4 - ], - "stay": [zone.tileClass, 0], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 3, - g_TileClasses.forest, 15, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.water, 2 - ], - "stay": [zone.tileClass, 0], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - }, - { - "func": addSmallMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.metal, 15, - g_TileClasses.water, 4 - ], - "stay": [zone.tileClass, 0], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["few", "normal", "many"] - }, - { - "func": addBerries, - "avoid": [ - g_TileClasses.berries, 30, - g_TileClasses.forest, 2, - g_TileClasses.metal, 4, - g_TileClasses.mountain, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 4, - g_TileClasses.water, 2 - ], - "stay": [zone.tileClass, 0], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] - }, - { - "func": addAnimals, + "func": addFish, "avoid": [ - g_TileClasses.animals, 10, - g_TileClasses.forest, 1, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.player, 15, - g_TileClasses.rock, 2, - g_TileClasses.water, 3 + g_TileClasses.fish, 10, ], - "stay": [zone.tileClass, 0], + "stay": [g_TileClasses.water, 4], "sizes": ["normal"], - "mixes": ["normal"], + "mixes": ["similar"], "amounts": ["many"] - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 10, - g_TileClasses.forest, 1, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.player, 15, - g_TileClasses.rock, 2, - g_TileClasses.water, 1 - ], - "stay": [zone.tileClass, 0], - "sizes": ["small"], - "mixes": ["normal"], - "amounts": ["tons"] - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 5, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.water, 3 - ], - "stay": [zone.tileClass, 0], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["some"] - }, - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "stay": [zone.tileClass, 0], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["tons"] - }, + } + ]); + yield 85; + + g_Map.log("Placing whale"); + g_Gaia.fish = "gaia/fauna_whale_fin"; + addElements([ { - "func": addDecoration, + "func": addFish, "avoid": [ - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 4 + g_TileClasses.fish, 2, + g_TileClasses.desert, 50, + g_TileClasses.steppe, 50 ], - "stay": [zone.tileClass, 0], + "stay": [g_TileClasses.water, 7], "sizes": ["small"], "mixes": ["same"], - "amounts": ["normal"] + "amounts": ["scarce"] } ]); -} -Engine.SetProgress(60); - -g_Map.log("Painting water"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(tWater), - new HeightConstraint(-Infinity, heightWaterLevel)); - -g_Map.log("Painting snow on mountains"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(tSnowedRocks), - [ - new HeightConstraint(heightSnow, Infinity), - avoidClasses( - g_TileClasses.africa, 0, - g_TileClasses.southern_europe, 0, - g_TileClasses.player, 6) - ]); - -Engine.SetProgress(70); + yield 95; -g_Map.log("Placing fish"); -g_Gaia.fish = "gaia/fish/generic"; -addElements([ - { - "func": addFish, - "avoid": [ - g_TileClasses.fish, 10, - ], - "stay": [g_TileClasses.water, 4], - "sizes": ["normal"], - "mixes": ["similar"], - "amounts": ["many"] - } -]); -Engine.SetProgress(85); - -g_Map.log("Placing whale"); -g_Gaia.fish = "gaia/fauna_whale_fin"; -addElements([ - { - "func": addFish, - "avoid": [ - g_TileClasses.fish, 2, - g_TileClasses.desert, 50, - g_TileClasses.steppe, 50 - ], - "stay": [g_TileClasses.water, 7], - "sizes": ["small"], - "mixes": ["same"], - "amounts": ["scarce"] - } -]); -Engine.SetProgress(95); - -placePlayersNomad( - g_Map.createTileClass(), - [ - stayClasses(g_TileClasses.land, 5), - avoidClasses( - g_TileClasses.forest, 2, - g_TileClasses.rock, 4, - g_TileClasses.metal, 4, - g_TileClasses.berries, 2, - g_TileClasses.animals, 2, - g_TileClasses.mountain, 2) - ]); + placePlayersNomad( + g_Map.createTileClass(), + [ + stayClasses(g_TileClasses.land, 5), + avoidClasses( + g_TileClasses.forest, 2, + g_TileClasses.rock, 4, + g_TileClasses.metal, 4, + g_TileClasses.berries, 2, + g_TileClasses.animals, 2, + g_TileClasses.mountain, 2) + ]); -setWindAngle(-0.589049); -setWaterTint(0.556863, 0.615686, 0.643137); -setWaterColor(0.494118, 0.639216, 0.713726); -setWaterWaviness(8); -setWaterMurkiness(0.87); -setWaterType("ocean"); + setWindAngle(-0.589049); + setWaterTint(0.556863, 0.615686, 0.643137); + setWaterColor(0.494118, 0.639216, 0.713726); + setWaterWaviness(8); + setWaterMurkiness(0.87); + setWaterType("ocean"); -setAmbientColor(0.72, 0.72, 0.82); + setAmbientColor(0.72, 0.72, 0.82); -setSunColor(0.733, 0.746, 0.574); -setSunRotation(Math.PI * 0.95); -setSunElevation(Math.PI / 6); + setSunColor(0.733, 0.746, 0.574); + setSunRotation(Math.PI * 0.95); + setSunElevation(Math.PI / 6); -setSkySet("cumulus"); -setFogFactor(0); -setFogThickness(0); -setFogColor(0.69, 0.616, 0.541); + setSkySet("cumulus"); + setFogFactor(0); + setFogThickness(0); + setFogColor(0.69, 0.616, 0.541); -setPPEffect("hdr"); -setPPContrast(0.67); -setPPSaturation(0.42); -setPPBloom(0.23); + setPPEffect("hdr"); + setPPContrast(0.67); + setPPSaturation(0.42); + setPPBloom(0.23); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/migration.js =================================================================== --- binaries/data/mods/public/maps/random/migration.js +++ binaries/data/mods/public/maps/random/migration.js @@ -2,372 +2,385 @@ Engine.LoadLibrary("rmgen-common"); 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/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; - -const g_Map = new RandomMap(heightSeaGround, tWater); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clLand = g_Map.createTileClass(); -const clIsland = g_Map.createTileClass(); - -const startAngle = randomAngle(); -const playerIDs = sortAllPlayers(); -const [playerPosition, playerAngle] = playerPlacementCustomAngle( - fractionToTiles(0.35), - mapCenter, - i => startAngle - Math.PI * (i + 1) / (numPlayers + 1)); - -g_Map.log("Creating player islands and docks"); -for (let i = 0; i < numPlayers; ++i) +function* GenerateMap() { + 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/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; + + global.g_Map = new RandomMap(heightSeaGround, tWater); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clLand = g_Map.createTileClass(); + const clIsland = g_Map.createTileClass(); + + const startAngle = randomAngle(); + const playerIDs = sortAllPlayers(); + const [playerPosition, playerAngle] = playerPlacementCustomAngle( + fractionToTiles(0.35), + mapCenter, + i => startAngle - Math.PI * (i + 1) / (numPlayers + 1)); + + g_Map.log("Creating player islands and docks"); + for (let i = 0; i < numPlayers; ++i) + { + createArea( + new ClumpPlacer(diskArea(defaultPlayerBaseRadius()), 0.8, 0.1, Infinity, + playerPosition[i]), + [ + new LayeredPainter([tWater, tShore, tMainTerrain], [1, 4]), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), + new TileClassPainter(clIsland), + new TileClassPainter(isNomad() ? clLand : clPlayer) + ]); + + if (isNomad()) + continue; + + const dockLocation = + findLocationInDirectionBasedOnHeight(playerPosition[i], mapCenter, -3 , 2.6, 3); + g_Map.placeEntityPassable(oDock, playerIDs[i], dockLocation, playerAngle[i] + Math.PI); + } + yield 10; + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "Walls": false, + // No city patch + "StartingAnimal": { + }, + "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 + } + }); + yield 15; + + g_Map.log("Create the continent body"); + const continentPosition = Vector2D.add(mapCenter, + new Vector2D(0, fractionToTiles(0.38)).rotate(-startAngle)).round(); createArea( - new ClumpPlacer(diskArea(defaultPlayerBaseRadius()), 0.8, 0.1, Infinity, playerPosition[i]), + new ClumpPlacer(diskArea(fractionToTiles(0.4)), 0.8, 0.08, Infinity, continentPosition), [ - new LayeredPainter([tWater, tShore, tMainTerrain], [1, 4]), + new LayeredPainter([tWater, tShore, tMainTerrain], [4, 2]), new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), - new TileClassPainter(clIsland), - new TileClassPainter(isNomad() ? clLand : clPlayer) - ]); - - if (isNomad()) - continue; - - const dockLocation = findLocationInDirectionBasedOnHeight(playerPosition[i], mapCenter, -3 , 2.6, 3); - g_Map.placeEntityPassable(oDock, playerIDs[i], dockLocation, playerAngle[i] + Math.PI); -} -Engine.SetProgress(10); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "Walls": false, - // No city patch - "StartingAnimal": { - }, - "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); - -g_Map.log("Create the continent body"); -const continentPosition = Vector2D.add(mapCenter, new Vector2D(0, fractionToTiles(0.38)).rotate(-startAngle)).round(); -createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.4)), 0.8, 0.08, Infinity, continentPosition), - [ - new LayeredPainter([tWater, tShore, tMainTerrain], [4, 2]), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), - new TileClassPainter(clLand) - ], - avoidClasses(clIsland, 8)); -Engine.SetProgress(20); - -g_Map.log("Creating shore jaggedness"); -createAreas( - new ClumpPlacer(scaleByMapSize(15, 80), 0.2, 0.1, Infinity), - [ - new LayeredPainter([tMainTerrain, tMainTerrain], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), - new TileClassPainter(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); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - [avoidClasses(clIsland, 10), stayClasses(clLand, 3)], - scaleByMapSize(100, 200) -); -Engine.SetProgress(30); - -g_Map.log("Creating hills"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), - [ - new LayeredPainter([tCliff, tHill], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - [avoidClasses(clIsland, 10, clHill, 15), stayClasses(clLand, 7)], - scaleByMapSize(1, 4) * numPlayers -); -Engine.SetProgress(34); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); -const types = [ - [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], - [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] -]; - -const forestSize = forestTrees / (scaleByMapSize(2,8) * numPlayers) * - (currentBiome() == "generic/savanna" ? 2 : 1); - -const num = Math.floor(forestSize / types.length); -for (const type of types) - createAreas( - new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) + new TileClassPainter(clLand) ], - [avoidClasses(clPlayer, 6, clForest, 10, clHill, 0), stayClasses(clLand, 7)], - num); -Engine.SetProgress(38); + avoidClasses(clIsland, 8)); + yield 20; -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + g_Map.log("Creating shore jaggedness"); createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), + new ClumpPlacer(scaleByMapSize(15, 80), 0.2, 0.1, Infinity), [ - new LayeredPainter( - [[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], - [1, 1]), - new TileClassPainter(clDirt) + new LayeredPainter([tMainTerrain, tMainTerrain], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), + new TileClassPainter(clLand) ], [ - avoidClasses( - clForest, 0, - clHill, 0, - clDirt, 5, - clIsland, 0), - stayClasses(clLand, 7) + borderClasses(clLand, 6, 3), + avoidClasses(clIsland, 8) ], - scaleByMapSize(15, 45)); + scaleByMapSize(2, 15) * 20, + 150); -Engine.SetProgress(42); + paintTerrainBasedOnHeight(1, 3, 0, tShore); + paintTerrainBasedOnHeight(-8, 1, 2, tWater); + yield 25; -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) + g_Map.log("Creating bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + [avoidClasses(clIsland, 10), stayClasses(clLand, 3)], + scaleByMapSize(100, 200) + ); + yield 30; + + g_Map.log("Creating hills"); 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); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 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); - -g_Map.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); - -g_Map.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); - -g_Map.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); - -g_Map.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); - -g_Map.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); - -g_Map.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); - -g_Map.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); - -g_Map.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); - -const planetm = currentBiome() == "generic/india" ? 8 : 1; - -g_Map.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); - -g_Map.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); - -g_Map.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)]); - -g_Map.ExportMap(); + new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), + [ + new LayeredPainter([tCliff, tHill], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) + ], + [avoidClasses(clIsland, 10, clHill, 15), stayClasses(clLand, 7)], + scaleByMapSize(1, 4) * numPlayers + ); + yield 34; + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + const types = [ + [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], + [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] + ]; + + const forestSize = forestTrees / (scaleByMapSize(2,8) * numPlayers) * + (currentBiome() == "generic/savanna" ? 2 : 1); + + const num = Math.floor(forestSize / types.length); + for (const type of types) + createAreas( + new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + [avoidClasses(clPlayer, 6, clForest, 10, clHill, 0), stayClasses(clLand, 7)], + num); + yield 38; + + g_Map.log("Creating dirt patches"); + for (const 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]), + new TileClassPainter(clDirt) + ], + [ + avoidClasses( + clForest, 0, + clHill, 0, + clDirt, 5, + clIsland, 0), + stayClasses(clLand, 7) + ], + scaleByMapSize(15, 45)); + + yield 42; + + g_Map.log("Creating grass patches"); + for (const 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)); + yield 46; + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), stayClasses(clLand, 7)], + scaleByMapSize(4,16), 100 + ); + yield 50; + + g_Map.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 + ); + yield 54; + + g_Map.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 + ); + yield 58; + + g_Map.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 + ); + yield 62; + + g_Map.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 + ); + yield 66; + + g_Map.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 + ); + yield 70; + + g_Map.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 + ); + yield 74; + + g_Map.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 + ); + yield 78; + + g_Map.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 + ); + yield 82; + + createStragglerTrees( + [oTree1, oTree2, oTree4, oTree3], + [avoidClasses(clForest, 1, clHill, 1, clPlayer, 9, clMetal, 6, clRock, 6), + stayClasses(clLand, 9)], + clForest, + stragglerTrees); + + yield 86; + + const planetm = currentBiome() == "generic/india" ? 8 : 1; + + g_Map.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) + ); + yield 90; + + g_Map.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) + ); + yield 94; + + g_Map.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 + ); + yield 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)]); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/neareastern_badlands.js =================================================================== --- binaries/data/mods/public/maps/random/neareastern_badlands.js +++ binaries/data/mods/public/maps/random/neareastern_badlands.js @@ -2,357 +2,362 @@ Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); -if (g_MapSettings.Biome) - setSelectedBiome(); -else - setBiome("generic/sahara"); - - -const tPrimary = g_Terrains.mainTerrain; -const tCity = g_Terrains.roadWild; -const tCityPlaza = g_Terrains.road; -const tSand = g_Terrains.tier3Terrain; -const tDunes = g_Terrains.tier4Terrain; -const tFineSand = g_Terrains.tier2Terrain; -const tCliff = g_Terrains.cliff; -const tDirt = g_Terrains.dirt; -const tForestFloor = "desert_forestfloor_palms"; -const tGrass = g_Terrains.forestFloor2; -const tGrassSand25 = g_Terrains.shoreBlend; -const tShore = g_Terrains.shore; -const tWaterDeep = g_Terrains.water; - -const oBerryBush = "gaia/fruit/grapes"; -const oCamel = "gaia/fauna_camel"; -const oFish = g_Gaia.fish; -const oGazelle = "gaia/fauna_gazelle"; -const oGiraffe = "gaia/fauna_giraffe"; -const oGoat = "gaia/fauna_goat"; -const oWildebeest = "gaia/fauna_wildebeest"; -const oStoneLarge = g_Gaia.stoneLarge; -const oStoneSmall = g_Gaia.stoneSmall; -const oMetalLarge = g_Gaia.metalLarge; -const oMetalSmall = g_Gaia.metalSmall; -const oOasisTree = "gaia/tree/senegal_date_palm"; -const oDatePalm = g_Gaia.tree1; -const oSDatePalm = g_Gaia.tree2; - -const aBush1 = g_Decoratives.bushMedium; -const aBush2 = "actor|props/flora/bush_desert_dry_a.xml"; -const aBush3 = g_Decoratives.bushSmall; -const aBush4 = "actor|props/flora/plant_desert_a.xml"; -const aBushes = [aBush1, aBush2, aBush3, aBush4]; -const aDecorativeRock = g_Decoratives.rockMedium; - -const pForest = [tForestFloor + TERRAIN_SEPARATOR + oDatePalm, tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, tForestFloor]; -const pForestOasis = [tGrass + TERRAIN_SEPARATOR + oOasisTree, tGrass + TERRAIN_SEPARATOR + oDatePalm, tGrass]; - -const heightLand = 10; - -const heightOffsetOasis = -11; -const heightOffsetHill1 = 16; -const heightOffsetHill2 = 16; -const heightOffsetHill3 = 16; -const heightOffsetBump = 2; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill1 = g_Map.createTileClass(); -const clOasis = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clPatch = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -const oasisRadius = scaleByMapSize(14, 40); - -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - -if (!isNomad()) - for (let i = 0; i < numPlayers; ++i) - createArea( - new ClumpPlacer(diskArea(defaultPlayerBaseRadius()), 0.9, 0.5, Infinity, playerPosition[i]), - new TileClassPainter(clPlayer)); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tCity, - "innerTerrain": tCityPlaza, - "width": 3, - "radius": 10 - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oDatePalm - } - // No decoratives -}); -Engine.SetProgress(10); - -g_Map.log("Creating dune patches"); -createAreas( - new ClumpPlacer(scaleByMapSize(40, 150), 0.2, 0.1, 0), - [ - new TerrainPainter(tDunes), - new TileClassPainter(clPatch) - ], - avoidClasses(clPatch, 2, clPlayer, 0), - scaleByMapSize(5, 20)); -Engine.SetProgress(15); - -g_Map.log("Creating sand patches"); -createAreas( - new ClumpPlacer(scaleByMapSize(25, 100), 0.2, 0.1, 0), - [ - new TerrainPainter([tSand, tFineSand]), - new TileClassPainter(clPatch) - ], - avoidClasses(clPatch, 2, clPlayer, 0), - scaleByMapSize(15, 50)); -Engine.SetProgress(20); - -g_Map.log("Creating dirt patches"); -createAreas( - new ClumpPlacer(scaleByMapSize(25, 100), 0.2, 0.1, 0), - [ - new TerrainPainter([tDirt]), - new TileClassPainter(clPatch) - ], - avoidClasses(clPatch, 2, clPlayer, 0), - scaleByMapSize(15, 50)); -Engine.SetProgress(25); - -g_Map.log("Creating oasis"); -createArea( - new ClumpPlacer(diskArea(oasisRadius), 0.6, 0.15, 0, mapCenter), - [ - new LayeredPainter([[tSand, pForest], [tGrassSand25, pForestOasis], tGrassSand25, tShore, tWaterDeep], [2, 3, 1, 1]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetOasis, 8), - new TileClassPainter(clOasis) - ]); - -Engine.SetProgress(30); - -g_Map.log("Creating oasis wildlife"); -let num = Math.round(Math.PI * oasisRadius / 8); -let constraint = new AndConstraint([borderClasses(clOasis, 0, 3), avoidClasses(clOasis, 0)]); -for (let i = 0; i < num; ++i) +function* GenerateMap(mapSettings) { - let animalPosition; - let r = 0; - const angle = 2 * Math.PI / num * i; - do { - // Work outward until constraint met - animalPosition = Vector2D.add(mapCenter, new Vector2D(r, 0).rotate(-angle)).round(); - ++r; - } while (!constraint.allows(animalPosition) && r < mapSize / 2); - - createObjectGroup( - new RandomGroup( + setBiome(mapSettings.Biome ?? "generic/sahara"); + + const tPrimary = g_Terrains.mainTerrain; + const tCity = g_Terrains.roadWild; + const tCityPlaza = g_Terrains.road; + const tSand = g_Terrains.tier3Terrain; + const tDunes = g_Terrains.tier4Terrain; + const tFineSand = g_Terrains.tier2Terrain; + const tCliff = g_Terrains.cliff; + const tDirt = g_Terrains.dirt; + const tForestFloor = "desert_forestfloor_palms"; + const tGrass = g_Terrains.forestFloor2; + const tGrassSand25 = g_Terrains.shoreBlend; + const tShore = g_Terrains.shore; + const tWaterDeep = g_Terrains.water; + + const oBerryBush = "gaia/fruit/grapes"; + const oCamel = "gaia/fauna_camel"; + const oFish = g_Gaia.fish; + const oGazelle = "gaia/fauna_gazelle"; + const oGiraffe = "gaia/fauna_giraffe"; + const oGoat = "gaia/fauna_goat"; + const oWildebeest = "gaia/fauna_wildebeest"; + const oStoneLarge = g_Gaia.stoneLarge; + const oStoneSmall = g_Gaia.stoneSmall; + const oMetalLarge = g_Gaia.metalLarge; + const oMetalSmall = g_Gaia.metalSmall; + const oOasisTree = "gaia/tree/senegal_date_palm"; + const oDatePalm = g_Gaia.tree1; + const oSDatePalm = g_Gaia.tree2; + + const aBush1 = g_Decoratives.bushMedium; + const aBush2 = "actor|props/flora/bush_desert_dry_a.xml"; + const aBush3 = g_Decoratives.bushSmall; + const aBush4 = "actor|props/flora/plant_desert_a.xml"; + const aBushes = [aBush1, aBush2, aBush3, aBush4]; + const aDecorativeRock = g_Decoratives.rockMedium; + + const pForest = [tForestFloor + TERRAIN_SEPARATOR + oDatePalm, + tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, tForestFloor]; + const pForestOasis = [tGrass + TERRAIN_SEPARATOR + oOasisTree, tGrass + TERRAIN_SEPARATOR + oDatePalm, + tGrass]; + + const heightLand = 10; + + const heightOffsetOasis = -11; + const heightOffsetHill1 = 16; + const heightOffsetHill2 = 16; + const heightOffsetHill3 = 16; + const heightOffsetBump = 2; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill1 = g_Map.createTileClass(); + const clOasis = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clPatch = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + const oasisRadius = scaleByMapSize(14, 40); + + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + + if (!isNomad()) + for (let i = 0; i < numPlayers; ++i) + createArea( + new ClumpPlacer(diskArea(defaultPlayerBaseRadius()), 0.9, 0.5, Infinity, + playerPosition[i]), + new TileClassPainter(clPlayer)); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tCity, + "innerTerrain": tCityPlaza, + "width": 3, + "radius": 10 + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oDatePalm + } + // No decoratives + }); + yield 10; + + g_Map.log("Creating dune patches"); + createAreas( + new ClumpPlacer(scaleByMapSize(40, 150), 0.2, 0.1, 0), + [ + new TerrainPainter(tDunes), + new TileClassPainter(clPatch) + ], + avoidClasses(clPatch, 2, clPlayer, 0), + scaleByMapSize(5, 20)); + yield 15; + + g_Map.log("Creating sand patches"); + createAreas( + new ClumpPlacer(scaleByMapSize(25, 100), 0.2, 0.1, 0), + [ + new TerrainPainter([tSand, tFineSand]), + new TileClassPainter(clPatch) + ], + avoidClasses(clPatch, 2, clPlayer, 0), + scaleByMapSize(15, 50)); + yield 20; + + g_Map.log("Creating dirt patches"); + createAreas( + new ClumpPlacer(scaleByMapSize(25, 100), 0.2, 0.1, 0), + [ + new TerrainPainter([tDirt]), + new TileClassPainter(clPatch) + ], + avoidClasses(clPatch, 2, clPlayer, 0), + scaleByMapSize(15, 50)); + yield 25; + + g_Map.log("Creating oasis"); + createArea( + new ClumpPlacer(diskArea(oasisRadius), 0.6, 0.15, 0, mapCenter), + [ + new LayeredPainter([[tSand, pForest], [tGrassSand25, pForestOasis], tGrassSand25, tShore, + tWaterDeep], [2, 3, 1, 1]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetOasis, 8), + new TileClassPainter(clOasis) + ]); + + yield 30; + + g_Map.log("Creating oasis wildlife"); + let num = Math.round(Math.PI * oasisRadius / 8); + let constraint = new AndConstraint([borderClasses(clOasis, 0, 3), avoidClasses(clOasis, 0)]); + for (let i = 0; i < num; ++i) + { + let animalPosition; + let r = 0; + const angle = 2 * Math.PI / num * i; + do { + // Work outward until constraint met + animalPosition = Vector2D.add(mapCenter, new Vector2D(r, 0).rotate(-angle)).round(); + ++r; + } while (!constraint.allows(animalPosition) && r < mapSize / 2); + + createObjectGroup( + new RandomGroup( + [ + new SimpleObject(oGiraffe, 2, 4, 0, 3), + new SimpleObject(oWildebeest, 3,5, 0,3), + new SimpleObject(oGazelle, 5,7, 0,3) + ], + true, + clFood, + animalPosition), + 0); + } + + g_Map.log("Creating oasis fish"); + constraint = new AndConstraint([borderClasses(clOasis, 15, 0), avoidClasses(clFood, 5)]); + num = Math.round(Math.PI * oasisRadius / 16); + for (let i = 0; i < num; ++i) + { + let fishPosition; + let r = 0; + const angle = 2 * Math.PI / num * i; + do { + // Work outward until constraint met + fishPosition = Vector2D.add(mapCenter, new Vector2D(r, 0).rotate(-angle)); + ++r; + } while (!constraint.allows(fishPosition) && r < mapSize / 2); + + createObjectGroup(new SimpleGroup([new SimpleObject(oFish, 1, 1, 0, 1)], true, clFood, + fishPosition), 0); + } + yield 35; + + g_Map.log("Creating level 1 hills"); + let hillAreas = createAreas( + new ClumpPlacer(scaleByMapSize(50,300), 0.25, 0.1, 0.5), + [ + new LayeredPainter([tCliff, tSand], [1]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetHill1, 1), + new TileClassPainter(clHill1) + ], + avoidClasses(clOasis, 3, clPlayer, 0, clHill1, 10), + scaleByMapSize(10,20), 100 + ); + yield 40; + + g_Map.log("Creating small level 1 hills"); + hillAreas = hillAreas.concat( + createAreas( + new ClumpPlacer(scaleByMapSize(25,150), 0.25, 0.1, 0.5), [ - new SimpleObject(oGiraffe, 2, 4, 0, 3), - new SimpleObject(oWildebeest, 3,5, 0,3), - new SimpleObject(oGazelle, 5,7, 0,3) + new LayeredPainter([tCliff, tSand], [1]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetHill2, 1), + new TileClassPainter(clHill1) ], - true, - clFood, - animalPosition), - 0); -} + avoidClasses(clOasis, 3, clPlayer, 0, clHill1, 3), + scaleByMapSize(15,25), + 100)); + + yield 45; + + g_Map.log("Creating decorative rocks"); + createObjectGroupsByAreasDeprecated( + new SimpleGroup( + [new RandomObject([aDecorativeRock, aBush2, aBush3], 3, 8, 0, 2)], + true), + 0, + borderClasses(clHill1, 0, 3), + scaleByMapSize(40,200), 50, + hillAreas); + + yield 50; + + g_Map.log("Creating level 2 hills"); + createAreasInAreas( + new ClumpPlacer(scaleByMapSize(25, 150), 0.25, 0.1, 0), + [ + new LayeredPainter([tCliff, tSand], [1]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetHill2, 1) + ], + [stayClasses(clHill1, 0)], + scaleByMapSize(15, 25), + 50, + hillAreas); -g_Map.log("Creating oasis fish"); -constraint = new AndConstraint([borderClasses(clOasis, 15, 0), avoidClasses(clFood, 5)]); -num = Math.round(Math.PI * oasisRadius / 16); -for (let i = 0; i < num; ++i) -{ - let fishPosition; - let r = 0; - const angle = 2 * Math.PI / num * i; - do { - // Work outward until constraint met - fishPosition = Vector2D.add(mapCenter, new Vector2D(r, 0).rotate(-angle)); - ++r; - } while (!constraint.allows(fishPosition) && r < mapSize / 2); - - createObjectGroup(new SimpleGroup([new SimpleObject(oFish, 1, 1, 0, 1)], true, clFood, fishPosition), 0); -} -Engine.SetProgress(35); - -g_Map.log("Creating level 1 hills"); -let hillAreas = createAreas( - new ClumpPlacer(scaleByMapSize(50,300), 0.25, 0.1, 0.5), - [ - new LayeredPainter([tCliff, tSand], [1]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetHill1, 1), - new TileClassPainter(clHill1) - ], - avoidClasses(clOasis, 3, clPlayer, 0, clHill1, 10), - scaleByMapSize(10,20), 100 -); -Engine.SetProgress(40); - -g_Map.log("Creating small level 1 hills"); -hillAreas = hillAreas.concat( + yield 55; + + g_Map.log("Creating level 3 hills"); createAreas( - new ClumpPlacer(scaleByMapSize(25,150), 0.25, 0.1, 0.5), + new ClumpPlacer(scaleByMapSize(12, 75), 0.25, 0.1, 0), [ new LayeredPainter([tCliff, tSand], [1]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetHill2, 1), - new TileClassPainter(clHill1) + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetHill3, 1) ], - avoidClasses(clOasis, 3, clPlayer, 0, clHill1, 3), + [stayClasses(clHill1, 0)], scaleByMapSize(15,25), - 100)); - -Engine.SetProgress(45); - -g_Map.log("Creating decorative rocks"); -createObjectGroupsByAreasDeprecated( - new SimpleGroup( - [new RandomObject([aDecorativeRock, aBush2, aBush3], 3, 8, 0, 2)], - true), - 0, - borderClasses(clHill1, 0, 3), - scaleByMapSize(40,200), 50, - hillAreas); - -Engine.SetProgress(50); - -g_Map.log("Creating level 2 hills"); -createAreasInAreas( - new ClumpPlacer(scaleByMapSize(25, 150), 0.25, 0.1, 0), - [ - new LayeredPainter([tCliff, tSand], [1]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetHill2, 1) - ], - [stayClasses(clHill1, 0)], - scaleByMapSize(15, 25), - 50, - hillAreas); - -Engine.SetProgress(55); - -g_Map.log("Creating level 3 hills"); -createAreas( - new ClumpPlacer(scaleByMapSize(12, 75), 0.25, 0.1, 0), - [ - new LayeredPainter([tCliff, tSand], [1]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetHill3, 1) - ], - [stayClasses(clHill1, 0)], - scaleByMapSize(15,25), - 50 -); -Engine.SetProgress(60); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 0), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - avoidClasses(clOasis, 0, clPlayer, 0, clHill1, 2), - scaleByMapSize(100, 200) -); - -Engine.SetProgress(65); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.5); -num = g_DefaultNumberOfForests; -createAreas( - new ClumpPlacer(forestTrees / num, 0.15, 0.1, 0.5), - [ - new TerrainPainter([tSand, pForest]), - new TileClassPainter(clForest) - ], - avoidClasses(clPlayer, 1, clOasis, 10, clForest, 10, clHill1, 1), - num, - 50); - -Engine.SetProgress(70); -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - avoidClasses(clOasis, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill1, 1) -); - -g_Map.log("Creating stone mines"); -createBalancedStoneMines( - oStoneSmall, - oStoneLarge, - clRock, - avoidClasses(clOasis, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill1, 1, clMetal, 10) -); -Engine.SetProgress(80); - -g_Map.log("Creating gazelles"); -let group = new SimpleGroup([new SimpleObject(oGazelle, 5,7, 0,4)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clOasis, 1, clForest, 0, clPlayer, 5, clHill1, 1, clFood, 10), - scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating goats"); -group = new SimpleGroup([new SimpleObject(oGoat, 2,4, 0,3)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clOasis, 1, clForest, 0, clPlayer, 5, clHill1, 1, clFood, 10), - scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating camels"); -group = new SimpleGroup([new SimpleObject(oCamel, 2,4, 0,2)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clOasis, 1, clForest, 0, clPlayer, 5, clHill1, 1, clFood, 10), - scaleByMapSize(5,20), 50 -); -Engine.SetProgress(85); - -createStragglerTrees( - [oDatePalm, oSDatePalm], - avoidClasses(clOasis, 1, clForest, 0, clHill1, 1, clPlayer, 4, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); -Engine.SetProgress(90); - -g_Map.log("Creating bushes"); -group = new SimpleGroup([new RandomObject(aBushes, 2,3, 0,2)]); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clOasis, 1, clHill1, 1, clPlayer, 0, clForest, 0), - scaleByMapSize(16, 262) -); - -g_Map.log("Creating more decorative rocks"); -group = new SimpleGroup([new SimpleObject(aDecorativeRock, 1,2, 0,2)]); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clOasis, 1, clHill1, 1, clPlayer, 0, clForest, 0), - scaleByMapSize(16, 262) -); - -placePlayersNomad(clPlayer, avoidClasses(clOasis, 4, clForest, 1, clMetal, 4, clRock, 4, clHill1, 4, clFood, 2)); - -setWaterWaviness(1.0); -setWaterType("clap"); -setWaterHeight(20); - -g_Map.ExportMap(); + 50 + ); + yield 60; + + g_Map.log("Creating bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, 0), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + avoidClasses(clOasis, 0, clPlayer, 0, clHill1, 2), + scaleByMapSize(100, 200) + ); + + yield 65; + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.5); + num = g_DefaultNumberOfForests; + createAreas( + new ClumpPlacer(forestTrees / num, 0.15, 0.1, 0.5), + [ + new TerrainPainter([tSand, pForest]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 1, clOasis, 10, clForest, 10, clHill1, 1), + num, + 50); + + yield 70; + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + avoidClasses(clOasis, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill1, 1) + ); + + g_Map.log("Creating stone mines"); + createBalancedStoneMines( + oStoneSmall, + oStoneLarge, + clRock, + avoidClasses(clOasis, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill1, 1, clMetal, 10) + ); + yield 80; + + g_Map.log("Creating gazelles"); + let group = new SimpleGroup([new SimpleObject(oGazelle, 5,7, 0,4)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clOasis, 1, clForest, 0, clPlayer, 5, clHill1, 1, clFood, 10), + scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating goats"); + group = new SimpleGroup([new SimpleObject(oGoat, 2,4, 0,3)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clOasis, 1, clForest, 0, clPlayer, 5, clHill1, 1, clFood, 10), + scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating camels"); + group = new SimpleGroup([new SimpleObject(oCamel, 2,4, 0,2)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clOasis, 1, clForest, 0, clPlayer, 5, clHill1, 1, clFood, 10), + scaleByMapSize(5,20), 50 + ); + yield 85; + + createStragglerTrees( + [oDatePalm, oSDatePalm], + avoidClasses(clOasis, 1, clForest, 0, clHill1, 1, clPlayer, 4, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + yield 90; + + g_Map.log("Creating bushes"); + group = new SimpleGroup([new RandomObject(aBushes, 2,3, 0,2)]); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clOasis, 1, clHill1, 1, clPlayer, 0, clForest, 0), + scaleByMapSize(16, 262) + ); + + g_Map.log("Creating more decorative rocks"); + group = new SimpleGroup([new SimpleObject(aDecorativeRock, 1,2, 0,2)]); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clOasis, 1, clHill1, 1, clPlayer, 0, clForest, 0), + scaleByMapSize(16, 262) + ); + + placePlayersNomad(clPlayer, avoidClasses(clOasis, 4, clForest, 1, clMetal, 4, clRock, 4, clHill1, 4, + clFood, 2)); + + setWaterWaviness(1.0); + setWaterType("clap"); + setWaterHeight(20); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/new_rms_test.js =================================================================== --- binaries/data/mods/public/maps/random/new_rms_test.js +++ binaries/data/mods/public/maps/random/new_rms_test.js @@ -1,12 +1,15 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const g_Map = new RandomMap(0, "grass1_spring"); +function* GenerateMap() +{ + global.g_Map = new RandomMap(0, "grass1_spring"); -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.39)) -}); + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.39)) + }); -placePlayersNomad(g_Map.createTileClass()); + placePlayersNomad(g_Map.createTileClass()); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/ngorongoro.js =================================================================== --- binaries/data/mods/public/maps/random/ngorongoro.js +++ binaries/data/mods/public/maps/random/ngorongoro.js @@ -21,554 +21,562 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setBiome("generic/savanna"); - -// ["dirta","savanna_wash_a","savanna_dirt_b","savanna_riparian_bank","savanna_grass_b","grass b soft dirt 50","grass1_spring","grass_field","grass1_spring","savanna_grass_a_wetseason","savanna_grass_b_wetseason","savanna_grass_a","new_savanna_grass_a","new_savanna_grass_b","new_savanna_grass_c","steppe_grass_dirt_66","peat_temp"]; - -g_Terrains.roadWild = "savanna_riparian_dry"; -g_Terrains.road = "road2"; - -g_Gaia.metalLarge = "gaia/ore/savanna_large"; -g_Gaia.metalSmall = "gaia/ore/tropical_small"; -g_Gaia.fish = "gaia/fish/tilapia"; -g_Gaia.tree1 = "gaia/tree/baobab"; -g_Gaia.tree2 = "gaia/tree/baobab"; -g_Gaia.tree3 = "gaia/tree/baobab"; -g_Gaia.tree4 = "gaia/tree/baobab"; -g_Gaia.tree5 = "gaia/tree/baobab"; - -g_Decoratives.grass = "actor|props/flora/grass_savanna.xml"; -g_Decoratives.grassShort = "actor|props/flora/grass_soft_dry_tuft_a.xml"; -g_Decoratives.rockLarge = "actor|geology/stone_savanna_med.xml"; -g_Decoratives.rockMedium = "actor|geology/stone_savanna_med.xml"; -g_Decoratives.bushMedium = "actor|props/flora/bush_desert_dry_a.xml"; -g_Decoratives.bushSmall = "actor|props/flora/bush_dry_a.xml"; - -const heightScale = num => num * g_MapSettings.Size / 320; - -const heightHighlands = heightScale(45); -const heightEden = heightScale(60); -const heightMax = 150; - -function setBiomeLowlands() -{ - g_Gaia.mainHuntableAnimal = "gaia/fauna_giraffe"; - g_Gaia.secondaryHuntableAnimal = "gaia/fauna_zebra"; - - g_Terrains.mainTerrain = "savanna_riparian_bank"; - g_Terrains.forestFloor1 = "savanna_dirt_rocks_b"; - g_Terrains.forestFloor2 = "savanna_dirt_rocks_c"; - g_Terrains.tier1Terrain = "savanna_dirt_rocks_a"; - g_Terrains.tier2Terrain = "savanna_grass_a"; - g_Terrains.tier3Terrain = "savanna_grass_b"; - g_Terrains.tier4Terrain = "savanna_forest_floor_a"; -} - -function setBiomeHighlands() -{ - - g_Gaia.mainHuntableAnimal = "gaia/fauna_lioness"; - g_Gaia.secondaryHuntableAnimal = "gaia/fauna_lion"; - - g_Terrains.mainTerrain = "savanna_grass_a_wetseason"; - g_Terrains.forestFloor1 = "savanna_grass_a"; - g_Terrains.forestFloor2 = "savanna_grass_b"; - g_Terrains.tier1Terrain = "savanna_grass_a_wetseason"; - g_Terrains.tier2Terrain = "savanna_grass_b_wetseason"; - g_Terrains.tier3Terrain = "savanna_shrubs_a_wetseason"; - g_Terrains.tier4Terrain = "savanna_shrubs_b"; -} - -function setBiomeEden() -{ - g_Gaia.mainHuntableAnimal = "gaia/fauna_rhinoceros_white"; - g_Gaia.secondaryHuntableAnimal = "gaia/fauna_elephant_african_bush"; -} - -const g_Map = new RandomMap(0, g_Terrains.mainTerrain); -const mapCenter = g_Map.getCenter(); - -initTileClasses(["eden", "highlands"]); - -g_Map.LoadHeightmapImage("ngorongoro.png", 0, heightMax); -Engine.SetProgress(15); - -g_Map.log("Smoothing heightmap"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, scaleByMapSize(0.1, 0.5), 1)); -Engine.SetProgress(25); - -g_Map.log("Marking land"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land)); -Engine.SetProgress(40); - -g_Map.log("Marking eden"); -createArea( - new DiskPlacer(fractionToTiles(0.14), mapCenter), - new TileClassPainter(g_TileClasses.eden), - new HeightConstraint(-Infinity, heightEden)); -Engine.SetProgress(45); - -g_Map.log("Marking highlands"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.highlands), - [ - new HeightConstraint(heightHighlands, Infinity), - avoidClasses(g_TileClasses.eden, 0) - ]); -Engine.SetProgress(50); - -g_Map.log("Painting cliffs"); -createArea( - new MapBoundsPlacer(), - [ - new TerrainPainter(g_Terrains.cliff), - new TileClassPainter(g_TileClasses.mountain), - ], - new SlopeConstraint(2, Infinity)); -Engine.SetProgress(55); - -if (!isNomad()) +function* GenerateMap(mapSettings) { - g_Map.log("Placing players"); - const [playerIDs, playerPosition] = createBases( - ...playerPlacementRandom( - sortAllPlayers(), - [ - avoidClasses( - g_TileClasses.mountain, 5, - g_TileClasses.highlands, 5, - g_TileClasses.eden, 5), - stayClasses(g_TileClasses.land, defaultPlayerBaseRadius()) - ]), - true); - - g_Map.log("Flatten the initial CC area"); - for (const position of playerPosition) - createArea( - new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, position), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); -} - -g_Map.log("Render lowlands"); -setBiomeLowlands(); -addElements([ + setBiome("generic/savanna"); + + // ["dirta","savanna_wash_a","savanna_dirt_b","savanna_riparian_bank","savanna_grass_b", + // "grass b soft dirt 50","grass1_spring","grass_field","grass1_spring", + // "savanna_grass_a_wetseason","savanna_grass_b_wetseason","savanna_grass_a", + // "new_savanna_grass_a","new_savanna_grass_b","new_savanna_grass_c","steppe_grass_dirt_66", + // "peat_temp"]; + + g_Terrains.roadWild = "savanna_riparian_dry"; + g_Terrains.road = "road2"; + + g_Gaia.metalLarge = "gaia/ore/savanna_large"; + g_Gaia.metalSmall = "gaia/ore/tropical_small"; + g_Gaia.fish = "gaia/fish/tilapia"; + g_Gaia.tree1 = "gaia/tree/baobab"; + g_Gaia.tree2 = "gaia/tree/baobab"; + g_Gaia.tree3 = "gaia/tree/baobab"; + g_Gaia.tree4 = "gaia/tree/baobab"; + g_Gaia.tree5 = "gaia/tree/baobab"; + + g_Decoratives.grass = "actor|props/flora/grass_savanna.xml"; + g_Decoratives.grassShort = "actor|props/flora/grass_soft_dry_tuft_a.xml"; + g_Decoratives.rockLarge = "actor|geology/stone_savanna_med.xml"; + g_Decoratives.rockMedium = "actor|geology/stone_savanna_med.xml"; + g_Decoratives.bushMedium = "actor|props/flora/bush_desert_dry_a.xml"; + g_Decoratives.bushSmall = "actor|props/flora/bush_dry_a.xml"; + + const heightScale = num => num * mapSettings.Size / 320; + + const heightHighlands = heightScale(45); + const heightEden = heightScale(60); + const heightMax = 150; + + function setBiomeLowlands() { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.eden, 2, - g_TileClasses.highlands, 2 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.eden, 2, - g_TileClasses.highlands, 2 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] + g_Gaia.mainHuntableAnimal = "gaia/fauna_giraffe"; + g_Gaia.secondaryHuntableAnimal = "gaia/fauna_zebra"; + + g_Terrains.mainTerrain = "savanna_riparian_bank"; + g_Terrains.forestFloor1 = "savanna_dirt_rocks_b"; + g_Terrains.forestFloor2 = "savanna_dirt_rocks_c"; + g_Terrains.tier1Terrain = "savanna_dirt_rocks_a"; + g_Terrains.tier2Terrain = "savanna_grass_a"; + g_Terrains.tier3Terrain = "savanna_grass_b"; + g_Terrains.tier4Terrain = "savanna_forest_floor_a"; } -]); -addElements(shuffleArray([ - { - "func": addSmallMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 6, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 10, - g_TileClasses.eden, 2, - g_TileClasses.highlands, 2 - - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["few"] - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 6, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 10, - g_TileClasses.eden, 2, - g_TileClasses.highlands, 2 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["scarce"] - }, + function setBiomeHighlands() { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 8, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 6, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.eden, 2, - g_TileClasses.highlands, 2 - ], - "sizes": ["normal"], - "mixes": ["similar"], - "amounts": ["normal"] - } -])); - -addElements(shuffleArray([ - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 6, - g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.eden, 2, - g_TileClasses.highlands, 2 - ], - "sizes": ["big"], - "mixes": ["similar"], - "amounts": ["many"] - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 6, - g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.eden, 2, - g_TileClasses.highlands, 2 - ], - "sizes": ["normal"], - "mixes": ["unique"], - "amounts": ["many"] - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 4, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 6, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.eden, 2, - g_TileClasses.highlands, 2 - ], - "sizes": ["big"], - "mixes": ["same"], - "amounts": ["many"] - } -])); -Engine.SetProgress(60); -g_Map.log("Render highlands"); -setBiomeHighlands(); -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12 - ], - "stay": [g_TileClasses.highlands, 2], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12 - ], - "stay": [g_TileClasses.highlands, 2], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] - } -]); + g_Gaia.mainHuntableAnimal = "gaia/fauna_lioness"; + g_Gaia.secondaryHuntableAnimal = "gaia/fauna_lion"; -addElements(shuffleArray([ - { - "func": addSmallMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 3, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.metal, 20 - ], - "stay": [g_TileClasses.highlands, 2], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 3, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 10 - ], - "stay": [g_TileClasses.highlands, 2], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 8, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 3, - g_TileClasses.player, 20, - g_TileClasses.rock, 3 - ], - "stay": [g_TileClasses.highlands, 2], - "sizes": ["huge"], - "mixes": ["similar"], - "amounts": ["many"] + g_Terrains.mainTerrain = "savanna_grass_a_wetseason"; + g_Terrains.forestFloor1 = "savanna_grass_a"; + g_Terrains.forestFloor2 = "savanna_grass_b"; + g_Terrains.tier1Terrain = "savanna_grass_a_wetseason"; + g_Terrains.tier2Terrain = "savanna_grass_b_wetseason"; + g_Terrains.tier3Terrain = "savanna_shrubs_a_wetseason"; + g_Terrains.tier4Terrain = "savanna_shrubs_b"; } -])); -addElements(shuffleArray([ + function setBiomeEden() { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 3, - g_TileClasses.player, 20, - g_TileClasses.rock, 2 - ], - "stay": [g_TileClasses.highlands, 2], - "sizes": ["huge"], - "mixes": ["same"], - "amounts": ["many"] - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 3, - g_TileClasses.player, 12, - g_TileClasses.rock, 2 - ], - "stay": [g_TileClasses.highlands, 2], - "sizes": ["huge"], - "mixes": ["same"], - "amounts": ["many"] + g_Gaia.mainHuntableAnimal = "gaia/fauna_rhinoceros_white"; + g_Gaia.secondaryHuntableAnimal = "gaia/fauna_elephant_african_bush"; } -])); -Engine.SetProgress(70); -g_Map.log("Render eden"); -setBiomeEden(); -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12 - ], - "stay": [g_TileClasses.eden, 2], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12 + global.g_Map = new RandomMap(0, g_Terrains.mainTerrain); + const mapCenter = g_Map.getCenter(); + + initTileClasses(["eden", "highlands"]); + + g_Map.LoadHeightmapImage("ngorongoro.png", 0, heightMax); + yield 15; + + g_Map.log("Smoothing heightmap"); + createArea( + new MapBoundsPlacer(), + new SmoothingPainter(1, scaleByMapSize(0.1, 0.5), 1)); + yield 25; + + g_Map.log("Marking land"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land)); + yield 40; + + g_Map.log("Marking eden"); + createArea( + new DiskPlacer(fractionToTiles(0.14), mapCenter), + new TileClassPainter(g_TileClasses.eden), + new HeightConstraint(-Infinity, heightEden)); + yield 45; + + g_Map.log("Marking highlands"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.highlands), + [ + new HeightConstraint(heightHighlands, Infinity), + avoidClasses(g_TileClasses.eden, 0) + ]); + yield 50; + + g_Map.log("Painting cliffs"); + createArea( + new MapBoundsPlacer(), + [ + new TerrainPainter(g_Terrains.cliff), + new TileClassPainter(g_TileClasses.mountain), ], - "stay": [g_TileClasses.eden, 2], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] - } -]); + new SlopeConstraint(2, Infinity)); + yield 55; -addElements(shuffleArray([ + if (!isNomad()) { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.metal, 3 - ], - "stay": [g_TileClasses.eden, 2], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["tons"] - }, - { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.metal, 3 - ], - "stay": [g_TileClasses.eden, 2], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["tons"] - }, - { - "func": addSmallMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.metal, 3 - ], - "stay": [g_TileClasses.eden, 2], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["tons"] - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 3, - g_TileClasses.metal, 3 - ], - "stay": [g_TileClasses.eden, 2], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["few"] - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 8, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 8, - g_TileClasses.player, 20, - g_TileClasses.rock, 3 - ], - "stay": [g_TileClasses.eden, 2], - "sizes": ["huge"], - "mixes": ["similar"], - "amounts": ["scarce"] + g_Map.log("Placing players"); + const [playerIDs, playerPosition] = createBases( + ...playerPlacementRandom( + sortAllPlayers(), + [ + avoidClasses( + g_TileClasses.mountain, 5, + g_TileClasses.highlands, 5, + g_TileClasses.eden, 5), + stayClasses(g_TileClasses.land, defaultPlayerBaseRadius()) + ]), + true); + + g_Map.log("Flatten the initial CC area"); + for (const position of playerPosition) + createArea( + new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, + position), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); } -])); -addElements(shuffleArray([ - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 2, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 3, - g_TileClasses.player, 20, - g_TileClasses.rock, 2 - ], - "stay": [g_TileClasses.eden, 2], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 8, - g_TileClasses.player, 12, - g_TileClasses.rock, 2 - ], - "stay": [g_TileClasses.eden, 2], - "sizes": ["huge"], - "mixes": ["same"], - "amounts": ["scarce"] - } -])); -Engine.SetProgress(80); - -placePlayersNomad( - g_Map.createTileClass(), - [ - stayClasses(g_TileClasses.land, 5), - avoidClasses( - g_TileClasses.forest, 2, - g_TileClasses.rock, 4, - g_TileClasses.metal, 4, - g_TileClasses.berries, 2, - g_TileClasses.animals, 2, - g_TileClasses.mountain, 2) + g_Map.log("Render lowlands"); + setBiomeLowlands(); + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.eden, 2, + g_TileClasses.highlands, 2 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.eden, 2, + g_TileClasses.highlands, 2 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + } ]); -setAmbientColor(0.521, 0.475, 0.322); - -setSunColor(0.733, 0.746, 0.574); -setSunRotation(Math.PI); -setSunElevation(1/2); - -setFogFactor(0); -setFogThickness(0); -setFogColor(0.69, 0.616, 0.541); + addElements(shuffleArray([ + { + "func": addSmallMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 6, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10, + g_TileClasses.eden, 2, + g_TileClasses.highlands, 2 + + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["few"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 6, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10, + g_TileClasses.eden, 2, + g_TileClasses.highlands, 2 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["scarce"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 8, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 6, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.eden, 2, + g_TileClasses.highlands, 2 + ], + "sizes": ["normal"], + "mixes": ["similar"], + "amounts": ["normal"] + } + ])); + + addElements(shuffleArray([ + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 6, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.eden, 2, + g_TileClasses.highlands, 2 + ], + "sizes": ["big"], + "mixes": ["similar"], + "amounts": ["many"] + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 6, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.eden, 2, + g_TileClasses.highlands, 2 + ], + "sizes": ["normal"], + "mixes": ["unique"], + "amounts": ["many"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 4, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 6, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.eden, 2, + g_TileClasses.highlands, 2 + ], + "sizes": ["big"], + "mixes": ["same"], + "amounts": ["many"] + } + ])); + yield 60; + + g_Map.log("Render highlands"); + setBiomeHighlands(); + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12 + ], + "stay": [g_TileClasses.highlands, 2], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12 + ], + "stay": [g_TileClasses.highlands, 2], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + } + ]); -setPPEffect("hdr"); -setPPContrast(0.67); -setPPSaturation(0.42); -setPPBloom(0.23); + addElements(shuffleArray([ + { + "func": addSmallMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 3, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 20 + ], + "stay": [g_TileClasses.highlands, 2], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 3, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10 + ], + "stay": [g_TileClasses.highlands, 2], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 8, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 3, + g_TileClasses.player, 20, + g_TileClasses.rock, 3 + ], + "stay": [g_TileClasses.highlands, 2], + "sizes": ["huge"], + "mixes": ["similar"], + "amounts": ["many"] + } + ])); + + addElements(shuffleArray([ + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 3, + g_TileClasses.player, 20, + g_TileClasses.rock, 2 + ], + "stay": [g_TileClasses.highlands, 2], + "sizes": ["huge"], + "mixes": ["same"], + "amounts": ["many"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 3, + g_TileClasses.player, 12, + g_TileClasses.rock, 2 + ], + "stay": [g_TileClasses.highlands, 2], + "sizes": ["huge"], + "mixes": ["same"], + "amounts": ["many"] + } + ])); + yield 70; + + g_Map.log("Render eden"); + setBiomeEden(); + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12 + ], + "stay": [g_TileClasses.eden, 2], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12 + ], + "stay": [g_TileClasses.eden, 2], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + } + ]); -g_Map.ExportMap(); + addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.metal, 3 + ], + "stay": [g_TileClasses.eden, 2], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + }, + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.metal, 3 + ], + "stay": [g_TileClasses.eden, 2], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + }, + { + "func": addSmallMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.metal, 3 + ], + "stay": [g_TileClasses.eden, 2], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 3, + g_TileClasses.metal, 3 + ], + "stay": [g_TileClasses.eden, 2], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["few"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 8, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 8, + g_TileClasses.player, 20, + g_TileClasses.rock, 3 + ], + "stay": [g_TileClasses.eden, 2], + "sizes": ["huge"], + "mixes": ["similar"], + "amounts": ["scarce"] + } + ])); + + addElements(shuffleArray([ + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 2, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 3, + g_TileClasses.player, 20, + g_TileClasses.rock, 2 + ], + "stay": [g_TileClasses.eden, 2], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 8, + g_TileClasses.player, 12, + g_TileClasses.rock, 2 + ], + "stay": [g_TileClasses.eden, 2], + "sizes": ["huge"], + "mixes": ["same"], + "amounts": ["scarce"] + } + ])); + yield 80; + + placePlayersNomad( + g_Map.createTileClass(), + [ + stayClasses(g_TileClasses.land, 5), + avoidClasses( + g_TileClasses.forest, 2, + g_TileClasses.rock, 4, + g_TileClasses.metal, 4, + g_TileClasses.berries, 2, + g_TileClasses.animals, 2, + g_TileClasses.mountain, 2) + ]); + + setAmbientColor(0.521, 0.475, 0.322); + + setSunColor(0.733, 0.746, 0.574); + setSunRotation(Math.PI); + setSunElevation(1/2); + + setFogFactor(0); + setFogThickness(0); + setFogColor(0.69, 0.616, 0.541); + + setPPEffect("hdr"); + setPPContrast(0.67); + setPPSaturation(0.42); + setPPBloom(0.23); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/northern_lights.js =================================================================== --- binaries/data/mods/public/maps/random/northern_lights.js +++ binaries/data/mods/public/maps/random/northern_lights.js @@ -1,289 +1,298 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tSnowA = ["polar_snow_b"]; -const tSnowB = "polar_ice_snow"; -const tSnowC = "polar_ice"; -const tSnowD = "polar_snow_a"; -const tForestFloor = "polar_tundra_snow"; -const tCliff = "polar_snow_rocks"; -const tSnowE = ["polar_snow_glacial"]; -const tRoad = "new_alpine_citytile"; -const tRoadWild = "new_alpine_citytile"; -const tShoreBlend = "alpine_shore_rocks_icy"; -const tShore = "alpine_shore_rocks"; -const tWater = "alpine_shore_rocks"; - -const oPine = "gaia/tree/pine_w"; -const oStoneLarge = "gaia/rock/alpine_large"; -const oStoneSmall = "gaia/rock/alpine_small"; -const oMetalLarge = "gaia/ore/alpine_large"; -const oFish = "gaia/fish/generic"; -const oWalrus = "gaia/fauna_walrus"; -const oArcticWolf = "gaia/fauna_wolf_arctic"; - -const aIceberg = "actor|props/special/eyecandy/iceberg.xml"; - -const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor, tForestFloor]; -const pForestS = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor, tForestFloor, tForestFloor]; - -const heightSeaGround = -5; -const heightLake = -4; -const heightLand = 3; -const heightHill = 25; - -const g_Map = new RandomMap(heightLand, tSnowA); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clIsland = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -const startAngle = randomAngle(); - -placePlayerBases({ - "PlayerPlacement": [ - sortAllPlayers(), - playerPlacementLine(0, new Vector2D(mapCenter.x, fractionToTiles(0.45)), fractionToTiles(0.2)).map( - pos => pos.rotateAround(startAngle, mapCenter)) - ], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - // No chicken, no berries - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oPine, - "count": scaleByMapSize(12, 30), - } - // No decoratives -}); -Engine.SetProgress(15); - -paintRiver({ - "parallel": true, - "start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(startAngle, mapCenter), - "end": new Vector2D(mapBounds.right, mapBounds.top).rotateAround(startAngle, mapCenter), - "width": 2 * fractionToTiles(0.31), - "fadeDist": 8, - "deviation": 0, - "heightRiverbed": heightSeaGround, - "heightLand": heightLand, - "meanderShort": 0, - "meanderLong": 0 -}); - -paintTileClassBasedOnHeight(-Infinity, 0.5, Elevation_ExcludeMin_ExcludeMax, clWater); - -g_Map.log("Creating shores"); -for (let i = 0; i < scaleByMapSize(20, 120); ++i) +function* GenerateMap() { - const position = new Vector2D(fractionToTiles(randFloat(0.1, 0.9)), fractionToTiles(randFloat(0.67, 0.74))).rotateAround(startAngle, mapCenter).round(); - createArea( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 30)), Infinity, position), + const tSnowA = ["polar_snow_b"]; + const tSnowB = "polar_ice_snow"; + const tSnowC = "polar_ice"; + const tSnowD = "polar_snow_a"; + const tForestFloor = "polar_tundra_snow"; + const tCliff = "polar_snow_rocks"; + const tSnowE = ["polar_snow_glacial"]; + const tRoad = "new_alpine_citytile"; + const tRoadWild = "new_alpine_citytile"; + const tShoreBlend = "alpine_shore_rocks_icy"; + const tShore = "alpine_shore_rocks"; + const tWater = "alpine_shore_rocks"; + + const oPine = "gaia/tree/pine_w"; + const oStoneLarge = "gaia/rock/alpine_large"; + const oStoneSmall = "gaia/rock/alpine_small"; + const oMetalLarge = "gaia/ore/alpine_large"; + const oFish = "gaia/fish/generic"; + const oWalrus = "gaia/fauna_walrus"; + const oArcticWolf = "gaia/fauna_wolf_arctic"; + + const aIceberg = "actor|props/special/eyecandy/iceberg.xml"; + + const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor, tForestFloor]; + const pForestS = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor, tForestFloor, tForestFloor]; + + const heightSeaGround = -5; + const heightLake = -4; + const heightLand = 3; + const heightHill = 25; + + global.g_Map = new RandomMap(heightLand, tSnowA); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clIsland = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + const startAngle = randomAngle(); + + placePlayerBases({ + "PlayerPlacement": [ + sortAllPlayers(), + playerPlacementLine(0, + new Vector2D(mapCenter.x, fractionToTiles(0.45)), fractionToTiles(0.2)).map( + pos => pos.rotateAround(startAngle, mapCenter)) + ], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + // No chicken, no berries + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oPine, + "count": scaleByMapSize(12, 30), + } + // No decoratives + }); + yield 15; + + paintRiver({ + "parallel": true, + "start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(startAngle, mapCenter), + "end": new Vector2D(mapBounds.right, mapBounds.top).rotateAround(startAngle, mapCenter), + "width": 2 * fractionToTiles(0.31), + "fadeDist": 8, + "deviation": 0, + "heightRiverbed": heightSeaGround, + "heightLand": heightLand, + "meanderShort": 0, + "meanderLong": 0 + }); + + paintTileClassBasedOnHeight(-Infinity, 0.5, Elevation_ExcludeMin_ExcludeMax, clWater); + + g_Map.log("Creating shores"); + for (let i = 0; i < scaleByMapSize(20, 120); ++i) + { + const position = new Vector2D(fractionToTiles(randFloat(0.1, 0.9)), + fractionToTiles(randFloat(0.67, 0.74))).rotateAround(startAngle, mapCenter).round(); + createArea( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 30)), + Infinity, position), + [ + new TerrainPainter(tSnowA), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), + new TileClassUnPainter(clWater) + ]); + } + + g_Map.log("Creating islands"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.1), [ new TerrainPainter(tSnowA), new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), + new TileClassPainter(clIsland), new TileClassUnPainter(clWater) - ]); -} - -g_Map.log("Creating islands"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.1), - [ - new TerrainPainter(tSnowA), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), - new TileClassPainter(clIsland), - new TileClassUnPainter(clWater) - ], - stayClasses(clWater, 7), - scaleByMapSize(10, 80)); - -paintTerrainBasedOnHeight(-6, 1, 1, tWater); - -g_Map.log("Creating lakes"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(5, 7)), Math.floor(scaleByMapSize(20, 50)), 0.1), - [ - new LayeredPainter([tShoreBlend, tShore, tWater], [1, 1]), - new SmoothElevationPainter(ELEVATION_SET, heightLake, 3), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 20, clWater, 20), - Math.round(scaleByMapSize(1, 4) * numPlayers)); - -paintTerrainBasedOnHeight(1, 2.8, 1, tShoreBlend); -paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); - -Engine.SetProgress(45); - -g_Map.log("Creating hills"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.1), - [ - new LayeredPainter([tCliff, tSnowA], [3]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 3), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 20, clHill, 15, clWater, 2, clBaseResource, 2), - scaleByMapSize(1, 4) * numPlayers -); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(100, 625, 0.7); -const types = [ - [[tSnowA, tSnowA, tSnowA, tSnowA, pForestD], [tSnowA, tSnowA, tSnowA, pForestD]], - [[tSnowA, tSnowA, tSnowA, tSnowA, pForestS], [tSnowA, tSnowA, tSnowA, pForestS]] -]; - -const forestSize = forestTrees / (scaleByMapSize(3,6) * numPlayers); - -const num = Math.floor(forestSize / types.length); -for (const type of types) - createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), forestTrees / (num * Math.floor(scaleByMapSize(2, 4))), Infinity), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) ], - avoidClasses(clPlayer, 20, clForest, 20, clHill, 0, clWater, 8), - num); - -g_Map.log("Creating iceberg"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aIceberg, 0, 2, 0, 4)], true, clRock), - 0, - [avoidClasses(clRock, 6), stayClasses(clWater, 4)], - scaleByMapSize(4, 16), - 100); -Engine.SetProgress(70); - -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) + stayClasses(clWater, 7), + scaleByMapSize(10, 80)); + + paintTerrainBasedOnHeight(-6, 1, 1, tWater); + + g_Map.log("Creating lakes"); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), + new ChainPlacer(1, Math.floor(scaleByMapSize(5, 7)), Math.floor(scaleByMapSize(20, 50)), 0.1), [ - new LayeredPainter([tSnowD, tSnowB, tSnowC], [2, 1]), - new TileClassPainter(clDirt) + new LayeredPainter([tShoreBlend, tShore, tWater], [1, 1]), + new SmoothElevationPainter(ELEVATION_SET, heightLake, 3), + new TileClassPainter(clWater) ], - avoidClasses( - clWater, 8, - clForest, 0, - clHill, 0, - clPlayer, 20, - clDirt, 16), - scaleByMapSize(20, 80)); - -for (const size of [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]) + avoidClasses(clPlayer, 20, clWater, 20), + Math.round(scaleByMapSize(1, 4) * numPlayers)); + + paintTerrainBasedOnHeight(1, 2.8, 1, tShoreBlend); + paintTileClassBasedOnHeight(-6, 0.5, 1, clWater); + + yield 45; + + g_Map.log("Creating hills"); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.1), [ - new TerrainPainter(tSnowE), - new TileClassPainter(clDirt) + new LayeredPainter([tCliff, tSnowA], [3]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 3), + new TileClassPainter(clHill) ], - avoidClasses( - clWater, 8, - clForest, 0, - clHill, 0, - clPlayer, 20, - clDirt, 16), - scaleByMapSize(20, 80)); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - scaleByMapSize(8,32), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - scaleByMapSize(8,32), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), - scaleByMapSize(8,32), 100 -); -Engine.SetProgress(80); - -createStragglerTrees( - [oPine], - avoidClasses(clWater, 5, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); - -g_Map.log("Creating deer"); -group = new SimpleGroup( - [new SimpleObject(oWalrus, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), - 3 * numPlayers, 50 -); - -Engine.SetProgress(90); - -g_Map.log("Creating sheep"); -group = new SimpleGroup( - [new SimpleObject(oArcticWolf, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), - 3 * numPlayers, 50 -); - -g_Map.log("Creating fish"); -group = new SimpleGroup( - [new SimpleObject(oFish, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clFood, 20), stayClasses(clWater, 6)], - 25 * numPlayers, 60 -); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2, clIsland, 4)); - -setSunColor(0.6, 0.6, 0.6); -setSunElevation(Math.PI/ 6); - -setWaterColor(0.02, 0.17, 0.52); -setWaterTint(0.494, 0.682, 0.808); -setWaterMurkiness(0.82); -setWaterWaviness(0.5); -setWaterType("ocean"); - -setFogFactor(0.95); -setFogThickness(0.09); -setPPSaturation(0.28); -setPPEffect("hdr"); - -setSkySet("fog"); -g_Map.ExportMap(); + avoidClasses(clPlayer, 20, clHill, 15, clWater, 2, clBaseResource, 2), + scaleByMapSize(1, 4) * numPlayers + ); + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(100, 625, 0.7); + const types = [ + [[tSnowA, tSnowA, tSnowA, tSnowA, pForestD], [tSnowA, tSnowA, tSnowA, pForestD]], + [[tSnowA, tSnowA, tSnowA, tSnowA, pForestS], [tSnowA, tSnowA, tSnowA, pForestS]] + ]; + + const forestSize = forestTrees / (scaleByMapSize(3,6) * numPlayers); + + const num = Math.floor(forestSize / types.length); + for (const type of types) + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), forestTrees / + (num * Math.floor(scaleByMapSize(2, 4))), Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 20, clForest, 20, clHill, 0, clWater, 8), + num); + + g_Map.log("Creating iceberg"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aIceberg, 0, 2, 0, 4)], true, clRock), + 0, + [avoidClasses(clRock, 6), stayClasses(clWater, 4)], + scaleByMapSize(4, 16), + 100); + yield 70; + + g_Map.log("Creating dirt patches"); + for (const 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([tSnowD, tSnowB, tSnowC], [2, 1]), + new TileClassPainter(clDirt) + ], + avoidClasses( + clWater, 8, + clForest, 0, + clHill, 0, + clPlayer, 20, + clDirt, 16), + scaleByMapSize(20, 80)); + + for (const 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(tSnowE), + new TileClassPainter(clDirt) + ], + avoidClasses( + clWater, 8, + clForest, 0, + clHill, 0, + clPlayer, 20, + clDirt, 16), + scaleByMapSize(20, 80)); + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + scaleByMapSize(8,32), 100 + ); + + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + scaleByMapSize(8,32), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), + scaleByMapSize(8,32), 100 + ); + yield 80; + + createStragglerTrees( + [oPine], + avoidClasses(clWater, 5, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + + g_Map.log("Creating deer"); + group = new SimpleGroup( + [new SimpleObject(oWalrus, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), + 3 * numPlayers, 50 + ); + + yield 90; + + g_Map.log("Creating sheep"); + group = new SimpleGroup( + [new SimpleObject(oArcticWolf, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 20), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating fish"); + group = new SimpleGroup( + [new SimpleObject(oFish, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clFood, 20), stayClasses(clWater, 6)], + 25 * numPlayers, 60 + ); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, + clFood, 2, clIsland, 4)); + + setSunColor(0.6, 0.6, 0.6); + setSunElevation(Math.PI/ 6); + + setWaterColor(0.02, 0.17, 0.52); + setWaterTint(0.494, 0.682, 0.808); + setWaterMurkiness(0.82); + setWaterWaviness(0.5); + setWaterType("ocean"); + + setFogFactor(0.95); + setFogThickness(0.09); + setPPSaturation(0.28); + setPPEffect("hdr"); + + setSkySet("fog"); + return g_Map; +} Index: binaries/data/mods/public/maps/random/oasis.js =================================================================== --- binaries/data/mods/public/maps/random/oasis.js +++ binaries/data/mods/public/maps/random/oasis.js @@ -1,313 +1,344 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tSand = ["desert_sand_dunes_100", "desert_dirt_cracks","desert_sand_smooth", "desert_dirt_rough", "desert_dirt_rough_2", "desert_sand_smooth"]; -const tDune = ["desert_sand_dunes_50"]; -const tForestFloor = "desert_forestfloor_palms"; -const tDirt = ["desert_dirt_rough","desert_dirt_rough","desert_dirt_rough", "desert_dirt_rough_2", "desert_dirt_rocks_2"]; -const tRoad = "desert_city_tile"; -const tRoadWild = "desert_city_tile"; -const tShore = "dirta"; -const tWater = "desert_sand_wet"; - -const ePalmShort = "gaia/tree/cretan_date_palm_short"; -const ePalmTall = "gaia/tree/cretan_date_palm_tall"; -const eBush = "gaia/fruit/grapes"; -const eCamel = "gaia/fauna_camel"; -const eGazelle = "gaia/fauna_gazelle"; -const eLion = "gaia/fauna_lion"; -const eLioness = "gaia/fauna_lioness"; -const eStoneMine = "gaia/rock/desert_large"; -const eMetalMine = "gaia/ore/desert_large"; - -const aFlower1 = "actor|props/flora/decals_flowers_daisies.xml"; -const aWaterFlower = "actor|props/flora/water_lillies.xml"; -const aReedsA = "actor|props/flora/reeds_pond_lush_a.xml"; -const aReedsB = "actor|props/flora/reeds_pond_lush_b.xml"; -const aRock = "actor|geology/stone_desert_med.xml"; -const aBushA = "actor|props/flora/bush_desert_dry_a.xml"; -const aBushB = "actor|props/flora/bush_desert_dry_a.xml"; -const aSand = "actor|particle/blowing_sand.xml"; - -const pForestMain = [tForestFloor + TERRAIN_SEPARATOR + ePalmShort, tForestFloor + TERRAIN_SEPARATOR + ePalmTall, tForestFloor]; -const pOasisForestLight = [tForestFloor + TERRAIN_SEPARATOR + ePalmShort, tForestFloor + TERRAIN_SEPARATOR + ePalmTall, tForestFloor,tForestFloor,tForestFloor - ,tForestFloor,tForestFloor,tForestFloor,tForestFloor]; - -const heightSeaGround = -3; -const heightFloraMin = -2.5; -const heightFloraReedsMax = -1.9; -const heightFloraMax = -1; -const heightLand = 1; -const heightSand = 3.4; -const heightOasisPath = 4; -const heightOffsetBump = 4; -const heightOffsetDune = 18; - -const g_Map = new RandomMap(heightLand, tSand); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clOasis = g_Map.createTileClass(); -const clPassage = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -const waterRadius = scaleByMapSize(7, 50); -const shoreDistance = scaleByMapSize(4, 10); -const forestDistance = scaleByMapSize(6, 20); - -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - -g_Map.log("Creating small oasis near the players..."); -const forestDist = 1.2 * defaultPlayerBaseRadius(); -for (let i = 0; i < numPlayers; ++i) +function* GenerateMap() { - let forestPosition; - let forestAngle; - do { - forestAngle = Math.PI / 3 * randFloat(1, 2); - forestPosition = Vector2D.add(playerPosition[i], new Vector2D(forestDist, 0).rotate(-forestAngle)); - } while ( - !createArea( - new ClumpPlacer(70, 1, 0.5, Infinity, forestPosition), - [ - new LayeredPainter([tForestFloor, pForestMain], [0]), - new TileClassPainter(clBaseResource) - ], - avoidClasses(clBaseResource, 0))); - - let waterPosition; - let flowerPosition; - let reedsPosition; - do { - const waterAngle = forestAngle + randFloat(1, 5) / 3 * Math.PI; - waterPosition = Vector2D.add(forestPosition, new Vector2D(6, 0).rotate(-waterAngle)).round(); - flowerPosition = Vector2D.add(forestPosition, new Vector2D(3, 0).rotate(-waterAngle)).round(); - reedsPosition = Vector2D.add(forestPosition, new Vector2D(5, 0).rotate(-waterAngle)).round(); - } while ( - !createArea( - new ClumpPlacer(diskArea(4.5), 0.9, 0.4, Infinity, waterPosition), - [ - new LayeredPainter([tShore, tWater], [1]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 3) + const tSand = ["desert_sand_dunes_100", "desert_dirt_cracks","desert_sand_smooth", + "desert_dirt_rough", "desert_dirt_rough_2", "desert_sand_smooth"]; + const tDune = ["desert_sand_dunes_50"]; + const tForestFloor = "desert_forestfloor_palms"; + const tDirt = ["desert_dirt_rough","desert_dirt_rough","desert_dirt_rough", "desert_dirt_rough_2", + "desert_dirt_rocks_2"]; + const tRoad = "desert_city_tile"; + const tRoadWild = "desert_city_tile"; + const tShore = "dirta"; + const tWater = "desert_sand_wet"; + + const ePalmShort = "gaia/tree/cretan_date_palm_short"; + const ePalmTall = "gaia/tree/cretan_date_palm_tall"; + const eBush = "gaia/fruit/grapes"; + const eCamel = "gaia/fauna_camel"; + const eGazelle = "gaia/fauna_gazelle"; + const eLion = "gaia/fauna_lion"; + const eLioness = "gaia/fauna_lioness"; + const eStoneMine = "gaia/rock/desert_large"; + const eMetalMine = "gaia/ore/desert_large"; + + const aFlower1 = "actor|props/flora/decals_flowers_daisies.xml"; + const aWaterFlower = "actor|props/flora/water_lillies.xml"; + const aReedsA = "actor|props/flora/reeds_pond_lush_a.xml"; + const aReedsB = "actor|props/flora/reeds_pond_lush_b.xml"; + const aRock = "actor|geology/stone_desert_med.xml"; + const aBushA = "actor|props/flora/bush_desert_dry_a.xml"; + const aBushB = "actor|props/flora/bush_desert_dry_a.xml"; + const aSand = "actor|particle/blowing_sand.xml"; + + const pForestMain = [tForestFloor + TERRAIN_SEPARATOR + ePalmShort, + tForestFloor + TERRAIN_SEPARATOR + ePalmTall, tForestFloor]; + const pOasisForestLight = [tForestFloor + TERRAIN_SEPARATOR + ePalmShort, + tForestFloor + TERRAIN_SEPARATOR + ePalmTall, tForestFloor, tForestFloor, tForestFloor, + tForestFloor, tForestFloor, tForestFloor, tForestFloor]; + + const heightSeaGround = -3; + const heightFloraMin = -2.5; + const heightFloraReedsMax = -1.9; + const heightFloraMax = -1; + const heightLand = 1; + const heightSand = 3.4; + const heightOasisPath = 4; + const heightOffsetBump = 4; + const heightOffsetDune = 18; + + global.g_Map = new RandomMap(heightLand, tSand); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clOasis = g_Map.createTileClass(); + const clPassage = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + const waterRadius = scaleByMapSize(7, 50); + const shoreDistance = scaleByMapSize(4, 10); + const forestDistance = scaleByMapSize(6, 20); + + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + + g_Map.log("Creating small oasis near the players..."); + const forestDist = 1.2 * defaultPlayerBaseRadius(); + for (let i = 0; i < numPlayers; ++i) + { + let forestPosition; + let forestAngle; + do { + forestAngle = Math.PI / 3 * randFloat(1, 2); + forestPosition = Vector2D.add(playerPosition[i], + new Vector2D(forestDist, 0).rotate(-forestAngle)); + } while ( + !createArea( + new ClumpPlacer(70, 1, 0.5, Infinity, forestPosition), + [ + new LayeredPainter([tForestFloor, pForestMain], [0]), + new TileClassPainter(clBaseResource) + ], + avoidClasses(clBaseResource, 0))); + + let waterPosition; + let flowerPosition; + let reedsPosition; + do { + const waterAngle = forestAngle + randFloat(1, 5) / 3 * Math.PI; + waterPosition = Vector2D.add(forestPosition, + new Vector2D(6, 0).rotate(-waterAngle)).round(); + flowerPosition = Vector2D.add(forestPosition, + new Vector2D(3, 0).rotate(-waterAngle)).round(); + reedsPosition = Vector2D.add(forestPosition, + new Vector2D(5, 0).rotate(-waterAngle)).round(); + } while ( + !createArea( + new ClumpPlacer(diskArea(4.5), 0.9, 0.4, Infinity, waterPosition), + [ + new LayeredPainter([tShore, tWater], [1]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 3) + ], + avoidClasses(clBaseResource, 0))); + + createObjectGroup(new SimpleGroup([new SimpleObject(aFlower1, 1, 5, 0, 3)], true, undefined, + flowerPosition), 0); + createObjectGroup(new SimpleGroup([new SimpleObject(aReedsA, 1, 3, 0, 0)], true, undefined, + reedsPosition), 0); + } + yield 20; + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad, + "painters": [ + new TileClassPainter(clPlayer) + ] + }, + "StartingAnimal": { + }, + "Berries": { + "template": eBush + }, + "Mines": { + "types": [ + { "template": eMetalMine }, + { "template": eStoneMine }, ], - avoidClasses(clBaseResource, 0))); + "distance": defaultPlayerBaseRadius(), + "maxAngle": Math.PI / 2, + "groupElements": shuffleArray([aBushA, aBushB, ePalmShort, ePalmTall]).map( + t => new SimpleObject(t, 1, 1, 3, 4)) + } + // Starting trees were set above + // No decoratives + }); + yield 30; - createObjectGroup(new SimpleGroup([new SimpleObject(aFlower1, 1, 5, 0, 3)], true, undefined, flowerPosition), 0); - createObjectGroup(new SimpleGroup([new SimpleObject(aReedsA, 1, 3, 0, 0)], true, undefined, reedsPosition), 0); -} -Engine.SetProgress(20); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad, - "painters": [ - new TileClassPainter(clPlayer) - ] - }, - "StartingAnimal": { - }, - "Berries": { - "template": eBush - }, - "Mines": { - "types": [ - { "template": eMetalMine }, - { "template": eStoneMine }, - ], - "distance": defaultPlayerBaseRadius(), - "maxAngle": Math.PI / 2, - "groupElements": shuffleArray([aBushA, aBushB, ePalmShort, ePalmTall]).map(t => new SimpleObject(t, 1, 1, 3, 4)) - } - // Starting trees were set above - // No decoratives -}); -Engine.SetProgress(30); - -g_Map.log("Creating central oasis"); -createArea( - new ClumpPlacer(diskArea(forestDistance + shoreDistance + waterRadius), 0.8, 0.2, Infinity, mapCenter), - [ - new LayeredPainter([pOasisForestLight, tWater], [forestDistance]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, forestDistance + shoreDistance), - new TileClassPainter(clOasis) - ]); - -Engine.SetProgress(40); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 3), - avoidClasses(clPlayer, 10, clBaseResource, 6, clOasis, 4), - scaleByMapSize(30, 70)); - -g_Map.log("Creating dirt patches"); -createAreas( - new ClumpPlacer(80, 0.3, 0.06, Infinity), - new TerrainPainter(tDirt), - avoidClasses(clPlayer, 10, clBaseResource, 6, clOasis, 4, clForest, 4), - scaleByMapSize(15, 50)); - -g_Map.log("Creating dunes"); -createAreas( - new ClumpPlacer(120, 0.3, 0.06, Infinity), - [ - new TerrainPainter(tDune), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetDune, 30) - ], - avoidClasses(clPlayer, 10, clBaseResource, 6, clOasis, 4, clForest, 4), - scaleByMapSize(15, 50)); - -Engine.SetProgress(50); - -if (mapSize > 150 && randBool()) -{ - g_Map.log("Creating path though the oasis"); - const pathWidth = scaleByMapSize(7, 18); - const points = distributePointsOnCircle(2, randomAngle(), waterRadius + shoreDistance + forestDistance + pathWidth, mapCenter)[0]; + g_Map.log("Creating central oasis"); createArea( - new PathPlacer(points[0], points[1], pathWidth, 0.4, 1, 0.2, 0), + new ClumpPlacer(diskArea(forestDistance + shoreDistance + waterRadius), 0.8, 0.2, Infinity, + mapCenter), [ - new TerrainPainter(tSand), - new SmoothElevationPainter(ELEVATION_SET, heightOasisPath, 5), - new TileClassPainter(clPassage) + new LayeredPainter([pOasisForestLight, tWater], [forestDistance]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, + forestDistance + shoreDistance), + new TileClassPainter(clOasis) ]); -} -g_Map.log("Creating some straggler trees around the passage"); -let group = new SimpleGroup([new SimpleObject(ePalmTall, 1,1, 0,0),new SimpleObject(ePalmShort, 1, 2, 1, 2), new SimpleObject(aBushA, 0,2, 1,3)], true, clForest); -createObjectGroupsDeprecated(group, 0, stayClasses(clPassage, 3), scaleByMapSize(60, 250), 100); - -g_Map.log("Creating stone mines"); -group = new SimpleGroup([new SimpleObject(eStoneMine, 1,1, 0,0),new SimpleObject(ePalmShort, 1,2, 3,3),new SimpleObject(ePalmTall, 0,1, 3,3) - ,new SimpleObject(aBushB, 1,1, 2,2), new SimpleObject(aBushA, 0,2, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clOasis, 10, clForest, 1, clPlayer, 30, clRock, 10,clBaseResource, 2, clHill, 1), - scaleByMapSize(6,25), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(eMetalMine, 1,1, 0,0),new SimpleObject(ePalmShort, 1,2, 2,3),new SimpleObject(ePalmTall, 0,1, 2,2) - ,new SimpleObject(aBushB, 1,1, 2,2), new SimpleObject(aBushA, 0,2, 1,3)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clOasis, 10, clForest, 1, clPlayer, 30, clMetal, 10,clBaseResource, 2, clRock, 10, clHill, 1), - scaleByMapSize(6,25), 100 -); -Engine.SetProgress(65); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( [new SimpleObject(aRock, 2,4, 0,2)], true, undefined ); -createObjectGroupsDeprecated(group, 0, avoidClasses(clOasis, 3, clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), 30, scaleByMapSize(10, 50)); - -Engine.SetProgress(70); - -g_Map.log("Creating camels"); -group = new SimpleGroup( - [new SimpleObject(eCamel, 1,2, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clOasis, 3, clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), - 1 * numPlayers, 50 -); -Engine.SetProgress(75); - -g_Map.log("Creating gazelles"); -group = new SimpleGroup( - [new SimpleObject(eGazelle, 2,4, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clOasis, 3, clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), - 1 * numPlayers, 50 -); -Engine.SetProgress(85); - -g_Map.log("Creating oasis animals"); -for (let i = 0; i < scaleByMapSize(5, 30); ++i) -{ - const animalPos = Vector2D.add(mapCenter, new Vector2D(forestDistance + shoreDistance + waterRadius, 0).rotate(randomAngle())); - createObjectGroup( - new RandomGroup( + yield 40; + + g_Map.log("Creating bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 3), + avoidClasses(clPlayer, 10, clBaseResource, 6, clOasis, 4), + scaleByMapSize(30, 70)); + + g_Map.log("Creating dirt patches"); + createAreas( + new ClumpPlacer(80, 0.3, 0.06, Infinity), + new TerrainPainter(tDirt), + avoidClasses(clPlayer, 10, clBaseResource, 6, clOasis, 4, clForest, 4), + scaleByMapSize(15, 50)); + + g_Map.log("Creating dunes"); + createAreas( + new ClumpPlacer(120, 0.3, 0.06, Infinity), + [ + new TerrainPainter(tDune), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetDune, 30) + ], + avoidClasses(clPlayer, 10, clBaseResource, 6, clOasis, 4, clForest, 4), + scaleByMapSize(15, 50)); + + yield 50; + + if (mapSize > 150 && randBool()) + { + g_Map.log("Creating path though the oasis"); + const pathWidth = scaleByMapSize(7, 18); + const points = distributePointsOnCircle(2, randomAngle(), + waterRadius + shoreDistance + forestDistance + pathWidth, mapCenter)[0]; + createArea( + new PathPlacer(points[0], points[1], pathWidth, 0.4, 1, 0.2, 0), [ - new SimpleObject(eLion, 1, 2, 0, 4), - new SimpleObject(eLioness, 1, 2, 2, 4), - new SimpleObject(eGazelle, 4, 6, 1, 5), - new SimpleObject(eCamel, 1, 2, 1, 5) - ], - true, - clFood, - animalPos), - 0); -} -Engine.SetProgress(90); - -g_Map.log("Creating bushes"); -group = new SimpleGroup( - [new SimpleObject(aBushB, 1,2, 0,2), new SimpleObject(aBushA, 2,4, 0,2)] -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clOasis, 2, clHill, 1, clPlayer, 1, clPassage, 1), - scaleByMapSize(10, 40), 20 -); - -const objectsWaterFlora = [ - new SimpleObject(aReedsA, 5, 12, 0, 2), - new SimpleObject(aReedsB, 5, 12, 0, 2) -]; - -g_Map.log("Creating sand blows and beautifications"); -for (let sandx = 0; sandx < mapSize; sandx += 4) - for (let sandz = 0; sandz < mapSize; sandz += 4) + new TerrainPainter(tSand), + new SmoothElevationPainter(ELEVATION_SET, heightOasisPath, 5), + new TileClassPainter(clPassage) + ]); + } + g_Map.log("Creating some straggler trees around the passage"); + let group = new SimpleGroup([new SimpleObject(ePalmTall, 1,1, 0,0), + new SimpleObject(ePalmShort, 1, 2, 1, 2), new SimpleObject(aBushA, 0,2, 1,3)], true, clForest); + createObjectGroupsDeprecated(group, 0, stayClasses(clPassage, 3), scaleByMapSize(60, 250), 100); + + g_Map.log("Creating stone mines"); + group = new SimpleGroup([new SimpleObject(eStoneMine, 1,1, 0,0), + new SimpleObject(ePalmShort, 1,2, 3,3), new SimpleObject(ePalmTall, 0,1, 3,3), + new SimpleObject(aBushB, 1,1, 2,2), new SimpleObject(aBushA, 0,2, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clOasis, 10, clForest, 1, clPlayer, 30, clRock, 10,clBaseResource, 2, clHill, 1), + scaleByMapSize(6,25), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(eMetalMine, 1,1, 0,0), + new SimpleObject(ePalmShort, 1,2, 2,3), new SimpleObject(ePalmTall, 0,1, 2,2), + new SimpleObject(aBushB, 1,1, 2,2), new SimpleObject(aBushA, 0,2, 1,3)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clOasis, 10, clForest, 1, clPlayer, 30, clMetal, 10,clBaseResource, 2, clRock, 10, + clHill, 1), + scaleByMapSize(6,25), 100 + ); + yield 65; + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( [new SimpleObject(aRock, 2,4, 0,2)], true, undefined ); + createObjectGroupsDeprecated(group, 0, avoidClasses(clOasis, 3, clForest, 0, clPlayer, 10, clHill, 1, + clFood, 20), 30, scaleByMapSize(10, 50)); + + yield 70; + + g_Map.log("Creating camels"); + group = new SimpleGroup( + [new SimpleObject(eCamel, 1,2, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clOasis, 3, clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), + 1 * numPlayers, 50 + ); + yield 75; + + g_Map.log("Creating gazelles"); + group = new SimpleGroup( + [new SimpleObject(eGazelle, 2,4, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clOasis, 3, clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), + 1 * numPlayers, 50 + ); + yield 85; + + g_Map.log("Creating oasis animals"); + for (let i = 0; i < scaleByMapSize(5, 30); ++i) { - const position = new Vector2D(sandx, sandz); - const height = g_Map.getHeight(position); - - if (height > heightSand) - { - if (randBool((height - heightSand) / 1.4)) - createObjectGroup(new SimpleGroup([new SimpleObject(aSand, 0, 1, 0, 2)], true, undefined, position), 0); - } - else if (height > heightFloraMin && height < heightFloraMax) + const animalPos = Vector2D.add(mapCenter, + new Vector2D(forestDistance + shoreDistance + waterRadius, 0).rotate(randomAngle())); + + createObjectGroup( + new RandomGroup( + [ + new SimpleObject(eLion, 1, 2, 0, 4), + new SimpleObject(eLioness, 1, 2, 2, 4), + new SimpleObject(eGazelle, 4, 6, 1, 5), + new SimpleObject(eCamel, 1, 2, 1, 5) + ], + true, + clFood, + animalPos), + 0); + } + yield 90; + + g_Map.log("Creating bushes"); + group = new SimpleGroup( + [new SimpleObject(aBushB, 1,2, 0,2), new SimpleObject(aBushA, 2,4, 0,2)] + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clOasis, 2, clHill, 1, clPlayer, 1, clPassage, 1), + scaleByMapSize(10, 40), 20 + ); + + const objectsWaterFlora = [ + new SimpleObject(aReedsA, 5, 12, 0, 2), + new SimpleObject(aReedsB, 5, 12, 0, 2) + ]; + + g_Map.log("Creating sand blows and beautifications"); + for (let sandx = 0; sandx < mapSize; sandx += 4) + for (let sandz = 0; sandz < mapSize; sandz += 4) { - if (randBool(0.4)) - createObjectGroup(new SimpleGroup([new SimpleObject(aWaterFlower, 1, 4, 1, 2)], true, undefined, position), 0); - else if (randBool(0.7) && height < heightFloraReedsMax) - createObjectGroup(new SimpleGroup(objectsWaterFlora, true, undefined, position), 0); + const position = new Vector2D(sandx, sandz); + const height = g_Map.getHeight(position); - if (clPassage.countMembersInRadius(position, 2)) + if (height > heightSand) + { + if (randBool((height - heightSand) / 1.4)) + createObjectGroup(new SimpleGroup([new SimpleObject(aSand, 0, 1, 0, 2)], true, + undefined, position), 0); + } + else if (height > heightFloraMin && height < heightFloraMax) { if (randBool(0.4)) - createObjectGroup(new SimpleGroup([new SimpleObject(aWaterFlower, 1, 4, 1, 2)], true, undefined, position), 0); + createObjectGroup(new SimpleGroup( + [new SimpleObject(aWaterFlower, 1, 4, 1, 2)], true, undefined, + position), 0); else if (randBool(0.7) && height < heightFloraReedsMax) - createObjectGroup(new SimpleGroup(objectsWaterFlora, true, undefined, position), 0); + createObjectGroup( + new SimpleGroup(objectsWaterFlora, true, undefined, position), 0); + + if (clPassage.countMembersInRadius(position, 2)) + { + if (randBool(0.4)) + createObjectGroup(new SimpleGroup( + [new SimpleObject(aWaterFlower, 1, 4, 1, 2)], true, undefined, + position), 0); + else if (randBool(0.7) && height < heightFloraReedsMax) + createObjectGroup( + new SimpleGroup(objectsWaterFlora, true, undefined, position), 0); + } } } - } -placePlayersNomad(clPlayer, avoidClasses(clOasis, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setSkySet("sunny"); -setSunColor(0.914,0.827,0.639); -setSunRotation(Math.PI/3); -setSunElevation(0.5); -setWaterColor(0, 0.227, 0.843); -setWaterTint(0, 0.545, 0.859); -setWaterWaviness(1.0); -setWaterType("clap"); -setWaterMurkiness(0.5); -setAmbientColor(0.501961, 0.501961, 0.501961); - -g_Map.ExportMap(); + placePlayersNomad(clPlayer, avoidClasses(clOasis, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, + clFood, 2)); + + setSkySet("sunny"); + setSunColor(0.914,0.827,0.639); + setSunRotation(Math.PI/3); + setSunElevation(0.5); + setWaterColor(0, 0.227, 0.843); + setWaterTint(0, 0.545, 0.859); + setWaterWaviness(1.0); + setWaterType("clap"); + setWaterMurkiness(0.5); + setAmbientColor(0.501961, 0.501961, 0.501961); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/persian_highlands.js =================================================================== --- binaries/data/mods/public/maps/random/persian_highlands.js +++ binaries/data/mods/public/maps/random/persian_highlands.js @@ -2,322 +2,328 @@ Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); -if (g_MapSettings.Biome) - setSelectedBiome(); -else +function* GenerateMap(mapSettings) +{ // TODO: Replace ugly default for atlas by a dropdown - setBiome("persian_highlands/summer"); - -const tDirtMain = g_Terrains.mainTerrain; -const tCity = g_Terrains.road; -const tCliff = g_Terrains.cliff; -const tLakebed1 = g_Terrains.lakebed1; -const tLakebed2 = g_Terrains.lakebed2; -const tForestFloor = g_Terrains.forestFloor1; -const tRocky = g_Terrains.tier1Terrain; -const tRocks = g_Terrains.tier2Terrain; -const tGrass = g_Terrains.tier3Terrain; - -const oOak = g_Gaia.tree1; -const oGrapesBush = g_Gaia.fruitBush; -const oCamel = g_Gaia.mainHuntableAnimal; -const oSheep = g_Gaia.secondaryHuntableAnimal; -const oGoat = g_Gaia.thirdHuntableAnimal; -const oStoneLarge = g_Gaia.stoneLarge; -const oStoneSmall = g_Gaia.stoneSmall; -const oMetalLarge = g_Gaia.metalLarge; - -const aDecorativeRock = g_Decoratives.rockMedium; -const aBush1 = g_Decoratives.bush1; -const aBush2 = g_Decoratives.bush2; -const aBush3 = g_Decoratives.bush3; -const aBush4 = g_Decoratives.bush4; -const aBushes = [aBush1, aBush2, aBush3, aBush4]; - -const pForestO = [tForestFloor + TERRAIN_SEPARATOR + oOak, tForestFloor + TERRAIN_SEPARATOR + oOak, tForestFloor, tDirtMain, tDirtMain]; - -const heightLand = 10; -const heightOffsetValley = -10; - -const g_Map = new RandomMap(heightLand, tDirtMain); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clPatch = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clCP = g_Map.createTileClass(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tCity, - "innerTerrain": tCity, - "painters": [ - new TileClassPainter(clPlayer) - ] - }, - "StartingAnimal": { - }, - "Berries": { - "template": oGrapesBush, - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } + setBiome(mapSettings.Biome ?? "persian_highlands/summer"); + + const tDirtMain = g_Terrains.mainTerrain; + const tCity = g_Terrains.road; + const tCliff = g_Terrains.cliff; + const tLakebed1 = g_Terrains.lakebed1; + const tLakebed2 = g_Terrains.lakebed2; + const tForestFloor = g_Terrains.forestFloor1; + const tRocky = g_Terrains.tier1Terrain; + const tRocks = g_Terrains.tier2Terrain; + const tGrass = g_Terrains.tier3Terrain; + + const oOak = g_Gaia.tree1; + const oGrapesBush = g_Gaia.fruitBush; + const oCamel = g_Gaia.mainHuntableAnimal; + const oSheep = g_Gaia.secondaryHuntableAnimal; + const oGoat = g_Gaia.thirdHuntableAnimal; + const oStoneLarge = g_Gaia.stoneLarge; + const oStoneSmall = g_Gaia.stoneSmall; + const oMetalLarge = g_Gaia.metalLarge; + + const aDecorativeRock = g_Decoratives.rockMedium; + const aBush1 = g_Decoratives.bush1; + const aBush2 = g_Decoratives.bush2; + const aBush3 = g_Decoratives.bush3; + const aBush4 = g_Decoratives.bush4; + const aBushes = [aBush1, aBush2, aBush3, aBush4]; + + const pForestO = [tForestFloor + TERRAIN_SEPARATOR + oOak, tForestFloor + TERRAIN_SEPARATOR + oOak, + tForestFloor, tDirtMain, tDirtMain]; + + const heightLand = 10; + const heightOffsetValley = -10; + + global.g_Map = new RandomMap(heightLand, tDirtMain); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clPatch = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clCP = g_Map.createTileClass(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tCity, + "innerTerrain": tCity, + "painters": [ + new TileClassPainter(clPlayer) + ] + }, + "StartingAnimal": { + }, + "Berries": { + "template": oGrapesBush, + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ], + "groupElements": shuffleArray(aBushes).map(t => new SimpleObject(t, 1, 1, 3, 4)) + }, + "Trees": { + "template": oOak, + "count": 3 + } + // No decoratives + }); + yield 10; + + g_Map.log("Creating rock patches"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 6)), Math.floor(scaleByMapSize(20, 45)), 0), + [ + new TerrainPainter(tRocky), + new TileClassPainter(clPatch) ], - "groupElements": shuffleArray(aBushes).map(t => new SimpleObject(t, 1, 1, 3, 4)) - }, - "Trees": { - "template": oOak, - "count": 3 - } - // No decoratives -}); -Engine.SetProgress(10); - -g_Map.log("Creating rock patches"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 6)), Math.floor(scaleByMapSize(20, 45)), 0), - [ - new TerrainPainter(tRocky), - new TileClassPainter(clPatch) - ], - avoidClasses(clPatch, 2, clPlayer, 0), - scaleByMapSize(5, 20)); -Engine.SetProgress(15); - -g_Map.log("Creating secondary rock patches"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), Math.floor(scaleByMapSize(15, 40)), 0), - [ - new TerrainPainter([tRocky, tRocks]), - new TileClassPainter(clPatch) - ], - avoidClasses(clPatch, 2, clPlayer, 4), - scaleByMapSize(15, 50)); -Engine.SetProgress(20); - -g_Map.log("Creating dirt patches"); -createAreas( - new ChainPlacer( - 1, - Math.floor(scaleByMapSize(3, 5)), - Math.floor(scaleByMapSize(15, 40)), - 0), - [ - new TerrainPainter([tGrass]), - new TileClassPainter(clPatch) - ], - avoidClasses(clPatch, 2, clPlayer, 4), - scaleByMapSize(15, 50)); -Engine.SetProgress(25); - -g_Map.log("Creating centeral plateau"); -createArea( - new ChainPlacer( - 2, - Math.floor(scaleByMapSize(5, 13)), - Math.floor(scaleByMapSize(35, 200)), - Infinity, - mapCenter, - 0, - [Math.floor(scaleByMapSize(18, 68))]), - [ - new LayeredPainter([tLakebed2, tLakebed1], [6]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetValley, 8), - new TileClassPainter(clCP) - ], - avoidClasses(clPlayer, 18)); -Engine.SetProgress(30); - -g_Map.log("Creating hills"); -for (let i = 0; i < scaleByMapSize(20, 80); ++i) - createMountain( - Math.floor(scaleByMapSize(40, 60)), - Math.floor(scaleByMapSize(3, 4)), - Math.floor(scaleByMapSize(6, 12)), - Math.floor(scaleByMapSize(4, 10)), - avoidClasses(clPlayer, 7, clCP, 5, clHill, Math.floor(scaleByMapSize(18, 25))), - randIntExclusive(0, mapSize), - randIntExclusive(0, mapSize), - tCliff, - clHill, - 14); -Engine.SetProgress(35); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.7); -const types = [ - [[tDirtMain, tForestFloor, pForestO], [tForestFloor, pForestO]], - [[tDirtMain, tForestFloor, pForestO], [tForestFloor, pForestO]] -]; -const forestSize = forestTrees / (scaleByMapSize(3,6) * numPlayers); -const num = Math.floor(forestSize / types.length); -for (const type of types) + avoidClasses(clPatch, 2, clPlayer, 0), + scaleByMapSize(5, 20)); + yield 15; + + g_Map.log("Creating secondary rock patches"); createAreas( - new ChainPlacer( - Math.floor(scaleByMapSize(1, 2)), - Math.floor(scaleByMapSize(2, 5)), - Math.floor(forestSize / Math.floor(scaleByMapSize(8, 3))), - Infinity), + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), Math.floor(scaleByMapSize(15, 40)), 0), [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) + new TerrainPainter([tRocky, tRocks]), + new TileClassPainter(clPatch) ], - avoidClasses( - clPlayer, 6, - clForest, 10, - clHill, 1, - clCP, 1), - num); -Engine.SetProgress(50); - -g_Map.log("Creating stone mines"); -createObjectGroupsDeprecated( - new SimpleGroup( + avoidClasses(clPatch, 2, clPlayer, 4), + scaleByMapSize(15, 50)); + yield 20; + + g_Map.log("Creating dirt patches"); + createAreas( + new ChainPlacer( + 1, + Math.floor(scaleByMapSize(3, 5)), + Math.floor(scaleByMapSize(15, 40)), + 0), [ - new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), - new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4), - new RandomObject(aBushes, 2, 4, 0, 2) + new TerrainPainter([tGrass]), + new TileClassPainter(clPatch) ], - true, - clRock), - 0, - [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1, clCP, 1)], - scaleByMapSize(2,8), - 100); - -g_Map.log("Creating small stone quarries"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3), new RandomObject(aBushes, 2, 4, 0, 2)], true, clRock), - 0, - [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1, clCP, 1)], - scaleByMapSize(2, 8), - 100); - -g_Map.log("Creating metal mines"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4), new RandomObject(aBushes, 2, 4, 0, 2)], true, clMetal), - 0, - [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 1, clCP, 1)], - scaleByMapSize(2,8), - 100); - -g_Map.log("Creating centeral stone mines"); -createObjectGroupsDeprecated( - new SimpleGroup( + avoidClasses(clPatch, 2, clPlayer, 4), + scaleByMapSize(15, 50)); + yield 25; + + g_Map.log("Creating centeral plateau"); + createArea( + new ChainPlacer( + 2, + Math.floor(scaleByMapSize(5, 13)), + Math.floor(scaleByMapSize(35, 200)), + Infinity, + mapCenter, + 0, + [Math.floor(scaleByMapSize(18, 68))]), [ - new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), - new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4), - new RandomObject(aBushes, 2,4, 0,2) + new LayeredPainter([tLakebed2, tLakebed1], [6]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetValley, 8), + new TileClassPainter(clCP) ], - true, - clRock), - 0, - stayClasses(clCP, 6), - 5*scaleByMapSize(5, 30), - 50); - -g_Map.log("Creating small stone quarries"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3), new RandomObject(aBushes, 2, 4, 0, 2)], true, clRock); -createObjectGroupsDeprecated(group, 0, - stayClasses(clCP, 6), - 5*scaleByMapSize(5,30), 50 -); - -g_Map.log("Creating centeral metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4), new RandomObject(aBushes, 2,4, 0,2)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - stayClasses(clCP, 6), - 5*scaleByMapSize(5,30), 50 -); - -Engine.SetProgress(60); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aDecorativeRock, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), - scaleByMapSize(16, 262), 50 -); - -Engine.SetProgress(65); - -g_Map.log("Creating bushes"); -group = new SimpleGroup( - [new SimpleObject(aBush2, 1,2, 0,1), new SimpleObject(aBush1, 1,3, 0,2)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), - scaleByMapSize(8, 131), 50 -); - -Engine.SetProgress(70); - -g_Map.log("Creating goat"); -group = new SimpleGroup( - [new SimpleObject(oGoat, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clCP, 2), - 3 * numPlayers, 50 -); - -g_Map.log("Creating sheep"); -group = new SimpleGroup( - [new SimpleObject(oSheep, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clCP, 2), - 3 * numPlayers, 50 -); - -g_Map.log("Creating grape bush"); -group = new SimpleGroup( - [new SimpleObject(oGrapesBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10, clCP, 2), - randIntInclusive(1, 4) * numPlayers + 2, 50 -); - -g_Map.log("Creating camels"); -group = new SimpleGroup( - [new SimpleObject(oCamel, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - stayClasses(clCP, 2), - 3 * numPlayers, 50 -); - -Engine.SetProgress(90); - -createStragglerTrees( - [oOak], - avoidClasses(clForest, 1, clHill, 1, clPlayer, 1, clBaseResource, 6, clMetal, 6, clRock, 6, clCP, 2), - clForest, - stragglerTrees); - -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -g_Map.ExportMap(); + avoidClasses(clPlayer, 18)); + yield 30; + + g_Map.log("Creating hills"); + for (let i = 0; i < scaleByMapSize(20, 80); ++i) + createMountain( + Math.floor(scaleByMapSize(40, 60)), + Math.floor(scaleByMapSize(3, 4)), + Math.floor(scaleByMapSize(6, 12)), + Math.floor(scaleByMapSize(4, 10)), + avoidClasses(clPlayer, 7, clCP, 5, clHill, Math.floor(scaleByMapSize(18, 25))), + randIntExclusive(0, mapSize), + randIntExclusive(0, mapSize), + tCliff, + clHill, + 14); + yield 35; + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.7); + const types = [ + [[tDirtMain, tForestFloor, pForestO], [tForestFloor, pForestO]], + [[tDirtMain, tForestFloor, pForestO], [tForestFloor, pForestO]] + ]; + const forestSize = forestTrees / (scaleByMapSize(3,6) * numPlayers); + const num = Math.floor(forestSize / types.length); + for (const type of types) + createAreas( + new ChainPlacer( + Math.floor(scaleByMapSize(1, 2)), + Math.floor(scaleByMapSize(2, 5)), + Math.floor(forestSize / Math.floor(scaleByMapSize(8, 3))), + Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses( + clPlayer, 6, + clForest, 10, + clHill, 1, + clCP, 1), + num); + yield 50; + + g_Map.log("Creating stone mines"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4), + new RandomObject(aBushes, 2, 4, 0, 2) + ], + true, + clRock), + 0, + [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1, clCP, 1)], + scaleByMapSize(2,8), + 100); + + g_Map.log("Creating small stone quarries"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3), + new RandomObject(aBushes, 2, 4, 0, 2)], true, clRock), + 0, + [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1, clCP, 1)], + scaleByMapSize(2, 8), + 100); + + g_Map.log("Creating metal mines"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4), + new RandomObject(aBushes, 2, 4, 0, 2)], true, clMetal), + 0, + [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 1, clCP, 1)], + scaleByMapSize(2,8), + 100); + + g_Map.log("Creating centeral stone mines"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4), + new RandomObject(aBushes, 2,4, 0,2) + ], + true, + clRock), + 0, + stayClasses(clCP, 6), + 5*scaleByMapSize(5, 30), + 50); + + g_Map.log("Creating small stone quarries"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3), + new RandomObject(aBushes, 2, 4, 0, 2)], true, clRock); + createObjectGroupsDeprecated(group, 0, + stayClasses(clCP, 6), + 5*scaleByMapSize(5,30), 50 + ); + + g_Map.log("Creating centeral metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4), + new RandomObject(aBushes, 2,4, 0,2)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + stayClasses(clCP, 6), + 5*scaleByMapSize(5,30), 50 + ); + + yield 60; + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aDecorativeRock, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), + scaleByMapSize(16, 262), 50 + ); + + yield 65; + + g_Map.log("Creating bushes"); + group = new SimpleGroup( + [new SimpleObject(aBush2, 1,2, 0,1), new SimpleObject(aBush1, 1,3, 0,2)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), + scaleByMapSize(8, 131), 50 + ); + + yield 70; + + g_Map.log("Creating goat"); + group = new SimpleGroup( + [new SimpleObject(oGoat, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clCP, 2), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating sheep"); + group = new SimpleGroup( + [new SimpleObject(oSheep, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clCP, 2), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating grape bush"); + group = new SimpleGroup( + [new SimpleObject(oGrapesBush, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10, clCP, 2), + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + + g_Map.log("Creating camels"); + group = new SimpleGroup( + [new SimpleObject(oCamel, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + stayClasses(clCP, 2), + 3 * numPlayers, 50 + ); + + yield 90; + + createStragglerTrees( + [oOak], + avoidClasses(clForest, 1, clHill, 1, clPlayer, 1, clBaseResource, 6, clMetal, 6, clRock, 6, + clCP, 2), + clForest, + stragglerTrees); + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/phoenician_levant.js =================================================================== --- binaries/data/mods/public/maps/random/phoenician_levant.js +++ binaries/data/mods/public/maps/random/phoenician_levant.js @@ -3,330 +3,342 @@ //TILE_CENTERED_HEIGHT_MAP = true; -const tCity = "medit_city_pavement"; -const tCityPlaza = "medit_city_pavement"; -const tHill = ["medit_dirt", "medit_dirt_b", "medit_dirt_c", "medit_rocks_grass", "medit_rocks_grass"]; -const tMainDirt = "medit_dirt"; -const tCliff = "medit_cliff_aegean"; -const tForestFloor = "medit_rocks_shrubs"; -const tGrass = "medit_rocks_grass"; -const tRocksShrubs = "medit_rocks_shrubs"; -const tRocksGrass = "medit_rocks_grass"; -const tDirt = "medit_dirt_b"; -const tDirtB = "medit_dirt_c"; -const tShore = "medit_sand"; -const tWater = "medit_sand_wet"; - -const oGrapeBush = "gaia/fruit/grapes"; -const oDeer = "gaia/fauna_deer"; -const oFish = "gaia/fish/generic"; -const oSheep = "gaia/fauna_sheep"; -const oGoat = "gaia/fauna_goat"; -const oStoneLarge = "gaia/rock/mediterranean_large"; -const oStoneSmall = "gaia/rock/mediterranean_small"; -const oMetalLarge = "gaia/ore/mediterranean_large"; -const oDatePalm = "gaia/tree/cretan_date_palm_short"; -const oSDatePalm = "gaia/tree/cretan_date_palm_tall"; -const oCarob = "gaia/tree/carob"; -const oFanPalm = "gaia/tree/medit_fan_palm"; -const oPoplar = "gaia/tree/poplar_lombardy"; -const oCypress = "gaia/tree/cypress"; - -const aBush1 = "actor|props/flora/bush_medit_sm.xml"; -const aBush2 = "actor|props/flora/bush_medit_me.xml"; -const aBush3 = "actor|props/flora/bush_medit_la.xml"; -const aBush4 = "actor|props/flora/bush_medit_me.xml"; -const aDecorativeRock = "actor|geology/stone_granite_med.xml"; - -const pForest = [tForestFloor + TERRAIN_SEPARATOR + oDatePalm, tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, tForestFloor + TERRAIN_SEPARATOR + oCarob, tForestFloor, tForestFloor]; - -const heightSeaGround = -3; -const heightShore = -1.5; -const heightLand = 1; -const heightIsland = 6; -const heightHill = 15; -const heightOffsetBump = 2; - -const g_Map = new RandomMap(heightLand, tHill); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clGrass = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clIsland = g_Map.createTileClass(); - -const startAngle = randIntInclusive(0, 3) * Math.PI / 2; - -placePlayerBases({ - "PlayerPlacement": [ - sortAllPlayers(), - playerPlacementLine(Math.PI / 2, new Vector2D(fractionToTiles(0.76), mapCenter.y), fractionToTiles(0.2)).map(pos => - pos.rotateAround(startAngle, mapCenter)) - ], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tCityPlaza, - "innerTerrain": tCity - }, - "StartingAnimal": { - }, - "Berries": { - "template": oGrapeBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oCarob, - "count": 2 - }, - "Decoratives": { - "template": aBush1 - } -}); -Engine.SetProgress(30); - -paintRiver({ - "parallel": true, - "start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(startAngle, mapCenter), - "end": new Vector2D(mapBounds.left, mapBounds.bottom).rotateAround(startAngle, mapCenter), - "width": mapSize, - "fadeDist": scaleByMapSize(6, 25), - "deviation": 0, - "heightRiverbed": heightSeaGround, - "heightLand": heightLand, - "meanderShort": 20, - "meanderLong": 0 -}); -Engine.SetProgress(40); - -paintTileClassBasedOnHeight(-Infinity, heightLand, Elevation_ExcludeMin_ExcludeMax, clWater); -paintTerrainBasedOnHeight(-Infinity, heightShore, Elevation_ExcludeMin_ExcludeMax, tWater); -paintTerrainBasedOnHeight(heightShore, heightLand, Elevation_ExcludeMin_ExcludeMax, tShore); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - avoidClasses(clWater, 2, clPlayer, 20), - scaleByMapSize(100, 200)); - -g_Map.log("Creating hills"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), - [ - new LayeredPainter([tCliff, tHill], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 20, clForest, 1, clHill, 15, clWater, 0), - scaleByMapSize(1, 4) * numPlayers * 3); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.5); -const num = scaleByMapSize(10,42); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), forestTrees / (num * Math.floor(scaleByMapSize(2, 5))), 0.5), - [ - new TerrainPainter([tForestFloor, pForest]), - new TileClassPainter(clForest) - ], - avoidClasses(clPlayer, 20, clForest, 10, clWater, 1, clHill, 1, clBaseResource, 3), - num, - 50); -Engine.SetProgress(50); - -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) +function* GenerateMap() +{ + const tCity = "medit_city_pavement"; + const tCityPlaza = "medit_city_pavement"; + const tHill = ["medit_dirt", "medit_dirt_b", "medit_dirt_c", "medit_rocks_grass", + "medit_rocks_grass"]; + const tMainDirt = "medit_dirt"; + const tCliff = "medit_cliff_aegean"; + const tForestFloor = "medit_rocks_shrubs"; + const tGrass = "medit_rocks_grass"; + const tRocksShrubs = "medit_rocks_shrubs"; + const tRocksGrass = "medit_rocks_grass"; + const tDirt = "medit_dirt_b"; + const tDirtB = "medit_dirt_c"; + const tShore = "medit_sand"; + const tWater = "medit_sand_wet"; + + const oGrapeBush = "gaia/fruit/grapes"; + const oDeer = "gaia/fauna_deer"; + const oFish = "gaia/fish/generic"; + const oSheep = "gaia/fauna_sheep"; + const oGoat = "gaia/fauna_goat"; + const oStoneLarge = "gaia/rock/mediterranean_large"; + const oStoneSmall = "gaia/rock/mediterranean_small"; + const oMetalLarge = "gaia/ore/mediterranean_large"; + const oDatePalm = "gaia/tree/cretan_date_palm_short"; + const oSDatePalm = "gaia/tree/cretan_date_palm_tall"; + const oCarob = "gaia/tree/carob"; + const oFanPalm = "gaia/tree/medit_fan_palm"; + const oPoplar = "gaia/tree/poplar_lombardy"; + const oCypress = "gaia/tree/cypress"; + + const aBush1 = "actor|props/flora/bush_medit_sm.xml"; + const aBush2 = "actor|props/flora/bush_medit_me.xml"; + const aBush3 = "actor|props/flora/bush_medit_la.xml"; + const aBush4 = "actor|props/flora/bush_medit_me.xml"; + const aDecorativeRock = "actor|geology/stone_granite_med.xml"; + + const pForest = [tForestFloor + TERRAIN_SEPARATOR + oDatePalm, + tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, tForestFloor + TERRAIN_SEPARATOR + oCarob, + tForestFloor, tForestFloor]; + + const heightSeaGround = -3; + const heightShore = -1.5; + const heightLand = 1; + const heightIsland = 6; + const heightHill = 15; + const heightOffsetBump = 2; + + global.g_Map = new RandomMap(heightLand, tHill); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clGrass = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clIsland = g_Map.createTileClass(); + + const startAngle = randIntInclusive(0, 3) * Math.PI / 2; + + placePlayerBases({ + "PlayerPlacement": [ + sortAllPlayers(), + playerPlacementLine(Math.PI / 2, + new Vector2D(fractionToTiles(0.76), mapCenter.y), fractionToTiles(0.2)).map(pos => + pos.rotateAround(startAngle, mapCenter)) + ], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tCityPlaza, + "innerTerrain": tCity + }, + "StartingAnimal": { + }, + "Berries": { + "template": oGrapeBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oCarob, + "count": 2 + }, + "Decoratives": { + "template": aBush1 + } + }); + yield 30; + + paintRiver({ + "parallel": true, + "start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(startAngle, mapCenter), + "end": new Vector2D(mapBounds.left, mapBounds.bottom).rotateAround(startAngle, mapCenter), + "width": mapSize, + "fadeDist": scaleByMapSize(6, 25), + "deviation": 0, + "heightRiverbed": heightSeaGround, + "heightLand": heightLand, + "meanderShort": 20, + "meanderLong": 0 + }); + yield 40; + + paintTileClassBasedOnHeight(-Infinity, heightLand, Elevation_ExcludeMin_ExcludeMax, clWater); + paintTerrainBasedOnHeight(-Infinity, heightShore, Elevation_ExcludeMin_ExcludeMax, tWater); + paintTerrainBasedOnHeight(heightShore, heightLand, Elevation_ExcludeMin_ExcludeMax, tShore); + + g_Map.log("Creating bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + avoidClasses(clWater, 2, clPlayer, 20), + scaleByMapSize(100, 200)); + + g_Map.log("Creating hills"); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), [ - new LayeredPainter( - [[tGrass, tRocksShrubs], [tRocksShrubs, tRocksGrass], [tRocksGrass, tGrass]], - [1, 1]), - new TileClassPainter(clDirt) + new LayeredPainter([tCliff, tHill], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) ], - avoidClasses(clForest, 0, clGrass, 5, clPlayer, 10, clWater, 4, clDirt, 5, clHill, 1), - scaleByMapSize(15, 45)); -Engine.SetProgress(55); + avoidClasses(clPlayer, 20, clForest, 1, clHill, 15, clWater, 0), + scaleByMapSize(1, 4) * numPlayers * 3); -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.5); + const num = scaleByMapSize(10,42); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), forestTrees / + (num * Math.floor(scaleByMapSize(2, 5))), 0.5), [ - new LayeredPainter( - [[tDirt, tDirtB], [tDirt, tMainDirt], [tDirtB, tMainDirt]], - [1, 1]), - new TileClassPainter(clDirt) + new TerrainPainter([tForestFloor, pForest]), + new TileClassPainter(clForest) ], - avoidClasses(clForest, 0, clDirt, 5, clPlayer, 10, clWater, 4, clGrass, 5, clHill, 1), - scaleByMapSize(15, 45)); -Engine.SetProgress(60); - -g_Map.log("Creating cyprus"); -createAreas( - new ClumpPlacer(diskArea(fractionToTiles(0.08)), 0.2, 0.1, 0.01), - [ - new LayeredPainter([tShore, tHill], [12]), - new SmoothElevationPainter(ELEVATION_SET, heightIsland, 8), - new TileClassPainter(clIsland), - new TileClassUnPainter(clWater) - ], - [stayClasses (clWater, 8)], - 1, - 100); - -g_Map.log("Creating cyprus mines"); -const mines = [ - new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock), - new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), - new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock) -]; -for (const mine of mines) - createObjectGroups( - mine, - 0, + avoidClasses(clPlayer, 20, clForest, 10, clWater, 1, clHill, 1, clBaseResource, 3), + num, + 50); + yield 50; + + g_Map.log("Creating grass patches"); + for (const 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( + [[tGrass, tRocksShrubs], [tRocksShrubs, tRocksGrass], [tRocksGrass, tGrass]], + [1, 1]), + new TileClassPainter(clDirt) + ], + avoidClasses(clForest, 0, clGrass, 5, clPlayer, 10, clWater, 4, clDirt, 5, clHill, 1), + scaleByMapSize(15, 45)); + yield 55; + + g_Map.log("Creating dirt patches"); + for (const 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( + [[tDirt, tDirtB], [tDirt, tMainDirt], [tDirtB, tMainDirt]], + [1, 1]), + new TileClassPainter(clDirt) + ], + avoidClasses(clForest, 0, clDirt, 5, clPlayer, 10, clWater, 4, clGrass, 5, clHill, 1), + scaleByMapSize(15, 45)); + yield 60; + + g_Map.log("Creating cyprus"); + createAreas( + new ClumpPlacer(diskArea(fractionToTiles(0.08)), 0.2, 0.1, 0.01), [ - stayClasses(clIsland, 9), - avoidClasses(clForest, 1, clRock, 8, clMetal, 8) + new LayeredPainter([tShore, tHill], [12]), + new SmoothElevationPainter(ELEVATION_SET, heightIsland, 8), + new TileClassPainter(clIsland), + new TileClassUnPainter(clWater) ], - scaleByMapSize(4, 16)); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 3, clHill, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 3, clHill, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clWater, 3, clHill, 1), - scaleByMapSize(4,16), 100 -); - -Engine.SetProgress(65); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aDecorativeRock, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 1), - scaleByMapSize(16, 262), 50 -); - -g_Map.log("Creating shrubs"); -group = new SimpleGroup( - [new SimpleObject(aBush2, 1,2, 0,1), new SimpleObject(aBush1, 1,3, 0,2), new SimpleObject(aBush4, 1,2, 0,1), new SimpleObject(aBush3, 1,3, 0,2)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clWater, 3, clPlayer, 0, clHill, 1), - scaleByMapSize(40, 360), 50 -); -Engine.SetProgress(70); - -g_Map.log("Creating fish"); -group = new SimpleGroup([new SimpleObject(oFish, 1,3, 2,6)], true, clFood); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clIsland, 2, clFood, 10), stayClasses(clWater, 5)], - 3*scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating sheeps"); -group = new SimpleGroup([new SimpleObject(oSheep, 5,7, 0,4)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 7, clWater, 3, clFood, 10, clHill, 1), - scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating goats"); -group = new SimpleGroup([new SimpleObject(oGoat, 2,4, 0,3)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 7, clWater, 3, clFood, 10, clHill, 1), - scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating deers"); -group = new SimpleGroup([new SimpleObject(oDeer, 2,4, 0,2)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 7, clWater, 3, clFood, 10, clHill, 1), - scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating grape bushes"); -group = new SimpleGroup( - [new SimpleObject(oGrapeBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 15, clHill, 1, clFood, 7), - randIntInclusive(1, 4) * numPlayers + 2, 50 -); -Engine.SetProgress(90); - -const stragglerTreeConfig = [ - [1, avoidClasses(clForest, 0, clWater, 4, clPlayer, 8, clMetal, 6, clHill, 1)], - [3, [stayClasses(clIsland, 9), avoidClasses(clRock, 4, clMetal, 4)]] -]; - -for (const [amount, constraint] of stragglerTreeConfig) - createStragglerTrees( - [oDatePalm, oSDatePalm, oCarob, oFanPalm, oPoplar, oCypress], - constraint, - clForest, - amount * stragglerTrees); - -setSkySet("sunny"); -setSunColor(0.917, 0.828, 0.734); -setWaterColor(0.263,0.314,0.631); -setWaterTint(0.133, 0.725,0.855); -setWaterWaviness(2.0); -setWaterType("ocean"); -setWaterMurkiness(0.8); - -setAmbientColor(0.447059, 0.509804, 0.54902); - -setSunElevation(0.671884); -setSunRotation(-0.582913); - -setFogFactor(0.2); -setFogThickness(0.15); -setFogColor(0.8, 0.7, 0.6); - -setPPEffect("hdr"); -setPPContrast(0.53); -setPPSaturation(0.47); -setPPBloom(0.52); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -g_Map.ExportMap(); + [stayClasses (clWater, 8)], + 1, + 100); + + g_Map.log("Creating cyprus mines"); + const mines = [ + new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock), + new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), + new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock) + ]; + for (const mine of mines) + createObjectGroups( + mine, + 0, + [ + stayClasses(clIsland, 9), + avoidClasses(clForest, 1, clRock, 8, clMetal, 8) + ], + scaleByMapSize(4, 16)); + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 3, clHill, 1), + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 3, clHill, 1), + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clWater, 3, clHill, 1), + scaleByMapSize(4,16), 100 + ); + + yield 65; + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aDecorativeRock, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 1), + scaleByMapSize(16, 262), 50 + ); + + g_Map.log("Creating shrubs"); + group = new SimpleGroup( + [new SimpleObject(aBush2, 1,2, 0,1), new SimpleObject(aBush1, 1,3, 0,2), + new SimpleObject(aBush4, 1,2, 0,1), new SimpleObject(aBush3, 1,3, 0,2)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clWater, 3, clPlayer, 0, clHill, 1), + scaleByMapSize(40, 360), 50 + ); + yield 70; + + g_Map.log("Creating fish"); + group = new SimpleGroup([new SimpleObject(oFish, 1,3, 2,6)], true, clFood); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clIsland, 2, clFood, 10), stayClasses(clWater, 5)], + 3*scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating sheeps"); + group = new SimpleGroup([new SimpleObject(oSheep, 5,7, 0,4)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 7, clWater, 3, clFood, 10, clHill, 1), + scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating goats"); + group = new SimpleGroup([new SimpleObject(oGoat, 2,4, 0,3)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 7, clWater, 3, clFood, 10, clHill, 1), + scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating deers"); + group = new SimpleGroup([new SimpleObject(oDeer, 2,4, 0,2)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 7, clWater, 3, clFood, 10, clHill, 1), + scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating grape bushes"); + group = new SimpleGroup( + [new SimpleObject(oGrapeBush, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 15, clHill, 1, clFood, 7), + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + yield 90; + + const stragglerTreeConfig = [ + [1, avoidClasses(clForest, 0, clWater, 4, clPlayer, 8, clMetal, 6, clHill, 1)], + [3, [stayClasses(clIsland, 9), avoidClasses(clRock, 4, clMetal, 4)]] + ]; + + for (const [amount, constraint] of stragglerTreeConfig) + createStragglerTrees( + [oDatePalm, oSDatePalm, oCarob, oFanPalm, oPoplar, oCypress], + constraint, + clForest, + amount * stragglerTrees); + + setSkySet("sunny"); + setSunColor(0.917, 0.828, 0.734); + setWaterColor(0.263,0.314,0.631); + setWaterTint(0.133, 0.725,0.855); + setWaterWaviness(2.0); + setWaterType("ocean"); + setWaterMurkiness(0.8); + + setAmbientColor(0.447059, 0.509804, 0.54902); + + setSunElevation(0.671884); + setSunRotation(-0.582913); + + setFogFactor(0.2); + setFogThickness(0.15); + setFogColor(0.8, 0.7, 0.6); + + setPPEffect("hdr"); + setPPContrast(0.53); + setPPSaturation(0.47); + setPPBloom(0.52); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, + clFood, 2)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/polar_sea.js =================================================================== --- binaries/data/mods/public/maps/random/polar_sea.js +++ binaries/data/mods/public/maps/random/polar_sea.js @@ -1,274 +1,279 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tPrimary = ["alpine_snow_01"]; -const tSecondary = "alpine_snow_02"; -const tShore = "alpine_ice_01"; -const tWater = "alpine_ice_01"; - -const oArcticFox = "gaia/fauna_fox_arctic"; -const oArcticWolf = "gaia/fauna_wolf_arctic_violent"; -const oMuskox = "gaia/fauna_muskox"; -const oWalrus = "gaia/fauna_walrus"; -const oWhaleFin = "gaia/fauna_whale_fin"; -const oWhaleHumpback = "gaia/fauna_whale_humpback"; -const oFish = "gaia/fish/generic"; -const oStoneLarge = "gaia/rock/polar_01"; -const oStoneSmall = "gaia/rock/alpine_small"; -const oMetalLarge = "gaia/ore/polar_01"; -const oWoodTreasure = "gaia/treasure/wood"; -const oMarket = "skirmish/structures/default_market"; - -const aRockLarge = "actor|geology/stone_granite_med.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aIceberg = "actor|props/special/eyecandy/iceberg.xml"; - -const heightSeaGround = -10; -const heightLand = 2; -const heightCliff = 3; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clArcticWolf = g_Map.createTileClass(); - -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - -const treasures = [{ - "template": oWoodTreasure, - "count": isNomad() ? 16 : 14 -}]; - -g_Map.log("Creating player markets"); -if (!isNomad()) - for (let i = 0; i < numPlayers; ++i) - { - const marketPos = Vector2D.add(playerPosition[i], new Vector2D(12, 0).rotate(randomAngle())).round(); - g_Map.placeEntityPassable(oMarket, playerIDs[i], marketPos, BUILDING_ORIENTATION); - addCivicCenterAreaToClass(marketPos, clBaseResource); - } +function* GenerateMap(mapSettings) +{ + const tPrimary = ["alpine_snow_01"]; + const tSecondary = "alpine_snow_02"; + const tShore = "alpine_ice_01"; + const tWater = "alpine_ice_01"; + + const oArcticFox = "gaia/fauna_fox_arctic"; + const oArcticWolf = "gaia/fauna_wolf_arctic_violent"; + const oMuskox = "gaia/fauna_muskox"; + const oWalrus = "gaia/fauna_walrus"; + const oWhaleFin = "gaia/fauna_whale_fin"; + const oWhaleHumpback = "gaia/fauna_whale_humpback"; + const oFish = "gaia/fish/generic"; + const oStoneLarge = "gaia/rock/polar_01"; + const oStoneSmall = "gaia/rock/alpine_small"; + const oMetalLarge = "gaia/ore/polar_01"; + const oWoodTreasure = "gaia/treasure/wood"; + const oMarket = "skirmish/structures/default_market"; + + const aRockLarge = "actor|geology/stone_granite_med.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aIceberg = "actor|props/special/eyecandy/iceberg.xml"; + + const heightSeaGround = -10; + const heightLand = 2; + const heightCliff = 3; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clArcticWolf = g_Map.createTileClass(); + + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + + const treasures = [{ + "template": oWoodTreasure, + "count": isNomad() ? 16 : 14 + }]; + + g_Map.log("Creating player markets"); + if (!isNomad()) + for (let i = 0; i < numPlayers; ++i) + { + const marketPos = Vector2D.add(playerPosition[i], + new Vector2D(12, 0).rotate(randomAngle())).round(); + g_Map.placeEntityPassable(oMarket, playerIDs[i], marketPos, BUILDING_ORIENTATION); + addCivicCenterAreaToClass(marketPos, clBaseResource); + } + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "Walls": "towers", + "CityPatch": { + "outerTerrain": tSecondary, + "innerTerrain": tSecondary + }, + "StartingAnimal": { + "template": oMuskox + }, + // No berries, no trees, no decoratives + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Treasures": { + "types": treasures + }, + }); + yield 30; + + g_Map.log("Creating central lake"); + createArea( + new ChainPlacer( + 2, + Math.floor(scaleByMapSize(5, 16)), + Math.floor(scaleByMapSize(35, 200)), + Infinity, + mapCenter, + 0, + [Math.floor(fractionToTiles(0.17))]), + [ + new LayeredPainter([tShore, tWater], [1]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 20)); -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "Walls": "towers", - "CityPatch": { - "outerTerrain": tSecondary, - "innerTerrain": tSecondary - }, - "StartingAnimal": { - "template": oMuskox - }, - // No berries, no trees, no decoratives - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Treasures": { - "types": treasures - }, -}); -Engine.SetProgress(30); - -g_Map.log("Creating central lake"); -createArea( - new ChainPlacer( - 2, - Math.floor(scaleByMapSize(5, 16)), - Math.floor(scaleByMapSize(35, 200)), - Infinity, - mapCenter, - 0, - [Math.floor(fractionToTiles(0.17))]), - [ - new LayeredPainter([tShore, tWater], [1]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 20)); - -Engine.SetProgress(40); - -g_Map.log("Creating small lakes"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(2, 4)), Math.floor(scaleByMapSize(20, 140)), 0.7), - [ - new LayeredPainter([tShore, tWater], [1]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 5), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 20), - scaleByMapSize(10, 16), - 1); -Engine.SetProgress(50); - -createBumps(avoidClasses(clWater, 2, clPlayer, 20)); -Engine.SetProgress(60); - -createHills( - [tSecondary, tSecondary, tSecondary], - avoidClasses(clPlayer, 20, clHill, 35), - clHill, - scaleByMapSize(20, 240)); -Engine.SetProgress(65); - -g_Map.log("Creating glacier patches"); -createPatches( - [scaleByMapSize(10, 20), scaleByMapSize(20, 30)], - tSecondary, - avoidClasses(clWater, 3, clDirt, 5, clPlayer, 12), - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(70); - -g_Map.log("Creating stone mines"); -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2, 5, 1, 3)] - ], - avoidClasses(clWater, 3, clPlayer, 20, clRock, 18, clHill, 2), - clRock); - -g_Map.log("Creating metal mines"); -createMines( - [ - [new SimpleObject(oMetalLarge, 1, 1, 0, 4)] - ], - avoidClasses(clWater, 3, clPlayer, 20, clMetal, 18, clRock, 5, clHill, 2), - clMetal); -Engine.SetProgress(75); - -createDecoration( - [ + yield 40; + + g_Map.log("Creating small lakes"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(2, 4)), Math.floor(scaleByMapSize(20, 140)), 0.7), [ - new SimpleObject(aRockMedium, 1, 3, 0, 1) + new LayeredPainter([tShore, tWater], [1]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 5), + new TileClassPainter(clWater) ], + avoidClasses(clPlayer, 20), + scaleByMapSize(10, 16), + 1); + yield 50; + + createBumps(avoidClasses(clWater, 2, clPlayer, 20)); + yield 60; + + createHills( + [tSecondary, tSecondary, tSecondary], + avoidClasses(clPlayer, 20, clHill, 35), + clHill, + scaleByMapSize(20, 240)); + yield 65; + + g_Map.log("Creating glacier patches"); + createPatches( + [scaleByMapSize(10, 20), scaleByMapSize(20, 30)], + tSecondary, + avoidClasses(clWater, 3, clDirt, 5, clPlayer, 12), + scaleByMapSize(15, 45), + clDirt); + yield 70; + + g_Map.log("Creating stone mines"); + createMines( [ - new SimpleObject(aRockLarge, 1, 2, 0, 1), - new SimpleObject(aRockMedium, 1, 3, 0, 2) - ] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - ], - avoidClasses(clWater, 0, clPlayer, 0)); - -createDecoration( - [ - [new SimpleObject(aIceberg, 1, 1, 1, 1)] - ], - [ - scaleByMapAreaAbsolute(8) - ], - [stayClasses(clWater, 4), avoidClasses(clHill, 2)]); -Engine.SetProgress(80); - -createFood( - [ - [new SimpleObject(oArcticFox, 1, 2, 0, 3)], - [new SimpleObject(isNomad() ? oArcticFox : oArcticWolf, 4, 6, 0, 4)], - [new SimpleObject(oWalrus, 2, 3, 0, 2)], - [new SimpleObject(oMuskox, 2, 3, 0, 2)] - ], - [ - 3 * numPlayers, - 5 * numPlayers, - 5 * numPlayers, - 12 * numPlayers - ], - avoidClasses(clPlayer, 35, clFood, 16, clWater, 2, clMetal, 4, clRock, 4, clHill, 2), - clFood); - -createFood( - [ - [new SimpleObject(oWhaleFin, 1, 2, 0, 2)], - [new SimpleObject(oWhaleHumpback, 1, 2, 0, 2)] - ], - [ - scaleByMapSize(1, 6) * 3, - scaleByMapSize(1, 6) * 3, - ], - [avoidClasses(clFood, 20, clHill, 5), stayClasses(clWater, 6)], - clFood); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 100 - ], - [avoidClasses(clFood, 12, clHill, 5), stayClasses(clWater, 6)], - clFood); -Engine.SetProgress(85); - -// Create trigger points where wolves spawn -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject("trigger/trigger_point_A", 1, 1, 0, 0)], true, clArcticWolf), - 0, - avoidClasses(clWater, 2, clMetal, 4, clRock, 4, clPlayer, 15, clHill, 2, clArcticWolf, 20), - 1000, - 100); -Engine.SetProgress(95); - -if (g_MapSettings.Daytime !== undefined ? g_MapSettings.Daytime == "dawn" : randBool(1/3)) -{ - setSkySet("sunset 1"); - setSunColor(0.8, 0.7, 0.6); - setAmbientColor(0.7, 0.6, 0.7); - setSunElevation(Math.PI * randFloat(1/24, 1/7)); -} -else -{ - setSkySet(pickRandom(["cumulus", "rain", "mountainous", "overcast", "rain", "stratus"])); - setSunElevation(Math.PI * randFloat(1/9, 1/7)); -} + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oStoneSmall, 2, 5, 1, 3)] + ], + avoidClasses(clWater, 3, clPlayer, 20, clRock, 18, clHill, 2), + clRock); -if (isNomad()) -{ - const constraint = avoidClasses(clWater, 4, clMetal, 4, clRock, 4, clHill, 4, clFood, 2); - [playerIDs, playerPosition] = placePlayersNomad(clPlayer, constraint); - - for (let i = 0; i < numPlayers; ++i) - placePlayerBaseTreasures({ - "playerID": playerIDs[i], - "playerPosition": playerPosition[i], - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": constraint, - "types": treasures - }); -} + g_Map.log("Creating metal mines"); + createMines( + [ + [new SimpleObject(oMetalLarge, 1, 1, 0, 4)] + ], + avoidClasses(clWater, 3, clPlayer, 20, clMetal, 18, clRock, 5, clHill, 2), + clMetal); + yield 75; + + createDecoration( + [ + [ + new SimpleObject(aRockMedium, 1, 3, 0, 1) + ], + [ + new SimpleObject(aRockLarge, 1, 2, 0, 1), + new SimpleObject(aRockMedium, 1, 3, 0, 2) + ] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + ], + avoidClasses(clWater, 0, clPlayer, 0)); + + createDecoration( + [ + [new SimpleObject(aIceberg, 1, 1, 1, 1)] + ], + [ + scaleByMapAreaAbsolute(8) + ], + [stayClasses(clWater, 4), avoidClasses(clHill, 2)]); + yield 80; -setSunRotation(randomAngle()); + createFood( + [ + [new SimpleObject(oArcticFox, 1, 2, 0, 3)], + [new SimpleObject(isNomad() ? oArcticFox : oArcticWolf, 4, 6, 0, 4)], + [new SimpleObject(oWalrus, 2, 3, 0, 2)], + [new SimpleObject(oMuskox, 2, 3, 0, 2)] + ], + [ + 3 * numPlayers, + 5 * numPlayers, + 5 * numPlayers, + 12 * numPlayers + ], + avoidClasses(clPlayer, 35, clFood, 16, clWater, 2, clMetal, 4, clRock, 4, clHill, 2), + clFood); -setWaterColor(0.3, 0.3, 0.4); -setWaterTint(0.75, 0.75, 0.75); -setWaterMurkiness(0.92); -setWaterWaviness(0.5); -setWaterType("clap"); + createFood( + [ + [new SimpleObject(oWhaleFin, 1, 2, 0, 2)], + [new SimpleObject(oWhaleHumpback, 1, 2, 0, 2)] + ], + [ + scaleByMapSize(1, 6) * 3, + scaleByMapSize(1, 6) * 3, + ], + [avoidClasses(clFood, 20, clHill, 5), stayClasses(clWater, 6)], + clFood); -setFogThickness(0.76); -setFogFactor(0.7); + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 100 + ], + [avoidClasses(clFood, 12, clHill, 5), stayClasses(clWater, 6)], + clFood); + yield 85; -setPPEffect("hdr"); -setPPContrast(0.6); -setPPSaturation(0.45); -setPPBloom(0.4); + // Create trigger points where wolves spawn + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject("trigger/trigger_point_A", 1, 1, 0, 0)], true, clArcticWolf), + 0, + avoidClasses(clWater, 2, clMetal, 4, clRock, 4, clPlayer, 15, clHill, 2, clArcticWolf, 20), + 1000, + 100); + yield 95; -g_Map.ExportMap(); + if (mapSettings.Daytime !== undefined ? mapSettings.Daytime == "dawn" : randBool(1/3)) + { + setSkySet("sunset 1"); + setSunColor(0.8, 0.7, 0.6); + setAmbientColor(0.7, 0.6, 0.7); + setSunElevation(Math.PI * randFloat(1/24, 1/7)); + } + else + { + setSkySet(pickRandom(["cumulus", "rain", "mountainous", "overcast", "rain", "stratus"])); + setSunElevation(Math.PI * randFloat(1/9, 1/7)); + } + + if (isNomad()) + { + const constraint = avoidClasses(clWater, 4, clMetal, 4, clRock, 4, clHill, 4, clFood, 2); + [playerIDs, playerPosition] = placePlayersNomad(clPlayer, constraint); + + for (let i = 0; i < numPlayers; ++i) + placePlayerBaseTreasures({ + "playerID": playerIDs[i], + "playerPosition": playerPosition[i], + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": constraint, + "types": treasures + }); + } + + setSunRotation(randomAngle()); + + setWaterColor(0.3, 0.3, 0.4); + setWaterTint(0.75, 0.75, 0.75); + setWaterMurkiness(0.92); + setWaterWaviness(0.5); + setWaterType("clap"); + + setFogThickness(0.76); + setFogFactor(0.7); + + setPPEffect("hdr"); + setPPContrast(0.6); + setPPSaturation(0.45); + setPPBloom(0.4); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/pompeii.js =================================================================== --- binaries/data/mods/public/maps/random/pompeii.js +++ binaries/data/mods/public/maps/random/pompeii.js @@ -21,442 +21,450 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setBiome("generic/aegean"); - -g_Terrains.lavaOuter = "LavaTest06"; -g_Terrains.lavaInner = "LavaTest05"; -g_Terrains.lavaCenter = "LavaTest04"; -g_Terrains.mainTerrain = "ocean_rock_a"; -g_Terrains.forestFloor1 = "dirt_burned"; -g_Terrains.forestFloor2 = "shoreline_stoney_a"; -g_Terrains.tier1Terrain = "rock_metamorphic"; -g_Terrains.tier2Terrain = "fissures"; -g_Terrains.tier3Terrain = "LavaTest06"; -g_Terrains.tier4Terrain = "ocean_rock_b"; -g_Terrains.roadWild = "road1"; -g_Terrains.road = "road1"; -g_Terrains.water = "ocean_rock_a"; -g_Terrains.cliff = "ocean_rock_b"; - -g_Gaia.mainHuntableAnimal = "gaia/fauna_goat"; -g_Gaia.secondaryHuntableAnimal = "birds/buzzard"; -g_Gaia.fruitBush = "gaia/fauna_chicken"; -g_Gaia.fish = "gaia/fish/generic"; -g_Gaia.tree1 = "gaia/tree/dead"; -g_Gaia.tree2 = "gaia/tree/oak_dead"; -g_Gaia.tree3 = "gaia/tree/dead"; -g_Gaia.tree4 = "gaia/tree/oak_dead"; -g_Gaia.tree5 = "gaia/tree/dead"; -g_Gaia.stoneSmall = "gaia/rock/alpine_small"; -g_Gaia.columnsDoric = "gaia/ruins/column_doric"; -g_Gaia.romanStatue = "gaia/ruins/stone_statues_roman"; -g_Gaia.unfinishedTemple = "gaia/ruins/unfinished_greek_temple"; -g_Gaia.dock = "structures/rome/dock"; -g_Gaia.dockRubble = "rubble/rubble_rome_dock"; - -g_Decoratives.smoke1 = "actor|particle/smoke_volcano.xml"; -g_Decoratives.smoke2 = "actor|particle/smoke_curved.xml"; -g_Decoratives.grass = "actor|props/flora/grass_field_parched_short.xml"; -g_Decoratives.grassShort = "actor|props/flora/grass_soft_dry_tuft_a.xml"; -g_Decoratives.bushMedium = "actor|props/special/eyecandy/barrels_buried.xml"; -g_Decoratives.bushSmall = "actor|props/special/eyecandy/handcart_1_broken.xml"; -g_Decoratives.skeleton = "actor|props/special/eyecandy/skeleton.xml"; -g_Decoratives.shipwrecks = [ - "actor|props/special/eyecandy/shipwreck_hull.xml", - "actor|props/special/eyecandy/shipwreck_ram_side.xml", - "actor|props/special/eyecandy/shipwreck_sail_boat.xml", - "actor|props/special/eyecandy/shipwreck_sail_boat_cut.xml", - "actor|props/special/eyecandy/barrels_floating.xml" -]; -g_Decoratives.statues = [ - "actor|props/special/eyecandy/statue_aphrodite_huge.xml", - "actor|props/special/eyecandy/sele_colonnade.xml", - "actor|props/special/eyecandy/well_1_b.xml", - "actor|props/special/eyecandy/anvil.xml", - "actor|props/special/eyecandy/wheel_laying.xml", - "actor|props/special/eyecandy/vase_rome_a.xml" -]; - -const heightScale = num => num * g_MapSettings.Size / 320; - -const heightSeaGround = heightScale(-30); -const heightDockMin = heightScale(-6); -const heightShorelineMin = heightScale(-1); -const heightShorelineMax = heightScale(0); -const heightWaterLevel = heightScale(0); -const heightDockMax = heightScale(1); -const heightLavaVesuv = heightScale(38); -const heightMountains = 140; - -const g_Map = new RandomMap(0, g_Terrains.mainTerrain); -const mapCenter = g_Map.getCenter(); - -initTileClasses(["decorative", "lava", "dock"]); - -g_Map.LoadHeightmapImage("pompeii.png", 0, heightMountains); -Engine.SetProgress(15); - -g_Map.log("Lowering sea ground"); -createArea( - new MapBoundsPlacer(), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 2), - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(20); - -g_Map.log("Smoothing heightmap"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, 0.8, 1)); -Engine.SetProgress(25); - -g_Map.log("Marking water"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.water), - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(30); - -g_Map.log("Marking land"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land), - avoidClasses(g_TileClasses.water, 0)); -Engine.SetProgress(35); - -g_Map.log("Painting cliffs"); -createArea( - new MapBoundsPlacer(), - [ - new TerrainPainter(g_Terrains.cliff), - new TileClassPainter(g_TileClasses.mountain), - ], - [ - avoidClasses(g_TileClasses.water, 2), - new SlopeConstraint(2, Infinity) - ]); -Engine.SetProgress(45); - -g_Map.log("Painting lava"); -const areaVesuv = createArea( - new RectPlacer(new Vector2D(mapCenter.x, fractionToTiles(0.3)), new Vector2D(fractionToTiles(0.7), fractionToTiles(0.15))), - [ - new LayeredPainter([g_Terrains.lavaOuter,g_Terrains.lavaInner, g_Terrains.lavaCenter], [scaleByMapSize(1, 3), 2]), - new TileClassPainter(g_TileClasses.lava) - ], - new HeightConstraint(heightLavaVesuv, Infinity)); -Engine.SetProgress(46); - -g_Map.log("Adding smoke"); -createObjectGroupsByAreas( - new SimpleGroup( +function* GenerateMap() +{ + setBiome("generic/aegean"); + + g_Terrains.lavaOuter = "LavaTest06"; + g_Terrains.lavaInner = "LavaTest05"; + g_Terrains.lavaCenter = "LavaTest04"; + g_Terrains.mainTerrain = "ocean_rock_a"; + g_Terrains.forestFloor1 = "dirt_burned"; + g_Terrains.forestFloor2 = "shoreline_stoney_a"; + g_Terrains.tier1Terrain = "rock_metamorphic"; + g_Terrains.tier2Terrain = "fissures"; + g_Terrains.tier3Terrain = "LavaTest06"; + g_Terrains.tier4Terrain = "ocean_rock_b"; + g_Terrains.roadWild = "road1"; + g_Terrains.road = "road1"; + g_Terrains.water = "ocean_rock_a"; + g_Terrains.cliff = "ocean_rock_b"; + + g_Gaia.mainHuntableAnimal = "gaia/fauna_goat"; + g_Gaia.secondaryHuntableAnimal = "birds/buzzard"; + g_Gaia.fruitBush = "gaia/fauna_chicken"; + g_Gaia.fish = "gaia/fish/generic"; + g_Gaia.tree1 = "gaia/tree/dead"; + g_Gaia.tree2 = "gaia/tree/oak_dead"; + g_Gaia.tree3 = "gaia/tree/dead"; + g_Gaia.tree4 = "gaia/tree/oak_dead"; + g_Gaia.tree5 = "gaia/tree/dead"; + g_Gaia.stoneSmall = "gaia/rock/alpine_small"; + g_Gaia.columnsDoric = "gaia/ruins/column_doric"; + g_Gaia.romanStatue = "gaia/ruins/stone_statues_roman"; + g_Gaia.unfinishedTemple = "gaia/ruins/unfinished_greek_temple"; + g_Gaia.dock = "structures/rome/dock"; + g_Gaia.dockRubble = "rubble/rubble_rome_dock"; + + g_Decoratives.smoke1 = "actor|particle/smoke_volcano.xml"; + g_Decoratives.smoke2 = "actor|particle/smoke_curved.xml"; + g_Decoratives.grass = "actor|props/flora/grass_field_parched_short.xml"; + g_Decoratives.grassShort = "actor|props/flora/grass_soft_dry_tuft_a.xml"; + g_Decoratives.bushMedium = "actor|props/special/eyecandy/barrels_buried.xml"; + g_Decoratives.bushSmall = "actor|props/special/eyecandy/handcart_1_broken.xml"; + g_Decoratives.skeleton = "actor|props/special/eyecandy/skeleton.xml"; + g_Decoratives.shipwrecks = [ + "actor|props/special/eyecandy/shipwreck_hull.xml", + "actor|props/special/eyecandy/shipwreck_ram_side.xml", + "actor|props/special/eyecandy/shipwreck_sail_boat.xml", + "actor|props/special/eyecandy/shipwreck_sail_boat_cut.xml", + "actor|props/special/eyecandy/barrels_floating.xml" + ]; + g_Decoratives.statues = [ + "actor|props/special/eyecandy/statue_aphrodite_huge.xml", + "actor|props/special/eyecandy/sele_colonnade.xml", + "actor|props/special/eyecandy/well_1_b.xml", + "actor|props/special/eyecandy/anvil.xml", + "actor|props/special/eyecandy/wheel_laying.xml", + "actor|props/special/eyecandy/vase_rome_a.xml" + ]; + + const heightScale = num => num * g_MapSettings.Size / 320; + + const heightSeaGround = heightScale(-30); + const heightDockMin = heightScale(-6); + const heightShorelineMin = heightScale(-1); + const heightShorelineMax = heightScale(0); + const heightWaterLevel = heightScale(0); + const heightDockMax = heightScale(1); + const heightLavaVesuv = heightScale(38); + const heightMountains = 140; + + global.g_Map = new RandomMap(0, g_Terrains.mainTerrain); + const mapCenter = g_Map.getCenter(); + + initTileClasses(["decorative", "lava", "dock"]); + + g_Map.LoadHeightmapImage("pompeii.png", 0, heightMountains); + yield 15; + + g_Map.log("Lowering sea ground"); + createArea( + new MapBoundsPlacer(), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 2), + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 20; + + g_Map.log("Smoothing heightmap"); + createArea( + new MapBoundsPlacer(), + new SmoothingPainter(1, 0.8, 1)); + yield 25; + + g_Map.log("Marking water"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.water), + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 30; + + g_Map.log("Marking land"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land), + avoidClasses(g_TileClasses.water, 0)); + yield 35; + + g_Map.log("Painting cliffs"); + createArea( + new MapBoundsPlacer(), [ - new SimpleObject(g_Decoratives.smoke1, 1, 1, 0, 4), - new SimpleObject(g_Decoratives.smoke2, 2, 2, 0, 4) + new TerrainPainter(g_Terrains.cliff), + new TileClassPainter(g_TileClasses.mountain), ], - false), - 0, - stayClasses(g_TileClasses.lava, 0), - scaleByMapSize(4, 12), - 20, - [areaVesuv]); -Engine.SetProgress(48); - -if (!isNomad()) -{ - g_Map.log("Placing players"); - const [playerIDs, playerPosition] = createBases( - ...playerPlacementRandom( - sortAllPlayers(), - [ - avoidClasses(g_TileClasses.mountain, 5), - stayClasses(g_TileClasses.land, scaleByMapSize(5, 15)) - ]), - false); - - g_Map.log("Flatten the initial CC area"); - for (const position of playerPosition) - createArea( - new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, position), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); -} -Engine.SetProgress(50); - -g_Map.log("Placing docks"); -const dockTypes = [ - { "template": g_Gaia.dock, "count": scaleByMapSize(1, 2) }, - { "template": g_Gaia.dockRubble, "count": scaleByMapSize(2, 3) } -]; -for (const dockType of dockTypes) - placeDocks( - dockType.template, - 0, - dockType.count, - g_TileClasses.water, - g_TileClasses.dock, - heightDockMin, - heightDockMax, [ - avoidClasses(g_TileClasses.dock, scaleByMapSize(10, 25)), - new StaticConstraint(avoidClasses( - g_TileClasses.mountain, scaleByMapSize(6, 8), - g_TileClasses.baseResource, 10)) + avoidClasses(g_TileClasses.water, 2), + new SlopeConstraint(2, Infinity) + ]); + yield 45; + + g_Map.log("Painting lava"); + const areaVesuv = createArea( + new RectPlacer(new Vector2D(mapCenter.x, fractionToTiles(0.3)), + new Vector2D(fractionToTiles(0.7), fractionToTiles(0.15))), + [ + new LayeredPainter([g_Terrains.lavaOuter,g_Terrains.lavaInner, g_Terrains.lavaCenter], + [scaleByMapSize(1, 3), 2]), + new TileClassPainter(g_TileClasses.lava) ], + new HeightConstraint(heightLavaVesuv, Infinity)); + yield 46; + + g_Map.log("Adding smoke"); + createObjectGroupsByAreas( + new SimpleGroup( + [ + new SimpleObject(g_Decoratives.smoke1, 1, 1, 0, 4), + new SimpleObject(g_Decoratives.smoke2, 2, 2, 0, 4) + ], + false), 0, - 50); -Engine.SetProgress(55); + stayClasses(g_TileClasses.lava, 0), + scaleByMapSize(4, 12), + 20, + [areaVesuv]); + yield 48; -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.lava, 2, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - }, + if (!isNomad()) { - "func": addDecoration, - "avoid": [ - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.lava, 2, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] + g_Map.log("Placing players"); + const [playerIDs, playerPosition] = createBases( + ...playerPlacementRandom( + sortAllPlayers(), + [ + avoidClasses(g_TileClasses.mountain, 5), + stayClasses(g_TileClasses.land, scaleByMapSize(5, 15)) + ]), + false); + + g_Map.log("Flatten the initial CC area"); + for (const position of playerPosition) + createArea( + new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, + position), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); } -]); -Engine.SetProgress(60); - -addElements(shuffleArray([ - { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.metal, 20, - g_TileClasses.lava, 5, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["few"] - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 10, - g_TileClasses.lava, 5, - g_TileClasses.water, 5 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["few"] - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 18, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 5, + yield 50; + + g_Map.log("Placing docks"); + const dockTypes = [ + { "template": g_Gaia.dock, "count": scaleByMapSize(1, 2) }, + { "template": g_Gaia.dockRubble, "count": scaleByMapSize(2, 3) } + ]; + for (const dockType of dockTypes) + placeDocks( + dockType.template, + 0, + dockType.count, + g_TileClasses.water, + g_TileClasses.dock, + heightDockMin, + heightDockMax, + [ + avoidClasses(g_TileClasses.dock, scaleByMapSize(10, 25)), + new StaticConstraint(avoidClasses( + g_TileClasses.mountain, scaleByMapSize(6, 8), + g_TileClasses.baseResource, 10)) + ], + 0, + 50); + yield 55; + + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.lava, 2, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.lava, 2, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + } + ]); + yield 60; + + addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 20, + g_TileClasses.lava, 5, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["few"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10, + g_TileClasses.lava, 5, + g_TileClasses.water, 5 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["few"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 18, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + } + ])); + yield 65; + + addElements(shuffleArray([ + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.lava, 10, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["few"] + }, + { + "func": addFish, + "avoid": [ + g_TileClasses.fish, 12, + g_TileClasses.player, 8 + ], + "stay": [g_TileClasses.water, 4], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["few"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 7, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.lava, 5, + g_TileClasses.water, 5 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + } + ])); + yield 70; + + g_Map.log("Adding gatherable stone statues"); + createObjectGroups( + new SimpleGroup( + [new SimpleObject(g_Gaia.romanStatue, 1, 1, 1, 4)], + true, + g_TileClasses.metal + ), + 0, + avoidClasses( + g_TileClasses.water, 2, g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.water, 2 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - } -])); -Engine.SetProgress(65); - -addElements(shuffleArray([ - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, + g_TileClasses.mountain, 3, g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, + g_TileClasses.lava, 5, + g_TileClasses.metal, 20 + ), + 5 * scaleByMapSize(1, 4), + 50); + yield 75; + + g_Map.log("Adding stone ruins"); + createObjectGroups( + new SimpleGroup( + [ + new SimpleObject(g_Gaia.unfinishedTemple, 0, 1, 1, 4), + new SimpleObject(g_Gaia.columnsDoric, 1, 1, 1, 4) + ], + true, + g_TileClasses.decorative + ), + 0, + avoidClasses( + g_TileClasses.water, 2, g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.lava, 10, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["few"] - }, - { - "func": addFish, - "avoid": [ - g_TileClasses.fish, 12, - g_TileClasses.player, 8 - ], - "stay": [g_TileClasses.water, 4], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["few"] - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 7, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, + g_TileClasses.mountain, 5, + g_TileClasses.forest, 2, g_TileClasses.lava, 5, - g_TileClasses.water, 5 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["tons"] - } -])); -Engine.SetProgress(70); - -g_Map.log("Adding gatherable stone statues"); -createObjectGroups( - new SimpleGroup( - [new SimpleObject(g_Gaia.romanStatue, 1, 1, 1, 4)], - true, - g_TileClasses.metal - ), - 0, - avoidClasses( - g_TileClasses.water, 2, - g_TileClasses.player, 20, - g_TileClasses.mountain, 3, - g_TileClasses.forest, 2, - g_TileClasses.lava, 5, - g_TileClasses.metal, 20 - ), - 5 * scaleByMapSize(1, 4), - 50); -Engine.SetProgress(75); - -g_Map.log("Adding stone ruins"); -createObjectGroups( - new SimpleGroup( + g_TileClasses.decorative, 20 + ), + scaleByMapSize(1, 4), + 20); + yield 80; + + g_Map.log("Adding shipwrecks"); + createObjectGroups( + new SimpleGroup(g_Decoratives.shipwrecks.map( + shipwreck => new SimpleObject(shipwreck, 0, 1, 1, 20)), true, g_TileClasses.decorative), + 0, [ - new SimpleObject(g_Gaia.unfinishedTemple, 0, 1, 1, 4), - new SimpleObject(g_Gaia.columnsDoric, 1, 1, 1, 4) + avoidClasses(g_TileClasses.decorative, 20), + stayClasses(g_TileClasses.water, 0) ], - true, - g_TileClasses.decorative - ), - 0, - avoidClasses( - g_TileClasses.water, 2, - g_TileClasses.player, 20, - g_TileClasses.mountain, 5, - g_TileClasses.forest, 2, - g_TileClasses.lava, 5, - g_TileClasses.decorative, 20 - ), - scaleByMapSize(1, 4), - 20); -Engine.SetProgress(80); - -g_Map.log("Adding shipwrecks"); -createObjectGroups( - new SimpleGroup(g_Decoratives.shipwrecks.map(shipwreck => new SimpleObject(shipwreck, 0, 1, 1, 20)), true, g_TileClasses.decorative), - 0, - [ - avoidClasses(g_TileClasses.decorative, 20), - stayClasses(g_TileClasses.water, 0) - ], - scaleByMapSize(1, 5), - 20); -Engine.SetProgress(85); - -g_Map.log("Adding more statues"); -createObjectGroups( - new SimpleGroup(g_Decoratives.statues.map(ruin => new SimpleObject(ruin, 0, 1, 1, 20)), true, g_TileClasses.decorative), - 0, - avoidClasses( - g_TileClasses.water, 2, - g_TileClasses.player, 20, - g_TileClasses.mountain, 2, - g_TileClasses.forest, 2, - g_TileClasses.lava, 5, - g_TileClasses.decorative, 20 - ), - scaleByMapSize(3, 15), - 30); -Engine.SetProgress(90); - -g_Map.log("Adding skeletons"); -createObjectGroups( - new SimpleGroup( - [new SimpleObject(g_Decoratives.skeleton, 3, 10, 1, 7)], - true, - g_TileClasses.dirt - ), - 0, - avoidClasses( - g_TileClasses.water, 2, - g_TileClasses.player, 10, - g_TileClasses.mountain, 2, - g_TileClasses.forest, 2, - g_TileClasses.decorative, 2 - ), - scaleByMapSize(1, 5), - 50); -Engine.SetProgress(95); - -placePlayersNomad( - g_Map.createTileClass(), - [ - stayClasses(g_TileClasses.land, 5), + scaleByMapSize(1, 5), + 20); + yield 85; + + g_Map.log("Adding more statues"); + createObjectGroups( + new SimpleGroup(g_Decoratives.statues.map(ruin => new SimpleObject(ruin, 0, 1, 1, 20)), true, + g_TileClasses.decorative), + 0, avoidClasses( - g_TileClasses.forest, 1, - g_TileClasses.rock, 4, - g_TileClasses.metal, 4, - g_TileClasses.animals, 2, - g_TileClasses.mountain, 2) - ]); - -setWaterTint(0.5, 0.5, 0.5); -setWaterColor(0.3, 0.3, 0.3); -setWaterWaviness(8); -setWaterMurkiness(0.87); -setWaterType("lake"); - -setAmbientColor(0.3, 0.3, 0.3); - -setSunColor(0.8, 0.8, 0.8); -setSunRotation(Math.PI); -setSunElevation(1/2); - -setFogFactor(0); -setFogThickness(0); -setFogColor(0.69, 0.616, 0.541); - -setSkySet("stormy"); - -setPPEffect("hdr"); -setPPContrast(0.67); -setPPSaturation(0.42); -setPPBloom(0.23); + g_TileClasses.water, 2, + g_TileClasses.player, 20, + g_TileClasses.mountain, 2, + g_TileClasses.forest, 2, + g_TileClasses.lava, 5, + g_TileClasses.decorative, 20 + ), + scaleByMapSize(3, 15), + 30); + yield 90; + + g_Map.log("Adding skeletons"); + createObjectGroups( + new SimpleGroup( + [new SimpleObject(g_Decoratives.skeleton, 3, 10, 1, 7)], + true, + g_TileClasses.dirt + ), + 0, + avoidClasses( + g_TileClasses.water, 2, + g_TileClasses.player, 10, + g_TileClasses.mountain, 2, + g_TileClasses.forest, 2, + g_TileClasses.decorative, 2 + ), + scaleByMapSize(1, 5), + 50); + yield 95; -g_Map.ExportMap(); + placePlayersNomad( + g_Map.createTileClass(), + [ + stayClasses(g_TileClasses.land, 5), + avoidClasses( + g_TileClasses.forest, 1, + g_TileClasses.rock, 4, + g_TileClasses.metal, 4, + g_TileClasses.animals, 2, + g_TileClasses.mountain, 2) + ]); + + setWaterTint(0.5, 0.5, 0.5); + setWaterColor(0.3, 0.3, 0.3); + setWaterWaviness(8); + setWaterMurkiness(0.87); + setWaterType("lake"); + + setAmbientColor(0.3, 0.3, 0.3); + + setSunColor(0.8, 0.8, 0.8); + setSunRotation(Math.PI); + setSunElevation(1/2); + + setFogFactor(0); + setFogThickness(0); + setFogColor(0.69, 0.616, 0.541); + + setSkySet("stormy"); + + setPPEffect("hdr"); + setPPContrast(0.67); + setPPSaturation(0.42); + setPPBloom(0.23); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/pyrenean_sierra.js =================================================================== --- binaries/data/mods/public/maps/random/pyrenean_sierra.js +++ binaries/data/mods/public/maps/random/pyrenean_sierra.js @@ -2,466 +2,496 @@ Engine.LoadLibrary("rmgen-common"); TILE_CENTERED_HEIGHT_MAP = true; -const tGrassSpecific = ["new_alpine_grass_d","new_alpine_grass_d", "new_alpine_grass_e"]; -const tGrass = ["new_alpine_grass_d", "new_alpine_grass_b", "new_alpine_grass_e"]; -const tGrassMidRange = ["new_alpine_grass_b", "alpine_grass_a"]; -const tGrassHighRange = ["new_alpine_grass_a", "alpine_grass_a", "alpine_grass_rocky"]; -const tHighRocks = ["alpine_cliff_b", "alpine_cliff_c","alpine_cliff_c", "alpine_grass_rocky"]; -const tSnowedRocks = ["alpine_cliff_b", "alpine_cliff_snow"]; -const tTopSnow = ["alpine_snow_rocky","alpine_snow_a"]; -const tTopSnowOnly = ["alpine_snow_a"]; -const tDirtyGrass = ["new_alpine_grass_d","alpine_grass_d","alpine_grass_c", "alpine_grass_b"]; -const tLushGrass = ["new_alpine_grass_a","new_alpine_grass_d"]; -const tMidRangeCliffs = ["alpine_cliff_b","alpine_cliff_c"]; -const tHighRangeCliffs = ["alpine_mountainside","alpine_cliff_snow" ]; -const tSand = ["beach_c", "beach_d"]; -const tSandTransition = ["beach_scrub_50_"]; -const tWater = ["sand_wet_a","sand_wet_b","sand_wet_b","sand_wet_b"]; -const tGrassLandForest = "alpine_forrestfloor"; -const tGrassLandForest2 = "alpine_grass_d"; -const tForestTransition = ["new_alpine_grass_d", "new_alpine_grass_b","alpine_grass_d"]; -const tRoad = "new_alpine_citytile"; -const tRoadWild = "new_alpine_citytile"; - -const oBeech = "gaia/tree/euro_beech"; -const oPine = "gaia/tree/aleppo_pine"; -const oBerryBush = "gaia/fruit/berry_01"; -const oDeer = "gaia/fauna_deer"; -const oFish = "gaia/fish/generic"; -const oRabbit = "gaia/fauna_rabbit"; -const oStoneLarge = "gaia/rock/alpine_large"; -const oStoneSmall = "gaia/rock/alpine_small"; -const oMetalLarge = "gaia/ore/alpine_large"; -const oMetalSmall = "gaia/ore/alpine_small"; - -const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; -const aGrassShort = "actor|props/flora/grass_soft_large.xml"; -const aRockLarge = "actor|geology/stone_granite_med.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aBushMedium = "actor|props/flora/bush_medit_me.xml"; -const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; - -const pForestLand = [tGrassLandForest + TERRAIN_SEPARATOR + oPine,tGrassLandForest + TERRAIN_SEPARATOR + oBeech, - tGrassLandForest2 + TERRAIN_SEPARATOR + oPine,tGrassLandForest2 + TERRAIN_SEPARATOR + oBeech, - tGrassLandForest,tGrassLandForest2,tGrassLandForest2,tGrassLandForest2]; -const pForestLandLight = [tGrassLandForest + TERRAIN_SEPARATOR + oPine,tGrassLandForest + TERRAIN_SEPARATOR + oBeech, - tGrassLandForest2 + TERRAIN_SEPARATOR + oPine,tGrassLandForest2 + TERRAIN_SEPARATOR + oBeech, - tGrassLandForest,tGrassLandForest2,tForestTransition,tGrassLandForest2, - tGrassLandForest,tForestTransition,tGrassLandForest2,tForestTransition, - tGrassLandForest2,tGrassLandForest2,tGrassLandForest2,tGrassLandForest2]; -const pForestLandVeryLight = [ tGrassLandForest2 + TERRAIN_SEPARATOR + oPine,tGrassLandForest2 + TERRAIN_SEPARATOR + oBeech, - tForestTransition,tGrassLandForest2,tForestTransition,tForestTransition,tForestTransition, - tGrassLandForest,tForestTransition,tGrassLandForest2,tForestTransition, - tGrassLandForest2,tGrassLandForest2,tGrassLandForest2,tGrassLandForest2]; - -const heightInit = -100; -const heightOcean = -22; -const heightWaterTerrain = -14; -const heightBase = -6; -const heightSand = -2; -const heightSandTransition = 0; -const heightGrass = 6; -const heightWaterLevel = 8; -const heightPyreneans = 15; -const heightGrassMidRange = 18; -const heightGrassHighRange = 30; -const heightPassage = scaleByMapSize(25, 40); -const heightHighRocks = heightPassage + 5; -const heightSnowedRocks = heightHighRocks + 10; -const heightMountain = heightHighRocks + 20; - -const heightOffsetHill = 7; -const heightOffsetHillRandom = 2; - -const g_Map = new RandomMap(heightInit, tGrass); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clPass = g_Map.createTileClass(); -const clPyrenneans = g_Map.createTileClass(); -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); - -const startAngle = randomAngle(); -const oceanAngle = startAngle + randFloat(-1, 1) * Math.PI / 12; - -const mountainLength = fractionToTiles(0.68); -const mountainWidth = scaleByMapSize(15, 55); - -const mountainPeaks = 100 * scaleByMapSize(1, 10); -const mountainOffset = randFloat(-1, 1) * scaleByMapSize(1, 12); - -const passageLength = scaleByMapSize(8, 50); - -const terrainPerHeight = [ - { - "maxHeight": heightGrass, - "steepness": 5, - "terrainGround": tGrass, - "terrainSteep": tMidRangeCliffs - }, - { - "maxHeight": heightGrassMidRange, - "steepness": 8, - "terrainGround": tGrassMidRange, - "terrainSteep": tMidRangeCliffs - }, - { - "maxHeight": heightGrassHighRange, - "steepness": 8, - "terrainGround": tGrassHighRange, - "terrainSteep": tMidRangeCliffs - }, - { - "maxHeight": heightHighRocks, - "steepness": 8, - "terrainGround": tHighRocks, - "terrainSteep": tHighRangeCliffs - }, - { - "maxHeight": heightSnowedRocks, - "steepness": 7, - "terrainGround": tSnowedRocks, - "terrainSteep": tHighRangeCliffs - }, - { - "maxHeight": Infinity, - "steepness": 6, - "terrainGround": tTopSnowOnly, - "terrainSteep": tTopSnow - } -]; - -g_Map.log("Creating initial sinusoidal noise"); -let baseHeights = []; -for (let ix = 0; ix < mapSize; ix++) +function* GenerateMap() { - baseHeights.push([]); - for (let iz = 0; iz < mapSize; iz++) + const tGrassSpecific = ["new_alpine_grass_d","new_alpine_grass_d", "new_alpine_grass_e"]; + const tGrass = ["new_alpine_grass_d", "new_alpine_grass_b", "new_alpine_grass_e"]; + const tGrassMidRange = ["new_alpine_grass_b", "alpine_grass_a"]; + const tGrassHighRange = ["new_alpine_grass_a", "alpine_grass_a", "alpine_grass_rocky"]; + const tHighRocks = ["alpine_cliff_b", "alpine_cliff_c","alpine_cliff_c", "alpine_grass_rocky"]; + const tSnowedRocks = ["alpine_cliff_b", "alpine_cliff_snow"]; + const tTopSnow = ["alpine_snow_rocky","alpine_snow_a"]; + const tTopSnowOnly = ["alpine_snow_a"]; + const tDirtyGrass = ["new_alpine_grass_d","alpine_grass_d","alpine_grass_c", "alpine_grass_b"]; + const tLushGrass = ["new_alpine_grass_a","new_alpine_grass_d"]; + const tMidRangeCliffs = ["alpine_cliff_b","alpine_cliff_c"]; + const tHighRangeCliffs = ["alpine_mountainside","alpine_cliff_snow" ]; + const tSand = ["beach_c", "beach_d"]; + const tSandTransition = ["beach_scrub_50_"]; + const tWater = ["sand_wet_a","sand_wet_b","sand_wet_b","sand_wet_b"]; + const tGrassLandForest = "alpine_forrestfloor"; + const tGrassLandForest2 = "alpine_grass_d"; + const tForestTransition = ["new_alpine_grass_d", "new_alpine_grass_b","alpine_grass_d"]; + const tRoad = "new_alpine_citytile"; + const tRoadWild = "new_alpine_citytile"; + + const oBeech = "gaia/tree/euro_beech"; + const oPine = "gaia/tree/aleppo_pine"; + const oBerryBush = "gaia/fruit/berry_01"; + const oDeer = "gaia/fauna_deer"; + const oFish = "gaia/fish/generic"; + const oRabbit = "gaia/fauna_rabbit"; + const oStoneLarge = "gaia/rock/alpine_large"; + const oStoneSmall = "gaia/rock/alpine_small"; + const oMetalLarge = "gaia/ore/alpine_large"; + const oMetalSmall = "gaia/ore/alpine_small"; + + const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; + const aGrassShort = "actor|props/flora/grass_soft_large.xml"; + const aRockLarge = "actor|geology/stone_granite_med.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aBushMedium = "actor|props/flora/bush_medit_me.xml"; + const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; + + const pForestLand = [tGrassLandForest + TERRAIN_SEPARATOR + oPine, + tGrassLandForest + TERRAIN_SEPARATOR + oBeech, tGrassLandForest2 + TERRAIN_SEPARATOR + oPine, + tGrassLandForest2 + TERRAIN_SEPARATOR + oBeech, tGrassLandForest, tGrassLandForest2, + tGrassLandForest2,tGrassLandForest2]; + const pForestLandLight = [tGrassLandForest + TERRAIN_SEPARATOR + oPine, + tGrassLandForest + TERRAIN_SEPARATOR + oBeech, tGrassLandForest2 + TERRAIN_SEPARATOR + oPine, + tGrassLandForest2 + TERRAIN_SEPARATOR + oBeech, tGrassLandForest,tGrassLandForest2, + tForestTransition, tGrassLandForest2, tGrassLandForest, tForestTransition, tGrassLandForest2, + tForestTransition, tGrassLandForest2, tGrassLandForest2, tGrassLandForest2, tGrassLandForest2]; + const pForestLandVeryLight = [tGrassLandForest2 + TERRAIN_SEPARATOR + oPine, + tGrassLandForest2 + TERRAIN_SEPARATOR + oBeech, tForestTransition, tGrassLandForest2, + tForestTransition, tForestTransition, tForestTransition, tGrassLandForest, tForestTransition, + tGrassLandForest2, tForestTransition, tGrassLandForest2, tGrassLandForest2, tGrassLandForest2, + tGrassLandForest2]; + + const heightInit = -100; + const heightOcean = -22; + const heightWaterTerrain = -14; + const heightBase = -6; + const heightSand = -2; + const heightSandTransition = 0; + const heightGrass = 6; + const heightWaterLevel = 8; + const heightPyreneans = 15; + const heightGrassMidRange = 18; + const heightGrassHighRange = 30; + const heightPassage = scaleByMapSize(25, 40); + const heightHighRocks = heightPassage + 5; + const heightSnowedRocks = heightHighRocks + 10; + const heightMountain = heightHighRocks + 20; + + const heightOffsetHill = 7; + const heightOffsetHillRandom = 2; + + global.g_Map = new RandomMap(heightInit, tGrass); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clPass = g_Map.createTileClass(); + const clPyrenneans = g_Map.createTileClass(); + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + + const startAngle = randomAngle(); + const oceanAngle = startAngle + randFloat(-1, 1) * Math.PI / 12; + + const mountainLength = fractionToTiles(0.68); + const mountainWidth = scaleByMapSize(15, 55); + + const mountainPeaks = 100 * scaleByMapSize(1, 10); + const mountainOffset = randFloat(-1, 1) * scaleByMapSize(1, 12); + + const passageLength = scaleByMapSize(8, 50); + + const terrainPerHeight = [ + { + "maxHeight": heightGrass, + "steepness": 5, + "terrainGround": tGrass, + "terrainSteep": tMidRangeCliffs + }, + { + "maxHeight": heightGrassMidRange, + "steepness": 8, + "terrainGround": tGrassMidRange, + "terrainSteep": tMidRangeCliffs + }, + { + "maxHeight": heightGrassHighRange, + "steepness": 8, + "terrainGround": tGrassHighRange, + "terrainSteep": tMidRangeCliffs + }, + { + "maxHeight": heightHighRocks, + "steepness": 8, + "terrainGround": tHighRocks, + "terrainSteep": tHighRangeCliffs + }, + { + "maxHeight": heightSnowedRocks, + "steepness": 7, + "terrainGround": tSnowedRocks, + "terrainSteep": tHighRangeCliffs + }, + { + "maxHeight": Infinity, + "steepness": 6, + "terrainGround": tTopSnowOnly, + "terrainSteep": tTopSnow + } + ]; + + g_Map.log("Creating initial sinusoidal noise"); + let baseHeights = []; + for (let ix = 0; ix < mapSize; ix++) { - const position = new Vector2D(ix, iz); - if (g_Map.inMapBounds(position)) + baseHeights.push([]); + for (let iz = 0; iz < mapSize; iz++) { - const height = heightBase + randFloat(-1, 1) + scaleByMapSize(1, 3) * (Math.cos(ix / scaleByMapSize(5, 30)) + Math.sin(iz / scaleByMapSize(5, 30))); - g_Map.setHeight(position, height); - baseHeights[ix].push(height); + const position = new Vector2D(ix, iz); + if (g_Map.inMapBounds(position)) + { + const height = heightBase + randFloat(-1, 1) + scaleByMapSize(1, 3) * + (Math.cos(ix / scaleByMapSize(5, 30)) + Math.sin(iz / scaleByMapSize(5, 30))); + g_Map.setHeight(position, height); + baseHeights[ix].push(height); + } + else + baseHeights[ix].push(heightInit); } - else - baseHeights[ix].push(heightInit); } -} -const playerIDs = sortAllPlayers(); -const playerPosition = playerPlacementArcs( - playerIDs, - mapCenter, - fractionToTiles(0.35), - oceanAngle, - 0.1 * Math.PI, - 0.9 * Math.PI); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oPine - }, - "Decoratives": { - "template": aGrassShort + const playerIDs = sortAllPlayers(); + const playerPosition = playerPlacementArcs( + playerIDs, + mapCenter, + fractionToTiles(0.35), + oceanAngle, + 0.1 * Math.PI, + 0.9 * Math.PI); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oPine + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 30; + + g_Map.log("Creating the pyreneans"); + const mountainVec = new Vector2D(mountainLength, 0).rotate(-startAngle); + const mountainStart = Vector2D.sub(mapCenter, Vector2D.div(mountainVec, 2)); + const mountainDirection = mountainVec.clone().normalize(); + createPyreneans(); + paintTileClassBasedOnHeight(heightPyreneans, Infinity, Elevation_ExcludeMin_ExcludeMax, clPyrenneans); + yield 40; + + /** + * Generates the mountain peak noise. + * + * @param {number} x - between 0 and 1 + * @returns {number} between 0 and 1 + */ + function sigmoid(x, peakPosition) + { + return 1 / (1 + Math.exp(x)) * + // If we're too far from the border, we flatten + (0.2 - Math.max(0, Math.abs(0.5 - peakPosition) - 0.3)) * 5; } -}); -Engine.SetProgress(30); - -g_Map.log("Creating the pyreneans"); -const mountainVec = new Vector2D(mountainLength, 0).rotate(-startAngle); -const mountainStart = Vector2D.sub(mapCenter, Vector2D.div(mountainVec, 2)); -const mountainDirection = mountainVec.clone().normalize(); -createPyreneans(); -paintTileClassBasedOnHeight(heightPyreneans, Infinity, Elevation_ExcludeMin_ExcludeMax, clPyrenneans); -Engine.SetProgress(40); - -/** - * Generates the mountain peak noise. - * - * @param {number} x - between 0 and 1 - * @returns {number} between 0 and 1 - */ -function sigmoid(x, peakPosition) -{ - return 1 / (1 + Math.exp(x)) * - // If we're too far from the border, we flatten - (0.2 - Math.max(0, Math.abs(0.5 - peakPosition) - 0.3)) * 5; -} -function createPyreneans() -{ - for (let peak = 0; peak < mountainPeaks; ++peak) + function createPyreneans() { - const peakPosition = peak / mountainPeaks; - const peakHeight = randFloat(0, 10); - - for (let distance = 0; distance < mountainWidth; distance += 1/3) + for (let peak = 0; peak < mountainPeaks; ++peak) { - const rest = 2 * (1 - distance / mountainWidth); - - const sigmoidX = - - 1 * (rest - 1.9) + - - 4 * - (rest - randFloat(0.9, 1.1)) * - (rest - randFloat(0.9, 1.1)) * - (rest - randFloat(0.9, 1.1)); + const peakPosition = peak / mountainPeaks; + const peakHeight = randFloat(0, 10); - for (const direction of [-1, 1]) + for (let distance = 0; distance < mountainWidth; distance += 1/3) { - const pos = Vector2D.sum([ - Vector2D.add(mountainStart, Vector2D.mult(mountainDirection, peakPosition * mountainLength)), - new Vector2D(mountainOffset, 0).rotate(-peakPosition * Math.PI * 4), - new Vector2D(distance, 0).rotate(-startAngle - direction * Math.PI / 2) - ]).round(); - - g_Map.setHeight(pos, baseHeights[pos.x][pos.y] + (heightMountain + peakHeight + randFloat(-9, 9)) * sigmoid(sigmoidX, peakPosition)); + const rest = 2 * (1 - distance / mountainWidth); + + const sigmoidX = + - 1 * (rest - 1.9) + + - 4 * + (rest - randFloat(0.9, 1.1)) * + (rest - randFloat(0.9, 1.1)) * + (rest - randFloat(0.9, 1.1)); + + for (const direction of [-1, 1]) + { + const pos = Vector2D.sum([ + Vector2D.add(mountainStart, Vector2D.mult(mountainDirection, + peakPosition * mountainLength)), + new Vector2D(mountainOffset, 0).rotate(-peakPosition * Math.PI * 4), + new Vector2D(distance, 0).rotate(-startAngle - direction * Math.PI / 2) + ]).round(); + + g_Map.setHeight(pos, baseHeights[pos.x][pos.y] + + (heightMountain + peakHeight + randFloat(-9, 9)) * + sigmoid(sigmoidX, peakPosition)); + } } } } -} - -g_Map.log("Creating passages"); -const passageLocation = 0.35; -const passageVec = mountainDirection.perpendicular().mult(passageLength); -for (const passLoc of [passageLocation, 1 - passageLocation]) - for (const direction of [1, -1]) - { - const passageStart = Vector2D.add(mountainStart, Vector2D.mult(mountainVec, passLoc)); - const passageEnd = Vector2D.add(passageStart, Vector2D.mult(passageVec, direction)); - - createPassage({ - "start": passageStart, - "end": passageEnd, - "startHeight": heightPassage, - "startWidth": 7, - "endWidth": 7, - "smoothWidth": 2, - "tileClass": clPass - }); - } -Engine.SetProgress(50); + g_Map.log("Creating passages"); + const passageLocation = 0.35; + const passageVec = mountainDirection.perpendicular().mult(passageLength); -g_Map.log("Smoothing the pyreneans"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, 0.3, 1), - new NearTileClassConstraint(clPyrenneans, 1)); + for (const passLoc of [passageLocation, 1 - passageLocation]) + for (const direction of [1, -1]) + { + const passageStart = Vector2D.add(mountainStart, Vector2D.mult(mountainVec, passLoc)); + const passageEnd = Vector2D.add(passageStart, Vector2D.mult(passageVec, direction)); + + createPassage({ + "start": passageStart, + "end": passageEnd, + "startHeight": heightPassage, + "startWidth": 7, + "endWidth": 7, + "smoothWidth": 2, + "tileClass": clPass + }); + } + yield 50; -g_Map.log("Creating oceans"); -for (const ocean of distributePointsOnCircle(2, oceanAngle, fractionToTiles(0.48), mapCenter)[0]) + g_Map.log("Smoothing the pyreneans"); createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.18)), 0.9, 0.05, Infinity, ocean), - [ - new ElevationPainter(heightOcean), - new TileClassPainter(clWater) - ]); - -g_Map.log("Smoothing around the water"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(5, 0.9, 1), - new NearTileClassConstraint(clWater, 5)); -Engine.SetProgress(55); - -g_Map.log("Creating hills"); -createAreas( - new ClumpPlacer(scaleByMapSize(60, 120), 0.3, 0.06, Infinity), - [ - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetHill, 4, heightOffsetHillRandom), - new TerrainPainter(tGrassSpecific), - new TileClassPainter(clHill) - ], - avoidClasses(clWater, 5, clPlayer, 20, clBaseResource, 6, clPyrenneans, 2), scaleByMapSize(5, 35)); - -g_Map.log("Creating forests"); -const types = [[tForestTransition, pForestLandVeryLight, pForestLandLight, pForestLand]]; -const forestSize = scaleByMapSize(40, 115) * Math.PI; -let num = Math.floor(scaleByMapSize(8,40) / types.length); -for (const type of types) - createAreas( - new ClumpPlacer(forestSize, 0.2, 0.1, Infinity), - [ - new LayeredPainter(type, [scaleByMapSize(1, 2), scaleByMapSize(3, 6), scaleByMapSize(3, 6)]), - new TileClassPainter(clForest) - ], - avoidClasses(clPlayer, 20, clPyrenneans,0, clForest, 7, clWater, 2), - num); -Engine.SetProgress(60); + new MapBoundsPlacer(), + new SmoothingPainter(1, 0.3, 1), + new NearTileClassConstraint(clPyrenneans, 1)); -g_Map.log("Creating lone trees"); -num = scaleByMapSize(80,400); - -let group = new SimpleGroup([new SimpleObject(oPine, 1,2, 1,3),new SimpleObject(oBeech, 1,2, 1,3)], true, clForest); -createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 8,clPyrenneans, 1), num, 20 ); - -g_Map.log("Painting terrain by height and slope"); -for (let i = 0; i < terrainPerHeight.length; ++i) - for (const steep of [false, true]) + g_Map.log("Creating oceans"); + for (const ocean of distributePointsOnCircle(2, oceanAngle, fractionToTiles(0.48), mapCenter)[0]) createArea( - new MapBoundsPlacer(), - new TerrainPainter(steep ? terrainPerHeight[i].terrainSteep : terrainPerHeight[i].terrainGround), + new ClumpPlacer(diskArea(fractionToTiles(0.18)), 0.9, 0.05, Infinity, ocean), [ - new NearTileClassConstraint(clPyrenneans, 2), - new HeightConstraint(terrainPerHeight[i - 1] ? terrainPerHeight[i - 1].maxHeight : -Infinity, terrainPerHeight[i].maxHeight), - steep ? - new SlopeConstraint(terrainPerHeight[i].steepness, Infinity) : - new SlopeConstraint(-Infinity, terrainPerHeight[i].steepness), + new ElevationPainter(heightOcean), + new TileClassPainter(clWater) ]); -for (let x = 0; x < mapSize; ++x) - for (let z = 0; z < mapSize; ++z) - { - const position = new Vector2D(x, z); - const height = g_Map.getHeight(position); - const heightDiff = g_Map.getSlope(position); + g_Map.log("Smoothing around the water"); + createArea( + new MapBoundsPlacer(), + new SmoothingPainter(5, 0.9, 1), + new NearTileClassConstraint(clWater, 5)); + yield 55; - const terrainShore = getShoreTerrain(position, height, heightDiff); - if (terrainShore) - createTerrain(terrainShore).place(position); - } + g_Map.log("Creating hills"); + createAreas( + new ClumpPlacer(scaleByMapSize(60, 120), 0.3, 0.06, Infinity), + [ + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetHill, 4, heightOffsetHillRandom), + new TerrainPainter(tGrassSpecific), + new TileClassPainter(clHill) + ], + avoidClasses(clWater, 5, clPlayer, 20, clBaseResource, 6, clPyrenneans, 2), + scaleByMapSize(5, 35)); + + g_Map.log("Creating forests"); + const types = [[tForestTransition, pForestLandVeryLight, pForestLandLight, pForestLand]]; + const forestSize = scaleByMapSize(40, 115) * Math.PI; + let num = Math.floor(scaleByMapSize(8,40) / types.length); + for (const type of types) + createAreas( + new ClumpPlacer(forestSize, 0.2, 0.1, Infinity), + [ + new LayeredPainter(type, [scaleByMapSize(1, 2), scaleByMapSize(3, 6), + scaleByMapSize(3, 6)]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 20, clPyrenneans,0, clForest, 7, clWater, 2), + num); + yield 60; + + g_Map.log("Creating lone trees"); + num = scaleByMapSize(80,400); + + let group = new SimpleGroup([new SimpleObject(oPine, 1,2, 1,3),new SimpleObject(oBeech, 1,2, 1,3)], + true, clForest); + createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 3, clForest, 1, clPlayer, 8, + clPyrenneans, 1), num, 20 ); + + g_Map.log("Painting terrain by height and slope"); + for (let i = 0; i < terrainPerHeight.length; ++i) + for (const steep of [false, true]) + createArea( + new MapBoundsPlacer(), + new TerrainPainter(steep ? terrainPerHeight[i].terrainSteep : + terrainPerHeight[i].terrainGround), + [ + new NearTileClassConstraint(clPyrenneans, 2), + new HeightConstraint(terrainPerHeight[i - 1] ? + terrainPerHeight[i - 1].maxHeight : -Infinity, + terrainPerHeight[i].maxHeight), + steep ? + new SlopeConstraint(terrainPerHeight[i].steepness, Infinity) : + new SlopeConstraint(-Infinity, terrainPerHeight[i].steepness), + ]); + + for (let x = 0; x < mapSize; ++x) + for (let z = 0; z < mapSize; ++z) + { + const position = new Vector2D(x, z); + const height = g_Map.getHeight(position); + const heightDiff = g_Map.getSlope(position); -function getShoreTerrain(position, height, heightDiff) -{ - if (height <= heightWaterTerrain) - return tWater; + const terrainShore = getShoreTerrain(position, height, heightDiff); + if (terrainShore) + createTerrain(terrainShore).place(position); + } - if (height <= heightSand && new NearTileClassConstraint(clWater, 2).allows(position)) - return heightDiff < 2.5 ? tSand : tMidRangeCliffs; + function getShoreTerrain(position, height, heightDiff) + { + if (height <= heightWaterTerrain) + return tWater; - // Notice the sand transition is also be painted below height -2 - if (height <= heightSandTransition && new NearTileClassConstraint(clWater, 3).allows(position)) - return heightDiff < 2.5 ? tSandTransition : tMidRangeCliffs; + if (height <= heightSand && new NearTileClassConstraint(clWater, 2).allows(position)) + return heightDiff < 2.5 ? tSand : tMidRangeCliffs; - return undefined; -} + // Notice the sand transition is also be painted below height -2 + if (height <= heightSandTransition && new NearTileClassConstraint(clWater, 3).allows(position)) + return heightDiff < 2.5 ? tSandTransition : tMidRangeCliffs; -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 20), scaleByMapSize(5, 40), scaleByMapSize(8, 60)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - [ - new TerrainPainter(tDirtyGrass), - new TileClassPainter(clDirt) - ], - avoidClasses(clWater, 3, clForest, 0, clPyrenneans,5, clHill, 0, clDirt, 5, clPlayer, 6), - scaleByMapSize(15, 45)); + return undefined; + } -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - new TerrainPainter(tLushGrass), - avoidClasses(clWater, 3, clForest, 0, clPyrenneans,5, clHill, 0, clDirt, 5, clPlayer, 6), - scaleByMapSize(15, 45)); - -Engine.SetProgress(70); - -// making more in dirt areas so as to appear different -g_Map.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(clWater, 2, clHill, 2, clPlayer, 5, clDirt, 0, clPyrenneans,2), scaleByMapSize(13, 200) ); -createObjectGroupsDeprecated(group, 0, stayClasses(clDirt,1), scaleByMapSize(13, 200),10); - -g_Map.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(clWater, 3, clHill, 2, clPlayer, 5, clDirt, 1, clForest, 0, clPyrenneans,2), scaleByMapSize(13, 200) ); -createObjectGroupsDeprecated(group, 0, stayClasses(clDirt,1), scaleByMapSize(13, 200),10); -Engine.SetProgress(75); - -g_Map.log("Creating bushes"); -group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] ); -createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 2, clPlayer, 1, clPyrenneans, 1), scaleByMapSize(13, 200), 50 ); - -Engine.SetProgress(80); - -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - avoidClasses(clWater, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clPyrenneans, 3) -); - -g_Map.log("Creating stone mines"); -createBalancedStoneMines( - oStoneSmall, - oStoneLarge, - clRock, - avoidClasses(clWater, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clPyrenneans, 3, clMetal, 10) -); - -Engine.SetProgress(85); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); -createObjectGroupsDeprecated( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0), scaleByMapSize(16, 262), 50 ); - -g_Map.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(clWater, 0, clForest, 0, clPlayer, 0), scaleByMapSize(8, 131), 50 ); - -Engine.SetProgress(90); - -g_Map.log("Creating deer"); -group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); -createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clPyrenneans, 1, clFood, 15), 3 * numPlayers, 50 ); - -g_Map.log("Creating rabbit"); -group = new SimpleGroup( [new SimpleObject(oRabbit, 2,3, 0,2)], true, clFood ); -createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clPyrenneans, 1, clFood,15), 3 * numPlayers, 50 ); - -g_Map.log("Creating berry bush"); -group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)],true, clFood ); -createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clPyrenneans, 1, clFood, 10), randIntInclusive(1, 4) * numPlayers + 2, 50); - -g_Map.log("Creating fish"); -group = new SimpleGroup( [new SimpleObject(oFish, 2,3, 0,2)], true, clFood ); -createObjectGroupsDeprecated(group, 0, [avoidClasses(clFood, 15), stayClasses(clWater, 6)], 20 * numPlayers, 60 ); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clPyrenneans, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); - -setSunElevation(Math.PI * randFloat(1/5, 1/3)); -setSunRotation(randomAngle()); - -setSkySet("cumulus"); -setSunColor(0.73,0.73,0.65); -setAmbientColor(0.45,0.45,0.50); -setWaterColor(0.263, 0.353, 0.616); -setWaterTint(0.104, 0.172, 0.563); -setWaterWaviness(5.0); -setWaterType("ocean"); -setWaterMurkiness(0.83); -setWaterHeight(heightWaterLevel); - -g_Map.ExportMap(); + g_Map.log("Creating dirt patches"); + for (const size of [scaleByMapSize(3, 20), scaleByMapSize(5, 40), scaleByMapSize(8, 60)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new TerrainPainter(tDirtyGrass), + new TileClassPainter(clDirt) + ], + avoidClasses(clWater, 3, clForest, 0, clPyrenneans,5, clHill, 0, clDirt, 5, clPlayer, 6), + scaleByMapSize(15, 45)); + + g_Map.log("Creating grass patches"); + for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + new TerrainPainter(tLushGrass), + avoidClasses(clWater, 3, clForest, 0, clPyrenneans,5, clHill, 0, clDirt, 5, clPlayer, 6), + scaleByMapSize(15, 45)); + + yield 70; + + // making more in dirt areas so as to appear different + g_Map.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(clWater, 2, clHill, 2, clPlayer, 5, clDirt, 0, + clPyrenneans,2), scaleByMapSize(13, 200) ); + createObjectGroupsDeprecated(group, 0, stayClasses(clDirt,1), scaleByMapSize(13, 200),10); + + g_Map.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(clWater, 3, clHill, 2, clPlayer, 5, clDirt, 1, + clForest, 0, clPyrenneans,2), scaleByMapSize(13, 200) ); + createObjectGroupsDeprecated(group, 0, stayClasses(clDirt,1), scaleByMapSize(13, 200),10); + yield 75; + + g_Map.log("Creating bushes"); + group = new SimpleGroup( [new SimpleObject(aBushMedium, 1,2, 0,2), + new SimpleObject(aBushSmall, 2,4, 0,2)] ); + createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 2, clPlayer, 1, clPyrenneans, 1), + scaleByMapSize(13, 200), 50 ); + + yield 80; + + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + avoidClasses(clWater, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clPyrenneans, 3) + ); + + g_Map.log("Creating stone mines"); + createBalancedStoneMines( + oStoneSmall, + oStoneLarge, + clRock, + avoidClasses(clWater, 2, clForest, 0, clPlayer, scaleByMapSize(15, 25), clPyrenneans, 3, + clMetal, 10) + ); + + yield 85; + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); + createObjectGroupsDeprecated( group, 0, avoidClasses(clWater, 0, clForest, 0, clPlayer, 0), + scaleByMapSize(16, 262), 50 ); + + g_Map.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(clWater, 0, clForest, 0, clPlayer, 0), + scaleByMapSize(8, 131), 50 ); + + yield 90; + + g_Map.log("Creating deer"); + group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); + createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, + clPyrenneans, 1, clFood, 15), 3 * numPlayers, 50 ); + + g_Map.log("Creating rabbit"); + group = new SimpleGroup( [new SimpleObject(oRabbit, 2,3, 0,2)], true, clFood ); + createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, + clPyrenneans, 1, clFood,15), 3 * numPlayers, 50 ); + + g_Map.log("Creating berry bush"); + group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)],true, clFood ); + createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, + clPyrenneans, 1, clFood, 10), randIntInclusive(1, 4) * numPlayers + 2, 50); + + g_Map.log("Creating fish"); + group = new SimpleGroup( [new SimpleObject(oFish, 2,3, 0,2)], true, clFood ); + createObjectGroupsDeprecated(group, 0, [avoidClasses(clFood, 15), stayClasses(clWater, 6)], + 20 * numPlayers, 60 ); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clPyrenneans, 4, clForest, 1, clMetal, 4, clRock, + 4, clFood, 2)); + + setSunElevation(Math.PI * randFloat(1/5, 1/3)); + setSunRotation(randomAngle()); + + setSkySet("cumulus"); + setSunColor(0.73,0.73,0.65); + setAmbientColor(0.45,0.45,0.50); + setWaterColor(0.263, 0.353, 0.616); + setWaterTint(0.104, 0.172, 0.563); + setWaterWaviness(5.0); + setWaterType("ocean"); + setWaterMurkiness(0.83); + setWaterHeight(heightWaterLevel); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/ratumacos.js =================================================================== --- binaries/data/mods/public/maps/random/ratumacos.js +++ binaries/data/mods/public/maps/random/ratumacos.js @@ -21,359 +21,364 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setBiome("generic/alpine"); - -g_Terrains.mainTerrain = "new_alpine_grass_d"; -g_Terrains.forestFloor1 = "alpine_grass_d"; -g_Terrains.forestFloor2 = "alpine_grass_c"; -g_Terrains.tier1Terrain = "new_alpine_grass_c"; -g_Terrains.tier2Terrain = "new_alpine_grass_b"; -g_Terrains.tier3Terrain = "alpine_grass_a"; -g_Terrains.tier4Terrain = "new_alpine_grass_e"; - -g_Gaia.mainHuntableAnimal = "gaia/fauna_deer"; -g_Gaia.secondaryHuntableAnimal = "gaia/fauna_pig"; -g_Gaia.fish = "gaia/fish/tilapia"; -g_Gaia.tree1 = "gaia/tree/poplar"; -g_Gaia.tree2 = "gaia/tree/toona"; -g_Gaia.tree3 = "gaia/fruit/apple"; -g_Gaia.tree4 = "gaia/tree/acacia"; -g_Gaia.tree5 = "gaia/tree/carob"; - -g_Decoratives.grass = "actor|props/flora/grass_soft_large.xml"; -g_Decoratives.grassShort = "actor|props/flora/grass_tufts_a.xml"; -g_Decoratives.rockLarge = "actor|geology/stone_granite_med.xml"; -g_Decoratives.rockMedium = "actor|geology/stone_granite_small.xml"; -g_Decoratives.bushMedium = "actor|props/flora/bush_tempe_a.xml"; -g_Decoratives.bushSmall = "actor|props/flora/bush_tempe_b.xml"; -g_Decoratives.reeds = "actor|props/flora/reeds_pond_lush_a.xml"; -g_Decoratives.lillies = "actor|props/flora/water_lillies.xml"; - -const heightScale = num => num * g_MapSettings.Size / 320; - -const heightReedsMin = heightScale(-2); -const heightShallow = heightScale(-1); -const heightWaterLevel = heightScale(0); -const heightShoreline = heightScale(3); -const heightPlayer = heightScale(10); +function* GenerateMap(mapSettings) +{ + setBiome("generic/alpine"); -const g_Map = new RandomMap(0, g_Terrains.mainTerrain); -const mapBounds = g_Map.getBounds(); -const mapCenter = g_Map.getCenter(); + g_Terrains.mainTerrain = "new_alpine_grass_d"; + g_Terrains.forestFloor1 = "alpine_grass_d"; + g_Terrains.forestFloor2 = "alpine_grass_c"; + g_Terrains.tier1Terrain = "new_alpine_grass_c"; + g_Terrains.tier2Terrain = "new_alpine_grass_b"; + g_Terrains.tier3Terrain = "alpine_grass_a"; + g_Terrains.tier4Terrain = "new_alpine_grass_e"; -const riverAngle = 0.65 * Math.PI; + g_Gaia.mainHuntableAnimal = "gaia/fauna_deer"; + g_Gaia.secondaryHuntableAnimal = "gaia/fauna_pig"; + g_Gaia.fish = "gaia/fish/tilapia"; + g_Gaia.tree1 = "gaia/tree/poplar"; + g_Gaia.tree2 = "gaia/tree/toona"; + g_Gaia.tree3 = "gaia/fruit/apple"; + g_Gaia.tree4 = "gaia/tree/acacia"; + g_Gaia.tree5 = "gaia/tree/carob"; -initTileClasses(["shoreline", "shallows"]); + g_Decoratives.grass = "actor|props/flora/grass_soft_large.xml"; + g_Decoratives.grassShort = "actor|props/flora/grass_tufts_a.xml"; + g_Decoratives.rockLarge = "actor|geology/stone_granite_med.xml"; + g_Decoratives.rockMedium = "actor|geology/stone_granite_small.xml"; + g_Decoratives.bushMedium = "actor|props/flora/bush_tempe_a.xml"; + g_Decoratives.bushSmall = "actor|props/flora/bush_tempe_b.xml"; + g_Decoratives.reeds = "actor|props/flora/reeds_pond_lush_a.xml"; + g_Decoratives.lillies = "actor|props/flora/water_lillies.xml"; -g_Map.LoadHeightmapImage("ratumacos.png", -3, 20); -Engine.SetProgress(15); + const heightScale = num => num * mapSettings.Size / 320; -g_Map.log("Smoothing heightmap"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, 0.1, 1)); -Engine.SetProgress(25); + const heightReedsMin = heightScale(-2); + const heightShallow = heightScale(-1); + const heightWaterLevel = heightScale(0); + const heightShoreline = heightScale(3); + const heightPlayer = heightScale(10); -g_Map.log("Creating shallows"); -for (let i = 0; i < scaleByMapSize(5, 12); ++i) -{ - const x = fractionToTiles(randFloat(0, 1)); - createPassage({ - "start": new Vector2D(x, mapBounds.bottom).rotateAround(riverAngle + Math.PI / 2 * randFloat(0.8, 1.2), mapCenter), - "end": new Vector2D(x, mapBounds.top).rotateAround(riverAngle + Math.PI / 2 * randFloat(0.8, 1.2), mapCenter), - "startWidth": scaleByMapSize(8, 12), - "endWidth": scaleByMapSize(8, 12), - "smoothWidth": 2, - "startHeight": heightShallow, - "endHeight": heightShallow, - "constraints": new HeightConstraint(-Infinity, heightShallow) - }); -} + global.g_Map = new RandomMap(0, g_Terrains.mainTerrain); + const mapBounds = g_Map.getBounds(); + const mapCenter = g_Map.getCenter(); -g_Map.log("Painting water"); -createArea( - new MapBoundsPlacer(), - [ - new TerrainPainter(g_Terrains.water), - new TileClassPainter(g_TileClasses.water) - ], - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(30); + const riverAngle = 0.65 * Math.PI; -g_Map.log("Marking land"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land), - avoidClasses(g_TileClasses.water, 0)); -Engine.SetProgress(35); + initTileClasses(["shoreline", "shallows"]); -g_Map.log("Painting shoreline"); -createArea( - new MapBoundsPlacer(), - [ - new TerrainPainter(g_Terrains.shore), - new TileClassPainter(g_TileClasses.shoreline) - ], - new HeightConstraint(heightWaterLevel, heightShoreline)); -Engine.SetProgress(40); + g_Map.LoadHeightmapImage("ratumacos.png", -3, 20); + yield 15; -placePlayerBases({ - "PlayerPlacement": playerPlacementRiver(riverAngle, fractionToTiles(0.6)), - "PlayerTileClass": g_TileClasses.player, - "BaseResourceClass": g_TileClasses.baseResource, - "Walls": "towers", - "CityPatch": { - "outerTerrain": g_Terrains.roadWild, - "innerTerrain": g_Terrains.road, - "painters": [ - new SmoothElevationPainter(ELEVATION_SET, heightPlayer, 2) - ] - }, - "StartingAnimal": { - }, - "Berries": { - "template": g_Gaia.fruitBush - }, - "Mines": { - "types": [ - { "template": g_Gaia.metalLarge }, - { "template": g_Gaia.stoneLarge } - ] - }, - "Trees": { - "template": g_Gaia.tree1, - "count": 2 - }, - "Decoratives": { - "template": g_Decoratives.rockMedium - } -}); + g_Map.log("Smoothing heightmap"); + createArea( + new MapBoundsPlacer(), + new SmoothingPainter(1, 0.1, 1)); + yield 25; -addElements([ + g_Map.log("Creating shallows"); + for (let i = 0; i < scaleByMapSize(5, 12); ++i) { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3, - g_TileClasses.shoreline, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3, - g_TileClasses.shoreline, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["many"] + const x = fractionToTiles(randFloat(0, 1)); + createPassage({ + "start": new Vector2D(x, mapBounds.bottom).rotateAround( + riverAngle + Math.PI / 2 * randFloat(0.8, 1.2), mapCenter), + "end": new Vector2D(x, mapBounds.top).rotateAround( + riverAngle + Math.PI / 2 * randFloat(0.8, 1.2), mapCenter), + "startWidth": scaleByMapSize(8, 12), + "endWidth": scaleByMapSize(8, 12), + "smoothWidth": 2, + "startHeight": heightShallow, + "endHeight": heightShallow, + "constraints": new HeightConstraint(-Infinity, heightShallow) + }); } -]); -addElements(shuffleArray([ - { - "func": addSmallMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 6, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 30, - g_TileClasses.water, 3, - g_TileClasses.shoreline, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["few"] - }, - { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 6, - g_TileClasses.player, 30, - g_TileClasses.rock, 30, - g_TileClasses.metal, 20, - g_TileClasses.water, 3, - g_TileClasses.shoreline, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal"] - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 6, - g_TileClasses.player, 30, - g_TileClasses.rock, 30, - g_TileClasses.metal, 20, - g_TileClasses.water, 3, - g_TileClasses.shoreline, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal"] - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 8, - g_TileClasses.metal, 3, - g_TileClasses.mountain, 6, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.water, 2, - g_TileClasses.shoreline, 2 + g_Map.log("Painting water"); + createArea( + new MapBoundsPlacer(), + [ + new TerrainPainter(g_Terrains.water), + new TileClassPainter(g_TileClasses.water) ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - } -])); + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 30; -addElements(shuffleArray([ - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 6, - g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.water, 3, - g_TileClasses.shoreline, 3 - ], - "sizes": ["huge"], - "mixes": ["similar"], - "amounts": ["tons"] - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 6, - g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.water, 3, - g_TileClasses.shoreline, 3 - ], - "sizes": ["huge"], - "mixes": ["similar"], - "amounts": ["tons"] - }, - { - "func": addBerries, - "avoid": [ - g_TileClasses.berries, 30, - g_TileClasses.forest, 5, - g_TileClasses.metal, 10, - g_TileClasses.mountain, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 10, - g_TileClasses.water, 3, - g_TileClasses.shoreline, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 4, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 6, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.water, 5, - g_TileClasses.shoreline, 3 + g_Map.log("Marking land"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land), + avoidClasses(g_TileClasses.water, 0)); + yield 35; + + g_Map.log("Painting shoreline"); + createArea( + new MapBoundsPlacer(), + [ + new TerrainPainter(g_Terrains.shore), + new TileClassPainter(g_TileClasses.shoreline) ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["tons"] - } -])); -Engine.SetProgress(80); + new HeightConstraint(heightWaterLevel, heightShoreline)); + yield 40; -createDecoration( - [ - [new SimpleObject(g_Decoratives.reeds, 1, 3, 0, 1)], - [new SimpleObject(g_Decoratives.lillies, 1, 2, 0, 1)] - ], - [ - scaleByMapAreaAbsolute(1800), - scaleByMapAreaAbsolute(900) - ], - new HeightConstraint(heightReedsMin, heightShoreline) -); -Engine.SetProgress(90); + placePlayerBases({ + "PlayerPlacement": playerPlacementRiver(riverAngle, fractionToTiles(0.6)), + "PlayerTileClass": g_TileClasses.player, + "BaseResourceClass": g_TileClasses.baseResource, + "Walls": "towers", + "CityPatch": { + "outerTerrain": g_Terrains.roadWild, + "innerTerrain": g_Terrains.road, + "painters": [ + new SmoothElevationPainter(ELEVATION_SET, heightPlayer, 2) + ] + }, + "StartingAnimal": { + }, + "Berries": { + "template": g_Gaia.fruitBush + }, + "Mines": { + "types": [ + { "template": g_Gaia.metalLarge }, + { "template": g_Gaia.stoneLarge } + ] + }, + "Trees": { + "template": g_Gaia.tree1, + "count": 2 + }, + "Decoratives": { + "template": g_Decoratives.rockMedium + } + }); -g_Map.log("Placing fish"); -addElements([ - { - "func": addFish, - "avoid": [ - g_TileClasses.fish, 10, + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3, + g_TileClasses.shoreline, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3, + g_TileClasses.shoreline, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["many"] + } + ]); + + addElements(shuffleArray([ + { + "func": addSmallMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 6, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 30, + g_TileClasses.water, 3, + g_TileClasses.shoreline, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["few"] + }, + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 6, + g_TileClasses.player, 30, + g_TileClasses.rock, 30, + g_TileClasses.metal, 20, + g_TileClasses.water, 3, + g_TileClasses.shoreline, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 6, + g_TileClasses.player, 30, + g_TileClasses.rock, 30, + g_TileClasses.metal, 20, + g_TileClasses.water, 3, + g_TileClasses.shoreline, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 8, + g_TileClasses.metal, 3, + g_TileClasses.mountain, 6, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2, + g_TileClasses.shoreline, 2 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + } + ])); + + addElements(shuffleArray([ + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 6, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.water, 3, + g_TileClasses.shoreline, 3 + ], + "sizes": ["huge"], + "mixes": ["similar"], + "amounts": ["tons"] + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 6, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.water, 3, + g_TileClasses.shoreline, 3 + ], + "sizes": ["huge"], + "mixes": ["similar"], + "amounts": ["tons"] + }, + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 10, + g_TileClasses.water, 3, + g_TileClasses.shoreline, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 4, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 6, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.water, 5, + g_TileClasses.shoreline, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["tons"] + } + ])); + yield 80; + + createDecoration( + [ + [new SimpleObject(g_Decoratives.reeds, 1, 3, 0, 1)], + [new SimpleObject(g_Decoratives.lillies, 1, 2, 0, 1)] ], - "stay": [g_TileClasses.water, 4], - "sizes": ["normal"], - "mixes": ["similar"], - "amounts": ["few"] - } -]); -Engine.SetProgress(95); + [ + scaleByMapAreaAbsolute(1800), + scaleByMapAreaAbsolute(900) + ], + new HeightConstraint(heightReedsMin, heightShoreline) + ); + yield 90; -placePlayersNomad( - g_Map.createTileClass(), - [ - stayClasses(g_TileClasses.land, 4), - avoidClasses( - g_TileClasses.forest, 1, - g_TileClasses.rock, 4, - g_TileClasses.metal, 4, - g_TileClasses.animals, 1) + g_Map.log("Placing fish"); + addElements([ + { + "func": addFish, + "avoid": [ + g_TileClasses.fish, 10, + ], + "stay": [g_TileClasses.water, 4], + "sizes": ["normal"], + "mixes": ["similar"], + "amounts": ["few"] + } ]); + yield 95; -setSunColor(0.733, 0.746, 0.574); + placePlayersNomad( + g_Map.createTileClass(), + [ + stayClasses(g_TileClasses.land, 4), + avoidClasses( + g_TileClasses.forest, 1, + g_TileClasses.rock, 4, + g_TileClasses.metal, 4, + g_TileClasses.animals, 1) + ]); -setWaterHeight(20 + heightWaterLevel); -setWaterTint(0.224, 0.271, 0.270); -setWaterColor(0.224, 0.271, 0.270); -setWaterWaviness(8); -setWaterMurkiness(0.87); -setWaterType("clap"); + setSunColor(0.733, 0.746, 0.574); -setAmbientColor(0.521, 0.475, 0.322); + setWaterHeight(20 + heightWaterLevel); + setWaterTint(0.224, 0.271, 0.270); + setWaterColor(0.224, 0.271, 0.270); + setWaterWaviness(8); + setWaterMurkiness(0.87); + setWaterType("clap"); -setSunRotation(-Math.PI); -setSunElevation(Math.PI / 6.25); + setAmbientColor(0.521, 0.475, 0.322); -setFogFactor(0); -setFogThickness(0); -setFogColor(0.69, 0.616, 0.541); + setSunRotation(-Math.PI); + setSunElevation(Math.PI / 6.25); -setPPEffect("hdr"); -setPPContrast(0.67); -setPPSaturation(0.42); -setPPBloom(0.23); + setFogFactor(0); + setFogThickness(0); + setFogColor(0.69, 0.616, 0.541); -g_Map.ExportMap(); + setPPEffect("hdr"); + setPPContrast(0.67); + setPPSaturation(0.42); + setPPBloom(0.23); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/red_sea.js =================================================================== --- binaries/data/mods/public/maps/random/red_sea.js +++ binaries/data/mods/public/maps/random/red_sea.js @@ -22,367 +22,372 @@ TILE_CENTERED_HEIGHT_MAP = true; -setBiome("generic/sahara"); +function* GenerateMap(mapSettings) +{ + setBiome("generic/sahara"); -g_Terrains.mainTerrain = new Array(4).fill("desert_sand_dunes_50").concat(["desert_sand_dunes_rocks", "desert_dirt_rough_2"]); -g_Terrains.forestFloor1 = "desert_grass_a_sand"; -g_Terrains.cliff = "desert_cliff_3_dirty"; -g_Terrains.forestFloor2 = "desert_grass_a_sand"; -g_Terrains.tier1Terrain = "desert_dirt_rocks_2"; -g_Terrains.tier2Terrain = "desert_dirt_rough"; -g_Terrains.tier3Terrain = "desert_dirt_rough"; -g_Terrains.tier4Terrain = "desert_sand_stones"; -g_Terrains.roadWild = "road2"; -g_Terrains.road = "road2"; -g_Terrains.additionalDirt1 = "desert_plants_b"; -g_Terrains.additionalDirt2 = "desert_sand_scrub"; -g_Gaia.tree1 = "gaia/tree/date_palm"; -g_Gaia.tree2 = "gaia/tree/senegal_date_palm"; -g_Gaia.tree3 = "gaia/fruit/date"; -g_Gaia.tree4 = "gaia/tree/cretan_date_palm_tall"; -g_Gaia.tree5 = "gaia/tree/cretan_date_palm_short"; -g_Gaia.fruitBush = "gaia/fruit/berry_05"; -g_Decoratives.grass = "actor|props/flora/grass_field_dry_tall_b.xml"; -g_Decoratives.grassShort = "actor|props/flora/grass_field_parched_short.xml"; -g_Decoratives.rockLarge = "actor|geology/stone_desert_med.xml"; -g_Decoratives.rockMedium = "actor|geology/stone_savanna_med.xml"; -g_Decoratives.bushMedium = "actor|props/flora/bush_desert_dry_a.xml"; -g_Decoratives.bushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; -g_Decoratives.dust = "actor|particle/dust_storm_reddish.xml"; + g_Terrains.mainTerrain = new Array(4).fill("desert_sand_dunes_50").concat( + ["desert_sand_dunes_rocks", "desert_dirt_rough_2"]); + g_Terrains.forestFloor1 = "desert_grass_a_sand"; + g_Terrains.cliff = "desert_cliff_3_dirty"; + g_Terrains.forestFloor2 = "desert_grass_a_sand"; + g_Terrains.tier1Terrain = "desert_dirt_rocks_2"; + g_Terrains.tier2Terrain = "desert_dirt_rough"; + g_Terrains.tier3Terrain = "desert_dirt_rough"; + g_Terrains.tier4Terrain = "desert_sand_stones"; + g_Terrains.roadWild = "road2"; + g_Terrains.road = "road2"; + g_Terrains.additionalDirt1 = "desert_plants_b"; + g_Terrains.additionalDirt2 = "desert_sand_scrub"; + g_Gaia.tree1 = "gaia/tree/date_palm"; + g_Gaia.tree2 = "gaia/tree/senegal_date_palm"; + g_Gaia.tree3 = "gaia/fruit/date"; + g_Gaia.tree4 = "gaia/tree/cretan_date_palm_tall"; + g_Gaia.tree5 = "gaia/tree/cretan_date_palm_short"; + g_Gaia.fruitBush = "gaia/fruit/berry_05"; + g_Decoratives.grass = "actor|props/flora/grass_field_dry_tall_b.xml"; + g_Decoratives.grassShort = "actor|props/flora/grass_field_parched_short.xml"; + g_Decoratives.rockLarge = "actor|geology/stone_desert_med.xml"; + g_Decoratives.rockMedium = "actor|geology/stone_savanna_med.xml"; + g_Decoratives.bushMedium = "actor|props/flora/bush_desert_dry_a.xml"; + g_Decoratives.bushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; + g_Decoratives.dust = "actor|particle/dust_storm_reddish.xml"; -const heightScale = num => num * g_MapSettings.Size / 320; + const heightScale = num => num * mapSettings.Size / 320; -const heightSeaGround = heightScale(-4); -const heightReedsMin = heightScale(-2); -const heightReedsMax = heightScale(-0.5); -const heightWaterLevel = heightScale(0); -const heightShoreline = heightScale(0.5); -const heightHills = heightScale(16); + const heightSeaGround = heightScale(-4); + const heightReedsMin = heightScale(-2); + const heightReedsMax = heightScale(-0.5); + const heightWaterLevel = heightScale(0); + const heightShoreline = heightScale(0.5); + const heightHills = heightScale(16); -const g_Map = new RandomMap(0, g_Terrains.mainTerrain); -const mapCenter = g_Map.getCenter(); + global.g_Map = new RandomMap(0, g_Terrains.mainTerrain); + const mapCenter = g_Map.getCenter(); -initTileClasses(["shoreline"]); + initTileClasses(["shoreline"]); -g_Map.LoadHeightmapImage("red_sea.png", 0, 25); -Engine.SetProgress(15); + g_Map.LoadHeightmapImage("red_sea.png", 0, 25); + yield 15; -g_Map.log("Lowering sea ground"); -createArea( - new MapBoundsPlacer(), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 2), - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(20); + g_Map.log("Lowering sea ground"); + createArea( + new MapBoundsPlacer(), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 2), + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 20; -g_Map.log("Smoothing heightmap"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, scaleByMapSize(0.1, 0.5), 1)); -Engine.SetProgress(25); + g_Map.log("Smoothing heightmap"); + createArea( + new MapBoundsPlacer(), + new SmoothingPainter(1, scaleByMapSize(0.1, 0.5), 1)); + yield 25; -g_Map.log("Marking water"); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.water), - new HeightConstraint(-Infinity, heightWaterLevel)); -Engine.SetProgress(30); + g_Map.log("Marking water"); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.water), + new HeightConstraint(-Infinity, heightWaterLevel)); + yield 30; -g_Map.log("Marking land"); -createArea( - new DiskPlacer(fractionToTiles(0.5), mapCenter), - new TileClassPainter(g_TileClasses.land), - avoidClasses(g_TileClasses.water, 0)); -Engine.SetProgress(35); + g_Map.log("Marking land"); + createArea( + new DiskPlacer(fractionToTiles(0.5), mapCenter), + new TileClassPainter(g_TileClasses.land), + avoidClasses(g_TileClasses.water, 0)); + yield 35; -g_Map.log("Painting shoreline"); -createArea( - new MapBoundsPlacer(), - [ - new TerrainPainter(g_Terrains.water), - new TileClassPainter(g_TileClasses.shoreline) - ], - new HeightConstraint(-Infinity, heightShoreline)); -Engine.SetProgress(40); + g_Map.log("Painting shoreline"); + createArea( + new MapBoundsPlacer(), + [ + new TerrainPainter(g_Terrains.water), + new TileClassPainter(g_TileClasses.shoreline) + ], + new HeightConstraint(-Infinity, heightShoreline)); + yield 40; -g_Map.log("Painting cliffs"); -createArea( - new MapBoundsPlacer(), - [ - new TerrainPainter(g_Terrains.cliff), - new TileClassPainter(g_TileClasses.mountain), - ], - [ - avoidClasses(g_TileClasses.water, 2), - new SlopeConstraint(2, Infinity) - ]); -Engine.SetProgress(45); + g_Map.log("Painting cliffs"); + createArea( + new MapBoundsPlacer(), + [ + new TerrainPainter(g_Terrains.cliff), + new TileClassPainter(g_TileClasses.mountain), + ], + [ + avoidClasses(g_TileClasses.water, 2), + new SlopeConstraint(2, Infinity) + ]); + yield 45; -if (!isNomad()) -{ - g_Map.log("Placing players"); - const [playerIDs, playerPosition] = createBases( - ...playerPlacementRandom( - sortAllPlayers(), - [ - avoidClasses(g_TileClasses.mountain, scaleByMapSize(5, 10)), - stayClasses(g_TileClasses.land, defaultPlayerBaseRadius()) - ]), - true); + if (!isNomad()) + { + g_Map.log("Placing players"); + const [playerIDs, playerPosition] = createBases( + ...playerPlacementRandom( + sortAllPlayers(), + [ + avoidClasses(g_TileClasses.mountain, scaleByMapSize(5, 10)), + stayClasses(g_TileClasses.land, defaultPlayerBaseRadius()) + ]), + true); - g_Map.log("Flatten the initial CC area"); - for (const position of playerPosition) - createArea( - new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, position), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); -} + g_Map.log("Flatten the initial CC area"); + for (const position of playerPosition) + createArea( + new ClumpPlacer(diskArea(defaultPlayerBaseRadius() * 0.8), 0.95, 0.6, Infinity, + position), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 6)); + } -addElements(shuffleArray([ - { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.metal, 20, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal"] - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 10, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal"] - }, - { + addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 20, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal"] + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal"] + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, 3, + g_TileClasses.forest, 20, + g_TileClasses.metal, 4, + g_TileClasses.mountain, 3, + g_TileClasses.player, 20, + g_TileClasses.rock, 4, + g_TileClasses.water, 2 + ], + "sizes": ["big"], + "mixes": ["similar"], + "amounts": ["few"] + } + ])); + yield 60; + + // Ensure initial forests + addElements([{ "func": addForests, "avoid": [ - g_TileClasses.berries, 3, - g_TileClasses.forest, 20, + g_TileClasses.berries, 2, + g_TileClasses.forest, 25, g_TileClasses.metal, 4, - g_TileClasses.mountain, 3, - g_TileClasses.player, 20, + g_TileClasses.mountain, 5, + g_TileClasses.player, 15, g_TileClasses.rock, 4, g_TileClasses.water, 2 ], - "sizes": ["big"], + "sizes": ["small"], "mixes": ["similar"], - "amounts": ["few"] - } -])); -Engine.SetProgress(60); + "amounts": ["tons"] + }]); + yield 65; -// Ensure initial forests -addElements([{ - "func": addForests, - "avoid": [ - g_TileClasses.berries, 2, - g_TileClasses.forest, 25, - g_TileClasses.metal, 4, - g_TileClasses.mountain, 5, - g_TileClasses.player, 15, - g_TileClasses.rock, 4, - g_TileClasses.water, 2 - ], - "sizes": ["small"], - "mixes": ["similar"], - "amounts": ["tons"] -}]); -Engine.SetProgress(65); + addElements(shuffleArray([ + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 10, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["normal", "many"] + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.player, 20, + g_TileClasses.rock, 4, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + }, + { + "func": addFish, + "avoid": [ + g_TileClasses.fish, 12, + g_TileClasses.player, 8 + ], + "stay": [g_TileClasses.water, 4], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.forest, 15, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.player, 20, + g_TileClasses.rock, 4, + g_TileClasses.water, 5 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": ["many"] + } + ])); + yield 70; -addElements(shuffleArray([ - { - "func": addBerries, - "avoid": [ - g_TileClasses.berries, 30, - g_TileClasses.forest, 5, - g_TileClasses.metal, 10, - g_TileClasses.mountain, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 10, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["normal", "many"] - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.player, 20, - g_TileClasses.rock, 4, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - }, - { - "func": addFish, - "avoid": [ - g_TileClasses.fish, 12, - g_TileClasses.player, 8 - ], - "stay": [g_TileClasses.water, 4], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.forest, 15, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.player, 20, - g_TileClasses.rock, 4, - g_TileClasses.water, 5 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": ["many"] - } -])); -Engine.SetProgress(70); + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3, + g_TileClasses.shoreline, 2 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["tons"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["similar"], + "amounts": ["many"] + } + ]); + yield 80; -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3, - g_TileClasses.shoreline, 2 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["tons"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["similar"], - "amounts": ["many"] - } -]); -Engine.SetProgress(80); + g_Map.log("Painting dirt patches"); + const dirtPatches = [ + { + "sizes": [2, 4], + "count": scaleByMapSize(2, 5), + "terrain": g_Terrains.additionalDirt1 + }, + { + "sizes": [4, 6, 8], + "count": scaleByMapSize(4, 8), + "terrain": g_Terrains.additionalDirt2 + } + ]; + for (const dirtPatch of dirtPatches) + createPatches( + dirtPatch.sizes, + dirtPatch.terrain, + [ + stayClasses(g_TileClasses.land, 6), + avoidClasses( + g_TileClasses.mountain, 4, + g_TileClasses.forest, 2, + g_TileClasses.shoreline, 2, + g_TileClasses.player, 12) + ], + dirtPatch.count, + g_TileClasses.dirt, + 0.5); + yield 85; -g_Map.log("Painting dirt patches"); -const dirtPatches = [ - { - "sizes": [2, 4], - "count": scaleByMapSize(2, 5), - "terrain": g_Terrains.additionalDirt1 - }, - { - "sizes": [4, 6, 8], - "count": scaleByMapSize(4, 8), - "terrain": g_Terrains.additionalDirt2 - } -]; -for (const dirtPatch of dirtPatches) - createPatches( - dirtPatch.sizes, - dirtPatch.terrain, - [ - stayClasses(g_TileClasses.land, 6), - avoidClasses( - g_TileClasses.mountain, 4, - g_TileClasses.forest, 2, - g_TileClasses.shoreline, 2, - g_TileClasses.player, 12) - ], - dirtPatch.count, - g_TileClasses.dirt, - 0.5); -Engine.SetProgress(85); + g_Map.log("Adding reeds"); + createObjectGroups( + new SimpleGroup( + [ + new SimpleObject(g_Decoratives.reeds, 5, 12, 1, 4), + new SimpleObject(g_Decoratives.rockMedium, 1, 2, 1, 5) + ], + false, + g_TileClasses.dirt), + 0, + new HeightConstraint(heightReedsMin, heightReedsMax), + scaleByMapSize(10, 25), + 5); + yield 90; -g_Map.log("Adding reeds"); -createObjectGroups( - new SimpleGroup( + g_Map.log("Adding dust"); + createObjectGroups( + new SimpleGroup([new SimpleObject(g_Decoratives.dust, 1, 1, 1, 4)], false), + 0, [ - new SimpleObject(g_Decoratives.reeds, 5, 12, 1, 4), - new SimpleObject(g_Decoratives.rockMedium, 1, 2, 1, 5) + stayClasses(g_TileClasses.land, 5), + avoidClasses(g_TileClasses.player, 10) ], - false, - g_TileClasses.dirt), - 0, - new HeightConstraint(heightReedsMin, heightReedsMax), - scaleByMapSize(10, 25), - 5); -Engine.SetProgress(90); - -g_Map.log("Adding dust"); -createObjectGroups( - new SimpleGroup([new SimpleObject(g_Decoratives.dust, 1, 1, 1, 4)], false), - 0, - [ - stayClasses(g_TileClasses.land, 5), - avoidClasses(g_TileClasses.player, 10) - ], - scaleByMapSize(10, 50), - 20); -Engine.SetProgress(95); + scaleByMapSize(10, 50), + 20); + yield 95; -placePlayersNomad( - g_Map.createTileClass(), - [ - stayClasses(g_TileClasses.land, 5), - avoidClasses( - g_TileClasses.forest, 2, - g_TileClasses.rock, 4, - g_TileClasses.metal, 4, - g_TileClasses.berries, 2, - g_TileClasses.animals, 2, - g_TileClasses.mountain, 2) - ]); + placePlayersNomad( + g_Map.createTileClass(), + [ + stayClasses(g_TileClasses.land, 5), + avoidClasses( + g_TileClasses.forest, 2, + g_TileClasses.rock, 4, + g_TileClasses.metal, 4, + g_TileClasses.berries, 2, + g_TileClasses.animals, 2, + g_TileClasses.mountain, 2) + ]); -setWindAngle(-0.43); -setWaterTint(0.161, 0.286, 0.353); -setWaterColor(0.129, 0.176, 0.259); -setWaterWaviness(8); -setWaterMurkiness(0.87); -setWaterType("lake"); + setWindAngle(-0.43); + setWaterTint(0.161, 0.286, 0.353); + setWaterColor(0.129, 0.176, 0.259); + setWaterWaviness(8); + setWaterMurkiness(0.87); + setWaterType("lake"); -setAmbientColor(0.58, 0.443, 0.353); + setAmbientColor(0.58, 0.443, 0.353); -setSunColor(0.733, 0.746, 0.574); -setSunRotation(Math.PI * 1.1); -setSunElevation(Math.PI / 7); + setSunColor(0.733, 0.746, 0.574); + setSunRotation(Math.PI * 1.1); + setSunElevation(Math.PI / 7); -setFogFactor(0); -setFogThickness(0); -setFogColor(0.69, 0.616, 0.541); + setFogFactor(0); + setFogThickness(0); + setFogColor(0.69, 0.616, 0.541); -setPPEffect("hdr"); -setPPContrast(0.67); -setPPSaturation(0.42); -setPPBloom(0.23); + setPPEffect("hdr"); + setPPContrast(0.67); + setPPSaturation(0.42); + setPPBloom(0.23); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/rhine_marshlands.js =================================================================== --- binaries/data/mods/public/maps/random/rhine_marshlands.js +++ binaries/data/mods/public/maps/random/rhine_marshlands.js @@ -1,309 +1,316 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tGrass = ["temp_grass", "temp_grass", "temp_grass_d"]; -const tForestFloor = "temp_plants_bog"; -const tGrassA = "temp_grass_plants"; -const tGrassB = "temp_plants_bog"; -const tMud = "temp_mud_a"; -const tRoad = "temp_road"; -const tRoadWild = "temp_road_overgrown"; -const tShoreBlend = "temp_grass_plants"; -const tShore = "temp_plants_bog"; -const tWater = "temp_mud_a"; - -const oBeech = "gaia/tree/euro_beech"; -const oOak = "gaia/tree/oak"; -const oBerryBush = "gaia/fruit/berry_01"; -const oDeer = "gaia/fauna_deer"; -const oHorse = "gaia/fauna_horse"; -const oWolf = "gaia/fauna_wolf"; -const oRabbit = "gaia/fauna_rabbit"; -const oStoneLarge = "gaia/rock/temperate_large"; -const oStoneSmall = "gaia/rock/temperate_small"; -const oMetalLarge = "gaia/ore/temperate_large"; - -const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; -const aGrassShort = "actor|props/flora/grass_soft_large.xml"; -const aRockLarge = "actor|geology/stone_granite_med.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; -const aLillies = "actor|props/flora/water_lillies.xml"; -const aBushMedium = "actor|props/flora/bush_medit_me.xml"; -const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; - -const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oBeech, tForestFloor]; -const pForestP = [tForestFloor + TERRAIN_SEPARATOR + oOak, tForestFloor]; - -const heightMarsh = -2; -const heightLand = 1; -const heightOffsetBumpWater = 1; -const heightOffsetBumpLand = 2; - -const g_Map = new RandomMap(heightLand, tGrass); - -const numPlayers = getNumPlayers(); - -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oBeech - }, - "Decoratives": { - "template": aGrassShort - } -}); -Engine.SetProgress(15); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBumpLand, 2), - avoidClasses(clPlayer, 13), - scaleByMapSize(300, 800)); - -g_Map.log("Creating marshes"); -for (let i = 0; i < 7; ++i) +function* GenerateMap() +{ + const tGrass = ["temp_grass", "temp_grass", "temp_grass_d"]; + const tForestFloor = "temp_plants_bog"; + const tGrassA = "temp_grass_plants"; + const tGrassB = "temp_plants_bog"; + const tMud = "temp_mud_a"; + const tRoad = "temp_road"; + const tRoadWild = "temp_road_overgrown"; + const tShoreBlend = "temp_grass_plants"; + const tShore = "temp_plants_bog"; + const tWater = "temp_mud_a"; + + const oBeech = "gaia/tree/euro_beech"; + const oOak = "gaia/tree/oak"; + const oBerryBush = "gaia/fruit/berry_01"; + const oDeer = "gaia/fauna_deer"; + const oHorse = "gaia/fauna_horse"; + const oWolf = "gaia/fauna_wolf"; + const oRabbit = "gaia/fauna_rabbit"; + const oStoneLarge = "gaia/rock/temperate_large"; + const oStoneSmall = "gaia/rock/temperate_small"; + const oMetalLarge = "gaia/ore/temperate_large"; + + const aGrass = "actor|props/flora/grass_soft_small_tall.xml"; + const aGrassShort = "actor|props/flora/grass_soft_large.xml"; + const aRockLarge = "actor|geology/stone_granite_med.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; + const aLillies = "actor|props/flora/water_lillies.xml"; + const aBushMedium = "actor|props/flora/bush_medit_me.xml"; + const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; + + const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oBeech, tForestFloor]; + const pForestP = [tForestFloor + TERRAIN_SEPARATOR + oOak, tForestFloor]; + + const heightMarsh = -2; + const heightLand = 1; + const heightOffsetBumpWater = 1; + const heightOffsetBumpLand = 2; + + global.g_Map = new RandomMap(heightLand, tGrass); + + const numPlayers = getNumPlayers(); + + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oBeech + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 15; + + g_Map.log("Creating bumps"); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(6, 12)), Math.floor(scaleByMapSize(15, 60)), 0.8), - [ - new LayeredPainter([tShoreBlend, tShore, tWater], [1, 1]), - new SmoothElevationPainter(ELEVATION_SET, heightMarsh, 3), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 20, clWater, Math.round(scaleByMapSize(7,16)*randFloat(0.8,1.35))), - scaleByMapSize(4,20)); - -g_Map.log("Creating reeds"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aReeds, 5, 10, 0, 4), new SimpleObject(aLillies, 5, 10, 0, 4)], true), - 0, - stayClasses(clWater, 1), - scaleByMapSize(400,2000), 100); -Engine.SetProgress(40); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBumpWater, 2), - stayClasses(clWater, 2), - scaleByMapSize(50, 100)); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.7); -const types = [ - [[tForestFloor, tGrass, pForestD], [tForestFloor, pForestD]], - [[tForestFloor, tGrass, pForestP], [tForestFloor, pForestP]] -]; -const forestSize = forestTrees / (scaleByMapSize(3,6) * numPlayers); -const num = Math.floor(forestSize / types.length); -for (const type of types) + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBumpLand, 2), + avoidClasses(clPlayer, 13), + scaleByMapSize(300, 800)); + + g_Map.log("Creating marshes"); + for (let i = 0; i < 7; ++i) + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(6, 12)), Math.floor(scaleByMapSize(15, 60)), + 0.8), + [ + new LayeredPainter([tShoreBlend, tShore, tWater], [1, 1]), + new SmoothElevationPainter(ELEVATION_SET, heightMarsh, 3), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 20, clWater, Math.round(scaleByMapSize(7,16)*randFloat(0.8,1.35))), + scaleByMapSize(4,20)); + + g_Map.log("Creating reeds"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aReeds, 5, 10, 0, 4), + new SimpleObject(aLillies, 5, 10, 0, 4)], true), + 0, + stayClasses(clWater, 1), + scaleByMapSize(400,2000), 100); + yield 40; + + g_Map.log("Creating bumps"); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), forestTrees / (num * Math.floor(scaleByMapSize(2, 4))), Infinity), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) - ], - avoidClasses(clPlayer, 20, clWater, 0, clForest, 10), - num); -Engine.SetProgress(50); - -g_Map.log("Creating mud patches"); -for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) - createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, Infinity), - [ - new LayeredPainter([tGrassA, tGrassB, tMud], [1, 1]), - new TileClassPainter(clDirt) - ], - avoidClasses(clWater, 1, clForest, 0, clDirt, 5, clPlayer, 8), - scaleByMapSize(15, 45)); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10)], - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10)], - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5)], - scaleByMapSize(4,16), 100 -); - -Engine.SetProgress(60); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aRockMedium, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 0), - scaleByMapSize(16, 262), 50 -); - -Engine.SetProgress(65); - -g_Map.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(clWater, 0, clForest, 0, clPlayer, 0), - scaleByMapSize(8, 131), 50 -); - -Engine.SetProgress(70); - -g_Map.log("Creating deer"); -group = new SimpleGroup( - [new SimpleObject(oDeer, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clFood, 13), - 6 * numPlayers, 50 -); - -g_Map.log("Creating horse"); -group = new SimpleGroup( - [new SimpleObject(oHorse, 1,3, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clFood, 13), - 3 * numPlayers, 50 -); - -Engine.SetProgress(75); - -g_Map.log("Creating rabbit"); -group = new SimpleGroup( - [new SimpleObject(oRabbit, 5,7, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clFood, 13), - 6 * numPlayers, 50 -); - -g_Map.log("Creating wolf"); -group = new SimpleGroup( - [new SimpleObject(oWolf, 1,3, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clFood, 13), - 3 * numPlayers, 50 -); - -g_Map.log("Creating berry bush"); -group = new SimpleGroup( - [new SimpleObject(oBerryBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clFood, 10), - randIntInclusive(1, 4) * numPlayers + 2, 50 -); - -Engine.SetProgress(80); - -createStragglerTrees( - [oOak, oBeech], - avoidClasses(clForest, 1, clPlayer, 13, clMetal, 6, clRock, 6, clWater, 0), - clForest, - stragglerTrees); - -Engine.SetProgress(85); - -g_Map.log("Creating small grass tufts"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aGrassShort, 1, 2, 0, 1)]), - 0, - avoidClasses(clWater, 2, clPlayer, 13, clDirt, 0), - scaleByMapSize(13, 200)); - -Engine.SetProgress(90); - -g_Map.log("Creating large grass tufts"); -createObjectGroupsDeprecated( - new SimpleGroup( - [ - new SimpleObject(aGrass, 2, 4, 0, 1.8), - new SimpleObject(aGrassShort, 3, 6, 1.2, 2.5) - ]), - 0, - avoidClasses(clWater, 3, clPlayer, 13, clDirt, 1, clForest, 0), - scaleByMapSize(13, 200)); - -Engine.SetProgress(95); - -g_Map.log("Creating bushes"); -createObjectGroupsDeprecated( - new SimpleGroup( - [ - new SimpleObject(aBushMedium, 1, 2, 0, 2), - new SimpleObject(aBushSmall, 2, 4, 0, 2) - ]), - 0, - avoidClasses(clWater, 1, clPlayer, 13, clDirt, 1), - scaleByMapSize(13, 200), - 50); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); - -setSkySet("cirrus"); -setWaterColor(0.753,0.635,0.345); // muddy brown -setWaterTint(0.161,0.514,0.635); // clear blue for blueness -setWaterMurkiness(0.8); -setWaterWaviness(1.0); -setWaterType("clap"); - -setFogThickness(0.25); -setFogFactor(0.6); - -setPPEffect("hdr"); -setPPSaturation(0.44); -setPPBloom(0.3); - -g_Map.ExportMap(); + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBumpWater, 2), + stayClasses(clWater, 2), + scaleByMapSize(50, 100)); + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(500, 2500, 0.7); + const types = [ + [[tForestFloor, tGrass, pForestD], [tForestFloor, pForestD]], + [[tForestFloor, tGrass, pForestP], [tForestFloor, pForestP]] + ]; + const forestSize = forestTrees / (scaleByMapSize(3,6) * numPlayers); + const num = Math.floor(forestSize / types.length); + for (const type of types) + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), + forestTrees / (num * Math.floor(scaleByMapSize(2, 4))), Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 20, clWater, 0, clForest, 10), + num); + yield 50; + + g_Map.log("Creating mud patches"); + for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, Infinity), + [ + new LayeredPainter([tGrassA, tGrassB, tMud], [1, 1]), + new TileClassPainter(clDirt) + ], + avoidClasses(clWater, 1, clForest, 0, clDirt, 5, clPlayer, 8), + scaleByMapSize(15, 45)); + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10)], + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clRock, 10)], + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clWater, 0, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5)], + scaleByMapSize(4,16), 100 + ); + + yield 60; + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aRockMedium, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0), + scaleByMapSize(16, 262), 50 + ); + + yield 65; + + g_Map.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(clWater, 0, clForest, 0, clPlayer, 0), + scaleByMapSize(8, 131), 50 + ); + + yield 70; + + g_Map.log("Creating deer"); + group = new SimpleGroup( + [new SimpleObject(oDeer, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clFood, 13), + 6 * numPlayers, 50 + ); + + g_Map.log("Creating horse"); + group = new SimpleGroup( + [new SimpleObject(oHorse, 1,3, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clFood, 13), + 3 * numPlayers, 50 + ); + + yield 75; + + g_Map.log("Creating rabbit"); + group = new SimpleGroup( + [new SimpleObject(oRabbit, 5,7, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clFood, 13), + 6 * numPlayers, 50 + ); + + g_Map.log("Creating wolf"); + group = new SimpleGroup( + [new SimpleObject(oWolf, 1,3, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 20, clFood, 13), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating berry bush"); + group = new SimpleGroup( + [new SimpleObject(oBerryBush, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clFood, 10), + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + + yield 80; + + createStragglerTrees( + [oOak, oBeech], + avoidClasses(clForest, 1, clPlayer, 13, clMetal, 6, clRock, 6, clWater, 0), + clForest, + stragglerTrees); + + yield 85; + + g_Map.log("Creating small grass tufts"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aGrassShort, 1, 2, 0, 1)]), + 0, + avoidClasses(clWater, 2, clPlayer, 13, clDirt, 0), + scaleByMapSize(13, 200)); + + yield 90; + + g_Map.log("Creating large grass tufts"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(aGrass, 2, 4, 0, 1.8), + new SimpleObject(aGrassShort, 3, 6, 1.2, 2.5) + ]), + 0, + avoidClasses(clWater, 3, clPlayer, 13, clDirt, 1, clForest, 0), + scaleByMapSize(13, 200)); + + yield 95; + + g_Map.log("Creating bushes"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(aBushMedium, 1, 2, 0, 2), + new SimpleObject(aBushSmall, 2, 4, 0, 2) + ]), + 0, + avoidClasses(clWater, 1, clPlayer, 13, clDirt, 1), + scaleByMapSize(13, 200), + 50); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); + + setSkySet("cirrus"); + setWaterColor(0.753,0.635,0.345); // muddy brown + setWaterTint(0.161,0.514,0.635); // clear blue for blueness + setWaterMurkiness(0.8); + setWaterWaviness(1.0); + setWaterType("clap"); + + setFogThickness(0.25); + setFogFactor(0.6); + + setPPEffect("hdr"); + setPPSaturation(0.44); + setPPBloom(0.3); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/river_archipelago.js =================================================================== --- binaries/data/mods/public/maps/random/river_archipelago.js +++ binaries/data/mods/public/maps/random/river_archipelago.js @@ -1,434 +1,468 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tGrass = ["tropic_grass_c", "tropic_grass_c", "tropic_grass_c", "tropic_grass_c", "tropic_grass_plants", "tropic_plants", "tropic_plants_b"]; -const tGrassA = "tropic_plants_c"; -const tGrassB = "tropic_plants_c"; -const tGrassC = "tropic_grass_c"; -const tForestFloor = "tropic_grass_plants"; -const tCliff = ["tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a_plants"]; -const tPlants = "tropic_plants"; -const tRoad = "tropic_citytile_a"; -const tRoadWild = "tropic_citytile_plants"; -const tShoreBlend = "tropic_beach_dry_plants"; -const tShore = "tropic_beach_dry"; -const tWater = "tropic_beach_wet"; - -const oTree = "gaia/tree/toona"; -const oPalm1 = "gaia/tree/palm_tropic"; -const oPalm2 = "gaia/tree/palm_tropical"; -const oStoneLarge = "gaia/rock/tropical_large"; -const oStoneSmall = "gaia/rock/tropical_small"; -const oMetalLarge = "gaia/ore/tropical_large"; -const oFish = "gaia/fish/generic"; -const oDeer = "gaia/fauna_deer"; -const oTiger = "gaia/fauna_tiger"; -const oBoar = "gaia/fauna_boar"; -const oPeacock = "gaia/fauna_peacock"; -const oBush = "gaia/fruit/berry_01"; -const oSpearman = "units/maur/infantry_spearman_b"; -const oArcher = "units/maur/infantry_archer_b"; -const oArcherElephant = "units/maur/elephant_archer_b"; - -const aRockLarge = "actor|geology/stone_granite_large.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aBush1 = "actor|props/flora/plant_tropic_a.xml"; -const aBush2 = "actor|props/flora/plant_lg.xml"; -const aBush3 = "actor|props/flora/plant_tropic_large.xml"; - -const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oTree, tForestFloor]; -const pForestP1 = [tForestFloor + TERRAIN_SEPARATOR + oPalm1, tForestFloor]; -const pForestP2 = [tForestFloor + TERRAIN_SEPARATOR + oPalm2, tForestFloor]; - -const heightSeaGround = -8; -const heightWaterLevel = 0; -const heightShore = 1; -const heightShoreBlend = 2.8; -const heightLand = 3; -const heightHill = 25; - -const g_Map = new RandomMap(heightSeaGround, tGrass); - -const numPlayers = getNumPlayers(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clPlayerTerritory = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clGaia = g_Map.createTileClass(); -const clStrip = []; - -const startAngle = randomAngle(); -const connectPlayers = randBool(); - -// Map layout -const stripWidthsLeft = connectPlayers ? - [[0.03, 0.09], [0.14, 0.25], [0.36, 0.46]] : - [[0, 0.06], [0.12, 0.23], [0.33, 0.43]]; - -// Mirror -let stripWidthsRight = clone(stripWidthsLeft); -stripWidthsRight.reverse(); -stripWidthsRight = stripWidthsRight.map(strip => [1 - strip[1], 1 - strip[0]]); - -const stripWidths = stripWidthsLeft.concat(stripWidthsRight); - -g_Map.log("Creating strips"); -for (let i = 0; i < stripWidths.length; ++i) +function* GenerateMap() { - clStrip[i] = g_Map.createTileClass(); - - const isPlayerStrip = i == 2 || i == 3; - for (let j = 0; j < scaleByMapSize(20, 100); ++j) + const tGrass = ["tropic_grass_c", "tropic_grass_c", "tropic_grass_c", "tropic_grass_c", "tropic_grass_plants", "tropic_plants", "tropic_plants_b"]; + const tGrassA = "tropic_plants_c"; + const tGrassB = "tropic_plants_c"; + const tGrassC = "tropic_grass_c"; + const tForestFloor = "tropic_grass_plants"; + const tCliff = ["tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a", "tropic_cliff_a_plants"]; + const tPlants = "tropic_plants"; + const tRoad = "tropic_citytile_a"; + const tRoadWild = "tropic_citytile_plants"; + const tShoreBlend = "tropic_beach_dry_plants"; + const tShore = "tropic_beach_dry"; + const tWater = "tropic_beach_wet"; + + const oTree = "gaia/tree/toona"; + const oPalm1 = "gaia/tree/palm_tropic"; + const oPalm2 = "gaia/tree/palm_tropical"; + const oStoneLarge = "gaia/rock/tropical_large"; + const oStoneSmall = "gaia/rock/tropical_small"; + const oMetalLarge = "gaia/ore/tropical_large"; + const oFish = "gaia/fish/generic"; + const oDeer = "gaia/fauna_deer"; + const oTiger = "gaia/fauna_tiger"; + const oBoar = "gaia/fauna_boar"; + const oPeacock = "gaia/fauna_peacock"; + const oBush = "gaia/fruit/berry_01"; + const oSpearman = "units/maur/infantry_spearman_b"; + const oArcher = "units/maur/infantry_archer_b"; + const oArcherElephant = "units/maur/elephant_archer_b"; + + const aRockLarge = "actor|geology/stone_granite_large.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aBush1 = "actor|props/flora/plant_tropic_a.xml"; + const aBush2 = "actor|props/flora/plant_lg.xml"; + const aBush3 = "actor|props/flora/plant_tropic_large.xml"; + + const pForestD = [tForestFloor + TERRAIN_SEPARATOR + oTree, tForestFloor]; + const pForestP1 = [tForestFloor + TERRAIN_SEPARATOR + oPalm1, tForestFloor]; + const pForestP2 = [tForestFloor + TERRAIN_SEPARATOR + oPalm2, tForestFloor]; + + const heightSeaGround = -8; + const heightWaterLevel = 0; + const heightShore = 1; + const heightShoreBlend = 2.8; + const heightLand = 3; + const heightHill = 25; + + global.g_Map = new RandomMap(heightSeaGround, tGrass); + + const numPlayers = getNumPlayers(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clPlayerTerritory = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clGaia = g_Map.createTileClass(); + const clStrip = []; + + const startAngle = randomAngle(); + const connectPlayers = randBool(); + + // Map layout + const stripWidthsLeft = connectPlayers ? + [[0.03, 0.09], [0.14, 0.25], [0.36, 0.46]] : + [[0, 0.06], [0.12, 0.23], [0.33, 0.43]]; + + // Mirror + let stripWidthsRight = clone(stripWidthsLeft); + stripWidthsRight.reverse(); + stripWidthsRight = stripWidthsRight.map(strip => [1 - strip[1], 1 - strip[0]]); + + const stripWidths = stripWidthsLeft.concat(stripWidthsRight); + + g_Map.log("Creating strips"); + for (let i = 0; i < stripWidths.length; ++i) { - const position = new Vector2D( - randFloat(mapBounds.bottom, mapBounds.top), - fractionToTiles(randFloat(...stripWidths[i]))).rotateAround(startAngle, mapCenter).round(); + clStrip[i] = g_Map.createTileClass(); + + const isPlayerStrip = i == 2 || i == 3; + for (let j = 0; j < scaleByMapSize(20, 100); ++j) + { + const position = new Vector2D( + randFloat(mapBounds.bottom, mapBounds.top), + fractionToTiles(randFloat(...stripWidths[i]))).rotateAround(startAngle, mapCenter) + .round(); + + createArea( + new ChainPlacer( + 1, + Math.floor(scaleByMapSize(3, connectPlayers && isPlayerStrip ? 8 : 7)), + Math.floor(scaleByMapSize(30, 60)), + Infinity, + position), + [ + new TerrainPainter(tGrass), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), + new TileClassPainter(clStrip[i]) + ]); + } + } + yield 20; + const playerPosition = playerPlacementLine(startAngle, mapCenter, + fractionToTiles(1 - stripWidthsLeft[2][0] - stripWidthsLeft[2][1])); + + // Either left vs right or top vs bottom + const playerIDs = randBool() ? sortAllPlayers() : primeSortAllPlayers(); + + g_Map.log("Ensuring player territory"); + const playerRadius = scaleByMapSize(12, 20); + for (let i = 0; i < numPlayers; ++i) createArea( - new ChainPlacer( - 1, - Math.floor(scaleByMapSize(3, connectPlayers && isPlayerStrip ? 8 : 7)), - Math.floor(scaleByMapSize(30, 60)), - Infinity, - position), + new ChainPlacer(1, 6, 40, 1, playerPosition[i], 0, [Math.floor(playerRadius)]), [ new TerrainPainter(tGrass), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), - new TileClassPainter(clStrip[i]) + new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), + new TileClassPainter(clPlayerTerritory) ]); - } -} -Engine.SetProgress(20); -const playerPosition = playerPlacementLine(startAngle, mapCenter, fractionToTiles(1 - stripWidthsLeft[2][0] - stripWidthsLeft[2][1])); - -// Either left vs right or top vs bottom -const playerIDs = randBool() ? sortAllPlayers() : primeSortAllPlayers(); - -g_Map.log("Ensuring player territory"); -const playerRadius = scaleByMapSize(12, 20); -for (let i = 0; i < numPlayers; ++i) - createArea( - new ChainPlacer(1, 6, 40, 1, playerPosition[i], 0, [Math.floor(playerRadius)]), + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": stayClasses(clPlayerTerritory, 4), + "Walls": "towers", + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad, + "radius": playerRadius / 3 + }, + "StartingAnimal": { + "template": oPeacock + }, + "Berries": { + "template": oBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oTree, + "count": 40 + } + // No decoratives + }); + yield 35; + + const areaWater = createArea( + new HeightPlacer(Elevation_IncludeMin_ExcludeMax, -Infinity, heightWaterLevel), [ - new TerrainPainter(tGrass), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), - new TileClassPainter(clPlayerTerritory) + new TerrainPainter(tWater), + new TileClassPainter(clWater) ]); -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": stayClasses(clPlayerTerritory, 4), - "Walls": "towers", - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad, - "radius": playerRadius / 3 - }, - "StartingAnimal": { - "template": oPeacock - }, - "Berries": { - "template": oBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oTree, - "count": 40 - } - // No decoratives -}); -Engine.SetProgress(35); - -const areaWater = createArea( - new HeightPlacer(Elevation_IncludeMin_ExcludeMax, -Infinity, heightWaterLevel), - [ - new TerrainPainter(tWater), - new TileClassPainter(clWater) - ]); - -createArea( - new HeightPlacer(Elevation_IncludeMin_ExcludeMax, heightWaterLevel, heightShore), - new TerrainPainter(tShore)); + createArea( + new HeightPlacer(Elevation_IncludeMin_ExcludeMax, heightWaterLevel, heightShore), + new TerrainPainter(tShore)); -createArea( - new HeightPlacer(Elevation_IncludeMin_ExcludeMax, heightShore, heightShoreBlend), - new TerrainPainter(tShoreBlend)); + createArea( + new HeightPlacer(Elevation_IncludeMin_ExcludeMax, heightShore, heightShoreBlend), + new TerrainPainter(tShoreBlend)); -Engine.SetProgress(40); + yield 40; -if (!isNomad()) -{ - g_Map.log("Creating gaia"); - for (let i = 0; i < 2; ++i) - for (let j = 0; j < scaleByMapSize(1, 8); ++j) - createObjectGroups( - new SimpleGroup( + if (!isNomad()) + { + g_Map.log("Creating gaia"); + for (let i = 0; i < 2; ++i) + for (let j = 0; j < scaleByMapSize(1, 8); ++j) + createObjectGroups( + new SimpleGroup( + [ + new SimpleObject(oSpearman, 8, 12, 2, 3), + new SimpleObject(oArcher, 8, 12, 2, 3), + new SimpleObject(oArcherElephant, 2, 3, 4, 5) + ], + true, + clGaia), + 0, [ - new SimpleObject(oSpearman, 8, 12, 2, 3), - new SimpleObject(oArcher, 8, 12, 2, 3), - new SimpleObject(oArcherElephant, 2, 3, 4, 5) + avoidClasses( + clWater, 2, + clForest, 1, + clPlayerTerritory, 0, + clHill, 1, + clGaia, 15), + stayClasses(clStrip[i == 0 ? 0 : stripWidths.length - 1], 1) ], - true, - clGaia), - 0, - [ - avoidClasses( - clWater, 2, - clForest, 1, - clPlayerTerritory, 0, - clHill, 1, - clGaia, 15), - stayClasses(clStrip[i == 0 ? 0 : stripWidths.length - 1], 1) - ], - scaleByMapSize(5, 10), - 50); -} + scaleByMapSize(5, 10), + 50); + } -g_Map.log("Creating hills"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.1), - [ - new LayeredPainter([tCliff, tGrass], [3]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 3), - new TileClassPainter(clHill) - ], - [ - avoidClasses( - clPlayerTerritory, 0, - clHill, 5, - clGaia, 1, - clWater, 2) - ], - scaleByMapSize(1, 5)); - -createBumps(avoidClasses(clPlayer, 8, clWater, 2), scaleByMapSize(20, 150), 2, 8, 4, 1, 4); -Engine.SetProgress(50); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(1000, 4000, 0.7); -const types = [ - [[tGrass, tGrass, tGrass, tGrass, pForestD], [tGrass, tGrass, tGrass, pForestD]], - [[tGrass, tGrass, tGrass, tGrass, pForestP1], [tGrass, tGrass, tGrass, pForestP1]], - [[tGrass, tGrass, tGrass, tGrass, pForestP2], [tGrass, tGrass, tGrass, pForestP2]] -]; -const forestSize = forestTrees / (scaleByMapSize(3, 6) * numPlayers); -const num = Math.floor(forestSize / types.length); -for (const type of types) + g_Map.log("Creating hills"); createAreas( - new ChainPlacer( - 1, - Math.floor(scaleByMapSize(3, 5)), - forestTrees / (num * Math.floor(scaleByMapSize(2, 4))), - 0.5), + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.1), [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) + new LayeredPainter([tCliff, tGrass], [3]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 3), + new TileClassPainter(clHill) ], - avoidClasses( - clPlayer, 12, - clForest, 6, - clHill, 0, - clGaia, 1, - clWater, 2), - num); - -createStragglerTrees( - [oTree, oPalm1, oPalm2], - avoidClasses( - clWater, 5, - clForest, 1, - clHill, 1, - clPlayer, 8, - clBaseResource, 4, - clGaia, 1, - clMetal, 4, - clRock, 4), - clForest, - stragglerTrees); - -Engine.SetProgress(60); - -g_Map.log("Creating grass patches"); -for (const 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([tGrassC, tGrassA, tGrassB], [2, 1]), - new TileClassPainter(clDirt) + avoidClasses( + clPlayerTerritory, 0, + clHill, 5, + clGaia, 1, + clWater, 2) ], + scaleByMapSize(1, 5)); + + createBumps(avoidClasses(clPlayer, 8, clWater, 2), scaleByMapSize(20, 150), 2, 8, 4, 1, 4); + yield 50; + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(1000, 4000, 0.7); + const types = [ + [[tGrass, tGrass, tGrass, tGrass, pForestD], [tGrass, tGrass, tGrass, pForestD]], + [[tGrass, tGrass, tGrass, tGrass, pForestP1], [tGrass, tGrass, tGrass, pForestP1]], + [[tGrass, tGrass, tGrass, tGrass, pForestP2], [tGrass, tGrass, tGrass, pForestP2]] + ]; + const forestSize = forestTrees / (scaleByMapSize(3, 6) * numPlayers); + const num = Math.floor(forestSize / types.length); + for (const type of types) + createAreas( + new ChainPlacer( + 1, + Math.floor(scaleByMapSize(3, 5)), + forestTrees / (num * Math.floor(scaleByMapSize(2, 4))), + 0.5), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses( + clPlayer, 12, + clForest, 6, + clHill, 0, + clGaia, 1, + clWater, 2), + num); + + createStragglerTrees( + [oTree, oPalm1, oPalm2], avoidClasses( - clWater, 8, - clForest, 0, - clHill, 0, + clWater, 5, + clForest, 1, + clHill, 1, + clPlayer, 8, + clBaseResource, 4, clGaia, 1, - clPlayerTerritory, 0, - clDirt, 16), - scaleByMapSize(20, 80)); + clMetal, 4, + clRock, 4), + clForest, + stragglerTrees); -g_Map.log("Creating dirt patches"); -for (const 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(tPlants), - new TileClassPainter(clDirt) - ], + yield 60; + + g_Map.log("Creating grass patches"); + for (const 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([tGrassC, tGrassA, tGrassB], [2, 1]), + new TileClassPainter(clDirt) + ], + avoidClasses( + clWater, 8, + clForest, 0, + clHill, 0, + clGaia, 1, + clPlayerTerritory, 0, + clDirt, 16), + scaleByMapSize(20, 80)); + + g_Map.log("Creating dirt patches"); + for (const 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(tPlants), + new TileClassPainter(clDirt) + ], + avoidClasses( + clWater, 8, + clForest, 0, + clHill, 0, + clGaia, 1, + clPlayerTerritory, 0, + clDirt, 16), + scaleByMapSize(20, 80)); + + g_Map.log("Creating stone mines"); + createObjectGroups( + new SimpleGroup( + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4), + new SimpleObject(oStoneLarge, 1, 1, 0, 4) + ], + true, + clRock), + 0, avoidClasses( - clWater, 8, - clForest, 0, - clHill, 0, + clWater, 3, + clForest, 1, + clPlayerTerritory, 0, clGaia, 1, + clRock, 10, + clHill, 1), + scaleByMapSize(4, 16), + 50); + + g_Map.log("Creating small stone mines"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock), + 0, + avoidClasses( + clWater, 4, + clForest, 1, clPlayerTerritory, 0, - clDirt, 16), - scaleByMapSize(20, 80)); + clGaia, 1, + clRock, 10, + clHill, 1), + scaleByMapSize(2, 8), + 50); -g_Map.log("Creating stone mines"); -createObjectGroups( - new SimpleGroup( - [ - new SimpleObject(oStoneSmall, 0, 2, 0, 4), - new SimpleObject(oStoneLarge, 1, 1, 0, 4) - ], - true, - clRock), - 0, - avoidClasses( - clWater, 3, - clForest, 1, - clPlayerTerritory, 0, - clGaia, 1, - clRock, 10, - clHill, 1), + g_Map.log("Creating metal mines"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), + 0, + avoidClasses( + clWater, 4, + clForest, 1, + clPlayerTerritory, 0, + clGaia, 1, + clMetal, 10, + clRock, 5, + clHill, 1), scaleByMapSize(4, 16), 50); -g_Map.log("Creating small stone mines"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock), - 0, - avoidClasses( - clWater, 4, - clForest, 1, - clPlayerTerritory, 0, - clGaia, 1, - clRock, 10, - clHill, 1), - scaleByMapSize(2, 8), - 50); - -g_Map.log("Creating metal mines"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), - 0, - avoidClasses( - clWater, 4, - clForest, 1, - clPlayerTerritory, 0, - clGaia, 1, - clMetal, 10, - clRock, 5, - clHill, 1), - scaleByMapSize(4, 16), - 50); - -g_Map.log("Creating small decorative rocks"); -createObjectGroups( - new SimpleGroup([new SimpleObject(aRockMedium, 1, 3, 0, 1)], true), - 0, - avoidClasses( - clWater, 2, - clForest, 1, - clGaia, 1, - clPlayer, 8, - clBaseResource, 4, - clHill, 0), - scaleByMapSize(50, 800), - 20); - -g_Map.log("Creating large decorative rocks"); -createObjectGroups( - new SimpleGroup([ - new SimpleObject(aRockLarge, 1, 2, 0, 1), - new SimpleObject(aRockMedium, 1, 3, 0, 2) - ], - true), - 0, - avoidClasses( - clWater, 2, - clForest, 1, - clGaia, 1, - clPlayer, 8, - clBaseResource, 4, - clHill, 0), - scaleByMapSize(25, 400), - 50); - -g_Map.log("Creating small grass tufts"); -createObjectGroups( - new SimpleGroup([new SimpleObject(aBush1, 1, 2, 0, 1)]), - 0, - avoidClasses( - clWater, 4, - clHill, 2, - clPlayer, 8, - clGaia, 1, - clBaseResource, 4, - clDirt, 0), - scaleByMapSize(100, 500)); -Engine.SetProgress(70); - -g_Map.log("Creating large grass tufts"); + g_Map.log("Creating small decorative rocks"); createObjectGroups( - new SimpleGroup([ - new SimpleObject(aBush2, 2, 4, 0, 1.8, -Math.PI / 8, Math.PI / 8), - new SimpleObject(aBush1, 3, 6, 1.2, 2.5, -Math.PI / 8, Math.PI / 8) - ]), + new SimpleGroup([new SimpleObject(aRockMedium, 1, 3, 0, 1)], true), 0, avoidClasses( - clWater, 4, - clHill, 2, + clWater, 2, + clForest, 1, clGaia, 1, clPlayer, 8, clBaseResource, 4, - clDirt, 1, - clForest, 0), - scaleByMapSize(100, 500)); -Engine.SetProgress(85); + clHill, 0), + scaleByMapSize(50, 800), + 20); -g_Map.log("Creating bushes"); + g_Map.log("Creating large decorative rocks"); createObjectGroups( new SimpleGroup([ - new SimpleObject(aBush3, 1, 2, 0, 2), - new SimpleObject(aBush2, 2, 4, 0, 2) - ]), 0, + new SimpleObject(aRockLarge, 1, 2, 0, 1), + new SimpleObject(aRockMedium, 1, 3, 0, 2) + ], + true), + 0, + avoidClasses( + clWater, 2, + clForest, 1, + clGaia, 1, + clPlayer, 8, + clBaseResource, 4, + clHill, 0), + scaleByMapSize(25, 400), + 50); + + g_Map.log("Creating small grass tufts"); + createObjectGroups( + new SimpleGroup([new SimpleObject(aBush1, 1, 2, 0, 1)]), + 0, avoidClasses( clWater, 4, - clHill, 1, - clPlayerTerritory, 0, + clHill, 2, + clPlayer, 8, clGaia, 1, - clDirt, 1), + clBaseResource, 4, + clDirt, 0), scaleByMapSize(100, 500)); - -g_Map.log("Creating deer"); + yield 70; + + g_Map.log("Creating large grass tufts"); + createObjectGroups( + new SimpleGroup([ + new SimpleObject(aBush2, 2, 4, 0, 1.8, -Math.PI / 8, Math.PI / 8), + new SimpleObject(aBush1, 3, 6, 1.2, 2.5, -Math.PI / 8, Math.PI / 8) + ]), + 0, + avoidClasses( + clWater, 4, + clHill, 2, + clGaia, 1, + clPlayer, 8, + clBaseResource, 4, + clDirt, 1, + clForest, 0), + scaleByMapSize(100, 500)); + yield 85; + + g_Map.log("Creating bushes"); + createObjectGroups( + new SimpleGroup([ + new SimpleObject(aBush3, 1, 2, 0, 2), + new SimpleObject(aBush2, 2, 4, 0, 2) + ]), 0, + avoidClasses( + clWater, 4, + clHill, 1, + clPlayerTerritory, 0, + clGaia, 1, + clDirt, 1), + scaleByMapSize(100, 500)); + + g_Map.log("Creating deer"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oDeer, 5, 7, 0, 4)], true, clFood), + 0, + avoidClasses( + clWater, 4, + clForest, 0, + clPlayerTerritory, 0, + clGaia, 1, + clHill, 1, + clFood, 20), + 3 * numPlayers, + 20); + + g_Map.log("Creating boar"); + createObjectGroups( + new SimpleGroup([new SimpleObject(oBoar, 2, 4, 0, 4)], true, clFood), + 0, + avoidClasses( + clWater, 4, + clForest, 0, + clPlayerTerritory, 0, + clGaia, 1, + clHill, 1, + clRock, 4, + clMetal, 4, + clFood, 20), + 2 * numPlayers, + 20); + + g_Map.log("Creating tigers"); createObjectGroups( - new SimpleGroup([new SimpleObject(oDeer, 5, 7, 0, 4)], true, clFood), + new SimpleGroup([new SimpleObject(oTiger, 1, 1, 0, 4)], true, clFood), 0, avoidClasses( clWater, 4, @@ -436,13 +470,16 @@ clPlayerTerritory, 0, clGaia, 1, clHill, 1, + clRock, 4, + clMetal, 4, clFood, 20), - 3 * numPlayers, + 2 * numPlayers, 20); + yield 95; -g_Map.log("Creating boar"); + g_Map.log("Creating berry bush"); createObjectGroups( - new SimpleGroup([new SimpleObject(oBoar, 2, 4, 0, 4)], true, clFood), + new SimpleGroup([new SimpleObject(oBush, 5, 7, 0, 4)], true, clFood), 0, avoidClasses( clWater, 4, @@ -452,70 +489,39 @@ clHill, 1, clRock, 4, clMetal, 4, - clFood, 20), - 2 * numPlayers, - 20); - -g_Map.log("Creating tigers"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oTiger, 1, 1, 0, 4)], true, clFood), - 0, - avoidClasses( - clWater, 4, - clForest, 0, - clPlayerTerritory, 0, - clGaia, 1, - clHill, 1, - clRock, 4, - clMetal, 4, - clFood, 20), - 2 * numPlayers, - 20); -Engine.SetProgress(95); - -g_Map.log("Creating berry bush"); -createObjectGroups( - new SimpleGroup([new SimpleObject(oBush, 5, 7, 0, 4)], true, clFood), - 0, - avoidClasses( - clWater, 4, - clForest, 0, - clPlayerTerritory, 0, - clGaia, 1, - clHill, 1, - clRock, 4, - clMetal, 4, - clFood, 10), - randIntInclusive(1, 4) * numPlayers, - 20); + clFood, 10), + randIntInclusive(1, 4) * numPlayers, + 20); -g_Map.log("Creating fish"); -createObjectGroupsByAreas( - new SimpleGroup([new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood), - 0, - [avoidClasses(clFood, 15), stayClasses(clWater, 4)], - scaleByMapSize(20, 100), - 20, - [areaWater]); + g_Map.log("Creating fish"); + createObjectGroupsByAreas( + new SimpleGroup([new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood), + 0, + [avoidClasses(clFood, 15), stayClasses(clWater, 4)], + scaleByMapSize(20, 100), + 20, + [areaWater]); -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2, clHill, 4)); + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2, + clHill, 4)); -setSunColor(0.6, 0.6, 0.6); -setSunElevation(Math.PI/ 3); + setSunColor(0.6, 0.6, 0.6); + setSunElevation(Math.PI/ 3); -setWaterColor(0.424, 0.534, 0.639); -setWaterTint(0.369, 0.765, 0.745); -setWaterWaviness(1.0); -setWaterType("default"); -setWaterMurkiness(0.35); + setWaterColor(0.424, 0.534, 0.639); + setWaterTint(0.369, 0.765, 0.745); + setWaterWaviness(1.0); + setWaterType("default"); + setWaterMurkiness(0.35); -setFogFactor(0.03); -setFogThickness(0.2); + setFogFactor(0.03); + setFogThickness(0.2); -setPPEffect("hdr"); -setPPContrast(0.7); -setPPSaturation(0.65); -setPPBloom(0.6); + setPPEffect("hdr"); + setPPContrast(0.7); + setPPSaturation(0.65); + setPPBloom(0.6); -setSkySet("stratus"); -g_Map.ExportMap(); + setSkySet("stratus"); + return g_Map; +} Index: binaries/data/mods/public/maps/random/rivers.js =================================================================== --- binaries/data/mods/public/maps/random/rivers.js +++ binaries/data/mods/public/maps/random/rivers.js @@ -2,288 +2,298 @@ Engine.LoadLibrary("rmgen-common"); 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; -let tShore = g_Terrains.shore; -let tWater = g_Terrains.water; -if (currentBiome() == "generic/india") +function* GenerateMap() { - tShore = "tropic_dirt_b_plants"; - tWater = "tropic_dirt_b"; -} -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 oMetalSmall = g_Gaia.metalSmall; - -const aGrass = g_Decoratives.grass; -const aGrassShort = g_Decoratives.grassShort; -const aReeds = g_Decoratives.reeds; -const aLillies = g_Decoratives.lillies; -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 = -3; -const heightShallows = -1; -const heightLand = 1; - -const g_Map = new RandomMap(heightLand, tMainTerrain); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clShallow = g_Map.createTileClass(); - -const [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oFruitBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oTree1, - "count": 2 - }, - "Decoratives": { - "template": aGrassShort + 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; + let tShore = g_Terrains.shore; + let tWater = g_Terrains.water; + if (currentBiome() == "generic/india") + { + tShore = "tropic_dirt_b_plants"; + tWater = "tropic_dirt_b"; } -}); - -g_Map.log("Creating central lake"); -createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.075)), 0.7, 0.1, Infinity, mapCenter), - [ - new LayeredPainter([tShore, tWater], [1]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), - new TileClassPainter(clWater) - ]); - -g_Map.log("Creating rivers between opponents"); -const numRivers = isNomad() ? randIntInclusive(4, 8) : numPlayers; -const rivers = distributePointsOnCircle(numRivers, startAngle + Math.PI / numRivers, fractionToTiles(0.5), mapCenter)[0]; -for (let i = 0; i < numRivers; ++i) -{ - if (isNomad() ? randBool() : areAllies(playerIDs[i], playerIDs[(i + 1) % numPlayers])) - continue; - - const shallowLocation = randFloat(0.2, 0.7); - const shallowWidth = randFloat(0.12, 0.21); - - paintRiver({ - "parallel": true, - "start": rivers[i], - "end": mapCenter, - "width": scaleByMapSize(10, 30), - "fadeDist": 5, - "deviation": 0, - "heightLand": heightLand, - "heightRiverbed": heightSeaGround, - "minHeight": heightSeaGround, - "meanderShort": 10, - "meanderLong": 0, - "waterFunc": (position, height, riverFraction) => { - - clWater.add(position); - - const isShallow = height < heightShallows && - riverFraction > shallowLocation && - riverFraction < shallowLocation + shallowWidth; - - const newHeight = isShallow ? heightShallows : Math.max(height, heightSeaGround); - - if (g_Map.getHeight(position) < newHeight) - return; - - g_Map.setHeight(position, newHeight); - createTerrain(height >= 0 ? tShore : tWater).place(position); - - if (isShallow) - clShallow.add(position); + 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 oMetalSmall = g_Gaia.metalSmall; + + const aGrass = g_Decoratives.grass; + const aGrassShort = g_Decoratives.grassShort; + const aReeds = g_Decoratives.reeds; + const aLillies = g_Decoratives.lillies; + 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 = -3; + const heightShallows = -1; + const heightLand = 1; + + global.g_Map = new RandomMap(heightLand, tMainTerrain); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clShallow = g_Map.createTileClass(); + + const [playerIDs, playerPosition, playerAngle, startAngle] = + playerPlacementCircle(fractionToTiles(0.35)); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oFruitBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oTree1, + "count": 2 + }, + "Decoratives": { + "template": aGrassShort } }); + + g_Map.log("Creating central lake"); + createArea( + new ClumpPlacer(diskArea(fractionToTiles(0.075)), 0.7, 0.1, Infinity, mapCenter), + [ + new LayeredPainter([tShore, tWater], [1]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), + new TileClassPainter(clWater) + ]); + + g_Map.log("Creating rivers between opponents"); + const numRivers = isNomad() ? randIntInclusive(4, 8) : numPlayers; + const rivers = distributePointsOnCircle(numRivers, startAngle + Math.PI / numRivers, + fractionToTiles(0.5), mapCenter)[0]; + for (let i = 0; i < numRivers; ++i) + { + if (isNomad() ? randBool() : areAllies(playerIDs[i], playerIDs[(i + 1) % numPlayers])) + continue; + + const shallowLocation = randFloat(0.2, 0.7); + const shallowWidth = randFloat(0.12, 0.21); + + paintRiver({ + "parallel": true, + "start": rivers[i], + "end": mapCenter, + "width": scaleByMapSize(10, 30), + "fadeDist": 5, + "deviation": 0, + "heightLand": heightLand, + "heightRiverbed": heightSeaGround, + "minHeight": heightSeaGround, + "meanderShort": 10, + "meanderLong": 0, + "waterFunc": (position, height, riverFraction) => { + + clWater.add(position); + + const isShallow = height < heightShallows && + riverFraction > shallowLocation && + riverFraction < shallowLocation + shallowWidth; + + const newHeight = isShallow ? heightShallows : Math.max(height, heightSeaGround); + + if (g_Map.getHeight(position) < newHeight) + return; + + g_Map.setHeight(position, newHeight); + createTerrain(height >= 0 ? tShore : tWater).place(position); + + if (isShallow) + clShallow.add(position); + } + }); + } + yield 40; + + createBumps(avoidClasses(clWater, 2, clPlayer, 20)); + + if (randBool()) + createHills([tMainTerrain, tCliff, tHill], avoidClasses(clPlayer, 20, clHill, 15, clWater, 2), + clHill, scaleByMapSize(3, 15)); + else + createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 15, clWater, 2), clHill, + scaleByMapSize(3, 15)); + + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + createDefaultForests( + [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], + avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 2), + clForest, + forestTrees); + + yield 50; + + g_Map.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); + + g_Map.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); + yield 55; + + g_Map.log("Creating metal mines"); + createBalancedMetalMines( + oMetalSmall, + oMetalLarge, + clMetal, + avoidClasses(clWater, 3, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1) + ); + + g_Map.log("Creating stone mines"); + createBalancedStoneMines( + oStoneSmall, + oStoneLarge, + clRock, + avoidClasses(clWater, 3, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1, clMetal, 10) + ); + + yield 65; + + let planetm = 1; + + if (currentBiome() == "generic/india") + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13) + ], + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); + + createDecoration( + [ + [new SimpleObject(aReeds, 1, 3, 0, 1)], + [new SimpleObject(aLillies, 1, 2, 0, 1)] + ], + [ + scaleByMapAreaAbsolute(800), + scaleByMapAreaAbsolute(800) + ], + stayClasses(clShallow, 0)); + + yield 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); + + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 25 * numPlayers + ], + [avoidClasses(clFood, 20), stayClasses(clWater, 6)], + clFood); + + yield 85; + + 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, clFood, 2, + clHill, 4)); + + setWaterWaviness(3.0); + setWaterType("lake"); + + return g_Map; } -Engine.SetProgress(40); - -createBumps(avoidClasses(clWater, 2, clPlayer, 20)); - -if (randBool()) - createHills([tMainTerrain, tCliff, tHill], avoidClasses(clPlayer, 20, clHill, 15, clWater, 2), clHill, scaleByMapSize(3, 15)); -else - createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 15, clWater, 2), clHill, scaleByMapSize(3, 15)); - -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); -createDefaultForests( - [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], - avoidClasses(clPlayer, 20, clForest, 17, clHill, 0, clWater, 2), - clForest, - forestTrees); - -Engine.SetProgress(50); - -g_Map.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); - -g_Map.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); - -g_Map.log("Creating metal mines"); -createBalancedMetalMines( - oMetalSmall, - oMetalLarge, - clMetal, - avoidClasses(clWater, 3, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1) -); - -g_Map.log("Creating stone mines"); -createBalancedStoneMines( - oStoneSmall, - oStoneLarge, - clRock, - avoidClasses(clWater, 3, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1, clMetal, 10) -); - -Engine.SetProgress(65); - -let planetm = 1; - -if (currentBiome() == "generic/india") - 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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13) - ], - avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); - -createDecoration( - [ - [new SimpleObject(aReeds, 1, 3, 0, 1)], - [new SimpleObject(aLillies, 1, 2, 0, 1)] - ], - [ - scaleByMapAreaAbsolute(800), - scaleByMapAreaAbsolute(800) - ], - stayClasses(clShallow, 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); - -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 25 * numPlayers - ], - [avoidClasses(clFood, 20), stayClasses(clWater, 6)], - clFood); - -Engine.SetProgress(85); - -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, clFood, 2, clHill, 4)); - -setWaterWaviness(3.0); -setWaterType("lake"); - -g_Map.ExportMap(); Index: binaries/data/mods/public/maps/random/saharan_oases.js =================================================================== --- binaries/data/mods/public/maps/random/saharan_oases.js +++ binaries/data/mods/public/maps/random/saharan_oases.js @@ -1,241 +1,248 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tPrimary = "desert_sand_dunes_100"; -const tCity = "desert_city_tile"; -const tCityPlaza = "desert_city_tile_plaza"; -const tFineSand = "desert_sand_smooth"; -const tDirt1 = "desert_dirt_rough_2"; -const tSandDunes = "desert_sand_dunes_50"; -const tDirt2 = "desert_dirt_rough"; -const tDirtCracks = "desert_dirt_cracks"; -const tShore = "desert_shore_stones"; -const tWaterDeep = "desert_shore_stones_wet"; -const tLush = "desert_grass_a"; -const tSLush = "desert_grass_a_sand"; - -const oGrapeBush = "gaia/fruit/grapes"; -const oCamel = "gaia/fauna_camel"; -const oGazelle = "gaia/fauna_gazelle"; -const oGoat = "gaia/fauna_goat"; -const oStoneLarge = "gaia/rock/badlands_large"; -const oStoneSmall = "gaia/rock/desert_small"; -const oMetalLarge = "gaia/ore/desert_large"; -const oDatePalm = "gaia/tree/date_palm"; -const oSDatePalm = "gaia/tree/cretan_date_palm_short"; -const oWoodTreasure = "gaia/treasure/wood"; -const oFoodTreasure = "gaia/treasure/food_bin"; - -const aBush1 = "actor|props/flora/bush_desert_a.xml"; -const aBush2 = "actor|props/flora/bush_desert_dry_a.xml"; -const aBush3 = "actor|props/flora/bush_medit_sm_dry.xml"; -const aBush4 = "actor|props/flora/plant_desert_a.xml"; -const aDecorativeRock = "actor|geology/stone_desert_med.xml"; - -const pForest = [tLush + TERRAIN_SEPARATOR + oDatePalm, tLush + TERRAIN_SEPARATOR + oSDatePalm, tLush]; - -const heightLand = 1; -const heightOffsetOasis = -3; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clTreasure = g_Map.createTileClass(); - -const [playerIDs, playerPosition, playerAngle] = playerPlacementCircle(fractionToTiles(0.35)); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tCityPlaza, - "innerTerrain": tCity - }, - "StartingAnimal": { - }, - "Berries": { - "template": oGrapeBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oSDatePalm - }, - "Decoratives": { - "template": aBush1 - } -}); -Engine.SetProgress(30); - -g_Map.log("Creating oases"); -const oasisRadius = fractionToTiles(scaleByMapSize(0.19, 0.22)); -for (let i = 0; i < numPlayers; ++i) +function* GenerateMap() { - const position = Vector2D.add(mapCenter, new Vector2D(oasisRadius, 0).rotate(-playerAngle[i])); - createArea( - new ClumpPlacer(diskArea(scaleByMapSize(16, 60)) * 0.185, 0.6, 0.15, 0, position), - [ - new LayeredPainter( - [tSLush ,[tLush, pForest], [tLush, pForest], tShore, tShore, tWaterDeep], - [2, 2, 1, 3, 1]), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetOasis, 10), - new TileClassPainter(clWater) - ]); + const tPrimary = "desert_sand_dunes_100"; + const tCity = "desert_city_tile"; + const tCityPlaza = "desert_city_tile_plaza"; + const tFineSand = "desert_sand_smooth"; + const tDirt1 = "desert_dirt_rough_2"; + const tSandDunes = "desert_sand_dunes_50"; + const tDirt2 = "desert_dirt_rough"; + const tDirtCracks = "desert_dirt_cracks"; + const tShore = "desert_shore_stones"; + const tWaterDeep = "desert_shore_stones_wet"; + const tLush = "desert_grass_a"; + const tSLush = "desert_grass_a_sand"; + + const oGrapeBush = "gaia/fruit/grapes"; + const oCamel = "gaia/fauna_camel"; + const oGazelle = "gaia/fauna_gazelle"; + const oGoat = "gaia/fauna_goat"; + const oStoneLarge = "gaia/rock/badlands_large"; + const oStoneSmall = "gaia/rock/desert_small"; + const oMetalLarge = "gaia/ore/desert_large"; + const oDatePalm = "gaia/tree/date_palm"; + const oSDatePalm = "gaia/tree/cretan_date_palm_short"; + const oWoodTreasure = "gaia/treasure/wood"; + const oFoodTreasure = "gaia/treasure/food_bin"; + + const aBush1 = "actor|props/flora/bush_desert_a.xml"; + const aBush2 = "actor|props/flora/bush_desert_dry_a.xml"; + const aBush3 = "actor|props/flora/bush_medit_sm_dry.xml"; + const aBush4 = "actor|props/flora/plant_desert_a.xml"; + const aDecorativeRock = "actor|geology/stone_desert_med.xml"; + + const pForest = [tLush + TERRAIN_SEPARATOR + oDatePalm, tLush + TERRAIN_SEPARATOR + oSDatePalm, + tLush]; + + const heightLand = 1; + const heightOffsetOasis = -3; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clTreasure = g_Map.createTileClass(); + + const [playerIDs, playerPosition, playerAngle] = playerPlacementCircle(fractionToTiles(0.35)); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tCityPlaza, + "innerTerrain": tCity + }, + "StartingAnimal": { + }, + "Berries": { + "template": oGrapeBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oSDatePalm + }, + "Decoratives": { + "template": aBush1 + } + }); + yield 30; + + g_Map.log("Creating oases"); + const oasisRadius = fractionToTiles(scaleByMapSize(0.19, 0.22)); + for (let i = 0; i < numPlayers; ++i) + { + const position = Vector2D.add(mapCenter, new Vector2D(oasisRadius, 0).rotate(-playerAngle[i])); + createArea( + new ClumpPlacer(diskArea(scaleByMapSize(16, 60)) * 0.185, 0.6, 0.15, 0, position), + [ + new LayeredPainter( + [tSLush ,[tLush, pForest], [tLush, pForest], tShore, tShore, tWaterDeep], + [2, 2, 1, 3, 1]), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetOasis, 10), + new TileClassPainter(clWater) + ]); + } + yield 50; + + g_Map.log("Creating grass patches"); + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new LayeredPainter( + [[tDirt1, tSandDunes], [tSandDunes, tDirt2], [tDirt2, tDirt1]], + [1, 1] + ), + new TileClassPainter(clDirt) + ], + avoidClasses(clForest, 0, clPlayer, 0, clWater, 1, clDirt, 5), + scaleByMapSize(15, 45)); + yield 55; + + g_Map.log("Creating dirt patches"); + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new LayeredPainter( + [[tDirt2, tDirtCracks], [tDirt2, tFineSand], [tDirtCracks, tFineSand]], + [1, 1] + ), + new TileClassPainter(clDirt) + ], + avoidClasses(clForest, 0, clDirt, 5, clPlayer, 0, clWater, 1), + scaleByMapSize(15, 45)); + yield 60; + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 26, clRock, 10, clWater, 1), + 2*scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 26, clRock, 10, clWater, 1), + 2*scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 26, clMetal, 10, clRock, 5, clWater, 1), + 2*scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aDecorativeRock, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clWater, 1, clForest, 0, clPlayer, 0), + scaleByMapSize(16, 262), 50 + ); + + g_Map.log("Creating shrubs"); + group = new SimpleGroup( + [new SimpleObject(aBush2, 1,2, 0,1), new SimpleObject(aBush1, 1,3, 0,2), + new SimpleObject(aBush4, 1,2, 0,1), new SimpleObject(aBush3, 1,3, 0,2)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clWater, 1, clPlayer, 0), + scaleByMapSize(10, 100), 50 + ); + + g_Map.log("Creating small decorative rocks on mines"); + group = new SimpleGroup( + [new SimpleObject(aDecorativeRock, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + stayClasses(clRock, 0), + 5*scaleByMapSize(16, 262), 50 + ); + + group = new SimpleGroup( + [new SimpleObject(aDecorativeRock, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + stayClasses(clMetal, 0), + 5*scaleByMapSize(16, 262), 50 + ); + + g_Map.log("Creating gazelles"); + group = new SimpleGroup([new SimpleObject(oGazelle, 5,7, 0,4)], true, clFood); + createObjectGroupsDeprecated(group, 0, + borderClasses(clWater, 8, 5), + 6*scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating goats"); + group = new SimpleGroup([new SimpleObject(oGoat, 2,4, 0,3)], true, clFood); + createObjectGroupsDeprecated(group, 0, + borderClasses(clWater, 8, 5), + 5*scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating treasures"); + group = new SimpleGroup([new SimpleObject(oFoodTreasure, 1,1, 0,2)], true, clTreasure); + createObjectGroupsDeprecated(group, 0, + borderClasses(clWater, 8, 5), + 3*scaleByMapSize(5,20), 50 + ); + + group = new SimpleGroup([new SimpleObject(oWoodTreasure, 1,1, 0,2)], true, clTreasure); + createObjectGroupsDeprecated(group, 0, + borderClasses(clWater, 8, 5), + 3*scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating camels"); + group = new SimpleGroup([new SimpleObject(oCamel, 2,4, 0,2)], true, clFood); + createObjectGroupsDeprecated(group, 0, + borderClasses(clWater, 14, 5), + 5*scaleByMapSize(5,20), 50 + ); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2, + clTreasure, 2)); + + setSkySet("sunny"); + setSunColor(0.746, 0.718, 0.539); + setWaterColor(0, 0.227, 0.843); + setWaterTint(0, 0.545, 0.859); + setWaterWaviness(1.0); + setWaterType("clap"); + setWaterMurkiness(0.5); + + return g_Map; } -Engine.SetProgress(50); - -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - [ - new LayeredPainter( - [[tDirt1, tSandDunes], [tSandDunes, tDirt2], [tDirt2, tDirt1]], - [1, 1] - ), - new TileClassPainter(clDirt) - ], - avoidClasses(clForest, 0, clPlayer, 0, clWater, 1, clDirt, 5), - scaleByMapSize(15, 45)); -Engine.SetProgress(55); - -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - [ - new LayeredPainter( - [[tDirt2, tDirtCracks], [tDirt2, tFineSand], [tDirtCracks, tFineSand]], - [1, 1] - ), - new TileClassPainter(clDirt) - ], - avoidClasses(clForest, 0, clDirt, 5, clPlayer, 0, clWater, 1), - scaleByMapSize(15, 45)); -Engine.SetProgress(60); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 26, clRock, 10, clWater, 1), - 2*scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 26, clRock, 10, clWater, 1), - 2*scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 26, clMetal, 10, clRock, 5, clWater, 1), - 2*scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aDecorativeRock, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clWater, 1, clForest, 0, clPlayer, 0), - scaleByMapSize(16, 262), 50 -); - -g_Map.log("Creating shrubs"); -group = new SimpleGroup( - [new SimpleObject(aBush2, 1,2, 0,1), new SimpleObject(aBush1, 1,3, 0,2), new SimpleObject(aBush4, 1,2, 0,1), new SimpleObject(aBush3, 1,3, 0,2)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clWater, 1, clPlayer, 0), - scaleByMapSize(10, 100), 50 -); - -g_Map.log("Creating small decorative rocks on mines"); -group = new SimpleGroup( - [new SimpleObject(aDecorativeRock, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - stayClasses(clRock, 0), - 5*scaleByMapSize(16, 262), 50 -); - -group = new SimpleGroup( - [new SimpleObject(aDecorativeRock, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - stayClasses(clMetal, 0), - 5*scaleByMapSize(16, 262), 50 -); - -g_Map.log("Creating gazelles"); -group = new SimpleGroup([new SimpleObject(oGazelle, 5,7, 0,4)], true, clFood); -createObjectGroupsDeprecated(group, 0, - borderClasses(clWater, 8, 5), - 6*scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating goats"); -group = new SimpleGroup([new SimpleObject(oGoat, 2,4, 0,3)], true, clFood); -createObjectGroupsDeprecated(group, 0, - borderClasses(clWater, 8, 5), - 5*scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating treasures"); -group = new SimpleGroup([new SimpleObject(oFoodTreasure, 1,1, 0,2)], true, clTreasure); -createObjectGroupsDeprecated(group, 0, - borderClasses(clWater, 8, 5), - 3*scaleByMapSize(5,20), 50 -); - -group = new SimpleGroup([new SimpleObject(oWoodTreasure, 1,1, 0,2)], true, clTreasure); -createObjectGroupsDeprecated(group, 0, - borderClasses(clWater, 8, 5), - 3*scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating camels"); -group = new SimpleGroup([new SimpleObject(oCamel, 2,4, 0,2)], true, clFood); -createObjectGroupsDeprecated(group, 0, - borderClasses(clWater, 14, 5), - 5*scaleByMapSize(5,20), 50 -); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2, clTreasure, 2)); - -setSkySet("sunny"); -setSunColor(0.746, 0.718, 0.539); -setWaterColor(0, 0.227, 0.843); -setWaterTint(0, 0.545, 0.859); -setWaterWaviness(1.0); -setWaterType("clap"); -setWaterMurkiness(0.5); - -g_Map.ExportMap(); Index: binaries/data/mods/public/maps/random/sahel.js =================================================================== --- binaries/data/mods/public/maps/random/sahel.js +++ binaries/data/mods/public/maps/random/sahel.js @@ -1,241 +1,246 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tPrimary = "savanna_grass_a"; -const tGrass2 = "savanna_grass_b"; -const tGrass3 = "savanna_shrubs_a"; -const tDirt1 = "savanna_dirt_rocks_a"; -const tDirt2 = "savanna_dirt_rocks_b"; -const tDirt3 = "savanna_dirt_rocks_c"; -const tDirt4 = "savanna_dirt_b"; -const tCityTiles = "savanna_tile_a"; -const tShore = "savanna_riparian_bank"; -const tWater = "savanna_riparian_wet"; - -const oBaobab = "gaia/tree/baobab"; -const oBerryBush = "gaia/fruit/berry_05"; -const oGazelle = "gaia/fauna_gazelle"; -const oGiraffe = "gaia/fauna_giraffe"; -const oGiraffeInfant = "gaia/fauna_giraffe_infant"; -const oElephant = "gaia/fauna_elephant_african_bush"; -const oElephantInfant = "gaia/fauna_elephant_african_infant"; -const oLion = "gaia/fauna_lion"; -const oLioness = "gaia/fauna_lioness"; -const oZebra = "gaia/fauna_zebra"; -const oStoneSmall = "gaia/rock/savanna_small"; -const oMetalLarge = "gaia/ore/savanna_large"; - -const aBush = "actor|props/flora/bush_medit_sm_dry.xml"; -const aRock = "actor|geology/stone_savanna_med.xml"; - -const heightSeaGround = -5; -const heightLand = 1; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); - -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tCityTiles, - "innerTerrain": tCityTiles - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { - "template": oMetalLarge - }, - { - "type": "stone_formation", - "template": oStoneSmall, - "terrain": tDirt4 - } - ] - }, - "Trees": { - "template": oBaobab, - "count": scaleByMapSize(2, 7), - "minDistGroup": 2, - "maxDistGroup": 7 - } - // No decoratives -}); -Engine.SetProgress(20); - -g_Map.log("Creating big patches"); -const patches = [tGrass2, tGrass3]; -for (let i = 0; i < patches.length; i++) - createAreas( - new ChainPlacer(Math.floor(scaleByMapSize(3, 6)), Math.floor(scaleByMapSize(10, 20)), Math.floor(scaleByMapSize(15, 60)), Infinity), - new TerrainPainter(patches[i]), - avoidClasses(clPlayer, 10), - scaleByMapSize(5, 20)); - -g_Map.log("Creating small patches"); -for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) - for (const patch of [tDirt1, tDirt2, tDirt3]) - createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, Infinity), - new TerrainPainter(patch), - avoidClasses(clPlayer, 12), - scaleByMapSize(4, 15)); - -g_Map.log("Creating water holes"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), Math.floor(scaleByMapSize(20, 60)), Infinity), - [ - new LayeredPainter([tShore, tWater], [1]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 7), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 24), - scaleByMapSize(1, 3)); -Engine.SetProgress(55); - -g_Map.log("Creating stone mines"); -for (let i = 0; i < scaleByMapSize(12,30); ++i) +function* GenerateMap() { - const position = new Vector2D(randIntExclusive(0, mapSize), randIntExclusive(0, mapSize)); - if (avoidClasses(clPlayer, 30, clRock, 25, clWater, 10).allows(position)) + const tPrimary = "savanna_grass_a"; + const tGrass2 = "savanna_grass_b"; + const tGrass3 = "savanna_shrubs_a"; + const tDirt1 = "savanna_dirt_rocks_a"; + const tDirt2 = "savanna_dirt_rocks_b"; + const tDirt3 = "savanna_dirt_rocks_c"; + const tDirt4 = "savanna_dirt_b"; + const tCityTiles = "savanna_tile_a"; + const tShore = "savanna_riparian_bank"; + const tWater = "savanna_riparian_wet"; + + const oBaobab = "gaia/tree/baobab"; + const oBerryBush = "gaia/fruit/berry_05"; + const oGazelle = "gaia/fauna_gazelle"; + const oGiraffe = "gaia/fauna_giraffe"; + const oGiraffeInfant = "gaia/fauna_giraffe_infant"; + const oElephant = "gaia/fauna_elephant_african_bush"; + const oElephantInfant = "gaia/fauna_elephant_african_infant"; + const oLion = "gaia/fauna_lion"; + const oLioness = "gaia/fauna_lioness"; + const oZebra = "gaia/fauna_zebra"; + const oStoneSmall = "gaia/rock/savanna_small"; + const oMetalLarge = "gaia/ore/savanna_large"; + + const aBush = "actor|props/flora/bush_medit_sm_dry.xml"; + const aRock = "actor|geology/stone_savanna_med.xml"; + + const heightSeaGround = -5; + const heightLand = 1; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tCityTiles, + "innerTerrain": tCityTiles + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { + "template": oMetalLarge + }, + { + "type": "stone_formation", + "template": oStoneSmall, + "terrain": tDirt4 + } + ] + }, + "Trees": { + "template": oBaobab, + "count": scaleByMapSize(2, 7), + "minDistGroup": 2, + "maxDistGroup": 7 + } + // No decoratives + }); + yield 20; + + g_Map.log("Creating big patches"); + const patches = [tGrass2, tGrass3]; + for (let i = 0; i < patches.length; i++) + createAreas( + new ChainPlacer(Math.floor(scaleByMapSize(3, 6)), Math.floor(scaleByMapSize(10, 20)), + Math.floor(scaleByMapSize(15, 60)), Infinity), + new TerrainPainter(patches[i]), + avoidClasses(clPlayer, 10), + scaleByMapSize(5, 20)); + + g_Map.log("Creating small patches"); + for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) + for (const patch of [tDirt1, tDirt2, tDirt3]) + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, Infinity), + new TerrainPainter(patch), + avoidClasses(clPlayer, 12), + scaleByMapSize(4, 15)); + + g_Map.log("Creating water holes"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), Math.floor(scaleByMapSize(20, 60)), + Infinity), + [ + new LayeredPainter([tShore, tWater], [1]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 7), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 24), + scaleByMapSize(1, 3)); + yield 55; + + g_Map.log("Creating stone mines"); + for (let i = 0; i < scaleByMapSize(12,30); ++i) { - createStoneMineFormation(position, oStoneSmall, tDirt4); - clRock.add(position); + const position = new Vector2D(randIntExclusive(0, mapSize), randIntExclusive(0, mapSize)); + if (avoidClasses(clPlayer, 30, clRock, 25, clWater, 10).allows(position)) + { + createStoneMineFormation(position, oStoneSmall, tDirt4); + clRock.add(position); + } } -} -g_Map.log("Creating metal mines"); -let group = new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clPlayer, 20, clMetal, 10, clRock, 8, clWater, 4), - scaleByMapSize(2,8), 100 -); - -Engine.SetProgress(65); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aRock, 1,3, 0,3)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clPlayer, 7, clWater, 1), - scaleByMapSize(200, 1200), 1 -); - -Engine.SetProgress(70); - -g_Map.log("Creating gazelle"); -group = new SimpleGroup( - [new SimpleObject(oGazelle, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), - scaleByMapSize(4,12), 50 -); - -g_Map.log("Creating zebra"); -group = new SimpleGroup( - [new SimpleObject(oZebra, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), - scaleByMapSize(4,12), 50 -); - -g_Map.log("Creating giraffe"); -group = new SimpleGroup( - [new SimpleObject(oGiraffe, 2,4, 0,4), new SimpleObject(oGiraffeInfant, 0,2, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), - scaleByMapSize(4,12), 50 -); - -g_Map.log("Creating elephants"); -group = new SimpleGroup( - [new SimpleObject(oElephant, 2,4, 0,4), new SimpleObject(oElephantInfant, 0,2, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), - scaleByMapSize(4,12), 50 -); - -g_Map.log("Creating lions"); -group = new SimpleGroup( - [new SimpleObject(oLion, 0,1, 0,4), new SimpleObject(oLioness, 2,3, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), - scaleByMapSize(4,12), 50 -); - -g_Map.log("Creating berry bush"); -group = new SimpleGroup( - [new SimpleObject(oBerryBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clPlayer, 20, clFood, 12, clRock, 7, clMetal, 6), - randIntInclusive(1, 4) * numPlayers + 2, 50 -); - -Engine.SetProgress(85); - -createStragglerTrees( - [oBaobab], - avoidClasses(clForest, 1, clPlayer, 20, clMetal, 6, clRock, 7, clWater, 1), - clForest, - scaleByMapSize(70, 500)); - -g_Map.log("Creating large grass tufts"); -group = new SimpleGroup( - [new SimpleObject(aBush, 2,4, 0,1.8, -Math.PI / 8, Math.PI / 8)] -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clPlayer, 2, clForest, 0), - scaleByMapSize(100, 1200) -); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); - -setSunColor(0.87451, 0.847059, 0.647059); -setWaterColor(0.741176, 0.592157, 0.27451); -setWaterTint(0.741176, 0.592157, 0.27451); -setWaterWaviness(2.0); -setWaterType("clap"); -setWaterMurkiness(0.835938); - -setAmbientColor(0.447059, 0.509804, 0.54902); - -setFogFactor(0.25); -setFogThickness(0.15); -setFogColor(0.847059, 0.737255, 0.482353); - -setPPEffect("hdr"); -setPPContrast(0.57031); -setPPBloom(0.34); - -g_Map.ExportMap(); + g_Map.log("Creating metal mines"); + let group = new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clPlayer, 20, clMetal, 10, clRock, 8, clWater, 4), + scaleByMapSize(2,8), 100 + ); + + yield 65; + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aRock, 1,3, 0,3)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clPlayer, 7, clWater, 1), + scaleByMapSize(200, 1200), 1 + ); + + yield 70; + + g_Map.log("Creating gazelle"); + group = new SimpleGroup( + [new SimpleObject(oGazelle, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), + scaleByMapSize(4,12), 50 + ); + + g_Map.log("Creating zebra"); + group = new SimpleGroup( + [new SimpleObject(oZebra, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), + scaleByMapSize(4,12), 50 + ); + + g_Map.log("Creating giraffe"); + group = new SimpleGroup( + [new SimpleObject(oGiraffe, 2,4, 0,4), new SimpleObject(oGiraffeInfant, 0,2, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), + scaleByMapSize(4,12), 50 + ); + + g_Map.log("Creating elephants"); + group = new SimpleGroup( + [new SimpleObject(oElephant, 2,4, 0,4), new SimpleObject(oElephantInfant, 0,2, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), + scaleByMapSize(4,12), 50 + ); + + g_Map.log("Creating lions"); + group = new SimpleGroup( + [new SimpleObject(oLion, 0,1, 0,4), new SimpleObject(oLioness, 2,3, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 1, clPlayer, 20, clFood, 11), + scaleByMapSize(4,12), 50 + ); + + g_Map.log("Creating berry bush"); + group = new SimpleGroup( + [new SimpleObject(oBerryBush, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clPlayer, 20, clFood, 12, clRock, 7, clMetal, 6), + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + + yield 85; + + createStragglerTrees( + [oBaobab], + avoidClasses(clForest, 1, clPlayer, 20, clMetal, 6, clRock, 7, clWater, 1), + clForest, + scaleByMapSize(70, 500)); + + g_Map.log("Creating large grass tufts"); + group = new SimpleGroup( + [new SimpleObject(aBush, 2,4, 0,1.8, -Math.PI / 8, Math.PI / 8)] + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clPlayer, 2, clForest, 0), + scaleByMapSize(100, 1200) + ); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); + + setSunColor(0.87451, 0.847059, 0.647059); + setWaterColor(0.741176, 0.592157, 0.27451); + setWaterTint(0.741176, 0.592157, 0.27451); + setWaterWaviness(2.0); + setWaterType("clap"); + setWaterMurkiness(0.835938); + + setAmbientColor(0.447059, 0.509804, 0.54902); + + setFogFactor(0.25); + setFogThickness(0.15); + setFogColor(0.847059, 0.737255, 0.482353); + + setPPEffect("hdr"); + setPPContrast(0.57031); + setPPBloom(0.34); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/sahel_watering_holes.js =================================================================== --- binaries/data/mods/public/maps/random/sahel_watering_holes.js +++ binaries/data/mods/public/maps/random/sahel_watering_holes.js @@ -1,386 +1,399 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tGrass = "savanna_grass_a"; -const tForestFloor = "savanna_forestfloor_a"; -const tCliff = "savanna_cliff_b"; -const tDirtRocksA = "savanna_dirt_rocks_c"; -const tDirtRocksB = "savanna_dirt_rocks_a"; -const tDirtRocksC = "savanna_dirt_rocks_b"; -const tHill = "savanna_cliff_a"; -const tRoad = "savanna_tile_a_red"; -const tRoadWild = "savanna_tile_a_red"; -const tGrassPatch = "savanna_grass_b"; -const tShore = "savanna_riparian_bank"; -const tWater = "savanna_riparian_wet"; - -const oBaobab = "gaia/tree/baobab"; -const oFig = "gaia/fruit/date"; -const oBerryBush = "gaia/fruit/berry_01"; -const oWildebeest = "gaia/fauna_wildebeest"; -const oFish = "gaia/fish/generic"; -const oGazelle = "gaia/fauna_gazelle"; -const oElephant = "gaia/fauna_elephant_african_bush"; -const oGiraffe = "gaia/fauna_giraffe"; -const oZebra = "gaia/fauna_zebra"; -const oStoneLarge = "gaia/rock/desert_large"; -const oStoneSmall = "gaia/rock/savanna_small"; -const oMetalLarge = "gaia/ore/savanna_large"; - -const aGrass = "actor|props/flora/grass_savanna.xml"; -const aGrassShort = "actor|props/flora/grass_medit_field.xml"; -const aRockLarge = "actor|geology/stone_savanna_med.xml"; -const aRockMedium = "actor|geology/stone_savanna_med.xml"; -const aBushMedium = "actor|props/flora/bush_desert_dry_a.xml"; -const aBushSmall = "actor|props/flora/bush_dry_a.xml"; - -const pForest = [tForestFloor + TERRAIN_SEPARATOR + oBaobab, tForestFloor + TERRAIN_SEPARATOR + oBaobab, tForestFloor]; - -const heightSeaGround = -4; -const heightShallows = -2; -const heightLand = 3; -const heightHill = 35; -const heightOffsetBump = 2; - -const g_Map = new RandomMap(heightLand, tGrass); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clShallows = g_Map.createTileClass(); - -const [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oBaobab, - "count": 5 - }, - "Decoratives": { - "template": aGrassShort +function* GenerateMap() +{ + const tGrass = "savanna_grass_a"; + const tForestFloor = "savanna_forestfloor_a"; + const tCliff = "savanna_cliff_b"; + const tDirtRocksA = "savanna_dirt_rocks_c"; + const tDirtRocksB = "savanna_dirt_rocks_a"; + const tDirtRocksC = "savanna_dirt_rocks_b"; + const tHill = "savanna_cliff_a"; + const tRoad = "savanna_tile_a_red"; + const tRoadWild = "savanna_tile_a_red"; + const tGrassPatch = "savanna_grass_b"; + const tShore = "savanna_riparian_bank"; + const tWater = "savanna_riparian_wet"; + + const oBaobab = "gaia/tree/baobab"; + const oFig = "gaia/fruit/date"; + const oBerryBush = "gaia/fruit/berry_01"; + const oWildebeest = "gaia/fauna_wildebeest"; + const oFish = "gaia/fish/generic"; + const oGazelle = "gaia/fauna_gazelle"; + const oElephant = "gaia/fauna_elephant_african_bush"; + const oGiraffe = "gaia/fauna_giraffe"; + const oZebra = "gaia/fauna_zebra"; + const oStoneLarge = "gaia/rock/desert_large"; + const oStoneSmall = "gaia/rock/savanna_small"; + const oMetalLarge = "gaia/ore/savanna_large"; + + const aGrass = "actor|props/flora/grass_savanna.xml"; + const aGrassShort = "actor|props/flora/grass_medit_field.xml"; + const aRockLarge = "actor|geology/stone_savanna_med.xml"; + const aRockMedium = "actor|geology/stone_savanna_med.xml"; + const aBushMedium = "actor|props/flora/bush_desert_dry_a.xml"; + const aBushSmall = "actor|props/flora/bush_dry_a.xml"; + + const pForest = [tForestFloor + TERRAIN_SEPARATOR + oBaobab, + tForestFloor + TERRAIN_SEPARATOR + oBaobab, tForestFloor]; + + const heightSeaGround = -4; + const heightShallows = -2; + const heightLand = 3; + const heightHill = 35; + const heightOffsetBump = 2; + + global.g_Map = new RandomMap(heightLand, tGrass); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clShallows = g_Map.createTileClass(); + + const [playerIDs, playerPosition, playerAngle, startAngle] = + playerPlacementCircle(fractionToTiles(0.35)); + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oBaobab, + "count": 5 + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 20; + + g_Map.log("Creating rivers"); + const riverStart = distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, + fractionToTiles(0.15), mapCenter)[0]; + const riverEnd = distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, + fractionToTiles(0.49), mapCenter)[0]; + + for (let i = 0; i < numPlayers; ++i) + { + const neighborID = (i + 1) % numPlayers; + + // Lake near the center + createArea( + new ClumpPlacer(diskArea(scaleByMapSize(5, 30)), 0.95, 0.6, Infinity, riverStart[i]), + [ + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 5)); + + // River between the players + createArea( + new PathPlacer(riverStart[i], riverEnd[i], scaleByMapSize(10, 50), 0.2, + 3 * scaleByMapSize(1, 4), 0.2, 0.05), + [ + new LayeredPainter([tShore, tWater, tWater], [1, 3]), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 5)); + + // Lake near the map border + createArea( + new ClumpPlacer(diskArea(scaleByMapSize(5, 22)), 0.95, 0.6, Infinity, riverEnd[i]), + [ + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 5)); + + // Shallows between neighbors + createPassage({ + "start": playerPosition[i], + "end": playerPosition[neighborID], + "startWidth": 10, + "endWidth": 10, + "smoothWidth": 4, + "startHeight": heightShallows, + "endHeight": heightShallows, + "constraints": new HeightConstraint(-Infinity, heightShallows), + "tileClass": clShallows + }); + + // Animals in shallows + const shallowPosition = Vector2D.average([playerPosition[i], playerPosition[neighborID]]) + .round(); + const objects = [ + new SimpleObject(oWildebeest, 5, 6, 0, 4), + new SimpleObject(oElephant, 2, 3, 0, 4) + ]; + + for (const object of objects) + createObjectGroup(new SimpleGroup([object], true, clFood, shallowPosition), 0); } -}); -Engine.SetProgress(20); -g_Map.log("Creating rivers"); -const riverStart = distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.15), mapCenter)[0]; -const riverEnd = distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.49), mapCenter)[0]; + paintTerrainBasedOnHeight(-6, 2, 1, tWater); -for (let i = 0; i < numPlayers; ++i) -{ - const neighborID = (i + 1) % numPlayers; + g_Map.log("Creating bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + avoidClasses(clWater, 2, clPlayer, 20), + scaleByMapSize(100, 200)); - // Lake near the center - createArea( - new ClumpPlacer(diskArea(scaleByMapSize(5, 30)), 0.95, 0.6, Infinity, riverStart[i]), + g_Map.log("Creating hills"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), [ - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), - new TileClassPainter(clWater) + new LayeredPainter([tGrass, tCliff, tHill], [1, 2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 3), + new TileClassPainter(clHill) ], - avoidClasses(clPlayer, 5)); + avoidClasses(clPlayer, 20, clHill, 15, clWater, 3), + scaleByMapSize(1, 4) * numPlayers); - // River between the players - createArea( - new PathPlacer(riverStart[i], riverEnd[i], scaleByMapSize(10, 50), 0.2, 3 * scaleByMapSize(1, 4), 0.2, 0.05), - [ - new LayeredPainter([tShore, tWater, tWater], [1, 3]), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 5)); + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(160, 900, 0.02); + const types = [ + [[tForestFloor, tGrass, pForest], [tForestFloor, pForest]] + ]; - // Lake near the map border - createArea( - new ClumpPlacer(diskArea(scaleByMapSize(5, 22)), 0.95, 0.6, Infinity, riverEnd[i]), - [ - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 4), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 5)); - - // Shallows between neighbors - createPassage({ - "start": playerPosition[i], - "end": playerPosition[neighborID], - "startWidth": 10, - "endWidth": 10, - "smoothWidth": 4, - "startHeight": heightShallows, - "endHeight": heightShallows, - "constraints": new HeightConstraint(-Infinity, heightShallows), - "tileClass": clShallows - }); + const forestSize = forestTrees / (0.5 * scaleByMapSize(2,8) * numPlayers); + const num = Math.floor(forestSize / types.length); + for (const type of types) + createAreas( + new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 20, clForest, 10, clHill, 0, clWater, 2), + num + ); + yield 50; + + g_Map.log("Creating dirt patches"); + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new LayeredPainter( + [[tGrass, tDirtRocksA], [tDirtRocksA, tDirtRocksB], + [tDirtRocksB, tDirtRocksC]], + [1, 1]), + new TileClassPainter(clDirt) + ], + avoidClasses(clWater, 3, clForest, 0, clHill, 0, clPlayer, 20), + scaleByMapSize(15, 45)); + + g_Map.log("Creating grass patches"); + for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + new TerrainPainter(tGrassPatch), + avoidClasses(clWater, 3, clForest, 0, clHill, 0, clPlayer, 20), + scaleByMapSize(15, 45)); + yield 55; + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + scaleByMapSize(4,16), 100 + ); - // Animals in shallows - const shallowPosition = Vector2D.average([playerPosition[i], playerPosition[neighborID]]).round(); - const objects = [ - new SimpleObject(oWildebeest, 5, 6, 0, 4), - new SimpleObject(oElephant, 2, 3, 0, 4) - ]; + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), + scaleByMapSize(4,16), 100 + ); - for (const object of objects) - createObjectGroup(new SimpleGroup([object], true, clFood, shallowPosition), 0); -} + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), + scaleByMapSize(4,16), 100 + ); -paintTerrainBasedOnHeight(-6, 2, 1, tWater); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - avoidClasses(clWater, 2, clPlayer, 20), - scaleByMapSize(100, 200)); - -g_Map.log("Creating hills"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), - [ - new LayeredPainter([tGrass, tCliff, tHill], [1, 2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 3), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 20, clHill, 15, clWater, 3), - scaleByMapSize(1, 4) * numPlayers); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(160, 900, 0.02); -const types = [ - [[tForestFloor, tGrass, pForest], [tForestFloor, pForest]] -]; - -const forestSize = forestTrees / (0.5 * scaleByMapSize(2,8) * numPlayers); -const num = Math.floor(forestSize / types.length); -for (const type of types) - createAreas( - new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) - ], - avoidClasses(clPlayer, 20, clForest, 10, clHill, 0, clWater, 2), - num + yield 65; + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aRockMedium, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), + scaleByMapSize(16, 262), 50 ); -Engine.SetProgress(50); -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - [ - new LayeredPainter( - [[tGrass, tDirtRocksA], [tDirtRocksA, tDirtRocksB], [tDirtRocksB, tDirtRocksC]], - [1, 1]), - new TileClassPainter(clDirt) - ], - avoidClasses(clWater, 3, clForest, 0, clHill, 0, clPlayer, 20), - scaleByMapSize(15, 45)); + g_Map.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(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), + scaleByMapSize(8, 131), 50 + ); -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - new TerrainPainter(tGrassPatch), - avoidClasses(clWater, 3, clForest, 0, clHill, 0, clPlayer, 20), - scaleByMapSize(15, 45)); -Engine.SetProgress(55); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), - scaleByMapSize(4,16), 100 -); - -Engine.SetProgress(65); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aRockMedium, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), - scaleByMapSize(16, 262), 50 -); - -g_Map.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(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0), - scaleByMapSize(8, 131), 50 -); - -Engine.SetProgress(70); - -g_Map.log("Creating wildebeest"); -group = new SimpleGroup( - [new SimpleObject(oWildebeest, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), - 3 * numPlayers, 50 -); - -Engine.SetProgress(75); - -g_Map.log("Creating gazelle"); -group = new SimpleGroup( - [new SimpleObject(oGazelle, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), - 3 * numPlayers, 50 -); - -g_Map.log("Creating elephant"); -group = new SimpleGroup( - [new SimpleObject(oElephant, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), - 3 * numPlayers, 50 -); - -g_Map.log("Creating giraffe"); -group = new SimpleGroup( - [new SimpleObject(oGiraffe, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), - 3 * numPlayers, 50 -); - -g_Map.log("Creating zebra"); -group = new SimpleGroup( - [new SimpleObject(oZebra, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), - 3 * numPlayers, 50 -); - -g_Map.log("Creating fish"); -group = new SimpleGroup( - [new SimpleObject(oFish, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clFood, 20), stayClasses(clWater, 6)], - 25 * numPlayers, 60 -); - -g_Map.log("Creating berry bush"); -group = new SimpleGroup( - [new SimpleObject(oBerryBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), - randIntInclusive(1, 4) * numPlayers + 2, 50 -); - -Engine.SetProgress(85); - -createStragglerTrees( - [oBaobab, oBaobab, oBaobab, oFig], - avoidClasses(clWater, 5, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); - -let planetm = 4; -g_Map.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(clWater, 2, clHill, 2, clPlayer, 2), - planetm * scaleByMapSize(13, 200) -); - -Engine.SetProgress(90); - -g_Map.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(clWater, 3, clHill, 2, clPlayer, 2, clForest, 0), - planetm * scaleByMapSize(13, 200) -); - -Engine.SetProgress(95); - -g_Map.log("Creating bushes"); -group = new SimpleGroup( - [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clWater, 2, clHill, 1, clPlayer, 1), - planetm * scaleByMapSize(13, 200), 50 -); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clHill, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); - -setSkySet("sunny"); - -setSunRotation(randomAngle()); -setSunElevation(Math.PI * randFloat(1/5, 1/4)); -setWaterColor(0.478,0.42,0.384); // greyish -setWaterTint(0.58,0.22,0.067); // reddish -setWaterMurkiness(0.87); -setWaterWaviness(0.5); -setWaterType("clap"); - -g_Map.ExportMap(); + yield 70; + + g_Map.log("Creating wildebeest"); + group = new SimpleGroup( + [new SimpleObject(oWildebeest, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), + 3 * numPlayers, 50 + ); + + yield 75; + + g_Map.log("Creating gazelle"); + group = new SimpleGroup( + [new SimpleObject(oGazelle, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating elephant"); + group = new SimpleGroup( + [new SimpleObject(oElephant, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating giraffe"); + group = new SimpleGroup( + [new SimpleObject(oGiraffe, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating zebra"); + group = new SimpleGroup( + [new SimpleObject(oZebra, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 5), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating fish"); + group = new SimpleGroup( + [new SimpleObject(oFish, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clFood, 20), stayClasses(clWater, 6)], + 25 * numPlayers, 60 + ); + + g_Map.log("Creating berry bush"); + group = new SimpleGroup( + [new SimpleObject(oBerryBush, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), + randIntInclusive(1, 4) * numPlayers + 2, 50 + ); + + yield 85; + + createStragglerTrees( + [oBaobab, oBaobab, oBaobab, oFig], + avoidClasses(clWater, 5, clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + + let planetm = 4; + g_Map.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(clWater, 2, clHill, 2, clPlayer, 2), + planetm * scaleByMapSize(13, 200) + ); + + yield 90; + + g_Map.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(clWater, 3, clHill, 2, clPlayer, 2, clForest, 0), + planetm * scaleByMapSize(13, 200) + ); + + yield 95; + + g_Map.log("Creating bushes"); + group = new SimpleGroup( + [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clWater, 2, clHill, 1, clPlayer, 1), + planetm * scaleByMapSize(13, 200), 50 + ); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clHill, 4, clForest, 1, clMetal, 4, clRock, 4, + clFood, 2)); + + setSkySet("sunny"); + + setSunRotation(randomAngle()); + setSunElevation(Math.PI * randFloat(1/5, 1/4)); + setWaterColor(0.478,0.42,0.384); // greyish + setWaterTint(0.58,0.22,0.067); // reddish + setWaterMurkiness(0.87); + setWaterWaviness(0.5); + setWaterType("clap"); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/schwarzwald.js =================================================================== --- binaries/data/mods/public/maps/random/schwarzwald.js +++ binaries/data/mods/public/maps/random/schwarzwald.js @@ -2,321 +2,346 @@ Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("heightmap"); -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); - -const oStoneLarge = 'gaia/rock/alpine_large'; -const oMetalLarge = 'gaia/ore/alpine_large'; -const oFish = "gaia/fish/generic"; - -const aGrass = 'actor|props/flora/grass_soft_small_tall.xml'; -const aGrassShort = 'actor|props/flora/grass_soft_large.xml'; -const aRockLarge = 'actor|geology/stone_granite_med.xml'; -const aRockMedium = 'actor|geology/stone_granite_med.xml'; -const aBushMedium = 'actor|props/flora/bush_medit_me.xml'; -const aBushSmall = 'actor|props/flora/bush_medit_sm.xml'; -const aReeds = 'actor|props/flora/reeds_pond_lush_b.xml'; - -const terrainPrimary = ["temp_grass_plants", "temp_plants_bog"]; -const terrainWood = ['alpine_forrestfloor|gaia/tree/oak', 'alpine_forrestfloor|gaia/tree/pine']; -const terrainWoodBorder = ['new_alpine_grass_mossy|gaia/tree/oak', 'alpine_forrestfloor|gaia/tree/pine', - 'temp_grass_long|gaia/tree/bush_temperate', 'temp_grass_clovers|gaia/fruit/berry_01', 'temp_grass_clovers_2|gaia/fruit/grapes', - 'temp_grass_plants|gaia/fauna_deer', 'temp_grass_plants|gaia/fauna_rabbit', 'new_alpine_grass_dirt_a']; -const 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']; -const 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']; -const baseTex = ['temp_road', 'temp_road_overgrown']; -const terrainPath = ['temp_road', 'temp_road_overgrown']; -const tWater = ['dirt_brown_d']; -const tWaterBorder = ['dirt_brown_d']; - -const heightLand = 1; -const heightOffsetPath = -0.1; - -const g_Map = new RandomMap(heightLand, terrainPrimary); - -const clPlayer = g_Map.createTileClass(); -const clPath = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clOpen = g_Map.createTileClass(); - -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapRadius = mapSize/2; - -const numPlayers = getNumPlayers(); -const baseRadius = 15; -const minPlayerRadius = Math.min(mapRadius - 1.5 * baseRadius, 5/8 * mapRadius); -const maxPlayerRadius = Math.min(mapRadius - baseRadius, 3/4 * mapRadius); - -let playerPosition = []; -const playerAngleStart = randomAngle(); -const playerAngleAddAvrg = 2 * Math.PI / numPlayers; -const playerAngleMaxOff = playerAngleAddAvrg/4; - -const resourceRadius = fractionToTiles(1/3); - -// Set up woods. -// For large maps there are memory errors with too many trees. A density of 256x192/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. -const maxTreeDensity = Math.min(256 * (192 + 8 * numPlayers) / Math.square(mapSize), 1); // Has to be tweeked but works ok. -const 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. -const 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. -const averageWaterCoverage = 1/5; // NOTE: Since erosion is not predictable actual water coverage might vary much with the same values. -const heightSeaGround = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); -const heightSeaGroundAdjusted = heightSeaGround + MIN_HEIGHT; -setWaterHeight(heightSeaGround); - -// Setting a 3x3 grid as initial heightmap. -const 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); - -g_Map.log("Smoothing map"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, 0.8, 5)); - -rescaleHeightmap(heightRange.min, heightRange.max); - -const heighLimits = [ - heightRange.min + 1/3 * (heightSeaGroundAdjusted - heightRange.min), // 0 Deep water - heightRange.min + 2/3 * (heightSeaGroundAdjusted - heightRange.min), // 1 Medium Water - heightRange.min + (heightSeaGroundAdjusted - heightRange.min), // 2 Shallow water - heightSeaGroundAdjusted + 1/8 * (heightRange.max - heightSeaGroundAdjusted), // 3 Shore - heightSeaGroundAdjusted + 2/8 * (heightRange.max - heightSeaGroundAdjusted), // 4 Low ground - heightSeaGroundAdjusted + 3/8 * (heightRange.max - heightSeaGroundAdjusted), // 5 Player and path height - heightSeaGroundAdjusted + 4/8 * (heightRange.max - heightSeaGroundAdjusted), // 6 High ground - heightSeaGroundAdjusted + 5/8 * (heightRange.max - heightSeaGroundAdjusted), // 7 Lower forest border - heightSeaGroundAdjusted + 6/8 * (heightRange.max - heightSeaGroundAdjusted), // 8 Forest - heightSeaGroundAdjusted + 7/8 * (heightRange.max - heightSeaGroundAdjusted), // 9 Upper forest border - heightSeaGroundAdjusted + (heightRange.max - heightSeaGroundAdjusted)]; // 10 Hilltop - -g_Map.log("Locating and smoothing playerbases"); -for (let i = 0; i < numPlayers; ++i) +function* GenerateMap() { - playerPosition[i] = Vector2D.add( - mapCenter, - new Vector2D(randFloat(minPlayerRadius, maxPlayerRadius), 0).rotate( - -((playerAngleStart + i * playerAngleAddAvrg + randFloat(0, playerAngleMaxOff)) % (2 * Math.PI)))).round(); - + 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); + + const oStoneLarge = 'gaia/rock/alpine_large'; + const oMetalLarge = 'gaia/ore/alpine_large'; + const oFish = "gaia/fish/generic"; + + const aGrass = 'actor|props/flora/grass_soft_small_tall.xml'; + const aGrassShort = 'actor|props/flora/grass_soft_large.xml'; + const aRockLarge = 'actor|geology/stone_granite_med.xml'; + const aRockMedium = 'actor|geology/stone_granite_med.xml'; + const aBushMedium = 'actor|props/flora/bush_medit_me.xml'; + const aBushSmall = 'actor|props/flora/bush_medit_sm.xml'; + const aReeds = 'actor|props/flora/reeds_pond_lush_b.xml'; + + const terrainPrimary = ["temp_grass_plants", "temp_plants_bog"]; + const terrainWood = ['alpine_forrestfloor|gaia/tree/oak', 'alpine_forrestfloor|gaia/tree/pine']; + const terrainWoodBorder = ['new_alpine_grass_mossy|gaia/tree/oak', + 'alpine_forrestfloor|gaia/tree/pine', 'temp_grass_long|gaia/tree/bush_temperate', + 'temp_grass_clovers|gaia/fruit/berry_01', 'temp_grass_clovers_2|gaia/fruit/grapes', + 'temp_grass_plants|gaia/fauna_deer', 'temp_grass_plants|gaia/fauna_rabbit', + 'new_alpine_grass_dirt_a']; + const 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']; + const 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']; + const baseTex = ['temp_road', 'temp_road_overgrown']; + const terrainPath = ['temp_road', 'temp_road_overgrown']; + const tWater = ['dirt_brown_d']; + const tWaterBorder = ['dirt_brown_d']; + + const heightLand = 1; + const heightOffsetPath = -0.1; + + global.g_Map = new RandomMap(heightLand, terrainPrimary); + + const clPlayer = g_Map.createTileClass(); + const clPath = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clOpen = g_Map.createTileClass(); + + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const mapRadius = mapSize/2; + + const numPlayers = getNumPlayers(); + const baseRadius = 15; + const minPlayerRadius = Math.min(mapRadius - 1.5 * baseRadius, 5/8 * mapRadius); + const maxPlayerRadius = Math.min(mapRadius - baseRadius, 3/4 * mapRadius); + + let playerPosition = []; + const playerAngleStart = randomAngle(); + const playerAngleAddAvrg = 2 * Math.PI / numPlayers; + const playerAngleMaxOff = playerAngleAddAvrg/4; + + const resourceRadius = fractionToTiles(1/3); + + // Set up woods. + // For large maps there are memory errors with too many trees. A density of 256x192/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. + // Has to be tweeked but works ok. + const maxTreeDensity = Math.min(256 * (192 + 8 * numPlayers) / Math.square(mapSize), 1); + const 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. + const 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. + const averageWaterCoverage = 1/5; // NOTE: Since erosion is not predictable actual water coverage might vary much with the same values. + const heightSeaGround = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * + (heightRange.max - heightRange.min); + const heightSeaGroundAdjusted = heightSeaGround + MIN_HEIGHT; + setWaterHeight(heightSeaGround); + + // Setting a 3x3 grid as initial heightmap. + const 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); + + g_Map.log("Smoothing map"); createArea( - new ClumpPlacer(diskArea(20), 0.8, 0.8, Infinity, playerPosition[i]), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(playerPosition[i]), 20)); -} + new MapBoundsPlacer(), + new SmoothingPainter(1, 0.8, 5)); + + rescaleHeightmap(heightRange.min, heightRange.max); + + const heighLimits = [ + // 0 Deep water + heightRange.min + 1/3 * (heightSeaGroundAdjusted - heightRange.min), + // 1 Medium Water + heightRange.min + 2/3 * (heightSeaGroundAdjusted - heightRange.min), + // 2 Shallow water + heightRange.min + (heightSeaGroundAdjusted - heightRange.min), + // 3 Shore + heightSeaGroundAdjusted + 1/8 * (heightRange.max - heightSeaGroundAdjusted), + // 4 Low ground + heightSeaGroundAdjusted + 2/8 * (heightRange.max - heightSeaGroundAdjusted), + // 5 Player and path height + heightSeaGroundAdjusted + 3/8 * (heightRange.max - heightSeaGroundAdjusted), + // 6 High ground + heightSeaGroundAdjusted + 4/8 * (heightRange.max - heightSeaGroundAdjusted), + // 7 Lower forest border + heightSeaGroundAdjusted + 5/8 * (heightRange.max - heightSeaGroundAdjusted), + // 8 Forest + heightSeaGroundAdjusted + 6/8 * (heightRange.max - heightSeaGroundAdjusted), + // 9 Upper forest border + heightSeaGroundAdjusted + 7/8 * (heightRange.max - heightSeaGroundAdjusted), + // 10 Hilltop + heightSeaGroundAdjusted + (heightRange.max - heightSeaGroundAdjusted)]; + + g_Map.log("Locating and smoothing playerbases"); + 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(); -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]), - new TileClassPainter(clPlayer) - ] - }, - // No chicken - "Berries": { - "template": "gaia/fruit/berry_01", - "minCount": 2, - "maxCount": 2 - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ], - "distance": 15, - "minAngle": Math.PI / 2, - "maxAngle": Math.PI - }, - "Trees": { - "template": "gaia/tree/oak_large", - "count": 2 + createArea( + new ClumpPlacer(diskArea(20), 0.8, 0.8, Infinity, playerPosition[i]), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(playerPosition[i]), 20)); } -}); -g_Map.log("Creating mines"); -for (const [minHeight, maxHeight] of [[heighLimits[3], (heighLimits[4] + heighLimits[3]) / 2], [(heighLimits[5] + heighLimits[6]) / 2, heighLimits[7]]]) - for (const [template, tileClass] of [[oStoneLarge, clRock], [oMetalLarge, 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) + 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]), + new TileClassPainter(clPlayer) + ] + }, + // No chicken + "Berries": { + "template": "gaia/fruit/berry_01", + "minCount": 2, + "maxCount": 2 + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } ], - scaleByMapSize(2, 8), - 100, - false); + "distance": 15, + "minAngle": Math.PI / 2, + "maxAngle": Math.PI + }, + "Trees": { + "template": "gaia/tree/oak_large", + "count": 2 + } + }); + + g_Map.log("Creating mines"); + for (const [minHeight, maxHeight] of [[heighLimits[3], (heighLimits[4] + heighLimits[3]) / 2], + [(heighLimits[5] + heighLimits[6]) / 2, heighLimits[7]]]) + for (const [template, tileClass] of [[oStoneLarge, clRock], [oMetalLarge, 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); + + yield 50; + + g_Map.log("Painting textures"); + const betweenShallowAndShore = (heighLimits[3] + heighLimits[2]) / 2; + createArea( + new HeightPlacer(Elevation_IncludeMin_IncludeMax, heighLimits[2], betweenShallowAndShore), + new LayeredPainter([terrainBase, terrainBaseBorder], [5])); -Engine.SetProgress(50); + paintTileClassBasedOnHeight(heighLimits[2], betweenShallowAndShore, 1, clOpen); -g_Map.log("Painting textures"); -const betweenShallowAndShore = (heighLimits[3] + heighLimits[2]) / 2; -createArea( - new HeightPlacer(Elevation_IncludeMin_IncludeMax, heighLimits[2], betweenShallowAndShore), - new LayeredPainter([terrainBase, terrainBaseBorder], [5])); + createArea( + new HeightPlacer(Elevation_IncludeMin_IncludeMax, heightRange.min, heighLimits[2]), + new LayeredPainter([tWaterBorder, tWater], [2])); -paintTileClassBasedOnHeight(heighLimits[2], betweenShallowAndShore, 1, clOpen); + paintTileClassBasedOnHeight(heightRange.min, heighLimits[2], 1, clWater); + yield 60; -createArea( - new HeightPlacer(Elevation_IncludeMin_IncludeMax, heightRange.min, heighLimits[2]), - new LayeredPainter([tWaterBorder, tWater], [2])); + g_Map.log("Painting paths"); + const pathBlending = numPlayers <= 4; + for (let i = 0; i < numPlayers + (pathBlending ? 1 : 0); ++i) + for (let j = pathBlending ? 0 : i + 1; j < numPlayers + 1; ++j) + { + const pathStart = i < numPlayers ? playerPosition[i] : mapCenter; + const 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), + new TileClassPainter(clPath) + ], + avoidClasses(clPath, 0, clOpen, 0, clWater, 4, clBaseResource, 4)); + } + yield 75; + + g_Map.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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13), + scaleByMapAreaAbsolute(13) + ], + avoidClasses(clForest, 1, clPlayer, 0, clPath, 3, clWater, 3)); -paintTileClassBasedOnHeight(heightRange.min, heighLimits[2], 1, clWater); -Engine.SetProgress(60); + yield 80; -g_Map.log("Painting paths"); -const pathBlending = numPlayers <= 4; -for (let i = 0; i < numPlayers + (pathBlending ? 1 : 0); ++i) - for (let j = pathBlending ? 0 : i + 1; j < numPlayers + 1; ++j) - { - const pathStart = i < numPlayers ? playerPosition[i] : mapCenter; - const pathEnd = j < numPlayers ? playerPosition[j] : mapCenter; + g_Map.log("Growing fish"); + createFood( + [ + [new SimpleObject(oFish, 2, 3, 0, 2)] + ], + [ + 100 * numPlayers + ], + [avoidClasses(clFood, 5), stayClasses(clWater, 4)], + clFood); - createArea( - new RandomPathPlacer(pathStart, pathEnd, 1.75, baseRadius / 2, pathBlending), - [ - new TerrainPainter(terrainPath), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetPath, 1), - new TileClassPainter(clPath) - ], - avoidClasses(clPath, 0, clOpen, 0, clWater, 4, clBaseResource, 4)); - } -Engine.SetProgress(75); - -g_Map.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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13), - scaleByMapAreaAbsolute(13) - ], - avoidClasses(clForest, 1, clPlayer, 0, clPath, 3, clWater, 3)); - -Engine.SetProgress(80); - -g_Map.log("Growing fish"); -createFood( - [ - [new SimpleObject(oFish, 2, 3, 0, 2)] - ], - [ - 100 * numPlayers - ], - [avoidClasses(clFood, 5), stayClasses(clWater, 4)], - clFood); - -Engine.SetProgress(85); - -g_Map.log("Planting reeds"); -const types = [aReeds]; -for (const 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); - -g_Map.log("Planting trees"); -for (let x = 0; x < mapSize; x++) - for (let z = 0; z < mapSize; z++) - { - const position = new Vector2D(x, z); + yield 85; - if (!g_Map.validTile(position)) - continue; + g_Map.log("Planting reeds"); + const types = [aReeds]; + for (const type of types) + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(type, 1, 1, 0, 0)], true), + 0, + borderClasses(clWater, 0, 6), + scaleByMapSize(1, 2) * 1000, + 1000); - // The 0.5 is a correction for the entities placed on the center of tiles - const radius = Vector2D.add(position, new Vector2D(0.5, 0.5)).distanceTo(mapCenter); - let minDistToSL = mapSize; - for (let i = 0; i < numPlayers; ++i) - minDistToSL = Math.min(minDistToSL, position.distanceTo(playerPosition[i])); + yield 90; - // Woods tile based - const tDensFactSL = Math.max(Math.min((minDistToSL - baseRadius) / baseRadius, 1), 0); - const tDensFactRad = Math.abs((resourceRadius - radius) / resourceRadius); - const tDensActual = (maxTreeDensity * tDensFactSL * tDensFactRad)*0.75; + g_Map.log("Planting trees"); + for (let x = 0; x < mapSize; x++) + for (let z = 0; z < mapSize; z++) + { + const position = new Vector2D(x, z); - if (!randBool(tDensActual)) - continue; + if (!g_Map.validTile(position)) + continue; - const border = tDensActual < randFloat(0, bushChance * maxTreeDensity); + // The 0.5 is a correction for the entities placed on the center of tiles + const radius = Vector2D.add(position, new Vector2D(0.5, 0.5)).distanceTo(mapCenter); + let minDistToSL = mapSize; + for (let i = 0; i < numPlayers; ++i) + minDistToSL = Math.min(minDistToSL, position.distanceTo(playerPosition[i])); - const constraint = border ? - avoidClasses(clPath, 1, clOpen, 2, clWater, 3, clMetal, 4, clRock, 4) : - avoidClasses(clPath, 2, clOpen, 3, clWater, 4, clMetal, 4, clRock, 4); + // Woods tile based + const tDensFactSL = Math.max(Math.min((minDistToSL - baseRadius) / baseRadius, 1), 0); + const tDensFactRad = Math.abs((resourceRadius - radius) / resourceRadius); + const tDensActual = (maxTreeDensity * tDensFactSL * tDensFactRad)*0.75; - if (constraint.allows(position)) - { - clForest.add(position); - createTerrain(border ? terrainWoodBorder : terrainWood).place(position); - } - } + if (!randBool(tDensActual)) + continue; -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clFood, 2, clMetal, 4, clRock, 4)); + const border = tDensActual < randFloat(0, bushChance * maxTreeDensity); -Engine.SetProgress(100); + const constraint = border ? + avoidClasses(clPath, 1, clOpen, 2, clWater, 3, clMetal, 4, clRock, 4) : + avoidClasses(clPath, 2, clOpen, 3, clWater, 4, clMetal, 4, clRock, 4); -g_Map.ExportMap(); + if (constraint.allows(position)) + { + clForest.add(position); + createTerrain(border ? terrainWoodBorder : terrainWood).place(position); + } + } + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clFood, 2, clMetal, 4, clRock, 4)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/scythian_rivulet.js =================================================================== --- binaries/data/mods/public/maps/random/scythian_rivulet.js +++ binaries/data/mods/public/maps/random/scythian_rivulet.js @@ -1,318 +1,329 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tMainTerrain = "alpine_snow_a"; -const tTier1Terrain = "snow rough"; -const tTier2Terrain = "snow_01"; -const tTier3Terrain = "snow rocks"; -const tForestFloor1 = "alpine_forrestfloor_snow"; -const tForestFloor2 = "polar_snow_rocks"; -const tCliff = ["alpine_cliff_a", "alpine_cliff_b"]; -const tHill = "alpine_snow_glacial"; -const tRoad = "new_alpine_citytile"; -const tRoadWild = "alpine_snow_rocky"; -const tShore = "alpine_shore_rocks_icy"; -const tWater = "polar_ice_b"; - -const oTreeDead = "gaia/tree/dead"; -const oOak = "gaia/tree/oak_dead"; -const oPine = "gaia/tree/pine"; -const oGrapes = "gaia/fruit/grapes"; -const oBush = "gaia/tree/bush_badlands"; -const oDeer = "gaia/fauna_deer"; -const oRabbit = "gaia/fauna_rabbit"; -const oWolf1 = "gaia/fauna_wolf"; -const oWolf2 = "gaia/fauna_wolf_arctic"; -const oHawk = "birds/buzzard"; -const oFish = "gaia/fish/generic"; -const oStoneLarge = "gaia/rock/alpine_large"; -const oStoneSmall = "gaia/rock/alpine_small"; -const oMetalLarge = "gaia/ore/alpine_large"; - -const aRockLarge = "actor|geology/stone_granite_large.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; -const aBushMedium = "actor|props/flora/plant_desert_a.xml"; -const aBushSmall = "actor|props/flora/bush_desert_a.xml"; -const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; -const aOutpostPalisade = "actor|props/structures/britons/outpost_palisade.xml"; -const aWorkshopChariot= "actor|props/structures/britons/workshop_chariot_01.xml"; - -const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTreeDead, tForestFloor2 + TERRAIN_SEPARATOR + oOak, tForestFloor2]; -const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTreeDead, tForestFloor1]; - -const heightSeaGround = -2; -const heightShoreLower = 0.7; -const heightShoreUpper = 1; -const heightLand = 2; -const heightSnowline = 12; -const heightOffsetLargeBumps = 4; - -const g_Map = new RandomMap(heightShoreUpper, tMainTerrain); - -const numPlayers = getNumPlayers(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRiver = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clShallowsFlora = g_Map.createTileClass(); - -const riverWidth = fractionToTiles(0.1); - -const startAngle = randomAngle(); - -const [playerIDs, playerPosition] = playerPlacementRiver(startAngle, fractionToTiles(0.6)); - -if (!isNomad()) - for (const position of playerPosition) - addCivicCenterAreaToClass(position, clPlayer); - -paintRiver({ - "parallel": false, - "start": new Vector2D(mapCenter.x, mapBounds.top).rotateAround(startAngle, mapCenter), - "end": new Vector2D(mapCenter.x, mapBounds.bottom).rotateAround(startAngle, mapCenter), - "width": riverWidth, - "fadeDist": scaleByMapSize(3, 14), - "deviation": 6, - "heightRiverbed": heightSeaGround, - "heightLand": heightLand, - "meanderShort": 40, - "meanderLong": 20 -}); -Engine.SetProgress(10); - -paintTileClassBasedOnHeight(-Infinity, heightShoreUpper, Elevation_ExcludeMin_ExcludeMax, clRiver); -Engine.SetProgress(15); - -createTributaryRivers( - startAngle + Math.PI / 2, - 4, - 10, - heightSeaGround, - [-Infinity, heightSeaGround], - Math.PI / 5, - clWater, - undefined, - avoidClasses(clPlayer, 4)); - -Engine.SetProgress(25); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": avoidClasses(clWater, 4), - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - "template": oDeer, - "distance": 18, - "minGroupDistance": 2, - "maxGroupDistance": 4, - "minGroupCount": 2, - "maxGroupCount": 3 - }, - "Berries": { - "template": oGrapes, - "minCount": 3, - "maxCount": 3 - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oTreeDead, - "count": 10 - }, - "Decoratives": { - "template": aBushSmall, - "minDist": 10, - "maxDist": 12 - } -}); -Engine.SetProgress(30); - -g_Map.log("Creating pools"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(2, 5)), Math.floor(scaleByMapSize(15, 60)), 0.8), - new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 3), - avoidClasses(clPlayer, 20), - scaleByMapSize(6, 20)); - -Engine.SetProgress(40); - -createBumps(avoidClasses(clPlayer, 2)); - -if (randBool()) - createHills([tCliff, tCliff, tHill], avoidClasses(clPlayer, 20, clWater, 1, clHill, 15, clRiver, 10), clHill, scaleByMapSize(3, 15)); -else - createMountains(tCliff, avoidClasses(clPlayer, 20, clWater, 1, clHill, 15, clRiver, 10), clHill, scaleByMapSize(3, 15)); - -g_Map.log("Creating large bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLargeBumps, 3), - avoidClasses(clPlayer, 2), - scaleByMapSize(100, 800)); - -createBumps(avoidClasses(clPlayer, 20)); - -paintTileClassBasedOnHeight(-Infinity, heightShoreUpper, Elevation_ExcludeMin_ExcludeMax, clWater); -paintTerrainBasedOnHeight(-Infinity, heightShoreUpper, Elevation_ExcludeMin_ExcludeMax, tWater); -paintTerrainBasedOnHeight(heightShoreUpper, heightShoreLower, Elevation_ExcludeMin_ExcludeMax, tShore); -paintTerrainBasedOnHeight(heightSnowline, Infinity, Elevation_ExcludeMin_ExcludeMax, tMainTerrain); - -Engine.SetProgress(50); - -g_Map.log("Creating dirt patches"); -createLayeredPatches( - [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], - [1, 1], - avoidClasses(clHill, 2, clDirt, 5, clPlayer, 12, clWater, 5, clForest, 4), - scaleByMapSize(25, 55), - clDirt); - -const [forestTrees, stragglerTrees] = getTreeCounts(200, 1200, 0.7); -createForests( - [tForestFloor1, tForestFloor2, tForestFloor1, pForest1, pForest2], - avoidClasses(clPlayer, 20, clWater, 2, clHill, 2, clForest, 12), - clForest, - forestTrees); - -createStragglerTrees( - [oTreeDead, oOak, oPine, oBush], - avoidClasses(clPlayer, 17, clWater, 2, clHill, 2, clForest, 1, clRiver, 4), - clForest, - stragglerTrees); - -Engine.SetProgress(55); - -g_Map.log("Creating stone mines"); -// Allow mines on the bumps at the river -createMines( - [ - [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], - [new SimpleObject(oStoneSmall, 2, 5, 1, 3)] - ], - avoidClasses(clForest, 4, clWater, 1, clPlayer, 20, clRock, 15, clHill, 1), - clRock); - -g_Map.log("Creating metal mines"); -createMines( - [ - [new SimpleObject(oMetalLarge, 1, 1, 0, 4)] - ], - avoidClasses(clForest, 4, clWater, 1, clPlayer, 20, clMetal, 15, clRock, 5, clHill, 1), - clMetal); - -Engine.SetProgress(65); - -createDecoration( - [ +function* GenerateMap() +{ + const tMainTerrain = "alpine_snow_a"; + const tTier1Terrain = "snow rough"; + const tTier2Terrain = "snow_01"; + const tTier3Terrain = "snow rocks"; + const tForestFloor1 = "alpine_forrestfloor_snow"; + const tForestFloor2 = "polar_snow_rocks"; + const tCliff = ["alpine_cliff_a", "alpine_cliff_b"]; + const tHill = "alpine_snow_glacial"; + const tRoad = "new_alpine_citytile"; + const tRoadWild = "alpine_snow_rocky"; + const tShore = "alpine_shore_rocks_icy"; + const tWater = "polar_ice_b"; + + const oTreeDead = "gaia/tree/dead"; + const oOak = "gaia/tree/oak_dead"; + const oPine = "gaia/tree/pine"; + const oGrapes = "gaia/fruit/grapes"; + const oBush = "gaia/tree/bush_badlands"; + const oDeer = "gaia/fauna_deer"; + const oRabbit = "gaia/fauna_rabbit"; + const oWolf1 = "gaia/fauna_wolf"; + const oWolf2 = "gaia/fauna_wolf_arctic"; + const oHawk = "birds/buzzard"; + const oFish = "gaia/fish/generic"; + const oStoneLarge = "gaia/rock/alpine_large"; + const oStoneSmall = "gaia/rock/alpine_small"; + const oMetalLarge = "gaia/ore/alpine_large"; + + const aRockLarge = "actor|geology/stone_granite_large.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + const aBushMedium = "actor|props/flora/plant_desert_a.xml"; + const aBushSmall = "actor|props/flora/bush_desert_a.xml"; + const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; + const aOutpostPalisade = "actor|props/structures/britons/outpost_palisade.xml"; + const aWorkshopChariot= "actor|props/structures/britons/workshop_chariot_01.xml"; + + const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTreeDead, + tForestFloor2 + TERRAIN_SEPARATOR + oOak, tForestFloor2]; + const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTreeDead, tForestFloor1]; + + const heightSeaGround = -2; + const heightShoreLower = 0.7; + const heightShoreUpper = 1; + const heightLand = 2; + const heightSnowline = 12; + const heightOffsetLargeBumps = 4; + + global.g_Map = new RandomMap(heightShoreUpper, tMainTerrain); + + const numPlayers = getNumPlayers(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRiver = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clShallowsFlora = g_Map.createTileClass(); + + const riverWidth = fractionToTiles(0.1); + + const startAngle = randomAngle(); + + const [playerIDs, playerPosition] = playerPlacementRiver(startAngle, fractionToTiles(0.6)); + + if (!isNomad()) + for (const position of playerPosition) + addCivicCenterAreaToClass(position, clPlayer); + + paintRiver({ + "parallel": false, + "start": new Vector2D(mapCenter.x, mapBounds.top).rotateAround(startAngle, mapCenter), + "end": new Vector2D(mapCenter.x, mapBounds.bottom).rotateAround(startAngle, mapCenter), + "width": riverWidth, + "fadeDist": scaleByMapSize(3, 14), + "deviation": 6, + "heightRiverbed": heightSeaGround, + "heightLand": heightLand, + "meanderShort": 40, + "meanderLong": 20 + }); + yield 10; + + paintTileClassBasedOnHeight(-Infinity, heightShoreUpper, Elevation_ExcludeMin_ExcludeMax, clRiver); + yield 15; + + createTributaryRivers( + startAngle + Math.PI / 2, + 4, + 10, + heightSeaGround, + [-Infinity, heightSeaGround], + Math.PI / 5, + clWater, + undefined, + avoidClasses(clPlayer, 4)); + + yield 25; + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": avoidClasses(clWater, 4), + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + "template": oDeer, + "distance": 18, + "minGroupDistance": 2, + "maxGroupDistance": 4, + "minGroupCount": 2, + "maxGroupCount": 3 + }, + "Berries": { + "template": oGrapes, + "minCount": 3, + "maxCount": 3 + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oTreeDead, + "count": 10 + }, + "Decoratives": { + "template": aBushSmall, + "minDist": 10, + "maxDist": 12 + } + }); + yield 30; + + g_Map.log("Creating pools"); + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(2, 5)), Math.floor(scaleByMapSize(15, 60)), 0.8), + new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 3), + avoidClasses(clPlayer, 20), + scaleByMapSize(6, 20)); + + yield 40; + + createBumps(avoidClasses(clPlayer, 2)); + + if (randBool()) + createHills([tCliff, tCliff, tHill], + avoidClasses(clPlayer, 20, clWater, 1, clHill, 15, clRiver, 10), clHill, + scaleByMapSize(3, 15)); + else + createMountains(tCliff, avoidClasses(clPlayer, 20, clWater, 1, clHill, 15, clRiver, 10), clHill, + scaleByMapSize(3, 15)); + + g_Map.log("Creating large bumps"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLargeBumps, 3), + avoidClasses(clPlayer, 2), + scaleByMapSize(100, 800)); + + createBumps(avoidClasses(clPlayer, 20)); + + paintTileClassBasedOnHeight(-Infinity, heightShoreUpper, Elevation_ExcludeMin_ExcludeMax, clWater); + paintTerrainBasedOnHeight(-Infinity, heightShoreUpper, Elevation_ExcludeMin_ExcludeMax, tWater); + paintTerrainBasedOnHeight(heightShoreUpper, heightShoreLower, Elevation_ExcludeMin_ExcludeMax, + tShore); + paintTerrainBasedOnHeight(heightSnowline, Infinity, Elevation_ExcludeMin_ExcludeMax, tMainTerrain); + + yield 50; + + g_Map.log("Creating dirt patches"); + createLayeredPatches( + [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], + [[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], + [1, 1], + avoidClasses(clHill, 2, clDirt, 5, clPlayer, 12, clWater, 5, clForest, 4), + scaleByMapSize(25, 55), + clDirt); + + const [forestTrees, stragglerTrees] = getTreeCounts(200, 1200, 0.7); + createForests( + [tForestFloor1, tForestFloor2, tForestFloor1, pForest1, pForest2], + avoidClasses(clPlayer, 20, clWater, 2, clHill, 2, clForest, 12), + clForest, + forestTrees); + + createStragglerTrees( + [oTreeDead, oOak, oPine, oBush], + avoidClasses(clPlayer, 17, clWater, 2, clHill, 2, clForest, 1, clRiver, 4), + clForest, + stragglerTrees); + + yield 55; + + g_Map.log("Creating stone mines"); + // Allow mines on the bumps at the river + createMines( [ - new SimpleObject(aRockMedium, 1, 3, 0, 1) + [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], + [new SimpleObject(oStoneSmall, 2, 5, 1, 3)] ], + avoidClasses(clForest, 4, clWater, 1, clPlayer, 20, clRock, 15, clHill, 1), + clRock); + + g_Map.log("Creating metal mines"); + createMines( + [ + [new SimpleObject(oMetalLarge, 1, 1, 0, 4)] + ], + avoidClasses(clForest, 4, clWater, 1, clPlayer, 20, clMetal, 15, clRock, 5, clHill, 1), + clMetal); + + yield 65; + + createDecoration( + [ + [ + new SimpleObject(aRockMedium, 1, 3, 0, 1) + ], + [ + new SimpleObject(aBushSmall, 1, 2, 0, 1), + new SimpleObject(aBushMedium, 1, 3, 0, 2), + new SimpleObject(aRockLarge, 1, 2, 0, 1) + ] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapSize(40, 360) + ], + avoidClasses(clWater, 2, clForest, 0, clPlayer, 20, clHill, 1)); + + yield 70; + + createFood( [ - new SimpleObject(aBushSmall, 1, 2, 0, 1), - new SimpleObject(aBushMedium, 1, 3, 0, 2), - new SimpleObject(aRockLarge, 1, 2, 0, 1) - ] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapSize(40, 360) - ], - avoidClasses(clWater, 2, clForest, 0, clPlayer, 20, clHill, 1)); - -Engine.SetProgress(70); - -createFood( - [ - [new SimpleObject(oHawk, 1, 1, 0, 3)], - [new SimpleObject(oWolf1, 4, 6, 0, 4)], - [new SimpleObject(oWolf2, 4, 8, 0, 4)], - [new SimpleObject(oDeer, 4, 6, 0, 2)], - [new SimpleObject(oRabbit, 1, 3, 4, 6)] - ], - [ - scaleByMapSize(3, 10), - scaleByMapSize(3, 10), - scaleByMapSize(3, 10), - scaleByMapSize(5, 20), - scaleByMapSize(5, 20) - ], - avoidClasses(clWater, 3, clPlayer, 20, clHill, 1, clFood, 10)); - -Engine.SetProgress(75); - -createFood( - [ - [new SimpleObject(oFish, 1, 2, 0, 2)] - ], - [ - 3 * numPlayers - ], - [avoidClasses(clPlayer, 8, clForest, 1, clHill, 4), stayClasses (clWater, 6)], - clFood); - -g_Map.log("Creating shallow flora"); -createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aReeds, 6, 14, 1, 5)], false, clShallowsFlora), - 0, - [ - new HeightConstraint(-1, 0), - avoidClasses(clShallowsFlora, 25), - ], - 20 * scaleByMapSize(13, 200), - 80); - -g_Map.log("Creating gallic decoratives"); -createDecoration( - [ - [new SimpleObject(aOutpostPalisade, 1, 1, 0, 1)], - [new SimpleObject(aWorkshopChariot, 1, 1, 0, 1)], - ], - [ - scaleByMapSize(2, 7), - scaleByMapSize(2, 7) - ], - avoidClasses(clForest, 1, clPlayer, 20, clBaseResource, 5, clHill, 4, clFood, 4, clWater, 5, clRock, 9, clMetal, 9)); - - -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 10, clWater, 5)); - -setSkySet(pickRandom(["fog", "stormy", "sunset"])); -setSunElevation(0.27); -setSunRotation(randomAngle()); -setSunColor(0.746, 0.718, 0.539); -setWaterColor(0.292, 0.347, 0.691); -setWaterTint(0.550, 0.543, 0.437); -setWaterMurkiness(0.83); -setWaterType("clap"); - -setWindAngle(startAngle); - -setFogColor(0.8, 0.76, 0.61); -setFogThickness(2); -setFogFactor(1.2); - -setPPEffect("hdr"); -setPPContrast(0.65); -setPPSaturation(0.42); -setPPBloom(0.6); - -g_Map.ExportMap(); + [new SimpleObject(oHawk, 1, 1, 0, 3)], + [new SimpleObject(oWolf1, 4, 6, 0, 4)], + [new SimpleObject(oWolf2, 4, 8, 0, 4)], + [new SimpleObject(oDeer, 4, 6, 0, 2)], + [new SimpleObject(oRabbit, 1, 3, 4, 6)] + ], + [ + scaleByMapSize(3, 10), + scaleByMapSize(3, 10), + scaleByMapSize(3, 10), + scaleByMapSize(5, 20), + scaleByMapSize(5, 20) + ], + avoidClasses(clWater, 3, clPlayer, 20, clHill, 1, clFood, 10)); + + yield 75; + + createFood( + [ + [new SimpleObject(oFish, 1, 2, 0, 2)] + ], + [ + 3 * numPlayers + ], + [avoidClasses(clPlayer, 8, clForest, 1, clHill, 4), stayClasses (clWater, 6)], + clFood); + + g_Map.log("Creating shallow flora"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aReeds, 6, 14, 1, 5)], false, clShallowsFlora), + 0, + [ + new HeightConstraint(-1, 0), + avoidClasses(clShallowsFlora, 25), + ], + 20 * scaleByMapSize(13, 200), + 80); + + g_Map.log("Creating gallic decoratives"); + createDecoration( + [ + [new SimpleObject(aOutpostPalisade, 1, 1, 0, 1)], + [new SimpleObject(aWorkshopChariot, 1, 1, 0, 1)], + ], + [ + scaleByMapSize(2, 7), + scaleByMapSize(2, 7) + ], + avoidClasses(clForest, 1, clPlayer, 20, clBaseResource, 5, clHill, 4, clFood, 4, clWater, 5, + clRock, 9, clMetal, 9)); + + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 10, + clWater, 5)); + + setSkySet(pickRandom(["fog", "stormy", "sunset"])); + setSunElevation(0.27); + setSunRotation(randomAngle()); + setSunColor(0.746, 0.718, 0.539); + setWaterColor(0.292, 0.347, 0.691); + setWaterTint(0.550, 0.543, 0.437); + setWaterMurkiness(0.83); + setWaterType("clap"); + + setWindAngle(startAngle); + + setFogColor(0.8, 0.76, 0.61); + setFogThickness(2); + setFogFactor(1.2); + + setPPEffect("hdr"); + setPPContrast(0.65); + setPPSaturation(0.42); + setPPBloom(0.6); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/snowflake_searocks.js =================================================================== --- binaries/data/mods/public/maps/random/snowflake_searocks.js +++ binaries/data/mods/public/maps/random/snowflake_searocks.js @@ -4,443 +4,461 @@ 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 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 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]; - -const heightIsland = 20; -const heightSeaGround = -5; - -const g_Map = new RandomMap(heightSeaGround, tWater); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clLand = g_Map.createTileClass(); - -const playerIslandRadius = scaleByMapSize(15, 30); - -const islandBetweenPlayerAndCenterDist = 0.16; -const islandBetweenPlayerAndCenterRadius = 0.81; -const centralIslandRadius = 0.36; - -var [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); - -var numIslands = 0; -var isConnected = []; -var islandPos = []; - -function initIsConnected() +function* GenerateMap() { - for (let m = 0; m < numIslands; ++m) + 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 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 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]; + + const heightIsland = 20; + const heightSeaGround = -5; + + global.g_Map = new RandomMap(heightSeaGround, tWater); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clLand = g_Map.createTileClass(); + + const playerIslandRadius = scaleByMapSize(15, 30); + + const islandBetweenPlayerAndCenterDist = 0.16; + const islandBetweenPlayerAndCenterRadius = 0.81; + const centralIslandRadius = 0.36; + + var [playerIDs, playerPosition, playerAngle, startAngle] = + playerPlacementCircle(fractionToTiles(0.35)); + + var numIslands = 0; + var isConnected = []; + var islandPos = []; + + function initIsConnected() { - isConnected[m] = []; - for (let n = 0; n < numIslands; ++n) - isConnected[m][n] = 0; + for (let m = 0; m < numIslands; ++m) + { + isConnected[m] = []; + for (let n = 0; n < numIslands; ++n) + isConnected[m][n] = 0; + } } -} - -function createIsland(islandID, size, tileClass) -{ - createArea( - new ClumpPlacer(size * diskArea(playerIslandRadius), 0.95, 0.6, Infinity, islandPos[islandID]), - [ - new TerrainPainter(tHill), - new SmoothElevationPainter(ELEVATION_SET, heightIsland, 2), - new TileClassPainter(tileClass) - ]); -} -function createIslandAtRadialLocation(playerID, islandID, playerIDOffset, distFromCenter, islandRadius) -{ - const angle = startAngle + (playerID * 2 + playerIDOffset) * Math.PI / numPlayers; - islandPos[islandID] = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(distFromCenter), 0).rotate(-angle)).round(); - createIsland(islandID, islandRadius, clLand); -} - -function createSnowflakeSearockWithCenter(sizeID) -{ - const [tertiaryIslandDist, tertiaryIslandRadius, islandBetweenPlayersDist, islandBetweenPlayersRadius] = islandSizes[sizeID]; - - const islandID_center = 4 * numPlayers; - numIslands = islandID_center + 1; - initIsConnected(); - - g_Map.log("Creating central island"); - islandPos[islandID_center] = mapCenter; - createIsland(islandID_center, centralIslandRadius, clLand); + function createIsland(islandID, size, tileClass) + { + createArea( + new ClumpPlacer(size * diskArea(playerIslandRadius), 0.95, 0.6, Infinity, + islandPos[islandID]), + [ + new TerrainPainter(tHill), + new SmoothElevationPainter(ELEVATION_SET, heightIsland, 2), + new TileClassPainter(tileClass) + ]); + } - for (let playerID = 0; playerID < numPlayers; ++playerID) + function createIslandAtRadialLocation(playerID, islandID, playerIDOffset, distFromCenter, + islandRadius) { - const playerID_neighbor = playerID + 1 < numPlayers ? playerID + 1 : 0; - - const islandID_player = playerID; - const islandID_playerNeighbor = playerID_neighbor; - const islandID_betweenPlayers = playerID + numPlayers; - const islandID_betweenPlayerAndCenter = playerID + 2 * numPlayers; - const islandID_betweenPlayerAndCenterNeighbor = playerID_neighbor + 2 * numPlayers; - const islandID_tertiary = playerID + 3 * numPlayers; - - g_Map.log("Creating island between the player and their neighbor"); - isConnected[islandID_betweenPlayers][islandID_player] = 1; - isConnected[islandID_betweenPlayers][islandID_playerNeighbor] = 1; - createIslandAtRadialLocation(playerID, islandID_betweenPlayers, 1, islandBetweenPlayersDist, islandBetweenPlayersRadius); - - g_Map.log("Creating an island between the player and the center"); - isConnected[islandID_betweenPlayerAndCenter][islandID_player] = 1; - isConnected[islandID_betweenPlayerAndCenter][islandID_center] = 1; - isConnected[islandID_betweenPlayerAndCenter][islandID_betweenPlayerAndCenterNeighbor] = 1; - createIslandAtRadialLocation(playerID, islandID_betweenPlayerAndCenter, 0, islandBetweenPlayerAndCenterDist, islandBetweenPlayerAndCenterRadius); - - g_Map.log("Creating tertiary island, at the map border"); - isConnected[islandID_tertiary][islandID_betweenPlayers] = 1; - createIslandAtRadialLocation(playerID, islandID_tertiary, 1, tertiaryIslandDist, tertiaryIslandRadius); + const angle = startAngle + (playerID * 2 + playerIDOffset) * Math.PI / numPlayers; + islandPos[islandID] = Vector2D.add(mapCenter, + new Vector2D(fractionToTiles(distFromCenter), 0).rotate(-angle)).round(); + createIsland(islandID, islandRadius, clLand); } -} -/** - * Creates one island in front of every player and connects it with the neighbors. - */ -function createSnowflakeSearockWithoutCenter() -{ - numIslands = 2 * numPlayers; - initIsConnected(); + function createSnowflakeSearockWithCenter(sizeID) + { + const [tertiaryIslandDist, tertiaryIslandRadius, islandBetweenPlayersDist, + islandBetweenPlayersRadius] = islandSizes[sizeID]; + + const islandID_center = 4 * numPlayers; + numIslands = islandID_center + 1; + initIsConnected(); + + g_Map.log("Creating central island"); + islandPos[islandID_center] = mapCenter; + createIsland(islandID_center, centralIslandRadius, clLand); + + for (let playerID = 0; playerID < numPlayers; ++playerID) + { + const playerID_neighbor = playerID + 1 < numPlayers ? playerID + 1 : 0; + + const islandID_player = playerID; + const islandID_playerNeighbor = playerID_neighbor; + const islandID_betweenPlayers = playerID + numPlayers; + const islandID_betweenPlayerAndCenter = playerID + 2 * numPlayers; + const islandID_betweenPlayerAndCenterNeighbor = playerID_neighbor + 2 * numPlayers; + const islandID_tertiary = playerID + 3 * numPlayers; + + g_Map.log("Creating island between the player and their neighbor"); + isConnected[islandID_betweenPlayers][islandID_player] = 1; + isConnected[islandID_betweenPlayers][islandID_playerNeighbor] = 1; + createIslandAtRadialLocation(playerID, islandID_betweenPlayers, 1, + islandBetweenPlayersDist, islandBetweenPlayersRadius); + + g_Map.log("Creating an island between the player and the center"); + isConnected[islandID_betweenPlayerAndCenter][islandID_player] = 1; + isConnected[islandID_betweenPlayerAndCenter][islandID_center] = 1; + isConnected[islandID_betweenPlayerAndCenter][islandID_betweenPlayerAndCenterNeighbor] = 1; + createIslandAtRadialLocation(playerID, islandID_betweenPlayerAndCenter, 0, + islandBetweenPlayerAndCenterDist, islandBetweenPlayerAndCenterRadius); + + g_Map.log("Creating tertiary island, at the map border"); + isConnected[islandID_tertiary][islandID_betweenPlayers] = 1; + createIslandAtRadialLocation(playerID, islandID_tertiary, 1, tertiaryIslandDist, + tertiaryIslandRadius); + } + } - for (let playerID = 0; playerID < numPlayers; ++playerID) + /** + * Creates one island in front of every player and connects it with the neighbors. + */ + function createSnowflakeSearockWithoutCenter() { - const playerID_neighbor = playerID + 1 < numPlayers ? playerID + 1 : 0; + numIslands = 2 * numPlayers; + initIsConnected(); + + for (let playerID = 0; playerID < numPlayers; ++playerID) + { + const playerID_neighbor = playerID + 1 < numPlayers ? playerID + 1 : 0; - const islandID_player = playerID; - const islandID_playerNeighbor = playerID_neighbor; - const islandID_inFrontOfPlayer = playerID + numPlayers; - const islandID_inFrontOfPlayerNeighbor = playerID_neighbor + numPlayers; + const islandID_player = playerID; + const islandID_playerNeighbor = playerID_neighbor; + const islandID_inFrontOfPlayer = playerID + numPlayers; + const islandID_inFrontOfPlayerNeighbor = playerID_neighbor + numPlayers; - isConnected[islandID_player][islandID_playerNeighbor] = 1; - isConnected[islandID_player][islandID_inFrontOfPlayer] = 1; - isConnected[islandID_inFrontOfPlayer][islandID_inFrontOfPlayerNeighbor] = 1; + isConnected[islandID_player][islandID_playerNeighbor] = 1; + isConnected[islandID_player][islandID_inFrontOfPlayer] = 1; + isConnected[islandID_inFrontOfPlayer][islandID_inFrontOfPlayerNeighbor] = 1; - createIslandAtRadialLocation(playerID, islandID_inFrontOfPlayer, 0, islandBetweenPlayerAndCenterDist, islandBetweenPlayerAndCenterRadius); + createIslandAtRadialLocation(playerID, islandID_inFrontOfPlayer, 0, + islandBetweenPlayerAndCenterDist, islandBetweenPlayerAndCenterRadius); + } } -} -function createSnowflakeSearockTiny() -{ - numIslands = numPlayers + 1; - initIsConnected(); + function createSnowflakeSearockTiny() + { + numIslands = numPlayers + 1; + initIsConnected(); - const islandID_center = numPlayers; + const islandID_center = numPlayers; - g_Map.log("Creating central island"); - islandPos[islandID_center] = mapCenter; - createIsland(numPlayers, 1, clLand); + g_Map.log("Creating central island"); + islandPos[islandID_center] = mapCenter; + createIsland(numPlayers, 1, clLand); - for (let playerID = 0; playerID < numPlayers; ++playerID) - { - const islandID_player = playerID; - isConnected[islandID_player][islandID_center] = 1; + for (let playerID = 0; playerID < numPlayers; ++playerID) + { + const islandID_player = playerID; + isConnected[islandID_player][islandID_center] = 1; + } } -} -const islandSizes = { - "medium": [0.41, 0.49, 0.26, 1], - "large1": [0.41, 0.49, 0.24, 1], - "large2": [0.41, 0.36, 0.28, 0.81] -}; + const islandSizes = { + "medium": [0.41, 0.49, 0.26, 1], + "large1": [0.41, 0.49, 0.24, 1], + "large2": [0.41, 0.36, 0.28, 0.81] + }; -if (mapSize <= 128) -{ - createSnowflakeSearockTiny(); -} -else if (mapSize <= 192) -{ - createSnowflakeSearockWithoutCenter(); -} -else if (mapSize <= 256) -{ - if (numPlayers < 6) - createSnowflakeSearockWithCenter("medium"); - else + if (mapSize <= 128) + { + createSnowflakeSearockTiny(); + } + else if (mapSize <= 192) + { createSnowflakeSearockWithoutCenter(); -} -else if (mapSize <= 320) -{ - if (numPlayers < 8) - createSnowflakeSearockWithCenter("medium"); + } + else if (mapSize <= 256) + { + if (numPlayers < 6) + createSnowflakeSearockWithCenter("medium"); + else + createSnowflakeSearockWithoutCenter(); + } + else if (mapSize <= 320) + { + if (numPlayers < 8) + createSnowflakeSearockWithCenter("medium"); + else + createSnowflakeSearockWithoutCenter(); + } else - createSnowflakeSearockWithoutCenter(); -} -else - createSnowflakeSearockWithCenter(numPlayers < 6 ? "large1" : "large2"); + createSnowflakeSearockWithCenter(numPlayers < 6 ? "large1" : "large2"); -g_Map.log("Creating player islands"); -for (let i = 0; i < numPlayers; ++i) -{ - islandPos[i] = playerPosition[i]; - createIsland(i, 1, isNomad() ? clLand : clPlayer); -} - -g_Map.log("Creating connectors"); -for (let i = 0; i < numIslands; ++i) - for (let j = 0; j < numIslands; ++j) - if (isConnected[i][j]) - createArea( - new PathPlacer(islandPos[i], islandPos[j], 11, 0, 1, 0, 0, Infinity), - [ - new SmoothElevationPainter(ELEVATION_SET, heightIsland, 2), - new TerrainPainter(tHill), - new TileClassPainter(clLand) - ]); - -g_Map.log("Painting cliffs"); -createArea( - new MapBoundsPlacer(), - new TerrainPainter(tCliff), - new SlopeConstraint(2, Infinity)); -Engine.SetProgress(30); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - // PlayerTileClass already marked above - "BaseResourceClass": clBaseResource, - "baseResourceConstraint": stayClasses(clPlayer, 4), - "Walls": "towers", - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - "StartingAnimal": { - }, - "Berries": { - "template": oFruitBush, - "distance": playerIslandRadius - 4 - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ], - "distance": playerIslandRadius - 4 - }, - "Trees": { - "template": oTree1, - "count": scaleByMapSize(10, 50), - "minDist": 11, - "maxDist": 11 - }, - "Decoratives": { - "template": aGrassShort + g_Map.log("Creating player islands"); + for (let i = 0; i < numPlayers; ++i) + { + islandPos[i] = playerPosition[i]; + createIsland(i, 1, isNomad() ? clLand : clPlayer); } -}); -Engine.SetProgress(40); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); -const types = [ - [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], - [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] -]; - -const forestSize = forestTrees / (scaleByMapSize(2, 8) * numPlayers) * (currentBiome() == "generic/savanna" ? 2 : 1); -const num = Math.floor(forestSize / types.length); -for (const type of types) - createAreas( - new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) - ], - [avoidClasses(clPlayer, 6, clForest, 10), stayClasses(clLand, 4)], - num); -Engine.SetProgress(55); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10), stayClasses(clLand, 5)], - 5*scaleByMapSize(4,16), 100 -); - -g_Map.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), stayClasses(clLand, 5)], - 5*scaleByMapSize(4,16), 100 -); - -g_Map.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), stayClasses(clLand, 5)], - 5*scaleByMapSize(4,16), 100 -); - -Engine.SetProgress(65); -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), + + g_Map.log("Creating connectors"); + for (let i = 0; i < numIslands; ++i) + for (let j = 0; j < numIslands; ++j) + if (isConnected[i][j]) + createArea( + new PathPlacer(islandPos[i], islandPos[j], 11, 0, 1, 0, 0, Infinity), + [ + new SmoothElevationPainter(ELEVATION_SET, heightIsland, 2), + new TerrainPainter(tHill), + new TileClassPainter(clLand) + ]); + + g_Map.log("Painting cliffs"); + createArea( + new MapBoundsPlacer(), + new TerrainPainter(tCliff), + new SlopeConstraint(2, Infinity)); + yield 30; + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + // PlayerTileClass already marked above + "BaseResourceClass": clBaseResource, + "baseResourceConstraint": stayClasses(clPlayer, 4), + "Walls": "towers", + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + "StartingAnimal": { + }, + "Berries": { + "template": oFruitBush, + "distance": playerIslandRadius - 4 + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ], + "distance": playerIslandRadius - 4 + }, + "Trees": { + "template": oTree1, + "count": scaleByMapSize(10, 50), + "minDist": 11, + "maxDist": 11 + }, + "Decoratives": { + "template": aGrassShort + } + }); + yield 40; + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + const types = [ + [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], + [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] + ]; + + const forestSize = forestTrees / (scaleByMapSize(2, 8) * numPlayers) * + (currentBiome() == "generic/savanna" ? 2 : 1); + const num = Math.floor(forestSize / types.length); + for (const type of types) + createAreas( + new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + [avoidClasses(clPlayer, 6, clForest, 10), stayClasses(clLand, 4)], + num); + yield 55; + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10), stayClasses(clLand, 5)], + 5*scaleByMapSize(4,16), 100 + ); + + g_Map.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), stayClasses(clLand, 5)], + 5*scaleByMapSize(4,16), 100 + ); + + g_Map.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), stayClasses(clLand, 5)], + 5*scaleByMapSize(4,16), 100 + ); + + yield 65; + g_Map.log("Creating dirt patches"); + for (const 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]), + new TileClassPainter(clDirt) + ], + [avoidClasses(clForest, 0, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)], + scaleByMapSize(15, 45)); + + g_Map.log("Creating grass patches"); + for (const 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, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)], + scaleByMapSize(15, 45)); + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aRockMedium, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + [avoidClasses(clForest, 0, clPlayer, 0), stayClasses(clLand, 4)], + scaleByMapSize(16, 262), 50 + ); + + g_Map.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), stayClasses(clLand, 4)], + scaleByMapSize(8, 131), 50 + ); + + yield 70; + + g_Map.log("Creating deer"); + group = new SimpleGroup( + [new SimpleObject(oMainHuntableAnimal, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 0, clPlayer, 10, clFood, 20), stayClasses(clLand, 4)], + 3 * numPlayers, 50 + ); + + yield 75; + + g_Map.log("Creating sheep"); + group = new SimpleGroup( + [new SimpleObject(oSecondaryHuntableAnimal, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 0, clPlayer, 10, clFood, 20), stayClasses(clLand, 4)], + 3 * numPlayers, 50 + ); + + g_Map.log("Creating fruits"); + group = new SimpleGroup( + [new SimpleObject(oFruitBush, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 0, clPlayer, 10, clFood, 20), stayClasses(clLand, 4)], + 3 * numPlayers, 50 + ); + yield 85; + + createStragglerTrees( + [oTree1, oTree2, oTree4, oTree3], + [avoidClasses(clForest, 1, clPlayer, 9, clMetal, 6, clRock, 6), stayClasses(clLand, 4)], + clForest, + stragglerTrees); + + let planetm = 1; + if (currentBiome() == "generic/india") + planetm = 8; + + g_Map.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(clPlayer, 2, clDirt, 0), stayClasses(clLand, 4)], + planetm * scaleByMapSize(13, 200) + ); + + yield 90; + + g_Map.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(clPlayer, 2, clDirt, 1, clForest, 0), stayClasses(clLand, 4)], + planetm * scaleByMapSize(13, 200) + ); + yield 95; + + g_Map.log("Creating bushes"); + group = new SimpleGroup( + [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] + ); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clPlayer, 1, clDirt, 1), stayClasses(clLand, 4)], + planetm * scaleByMapSize(13, 200), 50 + ); + + placePlayersNomad( + clPlayer, [ - new LayeredPainter([[tMainTerrain, tTier1Terrain],[tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]), - new TileClassPainter(clDirt) - ], - [avoidClasses(clForest, 0, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)], - scaleByMapSize(15, 45)); - -g_Map.log("Creating grass patches"); -for (const 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, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)], - scaleByMapSize(15, 45)); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aRockMedium, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - [avoidClasses(clForest, 0, clPlayer, 0), stayClasses(clLand, 4)], - scaleByMapSize(16, 262), 50 -); - -g_Map.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), stayClasses(clLand, 4)], - scaleByMapSize(8, 131), 50 -); - -Engine.SetProgress(70); - -g_Map.log("Creating deer"); -group = new SimpleGroup( - [new SimpleObject(oMainHuntableAnimal, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 0, clPlayer, 10, clFood, 20), stayClasses(clLand, 4)], - 3 * numPlayers, 50 -); - -Engine.SetProgress(75); - -g_Map.log("Creating sheep"); -group = new SimpleGroup( - [new SimpleObject(oSecondaryHuntableAnimal, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 0, clPlayer, 10, clFood, 20), stayClasses(clLand, 4)], - 3 * numPlayers, 50 -); - -g_Map.log("Creating fruits"); -group = new SimpleGroup( - [new SimpleObject(oFruitBush, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 0, clPlayer, 10, clFood, 20), stayClasses(clLand, 4)], - 3 * numPlayers, 50 -); -Engine.SetProgress(85); - -createStragglerTrees( - [oTree1, oTree2, oTree4, oTree3], - [avoidClasses(clForest, 1, clPlayer, 9, clMetal, 6, clRock, 6), stayClasses(clLand, 4)], - clForest, - stragglerTrees); - -let planetm = 1; -if (currentBiome() == "generic/india") - planetm = 8; - -g_Map.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(clPlayer, 2, clDirt, 0), stayClasses(clLand, 4)], - planetm * scaleByMapSize(13, 200) -); - -Engine.SetProgress(90); - -g_Map.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(clPlayer, 2, clDirt, 1, clForest, 0), stayClasses(clLand, 4)], - planetm * scaleByMapSize(13, 200) -); -Engine.SetProgress(95); - -g_Map.log("Creating bushes"); -group = new SimpleGroup( - [new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] -); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clPlayer, 1, clDirt, 1), stayClasses(clLand, 4)], - planetm * scaleByMapSize(13, 200), 50 -); - -placePlayersNomad( - clPlayer, - [ - stayClasses(clLand, 8), - avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clFood, 2) - ]); - -setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); -setSunRotation(randomAngle()); -setSunElevation(Math.PI * randFloat(1/5, 1/3)); - -g_Map.ExportMap(); + stayClasses(clLand, 8), + avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clFood, 2) + ]); + + setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); + setSunRotation(randomAngle()); + setSunElevation(Math.PI * randFloat(1/5, 1/3)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/stronghold.js =================================================================== --- binaries/data/mods/public/maps/random/stronghold.js +++ binaries/data/mods/public/maps/random/stronghold.js @@ -3,272 +3,275 @@ Engine.LoadLibrary("rmgen2"); Engine.LoadLibrary("rmbiome"); -setSelectedBiome(); +function* GenerateMap() +{ + setSelectedBiome(); -const heightLand = 30; + const heightLand = 30; -const g_Map = new RandomMap(heightLand, g_Terrains.mainTerrain); + global.g_Map = new RandomMap(heightLand, g_Terrains.mainTerrain); -initTileClasses(); + initTileClasses(); -createArea( - new MapBoundsPlacer(), - new TileClassPainter(g_TileClasses.land)); + createArea( + new MapBoundsPlacer(), + new TileClassPainter(g_TileClasses.land)); -Engine.SetProgress(20); + yield 20; -const [playerIDs, playerPosition] = - createBases( - ...playerPlacementByPattern( - "stronghold", - fractionToTiles(randFloat(0.2, 0.35)), - fractionToTiles(randFloat(0.05, 0.1)), - randomAngle(), - undefined), - false); -markPlayerAvoidanceArea(playerPosition, defaultPlayerBaseRadius()); + const [playerIDs, playerPosition] = + createBases( + ...playerPlacementByPattern( + "stronghold", + fractionToTiles(randFloat(0.2, 0.35)), + fractionToTiles(randFloat(0.05, 0.1)), + randomAngle(), + undefined), + false); + markPlayerAvoidanceArea(playerPosition, defaultPlayerBaseRadius()); -Engine.SetProgress(30); + yield 30; -addElements(shuffleArray([ - { - "func": addBluffs, - "baseHeight": heightLand, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.hill, 5, - g_TileClasses.mountain, 20, - g_TileClasses.plateau, 20, - g_TileClasses.player, 30, - g_TileClasses.valley, 5, - g_TileClasses.water, 7 - ], - "sizes": ["big", "huge"], - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addHills, - "avoid": [ - g_TileClasses.bluff, 5, - g_TileClasses.hill, 15, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.valley, 2, - g_TileClasses.water, 2 - ], - "sizes": ["normal", "big"], - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addMountains, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.mountain, 25, - g_TileClasses.plateau, 20, - g_TileClasses.player, 20, - g_TileClasses.valley, 10, - g_TileClasses.water, 15 - ], - "sizes": ["big", "huge"], - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addPlateaus, - "avoid": [ - g_TileClasses.bluff, 20, - g_TileClasses.mountain, 25, - g_TileClasses.plateau, 25, - g_TileClasses.player, 40, - g_TileClasses.valley, 10, - g_TileClasses.water, 15 - ], - "sizes": ["big", "huge"], - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addValleys, - "baseHeight": heightLand, - "avoid": [ - g_TileClasses.bluff, 5, - g_TileClasses.hill, 5, - g_TileClasses.mountain, 25, - g_TileClasses.plateau, 10, - g_TileClasses.player, 40, - g_TileClasses.valley, 15, - g_TileClasses.water, 10 - ], - "sizes": ["normal", "big"], - "mixes": g_AllMixes, - "amounts": g_AllAmounts - } -])); + addElements(shuffleArray([ + { + "func": addBluffs, + "baseHeight": heightLand, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.hill, 5, + g_TileClasses.mountain, 20, + g_TileClasses.plateau, 20, + g_TileClasses.player, 30, + g_TileClasses.valley, 5, + g_TileClasses.water, 7 + ], + "sizes": ["big", "huge"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addHills, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.hill, 15, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.valley, 2, + g_TileClasses.water, 2 + ], + "sizes": ["normal", "big"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addMountains, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 20, + g_TileClasses.player, 20, + g_TileClasses.valley, 10, + g_TileClasses.water, 15 + ], + "sizes": ["big", "huge"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addPlateaus, + "avoid": [ + g_TileClasses.bluff, 20, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 25, + g_TileClasses.player, 40, + g_TileClasses.valley, 10, + g_TileClasses.water, 15 + ], + "sizes": ["big", "huge"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addValleys, + "baseHeight": heightLand, + "avoid": [ + g_TileClasses.bluff, 5, + g_TileClasses.hill, 5, + g_TileClasses.mountain, 25, + g_TileClasses.plateau, 10, + g_TileClasses.player, 40, + g_TileClasses.valley, 15, + g_TileClasses.water, 10 + ], + "sizes": ["normal", "big"], + "mixes": g_AllMixes, + "amounts": g_AllAmounts + } + ])); -if (!isNomad()) - createBluffsPassages(playerPosition); + if (!isNomad()) + createBluffsPassages(playerPosition); -Engine.SetProgress(60); + yield 60; -addElements([ - { - "func": addLayeredPatches, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.dirt, 5, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.valley, 5, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - }, - { - "func": addDecoration, - "avoid": [ - g_TileClasses.bluff, 2, - g_TileClasses.forest, 2, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["normal"], - "amounts": ["normal"] - } -]); -Engine.SetProgress(70); + addElements([ + { + "func": addLayeredPatches, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.dirt, 5, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.valley, 5, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + }, + { + "func": addDecoration, + "avoid": [ + g_TileClasses.bluff, 2, + g_TileClasses.forest, 2, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["normal"], + "amounts": ["normal"] + } + ]); + yield 70; -addElements(shuffleArray([ - { - "func": addMetal, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 10, - g_TileClasses.metal, 20, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": g_AllAmounts - }, - { - "func": addStone, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 3, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 30, - g_TileClasses.rock, 20, - g_TileClasses.metal, 10, - g_TileClasses.water, 3 - ], - "sizes": ["normal"], - "mixes": ["same"], - "amounts": g_AllAmounts - }, - { - "func": addForests, - "avoid": [ - g_TileClasses.berries, - 5, g_TileClasses.bluff, - 5, g_TileClasses.forest, - 18, g_TileClasses.metal, 3, - g_TileClasses.mountain, 5, - g_TileClasses.plateau, 5, - g_TileClasses.player, 20, - g_TileClasses.rock, 3, - g_TileClasses.water, 2 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": ["few", "normal", "many", "tons"] - } -])); -Engine.SetProgress(80); + addElements(shuffleArray([ + { + "func": addMetal, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 10, + g_TileClasses.metal, 20, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": g_AllAmounts + }, + { + "func": addStone, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 3, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 30, + g_TileClasses.rock, 20, + g_TileClasses.metal, 10, + g_TileClasses.water, 3 + ], + "sizes": ["normal"], + "mixes": ["same"], + "amounts": g_AllAmounts + }, + { + "func": addForests, + "avoid": [ + g_TileClasses.berries, + 5, g_TileClasses.bluff, + 5, g_TileClasses.forest, + 18, g_TileClasses.metal, 3, + g_TileClasses.mountain, 5, + g_TileClasses.plateau, 5, + g_TileClasses.player, 20, + g_TileClasses.rock, 3, + g_TileClasses.water, 2 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": ["few", "normal", "many", "tons"] + } + ])); + yield 80; -addElements(shuffleArray([ - { - "func": addBerries, - "avoid": [ - g_TileClasses.berries, 30, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 5, - g_TileClasses.metal, 10, - g_TileClasses.mountain, 2, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 10, - g_TileClasses.spine, 2, - g_TileClasses.water, 3 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addAnimals, - "avoid": [ - g_TileClasses.animals, 20, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 2, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 20, - g_TileClasses.rock, 2, - g_TileClasses.spine, 2, - g_TileClasses.water, 3 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - }, - { - "func": addStragglerTrees, - "avoid": [ - g_TileClasses.berries, 5, - g_TileClasses.bluff, 5, - g_TileClasses.forest, 7, - g_TileClasses.metal, 2, - g_TileClasses.mountain, 1, - g_TileClasses.plateau, 2, - g_TileClasses.player, 12, - g_TileClasses.rock, 2, - g_TileClasses.spine, 2, - g_TileClasses.water, 5 - ], - "sizes": g_AllSizes, - "mixes": g_AllMixes, - "amounts": g_AllAmounts - } -])); -Engine.SetProgress(90); + addElements(shuffleArray([ + { + "func": addBerries, + "avoid": [ + g_TileClasses.berries, 30, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 5, + g_TileClasses.metal, 10, + g_TileClasses.mountain, 2, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 10, + g_TileClasses.spine, 2, + g_TileClasses.water, 3 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addAnimals, + "avoid": [ + g_TileClasses.animals, 20, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 2, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 20, + g_TileClasses.rock, 2, + g_TileClasses.spine, 2, + g_TileClasses.water, 3 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + }, + { + "func": addStragglerTrees, + "avoid": [ + g_TileClasses.berries, 5, + g_TileClasses.bluff, 5, + g_TileClasses.forest, 7, + g_TileClasses.metal, 2, + g_TileClasses.mountain, 1, + g_TileClasses.plateau, 2, + g_TileClasses.player, 12, + g_TileClasses.rock, 2, + g_TileClasses.spine, 2, + g_TileClasses.water, 5 + ], + "sizes": g_AllSizes, + "mixes": g_AllMixes, + "amounts": g_AllAmounts + } + ])); + yield 90; -placePlayersNomad( - g_TileClasses.player, - avoidClasses( - g_TileClasses.bluff, 4, - g_TileClasses.plateau, 4, - g_TileClasses.forest, 1, - g_TileClasses.metal, 4, - g_TileClasses.rock, 4, - g_TileClasses.mountain, 4, - g_TileClasses.animals, 2)); + placePlayersNomad( + g_TileClasses.player, + avoidClasses( + g_TileClasses.bluff, 4, + g_TileClasses.plateau, 4, + g_TileClasses.forest, 1, + g_TileClasses.metal, 4, + g_TileClasses.rock, 4, + g_TileClasses.mountain, 4, + g_TileClasses.animals, 2)); -g_Map.ExportMap(); + return g_Map; +} Index: binaries/data/mods/public/maps/random/survivalofthefittest.js =================================================================== --- binaries/data/mods/public/maps/random/survivalofthefittest.js +++ binaries/data/mods/public/maps/random/survivalofthefittest.js @@ -2,205 +2,222 @@ Engine.LoadLibrary("rmgen-common"); 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 = "nonbuilder|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; - -const g_Map = new RandomMap(heightHill, tMainTerrain); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clLand = g_Map.createTileClass(); -const clWomen = g_Map.createTileClass(); - -g_Map.log("Creating central area"); -createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.15)), 0.7, 0.1, Infinity, mapCenter), - [ - new TerrainPainter(tMainTerrain), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), - new TileClassPainter(clLand) - ]); -Engine.SetProgress(10); - -const [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.3)); -const halfway = distributePointsOnCircle(numPlayers, startAngle, fractionToTiles(0.375), mapCenter)[0].map(v => v.round()); -const attacker = distributePointsOnCircle(numPlayers, startAngle, fractionToTiles(0.45), mapCenter)[0].map(v => v.round()); -const passage = distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.5), mapCenter)[0]; - -g_Map.log("Creating player bases, passages, treasure seeker woman and attacker points"); -for (let i = 0; i < numPlayers; ++i) +function* GenerateMap() { - 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 - }); - - // Passage between player and neighbor + 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 = "nonbuilder|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; + + global.g_Map = new RandomMap(heightHill, tMainTerrain); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clLand = g_Map.createTileClass(); + const clWomen = g_Map.createTileClass(); + + g_Map.log("Creating central area"); createArea( - new PathPlacer(mapCenter, passage[i], scaleByMapSize(14, 24), 0.4, scaleByMapSize(3, 9), 0.2, 0.05), + new ClumpPlacer(diskArea(fractionToTiles(0.15)), 0.7, 0.1, Infinity, mapCenter), [ new TerrainPainter(tMainTerrain), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 4) + new SmoothElevationPainter(ELEVATION_SET, heightLand, 3), + new TileClassPainter(clLand) ]); - - // Treasure seeker woman - const femaleLocation = findLocationInDirectionBasedOnHeight(playerPosition[i], mapCenter, -3 , 3.5, 3).round(); - clWomen.add(femaleLocation); - g_Map.placeEntityPassable(oTreasureSeeker, playerIDs[i], femaleLocation, playerAngle[i] + Math.PI); - - // Attacker spawn point - g_Map.placeEntityAnywhere(aWaypointFlag, 0, attacker[i], Math.PI / 2); - g_Map.placeEntityPassable(triggerPointAttacker, playerIDs[i], attacker[i], Math.PI / 2); - - // Preventing mountains in the area between player and attackers at player - addCivicCenterAreaToClass(playerPosition[i], clPlayer); - clPlayer.add(attacker[i]); - clPlayer.add(halfway[i]); + yield 10; + + const [playerIDs, playerPosition, playerAngle, startAngle] = + playerPlacementCircle(fractionToTiles(0.3)); + const halfway = distributePointsOnCircle(numPlayers, startAngle, fractionToTiles(0.375), mapCenter)[0] + .map(v => v.round()); + const attacker = distributePointsOnCircle(numPlayers, startAngle, fractionToTiles(0.45), mapCenter)[0] + .map(v => v.round()); + const passage = distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, + fractionToTiles(0.5), mapCenter)[0]; + + g_Map.log("Creating player bases, passages, treasure seeker woman 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 + }); + + // Passage between player and neighbor + createArea( + new PathPlacer(mapCenter, passage[i], scaleByMapSize(14, 24), 0.4, scaleByMapSize(3, 9), + 0.2, 0.05), + [ + new TerrainPainter(tMainTerrain), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 4) + ]); + + // Treasure seeker woman + const femaleLocation = findLocationInDirectionBasedOnHeight(playerPosition[i], mapCenter, -3 , + 3.5, 3).round(); + clWomen.add(femaleLocation); + g_Map.placeEntityPassable(oTreasureSeeker, playerIDs[i], femaleLocation, + playerAngle[i] + Math.PI); + + // Attacker spawn point + g_Map.placeEntityAnywhere(aWaypointFlag, 0, attacker[i], Math.PI / 2); + g_Map.placeEntityPassable(triggerPointAttacker, playerIDs[i], attacker[i], Math.PI / 2); + + // Preventing mountains in the area between player and attackers at player + addCivicCenterAreaToClass(playerPosition[i], clPlayer); + clPlayer.add(attacker[i]); + clPlayer.add(halfway[i]); + } + yield 20; + + paintTerrainBasedOnHeight(heightLand + 0.12, heightHill - 1, Elevation_IncludeMin_ExcludeMax, + tCliff); + paintTileClassBasedOnHeight(heightLand + 0.12, heightHill - 1, Elevation_IncludeMin_ExcludeMax, + clHill); + yield 30; + + const landConstraint = new StaticConstraint(stayClasses(clLand, 5)); + + for (const triggerPointTreasure of triggerPointTreasures) + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(triggerPointTreasure, 1, 1, 0, 0)], true, clWomen), + 0, + [avoidClasses(clPlayer, 5, clHill, 5), landConstraint], + scaleByMapSize(40, 140), + 100); + yield 35; + + createBumps(landConstraint); + yield 40; + + const hillConstraint = new AndConstraint([avoidClasses(clHill, 5), + new StaticConstraint(avoidClasses(clPlayer, 20, clBaseResource, 3, clWomen, 5))]); + if (randBool()) + createHills([tMainTerrain, tCliff, tHill], [hillConstraint, landConstraint], clHill, + scaleByMapSize(10, 60) * numPlayers); + else + createMountains(tCliff, [hillConstraint, landConstraint], clHill, + scaleByMapSize(10, 60) * numPlayers); + yield 45; + + createHills( + [tCliff, tCliff, tHill], + [hillConstraint, avoidClasses(clLand, 5)], + clHill, + scaleByMapSize(15, 90) * numPlayers, + undefined, + undefined, + undefined, + undefined, + 55); + yield 50; + + const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); + createForests( + [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], + [avoidClasses(clForest, 5), new StaticConstraint([avoidClasses(clPlayer, 20, clHill, 0, + clBaseResource, 2, clWomen, 5), stayClasses(clLand, 4)])], + clForest, + forestTrees); + + yield 60; + + g_Map.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), landConstraint], + scaleByMapSize(15, 45), + clDirt); + yield 70; + + g_Map.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), landConstraint], + scaleByMapSize(15, 45), + clDirt); + yield 80; + + let planetm = 1; + if (currentBiome() == "generic/india") + 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)] + ], + [ + scaleByMapAreaAbsolute(16), + scaleByMapAreaAbsolute(8), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13), + planetm * scaleByMapAreaAbsolute(13) + ], + [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), landConstraint]); + yield 90; + + createStragglerTrees( + [oTree1, oTree2, oTree4, oTree3], + [avoidClasses(clForest, 7, clHill, 1, clPlayer, 9), stayClasses(clLand, 7)], + clForest, + stragglerTrees); + + return g_Map; } -Engine.SetProgress(20); - -paintTerrainBasedOnHeight(heightLand + 0.12, heightHill - 1, Elevation_IncludeMin_ExcludeMax, tCliff); -paintTileClassBasedOnHeight(heightLand + 0.12, heightHill - 1, Elevation_IncludeMin_ExcludeMax, clHill); -Engine.SetProgress(30); - -const landConstraint = new StaticConstraint(stayClasses(clLand, 5)); - -for (const triggerPointTreasure of triggerPointTreasures) - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(triggerPointTreasure, 1, 1, 0, 0)], true, clWomen), - 0, - [avoidClasses(clPlayer, 5, clHill, 5), landConstraint], - scaleByMapSize(40, 140), - 100); -Engine.SetProgress(35); - -createBumps(landConstraint); -Engine.SetProgress(40); - -const hillConstraint = new AndConstraint([avoidClasses(clHill, 5), new StaticConstraint(avoidClasses(clPlayer, 20, clBaseResource, 3, clWomen, 5))]); -if (randBool()) - createHills([tMainTerrain, tCliff, tHill], [hillConstraint, landConstraint], clHill, scaleByMapSize(10, 60) * numPlayers); -else - createMountains(tCliff, [hillConstraint, landConstraint], clHill, scaleByMapSize(10, 60) * numPlayers); -Engine.SetProgress(45); - -createHills( - [tCliff, tCliff, tHill], - [hillConstraint, avoidClasses(clLand, 5)], - clHill, - scaleByMapSize(15, 90) * numPlayers, - undefined, - undefined, - undefined, - undefined, - 55); -Engine.SetProgress(50); - -const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); -createForests( - [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], - [avoidClasses(clForest, 5), new StaticConstraint([avoidClasses(clPlayer, 20, clHill, 0, clBaseResource, 2, clWomen, 5), stayClasses(clLand, 4)])], - clForest, - forestTrees); - -Engine.SetProgress(60); - -g_Map.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), landConstraint], - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(70); - -g_Map.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), landConstraint], - scaleByMapSize(15, 45), - clDirt); -Engine.SetProgress(80); - -let planetm = 1; -if (currentBiome() == "generic/india") - 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)] - ], - [ - scaleByMapAreaAbsolute(16), - scaleByMapAreaAbsolute(8), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13), - planetm * scaleByMapAreaAbsolute(13) - ], - [avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), landConstraint]); -Engine.SetProgress(90); - -createStragglerTrees( - [oTree1, oTree2, oTree4, oTree3], - [avoidClasses(clForest, 7, clHill, 1, clPlayer, 9), stayClasses(clLand, 7)], - clForest, - stragglerTrees); - -Engine.SetProgress(95); - -g_Map.ExportMap(); Index: binaries/data/mods/public/maps/random/syria.js =================================================================== --- binaries/data/mods/public/maps/random/syria.js +++ binaries/data/mods/public/maps/random/syria.js @@ -1,285 +1,292 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tMainDirt = ["desert_dirt_rocks_1", "desert_dirt_cracks"]; -const tForestFloor1 = "forestfloor_dirty"; -const tForestFloor2 = "desert_forestfloor_palms"; -const tGrassSands = "desert_grass_a_sand"; -const tGrass = "desert_grass_a"; -const tSecondaryDirt = "medit_dirt_dry"; -const tCliff = ["desert_cliff_persia_1", "desert_cliff_persia_2"]; -const tHill = ["desert_dirt_rocks_1", "desert_dirt_rocks_2", "desert_dirt_rocks_3"]; -const tDirt = ["desert_dirt_rough", "desert_dirt_rough_2"]; -const tRoad = "desert_shore_stones"; -const tRoadWild = "desert_grass_a_stones"; - -const oTamarix = "gaia/tree/tamarix"; -const oPalm = "gaia/tree/date_palm"; -const oPine = "gaia/tree/aleppo_pine"; -const oBush = "gaia/fruit/grapes"; -const oCamel = "gaia/fauna_camel"; -const oGazelle = "gaia/fauna_gazelle"; -const oLion = "gaia/fauna_lion"; -const oStoneLarge = "gaia/rock/desert_large"; -const oStoneSmall = "gaia/rock/desert_small"; -const oMetalLarge = "gaia/ore/desert_large"; - -const aRock = "actor|geology/stone_desert_med.xml"; -const aBushA = "actor|props/flora/bush_desert_dry_a.xml"; -const aBushB = "actor|props/flora/bush_desert_dry_a.xml"; -const aBushes = [aBushA, aBushB]; - -const pForestP = [tForestFloor2 + TERRAIN_SEPARATOR + oPalm, tForestFloor2]; -const pForestT = [tForestFloor1 + TERRAIN_SEPARATOR + oTamarix,tForestFloor2]; - -const heightLand = 1; -const heightHill = 22; -const heightOffsetBump = 2; - -const g_Map = new RandomMap(heightLand, tMainDirt); - -const mapCenter = g_Map.getCenter(); -const numPlayers = getNumPlayers(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clGrass = g_Map.createTileClass(); - -const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - -g_Map.log("Creating big grass patches around the playerbases"); -for (let i = 0; i < numPlayers; ++i) +function* GenerateMap() { - if (!isNomad()) + const tMainDirt = ["desert_dirt_rocks_1", "desert_dirt_cracks"]; + const tForestFloor1 = "forestfloor_dirty"; + const tForestFloor2 = "desert_forestfloor_palms"; + const tGrassSands = "desert_grass_a_sand"; + const tGrass = "desert_grass_a"; + const tSecondaryDirt = "medit_dirt_dry"; + const tCliff = ["desert_cliff_persia_1", "desert_cliff_persia_2"]; + const tHill = ["desert_dirt_rocks_1", "desert_dirt_rocks_2", "desert_dirt_rocks_3"]; + const tDirt = ["desert_dirt_rough", "desert_dirt_rough_2"]; + const tRoad = "desert_shore_stones"; + const tRoadWild = "desert_grass_a_stones"; + + const oTamarix = "gaia/tree/tamarix"; + const oPalm = "gaia/tree/date_palm"; + const oPine = "gaia/tree/aleppo_pine"; + const oBush = "gaia/fruit/grapes"; + const oCamel = "gaia/fauna_camel"; + const oGazelle = "gaia/fauna_gazelle"; + const oLion = "gaia/fauna_lion"; + const oStoneLarge = "gaia/rock/desert_large"; + const oStoneSmall = "gaia/rock/desert_small"; + const oMetalLarge = "gaia/ore/desert_large"; + + const aRock = "actor|geology/stone_desert_med.xml"; + const aBushA = "actor|props/flora/bush_desert_dry_a.xml"; + const aBushB = "actor|props/flora/bush_desert_dry_a.xml"; + const aBushes = [aBushA, aBushB]; + + const pForestP = [tForestFloor2 + TERRAIN_SEPARATOR + oPalm, tForestFloor2]; + const pForestT = [tForestFloor1 + TERRAIN_SEPARATOR + oTamarix,tForestFloor2]; + + const heightLand = 1; + const heightHill = 22; + const heightOffsetBump = 2; + + global.g_Map = new RandomMap(heightLand, tMainDirt); + + const mapCenter = g_Map.getCenter(); + const numPlayers = getNumPlayers(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clGrass = g_Map.createTileClass(); + + const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + + g_Map.log("Creating big grass patches around the playerbases"); + for (let i = 0; i < numPlayers; ++i) + { + if (!isNomad()) + createArea( + new ClumpPlacer(diskArea(defaultPlayerBaseRadius()), 0.9, 0.5, Infinity, + playerPosition[i]), + new TileClassPainter(clPlayer)); + createArea( - new ClumpPlacer(diskArea(defaultPlayerBaseRadius()), 0.9, 0.5, Infinity, playerPosition[i]), - new TileClassPainter(clPlayer)); - - createArea( - new ChainPlacer( - 2, - Math.floor(scaleByMapSize(5, 12)), - Math.floor(scaleByMapSize(25, 60)) / (isNomad() ? 2 : 1), - Infinity, - playerPosition[i], - 0, - [Math.floor(scaleByMapSize(16, 30))]), - [ - new LayeredPainter([tGrassSands, tGrass], [3]), - new TileClassPainter(clGrass) - ]); -} -Engine.SetProgress(10); - -placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - // PlayerTileClass marked above - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad, - "radius": 10, - "width": 3 - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ], - "groupElements": [new RandomObject(aBushes, 2, 4, 2, 3)] - }, - "Trees": { - "template": pickRandom([oPalm, oTamarix]), - "count": 3 + new ChainPlacer( + 2, + Math.floor(scaleByMapSize(5, 12)), + Math.floor(scaleByMapSize(25, 60)) / (isNomad() ? 2 : 1), + Infinity, + playerPosition[i], + 0, + [Math.floor(scaleByMapSize(16, 30))]), + [ + new LayeredPainter([tGrassSands, tGrass], [3]), + new TileClassPainter(clGrass) + ]); } - // No decoratives -}); -Engine.SetProgress(20); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - avoidClasses(clPlayer, 13), - scaleByMapSize(300, 800)); - -g_Map.log("Creating hills"); -createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), - [ - new LayeredPainter([tCliff, tHill], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 3, clGrass, 1, clHill, 10), - scaleByMapSize(1, 3) * numPlayers * 3); - -Engine.SetProgress(25); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(400, 2000, 0.7); -const types = [ - [[tMainDirt, tForestFloor2, pForestP], [tForestFloor2, pForestP]], - [[tMainDirt, tForestFloor1, pForestT], [tForestFloor1, pForestT]] -]; -const forestSize = forestTrees / (scaleByMapSize(3,6) * numPlayers); -const num = Math.floor(forestSize / types.length); -for (const type of types) + yield 10; + + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + // PlayerTileClass marked above + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad, + "radius": 10, + "width": 3 + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ], + "groupElements": [new RandomObject(aBushes, 2, 4, 2, 3)] + }, + "Trees": { + "template": pickRandom([oPalm, oTamarix]), + "count": 3 + } + // No decoratives + }); + yield 20; + + g_Map.log("Creating bumps"); createAreas( - new ChainPlacer( - 1, - Math.floor(scaleByMapSize(3, 5)), - forestTrees / (num * Math.floor(scaleByMapSize(2, 4))), - 0.5), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) - ], - avoidClasses(clPlayer, 1, clGrass, 1, clForest, 10, clHill, 1), - num); - -Engine.SetProgress(40); + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + avoidClasses(clPlayer, 13), + scaleByMapSize(300, 800)); -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) + g_Map.log("Creating hills"); createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), - new LayeredPainter([tSecondaryDirt, tDirt], [1]), - avoidClasses(clHill, 0, clForest, 0, clPlayer, 8, clGrass, 1), - scaleByMapSize(50, 90)); -Engine.SetProgress(60); - -g_Map.log("Creating big patches"); -for (const size of [scaleByMapSize(6, 30), scaleByMapSize(10, 50), scaleByMapSize(16, 70)]) - createAreas( - new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), - new LayeredPainter([tSecondaryDirt, tDirt], [1]), - avoidClasses(clHill, 0, clForest, 0, clPlayer, 8, clGrass, 1), - scaleByMapSize(30, 90)); -Engine.SetProgress(70); - -g_Map.log("Creating stone mines"); -createObjectGroupsDeprecated( - new SimpleGroup( + new ChainPlacer(1, Math.floor(scaleByMapSize(4, 6)), Math.floor(scaleByMapSize(16, 40)), 0.5), [ - new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), - new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4), - new RandomObject(aBushes, 2, 4, 0, 2) + new LayeredPainter([tCliff, tHill], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) ], - true, - clRock), - 0, - [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1, clGrass, 1)], - scaleByMapSize(2, 8), - 100); - -g_Map.log("Creating small stone quarries"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3), new RandomObject(aBushes, 2,4, 0,2)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1, clGrass, 1)], - scaleByMapSize(2,8), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4), new RandomObject(aBushes, 2,4, 0,2)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 1, clGrass, 1)], - scaleByMapSize(2,8), 100 -); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aRock, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), - scaleByMapSize(16, 262), 50 -); - -g_Map.log("Creating bushes"); -group = new SimpleGroup( - [new SimpleObject(aBushB, 1,2, 0,1), new SimpleObject(aBushA, 1,3, 0,2)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), - scaleByMapSize(50, 500), 50 -); -Engine.SetProgress(80); - -g_Map.log("Creating gazelle"); -group = new SimpleGroup( - [new SimpleObject(oGazelle, 5,7, 0,4)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clGrass, 2), - 3 * numPlayers, 50 -); - -g_Map.log("Creating lions"); -group = new SimpleGroup( - [new SimpleObject(oLion, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clGrass, 2), - 3 * numPlayers, 50 -); - -g_Map.log("Creating camels"); -group = new SimpleGroup( - [new SimpleObject(oCamel, 2,3, 0,2)], - true, clFood -); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clGrass, 2), - 3 * numPlayers, 50 -); -Engine.SetProgress(85); - -createStragglerTrees( - [oPalm, oTamarix, oPine], - avoidClasses(clForest, 1, clHill, 1, clPlayer, 1, clMetal, 6, clRock, 6), - clForest, - stragglerTrees); - -createStragglerTrees( - [oPalm, oTamarix, oPine], - [avoidClasses(clForest, 1, clHill, 1, clPlayer, 1, clMetal, 6, clRock, 6), stayClasses(clGrass, 3)], - clForest, - stragglerTrees * (isNomad() ? 3 : 1)); - -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); - -setSkySet("sunny"); -setSunElevation(Math.PI / 8); -setSunRotation(randomAngle()); -setSunColor(0.746, 0.718, 0.539); -setWaterColor(0.292, 0.347, 0.691); -setWaterTint(0.550, 0.543, 0.437); -setWaterMurkiness(0.83); - -setFogColor(0.8, 0.76, 0.61); -setFogThickness(0.2); -setFogFactor(0.4); - -setPPEffect("hdr"); -setPPContrast(0.65); -setPPSaturation(0.42); -setPPBloom(0.6); - -g_Map.ExportMap(); + avoidClasses(clPlayer, 3, clGrass, 1, clHill, 10), + scaleByMapSize(1, 3) * numPlayers * 3); + + yield 25; + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(400, 2000, 0.7); + const types = [ + [[tMainDirt, tForestFloor2, pForestP], [tForestFloor2, pForestP]], + [[tMainDirt, tForestFloor1, pForestT], [tForestFloor1, pForestT]] + ]; + const forestSize = forestTrees / (scaleByMapSize(3,6) * numPlayers); + const num = Math.floor(forestSize / types.length); + for (const type of types) + createAreas( + new ChainPlacer( + 1, + Math.floor(scaleByMapSize(3, 5)), + forestTrees / (num * Math.floor(scaleByMapSize(2, 4))), + 0.5), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 1, clGrass, 1, clForest, 10, clHill, 1), + num); + + yield 40; + + g_Map.log("Creating dirt patches"); + for (const 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([tSecondaryDirt, tDirt], [1]), + avoidClasses(clHill, 0, clForest, 0, clPlayer, 8, clGrass, 1), + scaleByMapSize(50, 90)); + yield 60; + + g_Map.log("Creating big patches"); + for (const size of [scaleByMapSize(6, 30), scaleByMapSize(10, 50), scaleByMapSize(16, 70)]) + createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), + new LayeredPainter([tSecondaryDirt, tDirt], [1]), + avoidClasses(clHill, 0, clForest, 0, clPlayer, 8, clGrass, 1), + scaleByMapSize(30, 90)); + yield 70; + + g_Map.log("Creating stone mines"); + createObjectGroupsDeprecated( + new SimpleGroup( + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4), + new RandomObject(aBushes, 2, 4, 0, 2) + ], + true, + clRock), + 0, + [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1, clGrass, 1)], + scaleByMapSize(2, 8), + 100); + + g_Map.log("Creating small stone quarries"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3), + new RandomObject(aBushes, 2,4, 0,2)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1, clGrass, 1)], + scaleByMapSize(2,8), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4), + new RandomObject(aBushes, 2,4, 0,2)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 1, clGrass, 1)], + scaleByMapSize(2,8), 100 + ); + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aRock, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), + scaleByMapSize(16, 262), 50 + ); + + g_Map.log("Creating bushes"); + group = new SimpleGroup( + [new SimpleObject(aBushB, 1,2, 0,1), new SimpleObject(aBushA, 1,3, 0,2)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), + scaleByMapSize(50, 500), 50 + ); + yield 80; + + g_Map.log("Creating gazelle"); + group = new SimpleGroup( + [new SimpleObject(oGazelle, 5,7, 0,4)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clGrass, 2), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating lions"); + group = new SimpleGroup( + [new SimpleObject(oLion, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clGrass, 2), + 3 * numPlayers, 50 + ); + + g_Map.log("Creating camels"); + group = new SimpleGroup( + [new SimpleObject(oCamel, 2,3, 0,2)], + true, clFood + ); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 1, clHill, 1, clFood, 20, clGrass, 2), + 3 * numPlayers, 50 + ); + yield 85; + + createStragglerTrees( + [oPalm, oTamarix, oPine], + avoidClasses(clForest, 1, clHill, 1, clPlayer, 1, clMetal, 6, clRock, 6), + clForest, + stragglerTrees); + + createStragglerTrees( + [oPalm, oTamarix, oPine], + [avoidClasses(clForest, 1, clHill, 1, clPlayer, 1, clMetal, 6, clRock, 6), + stayClasses(clGrass, 3)], + clForest, + stragglerTrees * (isNomad() ? 3 : 1)); + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); + + setSkySet("sunny"); + setSunElevation(Math.PI / 8); + setSunRotation(randomAngle()); + setSunColor(0.746, 0.718, 0.539); + setWaterColor(0.292, 0.347, 0.691); + setWaterTint(0.550, 0.543, 0.437); + setWaterMurkiness(0.83); + + setFogColor(0.8, 0.76, 0.61); + setFogThickness(0.2); + setFogFactor(0.4); + + setPPEffect("hdr"); + setPPContrast(0.65); + setPPSaturation(0.42); + setPPBloom(0.6); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/tests/test_Constraint.js =================================================================== --- binaries/data/mods/public/maps/random/tests/test_Constraint.js +++ binaries/data/mods/public/maps/random/tests/test_Constraint.js @@ -10,10 +10,11 @@ Engine.LoadLibrary("rmgen"); -var g_MapSettings = { "Size": 512 }; -var g_Map = new RandomMap(0, "blackness"); - +function* GenerateMap() { + global.g_MapSettings = { "Size": 512 }; + global.g_Map = new RandomMap(0, "blackness"); + let tileClass = new TileClass(g_Map.getSize()); let addedPos = new Vector2D(5, 0); Index: binaries/data/mods/public/maps/random/tests/test_DiskPlacer.js =================================================================== --- binaries/data/mods/public/maps/random/tests/test_DiskPlacer.js +++ binaries/data/mods/public/maps/random/tests/test_DiskPlacer.js @@ -10,9 +10,10 @@ Engine.LoadLibrary("rmgen"); +function* GenerateMap() { - var g_MapSettings = { "Size": 512 }; - var g_Map = new RandomMap(0, "blackness"); + global.g_MapSettings = { "Size": 512 }; + global.g_Map = new RandomMap(0, "blackness"); let center = new Vector2D(10, 10); let area = createArea(new DiskPlacer(3, center)); @@ -44,30 +45,3 @@ // Contains map edge TS_ASSERT(area.contains(new Vector2D(0, 0))); } - -{ - // Contains points outside map disk range on CircularMap - var g_MapSettings = { "Size": 512, "CircularMap": true }; - var g_Map = new RandomMap(0, "blackness"); - var area = createArea(new DiskPlacer(10, new Vector2D(436, 436))); - - TS_ASSERT(area.contains(new Vector2D(438, 438))); - TS_ASSERT(area.contains(new Vector2D(437, 436))); - TS_ASSERT(area.contains(new Vector2D(436, 437))); - TS_ASSERT(area.contains(new Vector2D(435, 435))); - - area = createArea(new DiskPlacer(3, new Vector2D(0, 0))); - // Does not allow points out of map boundaries - TS_ASSERT(!area.contains(new Vector2D(-1, -1))); -} - -{ - var g_MapSettings = { "Size": 320, "CircularMap": true }; - var g_Map = new RandomMap(0, "blackness"); - // Does not error with floating point radius - var area = createArea(new DiskPlacer(86.4, new Vector2D(160, 160))); - // Does not error with extreme out of bounds disk - area = createArea(new DiskPlacer(86.4, new Vector2D(800, 800))); - // Does not error when disk on edge - area = createArea(new DiskPlacer(10, new Vector2D(321, 321))); -} Index: binaries/data/mods/public/maps/random/tests/test_DiskPlacerCircularMap.js =================================================================== --- /dev/null +++ binaries/data/mods/public/maps/random/tests/test_DiskPlacerCircularMap.js @@ -0,0 +1,27 @@ +Engine.GetTemplate = path => ( + { + "Identity": { + "GenericName": null, + "Icon": null, + "History": null + } + }); + +Engine.LoadLibrary("rmgen"); + +function* GenerateMap() +{ + // Contains points outside map disk range on CircularMap + global.g_MapSettings = { "Size": 512, "CircularMap": true }; + global.g_Map = new RandomMap(0, "blackness"); + var area = createArea(new DiskPlacer(10, new Vector2D(436, 436))); + + TS_ASSERT(area.contains(new Vector2D(438, 438))); + TS_ASSERT(area.contains(new Vector2D(437, 436))); + TS_ASSERT(area.contains(new Vector2D(436, 437))); + TS_ASSERT(area.contains(new Vector2D(435, 435))); + + area = createArea(new DiskPlacer(3, new Vector2D(0, 0))); + // Does not allow points out of map boundaries + TS_ASSERT(!area.contains(new Vector2D(-1, -1))); +} Index: binaries/data/mods/public/maps/random/tests/test_DiskPlacerError.js =================================================================== --- /dev/null +++ binaries/data/mods/public/maps/random/tests/test_DiskPlacerError.js @@ -0,0 +1,22 @@ +Engine.GetTemplate = path => ( + { + "Identity": { + "GenericName": null, + "Icon": null, + "History": null + } + }); + +Engine.LoadLibrary("rmgen"); + +function* GenerateMap() +{ + global.g_MapSettings = { "Size": 320, "CircularMap": true }; + global.g_Map = new RandomMap(0, "blackness"); + // Does not error with floating point radius + var area = createArea(new DiskPlacer(86.4, new Vector2D(160, 160))); + // Does not error with extreme out of bounds disk + area = createArea(new DiskPlacer(86.4, new Vector2D(800, 800))); + // Does not error when disk on edge + area = createArea(new DiskPlacer(10, new Vector2D(321, 321))); +} Index: binaries/data/mods/public/maps/random/tests/test_LayeredPainter.js =================================================================== --- binaries/data/mods/public/maps/random/tests/test_LayeredPainter.js +++ binaries/data/mods/public/maps/random/tests/test_LayeredPainter.js @@ -10,10 +10,11 @@ Engine.LoadLibrary("rmgen"); -var g_MapSettings = { "Size": 512 }; -var g_Map = new RandomMap(0, "blackness"); - +function* GenerateMap() { + global.g_MapSettings = { "Size": 512 }; + global.g_Map = new RandomMap(0, "blackness"); + let min = new Vector2D(4, 4); let max = new Vector2D(10, 10); Index: binaries/data/mods/public/maps/random/tests/test_RecoverableError.js =================================================================== --- binaries/data/mods/public/maps/random/tests/test_RecoverableError.js +++ binaries/data/mods/public/maps/random/tests/test_RecoverableError.js @@ -8,7 +8,6 @@ { TS_ASSERT(error instanceof Error); TS_ASSERT_EQUALS(error.message, "Failed to convert the yielded value to an integer."); - yield 50; return; } Index: binaries/data/mods/public/maps/random/tests/test_RectPlacer.js =================================================================== --- binaries/data/mods/public/maps/random/tests/test_RectPlacer.js +++ binaries/data/mods/public/maps/random/tests/test_RectPlacer.js @@ -10,10 +10,11 @@ Engine.LoadLibrary("rmgen"); -var g_MapSettings = { "Size": 512 }; -var g_Map = new RandomMap(0, "blackness"); - +function* GenerateMap() { + global.g_MapSettings = { "Size": 512 }; + global.g_Map = new RandomMap(0, "blackness"); + let min = new Vector2D(5, 5); let max = new Vector2D(7, 7); Index: binaries/data/mods/public/maps/random/tests/test_SmoothingPainter.js =================================================================== --- binaries/data/mods/public/maps/random/tests/test_SmoothingPainter.js +++ binaries/data/mods/public/maps/random/tests/test_SmoothingPainter.js @@ -10,10 +10,10 @@ Engine.LoadLibrary("rmgen"); -var g_MapSettings = { "Size": 512 }; -var g_Map; - +function* GenerateMap() { + global.g_MapSettings = { "Size": 512 }; + let min = new Vector2D(5, 5); let center = new Vector2D(6, 6); let max = new Vector2D(7, 7); @@ -23,7 +23,7 @@ // Test SmoothingPainter { - g_Map = new RandomMap(0, "blackness"); + global.g_Map = new RandomMap(0, "blackness"); let centerHeight = g_Map.getHeight(center); Index: binaries/data/mods/public/maps/random/tests/test_TileClass.js =================================================================== --- binaries/data/mods/public/maps/random/tests/test_TileClass.js +++ binaries/data/mods/public/maps/random/tests/test_TileClass.js @@ -10,56 +10,59 @@ Engine.LoadLibrary("rmgen"); -var g_MapSettings = { "Size": 512 }; -var g_Map = new RandomMap(0, "blackness"); - -// Test that that it checks by value, not by reference +function* GenerateMap() { - const tileClass = new TileClass(2); - const reference1 = new Vector2D(1, 1); - const reference2 = new Vector2D(1, 1); - tileClass.add(reference1); - TS_ASSERT(tileClass.has(reference2)); -} + global.g_MapSettings = { "Size": 512 }; + global.g_Map = new RandomMap(0, "blackness"); -// Test out-of-bounds -{ - const tileClass = new TileClass(32); + // Test that that it checks by value, not by reference + { + const tileClass = new TileClass(2); + const reference1 = new Vector2D(1, 1); + const reference2 = new Vector2D(1, 1); + tileClass.add(reference1); + TS_ASSERT(tileClass.has(reference2)); + } - const absentPoints = [ - new Vector2D(0, 0), - new Vector2D(0, 1), - new Vector2D(1, 0), - new Vector2D(-1, -1), - new Vector2D(2048, 0), - new Vector2D(0, NaN), - new Vector2D(0, Infinity) - ]; + // Test out-of-bounds + { + const tileClass = new TileClass(32); - for (const point of absentPoints) - TS_ASSERT(!tileClass.has(point)); -} + const absentPoints = [ + new Vector2D(0, 0), + new Vector2D(0, 1), + new Vector2D(1, 0), + new Vector2D(-1, -1), + new Vector2D(2048, 0), + new Vector2D(0, NaN), + new Vector2D(0, Infinity) + ]; -// Test getters -{ - const tileClass = new TileClass(88); + for (const point of absentPoints) + TS_ASSERT(!tileClass.has(point)); + } + + // Test getters + { + const tileClass = new TileClass(88); - const point = new Vector2D(5, 5); - tileClass.add(point); + const point = new Vector2D(5, 5); + tileClass.add(point); - const pointBorder = new Vector2D(1, 9); - tileClass.add(pointBorder); + const pointBorder = new Vector2D(1, 9); + tileClass.add(pointBorder); - TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 0), 1); - TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 1), 1); - TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 100), 2); + TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 0), 1); + TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 1), 1); + TS_ASSERT_EQUALS(tileClass.countMembersInRadius(point, 100), 2); - TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 1), 4); - TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 2), 12); - TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 3), 28); + TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 1), 4); + TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 2), 12); + TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(point, 3), 28); - // Points not on the map are not counted. - TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(pointBorder, 1), 4); - TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(pointBorder, 2), 11); - TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(pointBorder, 3), 22); + // Points not on the map are not counted. + TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(pointBorder, 1), 4); + TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(pointBorder, 2), 11); + TS_ASSERT_EQUALS(tileClass.countNonMembersInRadius(pointBorder, 3), 22); + } } Index: binaries/data/mods/public/maps/random/the_nile.js =================================================================== --- binaries/data/mods/public/maps/random/the_nile.js +++ binaries/data/mods/public/maps/random/the_nile.js @@ -1,412 +1,431 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tPrimary = "desert_sand_dunes_100"; -const tCity = "desert_city_tile"; -const tCityPlaza = "desert_city_tile_plaza"; -const tFineSand = "desert_sand_smooth"; -const tForestFloor = "desert_forestfloor_palms"; -const tGrass = "desert_dirt_rough_2"; -const tGrassSand50 = "desert_sand_dunes_50"; -const tGrassSand25 = "desert_dirt_rough"; -const tDirt = "desert_dirt_rough"; -const tDirtCracks = "desert_dirt_cracks"; -const tShore = "desert_sand_wet"; -const tLush = "desert_grass_a"; -const tSLush = "desert_grass_a_sand"; -const tSDry = "desert_plants_b"; - -const oBerryBush = "gaia/fruit/berry_01"; -const oCamel = "gaia/fauna_camel"; -const oGazelle = "gaia/fauna_gazelle"; -const oGoat = "gaia/fauna_goat"; -const oStoneLarge = "gaia/rock/badlands_large"; -const oStoneSmall = "gaia/rock/desert_small"; -const oMetalLarge = "gaia/ore/desert_large"; -const oDatePalm = "gaia/tree/date_palm"; -const oSDatePalm = "gaia/tree/cretan_date_palm_short"; -const eObelisk = "structures/obelisk"; -const ePyramid = "gaia/ruins/pyramid_minor"; -const oWoodTreasure = "gaia/treasure/wood"; -const oFoodTreasure = "gaia/treasure/food_bin"; - -const aBush1 = "actor|props/flora/bush_desert_a.xml"; -const aBush2 = "actor|props/flora/bush_desert_dry_a.xml"; -const aBush3 = "actor|props/flora/bush_medit_sm_dry.xml"; -const aBush4 = "actor|props/flora/plant_desert_a.xml"; -const aDecorativeRock = "actor|geology/stone_desert_med.xml"; -const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; -const aLillies = "actor|props/flora/water_lillies.xml"; - -const pForest = [tForestFloor + TERRAIN_SEPARATOR + oDatePalm, tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, tForestFloor]; - -const heightLand = 1; -const heightShore = 2; -const heightPonds = -7; -const heightSeaGround = -3; -const heightOffsetBump = 2; - -const g_Map = new RandomMap(heightLand, tPrimary); - -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const aPlants = mapSize < 256 ? - "actor|props/flora/grass_tropical.xml" : - "actor|props/flora/grass_tropic_field_tall.xml"; - -const numPlayers = getNumPlayers(); - -const clPlayer = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clGrass = g_Map.createTileClass(); -const clDesert = g_Map.createTileClass(); -const clPond = g_Map.createTileClass(); -const clShore = g_Map.createTileClass(); -const clTreasure = g_Map.createTileClass(); - -const desertWidth = fractionToTiles(0.25); -const startAngle = randomAngle(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementRiver(startAngle, fractionToTiles(0.4)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tCityPlaza, - "innerTerrain": tCity - }, - "StartingAnimal": { - }, - "Berries": { - "template": oBerryBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oDatePalm, - "count": 2 - }, - "Decoratives": { - "template": aBush1 - } -}); -Engine.SetProgress(30); - -const riverTextures = [ - { - "left": fractionToTiles(0), - "right": fractionToTiles(0.04), - "terrain": tLush, - "tileClass": clShore - }, - { - "left": fractionToTiles(0.04), - "right": fractionToTiles(0.06), - "terrain": tSLush, - "tileClass": clShore - }, - { - "left": fractionToTiles(0.06), - "right": fractionToTiles(0.09), - "terrain": tSDry, - "tileClass": clShore - }, - { - "left": fractionToTiles(0.25), - "right": fractionToTiles(0.5), - "tileClass": clDesert - } -]; - -const plantFrequency = 2; -let plantID = 0; - -paintRiver({ - "parallel": true, - "start": new Vector2D(mapCenter.x, mapBounds.top).rotateAround(startAngle, mapCenter), - "end": new Vector2D(mapCenter.x, mapBounds.bottom).rotateAround(startAngle, mapCenter), - "width": fractionToTiles(0.1), - "fadeDist": scaleByMapSize(3, 12), - "deviation": 0.5, - "heightRiverbed": heightSeaGround, - "heightLand": heightShore, - "meanderShort": 12, - "meanderLong": 50, - "waterFunc": (position, height, riverFraction) => { - - clWater.add(position); - createTerrain(tShore).place(position); - - // Place river bushes - if (height <= -0.2 || height >= 0.1) - return; - - if (plantID % plantFrequency == 0) - { - plantID = 0; - g_Map.placeEntityAnywhere(aPlants, 0, position, randomAngle()); +function* GenerateMap() +{ + const tPrimary = "desert_sand_dunes_100"; + const tCity = "desert_city_tile"; + const tCityPlaza = "desert_city_tile_plaza"; + const tFineSand = "desert_sand_smooth"; + const tForestFloor = "desert_forestfloor_palms"; + const tGrass = "desert_dirt_rough_2"; + const tGrassSand50 = "desert_sand_dunes_50"; + const tGrassSand25 = "desert_dirt_rough"; + const tDirt = "desert_dirt_rough"; + const tDirtCracks = "desert_dirt_cracks"; + const tShore = "desert_sand_wet"; + const tLush = "desert_grass_a"; + const tSLush = "desert_grass_a_sand"; + const tSDry = "desert_plants_b"; + + const oBerryBush = "gaia/fruit/berry_01"; + const oCamel = "gaia/fauna_camel"; + const oGazelle = "gaia/fauna_gazelle"; + const oGoat = "gaia/fauna_goat"; + const oStoneLarge = "gaia/rock/badlands_large"; + const oStoneSmall = "gaia/rock/desert_small"; + const oMetalLarge = "gaia/ore/desert_large"; + const oDatePalm = "gaia/tree/date_palm"; + const oSDatePalm = "gaia/tree/cretan_date_palm_short"; + const eObelisk = "structures/obelisk"; + const ePyramid = "gaia/ruins/pyramid_minor"; + const oWoodTreasure = "gaia/treasure/wood"; + const oFoodTreasure = "gaia/treasure/food_bin"; + + const aBush1 = "actor|props/flora/bush_desert_a.xml"; + const aBush2 = "actor|props/flora/bush_desert_dry_a.xml"; + const aBush3 = "actor|props/flora/bush_medit_sm_dry.xml"; + const aBush4 = "actor|props/flora/plant_desert_a.xml"; + const aDecorativeRock = "actor|geology/stone_desert_med.xml"; + const aReeds = "actor|props/flora/reeds_pond_lush_a.xml"; + const aLillies = "actor|props/flora/water_lillies.xml"; + + const pForest = [tForestFloor + TERRAIN_SEPARATOR + oDatePalm, + tForestFloor + TERRAIN_SEPARATOR + oSDatePalm, tForestFloor]; + + const heightLand = 1; + const heightShore = 2; + const heightPonds = -7; + const heightSeaGround = -3; + const heightOffsetBump = 2; + + global.g_Map = new RandomMap(heightLand, tPrimary); + + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const aPlants = mapSize < 256 ? + "actor|props/flora/grass_tropical.xml" : + "actor|props/flora/grass_tropic_field_tall.xml"; + + const numPlayers = getNumPlayers(); + + const clPlayer = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clGrass = g_Map.createTileClass(); + const clDesert = g_Map.createTileClass(); + const clPond = g_Map.createTileClass(); + const clShore = g_Map.createTileClass(); + const clTreasure = g_Map.createTileClass(); + + const desertWidth = fractionToTiles(0.25); + const startAngle = randomAngle(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementRiver(startAngle, fractionToTiles(0.4)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tCityPlaza, + "innerTerrain": tCity + }, + "StartingAnimal": { + }, + "Berries": { + "template": oBerryBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oDatePalm, + "count": 2 + }, + "Decoratives": { + "template": aBush1 } - ++plantID; - }, - "landFunc": (position, shoreDist1, shoreDist2) => { + }); + yield 30; - for (const riv of riverTextures) - if (riv.left < +shoreDist1 && +shoreDist1 < riv.right || - riv.left < -shoreDist2 && -shoreDist2 < riv.right) + const riverTextures = [ + { + "left": fractionToTiles(0), + "right": fractionToTiles(0.04), + "terrain": tLush, + "tileClass": clShore + }, + { + "left": fractionToTiles(0.04), + "right": fractionToTiles(0.06), + "terrain": tSLush, + "tileClass": clShore + }, + { + "left": fractionToTiles(0.06), + "right": fractionToTiles(0.09), + "terrain": tSDry, + "tileClass": clShore + }, + { + "left": fractionToTiles(0.25), + "right": fractionToTiles(0.5), + "tileClass": clDesert + } + ]; + + const plantFrequency = 2; + let plantID = 0; + + paintRiver({ + "parallel": true, + "start": new Vector2D(mapCenter.x, mapBounds.top).rotateAround(startAngle, mapCenter), + "end": new Vector2D(mapCenter.x, mapBounds.bottom).rotateAround(startAngle, mapCenter), + "width": fractionToTiles(0.1), + "fadeDist": scaleByMapSize(3, 12), + "deviation": 0.5, + "heightRiverbed": heightSeaGround, + "heightLand": heightShore, + "meanderShort": 12, + "meanderLong": 50, + "waterFunc": (position, height, riverFraction) => { + + clWater.add(position); + createTerrain(tShore).place(position); + + // Place river bushes + if (height <= -0.2 || height >= 0.1) + return; + + if (plantID % plantFrequency == 0) { - riv.tileClass.add(position); - - if (riv.terrain) - createTerrain(riv.terrain).place(position); + plantID = 0; + g_Map.placeEntityAnywhere(aPlants, 0, position, randomAngle()); } - } -}); -Engine.SetProgress(40); - -g_Map.log("Creating bumps"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - avoidClasses(clWater, 2, clPlayer, 6), - scaleByMapSize(100, 200)); - -g_Map.log("Creating ponds"); -const numLakes = Math.round(scaleByMapSize(1, 4) * numPlayers / 2); -const waterAreas = createAreas( - new ClumpPlacer(scaleByMapSize(2, 5) * 50, 0.8, 0.1, Infinity), - [ - new TerrainPainter(tShore), - new SmoothElevationPainter(ELEVATION_SET, heightPonds, 4), - new TileClassPainter(clPond) - ], - avoidClasses(clPlayer, 25, clWater, 20, clPond, 10), - numLakes); - -g_Map.log("Creating reeds"); -createObjectGroupsByAreasDeprecated( - new SimpleGroup([new SimpleObject(aReeds, 1, 3, 0, 1)], true), - 0, - stayClasses(clPond, 1), - numLakes, - 100, - waterAreas); - -g_Map.log("Creating lillies"); -createObjectGroupsByAreasDeprecated( - new SimpleGroup([new SimpleObject(aLillies, 1, 3, 0, 1)], true), - 0, - stayClasses(clPond, 1), - numLakes, - 100, - waterAreas); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(700, 3500, 0.5); -const num = scaleByMapSize(10,30); -createAreas( - new ClumpPlacer(forestTrees / num, 0.15, 0.1, 0.5), - [ - new TerrainPainter([pForest, tForestFloor]), - new TileClassPainter(clForest) - ], - avoidClasses(clPlayer, 19, clForest, 4, clWater, 1, clDesert, 5, clPond, 2, clBaseResource, 3), - num, - 50); - -Engine.SetProgress(50); - -g_Map.log("Creating grass patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + ++plantID; + }, + "landFunc": (position, shoreDist1, shoreDist2) => { + + for (const riv of riverTextures) + if (riv.left < +shoreDist1 && +shoreDist1 < riv.right || + riv.left < -shoreDist2 && -shoreDist2 < riv.right) + { + riv.tileClass.add(position); + + if (riv.terrain) + createTerrain(riv.terrain).place(position); + } + } + }); + yield 40; + + g_Map.log("Creating bumps"); createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + avoidClasses(clWater, 2, clPlayer, 6), + scaleByMapSize(100, 200)); + + g_Map.log("Creating ponds"); + const numLakes = Math.round(scaleByMapSize(1, 4) * numPlayers / 2); + const waterAreas = createAreas( + new ClumpPlacer(scaleByMapSize(2, 5) * 50, 0.8, 0.1, Infinity), [ - new LayeredPainter( - [[tGrass, tGrassSand50], [tGrassSand50, tGrassSand25], [tGrassSand25, tGrass]], - [1, 1]), - new TileClassPainter(clDirt) + new TerrainPainter(tShore), + new SmoothElevationPainter(ELEVATION_SET, heightPonds, 4), + new TileClassPainter(clPond) ], - avoidClasses(clForest, 0, clGrass, 5, clPlayer, 10, clWater, 1, clDirt, 5, clShore, 1, clPond, 1), - scaleByMapSize(15, 45)); -Engine.SetProgress(55); - -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + avoidClasses(clPlayer, 25, clWater, 20, clPond, 10), + numLakes); + + g_Map.log("Creating reeds"); + createObjectGroupsByAreasDeprecated( + new SimpleGroup([new SimpleObject(aReeds, 1, 3, 0, 1)], true), + 0, + stayClasses(clPond, 1), + numLakes, + 100, + waterAreas); + + g_Map.log("Creating lillies"); + createObjectGroupsByAreasDeprecated( + new SimpleGroup([new SimpleObject(aLillies, 1, 3, 0, 1)], true), + 0, + stayClasses(clPond, 1), + numLakes, + 100, + waterAreas); + + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(700, 3500, 0.5); + const num = scaleByMapSize(10,30); createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), + new ClumpPlacer(forestTrees / num, 0.15, 0.1, 0.5), [ - new LayeredPainter( - [[tDirt, tDirtCracks], [tDirt, tFineSand], [tDirtCracks, tFineSand]], - [1, 1]), - new TileClassPainter(clDirt) + new TerrainPainter([pForest, tForestFloor]), + new TileClassPainter(clForest) ], - avoidClasses(clForest, 0, clDirt, 5, clPlayer, 10, clWater, 1, clGrass, 5, clShore, 1, clPond, 1), - scaleByMapSize(15, 45)); - -Engine.SetProgress(60); - -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 1, clPond, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 1, clPond, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clWater, 1, clPond, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating stone mines"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 1, clPond, 1), stayClasses(clDesert, 3)], - scaleByMapSize(6,20), 100 -); - -g_Map.log("Creating small stone quarries"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 1, clPond, 1), stayClasses(clDesert, 3)], - scaleByMapSize(6,20), 100 -); - -g_Map.log("Creating metal mines"); -group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); -createObjectGroupsDeprecated(group, 0, - [avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clWater, 1, clPond, 1), stayClasses(clDesert, 3)], - scaleByMapSize(6,20), 100 -); - -Engine.SetProgress(65); - -g_Map.log("Creating small decorative rocks"); -group = new SimpleGroup( - [new SimpleObject(aDecorativeRock, 1,3, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clPond, 1), - scaleByMapSize(16, 262), 50 -); - -g_Map.log("Creating shrubs"); -group = new SimpleGroup( - [new SimpleObject(aBush2, 1,2, 0,1), new SimpleObject(aBush1, 1,3, 0,2), new SimpleObject(aBush4, 1,2, 0,1), new SimpleObject(aBush3, 1,3, 0,2)], - true -); -createObjectGroupsDeprecated( - group, 0, - avoidClasses(clWater, 1, clPlayer, 0, clPond, 1), - scaleByMapSize(20, 180), 50 -); -Engine.SetProgress(70); - -g_Map.log("Creating gazelles"); -group = new SimpleGroup([new SimpleObject(oGazelle, 5,7, 0,4)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 20, clWater, 1, clFood, 10, clDesert, 5, clPond, 1), - 3*scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating goats"); -group = new SimpleGroup([new SimpleObject(oGoat, 2,4, 0,3)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 20, clWater, 1, clFood, 10, clDesert, 5, clPond, 1), - 3*scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating treasures"); -group = new SimpleGroup([new SimpleObject(oFoodTreasure, 1,1, 0,2)], true, clTreasure); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 20, clWater, 1, clFood, 2, clDesert, 5, clTreasure, 6, clPond, 1), - 3*scaleByMapSize(5,20), 50 -); - -group = new SimpleGroup([new SimpleObject(oWoodTreasure, 1,1, 0,2)], true, clTreasure); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 20, clWater, 1, clFood, 2, clDesert, 5, clTreasure, 6, clPond, 1), - 3*scaleByMapSize(5,20), 50 -); - -g_Map.log("Creating camels"); -group = new SimpleGroup([new SimpleObject(oCamel, 2,4, 0,2)], true, clFood); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 0, clPlayer, 20, clWater, 1, clFood, 10, clDesert, 5, clTreasure, 2, clPond, 1), - 3*scaleByMapSize(5,20), 50 -); - -Engine.SetProgress(90); - -createStragglerTrees( - [oDatePalm, oSDatePalm], - avoidClasses(clForest, 0, clWater, 1, clPlayer, 20, clMetal, 6, clDesert, 1, clTreasure, 2, clPond, 1), - clForest, - stragglerTrees / 2); - -createStragglerTrees( - [oDatePalm, oSDatePalm], - avoidClasses(clForest, 0, clWater, 1, clPlayer, 20, clMetal, 6, clTreasure, 2), - clForest, - stragglerTrees / 10); - -createStragglerTrees( - [oDatePalm, oSDatePalm], - borderClasses(clPond, 1, 4), - clForest, - stragglerTrees); - -g_Map.log("Creating obelisks"); -group = new SimpleGroup( - [new SimpleObject(eObelisk, 1,1, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - [avoidClasses(clWater, 4, clForest, 3, clPlayer, 20, clMetal, 6, clRock, 6, clPond, 4, clTreasure, 2), stayClasses(clDesert, 3)], - scaleByMapSize(5, 30), 50 -); - -g_Map.log("Creating pyramids"); -group = new SimpleGroup( - [new SimpleObject(ePyramid, 1,1, 0,1)], - true -); -createObjectGroupsDeprecated( - group, 0, - [avoidClasses(clWater, 7, clForest, 6, clPlayer, 20, clMetal, 5, clRock, 5, clPond, 7, clTreasure, 2), stayClasses(clDesert, 3)], - scaleByMapSize(2, 6), 50 -); - -placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); - -setSkySet("sunny"); -setSunColor(0.711, 0.746, 0.574); -setWaterColor(0.541,0.506,0.416); -setWaterTint(0.694,0.592,0.522); -setWaterMurkiness(1); -setWaterWaviness(3.0); -setWaterType("lake"); - -g_Map.ExportMap(); + avoidClasses(clPlayer, 19, clForest, 4, clWater, 1, clDesert, 5, clPond, 2, clBaseResource, 3), + num, + 50); + + yield 50; + + g_Map.log("Creating grass patches"); + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new LayeredPainter( + [[tGrass, tGrassSand50], [tGrassSand50, tGrassSand25], + [tGrassSand25, tGrass]], + [1, 1]), + new TileClassPainter(clDirt) + ], + avoidClasses(clForest, 0, clGrass, 5, clPlayer, 10, clWater, 1, clDirt, 5, clShore, 1, + clPond, 1), + scaleByMapSize(15, 45)); + yield 55; + + g_Map.log("Creating dirt patches"); + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new LayeredPainter( + [[tDirt, tDirtCracks], [tDirt, tFineSand], [tDirtCracks, tFineSand]], + [1, 1]), + new TileClassPainter(clDirt) + ], + avoidClasses(clForest, 0, clDirt, 5, clPlayer, 10, clWater, 1, clGrass, 5, clShore, 1, + clPond, 1), + scaleByMapSize(15, 45)); + + yield 60; + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 1, clPond, 1), + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 1, clPond, 1), + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clWater, 1, clPond, 1), + scaleByMapSize(4,16), 100 + ); + + g_Map.log("Creating stone mines"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 1, clPond, 1), + stayClasses(clDesert, 3)], + scaleByMapSize(6,20), 100 + ); + + g_Map.log("Creating small stone quarries"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clWater, 1, clPond, 1), + stayClasses(clDesert, 3)], + scaleByMapSize(6,20), 100 + ); + + g_Map.log("Creating metal mines"); + group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); + createObjectGroupsDeprecated(group, 0, + [avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clWater, 1, clPond, 1), + stayClasses(clDesert, 3)], + scaleByMapSize(6,20), 100 + ); + + yield 65; + + g_Map.log("Creating small decorative rocks"); + group = new SimpleGroup( + [new SimpleObject(aDecorativeRock, 1,3, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clPond, 1), + scaleByMapSize(16, 262), 50 + ); + + g_Map.log("Creating shrubs"); + group = new SimpleGroup( + [new SimpleObject(aBush2, 1,2, 0,1), new SimpleObject(aBush1, 1,3, 0,2), + new SimpleObject(aBush4, 1,2, 0,1), new SimpleObject(aBush3, 1,3, 0,2)], + true + ); + createObjectGroupsDeprecated( + group, 0, + avoidClasses(clWater, 1, clPlayer, 0, clPond, 1), + scaleByMapSize(20, 180), 50 + ); + yield 70; + + g_Map.log("Creating gazelles"); + group = new SimpleGroup([new SimpleObject(oGazelle, 5,7, 0,4)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 20, clWater, 1, clFood, 10, clDesert, 5, clPond, 1), + 3*scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating goats"); + group = new SimpleGroup([new SimpleObject(oGoat, 2,4, 0,3)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 20, clWater, 1, clFood, 10, clDesert, 5, clPond, 1), + 3*scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating treasures"); + group = new SimpleGroup([new SimpleObject(oFoodTreasure, 1,1, 0,2)], true, clTreasure); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 20, clWater, 1, clFood, 2, clDesert, 5, clTreasure, 6, + clPond, 1), + 3*scaleByMapSize(5,20), 50 + ); + + group = new SimpleGroup([new SimpleObject(oWoodTreasure, 1,1, 0,2)], true, clTreasure); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 20, clWater, 1, clFood, 2, clDesert, 5, clTreasure, 6, + clPond, 1), + 3*scaleByMapSize(5,20), 50 + ); + + g_Map.log("Creating camels"); + group = new SimpleGroup([new SimpleObject(oCamel, 2,4, 0,2)], true, clFood); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 0, clPlayer, 20, clWater, 1, clFood, 10, clDesert, 5, clTreasure, 2, + clPond, 1), + 3*scaleByMapSize(5,20), 50 + ); + + yield 90; + + createStragglerTrees( + [oDatePalm, oSDatePalm], + avoidClasses(clForest, 0, clWater, 1, clPlayer, 20, clMetal, 6, clDesert, 1, clTreasure, 2, + clPond, 1), + clForest, + stragglerTrees / 2); + + createStragglerTrees( + [oDatePalm, oSDatePalm], + avoidClasses(clForest, 0, clWater, 1, clPlayer, 20, clMetal, 6, clTreasure, 2), + clForest, + stragglerTrees / 10); + + createStragglerTrees( + [oDatePalm, oSDatePalm], + borderClasses(clPond, 1, 4), + clForest, + stragglerTrees); + + g_Map.log("Creating obelisks"); + group = new SimpleGroup( + [new SimpleObject(eObelisk, 1,1, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + [avoidClasses(clWater, 4, clForest, 3, clPlayer, 20, clMetal, 6, clRock, 6, clPond, 4, + clTreasure, 2), stayClasses(clDesert, 3)], + scaleByMapSize(5, 30), 50 + ); + + g_Map.log("Creating pyramids"); + group = new SimpleGroup( + [new SimpleObject(ePyramid, 1,1, 0,1)], + true + ); + createObjectGroupsDeprecated( + group, 0, + [avoidClasses(clWater, 7, clForest, 6, clPlayer, 20, clMetal, 5, clRock, 5, clPond, 7, + clTreasure, 2), stayClasses(clDesert, 3)], + scaleByMapSize(2, 6), 50 + ); + + placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); + + setSkySet("sunny"); + setSunColor(0.711, 0.746, 0.574); + setWaterColor(0.541,0.506,0.416); + setWaterTint(0.694,0.592,0.522); + setWaterMurkiness(1); + setWaterWaviness(3.0); + setWaterType("lake"); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/unknown.js =================================================================== --- binaries/data/mods/public/maps/random/unknown.js +++ binaries/data/mods/public/maps/random/unknown.js @@ -4,1075 +4,1132 @@ 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.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 oTree4 = g_Gaia.tree4; -const oTree5 = g_Gaia.tree5; -const oFruitBush = g_Gaia.fruitBush; -const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal; -const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; -const oFish = g_Gaia.fish; -const oStoneLarge = g_Gaia.stoneLarge; -const oStoneSmall = g_Gaia.stoneSmall; -const oMetalLarge = g_Gaia.metalLarge; -const oWoodTreasure = "gaia/treasure/wood"; - -const aGrass = g_Decoratives.grass; -const aGrassShort = g_Decoratives.grassShort; -const aReeds = g_Decoratives.reeds; -const aLillies = g_Decoratives.lillies; -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 heightCliff = 3.12; -const heightHill = 18; -const heightOffsetBump = 2; - -const g_Map = new RandomMap(heightSeaGround, tWater); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -const clPlayer = g_Map.createTileClass(); -const clPlayerTerritory = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clWater = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clFood = g_Map.createTileClass(); -const clPeninsulaSteam = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); -const clLand = g_Map.createTileClass(); -const clShallow = g_Map.createTileClass(); - -var landElevationPainter = new SmoothElevationPainter(ELEVATION_SET, heightLand, 4); - -var unknownMapFunctions = { - "land": [ - "Continent", - "Isthmus", - "CentralRiverLand", - "EdgeSeas", - "Gulf", - "Lakes", - "Passes", - "Lowlands", - "Mainland" - ], - "naval": [ - "CentralSea", - "CentralRiverNaval", - "Archipelago", - "RiversAndLake" - ] -}; - -/** - * The player IDs and locations shall only be determined by the landscape functions if it's not a nomad game, - * because nomad maps randomize the locations after the terrain generation. - * The locations should only determined by the landscape functions to avoid placing bodies of water and resources into civic centers and the starting resources. - */ -var playerIDs = sortAllPlayers(); -var playerPosition = []; - -var g_StartingTreasures = false; -var g_StartingWalls = true; - -function createUnknownMap() +function* GenerateMap(mapSettings) { - const landscape = g_MapSettings.Landscape || pickRandom([...unknownMapFunctions.land, ...unknownMapFunctions.naval]); - global["unknown" + landscape](); - - paintUnknownMapBasedOnHeight(); + 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 oTree4 = g_Gaia.tree4; + const oTree5 = g_Gaia.tree5; + const oFruitBush = g_Gaia.fruitBush; + const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal; + const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; + const oFish = g_Gaia.fish; + const oStoneLarge = g_Gaia.stoneLarge; + const oStoneSmall = g_Gaia.stoneSmall; + const oMetalLarge = g_Gaia.metalLarge; + const oWoodTreasure = "gaia/treasure/wood"; + + const aGrass = g_Decoratives.grass; + const aGrassShort = g_Decoratives.grassShort; + const aReeds = g_Decoratives.reeds; + const aLillies = g_Decoratives.lillies; + 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 heightCliff = 3.12; + const heightHill = 18; + const heightOffsetBump = 2; + + global.g_Map = new RandomMap(heightSeaGround, tWater); + + const numPlayers = getNumPlayers(); + const mapSize = g_Map.getSize(); + const mapCenter = g_Map.getCenter(); + const mapBounds = g_Map.getBounds(); + + const clPlayer = g_Map.createTileClass(); + const clPlayerTerritory = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clWater = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clFood = g_Map.createTileClass(); + const clPeninsulaSteam = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + const clLand = g_Map.createTileClass(); + const clShallow = g_Map.createTileClass(); + + var landElevationPainter = new SmoothElevationPainter(ELEVATION_SET, heightLand, 4); + + var unknownMapFunctions = { + "land": [ + "Continent", + "Isthmus", + "CentralRiverLand", + "EdgeSeas", + "Gulf", + "Lakes", + "Passes", + "Lowlands", + "Mainland" + ], + "naval": [ + "CentralSea", + "CentralRiverNaval", + "Archipelago", + "RiversAndLake" + ] + }; + + /** + * The player IDs and locations shall only be determined by the landscape functions if it's not a + * nomad game, because nomad maps randomize the locations after the terrain generation. + * The locations should only determined by the landscape functions to avoid placing bodies of water + * and resources into civic centers and the starting resources. + */ + var playerIDs = sortAllPlayers(); + var playerPosition = []; + + var startingTreasures = false; + var startingWalls = true; + + const unknownFunctions = {}; + + function* createUnknownMap() + { + const landscape = mapSettings.Landscape || pickRandom( + [...unknownMapFunctions.land, ...unknownMapFunctions.naval]); + unknownFunctions[landscape](); - createUnknownPlayerBases(); + paintUnknownMapBasedOnHeight(); - createUnknownObjects(); + createUnknownPlayerBases(); - placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2, clWater, 10)); -} + yield* createUnknownObjects(); -/** - * Chain of islands or many disconnected islands. - */ -function unknownArchipelago() -{ - g_StartingWalls = "towers"; - g_StartingTreasures = true; - - const [pIDs, islandPosition] = playerPlacementCircle(fractionToTiles(0.35)); - if (!isNomad()) - { - [playerIDs, playerPosition] = [pIDs, islandPosition]; - markPlayerArea("large"); + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, + 2, clWater, 10)); } - g_Map.log("Creating islands"); - const islandSize = diskArea(scaleByMapSize(17, 29)); - for (let i = 0; i < numPlayers; ++i) - createArea( - new ClumpPlacer(islandSize, 0.8, 0.1, Infinity, islandPosition[i]), - landElevationPainter); - - const type = isNomad() ? randIntInclusive(1, 2) : randIntInclusive(1, 3); - if (type == 1) + /** + * Chain of islands or many disconnected islands. + */ + unknownFunctions.Archipelago = function() { - g_Map.log("Creating archipelago"); - createAreas( - new ClumpPlacer(islandSize * randFloat(0.8, 1.2), 0.8, 0.1, Infinity), - [ - landElevationPainter, - new TileClassPainter(clLand) - ], - null, - scaleByMapSize(2, 5) * randIntInclusive(8, 14)); + startingWalls = "towers"; + startingTreasures = true; - g_Map.log("Creating shore jaggedness with small puddles"); - createAreas( - new ClumpPlacer(scaleByMapSize(15, 80), 0.2, 0.1, Infinity), - [ - new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), - new TileClassPainter(clLand) - ], - borderClasses(clLand, 6, 3), - scaleByMapSize(12, 130) * 2, - 150); - } - else if (type == 2) - { - g_Map.log("Creating islands"); - createAreas( - new ClumpPlacer(islandSize * randFloat(0.6, 1.4), 0.8, 0.1, randFloat(0.0, 0.2)), - [ - landElevationPainter, - new TileClassPainter(clLand) - ], - avoidClasses(clLand, 3, clPlayerTerritory, 3), - scaleByMapSize(6, 10) * randIntInclusive(8, 14)); + const [pIDs, islandPosition] = playerPlacementCircle(fractionToTiles(0.35)); + if (!isNomad()) + { + [playerIDs, playerPosition] = [pIDs, islandPosition]; + markPlayerArea("large"); + } - g_Map.log("Creating small islands"); - createAreas( - new ClumpPlacer(islandSize * randFloat(0.3, 0.7), 0.8, 0.1, 0.07), - [ - new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), - new TileClassPainter(clLand) - ], - avoidClasses(clLand, 3, clPlayerTerritory, 3), - scaleByMapSize(2, 6) * randIntInclusive(6, 15), - 25); - } - else if (type == 3) - { - g_Map.log("Creating tight islands"); - createAreas( - new ClumpPlacer(islandSize * randFloat(0.8, 1.2), 0.8, 0.1, Infinity), - [ - landElevationPainter, - new TileClassPainter(clLand) - ], - avoidClasses(clLand, randIntInclusive(8, 16), clPlayerTerritory, 3), - scaleByMapSize(2, 5) * randIntInclusive(8, 14)); - } -} + g_Map.log("Creating islands"); + const islandSize = diskArea(scaleByMapSize(17, 29)); + for (let i = 0; i < numPlayers; ++i) + createArea( + new ClumpPlacer(islandSize, 0.8, 0.1, Infinity, islandPosition[i]), + landElevationPainter); -/** - * Disk shaped mainland with water on the edge. - */ -function unknownContinent() -{ - const waterHeight = -5; + const type = isNomad() ? randIntInclusive(1, 2) : randIntInclusive(1, 3); + if (type == 1) + { + g_Map.log("Creating archipelago"); + createAreas( + new ClumpPlacer(islandSize * randFloat(0.8, 1.2), 0.8, 0.1, Infinity), + [ + landElevationPainter, + new TileClassPainter(clLand) + ], + null, + scaleByMapSize(2, 5) * randIntInclusive(8, 14)); - if (!isNomad()) - { - g_Map.log("Ensuring player area"); - [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.25)); - markPlayerArea("small"); + g_Map.log("Creating shore jaggedness with small puddles"); + createAreas( + new ClumpPlacer(scaleByMapSize(15, 80), 0.2, 0.1, Infinity), + [ + new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), + new TileClassPainter(clLand) + ], + borderClasses(clLand, 6, 3), + scaleByMapSize(12, 130) * 2, + 150); + } + else if (type == 2) + { + g_Map.log("Creating islands"); + createAreas( + new ClumpPlacer(islandSize * randFloat(0.6, 1.4), 0.8, 0.1, randFloat(0.0, 0.2)), + [ + landElevationPainter, + new TileClassPainter(clLand) + ], + avoidClasses(clLand, 3, clPlayerTerritory, 3), + scaleByMapSize(6, 10) * randIntInclusive(8, 14)); - for (let i = 0; i < numPlayers; ++i) - createArea( - new ChainPlacer( - 2, - Math.floor(scaleByMapSize(5, 9)), - Math.floor(scaleByMapSize(5, 20)), - Infinity, - playerPosition[i], - 0, - [Math.floor(scaleByMapSize(23, 50))]), + g_Map.log("Creating small islands"); + createAreas( + new ClumpPlacer(islandSize * randFloat(0.3, 0.7), 0.8, 0.1, 0.07), + [ + new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), + new TileClassPainter(clLand) + ], + avoidClasses(clLand, 3, clPlayerTerritory, 3), + scaleByMapSize(2, 6) * randIntInclusive(6, 15), + 25); + } + else if (type == 3) + { + g_Map.log("Creating tight islands"); + createAreas( + new ClumpPlacer(islandSize * randFloat(0.8, 1.2), 0.8, 0.1, Infinity), [ landElevationPainter, new TileClassPainter(clLand) - ]); + ], + avoidClasses(clLand, randIntInclusive(8, 16), clPlayerTerritory, 3), + scaleByMapSize(2, 5) * randIntInclusive(8, 14)); + } } - g_Map.log("Creating continent"); - createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.38)), 0.9, 0.09, Infinity, mapCenter), - [ - landElevationPainter, - new TileClassPainter(clLand) - ]); - - if (randBool(1/3)) + /** + * Disk shaped mainland with water on the edge. + */ + unknownFunctions.Continent = function() { - g_Map.log("Creating peninsula (i.e. half the map not being surrounded by water)"); - const angle = randomAngle(); - const peninsulaPosition1 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.25), 0).rotate(-angle)); + const waterHeight = -5; + + if (!isNomad()) + { + g_Map.log("Ensuring player area"); + [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.25)); + markPlayerArea("small"); + + for (let i = 0; i < numPlayers; ++i) + createArea( + new ChainPlacer( + 2, + Math.floor(scaleByMapSize(5, 9)), + Math.floor(scaleByMapSize(5, 20)), + Infinity, + playerPosition[i], + 0, + [Math.floor(scaleByMapSize(23, 50))]), + [ + landElevationPainter, + new TileClassPainter(clLand) + ]); + } + + g_Map.log("Creating continent"); createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.38)), 0.9, 0.09, Infinity, peninsulaPosition1), + new ClumpPlacer(diskArea(fractionToTiles(0.38)), 0.9, 0.09, Infinity, mapCenter), [ landElevationPainter, new TileClassPainter(clLand) ]); - g_Map.log("Remembering to not paint shorelines into the peninsula"); - const peninsulaPosition2 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.35), 0).rotate(-angle)); - createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.33)), 0.9, 0.01, Infinity, peninsulaPosition2), - new TileClassPainter(clPeninsulaSteam)); - } - - createShoreJaggedness(waterHeight, clLand, 7); -} - -function unknownCentralSea() -{ - unknownCentralSeaOrIsthmus(false); -} - -function unknownIsthmus() -{ - unknownCentralSeaOrIsthmus(true); -} + if (randBool(1/3)) + { + g_Map.log("Creating peninsula (i.e. half the map not being surrounded by water)"); + const angle = randomAngle(); + const peninsulaPosition1 = Vector2D.add(mapCenter, + new Vector2D(fractionToTiles(0.25), 0).rotate(-angle)); + createArea( + new ClumpPlacer(diskArea(fractionToTiles(0.38)), 0.9, 0.09, Infinity, + peninsulaPosition1), + [ + landElevationPainter, + new TileClassPainter(clLand) + ]); -/** - * Creates a huge central river, possibly connecting the riversides with a narrow piece of land. - */ -function unknownCentralSeaOrIsthmus(isthmus) -{ - const waterHeight = -3; - - const startAngle = randomAngle(); - - const [riverStart, riverEnd] = centralRiverCoordinates(startAngle); - - paintRiver({ - "parallel": false, - "start": riverStart, - "end": riverEnd, - "width": fractionToTiles(scaleByMapSize(0.27, 0.42) + randFloat(0, 0.08)), - "fadeDist": scaleByMapSize(3, 12), - "deviation": 0, - "heightRiverbed": waterHeight, - "heightLand": heightLand, - "meanderShort": 20, - "meanderLong": 0, - "waterFunc": (position, height, riverFraction) => { - if (height < 0) - clWater.add(position); - }, - "landFunc": (position, shoreDist1, shoreDist2) => { - g_Map.setHeight(position, 3.1); - clLand.add(position); + g_Map.log("Remembering to not paint shorelines into the peninsula"); + const peninsulaPosition2 = Vector2D.add(mapCenter, + new Vector2D(fractionToTiles(0.35), 0).rotate(-angle)); + createArea( + new ClumpPlacer(diskArea(fractionToTiles(0.33)), 0.9, 0.01, Infinity, + peninsulaPosition2), + new TileClassPainter(clPeninsulaSteam)); } - }); - if (!isNomad()) + createShoreJaggedness(waterHeight, clLand, 7); + } + + unknownFunctions.CentralSea = function() { - [playerIDs, playerPosition] = playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.6)); - markPlayerArea("small"); + unknownCentralSeaOrIsthmus(false); } - if (isthmus) + unknownFunctions.Isthmus = function() { - g_Map.log("Creating isthmus (i.e. connecting the two riversides with a big land passage)"); - const [isthmusStart, isthmusEnd] = centralRiverCoordinates(startAngle + Math.PI / 2); - createArea( - new PathPlacer( - isthmusStart, - isthmusEnd, - scaleByMapSize(randIntInclusive(16, 24), randIntInclusive(100, 140)), - 0.5, - 3 * scaleByMapSize(1, 4), - 0.1, - 0.01), - [ - landElevationPainter, - new TileClassPainter(clLand), - new TileClassUnPainter(clWater) - ]); + unknownCentralSeaOrIsthmus(true); } - createExtensionsOrIslands(); - // Don't createShoreJaggedness since it doesn't fit artistically here -} + /** + * Creates a huge central river, possibly connecting the riversides with a narrow piece of land. + */ + function unknownCentralSeaOrIsthmus(isthmus) + { + const waterHeight = -3; -function unknownCentralRiverLand() -{ - unknownCentralRiver(true); -} + const startAngle = randomAngle(); -function unknownCentralRiverNaval() -{ - unknownCentralRiver(false); -} + const [riverStart, riverEnd] = centralRiverCoordinates(startAngle); -/** - * Creates a very small central river. - */ -function unknownCentralRiver(shallows) -{ - const waterHeight = -4; - const heightShallow = -2; + paintRiver({ + "parallel": false, + "start": riverStart, + "end": riverEnd, + "width": fractionToTiles(scaleByMapSize(0.27, 0.42) + randFloat(0, 0.08)), + "fadeDist": scaleByMapSize(3, 12), + "deviation": 0, + "heightRiverbed": waterHeight, + "heightLand": heightLand, + "meanderShort": 20, + "meanderLong": 0, + "waterFunc": (position, height, riverFraction) => { + if (height < 0) + clWater.add(position); + }, + "landFunc": (position, shoreDist1, shoreDist2) => { + g_Map.setHeight(position, 3.1); + clLand.add(position); + } + }); - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightLand)); + if (!isNomad()) + { + [playerIDs, playerPosition] = playerPlacementRiver(startAngle + Math.PI / 2, + fractionToTiles(0.6)); + markPlayerArea("small"); + } - const startAngle = randomAngle(); + if (isthmus) + { + g_Map.log( + "Creating isthmus (i.e. connecting the two riversides with a big land passage)"); + const [isthmusStart, isthmusEnd] = centralRiverCoordinates(startAngle + Math.PI / 2); + createArea( + new PathPlacer( + isthmusStart, + isthmusEnd, + scaleByMapSize(randIntInclusive(16, 24), randIntInclusive(100, 140)), + 0.5, + 3 * scaleByMapSize(1, 4), + 0.1, + 0.01), + [ + landElevationPainter, + new TileClassPainter(clLand), + new TileClassUnPainter(clWater) + ]); + } - if (!isNomad()) + createExtensionsOrIslands(); + // Don't createShoreJaggedness since it doesn't fit artistically here + } + + unknownFunctions.CentralRiverLand = function() { - [playerIDs, playerPosition] = playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.5)); - markPlayerArea("large"); + unknownCentralRiver(true); } - g_Map.log("Creating the main river"); - const [coord1, coord2] = centralRiverCoordinates(startAngle); - createArea( - new PathPlacer(coord1, coord2, scaleByMapSize(14, 24), 0.5, scaleByMapSize(3, 12), 0.1, 0.01), - new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), - avoidClasses(clPlayerTerritory, 4)); + unknownFunctions.CentralRiverNaval = function() + { + unknownCentralRiver(false); + } + + /** + * Creates a very small central river. + */ + function unknownCentralRiver(shallows) + { + const waterHeight = -4; + const heightShallow = -2; - g_Map.log("Creating small water spots at the map border to ensure separation of players"); - for (const coord of [coord1, coord2]) createArea( - new ClumpPlacer(diskArea(scaleByMapSize(5, 10)), 0.95, 0.6, Infinity, coord), - new SmoothElevationPainter(ELEVATION_SET, waterHeight, 2), - avoidClasses(clPlayerTerritory, 8)); + new MapBoundsPlacer(), + new ElevationPainter(heightLand)); - if (shallows) - { - g_Map.log("Creating the shallows of the main river"); - for (let i = 0; i <= randIntInclusive(1, scaleByMapSize(4, 8)); ++i) + const startAngle = randomAngle(); + + if (!isNomad()) { - const location = fractionToTiles(randFloat(0.15, 0.85)); - createPassage({ - "start": new Vector2D(location, mapBounds.top).rotateAround(startAngle, mapCenter), - "end": new Vector2D(location, mapBounds.bottom).rotateAround(startAngle, mapCenter), - "startWidth": scaleByMapSize(8, 12), - "endWidth": scaleByMapSize(8, 12), - "smoothWidth": 2, - "startHeight": heightShallow, - "endHeight": heightShallow, - "constraints": new HeightConstraint(-Infinity, heightShallow), - "tileClass": clShallow - }); + [playerIDs, playerPosition] = playerPlacementRiver(startAngle + Math.PI / 2, + fractionToTiles(0.5)); + markPlayerArea("large"); } - } - if (randBool(2/3)) - createTributaryRivers( - startAngle, - randIntInclusive(8, scaleByMapSize(12, 16)), - scaleByMapSize(10, 20), - -4, - [-6, -1.5], - Math.PI / 5, - clWater, - clShallow, - avoidClasses(clPlayerTerritory, 3)); -} + g_Map.log("Creating the main river"); + const [coord1, coord2] = centralRiverCoordinates(startAngle); + createArea( + new PathPlacer(coord1, coord2, scaleByMapSize(14, 24), 0.5, scaleByMapSize(3, 12), 0.1, + 0.01), + new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), + avoidClasses(clPlayerTerritory, 4)); -/** - * Creates a circular lake in the middle and possibly a river between each player ("pizza slices"). - */ -function unknownRiversAndLake() -{ - const waterHeight = -4; - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightLand)); + g_Map.log("Creating small water spots at the map border to ensure separation of players"); + for (const coord of [coord1, coord2]) + createArea( + new ClumpPlacer(diskArea(scaleByMapSize(5, 10)), 0.95, 0.6, Infinity, coord), + new SmoothElevationPainter(ELEVATION_SET, waterHeight, 2), + avoidClasses(clPlayerTerritory, 8)); - let startAngle; - if (!isNomad()) - { - let playerAngle; - [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); - markPlayerArea("small"); + if (shallows) + { + g_Map.log("Creating the shallows of the main river"); + for (let i = 0; i <= randIntInclusive(1, scaleByMapSize(4, 8)); ++i) + { + const location = fractionToTiles(randFloat(0.15, 0.85)); + createPassage({ + "start": new Vector2D(location, mapBounds.top).rotateAround(startAngle, + mapCenter), + "end": new Vector2D(location, mapBounds.bottom).rotateAround(startAngle, + mapCenter), + "startWidth": scaleByMapSize(8, 12), + "endWidth": scaleByMapSize(8, 12), + "smoothWidth": 2, + "startHeight": heightShallow, + "endHeight": heightShallow, + "constraints": new HeightConstraint(-Infinity, heightShallow), + "tileClass": clShallow + }); + } + } + + if (randBool(2/3)) + createTributaryRivers( + startAngle, + randIntInclusive(8, scaleByMapSize(12, 16)), + scaleByMapSize(10, 20), + -4, + [-6, -1.5], + Math.PI / 5, + clWater, + clShallow, + avoidClasses(clPlayerTerritory, 3)); } - const lake = randBool(3/4); - if (lake) + /** + * Creates a circular lake in the middle and possibly a river between each player ("pizza slices"). + */ + unknownFunctions.RiversAndLake = function() { - g_Map.log("Creating lake"); + const waterHeight = -4; createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.17)), 0.7, 0.1, Infinity, mapCenter), - [ - new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), - new TileClassPainter(clWater) - ]); + new MapBoundsPlacer(), + new ElevationPainter(heightLand)); - createShoreJaggedness(waterHeight, clWater, 3); - } - - // TODO: On nomad because the resource imbalances per island are too drastic + let startAngle; + if (!isNomad()) + { + let playerAngle; + [playerIDs, playerPosition, playerAngle, startAngle] = + playerPlacementCircle(fractionToTiles(0.35)); + markPlayerArea("small"); + } - { - g_Map.log("Creating small rivers separating players"); - for (const river of distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.5), mapCenter)[0]) + const lake = randBool(3/4); + if (lake) { + g_Map.log("Creating lake"); createArea( - new PathPlacer(mapCenter, river, scaleByMapSize(14, 24), 0.4, 3 * scaleByMapSize(1, 3), 0.2, 0.05), + new ClumpPlacer(diskArea(fractionToTiles(0.17)), 0.7, 0.1, Infinity, mapCenter), [ new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 5)); + ]); + + createShoreJaggedness(waterHeight, clWater, 3); + } + // TODO: On nomad because the resource imbalances per island are too drastic + + { + g_Map.log("Creating small rivers separating players"); + for (const river of distributePointsOnCircle(numPlayers, + startAngle + Math.PI / numPlayers, fractionToTiles(0.5), mapCenter)[0]) + { + createArea( + new PathPlacer(mapCenter, river, scaleByMapSize(14, 24), 0.4, + 3 * scaleByMapSize(1, 3), 0.2, 0.05), + [ + new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 5)); + + createArea( + new ClumpPlacer(diskArea(scaleByMapSize(4, 22)), 0.95, 0.6, Infinity, river), + [ + new SmoothElevationPainter(ELEVATION_SET, waterHeight, 0), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 5)); + } + + g_Map.log("Creating small lake"); createArea( - new ClumpPlacer(diskArea(scaleByMapSize(4, 22)), 0.95, 0.6, Infinity, river), + new ClumpPlacer(diskArea(fractionToTiles(0.04)), 0.7, 0.1, Infinity, mapCenter), [ - new SmoothElevationPainter(ELEVATION_SET, waterHeight, 0), + new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 5)); + ]); } - g_Map.log("Creating small lake"); - createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.04)), 0.7, 0.1, Infinity, mapCenter), - [ - new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), - new TileClassPainter(clWater) - ]); + if (!isNomad && lake && randBool(2/3)) + { + g_Map.log("Creating small central island"); + createArea( + new ClumpPlacer(diskArea(fractionToTiles(0.05)), 0.7, 0.1, Infinity, mapCenter), + [ + landElevationPainter, + new TileClassPainter(clWater) + ]); + } } - if (!isNomad && lake && randBool(2/3)) + /** + * Align players on a land strip with seas bordering on one or both sides that can hold islands. + */ + unknownFunctions.EdgeSeas = function() { - g_Map.log("Creating small central island"); + const waterHeight = -4; + createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.05)), 0.7, 0.1, Infinity, mapCenter), - [ - landElevationPainter, - new TileClassPainter(clWater) - ]); - } -} + new MapBoundsPlacer(), + new ElevationPainter(heightLand)); -/** - * Align players on a land strip with seas bordering on one or both sides that can hold islands. - */ -function unknownEdgeSeas() -{ - const waterHeight = -4; + const startAngle = randomAngle(); + if (!isNomad()) + { + playerIDs = sortAllPlayers(); + playerPosition = playerPlacementLine(startAngle + Math.PI / 2, mapCenter, + fractionToTiles(0.2)); + // Don't place the shoreline inside the CC, but possibly into the players territory + markPlayerArea("small"); + } - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightLand)); + for (const side of pickRandom([[0], [Math.PI], [0, Math.PI]])) + paintRiver({ + "parallel": true, + "start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(side + startAngle, + mapCenter), + "end": new Vector2D(mapBounds.left, mapBounds.bottom).rotateAround( + side + startAngle, mapCenter), + "width": scaleByMapSize(80, randFloat(270, 320)), + "fadeDist": scaleByMapSize(2, 8), + "deviation": 0, + "heightRiverbed": waterHeight, + "heightLand": heightLand, + "meanderShort": 20, + "meanderLong": 0 + }); - const startAngle = randomAngle(); - if (!isNomad()) - { - playerIDs = sortAllPlayers(); - playerPosition = playerPlacementLine(startAngle + Math.PI / 2, mapCenter, fractionToTiles(0.2)); - // Don't place the shoreline inside the CC, but possibly into the players territory - markPlayerArea("small"); + createExtensionsOrIslands(); + paintTileClassBasedOnHeight(0, heightCliff, 1, clLand); + createShoreJaggedness(waterHeight, clLand, 7, false); } - for (const side of pickRandom([[0], [Math.PI], [0, Math.PI]])) - paintRiver({ - "parallel": true, - "start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(side + startAngle, mapCenter), - "end": new Vector2D(mapBounds.left, mapBounds.bottom).rotateAround(side + startAngle, mapCenter), - "width": scaleByMapSize(80, randFloat(270, 320)), - "fadeDist": scaleByMapSize(2, 8), - "deviation": 0, - "heightRiverbed": waterHeight, - "heightLand": heightLand, - "meanderShort": 20, - "meanderLong": 0 - }); + /** + * Land shaped like a concrescent moon around a central lake. + */ + unknownFunctions.Gulf = function() + { + const waterHeight = -3; - createExtensionsOrIslands(); - paintTileClassBasedOnHeight(0, heightCliff, 1, clLand); - createShoreJaggedness(waterHeight, clLand, 7, false); -} + createArea( + new MapBoundsPlacer(), + new ElevationPainter(heightLand)); -/** - * Land shaped like a concrescent moon around a central lake. - */ -function unknownGulf() -{ - const waterHeight = -3; + const startAngle = randomAngle(); + if (!isNomad()) + { + g_Map.log("Determining player locations"); - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightLand)); + playerPosition = playerPlacementCustomAngle( + fractionToTiles(0.35), + mapCenter, + i => startAngle + 2/3 * Math.PI * (-1 + (numPlayers == 1 ? 1 : + 2 * i / (numPlayers - 1))))[0]; - const startAngle = randomAngle(); - if (!isNomad()) - { - g_Map.log("Determining player locations"); + markPlayerArea("large"); + } - playerPosition = playerPlacementCustomAngle( - fractionToTiles(0.35), - mapCenter, - i => startAngle + 2/3 * Math.PI * (-1 + (numPlayers == 1 ? 1 : 2 * i / (numPlayers - 1))))[0]; + const gulfParts = [ + { "radius": fractionToTiles(0.16), "distance": fractionToTiles(0) }, + { "radius": fractionToTiles(0.2), "distance": fractionToTiles(0.2) }, + { "radius": fractionToTiles(0.22), "distance": fractionToTiles(0.49) } + ]; - markPlayerArea("large"); + for (const gulfPart of gulfParts) + { + const position = Vector2D.sub(mapCenter, new Vector2D(gulfPart.distance, 0) + .rotate(-startAngle)).round(); + createArea( + new ClumpPlacer(diskArea(gulfPart.radius), 0.7, 0.05, Infinity, position), + [ + new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayerTerritory, defaultPlayerBaseRadius())); + } } - const gulfParts = [ - { "radius": fractionToTiles(0.16), "distance": fractionToTiles(0) }, - { "radius": fractionToTiles(0.2), "distance": fractionToTiles(0.2) }, - { "radius": fractionToTiles(0.22), "distance": fractionToTiles(0.49) } - ]; - - for (const gulfPart of gulfParts) + /** + * Mainland style with some small random lakes. + */ + unknownFunctions.Lakes = function() { - const position = Vector2D.sub(mapCenter, new Vector2D(gulfPart.distance, 0).rotate(-startAngle)).round(); + const waterHeight = -5; + createArea( - new ClumpPlacer(diskArea(gulfPart.radius), 0.7, 0.05, Infinity, position), + new MapBoundsPlacer(), + new ElevationPainter(heightLand)); + + if (!isNomad()) + { + [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + markPlayerArea("large"); + } + + g_Map.log("Creating lakes"); + createAreas( + new ClumpPlacer(scaleByMapSize(160, 700), 0.2, 0.1, Infinity), [ - new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), + new SmoothElevationPainter(ELEVATION_SET, waterHeight, 5), new TileClassPainter(clWater) ], - avoidClasses(clPlayerTerritory, defaultPlayerBaseRadius())); + [avoidClasses(clPlayerTerritory, 12), randBool() ? avoidClasses(clWater, 8) : + new NullConstraint()], + scaleByMapSize(5, 16)); } -} -/** - * Mainland style with some small random lakes. - */ -function unknownLakes() -{ - const waterHeight = -5; + /** + * A large hill leaving players only a small passage to each of the the two neighboring players. + */ + unknownFunctions.Passes = function() + { + const heightMountain = 24; + const waterHeight = -4; - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightLand)); + createArea( + new MapBoundsPlacer(), + new ElevationPainter(heightLand)); - if (!isNomad()) - { - [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - markPlayerArea("large"); - } + let playerAngle; + let startAngle; + if (!isNomad()) + { + [playerIDs, playerPosition, playerAngle, startAngle] = + playerPlacementCircle(fractionToTiles(0.35)); + markPlayerArea("small"); + } + else + startAngle = randomAngle(); - g_Map.log("Creating lakes"); - createAreas( - new ClumpPlacer(scaleByMapSize(160, 700), 0.2, 0.1, Infinity), - [ - new SmoothElevationPainter(ELEVATION_SET, waterHeight, 5), - new TileClassPainter(clWater) - ], - [avoidClasses(clPlayerTerritory, 12), randBool() ? avoidClasses(clWater, 8) : new NullConstraint()], - scaleByMapSize(5, 16)); -} + g_Map.log("Creating a mountain range between neighboring players"); + for (const mountain of distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, + fractionToTiles(0.5), mapCenter)[0]) + { + createArea( + new PathPlacer(mapCenter, mountain, scaleByMapSize(14, 24), 0.4, + 3 * scaleByMapSize(1, 3), 0.2, 0.05), + [ + // More smoothing than this often results in the mountainrange becoming + // passable to one player. + new SmoothElevationPainter(ELEVATION_SET, heightMountain, 1), + new TileClassPainter(clWater) + ], + avoidClasses(clPlayer, 5)); -/** - * A large hill leaving players only a small passage to each of the the two neighboring players. - */ -function unknownPasses() -{ - const heightMountain = 24; - const waterHeight = -4; + // Small mountain at the map border between the players to ensure separation of players + createArea( + new ClumpPlacer(diskArea(scaleByMapSize(4, 22)), 0.95, 0.6, Infinity, mountain), + new SmoothElevationPainter(ELEVATION_SET, heightMountain, 0), + avoidClasses(clPlayer, 5)); + } - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightLand)); + g_Map.log("Creating passages between neighboring players"); + const passes = numPlayers == 2 && distributePointsOnCircle(numPlayers * 3, startAngle, + fractionToTiles(0.35), mapCenter)[0]; + for (let i = 0; i < numPlayers && numPlayers > 1; ++i) + { + // For numPlayers > 2 use the playerPosition to not end up inside the mountains. + createArea( + new PathPlacer( + numPlayers == 2 ? passes[3 * i + 1] : playerPosition[i], + numPlayers == 2 ? passes[3 * i + 2] : playerPosition[(i + 1) % numPlayers], + scaleByMapSize(14, 24), + 0.4, + 3 * scaleByMapSize(1, 3), + 0.2, + 0.05), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 2)); + } - let playerAngle; - let startAngle; - if (!isNomad()) - { - [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); - markPlayerArea("small"); + if (randBool(2/5)) + { + g_Map.log("Create central lake"); + createArea( + new ClumpPlacer(diskArea(fractionToTiles(0.1)), 0.7, 0.1, Infinity, mapCenter), + [ + new SmoothElevationPainter(ELEVATION_SET, waterHeight, 3), + new TileClassPainter(clWater) + ]); + } + else + { + g_Map.log("Fill area between the paths"); + createArea( + new ClumpPlacer(diskArea(fractionToTiles(0.05)), 0.7, 0.1, Infinity, mapCenter), + [ + new SmoothElevationPainter(ELEVATION_SET, heightMountain, 4), + new TileClassPainter(clWater) + ]); + } } - else - startAngle = randomAngle(); - g_Map.log("Creating a mountain range between neighboring players"); - for (const mountain of distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.5), mapCenter)[0]) + /** + * Land enclosed by a hill that leaves small areas for civic centers and large central place. + */ + unknownFunctions.Lowlands = function() { - createArea( - new PathPlacer(mapCenter, mountain, scaleByMapSize(14, 24), 0.4, 3 * scaleByMapSize(1, 3), 0.2, 0.05), - [ - // More smoothing than this often results in the mountainrange becoming passable to one player. - new SmoothElevationPainter(ELEVATION_SET, heightMountain, 1), - new TileClassPainter(clWater) - ], - avoidClasses(clPlayer, 5)); + const heightMountain = 30; - // Small mountain at the map border between the players to ensure separation of players + g_Map.log("Creating mountain that is going to separate players"); createArea( - new ClumpPlacer(diskArea(scaleByMapSize(4, 22)), 0.95, 0.6, Infinity, mountain), - new SmoothElevationPainter(ELEVATION_SET, heightMountain, 0), - avoidClasses(clPlayer, 5)); - } + new MapBoundsPlacer(), + new ElevationPainter(heightMountain)); - g_Map.log("Creating passages between neighboring players"); - const passes = numPlayers == 2 && distributePointsOnCircle(numPlayers * 3, startAngle, fractionToTiles(0.35), mapCenter)[0]; - for (let i = 0; i < numPlayers && numPlayers > 1; ++i) - { - // For numPlayers > 2 use the playerPosition to not end up inside the mountains. - createArea( - new PathPlacer( - numPlayers == 2 ? passes[3 * i + 1] : playerPosition[i], - numPlayers == 2 ? passes[3 * i + 2] : playerPosition[(i + 1) % numPlayers], - scaleByMapSize(14, 24), - 0.4, - 3 * scaleByMapSize(1, 3), - 0.2, - 0.05), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 2)); - } + let playerAngle; + let startAngle; + if (!isNomad()) + { + [playerIDs, playerPosition, playerAngle, startAngle] = + playerPlacementCircle(fractionToTiles(0.35)); + markPlayerArea("small"); + } + else + startAngle = randomAngle(); + + g_Map.log("Creating valleys enclosed by the mountain"); + let valleys = numPlayers; + if (mapSize >= 128 && numPlayers <= 2 || + mapSize >= 192 && numPlayers <= 3 || + mapSize >= 320 && numPlayers <= 4 || + mapSize >= 384 && numPlayers <= 5 || + mapSize >= 448 && numPlayers <= 6) + valleys *= 2; + + g_Map.log("Creating player valley"); + for (const valley of distributePointsOnCircle(valleys, startAngle, fractionToTiles(0.35), + mapCenter)[0]) + { + createArea( + new ClumpPlacer(diskArea(scaleByMapSize(18, 32)), 0.65, 0.1, Infinity, valley), + [ + new SmoothElevationPainter(ELEVATION_SET, heightLand, 2), + new TileClassPainter(clLand) + ]); - if (randBool(2/5)) - { - g_Map.log("Create central lake"); - createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.1)), 0.7, 0.1, Infinity, mapCenter), - [ - new SmoothElevationPainter(ELEVATION_SET, waterHeight, 3), - new TileClassPainter(clWater) - ]); - } - else - { - g_Map.log("Fill area between the paths"); + // Passage from player to center + createArea( + new PathPlacer(mapCenter, valley, scaleByMapSize(14, 24), 0.4, + 3 * scaleByMapSize(1, 3), 0.2, 0.05), + [ + landElevationPainter, + new TileClassPainter(clWater) + ]); + } + + g_Map.log("Creating the big central area"); createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.05)), 0.7, 0.1, Infinity, mapCenter), + new ClumpPlacer(diskArea(fractionToTiles(0.18)), 0.7, 0.1, Infinity, mapCenter), [ - new SmoothElevationPainter(ELEVATION_SET, heightMountain, 4), + landElevationPainter, new TileClassPainter(clWater) ]); } -} - -/** - * Land enclosed by a hill that leaves small areas for civic centers and large central place. - */ -function unknownLowlands() -{ - const heightMountain = 30; - - g_Map.log("Creating mountain that is going to separate players"); - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightMountain)); - let playerAngle; - let startAngle; - if (!isNomad()) - { - [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); - markPlayerArea("small"); - } - else - startAngle = randomAngle(); - - g_Map.log("Creating valleys enclosed by the mountain"); - let valleys = numPlayers; - if (mapSize >= 128 && numPlayers <= 2 || - mapSize >= 192 && numPlayers <= 3 || - mapSize >= 320 && numPlayers <= 4 || - mapSize >= 384 && numPlayers <= 5 || - mapSize >= 448 && numPlayers <= 6) - valleys *= 2; - - g_Map.log("Creating player valley"); - for (const valley of distributePointsOnCircle(valleys, startAngle, fractionToTiles(0.35), mapCenter)[0]) + /** + * No water, no hills. + */ + unknownFunctions.Mainland = function() { createArea( - new ClumpPlacer(diskArea(scaleByMapSize(18, 32)), 0.65, 0.1, Infinity, valley), - [ - new SmoothElevationPainter(ELEVATION_SET, heightLand, 2), - new TileClassPainter(clLand) - ]); + new MapBoundsPlacer(), + new ElevationPainter(3)); - // Passage from player to center - createArea( - new PathPlacer(mapCenter, valley, scaleByMapSize(14, 24), 0.4, 3 * scaleByMapSize(1, 3), 0.2, 0.05), - [ - landElevationPainter, - new TileClassPainter(clWater) - ]); + if (!isNomad()) + { + [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + markPlayerArea("small"); + } } - g_Map.log("Creating the big central area"); - createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.18)), 0.7, 0.1, Infinity, mapCenter), - [ - landElevationPainter, - new TileClassPainter(clWater) - ]); -} - -/** - * No water, no hills. - */ -function unknownMainland() -{ - createArea( - new MapBoundsPlacer(), - new ElevationPainter(3)); + function centralRiverCoordinates(angle) + { + return [ + new Vector2D(mapBounds.left + 1, mapCenter.y), + new Vector2D(mapBounds.right - 1, mapCenter.y) + ].map(v => v.rotateAround(angle, mapCenter)); + } - if (!isNomad()) + function createShoreJaggedness(waterHeight, borderClass, shoreDist, inwards = true) { - [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - markPlayerArea("small"); + g_Map.log("Creating shore jaggedness"); + for (let i = 0; i < 2; ++i) + if (i || inwards) + createAreas( + new ChainPlacer(2, Math.floor(scaleByMapSize(4, 6)), 15, Infinity), + [ + new SmoothElevationPainter(ELEVATION_SET, i ? heightLand : waterHeight, + 4), + i ? new TileClassPainter(clLand) : new TileClassUnPainter(clLand) + ], + [ + avoidClasses(clPlayer, 20, clPeninsulaSteam, 20), + borderClasses(borderClass, shoreDist, shoreDist) + ], + scaleByMapSize(7, 130) * 2, + 150); } -} -function centralRiverCoordinates(angle) -{ - return [ - new Vector2D(mapBounds.left + 1, mapCenter.y), - new Vector2D(mapBounds.right - 1, mapCenter.y) - ].map(v => v.rotateAround(angle, mapCenter)); -} + function createExtensionsOrIslands() + { + const rnd = randIntInclusive(1, 3); -function createShoreJaggedness(waterHeight, borderClass, shoreDist, inwards = true) -{ - g_Map.log("Creating shore jaggedness"); - for (let i = 0; i < 2; ++i) - if (i || inwards) + if (rnd == 1) + { + g_Map.log("Creating islands"); createAreas( - new ChainPlacer(2, Math.floor(scaleByMapSize(4, 6)), 15, Infinity), + new ClumpPlacer(Math.square(randIntInclusive(scaleByMapSize(8, 15), + scaleByMapSize(15, 23))), 0.8, 0.1, randFloat(0, 0.2)), [ - new SmoothElevationPainter(ELEVATION_SET, i ? heightLand : waterHeight, 4), - i ? new TileClassPainter(clLand) : new TileClassUnPainter(clLand) + landElevationPainter, + new TileClassPainter(clLand) ], + avoidClasses(clLand, 3, clPlayer, 3), + scaleByMapSize(2, 5) * randIntInclusive(8, 14)); + } + else if (rnd == 2) + { + g_Map.log("Creating extentions"); + createAreas( + new ChainPlacer(Math.floor(scaleByMapSize(4, 7)), Math.floor(scaleByMapSize(7, 10)), + Math.floor(scaleByMapSize(16, 40)), 0.07), [ - avoidClasses(clPlayer, 20, clPeninsulaSteam, 20), - borderClasses(borderClass, shoreDist, shoreDist) + landElevationPainter, + new TileClassPainter(clLand) ], - scaleByMapSize(7, 130) * 2, - 150); -} + null, + scaleByMapSize(2, 5) * randIntInclusive(8, 14)); + } + } -function createExtensionsOrIslands() -{ - const rnd = randIntInclusive(1, 3); + /** + * Prevent impassable terrain and resource collisions at the the civic center and starting resources. + */ + function markPlayerArea(size) + { + for (let i = 0; i < numPlayers; ++i) + { + addCivicCenterAreaToClass(playerPosition[i], clPlayer); - if (rnd == 1) + if (size == "large") + createArea( + new ClumpPlacer(diskArea(scaleByMapSize(17, 29) / 3), 0.6, 0.3, Infinity, + playerPosition[i]), + new TileClassPainter(clPlayerTerritory)); + } + } + + function paintUnknownMapBasedOnHeight() { - g_Map.log("Creating islands"); - createAreas( - new ClumpPlacer(Math.square(randIntInclusive(scaleByMapSize(8, 15), scaleByMapSize(15, 23))), 0.8, 0.1, randFloat(0, 0.2)), - [ - landElevationPainter, - new TileClassPainter(clLand) - ], - avoidClasses(clLand, 3, clPlayer, 3), - scaleByMapSize(2, 5) * randIntInclusive(8, 14)); + paintTerrainBasedOnHeight(heightCliff, 40, 1, tCliff); + paintTerrainBasedOnHeight(3, heightCliff, 1, tMainTerrain); + paintTerrainBasedOnHeight(1, 3, 1, tShore); + paintTerrainBasedOnHeight(-8, 1, 2, tWater); + + unPaintTileClassBasedOnHeight(0, heightCliff, 1, clWater); + unPaintTileClassBasedOnHeight(-6, 0, 1, clLand); + + paintTileClassBasedOnHeight(-6, 0, 1, clWater); + paintTileClassBasedOnHeight(0, heightCliff, 1, clLand); + paintTileClassBasedOnHeight(heightCliff, 40, 1, clHill); } - else if (rnd == 2) + + /** + * Place resources and decoratives after the player territory was marked. + */ + function* createUnknownObjects() { - g_Map.log("Creating extentions"); + g_Map.log("Creating bumps"); createAreas( - new ChainPlacer(Math.floor(scaleByMapSize(4, 7)), Math.floor(scaleByMapSize(7, 10)), Math.floor(scaleByMapSize(16, 40)), 0.07), + new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), + new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), + [avoidClasses(clWater, 2, clPlayer, 10), stayClasses(clLand, 3)], + randIntInclusive(0, scaleByMapSize(1, 2) * 200)); + + g_Map.log("Creating hills"); + createAreas( + new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), [ - landElevationPainter, - new TileClassPainter(clLand) + new LayeredPainter([tCliff, tHill], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) ], - null, - scaleByMapSize(2, 5) * randIntInclusive(8, 14)); - } -} + [avoidClasses(clPlayer, 15, clHill, randIntInclusive(6, 18)), stayClasses(clLand, 0)], + randIntInclusive(0, scaleByMapSize(4, 8))*randIntInclusive(1, scaleByMapSize(4, 9)) + ); + yield 30; + + g_Map.log("Creating forests"); + const [numForest, numStragglers] = getTreeCounts(...rBiomeTreeCount(1)); + let types = [ + [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], + [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] + ]; + + const size = numForest / (scaleByMapSize(2, 8) * numPlayers); + let num = Math.floor(size / types.length); + for (const type of types) + createAreas( + new ClumpPlacer(numForest / num, 0.1, 0.1, Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + [avoidClasses(clPlayer, 20, clForest, randIntInclusive(5, 15), clHill, 2), + stayClasses(clLand, 4)], + num); + yield 50; + + g_Map.log("Creating dirt patches"); + const patchCount = (currentBiome() == "generic/savanna" ? 3 : 1) * scaleByMapSize(15, 45); + for (const patchSize of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + createAreas( + new ClumpPlacer(patchSize, 0.3, 0.06, 0.5), + [ + new LayeredPainter([[tMainTerrain, tTier1Terrain], + [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], + [1, 1]), + new TileClassPainter(clDirt) + ], + [avoidClasses(clForest, 0, clHill, 2, clDirt, 5, clPlayer, 7), + stayClasses(clLand, 4)], + patchCount); -/** - * Prevent impassable terrain and resource collisions at the the civic center and starting resources. - */ -function markPlayerArea(size) -{ - for (let i = 0; i < numPlayers; ++i) - { - addCivicCenterAreaToClass(playerPosition[i], clPlayer); + g_Map.log("Creating grass patches"); + for (const 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, 2, clDirt, 5, clPlayer, 7), + stayClasses(clLand, 4)], + patchCount); - if (size == "large") - createArea( - new ClumpPlacer(diskArea(scaleByMapSize(17, 29) / 3), 0.6, 0.3, Infinity, playerPosition[i]), - new TileClassPainter(clPlayerTerritory)); - } -} + yield 55; -function paintUnknownMapBasedOnHeight() -{ - paintTerrainBasedOnHeight(heightCliff, 40, 1, tCliff); - paintTerrainBasedOnHeight(3, heightCliff, 1, tMainTerrain); - paintTerrainBasedOnHeight(1, 3, 1, tShore); - paintTerrainBasedOnHeight(-8, 1, 2, tWater); + g_Map.log("Creating stone mines"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock), + 0, + [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 2), stayClasses(clLand, 3)], + randIntInclusive(scaleByMapSize(2, 9), scaleByMapSize(9, 40)), + 100); - unPaintTileClassBasedOnHeight(0, heightCliff, 1, clWater); - unPaintTileClassBasedOnHeight(-6, 0, 1, clLand); + g_Map.log("Creating small stone quarries"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock), + 0, + [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 2), stayClasses(clLand, 3)], + randIntInclusive(scaleByMapSize(2, 9), scaleByMapSize(9, 40)), + 100); - paintTileClassBasedOnHeight(-6, 0, 1, clWater); - paintTileClassBasedOnHeight(0, heightCliff, 1, clLand); - paintTileClassBasedOnHeight(heightCliff, 40, 1, clHill); -} + g_Map.log("Creating metal mines"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), + 0, + [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 2), + stayClasses(clLand, 3)], + randIntInclusive(scaleByMapSize(2, 9), scaleByMapSize(9, 40)), + 100); + yield 65; -/** - * Place resources and decoratives after the player territory was marked. - */ -function createUnknownObjects() -{ - g_Map.log("Creating bumps"); - createAreas( - new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), - new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), - [avoidClasses(clWater, 2, clPlayer, 10), stayClasses(clLand, 3)], - randIntInclusive(0, scaleByMapSize(1, 2) * 200)); - - g_Map.log("Creating hills"); - createAreas( - new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), - [ - new LayeredPainter([tCliff, tHill], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - [avoidClasses(clPlayer, 15, clHill, randIntInclusive(6, 18)), stayClasses(clLand, 0)], - randIntInclusive(0, scaleByMapSize(4, 8))*randIntInclusive(1, scaleByMapSize(4, 9)) - ); - Engine.SetProgress(30); - - g_Map.log("Creating forests"); - const [numForest, numStragglers] = getTreeCounts(...rBiomeTreeCount(1)); - let types = [ - [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], - [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] - ]; - - const size = numForest / (scaleByMapSize(2, 8) * numPlayers); - let num = Math.floor(size / types.length); - for (const type of types) - createAreas( - new ClumpPlacer(numForest / num, 0.1, 0.1, Infinity), - [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) - ], - [avoidClasses(clPlayer, 20, clForest, randIntInclusive(5, 15), clHill, 2), stayClasses(clLand, 4)], - num); - Engine.SetProgress(50); + g_Map.log("Creating small decorative rocks"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aRockMedium, 1, 3, 0, 1)], true), + 0, + [avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 2), stayClasses(clLand, 3)], + scaleByMapSize(16, 262), + 50); - g_Map.log("Creating dirt patches"); - const patchCount = (currentBiome() == "generic/savanna" ? 3 : 1) * scaleByMapSize(15, 45); - for (const patchSize of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - createAreas( - new ClumpPlacer(patchSize, 0.3, 0.06, 0.5), - [ - new LayeredPainter([[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]), - new TileClassPainter(clDirt) - ], - [avoidClasses(clForest, 0, clHill, 2, clDirt, 5, clPlayer, 7), stayClasses(clLand, 4)], - patchCount); + g_Map.log("Creating large decorative rocks"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aRockLarge, 1, 2, 0, 1), + new SimpleObject(aRockMedium, 1, 3, 0, 2)], true), + 0, + [avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 2), stayClasses(clLand, 3)], + scaleByMapSize(8, 131), + 50); + yield 70; - g_Map.log("Creating grass patches"); - for (const 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, 2, clDirt, 5, clPlayer, 7), stayClasses(clLand, 4)], - patchCount); - - Engine.SetProgress(55); - - g_Map.log("Creating stone mines"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock), - 0, - [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 2), stayClasses(clLand, 3)], - randIntInclusive(scaleByMapSize(2, 9), scaleByMapSize(9, 40)), - 100); - - g_Map.log("Creating small stone quarries"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock), - 0, - [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 2), stayClasses(clLand, 3)], - randIntInclusive(scaleByMapSize(2, 9), scaleByMapSize(9, 40)), - 100); - - g_Map.log("Creating metal mines"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), - 0, - [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 2), stayClasses(clLand, 3)], - randIntInclusive(scaleByMapSize(2, 9), scaleByMapSize(9, 40)), - 100); - Engine.SetProgress(65); - - g_Map.log("Creating small decorative rocks"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aRockMedium, 1, 3, 0, 1)], true), - 0, - [avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 2), stayClasses(clLand, 3)], - scaleByMapSize(16, 262), - 50); - - g_Map.log("Creating large decorative rocks"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)], true), - 0, - [avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 2), stayClasses(clLand, 3)], - scaleByMapSize(8, 131), - 50); - Engine.SetProgress(70); - - g_Map.log("Creating deer"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], true, clFood), - 0, - [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 2, clFood, 20), stayClasses(clLand, 2)], - randIntInclusive(numPlayers + 3, 5 * numPlayers + 4), - 50); - - g_Map.log("Creating berry bush"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oFruitBush, 5, 7, 0, 4)], true, clFood), - 0, - [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 2, clFood, 20), stayClasses(clLand, 2)], - randIntInclusive(1, 4) * numPlayers + 2, - 50); - Engine.SetProgress(75); - - g_Map.log("Creating sheep"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)], true, clFood), - 0, - [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 2, clFood, 20), stayClasses(clLand, 2)], - randIntInclusive(numPlayers + 3, 5 * numPlayers + 4), - 50); - - g_Map.log("Creating fish"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood), - 0, - avoidClasses(clLand, 4, clForest, 0, clPlayer, 0, clHill, 2, clFood, 20), - randIntInclusive(15, 40) * numPlayers, - 60); - Engine.SetProgress(85); - - g_Map.log("Creating straggler trees"); - types = [g_Gaia.tree1, g_Gaia.tree2, g_Gaia.tree3, g_Gaia.tree4]; - - num = Math.floor(numStragglers / types.length); - for (const type of types) + g_Map.log("Creating deer"); createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(type, 1, 1, 0, 3)], true, clForest), + new SimpleGroup([new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], true, clFood), 0, - [avoidClasses(clWater, 1, clForest, 1, clHill, 2, clPlayer, 0, clMetal, 6, clRock, 6, clBaseResource, 6), stayClasses(clLand, 4)], - num); - - const planetm = currentBiome() == "generic/india" ? 8 : 1; - - g_Map.log("Creating small grass tufts"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aGrassShort, 1, 2, 0, 1, -Math.PI / 8, Math.PI / 8)]), - 0, - [avoidClasses(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), stayClasses(clLand, 3)], - planetm * scaleByMapSize(13, 200)); - Engine.SetProgress(90); - - g_Map.log("Creating large grass tufts"); - createObjectGroupsDeprecated( - 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)]), - 0, - [avoidClasses(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), stayClasses(clLand, 3)], - planetm * scaleByMapSize(13, 200)); - Engine.SetProgress(95); - - g_Map.log("Creating shallow flora"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aLillies, 1, 2, 0, 2), new SimpleObject(aReeds, 2, 4, 0, 2)]), - 0, - stayClasses(clShallow, 1), - 60 * scaleByMapSize(13, 200), - 80); - - g_Map.log("Creating bushes"); - createObjectGroupsDeprecated( - new SimpleGroup([new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)]), - 0, - [avoidClasses(clWater, 1, clHill, 2, clPlayer, 1, clDirt, 1), stayClasses(clLand, 3)], - planetm * scaleByMapSize(13, 200), - 50); - - setSkySet(pickRandom(["cirrus", "cumulus", "sunny", "sunny 1", "mountainous", "stratus"])); - setSunRotation(randomAngle()); - setSunElevation(Math.PI * randFloat(1/5, 1/3)); -} + [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 2, clFood, 20), + stayClasses(clLand, 2)], + randIntInclusive(numPlayers + 3, 5 * numPlayers + 4), + 50); -function createUnknownPlayerBases() -{ - placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "BaseResourceClass": clBaseResource, - "Walls": g_StartingWalls, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad, - "painters": [ - new TileClassPainter(clPlayer) - ] - }, - "StartingAnimal": { - }, - "Berries": { - "template": oFruitBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Treasures": { - "types": [ - { - "template": oWoodTreasure, - "count": g_StartingTreasures ? 14 : 0 - } - ] - }, - "Trees": { - "template": oTree1 - }, - "Decoratives": { - "template": aGrassShort - } - }); -} + g_Map.log("Creating berry bush"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oFruitBush, 5, 7, 0, 4)], true, clFood), + 0, + [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 2, clFood, 20), + stayClasses(clLand, 2)], + randIntInclusive(1, 4) * numPlayers + 2, + 50); + yield 75; -createUnknownMap(); + g_Map.log("Creating sheep"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)], true, clFood), + 0, + [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 2, clFood, 20), + stayClasses(clLand, 2)], + randIntInclusive(numPlayers + 3, 5 * numPlayers + 4), + 50); -g_Map.ExportMap(); + g_Map.log("Creating fish"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood), + 0, + avoidClasses(clLand, 4, clForest, 0, clPlayer, 0, clHill, 2, clFood, 20), + randIntInclusive(15, 40) * numPlayers, + 60); + yield 85; + + g_Map.log("Creating straggler trees"); + types = [g_Gaia.tree1, g_Gaia.tree2, g_Gaia.tree3, g_Gaia.tree4]; + + num = Math.floor(numStragglers / types.length); + for (const type of types) + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(type, 1, 1, 0, 3)], true, clForest), + 0, + [avoidClasses(clWater, 1, clForest, 1, clHill, 2, clPlayer, 0, clMetal, 6, clRock, + 6, clBaseResource, 6), stayClasses(clLand, 4)], + num); + + const planetm = currentBiome() == "generic/india" ? 8 : 1; + + g_Map.log("Creating small grass tufts"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aGrassShort, 1, 2, 0, 1, -Math.PI / 8, Math.PI / 8)]), + 0, + [avoidClasses(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), stayClasses(clLand, 3)], + planetm * scaleByMapSize(13, 200)); + yield 90; + + g_Map.log("Creating large grass tufts"); + createObjectGroupsDeprecated( + 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)]), + 0, + [avoidClasses(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), + stayClasses(clLand, 3)], + planetm * scaleByMapSize(13, 200)); + yield 95; + + g_Map.log("Creating shallow flora"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aLillies, 1, 2, 0, 2), + new SimpleObject(aReeds, 2, 4, 0, 2)]), + 0, + stayClasses(clShallow, 1), + 60 * scaleByMapSize(13, 200), + 80); + + g_Map.log("Creating bushes"); + createObjectGroupsDeprecated( + new SimpleGroup([new SimpleObject(aBushMedium, 1, 2, 0, 2), + new SimpleObject(aBushSmall, 2, 4, 0, 2)]), + 0, + [avoidClasses(clWater, 1, clHill, 2, clPlayer, 1, clDirt, 1), stayClasses(clLand, 3)], + planetm * scaleByMapSize(13, 200), + 50); + + setSkySet(pickRandom(["cirrus", "cumulus", "sunny", "sunny 1", "mountainous", "stratus"])); + setSunRotation(randomAngle()); + setSunElevation(Math.PI * randFloat(1/5, 1/3)); + } + + function createUnknownPlayerBases() + { + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "BaseResourceClass": clBaseResource, + "Walls": startingWalls, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad, + "painters": [ + new TileClassPainter(clPlayer) + ] + }, + "StartingAnimal": { + }, + "Berries": { + "template": oFruitBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Treasures": { + "types": [ + { + "template": oWoodTreasure, + "count": startingTreasures ? 14 : 0 + } + ] + }, + "Trees": { + "template": oTree1 + }, + "Decoratives": { + "template": aGrassShort + } + }); + } + + yield* createUnknownMap(); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/volcanic_lands.js =================================================================== --- binaries/data/mods/public/maps/random/volcanic_lands.js +++ binaries/data/mods/public/maps/random/volcanic_lands.js @@ -1,186 +1,190 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const tGrass = ["cliff volcanic light", "ocean_rock_a", "ocean_rock_b"]; -const tGrassA = "cliff volcanic light"; -const tGrassB = "ocean_rock_a"; -const tGrassC = "ocean_rock_b"; -const tCliff = ["cliff volcanic coarse", "cave_walls"]; -const tRoad = "road1"; -const tRoadWild = "road1"; -const tLava1 = "LavaTest05"; -const tLava2 = "LavaTest04"; -const tLava3 = "LavaTest03"; - -const oTree = "gaia/tree/dead"; -const oStoneLarge = "gaia/rock/alpine_large"; -const oStoneSmall = "gaia/rock/alpine_small"; -const oMetalLarge = "gaia/ore/alpine_large"; - -const aRockLarge = "actor|geology/stone_granite_med.xml"; -const aRockMedium = "actor|geology/stone_granite_med.xml"; - -const pForestD = [tGrassC + TERRAIN_SEPARATOR + oTree, tGrassC]; -const pForestP = [tGrassB + TERRAIN_SEPARATOR + oTree, tGrassB]; - -const heightLand = 1; -const heightHill = 18; - -const g_Map = new RandomMap(heightLand, tGrassB); - -const numPlayers = getNumPlayers(); -const mapCenter = g_Map.getCenter(); - -const clPlayer = g_Map.createTileClass(); -const clHill = g_Map.createTileClass(); -const clForest = g_Map.createTileClass(); -const clDirt = g_Map.createTileClass(); -const clRock = g_Map.createTileClass(); -const clMetal = g_Map.createTileClass(); -const clBaseResource = g_Map.createTileClass(); - -placePlayerBases({ - "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), - "PlayerTileClass": clPlayer, - "BaseResourceClass": clBaseResource, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad - }, - // No berries, no chicken, no decoratives - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Trees": { - "template": oTree, - "count": scaleByMapSize(12, 30) - } -}); -Engine.SetProgress(15); - -createVolcano(mapCenter, clHill, tCliff, [tLava1, tLava2, tLava3], true, ELEVATION_SET); -Engine.SetProgress(45); - -g_Map.log("Creating hills"); -createAreas( - new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), - [ - new LayeredPainter([tCliff, tGrass], [2]), - new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), - new TileClassPainter(clHill) - ], - avoidClasses(clPlayer, 12, clHill, 15, clBaseResource, 2), - scaleByMapSize(2, 8) * numPlayers -); - -g_Map.log("Creating forests"); -const [forestTrees, stragglerTrees] = getTreeCounts(200, 1250, 0.7); -const types = [ - [[tGrassB, tGrassA, pForestD], [tGrassB, pForestD]], - [[tGrassB, tGrassA, pForestP], [tGrassB, pForestP]] -]; -const forestSize = forestTrees / (scaleByMapSize(2,8) * numPlayers); -const num = Math.floor(forestSize / types.length); -for (const type of types) +function* GenerateMap() +{ + const tGrass = ["cliff volcanic light", "ocean_rock_a", "ocean_rock_b"]; + const tGrassA = "cliff volcanic light"; + const tGrassB = "ocean_rock_a"; + const tGrassC = "ocean_rock_b"; + const tCliff = ["cliff volcanic coarse", "cave_walls"]; + const tRoad = "road1"; + const tRoadWild = "road1"; + const tLava1 = "LavaTest05"; + const tLava2 = "LavaTest04"; + const tLava3 = "LavaTest03"; + + const oTree = "gaia/tree/dead"; + const oStoneLarge = "gaia/rock/alpine_large"; + const oStoneSmall = "gaia/rock/alpine_small"; + const oMetalLarge = "gaia/ore/alpine_large"; + + const aRockLarge = "actor|geology/stone_granite_med.xml"; + const aRockMedium = "actor|geology/stone_granite_med.xml"; + + const pForestD = [tGrassC + TERRAIN_SEPARATOR + oTree, tGrassC]; + const pForestP = [tGrassB + TERRAIN_SEPARATOR + oTree, tGrassB]; + + const heightLand = 1; + const heightHill = 18; + + global.g_Map = new RandomMap(heightLand, tGrassB); + + const numPlayers = getNumPlayers(); + const mapCenter = g_Map.getCenter(); + + const clPlayer = g_Map.createTileClass(); + const clHill = g_Map.createTileClass(); + const clForest = g_Map.createTileClass(); + const clDirt = g_Map.createTileClass(); + const clRock = g_Map.createTileClass(); + const clMetal = g_Map.createTileClass(); + const clBaseResource = g_Map.createTileClass(); + + placePlayerBases({ + "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), + "PlayerTileClass": clPlayer, + "BaseResourceClass": clBaseResource, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad + }, + // No berries, no chicken, no decoratives + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Trees": { + "template": oTree, + "count": scaleByMapSize(12, 30) + } + }); + yield 15; + + createVolcano(mapCenter, clHill, tCliff, [tLava1, tLava2, tLava3], true, ELEVATION_SET); + yield 45; + + g_Map.log("Creating hills"); createAreas( - new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), + new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), [ - new LayeredPainter(type, [2]), - new TileClassPainter(clForest) + new LayeredPainter([tCliff, tGrass], [2]), + new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), + new TileClassPainter(clHill) ], - avoidClasses(clPlayer, 12, clForest, 10, clHill, 0, clBaseResource, 6), - num); + avoidClasses(clPlayer, 12, clHill, 15, clBaseResource, 2), + scaleByMapSize(2, 8) * numPlayers + ); -Engine.SetProgress(70); + g_Map.log("Creating forests"); + const [forestTrees, stragglerTrees] = getTreeCounts(200, 1250, 0.7); + const types = [ + [[tGrassB, tGrassA, pForestD], [tGrassB, pForestD]], + [[tGrassB, tGrassA, pForestP], [tGrassB, pForestP]] + ]; + const forestSize = forestTrees / (scaleByMapSize(2,8) * numPlayers); + const num = Math.floor(forestSize / types.length); + for (const type of types) + createAreas( + new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), + [ + new LayeredPainter(type, [2]), + new TileClassPainter(clForest) + ], + avoidClasses(clPlayer, 12, clForest, 10, clHill, 0, clBaseResource, 6), + num); + + yield 70; + + g_Map.log("Creating dirt patches"); + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new LayeredPainter([tGrassA, tGrassA], [1]), + new TileClassPainter(clDirt) + ], + avoidClasses(clForest, 0, clHill, 0, clPlayer, 12), + scaleByMapSize(20, 80)); + + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new TerrainPainter(tGrassB), + new TileClassPainter(clDirt) + ], + avoidClasses(clForest, 0, clHill, 0, clPlayer, 12), + scaleByMapSize(20, 80)); + + for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new TerrainPainter(tGrassC), + new TileClassPainter(clDirt) + ], + avoidClasses(clForest, 0, clHill, 0, clPlayer, 12), + scaleByMapSize(20, 80) + ); + + g_Map.log("Creating stone mines"); + let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), + new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), + scaleByMapSize(4,16), 100 + ); -g_Map.log("Creating dirt patches"); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - [ - new LayeredPainter([tGrassA, tGrassA], [1]), - new TileClassPainter(clDirt) - ], - avoidClasses(clForest, 0, clHill, 0, clPlayer, 12), - scaleByMapSize(20, 80)); + g_Map.log("Creating small stone mines"); + group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); + createObjectGroupsDeprecated(group, 0, + avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), + scaleByMapSize(4,16), 100 + ); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - [ - new TerrainPainter(tGrassB), - new TileClassPainter(clDirt) - ], - avoidClasses(clForest, 0, clHill, 0, clPlayer, 12), - scaleByMapSize(20, 80)); + g_Map.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), + scaleByMapSize(4,16), 100 + ); -for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - [ - new TerrainPainter(tGrassC), - new TileClassPainter(clDirt) - ], - avoidClasses(clForest, 0, clHill, 0, clPlayer, 12), - scaleByMapSize(20, 80) + yield 90; + + g_Map.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), + scaleByMapSize(16, 262), 50 + ); + + g_Map.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), + scaleByMapSize(8, 131), 50 ); -g_Map.log("Creating stone mines"); -let group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.log("Creating small stone mines"); -group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); -createObjectGroupsDeprecated(group, 0, - avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 1), - scaleByMapSize(4,16), 100 -); - -g_Map.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), - scaleByMapSize(4,16), 100 -); - -Engine.SetProgress(90); - -g_Map.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), - scaleByMapSize(16, 262), 50 -); - -g_Map.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), - scaleByMapSize(8, 131), 50 -); - -Engine.SetProgress(95); - -createStragglerTrees( - [oTree], - avoidClasses(clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6, clBaseResource, 6), - clForest, - stragglerTrees); - -placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4)); - -g_Map.ExportMap(); + yield 95; + + createStragglerTrees( + [oTree], + avoidClasses(clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6, clBaseResource, 6), + clForest, + stragglerTrees); + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4)); + + return g_Map; +} Index: binaries/data/mods/public/maps/random/wall_demo.js =================================================================== --- binaries/data/mods/public/maps/random/wall_demo.js +++ binaries/data/mods/public/maps/random/wall_demo.js @@ -1,322 +1,358 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); -const g_Map = new RandomMap(0, "grass1"); - -/** - * Demonstration code for wall placement. - * - * Some notes/reminders: - * - All angles (orientation) are in radians. - * - When looking at the map, with the x-axis being horizontal and the y-axis vertical: - * -- The origin point (0,0) of the map is in the bottom-left corner, - * -- A wall orientated at 0 has its "outside" facing right and its "inside" facing left. - * -- A wall orientated at Pi is reversed (obviously). - * -- A wall orientated at Pi/2 has its "outside" facing down and its "inside" facing up. - * - As a general rule, walls are drawn in a anti-clockwise direction. - * - * Some general notes concerning the arguments: - * - * - The first two arguments for most placement functions are x/y co-ordinates needed to position the wall. These are received via separate arguments, like in placeEntityPassable and their exact meaning differs between methods, but should be mostly self explanatory. The exception to this is placeLinearWall(), where the first four arguments are co-ordinates. However, whether two argument or four, the initial x/y co-ordinates are required parameters. - * - * - For some functions, the next argument is radius, indicating how far from a central point the wall should be drawn. The functions that use this are marked as doing so below. - * - * - The next argument is usually an array containing wall element type strings. (See the block comment for getWallElement() for a list of accepted type strings.) The exception to this is placeFortress(), which accepts a string here instead, identifying which of the predefined fortresses designs you wish to use. (See the example provided below for details.) - * - * Most functions will ask that you do not include "bending" wall elements in your array ("cornerIn", "cornerOut", "turn_{x}") and will complain if you attempt to do so. The ones that do this are clearly marked below. - * - * The array will generally look like: - * ["start", "medium", "tower", "gate", "tower", "medium", "end"] - * - * Remember that walls are drawn in an anti-clockwise direction. Thus, when looking at a wall element in-game, with the "outside" facing up, then the *next* wall element will be drawn to the left of *this* element. - * - * This argument is optional, and each function has a different default value. - * - * - The next argument is a string denoting the style of the wall. These are derived from the names of wallsets defined in 0ad: for example "athen_wallset_stone" becomes "athen_stone", and "rome_wallset_siege" becomes "rome_siege". (A full list can be found stored as the keys of the global constant g_WallStyles.) This argument is optional, and if not set, the civ's basic stone wallset will be used. - * - * - The next argument is the player-id of the player that is to own the wall. This argument is optional, and defaults to 0 (gaia). - * - * - The next argument is an angle defining the angle of orientation of the wall. The exact use differs slightly between functions, but hopefully the comments on the examples below should help. Also see the notes above about wall orientation. This argument is optional, and defaults to 0. - * - * - Any remaining arguments differ from function to function, but are all optional. Please read the comments below, and also the block comment of the function in wall_builder.js for further details. - * - * And have fun! - */ - -const mapSize = g_Map.getSize(); - -/** - * General wall placement setup - */ -const distToMapBorder = 5; -const distToOtherWalls = 10; -const buildableMapSize = mapSize - 2 * distToMapBorder; - -const position = new Vector2D(distToMapBorder, distToMapBorder); -const playerID = 0; -const wallStyleList = Object.keys(g_WallStyles); - -/** - * Custom wall placement (element based). - * - * Like most wall placement functions, we have to supply an x/y position. - * In this case, the x/y position marks the start of the wall. - * - * For this function, orientation indicates the angle at which the first - * wall element should be drawn. (The direction that the outside of the - * first wall element faces towards.) - * - * This function permits bending wall elements. - */ -for (const styleIndex in wallStyleList) +function* GenerateMap() { - const pos = Vector2D.add(position, new Vector2D(styleIndex * buildableMapSize / wallStyleList.length)); - const wall = ['start', 'long', 'tower', 'tower', 'tower', 'medium', 'outpost', 'medium', 'cornerOut', 'medium', 'cornerIn', 'medium', 'house', 'end', 'entryTower', 'start', 'short', 'barracks', 'gate', 'tower', 'medium', 'fort', 'medium', 'end']; - const style = wallStyleList[styleIndex]; - const orientation = Math.PI / 16 * Math.sin(styleIndex * Math.PI / 4); - placeWall(pos, wall, style, playerID, orientation); -} - -position.y += 80 + distToOtherWalls; - -/** - * Default fortress placement (chosen by fortress type string) - * - * The x/y position in this case marks the center point of the fortress. - * To make it clearer, we add an obilisk as a visual marker. - * - * This is the only wall placement function that does not take an array - * of elements as an argument. Instead, we provide a "type" that identifies - * a predefined design to draw. The list of possible types are: "tiny", - * "small", "medium", "normal", "large", "veryLarge", and "giant". - * - * For this function, orientation is the direction in which the main gate - * is facing. - */ -const fortressRadius = 15; // The space the fortresses take in average. Just for design of this map. Not passed to the function. - -for (const styleIndex in wallStyleList) -{ - const type = "tiny"; - const style = wallStyleList[styleIndex]; - const orientation = styleIndex * Math.PI / 32; - - const pos = Vector2D.sum([ - position, - new Vector2D(1, 1).mult(fortressRadius), - new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0) - ]); - - g_Map.placeEntityPassable("structures/obelisk", playerID, pos, orientation); - placeFortress(pos, type, style, playerID, orientation); -} - -position.y += 2 * fortressRadius + distToOtherWalls; - -/** - * 'Generic' fortress placement (iberian wall circuit code) - * - * The function used here is unusual in that the owner and style arguments - * are swapped. It is also unusual in that we do not supply an orientation. - * - * The x/y position in this case marks the center point of the fortress. - * To make it clearer, we add an obilisk as a visual marker. - * - * We also supply a radius value to dictate how wide the circuit of walls should be. - */ -let radius = Math.min((mapSize - position.y - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); -for (const styleIndex in wallStyleList) -{ - const style = wallStyleList[styleIndex]; - - const pos = Vector2D.sum([ - position, - new Vector2D(radius, radius), - new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0) - ]); + global.g_Map = new RandomMap(0, "grass1"); + + /** + * Demonstration code for wall placement. + * + * Some notes/reminders: + * - All angles (orientation) are in radians. + * - When looking at the map, with the x-axis being horizontal and the y-axis vertical: + * -- The origin point (0,0) of the map is in the bottom-left corner, + * -- A wall orientated at 0 has its "outside" facing right and its "inside" facing left. + * -- A wall orientated at Pi is reversed (obviously). + * -- A wall orientated at Pi/2 has its "outside" facing down and its "inside" facing up. + * - As a general rule, walls are drawn in a anti-clockwise direction. + * + * Some general notes concerning the arguments: + * + * - The first two arguments for most placement functions are x/y co-ordinates needed to position the + * wall. These are received via separate arguments, like in placeEntityPassable and their exact + * meaning differs between methods, but should be mostly self explanatory. The exception to this + * is placeLinearWall(), where the first four arguments are co-ordinates. However, whether two + * argument or four, the initial x/y co-ordinates are required parameters. + * + * - For some functions, the next argument is radius, indicating how far from a central point the wall + * should be drawn. The functions that use this are marked as doing so below. + * + * - The next argument is usually an array containing wall element type strings. (See the block + * comment for getWallElement() for a list of accepted type strings.) The exception to this is + * placeFortress(), which accepts a string here instead, identifying which of the predefined + * fortresses designs you wish to use. (See the example provided below for details.) + * + * Most functions will ask that you do not include "bending" wall elements in your array + * ("cornerIn", "cornerOut", "turn_{x}") and will complain if you attempt to do so. The ones that + * do this are clearly marked below. + * + * The array will generally look like: + * ["start", "medium", "tower", "gate", "tower", "medium", "end"] + * + * Remember that walls are drawn in an anti-clockwise direction. Thus, when looking at a wall + * element in-game, with the "outside" facing up, then the *next* wall element will be drawn to the + * left of *this* element. + * + * This argument is optional, and each function has a different default value. + * + * - The next argument is a string denoting the style of the wall. These are derived from the names of + * wallsets defined in 0ad: for example "athen_wallset_stone" becomes "athen_stone", and + * "rome_wallset_siege" becomes "rome_siege". (A full list can be found stored as the keys of the + * global constant g_WallStyles.) This argument is optional, and if not set, the civ's basic stone wallset will be used. + * + * - The next argument is the player-id of the player that is to own the wall. This argument is + * optional, and defaults to 0 (gaia). + * + * - The next argument is an angle defining the angle of orientation of the wall. The exact use + * differs slightly between functions, but hopefully the comments on the examples below should + * help. Also see the notes above about wall orientation. This argument is optional, and defaults + * to 0. + * + * - Any remaining arguments differ from function to function, but are all optional. Please read the + * comments below, and also the block comment of the function in wall_builder.js for further details. + * + * And have fun! + */ + + const mapSize = g_Map.getSize(); + + /** + * General wall placement setup + */ + const distToMapBorder = 5; + const distToOtherWalls = 10; + const buildableMapSize = mapSize - 2 * distToMapBorder; + + const position = new Vector2D(distToMapBorder, distToMapBorder); + const playerID = 0; + const wallStyleList = Object.keys(g_WallStyles); + + /** + * Custom wall placement (element based). + * + * Like most wall placement functions, we have to supply an x/y position. + * In this case, the x/y position marks the start of the wall. + * + * For this function, orientation indicates the angle at which the first + * wall element should be drawn. (The direction that the outside of the + * first wall element faces towards.) + * + * This function permits bending wall elements. + */ + for (const styleIndex in wallStyleList) + { + const pos = Vector2D.add(position, new Vector2D(styleIndex * buildableMapSize / + wallStyleList.length)); + const wall = ['start', 'long', 'tower', 'tower', 'tower', 'medium', 'outpost', 'medium', + 'cornerOut', 'medium', 'cornerIn', 'medium', 'house', 'end', 'entryTower', 'start', + 'short', 'barracks', 'gate', 'tower', 'medium', 'fort', 'medium', 'end']; + const style = wallStyleList[styleIndex]; + const orientation = Math.PI / 16 * Math.sin(styleIndex * Math.PI / 4); + placeWall(pos, wall, style, playerID, orientation); + } - g_Map.placeEntityPassable("structures/obelisk", playerID, pos, 0); - placeGenericFortress(pos, radius, playerID, style); -} + position.y += 80 + distToOtherWalls; + + /** + * Default fortress placement (chosen by fortress type string) + * + * The x/y position in this case marks the center point of the fortress. + * To make it clearer, we add an obilisk as a visual marker. + * + * This is the only wall placement function that does not take an array + * of elements as an argument. Instead, we provide a "type" that identifies + * a predefined design to draw. The list of possible types are: "tiny", + * "small", "medium", "normal", "large", "veryLarge", and "giant". + * + * For this function, orientation is the direction in which the main gate + * is facing. + */ + // The space the fortresses take in average. Just for design of this map. Not passed to the function. + const fortressRadius = 15; + + for (const styleIndex in wallStyleList) + { + const type = "tiny"; + const style = wallStyleList[styleIndex]; + const orientation = styleIndex * Math.PI / 32; + + const pos = Vector2D.sum([ + position, + new Vector2D(1, 1).mult(fortressRadius), + new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0) + ]); + + g_Map.placeEntityPassable("structures/obelisk", playerID, pos, orientation); + placeFortress(pos, type, style, playerID, orientation); + } -position.y += 2 * radius + distToOtherWalls; - -/** - * Circular wall placement - * - * It is possible with this function to draw complete circles, or arcs. - * Each side of the wall consists of the contents of the provided wall - * array, with the code calculating the number and angle of turns and - * sides automatically based on the calculated length of each side and - * the given radius. - * - * This function does not permit the use of bending wall elements. - * - * In this case, the x/y co-ordinates are the center point around which - * to draw the walls. To make this clearer, we add an obelisk as a visual - * marker. - * - * We also provide a radius to define the distance between the center - * point and the walls. - * - * For this function, orientation is the direction that the opening of an - * arc faces. If the wall is to be a complete circle, then this is used as - * the orientation of the first wall piece. - */ -radius = Math.min((mapSize - position.y - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); -for (const styleIndex in wallStyleList) -{ - const center = Vector2D.sum([position, new Vector2D(1, 1).mult(radius), new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)]); - const wallPart = ['tower', 'medium', 'house']; - const style = wallStyleList[styleIndex]; - const orientation = styleIndex * Math.PI / 16; - - // maxAngle is how far the wall should circumscribe the center. - // If equal to Pi * 2, then the wall will be a full circle. - // If less than Pi * 2, then the wall will be an arc. - const maxAngle = Math.PI / 2 * (styleIndex % 3 + 2); - - g_Map.placeEntityPassable("structures/obelisk", playerID, center, orientation); - placeCircularWall(center, radius, wallPart, style, playerID, orientation, maxAngle); -} + position.y += 2 * fortressRadius + distToOtherWalls; + + /** + * 'Generic' fortress placement (iberian wall circuit code) + * + * The function used here is unusual in that the owner and style arguments + * are swapped. It is also unusual in that we do not supply an orientation. + * + * The x/y position in this case marks the center point of the fortress. + * To make it clearer, we add an obilisk as a visual marker. + * + * We also supply a radius value to dictate how wide the circuit of walls should be. + */ + let radius = Math.min((mapSize - position.y - distToOtherWalls) / 3, (buildableMapSize / + wallStyleList.length - distToOtherWalls) / 2); + for (const styleIndex in wallStyleList) + { + const style = wallStyleList[styleIndex]; -position.y += 2 * radius + distToOtherWalls; - -/** - * Regular Polygonal wall placement - * - * This function draws a regular polygonal wall around a given point. All - * the sides follow the same pattern, and the (automatically calculated) - * angles at the corners are identical. We define how many corners we want. - * - * This function does not permit the use of bending wall elements. - * - * In this case, the x/y co-ordinates are the center point around which - * to draw the walls. To make this clearer, we add an obelisk as a visual - * marker. - * - * We also provide a radius to define the distance between the center - * point and the walls. - * - * After the usual array of wall elements to use, and before the style - * argument, we provide the name of a single wall element to use as a - * corner piece. - * - * In this function, orientation is the direction the first wall has its - * outward side facing or, if the `skipFirstWall` argument is true, the - * opening in the wall. - */ - -radius = Math.min((mapSize - position.y - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); -for (const styleIndex in wallStyleList) -{ - const centerPosition = Vector2D.sum([position, new Vector2D(1, 1).mult(radius), new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)]); - const wallParts = ['medium', 'tower']; // Function default: ['long', 'tower'] + const pos = Vector2D.sum([ + position, + new Vector2D(radius, radius), + new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0) + ]); - // Which wall element to use for the corners of the polygon - const cornerWallElement = 'tower'; + g_Map.placeEntityPassable("structures/obelisk", playerID, pos, 0); + placeGenericFortress(pos, radius, playerID, style); + } - const style = wallStyleList[styleIndex]; - const orientation = styleIndex * Math.PI / 16; + position.y += 2 * radius + distToOtherWalls; + + /** + * Circular wall placement + * + * It is possible with this function to draw complete circles, or arcs. + * Each side of the wall consists of the contents of the provided wall + * array, with the code calculating the number and angle of turns and + * sides automatically based on the calculated length of each side and + * the given radius. + * + * This function does not permit the use of bending wall elements. + * + * In this case, the x/y co-ordinates are the center point around which + * to draw the walls. To make this clearer, we add an obelisk as a visual + * marker. + * + * We also provide a radius to define the distance between the center + * point and the walls. + * + * For this function, orientation is the direction that the opening of an + * arc faces. If the wall is to be a complete circle, then this is used as + * the orientation of the first wall piece. + */ + radius = Math.min((mapSize - position.y - distToOtherWalls) / 3, (buildableMapSize / + wallStyleList.length - distToOtherWalls) / 2); + for (const styleIndex in wallStyleList) + { + const center = Vector2D.sum([position, new Vector2D(1, 1).mult(radius), + new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)]); + const wallPart = ['tower', 'medium', 'house']; + const style = wallStyleList[styleIndex]; + const orientation = styleIndex * Math.PI / 16; + + // maxAngle is how far the wall should circumscribe the center. + // If equal to Pi * 2, then the wall will be a full circle. + // If less than Pi * 2, then the wall will be an arc. + const maxAngle = Math.PI / 2 * (styleIndex % 3 + 2); + + g_Map.placeEntityPassable("structures/obelisk", playerID, center, orientation); + placeCircularWall(center, radius, wallPart, style, playerID, orientation, maxAngle); + } - // How many corners the polygon should have: - const numCorners = styleIndex % 6 + 3; + position.y += 2 * radius + distToOtherWalls; + + /** + * Regular Polygonal wall placement + * + * This function draws a regular polygonal wall around a given point. All + * the sides follow the same pattern, and the (automatically calculated) + * angles at the corners are identical. We define how many corners we want. + * + * This function does not permit the use of bending wall elements. + * + * In this case, the x/y co-ordinates are the center point around which + * to draw the walls. To make this clearer, we add an obelisk as a visual + * marker. + * + * We also provide a radius to define the distance between the center + * point and the walls. + * + * After the usual array of wall elements to use, and before the style + * argument, we provide the name of a single wall element to use as a + * corner piece. + * + * In this function, orientation is the direction the first wall has its + * outward side facing or, if the `skipFirstWall` argument is true, the + * opening in the wall. + */ + + radius = Math.min((mapSize - position.y - distToOtherWalls) / 2, (buildableMapSize / + wallStyleList.length - distToOtherWalls) / 2); + for (const styleIndex in wallStyleList) + { + const centerPosition = Vector2D.sum([position, new Vector2D(1, 1).mult(radius), + new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)]); + const wallParts = ['medium', 'tower']; // Function default: ['long', 'tower'] - // If true, the first side will not be drawn, leaving the wall open. - const skipFirstWall = true; + // Which wall element to use for the corners of the polygon + const cornerWallElement = 'tower'; - g_Map.placeEntityPassable("structures/obelisk", playerID, centerPosition, orientation); - placePolygonalWall(centerPosition, radius, wallParts, cornerWallElement, style, playerID, orientation, numCorners, skipFirstWall); -} + const style = wallStyleList[styleIndex]; + const orientation = styleIndex * Math.PI / 16; -position.y += 2 * radius + distToOtherWalls; - -/** - * Irregular Polygonal wall placement - * - * This function draws an irregular polygonal wall around a given point. - * Each side of the wall is different, each element used selected at - * pesudo-random from an assortment. The angles at the corners also differ. - * We can control this randomness by changing the irregularity argument. - * - * This function does not permit the use of bending wall elements. - * - * In this case, the x/y co-ordinates are the center point around which - * to draw the walls. To make this clearer, we add an obelisk as a visual - * marker. - * - * We also provide a radius to define the distance between the center - * point and the walls. - * - * The usual array of wall elements is left out here, instead we provide - * the name of a single wall element to use as a corner piece. - * - * In this function, orientation is the direction the first wall has its - * outward side facing or, if the `skipFirstWall` argument is true, the - * opening in the wall. - * - * The very last argument is the collection of wallparts used to build - * the wall. It is not defined in this example (so as to use the defaults) - * as it is not easy to comprehend. - */ -radius = Math.min((mapSize - position.y - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons -for (const styleIndex in wallStyleList) -{ - const centerPosition = Vector2D.sum([ - position, - new Vector2D(1, 1).mult(radius), - new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0) - ]); + // How many corners the polygon should have: + const numCorners = styleIndex % 6 + 3; - // Which wall element type will be used for the corners of the polygon. - const cornerWallElement = 'tower'; + // If true, the first side will not be drawn, leaving the wall open. + const skipFirstWall = true; - const style = wallStyleList[styleIndex]; - const orientation = styleIndex * Math.PI / 16; + g_Map.placeEntityPassable("structures/obelisk", playerID, centerPosition, orientation); + placePolygonalWall(centerPosition, radius, wallParts, cornerWallElement, style, playerID, + orientation, numCorners, skipFirstWall); + } - // How many corners the polygon will have - const numCorners = styleIndex % 6 + 3; + position.y += 2 * radius + distToOtherWalls; + + /** + * Irregular Polygonal wall placement + * + * This function draws an irregular polygonal wall around a given point. + * Each side of the wall is different, each element used selected at + * pesudo-random from an assortment. The angles at the corners also differ. + * We can control this randomness by changing the irregularity argument. + * + * This function does not permit the use of bending wall elements. + * + * In this case, the x/y co-ordinates are the center point around which + * to draw the walls. To make this clearer, we add an obelisk as a visual + * marker. + * + * We also provide a radius to define the distance between the center + * point and the walls. + * + * The usual array of wall elements is left out here, instead we provide + * the name of a single wall element to use as a corner piece. + * + * In this function, orientation is the direction the first wall has its + * outward side facing or, if the `skipFirstWall` argument is true, the + * opening in the wall. + * + * The very last argument is the collection of wallparts used to build + * the wall. It is not defined in this example (so as to use the defaults) + * as it is not easy to comprehend. + */ + radius = Math.min((mapSize - position.y - distToOtherWalls) / 2, (buildableMapSize / + wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons + for (const styleIndex in wallStyleList) + { + const centerPosition = Vector2D.sum([ + position, + new Vector2D(1, 1).mult(radius), + new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0) + ]); - // Irregularity of the polygon. - const irregularity = 0.5; + // Which wall element type will be used for the corners of the polygon. + const cornerWallElement = 'tower'; - // If true, the first side will not be drawn, leaving the wall open. - const skipFirstWall = true; + const style = wallStyleList[styleIndex]; + const orientation = styleIndex * Math.PI / 16; - g_Map.placeEntityPassable("structures/obelisk", playerID, centerPosition, orientation); - placeIrregularPolygonalWall(centerPosition, radius, cornerWallElement, style, playerID, orientation, numCorners, irregularity, skipFirstWall); -} + // How many corners the polygon will have + const numCorners = styleIndex % 6 + 3; -position.y += 2 * radius + distToOtherWalls; - -/** - * Linear wall placement - * - * This function draws a straight wall between two given points. - * - * This function does not permit the use of bending wall elements. - * - * This function has no orientation parameter, the wall pieces are angled - * automatically. Remember: each piece is placed to the left of the - * previous piece. Thus, if the start point is at the right-hand side of - * the screen and the end point is at the left-hand side, the "outside" - * of the walls is facing the top of the screen. - */ -// Two vars, just for this map; firstly how long the longest wall will be. -const maxWallLength = (mapSize - position.y - distToMapBorder - distToOtherWalls); -// And secondly, how many walls of the same style will be placed. -const numWallsPerStyle = Math.floor(buildableMapSize / distToOtherWalls / wallStyleList.length); - -for (const styleIndex in wallStyleList) - for (let wallIndex = 0; wallIndex < numWallsPerStyle; ++wallIndex) - { - const offsetX = (styleIndex * numWallsPerStyle + wallIndex) * buildableMapSize / wallStyleList.length / numWallsPerStyle; - const start = Vector2D.add(position, new Vector2D(offsetX, 0)); + // Irregularity of the polygon. + const irregularity = 0.5; - const offsetY = (wallIndex + 1) * maxWallLength / numWallsPerStyle; - const end = Vector2D.add(position, new Vector2D(offsetX, offsetY)); + // If true, the first side will not be drawn, leaving the wall open. + const skipFirstWall = true; - placeLinearWall(start, end, ['tower', 'medium'], wallStyleList[styleIndex], playerID); + g_Map.placeEntityPassable("structures/obelisk", playerID, centerPosition, orientation); + placeIrregularPolygonalWall(centerPosition, radius, cornerWallElement, style, playerID, + orientation, numCorners, irregularity, skipFirstWall); } -g_Map.ExportMap(); + position.y += 2 * radius + distToOtherWalls; + + /** + * Linear wall placement + * + * This function draws a straight wall between two given points. + * + * This function does not permit the use of bending wall elements. + * + * This function has no orientation parameter, the wall pieces are angled + * automatically. Remember: each piece is placed to the left of the + * previous piece. Thus, if the start point is at the right-hand side of + * the screen and the end point is at the left-hand side, the "outside" + * of the walls is facing the top of the screen. + */ + // Two vars, just for this map; firstly how long the longest wall will be. + const maxWallLength = (mapSize - position.y - distToMapBorder - distToOtherWalls); + // And secondly, how many walls of the same style will be placed. + const numWallsPerStyle = Math.floor(buildableMapSize / distToOtherWalls / wallStyleList.length); + + for (const styleIndex in wallStyleList) + for (let wallIndex = 0; wallIndex < numWallsPerStyle; ++wallIndex) + { + const offsetX = (styleIndex * numWallsPerStyle + wallIndex) * buildableMapSize / + wallStyleList.length / numWallsPerStyle; + const start = Vector2D.add(position, new Vector2D(offsetX, 0)); + + const offsetY = (wallIndex + 1) * maxWallLength / numWallsPerStyle; + const end = Vector2D.add(position, new Vector2D(offsetX, offsetY)); + + placeLinearWall(start, end, ['tower', 'medium'], wallStyleList[styleIndex], playerID); + } + + return g_Map; +} Index: binaries/data/mods/public/maps/random/wild_lake.js =================================================================== --- binaries/data/mods/public/maps/random/wild_lake.js +++ binaries/data/mods/public/maps/random/wild_lake.js @@ -3,579 +3,645 @@ Engine.LoadLibrary("rmbiome"); Engine.LoadLibrary("heightmap"); -const g_Map = new RandomMap(0, "whiteness"); - -/** - * getArray - To ensure a terrain texture is contained within an array - */ -function getArray(stringOrArrayOfStrings) +function* GenerateMap() { - if (typeof stringOrArrayOfStrings == "string") - return [stringOrArrayOfStrings]; - return stringOrArrayOfStrings; -} - -setSelectedBiome(); + global.g_Map = new RandomMap(0, "whiteness"); -// Terrain, entities and actors -const wildLakeBiome = [ - // 0 Deep water - { - "texture": getArray(g_Terrains.water), - "entity": [[g_Gaia.fish], 0.005], - "textureHS": getArray(g_Terrains.water), - "entityHS": [[g_Gaia.fish], 0.01] - }, - // 1 Shallow water - { - "texture": getArray(g_Terrains.water), - "entity": [[g_Decoratives.lillies, g_Decoratives.reeds], 0.3], - "textureHS": getArray(g_Terrains.water), - "entityHS": [[g_Decoratives.lillies], 0.1] - }, - // 2 Shore + /** + * getArray - To ensure a terrain texture is contained within an array + */ + function getArray(stringOrArrayOfStrings) { - "texture": getArray(g_Terrains.shore), - "entity": [ - [ - g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, - g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, - g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, - g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, - g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, - g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, - g_Gaia.mainHuntableAnimal, - g_Decoratives.grass, g_Decoratives.grass, - g_Decoratives.rockMedium, g_Decoratives.rockMedium, g_Decoratives.rockMedium, g_Decoratives.rockMedium, - g_Decoratives.rockMedium, g_Decoratives.rockMedium, g_Decoratives.rockMedium, g_Decoratives.rockMedium, - g_Decoratives.bushMedium, g_Decoratives.bushMedium, g_Decoratives.bushMedium, g_Decoratives.bushMedium, - g_Decoratives.bushMedium, g_Decoratives.bushMedium, g_Decoratives.bushMedium, g_Decoratives.bushMedium + if (typeof stringOrArrayOfStrings == "string") + return [stringOrArrayOfStrings]; + return stringOrArrayOfStrings; + } + + setSelectedBiome(); + + // Terrain, entities and actors + const wildLakeBiome = [ + // 0 Deep water + { + "texture": getArray(g_Terrains.water), + "entity": [[g_Gaia.fish], 0.005], + "textureHS": getArray(g_Terrains.water), + "entityHS": [[g_Gaia.fish], 0.01] + }, + // 1 Shallow water + { + "texture": getArray(g_Terrains.water), + "entity": [[g_Decoratives.lillies, g_Decoratives.reeds], 0.3], + "textureHS": getArray(g_Terrains.water), + "entityHS": [[g_Decoratives.lillies], 0.1] + }, + // 2 Shore + { + "texture": getArray(g_Terrains.shore), + "entity": [ + [ + g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, + g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, + g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, + g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, + g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, + g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, + g_Gaia.mainHuntableAnimal, g_Decoratives.grass, g_Decoratives.grass, + g_Decoratives.rockMedium, g_Decoratives.rockMedium, g_Decoratives.rockMedium, + g_Decoratives.rockMedium, g_Decoratives.rockMedium, g_Decoratives.rockMedium, + g_Decoratives.rockMedium, g_Decoratives.rockMedium, g_Decoratives.bushMedium, + g_Decoratives.bushMedium, g_Decoratives.bushMedium, g_Decoratives.bushMedium, + g_Decoratives.bushMedium, g_Decoratives.bushMedium, g_Decoratives.bushMedium, + g_Decoratives.bushMedium + ], + 0.3 ], - 0.3 - ], - "textureHS": getArray(g_Terrains.cliff), - "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, g_Decoratives.bushSmall], 0.05] - }, - // 3 Low ground - { - "texture": getArray(g_Terrains.tier1Terrain), - "entity": [ - [ - g_Decoratives.grass, - g_Decoratives.grassShort, - g_Decoratives.rockLarge, - g_Decoratives.rockMedium, - g_Decoratives.bushMedium, - g_Decoratives.bushSmall + "textureHS": getArray(g_Terrains.cliff), + "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, + g_Decoratives.bushSmall], 0.05] + }, + // 3 Low ground + { + "texture": getArray(g_Terrains.tier1Terrain), + "entity": [ + [ + g_Decoratives.grass, + g_Decoratives.grassShort, + g_Decoratives.rockLarge, + g_Decoratives.rockMedium, + g_Decoratives.bushMedium, + g_Decoratives.bushSmall + ], + 0.07 ], - 0.07 - ], - "textureHS": getArray(g_Terrains.cliff), - "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, g_Decoratives.bushSmall], 0.05] - }, - // 4 Mid ground. Player and path height - { - "texture": getArray(g_Terrains.mainTerrain), - "entity": [ - [ - g_Decoratives.grass, - g_Decoratives.grassShort, - g_Decoratives.rockLarge, - g_Decoratives.rockMedium, - g_Decoratives.bushMedium, - g_Decoratives.bushSmall + "textureHS": getArray(g_Terrains.cliff), + "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, + g_Decoratives.bushSmall], 0.05] + }, + // 4 Mid ground. Player and path height + { + "texture": getArray(g_Terrains.mainTerrain), + "entity": [ + [ + g_Decoratives.grass, + g_Decoratives.grassShort, + g_Decoratives.rockLarge, + g_Decoratives.rockMedium, + g_Decoratives.bushMedium, + g_Decoratives.bushSmall + ], + 0.07 ], - 0.07 - ], - "textureHS": getArray(g_Terrains.cliff), - "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, g_Decoratives.bushSmall], 0.05] - }, - // 5 High ground - { - "texture": getArray(g_Terrains.tier2Terrain), - "entity": [ - [ - g_Decoratives.grass, - g_Decoratives.grassShort, - g_Decoratives.rockLarge, - g_Decoratives.rockMedium, - g_Decoratives.bushMedium, - g_Decoratives.bushSmall + "textureHS": getArray(g_Terrains.cliff), + "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, + g_Decoratives.bushSmall], 0.05] + }, + // 5 High ground + { + "texture": getArray(g_Terrains.tier2Terrain), + "entity": [ + [ + g_Decoratives.grass, + g_Decoratives.grassShort, + g_Decoratives.rockLarge, + g_Decoratives.rockMedium, + g_Decoratives.bushMedium, + g_Decoratives.bushSmall + ], + 0.07 ], - 0.07 - ], - "textureHS": getArray(g_Terrains.cliff), - "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, g_Decoratives.bushSmall], 0.05] - }, - // 6 Lower hilltop forest border - { - "texture": getArray(g_Terrains.dirt), - "entity": [ - [ - g_Gaia.tree1, g_Gaia.tree1, - g_Gaia.tree3, g_Gaia.tree3, - g_Gaia.fruitBush, - g_Gaia.secondaryHuntableAnimal, - g_Decoratives.grass, g_Decoratives.grass, - g_Decoratives.rockMedium, g_Decoratives.rockMedium, - g_Decoratives.bushMedium, g_Decoratives.bushMedium + "textureHS": getArray(g_Terrains.cliff), + "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, + g_Decoratives.bushSmall], 0.05] + }, + // 6 Lower hilltop forest border + { + "texture": getArray(g_Terrains.dirt), + "entity": [ + [ + g_Gaia.tree1, g_Gaia.tree1, + g_Gaia.tree3, g_Gaia.tree3, + g_Gaia.fruitBush, + g_Gaia.secondaryHuntableAnimal, + g_Decoratives.grass, g_Decoratives.grass, + g_Decoratives.rockMedium, g_Decoratives.rockMedium, + g_Decoratives.bushMedium, g_Decoratives.bushMedium + ], + 0.25 ], - 0.25 - ], - "textureHS": getArray(g_Terrains.cliff), - "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, g_Decoratives.bushSmall], 0.1] - }, - // 7 Hilltop forest - { - "texture": getArray(g_Terrains.forestFloor1), - "entity": [ - [ - g_Gaia.tree1, - g_Gaia.tree2, - g_Gaia.tree3, - g_Gaia.tree4, - g_Gaia.tree5, - g_Decoratives.tree, - g_Decoratives.grass, - g_Decoratives.rockMedium, - g_Decoratives.bushMedium + "textureHS": getArray(g_Terrains.cliff), + "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, + g_Decoratives.bushSmall], 0.1] + }, + // 7 Hilltop forest + { + "texture": getArray(g_Terrains.forestFloor1), + "entity": [ + [ + g_Gaia.tree1, + g_Gaia.tree2, + g_Gaia.tree3, + g_Gaia.tree4, + g_Gaia.tree5, + g_Decoratives.tree, + g_Decoratives.grass, + g_Decoratives.rockMedium, + g_Decoratives.bushMedium + ], + 0.3 ], - 0.3 - ], - "textureHS": getArray(g_Terrains.cliff), - "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, g_Decoratives.bushSmall], 0.1] - } -]; - -const wildLakeEntities = Engine.ReadJSONFile("maps/random/wild_lake_biomes.json"); -const farmEntities = wildLakeEntities[currentBiome()].farmEntities; -const mercenaryCampEntities = wildLakeEntities[currentBiome()].mercenaryCampEntities; -const guards = mercenaryCampEntities - .map(ent => ent.Template) - .filter(ent => ent.indexOf("units/") != -1); -const campEntities = wildLakeEntities.campEntities.concat(guards); - -/** - * Resource spots and other points of interest - */ - -function placeMine(position, centerEntity, - decorativeActors = [ - g_Decoratives.grass, g_Decoratives.grassShort, - g_Decoratives.rockLarge, g_Decoratives.rockMedium, - g_Decoratives.bushMedium, g_Decoratives.bushSmall - ] -) -{ - g_Map.placeEntityPassable(centerEntity, 0, position, randomAngle()); - - const quantity = randIntInclusive(11, 23); - const dAngle = 2 * Math.PI / quantity; - for (let i = 0; i < quantity; ++i) - g_Map.placeEntityPassable( - pickRandom(decorativeActors), - 0, - Vector2D.add(position, new Vector2D(randFloat(2, 5), 0).rotate(-dAngle * randFloat(i, i + 1))), - randomAngle()); -} - -// Groves, only wood -const groveActors = [g_Decoratives.grass, g_Decoratives.rockMedium, g_Decoratives.bushMedium]; -const clGaiaCamp = g_Map.createTileClass(); - -function placeGrove(point, - groveEntities = [ - g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, - g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, - g_Gaia.tree3, g_Gaia.tree3, g_Gaia.tree3, - g_Gaia.tree4, g_Gaia.tree4, g_Gaia.tree5 - ], - groveActors = [g_Decoratives.grass, g_Decoratives.rockMedium, g_Decoratives.bushMedium], groveTileClass = undefined, - groveTerrainTexture = getArray(g_Terrains.forestFloor1) -) -{ - const position = new Vector2D(point.x, point.y); - g_Map.placeEntityPassable(pickRandom(["structures/gaul/outpost", g_Gaia.tree1]), 0, position, randomAngle()); + "textureHS": getArray(g_Terrains.cliff), + "entityHS": [[g_Decoratives.grassShort, g_Decoratives.rockMedium, + g_Decoratives.bushSmall], 0.1] + } + ]; - const quantity = randIntInclusive(20, 30); - const dAngle = 2 * Math.PI / quantity; - for (let i = 0; i < quantity; ++i) + const wildLakeEntities = Engine.ReadJSONFile("maps/random/wild_lake_biomes.json"); + const farmEntities = wildLakeEntities[currentBiome()].farmEntities; + const mercenaryCampEntities = wildLakeEntities[currentBiome()].mercenaryCampEntities; + const guards = mercenaryCampEntities + .map(ent => ent.Template) + .filter(ent => ent.indexOf("units/") != -1); + const campEntities = wildLakeEntities.campEntities.concat(guards); + + /** + * Resource spots and other points of interest + */ + + function placeMine(position, centerEntity, + decorativeActors = [ + g_Decoratives.grass, g_Decoratives.grassShort, + g_Decoratives.rockLarge, g_Decoratives.rockMedium, + g_Decoratives.bushMedium, g_Decoratives.bushSmall + ] + ) { - const angle = dAngle * randFloat(i, i + 1); - const dist = randFloat(2, 5); - let objectList = groveEntities; - if (i % 3 == 0) - objectList = groveActors; + g_Map.placeEntityPassable(centerEntity, 0, position, randomAngle()); + + const quantity = randIntInclusive(11, 23); + const dAngle = 2 * Math.PI / quantity; + for (let i = 0; i < quantity; ++i) + g_Map.placeEntityPassable( + pickRandom(decorativeActors), + 0, + Vector2D.add(position, + new Vector2D(randFloat(2, 5), 0).rotate(-dAngle * randFloat(i, i + 1))), + randomAngle()); + } - const pos = Vector2D.add(position, new Vector2D(dist, 0).rotate(-angle)); - g_Map.placeEntityPassable(pickRandom(objectList), 0, pos, randomAngle()); + // Groves, only wood + const groveActors = [g_Decoratives.grass, g_Decoratives.rockMedium, g_Decoratives.bushMedium]; + const clGaiaCamp = g_Map.createTileClass(); - const painters = [new TerrainPainter(groveTerrainTexture)]; - if (groveTileClass) - painters.push(new TileClassPainter(groveTileClass)); + function placeGrove(point, + groveEntities = [ + g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, + g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, + g_Gaia.tree3, g_Gaia.tree3, g_Gaia.tree3, + g_Gaia.tree4, g_Gaia.tree4, g_Gaia.tree5 + ], + groveActors = [g_Decoratives.grass, g_Decoratives.rockMedium, g_Decoratives.bushMedium], + groveTileClass = undefined, + groveTerrainTexture = getArray(g_Terrains.forestFloor1) + ) + { + const position = new Vector2D(point.x, point.y); + g_Map.placeEntityPassable(pickRandom(["structures/gaul/outpost", g_Gaia.tree1]), 0, position, + randomAngle()); - createArea( - new ClumpPlacer(5, 1, 1, Infinity, pos), - painters); + const quantity = randIntInclusive(20, 30); + const dAngle = 2 * Math.PI / quantity; + for (let i = 0; i < quantity; ++i) + { + const angle = dAngle * randFloat(i, i + 1); + const dist = randFloat(2, 5); + let objectList = groveEntities; + if (i % 3 == 0) + objectList = groveActors; + + const pos = Vector2D.add(position, new Vector2D(dist, 0).rotate(-angle)); + g_Map.placeEntityPassable(pickRandom(objectList), 0, pos, randomAngle()); + + const painters = [new TerrainPainter(groveTerrainTexture)]; + if (groveTileClass) + painters.push(new TileClassPainter(groveTileClass)); + + createArea( + new ClumpPlacer(5, 1, 1, Infinity, pos), + painters); + } } -} -g_WallStyles.other = { - "overlap": 0, - "fence": readyWallElement("structures/fence_long", "gaia"), - "fence_short": readyWallElement("structures/fence_short", "gaia"), - "bench": { "angle": Math.PI / 2, "length": 1.5, "indent": 0, "bend": 0, "templateName": "structures/bench" }, - "foodBin": { "angle": Math.PI / 2, "length": 1.5, "indent": 0, "bend": 0, "templateName": "gaia/treasure/food_bin" }, - "animal": { "angle": 0, "length": 0, "indent": 0.75, "bend": 0, "templateName": farmEntities.animal }, - "farmstead": { "angle": Math.PI, "length": 0, "indent": -3, "bend": 0, "templateName": farmEntities.building } -}; - -const fences = [ - new Fortress("fence", [ - "foodBin", "farmstead", "bench", - "turn_0.25", "animal", "turn_0.25", "fence", - "turn_0.25", "animal", "turn_0.25", "fence", - "turn_0.25", "animal", "turn_0.25", "fence" - ]), - new Fortress("fence", [ - "foodBin", "farmstead", "fence", - "turn_0.25", "animal", "turn_0.25", "fence", - "turn_0.25", "animal", "turn_0.25", "bench", "animal", "fence", - "turn_0.25", "animal", "turn_0.25", "fence" - ]), - new Fortress("fence", [ - "foodBin", "farmstead", "turn_0.5", "bench", "turn_-0.5", "fence_short", - "turn_0.25", "animal", "turn_0.25", "fence", - "turn_0.25", "animal", "turn_0.25", "fence", - "turn_0.25", "animal", "turn_0.25", "fence_short", "animal", "fence" - ]), - new Fortress("fence", [ - "foodBin", "farmstead", "turn_0.5", "fence_short", "turn_-0.5", "bench", - "turn_0.25", "animal", "turn_0.25", "fence", - "turn_0.25", "animal", "turn_0.25", "fence", - "turn_0.25", "animal", "turn_0.25", "fence_short", "animal", "fence" - ]), - new Fortress("fence", [ - "foodBin", "farmstead", "fence", - "turn_0.25", "animal", "turn_0.25", "bench", "animal", "fence", - "turn_0.25", "animal", "turn_0.25", "fence_short", "animal", "fence", - "turn_0.25", "animal", "turn_0.25", "fence_short", "animal", "fence" - ]) -]; -const num = fences.length; -for (let i = 0; i < num; ++i) - fences.push(new Fortress("fence", clone(fences[i].wall).reverse())); - -// Camps with fire and gold treasure -function placeCamp(position, - centerEntity = "actor|props/special/eyecandy/campfire.xml" -) -{ - g_Map.placeEntityPassable(centerEntity, 0, position, randomAngle()); - - const quantity = randIntInclusive(5, 11); - const dAngle = 2 * Math.PI / quantity; - for (let i = 0; i < quantity; ++i) + g_WallStyles.other = { + "overlap": 0, + "fence": readyWallElement("structures/fence_long", "gaia"), + "fence_short": readyWallElement("structures/fence_short", "gaia"), + "bench": + { + "angle": Math.PI / 2, + "length": 1.5, + "indent": 0, + "bend": 0, + "templateName": "structures/bench" + }, + "foodBin": + { + "angle": Math.PI / 2, + "length": 1.5, + "indent": 0, + "bend": 0, + "templateName": "gaia/treasure/food_bin" + }, + "animal": + { + "angle": 0, + "length": 0, + "indent": 0.75, + "bend": 0, + "templateName": farmEntities.animal + }, + "farmstead": + { + "angle": Math.PI, + "length": 0, + "indent": -3, + "bend": 0, + "templateName": farmEntities.building + } + }; + + const fences = [ + new Fortress("fence", [ + "foodBin", "farmstead", "bench", + "turn_0.25", "animal", "turn_0.25", "fence", + "turn_0.25", "animal", "turn_0.25", "fence", + "turn_0.25", "animal", "turn_0.25", "fence" + ]), + new Fortress("fence", [ + "foodBin", "farmstead", "fence", + "turn_0.25", "animal", "turn_0.25", "fence", + "turn_0.25", "animal", "turn_0.25", "bench", "animal", "fence", + "turn_0.25", "animal", "turn_0.25", "fence" + ]), + new Fortress("fence", [ + "foodBin", "farmstead", "turn_0.5", "bench", "turn_-0.5", "fence_short", + "turn_0.25", "animal", "turn_0.25", "fence", + "turn_0.25", "animal", "turn_0.25", "fence", + "turn_0.25", "animal", "turn_0.25", "fence_short", "animal", "fence" + ]), + new Fortress("fence", [ + "foodBin", "farmstead", "turn_0.5", "fence_short", "turn_-0.5", "bench", + "turn_0.25", "animal", "turn_0.25", "fence", + "turn_0.25", "animal", "turn_0.25", "fence", + "turn_0.25", "animal", "turn_0.25", "fence_short", "animal", "fence" + ]), + new Fortress("fence", [ + "foodBin", "farmstead", "fence", + "turn_0.25", "animal", "turn_0.25", "bench", "animal", "fence", + "turn_0.25", "animal", "turn_0.25", "fence_short", "animal", "fence", + "turn_0.25", "animal", "turn_0.25", "fence_short", "animal", "fence" + ]) + ]; + const num = fences.length; + for (let i = 0; i < num; ++i) + fences.push(new Fortress("fence", clone(fences[i].wall).reverse())); + + // Camps with fire and gold treasure + function placeCamp(position, + centerEntity = "actor|props/special/eyecandy/campfire.xml" + ) { - const angle = dAngle * randFloat(i, i + 1); - const dist = randFloat(1, 3); - g_Map.placeEntityPassable(pickRandom(campEntities), 0, Vector2D.add(position, new Vector2D(dist, 0).rotate(-angle)), randomAngle()); - } + g_Map.placeEntityPassable(centerEntity, 0, position, randomAngle()); - addCivicCenterAreaToClass(position, clGaiaCamp); -} + const quantity = randIntInclusive(5, 11); + const dAngle = 2 * Math.PI / quantity; + for (let i = 0; i < quantity; ++i) + { + const angle = dAngle * randFloat(i, i + 1); + const dist = randFloat(1, 3); + g_Map.placeEntityPassable(pickRandom(campEntities), 0, + Vector2D.add(position, new Vector2D(dist, 0).rotate(-angle)), randomAngle()); + } -function placeStartLocationResources( - point, - foodEntities = [g_Gaia.fruitBush, g_Gaia.startingAnimal], - groveEntities = [ - g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, - g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, - g_Gaia.tree3, g_Gaia.tree3, g_Gaia.tree3, - g_Gaia.tree4, g_Gaia.tree4, g_Gaia.tree5 - ], - groveTerrainTexture = getArray(g_Terrains.forestFloor1), - averageDistToCC = 10, - dAverageDistToCC = 2 -) -{ - function getRandDist() - { - return averageDistToCC + randFloat(-dAverageDistToCC, dAverageDistToCC); + addCivicCenterAreaToClass(position, clGaiaCamp); } - let currentAngle = randomAngle(); - // Stone - let dAngle = 4/9 * Math.PI; - let angle = currentAngle + randFloat(dAngle / 4, 3 * dAngle / 4); - placeMine(Vector2D.add(point, new Vector2D(averageDistToCC, 0).rotate(-angle)), g_Gaia.stoneLarge); - - currentAngle += dAngle; - - // Wood - let quantity = 80; - dAngle = 2/3 * Math.PI / quantity; - for (let i = 0; i < quantity; ++i) + function placeStartLocationResources( + point, + foodEntities = [g_Gaia.fruitBush, g_Gaia.startingAnimal], + groveEntities = [ + g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, g_Gaia.tree1, + g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, g_Gaia.tree2, + g_Gaia.tree3, g_Gaia.tree3, g_Gaia.tree3, + g_Gaia.tree4, g_Gaia.tree4, g_Gaia.tree5 + ], + groveTerrainTexture = getArray(g_Terrains.forestFloor1), + averageDistToCC = 10, + dAverageDistToCC = 2 + ) { - angle = currentAngle + randFloat(0, dAngle); - const dist = getRandDist(); - let objectList = groveEntities; - if (i % 2 == 0) - objectList = groveActors; + function getRandDist() + { + return averageDistToCC + randFloat(-dAverageDistToCC, dAverageDistToCC); + } - const position = Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle)); - g_Map.placeEntityPassable(pickRandom(objectList), 0, position, randomAngle()); + let currentAngle = randomAngle(); + // Stone + let dAngle = 4/9 * Math.PI; + let angle = currentAngle + randFloat(dAngle / 4, 3 * dAngle / 4); + placeMine(Vector2D.add(point, + new Vector2D(averageDistToCC, 0).rotate(-angle)), g_Gaia.stoneLarge); - createArea( - new ClumpPlacer(5, 1, 1, Infinity, position), - new TerrainPainter(groveTerrainTexture)); currentAngle += dAngle; - } - // Metal - dAngle = 4/9 * Math.PI; - angle = currentAngle + randFloat(dAngle / 4, 3 * dAngle / 4); - placeMine(Vector2D.add(point, new Vector2D(averageDistToCC, 0).rotate(-angle)), g_Gaia.metalLarge); - currentAngle += dAngle; + // Wood + let quantity = 80; + dAngle = 2/3 * Math.PI / quantity; + for (let i = 0; i < quantity; ++i) + { + angle = currentAngle + randFloat(0, dAngle); + const dist = getRandDist(); + let objectList = groveEntities; + if (i % 2 == 0) + objectList = groveActors; + + const position = Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle)); + g_Map.placeEntityPassable(pickRandom(objectList), 0, position, randomAngle()); + + createArea( + new ClumpPlacer(5, 1, 1, Infinity, position), + new TerrainPainter(groveTerrainTexture)); + currentAngle += dAngle; + } - // Berries and domestic animals - quantity = 15; - dAngle = 4/9 * Math.PI / quantity; - for (let i = 0; i < quantity; ++i) - { - angle = currentAngle + randFloat(0, dAngle); - const dist = getRandDist(); - g_Map.placeEntityPassable(pickRandom(foodEntities), 0, Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle)), randomAngle()); + // Metal + dAngle = 4/9 * Math.PI; + angle = currentAngle + randFloat(dAngle / 4, 3 * dAngle / 4); + placeMine(Vector2D.add(point, new Vector2D(averageDistToCC, 0).rotate(-angle)), + g_Gaia.metalLarge); currentAngle += dAngle; + + // Berries and domestic animals + quantity = 15; + dAngle = 4/9 * Math.PI / quantity; + for (let i = 0; i < quantity; ++i) + { + angle = currentAngle + randFloat(0, dAngle); + const dist = getRandDist(); + g_Map.placeEntityPassable(pickRandom(foodEntities), 0, Vector2D.add(point, + new Vector2D(dist, 0).rotate(-angle)), randomAngle()); + currentAngle += dAngle; + } } -} -/** - * Base terrain shape generation and settings - */ - -// Height range by map size -const heightScale = (g_Map.size + 512) / 1024 / 5; -const heightRange = { "min": MIN_HEIGHT * heightScale, "max": MAX_HEIGHT * heightScale }; - -// Water coverage -const averageWaterCoverage = 1 / 5; // NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with the same value -const heightSeaGround = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (heightRange.max - heightRange.min); // Water height in environment and the engine -const heightSeaGroundAdjusted = heightSeaGround + MIN_HEIGHT; // Water height as terrain height -setWaterHeight(heightSeaGround); - -// Generate base terrain shape -const lowH = heightRange.min; -const medH = (heightRange.min + heightRange.max) / 2; - -// Lake -let initialHeightmap = [ - [medH, medH, medH, medH, medH, medH], - [medH, medH, medH, medH, medH, medH], - [medH, medH, lowH, lowH, medH, medH], - [medH, medH, lowH, lowH, medH, medH], - [medH, medH, medH, medH, medH, medH], - [medH, medH, medH, medH, medH, medH], -]; -if (g_Map.size < 256) -{ - initialHeightmap = [ - [medH, medH, medH, medH, medH], - [medH, medH, medH, medH, medH], - [medH, medH, lowH, medH, medH], - [medH, medH, medH, medH, medH], - [medH, medH, medH, medH, medH] - ]; -} -if (g_Map.size >= 384) -{ - initialHeightmap = [ - [medH, medH, medH, medH, medH, medH, medH, medH], - [medH, medH, medH, medH, medH, medH, medH, medH], - [medH, medH, medH, medH, medH, medH, medH, medH], - [medH, medH, medH, lowH, lowH, medH, medH, medH], - [medH, medH, medH, lowH, lowH, medH, medH, medH], - [medH, medH, medH, medH, medH, medH, medH, medH], - [medH, medH, medH, medH, medH, medH, medH, medH], - [medH, medH, medH, medH, medH, medH, medH, medH], + /** + * Base terrain shape generation and settings + */ + + // Height range by map size + const heightScale = (g_Map.size + 512) / 1024 / 5; + const heightRange = { "min": MIN_HEIGHT * heightScale, "max": MAX_HEIGHT * heightScale }; + + // Water coverage + // NOTE: Since terrain generation is quite unpredictable actual water coverage might vary much with + // the same value + const averageWaterCoverage = 1 / 5; + // Water height in environment and the engine + const heightSeaGround = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * + (heightRange.max - heightRange.min); + // Water height as terrain height + const heightSeaGroundAdjusted = heightSeaGround + MIN_HEIGHT; + setWaterHeight(heightSeaGround); + + // Generate base terrain shape + const lowH = heightRange.min; + const medH = (heightRange.min + heightRange.max) / 2; + + // Lake + let initialHeightmap = [ + [medH, medH, medH, medH, medH, medH], + [medH, medH, medH, medH, medH, medH], + [medH, medH, lowH, lowH, medH, medH], + [medH, medH, lowH, lowH, medH, medH], + [medH, medH, medH, medH, medH, medH], + [medH, medH, medH, medH, medH, medH], ]; -} + if (g_Map.size < 256) + { + initialHeightmap = [ + [medH, medH, medH, medH, medH], + [medH, medH, medH, medH, medH], + [medH, medH, lowH, medH, medH], + [medH, medH, medH, medH, medH], + [medH, medH, medH, medH, medH] + ]; + } + if (g_Map.size >= 384) + { + initialHeightmap = [ + [medH, medH, medH, medH, medH, medH, medH, medH], + [medH, medH, medH, medH, medH, medH, medH, medH], + [medH, medH, medH, medH, medH, medH, medH, medH], + [medH, medH, medH, lowH, lowH, medH, medH, medH], + [medH, medH, medH, lowH, lowH, medH, medH, medH], + [medH, medH, medH, medH, medH, medH, medH, medH], + [medH, medH, medH, medH, medH, medH, medH, medH], + [medH, medH, medH, medH, medH, medH, medH, medH], + ]; + } + + setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, initialHeightmap, 0.8); -setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, initialHeightmap, 0.8); - -g_Map.log("Eroding map"); -for (let i = 0; i < 5; ++i) - splashErodeMap(0.1); - -g_Map.log("Smoothing map"); -createArea( - new MapBoundsPlacer(), - new SmoothingPainter(1, 0.5, Math.ceil(g_Map.size/128) + 1)); - -g_Map.log("Rescaling map"); -rescaleHeightmap(heightRange.min, heightRange.max); - -Engine.SetProgress(25); - -/** - * Prepare terrain texture placement - */ -const heighLimits = [ - heightRange.min + 3/4 * (heightSeaGroundAdjusted - heightRange.min), // 0 Deep water - heightSeaGroundAdjusted, // 1 Shallow water - heightSeaGroundAdjusted + 2/8 * (heightRange.max - heightSeaGroundAdjusted), // 2 Shore - heightSeaGroundAdjusted + 3/8 * (heightRange.max - heightSeaGroundAdjusted), // 3 Low ground - heightSeaGroundAdjusted + 4/8 * (heightRange.max - heightSeaGroundAdjusted), // 4 Player and path height - heightSeaGroundAdjusted + 6/8 * (heightRange.max - heightSeaGroundAdjusted), // 5 High ground - heightSeaGroundAdjusted + 7/8 * (heightRange.max - heightSeaGroundAdjusted), // 6 Lower forest border - heightRange.max // 7 Forest -]; -const playerHeightRange = { "min": heighLimits[3], "max": heighLimits[4] }; -const resourceSpotHeightRange = { "min": (heighLimits[2] + heighLimits[3]) / 2, "max": (heighLimits[4] + heighLimits[5]) / 2 }; -const playerHeight = (playerHeightRange.min + playerHeightRange.max) / 2; // Average player height - -g_Map.log("Chosing starting locations"); -const [playerIDs, playerPosition] = groupPlayersCycle(getStartLocationsByHeightmap(playerHeightRange, 1000, 30)); - -g_Map.log("Smoothing starting locations before height calculation"); -for (const position of playerPosition) + g_Map.log("Eroding map"); + for (let i = 0; i < 5; ++i) + splashErodeMap(0.1); + + g_Map.log("Smoothing map"); createArea( - new ClumpPlacer(diskArea(20), 0.8, 0.8, Infinity, position), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 20)); + new MapBoundsPlacer(), + new SmoothingPainter(1, 0.5, Math.ceil(g_Map.size/128) + 1)); + + g_Map.log("Rescaling map"); + rescaleHeightmap(heightRange.min, heightRange.max); + + yield 25; + + /** + * Prepare terrain texture placement + */ + const heighLimits = [ + // 0 Deep water + heightRange.min + 3/4 * (heightSeaGroundAdjusted - heightRange.min), + // 1 Shallow water + heightSeaGroundAdjusted, + // 2 Shore + heightSeaGroundAdjusted + 2/8 * (heightRange.max - heightSeaGroundAdjusted), + // 3 Low ground + heightSeaGroundAdjusted + 3/8 * (heightRange.max - heightSeaGroundAdjusted), + // 4 Player and path height + heightSeaGroundAdjusted + 4/8 * (heightRange.max - heightSeaGroundAdjusted), + // 5 High ground + heightSeaGroundAdjusted + 6/8 * (heightRange.max - heightSeaGroundAdjusted), + // 6 Lower forest border + heightSeaGroundAdjusted + 7/8 * (heightRange.max - heightSeaGroundAdjusted), + // 7 Forest + heightRange.max + ]; + const playerHeightRange = { "min": heighLimits[3], "max": heighLimits[4] }; + const resourceSpotHeightRange = + { + "min": (heighLimits[2] + heighLimits[3]) / 2, + "max": (heighLimits[4] + heighLimits[5]) / 2 + }; + const playerHeight = (playerHeightRange.min + playerHeightRange.max) / 2; // Average player height + + g_Map.log("Chosing starting locations"); + const [playerIDs, playerPosition] = + groupPlayersCycle(getStartLocationsByHeightmap(playerHeightRange, 1000, 30)); -Engine.SetProgress(30); + g_Map.log("Smoothing starting locations before height calculation"); + for (const position of playerPosition) + createArea( + new ClumpPlacer(diskArea(20), 0.8, 0.8, Infinity, position), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(position), 20)); -/** - * Calculate tile centered height map after start position smoothing but before placing paths - * This has nothing to to with TILE_CENTERED_HEIGHT_MAP which should be false! - */ -const tchm = getTileCenteredHeightmap(); + yield 30; -g_Map.log("Get points per height"); -const areas = heighLimits.map(heightLimit => []); -for (let x = 0; x < tchm.length; ++x) - for (let y = 0; y < tchm[0].length; ++y) - { - let minHeight = heightRange.min; - for (let h = 0; h < heighLimits.length; ++h) + /** + * Calculate tile centered height map after start position smoothing but before placing paths + * This has nothing to to with TILE_CENTERED_HEIGHT_MAP which should be false! + */ + const tchm = getTileCenteredHeightmap(); + + g_Map.log("Get points per height"); + const areas = heighLimits.map(heightLimit => []); + for (let x = 0; x < tchm.length; ++x) + for (let y = 0; y < tchm[0].length; ++y) { - if (tchm[x][y] >= minHeight && tchm[x][y] <= heighLimits[h]) + let minHeight = heightRange.min; + for (let h = 0; h < heighLimits.length; ++h) { - areas[h].push(new Vector2D(x, y)); - break; - } + if (tchm[x][y] >= minHeight && tchm[x][y] <= heighLimits[h]) + { + areas[h].push(new Vector2D(x, y)); + break; + } - minHeight = heighLimits[h]; + minHeight = heighLimits[h]; + } } - } -g_Map.log("Get slope limits per heightrange"); -const slopeMap = getSlopeMap(); -const minSlope = []; -const maxSlope = []; -for (let h = 0; h < heighLimits.length; ++h) -{ - minSlope[h] = Infinity; - maxSlope[h] = 0; - for (const point of areas[h]) + g_Map.log("Get slope limits per heightrange"); + const slopeMap = getSlopeMap(); + const minSlope = []; + const maxSlope = []; + for (let h = 0; h < heighLimits.length; ++h) { - const slope = slopeMap[point.x][point.y]; + minSlope[h] = Infinity; + maxSlope[h] = 0; + for (const point of areas[h]) + { + const slope = slopeMap[point.x][point.y]; - if (slope > maxSlope[h]) - maxSlope[h] = slope; + if (slope > maxSlope[h]) + maxSlope[h] = slope; - if (slope < minSlope[h]) - minSlope[h] = slope; + if (slope < minSlope[h]) + minSlope[h] = slope; + } } -} -g_Map.log("Paint areas by height and slope"); -for (let h = 0; h < heighLimits.length; ++h) - for (const point of areas[h]) - { - let entity; - let texture = pickRandom(wildLakeBiome[h].texture); - - if (slopeMap[point.x][point.y] < (minSlope[h] + maxSlope[h]) / 2) - { - if (randBool(wildLakeBiome[h].entity[1])) - entity = pickRandom(wildLakeBiome[h].entity[0]); - } - else + g_Map.log("Paint areas by height and slope"); + for (let h = 0; h < heighLimits.length; ++h) + for (const point of areas[h]) { - texture = pickRandom(wildLakeBiome[h].textureHS); - if (randBool(wildLakeBiome[h].entityHS[1])) - entity = pickRandom(wildLakeBiome[h].entityHS[0]); + let entity; + let texture = pickRandom(wildLakeBiome[h].texture); + + if (slopeMap[point.x][point.y] < (minSlope[h] + maxSlope[h]) / 2) + { + if (randBool(wildLakeBiome[h].entity[1])) + entity = pickRandom(wildLakeBiome[h].entity[0]); + } + else + { + texture = pickRandom(wildLakeBiome[h].textureHS); + if (randBool(wildLakeBiome[h].entityHS[1])) + entity = pickRandom(wildLakeBiome[h].entityHS[0]); + } + + g_Map.setTexture(point, texture); + + if (entity) + g_Map.placeEntityPassable(entity, 0, randomPositionOnTile(point), randomAngle()); } + yield 40; - g_Map.setTexture(point, texture); + g_Map.log("Placing resources"); + const avoidPoints = playerPosition.map(pos => pos.clone()); + for (let i = 0; i < avoidPoints.length; ++i) + avoidPoints[i].dist = 30; + const resourceSpots = getPointsByHeight(resourceSpotHeightRange, avoidPoints).map( + point => new Vector2D(point.x, point.y)); - if (entity) - g_Map.placeEntityPassable(entity, 0, randomPositionOnTile(point), randomAngle()); - } -Engine.SetProgress(40); - -g_Map.log("Placing resources"); -const avoidPoints = playerPosition.map(pos => pos.clone()); -for (let i = 0; i < avoidPoints.length; ++i) - avoidPoints[i].dist = 30; -const resourceSpots = getPointsByHeight(resourceSpotHeightRange, avoidPoints).map(point => new Vector2D(point.x, point.y)); - -Engine.SetProgress(55); - -g_Map.log("Placing players"); -if (isNomad()) - placePlayersNomad( - g_Map.createTileClass(), - [ - new HeightConstraint(playerHeightRange.min, playerHeightRange.max), - avoidClasses(clGaiaCamp, 8) - ]); -else - for (let p = 0; p < playerIDs.length; ++p) - { - placeCivDefaultStartingEntities(playerPosition[p], playerIDs[p], g_Map.size > 192); - placeStartLocationResources(playerPosition[p]); - } + yield 55; -let mercenaryCamps = isNomad() ? 0 : Math.ceil(g_Map.size / 256); -g_Map.log("Placing at most " + mercenaryCamps + " mercenary camps"); -for (let i = 0; i < resourceSpots.length; ++i) -{ - let radius; - const choice = i % (isNomad() ? 4 : 5); - if (choice == 0) - placeMine(resourceSpots[i], g_Gaia.stoneLarge); - if (choice == 1) - placeMine(resourceSpots[i], g_Gaia.metalLarge); - if (choice == 2) - placeGrove(resourceSpots[i]); - if (choice == 3) - { - placeCamp(resourceSpots[i]); - radius = 5; - } - if (choice == 4) + g_Map.log("Placing players"); + if (isNomad()) + placePlayersNomad( + g_Map.createTileClass(), + [ + new HeightConstraint(playerHeightRange.min, playerHeightRange.max), + avoidClasses(clGaiaCamp, 8) + ]); + else + for (let p = 0; p < playerIDs.length; ++p) + { + placeCivDefaultStartingEntities(playerPosition[p], playerIDs[p], g_Map.size > 192); + placeStartLocationResources(playerPosition[p]); + } + + let mercenaryCamps = isNomad() ? 0 : Math.ceil(g_Map.size / 256); + g_Map.log("Placing at most " + mercenaryCamps + " mercenary camps"); + for (let i = 0; i < resourceSpots.length; ++i) { - if (mercenaryCamps) + let radius; + const choice = i % (isNomad() ? 4 : 5); + if (choice == 0) + placeMine(resourceSpots[i], g_Gaia.stoneLarge); + if (choice == 1) + placeMine(resourceSpots[i], g_Gaia.metalLarge); + if (choice == 2) + placeGrove(resourceSpots[i]); + if (choice == 3) { - placeStartingEntities(resourceSpots[i], 0, mercenaryCampEntities); - radius = 15; - --mercenaryCamps; + placeCamp(resourceSpots[i]); + radius = 5; } - else + if (choice == 4) { - placeCustomFortress(resourceSpots[i], pickRandom(fences), "other", 0, randomAngle()); - radius = 10; + if (mercenaryCamps) + { + placeStartingEntities(resourceSpots[i], 0, mercenaryCampEntities); + radius = 15; + --mercenaryCamps; + } + else + { + placeCustomFortress(resourceSpots[i], pickRandom(fences), "other", 0, + randomAngle()); + radius = 10; + } } + + if (radius) + createArea( + new DiskPlacer(radius, resourceSpots[i]), + new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(resourceSpots[i]), + radius / 3)); } - if (radius) - createArea( - new DiskPlacer(radius, resourceSpots[i]), - new SmoothElevationPainter(ELEVATION_SET, g_Map.getHeight(resourceSpots[i]), radius / 3)); + return g_Map; } - -g_Map.ExportMap(); Index: source/graphics/tests/test_MapGenerator.h =================================================================== --- source/graphics/tests/test_MapGenerator.h +++ source/graphics/tests/test_MapGenerator.h @@ -60,22 +60,10 @@ const Script::StructuredClone result{RunMapGenerationScript(progress, scriptInterface, path, "{\"Seed\": 0}", JSPROP_ENUMERATE | JSPROP_PERMANENT)}; - if (path == "maps/random/tests/test_Generator.js" || - path == "maps/random/tests/test_RecoverableError.js") - { + if (path == "maps/random/tests/test_Generator.js") TS_ASSERT_EQUALS(progress.load(), 50); - TS_ASSERT_DIFFERS(result, nullptr); - } - else - { - // The test scripts don't call `ExportMap` so `RunMapGenerationScript` allways - // returns `nullptr`. - TS_ASSERT_EQUALS(result, nullptr); - // Because the test scripts don't call `ExportMap`, `GenerateMap` is searched, which - // doesn't exist. - TS_ASSERT_STR_CONTAINS(logger.GetOutput(), - "Failed to call the generator `GenerateMap`."); - } + + TS_ASSERT_DIFFERS(result, nullptr); } } };