from pathlib import Path import pytest from engine.character import BodyPart, Character, ClothingPiece from engine.defs import DefRegistry 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) # --- arm_slot_count ----------------------------------------------------------------------- def test_arm_slot_count_for_two_armed_species(registry): human = make_character(registry, "human") assert human.arm_slot_count() == 2 def test_arm_slot_count_for_four_armed_species(registry): reptilian = make_character(registry, "reptilian_quad") assert reptilian.arm_slot_count() == 4 def test_arm_slot_count_for_armless_species(registry): dog = make_character(registry, "dog") assert dog.arm_slot_count() == 0 def test_arm_slot_count_ignores_a_missing_arm(registry): human = make_character(registry, "human") human.body_parts.append(BodyPart("left_arm", "human_left_arm", removed=True)) assert human.arm_slot_count() == 1 # --- wear_item: bigger (more sleeves) fits smaller, not vice versa -------------------------- def test_two_armed_species_can_wear_a_four_armed_jacket(registry): human = make_character(registry, "human") assert human.wear_item("torso", "reptilian_jacket", registry) is True assert human.get_clothing("torso").item_def_id == "reptilian_jacket" def test_four_armed_species_cannot_wear_a_two_armed_jacket(registry): reptilian = make_character(registry, "reptilian_quad") assert reptilian.wear_item("torso", "leather_jacket", registry) is False assert reptilian.get_clothing("torso") is None def test_four_armed_species_can_wear_a_four_armed_jacket(registry): reptilian = make_character(registry, "reptilian_quad") assert reptilian.wear_item("torso", "reptilian_jacket", registry) is True def test_two_armed_species_can_wear_a_two_armed_jacket(registry): human = make_character(registry, "human") assert human.wear_item("torso", "leather_jacket", registry) is True def test_non_sleeved_item_ignores_arm_count_entirely(registry): # dog_saddlebag has no arm_slots_required set (0 = unconstrained) - arm count is # irrelevant for a non-sleeved item, regardless of body type dog = make_character(registry, "dog") assert dog.wear_item("back", "dog_saddlebag", registry) is True # --- wear_item: body_type gate (a dog can't wear human clothes, full stop) ------------------- def test_dog_cannot_wear_a_human_jacket(registry): dog = make_character(registry, "dog") assert dog.wear_item("torso", "leather_jacket", registry) is False assert dog.get_clothing("torso") is None def test_dog_cannot_wear_a_four_armed_jacket_either(registry): # arm count would technically fit (0 <= 4) but body_type ("quadruped" vs "biped") rejects # it outright - a completely different anatomy, not just a sleeve-count mismatch dog = make_character(registry, "dog") assert dog.wear_item("torso", "reptilian_jacket", registry) is False def test_dog_cannot_wear_a_human_backpack(registry): dog = make_character(registry, "dog") assert dog.wear_item("back", "backpack_basic", registry) is False def test_dog_can_wear_dog_equipment(registry): dog = make_character(registry, "dog") assert dog.wear_item("torso", "dog_harness", registry) is True assert dog.wear_item("back", "dog_saddlebag", registry) is True def test_biped_species_cannot_wear_dog_equipment(registry): human = make_character(registry, "human") reptilian = make_character(registry, "reptilian_quad") assert human.wear_item("torso", "dog_harness", registry) is False assert reptilian.wear_item("back", "dog_saddlebag", registry) is False def test_reptilian_and_zenari_share_biped_body_type_and_can_wear_each_others_jackets(registry): zenari = make_character(registry, "alien_tri") assert zenari.wear_item("torso", "reptilian_jacket", registry) is True # both bipeds, fits (2 <= 4) # --- wear_item: slot / replacement semantics ------------------------------------------------- def test_wear_item_rejects_item_meant_for_a_different_slot(registry): human = make_character(registry, "human") assert human.wear_item("back", "leather_jacket", registry) is False # leather_jacket is "torso" assert human.get_clothing("back") is None def test_wear_item_replaces_whatever_was_in_that_slot(registry): human = make_character(registry, "human") human.wear_item("torso", "leather_jacket", registry) human.wear_item("torso", "reptilian_jacket", registry) assert human.get_clothing("torso").item_def_id == "reptilian_jacket" assert len([c for c in human.clothing if c.slot == "torso"]) == 1 def test_wear_item_does_not_replace_on_failed_fit_check(registry): reptilian = make_character(registry, "reptilian_quad") reptilian.wear_item("torso", "reptilian_jacket", registry) assert reptilian.wear_item("torso", "leather_jacket", registry) is False assert reptilian.get_clothing("torso").item_def_id == "reptilian_jacket" # unchanged def test_take_off_clears_a_slot(registry): human = make_character(registry, "human") human.wear_item("torso", "leather_jacket", registry) human.take_off("torso") assert human.get_clothing("torso") is None def test_take_off_reveals_a_default_garment_underneath(registry): human = make_character(registry, "human", default_clothing=[ClothingPiece("torso", "leather_jacket")]) human.wear_item("torso", "reptilian_jacket", registry) assert human.get_clothing("torso").item_def_id == "reptilian_jacket" human.take_off("torso") assert human.get_clothing("torso").item_def_id == "leather_jacket" # fell back to the default