Deobfuscate, deduplicate and fix Corsica vs. Sardinia and Pyrenean Sierra, refs 9016b8d866, a796800bb1.

Use vector algebra instead of adding one equation for each dimension
everywhere, refs #4845.
Add common createPassage terrain helper function to unify
straightPassageMaker and the modified copy PassMaker, refs #4805.

On Corsica vs Sardinia:

Comfort island shaping by
not hardcoding and not hiding magic numbers behind magic equations,
not specifying areas and deriving the radius from the disk area,
but always refer to newly introduced radius globals and compute the area
using diskArea from 1a896f531a.

Don't give some players 10% more map area and place all circular island
parts at the same center location in the map corner.
Don't place trees and mines into passages.
Simplify and order numbers, increase fail fractions from 4 to 10.
Use mapCenter getter from refs #4854.

This was SVN commit r20732.
This commit is contained in:
elexis 2017-12-30 16:17:54 +00:00
parent 279cad48e7
commit 0c70fb3036
3 changed files with 162 additions and 260 deletions

View file

@ -42,6 +42,7 @@ InitMap();
var numPlayers = getNumPlayers();
var mapSize = getMapSize();
var mapCenter = getMapCenter();
var clIsland = createTileClass();
var clCreek = createTileClass();
@ -57,13 +58,20 @@ var clSettlement = createTileClass();
initTerrain(tVeryDeepWater);
var radiusBeach = fractionToTiles(0.57);
var radiusCreeks = fractionToTiles(0.52);
var radiusIsland = fractionToTiles(0.4);
var radiusLevel1 = fractionToTiles(0.35);
var radiusPlayer = fractionToTiles(0.25);
var radiusLevel2 = fractionToTiles(0.2);
var creeksArea = () => randBool() ? randFloat(10, 50) : scaleByMapSize(75, 100) + randFloat(0, 20);
var nbCreeks = scaleByMapSize(6, 15);
var nbSubIsland = 5;
var nbBeaches = scaleByMapSize(2, 5);
var nbPassagesIsland = scaleByMapSize(1, 4);
var beachSmallRadius = fractionToTiles(0.45);
var beachBigRadius = fractionToTiles(0.57);
var nbPassagesLevel1 = scaleByMapSize(4, 8);
var nbPassagesLevel2 = scaleByMapSize(2, 4);
var heightMain = 5;
var heightCreeks = -5;
@ -74,161 +82,116 @@ var heightOffsetLevel2 = 8;
var heightOffsetBumps = 2;
var heightOffsetAntiBumps = -5;
log("Creating Corsica and Sardinia");
var islandX = [0.01, 0.99];
var islandZ = [0.1, 0.9];
log("Creating Corsica and Sardinia...");
var swapAngle = randBool() ? Math.PI / 2 : 0;
if (swapAngle)
islandX.reverse();
var islandLocations = [new Vector2D(0.05, 0.05), new Vector2D(0.95, 0.95)].map(v => v.mult(mapSize).rotateAround(-swapAngle, mapCenter));
for (let island = 0; island < 2; ++island)
{
let fx = fractionToTiles(islandX[island]);
let fz = fractionToTiles(islandZ[island]);
log("Creating island area...");
createArea(
new ClumpPlacer(fractionToSize(0.3) * 1.8, 1, 0.5, 10, Math.round(fx), Math.round(fz)),
new ClumpPlacer(diskArea(radiusIsland), 1, 0.5, 10, islandLocations[island].x, islandLocations[island].y),
[
new LayeredPainter([tCliffs, tGrass], [2]),
new SmoothElevationPainter(ELEVATION_SET, heightMain, 0),
paintClass(clIsland)
],
null);
]);
log("Creating subislands...");
for (let i = 0; i < nbSubIsland + 1; ++i)
{
let angle = Math.PI * (island - i / (nbSubIsland * 2));
if (!swapAngle)
angle *= -1;
let angle = Math.PI * (island + i / (nbSubIsland * 2)) + swapAngle;
let location = Vector2D.add(islandLocations[island], new Vector2D(radiusIsland, 0).rotate(-angle));
createArea(
new ClumpPlacer(
fractionToSize(0.05) / 2,
0.6,
0.03,
10,
Math.round(fx + Math.sqrt(fractionToSize(0.3) * 0.55) * Math.sin(angle)),
Math.round(fz + Math.sqrt(fractionToSize(0.3) * 0.55) * Math.cos(angle))),
new ClumpPlacer(fractionToSize(0.05) / 2, 0.6, 0.03, 10, location.x, location.y),
[
new LayeredPainter([tCliffs, tGrass], [2]),
new SmoothElevationPainter(ELEVATION_SET, heightMain, 1),
paintClass(clIsland)
],
null);
]);
}
log("Creating creeks");
log("Creating creeks...");
for (let i = 0; i < nbCreeks + 1; ++i)
{
let radius = fractionToTiles(randFloat(0.49, 0.55));
let angle = Math.PI * (island + i * (1 / (nbCreeks * 2))) + swapAngle;
let location = Vector2D.add(islandLocations[island], new Vector2D(radiusCreeks, 0).rotate(-angle));
createArea(
new ClumpPlacer(
randBool() ? randFloat(10, 50) : scaleByMapSize(75, 100) + randFloat(0, 20),
0.4,
0.01,
10,
Math.round(fx + radius * Math.cos(angle)),
Math.round(fz + radius * Math.sin(angle))),
new ClumpPlacer(creeksArea(), 0.4, 0.01, 10, location.x, location.y),
[
new TerrainPainter(tSteepCliffs),
new SmoothElevationPainter(ELEVATION_SET, heightCreeks, 0),
paintClass(clCreek)
],
null);
]);
}
log("Creating beaches...");
for (let i = 0; i < nbBeaches + 1; ++i)
{
let angle = Math.PI * (island + (i / (nbBeaches * 2.5)) + 1 / (nbBeaches * 6) + randFloat(-1, 1) / (nbBeaches * 7)) + swapAngle;
let startX = Math.round(fx + beachSmallRadius * Math.cos(angle));
let startZ = Math.round(fz + beachSmallRadius * Math.sin(angle));
let endX = Math.round(fx + beachBigRadius * Math.cos(angle));
let endZ = Math.round(fz + beachBigRadius * Math.sin(angle));
let start = Vector2D.add(islandLocations[island], new Vector2D(radiusIsland, 0).rotate(-angle));
let end = Vector2D.add(islandLocations[island], new Vector2D(radiusBeach, 0).rotate(-angle));
createArea(
new ClumpPlacer(130, 0.7, 0.8, 10, Math.round((startX + endX * 3) / 4), Math.round((startZ + endZ * 3) / 4)),
[new SmoothElevationPainter(ELEVATION_SET, heightBeaches, 5)],
null);
new ClumpPlacer(130, 0.7, 0.8, 10, Math.round((start.x + end.x * 3) / 4), Math.round((start.y + end.y * 3) / 4)),
new SmoothElevationPainter(ELEVATION_SET, heightBeaches, 5));
straightPassageMaker(
Math.max(0, Math.min(startX, mapSize)),
Math.max(0, Math.min(startZ, mapSize)),
Math.max(0, Math.min(endX, mapSize)),
Math.max(0, Math.min(endZ, mapSize)),
25,
18,
4,
clShore,
null);
createPassage({
"start": start,
"end": end,
"startWidth": 18,
"endWidth": 25,
"smoothWidth": 4,
"tileClass": clShore
});
}
let x = Math.round((fx * 5 + fractionToTiles(0.5)) / 6.0);
let z = Math.round(fz);
log("Creating main relief");
log("Creating main relief...");
createArea(
new ClumpPlacer(fractionToSize(0.3) * 1.8, 1, 0.2, 4, x, z),
new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetMainRelief, fractionToTiles(0.45)),
null);
new ClumpPlacer(diskArea(radiusIsland), 1, 0.2, 10, islandLocations[island].x, islandLocations[island].y),
new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetMainRelief, fractionToTiles(0.45)));
log("Creating first level plateau");
log("Creating first level plateau...");
createArea(
new ClumpPlacer(fractionToSize(0.18) * 1.8, 0.95, 0.02, 4, x, z),
new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLevel1, 1),
null);
new ClumpPlacer(diskArea(radiusLevel1), 0.95, 0.02, 10, islandLocations[island].x, islandLocations[island].y),
new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLevel1, 1));
log("Creating first level passages...");
for (let i = 0; i <= 3; ++i)
for (let i = 0; i <= nbPassagesLevel1; ++i)
{
let radius = Math.sqrt(fractionToSize(0.18) * 1.8 / Math.PI) + 2;
let angle = Math.PI * (i / 7 + 1 / 9 + island) + swapAngle;
straightPassageMaker(
Math.round(x + (radius + 7) * Math.cos(angle)),
Math.round(z + (radius + 7) * Math.sin(angle)),
Math.round(x + (radius - 5) * Math.cos(angle)),
Math.round(z + (radius - 5) * Math.sin(angle)),
4,
10,
3,
clPassage,
tGrass);
createPassage({
"start": Vector2D.add(islandLocations[island], new Vector2D(radiusLevel1 + 10, 0).rotate(-angle)),
"end": Vector2D.add(islandLocations[island], new Vector2D(radiusLevel1 - 4, 0).rotate(-angle)),
"startWidth": 10,
"endWidth": 6,
"smoothWidth": 3,
"tileClass": clPassage
});
}
if (mapSize > 150)
{
log("Creating second level plateau");
log("Creating second level plateau...");
createArea(
new ClumpPlacer(fractionToSize(0.1), 0.98, 0.04, 4, x, z),
new ClumpPlacer(diskArea(radiusLevel2), 0.98, 0.04, 10, islandLocations[island].x, islandLocations[island].y),
[
new LayeredPainter([tCliffs, tGrass], [2]),
new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetLevel2, 1)
],
null);
]);
log("Creating second level passages...");
for (let i = 0; i < nbPassagesIsland; ++i)
for (let i = 0; i < nbPassagesLevel2; ++i)
{
let radius = Math.sqrt(fractionToSize(0.1) / Math.PI) + 2;
let angle = Math.PI * (i / (2 * nbPassagesIsland) + 1 / (4 * nbPassagesIsland) + island) + swapAngle;
straightPassageMaker(
Math.round(x + (radius + 5) * Math.cos(angle)),
Math.round(z + (radius + 5) * Math.sin(angle)),
Math.round(x + (radius - 4) * Math.cos(angle)),
Math.round(z + (radius - 4) * Math.sin(angle)),
1,
6,
2,
clPassage,
tGrass);
let angle = Math.PI * (i / (2 * nbPassagesLevel2) + 1 / (4 * nbPassagesLevel2) + island) + swapAngle;
createPassage({
"start": Vector2D.add(islandLocations[island], new Vector2D(radiusLevel2 + 3, 0).rotate(-angle)),
"end": Vector2D.add(islandLocations[island], new Vector2D(radiusLevel2 - 6, 0).rotate(-angle)),
"startWidth": 4,
"endWidth": 6,
"smoothWidth": 2,
"tileClass": clPassage
});
}
}
}
@ -246,10 +209,9 @@ for (let island = 0; island < 2; ++island)
for (let i = 0; i < playersPerIsland; ++i)
{
let angle = Math.PI * ((i + 0.5) / (2 * playersPerIsland) + island) + swapAngle;
playerAngle[p] = angle;
playerX[p] = islandX[island] + 0.36 * Math.cos(angle);
playerZ[p] = island + 0.36 * Math.sin(angle);
playerAngle[p] = Math.PI * ((i + 0.5) / (2 * playersPerIsland) + island) + swapAngle;
let pos = Vector2D.add(islandLocations[island], new Vector2D(radiusPlayer).rotate(-playerAngle[p]));
[playerX[p], playerZ[p]] = [pos.x, pos.y];
++p;
}
}
@ -262,8 +224,8 @@ for (var i = 0; i < numPlayers; i++)
var radius = 23;
// get the x and z in tiles
let fx = fractionToTiles(playerX[i]);
let fz = fractionToTiles(playerZ[i]);
let fx = playerX[i];
let fz = playerZ[i];
// let's create a nice platform
var placer = new ClumpPlacer(PI*radius*radius, 0.95, 0.3, 10, fx,fz);
@ -311,10 +273,9 @@ for (var i = 0; i < numPlayers; i++)
group = new SimpleGroup([new SimpleObject(ePine, 1,3, 1,4),new SimpleObject(ePalmTall, 0,1, 1,4),new SimpleObject(eFanPalm, 0,1, 0,2)], true, clForest);
createObjectGroupsDeprecated(group, 0, [avoidClasses(clBaseResource,3, clSettlement,0), stayClasses(clPlayer,1)], 150, 1000);
}
Engine.SetProgress(40);
log("Creating bumps");
log("Creating bumps...");
createAreas(
new ClumpPlacer(70, 0.6, 0.1, 4),
[new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetBumps, 3)],
@ -325,10 +286,10 @@ createAreas(
scaleByMapSize(20, 100),
5);
log("Creating anti bumps");
log("Creating anti bumps...");
createAreas(
new ClumpPlacer(120, 0.3, 0.1, 4),
[new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetAntiBumps, 6)],
new SmoothElevationPainter(ELEVATION_MODIFY, heightOffsetAntiBumps, 6),
avoidClasses(clPlayer, 6, clPassage, 2, clIsland, 2),
scaleByMapSize(20, 100),
5);
@ -428,6 +389,7 @@ for (let mine of [eMetalMine, eStoneMine])
clWater, 3,
clPlayer, 6,
clBaseResource, 4,
clPassage, 2,
clCliffs, 1)
],
scaleByMapSize(6, 25),
@ -466,6 +428,7 @@ createObjectGroupsDeprecated(
clForest, 0,
clPlayer, 6,
clBaseResource, 4,
clPassage, 2,
clCliffs, 2)
],
scaleByMapSize(350, 2500),
@ -584,77 +547,9 @@ setWaterTint(0.208, 0.659, 0.925);
setWaterMurkiness(0.72);
setWaterWaviness(2.0);
setWaterType("ocean");
ExportMap();
// this function will go from point [x1,z1] to point [x2,z2], while following a curve of width (starting-center-starting)
// it can smooth on the side depending on "smooth", which is the distance of the smooth. Tileclass and Terrain set a tileclass/terrain
// it effectively can create a smooth path from point [x1,z1] to point [x2,z2], ie Canyon, whatever.
// note: NOT efficient for large distances: I'm widely oversampling
function straightPassageMaker(x1, z1, x2, z2, startWidth, centerWidth, smooth, tileclass, terrain)
{
var mapSize = g_Map.size;
var stepNB = sqrt((x2-x1)*(x2-x1) + (z2-z1)*(z2-z1)) + 2;
var startHeight = getHeight(x1,z1);
var finishHeight = getHeight(x2,z2);
for (var step = 0; step <= stepNB; step+=0.5)
{
var ix = ((stepNB-step)*x1 + x2*step) / stepNB;
var iz = ((stepNB-step)*z1 + z2*step) / stepNB;
// 5 at star/end, and 0 at the center
var width = (abs(step - stepNB/2.0) *startWidth + (stepNB/2 - abs(step - stepNB/2.0)) * centerWidth ) / (stepNB/2);
var oldDirection = [x2-x1, z2-z1];
// let's get the perpendicular direction
var direction = [ -oldDirection[1],oldDirection[0] ];
if (abs(direction[0]) > abs(direction[1]))
{
direction[1] = direction[1] / abs(direction[0]);
if (direction[0] > 0)
direction[0] = 1;
else
direction[0] = -1;
}
else
{
direction[0] = direction[0] / abs(direction[1]);
if (direction[1] > 0)
direction[1] = 1;
else
direction[1] = -1;
}
for (var po = -Math.floor(width/2.0); po <= Math.floor(width/2.0); po+=0.5)
{
var rx = po*direction[0];
var rz = po*direction[1];
var targetHeight = ((stepNB-step)*startHeight + finishHeight*step) / stepNB;
if (round(ix + rx) < mapSize && round(iz + rz) < mapSize && round(ix + rx) >= 0 && round(iz + rz) >= 0)
{
// smoothing the sides
if ( abs(abs(po) - abs(Math.floor(width/2.0))) < smooth)
{
var localHeight = getHeight(round(ix + rx), round(iz + rz));
var localPart = smooth - abs(abs(po) - abs(Math.floor(width/2.0)));
var targetHeight = (localHeight * localPart + targetHeight * (1/localPart) )/ (localPart + 1/localPart);
}
g_Map.setHeight(round(ix + rx), round(iz + rz), targetHeight);
if (tileclass !== null)
addToClass(round(ix + rx), round(iz + rz), tileclass);
if (terrain !== null)
placeTerrain(round(ix + rx), round(iz + rz), terrain);
}
}
}
}
// no need for preliminary rounding
function getHeightDiff(x1, z1)
{

View file

@ -191,14 +191,16 @@ for (var i = 0; i < numPlayers; i++)
Engine.SetProgress(30);
log ("Creating the pyreneans...");
var MountainStartX = mapCenter.x + Math.cos(MoutainAngle) * fractionToTiles(0.34);
var MountainStartZ = mapCenter.y + Math.sin(MoutainAngle) * fractionToTiles(0.34);
var MountainEndX = mapCenter.x - Math.cos(MoutainAngle) * fractionToTiles(0.34);
var MountainEndZ = mapCenter.y - Math.sin(MoutainAngle) * fractionToTiles(0.34);
var mountainLength = fractionToTiles(0.68);
var MountainHeight = scaleByMapSize(50,65);
var mountainVec = new Vector2D(mountainLength, 0).rotate(-MoutainAngle);
var mountainVecHalf = Vector2D.mult(mountainVec, 1/2);
var mountainStart = Vector2D.add(mapCenter, mountainVecHalf);
var mountainEnd = Vector2D.sub(mapCenter, mountainVecHalf);
// Number of peaks
var MountainHeight = scaleByMapSize(50, 65);
var NumOfIterations = scaleByMapSize(100,1000);
var randomNess = randFloat(-scaleByMapSize(1,12),scaleByMapSize(1,12));
@ -215,10 +217,10 @@ for (var i = 0; i < NumOfIterations; i++)
for (var dist = 0; dist < width*3; dist++)
{
var okDist = dist/3;
var S1x = round((MountainStartX * (1-position) + MountainEndX*position) + randomNess*cos(position*3.14*4) + cos(MoutainAngle+PI/2)*okDist);
var S1z = round((MountainStartZ * (1-position) + MountainEndZ*position) + randomNess*sin(position*3.14*4) + sin(MoutainAngle+PI/2)*okDist);
var S2x = round((MountainStartX * (1-position) + MountainEndX*position) + randomNess*cos(position*3.14*4) + cos(MoutainAngle-PI/2)*okDist);
var S2z = round((MountainStartZ * (1-position) + MountainEndZ*position) + randomNess*sin(position*3.14*4) + sin(MoutainAngle-PI/2)*okDist);
var S1x = round((mountainStart.x * (1-position) + mountainEnd.x*position) + randomNess*cos(position*3.14*4) + cos(MoutainAngle+PI/2)*okDist);
var S1z = round((mountainStart.y * (1-position) + mountainEnd.y*position) + randomNess*sin(position*3.14*4) + sin(MoutainAngle+PI/2)*okDist);
var S2x = round((mountainStart.x * (1-position) + mountainEnd.x*position) + randomNess*cos(position*3.14*4) + cos(MoutainAngle-PI/2)*okDist);
var S2z = round((mountainStart.y * (1-position) + mountainEnd.y*position) + randomNess*sin(position*3.14*4) + sin(MoutainAngle-PI/2)*okDist);
// complicated sigmoid
// Ranges is 0-1, FormX is 0-1 too.
@ -254,21 +256,28 @@ for (var ix = 1; ix < mapSize-1; ix++)
}
Engine.SetProgress(48);
// Okay so the mountains are pretty much here.
// Making the passes
log("Creating passages...");
var passageLocation = 0.35;
var passageHeight = MountainHeight - 25;
var passageLength = scaleByMapSize(8, 50);
var passageVec = mountainVec.perpendicular().normalize().mult(passageLength);
var passWidth = scaleByMapSize(15,100) /1.8;
var S1x = round((MountainStartX * (0.35) + MountainEndX*0.65) + cos(MoutainAngle+PI/2)*passWidth);
var S1z = round((MountainStartZ * (0.35) + MountainEndZ*0.65) + sin(MoutainAngle+PI/2)*passWidth);
var S2x = round((MountainStartX * (0.35) + MountainEndX*0.65) + cos(MoutainAngle-PI/2)*passWidth);
var S2z = round((MountainStartZ * (0.35) + MountainEndZ*0.65) + sin(MoutainAngle-PI/2)*passWidth);
PassMaker(S1x, S1z, S2x, S2z, 4, 7, (getHeight(S1x,S1z) + getHeight(S2x,S2z))/2.0, MountainHeight-25, 2, clPass);
for (let passLoc of [passageLocation, 1 - passageLocation])
for (let direction of [1, -1])
{
let passageStart = Vector2D.add(mountainEnd, Vector2D.mult(mountainVec, passLoc));
let passageEnd = Vector2D.add(passageStart, Vector2D.mult(passageVec, direction));
S1x = round((MountainStartX * (0.65) + MountainEndX*0.35) + cos(MoutainAngle+PI/2)*passWidth);
S1z = round((MountainStartZ * (0.65) + MountainEndZ*0.35) + sin(MoutainAngle+PI/2)*passWidth);
S2x = round((MountainStartX * (0.65) + MountainEndX*0.35) + cos(MoutainAngle-PI/2)*passWidth);
S2z = round((MountainStartZ * (0.65) + MountainEndZ*0.35) + sin(MoutainAngle-PI/2)*passWidth);
PassMaker(S1x, S1z, S2x, S2z, 4, 7, (getHeight(S1x,S1z) + getHeight(S2x,S2z))/2.0, MountainHeight-25, 2, clPass);
createPassage({
"start": passageStart,
"end": passageEnd,
"startHeight": passageHeight,
"startWidth": 7,
"endWidth": 7,
"smoothWidth": 2,
"tileClass": clPass
});
}
Engine.SetProgress(50);
@ -525,64 +534,7 @@ function getNeighborsHeight(x1, z1)
height /= 8;
return height;
}
// Taken from Corsica vs Sardinia with tweaks
function PassMaker(x1, z1, x2, z2, startWidth, centerWidth, startElevation, centerElevation, smooth, tileclass, terrain)
{
var mapSize = g_Map.size;
var stepNB = sqrt((x2-x1)*(x2-x1) + (z2-z1)*(z2-z1)) + 2;
var startHeight = startElevation;
var finishHeight = centerElevation;
for (var step = 0; step <= stepNB; step+=0.5)
{
var ix = ((stepNB-step)*x1 + x2*step) / stepNB;
var iz = ((stepNB-step)*z1 + z2*step) / stepNB;
var width = (abs(step - stepNB/2.0) *startWidth + (stepNB/2 - abs(step - stepNB/2.0)) * centerWidth ) / (stepNB/2);
var oldDirection = [x2-x1, z2-z1];
// let's get the perpendicular direction
var direction = [ -oldDirection[1],oldDirection[0] ];
if (abs(direction[0]) > abs(direction[1]))
{
direction[1] = direction[1] / abs(direction[0]);
if (direction[0] > 0)
direction[0] = 1;
else
direction[0] = -1;
} else {
direction[0] = direction[0] / abs(direction[1]);
if (direction[1] > 0)
direction[1] = 1;
else
direction[1] = -1;
}
for (var po = -Math.floor(width/2.0); po <= Math.floor(width/2.0); po+=0.5)
{
var rx = po*direction[0];
var rz = po*direction[1];
var targetHeight = (abs(step - stepNB/2.0) *startHeight + (stepNB/2 - abs(step - stepNB/2.0)) * finishHeight ) / (stepNB/2);
if (round(ix + rx) < mapSize && round(iz + rz) < mapSize && round(ix + rx) >= 0 && round(iz + rz) >= 0)
{
// smoothing the sides
if ( abs(abs(po) - abs(Math.floor(width/2.0))) < smooth)
{
var localHeight = getHeight(round(ix + rx), round(iz + rz));
var localPart = smooth - abs(abs(po) - abs(Math.floor(width/2.0)));
var targetHeight = (localHeight * localPart + targetHeight * (1/localPart) )/ (localPart + 1/localPart);
}
g_Map.setHeight(round(ix + rx), round(iz + rz), targetHeight);
if (tileclass != null)
addToClass(round(ix + rx), round(iz + rz), tileclass);
if (terrain != null)
placeTerrain(round(ix + rx), round(iz + rz), terrain);
}
}
}
}
// no need for preliminary rounding
function getHeightDifference(x1, z1)
{
@ -610,4 +562,3 @@ function getHeightDifference(x1, z1)
diff /= todiv;
return diff;
}

