Skip to content

Story 1.9: the Observer, part two, actors, emotes, buffs and the hero - #63

Merged
watchthelight merged 3 commits into
mainfrom
story/1-9-the-observer-part-two-actors-emotes-buffs-and-the-hero
Sep 6, 2026
Merged

Story 1.9: the Observer, part two, actors, emotes, buffs and the hero#63
watchthelight merged 3 commits into
mainfrom
story/1-9-the-observer-part-two-actors-emotes-buffs-and-the-hero

Conversation

@watchthelight

Copy link
Copy Markdown
Owner

Closes #22

Summary

The Observer gains its actors and hero: every mob whose sprite is drawn, with its name, alignment, health as the bar's pips, the invisible flag, the emote its sprite shows and every buff with an icon; and the hero as the status pane, the hero window, the talents pane, the bag window and the quickslots show it.
A hidden mimic is the chest it is drawn as, a heap of the map and never an actor, with the crystal mimic naming its category as a crystal chest would; MimicDifferentialTest holds three real chests byte-identical to the mimics that imitate them.
The emote comes through hook row 4, a ten-line read-only accessor on CharSprite under the show and hide methods' lock, ledgered with its digest; ActorLeakTest changes a mob's state, target and seen flag with no frame drawn and holds the Observation unchanged.
The one thing to look at: Observer.actors(), Observer.hero() and the mimic loop in Observer.map(), where every read is a field the sprite, the bar or the HUD reads, and the hook in CharSprite.java.

