ctan
cfeb28e336
feat(combat): expose per-pair movement and threat info in observation
2026-09-06 14:01:34 +02:00
ctan
90c71bbeb0
feat(combat): expose class features and spell data in observation snapshot
2026-09-06 13:54:26 +02:00
ctan
f3d874790a
feat(combat): expose weapon reference in observation snapshot
2026-09-06 13:46:12 +02:00
ctan
cd8051f2c4
feat(combat): expose combat stats in observation snapshot
2026-09-06 13:38:53 +02:00
ctan
e75ab58055
feat(combat): add serializable Observation snapshot and LLMPolicy adapter
2026-09-06 11:07:30 +02:00
ctan
7843756de2
feat(combat): expose charge failure reasons via ChargeResult
2026-09-06 10:47:36 +02:00
ctan
56c8970d5b
feat(combat): expose threatened squares and movement cost fields for LLM policy
...
Rename _threatened_squares -> threatened_squares and
_enemies_threatening -> enemies_threatening (public read-only API for a
future LLM policy), and add reachable_ft(state, budget) and
movement_cost_ft(state, target) accessors returning movement costs in
feet. Pure exposure: no behavior change, resolution engine untouched,
goldens bit-identical.
2026-09-06 10:36:48 +02:00
ctan
9c49f85af8
feat(combat): resolve all natural melee weapons in full_attack
2026-09-06 10:22:58 +02:00
ctan
fdcd103e8a
feat(combat): add repair_weapon action to fix broken weapons
2026-09-06 10:05:55 +02:00
ctan
8e957c9fac
feat(combat): add retrieve_weapon action to recover stolen weapons
2026-09-06 10:01:07 +02:00
ctan
b640e29a91
feat(combat): add trick_condition field to Action for dirty trick
2026-09-05 18:49:56 +02:00
ctan
7fbf3988e9
feat(combat): add direction field to Action for directional maneuvers
2026-09-05 18:37:26 +02:00
ctan
66b6d1f387
feat(combat): support off-turn immediate actions via reaction policy
2026-09-05 17:03:51 +02:00
ctan
ab99ab67e3
feat(grid): apply elevation to movement cost and high ground
2026-09-05 16:18:56 +02:00
ctan
30f8905a3e
feat(combat): support multi-cell occupancy for large and larger creatures
2026-09-05 16:01:28 +02:00
ctan
7f57df16a6
feat(combat): support variable melee reach for weapons and creature size
2026-09-05 15:10:21 +02:00
ctan
7cb3653750
fix(combat): apply save negates to targeted spell damage effects
2026-09-05 12:52:58 +02:00
ctan
cd75a4f2bf
feat(combat): implement overrun, dirty trick, steal, reposition and drag maneuvers
2026-09-05 12:37:06 +02:00
ctan
2f2acd992f
fix(combat): evaluate conditional stat modifiers with action context
2026-09-05 12:17:58 +02:00
ctan
31d970dd5f
fix(combat): resolve touch attacks against touch AC and firearms
2026-09-05 11:28:46 +02:00
ctan
22d76e9677
fix(combat): channel energy targets living vs undead
2026-09-05 00:16:17 +02:00
ctan
7591614460
feat(cli): add --transcript option
2026-09-04 23:34:12 +02:00
ctan
83a5250ca6
fix(combat): deed range gating
2026-09-04 23:02:27 +02:00
ctan
c5f31c30d1
fix(combat): summon spawns only on passable cells
2026-09-04 23:02:27 +02:00
ctan
0dcb967033
test(combat): pin ScriptedRng transcripts, unique per scenario
2026-09-04 23:02:26 +02:00
ctan
6e08df6eb6
feat(combat): class abilities from default_policy
2026-09-04 23:02:26 +02:00
ctan
66a664ad85
fix(data): lich fear aura, paralyzing touch, slot keys
2026-09-04 23:02:26 +02:00
ctan
d0833c7a2c
feat(data): wire all 55 PC feats
2026-09-04 23:02:25 +02:00
ctan
5353018c80
fix(combat): single roll to escape grapple
2026-09-04 23:02:25 +02:00
ctan
f575c77037
fix(combat): sunder damages weapon not HP
2026-09-04 23:02:25 +02:00
ctan
6e4a9d8323
feat(combat): Combat Reflexes extra AoOs
2026-09-04 23:02:24 +02:00
ctan
679d405943
feat(combat): enforce prone/staggered/nauseated/paralyzed
2026-09-04 23:02:24 +02:00
ctan
0d61ad44ab
fix(combat): bound cackle hex extension
2026-09-04 23:02:24 +02:00
ctan
735642a607
fix(combat): summoned creatures act and expire
2026-09-04 23:02:23 +02:00
ctan
2e4d192522
refactor(combat): single source active_buffs/active_conditions
2026-09-04 23:02:23 +02:00
ctan
073da40fca
feat(combat): class-ability action kinds, engine RNG only
2026-09-04 23:02:22 +02:00
ctan
0058e71550
fix(combat): correct hex and AoE DCs, DR bypassed by spells
2026-09-04 23:02:22 +02:00
ctan
a7729eebf1
fix(combat): correct concentration DCs by situation
2026-09-04 23:02:22 +02:00
ctan
625e8c56b9
feat(runner): wire spell registry in CLI and Monte Carlo
2026-09-04 23:02:21 +02:00
ctan
fd94522546
feat(data): per-level spell slots for 8 PCs
2026-09-04 23:02:21 +02:00
ctan
1893072b5d
chore(lint): restore green gate
2026-09-04 23:02:20 +02:00
ctan
934d443d7d
feat(combat): summoning
2026-09-04 23:02:18 +02:00
ctan
8ae344fd16
feat(combat): area-of-effect spells
2026-09-04 23:02:17 +02:00
ctan
d792b6e28f
feat(combat): AoO and concentration on casting
2026-09-04 23:02:16 +02:00
ctan
0c2e3383d7
feat(combat): enforce behavioral condition flags
2026-09-04 23:02:16 +02:00
ctan
789d2f5396
fix(combat): correct spell DC formula
2026-09-04 23:02:15 +02:00
ctan
82148cea1e
test(loaders): add unit tests for combatant feat resolution and feature/spell handling
...
Tests for _resolve_feat (known/unknown/Toughness/Weapon Focus),
_resolve_features (filtering, empty lists), load_combatant with
features+spells integration, and backward-compat aliases.
Gate: 401 tests, ruff clean, basedpyright clean.
2026-08-18 15:11:28 +02:00
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
e9e8c26d50
feat(loaders): extend Foundry loader with feat/spell extraction
...
Map Foundry feat strings to AbilitySpec constants (Power Attack, Iron Will,
Alertness, Point-Blank Shot, Precise Shot, Dodge, Weapon Focus (X)).
Extract spell names from spellcasting.spells into Combatant.spells.
Wire features and spells into load_sheet_detailed return.
Add 41 tests (unit + golden on 8 real sheets).
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