diff --git a/binaries/data/mods/public/maps/random/english_channel.js b/binaries/data/mods/public/maps/random/english_channel.js index f711128803..cddaa5e387 100644 --- a/binaries/data/mods/public/maps/random/english_channel.js +++ b/binaries/data/mods/public/maps/random/english_channel.js @@ -218,7 +218,7 @@ for (let i = 0; i <= randIntInclusive(8, scaleByMapSize(12, 20)); ++i) log("Creating shallows in tributaries..."); for (let z of [0.25, 0.75]) - passageMaker( + createShallowsPassage( Math.round(fractionToTiles(0.2)), Math.round(fractionToTiles(z)), Math.round(fractionToTiles(0.8)), diff --git a/binaries/data/mods/public/maps/random/lorraine_plain.js b/binaries/data/mods/public/maps/random/lorraine_plain.js index 167b7360e1..fa2fd10723 100644 --- a/binaries/data/mods/public/maps/random/lorraine_plain.js +++ b/binaries/data/mods/public/maps/random/lorraine_plain.js @@ -162,7 +162,7 @@ log("Creating the shallows of the main river..."); for (let i = 0; i <= randIntInclusive(3, scaleByMapSize(4, 6)); ++i) { let cLocation = Math.floor(fractionToTiles(randFloat(0.15, 0.85))); - passageMaker( + createShallowsPassage( cLocation, Math.floor(fractionToTiles(0.35)), cLocation, @@ -230,7 +230,7 @@ for (let i = 0; i <= randIntInclusive(8, scaleByMapSize(12, 20)); ++i) log("Creating shallows to make tributaries passable..."); for (let coord of [0.25, 0.75]) - passageMaker( + createShallowsPassage( Math.floor(fractionToTiles(0.2)), Math.floor(fractionToTiles(coord)), Math.floor(fractionToTiles(0.8)), diff --git a/binaries/data/mods/public/maps/random/rmgen/gaia_terrain.js b/binaries/data/mods/public/maps/random/rmgen/gaia_terrain.js index c87898efbc..6351107aff 100644 --- a/binaries/data/mods/public/maps/random/rmgen/gaia_terrain.js +++ b/binaries/data/mods/public/maps/random/rmgen/gaia_terrain.js @@ -62,6 +62,226 @@ function createMountains(terrain, constraint, tileClass, count, maxHeight, minRa 14); } +/** + * Create a mountain using a technique very similar to ChainPlacer. + */ +function createMountain(maxHeight, minRadius, maxRadius, numCircles, constraint, x, z, terrain, tileClass, fcc = 0, q = []) +{ + if (constraint instanceof Array) + constraint = new AndConstraint(constraint); + + if (!g_Map.inMapBounds(x, z) || !constraint.allows(x, z)) + return; + + let mapSize = getMapSize(); + let queueEmpty = !q.length; + + let gotRet = []; + for (let i = 0; i < mapSize; ++i) + { + gotRet[i] = []; + for (let j = 0; j < mapSize; ++j) + gotRet[i][j] = -1; + } + + --mapSize; + + minRadius = Math.max(1, Math.min(minRadius, maxRadius)); + + let edges = [[x, z]]; + let circles = []; + + for (let i = 0; i < numCircles; ++i) + { + let badPoint = false; + let [cx, cz] = pickRandom(edges); + + let radius; + if (queueEmpty) + radius = randIntInclusive(minRadius, maxRadius); + else + { + radius = q.pop(); + queueEmpty = !q.length; + } + + let sx = Math.max(0, cx - radius); + let sz = Math.max(0, cz - radius); + let lx = Math.min(cx + radius, mapSize); + let lz = Math.min(cz + radius, mapSize); + + let radius2 = Math.square(radius); + + for (let ix = sx; ix <= lx; ++ix) + { + for (let iz = sz; iz <= lz; ++iz) + { + if (Math.euclidDistance2D(ix, iz, cx, cz) > radius2 || !g_Map.inMapBounds(ix, iz)) + continue; + + if (!constraint.allows(ix, iz)) + { + badPoint = true; + break; + } + + let state = gotRet[ix][iz]; + if (state == -1) + { + gotRet[ix][iz] = -2; + } + else if (state >= 0) + { + let s = edges.splice(state, 1); + gotRet[ix][iz] = -2; + + let edgesLength = edges.length; + for (let k = state; k < edges.length; ++k) + --gotRet[edges[k][0]][edges[k][1]]; + } + } + + if (badPoint) + break; + } + + if (badPoint) + continue; + + circles.push([cx, cz, radius]); + + for (let ix = sx; ix <= lx; ++ix) + for (let iz = sz; iz <= lz; ++iz) + { + if (gotRet[ix][iz] != -2 || + fcc && (x - ix > fcc || ix - x > fcc || z - iz > fcc || iz - z > fcc) || + ix > 0 && gotRet[ix-1][iz] == -1 || + iz > 0 && gotRet[ix][iz-1] == -1 || + ix < mapSize && gotRet[ix+1][iz] == -1 || + iz < mapSize && gotRet[ix][iz+1] == -1) + continue; + + edges.push([ix, iz]); + gotRet[ix][iz] = edges.length - 1; + } + } + + for (let [cx, cz, radius] of circles) + { + let sx = Math.max(0, cx - radius); + let sz = Math.max(0, cz - radius); + let lx = Math.min(cx + radius, mapSize); + let lz = Math.min(cz + radius, mapSize); + + let clumpHeight = radius / maxRadius * maxHeight * randFloat(0.8, 1.2); + + for (let ix = sx; ix <= lx; ++ix) + for (let iz = sz; iz <= lz; ++iz) + { + let distance = Math.euclidDistance2D(ix, iz, cx, cz); + + let newHeight = + randIntInclusive(0, 2) + + Math.round(2/3 * clumpHeight * (Math.sin(Math.PI * 2/3 * (3/4 - distance / radius)) + 0.5)); + + if (distance > radius) + continue; + + if (getHeight(ix, iz) < newHeight) + setHeight(ix, iz, newHeight); + else if (getHeight(ix, iz) >= newHeight && getHeight(ix, iz) < newHeight + 4) + setHeight(ix, iz, newHeight + 4); + + if (terrain !== undefined) + placeTerrain(ix, iz, terrain); + + if (tileClass !== undefined) + addToClass(ix, iz, tileClass); + } + } +} + +/** + * Generates a volcano mountain. Smoke and lava are optional. + * + * @param {number} fx - Horizontal coordinate of the center. + * @param {number} fz - Horizontal coordinate of the center. + * @param {number} tileClass - Painted onto every tile that is occupied by the volcano. + * @param {string} terrainTexture - The texture painted onto the volcano hill. + * @param {array} lavaTextures - Three different textures for the interior, from the outside to the inside. + * @param {boolean} smoke - Whether to place smoke particles. + * @param {number} elevationType - Elevation painter type, ELEVATION_SET = absolute or ELEVATION_MODIFY = relative. + */ +function createVolcano(fx, fz, tileClass, terrainTexture, lavaTextures, smoke, elevationType) +{ + log("Creating volcano"); + + let ix = Math.round(fractionToTiles(fx)); + let iz = Math.round(fractionToTiles(fz)); + + let baseSize = getMapArea() / scaleByMapSize(1, 8); + let coherence = 0.7; + let smoothness = 0.05; + let failFraction = 100; + let steepness = 3; + + let clLava = createTileClass(); + + let layers = [ + { + "clumps": 0.067, + "elevation": 15, + "tileClass": tileClass + }, + { + "clumps": 0.05, + "elevation": 25, + "tileClass": createTileClass() + }, + { + "clumps": 0.02, + "elevation": 45, + "tileClass": createTileClass() + }, + { + "clumps": 0.011, + "elevation": 62, + "tileClass": createTileClass() + }, + { + "clumps": 0.003, + "elevation": 42, + "tileClass": clLava, + "painter": lavaTextures && new LayeredPainter([terrainTexture, ...lavaTextures], [1, 1, 1]), + "steepness": 1 + } + ]; + + for (let i = 0; i < layers.length; ++i) + createArea( + new ClumpPlacer(baseSize * layers[i].clumps, coherence, smoothness, failFraction, ix, iz), + [ + layers[i].painter || new LayeredPainter([terrainTexture, terrainTexture], [3]), + new SmoothElevationPainter(elevationType, layers[i].elevation, layers[i].steepness || steepness), + paintClass(layers[i].tileClass) + ], + i == 0 ? null : stayClasses(layers[i - 1].tileClass, 1)); + + if (smoke) + { + let num = Math.floor(baseSize * 0.002); + createObjectGroup( + new SimpleGroup( + [new SimpleObject("actor|particle/smoke.xml", num, num, 0, 7)], + false, + clLava, + ix, + iz), + 0, + stayClasses(tileClass, 1)); + } +} + /** * Paint the given terrain texture in the given sizes at random places of the map to diversify monotone land texturing. */ @@ -93,3 +313,271 @@ function createLayeredPatches(sizes, terrains, terrainWidths, constraint, count, constraint, count); } + +/** + * Creates a meandering river at the given location and width. + * Optionally calls a function on the affected tiles. + * + * @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 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. + */ +function paintRiver(args) +{ + log("Creating the river"); + + let theta1 = randFloat(0, 1); + let theta2 = randFloat(0, 1); + + 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 mapSize = getMapSize(); + + for (let ix = 0; ix < mapSize; ++ix) + for (let iz = 0; iz < mapSize; ++iz) + { + if (args.constraint && !args.constraint.allows(ix, iz)) + continue; + + let x = ix / (mapSize + 1); + let z = iz / (mapSize + 1); + + let coord1 = args.horizontal ? z : x; + let coord2 = args.horizontal ? x : z; + + // River curve at this place + let curve1 = + meanderShort * rndRiver(theta1 + coord2 * mapSize / 128, seed1) + + meanderLong * rndRiver(theta2 + coord2 * mapSize / 256, seed2); + + let curve2 = args.parallel ? curve1 : + meanderShort * rndRiver(theta2 + coord2 * mapSize / 128, seed2) + + meanderLong * rndRiver(theta2 + coord2 * mapSize / 256, seed2); + + // Fuzz the river border + let devCoord1 = coord1 * randFloat(1 - args.deviation, 1 + args.deviation); + let devCoord2 = coord2 * randFloat(1 - args.deviation, 1 + args.deviation); + + let shoreDist1 = -devCoord1 + curve1 + args.position - args.width / 2; + let shoreDist2 = -devCoord1 + curve2 + args.position + args.width / 2; + + 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); + + setHeight(ix, iz, height); + + if (args.waterFunc) + args.waterFunc(ix, iz, height); + } + else if (args.landFunc) + args.landFunc(ix, iz, shoreDist1, shoreDist2); + } +} + +/** + * Helper function to create a meandering river. + * It works the same as sin or cos function with the difference that it's period is 1 instead of 2 pi. + */ +function rndRiver(f, seed) +{ + let rndRw = seed; + + for (let i = 0; i <= f; ++i) + rndRw = 10 * (rndRw % 1); + + let rndRr = f % 1; + let retVal = (i % 2 ? 1 : -1) * rndRr * (rndRr - 1); + + let rndRe = Math.floor(rndRw) % 5; + if (rndRe == 0) + retVal *= 2.3 * (rndRr - 0.5) * (rndRr - 0.5); + else if (rndRe == 1) + retVal *= 2.6 * (rndRr - 0.3) * (rndRr - 0.7); + else if (rndRe == 2) + retVal *= 22 * (rndRr - 0.2) * (rndRr - 0.3) * (rndRr - 0.3) * (rndRr - 0.8); + else if (rndRe == 3) + retVal *= 180 * (rndRr - 0.2) * (rndRr - 0.2) * (rndRr - 0.4) * (rndRr - 0.6) * (rndRr - 0.6) * (rndRr - 0.8); + else if (rndRe == 4) + retVal *= 2.6 * (rndRr - 0.5) * (rndRr - 0.7); + + return retVal; +} + +/** + * Create shallow water between (x1, z1) and (x2, z2) of tiles below maxHeight. + */ +function createShallowsPassage(x1, z1, x2, z2, width, maxHeight, shallowHeight, smooth, tileClass, terrain, riverHeight) +{ + let a = z1 - z2; + let b = x2 - x1; + + let distance = Math.euclidDistance2D(x1, z1, x2, z2); + let mapSize = getMapSize(); + + for (let ix = 0; ix < mapSize; ++ix) + for (let iz = 0; iz < mapSize; ++iz) + { + let c = a * (ix - x1) + b * (iz - z1); + let my = iz - b * c / Math.square(distance); + let inline = 0; + + let dis; + if (b == 0) + { + dis = Math.abs(ix - x1); + if (iz >= Math.min(z1, z2) && iz <= Math.max(z1, z2)) + inline = 1; + } + else if (my >= Math.min(z1, z2) && my <= Math.max(z1, z2)) + { + dis = Math.abs(c) / distance; + inline = 1; + } + + if (dis > width || !inline || getHeight(ix, iz) > maxHeight) + continue; + + if (dis > width - smooth) + setHeight(ix, iz, ((width - dis) * shallowHeight + riverHeight * (smooth - width + dis)) / smooth); + else if (dis <= width - smooth) + setHeight(ix, iz, shallowHeight); + + if (tileClass !== undefined) + addToClass(ix, iz, tileClass); + + if (terrain !== undefined) + placeTerrain(ix, iz, terrain); + } +} + +/** + * Creates a ramp from (x1, y1) to (x2, y2). + */ +function createRamp(x1, y1, x2, y2, minHeight, maxHeight, width, smoothLevel, mainTerrain, edgeTerrain, tileClass) +{ + let halfWidth = width / 2; + + let x3; + let y3; + + if (y1 == y2) + { + x3 = x2; + y3 = y2 + halfWidth; + } + else + { + x3 = x2 + halfWidth; + y3 = (x1 - x2) / (y1 - y2) * (x2 - x3) + y2; + } + + let minBoundX = Math.max(Math.min(x1, x2) - halfWidth, 0); + let minBoundY = Math.max(Math.min(y1, y2) - halfWidth, 0); + let maxBoundX = Math.min(Math.max(x1, x2) + halfWidth, getMapSize()); + let maxBoundY = Math.min(Math.max(y1, y2) + halfWidth, getMapSize()); + + for (let x = minBoundX; x < maxBoundX; ++x) + for (let y = minBoundY; y < maxBoundY; ++y) + { + let lDist = distanceOfPointFromLine(x3, y3, x2, y2, x, y); + let sDist = distanceOfPointFromLine(x1, y1, x2, y2, x, y); + let rampLength = Math.euclidDistance2D(x1, y1, x2, y2); + + if (lDist > rampLength || sDist > halfWidth) + continue; + + let height = ((rampLength - lDist) * maxHeight + lDist * minHeight) / rampLength; + + if (sDist >= halfWidth - smoothLevel) + { + height = (height - minHeight) * (halfWidth - sDist) / smoothLevel + minHeight; + + if (edgeTerrain) + placeTerrain(x, y, edgeTerrain); + } + else if (mainTerrain) + placeTerrain(x, y, mainTerrain); + + if (tileClass !== undefined) + addToClass(x, y, tileClass); + + if (getHeight(Math.floor(x), Math.floor(y)) < height && height <= maxHeight) + setHeight(x, y, height); + } +} + +/** + * Get The Intended Point In A Direction Based On Height. + * Retrieves the N'th point with a specific height in a line and returns it as a [x, y] array. + * + * @param startPoint - [x, y] array defining the start point + * @param endPoint - [x, y] array defining the ending point + * @param heightRange - [min, max] array defining the range which the height of the intended point can be. includes both "min" and "max" + * @param step - how much tile units per turn should the search go. more value means faster but less accurate + * @param n - how many points to skip before ending the search. skips """n-1 points""". + */ +function getTIPIADBON(startPoint, endPoint, heightRange, step, n) +{ + let X = endPoint[0] - startPoint[0]; + let Y = endPoint[1] - startPoint[1]; + + if (!X && !Y) + { + error("getTIPIADBON startPoint and endPoint are identical! " + new Error().stack); + return undefined; + } + + let M = Math.sqrt(Math.square(X) + step * Math.square(Y)); + let stepX = step * X / M; + let stepY = step * Y / M; + + let y = startPoint[1]; + let checked = 0; + + let mapSize = getMapSize(); + + for (let x = startPoint[0]; true; x += stepX) + { + let ix = Math.floor(x); + let iy = Math.floor(y); + + if (ix < mapSize || iy < mapSize) + { + if (getHeight(ix, iy) <= heightRange[1] && + getHeight(ix, iy) >= heightRange[0]) + ++checked; + + if (checked >= n) + return [x, y]; + } + + y += stepY; + + if (y > endPoint[1] && stepY > 0 || + y < endPoint[1] && stepY < 0 || + x > endPoint[1] && stepX > 0 || + x < endPoint[1] && stepX < 0) + return undefined; + } + + return undefined; +} diff --git a/binaries/data/mods/public/maps/random/rmgen/misc.js b/binaries/data/mods/public/maps/random/rmgen/misc.js index 9ffdbbe031..d2eac12eca 100644 --- a/binaries/data/mods/public/maps/random/rmgen/misc.js +++ b/binaries/data/mods/public/maps/random/rmgen/misc.js @@ -1,212 +1,3 @@ -///////////////////////////////////////////////////////////////////////////////////////// -// passageMaker -// -// Function for creating shallow water between two given points by changing the height of all tiles in -// the path with height less than or equal to "maxheight" to "height" -// -// x1,z1: Starting point of path -// x2,z2: Ending point of path -// width: Width of the shallow -// maxheight: Maximum height that it changes -// height: Height of the shallow -// smooth: smooth elevation in borders -// tileclass: (Optianal) - Adds those tiles to the class given -// terrain: (Optional) - Changes the texture of the elevated land -// -///////////////////////////////////////////////////////////////////////////////////////// - -function passageMaker(x1, z1, x2, z2, width, maxheight, height, smooth, tileclass, terrain, riverheight) -{ - var tchm = TILE_CENTERED_HEIGHT_MAP; - TILE_CENTERED_HEIGHT_MAP = true; - var mapSize = g_Map.size; - for (var ix = 0; ix < mapSize; ix++) - { - for (var iz = 0; iz < mapSize; iz++) - { - var a = z1-z2; - var b = x2-x1; - var c = (z1*(x1-x2))-(x1*(z1-z2)); - var dis = abs(a*ix + b*iz + c)/sqrt(a*a + b*b); - var k = (a*ix + b*iz + c)/(a*a + b*b); - var my = iz-(b*k); - var inline = 0; - if (b == 0) - { - dis = abs(ix-x1); - if ((iz <= Math.max(z1,z2))&&(iz >= Math.min(z1,z2))) - { - inline = 1; - } - } - else - { - if ((my <= Math.max(z1,z2))&&(my >= Math.min(z1,z2))) - { - inline = 1; - } - } - if ((dis <= width)&&(inline)) - { - if(g_Map.getHeight(ix, iz) <= maxheight) - { - if (dis > width - smooth) - { - g_Map.setHeight(ix, iz, ((width - dis)*(height)+(riverheight)*(smooth - width + dis))/(smooth)); - } - else if (dis <= width - smooth) - { - g_Map.setHeight(ix, iz, height); - } - if (tileclass !== undefined) - { - addToClass(ix, iz, tileclass); - } - if (terrain !== undefined) - { - placeTerrain(ix, iz, terrain); - } - } - } - } - } - TILE_CENTERED_HEIGHT_MAP = tchm; -} - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//rndRiver is a fuction that creates random values useful for making a jagged river. -// -//it works the same as sin or cos function. the only difference is that it's period is 1 instead of 2*pi -//it needs the "seed" parameter to use it to make random curves that don't get broken. -//seed must be created using randFloat(). or else it won't work -// -// f: Input: Same as angle in a sine function -// seed: Random Seed: Best to implement is to use randFloat() -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -function rndRiver(f, seed) -{ - var rndRq = seed; - var rndRw = rndRq; - var rndRe = 0; - var rndRr = f-floor(f); - var rndRa = 0; - for (var rndRx=0; rndRx<=floor(f); rndRx++) - { - rndRw = 10*(rndRw-floor(rndRw)); - } - if (rndRx%2==0) - { - var rndRs = -1; - } - else - { - var rndRs = 1; - } - rndRe = (floor(rndRw))%5; - if (rndRe==0) - { - rndRa = (rndRs)*2.3*(rndRr)*(rndRr-1)*(rndRr-0.5)*(rndRr-0.5); - } - else if (rndRe==1) - { - rndRa = (rndRs)*2.6*(rndRr)*(rndRr-1)*(rndRr-0.3)*(rndRr-0.7); - } - else if (rndRe==2) - { - rndRa = (rndRs)*22*(rndRr)*(rndRr-1)*(rndRr-0.2)*(rndRr-0.3)*(rndRr-0.3)*(rndRr-0.8); - } - else if (rndRe==3) - { - rndRa = (rndRs)*180*(rndRr)*(rndRr-1)*(rndRr-0.2)*(rndRr-0.2)*(rndRr-0.4)*(rndRr-0.6)*(rndRr-0.6)*(rndRr-0.8); - } - else if (rndRe==4) - { - rndRa = (rndRs)*2.6*(rndRr)*(rndRr-1)*(rndRr-0.5)*(rndRr-0.7); - } - return rndRa; -} - -/** - * Creates a meandering river at the given location and width. - * Optionally calls a function on the affected tiles. - * - * @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 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. - */ -function paintRiver(args) -{ - log("Creating the river"); - - let theta1 = randFloat(0, 1); - let theta2 = randFloat(0, 1); - - 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 mapSize = g_Map.size; - - for (let ix = 0; ix < mapSize; ++ix) - for (let iz = 0; iz < mapSize; ++iz) - { - if (args.constraint && !args.constraint.allows(ix, iz)) - continue; - - let x = ix / (mapSize + 1.0); - let z = iz / (mapSize + 1.0); - - let coord1 = args.horizontal ? z : x; - let coord2 = args.horizontal ? x : z; - - // River curve at this place - let cu1 = meanderShort * rndRiver(theta1 + coord2 * mapSize / 128, seed1); - let cu2 = meanderShort * rndRiver(theta2 + coord2 * mapSize / 128, seed2); - - cu1 += meanderLong * rndRiver(theta2 + coord2 * mapSize / 256, seed2); - cu2 += meanderLong * rndRiver(theta2 + coord2 * mapSize / 256, seed2); - if (args.parallel) - cu2 = cu1; - - // Fuzz the river border - let devCoord1 = coord1 * randFloat(1 - args.deviation, 1 + args.deviation); - let devCoord2 = coord2 * randFloat(1 - args.deviation, 1 + args.deviation); - - let shoreDist1 = -devCoord1 + cu1 + args.position - args.width / 2; - let shoreDist2 = -devCoord1 + cu2 + args.position + args.width / 2; - - 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); - - setHeight(ix, iz, height); - - if (args.waterFunc) - args.waterFunc(ix, iz, height); - } - else if (args.landFunc) - args.landFunc(ix, iz, shoreDist1, shoreDist2); - } -} - ///////////////////////////////////////////////////////////////////////////////////////// // createStartingPlayerEntities // @@ -362,412 +153,3 @@ function unPaintTileClassBasedOnHeight(minHeight, maxHeight, mode, tileclass) removeFromClass(qx, qz, tileclass); }); } - -///////////////////////////////////////////////////////////////////////////////////////// -// getTIPIADBON -// -// "get The Intended Point In A Direction Based On Height" -// gets the N'th point with a specific height in a line and returns it as a [x, y] array -// startPoint: [x, y] array defining the start point -// endPoint: [x, y] array defining the ending point -// heightRange: [min, max] array defining the range which the height of the intended point can be. includes both "min" and "max" -// step: how much tile units per turn should the search go. more value means faster but less accurate -// n: how many points to skip before ending the search. skips """n-1 points""". -// -/////////////////////////////////////////////////////////////////////////////////////////// - -function getTIPIADBON(startPoint, endPoint, heightRange, step, n) -{ - var stepX = step*(endPoint[0]-startPoint[0])/(sqrt((endPoint[0]-startPoint[0])*(endPoint[0]-startPoint[0]) + step*(endPoint[1]-startPoint[1])*(endPoint[1]-startPoint[1]))); - var stepY = step*(endPoint[1]-startPoint[1])/(sqrt((endPoint[0]-startPoint[0])*(endPoint[0]-startPoint[0]) + step*(endPoint[1]-startPoint[1])*(endPoint[1]-startPoint[1]))); - var y = startPoint[1]; - var checked = 0; - for (var x = startPoint[0]; true; x += stepX) - { - if ((floor(x) < g_Map.size)||(floor(y) < g_Map.size)) - { - if ((g_Map.getHeight(floor(x), floor(y)) <= heightRange[1])&&(g_Map.getHeight(floor(x), floor(y)) >= heightRange[0])) - { - ++checked; - } - if (checked >= n) - { - return [x, y]; - } - } - y += stepY; - if ((y > endPoint[1])&&(stepY>0)) - break; - if ((y < endPoint[1])&&(stepY<0)) - break; - if ((x > endPoint[1])&&(stepX>0)) - break; - if ((x < endPoint[1])&&(stepX<0)) - break; - } - return undefined; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// createRamp -// -// creates a ramp from point (x1, y1) to (x2, y2). -// x1, y1, x2, y2: determine the position of the start and end of the ramp -// minHeight, maxHeight: determine the height levels of the start and end point -// width: determines the width of the ramp -// smoothLevel: determines the smooth level around the edges of the ramp -// mainTerrain: (Optional) determines the terrain texture for the ramp -// edgeTerrain: (Optional) determines the terrain texture for the edges -// tileclass: (Optional) adds the ramp to this tile class -// -/////////////////////////////////////////////////////////////////////////////////////////// - -function createRamp (x1, y1, x2, y2, minHeight, maxHeight, width, smoothLevel, mainTerrain, edgeTerrain, tileclass) -{ - var halfWidth = width / 2; - var mapSize = g_Map.size; - - if (y1 == y2) - { - var x3 = x2; - var y3 = y2 + halfWidth; - } - else - { - var m = (x1 - x2) / (y1 - y2); - var b = y2 + m * x2; - var x3 = x2 + halfWidth; - var y3 = - m * x3 + b; - } - - var minBoundX = (x1 <= x2 ? (x1 > halfWidth ? x1 - halfWidth : 0) : (x2 > halfWidth ? x2 - halfWidth : 0)); - var maxBoundX = (x1 >= x2 ? (x1 < mapSize - halfWidth ? x1 + halfWidth : mapSize) : (x2 < mapSize - halfWidth ? x2 + halfWidth : mapSize)); - var minBoundY = (y1 <= y2 ? (y1 > halfWidth ? y1 - halfWidth : 0) : (y2 > halfWidth ? y2 - halfWidth : 0)); - var maxBoundY = (y1 >= y2 ? (x1 < mapSize - halfWidth ? y1 + halfWidth : mapSize) : (y2 < mapSize - halfWidth ? y2 + halfWidth : mapSize)); - - for (var x = minBoundX; x < maxBoundX; ++x) - { - for (var y = minBoundY; y < maxBoundY; ++y) - { - var lDist = distanceOfPointFromLine(x3, y3, x2, y2, x, y); - var sDist = distanceOfPointFromLine(x1, y1, x2, y2, x, y); - var rampLength = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); - if (lDist <= rampLength && sDist <= halfWidth) - { - var h = ((rampLength - lDist) * maxHeight + lDist * minHeight) / rampLength; - if (sDist >= halfWidth - smoothLevel) - { - h = (h - minHeight) * (halfWidth - sDist) / smoothLevel + minHeight; - if (edgeTerrain !== undefined) - placeTerrain(x, y, edgeTerrain); - } - else - { - if (mainTerrain !== undefined) - placeTerrain(x, y, mainTerrain); - } - if (tileclass !== undefined) - addToClass(x, y, tileclass); - if((g_Map.getHeight(floor(x), floor(y)) < h) && (h <= maxHeight)) - g_Map.setHeight(x, y, h); - } - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// createMountain -// -// creates a mountain using a tecnique very similar to chain placer. -// -/////////////////////////////////////////////////////////////////////////////////////////// - -function createMountain(maxHeight, minRadius, maxRadius, numCircles, constraint, x, z, terrain, tileclass, fcc, q) -{ - fcc = (fcc !== undefined ? fcc : 0); - q = (q !== undefined ? q : []); - - // checking for an array of constraints - if (constraint instanceof Array) - { - var constraintArray = constraint; - constraint = new AndConstraint(constraintArray); - } - - // Preliminary bounds check - if (!g_Map.inMapBounds(x, z) || !constraint.allows(x, z)) - { - return; - } - - var size = getMapSize(); - var queueEmpty = (q.length ? false : true); - - var gotRet = []; - for (var i = 0; i < size; ++i) - { - gotRet[i] = []; - for (var j = 0; j < size; ++j) - gotRet[i][j] = -1; - } - - --size; - - if (minRadius < 1) minRadius = 1; - if (minRadius > maxRadius) minRadius = maxRadius; - - var edges = [[x, z]]; - var circles = []; - - for (var i = 0; i < numCircles; ++i) - { - var badPoint = false; - var [cx, cz] = pickRandom(edges); - - if (queueEmpty) - var radius = randIntInclusive(minRadius, maxRadius); - else - { - var radius = q.pop(); - queueEmpty = (q.length ? false : true); - } - - var sx = cx - radius, lx = cx + radius; - var sz = cz - radius, lz = cz + radius; - - sx = (sx < 0 ? 0 : sx); - sz = (sz < 0 ? 0 : sz); - lx = (lx > size ? size : lx); - lz = (lz > size ? size : lz); - - var radius2 = radius * radius; - var dx, dz, distance2; - - //log (uneval([sx, sz, lx, lz])); - - for (var ix = sx; ix <= lx; ++ix) - { - for (var iz = sz; iz <= lz; ++ iz) - { - dx = ix - cx; - dz = iz - cz; - distance2 = dx * dx + dz * dz; - if (dx * dx + dz * dz <= radius2) - { - if (g_Map.inMapBounds(ix, iz)) - { - if (!constraint.allows(ix, iz)) - { - badPoint = true; - break; - } - - var state = gotRet[ix][iz]; - - if (state == -1) - { - gotRet[ix][iz] = -2; - } - else if (state >= 0) - { - - var s = edges.splice(state, 1); - - gotRet[ix][iz] = -2; - - var edgesLength = edges.length; - for (var k = state; k < edges.length; ++k) - { - --gotRet[edges[k][0]][edges[k][1]]; - } - } - } - } - } - if (badPoint) - break; - } - - if (badPoint) - continue; - else - circles.push([cx, cz, radius]); - - for (var ix = sx; ix <= lx; ++ix) - { - for (var iz = sz; iz <= lz; ++ iz) - { - if (fcc) - if ((x - ix) > fcc || (ix - x) > fcc || (z - iz) > fcc || (iz - z) > fcc) - continue; - - if (gotRet[ix][iz] == -2) - { - if (ix > 0) - { - if (gotRet[ix-1][iz] == -1) - { - edges.push([ix, iz]); - gotRet[ix][iz] = edges.length - 1; - continue; - } - } - if (iz > 0) - { - if (gotRet[ix][iz-1] == -1) - { - edges.push([ix, iz]); - gotRet[ix][iz] = edges.length - 1; - continue; - } - } - if (ix < size) - { - if (gotRet[ix+1][iz] == -1) - { - edges.push([ix, iz]); - gotRet[ix][iz] = edges.length - 1; - continue; - } - } - if (iz < size) - { - if (gotRet[ix][iz+1] == -1) - { - edges.push([ix, iz]); - gotRet[ix][iz] = edges.length - 1; - continue; - } - } - } - } - } - } - - var numFinalCircles = circles.length; - - for (var i = 0; i < numFinalCircles; ++i) - { - var point = circles[i]; - var cx = point[0], cz = point[1], radius = point[2]; - - var sx = cx - radius, lx = cx + radius; - var sz = cz - radius, lz = cz + radius; - - sx = (sx < 0 ? 0 : sx); - sz = (sz < 0 ? 0 : sz); - lx = (lx > size ? size : lx); - lz = (lz > size ? size : lz); - - var radius2 = radius * radius; - var dx, dz, distance2; - - var clumpHeight = radius / maxRadius * maxHeight * randFloat(0.8, 1.2); - - for (var ix = sx; ix <= lx; ++ix) - { - for (var iz = sz; iz <= lz; ++ iz) - { - dx = ix - cx; - dz = iz - cz; - distance2 = dx * dx + dz * dz; - - var newHeight = Math.round((Math.sin(PI * (2 * ((radius - Math.sqrt(distance2)) / radius) / 3 - 1/6)) + 0.5) * 2/3 * clumpHeight) + randIntInclusive(0, 2); - - if (dx * dx + dz * dz <= radius2) - { - if (g_Map.getHeight(ix, iz) < newHeight) - g_Map.setHeight(ix, iz, newHeight); - else if (g_Map.getHeight(ix, iz) >= newHeight && g_Map.getHeight(ix, iz) < newHeight + 4) - g_Map.setHeight(ix, iz, newHeight + 4); - if (terrain !== undefined) - placeTerrain(ix, iz, terrain); - if (tileclass !== undefined) - addToClass(ix, iz, tileclass); - } - } - } - } -} - -/** - * Generates a volcano mountain. Smoke and lava are optional. - * - * @param {number} fx - Horizontal coordinate of the center. - * @param {number} fz - Horizontal coordinate of the center. - * @param {number} tileClass - Painted onto every tile that is occupied by the volcano. - * @param {string} terrainTexture - The texture painted onto the volcano hill. - * @param {array} lavaTextures - Three different textures for the interior, from the outside to the inside. - * @param {boolean} smoke - Whether to place smoke particles. - * @param {number} elevationType - Elevation painter type, ELEVATION_SET = absolute or ELEVATION_MODIFY = relative. - */ -function createVolcano(fx, fz, tileClass, terrainTexture, lavaTextures, smoke, elevationType) -{ - log("Creating volcano"); - - let ix = Math.round(fractionToTiles(fx)); - let iz = Math.round(fractionToTiles(fz)); - - let baseSize = getMapArea() / scaleByMapSize(1, 8); - - let coherence = 0.7; - let smoothness = 0.05; - let failFraction = 100; - let steepness = 3; - - let clLava = createTileClass(); - - let layers = [ - { - "clumps": 0.067, - "elevation": 15, - "tileClass": tileClass - }, - { - "clumps": 0.05, - "elevation": 25, - "tileClass": createTileClass() - }, - { - "clumps": 0.02, - "elevation": 45, - "tileClass": createTileClass() - }, - { - "clumps": 0.011, - "elevation": 62, - "tileClass": createTileClass() - }, - { - "clumps": 0.003, - "elevation": 42, - "tileClass": clLava, - "painter": lavaTextures && new LayeredPainter([terrainTexture, ...lavaTextures], [1, 1, 1]), - "steepness": 1 - } - ]; - - for (let i = 0; i < layers.length; ++i) - createArea( - new ClumpPlacer(baseSize * layers[i].clumps, coherence, smoothness, failFraction, ix, iz), - [ - layers[i].painter || new LayeredPainter([terrainTexture, terrainTexture], [3]), - new SmoothElevationPainter(elevationType, layers[i].elevation, layers[i].steepness || steepness), - paintClass(layers[i].tileClass) - ], - i == 0 ? null : stayClasses(layers[i - 1].tileClass, 1)); - - if (smoke) - { - let num = Math.floor(baseSize * 0.002); - createObjectGroup( - new SimpleGroup( - [new SimpleObject("actor|particle/smoke.xml", num, num, 0, 7)], - false, - clLava, - ix, - iz), - 0, - stayClasses(tileClass, 1)); - } -} diff --git a/binaries/data/mods/public/maps/random/sahel_watering_holes.js b/binaries/data/mods/public/maps/random/sahel_watering_holes.js index 2e274ba500..3777caabcb 100644 --- a/binaries/data/mods/public/maps/random/sahel_watering_holes.js +++ b/binaries/data/mods/public/maps/random/sahel_watering_holes.js @@ -187,7 +187,7 @@ for (var i = 0; i < numPlayers; i++) { if (i+1 == numPlayers) { - passageMaker( + createShallowsPassage( round(fractionToTiles(playerX[i])), round(fractionToTiles(playerZ[i])), round(fractionToTiles(playerX[0])), @@ -209,7 +209,7 @@ for (var i = 0; i < numPlayers; i++) } else { - passageMaker( + createShallowsPassage( fractionToTiles(playerX[i]), fractionToTiles(playerZ[i]), fractionToTiles(playerX[i+1]), diff --git a/binaries/data/mods/public/maps/random/unknown.js b/binaries/data/mods/public/maps/random/unknown.js index bce6da7d5f..cc803a8bd7 100644 --- a/binaries/data/mods/public/maps/random/unknown.js +++ b/binaries/data/mods/public/maps/random/unknown.js @@ -458,9 +458,9 @@ else if (md == 4) //central river { var cLocation = randFloat(0.15,0.85); if (mdd1 == 1) - passageMaker(floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.35)), floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.65)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); + createShallowsPassage(floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.35)), floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.65)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); else - passageMaker(floor(fractionToTiles(0.35)), floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.65)), floor(fractionToTiles(cLocation)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); + createShallowsPassage(floor(fractionToTiles(0.35)), floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.65)), floor(fractionToTiles(cLocation)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); } } diff --git a/binaries/data/mods/public/maps/random/unknown_land.js b/binaries/data/mods/public/maps/random/unknown_land.js index 7cc4ef2417..e6ee3ee870 100644 --- a/binaries/data/mods/public/maps/random/unknown_land.js +++ b/binaries/data/mods/public/maps/random/unknown_land.js @@ -318,9 +318,9 @@ else if (md == 4) //central river { var cLocation = randFloat(0.15,0.85); if (mdd1 == 1) - passageMaker(floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.35)), floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.65)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); + createShallowsPassage(floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.35)), floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.65)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); else - passageMaker(floor(fractionToTiles(0.35)), floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.65)), floor(fractionToTiles(cLocation)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); + createShallowsPassage(floor(fractionToTiles(0.35)), floor(fractionToTiles(cLocation)), floor(fractionToTiles(0.65)), floor(fractionToTiles(cLocation)), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); } if (randBool()) diff --git a/binaries/data/mods/public/maps/random/unknown_nomad.js b/binaries/data/mods/public/maps/random/unknown_nomad.js index 19fd6db3d7..78e5965809 100644 --- a/binaries/data/mods/public/maps/random/unknown_nomad.js +++ b/binaries/data/mods/public/maps/random/unknown_nomad.js @@ -354,9 +354,9 @@ else if (md == 4) //central river { var cLocation = randFloat(0.15,0.85); if (mdd1 == 1) - passageMaker(fractionToTiles(cLocation), fractionToTiles(0.35), fractionToTiles(cLocation), fractionToTiles(0.65), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); + createShallowsPassage(fractionToTiles(cLocation), fractionToTiles(0.35), fractionToTiles(cLocation), fractionToTiles(0.65), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); else - passageMaker(fractionToTiles(0.35), fractionToTiles(cLocation), fractionToTiles(0.65), fractionToTiles(cLocation), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); + createShallowsPassage(fractionToTiles(0.35), fractionToTiles(cLocation), fractionToTiles(0.65), fractionToTiles(cLocation), scaleByMapSize(4,8), -2, -2, 2, clShallow, undefined, -4); } }