fix(rules): correct the evil eye hex

PF1e (APG Evil Eye): the target takes -2 on ONE chosen option (AC, ability checks, attack rolls, saving throws or skill checks) for 3 rounds, and "A Will save reduces this to just 1 round" — it never negates. _hex_evil_eye applied shaken (-2 attack AND saves) for 1 round with the save negating entirely. It now adds a targeted -2 attack ActiveBuff for 3 rounds, or 1 round on a successful Will save. Simplification documented in README: the option choice is not modeled (attack rolls are the engine's target). The hex-DC behavioral test now reads the -2 attack (3r) transcript line.

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 12:49:48 +02:00
parent 910ed1dc7d
commit f9c369380d
4 changed files with 61 additions and 16 deletions
+13 -12
View File
@@ -4756,27 +4756,28 @@ class CombatEngine:
elif hex_name == "cackle":
self._hex_cackle(state, target)
_EVIL_EYE_ROUNDS = 3
_EVIL_EYE_SAVED_ROUNDS = 1
def _hex_evil_eye(
self, state: CombatantState, target: CombatantState, hex_dc: int
) -> None:
"""Evil Eye: shaken (-2 AC or saves), 1 round, Will negates."""
"""Evil Eye (APG): -2 on one chosen option for 3 rounds; a Will save
reduces it to 1 round (never negates). Simplification: the chosen
option is attack rolls — the engine's other hex targets are not
selectable per cast."""
save_result = self.resolve_save(target, "will", hex_dc)
if save_result.success:
self._log(
f"round {self._current_round} {state.combatant.id}: evil eye on "
f"{target.combatant.id} -> SAVED"
)
return
target.active_conditions.append(
ActiveCondition(
condition=CONDITIONS_BY_NAME["shaken"],
rounds_left=1,
rounds = self._EVIL_EYE_SAVED_ROUNDS if save_result.success else self._EVIL_EYE_ROUNDS
target.active_buffs.append(
ActiveBuff(
modifiers=(StatModifier(target="attack", value=-2),),
rounds_left=rounds,
source=f"hex: evil_eye by {state.combatant.id}",
)
)
self._log(
f"round {self._current_round} {state.combatant.id}: evil eye on "
f"{target.combatant.id} -> shaken (1r)"
f"{target.combatant.id} -> -2 attack ({rounds}r)"
)
def _hex_slumber(