step 10.18: wip (not ticked)
This commit is contained in:
+45
-11
@@ -18,19 +18,19 @@ var SEED = 42;
|
||||
// ─── Zone / monster definitions (MUST match 008_balance.sql) ────────────────
|
||||
var ZONES = {
|
||||
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: 'Meadow Wolf', level: 2, hp: 350, attack: 12, defense: 8, speed: 16, xp: 110, goldMin: 5, goldMax: 12 },
|
||||
{ name: 'Goblin Scrapper', level: 3, hp: 300, attack: 18, defense: 8, speed: 11, xp: 180, goldMin: 8, goldMax: 18 },
|
||||
{ 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: 60, attack: 18, defense: 8, speed: 16, xp: 35, goldMin: 5, goldMax: 12 },
|
||||
{ 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: [
|
||||
{ name: 'Webspinner', level: 5, hp: 200, attack: 25, defense: 20, 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: 'Mossback Treant', level: 8, hp: 350, attack: 35, defense: 30, speed: 7, xp: 160, goldMin: 22, goldMax: 44 },
|
||||
{ name: 'Webspinner', level: 5, hp: 100, attack: 24, defense: 16, speed: 15, xp: 80, goldMin: 12, goldMax: 24 },
|
||||
{ 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: 180, attack: 30, defense: 22, speed: 7, xp: 150, goldMin: 22, goldMax: 44 },
|
||||
]},
|
||||
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: 'Stone Golem', level: 12, hp: 600, attack: 40, defense: 30, speed: 5, xp: 420, goldMin: 40, goldMax: 75 },
|
||||
{ name: 'Ashfang Drake', level: 14, hp: 450, attack: 45, defense: 25, speed: 18, xp: 600, goldMin: 55, goldMax: 110 },
|
||||
{ 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: 300, attack: 38, defense: 28, speed: 5, xp: 280, goldMin: 40, goldMax: 75 },
|
||||
{ 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) {
|
||||
// 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({
|
||||
class: hero.class, level: hero.level, hpCurrent: hero.hp,
|
||||
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);
|
||||
|
||||
var xpGained = 0, goldGained = 0;
|
||||
@@ -79,6 +91,15 @@ function simulateClass(className) {
|
||||
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);
|
||||
hero.hp = derived.maxHp;
|
||||
hero.maxHp = derived.maxHp;
|
||||
@@ -188,12 +209,18 @@ function simulateLevel1WinRate(zoneKey) {
|
||||
var className = CLASS_KEYS[ci];
|
||||
var cls = getClass(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 result = simulateHunt({
|
||||
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);
|
||||
|
||||
if (result.winner === 'hero') wins++;
|
||||
@@ -217,7 +244,14 @@ function simulateLevel5ForestWinRate() {
|
||||
var base = getBaseStats(className);
|
||||
var primary = cls.primary;
|
||||
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;
|
||||
|
||||
var derived = calcDerived(stats, 5, className);
|
||||
|
||||
var monster = pickMonster('forest', rng);
|
||||
|
||||
@@ -11,22 +11,22 @@
|
||||
--
|
||||
-- Tuning rationale:
|
||||
-- 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.
|
||||
-- Reduced monster defense to 3-12 range so heroes deal 10-24 damage per hit.
|
||||
-- Meadows: low attack (6-10) so L1 heroes win ~85% of fights.
|
||||
-- Crags: high attack (25-30) but low HP (150-400) so L1 heroes die fast but L10 heroes win ~55%.
|
||||
-- Previous pass (008) made monsters too tanky (200-400 HP) — L1 heroes couldn't kill
|
||||
-- within 20 rounds. Reduced HP to 30-45 for Meadows, 100-180 for Forest, 150-250 for Crags.
|
||||
-- Defense kept at 8 for Meadows (heroes deal 8-14 dmg/hit), 16-22 for Forest, 15-25 for Crags.
|
||||
-- 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) =====
|
||||
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 = 250, attack = 8, defense = 8, speed = 16, xp = 65, 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
|
||||
-- ===== MEADOWS MONSTERS (HP 50-70, attack 22-26 → ~75% L1 win rate) =====
|
||||
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 = 60, attack = 24, defense = 8, speed = 16, xp = 35, gold_min = 5, gold_max = 12 WHERE id = 2; -- Meadow Wolf
|
||||
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) =====
|
||||
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 = 250, attack = 30, defense = 30, speed = 14, xp = 120, 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
|
||||
-- ===== FOREST MONSTERS (HP 100-180, attack 30-38 → ~62% L5 win rate) =====
|
||||
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 = 130, attack = 34, defense = 20, speed = 14, xp = 100, gold_min = 18, gold_max = 36 WHERE id = 5; -- Bandit Cutthroat
|
||||
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%) =====
|
||||
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 = 300, attack = 30, defense = 12, 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
|
||||
-- ===== CRAGS MONSTERS (HP 150-300, attack 34-42, defense 18-28 → ~57% L10 win rate) =====
|
||||
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 = 38, defense = 28, speed = 5, xp = 280, gold_min = 40, gold_max = 75 WHERE id = 8; -- Stone Golem
|
||||
UPDATE monsters SET hp = 150, attack = 42, defense = 22, speed = 18, xp = 350, gold_min = 55, gold_max = 110 WHERE id = 9; -- Ashfang Drake
|
||||
|
||||
Reference in New Issue
Block a user