diff --git a/src/mudlib/combat/encounter.py b/src/mudlib/combat/encounter.py index 071990d..ba098c5 100644 --- a/src/mudlib/combat/encounter.py +++ b/src/mudlib/combat/encounter.py @@ -128,7 +128,7 @@ class CombatEncounter: defender_flying = getattr(self.defender, "flying", False) if attacker_flying != defender_flying: # Altitude mismatch - attack misses - template = "{attacker}'s attack miss{es} — {defender} {is|is} out of reach!" + template = "{attacker} miss{es} — {defender} {are|is} out of reach!" # Reset to IDLE self.state = CombatState.IDLE self.current_move = None diff --git a/tests/test_combat_zaxis.py b/tests/test_combat_zaxis.py index f8eceb0..bfe8534 100644 --- a/tests/test_combat_zaxis.py +++ b/tests/test_combat_zaxis.py @@ -237,3 +237,35 @@ async def test_attacker_flies_during_window_causes_miss(player, target, punch_ri # Attack should miss assert result.countered is True or result.damage == 0.0 + + +@pytest.mark.asyncio +async def test_flying_dodge_messages_correct_grammar(player, target, punch_right): + """Test flying dodge produces grammatically correct messages from both POVs.""" + from mudlib.render.pov import render_pov + + # Both grounded, start combat + player.flying = False + target.flying = False + + encounter = start_encounter(player, target) + encounter.attack(punch_right) + + # Advance to WINDOW phase + encounter.state = CombatState.WINDOW + + # Defender flies during window + target.flying = True + + # Resolve + result = encounter.resolve() + + # Render from both POVs + attacker_msg = render_pov(result.resolve_template, player, player, target) + defender_msg = render_pov(result.resolve_template, target, player, target) + + # Attacker POV should say "You miss — Vegeta is out of reach!" + assert attacker_msg == "You miss — Vegeta is out of reach!" + + # Defender POV should say "Goku misses — You are out of reach!" + assert defender_msg == "Goku misses — You are out of reach!"