Mi2dRPGamEng/tests/test_actions.py

142 lines
5.3 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.inventory import Inventory
from engine.item import ItemInstance
from engine.map import Map
from engine.tile import Tile, TileLayerInstance
from engine.world import World
from resources.logic.actions import activate_hand
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, field
class FixedRng:
def __init__(self, roll=15, choice_value="torso"):
self._roll = roll
self._choice_value = choice_value
def randint(self, _lo, _hi):
return self._roll
def choice(self, seq):
return self._choice_value if self._choice_value is not None else seq[0]
def test_empty_hand_attacks_unarmed(registry):
world, _field = make_world(registry)
attacker = make_human(registry, position=EntityPosition("field", 5, 5, 0))
attacker.bio["athletics"] = 10
defender = make_human(registry, position=EntityPosition("field", 6, 5, 0))
world.add_entity(attacker)
world.add_entity(defender)
result = activate_hand(attacker, world, registry, "right_hand", (1, 0, 0), rng=FixedRng())
assert result is not None
assert result.hit is True
assert result.weapon_bonus == 0.0
def test_empty_hand_with_no_target_ahead_is_a_no_op(registry):
world, _field = make_world(registry)
attacker = make_human(registry, position=EntityPosition("field", 5, 5, 0))
world.add_entity(attacker)
assert activate_hand(attacker, world, registry, "right_hand", (1, 0, 0)) is None
def test_wielded_melee_weapon_attacks(registry):
world, _field = make_world(registry)
attacker = make_human(registry, position=EntityPosition("field", 5, 5, 0))
attacker.wield_item("right_hand", "staff_oak", registry)
defender = make_human(registry, position=EntityPosition("field", 6, 5, 0))
world.add_entity(attacker)
world.add_entity(defender)
result = activate_hand(attacker, world, registry, "right_hand", (1, 0, 0), rng=FixedRng())
assert result.weapon_bonus == pytest.approx(6.0) # staff_oak
def test_wielded_gun_shoots(registry):
world, _field = make_world(registry)
shooter = make_human(registry, position=EntityPosition("field", 0, 5, 0))
shooter.wield_item("right_hand", "pistol_basic", registry)
target = make_human(registry, position=EntityPosition("field", 3, 5, 0))
world.add_entity(shooter)
world.add_entity(target)
result = activate_hand(shooter, world, registry, "right_hand", (1, 0, 0), rng=FixedRng())
assert result.hit is True
assert result.target_entity_id == target.entity_id
def test_wielded_deconstructor_interacts_with_tile_ahead(registry):
world, field = make_world(registry)
field.get_tile(6, 5, 0).room = TileLayerInstance("wood_wall")
character = make_human(registry, position=EntityPosition("field", 5, 5, 0))
character.wield_item("right_hand", "multi_deconstructor", registry)
world.add_entity(character)
result = activate_hand(character, world, registry, "right_hand", (1, 0, 0))
assert result is True
assert field.get_tile(6, 5, 0).room is None
def test_left_hand_deconstructor_uses_right_click_semantics(registry):
world, field = make_world(registry)
field.get_tile(6, 5, 0).room = TileLayerInstance("wood_wall")
character = make_human(registry, position=EntityPosition("field", 5, 5, 0))
character.wield_item("left_hand", "multi_deconstructor", registry)
character.inventory = Inventory(4, 4)
world.add_entity(character)
result = activate_hand(character, world, registry, "left_hand", (1, 0, 0))
assert result is not None
assert result.def_id == "wood_planks" # right-click behavior: yields an item
assert field.get_tile(6, 5, 0).room is None
def test_wielded_constructor_builds_on_bare_tile_ahead(registry):
world, field = make_world(registry)
character = make_human(registry, position=EntityPosition("field", 5, 5, 0))
character.wield_item("right_hand", "constructor_tool", registry)
character.inventory = Inventory(4, 4)
planks_def = registry.get_item_def("wood_planks")
character.inventory.place(ItemInstance("planks-1", "wood_planks"), planks_def, 0, 0)
world.add_entity(character)
result = activate_hand(character, world, registry, "right_hand", (1, 0, 0))
assert result is True
assert field.get_tile(6, 5, 0).room.def_id == "wood_wall"
def test_deconstructor_out_of_bounds_target_is_a_no_op(registry):
world, _field = make_world(registry)
character = make_human(registry, position=EntityPosition("field", 0, 0, 0))
character.wield_item("right_hand", "multi_deconstructor", registry)
world.add_entity(character)
assert activate_hand(character, world, registry, "right_hand", (-1, 0, 0)) is None