What changed

  • core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CharSprite.java: hook row 4, shatterfishEmote(); docs/UPSTREAM.md row 4, site index and diff budget (b5c38c7c41565c37 10 0).
  • shatterfish/harness/src/main/java/org/shatterfish/harness/observer/Observer.java: actors(), hero(), hidden mimics as heaps, the health, emote, buff and hunger rules.
  • shatterfish/api: HeapKind.EBONY_CHEST, the chest only an ebony mimic wears.
  • Tests: ActorLeakTest (in view, invisible, health pips, the emote against the state, buffs with icons), HeroSectionTest (the HUD's numbers, changes on screen, hunger as the icon), MimicDifferentialTest (three pairs byte-identical, then revealed; a hidden mimic out of view drawn only when stealthy and visited), Skeleton with the actors and the hero.
  • Docs: ADR-0006 amendment for story 1.9; rows in docs/rules/visibility.md and docs/rules/buffs.md.

How it was tested

  • ./gradlew build: green, 408 tests across 29 suites, twenty-five of them the seven observer suites.
  • Mutation battery of twenty on the committed tree, each against the four observer suites the story touches (story file, Evidence): all twenty caught, three of them added for the review's rules.
  • Fairness review: fairness-reviewer on 82107dcdf: FINDINGS with none blocking, seven should-fix findings all taken in 055d58d5e (story file, The fairness review): the sleep icon is applied as the next frame draws it, since the driver's frame runs before the acts and a stale icon would split the driver from the Overlay; a flavour buff's turns are carried only when its description prints them (the shadows of foliage do not); an ebony mimic is flagged faint; the mimic's alignment flip cited to its act; the ledger row's count; determinism reads for the new sections; one cite off by a line.
  • Rig numbers: n/a before E3.
  • Screenshots: n/a; the accessor is dead code to the game.

Docs

  • docs/adr/0006-observer-visibility-rules.md: amendment (the mob, emote, buff, hero and mimic rules with their cites, the losses recorded).
  • docs/UPSTREAM.md: row 4, the site index line and the diff budget line for CharSprite.java.
  • docs/rules/visibility.md: the mob sprite row's test; two rows for the emote and the hidden mimic. docs/rules/buffs.md: three rows' tests.
  • Story file _bmad-output/implementation-artifacts/1-9-the-observer-part-two-actors-emotes-buffs-and-the-hero.md.

Upstream files touched

  • core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CharSprite.java: ten added lines, a marker, three comment lines and one read-only method; nothing wrapped, nothing removed; ledger row 4.

The Observer gains actors() and hero(). A mob is present exactly when its sprite is drawn, in
the hero's field of view, with its display name, its alignment, its health as the bar over it
draws it (health over the greater of health plus shielding and the maximum, in the codec's
pips), the invisible flag for a sprite drawn faint, the emote its sprite shows, and every buff
with an icon, a flavour buff with the turns its description prints. The hero is what the status
pane, the hero window, the talents pane, the bag window and the quickslots show: the numbers as
printed, the talents of the tiers the pane shows, the unspent points as stars, hunger as the
icon's three states, and the six quickslots with their placeholders.

A hidden mimic is the chest it is drawn as: neutral and passive, it names itself as the chest,
a crystal one names its category as a crystal chest would, and it is drawn like any mob in view
and, when stealthy, once its cell is visited; so map() emits it as that chest, the ebony chest
only an ebony mimic wears included, and actors() never lists it. MimicDifferentialTest pairs the
chest, the locked chest and the crystal chest with the mimics that imitate them and holds each
pair byte-identical, then reveals the mimic.

The emote comes through hook row 4: CharSprite.emo is protected with no getter, so ten added
lines give a read-only accessor under the lock the show and hide methods take; docs/UPSTREAM.md
carries the row, the site index line and the digest. ActorLeakTest changes a sleeping mob's
state, target and seen flag with no frame drawn and holds the Observation unchanged, then
changes the icon and holds the emote changed. HeroSectionTest holds every field of the hero
section against the game and the JSON to no number behind the hunger icon.
…nly when printed, the ebony mimic faint

The fairness review passed on parity and found seven things to fix, all taken. The mob sprite
derives the sleep icon from the state on every update, and the driver's fenced frame updates
the sprites before the acts of a turn, so a mob put to sleep or woken during the turn read one
frame stale while the Overlay's unfenced frames would read fresh for the same Run. The Observer
now applies the sprite's rule as the next frame applies it, reading whether the mob sleeps for
that one drawn bit and dropping a sleep icon the next frame would hide; the alert, investigate
and lost icons, which the acts set, still come through the accessor. ADR-0006's amendment
records the one read of the state and why.

The shadows of foliage describe themselves without a cooldown, so a flavour buff's turns are
carried only when its description contains them. An ebony mimic hides at alpha 0.2 and now
carries the flag a faint heap carries. The mimic's alignment flip is cited to its act, the
ledger row counts ten lines as its digest does, and the new sections gain a determinism read:
two readings of one wait, with the level's mobs rebuilt in reverse order between them.
… to review

The story file records the twenty-mutation battery against the four observer suites the story
touches, the fairness review's seven findings and how each was taken, and the limitations handed
on: the sections still to come before observe(), the buffs that print their own numbers, the
examine hint a non-stealthy mimic carries, and the sleep icon read as the next frame draws it,
which the Overlay must match.
@watchthelight watchthelight added this to the E1 Harness milestone Sep 6, 2026
@watchthelight watchthelight added epic:E1 Harness area:harness Area: harness touches-upstream Edits an upstream file (hook); must be listed in docs/UPSTREAM.md fairness Touches Observer, ActionExecutor, brain, or information parity labels Sep 6, 2026
@watchthelight
watchthelight merged commit 828e178 into main Sep 6, 2026
3 checks passed
@watchthelight
watchthelight deleted the story/1-9-the-observer-part-two-actors-emotes-buffs-and-the-hero branch September 6, 2026 15:54
@watchthelight watchthelight mentioned this pull request Sep 6, 2026
21 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:harness Area: harness epic:E1 Harness fairness Touches Observer, ActionExecutor, brain, or information parity touches-upstream Edits an upstream file (hook); must be listed in docs/UPSTREAM.md

Projects

None yet

Development

Successfully merging this pull request may close these issues.

E1.9 The Observer, part two: actors, emotes, buffs and the hero

1 participant