Index: ps/trunk/binaries/data/mods/public/gui/common/settings.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/common/settings.js +++ ps/trunk/binaries/data/mods/public/gui/common/settings.js @@ -36,6 +36,7 @@ "GameSpeeds": loadSettingValuesFile("game_speeds.json"), "MapTypes": loadMapTypes(), "MapSizes": loadSettingValuesFile("map_sizes.json"), + "Biomes": loadSettingValuesFile("biomes.json"), "PlayerDefaults": loadPlayerDefaults(), "PopulationCapacities": loadPopulationCapacities(), "StartingResources": loadSettingValuesFile("starting_resources.json"), Index: ps/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js =================================================================== --- ps/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js +++ ps/trunk/binaries/data/mods/public/gui/gamesetup/gamesetup.js @@ -203,6 +203,11 @@ var g_MapFilterList; /** + * Array of biome identifiers supported by the currently selected map. + */ +var g_BiomeList; + +/** * Whether this is a single- or multiplayer match. */ var g_IsNetworked; @@ -356,6 +361,7 @@ }, "more": { "Dropdown": [ + "biome", "gameSpeed", "victoryCondition", "relicCount", @@ -479,6 +485,19 @@ "hidden": () => g_GameAttributes.mapType != "random", "autocomplete": 0, }, + "biome": { + "title": () => translate("Biome"), + "tooltip": (hoverIdx) => translate("Select the flora and fauna."), + "labels": () => g_BiomeList ? g_BiomeList.Title : [], + "ids": () => g_BiomeList ? g_BiomeList.Id : [], + "default": () => 0, + "defined": () => g_GameAttributes.settings.Biome !== undefined, + "get": () => g_GameAttributes.settings.Biome, + "select": (idx) => { + g_GameAttributes.settings.Biome = g_BiomeList && g_BiomeList.Id[idx]; + }, + "hidden": () => !g_BiomeList, + }, "numPlayers": { "title": () => translate("Number of Players"), "tooltip": (hoverIdx) => translate("Select number of players."), @@ -1450,6 +1469,35 @@ initDropdown("mapSelection"); } +function reloadBiomeList() +{ + let biomeList; + + if (g_GameAttributes.mapType == "random" && g_GameAttributes.settings.SupportedBiomes) + { + if (g_GameAttributes.settings.SupportedBiomes === true) + biomeList = g_Settings.Biomes; + else + { + biomeList = g_Settings.Biomes.filter( + biome => g_GameAttributes.settings.SupportedBiomes.indexOf(biome.Id) != -1); + + for (let biome of g_GameAttributes.settings.SupportedBiomes) + if (g_Settings.Biomes.every(bio => bio.Id != biome)) + warn("Map '" + g_GameAttributes.map + "' contains unknown biome '" + biome + "'") + } + } + + g_BiomeList = biomeList && prepareForDropdown( + [{ + "Id": "random", + "Title": translateWithContext("biome", "Random"), + "Description": translate("Pick a biome at random.") + }].concat(biomeList)); + + initDropdown("biome"); +} + function loadMapData(name) { if (!name || !g_MapPath[g_GameAttributes.mapType]) @@ -1515,6 +1563,7 @@ // Reload, as the maptype or mapfilter might have changed reloadMapFilterList(); + reloadBiomeList(); g_GameAttributes.settings.RatingEnabled = Engine.HasXmppClient(); Engine.SetRankedGame(g_GameAttributes.settings.RatingEnabled); @@ -1650,7 +1699,7 @@ function selectMap(name) { // Reset some map specific properties which are not necessarily redefined on each map - for (let prop of ["TriggerScripts", "CircularMap", "Garrison", "DisabledTemplates"]) + for (let prop of ["TriggerScripts", "CircularMap", "Garrison", "DisabledTemplates", "Biome", "SupportedBiomes"]) g_GameAttributes.settings[prop] = undefined; let mapData = loadMapData(name); @@ -1681,6 +1730,7 @@ for (let prop in mapSettings) g_GameAttributes.settings[prop] = mapSettings[prop]; + reloadBiomeList(); unassignInvalidPlayers(g_GameAttributes.settings.PlayerData.length); supplementDefaults(); } @@ -1802,6 +1852,9 @@ g_GameAttributes.settings.GameType = gameTypeSelected; } + if (g_GameAttributes.settings.Biome == "random") + g_GameAttributes.settings.Biome = pickRandom(g_GameAttributes.settings.SupportedBiomes); + g_GameAttributes.settings.TriggerScripts = g_GameAttributes.settings.VictoryScripts.concat(g_GameAttributes.settings.TriggerScripts || []); // Prevent reseting the readystate Index: ps/trunk/binaries/data/mods/public/l10n/messages.json =================================================================== --- ps/trunk/binaries/data/mods/public/l10n/messages.json +++ ps/trunk/binaries/data/mods/public/l10n/messages.json @@ -567,6 +567,7 @@ { "extractor": "json", "filemasks": [ + "simulation/data/settings/biomes.json", "simulation/data/settings/victory_conditions/*.json" ], "options": { Index: ps/trunk/binaries/data/mods/public/maps/random/amazon.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/amazon.js +++ ps/trunk/binaries/data/mods/public/maps/random/amazon.js @@ -7,7 +7,7 @@ InitMap(); log("Initializing tile classes..."); -setBiome(7); +setBiome(g_BiomeTropic); initMapSettings(); initTileClasses(); Index: ps/trunk/binaries/data/mods/public/maps/random/ambush.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/ambush.js +++ ps/trunk/binaries/data/mods/public/maps/random/ambush.js @@ -3,7 +3,7 @@ InitMap(); -randomizeBiome(); +setSelectedBiome(); initMapSettings(); initTileClasses(); Index: ps/trunk/binaries/data/mods/public/maps/random/ambush.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/ambush.json +++ ps/trunk/binaries/data/mods/public/maps/random/ambush.json @@ -5,7 +5,8 @@ "Description" : "High bluffs overlook the terrain below. Bountiful resources await on the cliffs, but beware of enemies planning an ambush.", "BaseTerrain" : ["medit_sea_depths"], "BaseHeight" : 2, - "Preview" : "ambush.png", + "Preview" : "ambush.png", + "SupportedBiomes": true, "CircularMap" : true } } Index: ps/trunk/binaries/data/mods/public/maps/random/bahrain.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/bahrain.js +++ ps/trunk/binaries/data/mods/public/maps/random/bahrain.js @@ -7,7 +7,7 @@ InitMap(); log("Initializing tile classes..."); -setBiome(3); +setBiome(g_BiomeDesert); initMapSettings(); initTileClasses(["island"]); Index: ps/trunk/binaries/data/mods/public/maps/random/flood.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/flood.js +++ ps/trunk/binaries/data/mods/public/maps/random/flood.js @@ -1,6 +1,6 @@ RMS.LoadLibrary("rmgen"); -let random_terrain = randomizeBiome([g_BiomeSavanna]); +setSelectedBiome(); const tMainTerrain = rBiomeT1(); const tForestFloor1 = rBiomeT2(); @@ -17,7 +17,7 @@ let tHill = rBiomeT8(); let tDirt = rBiomeT9(); -if (random_terrain == g_BiomeTemperate) +if (currentBiome() == g_BiomeTemperate) { tDirt = ["medit_shrubs_a", "grass_field"]; tHill = ["grass_field", "peat_temp"]; @@ -306,7 +306,7 @@ [avoidClasses(clPlayer, 25, clForest, 10, clBaseResource, 3, clMetal, 6, clRock, 3, clMountain, 2), stayClasses(clHill, 6)], clForest, 0.7, - random_terrain + currentBiome() ); log("Creating straggeler trees..."); @@ -317,7 +317,7 @@ log("Creating dirt patches..."); let sizes = [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]; -let numb = random_terrain == g_BiomeSavanna ? 3 : 1; +let numb = currentBiome() == g_BiomeSavanna ? 3 : 1; for (let i = 0; i < sizes.length; ++i) { @@ -378,7 +378,7 @@ createStragglerTrees(types, avoidClasses(clWater, 5, clForest, 7, clMountain, 1, clPlayer, 30, clMetal, 6, clRock, 3)); log("Creating decoration..."); -let planetm = random_terrain == g_BiomeTropic ? 8 : 1; +let planetm = currentBiome() == g_BiomeTropic ? 8 : 1; createDecoration ( [ @@ -404,7 +404,7 @@ avoidClasses(clPlayer, 30, clHill, 10, clFood, 5), clForest, 0.1, - random_terrain + currentBiome() ); log("Creating small grass tufts..."); Index: ps/trunk/binaries/data/mods/public/maps/random/flood.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/flood.json +++ ps/trunk/binaries/data/mods/public/maps/random/flood.json @@ -5,6 +5,15 @@ "Description" : "A great flood has moved across the valley enabling ships and troops to battle in chest deep waters.", "BaseTerrain" : ["medit_sand_wet"], "BaseHeight" : -2, + "SupportedBiomes": [ + "temperate", + "snowy", + "desert", + "alpine", + "mediterranean", + "tropic", + "autumn" + ], "Keywords": [], "Preview" : "flood.png", "CircularMap" : true Index: ps/trunk/binaries/data/mods/public/maps/random/howe_sound.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/howe_sound.js +++ ps/trunk/binaries/data/mods/public/maps/random/howe_sound.js @@ -7,7 +7,7 @@ InitMap(); log("Initializing tile classes..."); -setBiome(2); +setBiome(g_BiomeSnowy); initMapSettings(); initTileClasses(["island"]); Index: ps/trunk/binaries/data/mods/public/maps/random/island_stronghold.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/island_stronghold.js +++ ps/trunk/binaries/data/mods/public/maps/random/island_stronghold.js @@ -18,7 +18,7 @@ const g_InitialMineDistance = 14; const g_InitialTrees = 50; -let random_terrain = randomizeBiome([g_BiomeSavanna]); +setSelectedBiome(); const tMainTerrain = rBiomeT1(); const tForestFloor1 = rBiomeT2(); @@ -374,7 +374,7 @@ [avoidClasses(clPlayer, 10, clForest, 20, clHill, 10, clBaseResource, 5, clRock, 6, clMetal, 6), stayClasses(clLand, 3)], clForest, 1.0, - random_terrain + currentBiome() ); log("Creating hills..."); @@ -416,7 +416,7 @@ [avoidClasses(clForest, 0, clPlayer, 15, clHill, 1, clFood, 4, clRock, 6, clMetal, 6), stayClasses(clLand, 2)] ); -if (random_terrain == g_BiomeDesert) +if (currentBiome() == g_BiomeDesert) { log("Creating obelisks"); let group = new SimpleGroup( @@ -432,7 +432,7 @@ log("Creating dirt patches..."); let sizes = [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]; -let numb = random_terrain == g_BiomeSavanna ? 3 : 1; +let numb = currentBiome() == g_BiomeSavanna ? 3 : 1; for (let i = 0; i < sizes.length; ++i) { @@ -528,7 +528,7 @@ placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius, [stayClasses(clLand, 5)]); log("Creating small grass tufts..."); -let planetm = random_terrain == 7 ? 8 : 1; +let planetm = currentBiome() == 7 ? 8 : 1; group = new SimpleGroup( [new SimpleObject(aGrassShort, 1, 2, 0, 1, -PI / 8, PI / 8)] ); Index: ps/trunk/binaries/data/mods/public/maps/random/island_stronghold.json =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/island_stronghold.json +++ ps/trunk/binaries/data/mods/public/maps/random/island_stronghold.json @@ -1,12 +1,21 @@ { - "settings" : { - "Name" : "Island Stronghold", - "Script" : "island_stronghold.js", - "Description" : "Teams start off with nearly adjacent civic centers on a small island, offering a fortified base from which to expand.", - "BaseTerrain" : ["medit_sand_wet"], - "BaseHeight" : -10, - "Keywords": ["naval"], - "Preview" : "island_stronghold.png", - "CircularMap" : true - } + "settings" : { + "Name" : "Island Stronghold", + "Script" : "island_stronghold.js", + "Description" : "Teams start off with nearly adjacent civic centers on a small island, offering a fortified base from which to expand.", + "BaseTerrain" : ["medit_sand_wet"], + "BaseHeight" : -10, + "Keywords": ["naval"], + "Preview" : "island_stronghold.png", + "SupportedBiomes": [ + "temperate", + "snowy", + "desert", + "alpine", + "mediterranean", + "tropic", + "autumn" + ], + "CircularMap" : true + } } Index: ps/trunk/binaries/data/mods/public/maps/random/marmara.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/marmara.js +++ ps/trunk/binaries/data/mods/public/maps/random/marmara.js @@ -7,7 +7,7 @@ InitMap(); log("Initializing tile classes..."); -setBiome(5); +setBiome(g_BiomeMediterranean); initMapSettings(); initTileClasses(); Index: ps/trunk/binaries/data/mods/public/maps/random/mediterranean.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/mediterranean.js +++ ps/trunk/binaries/data/mods/public/maps/random/mediterranean.js @@ -7,7 +7,7 @@ InitMap(); log("Initializing environment..."); -setBiome(1); +setBiome(g_BiomeTemperate); initMapSettings(); initTileClasses(["autumn", "desert", "medit", "polar", "steppe", "temp"]); Index: ps/trunk/binaries/data/mods/public/maps/random/ngorongoro.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/ngorongoro.js +++ ps/trunk/binaries/data/mods/public/maps/random/ngorongoro.js @@ -7,7 +7,7 @@ InitMap(); log("Initializing tile classes..."); -setBiome(6); +setBiome(g_BiomeSavanna); initMapSettings(); initTileClasses(["eden", "highlands"]); Index: ps/trunk/binaries/data/mods/public/maps/random/pompeii.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/pompeii.js +++ ps/trunk/binaries/data/mods/public/maps/random/pompeii.js @@ -7,7 +7,7 @@ InitMap(); log("Initializing tile classes..."); -setBiome(5); +setBiome(g_BiomeMediterranean); initMapSettings(); initTileClasses(["decorative", "lava"]); Index: ps/trunk/binaries/data/mods/public/maps/random/ratumacos.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/ratumacos.js +++ ps/trunk/binaries/data/mods/public/maps/random/ratumacos.js @@ -7,7 +7,7 @@ InitMap(); log("Initializing tile classes..."); -setBiome(4); +setBiome(g_BiomeAlpine); initMapSettings(); initTileClasses(["shallowWater"]); Index: ps/trunk/binaries/data/mods/public/maps/random/red_sea.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/red_sea.js +++ ps/trunk/binaries/data/mods/public/maps/random/red_sea.js @@ -7,7 +7,7 @@ InitMap(); log("Initializing biome..."); -setBiome(3); +setBiome(g_BiomeDesert); initMapSettings(); initTileClasses(); Index: ps/trunk/binaries/data/mods/public/maps/random/rmgen/randombiome.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/rmgen/randombiome.js +++ ps/trunk/binaries/data/mods/public/maps/random/rmgen/randombiome.js @@ -1,11 +1,25 @@ -const g_BiomeTemperate = 1; -const g_BiomeSnowy = 2; -const g_BiomeDesert = 3; -const g_BiomeAlpine = 4; -const g_BiomeMediterranean = 5; -const g_BiomeSavanna = 6; -const g_BiomeTropic = 7; -const g_BiomeAutumn = 8; +/** + * Use constants as biome identifiers, so that we get reference errors if there is a typo. + */ +const g_BiomeTemperate = "temperate"; +const g_BiomeSnowy = "snowy"; +const g_BiomeDesert = "desert"; +const g_BiomeAlpine = "alpine"; +const g_BiomeMediterranean = "mediterranean"; +const g_BiomeSavanna = "savanna"; +const g_BiomeTropic = "tropic"; +const g_BiomeAutumn = "autumn"; + +const g_Biomes = deepfreeze([ + g_BiomeTemperate, + g_BiomeSnowy, + g_BiomeDesert, + g_BiomeAlpine, + g_BiomeMediterranean, + g_BiomeSavanna, + g_BiomeTropic, + g_BiomeAutumn +]); var g_BiomeID = g_BiomeTemperate; @@ -55,23 +69,35 @@ "tree": "actor|flora/trees/oak.xml" }; -/** - * Randomizes environment, optionally excluding some biome IDs. - */ -function randomizeBiome(avoid = []) +function currentBiome() { - let biomeIndex; - do - biomeIndex = randIntInclusive(1, 8); - while (avoid.indexOf(biomeIndex) != -1); + return g_BiomeID; +} - setBiome(biomeIndex); +function setSelectedBiome() +{ + if (g_Biomes.indexOf(g_MapSettings.Biome) == -1) + { + error("Can't set biome '" + g_MapSettings.Biome + "'"); + return; + } + + setBiome(g_MapSettings.Biome); +} - return biomeIndex; +function randomizeBiome() +{ + setBiome(pickRandom(g_Biomes)); + return g_BiomeID; } -function setBiome(biomeIndex) +function setBiome(biomeID) { + if (g_Biomes.indexOf(biomeID) == -1) + warn("Unknown biome: '" + biomeID + "'"); + else + g_BiomeID = biomeID; + setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); setSunRotation(randFloat(0, TWO_PI)); @@ -80,8 +106,6 @@ setUnitsAmbientColor(0.57, 0.58, 0.55); setTerrainAmbientColor(0.447059, 0.509804, 0.54902); - g_BiomeID = biomeIndex; - if (g_BiomeID == g_BiomeTemperate) { // temperate ocean blue, a bit too deep and saturated perhaps but it looks nicer. Index: ps/trunk/binaries/data/mods/public/simulation/data/settings/biomes.json =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/data/settings/biomes.json +++ ps/trunk/binaries/data/mods/public/simulation/data/settings/biomes.json @@ -0,0 +1,38 @@ +{ + "TranslatedKeys": ["Title"], + "Data": + [ + { + "Id": "temperate", + "Title": "Temperate" + }, + { + "Id": "snowy", + "Title": "Snowy" + }, + { + "Id": "desert", + "Title": "Desert" + }, + { + "Id": "alpine", + "Title": "Alpine" + }, + { + "Id": "mediterranean", + "Title": "Mediterranean" + }, + { + "Id": "savanna", + "Title": "Savanna" + }, + { + "Id": "tropic", + "Title": "Tropic" + }, + { + "Id": "autumn", + "Title": "Autumn" + } + ] +}