Mi2dRPGamEng/tests/test_species_samples.py

211 lines
8.9 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
from resources.logic.organs import apply_organ_interactions_tick
DEFS_DIR = Path(__file__).resolve().parent.parent / "resources" / "defs"
@pytest.fixture()
def registry():
return DefRegistry.load(DEFS_DIR)
def make_character(registry, species_id: str, **kwargs) -> Character:
return Character(species_id=species_id, default_body_parts=registry.new_default_body_parts(species_id), **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
# --- explicit, fully bespoke default_organs per species -------------------------------------
def test_human_species_gets_its_organs(registry):
parts = registry.new_default_body_parts("human")
torso = next(p for p in parts if p.slot == "torso")
assert {o.organ_def_id for o in torso.organs} == {"human_heart", "human_lungs", "human_liver", "human_kidneys"}
def test_bot_species_gets_bespoke_mechanical_organs(registry):
parts = registry.new_default_body_parts("bot")
head = next(p for p in parts if p.slot == "head")
torso = next(p for p in parts if p.slot == "torso")
assert {o.organ_def_id for o in head.organs} == {"bot_cpu", "bot_npu"}
assert {o.organ_def_id for o in torso.organs} == {
"bot_power_cell", "bot_hydraulic_fluid_bladder", "bot_cooling_fan",
}
def test_bot_power_cell_affects_multiple_organs(registry):
bot = make_character(registry, "bot")
torso = bot.get_or_create_body_part_override("torso")
power_cell = next(o for o in torso.organs if o.organ_def_id == "bot_power_cell")
power_cell.integrity = 0.0
apply_organ_interactions_tick(bot, registry, ticks=10)
head = bot.get_body_part("head")
cpu = next(o for o in head.organs if o.organ_def_id == "bot_cpu")
npu = next(o for o in head.organs if o.organ_def_id == "bot_npu")
fluid_bladder = next(o for o in bot.get_body_part("torso").organs if o.organ_def_id == "bot_hydraulic_fluid_bladder")
assert cpu.integrity < 100.0
assert npu.integrity < 100.0
assert fluid_bladder.integrity < 100.0
def test_reptilian_venom_gland_is_bespoke_not_shared_with_other_species(registry):
parts = registry.new_default_body_parts("reptilian_quad")
torso = next(p for p in parts if p.slot == "torso")
assert {o.organ_def_id for o in torso.organs} == {
"reptilian_heart", "reptilian_lung", "reptilian_liver", "reptilian_venom_gland",
}
def test_zenari_organs_are_bespoke(registry):
parts = registry.new_default_body_parts("alien_tri")
torso = next(p for p in parts if p.slot == "torso")
head = next(p for p in parts if p.slot == "head")
assert {o.organ_def_id for o in torso.organs} == {
"zenari_cardial_node", "zenari_respirator", "zenari_metabolizer", "zenari_filtration_organ",
}
assert {o.organ_def_id for o in head.organs} == {"zenari_cortex"}
def test_dog_organs_are_bespoke_not_shared_with_human(registry):
parts = registry.new_default_body_parts("dog")
torso = next(p for p in parts if p.slot == "torso")
assert {o.organ_def_id for o in torso.organs} == {"dog_heart", "dog_lungs", "dog_liver", "dog_kidneys"}
def test_no_species_shares_an_organ_id_with_another(registry):
species_ids = ("human", "reptilian_quad", "alien_tri", "bot", "dog")
seen: dict[str, str] = {}
for species_id in species_ids:
species = registry.get_species_def(species_id)
for organ_id in species.default_organs:
assert organ_id not in seen, f"{organ_id!r} shared between {seen.get(organ_id)!r} and {species_id!r}"
seen[organ_id] = species_id
# --- reptilian_quad: 4 arm slots -------------------------------------------------------------
def test_reptilian_has_four_arm_slots(registry):
species = registry.get_species_def("reptilian_quad")
slots = {p.slot for p in species.default_body_parts}
assert {"left_arm", "right_arm", "left_arm_2", "right_arm_2"} <= slots
def test_reptilian_can_wield_two_two_handed_tools_at_once(registry):
reptilian = make_character(registry, "reptilian_quad")
assert reptilian.wield_item("right_hand", "multi_deconstructor", registry) is True
assert reptilian.wield_item("right_hand_2", "constructor_tool", registry) is True
assert reptilian.get_held_item("left_hand").item_def_id == "multi_deconstructor"
assert reptilian.get_held_item("left_hand_2").item_def_id == "constructor_tool"
def test_reptilian_secondary_hand_pair_does_not_disturb_primary(registry):
reptilian = make_character(registry, "reptilian_quad")
reptilian.wield_item("right_hand", "staff_oak", registry)
reptilian.wield_item("right_hand_2", "multi_deconstructor", registry)
assert reptilian.get_held_item("right_hand").item_def_id == "staff_oak"
assert reptilian.get_held_item("left_hand") is None # staff is one-handed, doesn't touch left_hand
assert reptilian.get_held_item("left_hand_2").item_def_id == "multi_deconstructor"
def test_two_armed_alien_cannot_use_secondary_hand_pair(registry):
alien = make_character(registry, "alien_tri")
assert alien.wield_item("right_hand_2", "staff_oak", registry) is False
# --- alien_tri: 3 genders --------------------------------------------------------------------
def test_alien_tri_species_declares_three_genders(registry):
species = registry.get_species_def("alien_tri")
assert species.genders == ["alpha", "beta", "gamma"]
# --- dog: quadruped, no arms -----------------------------------------------------------------
def test_dog_has_no_arm_slots(registry):
species = registry.get_species_def("dog")
slots = {p.slot for p in species.default_body_parts}
assert slots == {"head", "torso", "front_left_leg", "front_right_leg", "back_left_leg", "back_right_leg"}
def test_dog_cannot_wield_anything(registry):
dog = make_character(registry, "dog")
assert dog.wield_item("right_hand", "staff_oak", registry) is False
assert dog.held_items == []
def test_dog_effective_speed_uses_all_four_legs(registry):
dog = make_character(registry, "dog")
human = make_character(registry, "human")
# 4 legs at 0.25 speed_factor each should sum to the same total factor as 2 legs at 0.5 each
assert dog.effective_speed(30.0, registry) == pytest.approx(human.effective_speed(30.0, registry))
def test_dog_can_perform_bite_attack_but_not_arm_dependent_abilities(registry):
dog = make_character(registry, "dog")
assert dog.can_perform_ability("melee_attack", registry) is True
assert dog.can_perform_ability("time_warp_sphere", registry) is False # not in dog's ability list at all
# --- one-ability-per-required-hand: de/constructor tools, verified across species -----------
def test_constructor_via_left_hand_also_builds(registry):
world, field = make_world(registry)
character = make_character(registry, "human", position=EntityPosition("field", 5, 5, 0))
character.wield_item("left_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, "left_hand", (1, 0, 0))
assert result is True
assert field.get_tile(6, 5, 0).room.def_id == "wood_wall"
def test_reptilian_secondary_pair_deconstructor_independent_of_primary_pair_tool(registry):
"""A 4-armed species can wield a 2-handed tool in each hand pair; activating one hand
pair's tool must not affect the other pair's separately-wielded tool - each required hand
only ever triggers the ability of whatever it itself is holding.
"""
world, field = make_world(registry)
field.get_tile(6, 5, 0).room = TileLayerInstance("wood_wall")
reptilian = make_character(registry, "reptilian_quad", position=EntityPosition("field", 5, 5, 0))
reptilian.wield_item("right_hand", "multi_deconstructor", registry)
reptilian.wield_item("right_hand_2", "constructor_tool", registry)
world.add_entity(reptilian)
# right_hand's deconstructor: left-click semantics (button="left") -> destroy, no item yielded
result = activate_hand(reptilian, world, registry, "right_hand", (1, 0, 0))
assert result is True
assert field.get_tile(6, 5, 0).room is None
# the secondary pair's constructor is untouched by the above and still independently usable
assert reptilian.get_held_item("left_hand_2").item_def_id == "constructor_tool"