Three Kingdoms: Warlord's Fate — complete playable game
- Stylized 3D ink-painting map of China (12 provinces, 32 cities, 17 factions) - Custom warlord creation (8 origins, banner, starting city) or historical factions - City management: 7 buildings, 5 dev tiers, recruitment from levies - Character system: stats, traits, loyalty, relationships, wounds, capture, death, succession - Turn-based tactical battles with formations, stances, hero skills, cinematic 3D replay - Sieges: assault, starvation, bribery, infiltration - Diplomacy with trust memory, alliances, NAPs, trade, marriage, espionage, betrayal - Scripted diverging history (Dong Zhuo, Guandu, Red Cliffs...) + world crises + court events - AI factions with distinct personalities; prisoners (execute/release/recruit/ransom) - Procedural guqin/taiko WebAudio score; save/load; victory + dynasty chronicle screens - View-relative camera controls; headless test suites (smoke, stress, map validator)
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
// map validation script (node)
|
||||
import { MAP_ROWS, PROVINCE_LETTERS, CITY_DEFS, hexToWorld, RIVERS } from "../js/data.js";
|
||||
|
||||
const rows = MAP_ROWS;
|
||||
const H = rows.length;
|
||||
const at = (c, r) => (r < 0 || r >= H || c < 0 || c >= (rows[r]?.length ?? 0)) ? "." : rows[r][c];
|
||||
const isLand = ch => ch !== ".";
|
||||
const provOf = ch => isLand(ch) ? ch.toLowerCase() : null;
|
||||
|
||||
// neighbors odd-r offset
|
||||
function nbrs(c, r) {
|
||||
const odd = r % 2;
|
||||
return [[c-1,r],[c+1,r],[c+odd-1,r-1],[c+odd,r-1],[c+odd-1,r+1],[c+odd,r+1]];
|
||||
}
|
||||
|
||||
// contiguity per province
|
||||
for (const P of PROVINCE_LETTERS) {
|
||||
const cells = [];
|
||||
for (let r = 0; r < H; r++) for (let c = 0; c < (rows[r].length); c++) if (provOf(rows[r][c]) === P) cells.push([c, r]);
|
||||
if (!cells.length) { console.log(`!! province ${P} EMPTY`); continue; }
|
||||
const set = new Set(cells.map(([c, r]) => c + "," + r));
|
||||
const seen = new Set([cells[0].join(",")]);
|
||||
const stack = [cells[0]];
|
||||
while (stack.length) {
|
||||
const [c, r] = stack.pop();
|
||||
for (const [nc, nr] of nbrs(c, r)) {
|
||||
if (provOf(at(nc, nr)) === P && !seen.has(nc + "," + nr)) { seen.add(nc + "," + nr); stack.push([nc, nr]); }
|
||||
}
|
||||
}
|
||||
console.log(`${set.size === seen.size ? "OK " : "SPLIT"} ${P}: ${cells.length} hexes${set.size !== seen.size ? " (" + (set.size - seen.size) + " orphan)" : ""}`);
|
||||
}
|
||||
|
||||
// adjacency between provinces
|
||||
const adj = new Set();
|
||||
for (let r = 0; r < H; r++) for (let c = 0; c < rows[r].length; c++) {
|
||||
const p = provOf(rows[r][c]); if (!p) continue;
|
||||
for (const [nc, nr] of nbrs(c, r)) { const q = provOf(at(nc, nr)); if (q && q !== p) adj.add([p, q].sort().join("")); }
|
||||
}
|
||||
console.log("adjacency:", [...adj].sort().join(" "));
|
||||
|
||||
// city checks
|
||||
let bad = 0;
|
||||
for (const [id, name, , prov, c, r] of CITY_DEFS) {
|
||||
const p = provOf(at(c, r));
|
||||
if (p !== prov) { console.log(`CITY BAD: ${name} wants ${prov} but tile(${c},${r})='${at(c, r)}'`); bad++; }
|
||||
}
|
||||
// uniqueness of city tiles
|
||||
const tiles = new Set();
|
||||
for (const [id, name, , , c, r] of CITY_DEFS) { const k = c + "," + r; if (tiles.has(k)) { console.log("CITY OVERLAP at", k); bad++; } tiles.add(k); }
|
||||
console.log(bad ? `${bad} city problems` : `all ${CITY_DEFS.length} cities valid & unique`);
|
||||
|
||||
// river points on land?
|
||||
for (const rv of RIVERS) for (const [c, r] of rv.pts) if (!isLand(at(c, r))) console.log(`river ${rv.name} off-land at ${c},${r}`);
|
||||
|
||||
// world extent
|
||||
let minX = 1e9, maxX = -1e9, minZ = 1e9, maxZ = -1e9;
|
||||
for (let r = 0; r < H; r++) for (let c = 0; c < rows[r].length; c++) if (isLand(rows[r][c])) {
|
||||
const [x, z] = hexToWorld(c, r);
|
||||
minX = Math.min(minX, x); maxX = Math.max(maxX, x); minZ = Math.min(minZ, z); maxZ = Math.max(maxZ, z);
|
||||
}
|
||||
console.log(`map world extent x:[${minX.toFixed(0)},${maxX.toFixed(0)}] z:[${minZ.toFixed(0)},${maxZ.toFixed(0)}]`);
|
||||
Reference in New Issue
Block a user