forked from mirrors/0ad
Extract a RandomPathPlacer prototype from Deep Forest (83422923aa) and Schwarzwald (49194819f6) duplication, refs #4805, #4804.
This allows creation of paths that are not linear nor sine-shaped like
the PathPlacer, refs #892.
To mimic the per-tile path elevation randomization on Deep Forest, use a
SmoothElevationPainter and it's randomization argument from 77f28c5a56.
Use vector algebra and the mapCenter getter, refs #4845, #4854.
This was SVN commit r20879.
This commit is contained in:
@@ -11,6 +11,7 @@ var clBaseResource = createTileClass();
|
||||
var templateStone = "gaia/geology_stone_temperate";
|
||||
var templateStoneMine = "gaia/geology_stonemine_temperate_quarry";
|
||||
var templateMetalMine = "gaia/geology_metal_temperate_slabs";
|
||||
var templateTemple = "other/unfinished_greek_temple";
|
||||
|
||||
var terrainWood = ['temp_grass_mossy|gaia/flora_tree_oak', 'temp_forestfloor_pine|gaia/flora_tree_pine', 'temp_mud_plants|gaia/flora_tree_dead',
|
||||
'temp_plants_bog|gaia/flora_tree_oak_large', "temp_dirt_gravel_plants|gaia/flora_tree_aleppo_pine", 'temp_forestfloor_autumn|gaia/flora_tree_carob']; //'temp_forestfloor_autumn|gaia/flora_tree_fig'
|
||||
@@ -36,51 +37,37 @@ var terrainHillBorder = ["temp_highlands", "temp_highlands", "temp_highlands", "
|
||||
var mapSize = getMapSize();
|
||||
var mapArea = getMapArea();
|
||||
var mapRadius = mapSize/2;
|
||||
var mapCenterX = mapRadius;
|
||||
var mapCenterZ = mapRadius;
|
||||
var mapCenter = getMapCenter();
|
||||
|
||||
var numPlayers = getNumPlayers();
|
||||
var baseRadius = 20;
|
||||
var minPlayerRadius = Math.min(mapRadius - 1.5 * baseRadius, 5/8 * mapRadius);
|
||||
var maxPlayerRadius = Math.min(mapRadius - baseRadius, 3/4 * mapRadius);
|
||||
var playerStartLocX = [];
|
||||
var playerStartLocZ = [];
|
||||
var playerPosition = [];
|
||||
var playerAngle = [];
|
||||
var playerAngleStart = randomAngle();
|
||||
var playerAngleAddAvrg = 2 * Math.PI / numPlayers;
|
||||
var playerAngleMaxOff = playerAngleAddAvrg/4;
|
||||
|
||||
// Setup eyecandy
|
||||
var templateEC = "other/unfinished_greek_temple";
|
||||
var radiusEC = Math.max(mapRadius/8, baseRadius/2);
|
||||
|
||||
// Setup paths
|
||||
var pathSucsessRadius = baseRadius/2;
|
||||
var pathAngleOff = Math.PI / 2;
|
||||
var pathWidth = 5; // This is not really the path's sickness in tiles but the number of tiles in the clumbs of the path
|
||||
|
||||
// Setup additional resources
|
||||
var resourceRadius = 2*mapRadius/3; // 3*mapRadius/8;
|
||||
var resourceRadius = fractionToTiles(1/3);
|
||||
var resourcePerPlayer = [templateStone, templateMetalMine];
|
||||
|
||||
// Setup woods
|
||||
// For large maps there are memory errors with too many trees. A density of 256*192/mapArea works with 0 players.
|
||||
// Around each player there is an area without trees so with more players the max density can increase a bit.
|
||||
var maxTreeDensity = Math.min(256 * (192 + 8 * numPlayers) / mapArea, 1); // Has to be tweeked but works ok
|
||||
var bushChance = 1/3; // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood
|
||||
|
||||
var playerIDs = [];
|
||||
var playerIDs = sortAllPlayers();
|
||||
for (var i=0; i < numPlayers; i++)
|
||||
{
|
||||
playerIDs[i] = i+1;
|
||||
playerAngle[i] = (playerAngleStart + i * playerAngleAddAvrg + randFloat(0, playerAngleMaxOff)) % (2 * Math.PI);
|
||||
playerStartLocX[i] = mapCenterX + Math.round(randFloat(minPlayerRadius, maxPlayerRadius) * Math.cos(playerAngle[i]));
|
||||
playerStartLocZ[i] = mapCenterZ + Math.round(randFloat(minPlayerRadius, maxPlayerRadius) * Math.sin(playerAngle[i]));
|
||||
playerPosition[i] = Vector2D.add(mapCenter, new Vector2D(randFloat(minPlayerRadius, maxPlayerRadius), 0).rotate(-playerAngle[i]).round());
|
||||
}
|
||||
Engine.SetProgress(10);
|
||||
|
||||
placePlayerBases({
|
||||
"PlayerPlacement": [playerIDs, playerStartLocX.map(tilesToFraction), playerStartLocZ.map(tilesToFraction)],
|
||||
"PlayerPlacement": [playerIDs, playerPosition.map(p => tilesToFraction(p.x)), playerPosition.map(p => tilesToFraction(p.y))],
|
||||
"BaseResourceClass": clBaseResource,
|
||||
// player class painted below
|
||||
"CityPatch": {
|
||||
@@ -114,117 +101,56 @@ placePlayerBases({
|
||||
});
|
||||
Engine.SetProgress(10);
|
||||
|
||||
// Place paths
|
||||
var doublePaths = true;
|
||||
if (numPlayers > 4)
|
||||
doublePaths = false;
|
||||
if (doublePaths == true)
|
||||
var maxI = numPlayers+1;
|
||||
else
|
||||
var maxI = numPlayers;
|
||||
for (var i = 0; i < maxI; i++)
|
||||
{
|
||||
if (doublePaths == true)
|
||||
var minJ = 0;
|
||||
else
|
||||
var minJ = i+1;
|
||||
for (var j = minJ; j < numPlayers+1; j++)
|
||||
log("Painting paths...");
|
||||
var pathBlending = numPlayers <= 4;
|
||||
for (let i = 0; i < numPlayers + (pathBlending ? 1 : 0); ++i)
|
||||
for (let j = pathBlending ? 0 : i + 1; j < numPlayers + 1; ++j)
|
||||
{
|
||||
// Setup start and target coordinates
|
||||
if (i < numPlayers)
|
||||
{
|
||||
var x = playerStartLocX[i];
|
||||
var z = playerStartLocZ[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
var x = mapCenterX;
|
||||
var z = mapCenterZ;
|
||||
}
|
||||
|
||||
if (j < numPlayers)
|
||||
{
|
||||
var targetX = playerStartLocX[j];
|
||||
var targetZ = playerStartLocZ[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
var targetX = mapCenterX;
|
||||
var targetZ = mapCenterZ;
|
||||
}
|
||||
|
||||
// Prepare path placement
|
||||
var angle = getAngle(x, z, targetX, targetZ);
|
||||
x += Math.round(pathSucsessRadius * Math.cos(angle));
|
||||
z += Math.round(pathSucsessRadius * Math.sin(angle));
|
||||
var targetReached = false;
|
||||
var tries = 0;
|
||||
// Placing paths
|
||||
while (targetReached == false && tries < 2*mapSize)
|
||||
{
|
||||
createArea(
|
||||
new ClumpPlacer(pathWidth, 1, 1, 1, x, z),
|
||||
[
|
||||
new TerrainPainter(terrainPath),
|
||||
new ElevationPainter(randFloat(-1, 0)),
|
||||
paintClass(clPath)
|
||||
],
|
||||
avoidClasses(clHill, 0, clBaseResource, 4));
|
||||
|
||||
// Set vars for next loop
|
||||
angle = getAngle(x, z, targetX, targetZ);
|
||||
if (doublePaths == true) // Bended paths
|
||||
{
|
||||
x += Math.round(Math.cos(angle + randFloat(-pathAngleOff/2, 3*pathAngleOff/2)));
|
||||
z += Math.round(Math.sin(angle + randFloat(-pathAngleOff/2, 3*pathAngleOff/2)));
|
||||
}
|
||||
else // Straight paths
|
||||
{
|
||||
x += Math.round(Math.cos(angle + randFloat(-pathAngleOff, pathAngleOff)));
|
||||
z += Math.round(Math.sin(angle + randFloat(-pathAngleOff, pathAngleOff)));
|
||||
}
|
||||
if (Math.euclidDistance2D(x, z, targetX, targetZ) < pathSucsessRadius)
|
||||
targetReached = true;
|
||||
tries++;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Engine.SetProgress(50);
|
||||
|
||||
// Place expansion resources
|
||||
for (var i=0; i < numPlayers; i++)
|
||||
{
|
||||
for (var rIndex = 0; rIndex < resourcePerPlayer.length; rIndex++)
|
||||
{
|
||||
if (numPlayers > 1)
|
||||
var angleDist = (playerAngle[(i+1)%numPlayers] - playerAngle[i] + 2 * Math.PI) % (2 * Math.PI);
|
||||
else
|
||||
var angleDist = 2 * Math.PI;
|
||||
|
||||
var placeX = Math.round(mapCenterX + resourceRadius * Math.cos(playerAngle[i] + (rIndex+1)*angleDist/(resourcePerPlayer.length+1)));
|
||||
var placeZ = Math.round(mapCenterX + resourceRadius * Math.sin(playerAngle[i] + (rIndex+1)*angleDist/(resourcePerPlayer.length+1)));
|
||||
|
||||
placeObject(placeX, placeZ, resourcePerPlayer[rIndex], 0, randomAngle());
|
||||
let pathStart = i < numPlayers ? playerPosition[i] : mapCenter;
|
||||
let pathEnd = j < numPlayers ? playerPosition[j] : mapCenter;
|
||||
|
||||
createArea(
|
||||
new ClumpPlacer(40, 1/2, 1/8, 1, placeX, placeZ),
|
||||
new RandomPathPlacer(pathStart, pathEnd, 1.25, baseRadius / 2, pathBlending),
|
||||
[
|
||||
new TerrainPainter(terrainPath),
|
||||
new SmoothElevationPainter(ELEVATION_SET, -2, 2, 1),
|
||||
paintClass(clPath)
|
||||
],
|
||||
avoidClasses(clHill, 0, clBaseResource, 4));
|
||||
}
|
||||
Engine.SetProgress(50);
|
||||
|
||||
log("Placing expansion resources...");
|
||||
for (let i = 0; i < numPlayers; ++i)
|
||||
for (let rIndex = 0; rIndex < resourcePerPlayer.length; ++rIndex)
|
||||
{
|
||||
let angleDist = numPlayers > 1 ?
|
||||
(playerAngle[(i + 1) % numPlayers] - playerAngle[i] + 2 * Math.PI) % (2 * Math.PI) :
|
||||
2 * Math.PI;
|
||||
|
||||
// they are supposed to be in between players on the same radius
|
||||
let angle = playerAngle[i] + angleDist * (rIndex + 1) / (resourcePerPlayer.length + 1);
|
||||
let position = Vector2D.add(mapCenter, new Vector2D(resourceRadius, 0).rotate(-angle)).round();
|
||||
|
||||
placeObject(position.x, position.y, resourcePerPlayer[rIndex], 0, randomAngle());
|
||||
|
||||
createArea(
|
||||
new ClumpPlacer(40, 1/2, 1/8, 1, position.x, position.y),
|
||||
[
|
||||
new LayeredPainter([terrainHillBorder, terrainHill], [1]),
|
||||
new ElevationPainter(randFloat(1, 2)),
|
||||
paintClass(clHill)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Engine.SetProgress(60);
|
||||
|
||||
// Place eyecandy
|
||||
placeObject(mapCenterX, mapCenterZ, templateEC, 0, randomAngle());
|
||||
addToClass(mapCenterX, mapCenterZ, clBaseResource);
|
||||
log("Placing temple...");
|
||||
placeObject(mapCenter.x, mapCenter.y, templateTemple, 0, randomAngle());
|
||||
addToClass(mapCenter.x, mapCenter.y, clBaseResource);
|
||||
|
||||
log("Creating central mountain...");
|
||||
createArea(
|
||||
new ClumpPlacer(Math.square(radiusEC), 1/2, 1/8, 1, mapCenterX, mapCenterZ),
|
||||
new ClumpPlacer(Math.square(radiusEC), 1/2, 1/8, 1, mapCenter.x, mapCenter.y),
|
||||
[
|
||||
new LayeredPainter([terrainHillBorder, terrainHill], [radiusEC/4]),
|
||||
new ElevationPainter(randFloat(1, 2)),
|
||||
@@ -233,14 +159,13 @@ createArea(
|
||||
|
||||
// Woods and general hight map
|
||||
for (var x = 0; x < mapSize; x++)
|
||||
{
|
||||
for (var z = 0;z < mapSize;z++)
|
||||
{
|
||||
// The 0.5 is a correction for the entities placed on the center of tiles
|
||||
var radius = Math.euclidDistance2D(x + 0.5, z + 0.5, mapCenterX, mapCenterZ);
|
||||
var radius = Math.euclidDistance2D(x + 0.5, z + 0.5, mapCenter.x, mapCenter.y);
|
||||
var minDistToSL = mapSize;
|
||||
for (var i=0; i < numPlayers; i++)
|
||||
minDistToSL = Math.min(minDistToSL, Math.euclidDistance2D(x, z, playerStartLocX[i], playerStartLocZ[i]));
|
||||
minDistToSL = Math.min(minDistToSL, Math.euclidDistance2D(x, z, playerPosition[i].x, playerPosition[i].y));
|
||||
|
||||
// Woods tile based
|
||||
var tDensFactSL = Math.max(Math.min((minDistToSL - baseRadius) / baseRadius, 1), 0);
|
||||
@@ -266,7 +191,6 @@ for (var x = 0; x < mapSize; x++)
|
||||
var hVarHills = 5 * (1 + Math.sin(x / 10) * Math.sin(z / 10));
|
||||
setHeight(x, z, getHeight(x, z) + hVarMiddleHill + hVarHills + 1);
|
||||
}
|
||||
}
|
||||
Engine.SetProgress(95);
|
||||
|
||||
placePlayersNomad(clPlayer, avoidClasses(clForest, 1, clBaseResource, 4));
|
||||
|
||||
@@ -267,3 +267,41 @@ PathPlacer.prototype.place = function(constraint)
|
||||
return ((failed > this.width*this.failfraction*dist) ? undefined : retVec);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a winded path between the given two vectors.
|
||||
* Uses a random angle at each step, so it can be more random than the sin form of the PathPlacer.
|
||||
* Omits the given offset after the start and before the end.
|
||||
*/
|
||||
function RandomPathPlacer(pathStart, pathEnd, pathWidth, offset, blended)
|
||||
{
|
||||
this.pathStart = Vector2D.add(pathStart, Vector2D.sub(pathEnd, pathStart).normalize().mult(offset)).round();
|
||||
this.pathEnd = pathEnd;
|
||||
this.offset = offset;
|
||||
this.blended = blended;
|
||||
this.clumpPlacer = new ClumpPlacer(diskArea(pathWidth), 1, 1, 1);
|
||||
this.maxPathLength = fractionToTiles(2);
|
||||
}
|
||||
|
||||
RandomPathPlacer.prototype.place = function(constraint)
|
||||
{
|
||||
let pathLength = 0;
|
||||
let points = [];
|
||||
let position = this.pathStart;
|
||||
|
||||
while (position.distanceTo(this.pathEnd) >= this.offset && pathLength++ < this.maxPathLength)
|
||||
{
|
||||
position.add(
|
||||
new Vector2D(1, 0).rotate(
|
||||
-getAngle(this.pathStart.x, this.pathStart.y, this.pathEnd.x, this.pathEnd.y) +
|
||||
-Math.PI / 2 * (randFloat(-1, 1) + (this.blended ? 0.5 : 0)))).round();
|
||||
|
||||
this.clumpPlacer.x = position.x;
|
||||
this.clumpPlacer.z = position.y;
|
||||
|
||||
for (let point of this.clumpPlacer.place(constraint) || [])
|
||||
if (points.every(p => p.x != point.x || p.z != point.z))
|
||||
points.push(point);
|
||||
}
|
||||
|
||||
return points;
|
||||
};
|
||||
|
||||
@@ -83,26 +83,20 @@ var tWaterBorder = ['dirt_brown_d'];
|
||||
|
||||
var mapSize = getMapSize();
|
||||
var mapArea = getMapArea();
|
||||
var mapCenter = getMapCenter();
|
||||
var mapRadius = mapSize/2;
|
||||
var mapCenterX = mapRadius;
|
||||
var mapCenterZ = mapRadius;
|
||||
|
||||
var numPlayers = getNumPlayers();
|
||||
var baseRadius = 15;
|
||||
var minPlayerRadius = Math.min(mapRadius - 1.5 * baseRadius, 5/8 * mapRadius);
|
||||
var maxPlayerRadius = Math.min(mapRadius - baseRadius, 3/4 * mapRadius);
|
||||
|
||||
var playerStartLocX = [];
|
||||
var playerStartLocZ = [];
|
||||
var playerPosition = [];
|
||||
var playerAngleStart = randomAngle();
|
||||
var playerAngleAddAvrg = 2 * Math.PI / numPlayers;
|
||||
var playerAngleMaxOff = playerAngleAddAvrg/4;
|
||||
|
||||
var pathSucsessRadius = baseRadius/2;
|
||||
var pathAngleOff = Math.PI/2;
|
||||
var pathWidth = 10; // This is not really the path's thickness in tiles but the number of tiles in the clumbs of the path
|
||||
|
||||
var resourceRadius = 2/3 * mapRadius;
|
||||
var resourceRadius = fractionToTiles(1/3);
|
||||
|
||||
// Setup woods
|
||||
// For large maps there are memory errors with too many trees. A density of 256*192/mapArea works with 0 players.
|
||||
@@ -110,9 +104,7 @@ var resourceRadius = 2/3 * mapRadius;
|
||||
var maxTreeDensity = Math.min(256 * (192 + 8 * numPlayers) / mapArea, 1); // Has to be tweeked but works ok
|
||||
var bushChance = 1/3; // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood
|
||||
|
||||
////////////////
|
||||
// Set height limits and water level by map size
|
||||
////////////////
|
||||
|
||||
// Set target min and max height depending on map size to make average steepness about the same on all map sizes
|
||||
var heightRange = {'min': MIN_HEIGHT * (g_Map.size + 512) / 8192, 'max': MAX_HEIGHT * (g_Map.size + 512) / 8192, 'avg': (MIN_HEIGHT * (g_Map.size + 512) +MAX_HEIGHT * (g_Map.size + 512))/16384};
|
||||
@@ -123,24 +115,16 @@ var waterHeight = -MIN_HEIGHT + heightRange.min + averageWaterCoverage * (height
|
||||
var waterHeightAdjusted = waterHeight + MIN_HEIGHT;
|
||||
setWaterHeight(waterHeight);
|
||||
|
||||
////////////////
|
||||
// Generate base terrain
|
||||
////////////////
|
||||
|
||||
// Setting a 3x3 Grid as initial heightmap
|
||||
var initialReliefmap = [[heightRange.max, heightRange.max, heightRange.max], [heightRange.max, heightRange.min, heightRange.max], [heightRange.max, heightRange.max, heightRange.max]];
|
||||
|
||||
setBaseTerrainDiamondSquare(heightRange.min, heightRange.max, initialReliefmap);
|
||||
// Apply simple erosion
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
globalSmoothHeightmap();
|
||||
|
||||
rescaleHeightmap(heightRange.min, heightRange.max);
|
||||
|
||||
//////////
|
||||
// Setup height limit
|
||||
//////////
|
||||
|
||||
// Height presets
|
||||
var heighLimits = [
|
||||
heightRange.min + 1/3 * (waterHeightAdjusted - heightRange.min), // 0 Deep water
|
||||
heightRange.min + 2/3 * (waterHeightAdjusted - heightRange.min), // 1 Medium Water
|
||||
@@ -154,29 +138,21 @@ var heighLimits = [
|
||||
waterHeightAdjusted + 7/8 * (heightRange.max - waterHeightAdjusted), // 9 Upper forest border
|
||||
waterHeightAdjusted + (heightRange.max - waterHeightAdjusted)]; // 10 Hilltop
|
||||
|
||||
//////////
|
||||
// Place start locations and apply terrain texture and decorative props
|
||||
//////////
|
||||
|
||||
// Get start locations
|
||||
var startLocations = getStartLocationsByHeightmap({'min': heighLimits[4], 'max': heighLimits[5]});
|
||||
|
||||
var playerHeight = (heighLimits[4] + heighLimits[5]) / 2;
|
||||
|
||||
for (var i=0; i < numPlayers; i++)
|
||||
for (let i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
let playerAngle = (playerAngleStart + i * playerAngleAddAvrg + randFloat(0, playerAngleMaxOff)) % (2* Math.PI);
|
||||
let x = Math.round(mapCenterX + randFloat(minPlayerRadius, maxPlayerRadius) * Math.cos(playerAngle));
|
||||
let z = Math.round(mapCenterZ + randFloat(minPlayerRadius, maxPlayerRadius) * Math.sin(playerAngle));
|
||||
playerPosition[i] = Vector2D.add(
|
||||
mapCenter,
|
||||
new Vector2D(randFloat(minPlayerRadius, maxPlayerRadius), 0).rotate(
|
||||
-((playerAngleStart + i * playerAngleAddAvrg + randFloat(0, playerAngleMaxOff)) % (2 * Math.PI)))).round();
|
||||
|
||||
playerStartLocX[i] = x;
|
||||
playerStartLocZ[i] = z;
|
||||
|
||||
rectangularSmoothToHeight({"x": x,"y": z} , 20, 20, playerHeight, 0.8);
|
||||
rectangularSmoothToHeight(playerPosition[i], 20, 20, playerHeight, 0.8);
|
||||
}
|
||||
|
||||
placePlayerBases({
|
||||
"PlayerPlacement": [sortAllPlayers(), playerStartLocX.map(tilesToFraction), playerStartLocZ.map(tilesToFraction)],
|
||||
"PlayerPlacement": [sortAllPlayers(), playerPosition.map(p => tilesToFraction(p.x)), playerPosition.map(p => tilesToFraction(p.y))],
|
||||
"BaseResourceClass": clBaseResource,
|
||||
"Walls": false,
|
||||
// player class painted below
|
||||
@@ -227,9 +203,7 @@ for (let [minHeight, maxHeight] of [[heighLimits[3], (heighLimits[4] + heighLimi
|
||||
|
||||
Engine.SetProgress(50);
|
||||
|
||||
//place water & open terrain textures and assign TileClasses
|
||||
log("Painting textures...");
|
||||
|
||||
var betweenShallowAndShore = (heighLimits[3] + heighLimits[2]) / 2;
|
||||
createArea(
|
||||
new HeightPlacer(Elevation_IncludeMin_IncludeMax, heighLimits[2], betweenShallowAndShore),
|
||||
@@ -242,89 +216,25 @@ createArea(
|
||||
new LayeredPainter([tWaterBorder, tWater], [2]));
|
||||
|
||||
paintTileClassBasedOnHeight(heightRange.min, heighLimits[2], 1, clWater);
|
||||
|
||||
Engine.SetProgress(60);
|
||||
|
||||
log("Placing paths...");
|
||||
|
||||
var doublePaths = true;
|
||||
if (numPlayers > 4)
|
||||
doublePaths = false;
|
||||
|
||||
if (doublePaths === true)
|
||||
var maxI = numPlayers+1;
|
||||
else
|
||||
var maxI = numPlayers;
|
||||
|
||||
for (var i = 0; i < maxI; i++)
|
||||
{
|
||||
if (doublePaths === true)
|
||||
var minJ = 0;
|
||||
else
|
||||
var minJ = i+1;
|
||||
|
||||
for (var j = minJ; j < numPlayers+1; j++)
|
||||
log("Painting paths...");
|
||||
var pathBlending = numPlayers <= 4;
|
||||
for (let i = 0; i < numPlayers + (pathBlending ? 1 : 0); ++i)
|
||||
for (let j = pathBlending ? 0 : i + 1; j < numPlayers + 1; ++j)
|
||||
{
|
||||
// Setup start and target coordinates
|
||||
if (i < numPlayers)
|
||||
{
|
||||
var x = playerStartLocX[i];
|
||||
var z = playerStartLocZ[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
var x = mapCenterX;
|
||||
var z = mapCenterZ;
|
||||
}
|
||||
let pathStart = i < numPlayers ? playerPosition[i] : mapCenter;
|
||||
let pathEnd = j < numPlayers ? playerPosition[j] : mapCenter;
|
||||
|
||||
if (j < numPlayers)
|
||||
{
|
||||
var targetX = playerStartLocX[j];
|
||||
var targetZ = playerStartLocZ[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
var targetX = mapCenterX;
|
||||
var targetZ = mapCenterZ;
|
||||
}
|
||||
|
||||
// Prepare path placement
|
||||
var angle = getAngle(x, z, targetX, targetZ);
|
||||
x += Math.round(pathSucsessRadius * Math.cos(angle));
|
||||
z += Math.round(pathSucsessRadius * Math.sin(angle));
|
||||
|
||||
var targetReached = false;
|
||||
var tries = 0;
|
||||
|
||||
// Placing paths
|
||||
while (targetReached === false && tries < 2*mapSize)
|
||||
{
|
||||
var placer = new ClumpPlacer(pathWidth, 1, 1, 1, x, z);
|
||||
var painter = [new TerrainPainter(terrainPath), new SmoothElevationPainter(ELEVATION_MODIFY, -0.1, 1.0), paintClass(clPath)];
|
||||
createArea(placer, painter, avoidClasses(clPath, 0, clOpen, 0 ,clWater, 4, clBaseResource, 4));
|
||||
|
||||
// addToClass(x, z, clPath); // Not needed...
|
||||
// Set vars for next loop
|
||||
angle = getAngle(x, z, targetX, targetZ);
|
||||
if (doublePaths === true) // Bended paths
|
||||
{
|
||||
x += Math.round(Math.cos(angle + randFloat(-pathAngleOff/2, 3*pathAngleOff/2)));
|
||||
z += Math.round(Math.sin(angle + randFloat(-pathAngleOff/2, 3*pathAngleOff/2)));
|
||||
}
|
||||
else // Straight paths
|
||||
{
|
||||
x += Math.round(Math.cos(angle + randFloat(-pathAngleOff, pathAngleOff)));
|
||||
z += Math.round(Math.sin(angle + randFloat(-pathAngleOff, pathAngleOff)));
|
||||
}
|
||||
|
||||
if (Math.euclidDistance2D(x, z, targetX, targetZ) < pathSucsessRadius)
|
||||
targetReached = true;
|
||||
|
||||
tries++;
|
||||
}
|
||||
createArea(
|
||||
new RandomPathPlacer(pathStart, pathEnd, 1.75, baseRadius / 2, pathBlending),
|
||||
[
|
||||
new TerrainPainter(terrainPath),
|
||||
new SmoothElevationPainter(ELEVATION_MODIFY, -0.1, 1),
|
||||
paintClass(clPath)
|
||||
],
|
||||
avoidClasses(clPath, 0, clOpen, 0 ,clWater, 4, clBaseResource, 4));
|
||||
}
|
||||
}
|
||||
|
||||
Engine.SetProgress(75);
|
||||
|
||||
log("Creating decoration...");
|
||||
@@ -380,10 +290,10 @@ for (var x = 0; x < mapSize; x++)
|
||||
continue;
|
||||
|
||||
// The 0.5 is a correction for the entities placed on the center of tiles
|
||||
var radius = Math.euclidDistance2D(x + 0.5, z + 0.5, mapCenterX, mapCenterZ);
|
||||
var radius = Math.euclidDistance2D(x + 0.5, z + 0.5, mapCenter.x, mapCenter.y);
|
||||
var minDistToSL = mapSize;
|
||||
for (var i=0; i < numPlayers; i++)
|
||||
minDistToSL = Math.min(minDistToSL, Math.euclidDistance2D(playerStartLocX[i], playerStartLocZ[i], x, z));
|
||||
minDistToSL = Math.min(minDistToSL, Math.euclidDistance2D(x, z, playerPosition[i].x, playerPosition[i].x));
|
||||
|
||||
// Woods tile based
|
||||
var tDensFactSL = Math.max(Math.min((minDistToSL - baseRadius) / baseRadius, 1), 0);
|
||||
|
||||
Reference in New Issue
Block a user