mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-19 02:21:24 +01:00
sky-burgs-sky-routes
This commit is contained in:
parent
2c3692f000
commit
73ab86b957
23 changed files with 919 additions and 49 deletions
|
|
@ -802,10 +802,13 @@ function buildGeoJsonBurgs() {
|
|||
xPixel: b.x,
|
||||
yPixel: b.y,
|
||||
elevation: parseInt(getHeight(pack.cells.h[b.cell])),
|
||||
skyAltitude: b.flying ? (b.altitude ?? 1000) : null,
|
||||
temperature: convertTemperature(temperature),
|
||||
temperatureLikeness: getTemperatureLikeness(temperature),
|
||||
capital: !!b.capital,
|
||||
port: !!b.port,
|
||||
flying: !!b.flying,
|
||||
skyPort: !!b.skyPort,
|
||||
citadel: !!b.citadel,
|
||||
walls: !!b.walls,
|
||||
plaza: !!b.plaza,
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ function drawBurgIcons() {
|
|||
|
||||
icons.selectAll("circle, use").remove(); // cleanup
|
||||
|
||||
// capitals
|
||||
const capitals = pack.burgs.filter(b => b.capital && !b.removed);
|
||||
// capitals (exclude sky burgs)
|
||||
const capitals = pack.burgs.filter(b => b.capital && !b.removed && !(b.flying || b.skyPort));
|
||||
const capitalIcons = burgIcons.select("#cities");
|
||||
const capitalSize = capitalIcons.attr("size") || 1;
|
||||
const capitalAnchors = anchors.selectAll("#cities");
|
||||
|
|
@ -35,8 +35,8 @@ function drawBurgIcons() {
|
|||
.attr("width", capitalAnchorsSize)
|
||||
.attr("height", capitalAnchorsSize);
|
||||
|
||||
// towns
|
||||
const towns = pack.burgs.filter(b => b.i && !b.capital && !b.removed);
|
||||
// towns (exclude sky burgs)
|
||||
const towns = pack.burgs.filter(b => b.i && !b.capital && !b.removed && !(b.flying || b.skyPort));
|
||||
const townIcons = burgIcons.select("#towns");
|
||||
const townSize = townIcons.attr("size") || 0.5;
|
||||
const townsAnchors = anchors.selectAll("#towns");
|
||||
|
|
@ -66,4 +66,20 @@ function drawBurgIcons() {
|
|||
.attr("height", townsAnchorsSize);
|
||||
|
||||
TIME && console.timeEnd("drawBurgIcons");
|
||||
|
||||
// Sky burgs (flying or sky port) — styled separately
|
||||
const sky = pack.burgs.filter(b => b.i && !b.removed && (b.flying || b.skyPort));
|
||||
const skyIcons = burgIcons.select("#skyburgs");
|
||||
const skySize = skyIcons.attr("size") || 0.6;
|
||||
|
||||
skyIcons
|
||||
.selectAll("circle")
|
||||
.data(sky)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("id", d => "burg" + d.i)
|
||||
.attr("data-id", d => d.i)
|
||||
.attr("cx", d => d.x)
|
||||
.attr("cy", d => d.y)
|
||||
.attr("r", skySize);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ window.Routes = (function () {
|
|||
// PHASE 1: IMMEDIATE PROCESSING (blocking - critical routes for trade and diplomacy)
|
||||
TIME && console.time("generateCriticalRoutes");
|
||||
const majorSeaRoutes = generateMajorSeaRoutes(); // Tier 1: Long-distance maritime trade
|
||||
const royalRoads = generateRoyalRoads(); // Tier 2: Capital-to-capital connections
|
||||
const royalRoads = generateRoyalRoads(); // Tier 2: Capital-to-capital roads
|
||||
const airRoutes = generateAirRoutes(); // Sky trade between sky ports
|
||||
TIME && console.timeEnd("generateCriticalRoutes");
|
||||
|
||||
// Create initial routes with critical paths only
|
||||
|
|
@ -831,8 +832,41 @@ window.Routes = (function () {
|
|||
routes.push({i: routes.length, group: "roads", feature, points, type: type || "royal"});
|
||||
}
|
||||
|
||||
// Air routes
|
||||
for (const {feature, cells, merged, type} of mergeRoutes(airRoutes)) {
|
||||
if (merged) continue;
|
||||
const points = getPoints("airroutes", cells, pointsArray);
|
||||
routes.push({i: routes.length, group: "airroutes", feature, points, type: type || "air"});
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
// Connect sky ports (flying burgs) using sparse graph
|
||||
function generateAirRoutes() {
|
||||
TIME && console.time("generateAirRoutes");
|
||||
const air = [];
|
||||
|
||||
const skyPorts = pack.burgs.filter(b => b && b.i && !b.removed && (b.skyPort || b.flying));
|
||||
if (skyPorts.length < 2) {
|
||||
TIME && console.timeEnd("generateAirRoutes");
|
||||
return air;
|
||||
}
|
||||
|
||||
// Use Urquhart edges to avoid a complete graph
|
||||
const points = skyPorts.map(b => [b.x, b.y]);
|
||||
const edges = calculateUrquhartEdges(points);
|
||||
edges.forEach(([ai, bi]) => {
|
||||
const a = skyPorts[ai];
|
||||
const b = skyPorts[bi];
|
||||
if (!a || !b) return;
|
||||
// For air routes, we can connect directly between burg cells
|
||||
air.push({feature: -1, cells: [a.cell, b.cell], type: "air"});
|
||||
});
|
||||
|
||||
TIME && console.timeEnd("generateAirRoutes");
|
||||
return air;
|
||||
}
|
||||
|
||||
// Function to append background-generated routes to pack
|
||||
function appendRoutesToPack(marketRoads, localRoads, footpaths, regionalSeaRoutes) {
|
||||
|
|
@ -1258,7 +1292,8 @@ window.Routes = (function () {
|
|||
roads: {burg_suffix: 3, prefix_suffix: 6, the_descriptor_prefix_suffix: 2, the_descriptor_burg_suffix: 1},
|
||||
secondary: {burg_suffix: 5, prefix_suffix: 4, the_descriptor_prefix_suffix: 1, the_descriptor_burg_suffix: 2},
|
||||
trails: {burg_suffix: 8, prefix_suffix: 1, the_descriptor_burg_suffix: 1},
|
||||
searoutes: {burg_suffix: 4, prefix_suffix: 2, the_descriptor_prefix_suffix: 1}
|
||||
searoutes: {burg_suffix: 4, prefix_suffix: 2, the_descriptor_prefix_suffix: 1},
|
||||
airroutes: {burg_suffix: 3, prefix_suffix: 5, the_descriptor_prefix_suffix: 2}
|
||||
};
|
||||
|
||||
const prefixes = [
|
||||
|
|
@ -1391,7 +1426,8 @@ window.Routes = (function () {
|
|||
roads: {road: 7, route: 3, way: 2, highway: 1},
|
||||
secondary: {road: 4, route: 2, way: 3, avenue: 1, boulevard: 1},
|
||||
trails: {trail: 4, path: 1, track: 1, pass: 1},
|
||||
searoutes: {"sea route": 5, lane: 2, passage: 1, seaway: 1}
|
||||
searoutes: {"sea route": 5, lane: 2, passage: 1, seaway: 1},
|
||||
airroutes: {"sky route": 5, "air lane": 3, skyway: 2, airway: 2, "aerial path": 1}
|
||||
};
|
||||
|
||||
function generateName({group, points}) {
|
||||
|
|
@ -1402,7 +1438,13 @@ window.Routes = (function () {
|
|||
const endB = end != null ? pack.cells.burg[end] : 0;
|
||||
const startName = startB ? getAdjective(pack.burgs[startB].name) : null;
|
||||
const endName = endB ? getAdjective(pack.burgs[endB].name) : null;
|
||||
const base = group === "searoutes" ? "Sea route" : group === "secondary" || group === "roads" ? "Road" : "Trail";
|
||||
const base = group === "searoutes"
|
||||
? "Sea route"
|
||||
: group === "airroutes"
|
||||
? "Sky route"
|
||||
: group === "secondary" || group === "roads"
|
||||
? "Road"
|
||||
: "Trail";
|
||||
if (startName && endName) return `${base} ${startName}–${endName}`;
|
||||
if (startName) return `${base} from ${startName}`;
|
||||
if (endName) return `${base} to ${endName}`;
|
||||
|
|
@ -1417,7 +1459,7 @@ window.Routes = (function () {
|
|||
if (model === "prefix_suffix") return `${ra(prefixes)} ${suffix}`;
|
||||
if (model === "the_descriptor_prefix_suffix") return `The ${ra(descriptors)} ${ra(prefixes)} ${suffix}`;
|
||||
if (model === "the_descriptor_burg_suffix" && burgName) return `The ${ra(descriptors)} ${burgName} ${suffix}`;
|
||||
return group === "searoutes" ? "Sea route" : "Route";
|
||||
return group === "searoutes" ? "Sea route" : group === "airroutes" ? "Sky route" : "Route";
|
||||
|
||||
function getBurgName() {
|
||||
const priority = [points.at(-1), points.at(0), points.slice(1, -1).reverse()];
|
||||
|
|
@ -1434,6 +1476,7 @@ window.Routes = (function () {
|
|||
secondary: d3.curveCatmullRom.alpha(0.1),
|
||||
trails: d3.curveCatmullRom.alpha(0.1),
|
||||
searoutes: d3.curveCatmullRom.alpha(0.5),
|
||||
airroutes: d3.curveCatmullRom.alpha(0.5),
|
||||
default: d3.curveCatmullRom.alpha(0.1)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ function editBurg(id) {
|
|||
byId("burgCulture").addEventListener("input", changeCulture);
|
||||
byId("burgNameReCulture").addEventListener("click", generateNameCulture);
|
||||
byId("burgPopulation").addEventListener("change", changePopulation);
|
||||
byId("burgAltitude")?.addEventListener("change", changeAltitude);
|
||||
burgBody.querySelectorAll(".burgFeature").forEach(el => el.addEventListener("click", toggleFeature));
|
||||
byId("burgLinkOpen").addEventListener("click", openBurgLink);
|
||||
byId("burgLinkEdit").addEventListener("click", changeBurgLink);
|
||||
|
|
@ -77,13 +78,25 @@ function editBurg(id) {
|
|||
byId("burgTemperature").innerHTML = convertTemperature(temperature);
|
||||
byId("burgTemperatureLikeIn").dataset.tip =
|
||||
"Average yearly temperature is like in " + getTemperatureLikeness(temperature);
|
||||
byId("burgElevation").innerHTML = getHeight(pack.cells.h[b.cell]);
|
||||
const altitudeRow = byId("burgAltitudeRow");
|
||||
if (b.flying) {
|
||||
altitudeRow.style.display = "flex";
|
||||
byId("burgAltitude").value = b.altitude ?? 1000;
|
||||
byId("burgElevation").innerHTML = `${b.altitude ?? 1000} m (sky altitude)`;
|
||||
} else {
|
||||
altitudeRow.style.display = "none";
|
||||
byId("burgElevation").innerHTML = getHeight(pack.cells.h[b.cell]);
|
||||
}
|
||||
|
||||
// toggle features
|
||||
if (b.capital) byId("burgCapital").classList.remove("inactive");
|
||||
else byId("burgCapital").classList.add("inactive");
|
||||
if (b.port) byId("burgPort").classList.remove("inactive");
|
||||
else byId("burgPort").classList.add("inactive");
|
||||
if (b.skyPort) byId("burgSkyPort").classList.remove("inactive");
|
||||
else byId("burgSkyPort").classList.add("inactive");
|
||||
if (b.flying) byId("burgFlying").classList.remove("inactive");
|
||||
else byId("burgFlying").classList.add("inactive");
|
||||
if (b.citadel) byId("burgCitadel").classList.remove("inactive");
|
||||
else byId("burgCitadel").classList.add("inactive");
|
||||
if (b.walls) byId("burgWalls").classList.remove("inactive");
|
||||
|
|
@ -292,12 +305,50 @@ function editBurg(id) {
|
|||
updateBurgPreview(burg);
|
||||
}
|
||||
|
||||
function changeAltitude() {
|
||||
const id = +elSelected.attr("data-id");
|
||||
const burg = pack.burgs[id];
|
||||
burg.altitude = Math.max(0, Math.round(+byId("burgAltitude").value));
|
||||
}
|
||||
|
||||
function toggleFeature() {
|
||||
const id = +elSelected.attr("data-id");
|
||||
const burg = pack.burgs[id];
|
||||
const feature = this.dataset.feature;
|
||||
const turnOn = this.classList.contains("inactive");
|
||||
if (feature === "port") togglePort(id);
|
||||
else if (feature === "skyPort") {
|
||||
burg.skyPort = +turnOn;
|
||||
// Assign to Sky State when turning on (if not a state capital)
|
||||
if (turnOn) {
|
||||
try {
|
||||
if (!burg.capital) {
|
||||
const skyId = ensureSkyState(id);
|
||||
if (burg.state !== skyId) {
|
||||
// Reassign cell ownership
|
||||
pack.cells.state[burg.cell] = skyId;
|
||||
burg.state = skyId;
|
||||
}
|
||||
}
|
||||
} catch (e) { ERROR && console.error(e); }
|
||||
}
|
||||
// Regenerate routes to reflect air network
|
||||
regenerateRoutes();
|
||||
}
|
||||
else if (feature === "flying") {
|
||||
burg.flying = +turnOn;
|
||||
if (turnOn) {
|
||||
try {
|
||||
const skyId = ensureSkyState(id);
|
||||
if (burg.state !== skyId) {
|
||||
pack.cells.state[burg.cell] = skyId;
|
||||
burg.state = skyId;
|
||||
}
|
||||
if (burg.altitude == null) burg.altitude = 1000;
|
||||
} catch (e) { ERROR && console.error(e); }
|
||||
}
|
||||
regenerateRoutes();
|
||||
}
|
||||
else if (feature === "capital") toggleCapital(id);
|
||||
else burg[feature] = +turnOn;
|
||||
if (burg[feature]) this.classList.remove("inactive");
|
||||
|
|
@ -434,8 +485,10 @@ function editBurg(id) {
|
|||
const id = +elSelected.attr("data-id");
|
||||
const burg = pack.burgs[id];
|
||||
|
||||
if (cells.h[cell] < 20) {
|
||||
tip("Cannot place burg into the water! Select a land cell", false, "error");
|
||||
const isWater = cells.h[cell] < 20;
|
||||
const allowWater = pack.burgs[id]?.flying || d3.event.altKey;
|
||||
if (isWater && !allowWater) {
|
||||
tip("Hold Alt or mark as Flying to place over water", false, "error");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -447,7 +500,7 @@ function editBurg(id) {
|
|||
const newState = cells.state[cell];
|
||||
const oldState = burg.state;
|
||||
|
||||
if (newState !== oldState && burg.capital) {
|
||||
if (newState !== oldState && burg.capital && !isWater) {
|
||||
tip("Capital cannot be relocated into another state!", false, "error");
|
||||
return;
|
||||
}
|
||||
|
|
@ -477,7 +530,15 @@ function editBurg(id) {
|
|||
cells.burg[burg.cell] = 0;
|
||||
cells.burg[cell] = id;
|
||||
burg.cell = cell;
|
||||
burg.state = newState;
|
||||
|
||||
// Set target state based on terrain and sky features
|
||||
if (isWater || burg.flying) {
|
||||
const skyId = ensureSkyState(id);
|
||||
cells.state[cell] = skyId;
|
||||
burg.state = skyId;
|
||||
} else {
|
||||
burg.state = newState;
|
||||
}
|
||||
burg.x = x;
|
||||
burg.y = y;
|
||||
if (burg.capital) pack.states[newState].center = burg.cell;
|
||||
|
|
|
|||
|
|
@ -281,12 +281,25 @@ function overviewBurgs(settings = {stateId: null, cultureId: null}) {
|
|||
const point = d3.mouse(this);
|
||||
const cell = findCell(...point);
|
||||
|
||||
if (pack.cells.h[cell] < 20)
|
||||
return tip("You cannot place state into the water. Please click on a land cell", false, "error");
|
||||
// Allow placing over water as a flying burg when Alt is held
|
||||
if (pack.cells.h[cell] < 20 && !d3.event.altKey)
|
||||
return tip("Hold Alt to place a flying burg over water", false, "error");
|
||||
if (pack.cells.burg[cell])
|
||||
return tip("There is already a burg in this cell. Please select a free cell", false, "error");
|
||||
|
||||
addBurg(point); // add new burg
|
||||
const id = addBurg(point); // add new burg
|
||||
|
||||
// Mark flying burgs and assign to Sky State, make them sky ports
|
||||
if (pack.cells.h[cell] < 20) {
|
||||
const burg = pack.burgs[id];
|
||||
burg.flying = 1;
|
||||
burg.skyPort = 1;
|
||||
if (burg.altitude == null) burg.altitude = 1000;
|
||||
const skyStateId = ensureSkyState(id);
|
||||
if (burg.state !== skyStateId) burg.state = skyStateId;
|
||||
// Keep as non-sea port
|
||||
burg.port = 0;
|
||||
}
|
||||
|
||||
if (d3.event.shiftKey === false) {
|
||||
exitAddBurgMode();
|
||||
|
|
@ -520,7 +533,7 @@ function downloadBurgsData() {
|
|||
let data = `Id,Burg,Province,Province Full Name,State,State Full Name,Culture,Religion,Population,`;
|
||||
data += `X_World (m),Y_World (m),X_Pixel,Y_Pixel,`; // New world coords + renamed pixel coords
|
||||
data += `Latitude,Longitude,`; // Keep for compatibility
|
||||
data += `Elevation (${heightUnit.value}),Temperature,Temperature likeness,`;
|
||||
data += `Elevation (${heightUnit.value}),Sky Altitude (m),Temperature,Temperature likeness,`;
|
||||
data += `Capital,Port,Citadel,Walls,Plaza,Temple,Shanty Town,Emblem,City Generator Link\n`;
|
||||
|
||||
const valid = pack.burgs.filter(b => b.i && !b.removed); // all valid burgs
|
||||
|
|
@ -553,6 +566,8 @@ function downloadBurgsData() {
|
|||
|
||||
// Continue with elevation and other data
|
||||
data += parseInt(getHeight(pack.cells.h[b.cell])) + ",";
|
||||
// Sky altitude in meters (only for flying burgs), else blank
|
||||
data += (b.flying ? (b.altitude ?? 1000) : "") + ",";
|
||||
const temperature = grid.cells.temp[pack.cells.g[b.cell]];
|
||||
data += convertTemperature(temperature) + ",";
|
||||
data += getTemperatureLikeness(temperature) + ",";
|
||||
|
|
|
|||
|
|
@ -227,6 +227,52 @@ function moveBurgToGroup(id, g) {
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure a dedicated locked Sky State exists; create if missing and return its id
|
||||
function ensureSkyState(anchorBurgId) {
|
||||
const {states, burgs, cultures, cells} = pack;
|
||||
|
||||
// Reuse existing sky state if present
|
||||
let sky = states.find(s => s && s.i && !s.removed && s.skyRealm);
|
||||
if (sky) return sky.i;
|
||||
|
||||
// Create a new locked Sky State
|
||||
const b = burgs[anchorBurgId];
|
||||
const i = states.length;
|
||||
const culture = (b && b.culture) || cells.culture?.[b?.cell] || 1;
|
||||
const type = "Generic";
|
||||
const name = "Sky Realm";
|
||||
const color = "#5b8bd4";
|
||||
const coa = COA.generate(null, null, null, cultures[culture]?.type || "Generic");
|
||||
coa.shield = COA.getShield(culture, null);
|
||||
|
||||
const newState = {
|
||||
i,
|
||||
name,
|
||||
type,
|
||||
color,
|
||||
capital: anchorBurgId,
|
||||
center: b.cell,
|
||||
culture,
|
||||
expansionism: 0.1,
|
||||
coa,
|
||||
lock: 1,
|
||||
skyRealm: 1
|
||||
};
|
||||
|
||||
states.push(newState);
|
||||
|
||||
// Assign the burg and its cell to the Sky State
|
||||
if (cells && typeof b.cell === "number") cells.state[b.cell] = i;
|
||||
if (b) {
|
||||
b.state = i;
|
||||
b.capital = 1;
|
||||
// Move to cities layer for capitals
|
||||
moveBurgToGroup(anchorBurgId, "cities");
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
function moveAllBurgsToGroup(fromGroup, toGroup) {
|
||||
const groupToMove = document.querySelector(`#burgIcons #${fromGroup}`);
|
||||
const burgsToMove = Array.from(groupToMove.children).map(x => x.dataset.id);
|
||||
|
|
@ -316,6 +362,9 @@ function togglePort(burg) {
|
|||
function getBurgLink(burg) {
|
||||
if (burg.link) return burg.link;
|
||||
|
||||
// Sky burgs: force MFCG with sky-friendly parameters
|
||||
if (burg.flying || burg.skyPort) return createMfcgLink(burg, true);
|
||||
|
||||
const population = burg.population * populationRate * urbanization;
|
||||
if (population >= options.villageMaxPopulation || burg.citadel || burg.walls || burg.temple || burg.shanty)
|
||||
return createMfcgLink(burg);
|
||||
|
|
@ -323,42 +372,42 @@ function getBurgLink(burg) {
|
|||
return createVillageGeneratorLink(burg);
|
||||
}
|
||||
|
||||
function createMfcgLink(burg) {
|
||||
function createMfcgLink(burg, isSky = false) {
|
||||
const {cells} = pack;
|
||||
const {i, name, population: burgPopulation, cell} = burg;
|
||||
const burgSeed = burg.MFCG || seed + String(burg.i).padStart(4, 0);
|
||||
|
||||
const sizeRaw = 2.13 * Math.pow((burgPopulation * populationRate) / urbanDensity, 0.385);
|
||||
const size = minmax(Math.ceil(sizeRaw), 6, 100);
|
||||
const size = isSky ? 25 : minmax(Math.ceil(sizeRaw), 6, 100);
|
||||
const population = rn(burgPopulation * populationRate * urbanization);
|
||||
|
||||
const river = cells.r[cell] ? 1 : 0;
|
||||
const coast = Number(burg.port > 0);
|
||||
const sea = (() => {
|
||||
if (!coast || !cells.haven[cell]) return null;
|
||||
const river = isSky ? 0 : (cells.r[cell] ? 1 : 0);
|
||||
const coast = isSky ? 0 : Number(burg.port > 0);
|
||||
|
||||
// calculate see direction: 0 = south, 0.5 = west, 1 = north, 1.5 = east
|
||||
const p1 = cells.p[cell];
|
||||
const p2 = cells.p[cells.haven[cell]];
|
||||
let deg = (Math.atan2(p2[1] - p1[1], p2[0] - p1[0]) * 180) / Math.PI - 90;
|
||||
if (deg < 0) deg += 360;
|
||||
return rn(normalize(deg, 0, 360) * 2, 2);
|
||||
})();
|
||||
const sea = !isSky && coast && cells.haven[cell]
|
||||
? (() => {
|
||||
const p1 = cells.p[cell];
|
||||
const p2 = cells.p[cells.haven[cell]];
|
||||
let deg = (Math.atan2(p2[1] - p1[1], p2[0] - p1[0]) * 180) / Math.PI - 90;
|
||||
if (deg < 0) deg += 360;
|
||||
return rn(normalize(deg, 0, 360) * 2, 2);
|
||||
})()
|
||||
: null;
|
||||
|
||||
const arableBiomes = river ? [1, 2, 3, 4, 5, 6, 7, 8] : [5, 6, 7, 8];
|
||||
const farms = +arableBiomes.includes(cells.biome[cell]);
|
||||
const farms = isSky ? 0 : +arableBiomes.includes(cells.biome[cell]);
|
||||
|
||||
const citadel = +burg.citadel;
|
||||
const urban_castle = +(citadel && each(2)(i));
|
||||
const citadel = isSky ? 1 : +burg.citadel;
|
||||
const urban_castle = isSky ? 1 : +(citadel && each(2)(i));
|
||||
const hub = isSky ? 0 : Routes.isCrossroad(cell);
|
||||
const walls = isSky ? 1 : +burg.walls;
|
||||
const plaza = isSky ? 1 : +burg.plaza;
|
||||
const temple = isSky ? 1 : +burg.temple;
|
||||
const shantytown = isSky ? 0 : +burg.shanty;
|
||||
const greens = isSky ? 1 : undefined;
|
||||
const gates = isSky ? 0 : -1;
|
||||
|
||||
const hub = Routes.isCrossroad(cell);
|
||||
const walls = +burg.walls;
|
||||
const plaza = +burg.plaza;
|
||||
const temple = +burg.temple;
|
||||
const shantytown = +burg.shanty;
|
||||
|
||||
const url = new URL("https://watabou.github.io/city-generator/");
|
||||
url.search = new URLSearchParams({
|
||||
const params = {
|
||||
name,
|
||||
population,
|
||||
size,
|
||||
|
|
@ -372,9 +421,13 @@ function createMfcgLink(burg) {
|
|||
plaza,
|
||||
temple,
|
||||
walls,
|
||||
shantytown,
|
||||
gates: -1
|
||||
});
|
||||
shantytown
|
||||
};
|
||||
if (greens !== undefined) params.greens = greens;
|
||||
if (gates !== undefined) params.gates = gates;
|
||||
|
||||
const url = new URL("https://watabou.github.io/city-generator/");
|
||||
url.search = new URLSearchParams(params);
|
||||
if (sea) url.searchParams.append("sea", sea);
|
||||
|
||||
return url.toString();
|
||||
|
|
|
|||
|
|
@ -401,11 +401,14 @@ function editHeightmap(options) {
|
|||
// find best cell for burgs
|
||||
for (const b of pack.burgs) {
|
||||
if (!b.i || b.removed) continue;
|
||||
b.cell = findBurgCell(b.x, b.y);
|
||||
// Keep flying burgs at their current (possibly water) cell
|
||||
if (!b.flying) {
|
||||
b.cell = findBurgCell(b.x, b.y);
|
||||
}
|
||||
b.feature = pack.cells.f[b.cell];
|
||||
|
||||
pack.cells.burg[b.cell] = b.i;
|
||||
if (!b.capital && pack.cells.h[b.cell] < 20) removeBurg(b.i);
|
||||
if (!b.capital && pack.cells.h[b.cell] < 20 && !b.flying) removeBurg(b.i);
|
||||
if (b.capital) pack.states[b.state].center = b.cell;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ function addStylePreset() {
|
|||
"#roads": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"],
|
||||
"#trails": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"],
|
||||
"#searoutes": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"],
|
||||
"#airroutes": ["opacity", "stroke", "stroke-width", "stroke-dasharray", "stroke-linecap", "filter", "mask"],
|
||||
"#statesBody": ["opacity", "filter"],
|
||||
"#statesHalo": ["opacity", "data-width", "stroke-width", "filter"],
|
||||
"#provs": ["opacity", "fill", "font-size", "font-family", "filter"],
|
||||
|
|
@ -290,6 +291,16 @@ function addStylePreset() {
|
|||
"stroke-dasharray",
|
||||
"stroke-linecap"
|
||||
],
|
||||
"#burgIcons > #skyburgs": [
|
||||
"opacity",
|
||||
"fill",
|
||||
"fill-opacity",
|
||||
"size",
|
||||
"stroke",
|
||||
"stroke-width",
|
||||
"stroke-dasharray",
|
||||
"stroke-linecap"
|
||||
],
|
||||
"#anchors > #cities": ["opacity", "fill", "size", "stroke", "stroke-width"],
|
||||
"#burgLabels > #towns": [
|
||||
"opacity",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue