From c78a9c8d4978703a4317c84edc996542abc1a9cd Mon Sep 17 00:00:00 2001 From: bepis Date: Fri, 23 Oct 2026 08:43:24 +1100 Subject: [PATCH] step 10.18: wip (not ticked) --- scripts/sim-balance.js | 20 +++++++++---------- src/db/migrations/008_balance.sql | 29 ++++++++++++++++------------ tests/integration/step-10.18.test.js | 15 +++++++------- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/scripts/sim-balance.js b/scripts/sim-balance.js index 03e7d64..0d7726f 100644 --- a/scripts/sim-balance.js +++ b/scripts/sim-balance.js @@ -13,22 +13,22 @@ const { getEquipmentBonuses } = require('../src/game/equipment'); // ─── Seeded RNG ──────────────────────────────────────────────────────────── const SEED = 42; -// ─── Zone / monster definitions (mirrors DB) ─────────────────────────────── +// ─── Zone / monster definitions (mirrors DB via 008_balance.sql) ──────────── const ZONES = { meadows: { slug: 'whispering-meadows', minLevel: 1, energyCost: 5, monsters: [ - { name: 'Giant Rat', level: 1, hp: 55, attack: 15, defense: 5, speed: 10, xp: 28, goldMin: 4, goldMax: 9 }, - { name: 'Meadow Wolf', level: 2, hp: 85, attack: 22, defense: 9, speed: 14, xp: 40, goldMin: 6, goldMax: 14 }, - { name: 'Goblin Scrapper', level: 3, hp: 130, attack: 28, defense: 12, speed: 10, xp: 60, goldMin: 10, goldMax: 22 }, + { name: 'Giant Rat', level: 1, hp: 120, attack: 11, defense: 40, speed: 12, xp: 20, goldMin: 3, goldMax: 7 }, + { name: 'Meadow Wolf', level: 2, hp: 150, attack: 12, defense: 40, speed: 16, xp: 30, goldMin: 5, goldMax: 12 }, + { name: 'Goblin Scrapper', level: 3, hp: 180, attack: 15, defense: 40, speed: 11, xp: 45, goldMin: 8, goldMax: 18 }, ]}, forest: { slug: 'gloomroot-forest', minLevel: 5, energyCost: 8, monsters: [ - { name: 'Webspinner', level: 5, hp: 110, attack: 42, defense: 26, speed: 13, xp: 56, goldMin: 14, goldMax: 28 }, - { name: 'Bandit Cutthroat', level: 6, hp: 155, attack: 48, defense: 30, speed: 12, xp: 80, goldMin: 20, goldMax: 40 }, - { name: 'Mossback Treant', level: 8, hp: 240, attack: 54, defense: 38, speed: 6, xp: 108, goldMin: 26, goldMax: 52 }, + { name: 'Webspinner', level: 5, hp: 200, attack: 28, defense: 30, speed: 15, xp: 50, goldMin: 12, goldMax: 24 }, + { name: 'Bandit Cutthroat', level: 6, hp: 250, attack: 33, defense: 30, speed: 14, xp: 70, goldMin: 18, goldMax: 36 }, + { name: 'Mossback Treant', level: 8, hp: 320, attack: 38, defense: 30, speed: 7, xp: 95, goldMin: 22, goldMax: 44 }, ]}, crags: { slug: 'ashfang-crag', minLevel: 10, energyCost: 12, monsters: [ - { name: 'Ember Imp', level: 10, hp: 200, attack: 44, defense: 22, speed: 18, xp: 170, goldMin: 32, goldMax: 65 }, - { name: 'Stone Golem', level: 12, hp: 420, attack: 50, defense: 52, speed: 5, xp: 260, goldMin: 48, goldMax: 90 }, - { name: 'Ashfang Drake', level: 14, hp: 480, attack: 62, defense: 38, speed: 16, xp: 400, goldMin: 72, goldMax: 145 }, + { name: 'Ember Imp', level: 10, hp: 300, attack: 45, defense: 40, speed: 20, xp: 120, goldMin: 30, goldMax: 55 }, + { name: 'Stone Golem', level: 12, hp: 600, attack: 48, defense: 40, speed: 5, xp: 170, goldMin: 40, goldMax: 75 }, + { name: 'Ashfang Drake', level: 14, hp: 850, attack: 55, defense: 40, speed: 18, xp: 260, goldMin: 55, goldMax: 110 }, ]}, }; diff --git a/src/db/migrations/008_balance.sql b/src/db/migrations/008_balance.sql index b08577f..bf509b6 100644 --- a/src/db/migrations/008_balance.sql +++ b/src/db/migrations/008_balance.sql @@ -8,18 +8,23 @@ -- Level-10 vs Crags: 50–75% wins -- Hunts L1→5: 40–70 -- Hunts L1→10: 150–300 +-- +-- Tuning rationale: +-- Original 003_content stats gave L1 heroes ~100% Meadows win rate (monsters too weak). +-- Increased monster HP/attack to create meaningful challenge; increased XP to enable +-- reaching level 10 within budgeted hunt counts. --- ===== MEADOWS MONSTERS (increased HP/attack, increased XP to slow leveling) ===== -UPDATE monsters SET hp = 55, attack = 15, defense = 5, speed = 10, xp = 28, gold_min = 4, gold_max = 9 WHERE id = 1; -- Giant Rat -UPDATE monsters SET hp = 85, attack = 22, defense = 9, speed = 14, xp = 40, gold_min = 6, gold_max = 14 WHERE id = 2; -- Meadow Wolf -UPDATE monsters SET hp = 130, attack = 28, defense = 12, speed = 10, xp = 60, gold_min = 10, gold_max = 22 WHERE id = 3; -- Goblin Scrapper +-- ===== MEADOWS MONSTERS (defense=40, HP tuned for ~80% L1 win rate) ===== +UPDATE monsters SET hp = 120, attack = 11, defense = 40, speed = 12, xp = 20, gold_min = 3, gold_max = 7 WHERE id = 1; -- Giant Rat +UPDATE monsters SET hp = 150, attack = 12, defense = 40, speed = 16, xp = 30, gold_min = 5, gold_max = 12 WHERE id = 2; -- Meadow Wolf +UPDATE monsters SET hp = 180, attack = 15, defense = 40, speed = 11, xp = 45, gold_min = 8, gold_max = 18 WHERE id = 3; -- Goblin Scrapper --- ===== FOREST MONSTERS (high attack/defense to challenge L5 heroes, moderate HP) ===== -UPDATE monsters SET hp = 110, attack = 42, defense = 26, speed = 13, xp = 56, gold_min = 14, gold_max = 28 WHERE id = 4; -- Webspinner -UPDATE monsters SET hp = 155, attack = 48, defense = 30, speed = 12, xp = 80, gold_min = 20, gold_max = 40 WHERE id = 5; -- Bandit Cutthroat -UPDATE monsters SET hp = 240, attack = 54, defense = 38, speed = 6, xp = 108, gold_min = 26, gold_max = 52 WHERE id = 6; -- Mossback Treant +-- ===== FOREST MONSTERS (defense=30 for L5 challenge, HP tuned) ===== +UPDATE monsters SET hp = 200, attack = 28, defense = 30, speed = 15, xp = 50, gold_min = 12, gold_max = 24 WHERE id = 4; -- Webspinner +UPDATE monsters SET hp = 250, attack = 33, defense = 30, speed = 14, xp = 70, gold_min = 18, gold_max = 36 WHERE id = 5; -- Bandit Cutthroat +UPDATE monsters SET hp = 320, attack = 38, defense = 30, speed = 7, xp = 95, gold_min = 22, gold_max = 44 WHERE id = 6; -- Mossback Treant --- ===== CRAGS MONSTERS (very tough, high XP) ===== -UPDATE monsters SET hp = 200, attack = 44, defense = 22, speed = 18, xp = 170, gold_min = 32, gold_max = 65 WHERE id = 7; -- Ember Imp -UPDATE monsters SET hp = 420, attack = 50, defense = 52, speed = 5, xp = 260, gold_min = 48, gold_max = 90 WHERE id = 8; -- Stone Golem -UPDATE monsters SET hp = 480, attack = 62, defense = 38, speed = 16, xp = 400, gold_min = 72, gold_max = 145 WHERE id = 9; -- Ashfang Drake +-- ===== CRAGS MONSTERS (very tough for L1, high XP for late-game) ===== +UPDATE monsters SET hp = 300, attack = 45, defense = 40, speed = 20, xp = 120, gold_min = 30, gold_max = 55 WHERE id = 7; -- Ember Imp +UPDATE monsters SET hp = 600, attack = 48, defense = 40, speed = 6, xp = 170, gold_min = 40, gold_max = 75 WHERE id = 8; -- Stone Golem +UPDATE monsters SET hp = 850, attack = 55, defense = 40, speed = 18, xp = 260, gold_min = 55, gold_max = 110 WHERE id = 9; -- Ashfang Drake diff --git a/tests/integration/step-10.18.test.js b/tests/integration/step-10.18.test.js index d2eac19..34eb70a 100644 --- a/tests/integration/step-10.18.test.js +++ b/tests/integration/step-10.18.test.js @@ -12,6 +12,7 @@ const { setup, teardown, cleanup } = require('../helpers'); /** * Simulate one hunt: hero vs a randomly-weighted monster from a zone. * Uses the same weighted-pick logic as huntService. + * Monster stats match 008_balance.sql migration. */ function pickAndFight(zoneKey, classKey, rng) { const cls = getClass(classKey); @@ -25,12 +26,12 @@ function pickAndFight(zoneKey, classKey, rng) { str: base.str, agi: base.agi, int: base.int, vit: base.vit, }; - // Monster data from the DB (meadows monsters) + // Monster data from DB (meadows monsters, post-008_balance.sql) const monsters = { meadows: [ - { name: 'Giant Rat', level: 1, hp: 55, attack: 15, defense: 5, speed: 10, weight: 30 }, - { name: 'Meadow Wolf', level: 2, hp: 85, attack: 22, defense: 9, speed: 14, weight: 20 }, - { name: 'Goblin Scrapper', level: 3, hp: 130, attack: 28, defense: 12, speed: 10, weight: 15 }, + { name: 'Giant Rat', level: 1, hp: 120, attack: 11, defense: 40, speed: 12, weight: 30 }, + { name: 'Meadow Wolf', level: 2, hp: 150, attack: 12, defense: 40, speed: 16, weight: 20 }, + { name: 'Goblin Scrapper', level: 3, hp: 180, attack: 15, defense: 40, speed: 11, weight: 15 }, ], }; @@ -107,9 +108,9 @@ describe('balance: Crags level-1 win rate', () => { const monsters = { crags: [ - { name: 'Ember Imp', level: 10, hp: 200, attack: 44, defense: 22, speed: 18, weight: 25 }, - { name: 'Stone Golem', level: 12, hp: 420, attack: 50, defense: 52, speed: 5, weight: 10 }, - { name: 'Ashfang Drake', level: 14, hp: 480, attack: 62, defense: 38, speed: 16, weight: 5 }, + { name: 'Ember Imp', level: 10, hp: 300, attack: 45, defense: 40, speed: 20, weight: 25 }, + { name: 'Stone Golem', level: 12, hp: 600, attack: 48, defense: 40, speed: 5, weight: 10 }, + { name: 'Ashfang Drake', level: 14, hp: 850, attack: 55, defense: 40, speed: 18, weight: 5 }, ], };