Index: binaries/data/mods/public/maps/random/extinct_volcano.js =================================================================== --- /dev/null +++ binaries/data/mods/public/maps/random/extinct_volcano.js @@ -0,0 +1,513 @@ +RMS.LoadLibrary("rmgen"); + +const tHillDark = "cliff volcanic light"; +const tHillMedium1 = "ocean_rock_a"; +const tHillMedium2 = "ocean_rock_b"; +const tHillVeryDark = ["cliff volcanic coarse", "cave_walls"]; +const tRoad = "road1"; +const tRoadWild = "road1"; +const tForestFloor1 = tHillMedium1; +const tForestFloor2 = tHillMedium2; +const tGrassA = "cliff volcanic light"; +const tGrassB = "ocean_rock_a"; +const tGrass3 = "temp_grass_plants"; +const tGrassPatchBlend = "temp_grass_long_b"; +const tGrassPatch = ["temp_grass_d", "temp_grass_clovers"]; +const tShoreBlend = "cliff volcanic light"; +const tShore = "ocean_rock_a"; +const tWater = "ocean_rock_b"; + +// Gaia entities +const oTree = "gaia/flora_tree_dead"; +const oTree2 = "gaia/flora_tree_euro_beech"; +const oTree3 = "gaia/flora_tree_oak"; +const oTree4 = "gaia/flora_tree_oak_dead"; +const oBush = "gaia/flora_bush_temperate"; +const oFruitBush = "gaia/flora_bush_berry"; +const oRabbit = "gaia/fauna_rabbit"; +const oGoat = "gaia/fauna_goat"; +const oBear = "gaia/fauna_bear"; +const oStoneLarge = "gaia/geology_stonemine_temperate_quarry"; +const oStoneSmall = "gaia/geology_stone_temperate"; +const oMetalLarge = "gaia/geology_metal_temperate_slabs"; +const oTower = "other/palisades_rocks_fort"; + +// Decorative props +const aRockLarge = "actor|geology/stone_granite_med.xml"; +const aRockMedium = "actor|geology/stone_granite_med.xml"; +const aBushMedium = "actor|props/flora/bush_tempe_me.xml"; +const aBushSmall = "actor|props/flora/bush_tempe_sm.xml"; +const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; +const aGrassShort = "actor|props/flora/grass_soft_large.xml"; + +const pForestD = [ + tForestFloor1 + TERRAIN_SEPARATOR + oTree, + tForestFloor2 + TERRAIN_SEPARATOR + oTree2, + tForestFloor1 +]; + +const pForestP = [ + tForestFloor1 + TERRAIN_SEPARATOR + oTree3, + tForestFloor2 + TERRAIN_SEPARATOR + oTree4, + tForestFloor1 +]; + +log("Initializing map..."); +InitMap(); + +var P_FOREST = 0.7; +var totalTrees = scaleByMapSize(1200, 3000); +var numForest = totalTrees * P_FOREST; +var numStragglers = totalTrees * (1.0 - P_FOREST); + +var numPlayers = getNumPlayers(); +var mapSize = getMapSize(); +var mapArea = mapSize * mapSize; + +// create tile classes +var clPlayer = createTileClass(); +var clHill = createTileClass(); +var clFood = createTileClass(); +var clForest = createTileClass(); +var clWater = createTileClass(); +var clDirt = createTileClass(); +var clGrass = createTileClass(); +var clRock = createTileClass(); +var clMetal = createTileClass(); +var clBaseResource = createTileClass(); +var clBumps = createTileClass(); +var clTower = createTileClass(); + +var ccMountainHeight = 25; + +// randomize player order +var playerIDs = []; +for (let i = 0; i < numPlayers; ++i) + playerIDs.push(i+1); +playerIDs = sortPlayers(playerIDs); + +// Place players +var startAngle = randFloat(0, 2 * PI); +for (let i = 0; i < numPlayers; ++i) +{ + let playerAngle = startAngle + i * 2 * PI / numPlayers; + let playerX = 0.5 + 0.35 * Math.cos(playerAngle); + let playerZ = 0.5 + 0.35 * Math.sin(playerAngle); + + let id = playerIDs[i]; + log("Creating base for player " + id + "..."); + let radius = scaleByMapSize(15, 25); + + let fx = fractionToTiles(playerX); + let fz = fractionToTiles(playerZ); + let ix = Math.round(fx); + let iz = Math.round(fz); + + // This one consists of many bumps, creating an omnidirectional ramp + createMountain( + ccMountainHeight, + Math.floor(scaleByMapSize(15, 15)), + Math.floor(scaleByMapSize(15, 15)), + Math.floor(scaleByMapSize(4, 10)), + avoidClasses(), + ix, + iz, + tHillDark, + clPlayer, + 14); + + // Flatten the initial CC area + let hillSize = PI * radius * radius; + createArea( + new ClumpPlacer(hillSize, 0.95, 0.6, 10, ix, iz), + [ + new LayeredPainter([tHillVeryDark, tHillMedium1], [radius]), + new SmoothElevationPainter(ELEVATION_SET, ccMountainHeight, radius), + paintClass(clPlayer) + ], + null); + + // Create the city patch + let cityRadius = radius / 3; + createArea( + new ClumpPlacer(PI * cityRadius * cityRadius, 0.6, 0.3, 10, ix, iz), + new LayeredPainter([tRoadWild, tRoad], [1]), + null); + + placeCivDefaultEntities(fx, fz, id, { 'iberWall': 'towers' }); + + // Create metal mine + let mAngle = randFloat(0, 2 * PI); + let mDist = 12; + createObjectGroup( + new SimpleGroup( + [new SimpleObject(oMetalLarge, 1, 1, 0, 0)], + true, + clBaseResource, + Math.round(fx + mDist * Math.cos(mAngle)), + Math.round(fz + mDist * Math.sin(mAngle))), + 0); + + // Create stone mines + mAngle += randFloat(PI/4, PI/3); + createObjectGroup( + new SimpleGroup( + [new SimpleObject(oStoneLarge, 1, 1, 0, 2)], + true, + clBaseResource, + Math.round(fx + mDist * Math.cos(mAngle)), + Math.round(fz + mDist * Math.sin(mAngle))), + 0); + + placeDefaultChicken(fx, fz, clBaseResource); + + // Create berry bushes + mAngle += randFloat(PI/4, PI/2); + let bbDist = 12; + createObjectGroup( + new SimpleGroup( + [new SimpleObject(oFruitBush, 5, 5, 0, 3)], + true, + clBaseResource, + Math.round(fx + bbDist * Math.cos(mAngle)), + Math.round(fz + bbDist * Math.sin(mAngle))), + 0); + + // Create starting trees + let num = Math.floor(hillSize / 60); + let tries = 10; + for (let x = 0; x < tries; ++x) + { + let tAngle = mAngle + randFloat(PI/3, PI/4); + let tDist = randFloat(10, 12); + if (createObjectGroup( + new SimpleGroup( + [new SimpleObject(oTree2, num, num, 0, 3)], + false, + clBaseResource, + Math.round(fx + tDist * Math.cos(tAngle)), + Math.round(fz + tDist * Math.sin(tAngle))), + 0, + avoidClasses(clBaseResource, 3))) + { + break; + } + } +} +RMS.SetProgress(15); + +createVolcano(0.5, 0.5, clHill, tHillVeryDark, undefined, false, ELEVATION_SET); +RMS.SetProgress(20); + +log("Creating lakes..."); +createAreas( + new ChainPlacer(5, 6, Math.floor(scaleByMapSize(10, 14)), 0.1), + [ + new LayeredPainter([tShoreBlend, tShore, tWater], [1, 1]), + new SmoothElevationPainter(ELEVATION_SET, -4, 3), + paintClass(clWater) + ], + avoidClasses(clPlayer, 0, clHill, 2, clWater, 12), + Math.round(scaleByMapSize(6, 12))); +RMS.SetProgress(25); + +createBumps(avoidClasses(clPlayer, 0, clHill, 0), scaleByMapSize(50, 300), 1, 10, 3, 0, scaleByMapSize(4, 10)); +paintTileClassBasedOnHeight(10, 100, 0, clBumps); +RMS.SetProgress(30); + +log("Creating hills..."); +createAreas( + new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, 1), + [ + new LayeredPainter([tHillDark, tHillDark, tHillDark], [2, 2]), + new SmoothElevationPainter(ELEVATION_SET, 18, 2), + paintClass(clHill) + ], + avoidClasses(clPlayer, 0, clHill, 15, clWater, 2, clBaseResource, 2), + scaleByMapSize(2, 8) * numPlayers); +RMS.SetProgress(35); + +log("Creating forests..."); +var types = [ + [[tGrassB, tGrassA, pForestD], [tGrassB, pForestD]], + [[tGrassB, tGrassA, pForestP], [tGrassB, pForestP]] +]; +var size = numForest / (scaleByMapSize(4, 12) * numPlayers); +var num = Math.floor(size / types.length); +for (let i = 0; i < types.length; ++i) + createAreas( + new ClumpPlacer(numForest / num, 0.1, 0.1, 1), + [ + new LayeredPainter(types[i], [2]), + paintClass(clForest) + ], + avoidClasses( + clPlayer, 4, + clForest, 10, + clHill, 0, + clWater, 2), + num); +RMS.SetProgress(40); + +log("Creating hill patches..."); +for (let size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + for (let type of [[tHillMedium1, tHillDark], [tHillDark, tHillMedium2], [tHillMedium1, tHillMedium2]]) + createAreas( + new ClumpPlacer(size, 0.3, 0.06, 0.5), + [ + new LayeredPainter(type, [1]), + paintClass(clGrass) + ], + avoidClasses( + clWater, 3, + clForest, 0, + clHill, 0, + clBumps, 0, + clPlayer, 0), + scaleByMapSize(20, 80)); +RMS.SetProgress(45); + +log("Creating grass patches..."); +createLayeredPatches( + [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], + [tGrassPatchBlend, tGrassPatch], + [1], + avoidClasses( + clWater, 1, + clForest, 0, + clHill, 0, + clGrass, 5, + clBumps, 0, + clPlayer, 0), + clDirt); +RMS.SetProgress(50); + +log("Creating stone mines..."); +createObjectGroups( + new SimpleGroup( + [ + new SimpleObject(oStoneSmall, 0, 2, 0, 4), + new SimpleObject(oStoneLarge, 1, 1, 0, 4) + ], + true, + clRock), + 0, + [ + stayClasses(clBumps, 1), + avoidClasses( + clWater, 3, + clForest, 1, + clPlayer, 0, + clRock, 15, + clHill, 0) + ], + 100, + 100); +RMS.SetProgress(55); + +log("Creating small stone quarries..."); +createObjectGroups( + new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock), + 0, + [ + stayClasses(clBumps, 1), + avoidClasses( + clWater, 3, + clForest, 1, + clPlayer, 0, + clRock, 15, + clHill, 0) + ], + 100, + 100); +RMS.SetProgress(60); + +log("Creating metal mines..."); +createObjectGroups( + new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), + 0, + [ + stayClasses(clBumps, 1), + avoidClasses( + clWater, 3, + clForest, 1, + clPlayer, 0, + clMetal, 15, + clRock, 10, + clHill, 0) + ], + 100, + 100); +RMS.SetProgress(65); + +log("Creating towers..."); +createObjectGroups( + new SimpleGroup([new SimpleObject(oTower, 1, 1, 0, 4)], true, clTower), + 0, + [ + stayClasses(clBumps, 3), + avoidClasses( + clMetal, 5, + clRock, 5, + clHill, 0, + clTower, 60, + clPlayer, 10, + clForest, 2) + ], + 500, + 1); +RMS.SetProgress(67); + +createDecoration( + [ + [new SimpleObject(aGrassShort, 1, 2, 0, 1)], + [ + new SimpleObject(aGrass, 2, 4, 0, 1.8), + new SimpleObject(aGrassShort, 3, 6, 1.2, 2.5) + ], + [ + new SimpleObject(aBushMedium, 1, 2, 0, 2), + new SimpleObject(aBushSmall, 2, 4, 0, 2) + ] + ], + [ + scaleByMapSize(15, 200), + scaleByMapSize(15, 200), + scaleByMapSize(15, 200) + ], + [ + stayClasses(clGrass, 0), + avoidClasses( + clWater, 0, + clForest, 0, + clPlayer, 0, + clHill, 0) + ]); +RMS.SetProgress(70); + +createDecoration( + [ + [ + new SimpleObject(aRockMedium, 1, 3, 0, 1) + ], + [ + new SimpleObject(aRockLarge, 1, 2, 0, 1), + new SimpleObject(aRockMedium, 1, 3, 0, 2) + ] + ], + [ + scaleByMapSize(15, 250), + scaleByMapSize(15, 150) + ], + avoidClasses( + clWater, 0, + clForest, 0, + clPlayer, 0, + clHill, 0 + )); +RMS.SetProgress(75); + +createFood( + [ + [new SimpleObject(oRabbit, 5, 7, 2, 4)], + [new SimpleObject(oGoat, 3, 5, 2, 4)] + ], + [ + scaleByMapSize(1, 6) * numPlayers, + scaleByMapSize(3, 10) * numPlayers + ], + [ + avoidClasses( + clWater, 1, + clForest, 0, + clPlayer, 0, + clHill, 1, + clFood, 20) + ], + clFood); +RMS.SetProgress(78); + +createFood( + [ + [new SimpleObject(oBear, 1, 1, 0, 2)] + ], + [ + 3 * numPlayers + ], + [ + avoidClasses( + clWater, 1, + clForest, 0, + clPlayer, 0, + clHill, 1, + clFood, 20 + ), + stayClasses(clForest, 2) + ], + clFood); +RMS.SetProgress(81); + +createFood( + [ + [new SimpleObject(oFruitBush, 1, 2, 0, 4)] + ], + [ + 3 * numPlayers + ], + [stayClasses(clGrass, 1), avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 1, clFood, 10)], + clFood); +RMS.SetProgress(85); + +log("Creating straggler trees and bushes..."); +var types = [oTree, oTree2, oTree3, oTree4, oBush]; +var num = Math.floor(numStragglers / types.length); +for (let type of types) + createObjectGroups( + new SimpleGroup( + [new SimpleObject(type, 1, 1, 0, 3)], + true, + clForest), + 0, + [ + stayClasses(clGrass, 1), + avoidClasses( + clWater, 5, + clForest, 1, + clHill, 1, + clPlayer, 0, + clMetal, 1, + clRock, 1) + ], + num); + +RMS.SetProgress(90); + +log("Creating straggler bushes..."); +createObjectGroups( + new SimpleGroup( + [new SimpleObject(oBush, 1, 3, 0, 3)], + true, + clForest + ), + 0, + [ + stayClasses(clGrass, 3), + avoidClasses( + clWater, 1, + clForest, 1, + clPlayer, 0, + clMetal, 1, + clRock, 1) + ], + numStragglers); +RMS.SetProgress(95); + +setWaterType("lake"); +setWaterWaviness(2); +setWaterColor(0.035, 0.047, 0.05); +setWaterTint(0.058, 0.05, 0.035); +setWaterMurkiness(0.9); + +setPPEffect("hdr"); + +ExportMap(); Index: binaries/data/mods/public/maps/random/extinct_volcano.json =================================================================== --- /dev/null +++ binaries/data/mods/public/maps/random/extinct_volcano.json @@ -0,0 +1,19 @@ +{ + "settings" : { + "Name" : "Extinct Volcano", + "Script" : "extinct_volcano.js", + "Description" : "[color=\"red\"]IMPORTANT NOTE: AI PLAYERS DO NOT WORK WITH THIS MAP[/color]\n\nA once fertile valley... desolated by the eruption of the long-dormant volcano in the heart of the region. Following years of empty, scorched deadness, signs of life started reappearing and spreading. Now the land is half-way to the full lushness of its former era. Alas, it is not to be: following a long stretch of drought, interminable rains have set in in the higher regions to the north. Water levels are rising at drastic levels, slowly forcing players to seek the high ground of the lesser, extinct volcanoes or the now again dormant great cone.", + "DisabledTemplates": [ + "structures/ptol_lighthouse" + ], + "BaseTerrain" : "ocean_rock_a", + "BaseHeight" : 1, + "Keywords": ["new", "trigger"], + "CircularMap" : true, + "Preview" : "extinctvolcano.png", + "TriggerScripts": [ + "scripts/TriggerHelper.js", + "random/extinct_volcano_triggers.js" + ] + } +} Index: binaries/data/mods/public/maps/random/extinct_volcano_triggers.js =================================================================== --- /dev/null +++ binaries/data/mods/public/maps/random/extinct_volcano_triggers.js @@ -0,0 +1,200 @@ +/** + * Whether to log the water levels and which units became killed or transformed to visual actors. + */ +var debugLog = false; + +/** + * Whether to rise the water to the maximum level in a minute or two. + */ +var debugWaterRise = false; + +/** + * Time in minutes when the water level starts to rise. + * Allow players to build up the economy and military for some time. + */ +var waterRiseStartTime = [22, 26]; + +/** + * Duration in minutes for which the notification will be shown that states that the water will rise soon. + */ +var waterRiseNotificationDuration = 1; + +/** + * Time in minutes between increases of the water level. + * If the water rises too fast, the hills are of no strategic importance, + * building structures would be pointless. + * + * At height 27, most trees are not gatherable anymore and enemies not reachable. + * At height 37 most hills are barely usable. + * + * At min 30 stuff at the ground level should not be gatherable anymore. + * At min 45 CC should be destroyed. + * + * Notice regular and military docks will raise with the water! + */ +var waterIncreaseTime = [0.5, 1]; + +/** + * Number of meters the waterheight increases each step. + * Each time the water level is changed, the pathfinder grids have to be recomputed. + * Therefore raising the level should occur as rarely as possible, i.e. have the value + * as big as possible, but as small as needed to keep it visually authentic. + */ +var waterLevelIncreaseHeight = 1; + +/** + * At which height to stop increasing the water level. + * Since players can survive on ships, don't endlessly raise the water. + */ +var maxWaterLevel = 70; + +/** + * Let buildings, relics and siege engines become actors, but kill organic units. + */ +var drownClass = "Organic"; + +/** + * Maximum height that units and structures can be submerged before drowning or becoming destructed. + */ +var drownHeight = 1; + +/** + * One of these warnings is printed some minutes before the water level starts to rise. + */ +var waterWarningTexts = [ + markForTranslation("It keeps on raining, we will have to evacuate soon!"), + markForTranslation("The rivers are standing high, we need to find a save place!"), + markForTranslation("We have got to find dry ground, our lands will drawn soon!"), + markForTranslation("The lakes start swallowing the land, we have to find shelter!") +]; + +/** + * Units to be garrisoned in the wooden towers. + */ +var garrisonedUnits = "units/rome_legionnaire_marian"; + +Trigger.prototype.RaisingWaterNotification = function() +{ + Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).AddTimeNotification({ + "message": pickRandom(waterWarningTexts), + "translateMessage": true + }, waterRiseNotificationDuration * 60 * 1000); +}; + +Trigger.prototype.DebugLog = function(txt) +{ + if (!debugLog) + return; + + let time = Math.round(Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer).GetTime() / 60 / 1000); + print("DEBUG [" + time + "] " + txt + "\n"); +}; + + +Trigger.prototype.GarrisonWoodenTowers = function() +{ + for (let gaiaEnt of Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).GetEntitiesByPlayer(0)) + { + let cmpIdentity = Engine.QueryInterface(gaiaEnt, IID_Identity); + if (!cmpIdentity || !cmpIdentity.HasClass("DefenseTower")) + continue; + + let cmpGarrisonHolder = Engine.QueryInterface(gaiaEnt, IID_GarrisonHolder); + if (!cmpGarrisonHolder) + continue; + + for (let newEnt of TriggerHelper.SpawnUnits(gaiaEnt, garrisonedUnits, cmpGarrisonHolder.GetCapacity(), 0)) + if (Engine.QueryInterface(gaiaEnt, IID_GarrisonHolder).Garrison(newEnt)) + Engine.QueryInterface(newEnt, IID_UnitAI).Autogarrison(gaiaEnt); + } +}; + +Trigger.prototype.RaiseWaterLevelStep = function() +{ + let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); + let time = cmpTimer.GetTime(); + let cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager); + let newLevel = cmpWaterManager.GetWaterLevel() + waterLevelIncreaseHeight; + cmpWaterManager.SetWaterLevel(newLevel); + this.DebugLog("Raising water level to " + Math.round(newLevel) + " took " + (cmpTimer.GetTime() - time)); + + if (newLevel < maxWaterLevel) + this.DoAfterDelay((debugWaterRise ? 10 : randFloat(...waterIncreaseTime) * 60) * 1000, "RaiseWaterLevelStep", {}); + else + this.DebugLog("Water reached final level"); + + let actorTemplates = {}; + let killedTemplates = {}; + + let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); + let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); + + for (let ent of cmpRangeManager.GetGaiaAndNonGaiaEntities()) + { + let cmpPosition = Engine.QueryInterface(ent, IID_Position); + if (!cmpPosition || !cmpPosition.IsInWorld()) + continue; + + let pos = cmpPosition.GetPosition(); + if (pos.y + drownHeight >= newLevel) + continue; + + let cmpIdentity = Engine.QueryInterface(ent, IID_Identity); + if (!cmpIdentity) + continue; + + let templateName = cmpTemplateManager.GetCurrentTemplateName(ent); + + // Animals and units drown + let cmpHealth = Engine.QueryInterface(ent, IID_Health); + if (cmpHealth && cmpIdentity.HasClass(drownClass)) + { + cmpHealth.Kill(); + + if (debugLog) + killedTemplates[templateName] = (killedTemplates[templateName] || 0) + 1; + + continue; + } + + // Resources and buildings become actors + // Do not use ChangeEntityTemplate for performance and + // because we don't need nor want the effects of MT_EntityRenamed + + let cmpVisualActor = Engine.QueryInterface(ent, IID_Visual); + if (!cmpVisualActor) + continue; + + let height = cmpPosition.GetHeightOffset(); + let rot = cmpPosition.GetRotation(); + + let actorTemplate = cmpTemplateManager.GetTemplate(templateName).VisualActor.Actor; + let seed = cmpVisualActor.GetActorSeed(); + Engine.DestroyEntity(ent); + + let newEnt = Engine.AddEntity("actor|" + actorTemplate); + Engine.QueryInterface(newEnt, IID_Visual).SetActorSeed(seed); + + let cmpNewPos = Engine.QueryInterface(newEnt, IID_Position); + cmpNewPos.JumpTo(pos.x, pos.z); + cmpNewPos.SetHeightOffset(height); + cmpNewPos.SetXZRotation(rot.x, rot.z); + cmpNewPos.SetYRotation(rot.y); + + if (debugLog) + actorTemplates[templateName] = (actorTemplates[templateName] || 0) + 1; + } + + this.DebugLog("Checking entities took " + (cmpTimer.GetTime() - time)); + this.DebugLog("Killed: " + uneval(killedTemplates)); + this.DebugLog("Converted to actors: " + uneval(actorTemplates)); +}; + + +{ + let waterRiseTime = debugWaterRise ? 0 : randFloat(...waterRiseStartTime); + let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); + cmpTrigger.GarrisonWoodenTowers(); + cmpTrigger.DoAfterDelay((waterRiseTime - waterRiseNotificationDuration) * 60 * 1000, "RaisingWaterNotification", {}); + cmpTrigger.DoAfterDelay(waterRiseTime * 60 * 1000, "RaiseWaterLevelStep", {}); +} Index: binaries/data/mods/public/maps/random/rmgen/misc.js =================================================================== --- binaries/data/mods/public/maps/random/rmgen/misc.js +++ binaries/data/mods/public/maps/random/rmgen/misc.js @@ -802,3 +802,85 @@ } } } + +/** + * Generates a volcano mountain. Smoke and lava are optional. + * + * @param {number} fx - Horizontal coordinate of the center. + * @param {number} fz - Horizontal coordinate of the center. + * @param {number} tileClass - Painted onto every tile that is occupied by the volcano. + * @param {string} terrainTexture - The texture painted onto the volcano hill. + * @param {array} lavaTextures - Three different textures for the interior, from the outside to the inside. + * @param {boolean} smoke - Whether to place smoke particles. + * @param {number} elevationType - Elevation painter type, ELEVATION_SET = absolute or ELEVATION_MODIFY = relative. + */ +function createVolcano(fx, fz, tileClass, terrainTexture, lavaTextures, smoke, elevationType) +{ + log("Creating volcano"); + + let ix = Math.round(fractionToTiles(fx)); + let iz = Math.round(fractionToTiles(fz)); + + let baseSize = mapArea / scaleByMapSize(1, 8); + + let coherence = 0.7; + let smoothness = 0.05; + let failFraction = 100; + let steepness = 3; + + let clLava = createTileClass(); + + let layers = [ + { + "clumps": 0.067, + "elevation": 15, + "tileClass": tileClass + }, + { + "clumps": 0.05, + "elevation": 25, + "tileClass": createTileClass() + }, + { + "clumps": 0.02, + "elevation": 45, + "tileClass": createTileClass() + }, + { + "clumps": 0.011, + "elevation": 62, + "tileClass": createTileClass() + }, + { + "clumps": 0.003, + "elevation": 42, + "tileClass": clLava, + "painter": lavaTextures && new LayeredPainter([terrainTexture, ...lavaTextures], [1, 1, 1]), + "steepness": 1 + } + ]; + + for (let i = 0; i < layers.length; ++i) + createArea( + new ClumpPlacer(baseSize * layers[i].clumps, coherence, smoothness, failFraction, ix, iz), + [ + layers[i].painter || new LayeredPainter([terrainTexture, terrainTexture], [3]), + new SmoothElevationPainter(elevationType, layers[i].elevation, layers[i].steepness || steepness), + paintClass(layers[i].tileClass) + ], + i == 0 ? null : stayClasses(layers[i - 1].tileClass, 1)); + + if (smoke) + { + let num = Math.floor(baseSize * 0.002); + createObjectGroup( + new SimpleGroup( + [new SimpleObject("actor|particle/smoke.xml", num, num, 0, 7)], + false, + clLava, + ix, + iz), + 0, + stayClasses(tileClass, 1)); + } +} Index: binaries/data/mods/public/maps/random/volcanic_lands.js =================================================================== --- binaries/data/mods/public/maps/random/volcanic_lands.js +++ binaries/data/mods/public/maps/random/volcanic_lands.js @@ -20,7 +20,6 @@ // decorative props var aRockLarge = "actor|geology/stone_granite_med.xml"; var aRockMedium = "actor|geology/stone_granite_med.xml"; -var aSmoke = "actor|particle/smoke.xml"; var pForestD = [tGrassC + TERRAIN_SEPARATOR + oTree, tGrassC]; var pForestP = [tGrassB + TERRAIN_SEPARATOR + oTree, tGrassB]; @@ -35,9 +34,6 @@ // create tile classes var clPlayer = createTileClass(); var clHill = createTileClass(); -var clHill2 = createTileClass(); -var clHill3 = createTileClass(); -var clHill4 = createTileClass(); var clForest = createTileClass(); var clDirt = createTileClass(); var clRock = createTileClass(); @@ -134,96 +130,19 @@ break; } } - RMS.SetProgress(15); -log("Creating volcano"); -var fx = fractionToTiles(0.5); -var fz = fractionToTiles(0.5); -var ix = round(fx); -var iz = round(fz); -var div = scaleByMapSize(1,8); -var placer = new ClumpPlacer(mapArea * 0.067 / div, 0.7, 0.05, 100, ix, iz); -var terrainPainter = new LayeredPainter( - [tCliff, tCliff], // terrains - [3] // widths -); -var elevationPainter = new SmoothElevationPainter( - ELEVATION_SET, // type - 15, // elevation - 3 // blend radius -); -createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill)], null); - -var placer = new ClumpPlacer(mapArea * 0.05 / div, 0.7, 0.05, 100, ix, iz); -var terrainPainter = new LayeredPainter( - [tCliff, tCliff], // terrains - [3] // widths -); -var elevationPainter = new SmoothElevationPainter( - ELEVATION_SET, // type - 25, // elevation - 3 // blend radius -); -createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill2)], stayClasses(clHill, 1)); - -var placer = new ClumpPlacer(mapArea * 0.02 / div, 0.7, 0.05, 100, ix, iz); -var terrainPainter = new LayeredPainter( - [tCliff, tCliff], // terrains - [3] // widths -); -var elevationPainter = new SmoothElevationPainter( - ELEVATION_SET, // type - 45, // elevation - 3 // blend radius -); -createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill3)], stayClasses(clHill2, 1)); - -var placer = new ClumpPlacer(mapArea * 0.011 / div, 0.7, 0.05, 100, ix, iz); -var terrainPainter = new LayeredPainter( - [tCliff, tCliff], // terrains - [3] // widths -); -var elevationPainter = new SmoothElevationPainter( - ELEVATION_SET, // type - 62, // elevation - 3 // blend radius -); -createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill4)], stayClasses(clHill3, 1)); - -var placer = new ClumpPlacer(mapArea * 0.003 / div, 0.7, 0.05, 100, ix, iz); -var terrainPainter = new LayeredPainter( - [tCliff, tLava1, tLava2, tLava3], // terrains - [1, 1, 1] // widths -); -var elevationPainter = new SmoothElevationPainter( - ELEVATION_SET, // type - 42, // elevation - 1 // blend radius -); -createArea(placer, [terrainPainter, elevationPainter, paintClass(clHill4)], stayClasses(clHill4, 1)); - -var num = floor(mapArea * 0.03 / 15 / div); -var tX = round(fx); -var tZ = round(fz); -var group = new SimpleGroup( - [new SimpleObject(aSmoke, num, num, 0,7)], - false, clBaseResource, tX, tZ -); -createObjectGroup(group, 0, stayClasses(clHill4,1)); - +createVolcano(0.5, 0.5, clHill, tCliff, [tLava1, tLava2, tLava3], true, ELEVATION_SET); RMS.SetProgress(45); log("Creating hills..."); -placer = new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, 1); -terrainPainter = new LayeredPainter( - [tCliff, tGrass], // terrains - [2] // widths -); -elevationPainter = new SmoothElevationPainter(ELEVATION_SET, 18, 2); createAreas( - placer, - [terrainPainter, elevationPainter, paintClass(clHill)], + new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, 1), + [ + new LayeredPainter([tCliff, tGrass], [2]), + new SmoothElevationPainter(ELEVATION_SET, 18, 2), + paintClass(clHill) + ], avoidClasses(clPlayer, 12, clHill, 15, clBaseResource, 2), scaleByMapSize(2, 8) * numPlayers ); Index: source/simulation2/components/CCmpRangeManager.cpp =================================================================== --- source/simulation2/components/CCmpRangeManager.cpp +++ source/simulation2/components/CCmpRangeManager.cpp @@ -1053,6 +1053,11 @@ return GetEntitiesByMask(~3); // bit 0 for owner=-1 and bit 1 for gaia } + virtual std::vector GetGaiaAndNonGaiaEntities() const + { + return GetEntitiesByMask(~1); // bit 0 for owner=-1 + } + std::vector GetEntitiesByMask(u32 ownerMask) const { std::vector entities; Index: source/simulation2/components/ICmpRangeManager.h =================================================================== --- source/simulation2/components/ICmpRangeManager.h +++ source/simulation2/components/ICmpRangeManager.h @@ -199,6 +199,11 @@ virtual std::vector GetNonGaiaEntities() const = 0; /** + * Returns a list of all entities owned by players or gaia. + */ + virtual std::vector GetGaiaAndNonGaiaEntities() const = 0; + + /** * Toggle the rendering of debug info. */ virtual void SetDebugOverlay(bool enabled) = 0; Index: source/simulation2/components/ICmpRangeManager.cpp =================================================================== --- source/simulation2/components/ICmpRangeManager.cpp +++ source/simulation2/components/ICmpRangeManager.cpp @@ -47,6 +47,7 @@ DEFINE_INTERFACE_METHOD_CONST_1("GetEntityFlagMask", u8, ICmpRangeManager, GetEntityFlagMask, std::string) DEFINE_INTERFACE_METHOD_CONST_1("GetEntitiesByPlayer", std::vector, ICmpRangeManager, GetEntitiesByPlayer, player_id_t) DEFINE_INTERFACE_METHOD_CONST_0("GetNonGaiaEntities", std::vector, ICmpRangeManager, GetNonGaiaEntities) +DEFINE_INTERFACE_METHOD_CONST_0("GetGaiaAndNonGaiaEntities", std::vector, ICmpRangeManager, GetGaiaAndNonGaiaEntities) DEFINE_INTERFACE_METHOD_1("SetDebugOverlay", void, ICmpRangeManager, SetDebugOverlay, bool) DEFINE_INTERFACE_METHOD_1("ExploreAllTiles", void, ICmpRangeManager, ExploreAllTiles, player_id_t) DEFINE_INTERFACE_METHOD_0("ExploreTerritories", void, ICmpRangeManager, ExploreTerritories)