Mi2dRPGamEng/tests/test_ability_cooldowns.py

138 lines
5.2 KiB
Python

from pathlib import Path
import pytest
from engine.character import Character
from engine.defs import DefRegistry
from engine.entity import EntityPosition
from engine.map import Map
from engine.tile import Tile, TileLayerInstance
from engine.ui import AbilityBarSlot
from engine.world import World
from resources.logic.actions import ABILITY_COOLDOWNS, activate_ability_bar_slot, activate_hand, activate_implant
DEFS_DIR = Path(__file__).resolve().parent.parent / "resources" / "defs"
@pytest.fixture()
def registry():
return DefRegistry.load(DEFS_DIR)
def make_human(registry, **kwargs) -> Character:
return Character(species_id="human", default_body_parts=registry.new_default_body_parts("human"), **kwargs)
def make_world(registry):
field = Map("field", 10, 10, 1)
for x in range(10):
for y in range(10):
field.set_tile(x, y, 0, Tile(flooring=TileLayerInstance("grass")))
world = World(registry=registry)
world.add_map(field)
return world
# --- Character.is_ability_ready / start_ability_cooldown ------------------------------------
def test_ability_ready_by_default(registry):
character = make_human(registry)
assert character.is_ability_ready("time_warp_sphere", now=0.0) is True
def test_start_ability_cooldown_blocks_until_it_expires(registry):
character = make_human(registry)
character.start_ability_cooldown("time_warp_sphere", now=10.0, duration=5.0)
assert character.is_ability_ready("time_warp_sphere", now=12.0) is False
assert character.is_ability_ready("time_warp_sphere", now=15.0) is True
def test_zero_duration_cooldown_is_a_no_op(registry):
character = make_human(registry)
character.start_ability_cooldown("time_warp_sphere", now=10.0, duration=0.0)
assert character.is_ability_ready("time_warp_sphere", now=10.0) is True
# --- activate_hand (chronowand) respects cooldown --------------------------------------------
def test_chronowand_cast_starts_a_cooldown(registry):
world = make_world(registry)
caster = make_human(registry, position=EntityPosition("field", 5, 5, 0))
caster.wield_item("right_hand", "chronowand", registry)
world.add_entity(caster)
activate_hand(caster, world, registry, "right_hand", (1, 0, 0), now=0.0)
assert caster.is_ability_ready("time_warp_sphere", now=0.0) is False
def test_chronowand_cannot_recast_while_on_cooldown(registry):
world = make_world(registry)
caster = make_human(registry, position=EntityPosition("field", 5, 5, 0))
caster.wield_item("right_hand", "chronowand", registry)
world.add_entity(caster)
activate_hand(caster, world, registry, "right_hand", (1, 0, 0), now=0.0)
result = activate_hand(caster, world, registry, "right_hand", (1, 0, 0), now=1.0)
assert result is None
assert len(world.time_warp_zones) == 1 # still just the first cast
def test_chronowand_can_recast_after_cooldown_expires(registry):
world = make_world(registry)
caster = make_human(registry, position=EntityPosition("field", 5, 5, 0))
caster.wield_item("right_hand", "chronowand", registry)
world.add_entity(caster)
activate_hand(caster, world, registry, "right_hand", (1, 0, 0), now=0.0)
cooldown = ABILITY_COOLDOWNS["time_warp_sphere"]
result = activate_hand(caster, world, registry, "right_hand", (1, 0, 0), now=cooldown + 0.1)
assert result is not None
assert len(world.time_warp_zones) == 2
# --- activate_implant respects cooldown -------------------------------------------------------
def test_implant_cannot_recast_while_on_cooldown(registry):
world = make_world(registry)
caster = make_human(registry, position=EntityPosition("field", 5, 5, 0))
caster.install_implant("chronoimplant", registry)
world.add_entity(caster)
activate_implant(caster, world, registry, "chronoimplant", now=0.0)
result = activate_implant(caster, world, registry, "chronoimplant", now=1.0)
assert result is None
assert len(world.time_warp_zones) == 1
# --- cooldown is shared across activation paths (hand, implant, ability bar) ------------------
def test_cooldown_is_shared_between_hand_and_implant_paths(registry):
world = make_world(registry)
caster = make_human(registry, position=EntityPosition("field", 5, 5, 0))
caster.wield_item("right_hand", "chronowand", registry)
caster.install_implant("chronoimplant", registry)
world.add_entity(caster)
activate_hand(caster, world, registry, "right_hand", (1, 0, 0), now=0.0)
# same underlying ability (time_warp_sphere), so the implant is also on cooldown now
result = activate_implant(caster, world, registry, "chronoimplant", now=1.0)
assert result is None
assert len(world.time_warp_zones) == 1
def test_ability_bar_slot_respects_cooldown_too(registry):
world = make_world(registry)
caster = make_human(registry, position=EntityPosition("field", 5, 5, 0))
caster.install_implant("chronoimplant", registry)
world.add_entity(caster)
slot = AbilityBarSlot(kind="implant", source_id="chronoimplant", ability_id="time_warp_sphere")
activate_ability_bar_slot(caster, world, registry, slot, (1, 0, 0), now=0.0)
result = activate_ability_bar_slot(caster, world, registry, slot, (1, 0, 0), now=1.0)
assert result is None
assert len(world.time_warp_zones) == 1