Initial commit — Jianghu Chronicles: Road of the Wandering Blade
Original open-world wuxia browser RPG: - Graphical 48px tile world (12 locations) with walkable character, NPC interaction, action spots, roaming enemies, travel portals - Tactical 10x7 grid battles: shapes, statuses, internals, 30+ techniques incl. tier-V ultimates & support arts across 6 weapon types - Full equipment: weapon/head/body/feet/2 accessories, 5 tiers, smithing - 6-chapter main story + side jobs board + bounty hunts + tournament - Crafting (smith/alchemy), fishing minigame, gambling, pickpocketing - Companions with chemistry passives, affection, romance, sects - Achievements, monster codex, day/night cycle, endings - 25-test headless smoke suite; no-cache static server included
This commit is contained in:
+64
@@ -0,0 +1,64 @@
|
||||
'use strict';
|
||||
/* ============================================================
|
||||
MAIN — boot, data validation
|
||||
============================================================ */
|
||||
|
||||
function Data_validate() {
|
||||
const problems = [];
|
||||
const chkItem = (id, where) => { if (!ITEMS[id]) problems.push(`missing item ${id} (${where})`); };
|
||||
// shops
|
||||
for (const nid of Object.keys(NPCS)) {
|
||||
const n = NPCS[nid];
|
||||
if (n.shop) n.shop.stock.forEach(i => chkItem(i, 'shop ' + nid));
|
||||
(n.teach || []).forEach(t => {
|
||||
if (t.tech && !TECHNIQUES[t.tech]) problems.push(`npc ${nid} teaches missing tech ${t.tech}`);
|
||||
if (t.internal && !INTERNALS[t.internal]) problems.push(`npc ${nid} teaches missing internal ${t.internal}`);
|
||||
});
|
||||
if (n.dlg && !DIALOGUES[n.dlg]) problems.push(`npc ${nid} dialogue missing: ${n.dlg}`);
|
||||
}
|
||||
// locations
|
||||
for (const lid of Object.keys(LOCS)) {
|
||||
LOCS[lid].npcs.forEach(nid => { if (!NPCS[nid]) problems.push(`loc ${lid} npc missing ${nid}`); });
|
||||
}
|
||||
TRAVEL.forEach(([a, b]) => {
|
||||
if (!LOCS[a]) problems.push('travel missing loc ' + a);
|
||||
if (!LOCS[b]) problems.push('travel missing loc ' + b);
|
||||
});
|
||||
// quests referenced in dialogues (rough scan)
|
||||
const refs = JSON.stringify(DIALOGUES).match(/q_[a-z0-9_]+/g) || [];
|
||||
[...new Set(refs)].forEach(q => { if (!QUESTS[q]) problems.push('dialogue references unknown quest ' + q); });
|
||||
// techniques referenced as manuals
|
||||
Object.values(ITEMS).filter(i => i.type === 'manual').forEach(m => {
|
||||
if (!TECHNIQUES[m.teach] && !INTERNALS[m.teach] && !LIGHTNESS[m.teach]) problems.push(`manual ${m.id} teaches unknown ${m.teach}`);
|
||||
});
|
||||
// origins items/techs
|
||||
Object.entries(ORIGINS).forEach(([oid, o]) => {
|
||||
(o.items || []).forEach(i => chkItem(i, 'origin ' + oid));
|
||||
(o.techs || []).forEach(t => { if (!TECHNIQUES[t]) problems.push(`origin ${oid} tech ${t} missing`); });
|
||||
});
|
||||
// upgrades / recipes
|
||||
Object.entries(SMITH_UPGRADES).forEach(([k, up]) => { chkItem(k, 'smith'); chkItem(up.to, 'smith->'); Object.keys(up.mats).forEach(m => chkItem(m, 'smith mat')); });
|
||||
ALCHEMY_RECIPES.forEach(r => { chkItem(r.out, 'alch'); Object.keys(r.mats).forEach(m => chkItem(m, 'alch mat')); });
|
||||
// dialogues nodes integrity
|
||||
for (const did of Object.keys(DIALOGUES)) {
|
||||
const D = DIALOGUES[did];
|
||||
for (const nid of Object.keys(D.nodes)) {
|
||||
const opts = typeof D.nodes[nid].opts === 'function' ? [] : (D.nodes[nid].opts || []);
|
||||
opts.forEach(o => { if (o.next && !D.nodes[o.next]) problems.push(`${did}.${nid} -> missing node ${o.next}`); });
|
||||
}
|
||||
}
|
||||
if (problems.length) {
|
||||
console.warn('[Data] issues found:');
|
||||
problems.forEach(p => console.warn(' -', p));
|
||||
} else {
|
||||
console.log('[Data] validation passed ✔');
|
||||
}
|
||||
return problems;
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
Data_validate();
|
||||
UI.init();
|
||||
UI.renderTitleMenu();
|
||||
Log.add('The jianghu stirs\u2026', 'sys');
|
||||
});
|
||||
Reference in New Issue
Block a user