Mi2dRPGamEng/tests/test_blocking.py

80 lines
2.9 KiB
Python

from pathlib import Path
import pytest
from engine.character import Character
from engine.defs import DefRegistry
from resources.logic.combat import 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 SequenceRng:
"""Deterministic stand-in: returns rolls from a fixed sequence, one call at a time."""
def __init__(self, rolls: list[int], choice_value=None):
self._rolls = list(rolls)
self._choice_value = choice_value
def randint(self, _lo, _hi):
return self._rolls.pop(0)
def choice(self, seq):
return self._choice_value if self._choice_value is not None else seq[0]
def test_non_blocking_defender_uses_flat_difficulty(registry):
attacker = make_human(registry)
defender = make_human(registry)
result = perform_attack(attacker, defender, registry, rng=SequenceRng([15], choice_value="torso"))
assert result.blocked_check is False
assert result.hit is True # 15 > BASE_DIFFICULTY(10)
def test_blocking_defender_uses_opposed_check(registry):
attacker = make_human(registry)
attacker.bio["athletics"] = 0
defender = make_human(registry, is_blocking=True)
defender.bio["athletics"] = 15 # strong defense roll
# attacker rolls 12, defender rolls 5 but has a high skill -> defender wins
result = perform_attack(attacker, defender, registry, rng=SequenceRng([12, 5], choice_value="torso"))
assert result.blocked_check is True
assert result.hit is False
def test_blocking_defender_can_still_be_hit_if_attacker_beats_the_opposed_check(registry):
attacker = make_human(registry)
attacker.bio["athletics"] = 15
defender = make_human(registry, is_blocking=True)
defender.bio["athletics"] = 0
result = perform_attack(attacker, defender, registry, rng=SequenceRng([18, 3], choice_value="torso"))
assert result.blocked_check is True
assert result.hit is True
def test_shield_bonus_helps_the_defender_block(registry):
attacker = make_human(registry) # bio athletics=0, so attacker_check == the raw roll
unshielded = make_human(registry, is_blocking=True)
shielded = make_human(registry, is_blocking=True)
shielded.wield_item("left_hand", "wooden_shield", registry)
# attacker rolls 10 (check=10), defender rolls 8 (check=8) both times;
# only wooden_shield's +4 block bonus should flip the outcome
result_unshielded = perform_attack(attacker, unshielded, registry, rng=SequenceRng([10, 8], choice_value="torso"))
result_shielded = perform_attack(attacker, shielded, registry, rng=SequenceRng([10, 8], choice_value="torso"))
assert result_unshielded.hit is True # 10 > 8
assert result_shielded.hit is False # 10 < 8 + 4 (shield bonus)