From a4c9f310561bdfc70e7725f39c9443c0bf490fec Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Fri, 13 Feb 2026 23:56:19 -0500 Subject: [PATCH] Cancel power-up tasks when combat starts When combat begins, any active power-up task on either the attacker or defender should be cancelled to prevent background power changes during combat. This ensures players can't continue charging while fighting. The fix checks both entities for a _power_task attribute and cancels it if present, then clears the reference. --- src/mudlib/combat/engine.py | 8 +++++++ tests/test_power.py | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/mudlib/combat/engine.py b/src/mudlib/combat/engine.py index 3668b81..8b575cd 100644 --- a/src/mudlib/combat/engine.py +++ b/src/mudlib/combat/engine.py @@ -42,6 +42,14 @@ def start_encounter(attacker: Entity, defender: Entity) -> CombatEncounter: ) active_encounters.append(encounter) + # Cancel any active power-up tasks + for entity in (attacker, defender): + task = getattr(entity, "_power_task", None) + if task is not None: + task.cancel() + if hasattr(entity, "_power_task"): + entity._power_task = None # type: ignore[attr-defined] + return encounter diff --git a/tests/test_power.py b/tests/test_power.py index 4a521ae..133bf39 100644 --- a/tests/test_power.py +++ b/tests/test_power.py @@ -307,3 +307,51 @@ async def test_power_to_number_raises_with_loop(player): # Should be increasing toward 80 assert player.pl > 10.0 assert player.stamina < 100.0 # deducting stamina + + +@pytest.mark.asyncio +async def test_combat_start_cancels_power_up(player, nearby_player): + """Test starting combat cancels any active power-up task.""" + from mudlib.combat.engine import start_encounter + + # Start player powering up + player.pl = 10.0 + player.max_pl = 100.0 + player.stamina = 100.0 + + await cmd_power(player, "up") + await asyncio.sleep(0.05) # Let power-up start + + # Verify power-up is active + assert player._power_task is not None + assert not player._power_task.done() + + # Start combat encounter + start_encounter(player, nearby_player) + + # Power-up task should be cancelled + assert player._power_task is None or player._power_task.cancelled() + + +@pytest.mark.asyncio +async def test_combat_start_cancels_defender_power_up(player, nearby_player): + """Test starting combat cancels defender's active power-up task.""" + from mudlib.combat.engine import start_encounter + + # Start nearby_player powering up + nearby_player.pl = 10.0 + nearby_player.max_pl = 100.0 + nearby_player.stamina = 100.0 + + await cmd_power(nearby_player, "up") + await asyncio.sleep(0.05) # Let power-up start + + # Verify power-up is active + assert nearby_player._power_task is not None + assert not nearby_player._power_task.done() + + # Start combat encounter (nearby_player is defender) + start_encounter(player, nearby_player) + + # Power-up task should be cancelled + assert nearby_player._power_task is None or nearby_player._power_task.cancelled()