import { describe, expect, it } from 'vitest';
import { PLAYER_COMBAT } from '../stats';
import { ENEMY_KINDS } from '../../../data/enemies';
/**
* Таблица баланса боевой модели демо-среза (согласована с планом и docs/world.md):
* удар — «гулкий звон» (будит пепел), резонанс — «низкий звон» (усыпляет).
*/
describe('PLAYER_COMBAT — таблица баланса', () => {
it('герой: 5 сердечек, окно неуязвимости 0.8 с', () => {
expect(PLAYER_COMBAT.maxHp).toBe(5);
expect(PLAYER_COMBAT.invulnTime).toBeCloseTo(0.8);
expect(PLAYER_COMBAT.knockback).toBe(0.75);
});
it('короткий удар: конус 1.0 юнита, 55°, урон 2, кулдаун 0.45 с', () => {
expect(PLAYER_COMBAT.coneRange).toBe(1.0);
expect((PLAYER_COMBAT.coneHalfAngle * 180) / Math.PI).toBeCloseTo(55);
expect(PLAYER_COMBAT.coneDamage).toBe(2);
expect(PLAYER_COMBAT.coneCooldown).toBeCloseTo(0.45);
});
it('резонанс: заряд 0.6 с, радиус 3.0, сон 4 с, кулдаун 3 с', () => {
expect(PLAYER_COMBAT.resonanceCharge).toBeCloseTo(0.6);
expect(PLAYER_COMBAT.resonanceRange).toBe(3.0);
expect(PLAYER_COMBAT.resonanceSleep).toBe(4);
expect(PLAYER_COMBAT.resonanceCooldown).toBe(3);
});
it('гулкий удар будит спящих в радиусе 4.5 юнитов', () => {
expect(PLAYER_COMBAT.wakeRadius).toBe(4.5);
});
it('ползун: слабый, но быстрый, контактный', () => {
const c = ENEMY_KINDS.crawler;
expect(c.hp).toBe(3);
expect(c.attackDamage).toBe(1);
expect(c.windup).toBe(0);
// Убивается одним коротким ударом (урон 2) не должен: нужно 2 удара
expect(Math.ceil(c.hp / PLAYER_COMBAT.coneDamage)).toBe(2);
});
it('плевун: хрупкий стрелок, держит дистанцию', () => {
const s = ENEMY_KINDS.spitter;
expect(s.hp).toBe(2);
expect(s.keepDistance).toBeGreaterThan(PLAYER_COMBAT.coneRange);
expect(s.attackRange).toBeGreaterThan(s.keepDistance ?? 0);
expect(s.windup).toBeGreaterThan(0);
});
it('наст: танк с тяжёлым замахом и уроном 2', () => {
const h = ENEMY_KINDS.heavy;
expect(h.hp).toBe(8);
expect(h.attackDamage).toBe(2);
expect(h.windup).toBeGreaterThanOrEqual(0.6);
// Четыре коротких удара (урон 2) убивают
expect(Math.ceil(h.hp / PLAYER_COMBAT.coneDamage)).toBe(4);
});
});