fix(rules): apply the -2 spell combat penalty to melee attacks
PF1e CRB (Magus Spell Combat): as a full-round action the magus casts a standard-action spell and makes all his melee attacks at -2. The penalty is threaded through the full-attack chain (_execute_attack -> _full_attack -> _full_attack_weapon -> _attack/_resolve_swing -> resolve_attack bonus_override) so it applies to every attack roll and crit confirmation. Simplification: the arcane pool cost is still not modeled. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -336,3 +336,42 @@ def test_misty_silent_when_bardic_rounds_exhausted() -> None:
|
||||
|
||||
assert not any(a.kind == "inspire_courage" for a in actions)
|
||||
assert not any(a.kind == "spell_combat" for a in actions)
|
||||
|
||||
|
||||
def test_spell_combat_melee_attacks_take_minus_two() -> None:
|
||||
"""CRB Magus Spell Combat: the full attack that accompanies the cast is
|
||||
made at -2 on every attack roll (vs the same swing in a normal full attack)."""
|
||||
misty = _combatant(
|
||||
"misty", resources={"bardic_rounds": 12}, spells=["Create Alcool"]
|
||||
)
|
||||
goblin = _combatant("goblin", hp_max=6)
|
||||
reg = load_spell_registry(SPELLS_DIR)
|
||||
# Queue: goblin AoO d20 (natural 1, auto-miss), then misty's swing d20=10.
|
||||
engine, me, enemy = _engine(misty, [goblin], spell_registry=reg, rng_queue=[1, 10])
|
||||
|
||||
engine._execute(
|
||||
me,
|
||||
Action(
|
||||
kind="spell_combat", target_id=enemy[0].combatant.id,
|
||||
spell_name="Create Alcool",
|
||||
),
|
||||
)
|
||||
|
||||
# Sword attack_bonus 3 + Spell Combat -2 = +1: d20 10 -> total 11 (misses AC 15).
|
||||
assert any(
|
||||
"sword vs goblin d20=10+1=11" in line for line in engine._transcript
|
||||
)
|
||||
|
||||
|
||||
def test_normal_full_attack_has_no_spell_combat_penalty() -> None:
|
||||
"""Control: the same scripted swing in a plain full attack keeps its +3."""
|
||||
misty = _combatant("misty", resources={"bardic_rounds": 12})
|
||||
goblin = _combatant("goblin", hp_max=6)
|
||||
reg = load_spell_registry(SPELLS_DIR)
|
||||
engine, me, enemy = _engine(misty, [goblin], spell_registry=reg, rng_queue=[10])
|
||||
|
||||
engine._execute(me, Action(kind="full_attack", target_id=enemy[0].combatant.id))
|
||||
|
||||
assert any(
|
||||
"sword vs goblin d20=10+3=13" in line for line in engine._transcript
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user