const test = require('node:test'); const assert = require('node:assert/strict'); const { calcDerived, computeEnergy, xpToNext, checkLevelUp, ENERGY_MAX } = require('../../src/game/stats'); // calcDerived tests test('calcDerived warrior at level 1 with no equipment', () => { const derived = calcDerived({ str: 8, agi: 4, int: 2, vit: 8 }, 1, 'warrior'); // maxHp = 50 + 8*10 + 1*5 = 135 assert.equal(derived.maxHp, 135); // primary = str = 8, attack = 5 + 8*2 + 1 = 22 assert.equal(derived.attack, 22); // defense = floor(8*1.5) = 12, +10% warrior = 13 assert.equal(derived.defense, 13); // speed = 10 + 4 = 14 assert.equal(derived.speed, 14); // critChance = min(40, 5 + floor(4*0.5)) = min(40, 7) = 7 assert.equal(derived.critChance, 7); }); test('calcDerived mage at level 1 with no equipment', () => { const derived = calcDerived({ str: 2, agi: 4, int: 9, vit: 5 }, 1, 'mage'); // maxHp = 50 + 5*10 + 1*5 = 105 assert.equal(derived.maxHp, 105); // primary = int = 9, attack = 5 + 9*2 + 1 = 24 assert.equal(derived.attack, 24); // defense = floor(5*1.5) = 7 (no warrior bonus) assert.equal(derived.defense, 7); // speed = 10 + 4 = 14 assert.equal(derived.speed, 14); // critChance = min(40, 5 + floor(4*0.5)) = 7 assert.equal(derived.critChance, 7); }); test('calcDerived ranger at level 1 with no equipment', () => { const derived = calcDerived({ str: 5, agi: 9, int: 3, vit: 5 }, 1, 'ranger'); // maxHp = 50 + 5*10 + 1*5 = 105 assert.equal(derived.maxHp, 105); // primary = agi = 9, attack = 5 + 9*2 + 1 = 24 assert.equal(derived.attack, 24); // defense = floor(5*1.5) = 7 assert.equal(derived.defense, 7); // speed = 10 + 9 = 19 assert.equal(derived.speed, 19); // critChance = min(40, 5 + floor(9*0.5)) + 8 = min(40, 9) + 8 = 17 assert.equal(derived.critChance, 17); }); test('calcDerived with equipment bonuses', () => { const derived = calcDerived( { str: 8, agi: 4, int: 2, vit: 8 }, 1, 'warrior', { bonus_str: 2, bonus_attack: 5, bonus_defense: 3 } ); // totalStr = 10, attack = 5 + 10*2 + 1 + 5 = 31 assert.equal(derived.attack, 31); // totalVit = 8, defense = floor(8*1.5) = 12, +3 equip = 15, +10% = 16 assert.equal(derived.defense, 16); }); // computeEnergy tests test('computeEnergy no time passed', () => { const result = computeEnergy(50, Date.now(), Date.now() - 1000); assert.equal(result.energy, 50); }); test('computeEnergy partial tick (less than 1 regen interval)', () => { const now = Date.now(); const result = computeEnergy(50, now - 10000, now); // 10s < 180s → no regen assert.equal(result.energy, 50); }); test('computeEnergy full tick', () => { const now = Date.now(); const result = computeEnergy(50, now - 360000, now); // 360s / 180s = 2 ticks assert.equal(result.energy, 52); }); test('computeEnergy caps at max', () => { const now = Date.now(); const result = computeEnergy(100, now - 3600000, now); assert.equal(result.energy, ENERGY_MAX); }); test('computeEnergy clock going backwards', () => { const result = computeEnergy(50, Date.now(), Date.now() - 100000); assert.equal(result.energy, 50); }); test('computeEnergy large gap', () => { const now = Date.now(); const result = computeEnergy(30, now - 36000000, now); // 10 hours ago assert.equal(result.energy, ENERGY_MAX); }); // xpToNext tests test('xpToNext level 1→2 is 100', () => { assert.equal(xpToNext(1), 100); }); test('xpToNext level 2→3 is 282', () => { assert.equal(xpToNext(2), 282); }); test('xpToNext level 5→6 is 1118', () => { assert.equal(xpToNext(5), 1118); }); // checkLevelUp tests test('checkLevelUp no level up', () => { const result = checkLevelUp(1, 50, 10); assert.equal(result.newLevel, 1); assert.equal(result.leveledUp, false); assert.equal(result.totalXp, 60); }); test('checkLevelUp exact threshold', () => { const result = checkLevelUp(1, 90, 10); assert.equal(result.newLevel, 2); assert.equal(result.leveledUp, true); assert.equal(result.totalXp, 0); }); test('checkLevelUp multiple level ups', () => { // L1→2 costs 100, L2→3 costs 282. Total 382 for 2 levels. 500 XP → 2 levels, 118 remaining. const result = checkLevelUp(1, 0, 500); assert.equal(result.newLevel, 3); assert.equal(result.leveledUp, true); assert.equal(result.totalXp, 118); }); test('checkLevelUp grants 3 points per level', () => { const result = checkLevelUp(1, 0, 282); // exactly enough for L1→L2 assert.equal(result.newLevel, 2); assert.equal(result.unspentPoints, 3); });