border tweak
This commit is contained in:
parent
4f0df3f6c5
commit
71b58cf033
7 changed files with 514 additions and 68 deletions
106
mapFeatures.js
106
mapFeatures.js
|
|
@ -132,23 +132,24 @@ export function generateMapFeatures(seed, terrain) {
|
|||
spine * 0.12
|
||||
);
|
||||
const clusterNoise = 0.72 + fbm(x * 0.34 + 13, y * 0.34 - 31, seed + 7001) * 0.46 + valueNoise(x, y, seed + 7002, 8) * 0.16;
|
||||
settlementCluster[i] = clamp((developable[i] * 0.52 + valleySettlement[i] * 0.28 + coastalSettlement[i] * 0.18 + agriculture[i] * 0.22) * clusterNoise);
|
||||
settlementCluster[i] = clamp((developable[i] * 0.50 + valleySettlement[i] * 0.26 + coastalSettlement[i] * 0.18 + agriculture[i] * 0.34 + plain[i] * 0.12) * clusterNoise);
|
||||
ruralSuitability[i] = clamp(
|
||||
agriculture[i] * 0.42 +
|
||||
developable[i] * 0.28 +
|
||||
agriculture[i] * 0.54 +
|
||||
developable[i] * 0.30 +
|
||||
valleySettlement[i] * 0.24 +
|
||||
coastalSettlement[i] * 0.15 +
|
||||
settlementCluster[i] * 0.24 -
|
||||
settlementCluster[i] * 0.30 -
|
||||
Math.max(0, elevation[i] - 0.64) * 0.56
|
||||
);
|
||||
townSuitability[i] = clamp(
|
||||
developable[i] * 0.40 +
|
||||
valleySettlement[i] * 0.26 +
|
||||
developable[i] * 0.38 +
|
||||
agriculture[i] * 0.18 +
|
||||
valleySettlement[i] * 0.24 +
|
||||
coastalSettlement[i] * 0.20 +
|
||||
confluence * 0.34 +
|
||||
basinField[i] * 0.16 +
|
||||
plain[i] * 0.12 +
|
||||
settlementCluster[i] * 0.16 -
|
||||
plain[i] * 0.18 +
|
||||
settlementCluster[i] * 0.22 -
|
||||
slope[i] * 0.34 -
|
||||
ridgeField[i] * 0.17 -
|
||||
spine * 0.10
|
||||
|
|
@ -303,21 +304,21 @@ export function generateMapFeatures(seed, terrain) {
|
|||
const villageScore = new Float32Array(SIZE);
|
||||
for (let i = 0; i < SIZE; i++) {
|
||||
if (sea[i]) continue;
|
||||
villageScore[i] = clamp(ruralSuitability[i] * 0.68 + valleySettlement[i] * 0.26 + coastalSettlement[i] * 0.18 + settlementCluster[i] * 0.08);
|
||||
villageScore[i] = clamp(ruralSuitability[i] * 0.60 + agriculture[i] * 0.30 + plain[i] * 0.15 + valleySettlement[i] * 0.24 + coastalSettlement[i] * 0.16 + settlementCluster[i] * 0.16);
|
||||
}
|
||||
const villages = pickRegionalPoints(villageScore, {
|
||||
stride: 2,
|
||||
threshold: 0.25 + rand(seed, 1031) * 0.04,
|
||||
totalMax: 140,
|
||||
minDistance: 5,
|
||||
threshold: 0.18 + rand(seed, 1031) * 0.030,
|
||||
totalMax: 280,
|
||||
minDistance: 4,
|
||||
seedOffset: 1030,
|
||||
kind: "Village",
|
||||
quotaForRegion: (regionId, st) => {
|
||||
if (!st || st.developableCells < 10) return 0;
|
||||
const vf = visibilityFactor(regionId, st);
|
||||
const raw = (st.developableCells / 65 + st.valleyCells / 44 + st.coastCells / 55 + 1.2) * vf;
|
||||
const min = st.area > 2600 ? 7 : st.area > 1400 ? 4 : st.area > 520 ? 2 : st.area > 220 ? 1 : 0;
|
||||
const max = st.area > 3600 ? 24 : st.area > 2200 ? 17 : st.area > 900 ? 9 : 4;
|
||||
const raw = (st.developableCells / 28 + st.plainCells / 42 + st.valleyCells / 34 + st.coastCells / 46 + 3.2) * vf;
|
||||
const min = st.area > 2600 ? 20 : st.area > 1400 ? 12 : st.area > 520 ? 5 : st.area > 220 ? 2 : 0;
|
||||
const max = st.area > 3600 ? 72 : st.area > 2200 ? 50 : st.area > 900 ? 25 : 10;
|
||||
return Math.round(clamp(raw + rand(seed, 1033 + regionId * 19) * 1.5, min, max));
|
||||
},
|
||||
}).map((p, n) => {
|
||||
|
|
@ -341,8 +342,10 @@ export function generateMapFeatures(seed, terrain) {
|
|||
);
|
||||
const valleyMouth = valleyField[i] > 0.22 && (plain[i] > 0.22 || basinField[i] > 0.18 || coastalLowland[i] > 0.18) ? 0.14 : 0;
|
||||
marketScore[i] = clamp(
|
||||
townSuitability[i] * 0.62 +
|
||||
villageInfluence[i] * 0.38 +
|
||||
townSuitability[i] * 0.58 +
|
||||
agriculture[i] * 0.16 +
|
||||
plain[i] * 0.14 +
|
||||
villageInfluence[i] * 0.40 +
|
||||
featurePull +
|
||||
valleyMouth +
|
||||
basinField[i] * 0.12 +
|
||||
|
|
@ -356,17 +359,17 @@ export function generateMapFeatures(seed, terrain) {
|
|||
|
||||
const markets = pickRegionalPoints(marketScore, {
|
||||
stride: 2,
|
||||
threshold: 0.31 + rand(seed, 1041) * 0.045,
|
||||
totalMax: 52,
|
||||
minDistance: 9,
|
||||
threshold: 0.245 + rand(seed, 1041) * 0.035,
|
||||
totalMax: 110,
|
||||
minDistance: 6,
|
||||
seedOffset: 1040,
|
||||
kind: "Market Town",
|
||||
quotaForRegion: (regionId, st) => {
|
||||
if (!st || st.townCells < 8) return 0;
|
||||
const vf = visibilityFactor(regionId, st);
|
||||
const raw = (st.developableCells / 260 + st.valleyCells / 150 + st.coastCells / 160 + 0.8) * vf;
|
||||
const min = st.area > 2600 ? 3 : st.area > 1200 ? 2 : st.area > 520 ? 1 : 0;
|
||||
const max = st.area > 3600 ? 9 : st.area > 2200 ? 7 : st.area > 800 ? 4 : 2;
|
||||
const raw = (st.developableCells / 105 + st.plainCells / 125 + st.valleyCells / 105 + st.coastCells / 130 + 2.1) * vf;
|
||||
const min = st.area > 2600 ? 9 : st.area > 1200 ? 5 : st.area > 520 ? 2 : 0;
|
||||
const max = st.area > 3600 ? 30 : st.area > 2200 ? 22 : st.area > 800 ? 10 : 5;
|
||||
return Math.round(clamp(raw + rand(seed, 1043 + regionId * 23) * 0.8, min, max));
|
||||
},
|
||||
extraScore: (x, y, i) => (distanceToNearest(commercialPorts, x, y) < 8 ? 0.07 : 0) + confluenceField[i] * 0.08,
|
||||
|
|
@ -779,8 +782,36 @@ export function generateMapFeatures(seed, terrain) {
|
|||
|
||||
const satelliteCities = [];
|
||||
const newTowns = [];
|
||||
const logisticsParks = [];
|
||||
const interchanges = [];
|
||||
const logisticsScore = new Float32Array(SIZE);
|
||||
for (let y = 2; y < MAP_H - 2; y++) {
|
||||
for (let x = 2; x < MAP_W - 2; x++) {
|
||||
const i = indexOf(x, y);
|
||||
if (sea[i]) continue;
|
||||
const flatAgriculturalCorridor = clamp(
|
||||
agriculture[i] * 0.34 +
|
||||
plain[i] * 0.24 +
|
||||
developable[i] * 0.20 +
|
||||
basinField[i] * 0.12 +
|
||||
coastalLowland[i] * 0.08 +
|
||||
roadInfluence[i] * 0.26 +
|
||||
railInfluence2[i] * 0.18 +
|
||||
stationInfluence[i] * 0.10 -
|
||||
slope[i] * 0.44 -
|
||||
ridgeField[i] * 0.32
|
||||
);
|
||||
const nearMajorCity = modernCities.some((c) => Math.hypot(c.x - x, c.y - y) < 4);
|
||||
logisticsScore[i] = nearMajorCity ? 0 : flatAgriculturalCorridor;
|
||||
}
|
||||
}
|
||||
const logisticsParks = pickGlobalPoints(logisticsScore, {
|
||||
threshold: 0.34,
|
||||
max: 18,
|
||||
minDistance: 12,
|
||||
seedOffset: 1450,
|
||||
predicate: (x, y, i) => logisticsScore[i] > 0.30 && (roadInfluence[i] > 0.10 || railInfluence2[i] > 0.08 || stationInfluence[i] > 0.08),
|
||||
}).map((p) => ({ ...p, kind: "Logistics Park", score: logisticsScore[indexOf(p.x, p.y)], population: 0 }));
|
||||
const logisticsInfluence = influenceFromPoints(logisticsParks, 4.8, () => 1.0);
|
||||
var landuse = new Uint8Array(SIZE);
|
||||
|
||||
// Re-run land-use classification after landuse allocation. The loop above is
|
||||
|
|
@ -856,6 +887,10 @@ export function generateMapFeatures(seed, terrain) {
|
|||
landuse[i] = LANDUSE.INDUSTRIAL;
|
||||
continue;
|
||||
}
|
||||
if (logisticsInfluence[i] > 0.24 && urbanCapacity[i] > 0.08 && (roadInfluence[i] > 0.08 || railInfluence2[i] > 0.06)) {
|
||||
landuse[i] = LANDUSE.LOGISTICS;
|
||||
continue;
|
||||
}
|
||||
if (core > 0.38 && urbanCapacity[i] > 0.10) {
|
||||
landuse[i] = LANDUSE.CBD;
|
||||
continue;
|
||||
|
|
@ -873,10 +908,11 @@ export function generateMapFeatures(seed, terrain) {
|
|||
landuse[i] = LANDUSE.SUBURB;
|
||||
} else if (roadLanduseInfluence[i] > 0.30 && urbanCapacity[i] > 0.10 && (townInfluence[i] > 0.05 || cityInfluence[i] > 0.11)) {
|
||||
landuse[i] = LANDUSE.SUBURB;
|
||||
} else if (agriculture[i] > 0.24 || rural > 0.22 || (developable[i] > 0.18 && plain[i] > 0.18)) {
|
||||
} else if (agriculture[i] > 0.16 || rural > 0.18 || (developable[i] > 0.13 && plain[i] > 0.13) || (basinField[i] > 0.18 && slope[i] < 0.34) || (coastalLowland[i] > 0.16 && slope[i] < 0.32)) {
|
||||
landuse[i] = LANDUSE.FARMLAND;
|
||||
} else {
|
||||
landuse[i] = elevation[i] > 0.52 || slope[i] > 0.34 ? LANDUSE.FOREST : LANDUSE.RURAL;
|
||||
const usablePlain = slope[i] < 0.30 && (plain[i] > 0.18 || developable[i] > 0.20 || basinField[i] > 0.20 || coastalLowland[i] > 0.18);
|
||||
landuse[i] = elevation[i] > 0.58 || slope[i] > 0.38 ? LANDUSE.FOREST : usablePlain ? LANDUSE.FARMLAND : LANDUSE.RURAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -916,6 +952,22 @@ export function generateMapFeatures(seed, terrain) {
|
|||
}
|
||||
}
|
||||
|
||||
for (const park of logisticsParks) {
|
||||
const r = 3;
|
||||
for (let dy = -r; dy <= r; dy++) {
|
||||
for (let dx = -r; dx <= r; dx++) {
|
||||
const x = park.x + dx;
|
||||
const y = park.y + dy;
|
||||
if (!inside(x, y)) continue;
|
||||
const i = indexOf(x, y);
|
||||
if (sea[i] || landuse[i] === LANDUSE.CBD || landuse[i] === LANDUSE.FOREST) continue;
|
||||
if (Math.hypot(dx, dy) <= r && (agriculture[i] > 0.18 || plain[i] > 0.15 || roadInfluence[i] > 0.06 || railInfluence2[i] > 0.05)) {
|
||||
landuse[i] = LANDUSE.LOGISTICS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maxDensity > 0) {
|
||||
for (let i = 0; i < SIZE; i++) {
|
||||
if (sea[i]) continue;
|
||||
|
|
@ -923,6 +975,8 @@ export function generateMapFeatures(seed, terrain) {
|
|||
let floor = ruralDensityFloor[i];
|
||||
if (lu === LANDUSE.FARMLAND) {
|
||||
floor = Math.max(floor, clamp(0.024 + agriculture[i] * 0.044 + ruralSuitability[i] * 0.024 + roadDensityInfluence[i] * 0.030 + stationDensityInfluence[i] * 0.026 + villageInfluence[i] * 0.018, 0, 0.110));
|
||||
} else if (lu === LANDUSE.LOGISTICS) {
|
||||
floor = Math.max(floor, clamp(0.018 + roadDensityInfluence[i] * 0.026 + railInfluence2[i] * 0.014 + logisticsInfluence[i] * 0.012, 0, 0.060));
|
||||
} else if (lu === LANDUSE.RURAL) {
|
||||
floor = Math.max(floor, clamp(0.012 + ruralSuitability[i] * 0.020 + developable[i] * 0.014 + roadDensityInfluence[i] * 0.024 + stationDensityInfluence[i] * 0.020, 0, 0.070));
|
||||
} else if (lu === LANDUSE.FOREST) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue