# BALANCE.md — Formulas & Starter Numbers All numbers below go in `src/game/constants.js`. Tune there, not inline. ## Energy ``` ENERGY_MAX = 100 ENERGY_REGEN_SECONDS = 180 // +1 per 3 min ENERGY_TONIC_RESTORE = 25 ``` ``` computeEnergy(stored, updatedAtMs, nowMs): if nowMs <= updatedAtMs: return {energy: stored, updatedAtMs} gained = floor((nowMs - updatedAtMs) / (REGEN_SECONDS*1000)) if stored + gained >= MAX: return {energy: MAX, updatedAtMs: nowMs} return {energy: stored + gained, updatedAtMs: updatedAtMs + gained*REGEN_SECONDS*1000} ``` (Keep leftover partial interval by advancing the timestamp only by whole ticks.) ## Leveling ``` xpToNext(level) = floor(100 * level^1.5) // L1→2: 100, L2→3: 282, L5→6: 1118, L10→11: 3162 MAX_LEVEL = 50 STAT_POINTS_PER_LEVEL = 3 ``` On level-up: `hp_current = maxHp`, loop to handle multiple level-ups from one reward. ## Derived stats ``` maxHp = 50 + vit*10 + level*5 + itemBonusVit*10 primary = STR | INT | AGI (by class) attack = 5 + primary*2 + level + equipment.bonus_attack defense = floor(vit*1.5) + equipment.bonus_defense (+10% if Warrior) speed = 10 + agi critChance% = min(40, 5 + floor(agi*0.5)) (+8 if Ranger) critMult = 1.5 ``` Equipment `bonus_str/agi/int/vit` are added to the base stats BEFORE the derived formulas. ## Damage ``` mitigation = 100 / (100 + defenderDefense) raw = attackerAttack * mitigation variance = rng.range(0.9, 1.1) dmg = max(1, round(raw * variance * (crit ? critMult : 1))) ``` Mage bonus: if defenderDefense >= 15, multiply `raw` by 1.15. Monsters crit at a flat 5%. ## Rewards ``` xp = monster.xp * levelDiffMult gold = rng.int(monster.gold_min, monster.gold_max) * levelDiffMult levelDiffMult = clamp(1 + 0.1*(monster.level - hero.level), 0.2, 1.5) ``` Loot: for each row in `loot_table` for that monster, roll `rng.float()*100 < chance_pct`. Max 2 distinct loot drops per fight. ## Defeat penalty `goldLost = floor(gold * 0.10)`; `hp_current = 1`; `deaths += 1`. ## Rest `restCost = level * 5` gold → heals to full. Free if hp already full is rejected (`NOTHING_TO_HEAL`). ## Starter monsters (use or tweak) | Zone | Name | Lv | HP | Atk | Def | Spd | XP | Gold | |---|---|---|---|---|---|---|---|---| | Meadows | Giant Rat | 1 | 20 | 6 | 1 | 12 | 8 | 1–3 | | Meadows | Meadow Wolf | 2 | 32 | 9 | 3 | 16 | 14 | 2–5 | | Meadows | Goblin Scrapper | 3 | 45 | 12 | 5 | 11 | 22 | 4–9 | | Forest | Webspinner | 5 | 70 | 18 | 8 | 15 | 40 | 8–16 | | Forest | Bandit Cutthroat | 6 | 90 | 22 | 12 | 14 | 55 | 12–24 | | Forest | Mossback Treant | 8 | 150 | 26 | 22 | 7 | 85 | 15–30 | | Crags | Ember Imp | 10 | 130 | 34 | 15 | 20 | 120 | 25–45 | | Crags | Stone Golem | 12 | 260 | 38 | 40 | 6 | 170 | 30–60 | | Crags | Ashfang Drake | 14 | 300 | 50 | 30 | 18 | 260 | 50–100 | ## Starter items (≥ 20 required; this is a minimum seed list) | Item | Type | Rarity | Lv | Buy | Bonus | |---|---|---|---|---|---| | Rusty Sword | weapon | common | 1 | 20 | +3 atk | | Apprentice Staff | weapon | common | 1 | 20 | +2 int, +1 atk | | Hunter's Shortbow | weapon | common | 1 | 20 | +2 agi, +1 atk | | Iron Blade | weapon | uncommon | 5 | 120 | +8 atk, +2 str | | Oakwood Staff | weapon | uncommon | 5 | 120 | +6 atk, +3 int | | Yew Longbow | weapon | uncommon | 5 | 120 | +6 atk, +3 agi | | Emberforged Greatsword | weapon | rare | 10 | 600 | +18 atk, +4 str | | Leather Jerkin | armor | common | 1 | 25 | +3 def | | Chainmail Vest | armor | uncommon | 5 | 140 | +9 def, +2 vit | | Drake-scale Armor | armor | rare | 12 | 700 | +22 def, +4 vit | | Wooden Charm | trinket | common | 1 | 30 | +1 vit | | Wolf-fang Pendant | trinket | uncommon | 3 | 90 | +2 agi | | Ember Ring | trinket | rare | 10 | 450 | +3 str,+3 int | | Minor Healing Potion | consumable | common | 1 | 15 | effect heal:50 | | Greater Healing Potion | consumable | uncommon | 8 | 60 | effect heal:150 | | Energy Tonic | consumable | uncommon | 1 | 80 | effect energy:25 | | Rat Tail | material | common | 1 | 0 | sell 2g | | Wolf Pelt | material | common | 2 | 0 | sell 5g | | Spider Silk | material | uncommon | 5 | 0 | sell 12g | | Imp Horn | material | uncommon | 10 | 0 | sell 30g | | Drake Scale | material | rare | 14 | 0 | sell 90g | Materials with `buy_price = 0` sell at: common 2×level, uncommon 4×level, rare 8×level (round down, min 1). ## Starter loot chances Common material from its zone's weakest monsters: 40%. Uncommon gear drops: 3–5%. Rare gear drops: 0.5–1% from top-tier zone monsters. Healing potion: 8% anywhere. ## Expedition starters | Name | Min Lv | Duration | Energy | XP | Gold | |---|---|---|---|---|---| | Scout the Old Road | 1 | 10 min | 10 | 40 | 10–25 | | Raid the Bandit Camp | 5 | 1 h | 25 | 300 | 80–160 | | Delve the Hollow | 10 | 4 h | 40 | 1400 | 300–600 | (Use short durations such as 20–60 s via an env flag `DEV_FAST_TIMERS=1` for testing.)