SOULGATE/server/tests/test_boss.py
2026-05-04 03:42:47 +02:00

143 lines
3.8 KiB
Python

# tests boss : vexaris + morveth + transitions
from unittest.mock import AsyncMock
from lobby import Lobby, LobbyPlayer
from game_loop import GameLoop
from constants import (
VEXARIS_HP, VEXARIS_HITBOX_RADIUS,
MORVETH_HP,
WAVE_BOSSES, SOUL_REWARDS,
)
from waves import WaveManager
from constants import PREPARATION_DURATION, TICK_DURATION
def make_lobby():
lobby = Lobby("TEST1", "p1")
lobby.players = [
LobbyPlayer("p1", "Alice", "kael"),
LobbyPlayer("p2", "Bob", "seris"),
LobbyPlayer("p3", "Clara", "aldric"),
]
return lobby
def _ticks(wm, n, enemy_count=0):
events = []
for _ in range(n):
events.extend(wm.tick(lambda t: None, enemy_count))
return events
def _complete_wave_phases(wm):
for _ in range(200_000):
wm.tick(lambda t: None, 0)
if wm.state != "combat":
return
raise AssertionError("vague combat infinie")
def _prep_ticks():
return int(PREPARATION_DURATION / TICK_DURATION) + 1
def _skip_initial_prep(wm):
while wm.state == "preparation":
wm.tick(lambda t: None, 0)
def test_wave_bosses():
assert WAVE_BOSSES[2] == "vexaris"
assert WAVE_BOSSES[3] == "morveth"
assert 1 not in WAVE_BOSSES
def test_spawn_vexaris():
loop = GameLoop(make_lobby(), AsyncMock())
loop.spawn_enemy("vexaris")
boss = loop.state.enemies[0]
assert boss.type == "vexaris"
assert boss.hp == VEXARIS_HP
assert boss.is_boss is True
def test_boss_tape_joueur_au_contact():
loop = GameLoop(make_lobby(), AsyncMock())
loop.spawn_enemy("vexaris")
boss = loop.state.enemies[0]
player = loop.state.players[0]
boss.x, boss.y = player.x, player.y
hp_initial = player.hp
loop._update_enemies()
assert player.hp < hp_initial
def test_boss_kill_donne_des_ames():
loop = GameLoop(make_lobby(), AsyncMock())
loop.spawn_enemy("vexaris")
boss = loop.state.enemies[0]
player = loop.state.players[0]
initial_souls = player.souls
from game_state import ProjectileState
loop.state.projectiles.append(ProjectileState(
id="pr_test", owner_id=player.id,
x=boss.x, y=boss.y, vx=0, vy=0,
damage=VEXARIS_HP, radius=VEXARIS_HITBOX_RADIUS + 1, ttl=1.0,
))
loop._update_projectiles()
assert player.souls == initial_souls + SOUL_REWARDS["vexaris"]
def test_spawn_morveth():
loop = GameLoop(make_lobby(), AsyncMock())
loop.spawn_enemy("morveth")
boss = loop.state.enemies[0]
assert boss.type == "morveth"
assert boss.hp == MORVETH_HP
def _morveth_at_pct(pct):
loop = GameLoop(make_lobby(), AsyncMock())
loop.spawn_enemy("morveth")
boss = loop.state.enemies[0]
boss.hp = max(1, int(boss.max_hp * pct))
boss.data.update({
"charge_cd": 99.0, "charge_timer": 0.0,
"charge_tx": 0.0, "charge_ty": 0.0,
"is_charging": False,
"burst_cd": 99.0,
"general_1_spawned": False,
"general_2_spawned": False,
"general_3_spawned": False,
})
return loop
def test_morveth_invoque_general_a_75():
loop = _morveth_at_pct(0.74)
loop._update_enemies()
generals = [e for e in loop.state.enemies if e.type == "general"]
assert len(generals) == 1
def test_morveth_pas_de_double_invocation():
loop = _morveth_at_pct(0.74)
loop._update_enemies()
loop._update_enemies()
generals = [e for e in loop.state.enemies if e.type == "general"]
assert len(generals) == 1
def test_victory_apres_morveth():
wm = WaveManager()
_skip_initial_prep(wm)
_complete_wave_phases(wm)
_ticks(wm, _prep_ticks())
_complete_wave_phases(wm)
_ticks(wm, 3) # Vexaris spawn + kill
_ticks(wm, _prep_ticks())
_complete_wave_phases(wm)
_ticks(wm, 3) # Morveth spawn + kill
assert wm.state == "victory"