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

340 lines
26 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict';
/* ============================================================
DATA: NPCs, world map, quests, origins, recipes, tournament
All names & lore are original fiction.
============================================================ */
/* ---------------- NPCs ---------------- */
const NPCS = {};
function defNpc(id, o) { o.id = id; NPCS[id] = o; }
defNpc('n_elderchen', { name: 'Elder Chen', title: 'Village Elder', loc: 'l_village', gender: 'm', hue: '#c9b28a', char: '陈', role: 'Keeps the peace and worries about everyone', dlg: 'd_elder', giftTags: ['kind'] });
defNpc('n_innkeeper_ma', { name: 'Innkeeper Ma', title: 'Willow Creek Inn', loc: 'l_village', gender: 'f', hue: '#b58f7a', char: '马', role: 'Hot beds, hotter congee', dlg: 'd_inn_ma', inn: 8, giftTags: ['kind'] });
defNpc('n_kid_xiaoli', { name: 'Xiaoli', title: 'Village Kid', loc: 'l_village', gender: 'f', hue: '#d4b84e', char: '李', role: 'Knows every rumor worth half a candy', dlg: 'd_kid', giftTags: ['youth', 'kind'] });
defNpc('n_merchant_su', { name: 'Merchant Su', title: 'Su & Sons Trading', loc: 'l_city', gender: 'm', hue: '#8fae6f', char: '苏', role: 'General goods, fair prices, better gossip', dlg: 'd_su', shop: { name: 'General Goods', stock: ['c_bun', 'c_herb_green', 'c_herb_red', 'ar_body_1', 'ar_body_2', 'ar_head_1', 'ar_foot_1', 'ar_foot_2', 'w_sword_1', 'w_blade_1', 'w_spear_1', 'w_staff_1', 'w_fist_1', 'w_hidden_1', 'gift_tea', 'gift_cakes', 'ac_jade'] }, giftTags: ['noble'] });
defNpc('n_innkeeper_zhou', { name: 'Innkeeper Zhou', title: 'Golden Carp Inn', loc: 'l_city', gender: 'm', hue: '#caa25f', char: '周', role: 'Runs the finest inn between two mountains', dlg: 'd_inn_zhou', inn: 14, giftTags: ['drinker'] });
defNpc('n_captain_yan', { name: 'Captain Yan', title: 'Garrison Liaison Office', loc: 'l_city', gender: 'f', hue: '#7d93ad', char: '燕', role: 'Sharp uniform, sharper tongue', dlg: 'd_yan', giftTags: ['scholar'] });
defNpc('n_arena_qian', { name: 'Host Qian', title: 'Martial Tournament Grounds', loc: 'l_city', gender: 'm', hue: '#c07a52', char: '钱', role: 'Announcer, bookie, friend of heroes', dlg: 'd_qian', giftTags: ['noble'] });
defNpc('n_beggar_hong', { name: 'Hong the Beggar', title: 'Wherever the wine is', loc: 'l_city', gender: 'm', hue: '#9c8f76', char: '洪', role: 'Drunk, ridiculous, occasionally terrifying', dlg: 'd_hong', spar: true, hiddenNpc: true, giftTags: ['drinker', 'kind'] });
defNpc('n_smith_wang', { name: 'Smith Wang', title: 'Ember Forge', loc: 'l_town', gender: 'm', hue: '#a5643f', char: '王', role: 'Forges blades and opinions equally hot', dlg: 'd_wang', smith: true, shop: { name: 'Forge Goods', stock: ['w_sword_2', 'w_blade_2', 'w_spear_2', 'w_staff_2', 'w_fist_2', 'w_hidden_2', 'ar_body_2', 'ar_body_3', 'ar_head_2', 'ar_foot_2', 'ar_foot_3', 'ac_bracer', 'mat_ore_1'] }, giftTags: ['fighter'] });
defNpc('n_alchemist_bai', { name: 'Alchemist Bai', title: 'Bai\u2019s Remedies', loc: 'l_town', gender: 'f', hue: '#9dbb74', char: '白', role: 'If it can be brewed, she has brewed it', dlg: 'd_bai', alchemy: true, shop: { name: 'Remedies', stock: ['c_pill_hp', 'c_pill_mp', 'c_antidote', 'c_herb_red', 'c_lotus', 'gift_tea'] }, giftTags: ['scholar'] });
defNpc('n_innkeeper_lu', { name: 'Innkeeper Lu', title: 'Ember Lodge', loc: 'l_town', gender: 'f', hue: '#bd9a6a', char: '卢', role: 'Feeds smiths, miners, and occasional heroes', dlg: 'd_inn_lu', inn: 10, giftTags: ['kind'] });
defNpc('n_hunter_ren', { name: 'Hunter Ren', title: 'Bamboo Edge Cabin', loc: 'l_bamboo', gender: 'm', hue: '#7f9663', char: '任', role: 'Traps wolves, trades pelts, mistrusts cities', dlg: 'd_ren', spar: true, teach: [{ tech: 't_blade_1', aff: 25, cost: 0, note: 'free for trusted friends' }], giftTags: ['fighter', 'drinker'] });
defNpc('n_tiehu', { name: 'Zhao Tiehu', title: 'Dockside Challenger', loc: 'l_dock', gender: 'm', hue: '#bf7d4f', char: '赵', role: 'Undefeated arm-wrestler of Peach Blossom Dock', dlg: 'd_tiehu', spar: true, companion: { wt: 'fist', techs: ['t_fist_1', 't_fist_2'], internal: 'i_water', hpM: 1.25, atkM: 0.95, defM: 1.15 }, giftTags: ['fighter', 'drinker'] });
defNpc('n_ferryman', { name: 'Old Gao the Ferryman', title: 'Peach Blossom Dock', loc: 'l_dock', gender: 'm', hue: '#8d9aa5', char: '高', role: 'Rows at night to a shore not on maps', dlg: 'd_ferry', giftTags: ['drinker'] });
defNpc('n_abbot_lian', { name: 'Abbot Lian', title: 'Pure Lotus Temple', loc: 'l_temple', gender: 'm', hue: '#c8b46a', char: '莲', role: 'Sweeps leaves, teaches sutras, sees everything', dlg: 'd_abbot',
teach: [
{ tech: 't_staff_2', aff: 20, cost: 300 },
{ tech: 't_staff_3', aff: 55, cost: 900, reqRep: ['temple', 20] },
{ internal: 'i_vajra', aff: 40, cost: 500 },
{ internal: 'i_sun', aff: 90, cost: 2000, reqFlag: 'sunHint' }
], giftTags: ['monk', 'scholar'] });
defNpc('n_monk_jing', { name: 'Monk Jing', title: 'Pure Lotus Temple', loc: 'l_temple', gender: 'm', hue: '#a8a06b', char: '静', role: 'Training-yard partner with infinite patience', dlg: 'd_jing', spar: true, giftTags: ['monk'] });
defNpc('n_master_yun', { name: 'Master Yun', title: 'Azure Cloud Sect', loc: 'l_sect', gender: 'f', hue: '#7d9bb8', char: '云', role: 'First Blade of Azure Cloud Peak', dlg: 'd_yun',
teach: [
{ tech: 't_sword_2', aff: 20, cost: 300 },
{ tech: 't_sword_3', aff: 55, cost: 900, reqRep: ['azure', 20] },
{ internal: 'i_azure', aff: 40, cost: 500 }
], giftTags: ['scholar'] });
defNpc('n_lin', { name: 'Lin Wan\u2019er', title: 'Azure Cloud Disciple', loc: 'l_sect', gender: 'f', hue: '#b8797d', char: '林', role: 'Sword prodigy, chronic winner, terrible loser', dlg: 'd_lin', spar: true, romanceable: true,
companion: { wt: 'sword', techs: ['t_sword_1', 't_sword_2'], internal: 'i_water', hpM: 1.0, atkM: 1.1, defM: 0.95 }, giftTags: ['fighter', 'romance'] });
defNpc('n_lady_miao', { name: 'Lady Miao', title: 'Serpent Veil Valley', loc: 'l_valley', gender: 'f', hue: '#87a06b', char: '苗', role: 'Smiles like honey, seasons everything with venom', dlg: 'd_miao',
teach: [
{ tech: 't_hidden_2', aff: 15, cost: 250 },
{ tech: 't_hidden_3', aff: 50, cost: 850, reqRep: ['serpent', 20] },
{ internal: 'i_serpent', aff: 35, cost: 450 }
], giftTags: ['noble'] });
defNpc('n_suqing', { name: 'Su Qingluo', title: 'Valley Physician', loc: 'l_valley', gender: 'f', hue: '#a5b879', char: '青', role: 'Cures what ails you; causes what cures you', dlg: 'd_suqing', romanceable: true,
companion: { wt: 'hidden', techs: ['t_hidden_1', 't_hidden_2'], internal: 'i_water', ai: 'support', hpM: 0.9, atkM: 1.0, defM: 0.95 }, giftTags: ['scholar', 'romance'] });
defNpc('n_master_guo', { name: 'Master Guo', title: 'Iron Fist Guild Hall', loc: 'l_garrison', gender: 'm', hue: '#b3703f', char: '郭', role: 'Retired pit-fighter running the guild hall', dlg: 'd_guo', spar: true,
teach: [
{ tech: 't_fist_2', aff: 20, cost: 300 },
{ tech: 't_fist_3', aff: 55, cost: 900, reqRep: ['fist', 20] }
], giftTags: ['fighter', 'drinker'] });
defNpc('n_drill_capt', { name: 'Drill-Captain Pei', title: 'Black Tortoise Garrison', loc: 'l_garrison', gender: 'm', hue: '#6f8296', char: '裴', role: 'Runs drills, bounty boards, and recruits ragged', dlg: 'd_pei', giftTags: ['fighter'] });
defNpc('n_broker_qiu', { name: 'Broker Qiu', title: 'Ghost Market', loc: 'l_market', gender: 'm', hue: '#9a86a8', char: '邱', role: 'Sells secrets by the ounce', dlg: 'd_broker', giftTags: ['scholar', 'noble'] });
defNpc('n_fence_wu', { name: 'Fence Wu', title: 'Ghost Market', loc: 'l_market', gender: 'f', hue: '#8a7d9c', char: '吴', role: 'Everything has a previous owner', dlg: 'd_fence', shop: { name: 'Acquisitions', stock: ['m_l_cloud', 'm_l_shadow', 'm_t_sword_2', 'm_t_blade_2', 'm_t_spear_2', 'm_t_staff_2', 'm_t_fist_2', 'm_t_hidden_2', 'ac_goldbell', 'c_fragment', 'c_elixir_power', 'c_elixir_swift', 'gift_silk', 'gift_book', 'gift_hairpin'] }, giftTags: ['noble'] });
/* ---------------- WORLD ---------------- */
const LOCS = {};
function defLoc(id, o) { o.id = id; LOCS[id] = o; }
defLoc('l_village', { name: 'Willow Creek Village', desc: 'Your home. Willows lean over the creek; chickens own the road.', danger: 0, region: 'Heartlands',
actions: [{ id: 'herb', label: 'Gather herbs', note: '1h · daily' }],
npcs: ['n_elderchen', 'n_innkeeper_ma', 'n_kid_xiaoli'] });
defLoc('l_city', { name: 'Qingyun City', desc: 'Ten thousand roofs, one hundred rumors, at least nine true.', danger: 0, region: 'Heartlands',
actions: [{ id: 'board', label: 'Bulletin Board', note: 'bounties & notices' }, { id: 'gamble', label: 'Dice den', note: 'moderate stakes' }, { id: 'pickpocket', label: 'Work the crowd', note: 'risky · daily' }],
npcs: ['n_merchant_su', 'n_innkeeper_zhou', 'n_captain_yan', 'n_arena_qian', 'n_beggar_hong'] });
defLoc('l_town', { name: 'Ember Town', desc: 'Coal smoke, ringing anvils, and the best noodles in the prefecture.', danger: 0, region: 'Heartlands',
npcs: ['n_smith_wang', 'n_alchemist_bai', 'n_innkeeper_lu'] });
defLoc('l_dock', { name: 'Peach Blossom Dock', desc: 'Petals on black water; barges going everywhere and nowhere.', danger: 0, region: 'Riverlands',
actions: [{ id: 'pickpocket', label: 'Work the crowd', note: 'risky · daily' }, { id: 'fish', label: 'Fish off the pier', note: 'timing · ×10 daily' }],
npcs: ['n_tiehu', 'n_ferryman'] });
defLoc('l_garrison', { name: 'Black Tortoise Garrison', desc: 'Banners, drill-yards, and the Empire\u2019s long memory.', danger: 0, region: 'Heartlands',
actions: [{ id: 'board', label: 'Military Bounty Board', note: 'better-paying bounties' }],
npcs: ['n_master_guo', 'n_drill_capt'] });
defLoc('l_bamboo', { name: 'Verdant Bamboo Sea', desc: 'Green light falls in stripes. Something is always watching.', danger: 2, region: 'Wilds',
pools: { low: ['e_wolf', 'e_snake'], mid: ['e_wolf', 'e_tiger', 'e_bandit'], high: ['e_tiger', 'e_bandit_vet'] },
actions: [{ id: 'herb', label: 'Gather herbs', note: '1h · daily' }, { id: 'camp', label: 'Make camp', note: '6h · restore 55%' }],
npcs: ['n_hunter_ren'] });
defLoc('l_mountain', { name: 'Cloudmist Ridge', desc: 'The pass winds through fog, old shrines, and newer ambushes.', danger: 2, region: 'Wilds',
pools: { low: ['e_wolf', 'e_boar'], mid: ['e_wolf', 'e_tiger', 'e_bandit'], high: ['e_tiger', 'e_bandit_vet', 'e_bear'] },
actions: [{ id: 'mine', label: 'Prospect for ore', note: '2h · daily' }, { id: 'camp', label: 'Make camp', note: '6h · restore 55%' }],
npcs: [] });
defLoc('l_valley', { name: 'Serpent Veil Valley', desc: 'Beautiful, fragrant, and quietly lethal. Mind where you step.', danger: 3, region: 'Deep Wilds',
pools: { mid: ['e_snake', 'e_poisoner'], high: ['e_poisoner', 'e_tiger', 'e_assassin'] },
actions: [{ id: 'herb', label: 'Gather rare herbs', note: '1h · daily' }, { id: 'camp', label: 'Make camp', note: '6h · restore 55%' }],
npcs: ['n_lady_miao', 'n_suqing'] });
defLoc('l_temple', { name: 'Pure Lotus Temple', desc: 'Incense, bells, and a training yard swept to mirror-brightness.', danger: 0, region: 'Highlands',
actions: [{ id: 'meditate', label: 'Meditate in the hall', note: '2h · cultivates internal arts' }, { id: 'dummy', label: 'Train at the posts', note: '1h · practice a technique' }],
npcs: ['n_abbot_lian', 'n_monk_jing'] });
defLoc('l_sect', { name: 'Azure Cloud Peak', desc: 'Stone stairs above the cloud-line; swords sing at dawn.', danger: 0, region: 'Highlands',
actions: [{ id: 'meditate', label: 'Meditate on the terrace', note: '2h' }, { id: 'dummy', label: 'Train at the posts', note: '1h · practice a technique' }, { id: 'secttasks', label: 'Mission Hall', note: 'tasks for sect reputation' }],
npcs: ['n_master_yun', 'n_lin'] });
defLoc('l_market', { name: 'Ghost Market', desc: 'A market with no daylight and no questions. Entry after dusk only.', danger: 1, region: 'Underworld', nightOnly: true,
actions: [{ id: 'gamble', label: 'Dice den', note: 'high stakes' }, { id: 'pickpocket', label: 'Lift a purse', note: 'very risky' }],
npcs: ['n_broker_qiu', 'n_fence_wu'] });
defLoc('l_tomb', { name: 'Ancient Tomb of the First Sword', desc: 'Buried stairs, patient dead things, and a door that remembers.', danger: 4, region: 'Deep Wilds',
pools: { high: ['e_sentinel', 'e_assassin'] },
npcs: [] });
const TRAVEL = [
['l_village', 'l_mountain', 2],
['l_village', 'l_city', 4],
['l_city', 'l_town', 2],
['l_city', 'l_dock', 1],
['l_city', 'l_garrison', 2],
['l_city', 'l_bamboo', 3],
['l_dock', 'l_market', 1],
['l_bamboo', 'l_sect', 2],
['l_bamboo', 'l_valley', 3],
['l_town', 'l_temple', 3],
['l_mountain', 'l_tomb', 3]
];
/* ---------------- QUESTS ---------------- */
const QUESTS = {
q_main_1: { name: 'Wolf Trouble', main: true, stages: [
'Speak with Elder Chen.',
'Cull the wolf packs on Cloudmist Ridge. (%K/wolves)',
'Report back to Elder Chen.'
],
doneText: 'The flocks sleep easy — for now.' },
q_main_2: { name: 'A Trail Leads to Qingyun', main: true, stages: [
'Find Captain Yan at the Garrison Liaison Office in Qingyun City.',
'Destroy the bandit camp on Cloudmist Ridge.',
'Defeat "One-Eye" Qiang.',
'Search the camp for evidence.'
],
doneText: 'Qiangs lead token now sits in Captain Yans evidence box.' },
q_main_3: { name: 'The Iron Umbrella', main: true, stages: [
'Learn about the Iron Umbrella Society. (Try the Ghost Market at night.)',
'Buy Broker Qiu\u2019s intelligence on the tournament plot.',
'Win through to the tournament finals in Qingyun City.',
'Expose the impostor among the finalists.'
],
doneText: 'Du Kang escaped with his life — but not his secrets.' },
q_main_4: { name: 'Gathering Storm', main: true, stages: [
'Recruit at least two companions to your banner.',
'Join a school or earn Garrison trust (rep 30).',
'Report to Captain Yan.'
],
doneText: 'You are no longer alone on the road.' },
q_main_5: { name: 'The Heaven\u2019s Ledger', main: true, stages: [
'Take the mountain path to the Ancient Tomb of the First Sword.',
'Silence two Tomb Sentinels guarding the descent. (%K/sentinels)',
'Reach the inner door before the Iron Umbrella takes the Ledger.',
'Claim the Heaven\u2019s Ledger.'
],
doneText: 'The Ledger weighs almost nothing, and changes everything.' },
q_main_6: { name: 'Showdown at Azure Peak', main: true, stages: [
'The Iron Umbrella marches on Azure Cloud Peak. Go there and hold the line.',
'Defeat Wu Zhaoshan.'
],
doneText: 'The umbrellas folded, one by one, until the sky was only sky.' },
q_cure: { name: 'The Alchemist\u2019s Favor', stages: [
'Alchemist Bai needs 2 Snake Gallbladders and 3 Green Herbs.',
'Bring the ingredients to Alchemist Bai in Ember Town.'
],
doneText: 'Bais fever cure saved three children. She shares her real recipes.' },
q_missing: { name: 'The Missing Woodcutter', stages: [
'Ask Hunter Ren in the Bamboo Sea about Uncle Ping.',
'Search the deep bamboo past the third bend.',
'Tell Elder Chen the news.'
],
doneText: 'Uncle Ping rests beneath the willows now. The village will remember.' },
q_trial_az: { name: 'Trials of Azure Cloud', stages: [
'Bring 2 Lotus Herbs from the Bamboo Sea to Master Yun.',
'Deliver the herbs.'
],
doneText: 'The gates of Azure Cloud Sect stand open to you.' }
};
/* ---------------- ORIGINS ---------------- */
const ORIGINS = {
farm: { name: 'Farmhand\u2019s Child', attrs: { con: 1, str: 1 }, silver: 30, items: ['w_staff_1', 'c_bun', 'c_bun'], techs: ['t_staff_1', 't_univ_1'],
desc: 'Raised on hoe-handles and early mornings.' },
merchant: { name: 'Merchant\u2019s Heir', attrs: { cha: 2, luk: 1 }, silver: 260, items: ['ac_jade', 'gift_fan', 'c_bun'], techs: ['t_univ_1'],
desc: 'You know what everything costs, including pride.' },
scholar: { name: 'Runaway Scholar', attrs: { wit: 3 }, silver: 90, items: ['gift_book', 'c_bun'], techs: ['t_univ_1'],
desc: 'You memorized the classics, then ran off to live in one.' },
hunter: { name: 'Hunter\u2019s Child', attrs: { agi: 2, str: 1 }, silver: 60, items: ['w_blade_1', 'mat_pelt', 'mat_pelt'], techs: ['t_blade_1', 't_univ_1'],
desc: 'You gutted your first boar at nine.' },
orphan: { name: 'Street Orphan', attrs: { agi: 2, luk: 2 }, silver: 45, items: ['w_hidden_1', 'c_bun'], techs: ['t_hidden_1', 't_univ_1'],
desc: 'The streets fed you table scraps and knife skills alike.' },
foundling: { name: 'Temple Foundling', attrs: { con: 2, wit: 1 }, silver: 20, items: ['w_staff_1', 'c_pill_hp'], techs: ['t_staff_1', 't_univ_1'],
desc: 'Left at the temple gate with a staff and a name tag. Both served you well.' }
};
const ORIGIN_IDS = Object.keys(ORIGINS);
/* ---------------- RECIPES ---------------- */
const SMITH_UPGRADES = {
w_sword_1: { to: 'w_sword_2', silver: 120, mats: { mat_ore_1: 2 } },
w_sword_2: { to: 'w_sword_3', silver: 450, mats: { mat_ore_2: 2 } },
w_sword_3: { to: 'w_sword_4', silver: 1400, mats: { mat_ore_3: 1, mat_ore_2: 2 } },
w_blade_1: { to: 'w_blade_2', silver: 120, mats: { mat_ore_1: 2 } },
w_blade_2: { to: 'w_blade_3', silver: 450, mats: { mat_ore_2: 2 } },
w_blade_3: { to: 'w_blade_4', silver: 1400, mats: { mat_ore_3: 1, mat_ore_2: 2 } },
w_spear_1: { to: 'w_spear_2', silver: 120, mats: { mat_ore_1: 2 } },
w_spear_2: { to: 'w_spear_3', silver: 450, mats: { mat_ore_2: 2 } },
w_spear_3: { to: 'w_spear_4', silver: 1400, mats: { mat_ore_3: 1, mat_ore_2: 2 } },
w_staff_1: { to: 'w_staff_2', silver: 110, mats: { mat_ore_1: 2 } },
w_staff_2: { to: 'w_staff_3', silver: 430, mats: { mat_ore_2: 2 } },
w_staff_3: { to: 'w_staff_4', silver: 1350, mats: { mat_ore_3: 1, mat_ore_2: 2 } },
w_fist_1: { to: 'w_fist_2', silver: 110, mats: { mat_ore_1: 2 } },
w_fist_2: { to: 'w_fist_3', silver: 430, mats: { mat_ore_2: 2 } },
w_fist_3: { to: 'w_fist_4', silver: 1350, mats: { mat_ore_3: 1, mat_ore_2: 2 } },
w_hidden_1: { to: 'w_hidden_2', silver: 110, mats: { mat_ore_1: 2 } },
w_hidden_2: { to: 'w_hidden_3', silver: 430, mats: { mat_ore_2: 2 } },
w_hidden_3: { to: 'w_hidden_4', silver: 1350, mats: { mat_ore_3: 1, mat_ore_2: 2 } },
ar_body_1: { to: 'ar_body_2', silver: 90, mats: { mat_ore_1: 2 } },
ar_body_2: { to: 'ar_body_3', silver: 300, mats: { mat_ore_2: 2 } },
ar_body_3: { to: 'ar_body_4', silver: 900, mats: { mat_ore_3: 1, mat_ore_2: 2 } },
ar_head_1: { to: 'ar_head_2', silver: 70, mats: { mat_ore_1: 1 } },
ar_head_2: { to: 'ar_head_3', silver: 240, mats: { mat_ore_2: 1 } },
ar_head_3: { to: 'ar_head_4', silver: 750, mats: { mat_ore_3: 1 } },
ar_foot_1: { to: 'ar_foot_2', silver: 60, mats: { mat_pelt: 2 } },
ar_foot_2: { to: 'ar_foot_3', silver: 200, mats: { mat_ore_1: 1, mat_pelt: 1 } },
ar_foot_3: { to: 'ar_foot_4', silver: 650, mats: { mat_ore_2: 1, mat_pelt: 2 } }
};
const ALCHEMY_RECIPES = [
{ id: 'r_hp', name: 'Healing Pill ×2', out: 'c_pill_hp', qty: 2, mats: { c_herb_red: 2 }, silver: 15, needFlag: null },
{ id: 'r_mp', name: 'Clear-Mind Pill ×2', out: 'c_pill_mp', qty: 2, mats: { c_lotus: 1, c_herb_green: 1 }, silver: 15, needFlag: null },
{ id: 'r_anti', name: 'Antidote Powder ×2', out: 'c_antidote', qty: 2, mats: { c_herb_green: 2 }, silver: 10, needFlag: null },
{ id: 'r_pow', name: 'Battle Elixir', out: 'c_elixir_power', qty: 1, mats: { mat_gall: 1, c_herb_red: 2 }, silver: 40, needFlag: 'knowsAlchemy' },
{ id: 'r_swi', name: 'Swift Elixir', out: 'c_elixir_swift', qty: 1, mats: { c_lotus: 1, mat_fang: 1 }, silver: 40, needFlag: 'knowsAlchemy' },
{ id: 'r_ven', name: 'Coat of Venom', out: 'c_venom', qty: 1, mats: { mat_gall: 2 }, silver: 30, needFlag: 'knowsAlchemy' },
{ id: 'r_ton', name: 'Vital Tonic', out: 'c_tonic', qty: 1, mats: { c_lotus: 2, mat_gall: 1 }, silver: 80, needFlag: 'knowsAlchemy' }
];
/* ---------------- TOURNAMENT ---------------- */
ENEMIES['e_champ_camellia'] = Object.assign({}, ENEMIES.e_bandit_vet, {
id: 'e_champ_camellia', name: 'Madame Camellia', tier: 3, hp: 150, atk: 22, def: 10, spd: 12, silver: [80, 130], exp: 130,
moves: [
{ n: 'Silk Whip Combo', mp: 12, p: 96, r: 1, sh: 'foe', hits: 2 },
{ n: 'Camellia Stance', mp: 12, p: 0, r: 0, sh: 'self', buff: { stat: 'spd', pct: 0.3, dur: 2 } },
{ n: 'Petal Storm Kick', mp: 16, p: 150, r: 1, sh: 'cross' }
]
});
const TOURNEY_LADDER = [
{ name: '"Brickwall" Luo', base: 'e_thug' },
{ name: 'Iron Sash Wei', base: 'e_bandit_vet' },
{ name: 'Madame Camellia', base: 'e_champ_camellia' },
{ name: 'Blade Saint Yun-Fei', base: 'e_duelist' }
];
/* ---------------- BOUNTY POOLS ---------------- */
const BOUNTY_POOLS = {
1: ['e_wolf', 'e_boar', 'e_snake', 'e_bandit', 'e_thug'],
2: ['e_tiger', 'e_bandit_vet', 'e_bandit_chief', 'e_guard_deserter_placeholder'],
3: ['e_assassin', 'e_poisoner', 'e_bear']
};
ENEMIES['e_deserter'] = Object.assign({}, ENEMIES.e_bandit_vet, {
id: 'e_deserter', name: 'Runaway Soldier', tier: 2, def: 8,
moves: [{ n: 'Saber Drill', mp: 8, p: 138, r: 1, sh: 'foe' }, { n: 'Braced Guard', mp: 10, p: 0, r: 0, sh: 'self', shield: 35 }]
});
BOUNTY_POOLS[2] = ['e_tiger', 'e_bandit_vet', 'e_bandit_chief', 'e_deserter'];
/* ---------------- TEMPLE TRIAL QUEST ---------------- */
QUESTS['q_trial_fl'] = {
name: 'Sweeping the Courtyard',
stages: [
'Prove patience: meditate once in the temple hall, then spar with Monk Jing.',
'Report to Abbot Lian.'
],
doneText: 'The Pure Lotus Temple opens its gates; the broom, however, remains yours.'
};
/* ---------------- ACHIEVEMENTS ---------------- */
const ACHIEVEMENTS = {
first_blood: { name: 'First Blood', desc: 'Win your first battle.' },
ridge_guardian:{ name: 'Ridge Guardian', desc: 'Complete "Wolf Trouble".' },
champion: { name: 'Ring Champion', desc: 'Win the Qingyun tournament.' },
hong_heir: { name: 'Hong\u2019s Heir', desc: 'Learn the Ten Thousand Rivers Palms.' },
sun_dawn: { name: 'Blazing Dawn', desc: 'Cultivate the lost Blazing Sun Manual.' },
keeper_truth: { name: 'Keeper of Truth', desc: 'Claim the Heaven\u2019s Ledger.' },
fat_purse: { name: 'Heavy Purse', desc: 'Hold 2,000 silver at once.' },
journeyman: { name: 'Journeyman', desc: 'Reach level 10.' },
master_qi: { name: 'Master of Qi', desc: 'Reach level 20.' },
band_three: { name: 'Band of Three', desc: 'Travel with three companions.' },
two_rivers: { name: 'Two Rivers, One Heart', desc: 'Find romance on the road.' },
after_dark: { name: 'After-Dark Customer',desc: 'Set foot in the Ghost Market.' },
water_patience:{ name: 'Patience of Water', desc: 'Catch 25 fish in a lifetime.' },
umbrellas_fall:{ name: 'Umbrellas Fold', desc: 'Finish the main story.' }
};
/* ---------------- BESTIARY LORE ---------------- */
const BEAST_LORE = {
e_wolf: 'Grey pack-hunters that grow bold whenever granaries do.',
e_boar: 'All shoulder and temper; farmers tell stories, fences tell more.',
e_snake: 'Green as spring bamboo, twice as patient.',
e_tiger: 'The Cloudmist stripe is prized by poets and avoided by everyone else.',
e_bear: 'It owns the berry slopes. You are renting.',
e_bandit: 'A knife, a grudge, and poor arithmetic.',
e_bandit_vet: 'Survived enough ambushes to run one properly.',
e_bandit_chief: 'Promoted by attrition \u2014 the men above him kept dying.',
e_thug: 'Collects debts for people who dislike paperwork.',
e_guard: 'Garrison drilled, halberd regulation, patience limited.',
e_assassin: 'An umbrella\u2019s shadow, sharpened.',
e_cultist: 'Sworn to silver paper oaths they cannot show their families.',
e_poisoner: 'Expelled from the Valley for excessive enthusiasm.',
e_duelist: 'Walks from town to town collecting styles and scars.',
e_sentinel: 'Carved to guard, carved to last, carved to kill.',
e_boss_qiang: 'Lost an eye to a magistrate\u2019s chain; repaid the ledger in lead.',
e_boss_dukang: 'Silk manners, silver umbrella, no refunds.',
e_boss_heihu: 'The Patriarch\u2019s enforcer. The umbrella never opens twice.',
e_boss_wu: 'Built the Iron Umbrella Society the way rivers build canyons.',
e_deserter: 'Kept the training, misplaced the flag.',
e_champ_camellia: 'Retired opera dancer; the kicks stayed.'
};
/* tier-V ultimates & support arts — masters' final teachings */
NPCS.n_hunter_ren.teach.push({ tech: 't_blade_5', aff: 75, cost: 2400 });
NPCS.n_master_yun.teach.push({ tech: 't_sword_5', aff: 80, cost: 2600 });
NPCS.n_abbot_lian.teach.push({ tech: 't_staff_5', aff: 80, cost: 2600 }, { tech: 't_univ_2', aff: 45, cost: 900 }, { tech: 't_univ_3', aff: 60, cost: 1200 });
NPCS.n_master_guo.teach.push({ tech: 't_fist_5', aff: 80, cost: 2600 });
NPCS.n_lady_miao.teach.push({ tech: 't_hidden_5', aff: 78, cost: 2500 });
NPCS.n_drill_capt.teach = [{ tech: 't_spear_5', aff: 70, cost: 2400 }];
/* richer shop stocks (late-game reach) */
NPCS.n_fence_wu.shop.stock.push('m_t_sword_5', 'm_t_blade_5', 'm_t_spear_5', 'm_t_staff_5', 'm_t_fist_5', 'm_t_hidden_5', 'm_univ_2', 'm_univ_3', 'ar_head_4', 'ar_body_4', 'ar_foot_4', 'ac_eye');
NPCS.n_smith_wang.shop.stock.push('ar_head_3');
NPCS.n_merchant_su.shop.stock.push('ar_foot_2');
/* ---------------- SIDE JOB QUESTS (job board) ---------------- */
Object.assign(QUESTS, {
q_herb_bai: { name: 'Bitter Roots, Kind Hearts', stages: ['Gather 5 Red Herb (herb spots in the wilds).', 'Deliver them at the job board.'],
doneText: 'Bai\u2019s shelves are full again; your pockets are, too.' },
q_ring_reeds: { name: 'The Ring in the Reeds', stages: ['Widow Chen\u2019s ring went down with a serpent\u2019s dinner. Cull 4 valley snakes.', 'Deliver the news at the job board.'],
doneText: 'The ring was in the third belly. The fourth was personal.' },
q_forge_coal: { name: 'Fuel for the Forge', stages: ['Prospect ore twice at Cloudmist Ridge.', 'Report to the job board.'],
doneText: 'Wang\u2019s forge roars for a week. He names an anvil after you.' },
q_night_watch: { name: 'Night Watch', stages: ['Cull 3 bandits on the roads.', 'Collect your wage at the job board.'],
doneText: 'The pass is quieter. Pei pretends not to be impressed.' },
q_alms_lotus: { name: 'Alms for the Lotus', stages: ['Donate 300 silver to the temple fund.', "Receive the abbot's blessing at the job board."],
doneText: 'Three hundred silver, one quiet mind. Fair trade.' },
q_lantern_dead: { name: 'Lanterns for the Dead', stages: ['Bring 2 Mulled Wine and 1 Lotus Herb for the river rite.', 'Deliver them at the job board.'],
doneText: 'Two lanterns downstream, one old song, no ghosts.' }
});