828afc15c0
Spells are SpellSpec dataclasses with typed effects: DamageEffect (dice + types, half-on-save), ConditionEffect (condition lookup + save negates), HealEffect (capped at hp_max), BuffEffect (transient StatModifiers). Range categories (personal/touch/close/medium/long) scale with caster level via spell_range_ft. JSON loader (load_spell/load_spell_registry) reads data/spells/*.json. The engine integrates spells via Action(kind='cast_spell') and _cast_spell: range check, line-of-effect gate, save resolution (resolve_save), effect application (_apply_spell_effects with DR via _apply_dr_for_types), transcript logging. The spell_registry is passed to CombatEngine; Combatant.spells holds known spell names. - spells.py: SpellSpec, 4 effect types, SpellRange/SaveType literals, spell_range_ft, JSON loader (uses Json type from foundry.py) - conditions.py: CONDITIONS_BY_NAME registry for condition lookup - combat.py: cast_spell Action kind, _execute_cast_spell dispatch, _cast_spell (range/LoE/save/effects/log), _apply_spell_effects, _apply_dr_for_types, _save_label helper, SpellSpec/BuffEffect/etc imports, spell_registry parameter on CombatEngine - models.py: spells field on Combatant - data/spells/: 10 spells (Magic Missile, Burning Hands, Fireball, Lightning Bolt, Acid Arrow, Cure Light/Moderate Wounds, Hold Person, Fear, Bull's Strength) - tests/test_spells.py: 29 tests (loading, range, damage/save/condition/ heal/buff/DR, out-of-range, unknown spell, dispatch, DC scaling) - pyproject.toml: PLR0913 ignore for combat.py (CombatEngine.__init__) - README.md: spells.py architecture section, Sorts removed from non-modeled list, 336 tests
66 lines
2.3 KiB
TOML
66 lines
2.3 KiB
TOML
[project]
|
||
name = "pf1e-simulator"
|
||
version = "0.1.0"
|
||
requires-python = ">=3.12"
|
||
dependencies = [
|
||
"pydantic>=2",
|
||
"pyyaml",
|
||
]
|
||
|
||
[project.scripts]
|
||
pf1e-sim = "pf1e_simulator.cli:main"
|
||
|
||
[build-system]
|
||
requires = ["hatchling"]
|
||
build-backend = "hatchling.build"
|
||
|
||
[tool.hatch.build.targets.wheel]
|
||
packages = ["src/pf1e_simulator"]
|
||
|
||
[dependency-groups]
|
||
dev = [
|
||
"pytest",
|
||
"ruff",
|
||
"basedpyright",
|
||
]
|
||
|
||
# ── Ruff ──────────────────────────────────────────────────────────────────────
|
||
[tool.ruff]
|
||
target-version = "py312"
|
||
line-length = 100
|
||
|
||
[tool.ruff.lint]
|
||
select = ["ALL"]
|
||
ignore = [
|
||
# D: docstring rules — we don't write docstrings everywhere in early scaffolding
|
||
"D",
|
||
# COM812: trailing-comma-in-missing — conflicts with ruff formatter
|
||
"COM812",
|
||
# ISC001: single-line-implicit-string-concatenation — conflicts with formatter
|
||
"ISC001",
|
||
# CPY001: missing copyright notice — we don't use copyright headers
|
||
"CPY001",
|
||
]
|
||
# RUF001: sigma in the CLI balance report is intentional, not a confusable
|
||
allowed-confusables = ["σ"]
|
||
|
||
[tool.ruff.lint.per-file-ignores]
|
||
# Tests: assert is expected, magic numbers are fine, annotations are noisy,
|
||
# parametrized golden tests legitimately take many arguments
|
||
"tests/**" = ["S101", "PLR2004", "ANN", "PLR0913", "PLR0917", "ARG001", "SLF001", "RUF059"]
|
||
# rng.py: `random.Random` is used for reproducible Monte Carlo streams, not cryptography
|
||
"src/pf1e_simulator/rng.py" = ["S311"]
|
||
# cli.py: stdout printing is the point of a CLI
|
||
"src/pf1e_simulator/cli.py" = ["T201"]
|
||
# combat.py: CombatEngine.__init__ needs 6 params (rng, grid, states, round_cap, policy, spell_registry)
|
||
"src/pf1e_simulator/combat.py" = ["PLR0913"]
|
||
|
||
# ── Basedpyright ──────────────────────────────────────────────────────────────
|
||
[tool.basedpyright]
|
||
typeCheckingMode = "strict"
|
||
include = ["src", "tests"]
|
||
|
||
# ── Pytest ────────────────────────────────────────────────────────────────────
|
||
[tool.pytest.ini_options]
|
||
testpaths = ["tests"]
|