from pathlib import Path import pytest from engine.character import Ailment, Character from engine.defs import DefRegistry from resources.logic.health_ticks import apply_bleeding_tick, apply_boost_expiry_tick from resources.logic.medical import treat_bleeding 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_hydraulibot(registry, **kwargs) -> Character: return Character(species_id="hydraulibot", default_body_parts=registry.new_default_body_parts("hydraulibot"), **kwargs) def make_motorbot(registry, **kwargs) -> Character: return Character(species_id="motorbot", default_body_parts=registry.new_default_body_parts("motorbot"), **kwargs) # --- treat_bleeding: species/item compatibility ----------------------------------------------- def test_bandage_treats_a_severed_limb_on_a_human(registry): human = make_human(registry) part = human.get_or_create_body_part_override("left_arm") part.removed = True assert treat_bleeding(human, "left_arm", "bandage", registry) is True assert part.bandaged is True def test_sealant_does_not_work_on_a_human(registry): human = make_human(registry) part = human.get_or_create_body_part_override("left_arm") part.removed = True assert treat_bleeding(human, "left_arm", "sealant", registry) is False assert part.bandaged is False def test_bandage_does_not_work_on_a_hydraulibot(registry): hydraulibot = make_hydraulibot(registry) part = hydraulibot.get_or_create_body_part_override("left_arm") part.removed = True assert treat_bleeding(hydraulibot, "left_arm", "bandage", registry) is False def test_sealant_treats_a_severed_limb_on_a_hydraulibot(registry): hydraulibot = make_hydraulibot(registry) part = hydraulibot.get_or_create_body_part_override("left_arm") part.removed = True assert treat_bleeding(hydraulibot, "left_arm", "sealant", registry) is True assert part.bandaged is True def test_sealant_treats_a_popped_fluid_hose_on_a_hydraulibot(registry): hydraulibot = make_hydraulibot(registry) part = hydraulibot.get_or_create_body_part_override("left_leg") part.ailments.append(Ailment(id="popped_fluid_hose", name="Popped Fluid Hose", severity=0.6)) assert treat_bleeding(hydraulibot, "left_leg", "sealant", registry) is True assert part.bandaged is True def test_treat_bleeding_is_a_no_op_when_the_part_is_not_bleeding(registry): human = make_human(registry) human.get_or_create_body_part_override("left_arm") # healthy, not removed assert treat_bleeding(human, "left_arm", "bandage", registry) is False def test_treat_bleeding_is_a_no_op_when_already_bandaged(registry): human = make_human(registry) part = human.get_or_create_body_part_override("left_arm") part.removed = True part.bandaged = True assert treat_bleeding(human, "left_arm", "bandage", registry) is False # --- apply_bleeding_tick: bandaging actually stops the loss ------------------------------------ def test_bandaged_severed_limb_does_not_bleed(registry): human = make_human(registry) part = human.get_or_create_body_part_override("left_arm") part.removed = True part.bandaged = True apply_bleeding_tick(human, registry, ticks=5) assert human.blood_percentage == 100.0 def test_unbandaged_severed_limb_still_bleeds(registry): human = make_human(registry) part = human.get_or_create_body_part_override("left_arm") part.removed = True apply_bleeding_tick(human, registry, ticks=5) assert human.blood_percentage < 100.0 def test_popped_fluid_hose_causes_bleeding_until_bandaged(registry): hydraulibot = make_hydraulibot(registry) part = hydraulibot.get_or_create_body_part_override("left_leg") part.ailments.append(Ailment(id="popped_fluid_hose", name="Popped Fluid Hose", severity=1.0)) apply_bleeding_tick(hydraulibot, registry, ticks=5) assert hydraulibot.blood_percentage < 100.0 hydraulibot.blood_percentage = 100.0 part.bandaged = True apply_bleeding_tick(hydraulibot, registry, ticks=5) assert hydraulibot.blood_percentage == 100.0 def test_ripped_tendon_alone_does_not_cause_bleeding(registry): human = make_human(registry) part = human.get_or_create_body_part_override("left_leg") part.ailments.append(Ailment(id="ripped_tendon", name="Ripped Tendon", severity=1.0)) apply_bleeding_tick(human, registry, ticks=5) assert human.blood_percentage == 100.0 def test_motorbot_never_bleeds_even_when_dismembered(registry): motorbot = make_motorbot(registry) part = motorbot.get_or_create_body_part_override("left_arm") part.removed = True apply_bleeding_tick(motorbot, registry, ticks=10) assert motorbot.blood_percentage == 100.0 def test_motorbot_broken_frame_piece_does_not_cause_bleeding(registry): # unlike popped_fluid_hose, broken_frame_piece isn't a causes_bleeding ailment motorbot = make_motorbot(registry) part = motorbot.get_or_create_body_part_override("left_leg") part.ailments.append(Ailment(id="broken_frame_piece", name="Broken Structural Frame Piece", severity=1.0)) apply_bleeding_tick(motorbot, registry, ticks=10) assert motorbot.blood_percentage == 100.0 # --- apply_boost_expiry_tick -------------------------------------------------------------------- def test_boost_expiry_tick_clears_an_expired_boost(registry): human = make_human(registry) human.active_boosts["strength"] = 1.6 human.boost_expirations["strength"] = 10.0 apply_boost_expiry_tick(human, now=10.0) assert "strength" not in human.active_boosts assert "strength" not in human.boost_expirations def test_boost_expiry_tick_leaves_a_still_active_boost(registry): human = make_human(registry) human.active_boosts["speed"] = 1.6 human.boost_expirations["speed"] = 10.0 apply_boost_expiry_tick(human, now=5.0) assert human.active_boosts["speed"] == 1.6