feat(runner): wire spell registry in CLI and Monte Carlo
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"""Wiring tests: the Monte Carlo runner loads the real spell registry and
|
||||
spellcasting PCs cast against ``data/spells/``.
|
||||
|
||||
The engine's ``spell_registry`` defaults to ``{}`` for retro-compat with pure
|
||||
unit tests; the runner must therefore load the registry from ``SPELLS_DIR`` and
|
||||
pass it into every ``CombatEngine`` so a caster PC actually produces
|
||||
``cast_spell`` actions in Monte Carlo.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from pf1e_simulator.combat import CombatEngine
|
||||
from pf1e_simulator.grid import Grid
|
||||
from pf1e_simulator.loaders import load_combatant
|
||||
from pf1e_simulator.map import load_map
|
||||
from pf1e_simulator.rng import SeededRng
|
||||
from pf1e_simulator.runner import EncounterSpec, Side, build_states
|
||||
from pf1e_simulator.spells import SPELLS_DIR, load_spell_registry
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
MAP = ROOT / "data" / "maps" / "sample_arena.yaml"
|
||||
ONI = ROOT / "data" / "pcs" / "oni.json"
|
||||
GOBLIN = ROOT / "data" / "monsters" / "goblin.json"
|
||||
|
||||
_NUM_SPELLS = 11
|
||||
|
||||
|
||||
def test_runner_loads_realtime_spell_registry() -> None:
|
||||
"""The runner's registry source holds all 11 real spells from data/spells/."""
|
||||
registry = load_spell_registry(SPELLS_DIR)
|
||||
assert len(registry) == _NUM_SPELLS
|
||||
|
||||
|
||||
def test_monte_carlo_caster_pc_casts_spell() -> None:
|
||||
"""oni (cleric) casts against data/spells/ once it drops below 50% HP.
|
||||
|
||||
oni's known spells overlap the registry's heal spells (Cure Light/Moderate
|
||||
Wounds); with enough damage taken it heals via cast_spell. The Monte Carlo
|
||||
loop mirrors run_encounter: build fresh states and one CombatEngine per run
|
||||
with the registry from SPELLS_DIR.
|
||||
"""
|
||||
spec = EncounterSpec(
|
||||
map=load_map(MAP),
|
||||
round_cap=100,
|
||||
sides=(
|
||||
Side(name="players", combatants=(load_combatant(ONI),), zone="A"),
|
||||
Side(name="monsters", combatants=(load_combatant(GOBLIN),) * 4, zone="B"),
|
||||
),
|
||||
)
|
||||
registry = load_spell_registry(SPELLS_DIR)
|
||||
grid = Grid.from_spec(spec.map)
|
||||
casts = 0
|
||||
for i in range(100):
|
||||
states = build_states(spec)
|
||||
rng = SeededRng(7 + i)
|
||||
result = CombatEngine(
|
||||
rng, grid, states, round_cap=spec.round_cap, spell_registry=registry
|
||||
).run()
|
||||
casts += sum(
|
||||
1
|
||||
for line in result.transcript
|
||||
if " vs " in line and "cast " in line
|
||||
)
|
||||
assert casts > 0
|
||||
Reference in New Issue
Block a user