5 Commits

Author SHA1 Message Date
ctan c88d8fd6f4 refactor(loaders): unify combatant loader, migrate PC features/spells
Rename monster.py → combatant.py with _KNOWN_FEATS lookup table
that resolves feat name strings to AbilitySpec constants (Power Attack,
Iron Will, Toughness, Weapon Focus, etc.). Unknown feats produce
minimal AbilitySpec (data preserved for future implementation).

Migrate all 8 PC JSONs (data/pcs/) with complete feat/spell lists
extracted from Foundry sheets — including traits, racial abilities,
and all spells. Monsters (goblin, orc) unchanged (no feats/spells).

Update all imports, add backward-compatible aliases (load_monster,
MonsterLoadError), update CLI to use load_combatant.

Gate: 377 tests, ruff clean, basedpyright clean.
2026-08-17 22:49:50 +02:00
ctan 828afc15c0 feat(spells): add spell system with 10 combat spells, cast_spell action
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
2026-08-17 22:49:50 +02:00
ctan 7297494e56 feat(data): transpose Foundry PC sheets into data/pcs
All 8 sheets from fiches_personnages/ converted to the strict Combatant
JSON schema (data/monsters convention) so the CLI can run PCs directly:

  --side players data/pcs/esha.json

- id derived from the file stem; source field points at the original sheet
- oni: placeholder attacks without encoded damage ('une Pioche', 'Weapon')
  left out, documented in notes (pick stats ambiguous light/heavy in the
  rules KB; no identification possible for 'Weapon')
- README: PC section now documents data/pcs usage
- tests: parametrized load check + golden spots for the 8 PC files
2026-08-17 22:49:50 +02:00
ctan 21698d76c6 feat(grid): map YAML schema, 5-10-5 grid, Dijkstra movement, corner LoS/cover 2026-08-17 22:49:50 +02:00
ctan 6ad37ae9ec feat(models): combatant schema, Foundry sheet loader, monster JSON schema 2026-08-17 22:49:50 +02:00