fix(rules): avoid the firing-into-melee penalty at 10 feet

SRD 'Attack - Shooting or Throwing into a Melee': a target at least 10 ft from the nearest friendly character lets you avoid the -4 penalty entirely (0, not -2). The -2 is reserved for targets two size categories larger than the engaged friendlies (0 at three+), which is not modeled (documented). Golden transcript unaffected (shot still misses).

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-09-12 13:21:26 +02:00
parent 84bcf004c3
commit d152d42af9
4 changed files with 29 additions and 12 deletions
+15 -6
View File
@@ -177,8 +177,7 @@ _UP_CLOSE_RANGE_FT = 30 # PF1e: Up Close and Deadly works within 30 ft
# PF1e: Point-Blank Shot grants +1/+1 within 30 ft with ranged weapons
_POINT_BLANK_RANGE_FT = 30
_FIRING_MELEE_PENALTY = -4 # PF1e: ranged attack into melee
_FIRING_MELEE_REDUCED_PENALTY = -2 # PF1e: -2 when the melee is 10+ ft away
_FIRING_MELEE_SAFE_FT = 10 # PF1e: 2 cells (10 ft) from attacker = reduced penalty
_FIRING_MELEE_SAFE_FT = 10 # PF1e: 2 cells (10 ft) = the -4 penalty is avoided
_SNEAK_ATTACK_FEATURE = "Sneak Attack" # PF1e: rogue class feature (precision dice)
_PRECISE_SHOT_FEATURE = "Precise Shot" # PF1e: feat negating firing-into-melee penalty
_IMPROVED_CRITICAL_FEATURE = "Improved Critical" # PF1e: feat doubling the threat range
@@ -2645,8 +2644,18 @@ class CombatEngine:
self, attacker: CombatantState, target: CombatantState
) -> int:
"""PF1e firing into melee: -4 on a ranged attack whose target is
engaged in melee, reduced to -2 when the target or every threatening
opponent stands 10+ ft from the attacker. Precise Shot removes it.
engaged in melee, avoided entirely (0) when the target or every
threatening opponent stands 10+ ft from the attacker. Precise Shot
removes it.
PF1e (SRD "Attack" — Shooting or Throwing into a Melee): "If your
target (or the part of your target you're aiming at, if it's a big
target) is at least 10 feet away from the nearest friendly character,
you can avoid the -4 penalty" — the 10+ ft clause is therefore 0, not
-2. The -2 applies only when the target is two size categories larger
than the friendly characters it is engaged with (and 0 at three or
more): size-category reduction is NOT modeled (documented
simplification).
The target is engaged when an active enemy of the target (not the
attacker itself) threatens the target's occupied cells with a melee
@@ -2665,11 +2674,11 @@ class CombatEngine:
if not threats:
return 0
if self.creature_distance(attacker, target) * _SQUARE_FT >= _FIRING_MELEE_SAFE_FT:
return _FIRING_MELEE_REDUCED_PENALTY
return 0
for threat in threats:
dist = self.creature_distance(attacker, threat) * _SQUARE_FT
if dist >= _FIRING_MELEE_SAFE_FT:
return _FIRING_MELEE_REDUCED_PENALTY
return 0
return _FIRING_MELEE_PENALTY
def _engaged_in_melee(self, state: CombatantState) -> bool: