Commit Graph

311 Commits

Author SHA1 Message Date
ctan 910ed1dc7d fix(spells): make the bleed spell bleed
PF1e (SRD spells/bleed.md): "Saving Throw Will negates" and the target takes 1 point of damage per round. Two divergences: the JSON declared a Fortitude save, and the bleeding condition never set the engine's bleed_damage field, so the spell was a no-op. Bleed now saves Will; _apply_condition_effect sets bleed_damage = 1 when a spell applies bleeding, and _decrement_durations lands the final tick as the last bleeding condition expires before clearing the field (heal-path clearing already existed in _stop_bleeding). README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 12:46:53 +02:00
ctan 8c7e7075ad fix(spells): correct the sound burst save
PF1e (SRD spells/sound-burst.md): "Every creature in the area takes 1d8 points of sonic damage and must succeed on a Fortitude save to avoid being stunned for 1 round" — the Fortitude partial negates the stun only, never the dice. The damage component declared half_on_save: true, halving the sonic damage on a successful save. DamageEffect gains a save_negates flag (default True, existing behavior unchanged); sound_burst.json declares half_on_save: false + save_negates: false so the 1d8 is full regardless while the condition keeps save_negates. README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 12:31:06 +02:00
ctan e3818fa6c9 fix(rules): make the run reachability check avoid difficult terrain
PF1e (CRB Movement): "You can't run or charge across difficult
terrain". _execute_run checked the explicit destination against the full
cost field (which routes through difficult terrain at 2x) but descended
with avoid_difficult=True, so a destination beyond rubble was accepted
(ok=True) yet silently truncated at the obstacle. _destination_reachable
now takes the same avoid_difficult constraint (difficult cells removed
from the field; a destination whose footprint touches difficult terrain is
not a legal run endpoint either), so verdict and path agree. The test that
pinned the old silent-stop-short convention now expects
unreachable_destination; README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 11:53:27 +02:00
ctan 8043dd393c fix(rules): scale reposition and drag distance with the margin
PF1e (APG Reposition / Drag): "For every 5 by which your attack exceeds
your opponent's CMD, you can move/drag the target an additional 5 feet."
Both handlers now walk 1 + margin//5 cells along the chosen (or auto-picked)
direction, stopping at the first obstacle or occupied square, mirroring the
bull rush scaling. README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 11:43:12 +02:00
ctan f9420c7b09 fix(rules): scale dirty trick duration and drop nauseated
PF1e (APG Dirty Trick): "This condition lasts for 1 round. For every 5
by which your attack exceeds your opponent's CMD, the penalty lasts 1
additional round" — rounds_left = 1 + margin//5. The RAW condition list
(blinded, dazzled, deafened, entangled, shaken, sickened) does not include
nauseated, so it is removed from TrickCondition. README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 11:34:20 +02:00
ctan 34be75c492 fix(rules): apply AC penalties to CMD
PF1e (SRD Combat Maneuvers): "Any penalties to a creature's AC also
apply to its CMD." _maneuver_cmd now folds negative AC modifiers into the
sum regardless of bonus type (grappled -2, other untyped penalties), and —
a maneuver being a melee attack roll — the prone -4 melee AC penalty.
Positive modifiers keep the eight SRD-listed types. The test that pinned
the old ignore-penalties convention is updated; README documents the rule.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 11:26:05 +02:00
ctan a4f7f4e5de fix(rules): exclude weapon special ability dice from critical multiplication
PF1e (CRB Critical Hits): "additional damage dice from weapon special
abilities (such as flaming) are not multiplied when you score a critical
hit". _resolve_hit_damage now multiplies only the physical dice plus flat
bonuses by crit_mult; energy-typed component dice are added at 1x (the
energy share on the DR path and the per-component resistance step drop
their crit factor). Sneak precision dice were already excluded. README
and the module convention list updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 11:21:35 +02:00
ctan a9b33e4055 fix(rules): apply the spell combat penalty to the spell attack
PF1e (CRB Magus Spell Combat): "any attack roll made as part of this
spell also takes this penalty". _execute_spell_combat now threads the -2
through _cast_spell into the melee/ranged touch attack helpers, so e.g.
Shocking Grasp delivered via Spell Combat attacks at -2 too. No global
state is touched: the penalty is a keyword threaded per cast.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 11:14:30 +02:00
ctan 068b49794e fix(rules): stop steal from taking held weapons
PF1e (APG Steal): "Items held in the hands (such as wielded weapons or
wands) also cannot be taken with the steal maneuver—you must use the disarm
combat maneuver instead." The model carries no non-held items, so a
successful steal now takes nothing and logs
"nothing stealable — wielded weapons require disarm". README updated; the
retrieve_weapon tests keep locking the restoration mechanism directly.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 11:06:08 +02:00
ctan 57a597babd fix(rules): cap reposition and drag by size category
PF1e (APG Reposition / Drag): "You can only reposition/drag an opponent
that is no more than one size category larger than you" — the same cap the
SRD puts on trip/bull rush/overrun. reposition and drag join
_SIZE_RESTRICTED_MANEUVERS, so a two-categories-larger target is rejected
outright (no roll, no AoO). README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 10:58:13 +02:00
ctan 5a848fd07c fix(rules): compute CMD from Strength and Dexterity directly
PF1e (SRD Combat Maneuvers): CMD = 10 + BAB + Strength modifier +
Dexterity modifier + special size modifier. The Tiny-or-smaller
Dex-for-Str substitution is CMB-only, but _maneuver_cmd reused
_maneuver_cmb for the base, so Tiny/Diminutive/Fine creatures got
10 + BAB + 2xDex + size and dropped Strength (live bug on the Tiny PC
ierlieth). The CMD base is now computed with str_mod directly; CMB
keeps its substitution.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 10:54:21 +02:00
ctan e1c9e78b4e fix(rules): stop auto-directed movement cutting corners
PF1e (CRB, Measuring Distance): "You can't move diagonally past a corner
(even by taking a 5-foot step)". _best_move_step (the greedy descent behind
the auto-directed move/run/5-foot-step) now enforces the same
diagonal_allowed corner check _step5_to and _best_flee_step already apply.

