# tests combat : hitbox, cooldown, projectile import math from unittest.mock import AsyncMock import pytest from combat import circle_overlap, normalize from constants import ATTACK_COOLDOWN, TICK_DURATION from game_loop import GameLoop from lobby import Lobby, LobbyPlayer def make_game_loop(class_name="seris"): player = LobbyPlayer(conn_id="c1", username="Test", player_class=class_name, is_ready=True, is_host=True) lobby = Lobby(code="TEST01", players=[player], started=True) return GameLoop(lobby, AsyncMock()) def test_circle_overlap_overlapping(): assert circle_overlap(0, 0, 1, 0.5, 0, 1) is True def test_circle_overlap_far_apart(): assert circle_overlap(0, 0, 0.5, 10, 10, 0.5) is False def test_normalize_diagonal(): dx, dy = normalize(1, 1) assert dx == pytest.approx(1 / math.sqrt(2)) assert dy == pytest.approx(1 / math.sqrt(2)) def test_normalize_zero(): assert normalize(0, 0) == (0.0, 0.0) def test_cooldown_decroit(): loop = make_game_loop() loop.state.players[0].cooldowns["attack"] = 0.5 loop._update_cooldowns() assert loop.state.players[0].cooldowns["attack"] == pytest.approx(0.5 - TICK_DURATION) def test_handle_attack_cree_projectile(): loop = make_game_loop() p = loop.state.players[0] loop.handle_attack(p.id, p.x + 5, p.y) assert len(loop.state.projectiles) == 1 assert p.cooldowns["attack"] == pytest.approx(ATTACK_COOLDOWN) def test_handle_attack_bloque_par_cd(): loop = make_game_loop() p = loop.state.players[0] p.cooldowns["attack"] = 0.5 loop.handle_attack(p.id, p.x + 5, p.y) assert len(loop.state.projectiles) == 0 def test_projectile_se_deplace(): loop = make_game_loop() p = loop.state.players[0] loop.handle_attack(p.id, p.x + 5, p.y) old_x = loop.state.projectiles[0].x loop._update_projectiles() assert loop.state.projectiles[0].x != old_x def test_projectile_disparait_quand_ttl_zero(): loop = make_game_loop() p = loop.state.players[0] loop.handle_attack(p.id, p.x + 5, p.y) loop.state.projectiles[0].ttl = 0.01 loop._update_projectiles() assert len(loop.state.projectiles) == 0