Story 1.9: the Observer, part two, actors, emotes, buffs and the hero - #63
Merged
watchthelight merged 3 commits intoSep 6, 2026
Conversation
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
deleted the
story/1-9-the-observer-part-two-actors-emotes-buffs-and-the-hero
branch
September 6, 2026 15:54
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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;
MimicDifferentialTestholds 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
CharSpriteunder the show and hide methods' lock, ledgered with its digest;ActorLeakTestchanges 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 inObserver.map(), where every read is a field the sprite, the bar or the HUD reads, and the hook inCharSprite.java.What changed
core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/CharSprite.java: hook row 4,shatterfishEmote();docs/UPSTREAM.mdrow 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.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),Skeletonwith the actors and the hero.docs/rules/visibility.mdanddocs/rules/buffs.md.How it was tested
./gradlew build: green, 408 tests across 29 suites, twenty-five of them the seven observer suites.fairness-revieweron82107dcdf: FINDINGS with none blocking, seven should-fix findings all taken in055d58d5e(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.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 forCharSprite.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._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.