Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/maps/random/alpine_valley.js
Engine.LoadLibrary("rmgen"); | Engine.LoadLibrary("rmgen"); | ||||
Engine.LoadLibrary("rmgen-common"); | Engine.LoadLibrary("rmgen-common"); | ||||
Engine.LoadLibrary("heightmap"); | |||||
TILE_CENTERED_HEIGHT_MAP = true; | TILE_CENTERED_HEIGHT_MAP = true; | ||||
/** | var tPrimary = ["new_alpine_grass_a", "new_alpine_grass_mossy"]; | ||||
* This class creates random mountainranges without enclosing any area completely. | var tSecondary = ["alpine_snow_a", "alpine_snow_b"]; | ||||
* | var tForestFloor = "alpine_forrestfloor"; | ||||
* To determine their location, a graph is created where each vertex is a possible starting or | var tSnowyForestFloor = "alpine_cliff_snow"; | ||||
* ending location of a mountainrange and each edge a possible mountainrange. | var tCliff = ["alpine_cliff", "alpine_mountainside"]; | ||||
* | var tRoughSnow = ["polar_snow_a"]; | ||||
* That graph starts nearly complete (i.e almost every vertex is connected to most other vertices). | var tSnowLine = ["path a"]; | ||||
* After a random edge was chosen and placed as a mountainrange, | var tSnowLineTrans = ["polar_snow_glacial", "alpine_snow_b", "alpine_snow_a"]; | ||||
* all edges that intersect, that leave a too small gap to another mountainrange or that are connected to | var tSnowCaps = ["polar_snow_glacial"]; | ||||
* too many other mountainranges are removed from the graph. | var tFarmland = "temp_farmland"; | ||||
* This is repeated until all edges were removed. | var tRoad = "temp_road_broken"; | ||||
*/ | var tRoadWild = "new_alpine_grass_a"; | ||||
function MountainRangeBuilder(args) | var tLakeBed = "alpine_shore_rocks"; | ||||
{ | var tShore = "alpine_shore_rocks_icy"; | ||||
/** | |||||
* These parameters paint the mountainranges after their location was determined. | |||||
*/ | |||||
this.pathplacer = args.pathplacer; | |||||
this.painters = args.painters; | |||||
this.constraint = args.constraint; | |||||
this.mountainWidth = args.mountainWidth; | |||||
/** | var oPine = "gaia/flora_tree_pine"; | ||||
* Minimum geometric distance between two mountains that don't end in one place (disjoint edges). | var oAleppoPine = "gaia/flora_tree_aleppo_pine" | ||||
*/ | var oWinterPine = "gaia/flora_tree_pine_w"; | ||||
this.minDistance = args.mountainWidth + args.passageWidth; | var oBerryBush = "gaia/flora_bush_berry"; | ||||
var oSheep = "gaia/fauna_sheep"; | |||||
var oDeer = "gaia/fauna_deer"; | |||||
var oRabbit = "gaia/fauna_rabbit"; | |||||
var oBear = "gaia/fauna_bear" | |||||
var oFish = "gaia/fauna_fish"; | |||||
var oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; | |||||
var oStoneSmall = "gaia/geology_stone_alpine_a"; | |||||
var oMetalLarge = "gaia/geology_metal_alpine_slabs"; | |||||
/** | var aGrass = "actor|props/flora/grass_soft_small_tall.xml"; | ||||
* Array of Vector2D locations where a mountainrange can start or end. | var aGrassShort = "actor|props/flora/grass_soft_large.xml"; | ||||
*/ | var aRockLarge = "actor|geology/stone_granite_med.xml"; | ||||
this.vertices = args.points; | var aRockMedium = "actor|geology/stone_granite_med.xml"; | ||||
var aBushMedium = "actor|props/flora/bush_medit_me.xml"; | |||||
var aBushSmall = "actor|props/flora/bush_medit_sm.xml"; | |||||
/** | |||||
* Number of mountainranges starting or ending at the given point. | |||||
*/ | |||||
this.vertexDegree = this.vertices.map(p => 0); | |||||
/** | |||||
* Highest number of mountainranges that can meet in one point (maximum degree of each vertex). | |||||
*/ | |||||
this.maxDegree = args.maxDegree; | |||||
/** | |||||
* Each possible edge is an array containing two vertex indices. | |||||
* The algorithm adds possible edges consecutively and removes subsequently invalid edges. | |||||
*/ | |||||
this.possibleEdges = []; | |||||
this.InitPossibleEdges(); | |||||
/** | |||||
* A two-dimensional array of booleans that are true if the two corresponding vertices may be connected by a new edge (mountainrange). | |||||
* It is initialized with some points that should never be connected and updated with every placed edge. | |||||
* The purpose is to rule out any cycles in the graph, i.e. prevent any territory enclosed by mountainranges. | |||||
*/ | |||||
this.verticesConnectable = []; | |||||
this.InitConnectable(); | |||||
/** | |||||
* Currently iterated item of possibleEdges that is either used as a mountainrange or removed from the possibleEdges. | |||||
*/ | |||||
this.index = undefined; | |||||
/** | |||||
* These variables hold the indices of the two points of that edge and the location of them as a Vector2D. | |||||
*/ | |||||
this.currentEdge = undefined; | |||||
this.currentEdgeStart = undefined; | |||||
this.currentEdgeEnd = undefined; | |||||
} | |||||
MountainRangeBuilder.prototype.InitPossibleEdges = function() | |||||
{ | |||||
for (let i = 0; i < this.vertices.length; ++i) | |||||
for (let j = numPlayers; j < this.vertices.length; ++j) | |||||
if (j > i) | |||||
this.possibleEdges.push([i, j]); | |||||
}; | |||||
MountainRangeBuilder.prototype.InitConnectable = function() | |||||
{ | |||||
for (let i = 0; i < this.vertices.length; ++i) | |||||
{ | |||||
this.verticesConnectable[i] = []; | |||||
for (let j = 0; j < this.vertices.length; ++j) | |||||
this.verticesConnectable[i][j] = i >= numPlayers || j >= numPlayers || i == j || i != j - 1 && i != j + 1; | |||||
} | |||||
}; | |||||
MountainRangeBuilder.prototype.SetConnectable = function(isConnectable) | |||||
{ | |||||
this.verticesConnectable[this.currentEdge[0]][this.currentEdge[1]] = isConnectable; | |||||
this.verticesConnectable[this.currentEdge[1]][this.currentEdge[0]] = isConnectable; | |||||
}; | |||||
MountainRangeBuilder.prototype.UpdateCurrentEdge = function() | |||||
{ | |||||
this.currentEdge = this.possibleEdges[this.index]; | |||||
this.currentEdgeStart = this.vertices[this.currentEdge[0]]; | |||||
this.currentEdgeEnd = this.vertices[this.currentEdge[1]]; | |||||
}; | |||||
/** | |||||
* Remove all edges that are too close to the current mountainrange or intersect. | |||||
*/ | |||||
MountainRangeBuilder.prototype.RemoveInvalidEdges = function() | |||||
{ | |||||
for (let i = 0; i < this.possibleEdges.length; ++i) | |||||
{ | |||||
this.UpdateCurrentEdge(); | |||||
let comparedEdge = this.possibleEdges[i]; | |||||
let comparedEdgeStart = this.vertices[comparedEdge[0]]; | |||||
let comparedEdgeEnd = this.vertices[comparedEdge[1]]; | |||||
let edge0Equal = this.currentEdgeStart == comparedEdgeStart; | |||||
let edge1Equal = this.currentEdgeStart == comparedEdgeEnd; | |||||
let edge2Equal = this.currentEdgeEnd == comparedEdgeEnd; | |||||
let edge3Equal = this.currentEdgeEnd == comparedEdgeStart; | |||||
if (!edge0Equal && !edge2Equal && !edge1Equal && !edge3Equal && testLineIntersection(this.currentEdgeStart, this.currentEdgeEnd, comparedEdgeStart, comparedEdgeEnd, this.minDistance) || | |||||
( edge0Equal && !edge2Equal || !edge1Equal && edge3Equal) && distanceOfPointFromLine(this.currentEdgeStart, this.currentEdgeEnd, comparedEdgeEnd) < this.minDistance || | |||||
(!edge0Equal && edge2Equal || edge1Equal && !edge3Equal) && distanceOfPointFromLine(this.currentEdgeStart, this.currentEdgeEnd, comparedEdgeStart) < this.minDistance) | |||||
{ | |||||
this.possibleEdges.splice(i, 1); | |||||
--i; | |||||
if (this.index > i) | |||||
--this.index; | |||||
} | |||||
} | |||||
}; | |||||
/** | |||||
* Tests using depth-first-search if the graph according to pointsConnectable contains a cycle, | |||||
* i.e. if adding the currentEdge would result in an area enclosed by mountainranges. | |||||
*/ | |||||
MountainRangeBuilder.prototype.HasCycles = function() | |||||
{ | |||||
let tree = []; | |||||
let backtree = []; | |||||
let pointQueue = [this.currentEdge[0]]; | |||||
while (pointQueue.length) | |||||
{ | |||||
let selectedPoint = pointQueue.shift(); | |||||
if (tree.indexOf(selectedPoint) == -1) | |||||
{ | |||||
tree.push(selectedPoint); | |||||
backtree.push(-1); | |||||
} | |||||
for (let i = 0; i < this.vertices.length; ++i) | |||||
{ | |||||
if (this.verticesConnectable[selectedPoint][i] || i == backtree[tree.lastIndexOf(selectedPoint)]) | |||||
continue; | |||||
// If the current point was encountered already, then a cycle was identified. | |||||
if (tree.indexOf(i) != -1) | |||||
return true; | |||||
// Otherwise visit this point next | |||||
pointQueue.unshift(i); | |||||
tree.push(i); | |||||
backtree.push(selectedPoint); | |||||
} | |||||
} | |||||
return false; | |||||
}; | |||||
MountainRangeBuilder.prototype.PaintCurrentEdge = function() | |||||
{ | |||||
this.pathplacer.start = this.currentEdgeStart; | |||||
this.pathplacer.end = this.currentEdgeEnd; | |||||
this.pathplacer.width = this.mountainWidth; | |||||
// Creating mountainrange | |||||
if (!createArea(this.pathplacer, this.painters, this.constraint)) | |||||
return false; | |||||
// Creating circular mountains at both ends of that mountainrange | |||||
for (let point of [this.currentEdgeStart, this.currentEdgeEnd]) | |||||
createArea( | |||||
new ClumpPlacer(diskArea(this.mountainWidth / 2), 0.95, 0.6, Infinity, point), | |||||
this.painters, | |||||
this.constraint); | |||||
return true; | |||||
}; | |||||
/** | |||||
* This is the only function meant to be publicly accessible. | |||||
*/ | |||||
MountainRangeBuilder.prototype.CreateMountainRanges = function() | |||||
{ | |||||
g_Map.log("Creating mountainrange with " + this.possibleEdges.length + " possible edges"); | |||||
let max = this.possibleEdges.length | |||||
while (this.possibleEdges.length) | |||||
{ | |||||
Engine.SetProgress(35 - 15 * this.possibleEdges.length / max); | |||||
this.index = randIntExclusive(0, this.possibleEdges.length); | |||||
this.UpdateCurrentEdge(); | |||||
this.SetConnectable(false); | |||||
if (this.vertexDegree[this.currentEdge[0]] < this.maxDegree && | |||||
this.vertexDegree[this.currentEdge[1]] < this.maxDegree && | |||||
!this.HasCycles() && | |||||
this.PaintCurrentEdge()) | |||||
{ | |||||
++this.vertexDegree[this.currentEdge[0]]; | |||||
++this.vertexDegree[this.currentEdge[1]]; | |||||
this.RemoveInvalidEdges(); | |||||
} | |||||
else | |||||
this.SetConnectable(true); | |||||
this.possibleEdges.splice(this.index, 1); | |||||
} | |||||
}; | |||||
if (randBool()) | |||||
{ | |||||
RandomMapLogger.prototype.printDirectly("Setting late spring biome.\n"); | |||||
var tPrimary = ["alpine_dirt_grass_50"]; | |||||
var tForestFloor = "alpine_forrestfloor"; | |||||
var tCliff = ["alpine_cliff_a", "alpine_cliff_b", "alpine_cliff_c"]; | |||||
var tSecondary = "alpine_grass_rocky"; | |||||
var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; | |||||
var tSnowLimited = ["alpine_snow_rocky"]; | |||||
var tDirt = "alpine_dirt"; | |||||
var tRoad = "new_alpine_citytile"; | |||||
var tRoadWild = "new_alpine_citytile"; | |||||
var oPine = "gaia/flora_tree_pine"; | |||||
var oBerryBush = "gaia/flora_bush_berry"; | |||||
var oDeer = "gaia/fauna_deer"; | |||||
var oRabbit = "gaia/fauna_rabbit"; | |||||
var oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; | |||||
var oStoneSmall = "gaia/geology_stone_alpine_a"; | |||||
var oMetalLarge = "gaia/geology_metal_alpine_slabs"; | |||||
var aGrass = "actor|props/flora/grass_soft_small_tall.xml"; | |||||
var aGrassShort = "actor|props/flora/grass_soft_large.xml"; | |||||
var aRockLarge = "actor|geology/stone_granite_med.xml"; | |||||
var aRockMedium = "actor|geology/stone_granite_med.xml"; | |||||
var aBushMedium = "actor|props/flora/bush_medit_me.xml"; | |||||
var aBushSmall = "actor|props/flora/bush_medit_sm.xml"; | |||||
} | |||||
else | |||||
{ | |||||
RandomMapLogger.prototype.printDirectly("Setting winter biome.\n"); | |||||
var tPrimary = ["alpine_snow_a", "alpine_snow_b"]; | |||||
var tForestFloor = "alpine_forrestfloor_snow"; | |||||
var tCliff = ["alpine_cliff_snow"]; | |||||
var tSecondary = "alpine_grass_snow_50"; | |||||
var tHalfSnow = ["alpine_grass_snow_50", "alpine_dirt_snow"]; | |||||
var tSnowLimited = ["alpine_snow_a", "alpine_snow_b"]; | |||||
var tDirt = "alpine_dirt"; | |||||
var tRoad = "new_alpine_citytile"; | |||||
var tRoadWild = "new_alpine_citytile"; | |||||
var oPine = "gaia/flora_tree_pine_w"; | |||||
var oBerryBush = "gaia/flora_bush_berry"; | |||||
var oDeer = "gaia/fauna_deer"; | |||||
var oRabbit = "gaia/fauna_rabbit"; | |||||
var oStoneLarge = "gaia/geology_stonemine_alpine_quarry"; | |||||
var oStoneSmall = "gaia/geology_stone_alpine_a"; | |||||
var oMetalLarge = "gaia/geology_metal_alpine_slabs"; | |||||
var aGrass = "actor|props/flora/grass_soft_dry_small_tall.xml"; | |||||
var aGrassShort = "actor|props/flora/grass_soft_dry_large.xml"; | |||||
var aRockLarge = "actor|geology/stone_granite_med.xml"; | |||||
var aRockMedium = "actor|geology/stone_granite_med.xml"; | |||||
var aBushMedium = "actor|props/flora/bush_medit_me_dry.xml"; | |||||
var aBushSmall = "actor|props/flora/bush_medit_sm_dry.xml"; | |||||
} | |||||
var heightLand = 3; | var heightLand = 3; | ||||
var heightOffsetBump = 2; | var heightLake = -5; | ||||
var snowlineHeight = 29; | var heightOffsetBump = scaleByMapSize(10, 75); | ||||
var heightMountain = 30; | var heightMountain = scaleByMapSize(60, 120); | ||||
var snowlineHeight = heightMountain * 0.6; | |||||
const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; | const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPine, tForestFloor]; | ||||
const pForestSnow = [tForestFloor + TERRAIN_SEPARATOR + oWinterPine, tSnowyForestFloor]; | |||||
var g_Map = new RandomMap(heightLand, tPrimary); | var g_Map = new RandomMap(heightLand, tPrimary); | ||||
Context not available. | |||||
const mapCenter = g_Map.getCenter(); | const mapCenter = g_Map.getCenter(); | ||||
var clPlayer = g_Map.createTileClass(); | var clPlayer = g_Map.createTileClass(); | ||||
var clGrass = g_Map.createTileClass(); | |||||
var clFarm = g_Map.createTileClass(); | |||||
var clHill = g_Map.createTileClass(); | var clHill = g_Map.createTileClass(); | ||||
var clWater = g_Map.createTileClass(); | |||||
var clForest = g_Map.createTileClass(); | var clForest = g_Map.createTileClass(); | ||||
var clDirt = g_Map.createTileClass(); | var clSnow = g_Map.createTileClass(); | ||||
var clRoughSnow = g_Map.createTileClass(); | |||||
var clRock = g_Map.createTileClass(); | var clRock = g_Map.createTileClass(); | ||||
var clMetal = g_Map.createTileClass(); | var clMetal = g_Map.createTileClass(); | ||||
var clFood = g_Map.createTileClass(); | var clFood = g_Map.createTileClass(); | ||||
var clBaseResource = g_Map.createTileClass(); | var clBaseResource = g_Map.createTileClass(); | ||||
paintTileClassBasedOnHeight(0, Infinity, 0, clGrass); | |||||
// Setup environment settings | |||||
g_Map.log("Configuring environment settings"); | |||||
setWaterType("clap"); | |||||
setWaterColor(0.713726, 0.854902, 0.803922); | |||||
setWaterTint(0.913725, 0.976471, 0.996078); | |||||
setWaterWaviness(3.29102); | |||||
setWaterMurkiness(0.674805); | |||||
setPPEffect("hdr"); | |||||
var env = randIntInclusive(0, 2); | |||||
if (env == 0) | |||||
{ | |||||
g_Map.log("Using Lighting Set Morning"); | |||||
setSkySet("cirrus"); | |||||
setSunColor(1, 0.886275, 0.556863); | |||||
setSunElevation(0.469398); | |||||
setSunRotation(-1.42353); | |||||
setTerrainAmbientColor(0.329412, 0.419608, 0.501961); | |||||
setUnitsAmbientColor(0.439216, 0.521569, 0.556863); | |||||
setFogColor(0.8, 0.8, 0.894118); | |||||
setFogFactor(0.4); | |||||
setFogThickness(0.2); | |||||
setPPBloom(0.35); | |||||
}else if (env == 1) | |||||
{ | |||||
g_Map.log("Using lighting set Afternoon"); | |||||
setSkySet("cloudless"); | |||||
setSunColor(1, 0.921569, 0.682353); | |||||
setSunElevation(0.670645); | |||||
setSunRotation(0.416702); | |||||
setTerrainAmbientColor(0.329412, 0.419608, 0.501961); | |||||
setUnitsAmbientColor(0.439216, 0.521569, 0.556863); | |||||
setFogColor(0.8, 0.8, 0.894118); | |||||
setFogFactor(0.3); | |||||
setFogThickness(0.2); | |||||
setPPBloom(0.25); | |||||
}else | |||||
{ | |||||
g_Map.log("Using Lighting set Evening"); | |||||
setSkySet("sunset"); | |||||
setSunColor(1.2652, 0.873236, 0.486234); | |||||
setSunElevation(0.378635); | |||||
setSunRotation(1.10222); | |||||
setTerrainAmbientColor(0.329412, 0.419608, 0.501961); | |||||
setUnitsAmbientColor(0.439216, 0.521569, 0.556863); | |||||
setFogColor(0.839216, 0.780392, 0.729412); | |||||
setFogFactor(0.3); | |||||
setFogThickness(0.22); | |||||
setPPBloom(0.35); | |||||
} | |||||
var [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); | var [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); | ||||
placePlayerBases({ | placePlayerBases({ | ||||
Context not available. | |||||
"innerTerrain": tRoad | "innerTerrain": tRoad | ||||
}, | }, | ||||
"Chicken": { | "Chicken": { | ||||
"template": oSheep | |||||
}, | }, | ||||
"Berries": { | "Berries": { | ||||
"template": oBerryBush | "template": oBerryBush | ||||
Context not available. | |||||
"Trees": { | "Trees": { | ||||
"template": oPine | "template": oPine | ||||
}, | }, | ||||
"Decoratives": { | |||||
"template": aGrassShort | |||||
} | |||||
}); | }); | ||||
Engine.SetProgress(20); | Engine.SetProgress(20); | ||||
new MountainRangeBuilder({ | new MountainRangeBuilder({ | ||||
"pathplacer": new PathPlacer(undefined, undefined, undefined, 0.4, scaleByMapSize(3, 12), 0.1, 0.1, 0.1), | "height": heightMountain, | ||||
"painters":[ | "width": heightMountain * 0.25, | ||||
new LayeredPainter([tCliff, tPrimary], [3]), | "maxLength": fractionToTiles(0.6), | ||||
new SmoothElevationPainter(ELEVATION_SET, heightMountain, 2), | "count": 16, | ||||
new TileClassPainter(clHill) | "bumpiness": 0.4, | ||||
], | "waviness": 0.75, | ||||
"constraint": avoidClasses(clPlayer, 20), | "terrain": [tCliff, tPrimary], | ||||
"passageWidth": scaleByMapSize(10, 15), | "tileclass": clHill, | ||||
"mountainWidth": scaleByMapSize(9, 15), | "constraint": avoidClasses(clPlayer, 15) | ||||
"maxDegree": 3, | |||||
"points": [ | |||||
// Four points near each player | |||||
...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.49), mapCenter)[0], | |||||
...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers * 1.4, fractionToTiles(0.34), mapCenter)[0], | |||||
...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers * 0.6, fractionToTiles(0.34), mapCenter)[0], | |||||
...distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.18), mapCenter)[0], | |||||
mapCenter | |||||
] | |||||
}).CreateMountainRanges(); | }).CreateMountainRanges(); | ||||
Engine.SetProgress(35); | Engine.SetProgress(35); | ||||
g_Map.log("Creating lakes"); | |||||
elexis: This is Alpine Valleys. Alpine Lakes exists already. | |||||
Not Done Inline ActionsI considered removing it and just calling this "The Alps". Alps maps without lakes are pretty awkward anyway. aeonios: I considered removing it and just calling this "The Alps". Alps maps without lakes are pretty… | |||||
var numLakes = randIntInclusive(0, Math.round(scaleByMapSize(1, 7))); | |||||
if (numLakes > 0) | |||||
createAreas( | |||||
new ChainPlacer(1, Math.floor(scaleByMapSize(4, 8)), Math.floor(scaleByMapSize(30, 120)), 0.7), | |||||
[ | |||||
new LayeredPainter([tShore, tLakeBed], [1]), | |||||
new SmoothElevationPainter(ELEVATION_SET, heightLake, 5), | |||||
new TileClassPainter(clWater) | |||||
], | |||||
avoidClasses(clPlayer, 20, clWater, 30, clHill, 7), | |||||
numLakes, | |||||
1); | |||||
createMountains(tCliff, avoidClasses(clPlayer, 20, clHill, 4, clWater, 4), clHill, scaleByMapSize(80, 320), Math.floor(scaleByMapSize(50, 90)), Math.floor(scaleByMapSize(4, 8)), Math.floor(scaleByMapSize(8, 18)), Math.floor(scaleByMapSize(4, 8))); | |||||
Engine.SetProgress(40); | |||||
paintTerrainBasedOnHeight(heightLand + 0.1, snowlineHeight, 0, tCliff); | paintTerrainBasedOnHeight(heightLand + 0.1, snowlineHeight, 0, tCliff); | ||||
paintTerrainBasedOnHeight(snowlineHeight, heightMountain, 3, tSnowLimited); | paintTerrainBasedOnHeight(snowlineHeight - 7, snowlineHeight, 3, tSnowLine); | ||||
paintTerrainBasedOnHeight(snowlineHeight, snowlineHeight + 5, 3, tSnowLineTrans); | |||||
paintTerrainBasedOnHeight(snowlineHeight + 5, Infinity, 3, tSnowCaps); | |||||
g_Map.log("Creating bumps"); | g_Map.log("Creating bumps"); | ||||
createAreas( | createAreas( | ||||
new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), | new ClumpPlacer(scaleByMapSize(75, 300), 0.3, 0.06, Infinity), | ||||
new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), | new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump * 2, scaleByMapSize(35, 150)), | ||||
avoidClasses(clPlayer, 10), | avoidClasses(clPlayer, 10, clWater, 2), | ||||
scaleByMapSize(50, 100)); | |||||
createAreas( | |||||
new ClumpPlacer(scaleByMapSize(50, 200), 0.3, 0.06, Infinity), | |||||
new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, scaleByMapSize(25, 100)), | |||||
avoidClasses(clPlayer, 10, clWater, 2), | |||||
scaleByMapSize(100, 200)); | scaleByMapSize(100, 200)); | ||||
Engine.SetProgress(40); | |||||
g_Map.log("Creating hills"); | Engine.SetProgress(50); | ||||
g_Map.log("Creating texture variation"); | |||||
// Create snow drift areas. | |||||
createAreas( | createAreas( | ||||
new ClumpPlacer(scaleByMapSize(40, 150), 0.2, 0.1, Infinity), | new ChainPlacer(fractionToTiles(0.05), fractionToTiles(0.1), scaleByMapSize(7, 25), 0.75), | ||||
[ | [ | ||||
new LayeredPainter([tCliff, tSnowLimited], [2]), | new TerrainPainter(tSecondary), | ||||
new SmoothElevationPainter(ELEVATION_SET, heightMountain, 2), | new TileClassPainter(clSnow) | ||||
new TileClassPainter(clHill) | |||||
], | ], | ||||
avoidClasses(clPlayer, 20, clHill, 14), | [avoidClasses(clPlayer, 40, clHill, 0, clWater, 0, clSnow, fractionToTiles(0.15))], | ||||
scaleByMapSize(10, 80) * numPlayers | randIntInclusive(scaleByMapSize(1, 3), scaleByMapSize(2, 6))); | ||||
); | Engine.SetProgress(60); | ||||
Engine.SetProgress(50); | |||||
g_Map.log("Creating forests"); | // Decorate snow areas | ||||
var [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); | createAreas( | ||||
var types = [ | new ChainPlacer(fractionToTiles(0.005), fractionToTiles(0.01), scaleByMapSize(7, 25), 0.75), | ||||
[[tForestFloor, tPrimary, pForest], [tForestFloor, pForest]] | [ | ||||
]; | new TerrainPainter(tRoughSnow), | ||||
new TileClassPainter(clRoughSnow) | |||||
], | |||||
[avoidClasses(clRoughSnow, 10), stayClasses(clSnow, 0)], | |||||
randIntInclusive(scaleByMapSize(3, 10), scaleByMapSize(20, 60))); | |||||
Engine.SetProgress(60); | |||||
var size = forestTrees / (scaleByMapSize(2,8) * numPlayers); | // Decorate grass areas with farmland | ||||
createAreas( | |||||
var num = Math.floor(size / types.length); | new ChainPlacer(4, 6, 10, 0.35), | ||||
for (let type of types) | [ | ||||
createAreas( | new TerrainPainter(tFarmland), | ||||
new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), | new TileClassPainter(clFarm) | ||||
[ | ], | ||||
new LayeredPainter(type, [2]), | [avoidClasses(clPlayer, 15, clHill, 5, clFarm, 50, clWater, 10, clSnow, 5), stayClasses(clGrass, 0)], | ||||
new TileClassPainter(clForest) | randIntInclusive(scaleByMapSize(2, 4), scaleByMapSize(4, 8))); | ||||
], | |||||
avoidClasses(clPlayer, 12, clForest, 10, clHill, 0), | |||||
num); | |||||
Engine.SetProgress(60); | Engine.SetProgress(60); | ||||
g_Map.log("Creating dirt patches"); | g_Map.log("Creating forests"); | ||||
for (let size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) | var [forestTrees, stragglerTrees] = getTreeCounts(750, 4000, 0.7); | ||||
createAreas( | |||||
new ClumpPlacer(size, 0.3, 0.06, 0.5), | |||||
[ | |||||
new LayeredPainter([[tDirt, tHalfSnow], [tHalfSnow, tSnowLimited]], [2]), | |||||
new TileClassPainter(clDirt) | |||||
], | |||||
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), | |||||
scaleByMapSize(15, 45)); | |||||
g_Map.log("Creating grass patches"); | // Create grassland forests | ||||
for (let size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) | createForests( | ||||
createAreas( | [tPrimary, tForestFloor, tForestFloor, pForest, pForest], | ||||
new ClumpPlacer(size, 0.3, 0.06, 0.5), | [avoidClasses(clPlayer, 20, clForest, 3, clWater, 2, clHill, 0, clSnow, 1, clRoughSnow, 1, clFarm, 3), stayClasses(clGrass, 0), nearClasses(clHill, 7)], | ||||
new TerrainPainter(tSecondary), | clForest, | ||||
avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), | forestTrees * 0.65); | ||||
scaleByMapSize(15, 45)); | |||||
createStragglerTrees( | |||||
[oPine, oAleppoPine], | |||||
[avoidClasses(clForest, 2, clHill, 1, clPlayer, 12, clWater, 3, clSnow, 1, clFarm, 3), nearClasses(clForest, 7)], | |||||
clForest, | |||||
stragglerTrees * 0.65); | |||||
// Create snowdrift forests | |||||
createForests( | |||||
[tSecondary, tSnowyForestFloor, tSnowyForestFloor, pForestSnow, pForestSnow], | |||||
[avoidClasses(clPlayer, 20, clForest, 3, clWater, 2, clHill, 0, clFarm, 3), stayClasses(clSnow, 0), nearClasses(clHill, 7)], | |||||
clForest, | |||||
forestTrees * 0.35); | |||||
createStragglerTrees( | |||||
[oWinterPine], | |||||
[avoidClasses(clForest, 2, clHill, 1, clPlayer, 12, clWater, 3, clFarm, 3), stayClasses(clSnow, 0), nearClasses(clForest, 7)], | |||||
clForest, | |||||
stragglerTrees * 0.35); | |||||
Engine.SetProgress(65); | Engine.SetProgress(65); | ||||
g_Map.log("Creating stone mines"); | g_Map.log("Creating stone mines"); | ||||
var group = new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock); | createMines( | ||||
createObjectGroupsDeprecated(group, 0, | [ | ||||
avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), | [new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)] | ||||
scaleByMapSize(4,16), 100 | ], | ||||
); | avoidClasses(clWater, 3, clForest, 1, clPlayer, 25, clRock, 25, clHill, 3, clFarm, 5), | ||||
clRock); | |||||
g_Map.log("Creating small stone mines"); | |||||
group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); | |||||
createObjectGroupsDeprecated(group, 0, | |||||
avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), | |||||
scaleByMapSize(4,16), 100 | |||||
); | |||||
g_Map.log("Creating metal mines"); | g_Map.log("Creating metal mines"); | ||||
group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); | createMines( | ||||
createObjectGroupsDeprecated(group, 0, | [ | ||||
avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), | [new SimpleObject(oMetalLarge, 1,1, 0,4)] | ||||
scaleByMapSize(4,16), 100 | ], | ||||
avoidClasses(clWater, 3, clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 3, clFarm, 5), | |||||
clMetal | |||||
); | ); | ||||
Engine.SetProgress(70); | Engine.SetProgress(70); | ||||
g_Map.log("Creating small decorative rocks"); | g_Map.log("Creating decorations"); | ||||
group = new SimpleGroup( | createDecoration( | ||||
[new SimpleObject(aRockMedium, 1,3, 0,1)], | [ | ||||
true | [new SimpleObject(aRockMedium, 1, 3, 0, 1)], | ||||
); | [new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)], | ||||
createObjectGroupsDeprecated( | ], | ||||
group, 0, | [ | ||||
avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), | scaleByMapSize(16, 262), | ||||
scaleByMapSize(16, 262), 50 | scaleByMapSize(8, 131), | ||||
); | ], | ||||
avoidClasses(clWater, 0, clForest, 0, clPlayer, 15, clHill, 1, clFarm, 1)); | |||||
g_Map.log("Creating large decorative rocks"); | createDecoration( | ||||
group = new SimpleGroup( | [ | ||||
[new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], | [new SimpleObject(aGrassShort, 1, 2, 0, 1)], | ||||
true | [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)] | ||||
createObjectGroupsDeprecated( | ], | ||||
group, 0, | [ | ||||
avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), | scaleByMapSize(13, 200), | ||||
scaleByMapSize(8, 131), 50 | scaleByMapSize(13, 200), | ||||
); | scaleByMapSize(13, 200) | ||||
], | |||||
avoidClasses(clWater, 0, clForest, 0, clPlayer, 15, clHill, 0, clSnow, 1, clFarm, 1)); | |||||
Engine.SetProgress(75); | Engine.SetProgress(75); | ||||
g_Map.log("Creating deer"); | g_Map.log("Creating food"); | ||||
group = new SimpleGroup( | createFood( | ||||
[new SimpleObject(oDeer, 5,7, 0,4)], | [ | ||||
true, clFood | [new SimpleObject(oDeer, 5, 7, 0, 4)], | ||||
); | [new SimpleObject(oRabbit, 2, 3, 0, 2)] | ||||
createObjectGroupsDeprecated(group, 0, | ], | ||||
avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), | [ | ||||
3 * numPlayers, 50 | scaleByMapSize(8, 24), | ||||
); | scaleByMapSize(8, 24) | ||||
], | |||||
avoidClasses(clWater, 3, clForest, 0, clPlayer, 25, clHill, 3, clFood, 10), | |||||
clFood); | |||||
createFood( | |||||
[ | |||||
[new SimpleObject(oBear, 1,1, 0,4)] | |||||
], | |||||
[ | |||||
scaleByMapSize(1, 7) | |||||
], | |||||
avoidClasses(clWater, 3, clForest, 0, clPlayer, 25, clHill, 3), | |||||
clFood); | |||||
g_Map.log("Creating berry bush"); | createFood( | ||||
group = new SimpleGroup( | [ | ||||
[new SimpleObject(oBerryBush, 5,7, 0,4)], | [new SimpleObject(oBerryBush, 4, 6, 1, 4)] | ||||
true, clFood | ], | ||||
); | [ | ||||
createObjectGroupsDeprecated(group, 0, | scaleByMapSize(2, 6) * randIntInclusive(1, 4) * numPlayers | ||||
avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), | ], | ||||
randIntInclusive(1, 4) * numPlayers + 2, 50 | avoidClasses(clWater, 3, clForest, 0, clPlayer, 20, clHill, 2, clFood, 10), | ||||
); | clFood); | ||||
g_Map.log("Creating rabbit"); | createFood( | ||||
group = new SimpleGroup( | [ | ||||
[new SimpleObject(oRabbit, 2,3, 0,2)], | [new SimpleObject(oSheep, 1, 1, 2, 3)] | ||||
true, clFood | ], | ||||
); | [ | ||||
createObjectGroupsDeprecated(group, 0, | scaleByMapSize(50, 200) | ||||
avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), | ], | ||||
3 * numPlayers, 50 | [nearClasses(clFarm, 5)], | ||||
); | clFood); | ||||
Engine.SetProgress(85); | |||||
createStragglerTrees( | createFood( | ||||
[oPine], | [ | ||||
avoidClasses(clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), | [new SimpleObject(oFish, 1, 3, 4, 6)] | ||||
clForest, | ], | ||||
stragglerTrees); | [ | ||||
scaleByMapSize(50, 400) * numLakes | |||||
], | |||||
[avoidClasses(clFood, 4), stayClasses(clWater, 5)], | |||||
clFood); | |||||
g_Map.log("Creating small grass tufts"); | Engine.SetProgress(85); | ||||
var planetm = 1; | |||||
group = new SimpleGroup( | |||||
[new SimpleObject(aGrassShort, 1,2, 0,1, -Math.PI / 8, Math.PI / 8)] | |||||
); | |||||
createObjectGroupsDeprecated(group, 0, | |||||
avoidClasses(clHill, 2, clPlayer, 2, clDirt, 0), | |||||
planetm * scaleByMapSize(13, 200) | |||||
); | |||||
Engine.SetProgress(90); | |||||
g_Map.log("Creating large grass tufts"); | |||||
group = new SimpleGroup( | |||||
[new SimpleObject(aGrass, 2,4, 0,1.8, -Math.PI / 8, Math.PI / 8), new SimpleObject(aGrassShort, 3,6, 1.2,2.5, -Math.PI / 8, Math.PI / 8)] | |||||
); | |||||
createObjectGroupsDeprecated(group, 0, | |||||
avoidClasses(clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), | |||||
planetm * scaleByMapSize(13, 200) | |||||
); | |||||
Engine.SetProgress(95); | |||||
g_Map.log("Creating bushes"); | |||||
group = new SimpleGroup( | |||||
[new SimpleObject(aBushMedium, 1,2, 0,2), new SimpleObject(aBushSmall, 2,4, 0,2)] | |||||
); | |||||
createObjectGroupsDeprecated(group, 0, | |||||
avoidClasses(clHill, 1, clPlayer, 1, clDirt, 1), | |||||
planetm * scaleByMapSize(13, 200), 50 | |||||
); | |||||
placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); | placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); | ||||
setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); | |||||
setSunRotation(randomAngle()); | |||||
setSunElevation(Math.PI * randFloat(1/5, 1/3)); | |||||
g_Map.ExportMap(); | g_Map.ExportMap(); | ||||
Context not available. |
Wildfire Games · Phabricator
This is Alpine Valleys. Alpine Lakes exists already.