Files
deepseek 8680f79102 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
2026-08-23 07:01:08 +00:00

65 lines
2.9 KiB
JavaScript

'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');
});