diff --git a/binaries/data/mods/public/maps/random/alpine_valley.js b/binaries/data/mods/public/maps/random/alpine_valley.js index 0af400a986..9b1b7f5dca 100644 --- a/binaries/data/mods/public/maps/random/alpine_valley.js +++ b/binaries/data/mods/public/maps/random/alpine_valley.js @@ -33,7 +33,7 @@ function MountainRangeBuilder(args) /** * Array of Vector2D locations where a mountainrange can start or end. */ - this.vertices = args.points; + this.vertices = args.getPoints(); /** * Number of mountainranges starting or ending at the given point. diff --git a/binaries/data/mods/public/maps/random/ardennes_forest.js b/binaries/data/mods/public/maps/random/ardennes_forest.js index 360974db59..aa5e928ef7 100644 --- a/binaries/data/mods/public/maps/random/ardennes_forest.js +++ b/binaries/data/mods/public/maps/random/ardennes_forest.js @@ -79,7 +79,7 @@ createArea( ]); Engine.SetProgress(5); -// Find all hills +g_Map.log("Finding hills"); var noise0 = new Noise2D(20); for (var ix = 0; ix < mapSize; ix++) for (var iz = 0; iz < mapSize; iz++) @@ -253,17 +253,12 @@ for (let size of [scaleByMapSize(50, 800), scaleByMapSize(50, 400), scaleByMapSi Engine.SetProgress(50); -var explorablePoints = []; - for (var ix = 0; ix < mapSize; ix++) for (var iz = 0; iz < mapSize; iz++) { let position = new Vector2D(ix, iz); let h = g_Map.getHeight(position); - if (h > 15 && h < 45 && clPlayer.countMembersInRadius(position, 1) == 0) - explorablePoints.push(position); - if (h > 35 && randBool(0.1) || h < 15 && randBool(0.05) && clHillDeco.countMembersInRadius(position, 1) == 0) g_Map.placeEntityAnywhere( @@ -273,7 +268,13 @@ for (var ix = 0; ix < mapSize; ix++) randomAngle()); } -var explorableArea = g_Map.createArea(explorablePoints); +var explorableArea = createArea( + new MapBoundsPlacer(), + undefined, + [ + new HeightConstraint(15, 45), + avoidClasses(clPlayer, 1) + ]); Engine.SetProgress(55); diff --git a/binaries/data/mods/public/maps/random/dodecanese.js b/binaries/data/mods/public/maps/random/dodecanese.js index 802c50d908..d6e9ef67bc 100644 --- a/binaries/data/mods/public/maps/random/dodecanese.js +++ b/binaries/data/mods/public/maps/random/dodecanese.js @@ -333,7 +333,7 @@ createDecoration( g_Map.log("Placing bridges"); var bridges = 0; -for (let bridgeStart of shuffleArray(areaShoreline.points)) +for (let bridgeStart of shuffleArray(areaShoreline.getPoints())) { if (new NearTileClassConstraint(clBridge, bridgeLength * 8).allows(bridgeStart)) continue; diff --git a/binaries/data/mods/public/maps/random/hellas.js b/binaries/data/mods/public/maps/random/hellas.js index 5124a159fe..2382a8ab44 100644 --- a/binaries/data/mods/public/maps/random/hellas.js +++ b/binaries/data/mods/public/maps/random/hellas.js @@ -119,7 +119,7 @@ while (true) if (!passableLandArea) continue; - landRatio = passableLandArea.points.length / diskArea(fractionToTiles(0.5)); + landRatio = passableLandArea.getPoints().length / diskArea(fractionToTiles(0.5)); g_Map.log("Land ratio: " + landRatio.toFixed(3)); if (landRatio < minLandRatio || landRatio > maxLandRatio) continue; @@ -153,7 +153,7 @@ while (true) new SlopeConstraint(2, Infinity) ]); - cliffsRatio = cliffsArea.points.length / Math.square(g_Map.getSize()); + cliffsRatio = cliffsArea.getPoints().length / Math.square(g_Map.getSize()); g_Map.log("Smoothing heightmap, cliff ratio: " + cliffsRatio.toFixed(3)); if (cliffsRatio < maxCliffRatio) break; @@ -295,11 +295,11 @@ var areaWater = createArea( stayClasses(clWater, 2)); g_Map.log("Creating docks"); -if (areaWater && areaWater.points.length) +if (areaWater && areaWater.getPoints().length) for (let i = 0; i < scaleByMapSize(1, 2); ++i) for (let tryNr = 0; tryNr < 60; ++tryNr) { - let positionLand = pickRandom(areaLand.points); + let positionLand = pickRandom(areaLand.getPoints()); let positionDock = areaWater.getClosestPointTo(positionLand); if (!g_Map.inMapBounds(positionDock) || !avoidClasses(clDock, 50, clPlayer, 30).allows(positionDock)) diff --git a/binaries/data/mods/public/maps/random/pompeii.js b/binaries/data/mods/public/maps/random/pompeii.js index 91b60098b8..0f1e35131d 100644 --- a/binaries/data/mods/public/maps/random/pompeii.js +++ b/binaries/data/mods/public/maps/random/pompeii.js @@ -177,7 +177,7 @@ createObjectGroupsByAreas( g_Map.log("Creating docks"); for (let i = 0; i < scaleByMapSize(2, 4); ++i) { - let positionLand = pickRandom(areaDockStart.points); + let positionLand = pickRandom(areaDockStart.getPoints()); let dockPosition = areaShoreline.getClosestPointTo(positionLand); if (!avoidClasses(g_TileClasses.mountain, scaleByMapSize(4, 6), g_TileClasses.dock, 10).allows(dockPosition)) diff --git a/binaries/data/mods/public/maps/random/rmgen-common/player.js b/binaries/data/mods/public/maps/random/rmgen-common/player.js index 4ec1209d9b..4011ac7848 100644 --- a/binaries/data/mods/public/maps/random/rmgen-common/player.js +++ b/binaries/data/mods/public/maps/random/rmgen-common/player.js @@ -633,7 +633,7 @@ function playerPlacementRandom(playerIDs, constraints = undefined) for (let i = 0; i < getNumPlayers(); ++i) { - let position = pickRandom(area.points); + let position = pickRandom(area.getPoints()); // Minimum distance between initial bases must be a quarter of the map diameter if (locations.some(loc => loc.distanceTo(position) < playerMinDist) || diff --git a/binaries/data/mods/public/maps/random/rmgen/Area.js b/binaries/data/mods/public/maps/random/rmgen/Area.js index 1ed78179f2..13e293a261 100644 --- a/binaries/data/mods/public/maps/random/rmgen/Area.js +++ b/binaries/data/mods/public/maps/random/rmgen/Area.js @@ -1,16 +1,27 @@ /** - * @file An Area is a set of points identified by an ID that was registered with the RandomMap. + * @file An Area is a set of Vector2D points and a cache to lookup membership quickly. */ function Area(points, id) { - this.points = points; - this.id = id; + this.points = deepfreeze(points); + + this.cache = []; + for (let x = 0; x < g_Map.getSize(); ++x) + this.cache[x] = new Uint8Array(g_Map.getSize()); + + for (let point of points) + this.cache[point.x][point.y] = 1; } -Area.prototype.getID = function() +Area.prototype.getPoints = function() { - return this.id; + return this.points; +}; + +Area.prototype.contains = function(point) +{ + return g_Map.inMapBounds(point) && this.cache[point.x][point.y] == 1; }; Area.prototype.getClosestPointTo = function(position) diff --git a/binaries/data/mods/public/maps/random/rmgen/Constraint.js b/binaries/data/mods/public/maps/random/rmgen/Constraint.js index 5c9b51cd48..e9272af77c 100644 --- a/binaries/data/mods/public/maps/random/rmgen/Constraint.js +++ b/binaries/data/mods/public/maps/random/rmgen/Constraint.js @@ -31,16 +31,29 @@ AndConstraint.prototype.allows = function(position) }; /** - * The AvoidAreaConstraint is met if the tile is not part of the given Area. - */ -function AvoidAreaConstraint(area) + * The StayAreasConstraint is met if some of the given Areas contains the point. + */ +function StayAreasConstraint(areas) { - this.area = area; + this.areas = areas; } -AvoidAreaConstraint.prototype.allows = function(position) +StayAreasConstraint.prototype.allows = function(position) { - return g_Map.area[position.x][position.y] != this.area.getID(); + return this.areas.some(area => area.contains(position)); +}; + +/** + * The AvoidAreasConstraint is met if none of the given Areas contain the point. + */ +function AvoidAreasConstraint(areas) +{ + this.areas = areas; +} + +AvoidAreasConstraint.prototype.allows = function(position) +{ + return this.areas.every(area => !area.contains(position)) }; /** diff --git a/binaries/data/mods/public/maps/random/rmgen/RandomMap.js b/binaries/data/mods/public/maps/random/rmgen/RandomMap.js index 4b66a8754b..9e799a7804 100644 --- a/binaries/data/mods/public/maps/random/rmgen/RandomMap.js +++ b/binaries/data/mods/public/maps/random/rmgen/RandomMap.js @@ -28,12 +28,9 @@ function RandomMap(baseHeight, baseTerrain) // Create 2D arrays for terrain objects and areas this.terrainEntities = []; - this.area = []; for (let i = 0; i < this.size; ++i) { - this.area[i] = new Uint16Array(this.size); - this.terrainEntities[i] = []; for (let j = 0; j < this.size; ++j) this.terrainEntities[i][j] = undefined; @@ -55,8 +52,6 @@ function RandomMap(baseHeight, baseTerrain) this.entities = []; - this.areaID = 0; - // Starting entity ID, arbitrary number to leave some space for player entities this.entityCount = 150; } @@ -315,17 +310,6 @@ RandomMap.prototype.setTerrainEntity = function(templateName, playerID, position new Entity(this.getEntityID(), templateName, playerID, position, orientation); }; -/** - * Constructs a new Area object and informs the Map which points correspond to this area. - */ -RandomMap.prototype.createArea = function(points) -{ - let areaID = ++this.areaID; - for (let p of points) - this.area[p.x][p.y] = areaID; - return new Area(points, areaID); -}; - RandomMap.prototype.createTileClass = function() { return new TileClass(this.size); diff --git a/binaries/data/mods/public/maps/random/rmgen/library.js b/binaries/data/mods/public/maps/random/rmgen/library.js index e64bce373f..e2d8eb1bbb 100644 --- a/binaries/data/mods/public/maps/random/rmgen/library.js +++ b/binaries/data/mods/public/maps/random/rmgen/library.js @@ -141,7 +141,7 @@ function createAreas(centeredPlacer, painter, constraint, amount, retryFactor = function createAreasInAreas(centeredPlacer, painter, constraint, amount, retryFactor, areas) { let placeFunc = function() { - centeredPlacer.setCenterPosition(pickRandom(pickRandom(areas).points)); + centeredPlacer.setCenterPosition(pickRandom(pickRandom(areas).getPoints())); return createArea(centeredPlacer, painter, constraint); }; @@ -169,7 +169,7 @@ function createObjectGroups(group, player, constraint, amount, retryFactor = 10, function createObjectGroupsByAreas(group, player, constraint, amount, retryFactor, areas, behaveDeprecated = false) { let placeFunc = function() { - group.setCenterPosition(pickRandom(pickRandom(areas).points)); + group.setCenterPosition(pickRandom(pickRandom(areas).getPoints())); return createObjectGroup(group, player, constraint); }; @@ -193,7 +193,7 @@ function createArea(placer, painters, constraints) if (!points) return undefined; - let area = g_Map.createArea(points); + let area = new Area(points); new MultiPainter(painters).paint(area); diff --git a/binaries/data/mods/public/maps/random/rmgen/painter/ElevationBlendingPainter.js b/binaries/data/mods/public/maps/random/rmgen/painter/ElevationBlendingPainter.js index 49865c745b..a42b309f01 100644 --- a/binaries/data/mods/public/maps/random/rmgen/painter/ElevationBlendingPainter.js +++ b/binaries/data/mods/public/maps/random/rmgen/painter/ElevationBlendingPainter.js @@ -9,6 +9,6 @@ function ElevationBlendingPainter(targetHeight, strength) ElevationBlendingPainter.prototype.paint = function(area) { - for (let point of area.points) + for (let point of area.getPoints()) g_Map.setHeight(point, this.strength * this.targetHeight + (1 - this.strength) * g_Map.getHeight(point)); }; diff --git a/binaries/data/mods/public/maps/random/rmgen/painter/ElevationPainter.js b/binaries/data/mods/public/maps/random/rmgen/painter/ElevationPainter.js index 938f45c60f..3d9ab515ff 100644 --- a/binaries/data/mods/public/maps/random/rmgen/painter/ElevationPainter.js +++ b/binaries/data/mods/public/maps/random/rmgen/painter/ElevationPainter.js @@ -8,7 +8,7 @@ function ElevationPainter(elevation) ElevationPainter.prototype.paint = function(area) { - for (let point of area.points) + for (let point of area.getPoints()) for (let vertex of g_TileVertices) { let position = Vector2D.add(point, vertex); diff --git a/binaries/data/mods/public/maps/random/rmgen/painter/HeightmapPainter.js b/binaries/data/mods/public/maps/random/rmgen/painter/HeightmapPainter.js index 0975e75777..5802709017 100644 --- a/binaries/data/mods/public/maps/random/rmgen/painter/HeightmapPainter.js +++ b/binaries/data/mods/public/maps/random/rmgen/painter/HeightmapPainter.js @@ -43,7 +43,7 @@ HeightmapPainter.prototype.paint = function(area) // Additional complexity to process all 4 vertices of each tile, i.e the last row too let seen = new Array(g_Map.height.length).fill(0).map(zero => new Uint8Array(g_Map.height.length).fill(0)); - for (let point of area.points) + for (let point of area.getPoints()) for (let vertex of g_TileVertices) { let vertexPos = Vector2D.add(point, vertex); diff --git a/binaries/data/mods/public/maps/random/rmgen/painter/LayeredPainter.js b/binaries/data/mods/public/maps/random/rmgen/painter/LayeredPainter.js index 2edc589e7f..8cb5da4a7a 100644 --- a/binaries/data/mods/public/maps/random/rmgen/painter/LayeredPainter.js +++ b/binaries/data/mods/public/maps/random/rmgen/painter/LayeredPainter.js @@ -22,7 +22,7 @@ LayeredPainter.prototype.paint = function(area) "area": area, "brushSize": 1, "gridSize": g_Map.getSize(), - "withinArea": (areaID, position) => g_Map.area[position.x][position.y] == areaID, + "withinArea": (area, position) => area.contains(position), "paintTile": (point, distance) => { let width = 0; let i = 0; diff --git a/binaries/data/mods/public/maps/random/rmgen/painter/RandomElevationPainter.js b/binaries/data/mods/public/maps/random/rmgen/painter/RandomElevationPainter.js index 04e977f64d..827b160642 100644 --- a/binaries/data/mods/public/maps/random/rmgen/painter/RandomElevationPainter.js +++ b/binaries/data/mods/public/maps/random/rmgen/painter/RandomElevationPainter.js @@ -9,7 +9,7 @@ function RandomElevationPainter(minHeight, maxHeight) RandomElevationPainter.prototype.paint = function(area) { - for (let point of area.points) + for (let point of area.getPoints()) for (let vertex of g_TileVertices) { let position = Vector2D.add(point, vertex); diff --git a/binaries/data/mods/public/maps/random/rmgen/painter/SmoothElevationPainter.js b/binaries/data/mods/public/maps/random/rmgen/painter/SmoothElevationPainter.js index 49433d266b..8d9dbdbd0b 100644 --- a/binaries/data/mods/public/maps/random/rmgen/painter/SmoothElevationPainter.js +++ b/binaries/data/mods/public/maps/random/rmgen/painter/SmoothElevationPainter.js @@ -45,7 +45,7 @@ SmoothElevationPainter.prototype.paint = function(area) // Get heightmap grid vertices within or adjacent to the area let brushSize = 2; let heightPoints = []; - for (let point of area.points) + for (let point of area.getPoints()) for (let dx = -1; dx < 1 + brushSize; ++dx) { let nx = point.x + dx; @@ -64,11 +64,11 @@ SmoothElevationPainter.prototype.paint = function(area) } // Every vertex of a tile is considered within the area - let withinArea = (areaID, position) => { + let withinArea = (area, position) => { for (let vertex of g_TileVertices) { let vertexPos = Vector2D.sub(position, vertex); - if (g_Map.inMapBounds(vertexPos) && g_Map.area[vertexPos.x][vertexPos.y] == areaID) + if (g_Map.inMapBounds(vertexPos) && area.contains(vertexPos)) return true; } @@ -94,10 +94,9 @@ SmoothElevationPainter.prototype.paint = function(area) }); // Smooth everything out - let areaID = area.getID(); for (let point of heightPoints) { - if (!withinArea(areaID, point)) + if (!withinArea(area, point)) continue; let count = 0; @@ -149,8 +148,7 @@ function breadthFirstSearchPaint(args) // Find all points outside of the area, mark them as seen and set zero distance let pointQueue = []; - let areaID = args.area.getID(); - for (let point of args.area.points) + for (let point of args.area.getPoints()) // The brushSize is added because the entire brushSize is by definition part of the area for (let dx = -1; dx < 1 + args.brushSize; ++dx) { @@ -160,7 +158,7 @@ function breadthFirstSearchPaint(args) let nz = point.y + dz; let position = new Vector2D(nx, nz); - if (!withinGrid(nx, nz) || args.withinArea(areaID, position) || saw[nx][nz]) + if (!withinGrid(nx, nz) || args.withinArea(args.area, position) || saw[nx][nz]) continue; saw[nx][nz] = 1; @@ -176,7 +174,7 @@ function breadthFirstSearchPaint(args) let point = pointQueue.shift(); let distance = dist[point.x][point.y]; - if (args.withinArea(areaID, point)) + if (args.withinArea(args.area, point)) args.paintTile(point, distance); // Enqueue neighboring points @@ -188,7 +186,7 @@ function breadthFirstSearchPaint(args) let nz = point.y + dz; let position = new Vector2D(nx, nz); - if (!withinGrid(nx, nz) || !args.withinArea(areaID, position) || saw[nx][nz]) + if (!withinGrid(nx, nz) || !args.withinArea(args.area, position) || saw[nx][nz]) continue; saw[nx][nz] = 1; diff --git a/binaries/data/mods/public/maps/random/rmgen/painter/SmoothingPainter.js b/binaries/data/mods/public/maps/random/rmgen/painter/SmoothingPainter.js index 2915ad408f..503c2f4762 100644 --- a/binaries/data/mods/public/maps/random/rmgen/painter/SmoothingPainter.js +++ b/binaries/data/mods/public/maps/random/rmgen/painter/SmoothingPainter.js @@ -33,7 +33,7 @@ SmoothingPainter.prototype.paint = function(area) // Additional complexity to process all 4 vertices of each tile, i.e the last row too let seen = new Array(heightmap.length).fill(0).map(zero => new Uint8Array(heightmap.length).fill(0)); - for (let point of area.points) + for (let point of area.getPoints()) for (let tileVertex of g_TileVertices) { let vertex = Vector2D.add(point, tileVertex); diff --git a/binaries/data/mods/public/maps/random/rmgen/painter/TerrainPainter.js b/binaries/data/mods/public/maps/random/rmgen/painter/TerrainPainter.js index 2480ed8f16..3e63e53ed6 100644 --- a/binaries/data/mods/public/maps/random/rmgen/painter/TerrainPainter.js +++ b/binaries/data/mods/public/maps/random/rmgen/painter/TerrainPainter.js @@ -9,6 +9,6 @@ function TerrainPainter(terrain) TerrainPainter.prototype.paint = function(area) { - for (let point of area.points) + for (let point of area.getPoints()) this.terrain.place(point); }; diff --git a/binaries/data/mods/public/maps/random/rmgen/painter/TerrainTextureArrayPainter.js b/binaries/data/mods/public/maps/random/rmgen/painter/TerrainTextureArrayPainter.js index 96d640139e..2da99cef24 100644 --- a/binaries/data/mods/public/maps/random/rmgen/painter/TerrainTextureArrayPainter.js +++ b/binaries/data/mods/public/maps/random/rmgen/painter/TerrainTextureArrayPainter.js @@ -16,7 +16,7 @@ TerrainTextureArrayPainter.prototype.paint = function(area) let sourceSize = Math.sqrt(this.textureIDs.length); let scale = sourceSize / g_Map.getSize(); - for (let point of area.points) + for (let point of area.getPoints()) { let sourcePos = Vector2D.mult(point, scale).floor(); g_Map.setTexture(point, this.textureNames[this.textureIDs[sourcePos.x * sourceSize + sourcePos.y]]); diff --git a/binaries/data/mods/public/maps/random/rmgen/painter/TileClassPainter.js b/binaries/data/mods/public/maps/random/rmgen/painter/TileClassPainter.js index dfd88211df..e1631833c1 100644 --- a/binaries/data/mods/public/maps/random/rmgen/painter/TileClassPainter.js +++ b/binaries/data/mods/public/maps/random/rmgen/painter/TileClassPainter.js @@ -8,6 +8,6 @@ function TileClassPainter(tileClass) TileClassPainter.prototype.paint = function(area) { - for (let point of area.points) + for (let point of area.getPoints()) this.tileClass.add(point); }; diff --git a/binaries/data/mods/public/maps/random/rmgen/painter/TileClassUnPainter.js b/binaries/data/mods/public/maps/random/rmgen/painter/TileClassUnPainter.js index 7cd8004e03..b368c565e7 100644 --- a/binaries/data/mods/public/maps/random/rmgen/painter/TileClassUnPainter.js +++ b/binaries/data/mods/public/maps/random/rmgen/painter/TileClassUnPainter.js @@ -8,6 +8,6 @@ function TileClassUnPainter(tileClass) TileClassUnPainter.prototype.paint = function(area) { - for (let point of area.points) + for (let point of area.getPoints()) this.tileClass.remove(point); }; diff --git a/binaries/data/mods/public/maps/random/rmgen2/gaia.js b/binaries/data/mods/public/maps/random/rmgen2/gaia.js index 61e441a66e..55be48adae 100644 --- a/binaries/data/mods/public/maps/random/rmgen2/gaia.js +++ b/binaries/data/mods/public/maps/random/rmgen2/gaia.js @@ -52,7 +52,7 @@ function addBluffs(constraint, size, deviation, fill, baseHeight) if (rendered[0] === undefined) continue; - var points = rendered[0].points; + var points = rendered[0].getPoints(); var corners = findCorners(points);