Index: ps/trunk/binaries/data/mods/public/maps/random/african_plains.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/african_plains.js (revision 28100) +++ ps/trunk/binaries/data/mods/public/maps/random/african_plains.js (revision 28101) @@ -1,307 +1,307 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); if (g_MapSettings.Biome) setSelectedBiome(); else setBiome("generic/savanna"); // Pick some biome defaults and overload a few settings. const tPrimary = g_Terrains.mainTerrain; const tForestFloor = g_Terrains.tier3Terrain; const tCliff = ["savanna_cliff_a", "savanna_cliff_a_red", "savanna_cliff_b", "savanna_cliff_b_red"]; const tSecondary = g_Terrains.tier1Terrain; const tGrassShrubs = g_Terrains.tier2Terrain; const tDirt = g_Terrains.tier3Terrain; const tDirt2 = g_Terrains.tier4Terrain; const tDirt3 = g_Terrains.dirt; const tDirt4 = g_Terrains.dirt; const tCitytiles = "savanna_tile_a"; const tShore = g_Terrains.shore; const tWater = g_Terrains.water; const oBaobab = pickRandom(["gaia/tree/baobab", "gaia/tree/baobab_3_mature", "gaia/tree/acacia"]); const oPalm = "gaia/tree/bush_tropic"; const oPalm2 = "gaia/tree/cretan_date_palm_short"; const oBerryBush = "gaia/fruit/berry_01"; const oWildebeest = "gaia/fauna_wildebeest"; const oZebra = "gaia/fauna_zebra"; const oRhino = "gaia/fauna_rhinoceros_white"; const oLion = "gaia/fauna_lion"; const oLioness = "gaia/fauna_lioness"; const oHawk = "birds/buzzard"; const oGiraffe = "gaia/fauna_giraffe"; const oGiraffe2 = "gaia/fauna_giraffe_infant"; const oGazelle = "gaia/fauna_gazelle"; const oElephant = "gaia/fauna_elephant_african_bush"; const oElephant2 = "gaia/fauna_elephant_african_infant"; const oCrocodile = "gaia/fauna_crocodile_nile"; const oFish = g_Gaia.fish; const oStoneLarge = g_Gaia.stoneLarge; const oStoneSmall = g_Gaia.stoneSmall; const oMetalLarge = g_Gaia.metalLarge; const oMetalSmall = g_Gaia.metalSmall; const aBush = g_Decoratives.bushMedium; const aRock = g_Decoratives.rockMedium; const pForest = [tForestFloor + TERRAIN_SEPARATOR + oPalm, tForestFloor + TERRAIN_SEPARATOR + oPalm2, tForestFloor]; const heightSeaGround = -5; const heightLand = 2; const heightCliff = 3; const g_Map = new RandomMap(heightLand, tPrimary); const numPlayers = getNumPlayers(); const mapSize = g_Map.getSize(); const clPlayer = g_Map.createTileClass(); const clHill = g_Map.createTileClass(); const clForest = g_Map.createTileClass(); const clWater = g_Map.createTileClass(); const clDirt = g_Map.createTileClass(); const clRock = g_Map.createTileClass(); const clMetal = g_Map.createTileClass(); const clFood = g_Map.createTileClass(); const clBaseResource = g_Map.createTileClass(); placePlayerBases({ "PlayerPlacement": playerPlacementCircle(fractionToTiles(0.35)), "PlayerTileClass": clPlayer, "BaseResourceClass": clBaseResource, "CityPatch": { "outerTerrain": tPrimary, "innerTerrain": tCitytiles }, "StartingAnimal": { }, "Berries": { "template": oBerryBush }, "Mines": { "types": [ { "template": oMetalLarge }, { "type": "stone_formation", "template": oStoneSmall, "terrain": tDirt4 } ] }, "Trees": { "template": oBaobab, "count": scaleByMapSize(3, 12), "minDistGroup": 2, "maxDistGroup": 6, "minDist": 15, "maxDist": 16 } // No decoratives }); Engine.SetProgress(20); // The specificity of this map is a bunch of watering holes & hills making it somewhat cluttered. const nbHills = scaleByMapSize(6, 16); const nbWateringHoles = scaleByMapSize(4, 10); { g_Map.log("Creating hills"); createHills([tDirt2, tCliff, tGrassShrubs], avoidClasses(clPlayer, 30, clHill, 15), clHill, nbHills); Engine.SetProgress(30); g_Map.log("Creating water holes"); createAreas( new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), Math.floor(scaleByMapSize(60, 100)), Infinity), [ new LayeredPainter([tShore, tWater], [1]), new SmoothElevationPainter(ELEVATION_SET, heightSeaGround, 7), new TileClassPainter(clWater) ], avoidClasses(clPlayer, 22, clWater, 8, clHill, 2), nbWateringHoles); Engine.SetProgress(45); paintTerrainBasedOnHeight(heightCliff, Infinity, 0, tCliff); } createBumps(avoidClasses(clWater, 2, clPlayer, 20)); g_Map.log("Creating forests"); createDefaultForests( [tPrimary, pForest, tForestFloor, pForest, pForest], avoidClasses(clPlayer, 20, clForest, 15, clHill, 0, clWater, 2), clForest, scaleByMapSize(200, 1000)); Engine.SetProgress(50); g_Map.log("Creating dirt patches"); createLayeredPatches( [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)], [[tDirt, tDirt3], [tDirt2, tDirt4]], [2], avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), scaleByMapSize(15, 45), clDirt); Engine.SetProgress(55); g_Map.log("Creating shrubs"); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tGrassShrubs, avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), scaleByMapSize(15, 45), clDirt); Engine.SetProgress(60); g_Map.log("Creating grass patches"); createPatches( [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)], tSecondary, avoidClasses(clWater, 3, clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), scaleByMapSize(15, 45), clDirt); Engine.SetProgress(65); g_Map.log("Creating metal mines"); createBalancedMetalMines( oMetalSmall, oMetalLarge, clMetal, avoidClasses(clWater, 4, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1) ); g_Map.log("Creating stone mines"); createBalancedStoneMines( oStoneSmall, oStoneLarge, clRock, avoidClasses(clWater, 4, clForest, 1, clPlayer, scaleByMapSize(20, 35), clHill, 1, clMetal, 10) ); Engine.SetProgress(70); createDecoration( [ [new SimpleObject(aBush, 1,3, 0,1)], [new SimpleObject(aRock, 1,2, 0,1)] ], [ scaleByMapAreaAbsolute(8), scaleByMapAreaAbsolute(8) ], avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 0)); Engine.SetProgress(75); // Roaming animals { - var placeRoaming = function(name, objs) + const placeRoaming = function(name, objs) { g_Map.log("Creating roaming " + name); const group = new SimpleGroup(objs, true, clFood); createObjectGroups(group, 0, avoidClasses(clWater, 3, clPlayer, 20, clFood, 11, clHill, 4), scaleByMapSize(3, 9), 50 ); }; placeRoaming("giraffes", [new SimpleObject(oGiraffe, 2, 4, 0, 4), new SimpleObject(oGiraffe2, 0, 2, 0, 4)]); placeRoaming("elephants", [new SimpleObject(oElephant, 2, 4, 0, 4), new SimpleObject(oElephant2, 0, 2, 0, 4)]); placeRoaming("lions", [new SimpleObject(oLion, 0, 1, 0, 4), new SimpleObject(oLioness, 2, 3, 0, 4)]); // Other roaming animals createFood( [ [new SimpleObject(oHawk, 1, 1, 0, 3)], [new SimpleObject(oGazelle, 3, 5, 0, 3)], [new SimpleObject(oZebra, 3, 5, 0, 3)], [new SimpleObject(oWildebeest, 4, 6, 0, 3)], [new SimpleObject(oRhino, 1, 1, 0, 3)] ], [ 3 * numPlayers, 3 * numPlayers, 3 * numPlayers, 3 * numPlayers, 3 * numPlayers, ], avoidClasses(clFood, 20, clWater, 5, clHill, 2, clPlayer, 16), clFood); } // Animals that hang around watering holes { // TODO: these have a high retry factor because our mapgen constraint logic is bad. - var placeWateringHoleAnimals = function(name, objs, numberOfGroups) + const placeWateringHoleAnimals = function(name, objs, numberOfGroups) { g_Map.log("Creating " + name + " around watering holes"); const group = new SimpleGroup(objs, true, clFood); createObjectGroups(group, 0, borderClasses(clWater, 6, 3), numberOfGroups, 50 ); }; placeWateringHoleAnimals( "crocodiles", [new SimpleObject(oCrocodile, 2, 3, 0, 3)], nbWateringHoles * 0.8 ); placeWateringHoleAnimals( "zebras", [new SimpleObject(oZebra, 2, 5, 0, 3)], nbWateringHoles ); placeWateringHoleAnimals( "gazelles", [new SimpleObject(oGazelle, 2, 5, 0, 3)], nbWateringHoles ); } g_Map.log("Creating other food sources"); createFood( [ [new SimpleObject(oBerryBush, 5, 7, 0, 4)] ], [ randIntInclusive(1, 4) * numPlayers + 2 ], avoidClasses(clWater, 3, clForest, 2, clPlayer, 20, clHill, 3, clFood, 10), clFood); createFood( [ [new SimpleObject(oFish, 2, 3, 0, 2)] ], [ 15 * numPlayers ], [avoidClasses(clFood, 20), stayClasses(clWater, 6)], clFood); Engine.SetProgress(85); g_Map.log("Creating straggler baobabs"); const group = new SimpleGroup([new SimpleObject(oBaobab, 1, 1, 0, 3)], true, clForest); createObjectGroups( group, 0, avoidClasses(clWater, 0, clForest, 2, clHill, 3, clPlayer, 12, clMetal, 4, clRock, 4), scaleByMapSize(15, 75) ); placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); // Adjust some biome settings; setSkySet("sunny"); setWaterType("clap"); g_Map.ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/alpine_valley.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/alpine_valley.js (revision 28100) +++ ps/trunk/binaries/data/mods/public/maps/random/alpine_valley.js (revision 28101) @@ -1,512 +1,512 @@ Engine.LoadLibrary("rmbiome"); Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); TILE_CENTERED_HEIGHT_MAP = true; /** * This class creates random mountainranges without enclosing any area completely. * * To determine their location, a graph is created where each vertex is a possible starting or * ending location of a mountainrange and each edge a possible mountainrange. * * That graph starts nearly complete (i.e almost every vertex is connected to most other vertices). * After a random edge was chosen and placed as a mountainrange, * all edges that intersect, that leave a too small gap to another mountainrange or that are connected to * too many other mountainranges are removed from the graph. * This is repeated until all edges were removed. */ function MountainRangeBuilder(args) { this.numPlayers = args.numPlayers; /** * 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; /** * Minimum geometric distance between two mountains that don't end in one place (disjoint edges). */ this.minDistance = args.mountainWidth + args.passageWidth; /** * Array of Vector2D locations where a mountainrange can start or end. */ this.vertices = args.points; /** * 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 = this.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 >= this.numPlayers || j >= this.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(); const comparedEdge = this.possibleEdges[i]; const comparedEdgeStart = this.vertices[comparedEdge[0]]; const comparedEdgeEnd = this.vertices[comparedEdge[1]]; const edge0Equal = this.currentEdgeStart == comparedEdgeStart; const edge1Equal = this.currentEdgeStart == comparedEdgeEnd; const edge2Equal = this.currentEdgeEnd == comparedEdgeEnd; const 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() { const tree = []; const backtree = []; const pointQueue = [this.currentEdge[0]]; while (pointQueue.length) { const 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 (const 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(map) { map.log("Creating mountainrange with " + this.possibleEdges.length + " possible edges"); const 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); } }; setBiome(g_MapSettings.Biome ?? "alpine/winter"); -var heightLand = 3; -var heightOffsetBump = 2; -var snowlineHeight = 29; -var heightMountain = 30; +const heightLand = 3; +const heightOffsetBump = 2; +const snowlineHeight = 29; +const heightMountain = 30; const pForest = [g_Terrains.forestFloor + TERRAIN_SEPARATOR + g_Gaia.tree1, g_Terrains.forestFloor]; const g_Map = new RandomMap(heightLand, g_Terrains.mainTerrain); const numPlayers = getNumPlayers(); const mapCenter = g_Map.getCenter(); const clPlayer = g_Map.createTileClass(); const clHill = g_Map.createTileClass(); const clForest = g_Map.createTileClass(); const clDirt = g_Map.createTileClass(); const clRock = g_Map.createTileClass(); const clMetal = g_Map.createTileClass(); const clFood = g_Map.createTileClass(); const clBaseResource = g_Map.createTileClass(); -var [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); +const [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); placePlayerBases({ "PlayerPlacement": [playerIDs, playerPosition], "PlayerTileClass": clPlayer, "BaseResourceClass": clBaseResource, "CityPatch": { "outerTerrain": g_Terrains.roadWild, "innerTerrain": g_Terrains.road }, "StartingAnimal": { }, "Berries": { "template": g_Gaia.fruitBush }, "Mines": { "types": [ { "template": g_Gaia.metalLarge }, { "template": g_Gaia.stoneLarge } ] }, "Trees": { "template": g_Gaia.tree1 }, "Decoratives": { "template": g_Decoratives.grassShort } }); Engine.SetProgress(20); new MountainRangeBuilder({ "numPlayers": numPlayers, "pathplacer": new PathPlacer(undefined, undefined, undefined, 0.4, scaleByMapSize(3, 12), 0.1, 0.1, 0.1), "painters":[ new LayeredPainter([g_Terrains.cliff, g_Terrains.mainTerrain], [3]), new SmoothElevationPainter(ELEVATION_SET, heightMountain, 2), new TileClassPainter(clHill) ], "constraint": avoidClasses(clPlayer, 20), "passageWidth": scaleByMapSize(10, 15), "mountainWidth": scaleByMapSize(9, 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(g_Map); Engine.SetProgress(35); paintTerrainBasedOnHeight(heightLand + 0.1, snowlineHeight, 0, g_Terrains.cliff); paintTerrainBasedOnHeight(snowlineHeight, heightMountain, 3, g_Terrains.snowLimited); g_Map.log("Creating bumps"); createAreas( new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), avoidClasses(clPlayer, 10), scaleByMapSize(100, 200)); Engine.SetProgress(40); g_Map.log("Creating hills"); createAreas( new ClumpPlacer(scaleByMapSize(40, 150), 0.2, 0.1, Infinity), [ new LayeredPainter([g_Terrains.cliff, g_Terrains.snowLimited], [2]), new SmoothElevationPainter(ELEVATION_SET, heightMountain, 2), new TileClassPainter(clHill) ], avoidClasses(clPlayer, 20, clHill, 14), scaleByMapSize(10, 80) * numPlayers ); Engine.SetProgress(50); g_Map.log("Creating forests"); const [forestTrees, stragglerTrees] = getTreeCounts(500, 3000, 0.7); const types = [ [[g_Terrains.forestFloor, g_Terrains.mainTerrain, pForest], [g_Terrains.forestFloor, pForest]] ]; -var size = forestTrees / (scaleByMapSize(2,8) * numPlayers); +const size = forestTrees / (scaleByMapSize(2, 8) * numPlayers); const num = Math.floor(size / types.length); for (const type of types) createAreas( new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), [ new LayeredPainter(type, [2]), new TileClassPainter(clForest) ], avoidClasses(clPlayer, 12, clForest, 10, clHill, 0), num); Engine.SetProgress(60); g_Map.log("Creating dirt patches"); for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) createAreas( new ClumpPlacer(size, 0.3, 0.06, 0.5), [ new LayeredPainter( [ [g_Terrains.dirt, g_Terrains.halfSnow], [g_Terrains.halfSnow, g_Terrains.snowLimited] ], [2]), new TileClassPainter(clDirt) ], avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), scaleByMapSize(15, 45)); g_Map.log("Creating grass patches"); for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) createAreas( new ClumpPlacer(size, 0.3, 0.06, 0.5), new TerrainPainter(g_Terrains.tier2Terrain), avoidClasses(clForest, 0, clHill, 0, clDirt, 5, clPlayer, 12), scaleByMapSize(15, 45)); Engine.SetProgress(65); g_Map.log("Creating stone mines"); -var group = new SimpleGroup( +let group = new SimpleGroup( [ new SimpleObject(g_Gaia.stoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(g_Gaia.stoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4) ], true, clRock); createObjectGroupsDeprecated(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clRock, 10, clHill, 1), scaleByMapSize(4,16), 100 ); g_Map.log("Creating small stone mines"); group = new SimpleGroup([new SimpleObject(g_Gaia.stoneSmall, 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"); group = new SimpleGroup([new SimpleObject(g_Gaia.metalLarge, 1, 1, 0, 4)], true, clMetal); createObjectGroupsDeprecated(group, 0, avoidClasses(clForest, 1, clPlayer, 20, clMetal, 10, clRock, 5, clHill, 1), scaleByMapSize(4,16), 100 ); Engine.SetProgress(70); g_Map.log("Creating small decorative rocks"); group = new SimpleGroup( [new SimpleObject(g_Decoratives.rockMedium, 1, 3, 0, 1)], true ); createObjectGroupsDeprecated( group, 0, avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(16, 262), 50 ); g_Map.log("Creating large decorative rocks"); group = new SimpleGroup( [ new SimpleObject(g_Decoratives.rockLarge, 1, 2, 0, 1), new SimpleObject(g_Decoratives.rockMedium, 1, 3, 0, 2) ], true ); createObjectGroupsDeprecated( group, 0, avoidClasses(clForest, 0, clPlayer, 0, clHill, 0), scaleByMapSize(8, 131), 50 ); Engine.SetProgress(75); g_Map.log("Creating deer"); group = new SimpleGroup( [new SimpleObject(g_Gaia.mainHuntableAnimal, 5, 7, 0, 4)], true, clFood ); createObjectGroupsDeprecated(group, 0, avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), 3 * numPlayers, 50 ); g_Map.log("Creating berry bush"); group = new SimpleGroup( [new SimpleObject(g_Gaia.fruitBush, 5, 7, 0, 4)], true, clFood ); createObjectGroupsDeprecated(group, 0, avoidClasses(clForest, 0, clPlayer, 20, clHill, 1, clFood, 10), randIntInclusive(1, 4) * numPlayers + 2, 50 ); g_Map.log("Creating rabbit"); group = new SimpleGroup( [new SimpleObject(g_Gaia.secondaryHuntableAnimal, 2, 3, 0, 2)], true, clFood ); createObjectGroupsDeprecated(group, 0, avoidClasses(clForest, 0, clPlayer, 10, clHill, 1, clFood, 20), 3 * numPlayers, 50 ); Engine.SetProgress(85); createStragglerTrees( [g_Gaia.tree1], avoidClasses(clForest, 1, clHill, 1, clPlayer, 12, clMetal, 6, clRock, 6), clForest, stragglerTrees); g_Map.log("Creating small grass tufts"); -var planetm = 1; +const planetm = 1; group = new SimpleGroup( [new SimpleObject(g_Decoratives.grassShort, 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(g_Decoratives.grass, 2, 4, 0, 1.8, -Math.PI / 8, Math.PI / 8), new SimpleObject(g_Decoratives.grassShort, 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(g_Decoratives.bushMedium, 1, 2, 0, 2), new SimpleObject(g_Decoratives.bushSmall, 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)); setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); setSunRotation(randomAngle()); setSunElevation(Math.PI * randFloat(1/5, 1/3)); g_Map.ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/ardennes_forest.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/ardennes_forest.js (revision 28100) +++ ps/trunk/binaries/data/mods/public/maps/random/ardennes_forest.js (revision 28101) @@ -1,462 +1,462 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); setBiome("generic/temperate"); const tPrimary = ["steppe_grass_03", "steppe_grass_03", "alpine_cliff_c", "temperate_grass_mud_01"]; const tGrass = ["steppe_grass_04", "steppe_grass_04", "aegean_grass_dirt_03"]; const tPineForestFloor = "steppe_grass_03"; const tForestFloor = [tPineForestFloor, tPineForestFloor, "temperate_grass_mud_01"]; const tCliff = ["alpine_cliff_c", "alpine_cliff_c", "temperate_cliff_01"]; const tCity = ["new_alpine_citytile", "new_alpine_grass_dirt_a"]; const tGrassPatch = ["alpine_grass_d"]; const oBoar = "gaia/fauna_boar"; const oDeer = "gaia/fauna_deer"; const oBear = "gaia/fauna_bear_brown"; const oPig = "gaia/fauna_pig"; const oBerryBush = "gaia/fruit/berry_01"; const oMetalSmall = "gaia/ore/alpine_small"; const oMetalLarge = "gaia/ore/temperate_large"; const oStoneSmall = "gaia/rock/alpine_small"; const oStoneLarge = "gaia/rock/temperate_large"; const oOak = "gaia/tree/oak"; const oOakLarge = "gaia/tree/oak_large"; const oPine = "gaia/tree/pine"; const oAleppoPine = "gaia/tree/fir"; const aTreeA = "actor|flora/trees/oak.xml"; const aTreeB = "actor|flora/trees/oak_large.xml"; const aTreeC = "actor|flora/trees/pine.xml"; const aTreeD = "actor|flora/trees/fir_tree.xml"; const aTrees = [aTreeA, aTreeB, aTreeC, aTreeD]; const aGrassLarge = "actor|props/flora/grass_soft_large.xml"; const aWoodLarge = "actor|props/special/eyecandy/wood_pile_1_b.xml"; const aWoodA = "actor|props/special/eyecandy/wood_sm_pile_a.xml"; const aWoodB = "actor|props/special/eyecandy/wood_sm_pile_b.xml"; const aBarrel = "actor|props/special/eyecandy/barrel_a.xml"; const aWheel = "actor|props/special/eyecandy/wheel_laying.xml"; const aCeltHomestead = "actor|structures/celts/homestead.xml"; const aCeltHouse = "actor|structures/celts/house.xml"; const aCeltLongHouse = "actor|structures/celts/longhouse.xml"; const pForest = [ tPineForestFloor+TERRAIN_SEPARATOR+oOak, tForestFloor, tPineForestFloor+TERRAIN_SEPARATOR+oPine, tForestFloor, tPineForestFloor+TERRAIN_SEPARATOR+oAleppoPine, tForestFloor, tForestFloor ]; const heightRavineValley = 2; const heightLand = 30; const heightRavineHill = 40; const heightHill = 50; const heightOffsetRavine = 10; const g_Map = new RandomMap(heightHill, tPrimary); const numPlayers = getNumPlayers(); const mapSize = g_Map.getSize(); const mapCenter = g_Map.getCenter(); const clPlayer = g_Map.createTileClass(); const clHill = g_Map.createTileClass(); const clForest = g_Map.createTileClass(); const clForestJoin = g_Map.createTileClass(); const clRock = g_Map.createTileClass(); const clMetal = g_Map.createTileClass(); const clFood = g_Map.createTileClass(); const clBaseResource = g_Map.createTileClass(); const clHillDeco = g_Map.createTileClass(); const clExplorable = g_Map.createTileClass(); g_Map.log("Creating the central dip"); createArea( new ClumpPlacer(diskArea(fractionToTiles(0.44)), 0.94, 0.05, 0.1, mapCenter), [ new LayeredPainter([tCliff, tGrass], [3]), new SmoothElevationPainter(ELEVATION_SET, heightLand, 3) ]); Engine.SetProgress(5); g_Map.log("Finding hills"); const noise0 = new Noise2D(20); for (let ix = 0; ix < mapSize; ix++) for (let iz = 0; iz < mapSize; iz++) { const position = new Vector2D(ix, iz); const h = g_Map.getHeight(position); if (h > heightRavineHill) { clHill.add(position); // Add hill noise const x = ix / (mapSize + 1.0); const z = iz / (mapSize + 1.0); const n = (noise0.get(x, z) - 0.5) * heightRavineHill; g_Map.setHeight(position, h + n); } } const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.3)); function distanceToPlayers(x, z) { let r = 10000; for (let i = 0; i < numPlayers; i++) { let dx = x - tilesToFraction(playerPosition[i].x); let dz = z - tilesToFraction(playerPosition[i].y); r = Math.min(r, Math.square(dx) + Math.square(dz)); } return Math.sqrt(r); } function playerNearness(x, z) { let d = fractionToTiles(distanceToPlayers(x,z)); if (d < 13) return 0; if (d < 19) return (d-13)/(19-13); return 1; } Engine.SetProgress(10); placePlayerBases({ "PlayerPlacement": [playerIDs, playerPosition], "BaseResourceClass": clBaseResource, // Playerclass marked below "CityPatch": { "outerTerrain": tCity, "innerTerrain": tCity, "radius": scaleByMapSize(5, 6), "smoothness": 0.05 }, "StartingAnimal": { "template": oPig }, "Berries": { "template": oBerryBush, "minCount": 3, "maxCount": 3 }, "Mines": { "types": [ { "template": oMetalLarge }, { "template": oStoneLarge } ], "distance": 16 }, "Trees": { "template": oOak, "count": 2 } // No decoratives }); g_Map.log("Marking player territory"); for (let i = 0; i < numPlayers; ++i) createArea( new ClumpPlacer(250, 0.95, 0.3, 0.1, playerPosition[i]), new TileClassPainter(clPlayer)); Engine.SetProgress(30); g_Map.log("Creating hills"); for (const size of [scaleByMapSize(50, 800), scaleByMapSize(50, 400), scaleByMapSize(10, 30), scaleByMapSize(10, 30)]) { const mountains = createAreas( new ClumpPlacer(size, 0.1, 0.2, 0.1), [ new LayeredPainter([tCliff, [tForestFloor, tForestFloor, tCliff]], [2]), new SmoothElevationPainter(ELEVATION_SET, heightHill, size < 50 ? 2 : 4), new TileClassPainter(clHill) ], avoidClasses(clPlayer, 8, clBaseResource, 2, clHill, 5), scaleByMapSize(1, 4)); if (size > 100 && mountains.length) createAreasInAreas( new ClumpPlacer(size * 0.3, 0.94, 0.05, 0.1), [ new LayeredPainter([tCliff, tForestFloor], [2]), new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetRavine, 3) ], stayClasses(clHill, 4), mountains.length * 2, 20, mountains); const ravine = createAreas( new ClumpPlacer(size, 0.1, 0.2, 0.1), [ new LayeredPainter([tCliff, tForestFloor], [2]), new SmoothElevationPainter(ELEVATION_SET, heightRavineValley, 2), new TileClassPainter(clHill) ], avoidClasses(clPlayer, 6, clBaseResource, 2, clHill, 5), scaleByMapSize(1, 3)); if (size > 150 && ravine.length) { g_Map.log("Placing huts in ravines"); createObjectGroupsByAreasDeprecated( new RandomGroup( [ new SimpleObject(aCeltHouse, 0, 1, 4, 5), new SimpleObject(aCeltLongHouse, 1, 1, 4, 5) ], true, clHillDeco), 0, [avoidClasses(clHillDeco, 3), stayClasses(clHill, 3)], ravine.length * 5, 20, ravine); createObjectGroupsByAreasDeprecated( new RandomGroup([new SimpleObject(aCeltHomestead, 1, 1, 1, 1)], true, clHillDeco), 0, [avoidClasses(clHillDeco, 5), stayClasses(clHill, 4)], ravine.length * 2, 100, ravine); // Place noise createAreasInAreas( new ClumpPlacer(size * 0.3, 0.94, 0.05, 0.1), [ new LayeredPainter([tCliff, tForestFloor], [2]), new SmoothElevationPainter(ELEVATION_SET, heightRavineValley, 2) ], [avoidClasses(clHillDeco, 2), stayClasses(clHill, 0)], ravine.length * 2, 20, ravine); createAreasInAreas( new ClumpPlacer(size * 0.1, 0.3, 0.05, 0.1), [ new LayeredPainter([tCliff, tForestFloor], [2]), new SmoothElevationPainter(ELEVATION_SET, heightRavineHill, 2), new TileClassPainter(clHill) ], [avoidClasses(clHillDeco, 2), borderClasses(clHill, 15, 1)], ravine.length * 2, 50, ravine); } } Engine.SetProgress(50); for (let ix = 0; ix < mapSize; ix++) for (let iz = 0; iz < mapSize; iz++) { const position = new Vector2D(ix, iz); const h = g_Map.getHeight(position); if (h > 35 && randBool(0.1) || h < 15 && randBool(0.05) && clHillDeco.countMembersInRadius(position, 1) == 0) g_Map.placeEntityAnywhere( pickRandom(aTrees), 0, randomPositionOnTile(position), randomAngle()); } const explorableArea = createArea( new MapBoundsPlacer(), undefined, [ new HeightConstraint(15, 45), avoidClasses(clPlayer, 1) ]); new TileClassPainter(clExplorable).paint(explorableArea); Engine.SetProgress(55); // Add some general noise - after placing height dependant trees for (let ix = 0; ix < mapSize; ix++) { const x = ix / (mapSize + 1.0); for (let iz = 0; iz < mapSize; iz++) { const position = new Vector2D(ix, iz); const z = iz / (mapSize + 1.0); const h = g_Map.getHeight(position); const pn = playerNearness(x,z); const n = (noise0.get(x,z) - 0.5) * 10; g_Map.setHeight(position, h + (n * pn)); } } Engine.SetProgress(60); g_Map.log("Creating forests"); -var [forestTrees, stragglerTrees] = getTreeCounts(1300, 8000, 0.8); -var [forestTreesJoin, forestTrees] = getTreeCounts(forestTrees, forestTrees, 0.25); +const [protoPorestTrees, stragglerTrees] = getTreeCounts(1300, 8000, 0.8); +const [forestTreesJoin, forestTrees] = getTreeCounts(protoPorestTrees, protoPorestTrees, 0.25); -var num = forestTrees / scaleByMapSize(20, 70); +const treeNum = forestTrees / scaleByMapSize(20, 70); createAreasInAreas( - new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), + new ClumpPlacer(forestTrees / treeNum, 0.1, 0.1, Infinity), [ new TerrainPainter(pForest), new TileClassPainter(clForest) ], avoidClasses(clPlayer, 5, clBaseResource, 4, clForest, 5, clHill, 4), - num, + treeNum, 100, [explorableArea] ); -var num = forestTreesJoin / (scaleByMapSize(4, 6) * numPlayers); +const joinNum = forestTreesJoin / (scaleByMapSize(4, 6) * numPlayers); createAreasInAreas( - new ClumpPlacer(forestTreesJoin / num, 0.1, 0.1, Infinity), + new ClumpPlacer(forestTreesJoin / joinNum, 0.1, 0.1, Infinity), [ new TerrainPainter(pForest), new TileClassPainter(clForest), new TileClassPainter(clForestJoin) ], [avoidClasses(clPlayer, 5, clBaseResource, 4, clForestJoin, 5, clHill, 4), borderClasses(clForest, 1, 4)], - num, + joinNum, 100, [explorableArea] ); Engine.SetProgress(70); g_Map.log("Creating grass patches"); for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) createAreas( new ClumpPlacer(size, 0.3, 0.06, 0.5), new TerrainPainter([tGrass, tGrassPatch]), avoidClasses(clForest, 0, clHill, 2, clPlayer, 5), scaleByMapSize(15, 45)); g_Map.log("Creating chopped forest patches"); for (const size of [scaleByMapSize(20, 120)]) createAreas( new ClumpPlacer(size, 0.3, 0.06, 0.5), new TerrainPainter(tForestFloor), avoidClasses(clForest, 1, clHill, 2, clPlayer, 5), scaleByMapSize(4, 12)); Engine.SetProgress(75); g_Map.log("Creating metal mines"); createBalancedMetalMines( oMetalSmall, oMetalLarge, clMetal, [stayClasses(clExplorable, 1), avoidClasses(clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1)] ); g_Map.log("Creating stone mines"); createBalancedStoneMines( oStoneSmall, oStoneLarge, clRock, [stayClasses(clExplorable, 1), avoidClasses(clForest, 0, clPlayer, scaleByMapSize(15, 25), clHill, 1, clMetal, 10)] ); Engine.SetProgress(80); g_Map.log("Creating wildlife"); let group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroupsByAreasDeprecated(group, 0, avoidClasses(clHill, 4, clForest, 0, clPlayer, 0, clBaseResource, 20), 3 * numPlayers, 100, [explorableArea] ); group = new SimpleGroup( [new SimpleObject(oBoar, 2,3, 0,5)], true, clFood ); createObjectGroupsByAreasDeprecated(group, 0, avoidClasses(clHill, 4, clForest, 0, clPlayer, 0, clBaseResource, 15), numPlayers, 50, [explorableArea] ); group = new SimpleGroup( [new SimpleObject(oBear, 1,1, 0,4)], false, clFood ); createObjectGroupsByAreasDeprecated(group, 0, avoidClasses(clHill, 4, clForest, 0, clPlayer, 20), scaleByMapSize(3, 12), 200, [explorableArea] ); Engine.SetProgress(85); g_Map.log("Creating berry bush"); group = new SimpleGroup( [new SimpleObject(oBerryBush, 5,7, 0,4)], true, clFood ); createObjectGroupsDeprecated(group, 0, avoidClasses(clForest, 0, clPlayer, 20, clHill, 4, clFood, 20), randIntInclusive(3, 12) * numPlayers + 2, 50 ); g_Map.log("Creating decorative props"); group = new SimpleGroup( [ new SimpleObject(aWoodA, 1,2, 0,1), new SimpleObject(aWoodB, 1,3, 0,1), new SimpleObject(aWheel, 0,2, 0,1), new SimpleObject(aWoodLarge, 0,1, 0,1), new SimpleObject(aBarrel, 0,2, 0,1) ], true ); createObjectGroupsByAreasDeprecated( group, 0, avoidClasses(clForest, 0), scaleByMapSize(5, 50), 50, [explorableArea] ); Engine.SetProgress(90); g_Map.log("Creating straggler trees"); const types = [oOak, oOakLarge, oPine, oAleppoPine]; -var num = Math.floor(stragglerTrees / types.length); +const stragglerNum = Math.floor(stragglerTrees / types.length); for (const type of types) createObjectGroupsByAreasDeprecated( new SimpleGroup([new SimpleObject(type, 1, 1, 0, 3)], true, clForest), 0, avoidClasses(clForest, 4, clHill, 5, clPlayer, 10, clBaseResource, 2, clMetal, 5, clRock, 5), - num, 20, + stragglerNum, 20, [explorableArea]); Engine.SetProgress(95); g_Map.log("Creating grass tufts"); group = new SimpleGroup( [new SimpleObject(aGrassLarge, 1,2, 0,1, -Math.PI / 8, Math.PI / 8)] ); createObjectGroupsByAreasDeprecated(group, 0, avoidClasses(clHill, 2, clPlayer, 2), scaleByMapSize(50, 300), 20, [explorableArea] ); placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2)); g_Map.ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/cycladic_archipelago.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/cycladic_archipelago.js (revision 28100) +++ ps/trunk/binaries/data/mods/public/maps/random/cycladic_archipelago.js (revision 28101) @@ -1,364 +1,364 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); const tOceanRockDeep = "medit_sea_coral_deep"; const tOceanCoral = "medit_sea_coral_plants"; const tBeachWet = "medit_sand_wet"; const tBeachDry = "medit_sand"; const tBeach = ["medit_rocks_grass","medit_sand", "medit_rocks_grass_shrubs"]; const tBeachBlend = ["medit_rocks_grass", "medit_rocks_grass_shrubs"]; const tCity = "medit_city_tile"; const tGrassDry = ["medit_grass_field_dry", "medit_grass_field_b"]; const tGrass = ["medit_rocks_grass", "medit_rocks_grass","medit_dirt","medit_rocks_grass_shrubs"]; const tGrassShrubs = "medit_shrubs"; const tCliffShrubs = ["medit_cliff_aegean_shrubs", "medit_cliff_italia_grass","medit_cliff_italia"]; const tCliff = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"]; const tForestFloor = "medit_forestfloor_a"; const tWater = "medit_sea_depths"; const oBeech = "gaia/tree/euro_beech"; const oBerryBush = "gaia/fruit/berry_01"; const oCarob = "gaia/tree/carob"; const oCypress1 = "gaia/tree/cypress"; const oCypress2 = "gaia/tree/cypress"; const oLombardyPoplar = "gaia/tree/poplar_lombardy"; const oPalm = "gaia/tree/medit_fan_palm"; const oPine = "gaia/tree/aleppo_pine"; const oDateT = "gaia/tree/cretan_date_palm_tall"; const oDateS = "gaia/tree/cretan_date_palm_short"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fish/generic"; const oWhale = "gaia/fauna_whale_humpback"; const oStoneLarge = "gaia/rock/mediterranean_large"; const oStoneSmall = "gaia/rock/mediterranean_small"; const oMetalLarge = "gaia/ore/mediterranean_large"; const oShipwreck = "gaia/treasure/shipwreck"; const oShipDebris = "gaia/treasure/shipwreck_debris"; const aRockLarge = "actor|geology/stone_granite_large.xml"; const aRockMed = "actor|geology/stone_granite_med.xml"; const aRockSmall = "actor|geology/stone_granite_small.xml"; const pPalmForest = [tForestFloor+TERRAIN_SEPARATOR+oPalm, tGrass]; const pPineForest = [tForestFloor+TERRAIN_SEPARATOR+oPine, tGrass]; const pPoplarForest = [tForestFloor+TERRAIN_SEPARATOR+oLombardyPoplar, tGrass]; const pMainForest = [tForestFloor+TERRAIN_SEPARATOR+oCarob, tForestFloor+TERRAIN_SEPARATOR+oBeech, tGrass, tGrass]; const heightSeaGround = -5; const heightLand = 3; const heightHill = 12; const heightOffsetBump = 2; const g_Map = new RandomMap(heightSeaGround, tWater); const numPlayers = getNumPlayers(); const mapSize = g_Map.getSize(); const mapCenter = g_Map.getCenter(); const clCoral = g_Map.createTileClass(); const clPlayer = g_Map.createTileClass(); const clIsland = g_Map.createTileClass(); const clCity = g_Map.createTileClass(); const clDirt = g_Map.createTileClass(); const clHill = g_Map.createTileClass(); const clForest = g_Map.createTileClass(); const clWater = g_Map.createTileClass(); const clRock = g_Map.createTileClass(); const clMetal = g_Map.createTileClass(); const clFood = g_Map.createTileClass(); const clBaseResource = g_Map.createTileClass(); //array holding starting islands based on number of players const startingPlaces=[[0],[0,3],[0,2,4],[0,1,3,4],[0,1,2,3,4],[0,1,2,3,4,5]]; const startAngle = randomAngle(); const islandRadius = scaleByMapSize(15, 40); const islandCount = Math.max(6, numPlayers); const islandPosition = distributePointsOnCircle(islandCount, startAngle, fractionToTiles(0.39), mapCenter)[0].map(position => position.round()); const centralIslandRadius = scaleByMapSize(15, 30); const centralIslandCount = Math.floor(scaleByMapSize(1, 4)); const centralIslandPosition = new Array(numPlayers).fill(0).map((v, i) => Vector2D.add(mapCenter, new Vector2D(fractionToTiles(randFloat(0.1, 0.16)), 0).rotate( -startAngle - Math.PI * (i * 2 / centralIslandCount + randFloat(-1, 1) / 8)).round())); const areas = []; -var nPlayer = 0; -var playerPosition = []; +let nPlayer = 0; +const playerPosition = []; function createCycladicArchipelagoIsland(position, tileClass, radius, coralRadius) { // Deep ocean rocks createArea( new ClumpPlacer(diskArea(radius + coralRadius), 0.7, 0.1, Infinity, position), [ new LayeredPainter([tOceanRockDeep, tOceanCoral], [5]), new TileClassPainter(clCoral) ], avoidClasses(clCoral, 0, clPlayer, 0)); // Island areas.push( createArea( new ClumpPlacer(diskArea(radius), 0.7, 0.1, Infinity, position), [ new LayeredPainter([tOceanCoral, tBeachWet, tBeachDry, tBeach, tBeachBlend, tGrass], [1, 3, 1, 1, 2]), new SmoothElevationPainter(ELEVATION_SET, heightLand, 5), new TileClassPainter(tileClass) ], avoidClasses(clPlayer, 0))); } g_Map.log("Creating player islands"); for (let i = 0; i < islandCount; ++i) { const isPlayerIsland = numPlayers >= 6 || i == startingPlaces[numPlayers - 1][nPlayer]; if (isPlayerIsland) { playerPosition[nPlayer] = islandPosition[i]; ++nPlayer; } createCycladicArchipelagoIsland(islandPosition[i], isPlayerIsland ? clPlayer : clIsland, islandRadius, scaleByMapSize(1, 5)); } g_Map.log("Creating central islands"); for (const position of centralIslandPosition) createCycladicArchipelagoIsland(position, clIsland, centralIslandRadius, 2); placePlayerBases({ "PlayerPlacement": [sortAllPlayers(), playerPosition], // PlayerTileClass is clCity here and painted below "BaseResourceClass": clBaseResource, "Walls": "towers", "CityPatch": { "radius": 6, "outerTerrain": tGrass, "innerTerrain": tCity, "painters": [ new TileClassPainter(clCity) ] }, "StartingAnimal": { }, "Berries": { "template": oBerryBush }, "Mines": { "types": [ { "template": oMetalLarge }, { "template": oStoneLarge } ] }, "Trees": { "template": oPalm, "count": 2 } // No decoratives }); Engine.SetProgress(20); g_Map.log("Creating bumps"); createAreasInAreas( new ClumpPlacer(scaleByMapSize(20, 60), 0.3, 0.06, Infinity), new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 3), avoidClasses(clCity, 0), scaleByMapSize(25, 75),15, areas); Engine.SetProgress(34); g_Map.log("Creating hills"); createAreasInAreas( new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), [ new LayeredPainter([tCliff, tCliffShrubs], [2]), new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), new TileClassPainter(clHill) ], avoidClasses(clCity, 15, clHill, 15), scaleByMapSize(5, 30), 15, areas); Engine.SetProgress(38); paintTileClassBasedOnHeight(-Infinity, 0, Elevation_ExcludeMin_ExcludeMax, clWater); g_Map.log("Creating forests"); -var forestTypes = [ +const forestTypes = [ [[tForestFloor, tGrass, pPalmForest], [tForestFloor, pPalmForest]], [[tForestFloor, tGrass, pPineForest], [tForestFloor, pPineForest]], [[tForestFloor, tGrass, pPoplarForest], [tForestFloor, pPoplarForest]], [[tForestFloor, tGrass, pMainForest], [tForestFloor, pMainForest]] ]; for (const type of forestTypes) createAreasInAreas( new ClumpPlacer(randIntInclusive(6, 17), 0.1, 0.1, Infinity), [ new LayeredPainter(type, [2]), new TileClassPainter(clForest) ], avoidClasses(clCity, 1, clWater, 3, clForest, 3, clHill, 1, clBaseResource, 4), scaleByMapSize(10, 64), 20, areas); Engine.SetProgress(42); g_Map.log("Creating stone mines"); let 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); createObjectGroupsByAreasDeprecated(group, 0, [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clRock, 6)], scaleByMapSize(4,16), 200, areas ); Engine.SetProgress(46); g_Map.log("Creating small stone mines"); group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroupsByAreasDeprecated(group, 0, [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clRock, 6)], scaleByMapSize(4,16), 200, areas ); Engine.SetProgress(50); g_Map.log("Creating metal mines"); group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroupsByAreasDeprecated(group, 0, [avoidClasses(clWater, 1, clForest, 1, clHill, 1, clPlayer, 5, clMetal, 6, clRock, 6)], scaleByMapSize(4,16), 200, areas ); Engine.SetProgress(54); g_Map.log("Creating shrub patches"); for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) createAreasInAreas( new ClumpPlacer(size, 0.3, 0.06, 0.5), [ new LayeredPainter([tBeachBlend, tGrassShrubs], [1]), new TileClassPainter(clDirt) ], avoidClasses(clWater, 3, clHill, 0, clDirt, 6, clCity, 0, clBaseResource, 4), scaleByMapSize(4, 16), 20, areas); Engine.SetProgress(58); g_Map.log("Creating grass patches"); for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) createAreasInAreas( new ClumpPlacer(size, 0.3, 0.06, 0.5), [ new LayeredPainter([tGrassDry], []), new TileClassPainter(clDirt) ], avoidClasses(clWater, 3, clHill, 0, clDirt, 6, clCity, 0, clBaseResource, 4), scaleByMapSize(4, 16), 20, areas); Engine.SetProgress(62); g_Map.log("Creating straggler trees"); for (const tree of [oCarob, oBeech, oLombardyPoplar, oLombardyPoplar, oPine]) createObjectGroupsByAreasDeprecated( new SimpleGroup([new SimpleObject(tree, 1,1, 0,1)], true, clForest), 0, avoidClasses(clWater, 2, clForest, 2, clCity, 3, clBaseResource, 4, clRock, 6, clMetal, 6, clPlayer, 1, clHill, 1), scaleByMapSize(2, 38), 50, areas ); Engine.SetProgress(66); g_Map.log("Create straggler cypresses"); group = new SimpleGroup( [new SimpleObject(oCypress2, 1,3, 0,3), new SimpleObject(oCypress1, 0,2, 0,2)], true ); createObjectGroupsByAreasDeprecated(group, 0, avoidClasses(clWater, 2, clForest, 2, clCity, 3, clBaseResource, 4, clRock, 6, clMetal, 6, clPlayer, 1, clHill, 1), scaleByMapSize(5, 75), 50, areas ); Engine.SetProgress(70); g_Map.log("Create straggler date palms"); group = new SimpleGroup( [new SimpleObject(oDateS, 1,3, 0,3), new SimpleObject(oDateT, 0,2, 0,2)], true ); createObjectGroupsByAreasDeprecated(group, 0, avoidClasses(clWater, 2, clForest, 1, clCity, 0, clBaseResource, 4, clRock, 6, clMetal, 6, clPlayer, 1, clHill, 1), scaleByMapSize(5, 75), 50, areas ); Engine.SetProgress(74); g_Map.log("Creating rocks"); group = new SimpleGroup( [new SimpleObject(aRockSmall, 0,3, 0,2), new SimpleObject(aRockMed, 0,2, 0,2), new SimpleObject(aRockLarge, 0,1, 0,2)] ); createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 0, clCity, 0), scaleByMapSize(30, 180), 50 ); Engine.SetProgress(78); g_Map.log("Creating deer"); group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 5, clForest, 1, clHill, 1, clCity, 10, clMetal, 6, clRock, 4, clFood, 8), 3 * numPlayers, 50 ); Engine.SetProgress(82); g_Map.log("Creating berry bushes"); group = new SimpleGroup([new SimpleObject(oBerryBush, 5,7, 0,3)], true, clFood); createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 2, clForest, 1, clHill, 1, clCity, 10, clMetal, 6, clRock, 4, clFood, 8), 1.5 * numPlayers, 100 ); Engine.SetProgress(86); g_Map.log("Creating Fish"); group = new SimpleGroup([new SimpleObject(oFish, 1,1, 0,3)], true, clFood); createObjectGroupsDeprecated(group, 0, [stayClasses(clWater,1),avoidClasses(clFood, 8)], scaleByMapSize(40,200), 100 ); Engine.SetProgress(90); g_Map.log("Creating Whales"); group = new SimpleGroup([new SimpleObject(oWhale, 1,1, 0,3)], true, clFood); createObjectGroupsDeprecated(group, 0, [stayClasses(clWater,1),avoidClasses(clFood, 8, clPlayer,4,clIsland,4)], scaleByMapSize(10,40), 100 ); Engine.SetProgress(94); g_Map.log("Creating shipwrecks"); group = new SimpleGroup([new SimpleObject(oShipwreck, 1,1, 0,3)], true, clFood); createObjectGroupsDeprecated(group, 0, [stayClasses(clWater,1),avoidClasses(clFood, 8)], scaleByMapSize(6,16), 100 ); Engine.SetProgress(98); g_Map.log("Creating shipwreck debris"); group = new SimpleGroup([new SimpleObject(oShipDebris, 1,2, 0,4)], true, clFood); createObjectGroupsDeprecated(group, 0, [stayClasses(clWater,1),avoidClasses(clFood, 8)], scaleByMapSize(10,20), 100 ); Engine.SetProgress(99); placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clForest, 1, clBaseResource, 4, clHill, 4, clMetal, 4, clRock, 4, clFood, 1)); setSkySet("sunny"); setWaterColor(0.2,0.294,0.49); setWaterTint(0.208, 0.659, 0.925); setWaterMurkiness(0.72); setWaterWaviness(3.0); setWaterType("ocean"); g_Map.ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/flood.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/flood.js (revision 28100) +++ ps/trunk/binaries/data/mods/public/maps/random/flood.js (revision 28101) @@ -1,300 +1,300 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); setSelectedBiome(); const tMainTerrain = g_Terrains.mainTerrain; const tForestFloor1 = g_Terrains.forestFloor1; const tForestFloor2 = g_Terrains.forestFloor2; const tCliff = g_Terrains.cliff; const tTier1Terrain = g_Terrains.tier1Terrain; const tTier2Terrain = g_Terrains.tier2Terrain; const tTier3Terrain = g_Terrains.tier3Terrain; const tRoad = g_Terrains.road; const tRoadWild = g_Terrains.roadWild; const tTier4Terrain = g_Terrains.tier4Terrain; const tShore = g_Terrains.shore; const tWater = g_Terrains.water; let tHill = g_Terrains.hill; let tDirt = g_Terrains.dirt; if (currentBiome() == "generic/temperate") { tDirt = ["medit_shrubs_a", "grass_field"]; tHill = ["grass_field", "peat_temp"]; } const oTree1 = g_Gaia.tree1; const oTree2 = g_Gaia.tree2; const oTree3 = g_Gaia.tree3; const oTree4 = g_Gaia.tree4; const oTree5 = g_Gaia.tree5; const oFruitBush = g_Gaia.fruitBush; const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal; const oFish = g_Gaia.fish; const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; const oStoneLarge = g_Gaia.stoneLarge; const oMetalLarge = g_Gaia.metalLarge; const aGrass = g_Decoratives.grass; const aGrassShort = g_Decoratives.grassShort; const aRockLarge = g_Decoratives.rockLarge; const aRockMedium = g_Decoratives.rockMedium; const aBushMedium = g_Decoratives.bushMedium; const aBushSmall = g_Decoratives.bushSmall; const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; const heightSeaGround = -2; const heightLand = 6; const heightStartingIslands = 2; const shoreRadius = 6; const g_Map = new RandomMap(heightSeaGround, tWater); const clPlayer = g_Map.createTileClass(); const clHill = g_Map.createTileClass(); const clMountain = g_Map.createTileClass(); const clForest = g_Map.createTileClass(); const clDirt = g_Map.createTileClass(); const clRock = g_Map.createTileClass(); const clMetal = g_Map.createTileClass(); const clFood = g_Map.createTileClass(); const clBaseResource = g_Map.createTileClass(); const numPlayers = getNumPlayers(); const mapSize = g_Map.getSize(); const mapCenter = g_Map.getCenter(); g_Map.log("Creating player islands..."); const [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.38)); for (let i = 0; i < numPlayers; ++i) createArea( new ClumpPlacer(diskArea(1.4 * defaultPlayerBaseRadius()), 0.8, 0.1, Infinity, playerPosition[i]), [ new LayeredPainter([tShore, tMainTerrain], [shoreRadius]), new SmoothElevationPainter(ELEVATION_SET, heightStartingIslands, shoreRadius), new TileClassPainter(clHill) ]); placePlayerBases({ "PlayerPlacement": [playerIDs, playerPosition], "PlayerTileClass": clPlayer, "BaseResourceClass": clBaseResource, "Walls": false, "CityPatch": { "outerTerrain": tRoadWild, "innerTerrain": tRoad }, "StartingAnimal": { }, "Berries": { "template": oFruitBush }, "Mines": { "types": [ { "template": oMetalLarge }, { "template": oStoneLarge } ] }, "Trees": { "template": oTree2, "count": 50, "maxDist": 16, "maxDistGroup": 7 }, "Decoratives": { "template": aGrassShort } }); Engine.SetProgress(40); g_Map.log("Creating central island"); createArea( new ChainPlacer( 6, Math.floor(scaleByMapSize(10, 15)), Math.floor(scaleByMapSize(200, 300)), Infinity, mapCenter, 0, [Math.floor(fractionToTiles(0.01))]), [ new LayeredPainter([tShore, tMainTerrain], [shoreRadius, 100]), new SmoothElevationPainter(ELEVATION_SET, heightLand, shoreRadius), new TileClassPainter(clHill) ], avoidClasses(clPlayer, 40)); for (let m = 0; m < randIntInclusive(20, 34); ++m) { const elevRand = randIntInclusive(6, 20); createArea( new ChainPlacer( 7, 15, Math.floor(scaleByMapSize(15, 20)), Infinity, new Vector2D(fractionToTiles(randFloat(0, 1)), fractionToTiles(randFloat(0, 1))), 0, [Math.floor(fractionToTiles(0.01))]), [ new LayeredPainter([tDirt, tHill], [Math.floor(elevRand / 3), 40]), new SmoothElevationPainter(ELEVATION_SET, elevRand, Math.floor(elevRand / 3)), new TileClassPainter(clHill) ], [avoidClasses(clBaseResource, 2, clPlayer, 40), stayClasses(clHill, 6)]); } for (let m = 0; m < randIntInclusive(8, 17); ++m) { const elevRand = randIntInclusive(15, 29); createArea( new ChainPlacer( 5, 8, Math.floor(scaleByMapSize(15, 20)), Infinity, new Vector2D(randIntExclusive(0, mapSize), randIntExclusive(0, mapSize)), 0, [Math.floor(fractionToTiles(0.01))]), [ new LayeredPainter([tCliff, tForestFloor2], [Math.floor(elevRand / 3), 40]), new SmoothElevationPainter(ELEVATION_MODIFY, elevRand, Math.floor(elevRand / 3)), new TileClassPainter(clMountain) ], [avoidClasses(clBaseResource, 2, clPlayer, 40), stayClasses(clHill, 6)]); } g_Map.log("Creating center bounty"); createObjectGroup( new SimpleGroup( [new SimpleObject(oMetalLarge, 3, 6, 25, Math.floor(fractionToTiles(0.25)))], true, clBaseResource, mapCenter), 0, [avoidClasses(clBaseResource, 20, clPlayer, 40, clMountain, 4), stayClasses(clHill, 10)]); createObjectGroup( new SimpleGroup( [new SimpleObject(oStoneLarge, 3, 6, 25, Math.floor(fractionToTiles(0.25)))], true, clBaseResource, mapCenter), 0, [avoidClasses(clBaseResource, 20, clPlayer, 40, clMountain, 4), stayClasses(clHill, 10)]); g_Map.log("Creating fish"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood), 0, avoidClasses(clHill, 10, clFood, 20), 10 * numPlayers, 60); -var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(0.7)); +const [forestTreesMainIsland, stragglerTreesMainIsland] = getTreeCounts(...rBiomeTreeCount(0.7)); createForests( [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], [avoidClasses(clPlayer, 25, clForest, 10, clBaseResource, 3, clMetal, 6, clRock, 6, clMountain, 2), stayClasses(clHill, 6)], clForest, - forestTrees); + forestTreesMainIsland); const types = [oTree1, oTree2, oTree4, oTree3]; createStragglerTrees( types, [avoidClasses(clBaseResource, 2, clMetal, 6, clRock, 6, clMountain, 2, clPlayer, 25), stayClasses(clHill, 6)], clForest, - stragglerTrees); + stragglerTreesMainIsland); Engine.SetProgress(65); g_Map.log("Creating dirt patches"); const numb = currentBiome() == "generic/savanna" ? 3 : 1; for (const size of [scaleByMapSize(3, 6), scaleByMapSize(5, 10), scaleByMapSize(8, 21)]) createAreas( new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), [ new LayeredPainter([[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]), new TileClassPainter(clDirt) ], avoidClasses(clForest, 0, clMountain, 0, clDirt, 5, clPlayer, 10), numb * scaleByMapSize(15, 45)); g_Map.log("Painting shorelines"); paintTerrainBasedOnHeight(1, heightStartingIslands, 0, tMainTerrain); paintTerrainBasedOnHeight(heightSeaGround, 1, 3, tTier1Terrain); g_Map.log("Creating grass patches"); for (const size of [scaleByMapSize(2, 4), scaleByMapSize(3, 7), scaleByMapSize(5, 15)]) createAreas( new ChainPlacer(1, Math.floor(scaleByMapSize(3, 5)), size, 0.5), new TerrainPainter(tTier4Terrain), avoidClasses(clForest, 0, clMountain, 0, clDirt, 5, clPlayer, 10), numb * scaleByMapSize(15, 45)); createFood( [ [new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], [new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)] ], [3 * numPlayers, 3 * numPlayers], [avoidClasses(clForest, 0, clPlayer, 20, clMountain, 1, clFood, 4, clRock, 6, clMetal, 6), stayClasses(clHill, 6)], clFood); Engine.SetProgress(75); createFood( [ [new SimpleObject(oFruitBush, 5, 7, 0, 4)] ], [3 * numPlayers], [avoidClasses(clForest, 0, clPlayer, 15, clMountain, 1, clFood, 4, clRock, 6, clMetal, 6), stayClasses(clHill, 6)], clFood); Engine.SetProgress(85); -var planetm = currentBiome() == "generic/india" ? 8 : 1; +const planetm = currentBiome() == "generic/india" ? 8 : 1; createDecoration( [ [new SimpleObject(aRockMedium, 1, 3, 0, 1)], [new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)], [new SimpleObject(aGrassShort, 2, 15, 0, 1)], [new SimpleObject(aGrass, 2, 10, 0, 1.8), new SimpleObject(aGrassShort, 3, 10, 1.2, 2.5)], [new SimpleObject(aBushMedium, 1, 5, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)] ], [ scaleByMapAreaAbsolute(16), scaleByMapAreaAbsolute(8), planetm * scaleByMapAreaAbsolute(13), planetm * scaleByMapAreaAbsolute(13), planetm * scaleByMapAreaAbsolute(13) ], avoidClasses(clForest, 2, clPlayer, 20, clMountain, 5, clFood, 1, clBaseResource, 2)); -var [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(0.1)); +const [forestTreesSurrounding, stragglerTreesSurrounding] = getTreeCounts(...rBiomeTreeCount(0.1)); createForests( [tMainTerrain, tForestFloor1, tForestFloor2, pForest1, pForest2], avoidClasses(clPlayer, 30, clHill, 10, clFood, 5), clForest, - forestTrees); + forestTreesSurrounding); g_Map.log("Creating small grass tufts"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(aGrassShort, 1, 2, 0, 1)]), 0, [avoidClasses(clMountain, 2, clPlayer, 2, clDirt, 0), stayClasses(clHill, 8)], planetm * scaleByMapSize(13, 200)); placePlayersNomad( clPlayer, new AndConstraint([ stayClasses(clHill, 2), avoidClasses(clMountain, 2, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)])); setSkySet(pickRandom(["cloudless", "cumulus", "overcast"])); setWaterMurkiness(0.4); g_Map.ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/latium.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/latium.js (revision 28100) +++ ps/trunk/binaries/data/mods/public/maps/random/latium.js (revision 28101) @@ -1,469 +1,473 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); const tOceanDepths = "medit_sea_depths"; const tOceanRockDeep = "medit_sea_coral_deep"; const tOceanRockShallow = "medit_rocks_wet"; const tOceanCoral = "medit_sea_coral_plants"; const tBeachWet = "medit_sand_wet"; const tBeachDry = "medit_sand"; const tBeachGrass = "medit_rocks_grass"; const tBeachCliff = "medit_dirt"; const tCity = "medit_city_tile"; const tGrassDry = ["medit_grass_field_brown", "medit_grass_field_dry", "medit_grass_field_b"]; const tGrass = ["medit_grass_field_dry", "medit_grass_field_brown", "medit_grass_field_b"]; const tGrassShrubs = ["medit_grass_shrubs", "medit_grass_flowers"]; const tGrassRock = ["medit_rocks_grass"]; const tDirt = "medit_dirt"; const tDirtCliff = "medit_cliff_italia"; const tGrassCliff = "medit_cliff_italia_grass"; const tCliff = ["medit_cliff_italia", "medit_cliff_italia", "medit_cliff_italia_grass"]; const tForestFloor = "medit_grass_wild"; const oBeech = "gaia/tree/euro_beech"; const oBerryBush = "gaia/fruit/berry_01"; const oCarob = "gaia/tree/carob"; const oCypress1 = "gaia/tree/cypress"; const oCypress2 = "gaia/tree/cypress"; const oLombardyPoplar = "gaia/tree/poplar_lombardy"; const oPalm = "gaia/tree/medit_fan_palm"; const oPine = "gaia/tree/aleppo_pine"; const oDeer = "gaia/fauna_deer"; const oFish = "gaia/fish/generic"; const oSheep = "gaia/fauna_sheep"; const oStoneLarge = "gaia/rock/mediterranean_large"; const oStoneSmall = "gaia/rock/mediterranean_small"; const oMetalLarge = "gaia/ore/mediterranean_large"; const aBushMedDry = "actor|props/flora/bush_medit_me_dry.xml"; const aBushMed = "actor|props/flora/bush_medit_me.xml"; const aBushSmall = "actor|props/flora/bush_medit_sm.xml"; const aBushSmallDry = "actor|props/flora/bush_medit_sm_dry.xml"; const aGrass = "actor|props/flora/grass_soft_large_tall.xml"; const aGrassDry = "actor|props/flora/grass_soft_dry_large_tall.xml"; const aRockLarge = "actor|geology/stone_granite_large.xml"; const aRockMed = "actor|geology/stone_granite_med.xml"; const aRockSmall = "actor|geology/stone_granite_small.xml"; const pPalmForest = [tForestFloor+TERRAIN_SEPARATOR+oPalm, tGrass]; const pPineForest = [tForestFloor+TERRAIN_SEPARATOR+oPine, tGrass]; const pPoplarForest = [tForestFloor+TERRAIN_SEPARATOR+oLombardyPoplar, tGrass]; const pMainForest = [tForestFloor+TERRAIN_SEPARATOR+oCarob, tForestFloor+TERRAIN_SEPARATOR+oBeech, tGrass, tGrass]; const heightSeaGround = -16; const heightLand = 0; const heightPlayer = 5; const heightHill = 12; const g_Map = new RandomMap(heightLand, tGrass); const numPlayers = getNumPlayers(); const mapSize = g_Map.getSize(); const mapCenter = g_Map.getCenter(); const mapBounds = g_Map.getBounds(); const clWater = g_Map.createTileClass(); const clCliff = g_Map.createTileClass(); const clForest = g_Map.createTileClass(); const clMetal = g_Map.createTileClass(); const clRock = g_Map.createTileClass(); const clFood = g_Map.createTileClass(); const clPlayer = g_Map.createTileClass(); const clBaseResource = g_Map.createTileClass(); -var WATER_WIDTH = 0.1; -var horizontal = randBool(); +const WATER_WIDTH = 0.1; g_Map.log("Creating players"); -var startAngle = randBool() ? 0 : Math.PI / 2; -var playerPosition = playerPlacementLine(startAngle + Math.PI / 2, mapCenter, fractionToTiles(randFloat(0.42, 0.46))); +const startAngle = randBool() ? 0 : Math.PI / 2; +const playerPosition = playerPlacementLine(startAngle + Math.PI / 2, mapCenter, + fractionToTiles(randFloat(0.42, 0.46))); function distanceToPlayers(x, z) { let r = Infinity; for (let i = 0; i < numPlayers; ++i) { let dx = x - tilesToFraction(playerPosition[i].x); let dz = z - tilesToFraction(playerPosition[i].y); r = Math.min(r, Math.square(dx) + Math.square(dz)); } return Math.sqrt(r); } function playerNearness(x, z) { let d = fractionToTiles(distanceToPlayers(x,z)); if (d < 13) return 0; if (d < 19) return (d-13)/(19-13); return 1; } for (const x of [mapBounds.left, mapBounds.right]) paintRiver({ "parallel": true, "start": new Vector2D(x, mapBounds.top).rotateAround(startAngle, mapCenter), "end": new Vector2D(x, mapBounds.bottom).rotateAround(startAngle, mapCenter), "width": 2 * fractionToTiles(WATER_WIDTH), "fadeDist": 16, "deviation": 0, "heightRiverbed": heightSeaGround, "heightLand": heightLand, "meanderShort": 0, "meanderLong": 0, "waterFunc": (position, height, z) => { clWater.add(position); } }); Engine.SetProgress(10); g_Map.log("Painting elevation"); -var noise0 = new Noise2D(scaleByMapSize(4, 16)); -var noise1 = new Noise2D(scaleByMapSize(8, 32)); -var noise2 = new Noise2D(scaleByMapSize(15, 60)); - -var noise2a = new Noise2D(scaleByMapSize(20, 80)); -var noise2b = new Noise2D(scaleByMapSize(35, 140)); - -var noise3 = new Noise2D(scaleByMapSize(4, 16)); -var noise4 = new Noise2D(scaleByMapSize(6, 24)); -var noise5 = new Noise2D(scaleByMapSize(11, 44)); +const noise0 = new Noise2D(scaleByMapSize(4, 16)); +const noise1 = new Noise2D(scaleByMapSize(8, 32)); +const noise2 = new Noise2D(scaleByMapSize(15, 60)); + +const noise2a = new Noise2D(scaleByMapSize(20, 80)); +const noise2b = new Noise2D(scaleByMapSize(35, 140)); + +const noise3 = new Noise2D(scaleByMapSize(4, 16)); +const noise4 = new Noise2D(scaleByMapSize(6, 24)); +const noise5 = new Noise2D(scaleByMapSize(11, 44)); -for (var ix = 0; ix <= mapSize; ix++) - for (var iz = 0; iz <= mapSize; iz++) +for (let ix = 0; ix <= mapSize; ix++) + for (let iz = 0; iz <= mapSize; iz++) { const position = new Vector2D(ix, iz); - var x = ix / (mapSize + 1.0); - var z = iz / (mapSize + 1.0); - var pn = playerNearness(x, z); + const x = ix / (mapSize + 1.0); + const z = iz / (mapSize + 1.0); + const pn = playerNearness(x, z); const c = startAngle ? z : x; const distToWater = clWater.has(position) ? 0 : (0.5 - WATER_WIDTH - Math.abs(c - 0.5)); let h = distToWater ? heightHill * (1 - Math.abs(c - 0.5) / (0.5 - WATER_WIDTH)) : g_Map.getHeight(position); // add some base noise - var baseNoise = 16*noise0.get(x,z) + 8*noise1.get(x,z) + 4*noise2.get(x,z) - (16+8+4)/2; + let baseNoise = + 16 * noise0.get(x, z) + + 8 * noise1.get(x, z) + + 4 * noise2.get(x, z) - + (16 + 8 + 4) / 2; if ( baseNoise < 0 ) { baseNoise *= pn; baseNoise *= Math.max(0.1, distToWater / (0.5 - WATER_WIDTH)); } const oldH = h; h += baseNoise; // add some higher-frequency noise on land if ( oldH > 0 ) h += (0.4 * noise2a.get(x,z) + 0.2 * noise2b.get(x,z)) * Math.min(oldH / 10, 1); // create cliff noise if ( h > -10 ) { let cliffNoise = (noise3.get(x,z) + 0.5*noise4.get(x,z)) / 1.5; if (h < 1) { var u = 1 - 0.3*((h-1)/-10); cliffNoise *= u; } cliffNoise += 0.05 * distToWater / (0.5 - WATER_WIDTH); if (cliffNoise > 0.6) { var u = 0.8 * (cliffNoise - 0.6); cliffNoise += u * noise5.get(x,z); cliffNoise /= (1 + u); } cliffNoise -= 0.59; cliffNoise *= pn; if (cliffNoise > 0) h += 19 * Math.min(cliffNoise, 0.045) / 0.045; } g_Map.setHeight(position, h); } Engine.SetProgress(20); g_Map.log("Painting terrain"); -var noise6 = new Noise2D(scaleByMapSize(10, 40)); -var noise7 = new Noise2D(scaleByMapSize(20, 80)); -var noise8 = new Noise2D(scaleByMapSize(13, 52)); -var noise9 = new Noise2D(scaleByMapSize(26, 104)); -var noise10 = new Noise2D(scaleByMapSize(50, 200)); +const noise6 = new Noise2D(scaleByMapSize(10, 40)); +const noise7 = new Noise2D(scaleByMapSize(20, 80)); +const noise8 = new Noise2D(scaleByMapSize(13, 52)); +const noise9 = new Noise2D(scaleByMapSize(26, 104)); +const noise10 = new Noise2D(scaleByMapSize(50, 200)); -for (var ix = 0; ix < mapSize; ix++) - for (var iz = 0; iz < mapSize; iz++) +for (let ix = 0; ix < mapSize; ix++) + for (let iz = 0; iz < mapSize; iz++) { const position = new Vector2D(ix, iz); - var x = ix / (mapSize + 1.0); - var z = iz / (mapSize + 1.0); - var pn = playerNearness(x, z); + const x = ix / (mapSize + 1.0); + const z = iz / (mapSize + 1.0); + const pn = playerNearness(x, z); // Compute height difference let minH = +Infinity; let maxH = -Infinity; for (const vertex of g_TileVertices) { const height = g_Map.getHeight(Vector2D.add(position, vertex)); minH = Math.min(minH, height); maxH = Math.max(maxH, height); } - var diffH = maxH - minH; + const diffH = maxH - minH; // figure out if we're at the top of a cliff using min adjacent height - var minAdjHeight = minH; + let minAdjHeight = minH; if (maxH > 15) { - var maxNx = Math.min(ix + 2, mapSize); - var maxNz = Math.min(iz + 2, mapSize); + const maxNx = Math.min(ix + 2, mapSize); + const maxNz = Math.min(iz + 2, mapSize); for (let nx = Math.max(ix - 1, 0); nx <= maxNx; ++nx) for (let nz = Math.max(iz - 1, 0); nz <= maxNz; ++nz) minAdjHeight = Math.min(minAdjHeight, g_Map.getHeight(new Vector2D(nx, nz))); } // choose a terrain based on elevation let t = tGrass; // water if (maxH < -12) t = tOceanDepths; else if (maxH < -8.8) t = tOceanRockDeep; else if (maxH < -4.7) t = tOceanCoral; else if (maxH < -2.8) t = tOceanRockShallow; else if (maxH < 0.9 && minH < 0.35) t = tBeachWet; else if (maxH < 1.5 && minH < 0.9) t = tBeachDry; else if (maxH < 2.3 && minH < 1.3) t = tBeachGrass; if (minH < 0) clWater.add(position); // cliffs if (diffH > 2.9 && minH > -7) { t = tCliff; clCliff.add(position); } else if (diffH > 2.5 && minH > -5 || maxH - minAdjHeight > 2.9 && minH > 0) { if (minH < -1) t = tCliff; else if (minH < 0.5) t = tBeachCliff; else t = [tDirtCliff, tGrassCliff, tGrassCliff, tGrassRock, tCliff]; clCliff.add(position); } // Don't place resources onto potentially impassable mountains if (minH >= 20) clCliff.add(position); // forests if (g_Map.getHeight(position) < 11 && diffH < 2 && minH > 1) { - var forestNoise = (noise6.get(x,z) + 0.5*noise7.get(x,z)) / 1.5 * pn - 0.59; + const forestNoise = (noise6.get(x, z) + 0.5 * noise7.get(x, z)) / 1.5 * pn - 0.59; // Thin out trees a bit if (forestNoise > 0 && randBool()) { if (minH < 11 && minH >= 4) { const typeNoise = noise10.get(x,z); if (typeNoise < 0.43 && forestNoise < 0.05) t = pPoplarForest; else if (typeNoise < 0.63) t = pMainForest; else t = pPineForest; clForest.add(position); } else if (minH < 4) { t = pPalmForest; clForest.add(position); } } } // grass variations if (t == tGrass) { - var grassNoise = (noise8.get(x,z) + 0.6*noise9.get(x,z)) / 1.6; + const grassNoise = (noise8.get(x, z) + 0.6 * noise9.get(x, z)) / 1.6; if (grassNoise < 0.3) t = (diffH > 1.2) ? tDirtCliff : tDirt; else if (grassNoise < 0.34) { t = (diffH > 1.2) ? tGrassCliff : tGrassDry; if (diffH < 0.5 && randBool(0.02)) g_Map.placeEntityAnywhere(aGrassDry, 0, randomPositionOnTile(position), randomAngle()); } else if (grassNoise > 0.61) { t = (diffH > 1.2 ? tGrassRock : tGrassShrubs); } else if (diffH < 0.5 && randBool(0.02)) g_Map.placeEntityAnywhere(aGrass, 0, randomPositionOnTile(position), randomAngle()); } createTerrain(t).place(position); } Engine.SetProgress(30); placePlayerBases({ "PlayerPlacement": [primeSortAllPlayers(), playerPosition], "PlayerTileClass": clPlayer, "BaseResourceClass": clBaseResource, "baseResourceConstraint": avoidClasses(clCliff, 4), "CityPatch": { "radius": 11, "outerTerrain": tGrass, "innerTerrain": tCity, "width": 4, "painters": [ new SmoothElevationPainter(ELEVATION_SET, heightPlayer, 2) ] }, "StartingAnimal": { }, "Berries": { "template": oBerryBush, "distance": 9 }, "Mines": { "types": [ { "template": oMetalLarge }, { "template": oStoneLarge } ] }, "Trees": { "template": oPalm, "count": 5, "minDist": 10, "maxDist": 11 } // No decoratives }); Engine.SetProgress(40); g_Map.log("Creating bushes"); -var group = new SimpleGroup( +let group = new SimpleGroup( [new SimpleObject(aBushSmall, 0,2, 0,2), new SimpleObject(aBushSmallDry, 0,2, 0,2), new SimpleObject(aBushMed, 0,1, 0,2), new SimpleObject(aBushMedDry, 0,1, 0,2)] ); createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 4, clCliff, 2), scaleByMapSize(9, 146), 50 ); Engine.SetProgress(45); g_Map.log("Creating rocks"); group = new SimpleGroup( [new SimpleObject(aRockSmall, 0,3, 0,2), new SimpleObject(aRockMed, 0,2, 0,2), new SimpleObject(aRockLarge, 0,1, 0,2)] ); createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 2, clCliff, 1), scaleByMapSize(9, 146), 50 ); Engine.SetProgress(50); g_Map.log("Creating large stone mines"); 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); createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 1, clForest, 4, clPlayer, 40, clRock, 60, clMetal, 10, clCliff, 3), scaleByMapSize(4,16), 100 ); g_Map.log("Creating small stone mines"); group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroups(group, 0, avoidClasses(clForest, 4, clWater, 1, clPlayer, 40, clRock, 30, clMetal, 10, clCliff, 3), scaleByMapSize(4,16), 100 ); g_Map.log("Creating metal mines"); group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,2)], true, clMetal); createObjectGroups(group, 0, avoidClasses(clForest, 4, clWater, 1, clPlayer, 40, clMetal, 50, clCliff, 3), scaleByMapSize(4,16), 100 ); Engine.SetProgress(60); createStragglerTrees( [oCarob, oBeech, oLombardyPoplar, oLombardyPoplar, oPine], avoidClasses(clWater, 5, clCliff, 4, clForest, 2, clPlayer, 15, clMetal, 6, clRock, 6), clForest, scaleByMapSize(10, 190)); Engine.SetProgress(70); g_Map.log("Creating straggler cypresses"); group = new SimpleGroup( [new SimpleObject(oCypress2, 1,3, 0,3), new SimpleObject(oCypress1, 0,2, 0,2)], true ); createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 5, clCliff, 4, clForest, 2, clPlayer, 15, clMetal, 6, clRock, 6), scaleByMapSize(5, 75), 50 ); Engine.SetProgress(80); g_Map.log("Creating sheep"); group = new SimpleGroup([new SimpleObject(oSheep, 2,4, 0,2)], true, clFood); createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8), 3 * numPlayers, 50 ); Engine.SetProgress(85); g_Map.log("Creating fish"); createObjectGroups( new SimpleGroup([new SimpleObject(oFish, 1, 1, 0, 1)], true, clFood), 0, [ avoidClasses(clFood, 10), stayClasses(clWater, 4), new HeightConstraint(-Infinity, heightLand) ], scaleByMapSize(8, 32)); Engine.SetProgress(90); g_Map.log("Creating deer"); group = new SimpleGroup( [new SimpleObject(oDeer, 5,7, 0,4)], true, clFood ); createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8), 3 * numPlayers, 50 ); Engine.SetProgress(95); g_Map.log("Creating berry bushes"); group = new SimpleGroup([new SimpleObject(oBerryBush, 5,7, 0,3)], true, clFood); createObjectGroupsDeprecated(group, 0, avoidClasses(clWater, 5, clForest, 2, clCliff, 1, clPlayer, 20, clMetal, 6, clRock, 6, clFood, 8), 1.5 * numPlayers, 100 ); placePlayersNomad(clPlayer, avoidClasses(clWater, 4, clCliff, 2, clForest, 1, clMetal, 4, clRock, 4, clFood, 2)); setSkySet("sunny"); setWaterColor(0.024,0.262,0.224); setWaterTint(0.133, 0.325,0.255); setWaterWaviness(2.5); setWaterType("ocean"); setWaterMurkiness(0.8); g_Map.ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/snowflake_searocks.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/snowflake_searocks.js (revision 28100) +++ ps/trunk/binaries/data/mods/public/maps/random/snowflake_searocks.js (revision 28101) @@ -1,446 +1,445 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); TILE_CENTERED_HEIGHT_MAP = true; setSelectedBiome(); const tMainTerrain = g_Terrains.mainTerrain; const tForestFloor1 = g_Terrains.forestFloor1; const tForestFloor2 = g_Terrains.forestFloor2; const tCliff = g_Terrains.cliff; const tTier1Terrain = g_Terrains.tier1Terrain; const tTier2Terrain = g_Terrains.tier2Terrain; const tTier3Terrain = g_Terrains.tier3Terrain; const tHill = g_Terrains.mainTerrain; const tRoad = g_Terrains.road; const tRoadWild = g_Terrains.roadWild; const tTier4Terrain = g_Terrains.tier4Terrain; const tWater = g_Terrains.water; const oTree1 = g_Gaia.tree1; const oTree2 = g_Gaia.tree2; const oTree3 = g_Gaia.tree3; const oTree4 = g_Gaia.tree4; const oTree5 = g_Gaia.tree5; const oFruitBush = g_Gaia.fruitBush; const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal; const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; const oStoneLarge = g_Gaia.stoneLarge; const oStoneSmall = g_Gaia.stoneSmall; const oMetalLarge = g_Gaia.metalLarge; const aGrass = g_Decoratives.grass; const aGrassShort = g_Decoratives.grassShort; const aRockLarge = g_Decoratives.rockLarge; const aRockMedium = g_Decoratives.rockMedium; const aBushMedium = g_Decoratives.bushMedium; const aBushSmall = g_Decoratives.bushSmall; const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; const heightIsland = 20; const heightSeaGround = -5; const g_Map = new RandomMap(heightSeaGround, tWater); const numPlayers = getNumPlayers(); const mapSize = g_Map.getSize(); const mapCenter = g_Map.getCenter(); const clPlayer = g_Map.createTileClass(); const clForest = g_Map.createTileClass(); const clDirt = g_Map.createTileClass(); const clRock = g_Map.createTileClass(); const clMetal = g_Map.createTileClass(); const clFood = g_Map.createTileClass(); const clBaseResource = g_Map.createTileClass(); const clLand = g_Map.createTileClass(); const playerIslandRadius = scaleByMapSize(15, 30); const islandBetweenPlayerAndCenterDist = 0.16; const islandBetweenPlayerAndCenterRadius = 0.81; const centralIslandRadius = 0.36; -var [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); +const [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); -var numIslands = 0; -var isConnected = []; -var islandPos = []; +let numIslands = 0; +const isConnected = []; +const islandPos = []; function initIsConnected() { for (let m = 0; m < numIslands; ++m) { isConnected[m] = []; for (let n = 0; n < numIslands; ++n) isConnected[m][n] = 0; } } function createIsland(islandID, size, tileClass) { createArea( new ClumpPlacer(size * diskArea(playerIslandRadius), 0.95, 0.6, Infinity, islandPos[islandID]), [ new TerrainPainter(tHill), new SmoothElevationPainter(ELEVATION_SET, heightIsland, 2), new TileClassPainter(tileClass) ]); } function createIslandAtRadialLocation(playerID, islandID, playerIDOffset, distFromCenter, islandRadius) { const angle = startAngle + (playerID * 2 + playerIDOffset) * Math.PI / numPlayers; islandPos[islandID] = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(distFromCenter), 0).rotate(-angle)).round(); createIsland(islandID, islandRadius, clLand); } -function createSnowflakeSearockWithCenter(sizeID) +function createSnowflakeSearockWithCenter([tertiaryIslandDist, tertiaryIslandRadius, + islandBetweenPlayersDist, islandBetweenPlayersRadius]) { - const [tertiaryIslandDist, tertiaryIslandRadius, islandBetweenPlayersDist, islandBetweenPlayersRadius] = islandSizes[sizeID]; - const islandID_center = 4 * numPlayers; numIslands = islandID_center + 1; initIsConnected(); g_Map.log("Creating central island"); islandPos[islandID_center] = mapCenter; createIsland(islandID_center, centralIslandRadius, clLand); for (let playerID = 0; playerID < numPlayers; ++playerID) { const playerID_neighbor = playerID + 1 < numPlayers ? playerID + 1 : 0; const islandID_player = playerID; const islandID_playerNeighbor = playerID_neighbor; const islandID_betweenPlayers = playerID + numPlayers; const islandID_betweenPlayerAndCenter = playerID + 2 * numPlayers; const islandID_betweenPlayerAndCenterNeighbor = playerID_neighbor + 2 * numPlayers; const islandID_tertiary = playerID + 3 * numPlayers; g_Map.log("Creating island between the player and their neighbor"); isConnected[islandID_betweenPlayers][islandID_player] = 1; isConnected[islandID_betweenPlayers][islandID_playerNeighbor] = 1; createIslandAtRadialLocation(playerID, islandID_betweenPlayers, 1, islandBetweenPlayersDist, islandBetweenPlayersRadius); g_Map.log("Creating an island between the player and the center"); isConnected[islandID_betweenPlayerAndCenter][islandID_player] = 1; isConnected[islandID_betweenPlayerAndCenter][islandID_center] = 1; isConnected[islandID_betweenPlayerAndCenter][islandID_betweenPlayerAndCenterNeighbor] = 1; createIslandAtRadialLocation(playerID, islandID_betweenPlayerAndCenter, 0, islandBetweenPlayerAndCenterDist, islandBetweenPlayerAndCenterRadius); g_Map.log("Creating tertiary island, at the map border"); isConnected[islandID_tertiary][islandID_betweenPlayers] = 1; createIslandAtRadialLocation(playerID, islandID_tertiary, 1, tertiaryIslandDist, tertiaryIslandRadius); } } /** * Creates one island in front of every player and connects it with the neighbors. */ function createSnowflakeSearockWithoutCenter() { numIslands = 2 * numPlayers; initIsConnected(); for (let playerID = 0; playerID < numPlayers; ++playerID) { const playerID_neighbor = playerID + 1 < numPlayers ? playerID + 1 : 0; const islandID_player = playerID; const islandID_playerNeighbor = playerID_neighbor; const islandID_inFrontOfPlayer = playerID + numPlayers; const islandID_inFrontOfPlayerNeighbor = playerID_neighbor + numPlayers; isConnected[islandID_player][islandID_playerNeighbor] = 1; isConnected[islandID_player][islandID_inFrontOfPlayer] = 1; isConnected[islandID_inFrontOfPlayer][islandID_inFrontOfPlayerNeighbor] = 1; createIslandAtRadialLocation(playerID, islandID_inFrontOfPlayer, 0, islandBetweenPlayerAndCenterDist, islandBetweenPlayerAndCenterRadius); } } function createSnowflakeSearockTiny() { numIslands = numPlayers + 1; initIsConnected(); const islandID_center = numPlayers; g_Map.log("Creating central island"); islandPos[islandID_center] = mapCenter; createIsland(numPlayers, 1, clLand); for (let playerID = 0; playerID < numPlayers; ++playerID) { const islandID_player = playerID; isConnected[islandID_player][islandID_center] = 1; } } const islandSizes = { "medium": [0.41, 0.49, 0.26, 1], "large1": [0.41, 0.49, 0.24, 1], "large2": [0.41, 0.36, 0.28, 0.81] }; if (mapSize <= 128) { createSnowflakeSearockTiny(); } else if (mapSize <= 192) { createSnowflakeSearockWithoutCenter(); } else if (mapSize <= 256) { if (numPlayers < 6) - createSnowflakeSearockWithCenter("medium"); + createSnowflakeSearockWithCenter(islandSizes.medium); else createSnowflakeSearockWithoutCenter(); } else if (mapSize <= 320) { if (numPlayers < 8) - createSnowflakeSearockWithCenter("medium"); + createSnowflakeSearockWithCenter(islandSizes.medium); else createSnowflakeSearockWithoutCenter(); } else - createSnowflakeSearockWithCenter(numPlayers < 6 ? "large1" : "large2"); + createSnowflakeSearockWithCenter(islandSizes["large" + (numPlayers < 6 ? "1" : "2")]); g_Map.log("Creating player islands"); for (let i = 0; i < numPlayers; ++i) { islandPos[i] = playerPosition[i]; createIsland(i, 1, isNomad() ? clLand : clPlayer); } g_Map.log("Creating connectors"); for (let i = 0; i < numIslands; ++i) for (let j = 0; j < numIslands; ++j) if (isConnected[i][j]) createArea( new PathPlacer(islandPos[i], islandPos[j], 11, 0, 1, 0, 0, Infinity), [ new SmoothElevationPainter(ELEVATION_SET, heightIsland, 2), new TerrainPainter(tHill), new TileClassPainter(clLand) ]); g_Map.log("Painting cliffs"); createArea( new MapBoundsPlacer(), new TerrainPainter(tCliff), new SlopeConstraint(2, Infinity)); Engine.SetProgress(30); placePlayerBases({ "PlayerPlacement": [playerIDs, playerPosition], // PlayerTileClass already marked above "BaseResourceClass": clBaseResource, "baseResourceConstraint": stayClasses(clPlayer, 4), "Walls": "towers", "CityPatch": { "outerTerrain": tRoadWild, "innerTerrain": tRoad }, "StartingAnimal": { }, "Berries": { "template": oFruitBush, "distance": playerIslandRadius - 4 }, "Mines": { "types": [ { "template": oMetalLarge }, { "template": oStoneLarge } ], "distance": playerIslandRadius - 4 }, "Trees": { "template": oTree1, "count": scaleByMapSize(10, 50), "minDist": 11, "maxDist": 11 }, "Decoratives": { "template": aGrassShort } }); Engine.SetProgress(40); g_Map.log("Creating forests"); const [forestTrees, stragglerTrees] = getTreeCounts(...rBiomeTreeCount(1)); const types = [ [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] ]; const forestSize = forestTrees / (scaleByMapSize(2, 8) * numPlayers) * (currentBiome() == "generic/savanna" ? 2 : 1); const num = Math.floor(forestSize / types.length); for (const type of types) createAreas( new ClumpPlacer(forestTrees / num, 0.1, 0.1, Infinity), [ new LayeredPainter(type, [2]), new TileClassPainter(clForest) ], [avoidClasses(clPlayer, 6, clForest, 10), stayClasses(clLand, 4)], num); Engine.SetProgress(55); g_Map.log("Creating stone mines"); let 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); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10), stayClasses(clLand, 5)], 5*scaleByMapSize(4,16), 100 ); g_Map.log("Creating small stone quarries"); group = new SimpleGroup([new SimpleObject(oStoneSmall, 2,5, 1,3)], true, clRock); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10), stayClasses(clLand, 5)], 5*scaleByMapSize(4,16), 100 ); g_Map.log("Creating metal mines"); group = new SimpleGroup([new SimpleObject(oMetalLarge, 1,1, 0,4)], true, clMetal); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5), stayClasses(clLand, 5)], 5*scaleByMapSize(4,16), 100 ); Engine.SetProgress(65); g_Map.log("Creating dirt patches"); for (const size of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) createAreas( new ClumpPlacer(size, 0.3, 0.06, 0.5), [ new LayeredPainter([[tMainTerrain, tTier1Terrain],[tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]), new TileClassPainter(clDirt) ], [avoidClasses(clForest, 0, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)], scaleByMapSize(15, 45)); g_Map.log("Creating grass patches"); for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) createAreas( new ClumpPlacer(size, 0.3, 0.06, 0.5), new TerrainPainter(tTier4Terrain), [avoidClasses(clForest, 0, clDirt, 5, clPlayer, 12), stayClasses(clLand, 5)], scaleByMapSize(15, 45)); g_Map.log("Creating small decorative rocks"); group = new SimpleGroup( [new SimpleObject(aRockMedium, 1,3, 0,1)], true ); createObjectGroupsDeprecated( group, 0, [avoidClasses(clForest, 0, clPlayer, 0), stayClasses(clLand, 4)], scaleByMapSize(16, 262), 50 ); g_Map.log("Creating large decorative rocks"); group = new SimpleGroup( [new SimpleObject(aRockLarge, 1,2, 0,1), new SimpleObject(aRockMedium, 1,3, 0,2)], true ); createObjectGroupsDeprecated( group, 0, [avoidClasses(clForest, 0, clPlayer, 0), stayClasses(clLand, 4)], scaleByMapSize(8, 131), 50 ); Engine.SetProgress(70); g_Map.log("Creating deer"); group = new SimpleGroup( [new SimpleObject(oMainHuntableAnimal, 5,7, 0,4)], true, clFood ); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 0, clPlayer, 10, clFood, 20), stayClasses(clLand, 4)], 3 * numPlayers, 50 ); Engine.SetProgress(75); g_Map.log("Creating sheep"); group = new SimpleGroup( [new SimpleObject(oSecondaryHuntableAnimal, 2,3, 0,2)], true, clFood ); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 0, clPlayer, 10, clFood, 20), stayClasses(clLand, 4)], 3 * numPlayers, 50 ); g_Map.log("Creating fruits"); group = new SimpleGroup( [new SimpleObject(oFruitBush, 5,7, 0,4)], true, clFood ); createObjectGroupsDeprecated(group, 0, [avoidClasses(clForest, 0, clPlayer, 10, clFood, 20), stayClasses(clLand, 4)], 3 * numPlayers, 50 ); Engine.SetProgress(85); createStragglerTrees( [oTree1, oTree2, oTree4, oTree3], [avoidClasses(clForest, 1, clPlayer, 9, clMetal, 6, clRock, 6), stayClasses(clLand, 4)], clForest, stragglerTrees); let planetm = 1; if (currentBiome() == "generic/india") planetm = 8; g_Map.log("Creating small grass tufts"); group = new SimpleGroup( [new SimpleObject(aGrassShort, 1,2, 0,1, -Math.PI / 8, Math.PI / 8)] ); createObjectGroupsDeprecated(group, 0, [avoidClasses(clPlayer, 2, clDirt, 0), stayClasses(clLand, 4)], 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(clPlayer, 2, clDirt, 1, clForest, 0), stayClasses(clLand, 4)], 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(clPlayer, 1, clDirt, 1), stayClasses(clLand, 4)], planetm * scaleByMapSize(13, 200), 50 ); placePlayersNomad( clPlayer, [ stayClasses(clLand, 8), avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clFood, 2) ]); setSkySet(pickRandom(["cirrus", "cumulus", "sunny"])); setSunRotation(randomAngle()); setSunElevation(Math.PI * randFloat(1/5, 1/3)); g_Map.ExportMap(); Index: ps/trunk/binaries/data/mods/public/maps/random/unknown.js =================================================================== --- ps/trunk/binaries/data/mods/public/maps/random/unknown.js (revision 28100) +++ ps/trunk/binaries/data/mods/public/maps/random/unknown.js (revision 28101) @@ -1,1078 +1,1078 @@ Engine.LoadLibrary("rmgen"); Engine.LoadLibrary("rmgen-common"); Engine.LoadLibrary("rmbiome"); TILE_CENTERED_HEIGHT_MAP = true; setSelectedBiome(); const tMainTerrain = g_Terrains.mainTerrain; const tForestFloor1 = g_Terrains.forestFloor1; const tForestFloor2 = g_Terrains.forestFloor2; const tCliff = g_Terrains.cliff; const tTier1Terrain = g_Terrains.tier1Terrain; const tTier2Terrain = g_Terrains.tier2Terrain; const tTier3Terrain = g_Terrains.tier3Terrain; const tHill = g_Terrains.hill; const tRoad = g_Terrains.road; const tRoadWild = g_Terrains.roadWild; const tTier4Terrain = g_Terrains.tier4Terrain; const tShore = g_Terrains.shore; const tWater = g_Terrains.water; const oTree1 = g_Gaia.tree1; const oTree2 = g_Gaia.tree2; const oTree4 = g_Gaia.tree4; const oTree5 = g_Gaia.tree5; const oFruitBush = g_Gaia.fruitBush; const oMainHuntableAnimal = g_Gaia.mainHuntableAnimal; const oSecondaryHuntableAnimal = g_Gaia.secondaryHuntableAnimal; const oFish = g_Gaia.fish; const oStoneLarge = g_Gaia.stoneLarge; const oStoneSmall = g_Gaia.stoneSmall; const oMetalLarge = g_Gaia.metalLarge; const oWoodTreasure = "gaia/treasure/wood"; const aGrass = g_Decoratives.grass; const aGrassShort = g_Decoratives.grassShort; const aReeds = g_Decoratives.reeds; const aLillies = g_Decoratives.lillies; const aRockLarge = g_Decoratives.rockLarge; const aRockMedium = g_Decoratives.rockMedium; const aBushMedium = g_Decoratives.bushMedium; const aBushSmall = g_Decoratives.bushSmall; const pForest1 = [tForestFloor2 + TERRAIN_SEPARATOR + oTree1, tForestFloor2 + TERRAIN_SEPARATOR + oTree2, tForestFloor2]; const pForest2 = [tForestFloor1 + TERRAIN_SEPARATOR + oTree4, tForestFloor1 + TERRAIN_SEPARATOR + oTree5, tForestFloor1]; const heightSeaGround = -5; const heightLand = 3; const heightCliff = 3.12; const heightHill = 18; const heightOffsetBump = 2; const g_Map = new RandomMap(heightSeaGround, tWater); const numPlayers = getNumPlayers(); const mapSize = g_Map.getSize(); const mapCenter = g_Map.getCenter(); const mapBounds = g_Map.getBounds(); const clPlayer = g_Map.createTileClass(); const clPlayerTerritory = g_Map.createTileClass(); const clHill = g_Map.createTileClass(); const clForest = g_Map.createTileClass(); const clWater = g_Map.createTileClass(); const clDirt = g_Map.createTileClass(); const clRock = g_Map.createTileClass(); const clMetal = g_Map.createTileClass(); const clFood = g_Map.createTileClass(); const clPeninsulaSteam = g_Map.createTileClass(); const clBaseResource = g_Map.createTileClass(); const clLand = g_Map.createTileClass(); const clShallow = g_Map.createTileClass(); -var landElevationPainter = new SmoothElevationPainter(ELEVATION_SET, heightLand, 4); +const landElevationPainter = new SmoothElevationPainter(ELEVATION_SET, heightLand, 4); -var unknownMapFunctions = { +const unknownMapFunctions = { "land": [ "Continent", "Isthmus", "CentralRiverLand", "EdgeSeas", "Gulf", "Lakes", "Passes", "Lowlands", "Mainland" ], "naval": [ "CentralSea", "CentralRiverNaval", "Archipelago", "RiversAndLake" ] }; /** * The player IDs and locations shall only be determined by the landscape functions if it's not a nomad game, * because nomad maps randomize the locations after the terrain generation. * The locations should only determined by the landscape functions to avoid placing bodies of water and resources into civic centers and the starting resources. */ -var playerIDs = sortAllPlayers(); -var playerPosition = []; +let playerIDs = sortAllPlayers(); +let playerPosition = []; -var g_StartingTreasures = false; -var g_StartingWalls = true; +let g_StartingTreasures = false; +let g_StartingWalls = true; function createUnknownMap() { const landscape = g_MapSettings.Landscape || pickRandom([...unknownMapFunctions.land, ...unknownMapFunctions.naval]); global["unknown" + landscape](); paintUnknownMapBasedOnHeight(); createUnknownPlayerBases(); createUnknownObjects(); placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clMetal, 4, clRock, 4, clHill, 4, clFood, 2, clWater, 10)); } /** * Chain of islands or many disconnected islands. */ function unknownArchipelago() { g_StartingWalls = "towers"; g_StartingTreasures = true; const [pIDs, islandPosition] = playerPlacementCircle(fractionToTiles(0.35)); if (!isNomad()) { [playerIDs, playerPosition] = [pIDs, islandPosition]; markPlayerArea("large"); } g_Map.log("Creating islands"); const islandSize = diskArea(scaleByMapSize(17, 29)); for (let i = 0; i < numPlayers; ++i) createArea( new ClumpPlacer(islandSize, 0.8, 0.1, Infinity, islandPosition[i]), landElevationPainter); const type = isNomad() ? randIntInclusive(1, 2) : randIntInclusive(1, 3); if (type == 1) { g_Map.log("Creating archipelago"); createAreas( new ClumpPlacer(islandSize * randFloat(0.8, 1.2), 0.8, 0.1, Infinity), [ landElevationPainter, new TileClassPainter(clLand) ], null, scaleByMapSize(2, 5) * randIntInclusive(8, 14)); g_Map.log("Creating shore jaggedness with small puddles"); createAreas( new ClumpPlacer(scaleByMapSize(15, 80), 0.2, 0.1, Infinity), [ new SmoothElevationPainter(ELEVATION_SET, heightLand, 4), new TileClassPainter(clLand) ], borderClasses(clLand, 6, 3), scaleByMapSize(12, 130) * 2, 150); } else if (type == 2) { g_Map.log("Creating islands"); createAreas( new ClumpPlacer(islandSize * randFloat(0.6, 1.4), 0.8, 0.1, randFloat(0.0, 0.2)), [ landElevationPainter, new TileClassPainter(clLand) ], avoidClasses(clLand, 3, clPlayerTerritory, 3), scaleByMapSize(6, 10) * randIntInclusive(8, 14)); g_Map.log("Creating small islands"); createAreas( new ClumpPlacer(islandSize * randFloat(0.3, 0.7), 0.8, 0.1, 0.07), [ new SmoothElevationPainter(ELEVATION_SET, heightLand, 6), new TileClassPainter(clLand) ], avoidClasses(clLand, 3, clPlayerTerritory, 3), scaleByMapSize(2, 6) * randIntInclusive(6, 15), 25); } else if (type == 3) { g_Map.log("Creating tight islands"); createAreas( new ClumpPlacer(islandSize * randFloat(0.8, 1.2), 0.8, 0.1, Infinity), [ landElevationPainter, new TileClassPainter(clLand) ], avoidClasses(clLand, randIntInclusive(8, 16), clPlayerTerritory, 3), scaleByMapSize(2, 5) * randIntInclusive(8, 14)); } } /** * Disk shaped mainland with water on the edge. */ function unknownContinent() { const waterHeight = -5; if (!isNomad()) { g_Map.log("Ensuring player area"); [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.25)); markPlayerArea("small"); for (let i = 0; i < numPlayers; ++i) createArea( new ChainPlacer( 2, Math.floor(scaleByMapSize(5, 9)), Math.floor(scaleByMapSize(5, 20)), Infinity, playerPosition[i], 0, [Math.floor(scaleByMapSize(23, 50))]), [ landElevationPainter, new TileClassPainter(clLand) ]); } g_Map.log("Creating continent"); createArea( new ClumpPlacer(diskArea(fractionToTiles(0.38)), 0.9, 0.09, Infinity, mapCenter), [ landElevationPainter, new TileClassPainter(clLand) ]); if (randBool(1/3)) { g_Map.log("Creating peninsula (i.e. half the map not being surrounded by water)"); const angle = randomAngle(); const peninsulaPosition1 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.25), 0).rotate(-angle)); createArea( new ClumpPlacer(diskArea(fractionToTiles(0.38)), 0.9, 0.09, Infinity, peninsulaPosition1), [ landElevationPainter, new TileClassPainter(clLand) ]); g_Map.log("Remembering to not paint shorelines into the peninsula"); const peninsulaPosition2 = Vector2D.add(mapCenter, new Vector2D(fractionToTiles(0.35), 0).rotate(-angle)); createArea( new ClumpPlacer(diskArea(fractionToTiles(0.33)), 0.9, 0.01, Infinity, peninsulaPosition2), new TileClassPainter(clPeninsulaSteam)); } createShoreJaggedness(waterHeight, clLand, 7); } function unknownCentralSea() { unknownCentralSeaOrIsthmus(false); } function unknownIsthmus() { unknownCentralSeaOrIsthmus(true); } /** * Creates a huge central river, possibly connecting the riversides with a narrow piece of land. */ function unknownCentralSeaOrIsthmus(isthmus) { const waterHeight = -3; const startAngle = randomAngle(); const [riverStart, riverEnd] = centralRiverCoordinates(startAngle); paintRiver({ "parallel": false, "start": riverStart, "end": riverEnd, "width": fractionToTiles(scaleByMapSize(0.27, 0.42) + randFloat(0, 0.08)), "fadeDist": scaleByMapSize(3, 12), "deviation": 0, "heightRiverbed": waterHeight, "heightLand": heightLand, "meanderShort": 20, "meanderLong": 0, "waterFunc": (position, height, riverFraction) => { if (height < 0) clWater.add(position); }, "landFunc": (position, shoreDist1, shoreDist2) => { g_Map.setHeight(position, 3.1); clLand.add(position); } }); if (!isNomad()) { [playerIDs, playerPosition] = playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.6)); markPlayerArea("small"); } if (isthmus) { g_Map.log("Creating isthmus (i.e. connecting the two riversides with a big land passage)"); const [isthmusStart, isthmusEnd] = centralRiverCoordinates(startAngle + Math.PI / 2); createArea( new PathPlacer( isthmusStart, isthmusEnd, scaleByMapSize(randIntInclusive(16, 24), randIntInclusive(100, 140)), 0.5, 3 * scaleByMapSize(1, 4), 0.1, 0.01), [ landElevationPainter, new TileClassPainter(clLand), new TileClassUnPainter(clWater) ]); } createExtensionsOrIslands(); // Don't createShoreJaggedness since it doesn't fit artistically here } function unknownCentralRiverLand() { unknownCentralRiver(true); } function unknownCentralRiverNaval() { unknownCentralRiver(false); } /** * Creates a very small central river. */ function unknownCentralRiver(shallows) { const waterHeight = -4; const heightShallow = -2; createArea( new MapBoundsPlacer(), new ElevationPainter(heightLand)); const startAngle = randomAngle(); if (!isNomad()) { [playerIDs, playerPosition] = playerPlacementRiver(startAngle + Math.PI / 2, fractionToTiles(0.5)); markPlayerArea("large"); } g_Map.log("Creating the main river"); const [coord1, coord2] = centralRiverCoordinates(startAngle); createArea( new PathPlacer(coord1, coord2, scaleByMapSize(14, 24), 0.5, scaleByMapSize(3, 12), 0.1, 0.01), new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), avoidClasses(clPlayerTerritory, 4)); g_Map.log("Creating small water spots at the map border to ensure separation of players"); for (const coord of [coord1, coord2]) createArea( new ClumpPlacer(diskArea(scaleByMapSize(5, 10)), 0.95, 0.6, Infinity, coord), new SmoothElevationPainter(ELEVATION_SET, waterHeight, 2), avoidClasses(clPlayerTerritory, 8)); if (shallows) { g_Map.log("Creating the shallows of the main river"); for (let i = 0; i <= randIntInclusive(1, scaleByMapSize(4, 8)); ++i) { const location = fractionToTiles(randFloat(0.15, 0.85)); createPassage({ "start": new Vector2D(location, mapBounds.top).rotateAround(startAngle, mapCenter), "end": new Vector2D(location, mapBounds.bottom).rotateAround(startAngle, mapCenter), "startWidth": scaleByMapSize(8, 12), "endWidth": scaleByMapSize(8, 12), "smoothWidth": 2, "startHeight": heightShallow, "endHeight": heightShallow, "constraints": new HeightConstraint(-Infinity, heightShallow), "tileClass": clShallow }); } } if (randBool(2/3)) createTributaryRivers( startAngle, randIntInclusive(8, scaleByMapSize(12, 16)), scaleByMapSize(10, 20), -4, [-6, -1.5], Math.PI / 5, clWater, clShallow, avoidClasses(clPlayerTerritory, 3)); } /** * Creates a circular lake in the middle and possibly a river between each player ("pizza slices"). */ function unknownRiversAndLake() { const waterHeight = -4; createArea( new MapBoundsPlacer(), new ElevationPainter(heightLand)); let startAngle; if (!isNomad()) { let playerAngle; [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); markPlayerArea("small"); } const lake = randBool(3/4); if (lake) { g_Map.log("Creating lake"); createArea( new ClumpPlacer(diskArea(fractionToTiles(0.17)), 0.7, 0.1, Infinity, mapCenter), [ new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), new TileClassPainter(clWater) ]); createShoreJaggedness(waterHeight, clWater, 3); } // TODO: On nomad because the resource imbalances per island are too drastic { g_Map.log("Creating small rivers separating players"); for (const river of distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.5), mapCenter)[0]) { createArea( new PathPlacer(mapCenter, river, scaleByMapSize(14, 24), 0.4, 3 * scaleByMapSize(1, 3), 0.2, 0.05), [ new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), new TileClassPainter(clWater) ], avoidClasses(clPlayer, 5)); createArea( new ClumpPlacer(diskArea(scaleByMapSize(4, 22)), 0.95, 0.6, Infinity, river), [ new SmoothElevationPainter(ELEVATION_SET, waterHeight, 0), new TileClassPainter(clWater) ], avoidClasses(clPlayer, 5)); } g_Map.log("Creating small lake"); createArea( new ClumpPlacer(diskArea(fractionToTiles(0.04)), 0.7, 0.1, Infinity, mapCenter), [ new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), new TileClassPainter(clWater) ]); } if (!isNomad && lake && randBool(2/3)) { g_Map.log("Creating small central island"); createArea( new ClumpPlacer(diskArea(fractionToTiles(0.05)), 0.7, 0.1, Infinity, mapCenter), [ landElevationPainter, new TileClassPainter(clWater) ]); } } /** * Align players on a land strip with seas bordering on one or both sides that can hold islands. */ function unknownEdgeSeas() { const waterHeight = -4; createArea( new MapBoundsPlacer(), new ElevationPainter(heightLand)); const startAngle = randomAngle(); if (!isNomad()) { playerIDs = sortAllPlayers(); playerPosition = playerPlacementLine(startAngle + Math.PI / 2, mapCenter, fractionToTiles(0.2)); // Don't place the shoreline inside the CC, but possibly into the players territory markPlayerArea("small"); } for (const side of pickRandom([[0], [Math.PI], [0, Math.PI]])) paintRiver({ "parallel": true, "start": new Vector2D(mapBounds.left, mapBounds.top).rotateAround(side + startAngle, mapCenter), "end": new Vector2D(mapBounds.left, mapBounds.bottom).rotateAround(side + startAngle, mapCenter), "width": scaleByMapSize(80, randFloat(270, 320)), "fadeDist": scaleByMapSize(2, 8), "deviation": 0, "heightRiverbed": waterHeight, "heightLand": heightLand, "meanderShort": 20, "meanderLong": 0 }); createExtensionsOrIslands(); paintTileClassBasedOnHeight(0, heightCliff, 1, clLand); createShoreJaggedness(waterHeight, clLand, 7, false); } /** * Land shaped like a concrescent moon around a central lake. */ function unknownGulf() { const waterHeight = -3; createArea( new MapBoundsPlacer(), new ElevationPainter(heightLand)); const startAngle = randomAngle(); if (!isNomad()) { g_Map.log("Determining player locations"); playerPosition = playerPlacementCustomAngle( fractionToTiles(0.35), mapCenter, i => startAngle + 2/3 * Math.PI * (-1 + (numPlayers == 1 ? 1 : 2 * i / (numPlayers - 1))))[0]; markPlayerArea("large"); } const gulfParts = [ { "radius": fractionToTiles(0.16), "distance": fractionToTiles(0) }, { "radius": fractionToTiles(0.2), "distance": fractionToTiles(0.2) }, { "radius": fractionToTiles(0.22), "distance": fractionToTiles(0.49) } ]; for (const gulfPart of gulfParts) { const position = Vector2D.sub(mapCenter, new Vector2D(gulfPart.distance, 0).rotate(-startAngle)).round(); createArea( new ClumpPlacer(diskArea(gulfPart.radius), 0.7, 0.05, Infinity, position), [ new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4), new TileClassPainter(clWater) ], avoidClasses(clPlayerTerritory, defaultPlayerBaseRadius())); } } /** * Mainland style with some small random lakes. */ function unknownLakes() { const waterHeight = -5; createArea( new MapBoundsPlacer(), new ElevationPainter(heightLand)); if (!isNomad()) { [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); markPlayerArea("large"); } g_Map.log("Creating lakes"); createAreas( new ClumpPlacer(scaleByMapSize(160, 700), 0.2, 0.1, Infinity), [ new SmoothElevationPainter(ELEVATION_SET, waterHeight, 5), new TileClassPainter(clWater) ], [avoidClasses(clPlayerTerritory, 12), randBool() ? avoidClasses(clWater, 8) : new NullConstraint()], scaleByMapSize(5, 16)); } /** * A large hill leaving players only a small passage to each of the the two neighboring players. */ function unknownPasses() { const heightMountain = 24; const waterHeight = -4; createArea( new MapBoundsPlacer(), new ElevationPainter(heightLand)); let playerAngle; let startAngle; if (!isNomad()) { [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); markPlayerArea("small"); } else startAngle = randomAngle(); g_Map.log("Creating a mountain range between neighboring players"); for (const mountain of distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, fractionToTiles(0.5), mapCenter)[0]) { createArea( new PathPlacer(mapCenter, mountain, scaleByMapSize(14, 24), 0.4, 3 * scaleByMapSize(1, 3), 0.2, 0.05), [ // More smoothing than this often results in the mountainrange becoming passable to one player. new SmoothElevationPainter(ELEVATION_SET, heightMountain, 1), new TileClassPainter(clWater) ], avoidClasses(clPlayer, 5)); // Small mountain at the map border between the players to ensure separation of players createArea( new ClumpPlacer(diskArea(scaleByMapSize(4, 22)), 0.95, 0.6, Infinity, mountain), new SmoothElevationPainter(ELEVATION_SET, heightMountain, 0), avoidClasses(clPlayer, 5)); } g_Map.log("Creating passages between neighboring players"); const passes = numPlayers == 2 && distributePointsOnCircle(numPlayers * 3, startAngle, fractionToTiles(0.35), mapCenter)[0]; for (let i = 0; i < numPlayers && numPlayers > 1; ++i) { // For numPlayers > 2 use the playerPosition to not end up inside the mountains. createArea( new PathPlacer( numPlayers == 2 ? passes[3 * i + 1] : playerPosition[i], numPlayers == 2 ? passes[3 * i + 2] : playerPosition[(i + 1) % numPlayers], scaleByMapSize(14, 24), 0.4, 3 * scaleByMapSize(1, 3), 0.2, 0.05), new SmoothElevationPainter(ELEVATION_SET, heightLand, 2)); } if (randBool(2/5)) { g_Map.log("Create central lake"); createArea( new ClumpPlacer(diskArea(fractionToTiles(0.1)), 0.7, 0.1, Infinity, mapCenter), [ new SmoothElevationPainter(ELEVATION_SET, waterHeight, 3), new TileClassPainter(clWater) ]); } else { g_Map.log("Fill area between the paths"); createArea( new ClumpPlacer(diskArea(fractionToTiles(0.05)), 0.7, 0.1, Infinity, mapCenter), [ new SmoothElevationPainter(ELEVATION_SET, heightMountain, 4), new TileClassPainter(clWater) ]); } } /** * Land enclosed by a hill that leaves small areas for civic centers and large central place. */ function unknownLowlands() { const heightMountain = 30; g_Map.log("Creating mountain that is going to separate players"); createArea( new MapBoundsPlacer(), new ElevationPainter(heightMountain)); let playerAngle; let startAngle; if (!isNomad()) { [playerIDs, playerPosition, playerAngle, startAngle] = playerPlacementCircle(fractionToTiles(0.35)); markPlayerArea("small"); } else startAngle = randomAngle(); g_Map.log("Creating valleys enclosed by the mountain"); let valleys = numPlayers; if (mapSize >= 128 && numPlayers <= 2 || mapSize >= 192 && numPlayers <= 3 || mapSize >= 320 && numPlayers <= 4 || mapSize >= 384 && numPlayers <= 5 || mapSize >= 448 && numPlayers <= 6) valleys *= 2; g_Map.log("Creating player valley"); for (const valley of distributePointsOnCircle(valleys, startAngle, fractionToTiles(0.35), mapCenter)[0]) { createArea( new ClumpPlacer(diskArea(scaleByMapSize(18, 32)), 0.65, 0.1, Infinity, valley), [ new SmoothElevationPainter(ELEVATION_SET, heightLand, 2), new TileClassPainter(clLand) ]); // Passage from player to center createArea( new PathPlacer(mapCenter, valley, scaleByMapSize(14, 24), 0.4, 3 * scaleByMapSize(1, 3), 0.2, 0.05), [ landElevationPainter, new TileClassPainter(clWater) ]); } g_Map.log("Creating the big central area"); createArea( new ClumpPlacer(diskArea(fractionToTiles(0.18)), 0.7, 0.1, Infinity, mapCenter), [ landElevationPainter, new TileClassPainter(clWater) ]); } /** * No water, no hills. */ function unknownMainland() { createArea( new MapBoundsPlacer(), new ElevationPainter(3)); if (!isNomad()) { [playerIDs, playerPosition] = playerPlacementCircle(fractionToTiles(0.35)); markPlayerArea("small"); } } function centralRiverCoordinates(angle) { return [ new Vector2D(mapBounds.left + 1, mapCenter.y), new Vector2D(mapBounds.right - 1, mapCenter.y) ].map(v => v.rotateAround(angle, mapCenter)); } function createShoreJaggedness(waterHeight, borderClass, shoreDist, inwards = true) { g_Map.log("Creating shore jaggedness"); for (let i = 0; i < 2; ++i) if (i || inwards) createAreas( new ChainPlacer(2, Math.floor(scaleByMapSize(4, 6)), 15, Infinity), [ new SmoothElevationPainter(ELEVATION_SET, i ? heightLand : waterHeight, 4), i ? new TileClassPainter(clLand) : new TileClassUnPainter(clLand) ], [ avoidClasses(clPlayer, 20, clPeninsulaSteam, 20), borderClasses(borderClass, shoreDist, shoreDist) ], scaleByMapSize(7, 130) * 2, 150); } function createExtensionsOrIslands() { const rnd = randIntInclusive(1, 3); if (rnd == 1) { g_Map.log("Creating islands"); createAreas( new ClumpPlacer(Math.square(randIntInclusive(scaleByMapSize(8, 15), scaleByMapSize(15, 23))), 0.8, 0.1, randFloat(0, 0.2)), [ landElevationPainter, new TileClassPainter(clLand) ], avoidClasses(clLand, 3, clPlayer, 3), scaleByMapSize(2, 5) * randIntInclusive(8, 14)); } else if (rnd == 2) { g_Map.log("Creating extentions"); createAreas( new ChainPlacer(Math.floor(scaleByMapSize(4, 7)), Math.floor(scaleByMapSize(7, 10)), Math.floor(scaleByMapSize(16, 40)), 0.07), [ landElevationPainter, new TileClassPainter(clLand) ], null, scaleByMapSize(2, 5) * randIntInclusive(8, 14)); } } /** * Prevent impassable terrain and resource collisions at the the civic center and starting resources. */ function markPlayerArea(size) { for (let i = 0; i < numPlayers; ++i) { addCivicCenterAreaToClass(playerPosition[i], clPlayer); if (size == "large") createArea( new ClumpPlacer(diskArea(scaleByMapSize(17, 29) / 3), 0.6, 0.3, Infinity, playerPosition[i]), new TileClassPainter(clPlayerTerritory)); } } function paintUnknownMapBasedOnHeight() { paintTerrainBasedOnHeight(heightCliff, 40, 1, tCliff); paintTerrainBasedOnHeight(3, heightCliff, 1, tMainTerrain); paintTerrainBasedOnHeight(1, 3, 1, tShore); paintTerrainBasedOnHeight(-8, 1, 2, tWater); unPaintTileClassBasedOnHeight(0, heightCliff, 1, clWater); unPaintTileClassBasedOnHeight(-6, 0, 1, clLand); paintTileClassBasedOnHeight(-6, 0, 1, clWater); paintTileClassBasedOnHeight(0, heightCliff, 1, clLand); paintTileClassBasedOnHeight(heightCliff, 40, 1, clHill); } /** * Place resources and decoratives after the player territory was marked. */ function createUnknownObjects() { g_Map.log("Creating bumps"); createAreas( new ClumpPlacer(scaleByMapSize(20, 50), 0.3, 0.06, Infinity), new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBump, 2), [avoidClasses(clWater, 2, clPlayer, 10), stayClasses(clLand, 3)], randIntInclusive(0, scaleByMapSize(1, 2) * 200)); g_Map.log("Creating hills"); createAreas( new ClumpPlacer(scaleByMapSize(20, 150), 0.2, 0.1, Infinity), [ new LayeredPainter([tCliff, tHill], [2]), new SmoothElevationPainter(ELEVATION_SET, heightHill, 2), new TileClassPainter(clHill) ], [avoidClasses(clPlayer, 15, clHill, randIntInclusive(6, 18)), stayClasses(clLand, 0)], randIntInclusive(0, scaleByMapSize(4, 8))*randIntInclusive(1, scaleByMapSize(4, 9)) ); Engine.SetProgress(30); g_Map.log("Creating forests"); const [numForest, numStragglers] = getTreeCounts(...rBiomeTreeCount(1)); let types = [ [[tForestFloor2, tMainTerrain, pForest1], [tForestFloor2, pForest1]], [[tForestFloor1, tMainTerrain, pForest2], [tForestFloor1, pForest2]] ]; const size = numForest / (scaleByMapSize(2, 8) * numPlayers); let num = Math.floor(size / types.length); for (const type of types) createAreas( new ClumpPlacer(numForest / num, 0.1, 0.1, Infinity), [ new LayeredPainter(type, [2]), new TileClassPainter(clForest) ], [avoidClasses(clPlayer, 20, clForest, randIntInclusive(5, 15), clHill, 2), stayClasses(clLand, 4)], num); Engine.SetProgress(50); g_Map.log("Creating dirt patches"); const patchCount = (currentBiome() == "generic/savanna" ? 3 : 1) * scaleByMapSize(15, 45); for (const patchSize of [scaleByMapSize(3, 48), scaleByMapSize(5, 84), scaleByMapSize(8, 128)]) createAreas( new ClumpPlacer(patchSize, 0.3, 0.06, 0.5), [ new LayeredPainter([[tMainTerrain, tTier1Terrain], [tTier1Terrain, tTier2Terrain], [tTier2Terrain, tTier3Terrain]], [1, 1]), new TileClassPainter(clDirt) ], [avoidClasses(clForest, 0, clHill, 2, clDirt, 5, clPlayer, 7), stayClasses(clLand, 4)], patchCount); g_Map.log("Creating grass patches"); for (const size of [scaleByMapSize(2, 32), scaleByMapSize(3, 48), scaleByMapSize(5, 80)]) createAreas( new ClumpPlacer(size, 0.3, 0.06, 0.5), new TerrainPainter(tTier4Terrain), [avoidClasses(clForest, 0, clHill, 2, clDirt, 5, clPlayer, 7), stayClasses(clLand, 4)], patchCount); Engine.SetProgress(55); g_Map.log("Creating stone mines"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(oStoneSmall, 0, 2, 0, 4, 0, 2 * Math.PI, 1), new SimpleObject(oStoneLarge, 1, 1, 0, 4, 0, 2 * Math.PI, 4)], true, clRock), 0, [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 2), stayClasses(clLand, 3)], randIntInclusive(scaleByMapSize(2, 9), scaleByMapSize(9, 40)), 100); g_Map.log("Creating small stone quarries"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(oStoneSmall, 2, 5, 1, 3)], true, clRock), 0, [avoidClasses(clForest, 1, clPlayer, 10, clRock, 10, clHill, 2), stayClasses(clLand, 3)], randIntInclusive(scaleByMapSize(2, 9), scaleByMapSize(9, 40)), 100); g_Map.log("Creating metal mines"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(oMetalLarge, 1, 1, 0, 4)], true, clMetal), 0, [avoidClasses(clForest, 1, clPlayer, 10, clMetal, 10, clRock, 5, clHill, 2), stayClasses(clLand, 3)], randIntInclusive(scaleByMapSize(2, 9), scaleByMapSize(9, 40)), 100); Engine.SetProgress(65); g_Map.log("Creating small decorative rocks"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(aRockMedium, 1, 3, 0, 1)], true), 0, [avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 2), stayClasses(clLand, 3)], scaleByMapSize(16, 262), 50); g_Map.log("Creating large decorative rocks"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(aRockLarge, 1, 2, 0, 1), new SimpleObject(aRockMedium, 1, 3, 0, 2)], true), 0, [avoidClasses(clWater, 0, clForest, 0, clPlayer, 0, clHill, 2), stayClasses(clLand, 3)], scaleByMapSize(8, 131), 50); Engine.SetProgress(70); g_Map.log("Creating deer"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(oMainHuntableAnimal, 5, 7, 0, 4)], true, clFood), 0, [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 2, clFood, 20), stayClasses(clLand, 2)], randIntInclusive(numPlayers + 3, 5 * numPlayers + 4), 50); g_Map.log("Creating berry bush"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(oFruitBush, 5, 7, 0, 4)], true, clFood), 0, [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 2, clFood, 20), stayClasses(clLand, 2)], randIntInclusive(1, 4) * numPlayers + 2, 50); Engine.SetProgress(75); g_Map.log("Creating sheep"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(oSecondaryHuntableAnimal, 2, 3, 0, 2)], true, clFood), 0, [avoidClasses(clWater, 0, clForest, 0, clPlayer, 8, clHill, 2, clFood, 20), stayClasses(clLand, 2)], randIntInclusive(numPlayers + 3, 5 * numPlayers + 4), 50); g_Map.log("Creating fish"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(oFish, 2, 3, 0, 2)], true, clFood), 0, avoidClasses(clLand, 4, clForest, 0, clPlayer, 0, clHill, 2, clFood, 20), randIntInclusive(15, 40) * numPlayers, 60); Engine.SetProgress(85); g_Map.log("Creating straggler trees"); types = [g_Gaia.tree1, g_Gaia.tree2, g_Gaia.tree3, g_Gaia.tree4]; num = Math.floor(numStragglers / types.length); for (const type of types) createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(type, 1, 1, 0, 3)], true, clForest), 0, [avoidClasses(clWater, 1, clForest, 1, clHill, 2, clPlayer, 0, clMetal, 6, clRock, 6, clBaseResource, 6), stayClasses(clLand, 4)], num); const planetm = currentBiome() == "generic/india" ? 8 : 1; g_Map.log("Creating small grass tufts"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(aGrassShort, 1, 2, 0, 1, -Math.PI / 8, Math.PI / 8)]), 0, [avoidClasses(clWater, 2, clHill, 2, clPlayer, 2, clDirt, 0), stayClasses(clLand, 3)], planetm * scaleByMapSize(13, 200)); Engine.SetProgress(90); g_Map.log("Creating large grass tufts"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(aGrass, 2, 4, 0, 1.8, -Math.PI / 8, Math.PI / 8), new SimpleObject(aGrassShort, 3, 6, 1.2, 2.5, -Math.PI / 8, Math.PI / 8)]), 0, [avoidClasses(clWater, 3, clHill, 2, clPlayer, 2, clDirt, 1, clForest, 0), stayClasses(clLand, 3)], planetm * scaleByMapSize(13, 200)); Engine.SetProgress(95); g_Map.log("Creating shallow flora"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(aLillies, 1, 2, 0, 2), new SimpleObject(aReeds, 2, 4, 0, 2)]), 0, stayClasses(clShallow, 1), 60 * scaleByMapSize(13, 200), 80); g_Map.log("Creating bushes"); createObjectGroupsDeprecated( new SimpleGroup([new SimpleObject(aBushMedium, 1, 2, 0, 2), new SimpleObject(aBushSmall, 2, 4, 0, 2)]), 0, [avoidClasses(clWater, 1, clHill, 2, clPlayer, 1, clDirt, 1), stayClasses(clLand, 3)], planetm * scaleByMapSize(13, 200), 50); setSkySet(pickRandom(["cirrus", "cumulus", "sunny", "sunny 1", "mountainous", "stratus"])); setSunRotation(randomAngle()); setSunElevation(Math.PI * randFloat(1/5, 1/3)); } function createUnknownPlayerBases() { placePlayerBases({ "PlayerPlacement": [playerIDs, playerPosition], "BaseResourceClass": clBaseResource, "Walls": g_StartingWalls, "CityPatch": { "outerTerrain": tRoadWild, "innerTerrain": tRoad, "painters": [ new TileClassPainter(clPlayer) ] }, "StartingAnimal": { }, "Berries": { "template": oFruitBush }, "Mines": { "types": [ { "template": oMetalLarge }, { "template": oStoneLarge } ] }, "Treasures": { "types": [ { "template": oWoodTreasure, "count": g_StartingTreasures ? 14 : 0 } ] }, "Trees": { "template": oTree1 }, "Decoratives": { "template": aGrassShort } }); } createUnknownMap(); g_Map.ExportMap();