Index: ps/trunk/binaries/data/mods/public/gui/common/MapCache.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/common/MapCache.js +++ ps/trunk/binaries/data/mods/public/gui/common/MapCache.js @@ -64,21 +64,13 @@ getMapPreview(mapType, mapPath, gameAttributes = undefined) { - let mapData = this.getMapData(mapType, mapPath); + let filename = gameAttributes && gameAttributes.settings && gameAttributes.settings.Preview || undefined; - let biomePreviewFile = - basename(mapPath) + "_" + - basename(gameAttributes && gameAttributes.settings.Biome || "") + ".png"; - - let biomePreview = Engine.TextureExists( - this.TexturesPath + this.PreviewsPath + biomePreviewFile) && biomePreviewFile; - - let filename = - biomePreview ? - biomePreview : - mapData && mapData.settings && mapData.settings.Preview ? - mapData.settings.Preview : - this.DefaultPreview; + if (!filename) + { + let mapData = this.getMapData(mapType, mapPath); + filename = mapData && mapData.settings && mapData.settings.Preview || this.DefaultPreview; + } return "cropped:" + this.PreviewWidth + "," + this.PreviewHeight + ":" + this.PreviewsPath + filename; } Index: ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/GameSettingsLayout.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/GameSettingsLayout.js +++ ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/GameSettingsLayout.js @@ -10,7 +10,9 @@ "MapFilter", "MapSelection", "MapSize", + "Landscape", "Biome", + "Daytime", "TriggerDifficulty", "Nomad", "Treasures", Index: ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/Single/Dropdowns/Biome.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/Single/Dropdowns/Biome.js +++ ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/Single/Dropdowns/Biome.js @@ -7,6 +7,8 @@ this.values = undefined; this.biomeValues = undefined; + this.lastBiome = undefined; + this.randomItem = { "Id": this.RandomBiomeId, "Title": setStringTags(this.RandomBiome, this.RandomItemTags), @@ -46,11 +48,13 @@ } else this.values = undefined; + + this.lastBiome = undefined; } onGameAttributesChange() { - if (!g_GameAttributes.mapType) + if (!g_GameAttributes.mapType || !g_GameAttributes.map) return; if (this.values) @@ -60,6 +64,18 @@ g_GameAttributes.settings.Biome = this.RandomBiomeId; this.gameSettingsControl.updateGameAttributes(); } + + if (this.lastBiome != g_GameAttributes.settings.Biome) + { + let biomePreviewFile = + basename(g_GameAttributes.map) + "_" + + basename(g_GameAttributes.settings.Biome || "") + ".png"; + + if (Engine.TextureExists(this.mapCache.TexturesPath + this.mapCache.PreviewsPath + biomePreviewFile)) + g_GameAttributes.settings.Preview = biomePreviewFile; + + this.lastBiome = g_GameAttributes.settings.Biome; + } } else if (g_GameAttributes.settings.Biome) { Index: ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/Single/Dropdowns/Daytime.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/Single/Dropdowns/Daytime.js +++ ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/Single/Dropdowns/Daytime.js @@ -0,0 +1,107 @@ +GameSettingControls.Daytime = class extends GameSettingControlDropdown +{ + constructor(...args) + { + super(...args); + + this.values = undefined; + } + + onHoverChange() + { + this.dropdown.tooltip = this.values.Description[this.dropdown.hovered] || this.Tooltip; + } + + onMapChange(mapData) + { + if (mapData && mapData.settings && mapData.settings.Daytime) + { + this.values = prepareForDropdown([ + { + "Id": "random", + "Name": setStringTags(this.RandomTitle, this.RandomItemTags), + "Description": this.RandomDescription, + "Preview": mapData.settings.Preview + }, + ...mapData.settings.Daytime + ]); + + this.dropdown.list = this.values.Name; + this.dropdown.list_data = this.values.Id; + } + else + this.values = undefined; + + this.setHidden(!this.values); + } + + onGameAttributesChange() + { + if (!g_GameAttributes.map) + return; + + if (this.values) + { + if (this.values.Id.indexOf(g_GameAttributes.settings.Daytime || undefined) == -1) + { + g_GameAttributes.settings.Daytime = "random"; + this.gameSettingsControl.updateGameAttributes(); + } + + let preview = this.values.Preview[this.values.Id.indexOf(g_GameAttributes.settings.Daytime)]; + if (!g_GameAttributes.settings.Preview || g_GameAttributes.settings.Preview != preview) + { + g_GameAttributes.settings.Preview = preview; + this.gameSettingsControl.updateGameAttributes(); + } + } + else if (g_GameAttributes.settings.Daytime !== undefined) + { + delete g_GameAttributes.settings.Daytime; + this.gameSettingsControl.updateGameAttributes(); + } + } + + onGameAttributesBatchChange() + { + if (g_GameAttributes.settings.Daytime) + this.setSelectedValue(g_GameAttributes.settings.Daytime); + } + + getAutocompleteEntries() + { + return this.values.Name; + } + + onSelectionChange(itemIdx) + { + g_GameAttributes.settings.Daytime = this.values.Id[itemIdx]; + + this.gameSettingsControl.updateGameAttributes(); + this.gameSettingsControl.setNetworkGameAttributes(); + } + + onPickRandomItems() + { + if (this.values && g_GameAttributes.settings.Daytime == "random") + { + g_GameAttributes.settings.Daytime = pickRandom(this.values.Id.slice(1)); + this.gameSettingsControl.updateGameAttributes(); + this.gameSettingsControl.pickRandomItems(); + } + } +}; + +GameSettingControls.Daytime.prototype.TitleCaption = + translate("Daytime"); + +GameSettingControls.Daytime.prototype.Tooltip = + translate("Select whether the match takes place at daylight or night."); + +GameSettingControls.Daytime.prototype.RandomTitle = + translateWithContext("daytime selection", "Random"); + +GameSettingControls.Daytime.prototype.RandomDescription = + translateWithContext("daytime selection", "Randomly pick a time of the day."); + +GameSettingControls.Daytime.prototype.AutocompleteOrder = 0; Index: ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/Single/Dropdowns/Landscape.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/Single/Dropdowns/Landscape.js +++ ps/trunk/binaries/data/mods/public/gui/gamesetup/GameSettings/Single/Dropdowns/Landscape.js @@ -0,0 +1,145 @@ +GameSettingControls.Landscape = class extends GameSettingControlDropdown +{ + constructor(...args) + { + super(...args); + + this.values = undefined; + this.lastLandscape = undefined; + this.mapData = undefined; + } + + onHoverChange() + { + this.dropdown.tooltip = this.values.Description[this.dropdown.hovered] || this.Tooltip; + } + + onMapChange(mapData) + { + this.mapData = mapData; + + if (mapData && mapData.settings && mapData.settings.Landscapes) + { + let randomItems = []; + for (let item of this.RandomItems) + if (item.Id == "random" || mapData.settings.Landscapes.land && mapData.settings.Landscapes.naval) + randomItems.push({ + "Id": item.Id, + "Name": setStringTags(item.Name, this.RandomItemTags), + "Description": item.Description, + "Preview": mapData.settings.Preview || this.mapCache.DefaultPreview + }); + + let sort = (item1, item2) => item1.Name > item2.Name; + + this.values = prepareForDropdown([ + ...randomItems, + ...mapData.settings.Landscapes.land.sort(sort), + ...mapData.settings.Landscapes.naval.sort(sort) + ]); + + this.dropdown.list = this.values.Name; + this.dropdown.list_data = this.values.Id; + } + else + this.values = undefined; + + this.lastLandscape = undefined; + + this.setHidden(!this.values); + } + + onGameAttributesChange() + { + if (this.values) + { + if (this.values.Id.indexOf(g_GameAttributes.settings.Landscape || undefined) == -1) + { + g_GameAttributes.settings.Landscape = "random"; + this.gameSettingsControl.updateGameAttributes(); + } + + if (this.lastLandscape != g_GameAttributes.settings.Landscape) + { + g_GameAttributes.settings.Preview = this.values.Preview[this.values.Id.indexOf(g_GameAttributes.settings.Landscape)]; + this.lastLandscape = g_GameAttributes.settings.Biome; + } + } + else if (g_GameAttributes.settings.Landscape !== undefined) + { + delete g_GameAttributes.settings.Landscape; + this.gameSettingsControl.updateGameAttributes(); + } + } + + onGameAttributesBatchChange() + { + if (g_GameAttributes.settings.Landscape) + this.setSelectedValue(g_GameAttributes.settings.Landscape); + } + + getAutocompleteEntries() + { + return this.values.Name; + } + + onSelectionChange(itemIdx) + { + g_GameAttributes.settings.Landscape = this.values.Id[itemIdx]; + + this.gameSettingsControl.updateGameAttributes(); + this.gameSettingsControl.setNetworkGameAttributes(); + } + + onPickRandomItems() + { + let items; + let landscapes = this.mapData.settings.Landscapes; + + switch (g_GameAttributes.settings.Landscape || undefined) + { + case "random": + items = [...landscapes.land, ...landscapes.naval]; + break; + case "random_land": + items = landscapes.land; + break; + case "random_naval": + items = landscapes.naval; + break; + default: + return; + } + + g_GameAttributes.settings.Landscape = pickRandom(items).Id; + this.gameSettingsControl.updateGameAttributes(); + this.gameSettingsControl.pickRandomItems(); + } +}; + +GameSettingControls.Landscape.prototype.TitleCaption = + translate("Landscape"); + +GameSettingControls.Landscape.prototype.Tooltip = + translate("Select one of the landscapes of this map."); + +GameSettingControls.Landscape.prototype.RandomItems = +[ + { + "Id": "random", + "Name": translateWithContext("landscape selection", "Random Land or Naval"), + "Description": translateWithContext("landscape selection", "Select a random land or naval map generation.") + }, + { + "Id": "random_land", + "Name": translateWithContext("landscape selection", "Random Land"), + "Description": translateWithContext("landscape selection", "Select a random land map generation.") + }, + { + "Id": "random_naval", + "Name": translateWithContext("landscape selection", "Random Naval"), + "Description": translateWithContext("landscape selection", "Select a random naval map generation.") + } +]; + +GameSettingControls.Landscape.prototype.AutocompleteOrder = 0; Index: ps/trunk/binaries/data/mods/public/gui/gamesetup/Panels/MapPreview.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/gamesetup/Panels/MapPreview.js +++ ps/trunk/binaries/data/mods/public/gui/gamesetup/Panels/MapPreview.js @@ -2,14 +2,26 @@ { constructor(gameSettingsControl, mapCache) { + this.gameSettingsControl = gameSettingsControl; this.mapCache = mapCache; this.mapInfoName = Engine.GetGUIObjectByName("mapInfoName"); this.mapPreview = Engine.GetGUIObjectByName("mapPreview"); + gameSettingsControl.registerMapChangeHandler(this.onMapChange.bind(this)); gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this)); } + onMapChange(mapData) + { + let preview = mapData && mapData.settings && mapData.settings.Preview; + if (!g_GameAttributes.settings.Preview || g_GameAttributes.settings.Preview != preview) + { + g_GameAttributes.settings.Preview = preview; + this.gameSettingsControl.updateGameAttributes(); + } + } + onGameAttributesBatchChange() { if (!g_GameAttributes.map || !g_GameAttributes.mapType) Index: ps/trunk/binaries/data/mods/public/maps/random/danubius.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/danubius.js +++ ps/trunk/binaries/data/mods/public/maps/random/danubius.js @@ -1,6 +1,8 @@ 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"; @@ -235,7 +237,7 @@ "Geto-Dacian Tribal Confederation", new Array(2).fill([ "gate", "pillar", "hut", "long", "long", - "cornerIn", "defense_tower", "long", "temple", "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), [])); @@ -303,8 +305,8 @@ for (let participants of ritualParticipants) { let [positions, angles] = distributePointsOnCircle(participants.count, startAngle, participants.radius * mRadius, meetingPlacePosition); - for (let i = 0; i < positions.length; ++i) - g_Map.placeEntityPassable(pickRandom(participants.templates), 0, positions[i], angles[i] + participants.angle); + for (let j = 0; j < positions.length; ++j) + g_Map.placeEntityPassable(pickRandom(participants.templates), 0, positions[j], angles[j] + participants.angle); } } @@ -323,7 +325,7 @@ placeCustomFortress(civicCenterPosition, fortressDanubiusSpikes, "danubius_spikes", 0, startAngle + Math.PI); // Place treasure, potentially inside buildings - for (let i = 0; i < gallicCCTreasureCount; ++i) + for (let j = 0; j < gallicCCTreasureCount; ++j) g_Map.placeEntityPassable( pickRandom(oTreasures), 0, @@ -444,7 +446,7 @@ g_Map.log("Creating grass patches"); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tGrass, tGrass2],[tGrass2, tGrass3], [tGrass3, tGrass]], + [[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), @@ -566,7 +568,7 @@ ], 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)]); + [stayClasses(clIsland, 4), avoidClasses(clForest, 1, clRock, 4, clMetal, 4)]); Engine.SetProgress(75); g_Map.log("Creating fish"); @@ -797,7 +799,7 @@ placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clMetal, 4, clRock, 4, clIsland, 4, clGauls, 20, clRitualPlace, 20, clForest, 1, clBaseResource, 4, clHill, 4, clFood, 2)); -if (randBool(2/3)) +if (day) { g_Map.log("Setting day theme"); setSkySet("cumulus"); Index: ps/trunk/binaries/data/mods/public/maps/random/danubius.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/danubius.json +++ ps/trunk/binaries/data/mods/public/maps/random/danubius.json @@ -5,10 +5,25 @@ "Description" : "Players start along the banks of the river Danube in the period following the expansion into Pannonia by the Celtic Boii tribe. Seeking to consolidate their hold on this land, celtic reinforcements have been sent to root out the remaining foreign cultures. Players not only have to vie for power amongst themselves, but also beat back these ruthless invaders. Ultimately, the Boii were defeated by the rising power of the Dacians, hence leading to the reemergence of the Geto-Dacian Confederation under King Burebista.", "Keywords": ["trigger", "naval"], "CircularMap" : true, - "Preview" : "danubius.png", + "Preview" : "danubius_night.png", "TriggerScripts" : [ "scripts/TriggerHelper.js", "random/danubius_triggers.js" + ], + "Daytime": + [ + { + "Id": "day", + "Name": "Day", + "Description": "Bright daylight illuminates the scene.", + "Preview" : "danubius_day.png" + }, + { + "Id": "night", + "Name": "Night", + "Description": "Attackers are covered by the darkness of the night.", + "Preview" : "danubius_night.png" + } ] } } Index: ps/trunk/binaries/data/mods/public/maps/random/polar_sea.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/polar_sea.js +++ ps/trunk/binaries/data/mods/public/maps/random/polar_sea.js @@ -134,7 +134,7 @@ g_Map.log("Creating dirt patches"); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], - [[tDirt,tHalfSnow], [tHalfSnow,tSnowLimited]], + [[tDirt, tHalfSnow], [tHalfSnow, tSnowLimited]], [2], avoidClasses(clWater, 3, clDirt, 5, clPlayer, 12), scaleByMapSize(15, 45), @@ -150,10 +150,10 @@ Engine.SetProgress(70); g_Map.log("Creating stone mines"); - createMines( +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)] + [new SimpleObject(oStoneSmall, 2, 5, 1, 3)] ], avoidClasses(clWater, 3, clPlayer, 20, clRock, 18, clHill, 2), clRock); @@ -161,7 +161,7 @@ g_Map.log("Creating metal mines"); createMines( [ - [new SimpleObject(oMetalLarge, 1,1, 0,4)] + [new SimpleObject(oMetalLarge, 1, 1, 0, 4)] ], avoidClasses(clWater, 3, clPlayer, 20, clMetal, 18, clRock, 5, clHill, 2), clMetal); @@ -241,7 +241,7 @@ 100); Engine.SetProgress(95); -if (randBool(1/3)) +if (g_MapSettings.Daytime !== undefined ? g_MapSettings.Daytime == "dawn" : randBool(1/3)) { setSkySet("sunset 1"); setSunColor(0.8, 0.7, 0.6); Index: ps/trunk/binaries/data/mods/public/maps/random/polar_sea.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/polar_sea.json +++ ps/trunk/binaries/data/mods/public/maps/random/polar_sea.json @@ -4,7 +4,7 @@ "Script" : "polar_sea.js", "Description" : "Players start in a cold polar region barren of vegetation. In the sea fish and whales abound, while the fragile icy land teems with huntable walruses and deadly wolves. These wolves, made ravenous by the harsh and forbidding climate, drawn by the scent of prey, have started appearing in terrifying numbers. A wise and strong ruler will not only achieve victory over his enemies, but also keep the number of these beasts at bay, lest they undermine his economy and cause his downfall. [color=\"red\"]Warning: It is inadvisable to disable treasures, since there is no gatherable wood. Not recommended for inexperienced players.[/color]", "Keywords": ["trigger"], - "Preview" : "polar_sea.png", + "Preview" : "polar_sea_dawn.png", "CircularMap" : true, "TriggerScripts" : [ "scripts/TriggerHelper.js", @@ -14,6 +14,21 @@ "gather_lumbering_ironaxes", "gather_lumbering_sharpaxes", "gather_lumbering_strongeraxes" + ], + "Daytime": + [ + { + "Id": "dawn", + "Name": "Dawn", + "Description": "Scattered sunlight illuminates the scenery in a vivid red tone.", + "Preview" : "polar_sea_dawn.png" + }, + { + "Id": "daylight", + "Name": "Daylight", + "Description": "The scenery is illuminated by direct or indirect sunlight.", + "Preview" : "polar_sea_daylight.png" + } ] } } Index: ps/trunk/binaries/data/mods/public/maps/random/the_unknown/unknown_common.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/the_unknown/unknown_common.js +++ ps/trunk/binaries/data/mods/public/maps/random/the_unknown/unknown_common.js @@ -1,1060 +0,0 @@ -/** - * @file This library is used to generate different map variations on the map Unknown, Unknown Land and Unknown Nomad. - */ - -/** - * True if all players should be connected via land and false if river or islands can split some if not all the players. - */ -var g_AllowNaval; - -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; - -var g_Map = new RandomMap(heightSeaGround, tWater); - -const numPlayers = getNumPlayers(); -const mapSize = g_Map.getSize(); -const mapCenter = g_Map.getCenter(); -const mapBounds = g_Map.getBounds(); - -var clPlayer = g_Map.createTileClass(); -var clPlayerTerritory = g_Map.createTileClass(); -var clHill = g_Map.createTileClass(); -var clForest = g_Map.createTileClass(); -var clWater = g_Map.createTileClass(); -var clDirt = g_Map.createTileClass(); -var clRock = g_Map.createTileClass(); -var clMetal = g_Map.createTileClass(); -var clFood = g_Map.createTileClass(); -var clPeninsulaSteam = g_Map.createTileClass(); -var clBaseResource = g_Map.createTileClass(); -var clLand = g_Map.createTileClass(); -var clShallow = g_Map.createTileClass(); - -var landElevationPainter = new SmoothElevationPainter(ELEVATION_SET, heightLand, 4); - -var unknownMapFunctions = { - "land": [ - "Continent", - "CentralSea", - "CentralRiver", - "EdgeSeas", - "Gulf", - "Lakes", - "Passes", - "Lowlands", - "Mainland" - ], - "naval": [ - "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() -{ - let funcs = unknownMapFunctions.land; - - if (g_AllowNaval) - funcs = funcs.concat(unknownMapFunctions.naval); - - global["unknown" + pickRandom(funcs)](); - - paintUnknownMapBasedOnHeight(); - - createUnknownPlayerBases(); - - createUnknownObjects(); - - placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2, clWater, 10)); -} - -/** - * Chain of islands or many disconnected islands. - */ -function unknownArchipelago() -{ - g_StartingWalls = "towers"; - g_StartingTreasures = true; - - let [pIDs, islandPosition] = playerPlacementCircle(fractionToTiles(0.35)); - if (!isNomad()) - { - [playerIDs, playerPosition] = [pIDs, islandPosition]; - markPlayerArea("large"); - } - - g_Map.log("Creating islands"); - let islandSize = diskArea(scaleByMapSize(17, 29)); - for (let i = 0; i < numPlayers; ++i) - createArea( - new ClumpPlacer(islandSize, 0.8, 0.1, Infinity, islandPosition[i]), - landElevationPainter); - - let 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)); - - 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)); - - 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)); - } -} - -/** - * Disk shaped mainland with water on the edge. - */ -function unknownContinent() -{ - let 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, mapCenter), - [ - landElevationPainter, - new TileClassPainter(clLand) - ]); - - if (randBool(1/3)) - { - g_Map.log("Creating peninsula (i.e. half the map not being surrounded by water)"); - let angle = randomAngle(); - let 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) - ]); - - g_Map.log("Remembering to not paint shorelines into the peninsula"); - let 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); -} - -/** - * Creates a huge central river, possibly connecting the riversides with a narrow piece of land. - */ -function unknownCentralSea() -{ - let waterHeight = -3; - - let startAngle = randomAngle(); - - let [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); - } - }); - - if (!isNomad()) - { - [playerIDs, playerPosition] = playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.6)); - markPlayerArea("small"); - } - - if (!g_AllowNaval || randBool()) - { - g_Map.log("Creating isthmus (i.e. connecting the two riversides with a big land passage)"); - let [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) - ]); - } - - createExtensionsOrIslands(); - // Don't createShoreJaggedness since it doesn't fit artistically here -} - -/** - * Creates a very small central river. - */ -function unknownCentralRiver() -{ - let waterHeight = -4; - let heightShallow = -2; - - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightLand)); - - let startAngle = randomAngle(); - - if (!isNomad()) - { - [playerIDs, playerPosition] = playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.5)); - markPlayerArea("large"); - } - - g_Map.log("Creating the main river"); - let [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)); - - g_Map.log("Creating small water spots at the map border to ensure separation of players"); - for (let 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)); - - if (!g_AllowNaval || randBool()) - { - g_Map.log("Creating the shallows of the main river"); - for (let i = 0; i <= randIntInclusive(1, scaleByMapSize(4, 8)); ++i) - { - let 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)); -} - -/** - * Creates a circular lake in the middle and possibly a river between each player ("pizza slices"). - */ -function unknownRiversAndLake() -{ - let waterHeight = -4; - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightLand)); - - let startAngle; - if (!isNomad()) - { - let playerAngle; - [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); - markPlayerArea("small"); - } - - let lake = randBool(3/4); - if (lake) - { - g_Map.log("Creating lake"); - createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.17)), 0.7, 0.1, Infinity, mapCenter), - [ - new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), - new TileClassPainter(clWater) - ]); - - createShoreJaggedness(waterHeight, clWater, 3); - } - - // Don't do this on nomad because the imbalances on the different islands are too drastic - if (!isNomad() && (!lake || randBool(1/3))) - { - g_Map.log("Creating small rivers separating players"); - for (let 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 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()) - { - g_Map.log("Creating small central island"); - createArea( - new ClumpPlacer(diskArea(fractionToTiles(0.05)), 0.7, 0.1, Infinity, mapCenter), - [ - landElevationPainter, - new TileClassPainter(clWater) - ]); - } -} - -/** - * Align players on a land strip with seas bordering on one or both sides that can hold islands. - */ -function unknownEdgeSeas() -{ - let waterHeight = -4; - - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightLand)); - - let 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"); - } - - for (let 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 - }); - - createExtensionsOrIslands(); - paintTileClassBasedOnHeight(0, heightCliff, 1, clLand); - createShoreJaggedness(waterHeight, clLand, 7, false); -} - -/** - * Land shaped like a concrescent moon around a central lake. - */ -function unknownGulf() -{ - let waterHeight = -3; - - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightLand)); - - let startAngle = randomAngle(); - if (!isNomad()) - { - g_Map.log("Determining player locations"); - - playerPosition = playerPlacementCustomAngle( - fractionToTiles(0.35), - mapCenter, - i => startAngle + 2/3 * Math.PI * (-1 + (numPlayers == 1 ? 1 : 2 * i / (numPlayers - 1))))[0]; - - markPlayerArea("large"); - } - - let 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 (let gulfPart of gulfParts) - { - let 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())); - } -} - -/** - * Mainland style with some small random lakes. - */ -function unknownLakes() -{ - let waterHeight = -5; - - createArea( - 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, 5), - new TileClassPainter(clWater) - ], - [avoidClasses(clPlayerTerritory, 12), randBool() ? avoidClasses(clWater, 8) : new NullConstraint()], - scaleByMapSize(5, 16)); -} - -/** - * A large hill leaving players only a small passage to each of the the two neighboring players. - */ -function unknownPasses() -{ - let heightMountain = 24; - let waterHeight = -4; - - createArea( - new MapBoundsPlacer(), - new ElevationPainter(heightLand)); - - let playerAngle; - let startAngle; - if (!isNomad()) - { - [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); - markPlayerArea("small"); - } - else - startAngle = randomAngle(); - - g_Map.log("Creating a mountain range between neighboring players"); - for (let 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)); - - // 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)); - } - - g_Map.log("Creating passages between neighboring players"); - let passes = distributePointsOnCircle(numPlayers * 2, startAngle, fractionToTiles(0.35), mapCenter)[0]; - for (let i = 0; i < numPlayers; ++i) - { - createArea( - new PathPlacer( - passes[2 * i], - passes[2 * ((i + 1) % numPlayers)], - scaleByMapSize(14, 24), - 0.4, - 3 * scaleByMapSize(1, 3), - 0.2, - 0.05), - new SmoothElevationPainter(ELEVATION_SET, heightLand, 2)); - } - - 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) - ]); - } -} - -/** - * Land enclosed by a hill that leaves small areas for civic centers and large central place. - */ -function unknownLowlands() -{ - let 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 (let 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) - ]); - - // 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.18)), 0.7, 0.1, Infinity, mapCenter), - [ - landElevationPainter, - new TileClassPainter(clWater) - ]); -} - -/** - * No water, no hills. - */ -function unknownMainland() -{ - createArea( - new MapBoundsPlacer(), - new ElevationPainter(3)); - - if (!isNomad()) - { - [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); - markPlayerArea("small"); - } -} - -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 createShoreJaggedness(waterHeight, borderClass, shoreDist, inwards = true) -{ - 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 createExtensionsOrIslands() -{ - let rnd = randIntInclusive(1, 3); - - if (rnd == 1) - { - 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)); - } - 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), - [ - landElevationPainter, - new TileClassPainter(clLand) - ], - null, - scaleByMapSize(2, 5) * randIntInclusive(8, 14)); - } -} - -/** - * 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 (size == "large") - createArea( - new ClumpPlacer(diskArea(scaleByMapSize(17, 29) / 3), 0.6, 0.3, Infinity, playerPosition[i]), - new TileClassPainter(clPlayerTerritory)); - } -} - -function paintUnknownMapBasedOnHeight() -{ - 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); -} - -/** - * 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"); - let [numForest, numStragglers] = getTreeCounts(...rBiomeTreeCount(1)); - let types = [ - [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], - [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] - ]; - - let size = numForest / (scaleByMapSize(2, 8) * numPlayers); - let num = Math.floor(size / types.length); - for (let 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 dirt patches"); - let patchCount = (currentBiome() == "generic/savanna" ? 3 : 1) * scaleByMapSize(15, 45); - for (let size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - [ - new LayeredPainter([[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]), - new TileClassPainter(clDirt) - ], - [avoidClasses(clForest, 0, clHill, 2, clDirt, 5, clPlayer, 7), stayClasses(clLand, 4)], - patchCount); - - g_Map.log("Creating grass patches"); - for (let size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) - createAreas( - new ClumpPlacer(size, 0.3, 0.06, 0.5), - new TerrainPainter(tTier4Terrain), - [avoidClasses(clForest, 0, clHill, 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 (let 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); - - let planetm = currentBiome() == "generic/tropic" ? 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)); -} - -function createUnknownPlayerBases() -{ - placePlayerBases({ - "PlayerPlacement": [playerIDs, playerPosition], - "BaseResourceClass": clBaseResource, - "Walls": g_StartingWalls, - "CityPatch": { - "outerTerrain": tRoadWild, - "innerTerrain": tRoad, - "painters": [ - new TileClassPainter(clPlayer) - ] - }, - "Chicken": { - }, - "Berries": { - "template": oFruitBush - }, - "Mines": { - "types": [ - { "template": oMetalLarge }, - { "template": oStoneLarge } - ] - }, - "Treasures": { - "types": [ - { - "template": oWoodTreasure, - "count": g_StartingTreasures ? 14 : 0 - } - ] - }, - "Trees": { - "template": oTree1 - }, - "Decoratives": { - "template": aGrassShort - } - }); -} Index: ps/trunk/binaries/data/mods/public/maps/random/unknown.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/unknown.js +++ ps/trunk/binaries/data/mods/public/maps/random/unknown.js @@ -1,9 +1,1075 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); -Engine.LoadLibrary("the_unknown"); -g_AllowNaval = true; +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; + +var g_Map = new RandomMap(heightSeaGround, tWater); + +const numPlayers = getNumPlayers(); +const mapSize = g_Map.getSize(); +const mapCenter = g_Map.getCenter(); +const mapBounds = g_Map.getBounds(); + +var clPlayer = g_Map.createTileClass(); +var clPlayerTerritory = g_Map.createTileClass(); +var clHill = g_Map.createTileClass(); +var clForest = g_Map.createTileClass(); +var clWater = g_Map.createTileClass(); +var clDirt = g_Map.createTileClass(); +var clRock = g_Map.createTileClass(); +var clMetal = g_Map.createTileClass(); +var clFood = g_Map.createTileClass(); +var clPeninsulaSteam = g_Map.createTileClass(); +var clBaseResource = g_Map.createTileClass(); +var clLand = g_Map.createTileClass(); +var 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() +{ + global["unknown" + g_MapSettings.Landscape || pickRandom([...unknownMapFunctions.land, ...unknownMapFunctions.naval])](); + + paintUnknownMapBasedOnHeight(); + + createUnknownPlayerBases(); + + createUnknownObjects(); + + placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2, clWater, 10)); +} + +/** + * Chain of islands or many disconnected islands. + */ +function unknownArchipelago() +{ + g_StartingWalls = "towers"; + g_StartingTreasures = true; + + let [pIDs, islandPosition] = playerPlacementCircle(fractionToTiles(0.35)); + if (!isNomad()) + { + [playerIDs, playerPosition] = [pIDs, islandPosition]; + markPlayerArea("large"); + } + + g_Map.log("Creating islands"); + let islandSize = diskArea(scaleByMapSize(17, 29)); + for (let i = 0; i < numPlayers; ++i) + createArea( + new ClumpPlacer(islandSize, 0.8, 0.1, Infinity, islandPosition[i]), + landElevationPainter); + + let 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)); + + 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)); + + 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)); + } +} + +/** + * Disk shaped mainland with water on the edge. + */ +function unknownContinent() +{ + let 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, mapCenter), + [ + landElevationPainter, + new TileClassPainter(clLand) + ]); + + if (randBool(1/3)) + { + g_Map.log("Creating peninsula (i.e. half the map not being surrounded by water)"); + let angle = randomAngle(); + let 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) + ]); + + g_Map.log("Remembering to not paint shorelines into the peninsula"); + let 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); +} + +/** + * Creates a huge central river, possibly connecting the riversides with a narrow piece of land. + */ +function unknownCentralSeaOrIsthmus(isthmus) +{ + let waterHeight = -3; + + let startAngle = randomAngle(); + + let [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); + } + }); + + if (!isNomad()) + { + [playerIDs, playerPosition] = playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.6)); + markPlayerArea("small"); + } + + if (isthmus) + { + g_Map.log("Creating isthmus (i.e. connecting the two riversides with a big land passage)"); + let [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) + ]); + } + + createExtensionsOrIslands(); + // Don't createShoreJaggedness since it doesn't fit artistically here +} + +function unknownCentralRiverLand() +{ + unknownCentralRiver(true); +} + +function unknownCentralRiverNaval() +{ + unknownCentralRiver(false); +} + +/** + * Creates a very small central river. + */ +function unknownCentralRiver(shallows) +{ + let waterHeight = -4; + let heightShallow = -2; + + createArea( + new MapBoundsPlacer(), + new ElevationPainter(heightLand)); + + let startAngle = randomAngle(); + + if (!isNomad()) + { + [playerIDs, playerPosition] = playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.5)); + markPlayerArea("large"); + } + + g_Map.log("Creating the main river"); + let [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)); + + g_Map.log("Creating small water spots at the map border to ensure separation of players"); + for (let 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)); + + if (shallows) + { + g_Map.log("Creating the shallows of the main river"); + for (let i = 0; i <= randIntInclusive(1, scaleByMapSize(4, 8)); ++i) + { + let 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)); +} + +/** + * Creates a circular lake in the middle and possibly a river between each player ("pizza slices"). + */ +function unknownRiversAndLake() +{ + let waterHeight = -4; + createArea( + new MapBoundsPlacer(), + new ElevationPainter(heightLand)); + + let startAngle; + if (!isNomad()) + { + let playerAngle; + [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); + markPlayerArea("small"); + } + + let lake = randBool(3/4); + if (lake) + { + g_Map.log("Creating lake"); + createArea( + new ClumpPlacer(diskArea(fractionToTiles(0.17)), 0.7, 0.1, Infinity, mapCenter), + [ + new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), + new TileClassPainter(clWater) + ]); + + 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 (let 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(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) + ]); + } +} + +/** + * Align players on a land strip with seas bordering on one or both sides that can hold islands. + */ +function unknownEdgeSeas() +{ + let waterHeight = -4; + + createArea( + new MapBoundsPlacer(), + new ElevationPainter(heightLand)); + + let 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"); + } + + for (let 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 + }); + + createExtensionsOrIslands(); + paintTileClassBasedOnHeight(0, heightCliff, 1, clLand); + createShoreJaggedness(waterHeight, clLand, 7, false); +} + +/** + * Land shaped like a concrescent moon around a central lake. + */ +function unknownGulf() +{ + let waterHeight = -3; + + createArea( + new MapBoundsPlacer(), + new ElevationPainter(heightLand)); + + let startAngle = randomAngle(); + if (!isNomad()) + { + g_Map.log("Determining player locations"); + + playerPosition = playerPlacementCustomAngle( + fractionToTiles(0.35), + mapCenter, + i => startAngle + 2/3 * Math.PI * (-1 + (numPlayers == 1 ? 1 : 2 * i / (numPlayers - 1))))[0]; + + markPlayerArea("large"); + } + + let 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 (let gulfPart of gulfParts) + { + let 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())); + } +} + +/** + * Mainland style with some small random lakes. + */ +function unknownLakes() +{ + let waterHeight = -5; + + createArea( + 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, 5), + new TileClassPainter(clWater) + ], + [avoidClasses(clPlayerTerritory, 12), randBool() ? avoidClasses(clWater, 8) : new NullConstraint()], + scaleByMapSize(5, 16)); +} + +/** + * A large hill leaving players only a small passage to each of the the two neighboring players. + */ +function unknownPasses() +{ + let heightMountain = 24; + let waterHeight = -4; + + createArea( + new MapBoundsPlacer(), + new ElevationPainter(heightLand)); + + let playerAngle; + let startAngle; + if (!isNomad()) + { + [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); + markPlayerArea("small"); + } + else + startAngle = randomAngle(); + + g_Map.log("Creating a mountain range between neighboring players"); + for (let 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)); + + // 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)); + } + + g_Map.log("Creating passages between neighboring players"); + let passes = distributePointsOnCircle(numPlayers * 2, startAngle, fractionToTiles(0.35), mapCenter)[0]; + for (let i = 0; i < numPlayers; ++i) + { + createArea( + new PathPlacer( + passes[2 * i], + passes[2 * ((i + 1) % numPlayers)], + scaleByMapSize(14, 24), + 0.4, + 3 * scaleByMapSize(1, 3), + 0.2, + 0.05), + new SmoothElevationPainter(ELEVATION_SET, heightLand, 2)); + } + + 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) + ]); + } +} + +/** + * Land enclosed by a hill that leaves small areas for civic centers and large central place. + */ +function unknownLowlands() +{ + let 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 (let 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) + ]); + + // 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.18)), 0.7, 0.1, Infinity, mapCenter), + [ + landElevationPainter, + new TileClassPainter(clWater) + ]); +} + +/** + * No water, no hills. + */ +function unknownMainland() +{ + createArea( + new MapBoundsPlacer(), + new ElevationPainter(3)); + + if (!isNomad()) + { + [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); + markPlayerArea("small"); + } +} + +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 createShoreJaggedness(waterHeight, borderClass, shoreDist, inwards = true) +{ + 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 createExtensionsOrIslands() +{ + let rnd = randIntInclusive(1, 3); + + if (rnd == 1) + { + 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)); + } + 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), + [ + landElevationPainter, + new TileClassPainter(clLand) + ], + null, + scaleByMapSize(2, 5) * randIntInclusive(8, 14)); + } +} + +/** + * 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 (size == "large") + createArea( + new ClumpPlacer(diskArea(scaleByMapSize(17, 29) / 3), 0.6, 0.3, Infinity, playerPosition[i]), + new TileClassPainter(clPlayerTerritory)); + } +} + +function paintUnknownMapBasedOnHeight() +{ + 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); +} + +/** + * 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"); + let [numForest, numStragglers] = getTreeCounts(...rBiomeTreeCount(1)); + let types = [ + [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], + [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] + ]; + + let size = numForest / (scaleByMapSize(2, 8) * numPlayers); + let num = Math.floor(size / types.length); + for (let 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 dirt patches"); + let patchCount = (currentBiome() == "generic/savanna" ? 3 : 1) * scaleByMapSize(15, 45); + for (let 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 grass patches"); + for (let size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + new TerrainPainter(tTier4Terrain), + [avoidClasses(clForest, 0, clHill, 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 (let 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); + + let planetm = currentBiome() == "generic/tropic" ? 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)); +} + +function createUnknownPlayerBases() +{ + placePlayerBases({ + "PlayerPlacement": [playerIDs, playerPosition], + "BaseResourceClass": clBaseResource, + "Walls": g_StartingWalls, + "CityPatch": { + "outerTerrain": tRoadWild, + "innerTerrain": tRoad, + "painters": [ + new TileClassPainter(clPlayer) + ] + }, + "Chicken": { + }, + "Berries": { + "template": oFruitBush + }, + "Mines": { + "types": [ + { "template": oMetalLarge }, + { "template": oStoneLarge } + ] + }, + "Treasures": { + "types": [ + { + "template": oWoodTreasure, + "count": g_StartingTreasures ? 14 : 0 + } + ] + }, + "Trees": { + "template": oTree1 + }, + "Decoratives": { + "template": aGrassShort + } + }); +} createUnknownMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/unknown.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/unknown.json +++ ps/trunk/binaries/data/mods/public/maps/random/unknown.json @@ -2,9 +2,87 @@ "settings" : { "Name" : "Unknown", "Script" : "unknown.js", - "Description" : "The unknown. Warning: May be a naval map.", + "Description" : "The unknown.", "Preview" : "unknown.png", "SupportedBiomes": "generic/", - "CircularMap" : true + "CircularMap" : true, + "Landscapes": { + "land" : [ + { + "Id": "Continent", + "Name": "Continent", + "Description": "All players starts on a continent surrounded by water.", + "Preview": "unknown_continent.png" + }, + { + "Id": "Isthmus", + "Name": "Isthmus", + "Description": "Two Mediterranean land masses connected by a narrow spit of land, called an 'Isthmus'.", + "Preview": "unknown_isthmus.png" + }, + { + "Id": "CentralRiver", + "Name": "Central River", + "Description": "A small central river.", + "Preview": "unknown_central_river.png" + }, + { + "Id": "EdgeSeas", + "Name": "Edge Seas", + "Description": "Players are aligned on a strip of land with seas bordering on one or both sides that may hold islands.", + "Preview": "unknown_edge_seas.png" + }, + { + "Id": "Gulf", + "Name": "Gulf", + "Description": "Land shaped like a concrescent moon around a central lake.", + "Preview": "unknown_gulf.png" + }, + { + "Id": "Lakes", + "Name": "Lakes", + "Description": "Mainland style with some small random lakes.", + "Preview": "unknown_lakes.png" + }, + { + "Id": "Passes", + "Name": "Passes", + "Description": "A large hill encompasses the map and leaves players only a small passage to the two neighboring players.", + "Preview": "unknown_passes.png" + }, + { + "Id": "Lowlands", + "Name": "Lowlands", + "Description": "The land is enclosed by a hill that leaves a small area per player connected to the large central place.", + "Preview": "unknown_lowlands.png" + }, + { + "Id": "Mainland", + "Name": "Mainland", + "Description": "A typical map without any water.", + "Preview": "unknown_mainland.png" + } + ], + "naval": [ + { + "Id": "CentralSea", + "Name": "Naval: Central Sea", + "Description": "A huge sea is dividing the map into two halves.", + "Preview": "unknown_central_sea.png" + }, + { + "Id": "Archipelago", + "Name": "Naval: Archipelago", + "Description": "Players are scattered across island chains and disconnected islands.", + "Preview": "unknown_archipelago.png" + }, + { + "Id": "RiversAndLake", + "Name": "Naval: Lake and rivers", + "Description": "A central lake with rivers possibly separating neighboring players.", + "Preview": "unknown_rivers_and_lake.png" + } + ] + } } } Index: ps/trunk/binaries/data/mods/public/maps/random/unknown_land.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/unknown_land.js +++ ps/trunk/binaries/data/mods/public/maps/random/unknown_land.js @@ -1,10 +0,0 @@ -Engine.LoadLibrary("rmgen"); -Engine.LoadLibrary("rmgen-common"); -Engine.LoadLibrary("rmbiome"); -Engine.LoadLibrary("the_unknown"); - -g_AllowNaval = false; - -createUnknownMap(); - -g_Map.ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/unknown_land.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/unknown_land.json +++ ps/trunk/binaries/data/mods/public/maps/random/unknown_land.json @@ -1,10 +0,0 @@ -{ - "settings" : { - "Name" : "Unknown Land", - "Script" : "unknown_land.js", - "Description" : "The unknown.", - "Preview" : "unknown.png", - "SupportedBiomes": "generic/", - "CircularMap" : true - } -}