Extend the random map river algorithm (7d0cc59136
) to allow arbitrary start and end points.
Reverse engineer and cleanup obfuscated Rivers map code, refsa9b963c3a5
. Use vector algebra to replace magic equations and express geometric intend. Fix seed typo by removing river curve duplicate. On the Rivers map, use areAllies directly instead of copying the diplomacies to a 2D array called isRiver. Use modulo operator instead of an if-statement with duplication to determine the neighbor of the last player, refs9272153ee7
. This was SVN commit r20429.
This commit is contained in:
parent
b3dbcc457b
commit
e596ef6011
@ -153,9 +153,11 @@ for (var i = 0; i < numPlayers; i++)
|
||||
RMS.SetProgress(30);
|
||||
|
||||
paintRiver({
|
||||
"horizontal": false,
|
||||
"parallel": false,
|
||||
"position": 0.5,
|
||||
"startX": 0.5,
|
||||
"startZ": 0,
|
||||
"endX": 0.5,
|
||||
"endZ": 1,
|
||||
"width": 0.35,
|
||||
"fadeDist": 0.025,
|
||||
"deviation": 0,
|
||||
@ -163,7 +165,7 @@ paintRiver({
|
||||
"landHeight": 2,
|
||||
"meanderShort": 20,
|
||||
"meanderLong": 0,
|
||||
"waterFunc": (ix, iz, height) => {
|
||||
"waterFunc": (ix, iz, height, riverFraction) => {
|
||||
|
||||
if (height < 0.7)
|
||||
addToClass(ix, iz, clWater);
|
||||
|
@ -404,11 +404,12 @@ for (let i = 0; i < numPlayers; ++i)
|
||||
}
|
||||
RMS.SetProgress(20);
|
||||
|
||||
log("Creating the river");
|
||||
paintRiver({
|
||||
"horizontal": false,
|
||||
"parallel": true,
|
||||
"position": 0.5,
|
||||
"startX": 0.5,
|
||||
"startZ": 0,
|
||||
"endX": 0.5,
|
||||
"endZ": 1,
|
||||
"width": waterWidth,
|
||||
"fadeDist": 0.025,
|
||||
"deviation": 0,
|
||||
@ -416,7 +417,7 @@ paintRiver({
|
||||
"landHeight": 2,
|
||||
"meanderShort": 30,
|
||||
"meanderLong": 0,
|
||||
"waterFunc": (ix, iz, height) => {
|
||||
"waterFunc": (ix, iz, height, riverFraction) => {
|
||||
|
||||
if (height < 0.7)
|
||||
addToClass(ix, iz, clWater);
|
||||
|
@ -147,9 +147,11 @@ for (var i = 0; i < numPlayers; i++)
|
||||
RMS.SetProgress(10);
|
||||
|
||||
paintRiver({
|
||||
"horizontal": true,
|
||||
"parallel": false,
|
||||
"position": 0.5,
|
||||
"startX": 0,
|
||||
"startZ": 0.5,
|
||||
"endX": 1,
|
||||
"endZ": 0.5,
|
||||
"width": 0.25,
|
||||
"fadeDist": 0.01,
|
||||
"deviation": 0,
|
||||
@ -157,7 +159,7 @@ paintRiver({
|
||||
"landHeight": landHeight,
|
||||
"meanderShort": 20,
|
||||
"meanderLong": 0,
|
||||
"waterFunc": (ix, iz, height) => {
|
||||
"waterFunc": (ix, iz, height, riverFraction) => {
|
||||
placeTerrain(ix, iz, height < -1.5 ? tWater : tShore);
|
||||
},
|
||||
"landFunc": (ix, iz, shoreDist1, shoreDist2) => {
|
||||
|
@ -52,6 +52,11 @@ var clLand = createTileClass();
|
||||
var clRiver = createTileClass();
|
||||
var clShallow = createTileClass();
|
||||
|
||||
var landHeight = 3;
|
||||
var shoreHeight = 2;
|
||||
var shallowHeight = -1.5;
|
||||
var waterHeight = -3;
|
||||
|
||||
log("Create the continent body");
|
||||
createArea(
|
||||
new ChainPlacer(
|
||||
@ -65,7 +70,7 @@ createArea(
|
||||
[Math.floor(mapSize * 0.49)]),
|
||||
[
|
||||
new LayeredPainter([tGrass, tGrass, tGrass], [4, 2]),
|
||||
new SmoothElevationPainter(ELEVATION_SET, 3, 4),
|
||||
new SmoothElevationPainter(ELEVATION_SET, landHeight, 4),
|
||||
paintClass(clLand)
|
||||
],
|
||||
null);
|
||||
@ -161,28 +166,26 @@ for (var i = 0; i < numPlayers; i++)
|
||||
|
||||
placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius);
|
||||
}
|
||||
|
||||
RMS.SetProgress(20);
|
||||
|
||||
var shallowHeight = -1.5;
|
||||
paintRiver({
|
||||
"horizontal": false,
|
||||
"parallel": true,
|
||||
"constraint": stayClasses(clLand, 0),
|
||||
"position": 0.5,
|
||||
"startX": 0.5,
|
||||
"startZ": 0,
|
||||
"endX": 0.5,
|
||||
"endZ": 1,
|
||||
"width": 0.07,
|
||||
"fadeDist": 0.025,
|
||||
"deviation": 0.005,
|
||||
"waterHeight": -3,
|
||||
"landHeight": 2,
|
||||
"deviation": 0.0025,
|
||||
"waterHeight": waterHeight,
|
||||
"landHeight": shoreHeight,
|
||||
"meanderShort": 12,
|
||||
"meanderLong": 0,
|
||||
"waterFunc": (ix, iz, height) => {
|
||||
"waterFunc": (ix, iz, height, z) => {
|
||||
addToClass(ix, iz, clRiver);
|
||||
placeTerrain(ix, iz, tWater);
|
||||
|
||||
let z = iz / (mapSize + 1.0);
|
||||
|
||||
if (height < shallowHeight && (
|
||||
z > 0.3 && z < 0.4 ||
|
||||
z > 0.5 && z < 0.6 ||
|
||||
|
@ -135,9 +135,11 @@ for (var i = 0; i < numPlayers; i++)
|
||||
RMS.SetProgress(10);
|
||||
|
||||
paintRiver({
|
||||
"horizontal": true,
|
||||
"parallel": true,
|
||||
"position": 1,
|
||||
"startX": 0,
|
||||
"startZ": 1,
|
||||
"endX": 1,
|
||||
"endZ": 1,
|
||||
"width": 0.5,
|
||||
"fadeDist": 0.05,
|
||||
"deviation": 0,
|
||||
@ -145,7 +147,7 @@ paintRiver({
|
||||
"landHeight": 1,
|
||||
"meanderShort": 20,
|
||||
"meanderLong": 0,
|
||||
"waterFunc": (ix, iz, height) => {
|
||||
"waterFunc": (ix, iz, height, riverFraction) => {
|
||||
|
||||
if (height < 0)
|
||||
addToClass(ix, iz, clWater);
|
||||
|
@ -136,9 +136,11 @@ const waterPos = 0.31;
|
||||
const mountainPos = 0.69;
|
||||
|
||||
paintRiver({
|
||||
"horizontal": false,
|
||||
"parallel": false,
|
||||
"position": 0,
|
||||
"startX": 0,
|
||||
"startZ": 0,
|
||||
"endX": 0,
|
||||
"endZ": 1,
|
||||
"width": 2 * waterPos,
|
||||
"fadeDist": 0.025,
|
||||
"deviation": 0,
|
||||
@ -146,11 +148,11 @@ paintRiver({
|
||||
"landHeight": 3,
|
||||
"meanderShort": 20,
|
||||
"meanderLong": 0,
|
||||
"waterFunc": (ix, iz, height) => {
|
||||
"waterFunc": (ix, iz, height, riverFraction) => {
|
||||
addToClass(ix, iz, clWater);
|
||||
},
|
||||
"landFunc": (ix, iz, shoreDist1, shoreDist2) => {
|
||||
if (ix > mountainPos * mapSize)
|
||||
if (ix > fractionToTiles(mountainPos))
|
||||
addToClass(ix, iz, clMountains)
|
||||
}
|
||||
});
|
||||
|
@ -113,17 +113,19 @@ for (var i = 0; i < numPlayers; i++)
|
||||
RMS.SetProgress(15);
|
||||
|
||||
paintRiver({
|
||||
"horizontal": true,
|
||||
"parallel": true,
|
||||
"position": 1,
|
||||
"startX": 0,
|
||||
"startZ": 1,
|
||||
"endX": 1,
|
||||
"endZ": 1,
|
||||
"width": 0.62,
|
||||
"fadeDist": 8 / mapSize,
|
||||
"fadeDist": tilesToFraction(8),
|
||||
"deviation": 0,
|
||||
"waterHeight": -5,
|
||||
"landHeight": 3,
|
||||
"meanderShort": 0,
|
||||
"meanderLong": 0,
|
||||
"waterFunc": (ix, iz, height) => {
|
||||
"waterFunc": (ix, iz, height, riverFraction) => {
|
||||
addToClass(ix, iz, clWater);
|
||||
},
|
||||
"landFunc": (ix, iz, shoreDist1, shoreDist2) => {
|
||||
|
@ -138,9 +138,11 @@ for (var i = 0; i < numPlayers; i++)
|
||||
RMS.SetProgress(30);
|
||||
|
||||
paintRiver({
|
||||
"horizontal": false,
|
||||
"parallel": true,
|
||||
"position": 0,
|
||||
"startX": 0,
|
||||
"startZ": 0,
|
||||
"endX": 0,
|
||||
"endZ": 1,
|
||||
"width": 1,
|
||||
"fadeDist": 0.05,
|
||||
"deviation": 0,
|
||||
@ -148,7 +150,7 @@ paintRiver({
|
||||
"landHeight": 1,
|
||||
"meanderShort": 20,
|
||||
"meanderLong": 0,
|
||||
"waterFunc": (ix, iz, height) => {
|
||||
"waterFunc": (ix, iz, height, riverFraction) => {
|
||||
|
||||
if (height < 0)
|
||||
addToClass(ix, iz, clWater);
|
||||
|
@ -63,19 +63,24 @@ var clFood = createTileClass();
|
||||
var clBaseResource = createTileClass();
|
||||
var clShallow = createTileClass();
|
||||
|
||||
var waterHeight = -3;
|
||||
var shallowHeight = -1;
|
||||
|
||||
initTerrain(tMainTerrain);
|
||||
|
||||
log("Creating central lake...");
|
||||
var centralLake = [0.5, 0.5];
|
||||
createArea(
|
||||
new ClumpPlacer(
|
||||
mapArea / 100 * Math.pow(scaleByMapSize(1, 6), 1/8),
|
||||
0.7,
|
||||
0.1,
|
||||
10,
|
||||
Math.round(fractionToTiles(0.5)),
|
||||
Math.round(fractionToTiles(0.5))),
|
||||
fractionToTiles(centralLake[0]),
|
||||
fractionToTiles(centralLake[1])),
|
||||
[
|
||||
new LayeredPainter([tShore, tWater, tWater, tWater], [1, 4, 2]),
|
||||
new SmoothElevationPainter(ELEVATION_SET, -3, 4),
|
||||
new SmoothElevationPainter(ELEVATION_SET, waterHeight, 4),
|
||||
paintClass(clWater)
|
||||
],
|
||||
null);
|
||||
@ -92,10 +97,10 @@ for (var i = 0; i < numPlayers; i++)
|
||||
var elevation = 20;
|
||||
|
||||
// get the x and z in tiles
|
||||
fx = fractionToTiles(playerX[i]);
|
||||
fz = fractionToTiles(playerZ[i]);
|
||||
ix = round(fx);
|
||||
iz = round(fz);
|
||||
var fx = fractionToTiles(playerX[i]);
|
||||
var fz = fractionToTiles(playerZ[i]);
|
||||
var ix = round(fx);
|
||||
var iz = round(fz);
|
||||
addCivicCenterAreaToClass(ix, iz, clPlayer);
|
||||
|
||||
// create the city patch
|
||||
@ -157,142 +162,53 @@ for (var i = 0; i < numPlayers; i++)
|
||||
|
||||
placeDefaultDecoratives(fx, fz, aGrassShort, clBaseResource, radius);
|
||||
}
|
||||
|
||||
RMS.SetProgress(20);
|
||||
|
||||
//init rivers
|
||||
var PX = [];
|
||||
var PZ = [];
|
||||
|
||||
//isRiver actually tells us if two points must be joined by river
|
||||
var isRiver = [];
|
||||
for (let m = 0; m < numPlayers + 1; ++m)
|
||||
log("Creating rivers between opponents...");
|
||||
var [riverX, riverZ] = distributePointsOnCircle(numPlayers, startAngle + Math.PI / numPlayers, 0.5, ...centralLake);
|
||||
for (let i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
isRiver[m] = [];
|
||||
for (let n = 0; n < numPlayers + 1; ++n)
|
||||
isRiver[m][n] = 0;
|
||||
if (areAllies(playerIDs[i] - 1, playerIDs[(i + 1) % numPlayers] - 1))
|
||||
continue;
|
||||
|
||||
let shallowLocation = randFloat(0.2, 0.7);
|
||||
let shallowWidth = randFloat(0.12, 0.21);
|
||||
|
||||
paintRiver({
|
||||
"parallel": true,
|
||||
"startX": riverX[i],
|
||||
"startZ": riverZ[i],
|
||||
"endX": centralLake[0],
|
||||
"endZ": centralLake[1],
|
||||
"width": tilesToFraction(scaleByMapSize(10, 30)),
|
||||
"fadeDist": tilesToFraction(5),
|
||||
"deviation": 0,
|
||||
"landHeight": getMapBaseHeight(),
|
||||
"waterHeight": waterHeight,
|
||||
"minHeight": waterHeight,
|
||||
"meanderShort": tilesToFraction(scaleByMapSize(20, 60) * scaleByMapSize(35, 160)),
|
||||
"meanderLong": 0,
|
||||
"waterFunc": (ix, iz, height, riverFraction) => {
|
||||
|
||||
addToClass(ix, iz, clWater);
|
||||
|
||||
let isShallow = height < shallowHeight &&
|
||||
riverFraction > shallowLocation &&
|
||||
riverFraction < shallowLocation + shallowWidth;
|
||||
|
||||
let newHeight = isShallow ? shallowHeight : Math.max(height, waterHeight);
|
||||
|
||||
if (getHeight(ix, iz) < newHeight)
|
||||
return;
|
||||
|
||||
setHeight(ix, iz, newHeight);
|
||||
placeTerrain(ix, iz, height >= 0 ? tShore : tWater);
|
||||
|
||||
if (isShallow)
|
||||
addToClass(ix, iz, clShallow);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//creating the first point in the center. all others are
|
||||
//connected to this one so all of our rivers join together
|
||||
//in the middle of the map
|
||||
var fx = fractionToTiles(0.5);
|
||||
var fz = fractionToTiles(0.5);
|
||||
var ix = round(fx);
|
||||
var iz = round(fz);
|
||||
PX[numPlayers]= fx;
|
||||
PZ[numPlayers]= fz;
|
||||
|
||||
var riverAngle = [];
|
||||
for (var c = 0 ; c < numPlayers ; c++)
|
||||
{
|
||||
//creating other points of the river and making them
|
||||
// join the point in the center of the map
|
||||
riverAngle[c] = startAngle + (((2 * c + 1) / (numPlayers * 2)) * TWO_PI );
|
||||
PX[c] = round(fractionToTiles(0.5 + 0.5 * cos(riverAngle[c])));
|
||||
PZ[c] = round(fractionToTiles(0.5 + 0.5 * sin(riverAngle[c])));
|
||||
//log (playerIDs[c], ",,," ,playerIDs[0]);
|
||||
//isRiver[c][numPlayers]=1;
|
||||
if ((c == numPlayers-1)&&(!areAllies(playerIDs[c]-1, playerIDs[0]-1)))
|
||||
isRiver[c][numPlayers]=1;
|
||||
else if ((c < numPlayers-1)&&(!areAllies(playerIDs[c]-1, playerIDs[c+1]-1)))
|
||||
isRiver[c][numPlayers]=1;
|
||||
}
|
||||
|
||||
//theta is the start value for rndRiver function. seed implies
|
||||
//the randomness. we must have one of these for each river we create.
|
||||
//shallowpoint and shallow length define the place and size of the shallow part
|
||||
var theta = [];
|
||||
var seed = [];
|
||||
var shallowpoint = [];
|
||||
var shallowlength = [];
|
||||
for (let q = 0; q < numPlayers + 1; ++q)
|
||||
{
|
||||
theta[q]=randFloat(0, 1);
|
||||
seed[q]=randFloat(2,3);
|
||||
shallowpoint[q]=randFloat(0.2,0.7);
|
||||
shallowlength[q]=randFloat(0.12,0.21);
|
||||
}
|
||||
|
||||
log ("Creating rivers...");
|
||||
//checking all the tiles
|
||||
for (var ix = 0; ix < mapSize; ix++)
|
||||
for (var iz = 0; iz < mapSize; iz++)
|
||||
for (var m = 0; m < numPlayers+1; m++)
|
||||
for (var n = 0; n < numPlayers+1; n++)
|
||||
{
|
||||
//checking if there is a river between those points
|
||||
if(isRiver[m][n] == 1)
|
||||
{
|
||||
//very important calculations. don't change anything. results
|
||||
//"dis" which is the distance to the riverline and "y" and "xm" which are
|
||||
//the coordinations for the point it's image is in.
|
||||
var a = PZ[m]-PZ[n];
|
||||
var b = PX[n]-PX[m];
|
||||
var c = (PZ[m]*(PX[m]-PX[n]))-(PX[m]*(PZ[m]-PZ[n]));
|
||||
var dis = abs(a*ix + b*iz + c)/sqrt(a*a + b*b);
|
||||
if (abs(a*ix + b*iz + c) != 0)
|
||||
var alamat = (a*ix + b*iz + c)/abs(a*ix + b*iz + c);
|
||||
else
|
||||
var alamat = 1;
|
||||
|
||||
var k = (a*ix + b*iz + c)/(a*a + b*b);
|
||||
var y = iz-(b*k);
|
||||
var xm = ix-(a*k);
|
||||
//this calculates which "part" of the river are we in now.
|
||||
//used for the function rndRiver.
|
||||
var sit = sqrt((PZ[n]-y)*(PZ[n]-y)+(PX[n]-xm)*(PX[n]-xm))/sqrt((PZ[n]-PZ[m])*(PZ[n]-PZ[m])+(PX[n]-PX[m])*(PX[n]-PX[m]));
|
||||
var sbms = scaleByMapSize(5,15) + alamat * ( scaleByMapSize(20, 60) * rndRiver( theta[m] + sit * 0.5 * (mapSize/64) , seed[m]) );
|
||||
if((dis < sbms)&&(y <= Math.max(PZ[m],PZ[n]))&&(y >= Math.min(PZ[m],PZ[n])))
|
||||
{
|
||||
//create the deep part of the river
|
||||
if (dis <= sbms-5){
|
||||
if ((sit > shallowpoint[m])&&(sit < shallowpoint[m]+shallowlength[m]))
|
||||
{
|
||||
//create the shallow part
|
||||
var h = -1;
|
||||
addToClass(ix, iz, clShallow);
|
||||
}
|
||||
else
|
||||
var h = -3;
|
||||
|
||||
var t = tWater;
|
||||
addToClass(ix, iz, clWater);
|
||||
}
|
||||
//creating the rough edges
|
||||
else if (dis <= sbms)
|
||||
{
|
||||
if ((sit > shallowpoint[m])&&(sit < shallowpoint[m]+shallowlength[m]))
|
||||
{
|
||||
if (2-(sbms-dis)<-1)
|
||||
{
|
||||
//checking if there is shallow water here
|
||||
var h = -1;
|
||||
addToClass(ix, iz, clShallow);
|
||||
}
|
||||
else
|
||||
var h = 2-(sbms-dis);
|
||||
}
|
||||
else
|
||||
var h = 2-(sbms-dis);
|
||||
|
||||
//we must create shore lines for more beautiful terrain
|
||||
if (sbms-dis<=2)
|
||||
var t = tShore;
|
||||
else
|
||||
var t = tWater;
|
||||
addToClass(ix, iz, clWater);
|
||||
}
|
||||
//we don't want to cause problems when river joins sea
|
||||
if (getHeight(ix, iz)>h)
|
||||
{
|
||||
placeTerrain(ix, iz, t);
|
||||
setHeight(ix, iz, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RMS.SetProgress(40);
|
||||
|
||||
createBumps(avoidClasses(clWater, 2, clPlayer, 20));
|
||||
|
@ -317,34 +317,61 @@ function createLayeredPatches(sizes, terrains, terrainWidths, constraint, count,
|
||||
/**
|
||||
* Creates a meandering river at the given location and width.
|
||||
* Optionally calls a function on the affected tiles.
|
||||
* Horizontal locations and widths (including fadeDist, meandering) are fractions of the mapsize.
|
||||
*
|
||||
* @property horizontal - Whether the river is horizontal or vertical
|
||||
* @property parallel - Whether the shorelines should be parallel or meander separately.
|
||||
* @property position - Location of the river. Number between 0 and 1.
|
||||
* @property width - Size between the two shorelines. Number between 0 and 1.
|
||||
* @property position - Location of the river.
|
||||
* @property width - Size between the two shorelines.
|
||||
* @property fadeDist - Size of the shoreline.
|
||||
* @property deviation - Fuzz effect on the shoreline if greater than 0.
|
||||
* @property waterHeight - Ground height of the riverbed.
|
||||
* @proeprty landHeight - Ground height of the end of the shoreline.
|
||||
* @property meanderShort - Strength of frequent meanders.
|
||||
* @property meanderLong - Strength of less frequent meanders.
|
||||
* @property waterFunc - Optional function called on water tiles, providing ix, iz, height.
|
||||
* @property landFunc - Optional function called on land tiles, providing ix, iz, shoreDist1, shoreDist2.
|
||||
* @property [constraint] - If given, ignores any tiles that don't satisfy the given Constraint.
|
||||
* @property [waterFunc] - Optional function called on tiles within the river.
|
||||
* Provides location on the tilegrid, new elevation and
|
||||
* the location on the axis parallel to the river as a fraction of the river length.
|
||||
* @property [landFunc] - Optional function called on land tiles, providing ix, iz, shoreDist1, shoreDist2.
|
||||
* @property [minHeight] - If given, only changes the elevation below this height while still calling the given functions.
|
||||
*/
|
||||
function paintRiver(args)
|
||||
{
|
||||
log("Creating the river");
|
||||
|
||||
let theta1 = randFloat(0, 1);
|
||||
let theta2 = randFloat(0, 1);
|
||||
// Model the river meandering as the sum of two sine curves.
|
||||
let meanderShort = fractionToTiles(args.meanderShort / scaleByMapSize(35, 160));
|
||||
let meanderLong = fractionToTiles(args.meanderLong / scaleByMapSize(35, 100));
|
||||
|
||||
// Unless the river is parallel, each riverside will receive an own random seed and starting angle.
|
||||
let seed1 = randFloat(2, 3);
|
||||
let seed2 = randFloat(2, 3);
|
||||
|
||||
let meanderShort = args.meanderShort / scaleByMapSize(35, 160);
|
||||
let meanderLong = args.meanderLong / scaleByMapSize(35, 100);
|
||||
let startingAngle1 = randFloat(0, 1);
|
||||
let startingAngle2 = randFloat(0, 1);
|
||||
|
||||
// Computes the deflection of the river at a given point.
|
||||
let riverCurve = (riverFraction, startAngle, seed) =>
|
||||
meanderShort * rndRiver(startAngle + fractionToTiles(riverFraction) / 128, seed) +
|
||||
meanderLong * rndRiver(startAngle + fractionToTiles(riverFraction) / 256, seed);
|
||||
|
||||
// Describe river width and length of the shoreline.
|
||||
let halfWidth = fractionToTiles(args.width / 2);
|
||||
let fadeDist = fractionToTiles(args.fadeDist);
|
||||
|
||||
// Describe river location in vectors.
|
||||
let mapSize = getMapSize();
|
||||
let vecStart = new Vector2D(args.startX, args.startZ).mult(mapSize);
|
||||
let vecEnd = new Vector2D(args.endX, args.endZ).mult(mapSize);
|
||||
let vecRiver = Vector2D.sub(vecStart, vecEnd);
|
||||
let riverLength = vecRiver.length();
|
||||
|
||||
// Describe river boundaries.
|
||||
let riverMinX = Math.min(vecStart.x, vecEnd.x);
|
||||
let riverMinZ = Math.min(vecStart.y, vecEnd.y);
|
||||
let riverMaxX = Math.max(vecStart.x, vecEnd.x);
|
||||
let riverMaxZ = Math.max(vecStart.y, vecEnd.y);
|
||||
|
||||
for (let ix = 0; ix < mapSize; ++ix)
|
||||
for (let iz = 0; iz < mapSize; ++iz)
|
||||
@ -352,41 +379,49 @@ function paintRiver(args)
|
||||
if (args.constraint && !args.constraint.allows(ix, iz))
|
||||
continue;
|
||||
|
||||
let x = ix / (mapSize + 1);
|
||||
let z = iz / (mapSize + 1);
|
||||
let vecPoint = new Vector2D(ix, iz);
|
||||
|
||||
let coord1 = args.horizontal ? z : x;
|
||||
let coord2 = args.horizontal ? x : z;
|
||||
// Compute the shortest distance to the river.
|
||||
let distanceToRiver = vecRiver.cross(Vector2D.sub(vecPoint, vecEnd)) / riverLength;
|
||||
|
||||
// River curve at this place
|
||||
let curve1 =
|
||||
meanderShort * rndRiver(theta1 + coord2 * mapSize / 128, seed1) +
|
||||
meanderLong * rndRiver(theta2 + coord2 * mapSize / 256, seed2);
|
||||
// Closest point on the river (i.e the foot of the perpendicular).
|
||||
let river = Vector2D.sub(vecPoint, vecRiver.perpendicular().mult(distanceToRiver / riverLength));
|
||||
|
||||
let curve2 = args.parallel ? curve1 :
|
||||
meanderShort * rndRiver(theta2 + coord2 * mapSize / 128, seed2) +
|
||||
meanderLong * rndRiver(theta2 + coord2 * mapSize / 256, seed2);
|
||||
// Only process points that actually are perpendicular with the river.
|
||||
if (river.x < riverMinX || river.x > riverMaxX ||
|
||||
river.y < riverMinZ || river.y > riverMaxZ)
|
||||
continue;
|
||||
|
||||
// Fuzz the river border
|
||||
let devCoord1 = coord1 * randFloat(1 - args.deviation, 1 + args.deviation);
|
||||
let devCoord2 = coord2 * randFloat(1 - args.deviation, 1 + args.deviation);
|
||||
// Coordinate between 0 and 1 on the axis parallel to the river.
|
||||
let riverFraction = river.distanceTo(vecStart) / riverLength;
|
||||
|
||||
let shoreDist1 = -devCoord1 + curve1 + args.position - args.width / 2;
|
||||
let shoreDist2 = -devCoord1 + curve2 + args.position + args.width / 2;
|
||||
// Amplitude of the river at this location.
|
||||
let riverCurve1 = riverCurve(riverFraction, startingAngle1, seed1);
|
||||
let riverCurve2 = args.parallel ? riverCurve1 : riverCurve(riverFraction, startingAngle2, seed2);
|
||||
|
||||
// Add noise.
|
||||
let deviation = fractionToTiles(args.deviation) * randFloat(-1, 1);
|
||||
|
||||
// Compute the distance to the shoreline.
|
||||
let sign = Math.sign(distanceToRiver || 1);
|
||||
let shoreDist1 = sign * riverCurve1 + Math.abs(distanceToRiver) - deviation - halfWidth;
|
||||
let shoreDist2 = sign * riverCurve2 + Math.abs(distanceToRiver) - deviation + halfWidth;
|
||||
|
||||
// Create the elevation for the water and the slopy shoreline and call the user functions.
|
||||
if (shoreDist1 < 0 && shoreDist2 > 0)
|
||||
{
|
||||
let height = args.waterHeight;
|
||||
|
||||
if (shoreDist1 > -args.fadeDist)
|
||||
height += (args.landHeight - args.waterHeight) * (1 + shoreDist1 / args.fadeDist);
|
||||
else if (shoreDist2 < args.fadeDist)
|
||||
height += (args.landHeight - args.waterHeight) * (1 - shoreDist2 / args.fadeDist);
|
||||
if (shoreDist1 > -fadeDist)
|
||||
height += (args.landHeight - args.waterHeight) * (1 + shoreDist1 / fadeDist);
|
||||
else if (shoreDist2 < fadeDist)
|
||||
height += (args.landHeight - args.waterHeight) * (1 - shoreDist2 / fadeDist);
|
||||
|
||||
setHeight(ix, iz, height);
|
||||
if (args.minHeight === undefined || height < args.minHeight)
|
||||
setHeight(ix, iz, height);
|
||||
|
||||
if (args.waterFunc)
|
||||
args.waterFunc(ix, iz, height);
|
||||
args.waterFunc(ix, iz, height, riverFraction);
|
||||
}
|
||||
else if (args.landFunc)
|
||||
args.landFunc(ix, iz, shoreDist1, shoreDist2);
|
||||
|
@ -168,21 +168,22 @@ const riverTextures = [
|
||||
];
|
||||
|
||||
const plantFrequency = 2;
|
||||
|
||||
var plantID = 0;
|
||||
|
||||
paintRiver({
|
||||
"horizontal": false,
|
||||
"parallel": true,
|
||||
"position": 0.5,
|
||||
"startX": 0.5,
|
||||
"startZ": 0,
|
||||
"endX": 0.5,
|
||||
"endZ": 1,
|
||||
"width": 0.1,
|
||||
"fadeDist": 0.025,
|
||||
"deviation": 0.005,
|
||||
"deviation": 0.0025,
|
||||
"waterHeight": -3,
|
||||
"landHeight": 2,
|
||||
"meanderShort": 12,
|
||||
"meanderLong": 50,
|
||||
"waterFunc": (ix, iz, height) => {
|
||||
"waterFunc": (ix, iz, height, riverFraction) => {
|
||||
|
||||
addToClass(ix, iz, clWater);
|
||||
placeTerrain(ix, iz, tShore);
|
||||
|
@ -289,13 +289,15 @@ function unknownContinent()
|
||||
function unknownCentralSea()
|
||||
{
|
||||
let waterHeight = -3;
|
||||
|
||||
let horizontal = randBool();
|
||||
|
||||
let [start, end] = centralRiverCoordinates(horizontal);
|
||||
paintRiver({
|
||||
"horizontal": horizontal,
|
||||
"parallel": false,
|
||||
"position": 0.5,
|
||||
"startX": tilesToFraction(start[0]),
|
||||
"startZ": tilesToFraction(start[1]),
|
||||
"endX": tilesToFraction(end[0]),
|
||||
"endZ": tilesToFraction(end[1]),
|
||||
"width": randFloat(0.22, 0.3) + scaleByMapSize(0.05, 0.2),
|
||||
"fadeDist": 0.025,
|
||||
"deviation": 0,
|
||||
@ -303,7 +305,7 @@ function unknownCentralSea()
|
||||
"landHeight": landHeight,
|
||||
"meanderShort": 20,
|
||||
"meanderLong": 0,
|
||||
"waterFunc": (ix, iz, height) => {
|
||||
"waterFunc": (ix, iz, height, riverFraction) => {
|
||||
if (height < 0)
|
||||
addToClass(ix, iz, clWater);
|
||||
},
|
||||
@ -531,10 +533,20 @@ function unknownEdgeSeas()
|
||||
}
|
||||
|
||||
for (let location of pickRandom([["first"], ["second"], ["first", "second"]]))
|
||||
{
|
||||
let margin = randFloat(0, scaleByMapSize(0, 0.1));
|
||||
let positionX = location == "first" ? [0, margin] : [1 - margin, 1];
|
||||
let positionZ = [0, 1];
|
||||
|
||||
if (!horizontal)
|
||||
[positionX, positionZ] = [positionZ, positionX];
|
||||
|
||||
paintRiver({
|
||||
"horizontal": horizontal,
|
||||
"parallel": false,
|
||||
"position": (location == "first" ? 0 : 1) + (location == "first" ? -1 : 1) * randFloat(0, scaleByMapSize(0, 0.1)),
|
||||
"startX": positionX[0],
|
||||
"startZ": positionZ[0],
|
||||
"endX": positionX[1],
|
||||
"endX": positionZ[1],
|
||||
"width": 0.62,
|
||||
"fadeDist": 0.015,
|
||||
"deviation": 0,
|
||||
@ -543,6 +555,7 @@ function unknownEdgeSeas()
|
||||
"meanderShort": 20,
|
||||
"meanderLong": 0
|
||||
});
|
||||
}
|
||||
|
||||
createExtensionsOrIslands();
|
||||
paintTileClassBasedOnHeight(0, cliffHeight, 1, clLand);
|
||||
|
Loading…
Reference in New Issue
Block a user