Mi2dRPGamEng/tests/test_armor.py

66 lines
2.4 KiB
Python

from pathlib import Path
import pytest
from engine.character import ClothingPiece, Character
from engine.defs import DefRegistry
from resources.logic.combat import defender_armor, perform_attack
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)
class FixedRng:
def __init__(self, roll: int, choice_value=None):
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_defender_armor_sums_worn_clothing(registry):
defender = make_human(registry, clothing=[ClothingPiece("torso", "leather_jacket")])
assert defender_armor(defender, registry) == pytest.approx(3.0) # leather_jacket's armor_reduction
def test_unarmored_defender_has_zero_armor(registry):
defender = make_human(registry)
assert defender_armor(defender, registry) == 0.0
def test_armor_reduces_damage_taken(registry):
attacker = make_human(registry)
attacker.bio["athletics"] = 10
unarmored = make_human(registry)
armored = make_human(registry, clothing=[ClothingPiece("torso", "leather_jacket")])
unarmored_result = perform_attack(attacker, unarmored, registry, rng=FixedRng(roll=15, choice_value="torso"))
armored_result = perform_attack(attacker, armored, registry, rng=FixedRng(roll=15, choice_value="torso"))
assert armored_result.armor_reduction == pytest.approx(3.0)
assert armored_result.damage == pytest.approx(max(0.0, unarmored_result.damage - 3.0))
def test_heavy_armor_can_absorb_a_hit_entirely(registry):
attacker = make_human(registry)
defender = make_human(registry, clothing=[ClothingPiece("torso", "leather_jacket")])
# a roll that only barely clears the DC: margin (1) is smaller than armor_reduction (3)
result = perform_attack(attacker, defender, registry, rng=FixedRng(roll=11, choice_value="torso"))
assert result.hit is True # the check itself succeeded...
assert result.damage == 0.0 # ...but armor soaked up all of it
assert defender.get_body_part("torso").integrity == pytest.approx(100.0)