tests/test_combat.py::test_ranged_no_line_of_effect_moves_around_wall
pinned the old corner-cutting step (0,1)->(1,2) past the wall at (0,2);
re-scripted for the legal (0,1)->(1,1) path (wall cover now applies).

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 10:48:12 +02:00
ctan 4b4e6f2726 fix(rules): stabilize a dying creature when healed
PF1e (CRB, Stable Characters and Recovery): any healing that cures a
dying creature of even 1 point makes it stable. _apply_heal_effect and
_channel_heal now set stabilized_hp when the healed hp stays negative,
so the creature stops losing 1 hp per round.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 10:35:44 +02:00
ctan 1363bb7f06 fix(rules): consume the current turn's swift for an in-turn immediate
PF1e (SRD Immediate Actions): "Using an immediate action on your turn is the same as using a swift action and counts as your swift action for that turn." The engine now tracks the acting combatant (_turn_actor); an immediate fired during its OWN turn sets swift_used_this_turn instead of immediate_used, so swift actions later in the turn's sequence are dropped (downgraded:immediate_swift) and no second immediate fires that round, while the next turn's swift stays free. Off-turn immediates keep consuming the next swift. The off-turn consumption test was retargeted to a true off-turn event and an in-turn test added; README updated (Actions immediates + budget classification).

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 10:00:25 +02:00
ctan dde6bc1f5d fix(rules): restrict nauseated creatures to a single move action
PF1e (SRD Conditions, nauseated): "The only action such a character can take is a single move actions per turn." _NAUSEA_MOVE_KINDS now holds only genuine move actions (move, stand_up, retrieve_weapon, repair_weapon): the 5-foot step and dropping prone are free actions and are dropped by the nauseated filter. The pinned filter test was retargeted; README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 09:44:53 +02:00
ctan 49aa79d612 fix(rules): restrict maneuvers to targets within one size category
PF1e (SRD Trip / Bull Rush / Overrun): "You can only [affect] an opponent who is no more than one size category larger than you." _execute_maneuver now rejects trip, bull_rush and overrun against a target two or more size categories larger: no roll, no provoked AoO, logged rejection. A _SIZE_ORDER ranking (Fine..Colossal, unknown -> Medium) backs the check; other maneuvers keep no size cap. README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 09:40:50 +02:00
ctan 1b60cd049b fix(rules): apply maneuver failure consequences
PF1e (SRD Trip): "If your attack fails by 10 or more, you are knocked prone instead" - a trip whose total lands at CMD-10 or below now knocks the attacker prone (1 round). PF1e (SRD Overrun): "If your overrun attempt fails, you stop in the space directly in front of the opponent, or the nearest open space in front of the creature" - a failed overrun from beyond adjacency walks the attacker to the free approach cell nearest the target; an already-adjacent attacker stays put. README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 09:34:57 +02:00
ctan 346e300eab fix(rules): scale the bull rush push distance with the margin
PF1e (SRD Bull Rush): "your target is pushed back 5 feet. For every 5 by which your attack exceeds your opponent's CMD you can push the target back an additional 5 feet." _bull_rush_push (and the explicit-direction branch) now walk 1 + margin//5 cells, stopping at the first obstacle; a natural-20 auto-success below CMD floors the margin at 0 (base push only). README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 09:27:03 +02:00
ctan 2f00d76ecc fix(rules): allow movement through friendly squares
PF1e (SRD Movement, Position and Distance): "You can move through a square occupied by a friendly character, unless you are charging." The move and run descents now route their Dijkstra cost field and greedy steps over hostile-only blocking (_blocked_hostile), so allies' squares are passable; a friendly square may only be entered when a free cell descends from it and the path tail is trimmed, so movement never ENDS on an occupied cell. Charge, withdraw, the auto 5-foot step and the Observation cost fields keep full blocking (documented). Corridor tests added; the Combat Reflexes multi-AoO transcript is unchanged. README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 09:18:29 +02:00
ctan faa8a72a86 fix(rules): let a natural 20 auto-succeed on escape
PF1e (SRD Combat Maneuvers): "Rolling a natural 20 while attempting a combat maneuver is always a success (except when attempting to escape from bonds)" - escaping a grapple is a combat maneuver, not bonds. _maneuver_escape now auto-succeeds on a natural 20 below CMD (the natural 1 auto-failure is unchanged). README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 08:58:11 +02:00
ctan c96579a485 fix(rules): forbid a diagonal 5-foot step past a corner
PF1e (SRD Measuring Distance): "You can't move diagonally past a corner (even by taking a 5-foot step)." _step5_to now rejects a diagonal destination whose two flanking squares are not both passable, reusing Grid.diagonal_allowed - the same corner rule the regular movement already applies. README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 08:54:36 +02:00
ctan 98b61c6cf8 fix(rules): add AC bonuses and flat-footed Dexterity to CMD
PF1e (SRD Combat Maneuver Defense): "A creature can also add any circumstance, deflection, dodge, insight, luck, morale, profane, and sacred bonuses to AC to its CMD [...] A flat-footed creature does not add its Dexterity bonus to its CMD." _maneuver_cmd now sums the target's eligible AC bonus modifiers (plus the dodge/circumstance runtime bonuses from total defense, fight defensively and aid another) and drops the Dexterity bonus (keeping any penalty) while the target denies its Dexterity to AC. README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 08:49:46 +02:00
ctan 47010c6e00 fix(rules): use Dexterity for the CMB of Tiny and smaller creatures
PF1e (SRD Combat Maneuvers): "Creatures that are size Tiny or smaller use their Dexterity modifier in place of their Strength modifier to determine their CMB." _maneuver_cmb now swaps Str for Dex when the size is Tiny, Diminutive or Fine. True 0-reach and co-occupancy for Tiny-or-smaller stay unmodelled (5-ft grid abstraction), documented in the README.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-12 08:44:44 +02:00
ctan 9d583a04c0 fix(rules): only total concealment blocks sneak attack
PF1e (CRB rogue Sneak Attack): "A rogue cannot sneak attack while
striking a creature with total concealment." _sneak_attack_dice now gates
on miss_chance >= 50 instead of any concealment > 0, so a blurred (20%)
target can still be sneak attacked while a displaced (50%) one cannot. The
test that pinned the old any-concealment denial was retargeted to total
concealment and a partial-concealment case added; README updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 23:41:06 +02:00
ctan a2825e73cc fix(rules): apply the power attack penalty to melee touch attacks
PF1e (CRB Power Attack): "take a -1 penalty on all melee attack rolls ...
The bonus damage does not apply to touch attacks." A melee touch (kind
"touch", no range increment) is a melee attack, so _power_attack_amt now
rides its attack and confirmation rolls; the +2X/+3X damage bonus stays
gated on kind == "melee". Ranged attacks and rays are unaffected. The
test that pinned the old melee-weapon-only simplification was rewritten to
lock the corrected behavior; README and abilities.py updated.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 23:35:07 +02:00
ctan 8a8b813889 fix(rules): pick the best target square for melee cover
PF1e (CRB Cover, Big Creatures and Cover): when making a melee attack
against a multi-square creature you can pick any of the squares it
occupies to determine cover. has_cover_cells/cover_bonus_cells now
aggregate the target side by the MINIMUM over target cells for melee and
keep the maximum (any line to any corner) for ranged; the attacker-side
minimum is unchanged. 1x1 geometry is bit-identical; no data case changes
today, locked by a unit test (Large target: melee 0, ranged +4).

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 23:29:59 +02:00
ctan 843cbf881c fix(rules): suppress attacks of opportunity through cover or total concealment
PF1e (CRB Cover): "You can't execute an attack of opportunity against an
opponent with cover relative to you"; (CRB Concealment): the same holds
against total concealment. _resolve_aoo now checks terrain cover
(cover_bonus_cells, melee line) and miss_chance >= 50 before striking,
logs the suppression and leaves the per-round budget unspent. Partial
concealment (blurred 20%) and normal attacks are unaffected.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 23:23:11 +02:00
ctan be2a755d17 fix(rules): stop damage reduction from eating energy damage
PF1e (CRB Damage Reduction): "Damage reduction does not negate ...
energy damage dealt along with an attack." _resolve_hit_damage now
splits the post-crit total and applies DR only to the non-energy share
(physical dice + flat bonuses + precision dice); energy components are
reduced solely by the per-component energy resistance/immunity step.
DR-bypass semantics (multi-component "and" requires every component)
are unchanged. Pure-physical weapons keep bit-identical arithmetic and
the golden transcripts are untouched.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 23:17:34 +02:00
ctan 1862c22b7b fix(rules): apply maneuver AoO damage as a penalty to the maneuver
PF1e (CRB Combat Maneuvers): "If you are hit by the target, you take the
damage normally and apply that amount as a penalty to the attack roll to
perform the maneuver." Capture the provoked AoO's damage in
_execute_maneuver and subtract it from the check total (floored at 0;
natural 20 still succeeds, natural 1 still fails; dropping below 0 hp
still forfeits). Escape and the Improved-feat exemption are untouched.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 23:11:57 +02:00
ctan 74bfeb5414 fix(rules): allow one movement opportunity per opponent per round
PF1e (CRB Attacks of Opportunity): moving out of more than one square
threatened by the same opponent in the same round counts as one
opportunity for that opponent. Track per-round movement provocation in
_move_aoo_provoked (cleared with _aoo_used at round start); the stand-up
trigger passes movement=False and still provokes. Ranged, casting and
maneuver triggers are untouched.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 23:08:11 +02:00
ctan 5568e0f8af fix(rules): knock prone only on a 5-point overrun margin
PF1e CRB 'Overrun': 'If your maneuver is successful, you move through
the target's space. If your attack exceeds your opponent's CMD by 5 or
more, ... the target is knocked prone.' The engine knocked the target
prone on ANY success. A plain success (margin 0-4) now only moves the
attacker through; prone requires total - CMD >= 5 (_OVERRUN_PRONE_MARGIN).

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 22:22:57 +02:00
ctan b453b19be2 fix(rules): stop a run from crossing difficult terrain
PF1e CRB 'Movement, Position and Distance - Difficult Terrain': 'You
can't run or charge across difficult terrain.' The run action reused the
move machinery (_descend_path), so it crossed rubble at 2x cost within
the 4x budget. The descent now takes an avoid_difficult option that
refuses every step whose footprint would touch a cell with move cost > 1
(the same rejection charge applies in _charge_path_clear); the run
moves up to the obstacle and stops there (deterministic, documented).
Move and charge behavior are unchanged.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 22:16:54 +02:00
ctan 4d89305881 fix(rules): distinguish natural reach from reach weapons
PF1e CRB 'Big and Little Creatures in Combat': a creature's natural
reach is a disk (a Large creature still threatens and strikes adjacent
squares), while a reach weapon doubles the wielder's natural reach but
'can't strike at their natural reach or less' (a ring whose dead zone is
the natural reach). The engine keyed the ring off reach_ft > 5, so
reach-10 natural attacks (giant belostomatid bite/claw, mounted
hooves) wrongly got a 5-ft dead zone.

