Skip to content

Make the cobra's spit blind, turn ghouls from the paralysed, pass over statues, and gaze on a basilisk's surprise - #199

Merged
mmacy merged 8 commits into
mainfrom
chunk/monster-tactics
Oct 30, 2026
Merged

mmacy merged 8 commits into
mainfrom
chunk/monster-tactics

Conversation

@mmacy

@mmacy mmacy commented Oct 30, 2026

Copy link
Copy Markdown
Owner

Fixes from round 3 of playtesting a game built on osrlib.

What changed

  • The cobra's spit blinds. A hit makes the target save versus death (the B/X poison save), or be blind for good, as the SRD says: "A hit causes permanent blindness (save vs poison)". A blind member can't attack ("A blind character is unable to attack"), and no gaze reaches them. The catalog's spit ability is now tagged blindness, not blinding_spit, and isn't manual.
  • Ghouls and thouls attack others. "After paralysing a target, ghouls will attack others", and the thoul's entry says the same. The default policy passes over a paralysed member while someone else is in reach. It reads a new attacks_others param on the paralysis ability, so a monster a game defines can use it too.
  • Statues. Monsters and NPC adventurers pass over a member turned to stone while someone else is in reach. When everyone in reach is stone, they still attack a statue, so the battle can end. The SRD doesn't say this, so the adaptations register records it as a judgment.
  • The basilisk's surprise gaze. Every living member of a surprised party meets the gaze once as the encounter opens, whatever the reaction ("Characters surprised by a basilisk meet its gaze"). Before, it only happened when the encounter went straight to battle. A basilisk that joins an open encounter surprised no one, so it doesn't gaze.

What to check

  • No golden file changed. With no paralysed or petrified member in reach, the target draw is the same as before, and draw-by-draw tests pin that.
  • One test in test_attack_routines.py pinned the spit doing nothing, so I removed it.
  • One case I left for a separate decision: if a surprise gaze turns the whole party to stone and no battle opens, the session stays in the encounter, because game over comes only from a death.

https://claude.ai/code/session_01V7ErtnsmhaP7aLwcfmzohD

mmacy added 8 commits October 30, 2026 15:33
Four playtest findings, each pinned by docstrings, the adaptations
register, and tests/test_monster_tactics.py. The tests are marked
xfail(reason="chunk: monster-tactics", strict=True), and the ones that
pass today are unmarked guards. No behavior changes in this commit.

- A spitting cobra's spit hit makes the target save versus death, the
  category for poison, or be blinded for good. The cobra's ability takes
  the effect's tag, blindness, and isn't manual.
- A monster whose paralysis ability has the param attacks_others, the
  ghoul and the thoul, passes over a member it has paralysed while
  another target is in reach.
- No monster picks a member turned to stone while another target is in
  reach. A paralysed member comes before a statue. When every member in
  reach is stone, the monster attacks a statue, as before.
- Every member of a party a basilisk surprises meets its gaze once as
  the encounter opens, whatever the stance, and a later battle doesn't
  repeat it.

The guard test_the_cobras_spit_applies_no_save_in_battle is removed from
tests/test_attack_routines.py, because the spit now blinds.
APPLIED_KINDS in tests/test_monster_attack_effects.py counts blindness.
No golden file changes.

Claude-Session: https://claude.ai/code/session_01V7ErtnsmhaP7aLwcfmzohD
…atues, and gaze on surprise

Four playtest findings, made to pass tests/test_monster_tactics.py.

- The spitting cobra's spit ability compiles under the tag blindness
  and isn't manual. Battle applies a blindness hit effect: the target
  saves versus death, the category for poison, or gains a permanent,
  undispellable blind condition. A second blinding attaches nothing.
- The ghoul's and the thoul's paralysis abilities carry attacks_others.
  ScriptedPolicy narrows its reachable targets before the draw: it drops
  statues while anyone else is in reach, and a monster with
  attacks_others also drops paralysed members while someone neither
  paralysed nor stone is in reach. An all-stone front rank comes back
  whole. A list with no paralysed or petrified member is unchanged, so
  the monster-action draw is the same as before.
- start_encounter runs the basilisk's surprise gaze on every living
  member as the encounter opens, whenever the party is surprised. The
  monsters' free round skips the gaze of such a gazer when the
  encounter's party_surprised is set, so no member meets it twice. The
  existing party_surprised field is the record, so no serialized model
  changes.

Data regenerated with python -m tools.srd_compile. No golden file
changed. CHANGELOG adds a Fixed bullet for the cobra, the ghouls, and
the statues, rewrites the unreleased surprise-gaze bullet to describe
the final behaviour, and extends the 2.0.1 replay list.

Claude-Session: https://claude.ai/code/session_01V7ErtnsmhaP7aLwcfmzohD
NpcPartyPolicy melees "the same as a monster", so an NPC adventurer
shouldn't pick a member turned to stone while another target is in
reach. One acceptance test pins that, marked
xfail(reason="chunk: monster-tactics", strict=True). Two guards pin
that a front rank of statues is still attacked with the same draw as
before, and that an NPC with no statue in reach draws as before, with
a paralysed member still a candidate. The ghoul's rule about paralysed
members belongs to the ghoul's and the thoul's abilities, so it doesn't
apply to NPCs.

Claude-Session: https://claude.ai/code/session_01V7ErtnsmhaP7aLwcfmzohD
NpcPartyPolicy's melee target choice now goes through the statue half
of the monster rule: it leaves out members turned to stone while a
target that isn't stone is in reach, and keeps the whole list when
every target is stone. A list with no statue is unchanged, so the
monster-action draw is the same as before. The ghoul's and the thoul's
rule about paralysed members stays with ScriptedPolicy, because it
belongs to their abilities.

_preferred_targets now builds on the shared _passing_over_statues. The
NpcPartyPolicy docstring says how an NPC picks its melee target instead
of "the same as a monster". The adaptations register and the statue
changelog bullet and replay item name the NPC case. No golden file
changed.

Claude-Session: https://claude.ai/code/session_01V7ErtnsmhaP7aLwcfmzohD
…gaze

Someone who can't see can't meet a gaze. Three acceptance tests, marked
xfail(reason="chunk: monster-tactics", strict=True), pin that a blind
front-rank member is spared the basilisk's and the medusa's gaze in a
battle round, and that a blind member is spared the surprise gaze when
the encounter opens. Each asserts the blindness as a precondition.

A guard pins that a basilisk spawned into an encounter already open
doesn't gaze at a party that was surprised when the encounter opened,
because the basilisk surprised no one. It holds today.

The adaptations register says both.

Claude-Session: https://claude.ai/code/session_01V7ErtnsmhaP7aLwcfmzohD
Someone who can't see can't meet a gaze. resolve_gaze now skips a
creature with the blind condition, as it skips one averting its eyes,
so neither the battle round's front-rank gaze nor the basilisk's
surprise gaze reaches a blind member. A blind creature rolls no save,
so the combat stream draws one fewer for each blind creature a gaze
would have reached. Nothing else draws differently.

The docstrings of resolve_gaze, Condition.BLIND, the battle module,
_resolve_gazes, and _surprise_gazes say so, and so do the gaze
changelog bullets. No golden file changed.

Claude-Session: https://claude.ai/code/session_01V7ErtnsmhaP7aLwcfmzohD
@mmacy
mmacy merged commit 256e81a into main Oct 30, 2026
5 checks passed
@mmacy
mmacy deleted the chunk/monster-tactics branch October 30, 2026 23:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant