138 lines
5.2 KiB
Python
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
|