fix(combat): witch hex trigger uses the SRD close range scaled by caster level (25 ft + 5 ft per 2 levels, extracted as spells.close_range_ft and shared with spell_range_ft) instead of the fixed _HEX_RANGE_FT 25 - a level-5 witch reaches 35 ft; + scaling regression test

This commit is contained in:
2026-09-19 19:07:41 +02:00
parent 6f01a8ebdd
commit 238e5f201e
3 changed files with 31 additions and 4 deletions
+8 -3
View File
@@ -141,6 +141,7 @@ from pf1e_simulator.spells import (
SaveType,
SpellEffect,
SummonEffect,
close_range_ft,
save_descriptors_for_effects,
spell_range_ft,
spell_save_descriptors,
@@ -8884,7 +8885,6 @@ def _normal_actions(
_GROUPED_ENEMY_COUNT = 2
_HEX_RANGE_FT = 25
def _emit_channel_energy(
@@ -8910,12 +8910,17 @@ def _emit_channel_energy(
def _emit_hex(
engine: CombatEngine, state: CombatantState, target: CombatantState | None
) -> bool:
"""True when nairda should hex: resource available and target within close range."""
"""True when nairda should hex: resource available and target within close range.
APG hexes carry a close range, which scales with the caster level
(SRD, Magic - Range: "Close - 25 ft. + 5 ft. per 2 caster levels").
"""
if state.resources_left.get("hexes", 0) <= 0:
return False
if target is None or not target.active:
return False
return engine.creature_distance(state, target) * _SQUARE_FT <= _HEX_RANGE_FT
dist_ft = engine.creature_distance(state, target) * _SQUARE_FT
return dist_ft <= close_range_ft(state.combatant.level)
def _spell_combat_actions(
+7 -1
View File
@@ -368,13 +368,19 @@ class SpellSpec:
description: str = ""
def close_range_ft(caster_level: int) -> int:
"""PF1e (SRD, Magic — Range): "Close — 25 ft. + 5 ft. per 2 caster levels".
Shared by spell ranges and class features with a close range (witch hexes)."""
return 25 + 5 * (caster_level // 2)
def spell_range_ft(spell: SpellSpec, caster_level: int) -> int:
if spell.range == "personal":
return 0
if spell.range == "touch":
return 5
if spell.range == "close":
return 25 + 5 * (caster_level // 2)
return close_range_ft(caster_level)
if spell.range == "medium":
return 100 + 10 * caster_level
return 400 + 40 * caster_level