# 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"