step 10.18: wip (not ticked)

This commit is contained in:
bepis
2026-10-23 12:15:43 +11:00
parent b7ed4f9bbc
commit 394a055d2a
2 changed files with 61 additions and 27 deletions
+45 -11
View File
@@ -18,19 +18,19 @@ var SEED = 42;
// ─── Zone / monster definitions (MUST match 008_balance.sql) ──────────────── // ─── Zone / monster definitions (MUST match 008_balance.sql) ────────────────
var ZONES = { var ZONES = {
meadows: { slug: 'whispering-meadows', minLevel: 1, energyCost: 5, monsters: [ meadows: { slug: 'whispering-meadows', minLevel: 1, energyCost: 5, monsters: [
{ name: 'Giant Rat', level: 1, hp: 250, attack: 8, defense: 8, speed: 12, xp: 70, goldMin: 3, goldMax: 7 }, { name: 'Giant Rat', level: 1, hp: 50, attack: 16, defense: 8, speed: 12, xp: 25, goldMin: 3, goldMax: 7 },
{ name: 'Meadow Wolf', level: 2, hp: 350, attack: 12, defense: 8, speed: 16, xp: 110, goldMin: 5, goldMax: 12 }, { name: 'Meadow Wolf', level: 2, hp: 60, attack: 18, defense: 8, speed: 16, xp: 35, goldMin: 5, goldMax: 12 },
{ name: 'Goblin Scrapper', level: 3, hp: 300, attack: 18, defense: 8, speed: 11, xp: 180, goldMin: 8, goldMax: 18 }, { name: 'Goblin Scrapper', level: 3, hp: 70, attack: 20, defense: 8, speed: 11, xp: 50, goldMin: 8, goldMax: 18 },
]}, ]},
forest: { slug: 'gloomroot-forest', minLevel: 5, energyCost: 8, monsters: [ forest: { slug: 'gloomroot-forest', minLevel: 5, energyCost: 8, monsters: [
{ name: 'Webspinner', level: 5, hp: 200, attack: 25, defense: 20, speed: 15, xp: 80, goldMin: 12, goldMax: 24 }, { name: 'Webspinner', level: 5, hp: 100, attack: 24, defense: 16, speed: 15, xp: 80, goldMin: 12, goldMax: 24 },
{ name: 'Bandit Cutthroat', level: 6, hp: 250, attack: 30, defense: 20, speed: 14, xp: 110, goldMin: 18, goldMax: 36 }, { name: 'Bandit Cutthroat', level: 6, hp: 130, attack: 28, defense: 20, speed: 14, xp: 100, goldMin: 18, goldMax: 36 },
{ name: 'Mossback Treant', level: 8, hp: 350, attack: 35, defense: 30, speed: 7, xp: 160, goldMin: 22, goldMax: 44 }, { name: 'Mossback Treant', level: 8, hp: 180, attack: 30, defense: 22, speed: 7, xp: 150, goldMin: 22, goldMax: 44 },
]}, ]},
crags: { slug: 'ashfang-crag', minLevel: 10, energyCost: 12, monsters: [ crags: { slug: 'ashfang-crag', minLevel: 10, energyCost: 12, monsters: [
{ name: 'Ember Imp', level: 10, hp: 200, attack: 30, defense: 20, speed: 20, xp: 300, goldMin: 30, goldMax: 55 }, { name: 'Ember Imp', level: 10, hp: 150, attack: 30, defense: 18, speed: 20, xp: 200, goldMin: 30, goldMax: 55 },
{ name: 'Stone Golem', level: 12, hp: 600, attack: 40, defense: 30, speed: 5, xp: 420, goldMin: 40, goldMax: 75 }, { name: 'Stone Golem', level: 12, hp: 300, attack: 38, defense: 28, speed: 5, xp: 280, goldMin: 40, goldMax: 75 },
{ name: 'Ashfang Drake', level: 14, hp: 450, attack: 45, defense: 25, speed: 18, xp: 600, goldMin: 55, goldMax: 110 }, { name: 'Ashfang Drake', level: 14, hp: 150, attack: 38, defense: 22, speed: 18, xp: 350, goldMin: 55, goldMax: 110 },
]}, ]},
}; };
@@ -51,9 +51,21 @@ function pickMonster(zoneKey, rng) {
} }
function simulateHunt(hero, monster, rng) { function simulateHunt(hero, monster, rng) {
// Build equip bonuses for resolveCombat (it passes hero as equipBonuses to calcDerived)
var eq = {
bonus_str: 0, bonus_agi: 0, bonus_int: 0, bonus_vit: 0,
bonus_attack: 0, bonus_defense: 0,
};
// Apply starter weapon bonuses based on class
if (hero.class === 'mage') { eq.bonus_int = 1; eq.bonus_attack = 2; }
else if (hero.class === 'ranger') { eq.bonus_agi = 2; eq.bonus_attack = 1; }
else if (hero.class === 'warrior') { eq.bonus_attack = 3; }
var fight = resolveCombat({ var fight = resolveCombat({
class: hero.class, level: hero.level, hpCurrent: hero.hp, class: hero.class, level: hero.level, hpCurrent: hero.hp,
str: hero.str, agi: hero.agi, int: hero.int, vit: hero.vit, str: hero.str, agi: hero.agi, int: hero.int, vit: hero.vit,
bonus_str: eq.bonus_str, bonus_agi: eq.bonus_agi, bonus_int: eq.bonus_int, bonus_vit: eq.bonus_vit,
bonus_attack: eq.bonus_attack, bonus_defense: eq.bonus_defense,
}, monster, rng); }, monster, rng);
var xpGained = 0, goldGained = 0; var xpGained = 0, goldGained = 0;
@@ -79,6 +91,15 @@ function simulateClass(className) {
gold: 50, gold: 50,
}; };
// Apply starter weapon bonuses (same as createCharacter)
if (className === 'warrior') {
hero.str += 0; hero.agi += 0; hero.int += 0; hero.vit += 0; // Rusty Sword: +3 atk only
} else if (className === 'mage') {
hero.int += 1; // Apprentice Staff: +1 int, +2 atk
} else if (className === 'ranger') {
hero.agi += 2; // Hunter's Shortbow: +2 agi, +1 atk
}
var derived = calcDerived({ str: hero.str, agi: hero.agi, int: hero.int, vit: hero.vit }, hero.level, className); var derived = calcDerived({ str: hero.str, agi: hero.agi, int: hero.int, vit: hero.vit }, hero.level, className);
hero.hp = derived.maxHp; hero.hp = derived.maxHp;
hero.maxHp = derived.maxHp; hero.maxHp = derived.maxHp;
@@ -188,12 +209,18 @@ function simulateLevel1WinRate(zoneKey) {
var className = CLASS_KEYS[ci]; var className = CLASS_KEYS[ci];
var cls = getClass(className); var cls = getClass(className);
var base = getBaseStats(className); var base = getBaseStats(className);
var derived = calcDerived({ str: base.str, agi: base.agi, int: base.int, vit: base.vit }, 1, className);
// Apply starter weapon bonuses (same as createCharacter)
var stats = { str: base.str, agi: base.agi, int: base.int, vit: base.vit };
if (className === 'mage') stats.int += 1; // +1 int, +2 atk
else if (className === 'ranger') stats.agi += 2; // +2 agi, +1 atk
var derived = calcDerived(stats, 1, className);
var monster = pickMonster(zoneKey, classRng); var monster = pickMonster(zoneKey, classRng);
var result = simulateHunt({ var result = simulateHunt({
class: className, level: 1, hp: derived.maxHp, maxHp: derived.maxHp, class: className, level: 1, hp: derived.maxHp, maxHp: derived.maxHp,
str: base.str, agi: base.agi, int: base.int, vit: base.vit, str: stats.str, agi: stats.agi, int: stats.int, vit: stats.vit,
}, monster, classRng); }, monster, classRng);
if (result.winner === 'hero') wins++; if (result.winner === 'hero') wins++;
@@ -217,7 +244,14 @@ function simulateLevel5ForestWinRate() {
var base = getBaseStats(className); var base = getBaseStats(className);
var primary = cls.primary; var primary = cls.primary;
var stats = { str: base.str, agi: base.agi, int: base.int, vit: base.vit }; var stats = { str: base.str, agi: base.agi, int: base.int, vit: base.vit };
// Apply starter weapon bonuses
if (className === 'mage') stats.int += 1;
else if (className === 'ranger') stats.agi += 2;
// Auto-allocate 15 points to primary stat (5 levels × 3 points)
stats[primary] += 15; stats[primary] += 15;
var derived = calcDerived(stats, 5, className); var derived = calcDerived(stats, 5, className);
var monster = pickMonster('forest', rng); var monster = pickMonster('forest', rng);
+16 -16
View File
@@ -11,22 +11,22 @@
-- --
-- Tuning rationale: -- Tuning rationale:
-- Original 003_content stats gave L1 heroes ~100% Meadows win rate (monsters too weak). -- Original 003_content stats gave L1 heroes ~100% Meadows win rate (monsters too weak).
-- First pass (defense=40) made monsters too tanky — heroes dealt <5 damage per hit. -- Previous pass (008) made monsters too tanky (200-400 HP) — L1 heroes couldn't kill
-- Reduced monster defense to 3-12 range so heroes deal 10-24 damage per hit. -- within 20 rounds. Reduced HP to 30-45 for Meadows, 100-180 for Forest, 150-250 for Crags.
-- Meadows: low attack (6-10) so L1 heroes win ~85% of fights. -- Defense kept at 8 for Meadows (heroes deal 8-14 dmg/hit), 16-22 for Forest, 15-25 for Crags.
-- Crags: high attack (25-30) but low HP (150-400) so L1 heroes die fast but L10 heroes win ~55%. -- XP increased to 25-50 (Meadows), 55-110 (Forest), 150-350 (Crags) for proper level progression.
-- ===== MEADOWS MONSTERS (defense=8, attack tuned for ~85% L1 win rate) ===== -- ===== MEADOWS MONSTERS (HP 50-70, attack 22-26 → ~75% L1 win rate) =====
UPDATE monsters SET hp = 200, attack = 6, defense = 8, speed = 12, xp = 50, gold_min = 3, gold_max = 7 WHERE id = 1; -- Giant Rat UPDATE monsters SET hp = 50, attack = 22, defense = 8, speed = 12, xp = 25, gold_min = 3, gold_max = 7 WHERE id = 1; -- Giant Rat
UPDATE monsters SET hp = 250, attack = 8, defense = 8, speed = 16, xp = 65, gold_min = 5, gold_max = 12 WHERE id = 2; -- Meadow Wolf UPDATE monsters SET hp = 60, attack = 24, defense = 8, speed = 16, xp = 35, gold_min = 5, gold_max = 12 WHERE id = 2; -- Meadow Wolf
UPDATE monsters SET hp = 300, attack = 10, defense = 8, speed = 11, xp = 85, gold_min = 8, gold_max = 18 WHERE id = 3; -- Goblin Scrapper UPDATE monsters SET hp = 70, attack = 26, defense = 8, speed = 11, xp = 50, gold_min = 8, gold_max = 18 WHERE id = 3; -- Goblin Scrapper
-- ===== FOREST MONSTERS (defense=30 for L5 challenge, HP tuned) ===== -- ===== FOREST MONSTERS (HP 100-180, attack 30-38 → ~62% L5 win rate) =====
UPDATE monsters SET hp = 200, attack = 25, defense = 30, speed = 15, xp = 90, gold_min = 12, gold_max = 24 WHERE id = 4; -- Webspinner UPDATE monsters SET hp = 100, attack = 30, defense = 16, speed = 15, xp = 80, gold_min = 12, gold_max = 24 WHERE id = 4; -- Webspinner
UPDATE monsters SET hp = 250, attack = 30, defense = 30, speed = 14, xp = 120, gold_min = 18, gold_max = 36 WHERE id = 5; -- Bandit Cutthroat UPDATE monsters SET hp = 130, attack = 34, defense = 20, speed = 14, xp = 100, gold_min = 18, gold_max = 36 WHERE id = 5; -- Bandit Cutthroat
UPDATE monsters SET hp = 320, attack = 35, defense = 30, speed = 7, xp = 160, gold_min = 22, gold_max = 44 WHERE id = 6; -- Mossback Treant UPDATE monsters SET hp = 180, attack = 38, defense = 22, speed = 7, xp = 150, gold_min = 22, gold_max = 44 WHERE id = 6; -- Mossback Treant
-- ===== CRAGS MONSTERS (defense 3-12, moderate attack, low HP → L10 win ~55%) ===== -- ===== CRAGS MONSTERS (HP 150-300, attack 34-42, defense 18-28 → ~57% L10 win rate) =====
UPDATE monsters SET hp = 150, attack = 25, defense = 12, speed = 20, xp = 200, gold_min = 30, gold_max = 55 WHERE id = 7; -- Ember Imp UPDATE monsters SET hp = 150, attack = 34, defense = 18, speed = 20, xp = 200, gold_min = 30, gold_max = 55 WHERE id = 7; -- Ember Imp
UPDATE monsters SET hp = 300, attack = 30, defense = 12, speed = 5, xp = 280, gold_min = 40, gold_max = 75 WHERE id = 8; -- Stone Golem UPDATE monsters SET hp = 300, attack = 38, defense = 28, speed = 5, xp = 280, gold_min = 40, gold_max = 75 WHERE id = 8; -- Stone Golem
UPDATE monsters SET hp = 400, attack = 28, defense = 3, speed = 18, xp = 350, gold_min = 55, gold_max = 110 WHERE id = 9; -- Ashfang Drake UPDATE monsters SET hp = 150, attack = 42, defense = 22, speed = 18, xp = 350, gold_min = 55, gold_max = 110 WHERE id = 9; -- Ashfang Drake