AttackSpec gains reach_weapon (parsed from the combatant JSON); the
disk-vs-ring rule is centralized in _melee_reach_zone_cells and applied
consistently to weapon selection, melee usability, threatened squares
and charge end placement. Esha's Lance is the only reach weapon in the
shipped data; Large natural attackers keep the default (disk).

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 22:06:46 +02:00
ctan 4f6b076a49 fix(rules): exempt retrieve and repair weapon from the disabled hit-point cost
PF1e (CRB, Disabled): a disabled creature can take move actions without further injuring itself. retrieve_weapon and repair_weapon are budget-classified move actions (_ACTION_ECONOMY_MOVE_KINDS) but were absent from _DISABLED_MOVE_KINDS, so a creature at 0 hp paid 1 hp to draw or mend a weapon. Added both kinds to the exempt set.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 21:22:03 +02:00
ctan fa01ed74c5 fix(rules): stop delay from double-processing the turn start
A freshly-delayed combatant is re-inserted into the round order and _take_turn runs a second time in the same round. That second pass re-ran _decrement_durations and _turn_gate, double-ticking bleed, double-decrementing buff/condition durations and re-firing the fear aura. The start-of-turn block is now skipped when delayed_this_round is already set at entry (cleared at round start, set only by a delay action); the delayed turn still gets its policy call, budget and execution.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 21:15:14 +02:00
ctan 1b5cac234e fix(rules): tick bleed and auto-fail stabilization for a dying creature
PF1e (CRB, Stable Characters and Recovery): characters taking continuous damage such as bleed automatically fail all Constitution checks made to stabilize, losing 1 hp per round in addition to the continuous damage. _process_dying never applied bleed (only _turn_gate, reached by active creatures did), so a bleeding dying creature lost 0 hp per round. It now ticks bleed_damage at the start of the dying turn and auto-fails the check (no d20 consumed), then evaluates death.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 21:06:10 +02:00
ctan 32c09df264 fix(rules): keep swift and free actions for staggered combatants
PF1e (CRB, Staggered): a staggered creature takes a single move OR standard action but can still take free, swift, and immediate actions. _staggered_filter returned only the first non-full-round action, so a disabled combatant with a queued swift bonus (deed/inspire_courage) lost its standard action. It now keeps every swift and free action plus the first move-or-standard, preserving the full_attack -> single attack downgrade.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 20:59:19 +02:00
ctan 529999da69 fix(rules): correct the inspire courage bonus type and saves
PF1e CRB (Bardic Performance - Inspire Courage): the attack/weapon-damage
bonus is a COMPETENCE bonus (not morale), so it stacks with morale sources
like Heroism; the performance also grants a +1 MORALE bonus on saving throws
against charm and fear effects, implemented as two descriptor-conditional
will modifiers (fear / mind_affecting) that dedupe via morale stacking.
Simplifications (documented): flat +1 (no scaling per four bard levels) and
mind_affecting stands in for the missing charm descriptor.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 20:35:01 +02:00
ctan 0fefb9cdd2 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>
2026-09-11 20:30:19 +02:00
ctan e321c67779 fix(rules): allow a Will save to halve channeled energy damage
PF1e CRB (Channel Energy): creatures damaged by channeled energy get a Will
save (DC 10 + half the channeler's level + her Charisma modifier) for half
damage (floor). Harm mode only; heal mode unchanged. Charisma is used RAW
even for casters whose spellcasting ability differs (channeling is a
Charisma class feature).

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 20:24:51 +02:00
ctan 6f784d3369 fix(rules): require a ranged touch attack for ray spells
PF1e CRB (Magic - Ranged Touch Attacks): spells delivered by ray require a
ranged touch attack (BAB + Dex vs touch AC, no range increment) to hit a
hostile target; a miss wastes the slot. SpellSpec gains requires_ranged_touch,
set on the 8 SRD-confirmed rays (Ray of Frost, Ray of Enfeeblement, Scorching
Ray, Acid Arrow, Acid Splash, Disrupt Undead, Shard of Chaos, Spear of Purity).
Magic Missile and area spells are unaffected. Simplification (documented): no
size modifier / Weapon Finesse on the roll.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 20:19:03 +02:00
ctan 24af1687ab fix(spells): backfill casting times for all imported spells 2026-09-11 15:01:42 +02:00
ctan b3398c16ce feat(observation): expose spell cast time in the snapshot
The per-spell Observation dict gains the additive cast_time key: the
registry spell's budget code on a hit, "standard" on a miss (mirroring
the engine's resolver fallback), so an LLM policy can schedule casts
against the action budget it sees reported back.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 14:13:13 +02:00
ctan c5426ffe34 feat(spells): honor spell cast time in the action budget
SpellSpec gains a cast_time field (seven budget codes; the JSON loader
also accepts RAW phrasings like "1 round" or "1 minute"). The pure
budget filters take a CastTimeResolver so a cast_spell occupies the slot
its casting time maps to: standard->standard, swift->swift (competing
with deed/inspire courage and dropped by a consumed immediate),
immediate/free->free, full_round and one_round->full_round (one_round
clamped: resolved end-of-turn, documented approximation), long->dropped
before the budget filter with the new downgraded:cast_time reason. The
engine binds its registry lookup via _cast_time_of (unknown names fall
back to standard, keeping transcripts byte-identical);
_choose_spell_action never selects long casts; the staggered filter now
drops full-round casts and spell_combat via the effective slot
(_FULL_ROUND_KINDS becomes dead and is deleted). Summon Monster I/II are
the only data spells marked 1 round. Metamagic full-round casting for
spontaneous casters is out of scope (future hook documented in
_cast_time_of).

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 14:09:58 +02:00
ctan 0997c8d1b5 feat(rules): allow a move action in place of a standard action
PF1e CRB (Actions in Combat): a move action can be taken instead of the
standard one. The budget filter now converts a second move action onto
the standard slot when the move slot is spent and the standard is still
free, so (move, stand_up) and (move, move) are legal; a third move (or
any further standard) is still surplus. The greedy walk is expressed
with a spent-slot map to stay inside the C901 complexity ceiling.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 13:53:45 +02:00
ctan e44ec75f2b fix(rules): classify run as a full-round action
PF1e CRB: running is a full-round action, not a move action. The budget
filter now classifies run as full-round (consumes the standard AND the
move slot), _FULL_ROUND_KINDS includes it for the staggered filter, and
the nauseated filter drops it (run is no longer move-like). The
moved_this_turn/running flags are unchanged; the _execute_run
moved_this_turn early return stays as defense in depth. default_policy
never emits run, so the golden transcripts are untouched.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-09-11 13:48:58 +02:00
ctan 9c6f5e277e feat(cli): render --transcript output as a table 2026-09-11 13:02:31 +02:00
ctan d6c8f88f77 feat(cli): add --simple-monster-death option to kill monsters at hp <= 0 2026-09-11 12:48:43 +02:00
ctan b7c80babfd fix(rules): enforce the action-economy budget on policy output
Apply the PF1e per-turn action budget (CRB Actions in Combat: one
standard + one move, or one full-round in place of both, plus one
swift) unconditionally to every sequence a policy returns, not only
the immediate/staggered/nauseated specializations.

- _action_economy_filter: greedy in-order walk keeping the earliest
  legal prefix-subsequence; a full-round action is only kept while
  both the standard and move slots are still free.
- Exhaustive kind->slot classification (standard / move / swift /
  full_round / free-conditional) over the Action.kind Literal,
  documented and locked by tests.
- Surplus actions dropped and reported as
  ActionResult(ok=False, reason="downgraded:action_economy") via a
  multiset drop diff (reports duplicate-kind surplus the set-based
  _dropped_kinds cannot).
- Composition order: general budget first, then the existing
  immediate/staggered/nauseated filters (unchanged).
- default_policy untouched and its turns verified legal by the
  validator; golden transcripts byte-identical.
2026-09-11 12:26:49 +02:00
ctan a4814b935b fix(rules): apply cover by attacker's best corner for multi-square attackers 2026-09-11 11:43:10 +02:00