forked from mirrors/0ad
Cleanup random map Area prototype following b4503bb61e.
Delete areaID and just identify the Area object by the actual JS object reference. Delete all references from Areas in the RandomMap object, especially the area property of the RandomMap object became invalid after creating a new area. This was replaced with a cache in the Area object and a contains function. Add getPoints getter, so that the Area property is not accessed directly. Deepfreeze points to prevent accidental overwrites. Implement StayAreasConstraint and extend currently unused AvoidAreaConstraint to accept multiple areas. This was SVN commit r21296.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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) ||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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));
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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]]);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user