View file

@ -585,6 +585,62 @@ function createShallowsPassage(x1, z1, x2, z2, width, maxHeight, shallowHeight,
}
}
/**
* Creates a smooth, passable path between between (startX, startZ) and (endX, endZ) with the given startWidth and endWidth.
* Paints the given tileclass and terrain.
*
* @property {Vector2D} start - Location of the passage.
* @property {Vector2D} end
* @property {number} startWidth - Size of the passage (perpendicular to the direction of the passage).
* @property {number} endWidth
* @property {number} [startHeight] - Fixed height to be used if the height at the location shouldn't be used.
* @property {number} [endHeight]
* @property {number} smoothWidth - Number of tiles at the passage border to apply height interpolation.
* @property {number} [tileClass] - Marks the passage with this tile class.
* @property {string} [terrain] - Texture to be painted on the passage area.
*/
function createPassage(args)
{
let bound = x => Math.max(0, Math.min(Math.round(x), getMapSize()));
let startHeight = args.startHeight !== undefined ? args.startHeight : getHeight(bound(args.start.x), bound(args.start.y));
let endHeight = args.endHeight !== undefined ? args.endHeight : getHeight(bound(args.end.x), bound(args.end.y));
let passageVec = Vector2D.sub(args.end, args.start);
let widthDirection = passageVec.perpendicular().normalize();
let lengthStep = 1 / (2 * passageVec.length());
for (let lengthFraction = 0; lengthFraction <= 1; lengthFraction += lengthStep)
{
let locationLength = Vector2D.add(args.start, Vector2D.mult(passageVec, lengthFraction));
let halfPassageWidth = (args.startWidth + (args.endWidth - args.startWidth) * lengthFraction) / 2;
let passageHeight = startHeight + (endHeight - startHeight) * lengthFraction;
for (let stepWidth = -halfPassageWidth; stepWidth <= halfPassageWidth; stepWidth += 0.5)
{
let location = Vector2D.add(locationLength, Vector2D.mult(widthDirection, stepWidth)).round();
if (!g_Map.inMapBounds(location.x, location.y))
continue;
let smoothDistance = args.smoothWidth + Math.abs(stepWidth) - halfPassageWidth;
g_Map.setHeight(
location.x,
location.y,
smoothDistance > 0 ?
(getHeight(location.x, location.y) * smoothDistance + passageHeight / smoothDistance) / (smoothDistance + 1 / smoothDistance) :
passageHeight);
if (args.tileClass)
addToClass(location.x, location.y, args.tileClass);
if (args.terrain)
placeTerrain(location.x, location.y, args.terrain);
}
}
}
/**
* Creates a ramp from (x1, y1) to (x2, y2).
*/