Index: binaries/data/mods/public/maps/random/extinct_volcano.js =================================================================== --- /dev/null +++ binaries/data/mods/public/maps/random/extinct_volcano.js @@ -0,0 +1,424 @@ +//ungatherable trees, initial trees stuck too +//zoom restriction +//lakes too small +//countdown timer for water + +// little actor stones +// volcano dust cloud +// bush_temple_underbrush +// grass_field_flowering_tall +// plant_tropic_large +// pond_lillies_large +// reeds_pond_lush_b +// shrub_spikes +// shrub_tropic_plant_flower +/* +tons of lag when rising the water the first time, fix by greater tree min dist +Cc hills might be higher +giant maps never ever load +paint terrain based on height +keep ways for ships to travel between players +mines should be rather on hills +few supermountains? +*/ + + +RMS.LoadLibrary("rmgen"); + +const tHillDark = "cliff volcanic light"; +const tCliff = tHillDark; +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; //"temp_forestfloor_a"; +const tForestFloor2 = tHillMedium2; //"temp_grass"; +const tGrass3 = "temp_grass_plants"; +const tGrassPatchBlend = "temp_grass_long_b"; +const tGrassPatch = ["temp_grass_d", "temp_grass_clovers"]; +const tLava1 = "cliff volcanic light"; // TODO: +const tLava2 = "cliff volcanic light"; +const tLava3 = "cliff volcanic light"; +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 oDeer = "gaia/fauna_deer"; +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"; + +// 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]; + +const pForestM = [ + tForestFloor1 + TERRAIN_SEPARATOR + oTree, + tForestFloor2 + TERRAIN_SEPARATOR + oTree2, + tForestFloor2 + TERRAIN_SEPARATOR + oTree3, + tForestFloor1 + TERRAIN_SEPARATOR + oTree4, + tForestFloor1]; + +log("Initializing map..."); +InitMap(); + +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(); + +// randomize player order +var playerIDs = []; +for (var i = 0; i < numPlayers; i++) + playerIDs.push(i+1); +playerIDs = sortPlayers(playerIDs); + +// place players +var playerX = new Array(numPlayers); +var playerZ = new Array(numPlayers); +var playerAngle = new Array(numPlayers); + +var startAngle = randFloat(0, TWO_PI); +for (var i = 0; i < numPlayers; i++) +{ + playerAngle[i] = startAngle + i*TWO_PI/numPlayers; + playerX[i] = 0.5 + 0.35*cos(playerAngle[i]); + playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]); +} + +var ccMountainHeight = 25; + +for (var i = 0; i < numPlayers; i++) +{ + var id = playerIDs[i]; + log("Creating base for player " + id + "..."); + + var radius = scaleByMapSize(15,25); + + // get the x and z in tiles + var fx = fractionToTiles(playerX[i]); + var fz = fractionToTiles(playerZ[i]); + var ix = round(fx); + var iz = 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 + var 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 + var cityRadius = radius/3; + var placer = new ClumpPlacer(PI*cityRadius*cityRadius, 0.6, 0.3, 10, ix, iz); + var painter = new LayeredPainter([tRoadWild, tRoad], [1]); + createArea(placer, painter, null); + + placeCivDefaultEntities(fx, fz, id, { 'iberWall': 'towers' }); + + // create metal mine + var bbAngle = randFloat(0, TWO_PI); + var bbDist = 10; + var mAngle = bbAngle; + while(abs(mAngle - bbAngle) < PI/3) + mAngle = randFloat(0, TWO_PI); + + var mDist = 12; + var mX = round(fx + mDist * cos(mAngle)); + var mZ = round(fz + mDist * sin(mAngle)); + var group = new SimpleGroup( + [new SimpleObject(oMetalLarge, 1,1, 0,0)], + true, clBaseResource, mX, mZ + ); + createObjectGroup(group, 0); + + // create stone mines + mAngle += randFloat(PI/4, PI/3); + mX = round(fx + mDist * cos(mAngle)); + mZ = round(fz + mDist * sin(mAngle)); + group = new SimpleGroup( + [new SimpleObject(oStoneLarge, 1,1, 0,2)], + true, clBaseResource, mX, mZ + ); + createObjectGroup(group, 0); + + placeDefaultChicken(fx, fz, clBaseResource); + + // create berry bushes + mAngle += randFloat(PI/4, PI/2); + var bbDist = 12; + var bbX = round(fx + bbDist * Math.cos(mAngle)); + var bbZ = round(fz + bbDist * Math.sin(mAngle)); + createObjectGroup( + new SimpleGroup( + [new SimpleObject(oFruitBush, 5, 5, 0, 3)], + true, clBaseResource, bbX, bbZ), + 0); + + // create starting trees + var num = Math.floor(hillSize / 60); + var tries = 10; + for (var x = 0; x < tries; ++x) + { + var tAngle = mAngle + randFloat(PI/3, PI/4); + var tDist = randFloat(10, 12); + var tX = round(fx + tDist * cos(tAngle)); + var tZ = round(fz + tDist * sin(tAngle)); + group = new SimpleGroup( + [new SimpleObject(oTree2, num, num, 0, 3)], + false, clBaseResource, tX, tZ + ); + if (createObjectGroup(group, 0, avoidClasses(clBaseResource, 2))) + break; + } +} +RMS.SetProgress(15); + +createVolcano(0.5, 0.5, clHill, tHillVeryDark, ELEVATION_SET, false); +RMS.SetProgress(45); + +log("Creating lakes..."); +createAreas( + new ChainPlacer(1, Math.floor(scaleByMapSize(5, 7)), Math.floor(scaleByMapSize(15, 20)), 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(4, 12)) +); + +createBumps(avoidClasses(clPlayer, 0, clHill, 0), scaleByMapSize(50, 300), 1, 10, 3, 0, 8, 500); +paintTileClassBasedOnHeight(10, 100, 0, clBumps); + +log("Creating hills..."); +createAreas( + new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, 1), + [ + new LayeredPainter([tHillDark, tHillMedium1, tHillMedium1], [2, 2]), + new SmoothElevationPainter(ELEVATION_SET, 18, 2), + paintClass(clHill) + ], + avoidClasses(clPlayer, 0, clHill, 15, clWater, 2, clBaseResource, 2), + scaleByMapSize(2, 8) * numPlayers +); + +log("Creating forests..."); +var MIN_TREES = 800; +var MAX_TREES = 2000; +var P_FOREST = 0.7; + +var totalTrees = scaleByMapSize(MIN_TREES, MAX_TREES); +var numForest = totalTrees * P_FOREST; +var numStragglers = totalTrees * (1.0 - P_FOREST); +var tGrass = ["cliff volcanic light", "ocean_rock_a", "ocean_rock_b"]; +var tGrassA = "cliff volcanic light"; +var tGrassB = "ocean_rock_a"; + +log("Creating forests..."); +var types = [ + [[tGrassB, tGrassA, pForestD], [tGrassB, pForestD]], + [[tGrassB, tGrassA, pForestP], [tGrassB, pForestP]] +]; + +var size = numForest / (scaleByMapSize(2,8) * numPlayers); +var num = floor(size / types.length); +for (var 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, 12, clForest, 10, clHill, 0), + num + ); +RMS.SetProgress(45); + +log("Creating hill patches..."); +for (let size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) + for (let type of [[tHillMedium1, tHillDark], [tHillDark, tHillVeryDark], [tHillMedium1, tHillVeryDark]]) + 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) + ); + +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) +); + +log("Creating stone mines..."); +group = new SimpleGroup([new SimpleObject(oStoneSmall, 0,2, 0,4), new SimpleObject(oStoneLarge, 1,1, 0,4)], true, clRock); +createObjectGroups(group, 0, + [stayClasses(clBumps, 1), avoidClasses(clWater, 3, clForest, 1, clPlayer, 0, clRock, 10, clHill, 4)], + scaleByMapSize(4,16), 100 +); + +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, 10, clHill, 4)], + scaleByMapSize(4,16), 100 +); + +log("Creating metal mines..."); +group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); +createObjectGroups(group, 0, + [stayClasses(clBumps, 1), avoidClasses(clWater, 3, clForest, 1, clPlayer, 0, clMetal, 10, clRock, 5, clHill, 4)], + scaleByMapSize(4,16), 100 +); +RMS.SetProgress(90); + +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)] + ); + +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) + ); + +createFood( + [ + [new SimpleObject(oRabbit, 5,7, 0,4)], + [new SimpleObject(oDeer, 2,3, 0,2)] + ], + [ + 3 * numPlayers, + 3 * numPlayers + ], + [avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 1, clFood, 20)] +); + +createFood( + [ + [new SimpleObject(oBear, 1,1, 0,2)], + ], + [ + 3 * numPlayers + ], + [avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 1, clFood, 20), stayClasses(clForest, 2)] +); + +createFood( + [ + [new SimpleObject(oFruitBush, 1,2, 0,4)] + ], + [ + 3 * numPlayers + ], + [stayClasses(clGrass, 1), avoidClasses(clWater, 1, clForest, 0, clPlayer, 0, clHill, 1, clFood, 10)] +); +RMS.SetProgress(95); + +log("Creating straggler trees and bushes..."); +var types = [oTree, oTree2, oTree3, oTree4, oBush]; +var num = 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 + ); + +log("Creating straggler bushes..."); +var types = [oBush]; +var num = floor(numStragglers / types.length); +for (let type of types) + createObjectGroups( + new SimpleGroup( + [new SimpleObject(type, 1,3, 0,3)], + true, clForest + ), + 0, + [avoidClasses(clWater, 1, clForest, 1, clPlayer, 0, clMetal, 1, clRock, 1), stayClasses(clGrass, 3)], + num + ); + +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,16 @@ +{ + "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 period. 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.", + "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,163 @@ +var debugLog = true; + +var debugWaterRise = false; + +/** + * Time in minutes when the players will be notified that the water level will rise. + */ +var waterRiseNotificationTime = [20, 22]; + +/** + * Time in minutes when the water level starts to rise. + * Allow players to build up the economy and military for some time. + */ +var waterRiseStartTime = [23, 26]; + +/** + * Time in minutes determining how often to increase 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 60 CC should be destroyed. + * + * Notice regular and military docks will raise with the water! + */ +var waterIncreaseTime = [1.5, 2]; + +/** + * How much height to increase 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; + +Trigger.prototype.RaisingWaterNotification = function() +{ + Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface).AddTimeNotification({ + "message": markForTranslation("The water keeps rising, we have to evacuate soon!"), + "translateMessage": true + }); +}; + +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.RaiseWaterLevelStep = function() +{ + let time = new Date().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 " + (new Date().getTime() - time)); + + time = new Date().getTime(); + let debugTemplates = {}; + let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); + for (let ent of Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).GetEntitiesByPlayer(0)) + { + let cmpPos = Engine.QueryInterface(ent, IID_Position); + if (!cmpPos || !cmpPos.IsInWorld() || cmpPos.GetPosition().y >= newLevel) + continue; + + let templateName = cmpTemplateManager.GetCurrentTemplateName(ent); + if (!templateName) + return false; + + let cmpVisualActor = Engine.QueryInterface(ent, IID_Visual); + if (!cmpVisualActor) + continue; + + let cmpIdentity = Engine.QueryInterface(ent, IID_Identity); + if (!cmpIdentity) + continue; + + // Animals drown + let cmpHealth = Engine.QueryInterface(ent, IID_Health); + if (cmpHealth && cmpIdentity.HasClass("Unit")) + { + cmpHealth.Kill(); + continue; + } + + // Resources become actors + // Do not use ChangeEntityTemplate for performance and + // because we don't need nor want the effects of MT_EntityRenamed + // For example not having the new (unselectable) entity selected + + let pos = cmpPos.GetPosition2D(); + let height = cmpPos.GetHeightOffset(); + let rot = cmpPos.GetRotation(); + let template = cmpTemplateManager.GetTemplate(templateName); + let actorTemplate = template.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.y); + cmpNewPos.SetHeightOffset(height); + cmpNewPos.SetXZRotation(rot.x, rot.z); + cmpNewPos.SetYRotation(rot.y); + + debugTemplates[actorTemplate] = (debugTemplates[actorTemplate] || 0) + 1; + } + + this.debugLog("Changing gaia entities to actors took " + (new Date().getTime() - time)); + this.debugLog("Changed the following entities: " + uneval(debugTemplates)); + + // Destroy all player entities below the water + // Men only once they are fully submerged (because they don't drown when their ankles get wet) + debugTemplates = {}; + time = new Date().getTime(); + for (let ent of Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).GetNonGaiaEntities()) + { + let cmpPos = Engine.QueryInterface(ent, IID_Position); + if (!cmpPos || !cmpPos.IsInWorld() || cmpPos.GetPosition().y >= newLevel) + continue; + + let templateName = cmpTemplateManager.GetCurrentTemplateName(ent); + debugTemplates[templateName] = (debugTemplates[templateName] || 0) + 1; + + // TODO: make buildings actors instead of deleting them + + let cmpHealth = Engine.QueryInterface(ent, IID_Health); + if (cmpHealth) + cmpHealth.Kill(); + else + Engine.DestroyEntity(ent); + } + + this.debugLog("Checking player entities took " + (new Date().getTime() - time)); + this.debugLog("Destroyed the following player entities: " + uneval(debugTemplates)); + + if (newLevel > maxWaterLevel) + return; + + this.DoAfterDelay((debugWaterRise ? 10 : randFloat(...waterIncreaseTime) * 60) * 1000, "RaiseWaterLevelStep", {}); +}; + + +{ + let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger); + cmpTrigger.DoAfterDelay(randFloat(...waterRiseNotificationTime) * 60 * 1000, "RaisingWaterNotification", {}); + cmpTrigger.DoAfterDelay(debugWaterRise ? 0 : randFloat(...waterRiseStartTime) * 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 @@ -804,3 +804,80 @@ } } } + +/** + * @param {number} x - horizontal coordinate + * @param {number} z - other horizontal coordinate + * @param {number} tileClass - which class to paint + * @param {number} elevationType - Elevation painter type, ELEVATION_SET = absolute or ELEVATION_MODIFY = relative + */ +function createVolcano(fx = 0.5, fz = 0.5, tileClass = clHill, terrainTexture = tCliff, elevationType = ELEVATION_SET, smoke = true) +{ + 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 clLast = createTileClass(); + + let layerSizes = [ + { + "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": clLast + } + ]; + + for (let i = 0; i < layerSizes.length; ++i) + createArea( + new ClumpPlacer(baseSize * layerSizes[i].clumps, coherence, smoothness, failFraction, ix, iz), + [ + new LayeredPainter([terrainTexture, terrainTexture], [3]), + new SmoothElevationPainter(elevationType, layerSizes[i].elevation, steepness), + paintClass(layerSizes[i].tileClass) + ], + i == 0 ? null : stayClasses(layerSizes[i - 1].tileClass, 1)); + + // lava + createArea( + new ClumpPlacer(baseSize * 0.003, coherence, smoothness, failFraction, ix, iz), + [ + new LayeredPainter([terrainTexture, tLava1, tLava2, tLava3], [1, 1, 1]), + new SmoothElevationPainter(elevationType, 42, 1), + paintClass(clLast) + ], + stayClasses(clLast, 1)); + + if (!smoke) + return; + + let num = Math.floor(baseSize * 0.002); + createObjectGroup( + new SimpleGroup( + [new SimpleObject("actor|particle/smoke.xml", num, num, 0, 7)], + false, createTileClass(), Math.round(fx), Math.round(fz) + ), + 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(); 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 );