Changelog — RPG98
All notable changes to RPG98 are documented here. Format follows Keep a Changelog. Versioning follows phase-tied semver — see CLAUDE.md for the full versioning rules.
[v0.5.565] — 2026-08-19
Changed
- Game assets now ship as packed, obfuscated archives (art/sfx/music paks) instead of loose files — per our artists' licenses, players shouldn't be able to rip sprites straight off the SD card. Dev builds still run on loose files; the auto-updater re-downloads only the pak that changed.
[v0.5.564] — 2026-08-19
Changed
- The quick-use cooldown is now what it was always designed to be: one shared 2-second lock across the whole menu — using anything (stamina vial, health potion, food) briefly locks all three slots, so no more potion-into-food chaining. Previously only health potions had the gate, stamina/food had none, and the food slot's sweep showed the buff timer instead. The sweep now starts at 12 o'clock the frame you consume (client mirrors the cooldown locally instead of waiting a snapshot).
[v0.5.563] — 2026-08-19
Fixed
- Quick-slot cooldown sweeps started ~20% pre-elapsed for some foods (the sweep was wired to the food BUFF duration, which varies 8–12s by kind, against a fixed 10s max).
- Topping off a quick slot that was already full looked like it swapped amounts with the bag stack (the slot silently repointed to the selected stack). Selecting the same kind now always tops off — a full slot is simply a no-op; only selecting a different item swaps.
[v0.5.562] — 2026-08-19
Added
- The server writes a tiny status beacon (player counts + version) every 10 seconds — the new reaversrest.com site reads it for its live "US EAST ONLINE" pill.
[v0.5.561] — 2026-08-17
Fixed
- A party member who wasn't the leader could open a portal and silently queue SOLO while the party stood — leaving them stuck in a lobby, unable to accept the leader's party queue (the likely first domino in the 2026-08-16 party session). The server now rejects it with "ONLY THE PARTY LEADER CAN OPEN A PORTAL".
[v0.5.560] — 2026-08-17
Fixed
- Canceling a party queue silently broke the party. Two bugs stacked: the client wiped its local party roster on queue cancel even though the server keeps the party (so both players thought they were solo and queued unpartied), and the server dropped a player from their party the instant their hub socket closed — which the client's normal cancel-and-reconnect dance triggers. The client now keeps the roster, and the server gives a 20-second grace window for the character to reappear before removing them from the party.
- The LEADER PAYS toggle on the portal confirm screen could silently not appear if the party roster hadn't synced when the overlay opened — the leader check now refreshes live as party updates arrive.
[v0.5.559] — 2026-08-16
Changed
- The summoning circle's countdown spin-up was way too fast — now a gentle acceleration (220ms → 150ms per frame) instead of tripling its speed.
[v0.5.558] — 2026-08-16
Added
- Feeding the summoning circle now starts a 10-second preparation countdown — "THE CIRCLE STIRS - N" counts down for the whole run before the dragon erupts. Time to pot up, position, or run.
Changed
- The circle earns its states: a slow breathing pulse while dormant, spinning up faster and faster through the countdown, then fading out once the boss arrives. It's translucent throughout — the dungeon floor reads through the runes.
Fixed
- The offering menu's option lines overflowed the modal (and the screen). Each rung is now a two-line entry — cost on top, dragon underneath — with a note about the 10s delay.
[v0.5.557] — 2026-08-13
Fixed
- The summoning circle's offering menu never actually rendered in real dungeons — its draw call was accidentally nested inside the tutorial practice-chamber's overlay branch, so pressing A near a circle opened an invisible menu that swallowed every input until B. The menu, its result toast, and the "A: FEED THE CIRCLE" hint now draw in the normal dungeon path.
- The circle's interact zone shrank from 64px to 40px radius — it covered a wide area around the lair and hijacked A-presses aimed at nearby barrels.
[v0.5.556] — 2026-08-13
Fixed
- The portal's proximity hum audibly repeated — its assigned sample is a one-shot with an attack/decay arc, so looping it sounded like a stuck record. Portal and summoning-circle hums now play once as you enter range instead of looping. (The low-health heartbeat keeps looping — a repeating thud is the point there.)
[v0.5.555] — 2026-08-13
Added
- Sound pass 2 (~70 more cues wired): menu navigation everywhere (cursor/confirm/back in login, register, character select, settings, inventory; typewriter ticks on the on-screen keyboard), equip/unequip/quick-slot foley, per-tome cast sounds (all 20 abilities), starter class abilities, status-effect landings (poison, burn, slow, root, curse, Songstruck's detuning sting), stun+knockback, crucible deposit/phase-complete/collect (town and dungeon), crystal ball channel and shatter, party invites, mailbox flap, bounty accept and payout.
- The mixer can now hold looping ambient sounds: low-health heartbeat (<25%), the summoning circle's runic pulse and the open portal's hum fade in by proximity.
- All 10 music loops pre-converted to the Miyoo's native 8kHz mono — 152MB of WAVs now ship as 14MB, load ~11× faster, and sound slightly cleaner (proper anti-alias filter instead of the runtime nearest-neighbour).
[v0.5.554] — 2026-08-12
Fixed
- Sound effects fired noticeably late: the mixer kept the ALSA buffer pinned full (
100ms+ of pre-mixed audio ahead of the DAC), so every new sound queued behind it — and each play re-read its WAV from the SD card. The mixer now paces itself to stay only ~50ms ahead (wall-clock, since the MI ALSA stub can't report queue depth), and all cue WAVs are preloaded into RAM (4MB) at startup.
[v0.5.553] — 2026-08-11
Added
- First sounds: the game is no longer silent. Attacks (per weapon), enemy hits, boss death sting, getting hurt, class movement abilities, potions and food, the portal-open gong, collapse warning, extraction and death stings, downed/revive, loot pickups graded by what they are (coin tick → Aether shimmer → Legendary mini-fanfare), barrels, chests, corpse rummage, the summoning circle, tutorial lesson ticks, and hub vault/vendor/dialogue foley — ~40 cues wired from the new sound manifest (162 cues assigned via the picker tool).
[v0.5.552] — 2026-08-11
Added
- Boss-summon telemetry: every circle feed is logged (tier, dragon, dungeon) and resolved at the kill (fight duration), with a summons section in combat_report.sh — the offering costs get tuned from data.
[v0.5.551] — 2026-08-11
Added
- Boss summoning: Empowered lairs hold a dormant runic circle instead of a roaming boss. Feed it 1 Aether Core to call the dungeon's dragon (Sylvan in the Mossmaul, Infernal in the Redrot) or 3 to call the Primordial Drakon — whose death chest guarantees a Legendary. One summon per run, offering burned win or lose, mini-bosses still roam. The drakes wander free; the true dragons only answer a paid call.
- The inventory shows a bag fill counter — red with a scroll nudge when overflow rows (crafts, gifts, mail) push you past capacity.
[v0.5.550] — 2026-08-09
Fixed
- Tome of Thorns wounds enemies now: zone damage measured enemy positions with a 16px-entity assumption, so 32px enemies never counted as "standing in" thorns, magma pools, or spore clouds. Real hitboxes are used — enemies pressing against a thorn wall while chasing you bleed for it.
[v0.5.549] — 2026-08-09
Fixed
- Echo Step bounce, round three: the reconciliation poison guard was loose enough (64px) for the rubber-band to live indefinitely just under it — observed as a stable ±61px flip-flop when packet loss hid the entire dash window from the client. The guard is now 24px (legit unconfirmed movement tops out ~21px even at 250ms ping), so any oscillation snaps to the server and heals in one snapshot.
[v0.5.548] — 2026-08-09
Added
- Always-top fringe flags: the portal's entrance arch (and anything painted with the map editor's new A mode) draws over the player unconditionally — the escape hatch from the Y-sort depth rules for things you walk under.
[v0.5.547] — 2026-08-09
Changed
- Portal repositioned to center the symmetrized plaza (placed with the new live-preview portal placer).
[v0.5.546] — 2026-08-09
Changed
- Portal plaza symmetrized (map polish).
[v0.5.545] — 2026-08-08
Fixed
- Wall-mounted fringe (the tavern's animal heads) stays over players standing at the wall: fringe depth runs now extend through the solid tiles beneath them, anchoring wall decor at the base of its wall. Free-standing furniture still Y-sorts at its own tile.
[v0.5.544] — 2026-08-08
Fixed
- Dungeon layering matches the hub now: platform edges, southern wall drapes, and crucible-side fringe no longer cover a player standing in front of them — the over-redraw skips fringe runs that bottom out above your feet (the base render already shows them beneath you).
[v0.5.543] — 2026-08-08
Fixed
- Walking behind a building no longer puts you on the roof: fringe depth anchors to the bottom of each contiguous vertical run, so multi-row roofs sort as one unit while single-tile furniture keeps the new front/behind layering.
[v0.5.542] — 2026-08-08
Changed
- NPC interact hints match the POI format ("A: GRIM" instead of "A: TALK TO GRIM") — the long form ran twice as wide and read as a bigger, off-center label.
[v0.5.541] — 2026-08-08
Changed
- Fringe furniture depth-sorts with people now: stand in front of a chair and you're in front of it; walk behind and it covers you. Every fringe tile joins the sprite depth sort keyed by its bottom edge — tree tops and overhangs behave as before.
[v0.5.540] — 2026-08-08
Fixed
- Half-tile collision blocks from every direction now — crossing one sideways could slip straight through (the 12px foot hitbox straddled the 8px solid strip and the corner samples missed it). Movement uses true box-overlap tests against each tile's solid region.
Changed
- More hub map polish.
[v0.5.539] — 2026-08-08
Fixed
- NPCs can't end up parked on furniture outside their painted zone anymore: interrupted strolls left them stopped half a tile inside a blocking neighbor (Crowe on a chair). Strolls now only start when the whole straight line stays on painted tiles, and any blocked walk settles back onto the last legal tile.
[v0.5.538] — 2026-08-08
Fixed
- Talking to NPCs from the north works at a natural distance — proximity now measures against their whole body instead of their foot tile (approaching faces first no longer required leaning into them). Their sprites also sit a few pixels lower so their feet land on the actual tile instead of appearing to stand outside their patch.
[v0.5.537] — 2026-08-08
Added
- The frog fountain runs: a 3-frame water loop — mouth stream flowing, basin shimmering, splash at the foot — placed via the new fountain map marker.
[v0.5.536] — 2026-08-08
Added
- Every townsperson walks a hand-painted wander zone now — arbitrary shapes instead of rectangles, including tiles players can't stand on (Grim works his side of the counter). The whole cast was repositioned to their designed haunts.
- Off-screen edge indicators point at NPCs owed a bounty turn-in — same hopping gold diamond as the tutorial's.
[v0.5.535] — 2026-08-07
Changed
- More Blackthorn Hollow map polish.
[v0.5.534] — 2026-08-07
Changed
- Food design rule enforced: potions are instant and single-purpose; food always restores health AND stamina over time. Blackthorn Ale heals now (20 HP + 20 stamina over 10s), and Chicken Legs and Bread Loaves gained a light stamina trickle. Summons still won't drink your ale.
[v0.5.533] — 2026-08-07
Changed
- Echo Step dashes through chests, barrels, and clutter — only walls, canals, platforms, and crucibles stop it. Ending a dash inside a barrel is fine: you just walk out (the escape hatch already allowed leaving any solid you overlap).
[v0.5.532] — 2026-08-07
Fixed
- Tome of Venom works for ranged classes: the poison coat only applied to melee swings — arrows and staff bolts resolve in the projectile path, which never checked it. Bow Rangers' venom now lands with every coated shot.
- The quick-use menu tags found food with "FOUND" — food picked up mid-run is edible without slotting (quick slots lock in the deep), and now the menu says so instead of feeding you a mystery drumstick.
Changed
- Bag-full rejections log full diagnostics server-side (chasing a "full with a visible open slot" report).
[v0.5.531] — 2026-08-07
Added
- The bounty board finally looks like one: a weathered notice board by the square — grain, rain streaks, worn shingles, torn postings, and one notice somebody already ripped off. Military-camp props (palisade, tents, spikes) joined the town tileset for future map work.
[v0.5.530] — 2026-08-06
Fixed
- Stacked tiles (Alt+LMB in the map editor) bake correctly now — Grim's inn gets its counter tops back; stacked mask cells were silently skipped by the bake.
Changed
- Spawn rooms refined: zones, chests, and respawn points repositioned with the new spawn-zone editor, plus further map and interior-tileset polish.
[v0.5.529] — 2026-08-05
Fixed
- The interiors tileset's black zones render as transparent now (hand-edited + re-baked) — no more solid black boxes on the hub map.
[v0.5.528] — 2026-08-05
Changed
- Blackthorn Hollow map update: the three spawn chests now sit in proper spawn rooms with real walls and collision, spread apart so fresh arrivals don't stack on each other.
[v0.5.527] — 2026-08-05
Fixed
- The NPC quest "!" actually hops now — the bounce was fed a constant (the tile size masquerading as a timer), so it sat frozen. Real animation time is threaded through.
Changed
- The marker is back to the rounded glyph look (font-rendered with a 4-way outline) at a middle size — the hand-drawn version read too square, and 20px was too much.
[v0.5.526] — 2026-08-05
Changed
- Interact hints ("A: TALK TO GRIM", "A: OPEN IRONVAULT", "A: OPEN CHEST"...) float under your character now, dungeon floor-label style, with a drop shadow — they were fighting the tutorial banner at top-center and read as UI instead of world. START: MENU stays quietly at the top.
- The off-screen quest diamond draws above the objective banner instead of hiding behind it, and the "R2: JOURNAL" hint got a shadow and a readable blue-steel color.
[v0.5.525] — 2026-08-05
Fixed
- Echo Step no longer freezes in open areas: the dash's wall sweep counted tiles the player was already standing on or against (crucible top rows, breakable edges are blocked-marked but effectively walkable), so the whole dash whiffed on the spot — the divergence that fed the bounce. Only newly-entered tiles stop the dash now.
[v0.5.524] — 2026-08-05
Fixed
- Echo Step bounce: dashing into a wall left the position rubber-banding ±50px every other frame. The input-replay log kept references from around the dash window; reconciliation replayed them as phantom displacement just under the poison guard. The log is purged whenever the server owns the position (dash, void shift, knockback, stun), so stale references can't fight the sync.
[v0.5.523] — 2026-08-05
Changed
- The gold "!" over NPCs is twice the size and hops now — an abs-sine bounce that lands and springs, drawn with a real outline. Applies to bounty turn-ins and tutorial targets alike.
[v0.5.522] — 2026-08-05
Changed
- The off-screen quest indicator is 2.5x bigger (23px diamond, chunky !) with a deeper bob — it was easy to miss at 9px.
- Step 2 marks only Mira — Grim kept his exclamation mark for the lost-keepsake fallback, but two marks read as two errands. His replacement prompt is still in his dialogue if you need it.
[v0.5.521] — 2026-08-05
Changed
- Walking away from your spawn chest no longer forfeits it — come back any time this hub session and it's still yours (proximity is the only gate now, and the chest sprite stays closed until actually looted). Logging out without looting still loses it, and death still grants a fresh one on respawn.
[v0.5.520] — 2026-08-05
Changed
- Bounty WHERE lines say the whole thing now — they were written telegraphic back when the terms panel couldn't wrap ("STABLE+ KILLS, CHESTS ANYWHERE" reads "STABLE+ ENEMY KILLS - CHESTS DROP IT ANYWHERE", the smelt line mentions the tax difference, the cull lines name what you're walking into).
[v0.5.519] — 2026-08-05
Added
- Off-screen quest indicator: while Grim's chain is active, a bobbing gold diamond at the screen edge points toward the current objective — the target NPC, or the portal/crucible/board on those steps.
Fixed
- The quest journal's OBJECTIVE/WHERE/HINT values word-wrap properly and the panel grows to fit — no more clipped lines (the missing ")" on Mira's page). Rule adopted: copy wraps, layout reflows; text never gets truncated to fit.
[v0.5.518] — 2026-08-05
Changed
- The tutorial journals now match the bounty book: header strip, the step NPC's portrait as the "poster", a spoken pitch in their voice, an OBJECTIVE/WHERE/HINT terms panel, and full-size body text. All the mechanics copy was rewritten so every page adds real information (combo steps, the loose-consumables portal rule, tax math, tome death rules).
Fixed
- Grim's bread can no longer silently block the portal: tutorial players who queue with loose food get "SLOT IT (SELECT), EAT IT, OR VAULT IT" instead of jargon about mail, and the Kit Up page teaches the rule.
- The light-attack lesson can't dead-end anymore: if the dungeon runs out of living enemies before 3 hits land, a lone straggler respawns near the player.
[v0.5.517] — 2026-08-05
Added
- Tutorial requirements mode: every lesson in the tutorial dungeon is now required, in any order. The portal stays shut (and no timer runs) until the last lesson checks off — then "THE WAY OUT IS OPEN", the portal wakes, and the real 4-minute collapse starts counting. Lethal, normal corpse rule: the clock is the final lesson.
- GRIM'S LESSONS journal: R2 in the tutorial dungeon opens every lesson as its own entry, each with a detail page teaching the mechanic behind it (combo steps, charge timing, stamina, tome loss rules, the corpse rule).
- The hub quest journal gets an A: MORE DETAIL page per chain step — the vault rule, portal modes, crucible tax, sockets, food buffs, bounty flow.
- Tutorial maps regenerate if a roll produces zero chests or zero breakables, so every lesson is always completable.
[v0.5.516] — 2026-08-05
Fixed
- Spoils completes when you deposit an item into the Town Crucible — the crucible runs the moment something goes in (X is only pause/resume), so the old start-button hook never fired in the normal flow.
[v0.5.515] — 2026-08-05
Changed
- Smoke bomb rework: the cloud swells from small to full size on cast, its perimeter undulates continuously (four phase-shifted outlines ping-ponged) instead of holding one frozen shape, and it's translucent enough to see your own player inside it. All ground zones get the grow-in and living edge; only smoke drops the overhead opacity boost.
[v0.5.514] — 2026-08-04
Fixed
- The light-attack lesson counts ranged hits — arrows and staff bolts land in the projectile tick, which the counter never saw, so bow Rangers and Arcanists could clear the whole dungeon at 0/3. The checklist line also reads "TAP A: LAND 3 HITS" now instead of the baffling "STRIKE WITH A".
[v0.5.513] — 2026-08-04
Fixed
- Kit Up accepts either tonic — stamina counts the same as health (it checked only health potions before). Grim fronts 12 ingots, priced to Crowe's shelf.
- Kit Up re-checks on hub entry and after talking to Grim, so a player who already satisfied it (like a stamina-tonic buyer under the old rule) advances on next login instead of being stuck.
[v0.5.512] — 2026-08-04
Fixed
- Kit Up's economy actually works now: Grim fronts 15 ingots (was 10 — not enough for Crowe's 12-ingot health tonic), and every tutorial text says tonic instead of vial. Vials only drop in dungeons; the pre-run purchase is Crowe's tonic.
[v0.5.511] — 2026-08-04
Added
- The tutorial dive is truly solo now: a step-4 player never pools with randoms in the free queue (either direction — their run launches in ~2 seconds), and party invites are blocked both ways until their first extraction.
- Veyra notices what you're carrying: her sigil line changes when you actually have socketed gear in your bag.
Changed
- The locked bounty board speaks Grim's line from the spec: "COME BACK WHEN YOU'VE PROVEN YOU CAN COME BACK - GRIM".
- "Land 3 light attacks" counts landed hits now (the combo system's own signal) — whiffing at air doesn't tick the lesson.
- Spoils requires smelting a real item — firing the crucible with only fragments doesn't count.
[v0.5.510] — 2026-08-04
Added
- The quest journal (R2) carries Grim's chain while it's active: a full page with the quest title, the objective, and the explanation the top-of-screen banner can't fit — why the vault matters, where the ingots came from, what the crucible tax is. The banner now shows a small "R2: JOURNAL" hint so the button gets taught.
[v0.5.509] — 2026-08-04
Added
- The tutorial speaks through the NPCs now, not just the banner: Mira has her own keepsake line that opens the vault, Crowe gets a marker and a "Grim sent me for a vial" line that opens his shop, and Grim explains the kit, points at the portal, and sends you to the board at the right moments.
- Grim keeps spare weapons — a tutorial player who walked away from their spawn chest (forfeiting it) gets a plain Common class weapon from him instead of being stuck at Kit Up.
Changed
- Kit Up banner names Crowe as the vial source.
[v0.5.508] — 2026-08-04
Added
- Mira can open the vault directly from conversation ("Open my vault.") — she's the vault keeper, so the tutorial's marker over her head now leads somewhere honest. The vault door POI still works as before.
[v0.5.507] — 2026-08-04
Fixed
- Grim's tutorial conversation closes after you pick a quest line instead of re-offering the same intro choices — the script advances with the chain now.
[v0.5.506] — 2026-08-04
Added
- Grim's introductory quest chain — new characters are walked through the whole loop in 8 steps: Grim's orientation, vaulting his keepsake (the Iron Rule), kitting up, a tutorial dungeon run, a first smelt, Veyra's sigil gift, an ale on the house, and a first bounty. Veterans and alts can skip it at Grim's first dialogue ("I know my way around" — no rewards).
- Grim's Keepsake — a worthless-by-design memento every new reaver vaults before their first run. Four necklace looks, one per character; it can't be sold or smelted, and Grim replaces it if you lose it before it's vaulted.
- The tutorial run — a solo PvE Unstable dive with no collapse timer, a guaranteed Common tome in the first chest, and a GRIM'S LESSONS checklist that ticks off light attacks, a heavy, sprinting, your ability, a barrel, and the chest-tome-cast lesson before pointing you at the portal.
Changed
- The bounty board stays locked until the chain's final step ("PROVE YOURSELF FIRST - GRIM") — the only thing the tutorial gates. Existing characters are unaffected (their chain is marked complete by migration).
[v0.5.505] — 2026-08-04
Fixed
- A tome on cooldown can no longer be swapped out mid-run — trading a humming tome for a fresh one was a free bypass of the entire cooldown system.
[v0.5.504] — 2026-08-03
Changed
- The question you can ask Thalor is gentler — "What was it like, coming back?" — and his answer ends on what he lost: "The memories stay. The rest doesn't."
[v0.5.503] — 2026-08-03
Changed
- Thalor's board notice about his return is more discreet. He still won't talk about it.
[v0.5.502] — 2026-08-03
Fixed
- Hazel no longer delivers walls of text — boon announcements stand alone, and the garden total or the "still carrying more" nudge appear one at a time on plain donations, never stacked. Fewer dashes in her voice, too.
[v0.5.501] — 2026-08-03
Changed
- Summons eat like creatures, not vacuums — they chew for 2 seconds before each bite, and food now heals them over time with the exact same regen it gives players (chicken: 16 HP over 8s, stew: 36 over 12s). A digesting summon won't take another bite until the meal finishes, so it eats only what it needs. Ale is ignored — it does nothing for their health, and they know it.
[v0.5.500] — 2026-08-03
Added
- You can feed your summons. Drop food from your quick menu and a hurt companion will walk over and eat it — chicken legs heal 25, hearty stew a full 50. It only ever eats food you dropped, and only when hurt. Green heal numbers and a puff of crumbs included.
- Sanctuary shelters summons — your companions now regen inside your Sanctuary zone alongside the party.
[v0.5.499] — 2026-08-03
Changed
- Elemental summons fire their own bolts — a flickering fire wisp, a spinning frost shard, a bubbling blight globule — small companion-scale shots instead of borrowing the Arcanist's big blue bolt.
[v0.5.498] — 2026-08-03
Added
- Summoned elementals wear their element: the Flame's embers rise off it, the Frost's glints orbit, the Blight sheds drifting spores. (The genuinely last VFX checklist item.)
[v0.5.497] — 2026-07-30
Changed
- Root vines get real art — same curling tendrils, now with shaded stems, thorn nubs, and glinting leaf tips.
[v0.5.496] — 2026-07-30
Added
- The VFX checklist closes — Grasp draws its crackling pull-line, Poison Blade drips venom off your hand while armed (teammates see it too), summons arrive in a puff of void-smoke, Arrow Storm actually rains arrows into its circle, and winding-up trogkin kick dust at their heels.
[v0.5.495] — 2026-07-30
Added
- Cast moments — Gale Force bursts wind rings, Fae Steps sparkles at both ends of the blink, crystal balls shimmer when scrying, and Sanctuary shows green healing motes rising off you while it works.
- The Void watches — every Void Field now has a single slow-blinking eye at its heart, and its iris follows you.
[v0.5.494] — 2026-07-30
Fixed
- Corpse containers spawn where the body actually fell (they'd been landing a tile-plus northwest — the drop tile came from the sprite's corner, not its center).
- Downed and dying players keep their facing — the pack's death poses exist for all 8 directions, but row 0 was hardcoded, so everyone collapsed the same way.
[v0.5.493] — 2026-07-30
Changed
- Boss zones arrive as attacks — Mossmane and Magmascale drakes now lob globs that splash their clouds and pools where they land (at your position when thrown, so they're dodgeable); breath drakes breathe in front of themselves instead of at their own feet.
Added
- The Siren sings — her slow-zone is gone. She fires a drifting musical note; struck players are Songstruck for 5 seconds: d-pad directions scramble, notes dance overhead. 20-second cooldown, because it's exactly as rude as it sounds.
[v0.5.492] — 2026-07-30
Fixed
- Spore clouds look airborne — the ground-streak blotches became churning mist, and spores drift in individual directions instead of synchronized waves.
[v0.5.491] — 2026-07-30
Added
- The Returned rise properly — every revive (tome or hold-A channel) plays a resurrection moment at the risen player: the void's violet ring collapses inward, a white-gold flash answers, twin rings burst outward, and light motes climb from the spot. Visible to the whole party.
[v0.5.490] — 2026-07-30
Added
- You feel it when it lands — contracting a debuff (poison, curse, root, stun, any of them) flashes expanding rings and rising sparks in the effect's color on your character, matching the HUD icon that appears. Re-applications flash too.
[v0.5.489] — 2026-07-30
Added
- Enemy projectiles get real — all six (fireball, necrotic bolt, magic bolt, vine shot, web shot, void bolt) fly as animated sprites with fading motion trails, and every one pops an impact burst in its own color when it connects — or fizzles against a wall.
[v0.5.488] — 2026-07-30
Added
- Ground zones reborn — every zone (webs, spores, magma, void, vines, fire, smoke, thorns, sanctuary) now renders as an animated texture with a soft organic outline unique to each cast, replacing the flat tile-circles. Enveloping clouds (web, smoke, fire breath, spores) draw over the player at higher opacity; the rest stay on the ground beneath you.
[v0.5.487] — 2026-07-29
Fixed
- Duplicate item ids repaired and prevented — the id minter was blind to items parked in quick slots, the mailbox, and auction listings, so new items could be born with an id already in use. This was the true root of the quick-slot chaos (stews in the health slot, drinking stew as a potion, vanishing tonics). A one-time migration re-mints every duplicate; the minter now scans all six item tables.
[v0.5.486] — 2026-07-29
Fixed
- Quick slots stay loaded across runs — eating a slotted stack down to zero (or any mid-run stack churn) used to silently unequip the slot at extraction, dumping the survivor into your bag. Slots now restore by item identity when the exact stack is gone.
[v0.5.485] — 2026-07-29
Fixed
- Platform tops render over the player again — the fringe layer's post-entity pass had been skipped ever since map baking landed.
- Crucibles can be approached from behind — the top row of the 4×4 is walkable now, and its cap draws over players standing behind it.
- The food-buff indicator shows what you actually ate (stew shows stew) instead of the procedural chicken leg.
[v0.5.484] — 2026-07-29
Fixed
- The portal mode picker's cost icons (Aether, Aether Core) use the real atlas art instead of hand-drawn minis.
[v0.5.483] — 2026-07-29
Changed
- Growing dungeon flowers draw at 60% size, planted at the base of their tile. Icon refresh batch rides along (enemy debuff icons among them).
[v0.5.482] — 2026-07-29
Changed
- Dungeon flowers stand up straight — stems redrawn vertical (with leaf nubs) on all six colors.
[v0.5.481] — 2026-07-29
Changed
- Flowers sorted — growing flowers in dungeons show their true colors (six per-color sprites: Bonewhite through Void-violet), while bagged flowers show the tied bundle. Floor icons from the atlas also stop drawing ghost outline echoes.
- The icon set is complete — all 174 keys assigned; nothing procedural remains except deliberate fallbacks.
[v0.5.480] — 2026-07-28
Added
- Flowers get a proper bundle icon — three blossoms in the dungeon colors, tied with gold string. Shown in bags, Hazel's donations, and floor drops.
[v0.5.479] — 2026-07-28
Added
- The crystal balls get real icons — a bright gold-glinted Flawless and a misty Clouded, hand-painted, shown in inventories and the hotbar X slot.
[v0.5.478] — 2026-07-28
Fixed
- Bear traps render at the game's normal 2× scale in dungeons — they'd been drawn at half size all along (the art also only fills ~27% of its frame, which compounded it). The snare icon is re-derived from the cropped art and actually reads as a trap now.
[v0.5.477] — 2026-07-28
Fixed
- Currency icons (ingots, aether, cores, stones, fragments, flowers) now use real art everywhere they appear without a full item in hand — shop cost rows, the portal mode picker, crucible fees. Empty-slot silhouettes stay procedural on purpose.
[v0.5.476] — 2026-07-28
Changed
- Grim's Hearty Stew icon actually contains stew now (hand-painted pot fill — potato, carrot, herb and all).
[v0.5.475] — 2026-07-28
Changed
- Active class-ability buffs (Second Wind and friends) show your assigned hotbar icon instead of the old procedural glyph; dedicated buff icons can override later.
[v0.5.474] — 2026-07-28
Fixed
- Veyra's bulk core crafting caps the quantity selector at what you can actually afford (shown as MAX n) instead of counting to 99 for the fun of it.
[v0.5.473] — 2026-07-28
Changed
- Hotbar icons fill the whole slot, and the cooldown sweep is now translucent so the icon stays visible beneath it.
[v0.5.472] — 2026-07-28
Added
- Icon batch 3 — atlas grows to 133 icons (sigils, more tomes, class hotbars filled out). Heavy attack (hold A) gets its own hotbar slot icon per class, falling back to the basic-attack art until picked. The icon tool gained flip/rotate/tint effects, per-class hotbar groups, and rarity-grouped sigils along the way.
[v0.5.471] — 2026-07-27
Added
- Hotbar icons — the A/AA/X/Y/B slots now show your picked class-ability icons (basic attack, starter, movement) and the equipped tome's art, drawn under the cooldown sweep. Unpicked slots keep the plain square. 115 icons in the atlas now.
[v0.5.470] — 2026-07-27
Changed
- Aether Cores stack to 10 (was 5), matching Void Stones.
[v0.5.469] — 2026-07-27
Fixed
- Real icons now fill their inventory cells (48px, centered) instead of hiding in the top-left quadrant, and no longer overlap the cursor border.
[v0.5.468] — 2026-07-27
Added
- Real item icons begin — 95 hand-picked icons (weapons by rarity, armor by set, potions, food, currency, tomes) now draw in every inventory surface: bag, vault, trade, auction, corpse loot, floor drops. Anything not yet assigned keeps its procedural shape and gets upgraded as the icon set grows. Icons resolve from item properties, so legacy-named gear displays correctly.
[v0.5.467] — 2026-07-26
Fixed
- Item stories say "in an Unstable dungeon" (article grammar), and Hazel's garden total gets thousands separators — she intends the number to get big.
[v0.5.466] — 2026-07-26
Added
- Items remember (provenance, M023) — gear and tomes now write a life story: found in a dungeon, bought from Crowe, lost with your corpse, recovered from someone else's, traded, auctioned, sold to Pell, smelted. Append-only history, headed for a website page once the stories accrue.
- Vendor ledger — every Pell sale and Crowe purchase is logged for economy tuning.
- Hazel counts the blooms — donate flowers and she'll tell you the garden's town-wide lifetime total. It remembers every one.
[v0.5.465] — 2026-07-26
Added
- Damage-dealt telemetry (M022) — runs now log damage dealt, hits, overkill, downs, and sustain use, plus a per-enemy-family combat breakdown, all counted in memory and written once at run end (zero mid-run cost).
tools/combat_report.shprints the difficulty-ladder tuning tables. No gameplay changes — this is the instrument the combat tuning pass has been waiting on.
[v0.5.464] — 2026-07-26
Added
- The notice-post grows up — the daily town notice pool expands from 12 to 180: twelve notices from every resident of the Hollow, the lore cast included. Thalor checks the board to be seen, Eldrin will not tell the pipe story again, the bench remains taken. One per day, six months before a repeat.
[v0.5.463] — 2026-07-26
Changed
- Posting details say "EXPIRES: IN 4H 20M" instead of "COMES DOWN IN" — and Pell's crowbar notice reads properly now. (It is still his.)
[v0.5.462] — 2026-07-25
Changed
- The lore cast joins the bounty board — Thorne now posts every hunt (culls, slaying, trophies, the boss week: "come back and I'll shake your hand"), Brother Garrick requests Aether samples for the archive, and Sister Mirel keeps the weekly extractions — the returned have a duty to the living. Grim still counts who comes home on the daily postings. Every new poster has their own pitch and payday lines, gold markers, chained turn-ins, receipts — all of it.
[v0.5.461] — 2026-07-24
Fixed
- Closing the bounty journal could crash the game — pressing B while a second input landed in the same frame walked into freed overlay state and panicked. The board and the player menu had the same latent hazard; all three are hardened.
[v0.5.460] — 2026-07-24
Fixed
- The quick-use menu actually uses things now — the open menu owns all input, and the A-to-consume handler was living outside it, unreachable. A consumes, R1 also closes.
[v0.5.459] — 2026-07-24
Changed
- Craft Aether Cores in bulk — Veyra's crafting confirm has a quantity picker now (D-pad left/right, then READY). One conversation, as many cores as your ingredients cover, instead of re-selecting the dialogue per core.
[v0.5.458] — 2026-07-24
Changed
- Bounty tuning pass 2, from real run data — the fragment supply posting asks for 60–100 (was 120–200: a ten-run grind for exactly the players who need the coin), and the aether-gathering and extract-richer postings now honestly say STABLE OR RICHER instead of being silently impossible at Unstable. Unstable remains the safety-net tier by design — the board just stops pretending otherwise.
[v0.5.457] — 2026-07-24
Changed
- Quick-use is intentional now — R1 toggles the menu open and it stays open: D-pad picks, A consumes, B cancels. No more use-on-release.
Fixed
- Found food is edible — a chicken leg picked up mid-run silently did nothing, because eating only worked from the (locked) pre-run food slot. Anything edible you find now works from the quick-use menu; your slotted food still goes first.
[v0.5.456] — 2026-07-24
Changed
- Bounty wording pass — "NOT YET TAKEN" is now "NOT STARTED"; the extraction postings speak the game's own verbs: "EXTRACT 8 TIMES" / "WALK BACK OUT" and "EXTRACT 40+ INGOTS RICHER" / "WALK OUT RICHER".
[v0.5.455] — 2026-07-24
Fixed
- Posting details word-wrap — long terms clipped at the screen edge ("...A STABLE+ RUN (STABLE OR R"). Every row of the terms panel now wraps onto extra lines, using the blank space the page always had.
- The Deep Delve posting said "STABLE+" and "(STABLE OR RICHER)" in the same breath — once is enough.
[v0.5.454] — 2026-07-23
Fixed
- The loading bar's real final chunk was the soundtrack — an 18 MB music file loaded and resampled on the main thread right after the bake, freezing the bar's last stretch. It loads in the background now; the music starts a beat later, the bar never stops. (Credit where due: "it could be something happening after the map bakes" — it was.)
[v0.5.453] — 2026-07-23
Fixed
- Found the bake's real silent chunk — it wasn't the map tiles, it was composing your character's paper-doll (a dozen layer files off the SD card) before the tile work even started. The compose now reports per layer, so "Baking the dungeon" moves the whole way through.
[v0.5.452] — 2026-07-23
Fixed
- The bake reports in too — "Baking the dungeon" was the bar's last silent chunk; it now ticks per map row, so bigger dungeons smoothly take their genuinely longer share of the bar instead of jumping a mode-sized gap.
[v0.5.451] — 2026-07-23
Fixed
- The loading bar tells the truth now — it used to sit at a hardcoded third while the real work (119 creature sheets off the SD card, the tileset, the bake) happened behind a frozen frame. Every asset decode now reports in as it completes, so the bar moves exactly as fast as the SD card does — no theater, no artificial delay. The detail line names what's actually loading ("Loading creatures 57/119").
- The loading screen said "RIFT" — the last survivor of the old word, hiding on a screen that flew by too fast to read. They're dungeons.
[v0.5.450] — 2026-07-23
Fixed
- Receipt page cleaned up — the header is a size down from its shout, long reward lines word-wrap instead of running offscreen, and the portrait and name step aside: a receipt is a document, not dialogue, so the payout gets the full width of the box.
[v0.5.449] — 2026-07-22
Changed
- Paydays got a proper receipt — the poster speaks their line clean, and the payout is its own page: BOUNTY COMPLETED, the job's name, and labeled reward lines (clean sweep bonus called out in gold). Chained claims alternate line, receipt, line, receipt.
- The quest journal is now the BOUNTY JOURNAL — R2, same journal, right name.
[v0.5.448] — 2026-07-22
Changed
- Paydays chain in one conversation — a poster who owes you several completed bounties pays them one after another as you advance the dialogue, each with its own line, instead of making you close and re-greet between claims. First meetings flow into it too: introduction first, then straight to business.
[v0.5.447] — 2026-07-22
Fixed
- Soul-bound items stay bound — they can no longer be listed on the auction house, sold to Pell, or offered in player trades. They never leave your hands (except to the void).
- A refused bounty claim no longer eats the posting — the client treated any refusal as "claimed," hiding the poster's marker and blocking retries. It now re-syncs with the server instead. If Grim owed you one, relog and he'll remember.
[v0.5.446] — 2026-07-22
Added
- DOWNED, NOT DEAD — take lethal damage with a teammate still standing and you drop instead of dying: 30 seconds on the clock (shrinking to 20, then 10, on repeat downs). A teammate holds A over your body for 10 seconds to bring you up at 10 HP — channeling pauses the clock; getting interrupted resets the hold. Enemies ignore the downed. Nobody standing on your team? Everyone down goes down for good — solo included.
- THE TOME OF THE RETURNED — Legendary, Empowered treasure. Forces the void to give a downed teammate back: instant, at range, 20% health, two-minute cooldown. Lost on death like every tome. The returned have a duty to the living.
- Finishing (PvPvE) — a downed rival isn't safe: three hits of any kind finish them, skipping the clock, and every finish hit breaks an in-progress revive. Fight over the body.
- Death has a beat now — your fall plays out, the world fades to black, and then the void tells you what it kept.
[v0.5.445] — 2026-07-21
Added
- Lirien walks the garden's edge — the last of the lore cast. She listens to the Aether: how it moves, how it sings in the flowers. Ask her what it costs. The Aether triangle is complete — Garrick studies it, Veyra works it, Lirien feels it — and Brother Garrick's updated look ships alongside her.
[v0.5.444] — 2026-07-21
Fixed
- Journal details open the right quest again — after paid jobs started leaving the list, the cursor was still secretly counting them, so inspecting a lower row could show a different (already-paid) job's details.
[v0.5.443] — 2026-07-21
Added
- Economy telemetry — runs now log where the money actually came from: fragments/aether/flowers picked up vs. converted at a dungeon crucible, plus chests opened and barrels smashed. Drop rates and smelt values can now be tuned separately instead of guessed at from bag totals.
[v0.5.442] — 2026-07-21
Changed
- Paid jobs leave the quest journal — once you've collected, the entry is gone. Clear the whole board and the journal says so: "ALL JOBS DONE AND PAID. NEW POSTINGS AT DAWN."
[v0.5.441] — 2026-07-21
Fixed
- Vendors no longer moonwalk away from conversations — an NPC that was mid-stroll when you talked to them resumed walking while still facing you. They turn back around now.
- Hazel acknowledges the posting on the spot — donating flowers that complete the donation bounty now says so in her reply ("POSTING COMPLETE - TALK TO ME AGAIN FOR YOUR PAY"), the journal updates instantly, and her gold ! appears without needing to open the quest journal first.
- The fresh-flower bank only spends when it should — donating without having taken the donation posting (or beyond what it needs) no longer silently drains your week's fresh-flower credit.
[v0.5.440] — 2026-07-21
Fixed
- Your familiars don't body-block you anymore — friendly summons (yours or a teammate's) no longer collide with movement, so no more getting pinned by your own owlbear or having an Echo Step die against his hindquarters. Rival-team summons stay solid — they're combatants.
- "Skirmisher" is finally "RANGER" everywhere — the class rename had one stale label left, and it showed in the waiting room among other places.
[v0.5.439] — 2026-07-21
Fixed
- Sable's hood is black in the world, not just her portrait — her hood's art is painted in red key colors that need translating before the leather palette applies; the NPC renderer skipped the translation the gear renderer (and the portrait tool) already knew about.
- Sable no longer calls Aether a scar — the metaphor is fully retired; she now reads the material truth in her own register: "It is what the void builds with. Walls, beasts, blooms - all one material, wearing different shapes."
[v0.5.438] — 2026-07-21
Fixed
- Queued crucible items can be taken back — both crucibles, town and dungeon. Items waiting in line come back whole; pulling the one already in the fire forfeits its progress and the next in line takes its place. (The withdraw tab always listed them — the server just refused.)
- Smelt bounty credit now lands when an item FINISHES smelting, not when you deposit it — depositing and immediately withdrawing would have been free bounty progress.
[v0.5.437] — 2026-07-21
Changed
- Lira patrols AROUND the portal now — a proper circuit at a respectful three-tile distance, instead of wandering into the plaza itself. Watching who comes and goes, from where a watcher would actually stand.
[v0.5.436] — 2026-07-21
Changed
- The board asks for real work now — bounty counts roughly doubled across the slots (culls, slaying, gathering, chests, weeklies), tuned so a full daily sweep takes a few runs instead of one lucky dungeon.
- Hazel wants FRESH flowers — donation bounties only count blooms brought home this week. Your stockpile still buys her boons, but the posting wants flowers that are still humming. She'll explain.
- "Earning" aether means bringing it home — the weekly aether bounty counts what comes through the portal with you (picked up or smelted in the depths). Town-smelting old gear no longer counts.
- The smelter is the rest-day job — when "Feed the Crucibles" is posted, it stays stockpile-friendly on purpose. One honest day's work without a sword swing.
- Runs now log combat telemetry (class, health, gear score, damage taken, cause of death) for tuning.
[v0.5.435] — 2026-07-21
Changed
- The journal tells you who's paying — highlight a finished job and the footer says exactly where to go: "VISIT CROWE TO COLLECT YOUR REWARD." Same on the job's detail page.
[v0.5.434] — 2026-07-21
Added
- Crash trap — if the game ever panics, it now writes what happened to
crash.logon the SD card (survives reboots), and launch.sh keeps the previous session's log. A weak-wifi crash on 07-21 left no evidence; the next one will.
Changed
- Journal hint no longer says rewards come "from the poster" — "PAY IS COLLECTED IN PERSON."
[v0.5.433] — 2026-07-21
Added
- Postings got their fine print — reading a bounty now shows the poster's portrait, their pitch, and a proper terms panel: the exact job and numbers, WHERE the work is ("THE MOSSMAUL - THE OPEN CAVERNS", "CHEST HOARDS, STABLE+"), the reward, when the posting comes down, and your progress.
- The quest journal opens details too — cursor over an accepted job and press A for the same full posting view, anywhere: hub or mid-dungeon.
[v0.5.432] — 2026-07-21
Fixed
- Brother Garrick got his science right — he described Aether as "residue the void leaves behind," which contradicts how it actually works: Aether is what dungeons are MADE of. The scholar now teaches it properly ("we aren't gathering leftovers down there; we're taking the place apart"). Sable still calls it a scar — but poets are allowed to be wrong.
[v0.5.431] — 2026-07-21
Fixed
- Thalor's darkest line had a grammar stumble ("...I keep getting sent back... one day it won't"). Now: "I just keep waking up in the back room... and I'm terrified that one day I won't."
[v0.5.430] — 2026-07-21
Changed
- The town stopped repeating itself — asking around about Void Rejection now sounds like asking eight different people, not one script: each conversation phrases the question differently, and the old survival rules became what they always were underneath — a creed. Thorne recites it. Eldrin paid the price for ignoring it. Lira learned it from Thorne. Elias and Thalor still answer the same question differently, on purpose.
[v0.5.429] — 2026-07-21
Fixed
- Dialogue choices no longer run off the box — five lore-NPC questions were longer than the 38 characters the choice list can show and truncated mid-word ("...rejects some pe"). All shortened, and a test now fails the build if any future line is too wide.
[v0.5.428] — 2026-07-21
Added
- The lore cast walks Blackthorn Hollow — eight new townsfolk, each with their own haunt: Eldrin the retired Reaver (plaza), Lira the scout (portal square), Thorne the watchman (west side), Sable at the garden's edge, Elias and Thalor in the Rest's back rooms — the same rooms the void returns you to — Sister Mirel at her corner, and Brother Garrick at the Aether Forge. They introduce themselves once, and they have things to say.
- Gold nametags mark the talkers — lore folk wear parchment-gold names; vendors keep cyan. Gold is a person, cyan is a service.
- Ask around about Void Rejection. Seven people will tell you seven different things. Nobody is lying.
[v0.5.427] — 2026-07-21
Fixed
- The daily town notice stays on the board — it was leaking onto the quest journal, where a stray "NOTICE: ... - CROWE" made no sense.
- Crowe's notice got its joke back — a screen-width trim had cut "NO QUESTIONS." and left "SOME QUESTIONS." dangling. Now: "BUYING THE UNUSUAL. NO QUESTIONS. WELL, SOME."
[v0.5.426] — 2026-07-21
Changed
- Taking a job takes it off the board — accepted postings move to your quest journal; the board only shows work still available. Take all four and it says so: "YOU'VE TAKEN EVERY JOB. NEW POSTINGS AT DAWN."
- Board footer fixed — the hint text overlapped; it's just "A: READ BOUNTY" now.
[v0.5.425] — 2026-07-21
Changed
- Dialogue de-duplication pass — Mira and Grim got new first-meeting lines (Mira's read awkwardly and both echoed their stock lines), and seven turn-in lines were rewritten where they'd recycled a first meeting, an opener, or the job posting's own pitch. Every character keeps their signature motif in exactly one place now.
[v0.5.424] — 2026-07-21
Changed
- The board and the journal are now genuinely different things. The BOUNTY BOARD (at the plaza only) shows job POSTINGS — headline titles ("WANTED: THE WILD THINGS", "THE FORGE IS HUNGRY"), poster, reward, and NEW/TAKEN status; open one to read the pitch and the fine print (TERMS), then take the job or leave it. The QUEST JOURNAL (R2, everywhere — hub and dungeon) is the tracker: your accepted jobs with literal objectives and progress bars.
- Posting details now show TERMS — the exact objective — under the headline, so the flavor and the contract are both on the page.
[v0.5.423] — 2026-07-21
Changed
- Jobs are taken, not inherited — the Bounty Board is now a real board: browse the four postings, read one (each poster pitches the job in their own words), and TAKE THE JOB — or leave it. Progress only counts on jobs you've accepted.
- R2 in dungeon is now the QUEST JOURNAL — your accepted jobs only. The board itself lives in town.
- One payday per conversation — a poster with two finished jobs pays them one at a time, each named in the summary, and tells you to talk again for the rest.
- The board opens instantly in the hub — it shows cached state and refreshes in the background instead of waiting on the server.
Fixed
- "Come out richer" deed no longer counts the ingots you walked in with — it's net gain now, and the target dropped from 150–250 to a telemetry-tuned 30–60. Walking wealth through the door is not an achievement.
[v0.5.422] — 2026-07-20
Added
- THE BOUNTY BOARD — the last unbuilt hub system. Three daily bounties (the Hunt, the Harvest, the Deed) and one weekly, freshly generated every day at 5am Central (weekly Mondays), the same board for every Reaver. Check it at the board by the plaza — or press R2 anywhere, hub or dungeon, for the full-screen view.
- Progress rides your extraction — kills, pickups, chests, and barrels count while you run, but only pay out if you make it back through the portal. Die and the run's bounty progress dies with you. The in-dungeon view (R2) shows live at-risk numbers; extraction-type bounties count only at the portal.
- Party kills share credit — anything your teammates kill counts for your bounties too.
- Get paid in person — completed bounties show a gold ! over the poster's nametag; talk to them and they pay you in character. Claims are ingots, aether, and on weeklies a void stone (plus an aether core on Empowered weeks).
- Clean sweep — finish and claim all three dailies in one day for +15 bonus ingots.
- First meetings — every vendor now introduces themselves the first time a character talks to them (once, ever).
- Town notices — the board carries a rotating daily notice from the townsfolk. The stew is surface goods only. Stop asking.
- Run telemetry now records kills per run (extraction and death alike) for tuning.
[v0.5.421] — 2026-07-20
Fixed
- "Item not in bag" at Pell's self-heals — when the sell list goes stale, it now refreshes itself from your actual bag on the spot ("LIST REFRESHED — TRY AGAIN") instead of making you close and reopen his dialogue. The server also logs full detail when it happens, so the next occurrence tells us the root cause.
[v0.5.420] — 2026-07-20
Fixed
- The quick-use strip shows what's actually loaded — the food slot always drew a drumstick regardless of contents, so a slotted Blackthorn Ale looked like a chicken leg (the buff it gave was always the correct one — the ale's stamina regen; only the picture lied). Potion slots show their real tier art too.
[v0.5.419] — 2026-07-20
Fixed
- Vendor walk animations no longer sprint — idle breathing time was banking into the walk-animation clock, so after standing a while a vendor's first stroll played its steps at ludicrous speed (movement itself was fine). Separate clocks now.
[v0.5.418] — 2026-07-20
Added
- Run telemetry — the server now permanently logs every run outcome (extracted or died) with duration, mode, dungeon type, and carried-in vs carried-out currency totals. Invisible to players; it exists so bounty goals and rewards get tuned against real play data instead of guesses.
[v0.5.417] — 2026-07-20
Changed
- Esper helmets bloom with yellow eyes — the glow defaults to the classic yellow instead of a random color; Hazel can dye it red, blue, or any everbloom whenever you like. Existing esper blooms that hadn't chosen a color are set to yellow.
- Vendors breathe — the paper-doll cast now has the same idle breathing as players instead of holding a frozen pose.
[v0.5.416] — 2026-07-20
Changed
- Trogkin chest guards now appear only in Stable and Empowered Mossmaul dungeons — mirroring the Redrot's beholders. Unstable chests in both dungeons go unguarded; the good hoards get the good guards.
[v0.5.415] — 2026-07-20
Changed
- The dyer of Blackthorn Hollow is named Hazel — nametag, dialogue, and Hazel's Dyeworks all updated. Same garden, same streak, same opinions about other Reavers' flowers.
[v0.5.414] — 2026-07-20
Fixed
- Vendors walk their diagonals properly — facing was recomputed every frame with only four directions, flapping between axis facings mid-stroll, and positions truncated to whole pixels per axis (stair-step jitter). Facing now locks to the true 8-direction heading when a stroll starts, and positions round smoothly. Vendors also turn to face you diagonally when you talk to them.
[v0.5.413] — 2026-07-20
Changed
- Dyeing returns you to the gear list — after a dye applies, the cursor goes back to your pieces instead of lingering in the palette. The variant-look toggle (X) stays where you are, since it's a free in-place flip.
[v0.5.412] — 2026-07-20
Added
- Six grounded hair colors — auburn, copper, strawberry blonde, sandy blonde, chestnut, and ash brown join the character creator (and beards). The loud colors remain for those who want them; redheads no longer have to settle for candy apple.
[v0.5.411] — 2026-07-20
Fixed
- Vendor portraits sit flush in their frames — shorter heads (Grim, Crowe, Mira) had blank space floating above them; portraits are now head-anchored. New tool:
tools/npc_portraits.pyregenerates every portrait fromhub_npcs.jsonin one command.
[v0.5.410] — 2026-07-20
Changed
- The dye menu is titled "Elowen's Dyeworks."
[v0.5.409] — 2026-07-20
Fixed
- Elowen's dialogue portrait regenerated from her actual doll — the gray streak now matches her in-world hair exactly.
[v0.5.408] — 2026-07-20
Changed
- The whole town walks in the new style — Grim, Crowe, Mira, Veyra, and Pell join Elowen as paper-doll characters, each with a matching dialogue portrait. The vendor cast is fully migrated.
- Crowe traded his olive shirt (he and Grim were wearing the same one) for a gold-amber merchant's cut.
[v0.5.407] — 2026-07-20
Fixed
- Elowen's nametag sits above her head — it was anchored to the old 38px sprite box and landed over her eyes on the taller paper-doll body. Paper-doll NPCs now anchor tags to the visible head.
- Player nametags (hub and dungeon) raised a few pixels so the 30%-larger dolls and tall hats can't collide with them.
[v0.5.406] — 2026-07-20
Changed
- Elowen walks the garden as a paper-doll now — the first vendor rendered in the new character style: her own outfit, silver-trimmed boots, and the gray streak visible from every angle as she wanders. The other vendors will follow.
[v0.5.405] — 2026-07-20
Changed
- Elowen has a gray streak in her hair — on her sprite from every angle it shows, and on a new dialogue portrait rendered in the paper-doll style (the first vendor to get one). Some things about a person are worth keeping exactly as they are.
[v0.5.404] — 2026-07-19
Added
- The shogun's crest is dyeable — the gold ornament gets its accent channel from the metal palette (plus everblooms). The ties stay as they are. That completes the accent set: every everbloom helmet with a second color now has it in the dye shop.
[v0.5.403] — 2026-07-19
Added
- The musketeer's feather is dyeable — the plume gets its own accent channel (steel/silver/gold/bronze, plus everblooms). The band and buckle stay leather.
- Esper eye glow is dyeable — both esper hats' eye shapes get an accent channel: yellow, red, or blue, plus everblooms. The eyes also no longer change color when you dye the hat itself — hat cloth and eye glow are independent now.
Fixed
- Valkyrie wings actually take accent dye — the wing pixels are painted in cloth colors, so pointing them at the metal palette needed a proper cross-palette mapping; before this they ignored the accent entirely.
[v0.5.402] — 2026-07-19
Added
- Accent dyeing — helmets with a second color channel (the khaan's trim, the valkyrie's wings, the soldier-helm's plume, the kheshig's trim) can now have that channel dyed at Elowen's. Y swaps between MAIN and ACCENT in the swatch picker; stage both, then one press applies the whole look for a single 5 crux — per-piece pricing. Everbloom colors work on accents too.
Changed
- The valkyrie's wing accent dyes from the metal palette (steel/silver/gold/bronze) rather than the cloth colors.
- The everbloom marker on swatch chips has a dark border so it reads on light colors.
[v0.5.401] — 2026-07-19
Changed
- Helmet recast — Voidguard's everbloom is now the winged valkyrie helm ("Valkyrie's Wing"). Voidstitched wears the traveller straw hat as its standard helmet and blooms into the shogun helm ("Shogun's Crown"). Existing pieces change art automatically; Voidstitched helmets dyed under the old palette are reset to their natural color (the ramp family changed).
[v0.5.400] — 2026-07-19
Changed
- Ironclad and Voidguard everbloom variants swapped — Ironclad now blooms into Khaan's Spire (tall spiked helm), Voidguard into Paladin's Plume (winged helm). Already-bloomed helmets change art automatically.
[v0.5.399] — 2026-07-19
Changed
- Bloomed helmets keep their set name — blooming now prefixes "Everbloom" ("Everbloom Ironclad Helm") instead of replacing the name entirely, so the piece still reads as part of its set. The variant names (Paladin's Plume, Esper's Veil...) live on as the look's title — Elowen announces them, and the dye shop's toggle line names the look. Already-bloomed helmets are renamed back into their sets automatically.
[v0.5.398] — 2026-07-19
Fixed
- Void-violet no longer purples the linework — high-chroma hues read loud on dark outline pixels; violet's structure tint is dialed way down (per-color override, more can follow).
- Bonewhite's swatch chip is actually bone-white — chips were sampling the most-changed palette column, which for light dyes on dark gear families is a dark column. Chips now show the median-brightness dye shade.
[v0.5.397] — 2026-07-19
Fixed
- Everbloom colors have real contrast now — dyed pieces keep 40% of their family's original value range (bright highlights stay bright, deep shadows stay deep) instead of being squeezed into the color's narrow band, and dark structure pixels take a subtle 30% tint of the dye so blacks harmonize with the color instead of sitting detached from it.
- Palette recoloring now only treats base-palette colors as keys — generated dye rows could coincide with real art pixel values and remap pixels that were never meant to change (caught by the pixel-perfect golden test).
[v0.5.396] — 2026-07-19
Fixed
- Unlocked everbloom colors show up from login — previously they were invisible in the dye shop until your next donation refreshed the state (a startup message was being discarded by the request/response reader).
- Everbloom colors no longer wash out the art — the generator was tinting outline and deep-shadow palette columns that the base game keeps constant. Structure columns now stay untouched (matching how the stock colorways behave), so linework stays dark and pieces keep their contrast. Straw hats keep their straw and dye only their band, as the pack intended.
- Dye swatch chips now sample the column that actually changes — on band-dyed families every chip previously showed the same fixed color.
[v0.5.395] — 2026-07-19
Fixed
- Variant look toggle is actually reachable — the "VARIANT LOOK: ON/OFF" status showed from the dye shop's item list, but X only worked inside the swatch picker (and the item-list footer never mentioned it). X now toggles from both views, and the footer shows the hint whenever a bloomed piece is selected.
[v0.5.394] — 2026-07-19
Changed
- Elowen takes one boon's worth of flowers per visit — donating a big pile no longer triggers a wall of stacked unlock announcements. She accepts only enough to reach the next threshold, announces that one boon properly, and asks for the rest next time you talk. Bring her 500 flowers and you get five little ceremonies instead of one long speech.
[v0.5.393] — 2026-07-19
Fixed
- Flowers no longer sprout in unreachable spots — platforms and canals carve their structures after overgrowth is painted, so a flower could seed on top of a platform you can't climb. Flowers now require genuinely walkable floor.
Added
- Console:
/mailto <character> flowers <n>for testing Elowen's donation flow.
[v0.5.392] — 2026-07-19
Fixed
- Hub joins landed at Reaver's Rest instead of where you belong — a new join-sequence message (Elowen's progress) was arriving before the authoritative position, so the client fell back to the tavern spawn on every login and extraction. Message order restored; extraction returns you to the portal again.
- Dye shop layout pass — header no longer clips at the screen edge, the worn "W" tag sits clear of item names, the item list is wider (long set names fit), and the character preview is properly centered.
Changed
- The dye menu is titled "Elowen's Dye Shop" (was "Dye Garden").
[v0.5.391] — 2026-07-19
Added
- Elowen, the Dyer of Blackthorn Hollow — a new NPC living in the garden cottage west of the Reaver's Rest tavern, tending the only true green in town. She has openers, garden lore, and opinions about other Reavers' flowers.
- Flowers grow in the dungeons — overgrowth patches now sprout 3–6 pickable flowers (THE MOSSMAUL grows white/blue/pink, THE REDROT red/yellow/deep purple). They stack into one bundle, are worth nothing to Pell or the crucibles, and are lost on death like all cargo. Elowen wants them.
- Flower boons — every 100 flowers donated, something happens: the set helmet you're wearing BLOOMS into an exclusive variant (renamed, renders new art, rides the item through trade/loot/death), or a new everbloom dye color unlocks, or — once she's taught you everything — a pouch of ingots. Her thank-yous hint at your progress; she never says numbers.
- Elowen's dye service — recolor any worn or carried armor piece for 5 Crux Ingots: full-screen menu, live preview of your character wearing the color, every color in the piece's palette family. Twenty unlock-only everbloom colors exist across every gear family — including Duskblack, which has left the random drop pool to become the first of them (existing black gear keeps its look).
- Variant look toggle — bloomed headwear can switch between its everbloom art and the set's standard hat, free, in the dye menu (X).
Changed
- Random drop colors are now frozen against future palette growth — adding new dye colors can never reshuffle the color of gear you already own.
[v0.5.390] — 2026-07-16
Changed
- Quick-use moved to R1 — the potion/food strip you reach for constantly now sits on the easier shoulder button (hold R1, D-pad to cycle, release to use, B to cancel). R2 is reserved for the upcoming quest log.
[v0.5.389] — 2026-07-16
Changed
- Knockback camera is much calmer — getting bowled by a Trogkin charge (or any knockback) now sends your character visibly flying across the frame while the camera drifts lazily after, instead of the viewport chasing every jolt. Same recovery, a third of the camera motion.
[v0.5.388] — 2026-07-16
Fixed
- Second Wind's red halo fits again — the glow was still sized for the old sprite dimensions (swallowed behind your 30%-larger body locally, oversized and off-center on other players). Now sized and centered from the scaled sprite box.
[v0.5.387] — 2026-07-16
Fixed
- Crash wearing the ranger-hat — v0.5.386's hat-alignment scan assumed every sprite sheet has 29 columns; the pack's ranger-hat sheet is one column short, crashing the client on load for anyone wearing it (reported as "my rangers crash the Flip"). Bounds are clamped and a regression test pins it.
[v0.5.386] — 2026-07-16
Fixed
- Hats stay on heads mid-stride — some pack hats (the ranger-hat most visibly) bob on the wrong walk frames, dipping over the eyes. The composer now re-syncs every hat to the body's actual head position frame-by-frame in all 8 directions.
[v0.5.385] — 2026-07-16
Fixed
- Charging at nothing no longer draws the bow — the heavy attack's held wind-up pose also requires a live target lock now, matching the swing rule. Charging at barrels or empty air keeps your normal stance until the kick.
[v0.5.384] — 2026-07-16
Fixed
- East/west walking rhythm — the walk cycle played all four frames at a uniform rate, but the pack's gait holds the passing pose longer than the steps (140ms/200ms). In profile view the two step frames are nearly identical silhouettes, so the even timing read as a missing frame / double speed. The proper rhythm now plays everywhere (you, other players, hub).
[v0.5.383] — 2026-07-16
Fixed
- No more point-blank bow draws at barrels — the weapon swing animation only plays when your attack has a live target lock. Breaking barrels (and swinging at empty air) shows the quick kick instead, for every class.
[v0.5.382] — 2026-07-16
Fixed
- Getting shot makes enemies angry — arrows and bolts now pull aggro onto the shooter (previously an enemy hit from beyond its detection range just stood there taking it). Normal chase leashing still applies at extreme range.
- Off-screen target locks tightened — locks now drop 1 tile past the viewport edge (was 2), the L1 target cycle only offers enemies actually on screen, and multishot won't aim its fan at an off-screen lock (falls back to your facing).
[v0.5.381] — 2026-07-16
Fixed
- Pell's sell list no longer goes stale — sale confirmations that arrived a beat late were discarded, leaving sold stacks in the list (and "Item not in bag" on the retry, plus ghosts in your inventory until you reopened Pell). Confirmations now apply whenever they arrive, prefer the entry under your cursor, and keep the inventory view in sync.
[v0.5.380] — 2026-07-16
Changed
- Regular enemies render 25% larger — feet-anchored, hitboxes unchanged. Keeps the rank-and-file threatening next to the scaled-up heroes; mini-bosses and bosses stay their already-imposing native size. Death tumbles, stun glows, blink trails, and health bars all track the new size.
[v0.5.379] — 2026-07-16
Fixed
- Shot-facing snap is reliable — the snap was computed before auto-targeting ran each frame, so shots that acquired (or switched) their target in the same instant aimed the animation at the old lock or nothing. The snap now resolves after targeting settles.
[v0.5.378] — 2026-07-16
Added
- Kiting reads like kiting — Rangers and Arcanists briefly snap to face their locked target while the shot animation plays, then return to their movement facing. Run one way, twist, loose, keep running.
[v0.5.377] — 2026-07-16
Fixed
- B-slot cooldown sweep — the Warrior's HUD used a stale 10s max for Bull Charge's 15s cooldown, pegging the slot as a solid black square for the first 5 seconds (it looked dead, not cooling). All three classes' maxes now match the server.
Added
- Bull Charge has a look now — a hot orange V-wedge punches ahead of the charge with fading rust afterimages trailing behind. Rivals and teammates charging near you get the trail too.
Notes
- Movement specials (Bull Charge, Echo Step, Void Shift) aim diagonally since v0.5.372 — they follow your full 8-direction facing.
[v0.5.376] — 2026-07-16
Fixed
- Idle breathing, actually everywhere — the "sitting legless" idle was the HUB pinning idle to the exhale frame with no animation; the dungeon's breathing cycle was fine all along. Breathing now runs in both hub and dungeon (you and everyone else), and black leather is back in the random dye pool.
[v0.5.375] — 2026-07-16
Fixed
- The sitting-down legless idle — the idle "breathing" cycle alternated with an exhale frame whose body drops a pixel and whose legs shrink to a single row of outline pixels; at game scale it read as a glitch. Standing characters now hold the pack's canonical tall standing pose (the same base frame its hurt/death animations build from). Breathing may return if the exhale frame gets a touch-up.
[v0.5.374] — 2026-07-16
Fixed
- Invisible legs while standing — random drop dyes could roll pure-black leather boots, which vanish (along with the idle stance's dark outlines) against dungeon floors. Random dyes now stick to the pack's natural palettes; black stays reserved for deliberate dyeing later. Idle characters also breathe now (subtle two-frame cycle) instead of freezing.
- Echo Step decoys wear your face — the decoy left behind now uses your composed paper-doll (correct gear, 8-direction facing, proper size) instead of the retired hero sprite.
Changed
- Arrows fly true — Ranger arrows no longer curve toward their target; they travel in a straight line, noticeably faster. Lead your shots.
[v0.5.373] — 2026-07-16
Changed
- Arrows look like arrows — Ranger shots are drawn as a proper arrow (wood shaft, steel head, red fletching) instead of a recolored arcane bolt. Placeholder until real art.
- Weapons are class-exclusive — swords are Warrior-only and bows Ranger-only at every rarity (staves were always Arcanist). Starter chests now always give your class's weapon. Bows got their own inventory icon.
- Real attack animations — basic attacks play your weapon's swing (sword slash, bow draw, stave cast) for you and everyone watching; holding a charged attack holds the wind-up pose, which snaps into the full swing when it fires.
[v0.5.372] — 2026-07-16
Fixed
- True diagonal facing — the main player draw path (and the hub) still ran the old 4-direction sprite logic, scrambling rows on the new 8-direction sheets. Diagonal movement now faces diagonally, everywhere.
- Your gear renders again — appearance data arriving during the dungeon loading screen was being discarded, leaving you drawn bare until an equip change.
Changed
- Characters render 30% larger — players (and corpses) draw at 1.3x, feet-anchored, so the chibi bodies hold their own next to enemies. Source frames untouched; hitboxes unchanged.
[v0.5.371] — 2026-07-16
Fixed
- Character creator shows the bare body — the identity preview was accidentally dressed in starter gear, hiding the skin tones and hair styles you were choosing. Now fully bare, and L1/R1 rotates the preview through all 8 facings.
[v0.5.370] — 2026-07-16 — THE VOID REMADE THE HOLLOW
The puny migration: the biggest visual overhaul since the game began. This release is protocol-breaking — clients auto-update on next launch. Existing characters keep everything they own; the Void just gave everyone a new face.
Added
- Paper-doll characters — heroes are now composed from layered, dyeable pieces: your face is yours (skin tone, hair, facial hair, eyes chosen in the new character creator) and your gear is VISIBLE — helmet, outfit, gloves, and boots render exactly what you're wearing. Read a rival's loadout at a glance.
- True 8-direction sprites with real walk, attack, hurt, and death animations. Corpses now actually fall.
- Character creator — new characters pick their look; existing characters are routed through it once ("choose your face") and then straight into the Hollow.
- Contraband rarity — retired items (shields, old unspawnable gear) survive in your storage as dark-red relics: never equippable, still smeltable. Equipped shields were unequipped to your mailbox with a note.
Changed
- The Skirmisher is now the RANGER — spears became bows (your spears converted automatically). Basic attacks fire homing arrows; the heavy attack is MULTISHOT, a high-powered three-arrow fan. Shadow Mend and Echo Step unchanged.
- Shields have left the Hollow — R1 block, shield drops, and shield stats are gone; the loadout screen is a clean symmetric doll now. The Warrior's Shield Charge is reborn as Bull Charge.
- Set bonuses reworked — every set now has all three tiers: Ironclad Epic builds stacking damage resist as you take hits, Ironclad Legendary survives one killing blow per run at 1 HP, Voidguard Epic hastens Second Wind when struck, Shadowthread Epic hastens Echo Step on arrow kills.
[v0.5.369] — 2026-07-15
Fixed
- Summons can no longer be shoved into geometry — teammates now walk through their own team's familiars instead of pushing them, shove destinations are validated by the sprite's center (a body-shove could previously wedge a familiar's center inside a chest tile, where its own pathing failed every step forever), and any summon that still ends up center-stuck snaps back to its owner.
- Tome cooldowns are tracked per tome — swapping tomes mid-run no longer carries the old tome's timer onto the new one (a 300s summon cooldown landing on a 30s utility tome read as "my cooldown got reset"). Each ability keeps its own timer, so a cheap-tome round-trip can't skip a big cooldown either.
- Trogkin charge no longer shakes the whole screen — the camera eases smoothly through knockback instead of replaying each discrete server step as a full-viewport lurch; the stumble stays on your character where it belongs.
- Auto-target re-evaluates — a clearly closer enemy entering the screen now takes the lock (with hysteresis so two enemies at similar range don't flip-flop). Targets you picked manually with L1 stay sticky.
- Locked melee attacks respect facing — a target lock is aim assist, not a 360° hit. The target must be in your front hemisphere, so a pixie blinking behind you actually forces you to turn around now.
- Fae blink has a beat before the strike — pixies and faeries no longer hit on the same tick they teleport (which was unreactable); they land behind you, pause ~0.4s, then swing. Combined with the facing fix, turning around in time is now real counterplay. The afterimage trail is also thicker and lingers longer (7 ghosts over ~0.5s, was 4 over 0.3s) so the reposition reads clearly.
Changed
- Trogkin charge smashes barrels — a charging Trogkin ploughs straight through breakables in its path (dropping their loot) instead of stopping at them like a wall.
- Set bonuses show on the item — set pieces now list their set bonus right in the item details: a two-line block naming the bonus tier this piece's rarity contributes, labeled and colored by that rarity (an Epic piece shows its Epic bonus in purple). Bonuses activate when wearing 5 pieces; the tier is set by the lowest-rarity piece.
- Stoneweave is now Voidsilk — the Arcanist's armored-robe set gets a name that fits where it comes from (Void-born loot, not masonry). Existing pieces migrate automatically on server start, mid-run and vaulted alike; the set bonuses are unchanged. New flavor to match.
- Crowe's daily specials sharpened — Ironweave (Rare) now guarantees only the big HP roll; Wyrmweave (Epic) keeps the guaranteed HP and a guaranteed defensive stat, making the 5%-of-days special meaningfully juicier.
[v0.5.368] — 2026-07-13
Changed
- Weak-WiFi grace pass — playing at the edge of your router's range no longer boots you to the menu without a word:
- the hub tolerates 20s of connection stall (was 10s) before reacting, matching how marginal links actually behave;
- a hub disconnect now auto-reconnects (up to 3 attempts with an on-screen retry counter) instead of dumping you at the menu;
- the in-dungeon reconnect window doubled to 40s;
- and every remaining fall to the main menu says why ("CONNECTION LOST — LOG BACK IN TO REJOIN YOUR RUN" after a dungeon drop, which the character-select takeover then honors).
[v0.5.367] — 2026-07-13
Changed
- Admin panel uses real password auth — the browser's native login prompt (HTTP Basic) instead of a token in the URL. Set your own password via the panel's "Change admin password" card or
/passwdin the console; it's stored only as a salted SHA-256 hash. The old plaintext token migrates automatically on first boot (same secret keeps working, plaintext file deleted).?token=<password>still works for curl scripting.
[v0.5.366] — 2026-07-13
Changed
- Admin mail form is fully graphical — character dropdown (live from the DB), item-type picker grouped by Gear/Sigils/Currency/Special, with rarity, sigil-stat, class, and amount fields appearing only where they apply, plus a live preview of the composed command. No more typing console grammar into a text box.
- Log retention raised to ~100MB — the active log rotates at 10MB into timestamped generations; oldest generations are pruned once the logs folder exceeds 100MB (previously max ~10MB kept).
[v0.5.365] — 2026-07-13
Added
- Server logs persist + admin log viewer — the supervisor now tees all server output to
logs/server.log(5MB rotation, one previous generation kept), and the admin panel gains a live-tailing log card (auto-refresh toggle, sticks to the bottom). Previously logs lived only in the tmux pane and died with it.
[v0.5.364] — 2026-07-13
Added
- Web admin panel — a token-gated dashboard at
:9878/adminon the game server: who's online (hub and dungeons, refreshing live), a mail-item form speaking the full console grammar (gear, sigils, currency, crystal balls), and a scheduled-restart button with the in-game countdown. The token lives indata/admin_tokenon the server and is printed at boot. No client changes — the panel drives the same code as the tmux console.
[v0.5.363] — 2026-07-13
Added
- Bear trap art — the Tome of Snares trap now uses the real 4-frame sprite: the armed jaw sits on the floor for your team, and springing it plays the snap animation in place. Rivals still see their disguise clutter fling apart. (The procedural placeholder remains as a fallback if the asset is missing.)
[v0.5.362] — 2026-07-13
Fixed
- Town Crucible withdrawals no longer show a phantom second fragment stack — the server merges withdrawn items into your bag, but the crucible's local view appended them as a new row until reopen. Same fix family as the v0.5.337 shop-purchase bug; the merge logic now lives in one shared helper used by all client bag views, and the Dungeon Crucible's version gained the full rarity/food-kind merge key.
[v0.5.361] — 2026-07-13
Fixed
- Vendor greetings and farewells now rotate — the random pick repeated constantly with only 3 lines (Pell seemed to have a single opener). Consecutive conversations are guaranteed to cycle through all lines, with openers and closers on different strides so the pairings vary too.
[v0.5.360] — 2026-07-13
Changed
- Pell wears npc_13 (sprite + portrait).
- Hub NPC sprites 4px wider (28 → 32) — the 16×16 source stretch was a touch too lean; placeholder until better-proportioned sprites land.
[v0.5.359] — 2026-07-13
Changed
- Pell relocated — now just south-east of the Dungeon Portal, the first face you can visit after extracting with a bag full of vials.
- Pell's dialogue de-glassed — three "glass" references trimmed to zero; "Bottles. Legs." carries the flavor.
Fixed
- Hub NPCs respect collision — all vendors (not just Pell) were wandering through walls and solid tiles; NPC strolls now stop at any solid the player can't walk through, and wander targets on solid tiles are skipped.
[v0.5.358] — 2026-07-13
Changed
- Pell pays the same for health and stamina — vials both 3, tonics both 6.
[v0.5.357] — 2026-07-13
Added
- Pell, the buyback man. A new vendor in the central plaza who buys dungeon salvage for Crux Ingots: health and stamina vials (3/2), tonics (6/5), and chicken legs (4 — a premium; ask him why). The game's first sell screen: A sells one, Y sells the stack. Ask him about the chicken legs.
- Tonics now drop in dungeons — the Uncommon brews appear everywhere vials do, at exactly one-fifth the rate (chests and barrels).
[v0.5.356] — 2026-07-13
Fixed
- Sign-in/sign-up cursor no longer covers first letters — the cyan selection edge sat exactly on the first glyph of labels and values (the S in SERVER, the U in US East…); the highlight now extends into the left margin instead.
[v0.5.355] — 2026-07-13
Changed
- Aether flavor rewritten — it isn't bottled; it's what escapes Void-made things: "It bleeds from everything the Void has made. Weighs less than nothing." (Consistent with smelting yield, enemy drops, and chest finds.)
[v0.5.354] — 2026-07-13
Added
- Real lowercase rendering — the 5×7 glyph font gains a full a–z set, so text boxes, keyboard labels, character lists, and in-world nametags finally show casing exactly as typed. (The 8×8 font already had lowercase; the two now agree.)
Changed
- Character names keep their casing, uniqueness ignores it — "Rian" existing now blocks "rian", "RIAN", and every other casing at creation.
- Front-door cursor unified with the hub — main menu, sign-in, sign-up, character select, and settings all use the hub's gold selection bar with the cyan left edge.
[v0.5.353] — 2026-07-13
Changed
- Breathing room between description and flavor text — the quoted lore line sat close enough to the functional text to read as its continuation (most visible on tomes); the gap widened at every site (bag detail, both inspect cards, shop panel).
[v0.5.352] — 2026-07-13
Changed
- Lore-consistency pass on flavor text — new canon: dungeon loot is Void-born (that's why smelting it yields Aether); nothing that drops in a dungeon claims surface manufacture anymore. Rewrote Sturdy Helm ("No smith in the Hollow will claim it."), Sturdy Treads, the Ironclad set line, and gave the Void Stone a better line ("A knot of the Void gone solid. Hold it too long and it holds back.").
[v0.5.351] — 2026-07-13
Changed
- Blood pool reshaped — narrower than the body and roughly twice as tall (ground-27 to ground-2), reading as a rounded oval under the corpse instead of a wide thin strip.
[v0.5.350] — 2026-07-13
Changed
- Corpses lie at natural proportions — the squish is gone; the rotated body rests at full size, with the blood pool moved up under its visible mass.
- Corpses show an interaction hint — approach one and "
'S REMAINS / A: SEARCH" appears, matching ground-item prompts.
Fixed
- All three hub spawn chests are solid — collision previously applied only to your own zone's chest; now every spawn chest blocks movement, owned or not, opened or not.
[v0.5.349] — 2026-07-13
Changed
- Corpses now fall over — a half-second death animation: the body collapses, keels over sideways (new rotated-sprite rendering), and settles darkened in a blood pool. The pool is bigger and actually visible now.
Fixed
- Kill messages name your killer — "SLAIN BY WARPHORN" instead of "SLAIN BY MON-033". Names come from the enemy index, covering all 119 kinds including boss adds.
[v0.5.348] — 2026-07-13
Added
- Player corpses are now loot containers. Dying leaves a persistent body at your tile (your sprite, fallen and darkened, with a nametag) holding everything you carried — no more items scattering on the ground. Anyone can walk up and press A to open "
'S REMAINS": one shared pool, first come first served, with all the usual bag-capacity and stack rules. Bodies stay visible for the whole run, even after being picked clean. PvE teammates can rescue your gear; PvPvE rivals can strip you — as the Void intended.
[v0.5.347] — 2026-07-12
Fixed
- Dying while disconnected now tells you about it — logging back in after your ghost died showed you silently respawned at the inn with an empty bag. The server now sends the kill reason ahead of hub entry and the client shows a full-screen death notice ("THE VOID KEPT WHAT YOU CARRIED").
- Second Wind glow renders correctly on other players' screens — the red pulse was drawn over the remote warrior's sprite (tinting the whole body) instead of behind it as a border glow, the way the warrior's own screen has always drawn it.
[v0.5.346] — 2026-07-12
Fixed
- Movement rubber-banding can no longer lock in permanently — the anti-teleport clamp's "self-heal" allowance was capped at ~99px, so any client/server position divergence beyond that was rejected forever (observed live as a 108px desync during a pixie fight). After ~1.5s of continuous rejections the clamp now yields and resyncs to the client (honest drift reconciles in 1-2 snapshots, so a sustained streak means broken state, not cheating; worst-case exploit throughput is slower than walking). Rejection logs now include the server-side position, streak length, and stun/knockback timers, and are rate-limited. Server-only fix.
[v0.5.345] — 2026-07-12
Changed
- Flavor text polish — now rendered in the same color as the functional description and wrapped in quotes.
Fixed
- Flavor text no longer overlaps socket info — the description block in the bag detail pane sat at a fixed height; on gear with several affixes and sockets the two collided. The block now flows below whatever the stats section actually used (soul-bound tag included).
[v0.5.344] — 2026-07-12
Fixed
- Post-extraction return to hub no longer bounces to the main menu every other run — v0.5.341's single-session rule invalidated the device's saved session token on each auto-reconnect (the server minted a fresh token and deleted the old one, but the client keeps using its stored token). Token-authenticated logins now keep their token and just refresh its expiry; password logins still mint fresh and kick other devices. Server-only fix.
[v0.5.343] — 2026-07-12
Fixed
- Rejoined runs are no longer a ghost town — the server kept the old session's input sequence counter, so every input from a freshly-relogged client was discarded as stale: your server-side position froze at the resume spot (no enemies ever streamed in) and attacks resolved there instead of where you stood (barrels "broke" visually but kept collision). Both rejoin paths now reset the counter and the movement clamp. Server-only fix.
[v0.5.342] — 2026-07-12
Fixed
- Hub no longer freezes on a silently dead connection — a 10s TCP-silence watchdog (hub snapshots arrive at 20Hz) now drops to the main menu when the link dies without a close ever reaching the device (e.g. a kick or server crash while your WiFi is stalled). Previously this required a hard power-off.
- Dungeon takeover resumes at your real position — the RejoinRun bundle now carries the ghost's live coordinates; previously the rejoined client spawned at the dungeon entrance (and disagreed with the server's anti-teleport clamp about where you were).
- Silent network death in a dungeon now triggers the reconnect flow — if no snapshot arrives for 8s (they come 30×/s), the client starts reconnecting instead of letting you walk a frozen world indefinitely. Brief blips under 8s still self-heal invisibly.
- Rejoin works even when the server never noticed you drop — RejoinDungeon now claims the account's session slot first, which force-ghosts a zombie connection (silent drops leave the server thinking you're still connected) and then rejoins normally.
[v0.5.341] — 2026-07-12
Added
- One live session per account — logging in kicks any existing session on the account ("new login wins"), with an "ACCOUNT LOGGED IN FROM ANOTHER DEVICE" notice on the kicked device. Fixes the ghost-player-in-hub bug after a laggy disconnect. Old session tokens are invalidated so the kicked device can't silently reclaim the account.
- Fresh-login dungeon takeover — if your character is ghosted in a live run (dropped connection or kicked session), selecting them at character select puts you straight back into the dungeon with your run bag, quick slots, equipped gear, ground loot, looted-chest and smashed-barrel state all restored. No more losing a run to a router hiccup.
- Reconnect window extended 30s → 120s — your body stays in the world (and killable) the whole time.
Fixed
- Combat-logging no longer preserves your bag — a player killed while disconnected now drops all carried loot at their tile immediately, exactly like a live death; killers can loot the corpse pile. Reconnecting after dying shows the proper death screen.
[v0.5.340] — 2026-07-12
Added
- Flavor text on every item in the game (~85 lines, new
client/src/flavor.rs): all live generic gear (weapons at every rarity, Common/Uncommon armor and shields, bags), one lore line per class armor set, all 20 ability tomes, both crystal balls, every consumable, sigils by stat, Crowe's daily families — and yes, Crux Fragments, Ingots, Aether, Void Stones, and Aether Cores. Rendered in a muted warm tan beneath the functional description in the bag detail pane, both inspect cards, and the shop's right panel. Derived client-side from item identity — no data or protocol changes, and every item ever dropped gets its line retroactively. - The hub inspect card now shows functional descriptions too — it previously ended at the sockets list; it now mirrors the loadout inspect card.
[v0.5.339] — 2026-07-11
Fixed
- Forge apply-sigil fee line no longer cut off — "FEE: 20-60 INGOTS BY RARITY" (dropped the redundant "SIGIL"; the line was 33 chars against ~33 chars of panel).
- Dungeon chest popup widened 280 → 360px — long gear names (Voidstitched pieces) were overlapping the border. Names also truncate defensively so nothing can ever run under the amount column.
[v0.5.338] — 2026-07-11
Fixed
- Party overlay says (N/3), not (N/4) — the header was hardcoded to the old cap.
PARTY_MAX = 3now lives in the shared crate and drives the display. - Party member names no longer look offline — non-leader names were drawn in dim gray; all members now get the bright color (the gold dot still marks the leader).
- The 3-member cap is actually enforced — the server never checked party size on invite or accept. Invites from a full party are now blocked server-side (including the invite-then-fill race), and the client shows "PARTY IS FULL" instead of sending a doomed invite.
[v0.5.337] — 2026-07-11
Fixed
- Bought consumables stack in the bag display — tonics, bread, stew, rations (and Aether bundles) merge into existing stacks up to the cap (3 for potions/food) the moment you buy them. The server was already merging correctly; the client was appending a separate row per purchase, so the bag showed phantom single-item stacks until the next full reload.
[v0.5.336] — 2026-07-11
Fixed
- Grim's menu line no longer offers chicken — "Ale, bread, rations, stew." His dungeon-news line was also reworded ("Don't go down hungry. On principle.") so the two prompts stop repeating the same sentence.
[v0.5.335] — 2026-07-11
Added
- Bread Loaf — Grim's fresh-baked HP food (4 Crux): 2 HP/s for 10s (20 HP total), with its own domed-loaf icon.
Changed
- Chicken Leg pulled from Grim's menu — it's dungeon scavenge now, found in barrels and chests only.
- Chicken Leg nerfed — buff duration 10s → 8s (16 HP total), so the bought loaf beats the scavenged drumstick.
[v0.5.334] — 2026-07-11
Changed
- Consumable descriptions normalized — stamina is "SP" everywhere (matching the quick-use strip), and food text only mentions the pools it actually regenerates. Blackthorn Ale no longer advertises "0 HP/s"; it reads "2 SP/s for 10s (20 SP total)".
- Food names render in meat-brown — the identity color the food icons already use — in shop lists, bag/loadout detail panes, inspect cards, crucible panels, vault, mailbox, auction, trade, and drop popups. Consumables (vials, tonics, currency) likewise use their identity colors at those name sites, matching the dungeon chest popup convention. Rarity borders and labels are untouched.
- All food is Common rarity — Hearty Stew shipped as Uncommon, which made its name green while the rest of the menu was gray. Price carries the tiering now. A DB migration (M013) rewrites any stored Uncommon food so old stew still stacks with newly bought stew.
- Grim's dungeon-news line no longer offers torches (not an item players can use). He tells you to eat something before going down instead. On principle.
[v0.5.333] — 2026-07-11
Added
- Grim's inn is open for business. The innkeeper gets the vendor treatment — three laconic greetings and farewells, a "How's business?" in his register ("Everyone eats before a run. Not everyone eats after."), his dungeon-news line, and the REAVER'S REST — the inn the game is named after: Chicken Leg (4 Crux), Field Ration (8), Hearty Stew (15). Food now has its proper home; Crowe's counter stays gear and brews.
[v0.5.332] — 2026-07-11
Changed
- Crowe's shop is now "CROWE'S PRIVATE STOCK" — one big header instead of the confusing "AUCTION HOUSE / CROWE" pair. He runs the Auction House building, but this counter sells his own goods; the naming now keeps the two apart. Mira's shop header reads "IRONVAULT SUPPLY".
[v0.5.331] — 2026-07-11
Changed
- Shop rows stretch to fill the list — row height is computed from the stock count, so Crowe's nine items use the full space down to the hint bar (46px rows today) and Mira's short list gets comfortable tall rows instead of a cramped strip with dead space below.
[v0.5.330] — 2026-07-11
Fixed
- Crowe's list no longer overlaps the button hints — rows tightened from 50px to 44px, so all nine stock items fit above the hint bar.
- The shop's right panel now shows item descriptions — the same functional text as the inventory (potion heals, food regen, orb behavior), word-wrapped between the stats and the price box.
- The Y:INSPECT modal and the Town Crucible's detail pane show descriptions too — the inspect card never displayed description text at all, so inspecting from the Loadout told you nothing about what a consumable does.
[v0.5.329] — 2026-07-11
Added
- Three daily weapons at Crowe's: a shield, a staff, and — alternating by day — a sword or spear. Genuine dungeon-style rolls (normal affixes, sockets, weapon bases) at Uncommon (60%, 50 Crux) or Rare (40%, 100 Crux), same items for every player each day.
Changed
- The Wyrmweave day is rarer: 5% (was 20%) — the Epic armor special is now a genuine event.
Removed
- Field Ration and Hearty Stew left Crowe's shelves — food is moving to Grim's inn (his vendor pass will re-list them). Chicken legs still drop in dungeons; existing rations/stew in bags keep working.
[v0.5.328] — 2026-07-10
Removed
- The temporary 300 Crux Ingots in spawn chests (added in v0.5.316 for hub-system testing). Fresh characters start with the class weapon and armor piece only.
Added
- Consumables and crystal balls now show functional descriptions — potions state their exact heal/restore and cooldown (stamina ones note the Disease cure), food shows per-second regen with totals, and both orbs spell out channel time, reveal duration, cooldown, and the Clouded ball's shatter count. Derived from the live game numbers, so rebalances update the text automatically.
Fixed
- One-time database migration refreshes stored item names — old "Health Potion"/"Stamina Potion" blobs become Vials and the three soul-bound orbs become Flawless Crystal Balls in every table (bags, vaults, equipped, quick slots, mailbox, auction listings). Mixed old/new names were double-counting the Portal Courier's per-type fee.
[v0.5.327] — 2026-07-10
Changed
- Field Ration buffed to 2 HP/s (now 20 HP + 20 stamina over 10 seconds — a true chicken-leg-plus-stamina).
- Crystal balls draw as crystal balls everywhere — a 32px orb icon now covers shop rows, ground loot, and every other small-icon context (both orbs; the pedestal keeps the rarity color, so Flawless is gold-based and Clouded blue-based). The shop's detail panel also uses item-aware icons now (stew and ration no longer show a chicken leg there).
[v0.5.326] — 2026-07-10
Added
- The Clouded Crystal Ball — Crowe sells the fragile twin of the legendary orb for 150 Crux. Same 5-second channel, 60-second cooldown, and 15-second portal/crucible reveal — but it holds only 10 charges, shown as "N/10" on the item, and shatters on the last one (gone from your Tome slot, with a toast to mourn it). Charges are tracked server-side and survive relogs.
- Limited-use items are now a real mechanic — any future item can carry "N/M uses" and it displays in the bag grid and Loadout automatically.
Changed
- The original orb is now the "Flawless Crystal Ball" — only three exist, and they've earned the name: once channeled, its reveal now lasts the entire run (previously timed like the Clouded one). Existing orbs rename themselves automatically.
[v0.5.325] — 2026-07-10
Added
- Consumables have their own icons now. Dungeon-found Vials draw as narrow vials (Crowe's Tonics keep the full flask), Hearty Stew is a steaming bowl, and the new Field Ration is a wrapped pack — everywhere items render: bag, ground loot, trade rows, quick slots.
- Field Ration (Crowe, 8 Crux): the budget traveling meal — 1 HP/s + 2 stamina/s for 10 seconds. (Hearty Stew is planned to move to Grim's inn when his vendor pass lands.)
[v0.5.324] — 2026-07-10
Added
- Crowe's Tradehouse, refreshed. Three random greetings and farewells in his silver-tongued voice, plus a "How's business?" that mirrors Mira's — the deaths that bury her in paperwork are his sales pitch ("Every Reaver who dies down there was carrying somebody else's tonics").
- New stock: Health Tonic (12 Crux, heals 60), Stamina Tonic (10, restores 55), Hearty Stew (15 — 3 HP/s AND 3 stamina/s for 12 seconds). Brewed goods, a clear tier above dungeon finds.
- The Daily Special: an HP-affix armor piece that rotates every day — the only vendor source of HP-affix armor. Usually a Rare "Ironweave" piece (100 Crux, 1 socket); roughly one day in five it's an Epic "Wyrmweave" (250 Crux, 2 sockets). Slot, affix rolls, and rarity are the same for every player each day. (Replaces the fixed Ironweave Cuirass.)
Changed
- Dungeon potions renamed and rebalanced: they're Health Vials / Stamina Vials now — scavenged, not brewed — and the Health Vial heals 30 (was 40, which was over half an Arcanist's base pool). Stamina Vial unchanged at 30. Potion strength is now tied to the item's rarity.
- Vials and Tonics never stack together — stack merging everywhere (quick slots, pickups, vault, courier, golem) now respects the potency tier.
[v0.5.323] — 2026-07-10
Fixed
- Mira no longer quotes vault upgrades you already own. The client's cached vault tier starts at 0 each hub session and only synced when the vault was opened — so at a fully upgraded vault she'd still offer the tier-1 expansion (the purchase would have been safely refused, but the quote lied). She now checks the ledger — fetches the authoritative tier — before quoting. The old upgrade-overlay path (POI) had the same stale-cache bug since it was built; also fixed.
Changed
- Dialogue hints trimmed — no more UP/DOWN clutter: just "A: CONFIRM B: CLOSE" on the prompt list, and "B: CANCEL" in transaction confirms (where B backs out of the deal, not the conversation).
[v0.5.322] — 2026-07-10
Changed
- Loadout: quick-use slots spaced out — labels were landing 1px under the icon above, making it unreadable which slot they belonged to. Each block now has clear separation so the label reads with the icon below it.
- Loadout: expansion slots (Sash/Pouch/Backpack) moved flush against the right screen edge with the same stacked-label treatment as the quick-use strip, right-aligned — the two columns now mirror each other.
- Mira: "How's business?" reworded — "Slow. Reavers keep dying with their best gear on them. The Void gets the loot, I get the paperwork." (Dying Reavers make her job worse, not easier.)
[v0.5.321] — 2026-07-10
Changed
- Loadout quick-use strip restacked vertically — "SLOT 1 / STAMINA" labels now sit above each slot icon instead of cramped text beside it, the stack count draws on the icon (bag-grid style), and the inline button hints are gone: the bottom hint bar covers quick slots like every other slot. Empty slots show a small EMPTY tag.
- Mira: "upgrade my vault" (dropped "space"), and her max-vault line no longer teases premium accounts: "That's the limit - two full vaults. More than most Reavers ever live to fill. Prove me wrong."
[v0.5.320] — 2026-07-10
Added
- Mira runs the Ironvault through conversation — the second vendor to get the dialogue treatment. Random greetings and farewells in her dry, security-obsessed voice; vault upgrades handled entirely in dialogue (she quotes only the next tier — READY. to commit, and she reports the outcome); a shop selling the storage accessories (Leather Sash/Pouch/Backpack, moved from Crowe — storage is her business); and a "How's business?" flavor line.
Changed
- Vault upgrade costs are now tiered: 50 → 100 → 150 Crux (was a flat 100 per tier; same 300 total with a gentler on-ramp).
- Crowe's stock is Void Stones, Aether, and the Ironweave Cuirass for now — his own shop refresh is planned.
- Veyra confirms sigil work in her own words. When the forge was opened through her dialogue, applying or removing a sigil now returns you to the conversation with her reporting the outcome — "Bound and holding…", "Came out clean…", or "The binding fought back…" when a removal destroys the sigil. The POI path keeps the banner.
[v0.5.319] — 2026-07-10
Added
- Sigils can now be socketed into gear you're WEARING. The forge previously only worked on bag items — the common case (enhancing your equipped weapon/armor) silently required unequip → forge → re-equip. Apply and remove now work on worn gear directly, on the server and in the UI.
Changed
- Sigil apply/remove pickers redesigned. Two-pane layout: gear list on the left split into EQUIPPED (first — that's where you'll usually shop) and BAG sections, with item icons and socket pips (filled squares = socketed sigils in their rarity color); live detail pane on the right showing the hovered item's sockets, existing sigil stats, and the fee with your ingot balance. Step headers ("STEP 1/2: CHOOSE GEAR") make the flow explicit.
- The forge dropped its pink theme. Standard dark palette matching the crucible/auction house, with a single muted purple accent in the title. Successful operations return you to the screen you entered from instead of the main menu.
Fixed
- Chat wheel can no longer open over NPC dialogue (or the Aether Forge, vault upgrade, portal courier, and player menus — none of the newer overlays were in the "something is open" check that gates L2).
Changed
- The game is now titled "Reaver's Rest". The Miyoo app launcher label, launcher description, and the in-game title screen all carry the new working name (previously the RPG98 codename). Install paths and save locations are unchanged.
[v0.5.318] — 2026-07-10
Changed
- Town Crucible button hint matches the active tab — "A:DEPOSIT" on the deposit tab, "A:WITHDRAW" on the withdraw tab (was a combined "A:DEPOSIT/WITHDRAW"), consistent with the Dungeon Crucible.
- The unmissable auction-house cursor is now everywhere. Same warm highlight + cyan edge bar applied to: both Crucibles, the auction house My Listings tab, Crowe's shop, the mailbox, the player-trade window, and all four Aether Forge pick lists. No more squinting at two nearly-identical dark blues.
[v0.5.317] — 2026-07-10
Added
- Veyra now runs the Aether Forge through conversation. Random greetings and farewells, direct menu hooks ("I want to apply a sigil" jumps straight to that screen), and Aether Core crafting handled entirely in dialogue — she quotes the cost (100 Aether + 1 Void Stone + 20 Crux fee), you confirm with READY., and she tells you how it went (or exactly what you're short). The dialogue engine gained random openers/closers, inline transaction confirms, and farewell lines — the same treatment will roll out to other vendors.
Changed
- Agility's role is now legible: it's your stamina stat. AGI has always fed max stamina (+2 per point) — by design, it never affects movement speed. The Character tab's AGI row is replaced by a STAM row (in stamina teal) showing your effective max stamina, the same way MaxHealth folds into the HP row. Item cards still show per-piece AGI.
[v0.5.316] — 2026-07-10
Fixed
- Spawn chest loot is now actually granted. Opening the chest showed the items in an overlay but the server never wrote them to your bag — the loot was pure display. Items now persist to the bag on open, and the overlay says "ADDED TO YOUR BAG".
Changed
- Shield block % is now driven by your equipped shield instead of a flat 30%. The shield is its own thing: its defense/ward (affixes + sigils) no longer add to your body's DEF/WARD totals — they set the R1 block instead: 15% base + 1% per point, capped at 55% (Legendary Ironclad set: +10%, cap 65%). No shield equipped = no block. The Character tab shows a new BLOCK row.
- Shields only accept Defense and Ward sigils now (the forge refuses others — they'd contribute nothing), and newly dropped shields roll only DEF/WARD base affixes.
- TEMP: spawn chests include 300 Crux Ingots for hub-system testing. Will be removed before any public build.
[v0.5.315] — 2026-07-09
Changed
- Internal: repository reorganization. Legacy asset packs and abandoned experiments condensed into
_archive/, build outputs intodist/(untracked). Server tileset-config lookups and tool defaults now point solely at the canonicalassets/tree. No gameplay changes.
[v0.5.314] — 2026-07-09
Fixed
- Spawn chest no longer forfeits before you can loot it. The spawn zone is a tiny 3×3-tile box and the exit check compared the sprite's top-left corner against its raw bounds — about 1.5 tiles of movement (even walking toward the chest) counted as leaving the zone, which permanently opens the chest. The check now uses the player's foot centre with a 2-tile grace margin, so only genuinely wandering off forfeits the loot.
- Spawn chest is now solid. Its tile comes from spawn-zone data rather than the map's collision layer, so nothing ever blocked walking through it.
[v0.5.313] — 2026-07-08
Changed
- Elemental summons reworked (from playtest feedback that they die too fast):
- HP raised 60 → 100.
- All three now open with an element bolt (6-tile range) before closing to melee: Fire keeps the fastest bolt (~1.3s cooldown, 8 dmg — still the ranged specialist), Frost and Poison poke every 3s (6 / 5 dmg). Bolts also hit rival players (straight shot).
- Below 35% health they flee — backing straight away from the threat, firing bolts over the shoulder while retreating. No melee while fleeing.
- Fire elemental gets a real melee value (6) — it was accidentally falling through to Poison's 5 against rival players.
- Player bolts no longer clip friendly summons — a straight-shot bolt used to be able to hit your own team's Golem or elemental standing in the flight path.
- The Golem now actively seeks out barrels and loot within 10 tiles of its owner (about a screen — the same leash combat summons use) instead of only smashing what it happens to brush against while heeling. Barrels always; ground loot only while its hold has room. It returns to heel when the area is cleared, and never wanders beyond the leash.
Fixed
- Arcane bolts no longer draw underneath barrels and chests. Projectiles (player and enemy) were rendered before the y-sorted object layer; they now draw above the whole world layer, as befits things flying through the air.
- Dungeon Crucibles now block line of sight — the 4×4 stone furnace stops bolts, beams, targeting, and enemy detection, same as walls. You can genuinely take cover behind one.
- Solid rock now blocks bolts and sight. Plain carved-rock walls were never in the line-of-sight set (only canals and decorative platforms were) — projectiles could fly straight through the rock between rooms, and sight lines ignored it. Everything that blocks sight now also extinguishes projectiles on contact: rock, platforms, canals, crucibles — both player and enemy shots.
- Enemies across a canal can no longer aggro you. Aggro acquisition now requires line-of-sight (walls, platforms, canals) — resolving the inconsistency where water blocked YOUR targeting but enemies could still lock onto you through it and hold your loot pickups hostage from the far bank. Once a chase starts, it persists around corners as before; only the initial detection needs sight.
- Bosses no longer spawn half-inside walls (usually a south border). The spawn footprint check only consulted the blocked-object set — walls live in the tile map, which it never read, so a 4×4 boss anchored near a south border passed as "clear" with its lower rows inside the wall. Boss (4×4) and mini-boss (2×2) placement now require every footprint tile to be walkable floor and in-bounds.
- Knockback can no longer embed large enemies in walls. Landing validation used a player-sized hitbox for everyone; a 64px boss could land with most of its body inside geometry. Knockback now validates the target's real hitbox (full edge coverage, not just corners), for bosses, mini-bosses, and regular enemies alike.
[v0.5.312] — 2026-07-08
Changed
- Auto-targeting now covers tome casts — Doom's Mark, the Grasp, and Fae Steps lock the nearest enemy automatically when you cast with no target, same as basic attacks. Manual L1 targeting stays available but is never required.
- Auto-targeting only considers on-screen enemies. The snapshot intentionally carries off-screen bosses and pursuers, and the auto-lock could pick one of those — it now ignores anything outside the viewport.
- Bag grid: empty slots are now fully navigable. With storage upgrades pushing capacity past the 30 visible slots, the cursor can now travel through every empty slot down to the bottom of your capacity — previously you couldn't scroll past the last occupied row, so lower empty rows were invisible until an item landed in them. A/X on an empty slot do nothing, the detail panel shows "-- EMPTY --", and the scroll arrow now reflects total capacity. Also fixed cursor-right miscounting its bound while the grid was scrolled.
[v0.5.311] — 2026-07-08
Changed
- Tome of the Watcher: rivals now see placed sensors as tileset clutter (same per-viewer disguise scheme as bear traps) instead of receiving nothing — the eye rune stays visible to the owner's team only. When a sensor trips, the sonar ping now renders for everyone nearby, so a rival who wanders past "clutter" gets a tell that they've been spotted; the "WATCHER TRIPPED" toast remains owner-team only.
- Watcher trips now point with a pulsing edge-of-screen indicator instead of "- EAST" text in the toast: while the trip point is off-screen, an amber eye pulses at the screen edge in its direction for 3 seconds.
Fixed
- Chest tomes no longer spawn as broken legacy tomes (e.g. "Arcane Tome" with no ability).
roll_chest_lootwas the one drop path that never rolled a tome ability — chest tomes now tomeify at roll time like enemy drops. Legacy tomes already in a bag continue to self-heal on inventory load. - Equip slot swaps now truly stick. The displaced item stays in the equipped item's bag slot across inventory reopens and re-logins — previously the client re-sorted the bag by item id every time the screen was built, which yanked old items (most visibly the Crystal Ball) to slot 1 after every swap. The server's bag row order (which already preserved swaps) is now authoritative.
[v0.5.310] — 2026-07-08
Fixed
- Can't get trapped inside chests/breakables anymore. If a solid object overlaps your position (e.g. a chest generated clipping the spawn point), it no longer blocks your movement — you walk out, and it turns solid behind you. Same escape-hatch rule enemies already had.
[v0.5.309] — 2026-07-08
Fixed
- Tome parity: every tome now affects monsters AND rival players.
- Tome of Webs finally slows monsters — built real enemy slow machinery (half speed for chase and patrol while webbed), which also unblocks Time Warp later.
- Gale Force shoves rival players away, Ancient's Roar staggers them (0.7s vs the monsters' 1s), Tome of Venom poisons rivals on hit, Doom's Mark can mark a locked rival player (+50% damage from all sources, purple pulse visible to everyone), Fae Steps blinks behind a locked rival, and the Grasp yanks rival players to you.
[v0.5.308] — 2026-07-08
Changed
- Monsters now fight back against summons. Combat summons (Owlbear and the three Elementals) join players and Echo Step decoys as valid monster targets — enemies attack whichever is closest, so a summon standing between you and a pack genuinely tanks. The Golem stays fully neutral: it fights nothing and nothing attacks it. (Closes the v0.5.307 known limitation.)
[v0.5.307] — 2026-07-08
Added
- Ability Tomes Phase C — summons. Five new tomes; the tome roster is complete at 21 abilities:
- Epic — Tome of the Owlbear: a bruiser that fights beside you (monsters AND rival players). Tome of the Golem: an untouchable utility familiar — never fights, follows you, smashes barrels, and gathers world-dropped loot (8 slots); its haul is mailed to you on extraction, dropped where it stands if you die.
- Legendary — Tome of the Flame / Frost / Blight: the three elementals. Flame hurls ranged fire bolts; Frost's blows briefly freeze; Blight's blows stack poison.
- No timers: summons live until killed, replaced, or the run ends. One ally at a time — casting a different summon replaces the old one (a replaced Golem drops its hold); recasting the same one while it lives is refused without burning the cooldown. Rival players can kill your combat summons; your own team can't hit them, and summons never trip their own team's traps or watchers, spring loot drops, or take friendly tome AoE.
- Ally summons render with a green ring underfoot (amber for a rival's), and never cull out of your snapshot.
Known limitation
- Monsters don't actively target summons yet (rivals do) — monster-vs-summon retaliation is a follow-up.
[v0.5.306] — 2026-07-08
Added
- Ability Tomes Phase B — ten more tomes, all five rarities open.
- Common: Tome of the Grasp (yank your locked target to you + stagger; bosses immune) · Tome of the Watcher (hidden sensor, 2 active — alerts your team with a direction when a monster or rival crosses; invisible to rival players)
- Uncommon: Tome of Webs (web field that slows rival players)
- Rare: Tome of Fae Steps (blink behind your locked target) · Tome of the Molten Pool (magma pool burns monsters + rivals) · Tome of the Venom Cloud (heavy stacking poison cloud)
- Epic: Tome of the Arrow Storm (1s telegraphed devastation circle — dodgeable, red danger ring) · Tome of Sanctuary (consecrated ground heals your team) · Tome of the Gazer's Ray (windup, then a piercing 10-tile beam)
- Legendary: Tome of the Ancient's Roar (the Drakon's own stagger, shockwave and all)
- Player-cast zones never harm the caster's team; enemy-cast zones are unchanged. Epic and Legendary tome drops no longer clamp down.
[v0.5.305] — 2026-07-08
Added
- Ability Tomes (Phase A). The X button comes alive: tomes now drop as pure ability items (no stat affixes — the tome IS its ability), one equipped in the Tome slot, cast with X, permanently lost on death like all equipped gear. Six launch abilities, each native to one rarity:
- Common — Tome of Smoke: drop a 4s smoke cloud; enemies inside it lose track of you. Tome of Snares: place a hidden bear trap (3 per dungeon) — teammates see the trap, rival players see harmless tileset clutter until it springs (flings the disguise, damage + root). Works on monsters and players.
- Uncommon — Tome of the Gale: blast all nearby enemies away. Tome of Venom: coat your weapon; the next 5 hits apply stacking poison.
- Rare — Tome of Doom's Mark: your locked target takes +50% damage from ALL sources for 8s (marked enemies pulse purple for everyone). Tome of Thorns: raise a 3-tile thorn wall ahead — blocks movement (enemies path around it), wounds anything standing in it.
- The X hotbar slot shows the tome cooldown sweep; the inspect screen shows each tome's ability description. Tome drops above Rare clamp to Rare until higher pools open. Existing owned tomes are retro-assigned an ability on load — no stash goes dead.
[v0.5.304] — 2026-07-07
Added
- Vendors attend the conversation. The NPC you're talking to now stops wandering, drops to idle, and turns to face you for the duration of the dialogue — then resumes their stroll. Other NPCs keep wandering behind the dialogue box. (NPCs are client-side, so this changes nothing on other players' screens.)
[v0.5.303] — 2026-07-07
Fixed
- The hub no longer freezes while menus are open. Talking to a vendor (or having the vault, auction house, inventory, or any overlay open) paused the whole world — NPCs stopped wandering, the portal and light flickers froze, chat bubbles stuck, and your own position stopped broadcasting to other players. Ambient world updates now always run; overlays only capture input. Other players keep moving, NPCs keep wandering, and you stay visible standing at the vendor on everyone else's screen.
[v0.5.302] — 2026-07-07
Changed
- Maintenance release — version bump and deploy artifacts only; no gameplay changes.
[v0.5.301] — 2026-07-07
Changed
- Party loot-share toast moved below the player (y 200 → 280) — it slightly overlapped the character sprite.
[v0.5.300] — 2026-07-07
Fixed
- Auction house cursor is now unmissable — selected rows get a warm highlight, cyan left bar, and border lines (browse and listing views; the old selected/unselected backgrounds were nearly identical dark blues).
- Player-to-player trade item picker rebuilt — full-screen panel (was a cramped 300×240 modal), real item icons (same renderer as the inventory), identity/rarity name colors for every item, room for long names, stack counts, and a position indicator when scrolling.
- Control effects on other players are now visible. Root vines were only drawn on your own character — in co-op, a rooted teammate looked free. The rooted state now travels in the snapshot and everyone in view sees the vines; stunned players also tremor like stunned enemies do. (Audited the rest: ground zones and boss telegraphs were already broadcast to everyone; Slow/Disease/Curse are non-positional and read through movement/HP.)
[v0.5.299] — 2026-07-07
Fixed
- Early-run choppiness — real cause found. With every enemy alive at run start, the world snapshot (~45 bytes/enemy × up to 50 enemies) exceeded the ~1472-byte UDP payload limit and fragmented; on WiFi, losing any single fragment drops the whole snapshot, so all remote entities (other players AND enemies) stuttered for the first 30-60 seconds until enough enemies died to shrink the packet under the MTU. Snapshots are now interest-culled per player: only enemies within 14 tiles (plus bosses and anything chasing you) are included, capped at 24 by distance — packets stay well under the MTU for the whole run. A server warning logs if any snapshot ever approaches fragmentation size again.
[v0.5.298] — 2026-07-07
Fixed
- Runaway-position crash after Echo Step. A Skirmisher dash could (rarely) leave the client's predicted position poisoned; the reconciliation then re-applied the bogus "unconfirmed displacement" every frame, oscillating the Y coordinate into the ±100,000s (visible server-side as a wall of "rejected impossible move" logs) until a tile-index computation went out of bounds and crashed the client. Three layers of hardening: reconciliation now discards any displacement beyond 4 tiles and snaps to the server position (self-heals in one snapshot), the predicted position is hard-clamped to map bounds every frame (with a NaN guard), and acked entries are pruned from the input log.
[v0.5.297] — 2026-07-07
Fixed
- In-dungeon quick-slot top-off, verified this time. The v0.5.283 merge required the two stacks' display names to match exactly — any naming drift between item sources silently degraded the top-off into a full swap. The merge/swap logic is now extracted into a unit-tested function (5 tests covering top-off, remainder, drained-source removal, full-slot swap, and empty-slot equip) that compares slot + food kind only, exactly like the hub merge.
[v0.5.296] — 2026-07-07
Fixed
- Hub depth sorting. NPCs always drew on top of players regardless of position — standing below (in front of) a vendor still put your character behind them. Players and NPCs now render in one pass sorted by foot position, so whoever stands lower on screen correctly draws in front.
[v0.5.295] — 2026-07-07
Fixed
- Vendor dialogue gaps and tiny text. Dialogue text authored with typographic characters (em-dashes, curly apostrophes) rendered as multi-space holes — the bitmap font has no glyphs above ASCII, so each byte of a multi-byte character drew as a blank. All NPC text is now ASCII-folded at load ('you've', '-' for em-dash, etc.). Dialogue body and prompt text also moved up from the Small font to MediumFull — noticeably more readable on the 3.5" screen.
[v0.5.294] — 2026-07-07
Fixed
- Single-tile gaps in the hub are now passable. The hub foot hitbox was exactly one tile wide (16px), which made fitting through a 16px gap mathematically impossible — the alignment window was zero pixels. The foot box is now 12×12, and a corner-slide assist nudges you toward a gap's opening when you push into it slightly misaligned, so doorways and alleys glide instead of dead-stopping.
[v0.5.293] — 2026-07-07
Changed
- Hub map update. Removed the Crowe, Aether Forge, and Vault Upgrade POI zones — those services are now handled by their vendor NPCs. Light source placement polish; rebaked ground/fringe layers.
[v0.5.292] — 2026-07-07
Fixed
- Hub light art is now grid-aligned. Light art was drawn centred on the marker tile (torch-glow semantics), straddling four tiles at a half-tile offset — it never lined up with the 2×2 blocks being authored. The marker tile is now the top-left of an exact 2×2 art block, in both the editor preview and the client (dungeon torches keep their centred behavior).
- Editor light previews honor rotation, and the current hub map's lights got
rot: 90— the flame art in this tileset is authored sideways (the dungeon uprights it the same way).
[v0.5.291] — 2026-07-07
Changed
- Map editor: the marker kind selector is now a dropdown. Click the kind box to expand the full list (each kind shown with its marker color), click to select; hover highlights, Up/Down navigates while open, Esc closes the list without cancelling the dialog. Arrow-key cycling still works for keyboard users. Editor-only change — no client/server deploy.
[v0.5.290] — 2026-07-07
Fixed
- Map editor marker dialog. Cancel (Esc and the button) never actually closed the dialog — the cancel signal was indistinguishable from "keep waiting". Fixed with a distinct sentinel. Also: placing a new marker while a 2×2 tileset region is selected now defaults the kind to "light" (the light-placement gesture), and otherwise defaults to the last-used kind instead of always "spawn" — so the ←/→ kind cycling is rarely needed.
[v0.5.289] — 2026-07-07
Added
- Per-light flame art selection in the map editor. Select any 2×2 region in the tileset panel, then place (or click-edit) a light marker — that region becomes the light's flame art (blue, red, yellow, anything). The editor previews the actual bound art on the canvas; unbound lights fall back to the default yellow torch flame. The client groups lights by art, pre-rotates each unique flame's flicker frames once at load, and renders every group through the same optimized torch path.
[v0.5.288] — 2026-07-07
Added
- Light sources in the map editor + hub. The map editor gained a "light" object kind (warm-yellow glow footprint on the canvas); the hub client loads them from hub.json and renders torch-style flicker overlays centred on each light tile. Rendering goes through the dungeon's optimized torch path (viewport culling, clipped loops, fixed-point integer blending from v0.5.275), and flicker frames only load when the map actually has lights.
[v0.5.287] — 2026-07-07
Fixed
- Dungeon Crucible scroll clamp. The dungeon crucible already clamped its cursor when the row list shrank (so it never had the town crucible's vanishing-cursor bug), but it didn't clamp scroll — shrinking the list while scrolled deep could leave the highlighted row parked above the visible window. Scroll now follows the cursor.
[v0.5.286] — 2026-07-07
Fixed
- Town Crucible cursor vanishing after withdrawing the last item. The row list shrinks on withdraw (and deposit / server refresh) but the cursor was never clamped, leaving it pointing past the end — invisible until the player pressed Up. Cursor and scroll now clamp on every list mutation.
[v0.5.285] — 2026-07-07
Fixed
- Crash moving the loadout cursor onto a quick-use slot. The bottom hint bar still indexed the 11-slot gear array with the new quick-slot cursor positions (11–13) — out-of-bounds panic. Last unguarded site; all cursor uses audited. The hint bar now also correctly shows A:UNEQUIP for quick slots mid-run.
- Mailbox showing empty on a slow read. Opening the mailbox used a 500ms network read that silently rendered an empty mailbox on timeout — indistinguishable from "your mail is gone". The timeout is now 1.5s, and a failed read shows "CONNECTION SLOW - CLOSE AND REOPEN" instead of an empty list. (Courier deliveries were verified safe in the database all along.)
[v0.5.284] — 2026-07-06
Changed
- Portal Courier wording: the headline now reads "CONSUMABLES TRAVEL IN QUICK SLOTS ONLY." — accurate (slotted consumables do enter) — with the blocked-item list introduced by "These bagged items can't come along:".
[v0.5.283] — 2026-07-06
Changed
- Courier fee is now 1 ingot per unique item type, capped at 5. Three stacks of chicken legs = 1 ingot; chicken + health potions = 2. Enforced identically in the quote and the charge.
- Party members hit the same courier gate. Members confirm queue entry at the portal, so pressing A with consumables in bag now opens the Portal Courier panel first — pay and the accept goes through, or back out and vault. Same rules for everyone; the free launch-time strip remains only as an anti-bypass backstop, and it now charges the fee best-effort too.
Fixed
- Slotting the same consumable type now tops off instead of swapping. Using a found stack of the type already equipped moves units into the quick slot up to its max (3), leaving the remainder in the bag — matching hub behavior. Different types still swap.
- Ghost stacks in the dungeon inventory. After slotting a consumable mid-run, both stacks appeared in the bag grid (alongside the quick-slot copy) until the screen was reopened. The bag view now correctly excludes quick-slotted items and prunes emptied stacks live.
- The Portal Courier screen no longer says "rift".
[v0.5.282] — 2026-07-06
Changed
- The Rift Porter is now the Portal Courier, and the delivery fee is 1 Crux Ingot per stack (regardless of stack size) instead of fragments.
- Party members no longer auto-decline the queue over bag consumables. Members accept from anywhere in the hub and never see the courier gate, so hard-cancelling the whole party over housekeeping was wrong. Their accept now always goes through; any consumables in their bag are mailed back free by the Portal Courier at launch.
[v0.5.281] — 2026-07-06
Changed
- Quick-use restructure. Sustain is now genuinely capped by your three quick-use slots:
- You can now equip potions and food to quick slots inside dungeons. Found consumables are slotted mid-run from the inventory (the "HUB ONLY" lock is gone). Slotting swaps: the incoming stack takes the slot, the old one returns to your bag.
- Consumables can't enter the rift. Approaching the portal with potions/food in your bag opens the Rift Porter screen instead of the mode menu: pay 1 Crux Fragment per stack to ship them to your mailbox (30-day hold), or cancel and use the vault for free. Enforced server-side at queue join, party accept, and launch. Everything else — gear, currencies, ingots, void stones, aether, cores — carries freely.
- Drinking/eating pulls only from equipped quick slots. Previously bag-carried health potions were all silently drinkable mid-run, making the hub-only rule cosmetic; that loophole is closed. Found potions must be slotted before use.
- Quick slots are now navigable in the Loadout tab — cursor over to the SP/HP/FD strip to inspect (Y) or unequip (A) them, in the hub or mid-run.
[v0.5.280] — 2026-07-06
Fixed
- The loading screen now covers the actual load. The slow part of entering a dungeon — reading tilesets/sprites from the SD card and baking the map, 1–3 seconds on device — happened before the loading screen ever rendered, leaving a frozen frame; the screen itself only covered the fast network handshake, which is why it flashed by. The "Baking dungeon..." phase now draws before the blocking work starts, so the screen is up for the whole real duration, with the progress bar advancing through all three phases (bake → party → world sync).
- First-minute choppy enemy movement (likely fix). The WiFi power-save disable in launch.sh only set the driver module parameter, which is read at association time — if WiFi was already connected when the game launched (always), it did nothing, leaving the 8188fu module batching packets into bursts until sustained traffic held the radio awake. That matches the intermittent "choppy for a minute, then normalizes" pattern. launch.sh now also runs
iwconfig wlan0 power off, which takes effect immediately on the live interface. Takes effect from the second launch after updating.
[v0.5.279] — 2026-07-06
Changed
- Stamina teal darkened to a true blue-green. The v0.5.276 teal leaned aqua/light-blue; it's now a proper dark teal in the Game Boy Color sense — RGB(15,150,140) — across the potion name text, icon, and HUD stamina ring.
[v0.5.278] — 2026-07-06
Changed
- The dungeon loading screen now waits for something real. It previously dismissed the moment the server said "go" (TCP DungeonStart) — before the world was actually streaming. It now holds through a second phase, "Syncing world...", until the first UDP snapshot lands, re-sending the lossy UDP registration every 300ms until it does. On a clean LAN this adds a single frame; on WAN or with packet loss it holds exactly as long as needed — and should fix the co-op bug where a player spawned into an empty world (no enemies/party) that blinked in late.
- The loading screen also shows real run data now: portal mode and time limit, the party roster with classes, per-phase status, and the extraction rule reminder.
[v0.5.277] — 2026-07-06
Changed
- Stamina identity is now fully teal. Following the potion text/icon change in v0.5.276, the HUD stamina ring (the B-slot gauge) is now teal as well, so everything stamina-related shares one color. The exhausted state stays red — that's a warning, not an identity.
[v0.5.276] — 2026-07-06
Changed
- Stamina potion color is now teal (was amber). In chest popups and loot lists the amber name/icon read almost identically to Legendary gold. Teal keeps full readability at small font sizes (a muddier yellow wouldn't), collides with no rarity or currency color, and pairs naturally with the health potion's red.
[v0.5.275] — 2026-07-06
Changed
- Big dungeon FPS improvements. Three render hot spots were fixed for the 30fps target:
- Torch glows now skip torches that are off screen (previously every torch in the map — often 50+ — ran its full per-pixel loop each frame) and blend with integer math instead of per-pixel floating point.
- Chat wheel no longer tanks FPS: the full-screen dim behind it (and behind the pause menu and other overlays) now darkens whole pixels with a single shift+mask instead of three integer divisions per pixel — roughly an order of magnitude cheaper.
- Sprite/tile blitting (the core routine behind every tile and sprite, 1000+ calls per frame) dropped two per-pixel costs from its inner loop: an integer divide replaced by error-accumulator stepping, and the sheet-bounds crash guard now checked once per blit instead of once per pixel — same safety, no per-pixel tax.
[v0.5.274] — 2026-07-06
Added
- Root now shows a visual cue. While snared, animated green vines curl up around the player's feet, gently swaying with periodic twitches — so it's immediately clear why you can't walk (and that you can still turn and fight). Purely visual, client-side.
[v0.5.273] — 2026-07-06
Fixed
- You can now turn while rooted. Root (the Verdant Drakon's vines and similar snares) was locking your facing as well as your movement, so it played like a partial stun. It now works like a proper root: your feet are stuck, but you can freely pivot to face — and attack — in any direction. Only Stun is a full input lock.
[v0.5.272] — 2026-07-06
Added
- Trogkin charge telegraph. The charge has a deliberate ~0.75s wind-up so it can be dodged, but nothing showed on screen — the enemy just froze, then rocketed across the room. It now rattles with an agitated side-to-side shake during the wind-up so you can see the charge coming.
- Boss add-summon burst. When a boss hits 70%/35% HP and summons a wave of neophyte adds, an eldritch-green ring now bursts at each spawn tile instead of the adds silently popping into existence.
- Boss enrage tell. When a boss drops below 50% HP (where it speeds up and attacks faster), it flashes a red burst and gains a pulsing red aura for the rest of the fight, so the difficulty spike reads clearly.
[v0.5.271] — 2026-07-05
Changed
- Disease now lasts 30 seconds (was 8s). The stamina-lockout debuff from Infernal enemies and the Primordial Drakon's roar is meant to be a real threat window, not a brief nuisance.
Added
- Fae blink now leaves an afterimage trail. Pixies and faeries teleport behind the player to strike; previously they simply popped in, which was hard to read. A short trail of fading purple ghost silhouettes now streaks from their old position to where they reappear, so the blink registers as motion. Purely visual, client-side — no protocol change.
[v0.5.270] — 2026-07-05
Changed
- Knockback now reads as a visible arc, and the Trogkin charge stun is 1.5s. Because the camera follows the player, a horizontal shove alone barely registered on screen. The player now does a short render-only vertical hop when knocked back (like enemies do), so it clearly reads as getting flung — without moving the camera. Displacement was increased (~0.9 → ~1.75 tiles) and the Trogkin charge stun raised from 0.5s to a full 1.5s.
[v0.5.269] — 2026-07-05
Fixed
- Knockback camera bounce. After the v0.5.268 glide, the client's displacement reconciliation kept running during the knockback and re-added "unconfirmed displacement" every frame — a feedback loop that oscillated the player position and bounced the camera several times. The client now hard-follows the server's gliding position for the whole stun and skips displacement reconciliation while stunned, so the shove is a single clean glide.
[v0.5.268] — 2026-07-05
Changed
- Knockback now glides instead of teleporting. Player knockback (Trogkin charge, PvP) used to snap the player to the landing spot in a single frame, causing a hard camera jerk. It now animates the displacement over the
0.5s arc window server-side (1px/tick), so the client follows a smooth path — a firm shove rather than a snap. Fixes the screenjerk on the Trogkin charge and smooths PvP knockback too.
[v0.5.267] — 2026-07-05
Fixed
- Trogkin charge no longer knocks the player into walls (and crashes the client). The knockback landing check only validated the sprite's top-left tile, not the player's actual foot hitbox — so a charge near a wall could embed the player's body in geometry, after which the client thrashed trying to reconcile and could crash. The landing now validates the full hitbox (also fixes the same latent issue for PvP knockback). Charge knockback strength was also reduced (~1.5 → ~0.9 tiles) so it's a firm shove, not a launch.
[v0.5.266] — 2026-07-05
Changed
- Auction listings now last 30 days (was 7), and the per-character listing cap is now 30 (was 10).
Fixed
- Auction house "select item to list" now scrolls. The item picker only ever drew the first ~18 items and never followed the cursor, so navigating past the visible rows sent the highlight off-screen. The list now scrolls to keep the cursor visible and shows a position indicator (e.g.
19/42) when it overflows. - Vendor NPCs can no longer trap the player. NPC collision is now one-way in effect: a vendor still blocks you from walking into it, but if one wanders onto you it no longer locks you in place — you can always walk free. Their collision box was also shrunk so they feel less bulky to move around.
- Test chamber no longer disconnects after ~5s of idle. The join-wait read timeout wasn't cleared before the connection was handed to the dungeon's background reader, so an idle test chamber (which sends almost no TCP) hit the timeout and booted the player to the main menu. The timeout is now cleared on entry.
[v0.5.265] — 2026-07-05
Added
- Primordial Drakon's ancient roar. The last missing boss ability: every ~9s (halved while enraged) the Drakon unleashes a screen-wide pulse that curses and diseases every player near it. It's telegraphed by a purple screen flash and an expanding shockwave ring from the boss. All three full bosses now have complete ability kits.
[v0.5.264] — 2026-07-05
Added
- Infernal Dragon and Sylvan Dragon now have ability kits. Previously they were plain melee with big HP. Each now cycles through three zone abilities (one every ~2.5s, halved while enraged below 50% HP):
- Sylvan Dragon (119): vine breath and thorn slam (root zones on the dragon) + spore cloud (a lingering poison zone dropped on a player).
- Infernal Dragon (118): fire breath and ember burst (burn zones on the dragon) + magma slam (a persistent magma pool dropped on a player).
[v0.5.263] — 2026-07-05
Added
- Bosses now summon adds and enter a rage phase. The three full bosses (Primordial Drakon, Infernal Dragon, Sylvan Dragon) previously did nothing special beyond big HP. Now:
- At 70% and 35% HP each boss summons a wave of its neophyte drake adds near itself (Primordial Drakon → Gale/Notcurne/Ashen; Infernal Dragon → Spark/Cinder; Sylvan Dragon → Cypher/Briar). Adds are placed on open tiles around the boss.
- Below 50% HP the boss enrages — it attacks twice as often and moves noticeably faster.
[v0.5.262] — 2026-07-05
Added
- Beholder eye ray now has a visual and is dodgeable. Previously the eye ray stunned you from off-screen with no indication. It now has a ~0.4s wind-up telegraph — a gold ring that converges on the charging beholder — and breaking line of sight before it completes cancels the ray entirely (and puts it on cooldown). When it fires, a gold beam flashes from the beholder to the impact point.
Changed
- Trogkin charge now bowls you over. A landed charge displaces the player ~1.5 tiles from the impact and applies a brief 0.5s stumble stun, instead of the previous 1.5s stationary lock — it reads as an impact rather than a generic stun.
[v0.5.261] — 2026-07-05
Fixed
- Enemy crowd-control effects now actually work. Stun, Knockback, Root, Slow, and Disease were being rolled and applied server-side but never enforced — they were purely cosmetic. This silently disabled the signature ability of several enemies (Beholder eye-ray, Scorpion sting, Gloomwidow web, Overgrown root-casters, Siren, Trogkin charge landing):
- Stun / Knockback now route through the same full-lock channel as PvP stuns — the player can't move or attack for the duration, with the gold stun timer on the HUD.
- Root now locks player movement (attacks still work).
- Slow now halves player movement speed while active.
- Disease now blocks stamina regen for its duration; using a stamina potion cures it (its intended counterplay).
[v0.5.260] — 2026-07-05
Fixed
- Dungeon crucible no longer causes disconnects. Depositing into a dungeon crucible could trigger a "reconnecting" drop that then recurred repeatedly in that run. Root cause: the dungeon's message loop raced a non-cancel-safe
read_exactagainst the outgoing-event channel in aselect!. Once a crucible starts smelting the server pushes updates at 30 Hz, which constantly cancelled the read mid-frame and lost bytes, desyncing the stream and tearing down the connection — and since rejoining resumed the still-smelting crucible, it happened again immediately. Replaced the reader with a cancel-safeFramedReaderthat keeps its buffer across cancellation (also applied to the lobby and test-chamber loops, which had the same latent bug).
Changed
- Reconnect screen shows the frozen dungeon instead of a black screen. While reconnecting, the last rendered frame is held and dimmed under the "RECONNECTING" text, so a brief drop reads as a pause rather than a crash.
[v0.5.259] — 2026-07-02
Security
- UDP input is now authenticated. Each run mints a per-player secret token, delivered in
Connected/TestChamberJoinedand echoed in everyPlayerInput; the server drops packets whose token doesn't match. Previously anyone could send input for a guessable sequentialplayer_idand drive another player's character, fire their abilities, or redirect their snapshot stream to themselves. - Server-side movement validation (anti-teleport). The server now rejects client positions that jump farther than sprint speed allows (with generous tolerance for latency), so teleport-to-extract and loot-vacuum-from-spawn no longer work. Server-driven dashes/knockback re-bootstrap the check so legit fast movement is never flagged.
- Trade sessions verify participants.
AddTradeItem,RemoveTradeItem,LockTrade,CancelTrade, andDeclineTradenow reject any sender who isn't a party to the trade — previously a third party who guessed a trade id could pull items out of a stranger's open trade into their own bag, or force it to execute. - Rejoin verifies ownership.
RejoinDungeonnow confirms the reconnecting account actually owns the character before handing over control — previously any authenticated account could hijack any disconnected player during their 30s reconnect window. - Extraction acts only on your own character.
RequestExtractionignored a client-suppliedplayer_id, letting a client force-extract a teammate/enemy off the portal (and desyncing UDP routing). It now operates only on the connection's own player. - Proximity checks on world interaction. Loot pickup, chest opening, and barrel-smashing now require the player to actually be near the target tile; item drops land at the player's real server position instead of a client-chosen tile. Blocks remote loot-vacuum, remote chest opening, and dropping items into walls / across the map.
- Legacy
Connectpath removed. The old unauthenticated Connect → SelectClass flow (no login, no version check) that let anyone drop straight into a dungeon has been deleted.
Note: this release changes the client↔server wire protocol. Client and server must be on 0.5.259+ together; the auto-updater and version gate keep them in lockstep.
[v0.5.258] — 2026-07-02
Fixed
- Client can no longer OOM-crash on a network stall — the client's framed-message reader had no length cap, so if a read timeout ever desynced the TCP stream mid-message, the next 4 bytes (garbage) could request an allocation of up to 4 GiB and instantly kill the game on the 128 MB handheld. Capped at 8 MB (far above any legitimate message, including a full dungeon map).
- Dungeon loading screen no longer softlocks the handheld — if the server dropped or hung right after lobby start, the client sat on "ENTERING DUNGEON" forever with dead input. It now disconnects cleanly if the connection is lost during load, and gives up with an error after 45s if the dungeon never starts.
- Reconnect and test-chamber entry no longer freeze on an unresponsive server — the post-death hub reconnect and the debug test-chamber both did blocking reads with no timeout, so a server that accepted the connection but never replied froze the render thread indefinitely. Both now use bounded reads (10s / 5s) and fall through to a clean disconnect.
- Auto-updater verifies downloads before installing — downloaded files were renamed into place without checking integrity, and an HTTP/1.0 connection dropping mid-body reads as success, so a truncated binary could be atomically installed over the working one (device won't launch until manual redeploy). Each file is now verified against the manifest size + SHA256 before being placed.
[v0.5.257] — 2026-07-02
Fixed
- Death no longer duplicates carried items — the death handler was dropping both the live run-bag and the stale launch-time DB bag snapshot as ground loot, so every item carried into a run dropped twice (item/currency duplication, exploitable in co-op). It now drops the run-bag + equipped gear only; the DB bag rows are still cleared but never double-dropped.
SetQuickSlotcan no longer crash the server — an out-of-rangeslot_index(≥ 3) panicked while holding the DB mutex, poisoning it and bricking the whole server for all players. Out-of-range indices are now rejected before any DB work (which also prevented a silent bag-item loss on the bad path).- Hub overlay double-press crash — the portal-select, town-crucible, friend-request, view-loadout, and player-card overlays could panic if two key presses landed in the same frame while the overlay was closing (unwrap on a just-cleared state). All five now stop processing events the moment the overlay closes.
- Bosses and mini-bosses now have real HP — special enemies spawned with a hardcoded 40 HP in live dungeons (dying to ~2 hits), while the test chamber gave them 400/1200. Real spawns now use the same tier-based HP (mini-boss 400, boss 1200). This likely explains "boss missing" reports in Empowered — it spawned and was instantly killed.
- Sprite rendering hardened against bad source rects — all
blit_spritevariants now clip out-of-bounds source pixels instead of panicking, and enemy facing rows from snapshots are clamped to the 4 valid directions. Removes a likely mid-combat client crash from any sprite sheet whose real dimensions differ from the caller's assumption. - Test suite + fresh-DB startup restored — unit tests no longer failed to compile (missing
sigils/bag_capacityin test constructors), and a fresh server database no longer panics on boot from the M012 mailbox migration colliding with the base schema.
[v0.5.256] — 2026-07-02
Changed
- Arcanist auto-target — attacking with no target selected now automatically snaps to the nearest alive enemy. Target persists for follow-up attacks; L1 still overrides manually at any time. Applies to all offensive inputs (light attack, heavy, ability, special moves).
[v0.5.255] — 2026-07-02
Changed
- NPC sprite size — NPCs now render at 28×38 px (non-square) to better match player visual height while compensating for the 16×16 source frames being from a different art style than the 32×32 player sprites. Placeholder until NPC sheets are replaced.
[v0.5.254] — 2026-07-02
Changed
- NPC sprite scale — NPCs now render at 64×64 screen pixels (matching player sprite size), up from 32×32. Sprites are horizontally centred on their tile and feet-anchored to the tile bottom.
[v0.5.253] — 2026-07-02
Changed
- NPC wander tuning — walk speed reduced to 1.2 tiles/sec (48% of player speed) for a casual amble feel. Per-step travel capped at 3 tiles so NPCs meander locally rather than crossing their whole zone. Idle time between steps is now a global constant (5–10s) instead of a per-NPC JSON field;
step_interval_msremoved fromhub_npcs.json.
Added
- NPC collision — players can no longer walk through NPCs; each NPC blocks their current tile.
- NPC nametags — names float above sprites in yellow with a drop shadow, matching the player nametag style.
[v0.5.252] — 2026-07-02
Added
- NPC nametags — NPC names now float above their sprites in yellow (distinct from player nametags which are blue-white), with a drop shadow, culled to the viewport.
[v0.5.251] — 2026-07-02
Added
- Hub NPCs — four characters now populate Blackthorn Hollow: Grim (tavern keeper), Bargus Crowe (trader), Mira (vault keeper), Veyra (Aether Forge). Each wanders a defined zone, animates from their sprite sheet, and can be talked to with A. Dialogue shows a bottom-panel overlay with portrait, opener text, three prompt choices, and responses. Vendor NPCs open their respective hub overlays via the dialogue action system.
- hub_npcs.json — data-driven NPC definitions: spawn point, wander zone, step interval, proximity trigger distance, dialogue tree (opener / prompts / closer), and optional vendor id.
- Portrait assets — 23 NPC portrait PNGs cut from townfolk sprite sheets, stored in
assets/portraits/. - NPC editor tool (
tools/npc_editor.py) — visual editor for placing spawn dots and wander zones on the hub map, editing names/sprites/step intervals, and authoring dialogue trees entirely within the pygame window (no terminal prompts). - Portrait cutter tool (
tools/portrait_cutter.py) — pygame tool for cropping 16×16 face portraits from 48×64 townfolk sprite sheets and saving them toassets/portraits/.
[v0.5.250] — 2026-07-01
Fixed
- Crucible always spawns — clearance check now uses a 3→1→0 tile fallback so crucibles always place when the mode requires them (Empowered = 100%, Stable = 30–40%). Fallback cases are logged. Most maps will still get full 3-tile clearance from canals/walls.
[v0.5.249] — 2026-07-01
Fixed
- Crucible canal clearance — dungeon crucibles now require 3 tiles of clear floor on all sides before placement. Canals and walls are
Tile::Wallin the grid, so this also prevents crucibles from spawning partially overlapping or adjacent to water.
[v0.5.248] — 2026-07-01
Fixed
- Bake blit performance —
blit_spritefor the full-viewport bake blit iterated 482×641 = ~309k destination pixels with per-pixel alpha checks and integer division. Replaced withblit_bake_2x, a specialized 2× opaque blit that iterates 241×321 = ~77k source pixels, skips alpha (bake is fully opaque), and writes each pixel to both adjacent dst positions without division. Eliminates the main cause of FPS regression introduced by baking.
[v0.5.247] — 2026-07-01
Fixed
- Bake: canal bank tiles missing —
bank_uvoverlays (shore sprites around water) were not baked because they are Ground-layer tiles and the Ground pass only drewbank_uvfor Mask/Fringe layers. Now drawn correctly. - Bake: platform face tiles missing — platform face/cap sprites (
plat_mask/plat_fringeUVs in the Ground layer) were not drawn; the bake Ground pass only drewplat_ground. Now iterates[plat_mask, plat_fringe]in the Ground pass to matchdraw_map_layerbehavior. - Dungeon entry inventory missing —
ItemPickedUp,QuickSlotsContents,EquippedContents, andLootDroppedmessages sent by the server beforeDungeonStartwere silently dropped by the loading gate. They are now handled during the bake-loading drain so the player enters with their correct loadout.
[v0.5.246] — 2026-07-01
Fixed
- Bake viewport dimensions — baked map was only rendering the top-left quarter of the 640×480 screen; padding constants and blit dimensions were all half the correct size.
[v0.5.245] — 2026-07-01
Added
- Map bake + readiness handshake — dungeon tile layers (Ground/Mask/Fringe) are now pre-rendered into a single pixel buffer immediately after connecting. Each frame blits the viewport at 2× instead of iterating every visible tile three times. Animated tiles (torches, canals) are redrawn individually each frame on top. Server holds AI/combat until all players in the run confirm ready (or a 30-second timeout fires), so no one enters the dungeon while their client is still loading. A loading bar ("N/M players ready") is shown during the wait. Solo runs see no perceptible delay.
[v0.5.244] — 2026-07-01
Fixed
- PvP team spawns separated — in PvPvE runs, team 2 now spawns in the room furthest from team 1's spawn (excluding the portal room). Previously all players spawned at the same tile.
[v0.5.243] — 2026-06-30
Fixed
- Dungeon reconnect write-timeout bug — after reconnecting to a dungeon run, the 3-second write timeout set during the handshake was never cleared, meaning any brief client→server TCP stall after reconnect would fail writes prematurely and trigger another disconnect. Now cleared immediately on reconnect success.
- Server-side TCP write error logging —
write_messagenow logs the OS error on write failure so future disconnect causes are identifiable in the server console. - Crucible deposit disconnect log — server now logs explicitly when the TCP write in the deposit response path fails, pinpointing which specific write caused the TCP drop.
[v0.5.242] — 2026-06-30
Added
- Townfolk sprites — 23 NPC sprites processed into
assets/townfolk/npc_01.png–npc_23.png(48×64, 3 frames × 4 directions: left-step, idle, right-step). Includes blacksmith, merchants, villagers, and hero variants. - Spawn zone chests visible —
hub.jsonnow includes spawn zone data; chests render correctly on the hub map (closed for your zone on fresh respawn, open otherwise).
[v0.5.241] — 2026-06-30
Changed
- Dungeon crucible layout — progress bar now flows directly under the item description in the right panel (matching the town crucible layout). Dungeon timer moved from the cramped header row to the bottom-left of the screen, below the item list.
[v0.5.240] — 2026-06-30
Changed
- Auction House currency — Aether can no longer be used as a listing price. Only Crux Ingots are accepted. Existing Aether-priced listings remain visible and purchasable until they expire; no new Aether listings can be created.
[v0.5.239] — 2026-06-29
Fixed
- Co-op dungeon blank startup — non-host player's client now sends a UDP registration packet from inside
DungeonState::new(), immediately after opening the socket, instead of waiting for the firsttick_dungeoncall. Asset loading (1–2s on SD card) happens beforenew(), giving the server time to respond; by the first rendered frame the snapshot is already waiting in the socket buffer. Previously, non-host players saw a blank dungeon (no enemies, no party member, no HUD) for one or more frames until the UDP address was registered.
[v0.5.238] — 2026-06-29
Fixed
- Echo Step wall clipping — reconciliation now suppresses displacement re-application on the snapshot frame when echo step transitions from active to finished. Previously,
disp_x = d.player.x - rec_xdouble-counted the tail of the dash (rec_x was logged against a mid-dash hard-synced position while d.player.x held the post-dash position), overshootingown.xand visually placing the player inside or past walls. Aprev_echo_steppingflag now triggers an extra hard-sync on that transition frame and skips reconciliation, matching the existing void-shift pattern.
[v0.5.237] — 2026-06-29
Changed
- Server-authoritative hub position — hub position is now owned by the server. The client no longer stores
hub_x/hub_yinconfig.toml. On hub join, the server sends aHubPosition(returning players) orSpawnZoneAssigned(new/post-death) message; the client does a brief blocking handshake inHubState::new()and waits for that message before rendering. Position is saved to the DB (hub_x/hub_ycolumns) when the player leaves the hub.
[v0.5.236] — 2026-06-29
Fixed
- Hub spawn zones — spawn zone assignment is now conditional. New characters and players who died on their last run are placed in a spawn zone (with starter chest). Players logging in normally or returning from a successful extraction spawn at their last known hub position. Driven by a
needs_hub_respawnDB flag: set on character creation (default 1) and on death, cleared on hub join. - Spawn chest sprite — hub spawn chests now use the same chest sprite sheet as dungeon chests instead of the placeholder colored rectangle.
[v0.5.235] — 2026-06-28
Added
- Auction house class info — item detail panel now shows class restriction ("Warrior Only", "Skirmisher / Arcanist", etc.) in the right column after affixes. Green if your current character can equip it, red if not.
Changed
- Auction listing truncation — long item names in the browse list now end with "..." instead of being hard-cut mid-word.
- Auction detail word wrap — long item names in the detail panel wrap to a second line instead of overflowing.
[v0.5.234] — 2026-06-28
Fixed
- Lobby disconnect detection — if the server closes the TCP connection while the client is showing "LAUNCHING...", the lobby now returns to main menu instead of looping forever.
[v0.5.233] — 2026-06-26
Changed
- Test chamber — map resized from 50×34 to 25×19 (roughly 25% larger than the visible screen area). Containment area and yellow border removed; enemies now spawn randomly across the full interior. Player spawns at the true center tile (12, 9).
- Queue timings — quiet-server countdown reduced from 20s → 10s; active-server countdown from 60s → 45s.
- Crucible timer position — progress bar/timer in the dungeon crucible now anchored to the bottom-right of the info panel instead of floating below the item description.
Fixed
- Lobby countdown — timer now ticks down locally between server updates instead of freezing at the value sent when the last player joined.
[v0.5.232] — 2026-06-26
Fixed
- Spawn zone bake — map editor bake (Ctrl+B) now forwards
spawn_zonesinto the outputhub.json; zones authored in S-mode are now correctly active at runtime.
[v0.5.231] — 2026-06-26
Added
- Spawn zone system — map editor gains S-mode (press S) for authoring rectangular spawn zones with draggable handles: a gold chest marker and a green player-spawn marker. Zones can border but not overlap; right-click deletes. Saved to
hub.jsonasspawn_zones. - Hub spawn zone mechanics — players assigned to a zone on hub entry (least-occupied first); invisible to other players in the same zone until either leaves. Walking out marks the zone as exited for that session.
- Starter chest — each spawn zone has a personal chest. First interaction (A near chest) grants 2 starter items (weapon + armor/shield, Common–Uncommon rarity; Warrior/Skirmisher get Sword or Spear, Arcanist gets Staff). Chest locks permanently once you leave the zone or loot it — re-entry allowed but no re-loot.
- Chest rendering — closed (gold-banded) and open (grey lid) chest sprites drawn at zone chest tiles. Proximity hint "A: OPEN CHEST" shown when adjacent.
[v0.5.230] — 2026-06-25
Added
- Umbral group life steal — "Hellspawn" group renamed to "Umbral". Succubus, Incubus, Shadowveil, Bloodthorn, Dracul now have 25% life steal on melee hit (same as Fae), applies Drained debuff.
- Golem life steal — Earth Golem (30), Stone Golem (78), Magma Golem (79) now have guaranteed 100% life steal on every melee hit. Heals 30% of damage dealt.
- Magma Golem scorching touch — Magma Golem (79) also applies Burn on every melee hit.
- Scorchfang Drake scorching bite — Scorchfang Drake (114) applies guaranteed Burn on every melee hit (4 Arcane dmg/0.5s for 3s).
- Siren slow song — Siren (21) periodically places a WebZone slow field while chasing (4s duration, 3s CD, 5-tile range).
- Verdant Drake vine breath — Verdant Drake (111) places a VineZone (Root) when a player is within 4 tiles (3s duration, 5s CD).
- Thornback Drake thorn burst — Thornback Drake (112) places a close-range fire zone when a player is within 2 tiles (Burn, 2s duration, 3s CD).
- Embercrest Drake fire breath — Embercrest Drake (113) places a FireBreath zone (Burn) when a player is within 4 tiles (3s duration, 6s CD).
- New ground zone kinds —
VineZone(Root, dark green) andFireBreath(Burn, bright orange) added to the zone system. - Boss 117 renamed — "Ancient Wyrm" is now "Primordial Drakon".
- NPC Reference page updated —
/npcsnow reflects all new abilities, Umbral rename, and Primordial Drakon.
[v0.5.229] — 2026-06-25
Added
- NPC Reference page at
/npcs— every enemy grouped by type with HP, defense, ward, melee stats, on-hit effects, ability names, damage types, cooldowns, and ranges. Sourced live from server code.
Fixed
- No loot drops in the test chamber. Enemies killed in the test chamber no longer drop gear or Crux Fragments.
[v0.5.228] — 2026-06-25
Changed
- Test chamber map is now 50×34 tiles — all-floor interior with only border walls. Previously had internal arena walls and a narrow south corridor.
- Test chamber containment boundary is now drawn as a 1px yellow border on-screen around the patrol region (cols 5–44, rows 4–29). No physical walls; NPCs are clamped client-side.
Fixed
- Bosses and mini-bosses no longer spawn chests when killed in the test chamber.
- Test chamber has no dungeon timer and no collapse. Previously Unstable mode would collapse the dungeon after ~6 minutes; the chamber now runs indefinitely.
[v0.5.224] — 2026-06-25
Added
- PvE open queue — adaptive launch timer: replacing the manual A:START host mechanic, the queue now runs a countdown before launching the dungeon. Base timer is 20–60s, graduated by recent queue activity in the last 5 minutes. Each new player who joins extends the timer by 10s (capped at 90s total from first join). When the room hits 3 players the timer collapses to 5s.
- PvE queue max 3 players: fourth player attempting to join a full open PvE queue is rejected with "DUNGEON IS FULL (3/3)" and returned to the hub.
- Lobby countdown display: open PvE lobby now shows "LAUNCHING IN Xs B:LEAVE" instead of "A:START".
Fixed
- Co-op queue race condition: the old system allowed the host to start with a single button press before other players joined, causing co-op partners to be left in the lobby. The timer-driven system eliminates this by giving all players a guaranteed window to join before the dungeon starts.
[v0.5.223] — 2026-06-25
Changed
- Merged
enemy-combat-abilitiesbranch to main.
[v0.5.222] — 2026-06-25
Changed
- Hub map — zone boundaries configured for all POIs; POI labels and editor anchor dots removed (zones now authoritative for proximity detection).
- Map editor — Zone mode (
Z): POI list panel + drag-to-draw zones on canvas, saved to hub.json. Fixed Ctrl+S corrupting hub.json after bake.
[v0.5.221] — 2026-06-25
Changed
- Hub map — Crucible and Aether Forge mapped out.
[v0.5.220] — 2026-06-25
Added
- Map editor tile stacking —
Alt+LMBappends a tile to the mask or fringe cell stack instead of replacing; supports multiple overlapping tiles per cell for complex scenery. - Tileset config → live map update —
Ctrl+Enow relocates existing painted cells to the new layer when a tile's ground/mask/fringe assignment is changed. Stacked cells are handled per-tile.
Changed
- Hub POI labels — Crucible and Aether Forge labels removed (identifiable from map tiles); portal label was already removed.
[v0.5.219] — 2026-06-25
Fixed
- Hub portal performance — radial edge-fade now uses a precomputed LUT (zero float math per frame) instead of per-pixel sqrt/powf; eliminates the ~10 FPS drop near the portal.
Changed
- Hub portal fade — edge fade tightened to outer 18% only; center stays at dungeon portal opacity, edges fade toward transparent.
[v0.5.218] — 2026-06-25
Changed
- Hub portal — doubled to 256px (2× dungeon size), radial transparency fade on edges, portal label removed (animation is self-evident).
[v0.5.217] — 2026-06-25
Changed
- Hub portal size + position — enlarged to 50% larger than dungeon portal (128→192px / 6 tiles), recentered to correct position.
[v0.5.216] — 2026-06-25
Changed
- Hub portal position + size — portal shifted one tile right and enlarged 25% (128→160px) to better fill the portal zone.
[v0.5.215] — 2026-06-25
Added
- Hub portal animation — the animated dungeon portal now renders in the hub map at the Portal POI location, centered on the tile marker (same sprite and animation as in-dungeon portals).
[v0.5.214] — 2026-06-24
Added
- Map editor bake (
Ctrl+B) — renders ground + mask layers tohub_ground.png, packs unique fringe tiles into a compacthub_fringe.png, and writes a portablehub.jsonwith relative paths. POI zones are auto-merged from a siblinghub.jsonwhen current objects lack zone data. - Hub baked-ground rendering — client loads
hub_ground.pngwhen present and blits it per-tile in passes 1+2, replacing per-tileset tile lookups. Falls back to existing tile-by-tile renderer when no baked image exists. - Map editor Save As (
Ctrl+Shift+S) — always prompts for a destination path rather than silently overwriting the loaded file. - Hub map round-trip — loading a hub-format JSON in the map editor now preserves all object fields (
zone,tile_color, etc.) soCtrl+Swrites back a valid hub.json without data loss.
Fixed
- WiFi power management —
launch.shnow disables WiFi power save (rtw_power_mgnt=0) on launch, covering all known module name variants (8188fu,rtl8188fu,8188eu). Reduces per-packet jitter from ~10ms mdev to ~1ms mdev on LAN. - Auto-updater changelog — root
CHANGELOG.mdwas missing entries v0.5.201–v0.5.213 that had accumulated only in the website copy; all entries restored sochangelog.rssgenerated byrelease_do.shreflects the full history.
[v0.5.213] — 2026-06-24
Fixed
- Enemy staircase movement — A* pathfinding re-enabled for 8-directional movement (diagonals cost 3 ≈ √2 × 2; cardinals cost 2). The original diagonal implementation was removed in v0.3.0 due to corner clipping, but the root fix — requiring both orthogonal neighbours to be walkable before allowing a diagonal step — was not in place at the time. No-corner-cutting guard now enforced; heuristic updated from Chebyshev to octile distance (exact lower bound for this cost scheme). Mini-boss and boss staircase movement eliminated.
[v0.5.212] — 2026-06-24
Fixed
- Zone debuffs apply immediately on entry —
tick_ground_zonespreviously applied effects only at a 1-second interval (tick % 30 == 0), leaving a gap of up to 1 full second before Slow/Poison/Burn/PortalBlock activated after stepping into a zone. Now checks overlap every tick and applies the effect as soon as a player enters, then refreshes only when the remaining duration drops below the interval threshold. DoT tick timers and TCP message frequency are unchanged. - Zone visual infinite horizontal stripe —
fill_rect_blendcast(x + w)asusizebefore clamping, causing negative values to wrap to a huge number and.min(self.w)to return the full screen width. Every row of a zone tile positioned far off-screen painted the full screen width as a horizontal stripe. Fixed to clamp ini32before casting tousize.
[v0.5.211] — 2026-06-24
Fixed
- Initial ability cooldown burst — all enemies now spawn with randomized
ability_cooldownandability2_cooldown(0–90 and 0–60 ticks respectively, derived from each enemy's per-instance RNG seed). Previously every caster, aura, and zone enemy had cooldown 0 at dungeon start, causing a simultaneous first-tick burst of projectile spawns, TCP messages, and LOS checks that made NPCs appear choppy for the first ~2 minutes of a run.
[v0.5.210] — 2026-06-23
Added
- Floating heal numbers on enemies —
EnemyHealedTCP message now spawns a green "+N" floating number above the healed enemy's position (Wyld Knight ally heals, life steal). Uses the sameDamageNumbersystem as player damage floaters.
[v0.5.209] — 2026-06-23
Added
- Ground zone rendering — client stores active zones from
ZoneCreated/ZoneExpiredTCP messages and renders each zone as a tile-by-tile blended overlay (efficient on ARM — only tiles within the zone radius are painted). Visuals by kind: WebZone (grey tint + crosshair accent), SporeCloud (green tint + three spore dots), MagmaPool (orange-red tint + small flame shape), VoidField (dark purple tint + concentric ring accent). Zones are drawn above the floor layer and below loot/entities.
[v0.5.208] — 2026-06-23
Added
- Enemy projectile rendering — in-flight enemy projectiles are drawn each frame from
WorldSnapshot.enemy_projectiles, layered above loot and below entities. Visual by kind: Fireball (layered orange glow + bright core), NecroticBolt (dark purple aura + solid core), MagicBolt (cyan with bright center), VineShot (dark green oval + circle), WebShot (grey circle with crosshair lines), VoidBolt (layered black/deep-purple with bright magenta core).
[v0.5.207] — 2026-06-23
Added
- Debuff icon HUD strip — client now receives
EffectApplied/EffectClearedTCP messages and renders enemy status effects as pixel-art icons with countdown timers and proportional duration bars. Eight effects shown: Disease (sickly green circles), Poison (green drip), Burn (orange flame), Curse (purple skull), Drained (dark red arrow), Root (brown vines), Slow (icy blue footprints), PortalBlock (red cancel circle). Stun uses the existingstun_ticksslot; Knockback (0.5s) is omitted. - Portal-block enforcement — when
PortalBlockis active the portal highlight and extraction ring are suppressed entirely; player cannot extract while the debuff is running.
[v0.5.206] — 2026-06-23
Added
- Ground zone system —
tick_ground_zones()runs every server tick: zones decrement their duration, apply effects to overlapping players once per second (Slow in WebZone, Poison in SporeCloud, Burn in MagmaPool, PortalBlock + 2 Arcane dmg/s in VoidField), and broadcastZoneExpiredTCP on removal. - VoidBolt → VoidField — Primordial Drakon's VoidBolt now spawns a 10s VoidField ground zone on wall or player impact.
- Mossmane Drake SporeCloud (kind 115): exhales a 8s SporeCloud zone at its feet when a player is within 5 tiles; 6s cooldown.
- Magmascale Drake MagmaPool (kind 116): breathes a 6.7s MagmaPool zone at its feet when a player is within 5 tiles; 5s cooldown.
ZoneCreated/ZoneExpiredTCP messages — added toServerMessage; clients receive reliable zone lifecycle events for rendering (Step 14).
[v0.5.205] — 2026-06-23
Added
- Enemy projectile system —
tick_enemy_projectiles()runs every server tick: projectiles move at 3.5 px/tick, expire on wall collision or 4s lifetime, deal damage + on-hit effects on player collision. On-hit behaviors by kind: Fireball (10 Arcane + Burn), NecroticBolt (8 Arcane + Curse), MagicBolt (6 Arcane), VineShot (4 Physical + Root), WebShot (spawns WebZone ground zone), VoidBolt (12 Arcane). - Ranged caster AI spawning — six enemy types now fire projectiles when chasing a player in range: Ratkin Scorcher (kind 61, Fireball, 4s CD), Skeleton Mage (kind 35, NecroticBolt, 3s CD), Moon Fae (kind 91, MagicBolt, 2.5s CD), Thornstalker/Bramblesprout/Mandrake (kinds 43/44/38, VineShot, 3s CD), Gloomwidow (kind 29, WebShot, 5s CD), Primordial Drakon (kind 117, VoidBolt, 4s CD).
- Enemy projectile state in WorldSnapshot —
enemy_projectilesfield is now populated each UDP tick so clients receive in-flight projectile positions/velocities for rendering (Step 13).
[v0.5.204] — 2026-06-23
Added
- AI ability system — five enemy-specific active behaviors implemented server-side:
- Dustwight curse aura (kind 75): pulses Curse to all players within 4 tiles every second; cooldown resets on pulse.
- Trogkin charge (kinds 25/55/82/90/65): spots target within 8 tiles → 22-tick wind-up → 0.5s charge at 6 px/tick; hits player (knockback) or wall (stop); 15s cooldown.
- Beholder eye ray (kinds 13/17/50/63/86): line-of-sight check within 8 tiles → instant Stun on target; 3s cooldown.
- Wyld Knight heal (kind 74): heals Fae allies at ≤40% HP within 5 tiles for 20% max HP; 10s cooldown.
- Pixie / Faery offensive blink (kinds 37/49): teleport behind player within 8 tiles → immediate melee hit; 6s cooldown.
[v0.5.203] — 2026-06-23
Added
- On-hit status effect application — enemy melee attacks now roll group-based effects: Diseased (Disease 20%), Insectoid/Overgrown (Poison 25%), Undead (Curse 20%), Fae/Umbral (Life Steal 25%), Void Serpents (PortalBlock guaranteed). Scorpion tail sting adds Stun 30%. Life steal heals enemy + sends
EnemyHealedTCP; all effects sendEffectAppliedTCP. push_player_effecthelper — single entry point to add any status effect to a player with refresh-on-reapply behavior.- enemy_index.json renames — group "hellspawn" → "umbral"; kind 117 "Ancient Wyrm" → "Primordial Drakon".
[v0.5.202] — 2026-06-23
Added
- Status effect tick system —
tick_player_effects()runs every server frame: Poison ticks every 1s (Physical, 3 dmg), Burn ticks every 0.5s (Arcane, 4 dmg); all effects count down their duration and are removed with anEffectClearedTCP message when they expire. DoT deaths set kill_reason and sendPlayerDied.
[v0.5.201] — 2026-06-23
Added
- Enemy armor mitigation — all enemy damage paths now route through
apply_enemy_damage(dtype): Physical hits subtractdefense_flat, Arcane hits subtractward_flat, minimum 1 damage guaranteed. - Curse debuff framework —
active_effects: Vec<ActiveEffect>added toPlayerEntry;curse_factor()applies -25% outgoing damage to all player attack paths when Curse is active (light, heavy, bolts, spin, kick, chains).
[v0.5.200] — 2026-06-23
Fixed
- Social menu default tab — priority is now Party → Requests → Friends. Pending request count is tracked independently of the toast timer, so the Requests tab auto-selects correctly even if the player opens the menu long after the login notification expired.
[v0.5.199] — 2026-06-23
Fixed
- Asset filename — renamed
Spike Trap.png→Spike_Trap.pngto fix auto-updater failure caused by space in filename.
[v0.5.198] — 2026-06-23
Changed
- Heavy attack cooldowns — now class-specific: Warrior 3s (unchanged), Skirmisher 6s (was 3s), Arcanist 10s (was 3s).
- Warrior momentum cooldown — Shield Charge bumped from 10s to 15s to match Echo Step and Void Shift.
- Skirmisher combo scaling — removed
combo_multfrom light attack damage; combo stacking is now Warrior-only. Combo step tracking removed from Skirmisher path entirely.
[v0.5.197] — 2026-06-22
Fixed
- PvP search countdown accuracy — server now sends the correct initial timeout (45s if alone, 120s if opponents already searching) when entering the PvP pool, and pushes
PvpSearchUpdateto all pool members whenever pool composition changes (someone joins or leaves). The client resets its countdown on each update, so the displayed timer always matches what the server will actually fire — no more "countdown ends partway" when opponents drop out.
[v0.5.196] — 2026-06-18
Changed
- Auction House listing fee — reduced from 20 to 5 Crux Ingots.
Fixed
- Loot share — player-dropped currency — dropping and re-picking up Crux Fragments/Ingots/Aether no longer triggers the loot share split with teammates; loot share now only fires for world loot (enemy drops, chests, barrels).
- Oversized stack normalization —
merge_bag_itemandmerge_vault_itemnow loop when splitting overflow so items exceeding stack_max are always stored as proper-sized stacks. Anormalize_stackspass runs on login to repair any existing corrupted stacks (e.g. a 999-aether item from an admin gift will be split to 100-stacks automatically).
[v0.5.195] — 2026-06-18
Fixed
- Portal queue count flash — flash timer now ticks even while the portal select overlay is open (was frozen due to early return); extended flash duration from 0.5s to 2.0s with a smooth fade so the yellow highlight is reliably visible.
[v0.5.194] — 2026-06-18
Fixed
- Portal confirm modal — L/R toggle — left/right d-pad now toggles PvP/Co-op from any row in the confirm modal (including the ENTER DUNGEON row); previously only worked when cursor was on row 0.
- Portal confirm modal — hint text — "L/R" relabelled to "< >" to clarify d-pad left/right, not shoulder buttons.
- Dungeon portal — IN DUNGEONS double-count — fixed
WorldRegistry::all_worlds()returning duplicate world Arcs when multiple players share a world; a 2-player stable run was showing as 4.
[v0.5.193] — 2026-06-17
Changed
- Portal confirm modal — dim background — portal panel is darkened when the confirm sub-screen opens so the modal reads as a distinct layer.
- Portal confirm modal — A always confirms — pressing A from anywhere in the modal enters the dungeon with current settings; no longer need to navigate down to the ENTER DUNGEON button.
- Portal confirm modal — cursor starts on ENTER DUNGEON — quick double-tap A (select mode → confirm) goes straight in; navigate Up to change PvP/leader-pays options first.
- Portal confirm modal — hint bar — added
A:CONFIRM L/R:TOGGLE B:BACKat the bottom of the modal.
[v0.5.192] — 2026-06-17
Changed
- Portal select — cost line — now shows full item name ("20 AETHER" / "1 AETHER CORE") with mini icon right-aligned to the left column edge.
- Portal select — queue labels — "QUEUE CO-OP/PVP" renamed to "QUEUING CO-OP/PVP".
- Portal select — dim contrast — zero-count queue lines use a more obviously gray color to distinguish from active.
- Enemy player reticle — ellipse moved down 7px for better body alignment.
[v0.5.191] — 2026-06-17
Changed
- Portal select — cost moved to left column — cost line ("COST: FREE / 20 / 1") now sits pinned to the bottom of the left column with a mini inline icon for Aether and Aether Core.
- Portal select — queue counts dim/flash — queue count lines are now dim gray when 0 and bright green when > 0; numbers flash yellow briefly when the value changes.
- Portal select — right column reorganised — crucible spawn % moved to top of right column now that cost has moved; count lines have more breathing room.
[v0.5.190] — 2026-06-17
Changed
- Portal select — larger secondary text — crucible spawn %, pvp type label, queue/dungeon counts, and "INSUFFICIENT FUNDS" all upgraded from Small (8px) to MediumFull (12px). Panel height expanded from 420→450 and card rows from 110→124px to fit everything with comfortable spacing.
[v0.5.189] — 2026-06-17
Changed
- Portal select — accurate durations — displayed run times updated to match server: 6 min (Unstable), 12 min (Stable), 18 min (Empowered).
- Portal select — split queue/dungeon counts — each mode now shows "QUEUE CO-OP: N", "QUEUE PVP: N", and "IN DUNGEONS: N" separately (Unstable shows "QUEUING: N" and "IN DUNGEON: N").
[v0.5.188] — 2026-06-17
Changed
- Enemy player reticle position — red ellipse indicator raised 15px so it sits at the body center rather than the lower third.
- Stable dungeon crucible spawn rate — increased from 40% to 50%.
- Smelt speed — smelting is now 37.5% faster (divisor 5→8): ~1.25s per ingot-worth, ~0.25s per fragment, ~1.875s per aether unit. Applies equally to town and dungeon crucibles.
[v0.5.187] — 2026-06-17
Added
- Co-op option for Empowered mode — Empowered previously forced PvP; it now shows the same Co-op/PvP toggle in the confirm dialog as Stable.
Changed
- Portal select terminology — "PvE" renamed to "Co-op" and "PvPvE" renamed to "PvP" throughout the portal select UI, confirm dialog, and queue-waiting screen.
- Per-mode active counts — Unstable now always shows "ACTIVE: N" (even when 0). Stable and Empowered each show two lines: "CO-OP: N" and "PVP: N". Counts combine players in queue and players currently in dungeons of that type.
[v0.5.186] — 2026-06-17
Fixed
- Skirmisher Echo Step overshooting (felt like 7+ tiles instead of 4) — displacement reconciliation was compounding during the dash: each frame correction set
client_posto the echo-step position, and the next frame'sdisp = client_pos - recorded_posincluded the previous correction's entire jump as "unconfirmed movement," snowballing the total. The fix hard-syncs the client to the server position during the echo step (same pattern already used for Warrior charge and Void Shift), then resumes normal reconciliation once the dash ends.
[v0.5.185] — 2026-06-17
Fixed
- Arcanist basic attack (bolt) never fired at locked enemy players — the
light_attackerssnapshot omittedtarget_player_id, so the Arcanist bolt-firing branch only checkedtarget_id(NPC enemies). When an enemy player was locked via L1,target_idwas None and the attack silently consumed the cooldown without firing. The fix addstarget_player_idto the snapshot and fires a straight-flying bolt toward the enemy player's center when no NPC target is set; the existing PvP proximity check intick_projectileshandles the hit.
[v0.5.184] — 2026-06-17
Fixed
- L1 targeting never reached enemy players on a normal tap — the raw key-release handler that fires L1 immediately (before the 120ms gesture window) only searched
snap.enemies(NPC enemies) and setl1_cycle_consumed = true, which silently blocked the gestureTap(L1)path that had enemy-player cycling. Net result: tapping L1 would never lock onto an enemy player; only the double-tap snap-to-closest worked. The raw release handler now uses the same combined list (NPC enemies + on-screen enemy players, sorted by distance, cyclingtarget_enemy_idortarget_player_idas appropriate). - No visual feedback when targeting an enemy player — locking an NPC enemy showed a cyan ellipse under their feet, but locking an enemy player showed nothing, making it impossible to tell if targeting worked. A red ellipse reticle + "LOCKED" label now appears under the targeted enemy player's feet.
[v0.5.183] — 2026-06-17
Fixed
- Enemy players couldn't be targeted or hit in PvPvE — L1 target cycling only searched
snap.enemies(NPC enemies), so enemy players were never in the target list. The Arcanist's heavy attack (arcane lightning) requires a locked target and would silently do nothing. Fixed by: (1) addingtarget_player_id: Option<u32>as a separate field inPlayerInput(NPC enemy IDs and player IDs share the same u32 space and can collide); (2) L1 tap/double-tap now builds a combined target list from NPC enemies and on-screen enemy players, cycling through both; (3) the server Arcanist heavy-attack handler checkstarget_player_idwhentarget_idis unset, dealing full arcane lightning damage + chain bounce + AoE knockback to enemy players; (4)still_validexpiry now clears bothtarget_enemy_idandtarget_player_idappropriately.
[v0.5.182] — 2026-06-17
Changed
- Auction House returns always go to mailbox, never silently into bag — expired listings and sale proceeds (currency payout to seller, item delivery to buyer) now always land in the mailbox first. If mailbox is full the item sits as
expired_pendingand retries when space opens. This gives players a clear receipt and means nothing ever appears in the bag without their knowledge.
Added
- Mailbox notification toast in hub — a green banner appears in the hub when mailbox items are waiting: on login (if items are already there), when a purchase delivers to your mailbox, and when an expired listing is returned while you're online. The banner shows "YOU HAVE N ITEMS IN YOUR MAILBOX — BOUNTY BOARD" and fades after 8 seconds.
[v0.5.181] — 2026-06-17
Fixed
- Last 3 bag slot borders missing in dungeon inventory — when quick slot items were loaded (e.g. 3 health potions), the displayed bag capacity was incorrectly reduced by the number of quick slot items (
bag_capacity - qs_ids.len()), hiding the empty slot indicators for the last 3 slots even though items could still be picked up into them. Quick slot items are stored in a separate DB table and do not consume bag capacity; the capacity passed to the inventory grid now uses the unmodifiedbag_capacityvalue. - Dungeon Crucible "QUEUE FULL" flash message never cleared — the
ui.msgtimer was set to 2.0 seconds but never decremented each frame, causing the banner at the bottom of the crucible overlay to persist indefinitely after trying to deposit into a full queue. The timer is now ticked bydteach frame and the message is cleared when it reaches zero. - Mini-boss death chest could spawn on a player's tile, trapping them — the free-tile search on boss death checked for existing chests and solid map tiles but not player positions. If a player was standing on the kill tile or an adjacent tile, the chest would land directly under them, making them immovable. Player tile positions are now excluded from candidate tiles during the spiral search.
[v0.5.180] — 2026-06-16
Fixed
- Update failure screen could trap players in an inescapable loop — if a required update failed to download, the only option was A/B:OK which went to MainMenu, which tried to connect to the server, which rejected the old client, which went back to UpdateRequired, which started the download again — repeat until power-cycle. Fixed:
InstallingUpdatefailure now showsA:RETRY B:EXIT(B exits the game cleanly).UpdateRequiredalso now showsB:EXITso there's always an escape hatch. - Update failure error message was cut off at 54 characters — for long filenames like
assets/Forest Pack 22 Items.pngthe filename alone filled the budget, truncating the actual error to "ser". Fixed by splitting the"Download failed (PATH): REASON"format across two lines — filename on line 1, error reason on line 2, each up to 68 chars (FontSize::Small at 9px fits 70 chars on the 640px screen). - Raw asset pack files were included in update bundles — loose files with spaces in their names (
Forest Pack 22 Items.png,Paid Pack/, etc.) were inassets/and got picked up by the release rsync, causing the auto-updater to fail with HTTP 404. Moved toraw_assets/(now gitignored) which is not deployed.
[v0.5.179] — 2026-06-16
Fixed
- Echo Step (and Skirmisher momentum) could leave players stuck inside walls or breakables — root cause:
echo_step_timer > 0was not in the server-side position guard (udp_recv_loop), so client UDP position packets kept overwriting the server's echo-step movement each tick. The position fight could land the player inside solid geometry, and since the client reconciles to the server snapshot they'd be stuck with no way out. Fixed by addingecho_step_timer == 0to the guard, matching how Void Shift and knockback are already protected. Warrior Shield Charge is intentionally client-authoritative and unchanged.
Changed
- Lobby A:START button now shows player count state — host sees
WAITING FOR PARTY... B:LEAVE(dimmed) while party members haven't joined the queue yet, switching to the normalA:START B:LEAVEonce everyone is present. Pressing A while the party isn't assembled is now a no-op on the client (no request sent, no 10-second spin). If A is pressed while the party is full but the server takes time to respond, the timeout now falls back to staying in lobby (no longer incorrectly goes to MainMenu).
[v0.5.178] — 2026-06-16
Fixed
- PvP/party queue race: one player enters dungeon while others are stuck in lobby — the lobby host could manually press A:START before all party members had joined the queue, causing the dungeon to launch with a partial player set. Fixed by adding a count check in the
ReadyStarthandler (ignores the press ifcount < party_size) and a belt-and-suspenders re-verify inside thedo_startblock after acquiring the queue lock. - Ghost players from mid-lobby disconnect — if a non-host player disconnected between joining the lobby queue and the host sending them
Connected, the host'slet _ = send()silently swallowed the error and left a ghost entry inGameWorldthat would never clean up. Now: (1) a pre-flight check before building the dungeon aborts cleanly (no costs deducted,RunFailedsent to remaining players) if any non-host channel is already closed; (2) if a player disconnects in the narrow window between pre-flight and send, the failed send is detected and the ghost is removed fromGameWorldandworld_registryimmediately rather than leaked. RunFailednetwork message — newServerMessage::RunFailed { reason }lets the server notify lobby and dungeon clients that a run was aborted. Lobby clients receive it and return to hub; dungeon clients (in the edge case where one non-host already receivedConnected) forward to hub viaReturningToHub.
[v0.5.177] — 2026-06-16
Fixed
- Empowered portal cost not deducted when leader_pays — root cause was a race between the leader and non-leader tasks entering the lobby queue; whichever joined the queue first became host and ran the dungeon build, but the build code used
ch.id(the host's char ID) to identify the payer instead of the actual party leader's char ID. Nowleader_char_idis threaded explicitly through the proceed signal so the build loop always charges the correct player regardless of queue join order. - Empowered cost deducted 1 core instead of party_size cores when leader_pays — with leader_pays, the leader is meant to cover all party members (1 core per player); the deduction now uses
party_sizecores instead of 1. Stable mode deduction similarly scaled (party_size × 20 Aether). Validation at queue-join time also updated to require≥ party_sizecores when leader_pays=true. - LootShareGrant double-counted Aether/currency amounts — the client handler matched a share grant by slot type and added
item.amount(which is the server's new total, not the delta) to the found stack, causing values to inflate. Fixed to match by item ID (same as ItemPickedUp) and set the full value rather than adding a delta. Toast now shows the actual gained amount, not the total.
[v0.5.176] — 2026-06-15
Added
- Entity interpolation — NPC enemies and other players now have smoothed display positions (
enemy_display/entity_display) that lerp toward the latest snapshot position each frame (~66% per frame at 30 fps, target catch-up in ~50ms). Eliminates the stutter/skip caused by 30 Hz snapshot phase jitter on WiFi. Large position jumps (>64px — knockback landings, spawns) snap immediately so entities don't visibly slide across the screen. - Collision extrapolation — Enemy and enemy-team player hitboxes for movement collision are now forward-extrapolated using inter-snapshot velocity (
snap_pos + (snap_pos − prev_snap_pos) × ticks_since_snap, capped at 2 ticks). Hitboxes reflect where entities actually are now rather than where they were when the last snapshot was sent, fixing the "walk through moving enemies/players" bug when both are in motion simultaneously.
Fixed
- Enemy-team players appeared in the TEAM panel — the top-right HUD panel was showing all other players regardless of team; now filtered to only show teammates (players in
team_colors). - Dungeon bag showed phantom empty slots — fixed in v0.5.175: quick-slot items count against bag capacity but were excluded from the display grid, making their slots appear empty. Displayed capacity now subtracts the quick-slot count.
[v0.5.175] — 2026-06-14
Fixed
- Dungeon bag showed phantom empty slots when quick-slot items were held — the bag grid was constructed with full
bag_capacity(e.g. 10) but displayed only the non-quick-slot items (e.g. 7), making quick-slot-occupied positions appear as empty usable slots. Fix: the displayed capacity is nowbag_capacity − quick_slot_count, so the grid and slot counter accurately reflect the actual available regular-bag slots.
[v0.5.174] — 2026-06-14
Added
- Dead player body rendering — when another player is dead (health ≤ 0 but still in the snapshot), their sprite is drawn as a 90° CW-rotated south-facing idle frame in full grayscale at 62% opacity; name tag and all glow effects are suppressed. Bodies persist until the server removes the player from the run.
- PvP knockback — Warrior Shield Charge, Warrior heavy AoE, and Skirmisher spin now push enemy-team players to a computed landing position (wall-bounce logic identical to enemy knockback). The server holds the client's position override via
kb_timerfor 15 ticks while the reconciliation corrects the client's local prediction. Charge knockback is directional (along charge direction); heavy AoE and spin are radial from the attacker center. - Client hard-sync on new stun — when a snapshot first delivers
stun_ticks > 0to a player who was unstunned, the client immediately snaps to the server position, preventing the local position from fighting the server's knockback landing.
Fixed
- Warrior charge and heavy attacks had no knockback on players —
pvp_radius_hitapplied damage and stun but never moved the target;pvp_knockback()helper added for this purpose. - Skirmisher spin had no knockback on players — same fix.
[v0.5.173] — 2026-06-14
Fixed
- PvP combat was silently broken — all players were added to the dungeon world with a hardcoded
team_id=1, so every PvP check (t_team == owner_team) treated opponents as allies and skipped them. Fixed by passingqp.team_id(set by the matchmaker: 1 vs 2) toadd_player. - Enemy-team players now block movement — walking into an opponent is now blocked by the same AABB escape-hatch logic used for NPC enemies. Uses the standard player hitbox (
PHB_L/T/R/B = 8/10/24/26). Charge movement still bulldozes through (server handles knockback). Ally players and NPC enemies remain non-blocking relative to each other.
[v0.5.172] — 2026-06-14
Added
- PvP combat fully wired — all player attacks now check enemy-team players in addition to enemies:
- Light attacks (Warrior/generic box, Skirmisher multi-hit with bleed) hit players in the forward attack box
- Heavy attacks: Warrior AoE and Skirmisher spin deal physical damage + apply bleed to nearby players; Arcanist lightning AoE deals arcane damage and stuns (3s) nearby players
- Shield Charge body-slams enemy-team players in a 2-tile radius, dealing physical damage and stunning for 3s
- Arcane bolts collide with enemy-team player hitboxes in flight (proximity check per tick), dealing arcane damage on impact
- Unarmed kick hits players in the forward box
- Full mitigation stack applies to player-vs-player damage —
PhysDefensereduces physical hits;Wardstat reduces arcane hits (Arcanist lightning, arcane bolts); Warrior DR, Skirmisher Fade DR, shield cone block, Arcane Ward (hits-based), Ironclad Epic block, and legacy damage shield all function in PvP - Bleed debuff ticks on players — Skirmisher bleed applies and ticks every
BLEED_TICK_INTERVALticks as physical damage; death from bleed shows "SLAIN BY BLEED" - Stun input lock — while
stun_ticks > 0(received from server snapshot), movement is cleared and all action/ability/momentum flags are zeroed; the player cannot move, attack, shield, or use abilities until the stun expires - Debuff icon strip — stun and bleed debuffs now show as icons below the HP bar (alongside existing food/ability buff icons): gold lightning-bolt icon for stun, red drip-drop icon for bleed, each with a live seconds countdown
- Damage numbers on other players — already functional via
prev_healthtracking in the snapshot loop; verified no changes needed
Changed
apply_player_damage()is now the single damage path for both PvE (enemy attacks) and PvP —ai.rscalls it instead of an inline block, ensuring the full mitigation stack applies in all contextsWardstat now active — previously wired toPlayerEntry.ward_flatbut never applied; now reduces arcane damage inapply_player_damage()
[v0.5.171] — 2026-06-14
Changed
- PvPvE search moves into the lobby screen — clicking a PvPvE portal now immediately transitions to the lobby screen in "searching" mode rather than showing a small overlay banner in the hub. Full-screen purple UI shows mode, countdown, and a "NO MATCH FOUND · ENTERS AS PVE" notice. B cancels the search and returns to hub; pressing B is blocked once a match result flash is showing.
- Lobby B-cancel hardened — B:CANCEL during a match-result flash (1.5s window after "OPPONENTS FOUND!" or "NO MATCH · ENTERING PVE") is now ignored, preventing a spurious
LeaveQueueafter the server has already resolved the match. - Server cleans up PvP pool slot immediately on cancel — added a
LeaveQueuehandler to the hub loop so the pvp group is removed from the pool the moment the player cancels, closing the timing window where a stale slot could trigger a phantom match for another player.
Removed
- Old PvP pool overlay (
draw_pvp_pool_overlay,PvpPoolState, hub-sidePvpMatched/PvpFallbackhandlers) — all replaced by the new lobby searching screen.
[v0.5.170] — 2026-06-14
Changed
- PvPvE matching: 1v1 works immediately — removed the Phase 1 gate that required groups of 3 before matching. Now: if no 3-player group exists anywhere in the pool, any equal-size pair matches right away (two solo players = instant 1v1).
- Smarter PvE fallback timeout — instead of a fixed 3-minute wait, the server falls back based on pool state: 45s if you're alone (no other groups on same mode), 120s if others are present but no same-size match yet.
- PvpPoolJoined
timeout_secsupdated — server now sends 120 (was 180) to reflect the new upper bound.
Fixed
- PvPvE countdown showing garbled characters (e.g. "A7S") — the digit formatter only handled 2-digit values; values ≥ 100 overflowed into non-digit ASCII. Now formats up to 3 digits correctly.
[v0.5.169] — 2026-06-14
Changed
- Dungeon Portal UI overhaul: panel expanded from 320×210 to 608×420 (full-screen minus thin margin). Each of the three portal modes now gets its own 110px card with a clear two-column layout — left column shows mode name (Large font), size/duration, and PvP type; right column shows cost (accent-coloured), crucible spawn rate, and active player count (green, only when >0). Locked modes display "INSUFFICIENT FUNDS" in red. Confirm sub-screen (PvP type toggle, Leader Pays toggle, Enter Dungeon) widened to 420px with properly spaced 32px rows.
[v0.5.168] — 2026-06-14
Added
- Party tab in social menu (Phase 5): the L1 social menu now has a third tab — Party — that auto-opens when the player is in a party. Shows all members with name (gold for leader), "(YOU)" marker, and "IN TOWN" / "IN DUNGEON" status. Leader sees X:KICK and Y:PROMOTE hints on non-self rows for in-town members.
- Kick and transfer leadership: leaders can kick a member (sends
KickPartyMember) or transfer leadership (TransferLeadership). Both update all remaining members viaPartyUpdate. - In-dungeon member visibility: party members currently in a dungeon now appear in the party tab using cached info (name, class, sprite). Cache is populated when a player enters the hub and when an invite is accepted.
Party.member_infoHashMap added toparty.rs. KickPartyMember/TransferLeadershipserver handlers: validate leader, translate hub_id → char_id, notify kicked player withPartyDisbanded { reason: "KICKED FROM PARTY" }, broadcastPartyUpdateto remaining members.- 3-tab social menu cycling: L1/R1 now cycle through Party → Friends → Requests → Party. Menu auto-opens on Party tab if in a party, otherwise Friends tab.
[v0.5.167] — 2026-06-14
Added
- Live queue counts in portal UI (Phase 4): the Dungeon Portal mode list now shows "N ACTIVE" in green next to each mode when players are in that queue or pool. Unstable shows lobby queue size; Stable shows PvE + PvPvE pool combined; Empowered shows PvPvE pool. Count is hidden when zero.
QueueCountsserver message:hub_tick_loopbroadcasts queue and pool counts to all hub players once per second, only when the counts change.hub_tick_loopnow takesqueueandpvp_poolparameters.
[v0.5.166] — 2026-06-14
Added
- PvPvE matchmaking pool (Phase 3): Stable PvPvE and Empowered runs now enter a server-side matching pool instead of going straight to the lobby. Groups (solo or party) are matched against opponents of equal team size. Phase 1 (<2min): 3v3 only. Phase 2 (2–3min): any equal-size pair. Phase 3 (≥3min): PvE fallback.
PvpPoolstructs inserver/src/queue.rs:PvpGroup,PvpMember,PvpPoolwithadd_group(),remove_group(), andtry_match_and_notify()(checked every 500ms bypvp_matchmaker_loop).team_id: u8onQueuedPlayer: each queued player now carries their assigned team ID (1 = team A, 2 = team B, 1 = PvE/no teams). This flows through toRosterEntry.team_idat dungeon launch, replacing the hardcoded1.- New server messages:
PvpPoolJoined,PvpFallback,PvpMatched— signal pool entry, PvE fallback, and successful opponent match to the client. - "SEARCHING FOR OPPONENTS" banner: purple bordered panel displayed when in the PvP matchmaking pool, showing mode, timeout countdown, and B:cancel.
Changed
- Solo PvPvE stays in hub: solo players entering Stable PvPvE no longer immediately transition to the lobby. They remain in the hub loop, waiting for a pool match or timeout.
- Party PvPvE pool entry: after all party members accept, the whole group enters the pool together instead of breaking to lobby directly. Non-leaders wait on their
proceed_rx; the leader stays in the hub loop until the pool fires. queue_proceed_txextended to(PortalMode, usize, bool, bool, u8)— addsteam_idso matched players know their team assignment when they enter the lobby.pvp_matchmaker_loopadded as a background task inmain.rs, runs every 500ms.
[v0.5.165] — 2026-06-14
Added
- Non-leader portal info panel (Phase 2b): non-leader party members now see a top panel showing the mode (e.g. "STABLE - PVPVE"), countdown, and "LEADER IS COVERING YOUR COST" when leader_pays is active. Previously it was just a floating countdown string.
Changed
- leader_pays at dungeon launch: when the leader enables "Leader Pays," only the leader's Aether/core is deducted at dungeon launch; all other party members enter free. Non-leaders receive the
leader_paysflag via the queue proceed signal. - PartyQueueStarted now carries
pvpandleader_paysfields so the non-leader UI can display exactly what the leader configured. - queue_proceed_tx extended to carry
(PortalMode, party_size, pvp, leader_pays)so non-leaders know the full run settings when they break out of the hub loop.
[v0.5.164] — 2026-06-14
Added
- Portal settings screen (Phase 2a): pressing A at the Dungeon Portal now opens a settings screen before queuing. Stable mode adds a PvE / PvPvE toggle; Empowered is always PvPvE. Party leaders also see a "Leader Pays" toggle (covers the Aether/core cost for all members). Unstable (free) skips the confirm step and queues immediately.
pvpandleader_paysfields on EnterQueue: wire protocol updated to carry both flags to the server. Server logs them; PvPvE matchmaking uses them in Phase 3.
Changed
- Party persistence through dungeons (Phase 1): parties formed in the hub now survive dungeon runs. Members are flagged
in_dungeonon dungeon entry instead of having the party dissolved. When they return to hub, the flag clears and a party update is broadcast to all members. - Queue cancel keeps party: canceling or timing out a party queue no longer dissolves the party — members stay grouped and receive a cancel-reason notification.
- Party state keyed by character_id:
PartyStatenow uses persistenti64character IDs instead of ephemeralu32hub IDs, so party membership survives reconnects and dungeon transitions.
[v0.5.163] — 2026-06-14
Changed
- Crucible aether multipliers: Rare 3→5, Epic 4→15, Legendary 5→35 per augment socket. A 3-socket Legendary now yields 105 raw (52 after town tax) instead of 15 (7 after tax).
- Tome aether yield: Ability Tomes now yield aether at the crucible as 1-socket-equivalents (previously 0 due to having no sockets).
Fixed
- Potion cooldown wrongly shown as buff: health potion cooldown was appearing as a persistent HUD buff icon. Removed — the linger slot in the R2 menu is the correct place for it.
- Quick-use linger not rendering: the linger slot was drawn inside
if d.r2_held, so it never appeared after releasing R2. Moved outside the block so it renders correctly.
[v0.5.162] — 2026-06-14
Added
- Empowered mini-bosses: Empowered dungeons now also spawn 2 mini-bosses in addition to the main boss. Mini-bosses must be ≥40 tiles (Chebyshev) from the boss and ≥8 tiles from each other.
- Potion cooldown in buff row: a health potion icon now appears in the HUD buff row when the potion cooldown is active, visible without opening the R2 menu.
- Quick-use linger: after consuming a food or potion from the R2 menu, the used slot stays on screen for 2 seconds showing the clock sweep, then disappears.
Changed
- Buff row layout: timer now appears centered below each buff icon instead of to the right, fitting more icons horizontally beneath the HP bar.
- Buff timers: all buff/cooldown timers in the HUD row are now white (food timer was previously green).
- Legendary weapon class lock: Soulreaver (legendary sword) is now Warrior-only; Stormspear (legendary spear) is now Skirmisher-only. Common/Uncommon/Rare swords and spears remain equippable by both classes.
Fixed
- Quick-use icon during cooldown: when the last of an item type was consumed, the slot icon in the R2 menu went nearly invisible. It now stays dim-but-visible while the cooldown ticks down.
[v0.5.161] — 2026-06-14
Changed
- Void Stone crucible value: raw aether yield raised from 5 → 60 per stone (30 Aether after town crucible tax, full 60 at dungeon crucible).
- Void Stone acquisition: removed floor spawns near dungeon crucibles. Stable and Empowered boss/mini-boss chests (type 7) now guarantee a Void Stone, ensuring at least one per run. Flat per-chest chance adjusted: 10% Unstable, 15% Stable, 20% Empowered.
[v0.5.160] — 2026-06-14
Added
- Party loot sharing: when you pick up Crux Ingots, Crux Fragments, or Aether, each party teammate in the same dungeon automatically receives 50% of the amount (rounded down; skipped if it would be 0). Applies to ground pickups, chest loot, and dungeon crucible withdrawals. Teammates see a brief
+X INGOTS (FROM NAME)HUD toast. Town crucible excluded.
[v0.5.159] — 2026-06-14
Fixed
- Dungeon crucible light not visible to other players: when a player started smelting, only they received the state update — other players in the dungeon saw the crucible tile as inactive/dark. Server now broadcasts
DungeonCrucibleActiveto all dungeon players when smelting is toggled on, andDungeonCrucibleIdleto all when manually paused.
[v0.5.158] — 2026-06-14
Fixed
- Social menu opening on Requests tab: L1 opens the social menu, but
tick_social_menuprocessed the same L1 press in the same tick, immediately toggling the tab from Friends → Requests. Social menu now skips input processing on the frame it was opened.
[v0.5.157] — 2026-06-14
Fixed
- Chest loot fallback: gear roll now retries up to 4 times before giving up (avoids the ~12% empty-gear scenario on low-type chests). Fallback when all probabilistic rolls still miss now gives 1–3 Crux Ingots + 5–12 Crux Fragments instead of just 3–7 fragments.
- Death chest collision:
chest_set(used for client-side player collision) was built once at dungeon load and never updated when a boss/mini-boss death chest spawned. Death chests now register intochest_setimmediately so they block movement. - Death chest overlap: if a boss/mini-boss died on the same tile as an existing chest, the death chest was silently stacked on top making it inaccessible. Server now scans the kill tile and up to 8 adjacent tiles to find the nearest free spot.
- 4-digit stack amount display:
amt_bufwas 4 bytes (x+ 3 digits), truncating silently for amounts ≥ 1000. Expanded to 5 bytes with a>= 1000branch in all three display sites (dungeon inventory list, dungeon ground loot panel, hub crucible list).
Changed
- Stack sizes: Crux Ingot max stack raised from 100 → 500; Crux Fragment max stack raised from 100 → 1000.
[v0.5.156] — 2026-06-13
Fixed
- Trade window opening before accept: the initiator (A) was sent
TradeOpenedimmediately when the request was sent, opening the full trade window before B accepted. Server now sendsTradeRequestedto A instead, which shows a "WAITING FOR X..." screen with B:Cancel. The trade window only opens when B actually accepts.
[v0.5.155] — 2026-06-13
Changed
- Trade window item rows: replaced placeholder colored rects with
draw_item_icon_flooricons (matching Crowe stall style); each row now shows icon + rarity-colored name + a sub-line (first affix, augment socket count, or stack quantity). Row height increased from 36 to 50px to accommodate. - Social menu default tab: menu now opens on the Requests tab when there are pending incoming friend requests; defaults to Friends otherwise. Tab auto-switches only on first data load, not on subsequent background refreshes.
[v0.5.154] — 2026-06-13
Fixed
- Trade: pre-accept items now visible on accept: when the trade initiator (A) added items before the target (B) accepted the invite, B's trade window showed empty on open. Server now snapshots A's current offer at accept time and sends it to both sides immediately via
TradeUpdated. - Trade: stackable quantity picker: selecting a stackable item from the bag picker (amount > 1) now opens a quantity selector (
< N / max >) instead of adding the full stack. Up/Down or Left/Right adjusts ±1, L1/R1 adjusts ±10, A confirms, B returns to item list. Theamountfield is now sent withAddTradeItemand the server takes only the requested quantity from the stack (leaving the remainder in the bag).
[v0.5.152] — 2026-06-13
Fixed
- Friend accept from Deferred was silently failing: the DB UPDATE required
status = 'pending'but deferred rows havestatus = 'ignored'; changed toIN ('pending', 'ignored')so both normal and deferred accepts work - Social menu live updates: menu now auto-refreshes every 4 seconds while open; also triggers an immediate refresh when
FriendRequestReceived,FriendRequestResult(success), orFriendAcceptedarrives; also triggers 0.5s-delayed refresh after accepting/deferring/deleting from within the menu
[v0.5.151] — 2026-06-13
Fixed
- Social menu — Deferred requests: A now accepts a deferred friend request; X deletes it. Previously A did nothing on deferred entries.
- Social menu — renamed Ignore → Defer: hint bar shows
Y:DEFERon Pending In; deferred section is labeled "DEFERRED"; in-hub prompt showsY:DEFER. - Social menu — Deferred hint: context-sensitive hint shows
A:ACCEPT X:DELETEwhen cursor is on a deferred entry.
[v0.5.150] — 2026-06-13
Fixed
- Social menu: L1 now cycles tabs (Friends ↔ Requests) while the menu is open; B closes. Previously L1 was closing the menu instead.
- Trade — CONFIRM slot: was only shown when the offer was full (8 items). Now always visible as the last row regardless of how many items are offered.
- Trade — remove control: X removes an offered item; A no longer removes (A now only selects ADD ITEM or activates LOCK IN). Hint at the bottom updates to show X:REMOVE when an item row is selected.
[v0.5.149] — 2026-06-13
Added
- Player-to-player item trading: Hub players can initiate a trade via the Player Card (Trade option, was "(soon)")
- Bilateral trade window: split-screen with YOUR OFFER (left) and THEIR OFFER (right)
- Each side can add up to 8 items from their bag via a bag picker sub-screen (A:ADD / B:CANCEL)
- Items are removed from the trader's bag immediately when added to the offer
- Both players lock in their offer separately by selecting [ LOCK IN ]; when both are locked the server executes the trade
- Items overflow to the recipient's mailbox (with notification) if their bag is full at trade time
- Either player can cancel at any time (B) — all held items are returned to their owners
- Trade is also cancelled cleanly on hub disconnect
shared::TRADE_MAX_ITEMS = 8— enforced on both server and client- New DB helpers:
take_bag_item(already existed),trade_deliver,trade_cancel - Trade sessions tracked in
HubWorld.trades: HashMap<u32, TradeSession>
[v0.5.148] — 2026-06-13
Added
- Friend system (Phase 1): character-based friends, 50-cap, stored in SQLite
friendshipstable- Player Card → Add Friend: sends
SendFriendRequestto the server; target receives an in-hub prompt (A:Accept / X:Deny / Y:Ignore); ignored requests go to the Requests tab for later review - Social menu (L1 press-to-toggle): full-screen overlay with two tabs — Friends (status: In Town / In Dungeon / Offline + last-seen days) and Requests (Pending In, Pending Out, Ignored, Recently Played With); closes with B
- Party invite from social menu: A on an In Town (not in party) friend sends an invite
- Remove friend: Y on a friend opens a confirmation prompt; confirmed with A; silent removal (no notification to removed player)
- Hub entry notification: toast banner shows count of pending friend requests on login; disappears after 5 seconds
- Recently Played With: co-op partners are recorded in
recently_played_withon successful extraction; shown in Requests tab for non-friends; A sends a friend request if they're online - Last online tracking:
characters.last_online_atupdated on hub leave; used for "Xd ago" display on offline friends
- Player Card → Add Friend: sends
- DB migrations: new tables
friendshipsandrecently_played_with;last_online_at INTEGERcolumn added tocharacters
[v0.5.147] — 2026-06-11
Added
- View Loadout: selecting "View Loadout" on another player's card sends
RequestPlayerLoadoutto the server; server reads their equipped items from DB and responds withPlayerLoadoutContents; client renders a full-screen loadout view with the player's name + class in the header; D-pad navigates slots, Y opens the inspect modal, B closes HubPlayerEntry.character_id— allows server to look up any hub player's DB record by hub ID
[v0.5.146] — 2026-06-11
Changed
- Player interaction menu: pressing A near another hub player now opens a small menu (View Loadout / Party Invite / Add Friend / Trade) instead of sending an invite immediately; navigate with D-pad, A confirms; only Party Invite is active — other options show "(soon)"
[v0.5.145] — 2026-06-11
Changed
- Inspect modal — socket names: filled sockets now show the sigil name (e.g. "Warbrand ATK +8") derived from stat + rarity via
shared::sigil_display_name
[v0.5.144] — 2026-06-11
Added
- Loadout inspect modal: press Y on any equipped item to open a full-screen detail overlay — large 64×64 icon, name, slot/rarity, damage type, class restriction, all affixes with inline sigil bonuses, and a per-socket breakdown showing rarity/stat/value for each filled socket or "empty" for open ones; B closes
[v0.5.143] — 2026-06-11
Fixed
- Character sprite #25–32 shows white square:
SPRITE_COUNTwas 32 but only 24 sprite files exist; picker wrapped the index so creation appeared to work, but the stored sprite number (25–32) failed to load in-game and fell back to a gray placeholder rectangle. Fixed by settingSPRITE_COUNT = 24; server now also rejectsCreateCharacterwith a sprite outside 1–24
[v0.5.142] — 2026-06-10
Added
- Auction anti-abuse — cancel → direct bag: cancelling a listing now returns the item directly to bag (denied with message if bag is full); no mailbox round-trip that could be exploited for storage
- Auction anti-abuse — mailbox cap 20: expired/purchased items go to mailbox only if the recipient has fewer than 20 entries; if mailbox is also full, the listing is set to
expired_pendingand retried automatically by the expiry loop (and immediately when any mailbox slot is claimed) - Auction anti-abuse — 30-day mailbox TTL: auction-originated mailbox entries expire after 30 days;
days leftshown in the mailbox UI per entry; expiry loop purges stale entries before retrying pending deliveries - DB migration M012:
mailbox_expires_at INTEGER DEFAULT NULLcolumn added tomailbox_items
Changed
MailboxEntrywire type gainsexpires_at: Option<i64>(serde default = None for backward compat)add_mailbox_itemsignature gainsexpires_at: Option<i64>param; all existing callers passNone
[v0.5.141] — 2026-06-10
Changed
- Auction House — visual overhaul: listing rows now 54px tall with 32×32 item icon, rarity label, seller name, compact socket dots, and price in MediumFull; tab bar and filter bar use MediumFull throughout
- Auction House — detail screen: two-column layout; affixes/price/confirm on right in MediumFull; sockets shown with
draw_sockets; icon usesitem_icon_color - Auction listing — price input: R1/R2 increase price (+10/+100), L1/L2 decrease (-10/-100)
[v0.5.139] — 2026-06-09
Added
- Crowe's shop — Void Stone: listed for 100 Crux Ingots (top of shop)
- Crowe's shop — Aether exchange: 60 Aether for 100 Crux Ingots (top of shop); stacks with existing Aether in bag
Fixed
- Crowe's shop — colored icons: detail panel now uses
item_icon_colorso Common bags show warm leather colors and currency/crafting items show their proper colors instead of flat gray
[v0.5.138] — 2026-06-09
Fixed
- Crowe stall position: zone moved to [69,48,70,49] — the same relative offset within the Auction House that VaultUpgrade occupies within the Ironvault (lower-center of the building)
[v0.5.137] — 2026-06-09
Fixed
- Hub sub-zone borders: VaultUpgrade and Crowe zone highlight borders are now drawn after the mask tile layer instead of before it, so building tiles no longer paint over them — the border is visible whenever the zone is on screen, not just when standing inside it
[v0.5.136] — 2026-06-09
Fixed
- Auction House — Crowe sub-zone: added
crowemarker tohub.jsonso the 2×2 stall at the top-left of the tradehouse zone is correctly highlighted and activatable; pressing A inside it opens Crowe's vendor screen, pressing A elsewhere in the building opens the Auction House - Auction House — seller mail: payout mail now shows who bought the item ("Auction: Playername bought your Item for 100 Crux Ingots")
[v0.5.135] — 2026-06-09
Added
- Auction House — full player-to-player marketplace in the hub (Crowe's Tradehouse):
- Players can list up to 10 items at a time for Crux Ingots or Aether; 20-ingot listing fee (non-refundable), deducted immediately
- Browse screen: filter by category (All/Weapon/Armor/Sigil/Bag/Other), rarity, and sort order (price asc/desc, rarity, newest); paginated results
- "My Listings" tab shows active listings and allows cancellation (item returned via mailbox)
- Purchases and sales settle through the existing mailbox — buyer gets the item, seller gets the currency
- Expired listings (7 days) auto-cancel via a background task; item returned to seller via mailbox, listing fee not returned
- Server:
auction_listingsSQLite table;db::auction_*query functions;network::auction_expiry_loop - Shared:
AuctionCurrency,AuctionCategory,AuctionSort,AuctionListingEntrytypes; client/server message variants - Client: full-screen auction UI with browse, detail/buy, list flow (pick item → set price → confirm), and my-listings screens
[v0.5.134] — 2026-06-09
Fixed
- Boss/mini-boss never spawning: footprint filter was checking against sparse enemy spawn points instead of unblocked tiles — a 4×4 grid of consecutive spawn coords almost never exists, so bosses were always skipped. Now correctly checks
!map_blockedfor all tiles in the footprint.
[v0.5.133] — 2026-06-09
Added
- Death chests: bosses (kinds 117–119) drop a type 7 chest on death; mini-bosses (111–116) drop a 50/50 Stable (types 2–4) or Empowered (types 5–6) chest. Chests appear at the kill tile and are fully interactable via the normal chest flow.
- Type 7 boss chest: always 2 gear items rolling Epic/Legendary only (60% Legendary / 40% Epic), 25% sigil chance. Boss-exclusive, not generated by dungeon generation.
Changed
- Chest type ranges by mode: Unstable now uses types 0–1; Stable uses 2–4; Empowered uses 5–6. Type 7 is reserved for boss death chests.
- Gear item count per chest type: 0–1 = 1 item; 2–4 = 1 or 2; 5–7 = always 2. Sigil chances: 0–1 = 10%, 2–4 = 15%, 5–6 = 20%, 7 = 25%.
[v0.5.132] — 2026-06-09
Fixed
- Boss/mini-boss wall clipping: spawn candidate tiles are now filtered to require a clear full footprint before scoring — bosses need a 4×4 tile clear area, mini-bosses need 2×2. Prevents either from spawning with their sprite overlapping a wall.
[v0.5.131] — 2026-06-09
Fixed
- Boss/mini-boss facing and attack range: AI now uses the correct sprite-scaled center per enemy kind (boss=x+32, mini-boss=x+16, regular=x+8). Attack range is also per-enemy:
player_half(16) + enemy_half + 4px margin, so bosses engage at ~52px and mini-bosses at ~36px instead of a flat 20px. Fixes bosses standing adjacent to the player but facing the wrong direction and never landing attacks.
[v0.5.130] — 2026-06-09
Fixed
- Boss/mini-boss hitbox: combat hit detection now uses the actual sprite frame size per enemy kind — bosses (kinds 117–119) get a 64×64 hitbox, mini-bosses (111–116) get 32×32, regular enemies stay at 16×16. Affects melee overlap checks, targeted attack range, AoE center, projectile tracking and collision.
[v0.5.129] — 2026-06-08
Added
- Boss spawning: Empowered dungeons now spawn one boss enemy chosen from the boss pool for the active tileset. Boss is placed in the farthest 25% of available floor tiles from the player spawn for seed-driven variety.
- Mini-boss spawning: Stable dungeons now spawn 1 mini-boss (2 if the dungeon has a crucible), chosen from the mini-boss pool for the active tileset. Mini-bosses are placed at least 8 tiles apart in the far third of the dungeon.
- Boss/mini-boss enemy entries: kinds 111–116 (Stable mini-bosses) and 117–119 (Empowered bosses) added to
enemy_index.json. Dragon 119 (Sylvan) tileset 01 only; 118 (Infernal) tileset 02 only; 117 (Ancient Wyrm) either tileset.
[v0.5.128] — 2026-06-07
Added
- Primary group weighting: each tileset now has a designated primary enemy group that spawns at 3× weight on open floor tiles — fae on tileset 01, undead on tileset 02. Gives each dungeon a distinct identity without removing other groups.
Everywherepool fix: enemies taggedeverywherenow inject into the open floor pool as minority flavor rather than sitting in an unreachable fallback bucket. Hellspawn, reptids, and slimes actually spawn now.- Boss ad system: neophyte (drake) enemies marked
boss_ad: truein the enemy index — reserved for boss room spawning once bosses are implemented. Removed from regular spawn pools. - Enemy index tool: boss ad toggle on each card (greys out modes/spawn when checked); primary group display in toolbar; import/export round-trips
boss_adfield.
Changed
- Tileset 02 spawn redesign: undead moved to open floor (primary group); insectoids moved to overgrowth. Tileset 02 now reads as a haunted ruin rather than a bug cave.
- Insectoids: locked to tileset 02 only (was null/any).
- Crawlscale (kind 3): named; joins Creepscale as a reptid on tileset 02.
Fixed
- Momentum ability fires during stamina exhaustion: B double-tap (Warrior charge, Skirmisher echo step, Arcanist void shift) no longer fires while the stamina bar is red. All three arms now gate on
!stamina_exhaustedin addition to the stamina cost check.
[v0.5.127] — 2026-06-05
Added
- Zone-aware enemy spawning: enemies now spawn based on proximity to dungeon POIs. Spawn tiles within 2 tiles of a canal get aquatic enemies; within 2 of a platform get diseased/ratkin; within 5 of the portal get void serpents; within 2 of a chest get trogkin (01) or beholders (02, S/E); within 1 of overgrowth get plant enemies (01) or undead (02); everything else gets fae (01), reptids (02), or insectoids for open floor.
everywhereenemies fill in when a zone has no specific pool. server/src/enemy_index.rs: loadsassets/enemy_index.jsonat first use (OnceLock).EnemyIndex::build_zone_pools(mode, tileset_id)produces filtered pools;ZoneData::from_map(&map)+classify(tx, ty)classifies each spawn tile.assets/enemy_index.json: source of truth for all enemy spawn configuration, generated fromtools/enemy_index/.
[v0.5.126] — 2026-06-03
Added
- Class requirement label in all inventory screens: inventory detail panel, IronVault, and town crucible now show the same green/red class label introduced in the dungeon crucible. Green = equippable by your class, red = not. Replaces the old amber "Class: X" label in inventory and vault.
[v0.5.125] — 2026-06-03
Fixed
- Tileset _02 crucible fire:
light_flickerwasnullin the _02 crucible config, causing fallback to per-cell pulsing. Set to[8, 6]— the same 2×2 flame sprite used by _02 torches — so both tilesets now use the torch-style wobble animation.
[v0.5.124] — 2026-06-03
Fixed
- Crucible fire stays on when empty:
crucible_statesnow tracksactive && current.is_some()instead of justactive. The crucible'sactiveflag defaults totrue(ready to smelt), which was causing the fire art to show even when the queue was empty. Fire now only renders when something is actively being smelted.
[v0.5.123] — 2026-06-03
Fixed
- Crucible only spawns for tilesets with configured crucible art: tileset _02 has no
crucibleconfig block, so its runs were showing the colored-box placeholder and no fire animation. The server now checkstileset_has_crucible(tileset_id)before placing a crucible — tileset _02 dungeons simply won't have a crucible until the art is configured.
[v0.5.122] — 2026-06-03
Fixed
- Crucible auto-off: server now broadcasts
DungeonCrucibleIdleto all dungeon players when the last item finishes. Client sets the crucible tiles back to the alt (off) state without requiring the player to reopen the UI. - Clutter z-order: mask-layer clutter moved from the entity Y-sort pass to a flat pass between
draw_map_layer(Mask)and destroyed breakables. Ground loot and entities now render above clutter correctly; weird per-row Y-sorting artefacts are gone.
[v0.5.121] — 2026-06-03
Added
- Crucible proximity hint: "A: OPEN CRUCIBLE" appears below the player sprite when standing on either access tile (hidden when UI is already open).
- Class requirement in crucible item detail: item descriptions now show which class(es) can equip the hovered item, coloured green if it fits the player's own class, red if not.
Fixed
- Crucible fire rendering: when
light_flickerframes are configured, per-celltile_lightpulsing sprites are skipped — the rotation wobble is the sole fire effect, matching the torch aesthetic. - Crucible tile state stays on:
DungeonCrucibleUpdatenow writescrucible_statesso the world tile art reflects active/idle changes while the UI is open; closing the UI (B) also saves the final state.
[v0.5.120] — 2026-06-03
Added
- Crucible fire flicker: when a tileset's crucible config includes
light_flickerUV +light_flicker_rotation, a torch-style wobble animation is rendered centered on the fire cells while the crucible is active.CrucibleConfiggainslight_flicker/light_flicker_rotationfields;DungeonAssetsloads the frames at dungeon entry.
[v0.5.119] — 2026-06-03
Fixed
- Clutter per-row Y-sorting: each row of a multi-tile clutter piece now sorts independently in the entity pass. Top and bottom rows layer correctly against entities rather than the whole piece flipping at once.
- Clutter collision — bottom row only: both server
map_blockedand clientclient_solidnow only block the bottom row of multi-row collision pieces. Players can walk under overhanging parts.
[v0.5.118] — 2026-06-03
Fixed
- Crucible collision: client-side
try_movenow blocks against the 4×4 crucible footprint and collision clutter cells, so movement prediction matches the server. - Crucible interaction: server now uses rounded tile position with ±1 tile tolerance, fixing silent rejections caused by sub-pixel position rounding.
- Clutter layer rendering: clutter tile layers now strictly follow
tile_layersconfig assignments. Tiles not assigned intile_layersdefault to Mask (Y-sorted with entities). world.rsclutter collision path: uses same multi-path fallback asdungeon.rs— reads fromupdates/assets/whererelease_do.shdeploys configs.
[v0.5.117] — 2026-06-03
Fixed
- Clutter layer rendering: clutter tiles now respect their
tile_layersassignment — ground tiles render before entities, mask tiles Y-sort with entities, fringe tiles render above entities. Previously everything rendered in the entity pass. - Tileset config update: updated both
_01and_02tileset configs are now picked up correctly on next deploy.
[v0.5.116] — 2026-06-03
Fixed
- Breakable type selection: type count now read from tileset config instead of being hardcoded per portal mode — all configured breakable types can now spawn, not just the first.
- Clutter not spawning: server config reader now checks
updates/assets/tilesets/dungeons/(whererelease_do.shdeploys configs) before falling back to the legacyassets_gif/path.
[v0.5.115] — 2026-06-02
Added
- Seed-driven tileset selection: dungeon seed determines which tileset is loaded (
_01or_02).DungeonMapgainstileset_id; client loads the matching PNG + config. - Config-driven crucible structure: 4×4 tile structure replaces the 2×2 placeholder. Per-cell
tile_altshown when off,tilewhen active. Per-cell light sprites pulse in opacity when smelting. - Tile-based crucible interaction: players must stand on the two access tiles (centre of the row below the structure) to open the crucible. Server validates tile position.
- Ground clutter system: server places decorative/blocking objects per tileset config density and weights. Collision clutter cells block movement. Client renders clutter Y-sorted with the world.
TilesetConfigextended: newClutterEntry,CrucibleCell,CrucibleConfigstructs with#[serde(default)]so existing configs load without changes.
Changed
- Crucible spawns before chests, breakables, and clutter so nothing lands on its footprint or access tiles.
[v0.5.114] — 2026-06-01
Added
/mailtocurrency commands: server console now supports/mailto <character> ingot <amount>,fragment <amount>, andaether <amount>.
Fixed
- Preflight false "offline" on boot: update server check now uses a 5-second connect timeout instead of blocking indefinitely. Previously WiFi not being fully up at boot caused immediate connection failures, burning through all 3 retries and showing "offline" even though the server was fine.
- Empty inventory on first login after device restart: bag and equipped-item request timeouts bumped from 500ms to 2000ms. On a cold WiFi connection the server sometimes took longer than 500ms to respond, causing inventory to load empty (data was always safe — a relog fixed it).
[v0.5.113] — 2026-06-01
Fixed
- Aether Forge bag sync: all three forge operations now keep the displayed bag accurate after completing — Craft Aether Core deducts ingredients, Apply Sigil removes the consumed sigil and deducts ingot cost (rarity-tiered), Remove Sigil deducts the flat 25-ingot fee. Previously the CraftConfirm screen would show stale ingredient counts as if the craft had failed.
[v0.5.112] — 2026-05-31
Added
- Classes & Controls page at
/classeson the website: class stats, per-class attack descriptions with cooldowns, abilities, and full control reference.
Changed
- Per-class light attack cooldowns: Warrior 0.6s (slowest, combo chain), Skirmisher 0.37s (fastest, multi-hit), Arcanist 0.5s (tracking bolt).
- Warrior combo decay bumped to 54 ticks (1.8s) — 3 swing windows, calibrated to new cooldown.
- Combo dots hidden for Skirmisher and Arcanist — visual indicator is Warrior-only.
- Skirmisher light damage corrected to 0.70× per hit (was 0.75 briefly, reverted to original).
[v0.5.111] — 2026-05-31
Added
- Enemy family system: enemies now spawn from 2 randomly selected family groups per dungeon run (slimes, reptids, undead, aquatic, etc.) rather than drawing from the full 1–110 sprite pool. 15 spawnable families derived from
tools/enemy_index/index.json. Stats unchanged for now.
[v0.5.110] — 2026-05-31
Added
- Sigil smelting aether value: sigils now yield aether when smelted (1-socket equivalent) — Rare → 2, Epic → 2, Legendary → 3 (after 50% tax).
- Void Stone smelting: VoidStones are now smeltable and yield 3 Aether per stone after tax (~50% more than a Rare sigil). They now appear in the crucible deposit list.
Fixed
- Chest loot guaranteed: chest rolls now always produce at least one item — if all probabilistic rolls miss, 3–7 Crux Fragments drop as a fallback.
- Ground loot pickup with off-screen aggro: loot pickup is no longer blocked by enemies that have aggro but are off-screen. Only on-screen aggroed enemies suppress the A press.
[v0.5.109] — 2026-05-31
Added
- Empowered portal mode unlocked: checks for ≥1 Aether Core, void-purple label, confirmation overlay. All dungeon parameters (128×128, best chests, Legendary loot, 100% crucible) were already in place.
- Ironweave Cuirass added to Tradehouse stock: Rare chest piece, DEF +8 / HP +15, 1 socket, 100 ingots.
- Void Stones in chest loot: 13% flat drop rate across all modes.
- Aether Core crafting now costs 20 Crux Ingots in addition to 100 Aether + 1 Void Stone.
Changed
- Aether Forge UI: sub-screens have a right-side cost column (ingot icon + price). CraftConfirm redesigned as split layout (item preview left, required ingredients right with have/need indicators).
- Tradehouse redesign: split layout with item detail panel (big icon, affixes, ingot price, have/need). Buy blocked when unaffordable;
A:BUYhidden from hint bar. Centered overlay banner on purchase. Rows dim when unaffordable. - Sigil socket rules: Sash/Pouch/Backpack now accept DEF, WARD, AGI, and HP sigils (previously AGI/HP only).
- Portal select colors: Stable label aether pink, Empowered label light void purple. Confirmation overlays match.
Fixed
- Dungeon timer: 12-minute Empowered collapse window was showing as
2:XX— timer now handles two-digit minutes correctly. - Iron Vault class restrictions: detail panel now shows class requirement label (e.g. "Class: Warrior").
- Chest popup: LOOT SELECTED closes silently; bag-full shows HUD flash instead of reopening the popup.
- Dungeon crucible: stale UI cleared on reconnect; write failures break cleanly.
- Void Stone spawning: stones spawn below the crucible footprint (were inside it, unreachable) and are now broadcast to joining players.
[v0.5.107] — 2026-05-31
Added
- Empowered portal mode unlocked: portal select now checks for ≥1 Aether Core (was hard-locked). Shows
1 COREcost in aether pink with a confirmation overlay. All dungeon parameters were already tuned (128×128 map, best chests, Legendary loot, 100% crucible). - Void Stones in chest loot: 13% flat drop chance across all modes and chest types.
[v0.5.106] — 2026-05-30
Fixed
- Dungeon crucible disconnect → broken UI: after a TCP disconnect during crucible use, the client now clears the stale crucible overlay on reconnect (server already clears
in_use_byon disconnect, so the old UI was permanently non-functional until manually closed). Player can simply reopen the crucible after reconnecting. - Crucible write failures now break cleanly: previously a failed TCP write during a crucible response was silently ignored, leaving the stream in a bad state. All crucible handlers (open/deposit/withdraw/retrieve/toggle) now call
breakon write failure, triggering the reconnect window immediately instead of letting the broken stream linger.
[v0.5.105] — 2026-05-30
Fixed
- Void Stone spawning near dungeon crucibles: stones were placed inside the 2×2 crucible footprint (unreachable) and never broadcast to clients as
LootDropped(invisible). Stones now spawn on the floor tiles just below the crucible with a floor-tile check and are sent to players at dungeon start.
[v0.5.104] — 2026-05-29
Added
- Sigil slot restrictions: sigils can only be socketed into compatible slot types — ATK/AGI/HP on weapons, DEF/WARD/HP on armor/shield, AGI/HP on accessories, any on Tomes. Incompatible sigils are dimmed with [INCOMPATIBLE] label; A is blocked client-side and server enforces it too.
- Tiered sigil apply cost: Rare=20, Epic=40, Legendary=60 Crux Ingots (was flat 25). Removal stays flat 25. Hint line updates dynamically for the highlighted sigil.
- Orphan sigil stat rows: socketing a sigil whose stat has no base affix (e.g. HP sigil on a sword) now shows a standalone HP +# row in the stat identity color below the regular affixes.
[v0.5.103] — 2026-05-29
Fixed
- Vault sigil icons: vault grid was calling
draw_slot_icon(slot)which has no sigil awareness; now callsdraw_item_icon(item)so stat-specific rune icons display correctly (was showing old generic placeholder). - Inventory stat colors: HP, ATK, DEF, WARD, AGI labels in the stats panel now use
sigil_stat_color()— matching the colors on sigil icons and sockets instead of the old independent palette.
[v0.5.102] — 2026-05-29
Changed
DamageType::Magical→Arcane: staff damage and enemy spell damage are now labelled "Arcane" everywhere (inventory, hub, dungeon inspect). M011 migration rewrites existing item JSON on server start so no items are lost.- Chest loot text colors: currency and consumable items in the chest popup now display in identity colors — Aether (aether pink), Crux Fragment/Ingot (crux blue-gray), Health Potion (red), Stamina Potion (amber), Void Stone (void purple). Gear still uses rarity color.
[v0.5.101] — 2026-05-29
Fixed
- Warrior Shield Charge jitter: removed stale
own.charginghard-sync from client reconciliation — the client was snapping position back to the server's lagging copy every snapshot tick, killing net movement. Charge is now fully client-authoritative with no server position override during the charge window. - Missing items after Ward rename (M010 migration): items with
"MagicDefense"affixes or sigil stats were silently dropped on deserialization after theStatKindrename in v0.5.98. M010 rewrites the old variant name in all four item tables on first server start, restoring any affected gear.
[v0.5.100] — 2026-05-29
Changed
/mailtosigil command: now accepts an optional stat argument —/mailto <char> sigil <atk|def|ward|agi|hp> <rare|epic|legendary>. Omitting the stat still rolls randomly as before.
[v0.5.99] — 2026-05-29
Changed
- Socket rendering: filled sockets now show stat color as fill and rarity color as border (was: rarity color fill, fixed grey border). Empty sockets unchanged.
- Sigil bonus text: inline sigil bonus values on item affix lines (e.g.,
ATK +5 +8) now render in the sigil's stat color instead of the rarity color — matches the socket gem and icon color.
[v0.5.98] — 2026-05-29
Added
- Stat-specific sigil icons: each of the 5 stat types now has a distinct rune icon — ATK (chevron Λ), DEF (triple bar ≡), WARD (concentric rings), AGI (staggered speed lines), HP (compass rose / cardinal ticks). Icons appear in inventory, hub item lists, and ground loot.
StatKind::MaxHealth: new stat type for HP sigils. Wires throughEquippedStats→add_player→ playermax_health.- 15 named sigils with per-stat, per-rarity names: Warbrand/Deathmark/Ashen Seal (ATK), Ironmark/Bulwark Brand/Stoneheart Seal (DEF), Nullmark/Aetherveil/Voidbrand (WARD), Swiftmark/Phantom Brand/Wraithseal (AGI), Bloodmark/Sanguine Brand/Soul Seal (HP).
sigil_stat_color(stat)function in inventory.rs for use in socket rendering (Step 3).
[v0.5.97] — 2026-05-29
Fixed
- Warrior Shield Charge collision (Option A): charge movement is now fully client-authoritative, using the same
try_move/ axis-separated collision as walking. The server retains only game-effect responsibilities: breakable smashing (via current client-reported position) and enemy knockback/stun. This eliminates all wall clip-through and stuck-in-wall bugs — the client's collision is already battle-tested at walking speeds and handles edge walls correctly.
[v0.5.96] — 2026-05-29
Fixed
- Warrior Shield Charge collision: reverted strict wall approach (which prevented charging near any wall); now uses the original permissive edge-wall logic but sub-steps each tick's displacement into 3 × 2px steps, preventing
map_blockedtiles (canals, platforms) from being skipped at charge speed.
[v0.5.95] — 2026-05-29
Fixed
- AetherCore icon: legendary gold outer ring (thinner, r=13), mid-aether-pink inner ring, aether-pink core, void-purple center. Cardinal marks in dark aether pink.
- Warrior Shield Charge collision: charge no longer clips through dungeon walls. Switched from permissive edge-wall logic (harmless at walking speed but unsafe at 6 px/tick) to strict
Tile::Walldetection with a per-tick whitelist of tiles the hitbox already occupies, so the charge can exit adjacent wall tiles without aborting immediately.
[v0.5.94] — 2026-05-29
Fixed
- Sigil stats in inventory stat panel: equipped gear sigil bonuses now count toward ATK/DEF/MDEF/AGI totals displayed in the inventory loadout panel.
- VoidStone icon: bottom shadow brightened (was near-black, now visible mid-purple); top facet toned down; gem shifted down for better vertical centering.
- AetherCore icon: redesigned as arcane medallion — gold outer disc with dark-gold cardinal engravings, void purple ring, aether pink inner disc, bright center glow.
[v0.5.93] — 2026-05-29
Fixed
- Sigil stats not applying on equip:
load_equipped_statsnow sums sigil values alongside item affixes, so a weapon with a +13 sigil correctly adds all 23 points when equipped. - Stat display format: item affixes now render as
ATK +5(stat name first) everywhere — inventory detail panel and hub item inspect. Sigil bonuses follow inline in their rarity color. - VoidStone icon: redesigned as a deep purple faceted gem with cleaner pixel steps, upper highlight facet, sparkle spot, and shadowed lower half. No longer uses Common gray.
- AetherCore icon: redesigned with void purple hex shell and aether pink energy ring + bright center core. Two-color hardcoded palette.
- Aether Forge hint: walking up now shows
A: AETHER FORGEinstead of[COMING SOON]. /mailtovoid_stone / aether_core / sigil: console commands now support gifting the new item types.
[v0.5.92] — 2026-05-29
Added
- Sigil drops: chests now roll sigils (Rare/Epic/Legendary only, gated by portal mode — Unstable=Rare only, Stable=Rare/Epic, Empowered=all three). Chance scales with chest quality (10%/15%/20%).
- Aether Core crafting:
CraftAetherCoreserver handler — validates 100 Aether + 1 Void Stone in bag, consumes them, produces and saves an Aether Core, responds withAetherCoreCrafted. - Apply Sigil service:
ApplySigilserver handler — costs 25 Crux Ingots, removes sigil item from bag, fills the first empty socket on the target item with aSigilEntry, responds withApplySigilResult. - Remove Sigil service:
RemoveSigilserver handler — costs 25 Crux Ingots, rolls survival (Rare 50%, Epic 65%, Legendary 80%), clears socket, optionally returns sigil item to bag, responds withRemoveSigilResult. - Empowered queue gate: entering Empowered mode now validates presence of 1 Aether Core at queue-join and consumes it at dungeon launch (same pattern as Stable's 20 Aether gate).
- Aether Forge UI (
hub.rs): newForgeStateoverlay; A near Veyra's forge opens main menu with Craft Aether Core / Apply Sigil / Remove Sigil. Each path has its own sub-screen (cost confirm, item picker, sigil picker, socket picker) using the standard full-screen overlay pattern. PoiKind::AetherForge: new variant inhub_map.rs;hub.jsonupdated from"poi"to"aether_forge"; POI label rendered in violet.- Sigil display in item detail: filled sockets now show their rarity color instead of an empty dark square. Affix lines show inline sigil bonuses in the sigil's rarity color (e.g. "ATK +5 +3" where "+3" is blue for a Rare sigil).
stat_name()helper: exported frominventory.rsfor use in hub.rs forge screens.
[v0.5.91] — 2026-05-28
Fixed
- Enemy death on proximity: enemy-enemy and enemy-player separation pushes now check
map_tilesforTile::Wallin addition tomap_blocked. Previously, only canal/chest/breakable tiles were inmap_blocked; dungeon wall tiles were not, so a separation push near a wall could move an enemy into it, triggering the void-tile safety kill on the next tick. - Bag sort consistency:
sort_bag()is now only called inInventoryState::new()and theLoadQuickSlothandler. Removed rogue calls from unequip (hub), trade buy,remove_item_by_id,restore_item, and the dungeon displaced-item safety net — all now append to end of bag without re-sorting.
[v0.5.90] — 2026-05-28
Fixed
- Vault deposit routing (root cause):
VaultContentsnow sends two separate lists (vault1,vault2) instead of a flat list. Previous fix routed deposits server-side correctly but the client's count-based split was reassigning vault 2 items back into vault 1 whenever vault 1 wasn't full. Eliminatedsplit_vault_itemsentirely. - Vault hint text consistency: empty vault 2
Nonebranch now says"L2/R2: VAULT"matching all other branches (was"L2/R2: SWITCH VAULT").
Changed
- Vault Upgrade zone repositioned: moved to the center of the bottom half of the Iron Vault area (was near top-left corner). Fallback map updated to match.
- Vault Upgrade tile color: new copper-amber color (kind 11) distinguishes the 2×2 upgrade zone from surrounding iron vault floor tiles.
[v0.5.89] — 2026-05-28
Fixed
- Deposit routes to active vault: items now deposit into whichever vault (1 or 2) is currently selected, instead of always going to Vault 1.
VaultDepositmessage now carriesvault_num; server routes to the correct vault slot and enforces per-slot capacity. - Deposit mode slot count: count below vault grid now shows bag inventory (
n/capacity) when in Deposit mode, and vault count when in Withdraw mode. - Vault refresh on tab switch: switching from Deposit → Withdraw now immediately fetches fresh VaultContents from the server, so newly deposited items appear without needing to close and re-enter the vault.
- M009 DB migration: adds
vault_slotcolumn tovault_items(existing rows default to slot 1); items are now stored with an explicit vault-slot tag so Vault 1 and Vault 2 are cleanly separated in the database.
[v0.5.88] — 2026-05-28
Fixed
- Vault slot borders: empty slots now use inventory-matching dim border
[42,48,65]; slots beyond vault capacity (locked) draw nothing — no border at all. Matches inventory style exactly. - Vault button mapping: L1/R1 always toggles DEPOSIT/WITHDRAW tab; L2/R2 switches between Vault 1 and Vault 2 (only active when tier ≥ 2). Removed the X shortcut added in v0.5.87.
Added
- Bag slot count in inventory:
{used}/{total}displayed below the bag grid, matching the vault count position. Red when full, green otherwise.
[v0.5.87] — 2026-05-28
Added
- Vault expansion system: IronVault now starts at 15 slots (was 30). Walk into the
vault_upgradevendor zone inside the Iron Vault area and press A to purchase upgrades — Tier 1 expands Vault 1 to 30 slots, Tier 2 unlocks a second 15-slot vault, Tier 3 expands Vault 2 to 30 slots. Each upgrade costs 100 Crux Ingots and must be purchased sequentially. - Vault 2 switcher: when both vaults are unlocked (tier ≥ 2), L1/R1 switches between Vault 1 and Vault 2. X cycles DEPOSIT/WITHDRAW tab. Single-vault players keep L1/R1 for tab switching as before.
- Vault number indicator: replaces the old hardcoded count in the vault header; slot count moves below the item grid.
- M008 DB migration: on server startup, vault items in positions 16–30 (by insertion order) are moved to the mailbox so existing players aren't silently over-capacity after the vault size reduction.
vault_upgradePOI: 2×2 walk-in zone inside the Iron Vault area on both the authored hub map and the fallback map.
[v0.5.86] — 2026-05-28
Fixed
- Warrior charge range: charge now uses the same permissive wall collision as normal walking — stops at the same distance from walls instead of 1 tile early.
- Sprint stamina drain: stamina no longer drains while holding B and standing still; drain only occurs when actually moving.
[v0.5.85] — 2026-05-28
Fixed
- Wall collision — normal movement: reverted client collision to permissive behavior (edge walls with at least one floor neighbor are passable). Players can hug walls the way they used to; only deep-interior walls block.
- Warrior charge — water overshoot: charge uses strict wall collision (any wall tile stops it), preventing the sprite from overshooting through wall boundaries into canal/water tiles.
[v0.5.84] — 2026-05-28
Fixed
- Quick slot top-off: when topping off a quick slot that already holds some of a consumable type, the server now drains from all matching bag stacks (largest first) until the slot is full, rather than only from the specific item the cursor was on. Smaller stacks no longer get silently consumed while a larger stack sits untouched.
[v0.5.83] — 2026-05-28
Fixed
- Client wall collision: client now blocks on any non-Floor/Door tile, matching the server exactly. Previously only "deep interior" wall tiles blocked movement, letting the player drift partially into edge walls — this caused the server's charge collision to fire on parallel charges near walls.
- Warrior Shield Charge — wall abort: charge now immediately sets timer to 0 on a full block instead of draining in place one tick at a time.
- Inventory — sync_from re-sort:
sync_fromno longer callssort_bag()every frame. Equip swaps stay in-place across frames; chest loot appends to the end of the bag rather than jumping to its id-sorted position.
[v0.5.82] — 2026-05-28
Changed
- Balance — Warrior damage: 1.0× → 1.25× (stronger single-target presence)
- Balance — Skirmisher damage: 1.2× → 0.8× (per-hit nerf to offset multi-target reach on basic attack and spin)
[v0.5.81] — 2026-05-28
Fixed
- Warrior Shield Charge — wall-slide: charge no longer runs in place when moving parallel to (or directly into) a wall. Axis-separated fallback now skips axes with no movement so fully-blocked resolves correctly.
Changed
- Inventory — equip swap: displaced item stays at the same bag position (no re-sort on equip swaps).
- Warrior Shield Charge — breakables: charge now smashes any breakable (barrel) in its path, clearing it and rolling a normal drop.
[v0.5.80] — 2026-05-28
Fixed
- Inventory — quick slot equip position: loading a potion or food into a quick slot no longer moves the item in the bag. Partial stacks stay at their original position; cursor is restored by item id after the server roundtrip.
[v0.5.79] — 2026-05-28
Changed
- Inventory sort: bag items now sort oldest-to-newest (by acquisition order / item id) with no slot grouping. Items stay in acquisition order across equip swaps, pickups, and drops.
- Dungeon timings: Unstable 6 min total (2 min lock + 4 min collapse); Stable 12 min total (4 min lock + 8 min collapse); Empowered 18 min total (6 min lock + 12 min collapse).
[v0.5.78] — 2026-05-28
Fixed
- Crucible — currency stack overflow: smelt outputs now create additional stacks (up to
stack_maxeach) instead of silently capping/discarding the excess. Smelting 20+ items no longer loses fragments over 100. - Dungeon crucible withdraw — stack merge: withdrawn currency now merges into existing run_bag stacks (respecting
stack_max) rather than appending as a separate item. Fixes 134-ingot phantom stacks. - Inventory — equip swap position: bag sort now uses a stable sort by slot group only (no secondary sort by item id). Displaced items stay at the same bag position rather than jumping to the first slot in their group.
- Warrior Shield Charge — wall slide: charge now uses axis-separated collision, allowing the charge to slide along a wall when moving parallel to it. Previously any wall adjacency stopped the charge entirely.
[v0.5.77] — 2026-05-27
Fixed
- Inventory — equip swap cursor: when displacing an equipped item, the cursor now follows the displaced item to its sorted bag position so you can see where it landed. Previously the cursor was restored to the old position (showing a different item), making the swap appear to go to an unexpected slot.
[v0.5.76] — 2026-05-27
Fixed
- Town crucible — progress bar animation: bar now advances smoothly every frame via local client interpolation (corrected by server heartbeat). Previously the bar only jumped every ~350ms, appearing frozen.
[v0.5.75] — 2026-05-27
Added
- Town crucible — anti-storage cleanup timer: closing the crucible overlay with items still inside (queue, current, or output) starts a 10-minute server-side cleanup timer. Re-opening the overlay before it expires cancels the timer. If the timer reaches zero, all crucible contents are silently deleted. This prevents the crucible from being used as extra bag space between dungeon runs. Items in queue/output are lost — same commitment mechanic as the dungeon crucible.
[v0.5.74] — 2026-05-27
Fixed
- Town crucible — tab switching: L/R D-pad no longer switches tabs; L1/R1 now cycle DEPOSIT ↔ WITHDRAW (consistent with vault).
- Town crucible — progress bar: server now sends
TownCrucibleUpdateheartbeat every ~350ms (7 ticks) while an item is smelting, so the progress bar advances smoothly on the client. - Town crucible — output tag: output items now show
xN DONEwith quantity (matching dungeon crucible format) instead of plainREADY. - Town crucible — hint bar: updated hint to read
L1/R1:TAB.
[v0.5.73] — 2026-05-27
Added
- Town crucible — queue model: Town crucible now matches the dungeon crucible exactly. DEPOSIT tab: select items from bag one at a time (A to queue). WITHDRAW tab: view current smelting item + queue + ready output; A withdraws all output items. L/R cycle tabs; X toggle pause/resume; B close.
- Town crucible — personal instances: Each player gets their own private crucible session (
hub_id-keyed on server). No item sharing or theft between players. Output items are flushed to DB on disconnect. - Town crucible — 50% tax preserved:
produce_smelt_outputs_taxed()applied at each item's smelt completion inhub_tick_loop. - Dungeon crucible — item description in right panel: DEPOSIT tab shows hovered item name/slot/rarity/affixes/description. WITHDRAW tab shows same description + progress bar for the currently smelting item. QUEUE and DONE counts removed.
Fixed
- Crystal Ball — toast position: "Pondering Orb" sweep-bar toast moved from bottom of screen to the same vertical zone as the "HOLD SELECT TO EXTRACT" ring (
fh/4 + 24). - Crystal Ball — X hotbar cooldown: X slot now shows a clock-sweep cooldown overlay while the 60s orb cooldown runs down. Was always blank after channeling.
- Crystal Ball — icon color: Orb is now faint blue-white (RGB 210,225,255) with deeper blue depth tint and white shine. Was rendering yellow/gold (was using rarity color instead of fixed orb color).
[v0.5.72] — 2026-05-27
Added
- Item description field —
description: Option<String>onItem(serde default = None; no DB migration). Rendered in the inventory detail panel as word-wrapped gray text below the sockets section. - SOUL BOUND tag in detail panel — teal label shown for any soul_bound item.
- Crystal Ball description — "X: Reveal portal & crucible (15s). 60s cd." shown in its detail panel.
/mailto <character> <slot> <rarity>— generate and mail any gear item by slot+rarity (e.g./mailto rian staff legendary). Uses the same affix/augment/weapon-variant rolling as chest loot.
[v0.5.71] — 2026-05-27
Added
- Crystal Ball — Legendary soul-bound Tome (
/mailto <character> crystal_ballto deliver). Soul-bound items survive death: equipped items re-equip, bag items return to bag. Server re-saves them afterclear_equipped_items/clear_bag_itemson death. - Crystal Ball ability — X button (5s channel while moving). "Pondering Orb" sweep-bar toast while casting. On completion: offscreen portal and crucible indicators appear for 15 seconds regardless of discovery state. 60s cooldown.
- Crystal Ball icon — Procedural orb/pedestal icon (distinct from book Tome icon). Rendered in inventory equip/bag panels.
- Soul-bound drop protection (dungeon) — Dropping a soul-bound item from the inventory shows "ITEM WILL BE PERMANENTLY DELETED" confirmation modal. On confirm the item is removed from the game; server skips ground-loot placement.
/mailtoconsole command —sudo rpg98then/mailto <character_name> crystal_balldelivers the item to the character's mailbox (accessible at the Bounty Board).find_character_by_name— New DB helper for case-insensitive character lookup by name.soul_bound: boolfield onItem—#[serde(default)]— no DB migration needed; existing items deserialize asfalse.
[v0.5.70] — 2026-05-27
Fixed
- MENU button closes game in dungeon:
tick_dungeonhad its ownKey::Menu → RequestLogout → Quithandler left over from before MENU was globally claimed for the bug report overlay. MENU press was quitting the dungeon before the overlay could open. Handler removed — logout is via Start menu only.
[v0.5.69] — 2026-05-27
Fixed
- Bug report overlay — input bleed-through: D-pad/button events were reaching the game state (hub/dungeon) while the overlay was open, causing visible movement. All state-machine input is now suppressed when the overlay is active.
- Lobby ping never updating: server's
run_lobby_loopdroppedClientMessage::Pingas "unexpected" without responding. AddedPing → Ponghandler so lobby ping now updates every 2 seconds. - Hub ping N/A in bug report: hub
ping_mswas hardcoded toNonein the bug report context. Now reads the live value fromHubState.
[v0.5.68] — 2026-05-27
Changed
- Bug report overlay: SUBMIT/CANCEL buttons moved up 32px; hint text moved up 8px.
[v0.5.67] — 2026-05-27
Fixed
- Bug report overlay — cancel cooldown: closing the overlay without submitting no longer triggers a cooldown. Cooldown (60s) is now only applied after a successful submit.
- Bug report overlay — button centering: SUBMIT and CANCEL are now each centered in their respective half of the panel instead of left-aligned.
- Bug report overlay — state label over button: state name ("Hub", "Dungeon", etc.) was drawn on top of the SUBMIT button. State label removed from overlay; it's redundant since the screenshot shows context.
- Bug report overlay — hint text overlap: hint line was positioned inside the button rect (
py+ph-20), causing overlap. Hint is now drawn atpy+ph-14(below the buttons), and is drawn before the buttons so it can't overwrite them.
[v0.5.66] — 2026-05-27
Fixed
- Bug report overlay — checkbox rendering:
[and]are absent from the GLYPH_FONT used byFontSize::Medium, so checkbox indicators were invisible. Replaced text-based[ x ]/[ ]withfill_rect-drawn bordered boxes (11×11 px, teal fill when checked). - Bug report overlay — layout overlap: checkbox rows extended into the thumbnail area (ending at px+250 vs thumbnail at px+246). Tightened label position — rows now end at px+200, well clear of the preview.
- Bug report overlay — default cursor: overlay opened with SUBMIT selected; now opens with the first category (ENEMY AI) selected.
- Bug report overlay — hint/state overlap: state label and hint line were drawn at the same Y coordinate; state label moved up by 14px.
- Server player count leak (multiplayer): in the lobby queue path, if a non-host player's TCP connection dropped after the host inserted their
world_registryentry but before they enteredrun_dungeon_loop, their entry leaked permanently. Registry is now cleaned up in all lobby exit paths.
[v0.5.65] — 2026-05-27
Added
- Global bug report via MENU button: pressing the center MENU button from any game state (dungeon, hub, lobby, menus) snapshots the current frame and opens the bug report overlay. Context metadata (seed, portal mode, HP, ping, tile position, party size, class) is automatically included when available for the current state.
- Submit closes immediately: bug report submits fire-and-forget in a background thread. The overlay closes instantly; no more waiting for the server.
- Client-side rate limit: 60-second cooldown after submit (5-second cooldown after cancel) prevents overlay spam.
- Server-side rate limit:
POST /reportrejects subsequent submissions from the same IP within 60 seconds with HTTP 429. - Screenshot saves locally: Start > SCREENSHOT in the dungeon (and hub) now saves a PNG to
/mnt/SDCARD/Saves/CurrentProfile/saves/RPG98/screenshots/rpg98_<timestamp>.pnginstead of uploading. Screenshots from the bug report overlay still upload. - Hub screenshot: Start menu in the hub town now includes a SCREENSHOT option with camera-flash effect.
bug_report.rsmodule: BugReportState, BugReportContext, upload_report, submit_report, draw_bug_report_overlay, save_screenshot_local extracted into their own client module.- Updated binary report format: new context_flags bitmask replaces the old fixed metadata block. Optional fields (seed, portal_mode, HP, ping, party_size, tile_pos) are present only when applicable to the current game state. State name ("Dungeon", "Hub", "Lobby", etc.) added as a field.
- Updated HTML viewer:
GET /reportsnow shows State field and renders optional metadata rows only when present.
Removed
- BUG REPORT option from dungeon Start menu (replaced by global MENU button).
- Screenshot upload from dungeon Start menu (now saves locally).
[v0.5.64] — 2026-05-26
Fixed
- Bug report SUBMIT button invisible: button position check used
idx == 4but button indices are 6 (SUBMIT) and 7 (CANCEL), so both were drawn at the same right-side position. SUBMIT now draws on the left half of the panel. - Reports viewer Class/Portal on same line: HTML card was showing "Class: Warrior — Stable". Portal mode is now a separate row.
[v0.5.63] — 2026-05-26
Fixed
- Equipped spear shows sword icon in loadout:
draw_loadoutwas passingslot(alwaysSlot::Swordfor the weapon column inEQUIP_SLOTS) todraw_slot_iconinstead ofitem.slot. Now passes the actual equipped item's slot so spears and staves render their own icon. - Spear icon redesigned: both the 64×64 loadout icon and 32×32 floor-loot icon now show a leaf-blade spearhead (tapered point, widest in the middle, narrowing back to the shaft), socket lugs where the head meets the shaft, a long thin shaft, and a ferrule + butt spike — clearly distinct from the sword crossguard silhouette.
[v0.5.62] — 2026-05-26
Fixed
- Bug report auto-submitting on open: the A press that selected BUG REPORT from the Start menu was being consumed by the overlay on the same frame, immediately firing SUBMIT (cursor defaults to 6). Fixed with a
just_openedflag that skips input processing for one frame after the overlay is created. - Reports web viewer + Discord bot feed:
GET /reportsnow serves an HTML page with screenshot/bug-report cards (thumbnail, metadata, categories).GET /reports/feed.jsonreturns all reports as a JSON array includingpng_urlfor bot consumption.GET /reports/<file>serves individual PNGs and JSON sidecars.
[v0.5.61] — 2026-05-26
Added
- Bug report / screenshot metadata: uploaded reports now include client version, portal mode, player class, current HP, max HP, ping, party size, and tile position (x, y). All fields appear in the JSON sidecar saved to
reports/. The server log line now prints a full summary. Binary format extended with a versioned metadata block after the username field.
[v0.5.60] — 2026-05-26
Changed
- Bug report checkbox style: unchecked shows
[ ], checked shows[ x ]— wider brackets with spacing for readability. - Bug report opens with SUBMIT pre-selected: cursor now defaults to the SUBMIT button so the most common flow (check a box, submit) requires fewer presses.
- Bug report categories expanded: added NETWORK / LAG and CRASH / FREEZE to the category list (was 4, now 6). Server JSON sidecar updated with matching field names.
[v0.5.59] — 2026-05-26
Fixed
- Bug report thumbnail overlapping seed text: thumbnail was drawn after the seed text in the same y-band, causing the thumbnail pixels to overwrite the end of the seed number. Thumbnail now starts 46px from the panel top (below the seed line at py+30) so they occupy separate y regions.
- Bug report Left/Right navigation: pressing Left/Right while on the button row now moves between SUBMIT (Left) and CANCEL (Right) directly, rather than requiring Up/Down to reach them separately.
[v0.5.58] — 2026-05-26
Added
- Screenshot capture: Start menu now has a SCREENSHOT option. Pressing it captures the framebuffer at the moment Start was pressed (before the menu darkens the scene), uploads it as a raw-BGRA POST to the server (port 9878), which converts to PNG and saves to
reports/. A white border flash confirms the capture. - In-dungeon bug reports: Start menu now has a BUG REPORT option. Opens a full-screen overlay showing a 160×120 thumbnail of the captured frame, the dungeon seed, four category checkboxes (Enemy AI / Item-Loot / Visual / Other), and Submit/Cancel. Upload runs on a background thread; overlay shows UPLOADING… then SENT! or FAILED for 2 seconds before auto-closing.
POST /reportserver endpoint: HTTP server on port 9878 now accepts bug report and screenshot uploads. Body is a custom binary format (magic + dimensions + seed + categories + BGRA pixels). Server converts BGRA→RGBA, saves PNG + JSON sidecar toreports/on the DO VPS.- Dungeon seed in DungeonMap:
seed: u64added toDungeonMapand set by the server at generation time. Used in bug reports; previously the seed was local to the lobby function and not accessible to clients. - Start menu "LOG OUT" label: renamed from "EXIT GAME" to match the actual behavior wired up in v0.5.57.
- Dynamic
draw_menu: menu panel height now scales with the number of options rather than being hardcoded for 4 items.
[v0.5.57] — 2026-05-26
Fixed
- Dungeon logout leaves ghost player taking damage: using Start → Exit Game (or Escape) from inside a dungeon now sends a
RequestLogoutmessage to the server before closing the TCP connection. The server immediately removes the player from the world and persists run items, bypassing the 30-second reconnect window that previously kept the ghost alive and vulnerable until it expired.
[v0.5.56] — 2026-05-26
Fixed
- "Unknown Armor" chest drops: Ability Tomes (
Slot::Tome) were incorrectly eligible for armor set names in chest loot generation —set_piece_namehas no Tome entry and would return the catch-all"Unknown Armor". Addedslot != Slot::Tomeguard to the chest lootset_nameeligibility check (enemy drop version was fixed in v0.5.55).
[v0.5.55] — 2026-05-26
Fixed
- Displaced bag expansion item not visible in dungeon inventory: when equipping a Backpack/Sash/Pouch over an already-equipped one in a dungeon run, the old item (displaced back to bag) could fail to appear in the inventory grid during the same session. Added a defensive check after
apply_equip_result— if the displaced item is not already ininv.bag, it is pushed in. The item was always persisted server-side (visible at hub entry); this was a display-only gap.
Changed
- Bag expansion dungeon rarity floor raised to Epic: Sash/Pouch/Backpack now require Epic rarity to drop from enemies or chests (previously Rare). In Unstable mode (max Rare) they never drop at all. Stable mode can yield Epic versions with stat affixes; Empowered mode can yield Legendary versions with extra slots. Common versions remain exclusively from Crowe's Tradehouse.
[v0.5.54] — 2026-05-26
Added
- Crowe's Tradehouse: New hub POI interaction at the Tradehouse. Pressing A opens a vendor screen selling Common Leather Sash (40 Crux Ingots), Leather Pouch (40 Crux Ingots), and Leather Backpack (80 Crux Ingots). Purchase deducts ingots from bag, adds item directly to bag, shows inline feedback.
PoiKind::Tradehouseadded;hub.jsonupdated. - Legendary bag expansion bonus: Legendary-tier Sash and Pouch now grant +10 slots (up from +5); Legendary Backpack grants +20 slots (up from +10).
bag_slots(self)now takes rarity as an argument and all call sites updated. - Bag expansion overflow protection: Server now rejects
UnequipItemif removing the item would leave more bag items than the new capacity. Server also rejects equipping a lower-tier bag expansion item that would shrink capacity below current bag count. Client shows a toast on rejection. - Live bag capacity update: Equipping or unequipping a bag expansion item in the hub now immediately updates the visible slot count in the inventory overlay without needing to close and reopen it.
UnequipRejectedmessage: New server message type carrying a reason string for rejected unequip attempts.- Trade messages:
RequestTradeList,BuyTradeItem,TradeListContents,TradeBuyResult,TradeBuyFailed, andTradeItemstruct added to shared crate.
Changed
- Bag expansion items in dungeons now minimum Rare: Sash/Pouch/Backpack dropped from enemies or chests are floored to Rare rarity. Common versions are sold exclusively at the Tradehouse.
- Bag expansion icon colors: At Common rarity, Sash (tan), Pouch (orange-brown), and Backpack (olive) use slot-specific warm colors instead of generic gray. Rare+ still use normal rarity colors.
- Inventory slot borders refined: Empty usable slots now have a more visible border (brighter steel-blue tint). Locked beyond-capacity slots use a subtler muted plum border instead of the more stark rose-pink.
[v0.5.53] — 2026-05-26
Fixed
- Bag expansion gear not taking effect mid-run: equipping a Sash/Pouch/Backpack during a dungeon run now correctly updates
bag_capacityon both the server (PlayerEntry) and the client (DungeonState). Previously the capacity stayed at the dungeon-entry value until the next run. - Locked inventory slots now visually distinct: slots beyond current bag capacity now render with a dark rose/pink border instead of the near-invisible dark grey border.
[v0.5.52] — 2026-05-26
Fixed
- Chest loot bag overflow: "Loot All" and "Loot Selected" now respect bag capacity. Items that don't fit are returned to the chest and the popup re-opens showing only the leftovers with a "BAG FULL" banner and a red border. Stackables still merge into existing stacks for free; only genuinely new slots are counted against capacity.
[v0.5.51] — 2026-05-26
Added
- Bounty Board mailbox: New POI interaction at the Bounty Board in the hub. Pressing A opens a full-screen mailbox overlay showing unclaimed items sent by the server. Players can claim items one at a time (A: claim, B: close). Shows sender name and per-item message. Handles bag-full gracefully (shows "BAG FULL" inline, item stays in mailbox).
- DB migration M007: On server startup, any character with more bag items than their current bag capacity has the overflow moved to the mailbox automatically. Items arrive with a "Returned from inventory — bag size was reduced in v0.5.49" message. This migrates testers who had 100+ item inventories before the 10-slot cap was introduced.
- General mailbox infrastructure:
mailbox_itemsSQLite table;add_mailbox_item,list_mailbox_items,claim_mailbox_item,mailbox_item_countDB functions;RequestMailboxandClaimMailboxItemclient messages;MailboxContents,MailboxClaimResult,MailboxClaimBagFullserver messages;MailboxEntryshared struct. PoiKind::BountyBoard: New POI kind inhub_map.rsso the Bounty Board can be distinguished from genericPoimarkers (proximity hint and label color updated).
Fixed
- Phantom pickup bug: Items were being removed from the ground and the
LootRemovedbroadcast sent to all clients before the server checked whether the picking-up player had bag space. If the check then failed, the item was re-added server-side but no newLootDroppedwas sent, leaving it invisible on every client's screen. Fix: capacity check now runs first; only on success are the item removed andLootRemovedbroadcast.
[v0.5.49] — 2026-05-26
Added
- Inventory expansion gear: Sash (+5 slots), Pouch (+5 slots), Backpack (+10 slots) — equippable items that increase bag capacity; all classes can use them; Common versions are sold at the Tradehouse (currency sink), Rare+ versions drop in dungeons with affixes
- Dynamic bag capacity: base 10 slots; cap scales with equipped expansion gear up to 30 max; slot count per item is fixed, rarity affects affix quality only;
bag_capacityfield onPlayerEntry,EquippedStats,InventoryState;EquippedContentsmessage now carriesbag_capacity - Bag grid capacity display: slots beyond current capacity render as locked (very dark, dim border) rather than open empty slots; usable empty slots shown normally
- BAG FULL notification: server rejects pickup when
non_qs_count >= bag_capacityand sendsBagFullTCP message; client shows "BAG FULL" in red centered on screen for 2 seconds - Sash/Pouch/Backpack slot icons: pixel-art icons added to both
draw_slot_icon(64×64) anddraw_slot_icon_floor(32×32); visual identity: sash = horizontal band with clasp, pouch = drawstring bag, backpack = rectangular pack with straps - Loadout navigation: Sash/Pouch/Backpack slots at x=476 are now functional LOADOUT entries (indices 8/9/10), linked into D-pad navigation from Shield and Tome slots
Fixed
slot_group()inInventoryState::new()now coversSlot::Sash | Slot::Pouch | Slot::Backpack(group 2, sorted before currency)slot_to_str()indb.rscovers new bag expansion slots ("sash","pouch","backpack")- Hub drop detail panel covers new bag expansion slots with
"Bag Expansion"type label - Empty quick-slot color references resolved (was referencing removed
exp_bg/bdr/colvariables from deleted placeholder code)
[v0.5.48] — 2026-05-25
Added
- Class restriction label in item detail panel: items that are class-locked now show
Class: Warrior/Class: Skirmisher/Class: Arcanistin amber text below the rarity line; covers staves (always Arcanist), Epic+ swords (Warrior only), Epic+ spears (Skirmisher only), and all named armor/shields (Rare+)
Fixed
- Arcanist shield equip: Arcanists were incorrectly blocked from all shields; Common/Uncommon shields are now universal; Rare+ shields are class-locked via
set_name(same logic as named armor) - Named shields in loot: Rare+ shields now roll a
set_nameand get class-appropriate names (Ironclad Bulwark, Voidguard Aegis, etc.) and contribute toward their set's 5-piece completion
[v0.5.47] — 2026-05-25
Added
- ArmorSet system: 6 named armor sets (Ironclad, Voidguard, Shadowthread, Voidstitched, ArcanicMantle, Stoneweave), one per class per rarity tier (Rare/Epic/Legendary); 5-piece completion required for any bonus; mixing same-archetype rarities awards the lowest rarity's tier
- Class-restricted sets: Rare+ armor with a
set_namecan only be equipped by its owner class (can_equipenforced in both hub and dungeon equip handlers;EquipRejectedmessage carries fullItemback for client restore) - Rare set bonuses: flat stat buffs per set — Ironclad +phys_def, Voidguard +magic_def, Shadowthread +attack, Voidstitched +agility, ArcanicMantle +magic_def, Stoneweave +attack
- Epic set bonuses: Ironclad — successful block builds an absorb shield equal to damage blocked; Voidguard — (deferred, PvP-gated); Shadowthread — at max combo step (3) a hit holds at step 3 instead of wrapping; Voidstitched — basic light bleed proc restores 15 stamina; ArcanicMantle — Arcane Ward retaliatory bolt fires on ward absorb (wired in
ai.rs); Stoneweave — bolt kill reduces Void Shift cooldown by 15s - Legendary set bonuses: Ironclad — block reduces damage by 45% (up from 30%); Voidguard — Second Wind also fills 20% max HP as damage shield; Shadowthread — combo decay slows to ~3s between steps; Voidstitched — bleed proc chance raised to 50% (from 33%); ArcanicMantle — Arcane Ward grants 4 charges (from 2); Stoneweave — bolt hit restores 8 damage shield
- Biased affix rolling: named sets use
set_stat_priority()— primary identity stat always rolls first, guaranteeing thematic identity even at Rare - 30 named set pieces: each of the 6 sets has unique item names per slot (e.g. Ironclad Greathelm, Voidguard Mantle, Shadowthread Hood)
EquipRejectedserver message: carries fullItemback to client so optimistically-removed items are restored on rejection; hub shows reason text, dungeon silently restores to bagpeek_bag_item(): read-only DB lookup by item id used for hub pre-check beforeequip_item()is called
Changed
StatKind::DefenseFlatrenamedPhysDefense;StatKind::MoveSpeedrenamedAgility(DB migration M006)
[v0.5.46] — 2026-05-25
Fixed
- Unarmed attack dead zone: A-button releases in the 120–500ms window were silently dropped; any release under 500ms that didn't auto-fire a heavy now correctly fires a light attack
Changed
- Class-weapon restrictions: Arcanist cannot equip Sword or Spear; Warrior and Skirmisher cannot equip Staves; enforced server-side in both hub and dungeon equip handlers
[v0.5.45] — 2026-05-25
Added
- Weapon slot split:
Slot::Weaponreplaced bySlot::Sword,Slot::Spear,Slot::Staff; all share one physical equip slot viaequip_key(); DB migration M005 auto-renames existing rows - DamageType:
Physical(Sword/Spear) andMagical(Staff + arcane bolt); tracked onItemandPlayerEntry;#[serde(default)]ensures old DB items deserialize safely - Server-authoritative stamina: class base pools (Warrior 100, Skirmisher 130, Arcanist 75); Agility affix adds +2/point; sprint 15/s, block 8/s, regen 10/s (0.5s delay, half-rate exhaustion recovery); momentum abilities cost 40% class base;
stamina/stamina_maxsent in every snapshot - Equipment-gated attacks: armed attacks use class-specific behaviors (Arcanist bolt, Skirmisher multi-hit/spin, Warrior cone/charge); unarmed attacks always available as class-neutral punch (light) and kick (heavy) at base damage with no modifiers; walk animation cycles briefly on unarmed attack
- Shield mechanics:
Slot::Shieldmust be equipped for R1 to activate; block stance drains stamina at 8/s; shield auto-drops on exhaustion; server gates all combat suppression checks onhas_shield - Live equip stat refresh: equipping an item mid-dungeon now immediately updates server-side combat stats (attack, defense, weapon type, has_weapon, has_shield, agility) — previously these only applied at run entry
EquippedStatsstruct: replaces the growing tuple returned byload_equipped_stats; fields:attack,phys_def,magic_def,agility,weapon_dmg,has_weapon,has_shield
Changed
- StatKind:
DefenseFlat→PhysDefense,MoveSpeed→Agility; DB migration M006 auto-renames existing affix rows; inventory and hub UI updated with new labels - Momentum ability costs: hardcoded
50.0replaced byclass.stats().momentum_cost()(40% of class base stamina) on both server and client - Stamina REGEN constant: corrected client-side prediction from 15/s to 10/s to match server
[v0.5.44] — 2026-05-25
Fixed
- Void Shift emerge animation: sprite now rises head-first from the ground (mirror of the sink). Top rows of the sprite appear at foot level and move upward as more body is revealed, fading in from opacity 60 to 128 (ghost level). Previously the feet appeared first.
- Arcane lightning position: reverted the 16px downward shift from v0.5.43; kept the 150% size increase.
- Enemy patrol frozen during Arcanist ghost phase:
in_rangecheck now uses a proximity list that includes ghosted players, and patrol runs unconditionally when not chasing. Enemies no longer freeze for the duration of the ghost. - Enemies don't move after Void Shift aggro-clear:
patrol_timeris now reset to 0 on aggro-clear so enemies immediately pick a new patrol destination.
[v0.5.43] — 2026-05-25
Changed
- Arcanist arcane lightning size: increased from 125% to 150% scale (96×144px on screen). Anchor shifted 16 logical pixels lower to keep the effect centered on the enemy.
[v0.5.42] — 2026-05-25
Fixed
- Enemies freeze during Arcanist Void Shift ghost phase: when all players were ghosted,
player_centerswas empty, causing the AI loop tocontinuebefore reaching the patrol branch.in_rangecheck now uses a separateplayer_proximitylist that includes ghosted players, and the aggro/chase block is wrapped inif let Some(nearest)so patrol runs unconditionally when!is_chasing. - Enemies don't pick new patrol target after losing aggro to Void Shift: the aggro-clear loop in
combat.rsnow resetspatrol_timer = 0so enemies immediately choose a new patrol destination instead of waiting out a potentially long timer.
[v0.5.41] — 2026-05-25
Changed
- Knockback wall bounce: replaced wall-slide fallback with vector reflection. When a knockback landing is blocked, the helper tests each axis independently to determine whether the X or Y component (or both, for a corner) hit a wall, then reflects that component and retries. Enemies now bounce off walls at the opposite angle rather than sliding along them. Falls back to current position only if the bounce destination is also blocked.
[v0.5.40] — 2026-05-25
Fixed
- Enemy knockback lands in walls/void: all four knockback sites (Arcanist chain lightning, Skirmisher spin, Warrior/Skirmisher heavy attack, Shield Charge) now use a shared
is_valid_landinghelper that checks bothmap_blockedand floor tile validity. Heavy attack and Shield Charge include a wall-slide fallback (try X-only, then Y-only) before giving up and leaving the enemy in place. - Shield Charge has zero knockback collision check: the charge loop previously set
enemy.x/y = land_x/yunconditionally with no wall or floor check at all. Now validated with the same wall-slide logic as other knockback sources. - Knockback re-trigger: all knockback sites now skip enemies with
kb_arc_timer > 0— an enemy mid-arc can't be knocked again by any source until they land. - Shield Charge multi-hit: the charge applied knockback/stun every tick it was active, hitting the same enemy repeatedly. The
kb_arc_timer > 0guard prevents re-hitting the same enemy on subsequent charge ticks. - Enemy escapes dungeon (last-resort): each AI tick now kills any enemy whose tile is non-floor (void or wall). Guarantees loot drops even if an enemy slips past the landing checks. Runs before normal AI so it's silent.
[v0.5.39] — 2026-05-25
Fixed
- All momentum abilities escape dungeon bounds: Shield Charge, Echo Step, and Void Shift BFS all checked
map_blockedfor collision, but void tiles outside dungeon rooms are not in that set — they're simply absent. Added a floor tile validity check (Tile::Floor | Tile::Door) alongside the blocked check for all three. Void Shift BFS now skips void tiles entirely during pathfinding; Echo Step and Shield Charge stop movement when any tile in the swept path is non-floor.
[v0.5.38] — 2026-05-25
Fixed
- Void Shift snap-back to origin (CRITICAL): the UDP position gate only blocked client position inputs during the sink phase. When the teleport fired (
sink_timer == 0), the gate opened immediately and the server processed buffered client inputs that still carried the pre-teleport position, overwriting the destination. Gate now also blocks during the emerge phase.
[v0.5.37] — 2026-05-25
Fixed
- Void Shift camera flash: the camera lerp divisor was left at 20 after the timer was reduced to 10, causing the camera to jump 75% of the way to the teleport destination on the very first frame. Now correctly divides by 10.
- Void Shift sink opacity fade: sprite now fades from fully opaque to ~24% opacity (never invisible) as it descends and clips, making the disappearing effect more visually prominent alongside the position shift.
[v0.5.36] — 2026-05-25
Fixed
- Void Shift stuck-after-teleport (CRITICAL): the teleport detection and position hard-sync were nested inside the
input_log.find()block — if the server'sack_seqhad no matching entry (common under packet delay), the teleport was never acknowledged client-side. The player's local position stayed at the pre-teleport tile and the camera never panned, leaving the player visually and physically stuck. These now run on every received snapshot, independent of input log matching. - Void Shift camera pan not triggering: same root cause as above — the camera lerp start was also gated on
input_log.find(), so the camera never panned to the teleport destination when acks were out of sync. - Void Shift animation sync: sink and emerge durations reduced from 15 to 10 ticks (~0.33 s each). Camera pan reduced from 20 to 10 ticks to match, so the camera arrives as emerge completes — you now see the re-emergence rather than appearing at the destination after the camera catches up.
- Void Shift sink visual: restored original descend-plus-clip approach (sprite moves down while bottom is masked at ground level — feet disappear first). The "out of sync" perception was that at 15 ticks the per-frame change was too small to read; at 10 ticks both the descent and the clip are large enough per frame to feel simultaneous.
[v0.5.35] — 2026-05-25
Changed
- Void Shift destination uses BFS pathfinding: the teleport target is now found via a breadth-first search across walkable tiles, ensuring the Arcanist always lands on reachable open ground. The previous ray-cast approach could fail in tight corridors; BFS naturally navigates around corners and picks the best reachable tile up to 10 tiles away (preferring the facing direction).
- Void Shift sink/emerge animation: instead of a plain fade, the Arcanist now visually sinks into the ground (sprite shifts down while the bottom is clipped, feet-first) over 0.5 s. On re-emergence, the sprite grows upward from the ground at 50% ghost opacity over another 0.5 s.
- Void Shift camera pan: when the teleport fires, the camera smoothly pans to the new position over ~0.67 s using a quadratic ease-out, rather than snapping instantly.
[v0.5.34] — 2026-05-25
Added
- Void Shift (Arcanist B double-tap): the Arcanist sinks underground over 0.5 s, then teleports up to 10 tiles in the facing direction (smart obstacle avoidance tries all 8 directions and picks the longest clear path). On emergence all enemies targeting the Arcanist lose aggro. The Arcanist then enters a 3-second ghost state (50% opacity) during which enemies cannot detect them unless attacked. Costs 50% stamina, 15-second cooldown.
Changed
- Hotbar slot styling standardized: all ability slots (A, AA, X, Y, B) are now plain gray squares with a black clock sweep for cooldowns — no colored backgrounds for active states. The blue border trace on the AA slot while A is held charging is unchanged. The B slot now shows the correct per-class cooldown: Shield Charge (Warrior), Echo Step (Skirmisher), Void Shift (Arcanist).
Fixed
- Inventory cursor jump on equip: after equipping an item, the cursor was tracking the displaced item to its sorted position instead of staying at the slot the player was on. Cursor now restores to the same visual flat index after the equip completes.
[v0.5.33] — 2026-05-25
Fixed
- Party invite loop: a player could invite the person who had already invited them (effectively re-inviting someone already in the same party). The
InviteToPartyhandler now silently drops invites when the sender and target are already in the same party, or when the target is already in any party. - Echo Step tunneling through chests/walls: the Skirmisher's B double-tap dash could clip through solid tiles when the step distance (16 px) equaled the tile size. The wall collision check is now a swept AABB that tests all tiles in the bounding box spanning the full movement arc, not just the destination corners.
[v0.5.32] — 2026-05-25
Fixed
- Inventory shuffle on item changes: items now stay in a stable, predictable order (weapons first, then armor, then consumables, then currency — each group sorted by item ID). Items no longer appear to jump around when one is removed; only the affected slot shifts.
- Equip flash in dungeon: the equipped item stays visible in the bag while the server round-trip is in flight. The slot only updates when
EquipResultarrives, eliminating the 1–3 frame gap where the bag looked like it was missing an item.
[v0.5.31] — 2026-05-25
Added
- Dungeon reconnect: when the TCP connection drops mid-run, the client shows a "Reconnecting..." countdown overlay (20 s) and retries every second. The server keeps the player's world slot alive for 30 s; on successful reconnect the player is wired back in without losing any run state. If the window expires on either side, normal disconnect handling kicks in. Session token is used to authenticate the rejoin. Only applies to unexpected drops — death and extraction still clean up immediately.
[v0.5.30] — 2026-05-22
Added
- Lobby ping display: the waiting room now shows a live RTT indicator in the top-right corner. A
Ping/Ponground-trip is sent every 2 seconds; the result is color-coded green (<100 ms), yellow (100–299 ms), or red (≥300 ms). Pong is now also handled inside the dungeon loop on the server (was missing).
Changed
- Stun visuals differentiated by class: Warrior stuns show only the
!exclamation mark; Arcanist stuns show only the electric yellow pulse glow. Previously both effects appeared for every stun type. - Enemy death animation revised (3 phases): rotation + knockback run simultaneously for 0.5 s, then the sprite desaturates to grayscale over 0.5 s, then fades to transparent over 0.5 s. Previously the body faded directly to black.
Fixed
- Dungeon Crucible stability: replaced several
HashMap[]index panics and bareunwrap()calls in crucible deposit/withdraw/retrieve handlers with safeif let Some(...)patterns. Added per-handler server logging to aid future diagnosis. - usize subtraction underflow: crucible
QUEUE_MAX - input_len()now usessaturating_subto avoid a panic when input exceeds the max.
[v0.5.29] — 2026-05-22
Changed
- Enemy death animation rework: replaced squish effect with a 90° rotation around the enemy's feet. Enemies facing east or north fall counter-clockwise; west or south fall clockwise. Rotation takes 0.65 s (was 0.35 s squish), fade-out takes 0.55 s (was 0.45 s) — slower and more readable overall.
[v0.5.28] — 2026-05-22
Added
- Enemy death animations: when an enemy dies, it falls sideways with a squish effect (upright → flat over 0.35 s), inheriting knockback velocity so the body lands at the loot drop position, then fades out (0.45 s). Facing direction is derived from knockback arc direction or server-authoritative facing. Visible to all players.
- Arcanist chain lightning: heavy attack (charged A) now damages up to 2 additional nearby enemies within 64 px at 60% damage each, in addition to the primary target. Targets chosen by proximity (nearest first).
- Stunned enemy glow: enemies affected by Arcanist stun now pulse with a yellow silhouette glow (electric yellow, sin-wave pulsing).
- Arcane lightning animation scaled up 25%: spell impact animation renders at 2.5× instead of 2×, keeping it visually centered on the impact point.
[v0.5.27] — 2026-05-22
Added
- Echo Step (Skirmisher B double-tap): Skirmisher dashes ~4 tiles in facing direction, ignoring enemy bodies (walls still stop it). Costs 50% stamina, 15 s cooldown. Spawns a semi-transparent decoy at the origin that persists for 3 s and pulls enemy aggro — nearby enemies treat the decoy as a valid target and converge on it instead of chasing the player. Decoy visible to all players in the run.
[v0.5.26] — 2026-05-22
Changed
- Shadow Mend reduces enemy aggro range: while Shadow Mend is active, enemies' detection range is halved (25% of the normal area), making it much harder for enemies to notice the Skirmisher during the buff.
[v0.5.25] — 2026-05-22
Changed
- Shadow Mend rework (Skirmisher Y): removed speed boost and stamina recovery. Added 1.5 s shadow fade window at activation (50% DR). Visual effect now lasts the full 8 s — sprite renders as a black semi-transparent silhouette for the entire buff duration. HP regen unchanged (50% over 8 s). Effect visible to other players.
[v0.5.24] — 2026-05-22
Fixed
- Second Wind glow visible to teammates: glow effect was only rendered for the local player. Now also drawn on remote Warrior players when their
ability_activeflag is set in the snapshot.
[v0.5.23] — 2026-05-22
Added
- Second Wind glow (Warrior): while Second Wind is active, a red silhouette of the player sprite is drawn behind the normal sprite at ~1.18× size, pulsing in scale and opacity at ~1.5 Hz, creating a red aura effect.
[v0.5.22] — 2026-05-22
Fixed
- L1 targeting not picking nearest enemy: cycle list was in snapshot order (enemy spawn order), so the first L1 tap with no target could lock onto a distant corner enemy. Both the quick-release and gesture-tap paths now sort visible enemies by distance to the player before cycling, so the first tap always lands on the nearest one.
[v0.5.21] — 2026-05-22
Changed
- Update screen changelog: now shows the last 5 version entries instead of just the latest one, so players updating across multiple versions can see the full recent history. Version headers render in blue, section headers in green, bullets in grey.
[v0.5.20] — 2026-05-22
Fixed
- Items blocked by off-screen enemies: enemy hitbox list for client-side movement was built from all alive enemies in the snapshot, including ones far off-screen. An enemy elsewhere in the dungeon could coincidentally block movement onto a loot tile. Now only enemies within 160px (10 tiles) of the player contribute hitboxes.
[v0.5.19] — 2026-05-21
Fixed
- Enemy collision — player getting stuck: restored client-side enemy hitbox computation (was accidentally passing an empty slice) and added server-side enemy→player separation force that pushes enemies away from player hitboxes each tick, preventing overlap from accumulating. Client escape hatch (already-overlapping = can always move out) is preserved.
[v0.5.18] — 2026-05-22
Changed
- Warrior charge animation: shield walk frames now cycle at 24fps (3× normal) during the charge instead of using the static walk rate, giving a fast scrambling-forward feel.
[v0.5.17] — 2026-05-21
Changed
- Warrior charge animation: player now renders with the shield-walk sprite sheet during the charge (same as
R1hold), matching the "charging with shield out" description.
Fixed
- Enemy HP bars during knockback: bars were drawn at the landing position while the sprite was mid-arc. Now uses the same arc-interpolated position (including parabolic rise) as the sprite draw pass.
[v0.5.16] — 2026-05-21
Fixed
- Warrior charge — player bounce-back: displacement-based reconciliation was double-adding the server-driven movement, causing the client to shoot past the charge endpoint. During a charge (
e.charging == truein snapshot), the client now hard-syncs position directly from the server instead of computing displacement. - Warrior charge — player exits dungeon: wall collision only checked the sprite top-left corner tile; the right edge of the player hitbox (at
nx+24) passed through boundary walls. Now checks all 4 hitbox corners (PHB_L/R/T/B) againstmap_blocked.
[v0.5.15] — 2026-05-21
Fixed
- Warrior charge trigger never fired:
process_attackswas latchingprev_action_flags2 = action_flags2at its end, thenprocess_chargeran immediately after — so both values were already equal and the rising-edge check (cur != 0 && prev == 0) could never pass. Fixed by moving the latch to the top of each player's iteration insideprocess_charge, using the true previous-tick value for edge detection.
[v0.5.14] — 2026-05-21
Added
- Warrior B double-tap charge ability: double-tapping B triggers a forward charge at 3× sprint speed (6 px/tick) for 3 tiles, then decelerates over 2 tiles. Requires ≥50 stamina. 10-second cooldown (300 ticks). Any enemy within 2 tiles of the charge path is knocked back 64px in the charge direction (2× Warrior heavy-attack knockback) and stunned for 3 seconds. The B hotbar slot shows charge cooldown for Warriors, with an orange flash while the charge is active. Server drives position during the charge — client position updates are suppressed.
action_flags2field added toPlayerInput(bit 0 = charge trigger);charge_cooldownandchargingadded toEntityStatesnapshot.
[v0.5.13] — 2026-05-21
Fixed
- Enemy flanking (revised again): soft-obstacle A* alone failed when a second group spawned from the same area — all enemies still found the same path since no one was blocking it yet. Added a stable directional preference per enemy based on
id % 8: while more than 4 tiles from the player, each enemy aims for an offset position 3 tiles away in one of 8 directions (N/NE/E/SE/S/SW/W/direct). Within 4 tiles, enemies switch to the player tile directly so they reliably enter attack range. Soft-blocking A* is kept as a third layer for enemies that share the same directional slot.
[v0.5.12] — 2026-05-21
Fixed
- Enemy flanking (revised): replaced the per-tick ring-tile assignment system (which caused constant goal oscillation as sort order changed, resulting in enemies bouncing between 2 tiles) with a simpler A* soft-obstacle approach. Each enemy now treats all other living enemies' current tile positions as soft obstacles when repathfinding. Because every enemy has a unique set of obstacles to route around, they naturally find different paths to the same goal (the player) and approach from spread directions.
[v0.5.11] — 2026-05-21
Fixed
- Enemy flanking — no more single-file approach: chasing enemies now get assigned unique ring tiles around the player as their path goal, so groups spread out and approach from different directions. Nearest enemies claim ring-1 (adjacent) positions first; rings 2 and 3 handle overflow for large groups (covers up to ~48 simultaneous enemies). Enemy attack range is unchanged — enemies still close to overlap range to land hits, they just arrive from different angles.
- Light attack near-clip fix: the forward attack box previously started 8px ahead of the player center (
REACH=20 - HALF=12), so enemies overlapping or very close to the player fell behind the near edge and couldn't be hit. Box is nowREACH=14, HALF=14— near edge starts at player center (0px), far edge at 28px, 28px wide. All hit-count rules preserved (Warrior=1, Skirmisher=up to 3). Heavy attacks (AoE radius / Arcanist cone) are unaffected.
[v0.5.1] — 2026-05-21
Fixed
- L1 quick targeting — no more dropped cycles: L1 cycle now fires on raw
InputEvent::Release(if it was a short tap, <150ms, no hold or double-tap) instead of waiting for the gesture detector'sTapevent 120ms later. Thel1_cycle_consumedflag prevents the gesture Tap from double-firing, and the flag resets on each new L1 press so subsequent taps always work.
[v0.5.0] — 2026-05-21
Added
- Skirmisher multi-target basic attack: light attack now hits up to 3 enemies in range, with 33% chance per hit to apply bleed. Damage per hit is reduced (0.7× base) so single-target output sits below Warrior, but multi-target hits and bleed procs make it feel strong overall.
Fixed
- Dungeon input reliability — all one-shot actions:
attack_pressed,heavy_attack_pressed,ability_pressed,potion_pressed,food_pressed, andstamina_pressedare now latched for 3 frames instead of clearing after a single UDP packet. At 30fps client + 30Hz server tick there was a ~50% chance any given press was missed; the latch window guarantees the server tick sees the flag regardless of phase alignment. - Defensive ability (Y) 120ms gesture delay eliminated: Y now fires on raw
InputEvent::Pressinstead of waiting for the gesture detector's double-tap window to expire (which cost 120ms of dead time since Y has no double-tap action). Response is now immediate. - Combo mash penalty using edge detection: the server now tracks
prev_action_flagsand only applies the mash penalty on a0→1transition of the attack bit. This prevents the latch frames of a legitimate press from being misread as a new mash and collapsing the combo. - Skirmisher spin ends facing starting direction: client spin animation was using a step-timer that only produced 3 rotations in 15 ticks (stopping one direction short). Now mirrors the server's
% 4 == 0logic for exactly 4 rotations, returning to the original facing. - Blood drop icon centered over enemy: bleed debuff icon was offset 8px right (leftover stun-icon offset). Now centered on the enemy sprite.
[v0.4.113] — 2026-05-21
Fixed
- Quick slot stack shuffles to end of inventory: when topping off a quick slot from a partial stack in the bag, the server was deleting the bag row and re-inserting the remainder, pushing it to the bottom. The leftover is now updated in place via
UPDATE bag_items, preserving its position in the inventory list.
[v0.4.112] — 2026-05-20
Fixed
- Quick slot items refilling after extraction: the server was intentionally consuming stash items before the quick slot item when processing potion/food use, so the QS item survived the run with its original amount and was always restored at full count. The preference is now inverted — the server consumes the specific QS item first (by ID) and only falls back to stash items once it's depleted, matching what the player sees in the quick menu.
[v0.4.111] — 2026-05-20
Changed
- Pickup hint shows combat state: when near a loot item with enemies aggroed, the hint below the player now reads "A: COMBAT BLOCKED" in dimmed red instead of "A: PICK UP", making the restriction immediately visible without pressing anything.
[v0.4.110] — 2026-05-20
Fixed
- Inventory cursor jumps after equipping: when equipping an item in the dungeon (especially the last item in the bag), the cursor would snap to the wrong row/column because
sync_fromruns beforeEquipResultarrives and callsclamp_bag_cursoron the now-smaller bag — recalculating col/row from a clamped flat index that lands at a different grid cell. Nowpending_equip_flatrecords the exact flat index at the moment A is pressed;apply_equip_resultuses it to insert the displaced item at the original slot and moves the cursor there withset_cursor_to_flat.
[v0.4.109] — 2026-05-20
Fixed
- Combat pickup suppression now truly aggro-based: added
chasing_player_id: Option<u32>toEnemyStatein the UDP snapshot so the client knows exactly which enemies are aggroed on it. Client-side pickup suppression now checkse.chasing_player_id == Some(player_id)— identical to the server check — replacing the incorrect proximity fallback from v0.4.108.
[v0.4.108] — 2026-05-20
Fixed
- A button locked out during combat near loot: client was sending
PickupItemwhen any ground loot was in range, settinginteracted = trueand preventing the attack timer from arming — even when the server rejected the pickup. Client now checks for living enemies within aggro range (120px) before attempting pickup; if enemies are present, A falls through to attack.
[v0.4.107] — 2026-05-20
Fixed
- Blood drop icon redesigned: circular base (8px wide) with a narrow triangular peak connecting at the equator (widest point), tapering to a 2px tip — true teardrop silhouette.
- Combat pickup block broken by dead enemies: enemies keep
is_chasing = trueafter dying (they stay in the Vec withhealth = 0), so the aggro check was always firing. Addedhealth > 0.0guard so only living enemies block pickup.
[v0.4.106] — 2026-05-20
Fixed
- Aether consumed on queue back-out: Stable run cost (20 Aether) was deducted when entering the lobby queue. It is now deducted only when the dungeon actually launches, so backing out of the waiting room is always free. Balance validation still happens at queue join so an insufficient-aether rejection is shown immediately.
- Accidental item pickup during combat: Ground items can no longer be picked up while any enemy has the player aggroed. The server tracks which player each enemy is targeting and rejects
PickupItemrequests during active combat. Pickup becomes available again as soon as enemies leash (no re-aggro in LEASH_RANGE), so all classes — including Arcanist fighting at range — are covered without proximity hacks.
[v0.4.105] — 2026-05-20
Fixed
- Bleed icon orientation: teardrop now has narrow point at top and wide round bulb at bottom (6px wide body, rounded top tip, rounded bottom corners), matching a true blood-drop shape.
- Dungeon crucible scroll area: increased visible rows from 8 to 12 in both the deposit and withdraw lists, using the full available vertical space.
- CruxFragment display overflow: amount badge rendered as
x:for stacks of 100 due to 3-byte digit buffer overflow; extended to 4 bytes with proper 3-digit branch. - CruxFragment stacking overflow: picking up fragments when an existing stack had no room to fit all of them silently dropped the remainder; excess now correctly spills into a new stack slot.
[v0.4.104] — 2026-05-20
Fixed
- Enemy facing during attack: enemies always faced the direction they were walking when they first entered attack range, then never updated. The server now tracks a
facingfield on each enemy (updated every tick from movement direction and, critically, from the direction to the target player while in attack range). The snapshot sends it to clients, which now use it directly instead of deriving facing from position delta.
[v0.4.103] — 2026-05-20
Fixed
- Equip swap losing displaced items: if the server's
EquipResultarrived after the client's 500ms read window had timed out,poll_serverwas consuming and silently discarding it on the next tick. This caused displaced items (old leggings, old gloves, etc.) to never appear in the bag, or to appear at the wrong position after a subsequent equip consumed the buffered result out of order.EquipResultandUnequipResultare now handled directly inpoll_serverso they're always applied regardless of timing.
[v0.4.102] — 2026-05-20
Fixed
- Skirmisher spin animation now visible: sprite direction was driven by
direction(updated by movement input) rather thanfacing(updated by spin logic). Added a post-movement sync that mapsfacing→Directionduring spin so the sprite actually rotates clockwise while the attack plays. - Bleed icon corrected: teardrop is now right-side up (bulb at top, narrow point at bottom), more bulbous (8px wide body vs 4px before), and properly centered at 14px tall.
[v0.4.101] — 2026-05-19
Fixed
- Bleed icon size and centering: the red teardrop icon above bleeding enemies was too small (8px) and misaligned. Resized to 14px tall (matching the stun
!height) with a proper centered teardrop shape — narrow tip, wide body, rounded base.
[v0.4.100] — 2026-05-20
Added
- Version number on all screens: version string now visible (muted grey, bottom-right) on the main menu, login, and register screens, in addition to the preflight screen.
[v0.4.99] — 2026-05-20
Fixed
- Version number visible: version string on preflight screen was drawn in a near-invisible dark colour; now rendered in a readable muted grey.
[v0.4.98] — 2026-05-20
Added
- Skirmisher spin attack: Skirmisher heavy attack (double-tap A) is now a distinct spin move — full 360° AoE, 55px reach (vs Warrior's 40px), lighter knockback, plus a bleed debuff that ticks damage every second for 10 seconds. The player sprite visibly spins clockwise for ~0.5s, visible to all clients on screen.
- Bleed debuff icon: a red teardrop icon appears above enemies currently bleeding, offset to the right of the stun
!so both can show simultaneously. - Warrior heavy attack cone: Warrior charged attack is now a 180° forward cone — only enemies in the facing half-plane are hit. Effectively identical reach but rewards directional play.
- Strict client version enforcement: server now rejects any client not matching the exact deployed version. Outdated clients are shown the update screen immediately on login rather than entering a broken game state.
Fixed
- Dungeon crucible stack overflow: ingots and aether produced by the dungeon crucible could accumulate beyond the 100-item stack cap. Outputs are now capped to
stack_max()on each smelt cycle.
[v0.4.97] — 2026-05-19
Added
- Enemy attack animation: enemies lurch ~8px toward the player when they strike — a sine-arc offset that peaks and returns over ~270ms, with walk frames cycling at double speed during the lurch. Broadcast via the UDP snapshot so all clients on screen see it simultaneously.
- FOUND wheel pings: sending "I found a portal!" or "I found a crucible!" via the chat wheel now unlocks the corresponding offscreen indicator for all teammates who receive the message.
[v0.4.96] — 2026-05-19
Added
- Dungeon crucible offscreen indicator: a discovery-gated orange-red triangle appears on the screen edge pointing toward a dungeon crucible once the player has seen it. Replaces the incorrect hub-side indicator shipped in v0.4.95.
Changed
- Quick chat wheel "FOUND": renamed from "LOOT". Replaced "Good loot here", "Leaving loot", and "Take it" with "I found a portal!", "I found a crucible!", "I found a chest!", and "Loot over here!".
- Chat wheel brightness: normal (unselected) segments brightened so the wheel reads clearly against the dark modal background while the highlighted slice remains distinct.
- Dungeon crucible smelt times: ~40% faster across all rarities. Formula divisor raised from 3 to 5; fragment remainder coefficient lowered from 3 to 2. Typical Rare: ~17s (was ~31s), Epic: ~27–47s (was ~45–81s), Legendary: ~76–91s (was ~2m 8s–2m 33s).
- Dungeon timer position: shifts down when the server shutdown banner is active so the two don't overlap.
Fixed
- v0.4.95 crucible indicator correction: the indicator in v0.4.95 was attached to the hub Town Crucible (always visible) instead of the dungeon crucible. Hub indicator removed; dungeon indicator added with proper discovery gate.
[v0.4.95] — 2026-05-19
Added
- TCP disconnect detection: hub and dungeon now detect a dropped TCP connection (server shutdown or network loss) and immediately boot the player back to the main menu instead of silently freezing.
- Server shutdown preflight status: server writes
updates/status.jsonon startup (clean) and during/shutdowncountdowns. Client reads it during preflight and on main menu — PLAY/SIGN UP are locked and a banner readsSERVER SHUTTING DOWN -- LOGINS DISABLEDwhen a shutdown is in progress. - Dungeon crucible default tab: defaults to WITHDRAW when items are pending/queued/ready, DEPOSIT when empty.
- Dungeon crucible hit markers: damage flash (red corner indicators) now renders correctly over the crucible UI overlay.
Changed
- Loot rebalancing (Stable/Empowered): Common rarity slightly decreased, Uncommon/Rare increased. Enemies in Stable/Empowered modes now have a chance to drop Aether (1–3 at 25% in Stable; 1–4 at 30% in Empowered). Chest Aether yields bumped (Stable: 3–12 at 55%; Empowered: 4–16 at 60%). Stable crucible spawn restored to 40%.
[v0.4.94] — 2026-05-19
Changed
- Hub map tile colors: main menu now renders the hand-authored tile paint layer from
hub.json— all locations show their editor-painted colors instead of the old hardcoded scheme. - Main menu connectivity gates: PLAY and SIGN UP are dimmed and unselectable when the game server is unreachable. A banner at the bottom explains why:
NO INTERNET CONNECTIONorGAME SERVERS OFFLINE. - Update required is now a wall: when a mandatory update is detected, the game goes directly to the Update Required screen with no back option — update must be installed to proceed.
- Update available banner: changed from "press PLAY to see details" to "GO TO SETTINGS TO INSTALL".
[v0.4.93] — 2026-05-19
Added
- Hub map JSON: Blackthorn Hollow now loads from
assets/maps/hub.json— a hand-authored map with painted tile colors for every location (plaza, trails, buildings). Falls back to the programmatic layout if the file is missing. - Zone-entry POI activation: hub points-of-interest now require the player to physically walk onto one of the location's painted tiles to trigger the interaction prompt. Previously activated within a radius.
[v0.4.92] — 2026-05-19
Added
- Preflight screen: on startup, a dedicated full-screen check runs before the main menu — verifies update server, game server (with ping latency), controller, and audio. Auto-advances once all checks resolve (or 15 s timeout). Resolves the Flip issue where the update check failed silently on first boot because WiFi wasn't yet up.
Changed
- Dungeon crucible UI redesign: now matches IronVault style — plain tab bar at top (DEPOSIT / WITHDRAW), active tab underlined in blue, no title box. Defaults to DEPOSIT on open. L1/R1 switches tabs. ON/OFF indicator moved to the header corner.
- Stable crucible spawn set to 100% during testing (TODO: restore to ~35% before release).
- Update check retries: manifest fetch now retries up to 3 times with a 4 s gap before giving up, so slow WiFi at boot no longer causes a missed update notification.
- Version bumping:
release_do.shno longer auto-increments the patch version. Setclient/Cargo.tomlmanually before running the script to avoid phantom "update available" on newly-updated clients.
Fixed
- Y ability cooldown sweep: the hotbar sweep now animates during the active buff phase, not only after the buff expires. The Y slot shows a green tint while the buff is running.
- Updater B button: B now works to cancel during the Checking phase and to dismiss on the Done/Failed screens.
[v0.4.88] — 2026-05-19
Added
SAFE_DISCONNECTflag: disconnecting mid-run saves items back to bag (no loss). SetSAFE_DISCONNECT = falseinserver/src/network.rsbefore release to enforce the extraction loop.
[v0.4.85] — 2026-05-18
Changed
- Mode-gated rarity drops: rarity is now capped by portal mode. Unstable: Common/Uncommon/Rare only (65/25/10%). Stable: adds Epic (61/25/10/4%). Empowered: full table including Legendary (60/25/10/4/1%). Applies to both enemy drops and chest loot.
- Stable chest aether doubled: Stable and Empowered chests drop 2–10 Aether (was 1–5 for all modes).
[v0.4.84] — 2026-05-18
Changed
- Per-mode dungeon loot scaling: all spawn parameters now live in a single per-mode table in
generate(). Stable dungeons use chest types 3–5 (Unstable uses 0–2, Empowered 5–7), 5 max chests (up from 3), enemy cap 35 (up from 20), barrel density 2.0/room (up from 1.5), 2 barrel type variants.max_chest_typeparameter removed fromgenerate(). - Stable crucible spawn restored to ~35%: was set to 100% during testing.
[v0.4.83] — 2026-05-18
Fixed
- Aether multipliers off by one:
aether_multiplier()was Common=0…Legendary=4 instead of the intended Common=1…Legendary=5. This caused Uncommon items to yield the same aether from the dungeon crucible as the taxed town crucible (both 1), making the tax-free dungeon crucible feel identical to the town one. Now dungeon gives 2× aether vs town's 1× for Uncommon items, scaling up from there. - Stable portal always shows cost: the portal selection screen showed "NEED AETHER" instead of "20 AETHER" when you couldn't afford Stable. Cost is now always visible.
[v0.4.82] — 2026-05-18
Fixed
- Player ID collision across dungeon worlds: enemies and players shared the same
next_idcounter perGameWorld, so a dungeon with 16 enemies would give the player id=17. Two concurrent runs could produce identical player IDs, causingWorldRegistryto silently overwrite one entry. This meant one player's UDP inputs routed to the wrong world — their character froze server-side while enemies caught up and attacked from what appeared to be off-screen. Fixed by introducing a globalAtomicU32counter for player IDs so they are unique across all worlds. Enemies keep a world-local counter since they are never in the registry.
[v0.4.81] — 2026-05-18
Added
- Off-screen portal indicator: a purple edge arrow appears when the extraction portal is off-screen, using the same triangle indicator system as teammates. The arrow only appears after the player has seen the portal on-screen at least once — it has to be discovered first.
[v0.4.80] — 2026-05-17
Changed
- Smelting 3× faster:
smelt_duration_secsdivides by 3 across the board — gear and currency smelt much quicker. - Crucible timer display: timer now formats as
Xm00sfor durations ≥ 60 seconds, preventing garbled characters from 3-digit second values. - Crucible hint bar:
A:ACTreplaced with context-aware labels —A:TAKEwhen cursor is on a DONE or QUEUED item (or a paused smelting item),A:---when the smelting item is actively processing and can't be retrieved. - Output rows show quantity: DONE items now display
xN DONEon the right side so you can see the stack size at a glance.
[v0.4.79] — 2026-05-17
Changed
- Dungeon Crucible redesign — unified Manage/Deposit UX: replaced the two-panel BAG/OUTPUT layout with two distinct modes. Manage mode shows a single unified list: currently smelting item (with inline progress bar), queued items tagged "QUEUED", and output items tagged "DONE". Deposit mode shows smeltable bag items for depositing. Switch modes with X; retrieve queued items or withdraw done items with A; Y toggles on/off; B closes.
- Crucible item retrieval: queued (unprocessed) items can be retrieved back to the bag at any time from Manage mode. The currently smelting item can only be retrieved when the crucible is paused (Y to pause first).
- Added
DungeonCrucibleRetrieveclient message for returning items from crucible to bag.
[v0.4.78] — 2026-05-17
Added
- Dungeon Crucible on/off toggle: X button in the crucible UI pauses or resumes smelting. When off, the timer freezes and the progress bar, item name, and "SMELTING" label grey out; the timer reads "PAUSED". The right-panel header shows "SMELTING ON" (green) or "SMELTING OFF" (grey).
[v0.4.77] — 2026-05-17
Changed
- Dynamic dungeon grid sizes: dungeon generation now uses per-mode dimensions via thread-local state. Unstable stays 64×64. Stable is now 96×96. Empowered is 128×128. Room counts and max room size also scale up with each mode. Position clamping in
ai.rsandcombat.rsnow usesworld.map_width/map_heightinstead of the old shared constants.
[v0.4.76] — 2026-05-17
Changed
- Dungeon Crucible UX: removed two-step A-to-select + X-to-confirm. A now immediately deposits the highlighted bag item or withdraws the highlighted output item. X is gone. Hint bar and sub-header updated.
- Dungeon Crucible output stacking: smelted outputs (Ingots, Fragments, Aether) now merge into existing stacks in the output tray instead of creating separate items per smelt.
Fixed
- Dungeon Crucible progress bar frozen: server now sends a
DungeonCrucibleUpdateheartbeat every 10 ticks (~333ms) while smelting is active and a player has the UI open, not only when an item finishes.
[v0.4.75] — 2026-05-17
Changed
- Per-mode dungeon timings:
GameWorldnow storesportal_mode; the tick loop computes portal lock and collapse window from it. Stable: 4 min lock + 6 min collapse (was 2.5+2.5 shared). Empowered: 5+10 min (placeholder). Unstable unchanged at 2.5+2.5.
[v0.4.74] — 2026-05-17
Fixed
- Dungeon crucible deposit not reflecting in BAG panel: after depositing items, the client's local run_bag was never updated — items remained visible in the BAG panel as if nothing happened. On
DungeonCrucibleUpdate, the client now strips any items that the server reports as being in the crucible (current + queue) from its locald.run_bag.
[v0.4.73] — 2026-05-17
Fixed
- Bag wipe on logout after extraction: after a successful extraction, the dungeon disconnect handler was calling
overwrite_bag_itemswith an empty list (becauserun_bagis cleared at extraction time), wiping the player's saved loot. Equipped loadout was unaffected because it's a separate table. Fixed by skipping the bag write in the disconnect handler whenextracted_notifiedis already set.
[v0.4.72] — 2026-05-17
Added
- Stable dungeon Aether gate: Stable mode now costs 20 Aether to enter. Portal select reads the player's bag on open and shows the Stable row as "20 AETHER" (amber) when affordable, or "NEED AETHER" (locked) when not. Pressing A on Stable opens a confirmation overlay ("SPEND 20 AETHER? / YOU HAVE: N") before sending
EnterQueue. Server deducts 20 Aether from bag on receipt ofEnterQueue { Stable }and rejects withEnterQueueFailedif the player somehow lacks funds. ServerMessage::EnterQueueFailed { reason }— server sends this when a queue entry is rejected due to insufficient currency; client closes the portal select and shows the reason in the feedback banner.
[v0.4.71] — 2026-05-17
Added
- Dungeon Crucible: server-side crucible object placed inside dungeons (0% Unstable, ~35% Stable, 100% Empowered). Items stay in the crucible during smelting — not in the player's bag — so they persist even if the depositing player dies or leaves. Sequential FIFO smelting, taxless, one player at a time (mutex via
in_use_by). - Dungeon Crucible UI: full-screen overlay in
client/src/dungeon.rs. BAG panel for selecting and depositing smeltable run bag items; OUTPUT panel for selecting and withdrawing smelted results. Right panel shows current item + progress bar, queue depth, and output count. L1/R1 switches panels; A selects; X deposits or withdraws; B closes and releases the lock. DUNGEON_CRUCIBLE_QUEUE_MAXconstant inshared/src/lib.rs(15 slots) — referenced by both client capacity check and server handler.- Crucible render in dungeon world: 2×2 tile placeholder block rendered in the Y-sorted draw pass; amber label; slightly lighter when the player has the UI open.
Changed
- Town Crucible button label:
X:PROCESS→X:SMELT; in-progress status text:PROCESSING→SMELTING
[v0.4.70] — 2026-05-17
Added
- Beta download page:
/betaroute on rpg98.com (hidden from nav) with install instructions for Onion OS, Allium, and stock Miyoo Linux; updated controls reference - Beta packaging script:
package_beta.shbuilds and zips the ARM release intorpg98-beta.zipfor distribution
Fixed
- Icon broken on Miyoo Mini Flip and Allium:
config.jsonicon field used an absolute Onion-specific path (/mnt/SDCARD/Icons/Default/app/rpg98.png) which doesn't exist on other OSes; changed to relativeicon.png - Client crash on Flip when launched from menu: stock Miyoo Linux launcher injects
LD_PRELOAD=libssgfx.sointo the process environment;launch.shnow runsunset LD_PRELOADbefore starting the binary - launch.sh not cross-OS: previously sourced Onion-specific
stop_audioserver.shunconditionally; now conditional on the file existing
Changed
- Roadmap phase statuses updated: Phase 2 and 4 marked Complete, Phase 5 marked In Progress
- launcher/ directory:
config.jsonandlaunch.share now repo files;release_do.shanddeploy.shuse them instead of inlining
[v0.4.66] — 2026-05-17
Added
- Teammate panel always visible in dungeon: top-right panel now shows whenever other players are present in the run, driven by
WorldSnapshot.entitiesrather than pre-formed party data — matchmade solo-queue teammates show up automatically - HP bars in teammate panel: each row shows a green→yellow→red HP bar below the player name, sourced from
EntityState.health / max_health
Fixed
- IronVault overflow past 30 slots:
merge_vault_itemcreated a new overflow row without checking capacity, allowing >30 items when a stackable deposit partially filled existing stacks. Overflow row creation now gates oncount_vault_items < VAULT_CAPACITY
[v0.4.64] — 2026-05-17
Added
- Death reason on death screen: death screen now shows the cause of death below "YOU HAVE FALLEN" —
SLAIN BY MON-XXXfor enemy kills,CLAIMED BY THE COLLAPSEfor dungeon collapse; server sets reason at kill site and passes it throughDeathResult
[v0.4.62] — 2026-05-17
Added
- Unequip in Loadout tab: pressing A on an occupied equipment slot in the hub Loadout screen sends
UnequipItemto the server; the item moves to bag. Hint showsA:UNEQUIPwhen a slot has an item and inventory is not in-run
[v0.4.61] — 2026-05-17
Added
- Dungeon timer: 2.5-minute portal lock phase followed by a 2.5-minute collapse window. Timer displayed top-center at all times (
OPENS IN M:SS/EXTRACT M:SS). Portal cannot be activated during the lock phase (server-enforced). On collapse, all remaining players receivePlayerDiedand lose everything they carried - Proximity hints below player sprite: loot and chest interaction hints now draw directly below the local player sprite in
Smallfont with a 1px drop shadow, instead of at the top of the screen in the largerMediumFullfont
Fixed
- Targeted enemy HP bar removed: top-right enemy HP bar conflicted with the party panel; removed. Enemy HP bars on-sprite are sufficient
[v0.4.60] — 2026-05-17
Fixed
- IronVault full but stackable items blocked: capacity check fired before attempting to merge into existing partial stacks. Depositing fragments (or any stackable) into a full vault now succeeds as long as an existing non-full stack of the same type exists — no new row is needed, so the cap doesn't apply
[v0.4.59] — 2026-05-17
Added
- Warrior heavy attack slash animation: 3-frame
slash01_0sprite plays on heavy attack fire (0.225s); visible to all players in the dungeon; gated on cooldown so animation only fires when the server will actually process the attack
Fixed
- Potions not healing:
p.potionswas always initialized to 0 at dungeon entry regardless of how many potions were in the player's bag.process_potionsgates onp.potions > 0, so all potion uses were silently rejected. Potions are now counted fromrun_bag(initial stash + quick slots) at dungeon entry - Quick-use items replenished on extraction: extraction path used
merge_bag_itemon top of intact pre-run DB rows, restoring consumed potions to their pre-run count. Extraction now usesoverwrite_bag_items, matching the disconnect path - Client crash on dropped TCP connection:
write_messagepanicked on TCP writes when the server closed the connection mid-combat. Now returnsbooland handles errors gracefully - Blank inventory after crash-reconnect:
clear_bag_itemsat dungeon entry created a brief empty-DB window; fast reconnect during a run showed an empty bag. Entry no longer clears; disconnect usesoverwrite_bag_itemsatomically - Stun exclamation mark hidden behind HP bars:
!y-offset corrected so it clears above the HP bar - Inventory cursor on equip: displaced item now inserted at cursor position rather than end of bag when
EquipResultarrives aftersync_fromalready removed the equipped item
[v0.4.53] — 2026-05-16
Added
- Arcanist light attack — tracking projectile: basic attack now fires an animated arcane bolt toward the L1-locked target instead of melee. Bolt steers toward the enemy each tick and expires on collision or when the target dies
- Arcanist heavy attack — Arcane Lightning: charged attack requires a locked target with line of sight; deals instant damage to the primary target plus AoE knockback and a 3-second stun (5-tile radius) to all enemies nearby
- Stun system: stunned enemies are fully frozen by AI; a yellow
!indicator appears above their heads; enemies shake horizontally (±2px, ~5 Hz) while stunned to sell the electrocuted feel - Arcane Lightning impact animation:
arcane_lightning.png(15 frames, 32×48 per frame) plays at the hit location, bottom-aligned to the enemy hitbox; broadcast over TCP so all players in the run see it blit_sprite_rotatedrenderer method: per-pixel inverse-rotation blit for the arcane bolt, which rotates to point toward its target each tick- Line of sight system: all Arcanist attacks (light and heavy) require unobstructed LoS between player and target. Ray-marched through
map_walls(canal + platforms only — chests and barrels are transparent). Blocked shot breaks the combo; off-screen target clears the lock - Projectile wall collision: arcane bolt expires immediately if its next position would enter a wall tile
- Off-screen target loss: client drops the L1 lock when the targeted enemy moves more than 2 tiles outside the viewport; server also enforces this at attack time
- Enemy density increased: dungeons now place 2 enemies per non-spawn room (was 1), capped at 20 (was 10), giving 14–20 enemies per run
- Enemy-enemy tile reservation: when a chasing enemy picks its next A* waypoint, it checks whether another enemy has already claimed that tile and waits one tick if so — prevents enemies from running directly on top of each other
- Enemy separation at rest: enemies standing at a tile center are gently pushed apart (12px effective radius, 0.25 strength) to reduce visible stacking when idle
Changed
- Enemy chase speed: 24 px/s → 45 px/s (slightly faster than player walk at 40 px/s; sprint at 60 px/s still escapes)
- Enemy patrol speed: 12 px/s → 30 px/s (2/3 of chase, mirroring the player walk/sprint ratio)
- Arcane bolt sprite: resized from 157×16 to 155×16 (5 × 31px frames) to fix a stride mismatch that caused rows to read from the wrong pixel offset
Fixed
- Arcane bolt rotation: sprite was not rotating toward its target — fixed by replacing flip-x logic with
blit_sprite_rotatedandangle = atan2(vy, vx) - Enemy AI stuck on each other: separation push was applied mid-tile-walk, fighting the tile-locked movement system and freezing enemies. Pixel-space separation now only fires when enemies are at a tile center (
target_tile == None)
[v0.4.42] — 2026-05-15
Changed
- Live inventory state: dungeon inventory no longer takes a snapshot at open time.
d.equippedis populated at dungeon entry viaEquippedContentsand updated on everyEquipResult;sync_from()keepsinv.bagin sync withd.run_bagevery frame the inventory is open. Eliminates stale-snapshot drift and the 500msRequestEquippedspin-wait on inventory open - Optimistic equip in dungeon:
EquipItemnow removes the item fromrun_bagimmediately on the client (no spin-wait);EquipResultadds any displaced item back and updatesd.equipped
Fixed
- Currency items equippable as gear: Crux Fragments, Ingots, and Aether could be accidentally equipped to gear slots, duplicating their amount.
Slot::is_gear()guard added — server rejects non-gearEquipItemrequests and restores the item torun_bag; client also skips the optimistic remove for non-gear items - Chest popup crash: if two key presses landed in the same frame while the chest loot popup was open (e.g. rapid input while being attacked), the second event would
unwrap()aNonepopup and panic. Added abreakguard at the top of the event loop - Drop quantity modal crash: same multi-event panic in the drop quantity modal; same fix applied
- Quick slot items in bag after disconnect: on client crash/disconnect mid-run, the server saved all
run_bagitems tobag_itemswith no quick slot distinction. Now uses the samepre_run_quick_slot_idslogic as extraction — QS items go back toquick_slot_items, non-QS items go tobag_items
[v0.4.38] — 2026-05-15
Fixed
- Dungeon item drop — item lost on server-side failure: when the server couldn't find a dropped item in the player's run_bag (e.g. race with equip), it sent nothing, leaving the item removed from the client's inventory and absent from the floor. Server now sends
DropFailedin this case, and the client restores the item to the run_bag and inventory display - Dungeon item drop — diagnostic logging: server now logs the full run_bag ID list when a drop fails so the exact desync can be identified
Added
DropFailedprotocol message: newServerMessage::DropFailed { item_id }that the server sends when a drop can't be processed; client uses it to recover the item instead of silently losing it
[v0.4.36] — 2026-05-15
Fixed
- Dungeon item drop — missing LootDropped: when the player dropped an item then immediately re-opened the inventory, the server's
LootDroppedreply arrived during theRequestEquippedspin-wait and was silently discarded (Ok(_) => {}). Changed to save it inpending_tcpso it is processed in the next drain loop — item now reliably appears on the floor - Dungeon item drop — movement while inventory open: D-pad inputs used for inventory cursor navigation were simultaneously updating the character's held-movement state, so the player could drift far from the drop site while browsing; dropping an item no longer looked like the item disappeared. Movement flags are now cleared whenever the inventory or drop-quantity modal is open
Changed
- Arcane Ward dome: border opacity reduced to 55% (140/255) for a softer glow feel
- Buff icon countdown text: always white for all classes (was class-coloured)
Added
- Buff icons — class abilities: each defensive ability now has a unique icon on its buff square: Warrior = shield silhouette, Skirmisher = double upward chevron (^^), Arcanist = mini dome arc with a tiny wizard silhouette inside
- Arcane Ward visibility: other players in the dungeon now see the dome on any Arcanist who has the ward active, including the two-hit vs one-hit colour dim
[v0.4.35] — 2026-05-15
Changed
- Arcane Ward dome: visual changed from full oval ring to a half-arc (top half only, opening faces ground — like a 'C' on its side); uses new
draw_arcrenderer method - Buff icon row: replaced per-class chips above hotbar with a unified icon row below the HP bar — same style as the food buff (32×32 coloured square + "Ns" countdown); slots fill left-to-right as buffs become active; supports any number of simultaneous buffs
Added
draw_arcrenderer method: draws a thick partial ellipse within an angular range; reusable for future arc-style effects
[v0.4.33] — 2026-05-15
Added
- Arcane Ward (Arcanist Y ability): 8-second defensive buff — 2-hit magical damage negation shield, 60% max HP regen over the duration
- Dome visual: oval purple ring drawn around the Arcanist in world-space while the ward is active; dims from bright to muted when 1 hit remains
draw_ringrenderer method: thick ellipse outline used for the dome; reusable for future effects
[v0.4.32] — 2026-05-15
Added
- Shadow Mend (Skirmisher Y ability): 8-second defensive buff — 50% max HP regen and 100% stamina regen distributed over the duration; also grants 1.4× movement speed while active
[v0.4.31] — 2026-05-15
Added
- Second Wind (Warrior Y ability): 8-second defensive buff — 40% damage reduction for the duration, 40% max HP regen distributed evenly across the 8 seconds
- Buff chip HUD: gold "2W" chip above the Y button when Second Wind is active, with a duration drain bar
- Character select: Y button labeled "Defense" instead of "Ability"
Changed
- Second Wind no longer heals instantly on activation; regen is spread across the 8-second window
[v0.4.28] — 2026-05-14
Added
- Quick chat wheel: L2 opens a radial wheel of 8 options; L1/R1 cycles between 3 wheels (General, Combat, Callouts); A sends the selected message
- Chat bubbles: pill-shaped bubbles appear above player heads with screen clamping so they stay visible near edges
- Off-screen chat indicators: static edge-pinned triangles point toward off-screen chatting players, colored by team with a 1px border
- Changelog on update screen: update prompts now show the latest patch notes fetched from the server manifest
- B: back to menu on update screens: both UpdateAvailable and UpdateRequired screens now allow B to return to the main menu
- Soft update block: pressing Play or Sign Up redirects to the update screen when a newer version is available; Settings and Quit still accessible
Fixed
- Hub camera centering fixed
- L1 no longer opens the player status overlay while the chat wheel is open
- Update check re-runs on Play/Sign Up press, fixing a race condition where the background check could complete before networking was ready
[v0.4.19] — 2026-05-13
Added
- Server console (
server/src/console.rs):/wholists all online hub and dungeon players;/shutdown [secs]broadcasts a countdown banner to all connected clients then exits; runs as a background Tokio task reading stdin - Shutdown banner: full-width red overlay rendered on top of all screens (hub and dungeon) showing "SERVER SHUTTING DOWN IN Xs"; persists above every overlay/modal until exit
- Server management script (
start_console.sh, deployed to/usr/local/bin/rpg98): starts or attaches to a tmux session running the server, self-updates from/tmp/rpg98_console_newon launch, applies staged binaries from/tmp/rpg98_server_new - Server-authoritative team assignment:
team_id: u8added toRosterEntryin shared; server stamps all PvE queue members withteam_id=1; client builds party list and team-color map from roster at dungeon entry instead of assuming solo = no party - Team colors: teammates above their heads now render in assigned team color with drop shadow; Blue/Yellow/Green for slots 0/1/2; Red reserved for future enemy players; constants in
dungeon.rs - Off-screen teammate indicators: small colored arrowhead triangle drawn at the screen edge (12px margin) pointing inward toward any teammate whose screen position is outside the viewport; color matches the teammate's assigned team color; rendered between entity pass and HUD so it appears on top of sprites
Changed
- Hub status overlay key: moved from R1 to L1 (hint text updated)
- Player caps: max 6 per dungeon (was 8), max 3 per team (was 4); docs and CLAUDE.md updated; example compositions now
3v3, 2v2v2, 3v2v1
[v0.4.0] — 2026-05-13
Phase 4 milestone release. All Phase 4 systems and the majority of Phase 5 multiplayer infrastructure are complete. Version bump re-syncs the version number with actual phase progress (had been incrementing 0.3.x patches through the entirety of Phase 4 and Phase 5 early work).
Complete since v0.3.0
- Account & auth system: registration, login, session tokens (30-day TTL), saved password hash (no re-entry on relaunch), always-show login screen with pre-filled credentials
- Character system: up to 3 characters per account, creator with class + sprite picker (32 sprites), delete confirmation
- Loot system: rarity tiers (Common→Legendary), random affixes, augment slots, per-player chest rolls, ground loot icons, rarity colors
- Inventory & equip: 4-quadrant icon grid (Bag/Equip/Item/Stats), procedural slot icons, equip/displace flow, drop from dungeon
- IronVault: safe bank storage in Blackthorn Hollow hub; full deposit/withdraw UI (A=full stack, Y=choose amount), 30-slot cap
- Hub drop modal: permanent item delete from bag with confirmation overlay and "never show again" checkbox
- Town Crucible: CruxFragment/Ingot conversion (50% tax), Aether output, full selection UI
- Three currencies: CruxFragment, CruxIngot, Aether — all as inventory items, no numeric counters
- Blackthorn Hollow hub: 96×96 map, 7 POIs, multiplayer (other players visible at 20 Hz), saved position
- Extraction loop: hold Select 1.5s on portal; all carried items at risk on death (drop as ground loot); IronVault is only safe storage
- Portal mode selection: Unstable (free), Stable (20 Aether, locked), Empowered (1 Aether Core, locked)
- Multiplayer queues & lobby: shared queue, waiting room, auto-start on party fill
- Party system: hub invite flow, 30s countdown queue entry, party panel HUD in hub and dungeon, auto-dissolve on run start
- In-dungeon multiplayer: other players rendered with correct sprites and name tags; dungeon party panel
- Auto-updater: 4-phase system — HTTP file server (port 9878), version enforcement at login, background manifest check, download/apply/re-exec
- Quick-slot stacking lock: pickups never stack into pre-run quick slot items mid-dungeon
[v0.3.53] — 2026-05-11
Added
- Quick slot equipping: pressing A on a consumable (HealthPotion, StaminaPotion, Food) in the inventory bag now loads it into the matching quick slot (SP=0, HP=1, FD=2) instead of trying to equip it as gear; quick slot state persists across inventory opens during a run
- Quick slots visible in loadout: loadout tab quick slot area now shows the loaded item's icon color, name, and stack count when a slot is populated; shows type label + "empty" + "A: EQUIP" hint when nothing is loaded
- Buff icons below HP bar: a green dot + "REGEN" label appears below the HP bar when a food/regen buff is active (driven by
EntityState.buffsbit 0) - Stamina potion server-side deduction: server now removes one StaminaPotion from run_bag when bit 7 (0x80) is set in action_flags (
process_stamina_potionsincombat.rs) - Optimistic run_bag deduction: using a consumable via R2 immediately decrements the item in
d.run_bagclient-side, clearing the quick slot when the stack is exhausted; stamina potions also restore 30 stamina locally on use
Changed
- Health potion heal: changed from 40% max HP (percentage) to flat 30 HP
- Food buff rate:
ChickenLegnow gives 1.0 HP/sec over 10s (= 10 HP total), down from 2.5 HP/sec - R2 strip counts: quick slot strips now show the actual stack count from
d.run_bag, coloured bright when stocked and dim when empty; guard added so consume flags are only sent when items are actually loaded EntityStategainsbuffs: u8field (bit 0 = food/regen buff active); populated from!p.active_buffs.is_empty()each tick
[v0.3.52] — 2026-05-10
Added
- Town Crucible UI (
hub.rs): blocking overlay opened by pressing A near TOWN CRUCIBLE POI; scrollable checklist of eligible stash items (CruxFragments + gear) with per-item fragment value shown; A toggles selection, X sendsProcessCrucibleto server; displays live preview of ingots/leftover-fragments after 50% tax; success/error banner; amber[35,110,185,255]border and proximity hint; B closes ProcessCrucible/CrucibleResultwire messages (shared): client sends item IDs; server atomically removes items from stash, applies 50% tax, converts (10 fragments = 1 ingot), merges produced items into stash, responds withCrucibleResult { removed_ids, produced }PoiKind::Crucibleinhub_map.rs: new variant cleanly distinguishes the Crucible POI from genericPoiin proximity checks
Changed
- Currency redesign — CruxFragment / CruxIngot split:
Slot::Cruxrenamed toSlot::CruxFragment(common drop, stacks to 999);Slot::CruxIngotadded (main spendable currency, 10 fragments = 1 ingot via Crucible);Slot::Aetheradded as rare magical essence (never lost on death) - Legacy numeric crux removed:
crux: u32andrun_crux: u32fields dropped fromPlayerEntry;initial_cruxparam removed fromadd_player();db::get_crux()anddb::set_crux()functions deleted; crux no longer persisted tocharacterstable — all currency lives instash_itemsas inventory items CharacterSummarycleaned up:crux: u32andaether: u32fields removed — both currencies are now pure inventory items; DB columns retained for M001 migration compatibility- "Compactor" renamed to "Crucible" throughout:
PoiKind::Crucible, hub POI label, CLAUDE.md, Phase 4 doc, portal modes table ("Dungeon Crucible Chance"), Phase 5 description - Hub HUD: removed stale
$NNNcrux HUD display line; HUD is now name + class (2 lines)
Fixed
filter(|(_, &s)| s)pattern inCrucibleState::preview()and input handler — changed tofilter(|(_, s)| **s)(cannot explicitly dereference within an implicitly-borrowing pattern)- Three
Itemstruct literals in test helpers (server/src/db.rs×2,client/src/inventory.rs×1) missingcrux_fragment_valuefield — addedcrux_fragment_value: 0
[v0.3.51] — 2026-05-10
Fixed
- Item ID collision across server restarts:
next_item_idpreviously reset to 1 on every server start; items saved to DB from previous sessions also had IDs starting at 1, causing newly dropped loot to alias old stash items — equipping what appeared to be a new item would instead equip a different (older) item from the initial stash that happened to share the same ID; fixed by seedingnext_item_idfrommax(all stored item IDs) + 1at startup viadb::max_item_id()
Added
- Equip debug logging: client now logs
[client] equip okor[client] equip spin-wait TIMED OUTon every equip attempt;apply_equip_resultlogs slot assignment and stash-miss warnings — aids future diagnosis of equip flow issues - Late EquipResult safety net: dungeon TCP drain now handles
EquipResultas a fallback — if the spin-wait times out before the server responds, the result is still applied when it arrives rather than silently dropped
[v0.3.48] — 2026-05-10
Fixed
- Dropped items invisible in dungeon: server now moves all stash items (not just stackables) into
run_bagat dungeon entry and clears DB stash —DropItemhandler can always find the item; previously non-stackable stash items shown in the dungeon inventory would silently vanish when dropped because the server couldn't locate them inrun_bag - Inventory order inconsistency: equipping an item now swaps in place — the displaced item takes the equipped item's exact position in both the client
Vecand the DB (equip_itemUPDATEs the stash row rather than DELETE+INSERT); dungeon server equip handler capturesbag_idxand inserts displaced at that position; dungeon inventory open simplified to used.run_bagdirectly (no separate stash fetch needed now that all items are inrun_bag)
Added
- Damage flash overlay: blended red L-bracket corners flash over the inventory screen whenever the player takes damage while it is open; resets to 0.5s on each hit and fades linearly;
Framebuffer::fill_rect_blendadded to renderer for per-pixel alpha blending
[v0.3.47] — 2026-05-08
Added
- LOADOUT tab body silhouette: 8 equipment slots arranged spatially on screen (Helmet top-center, Weapon/Chest/Shield column, Gloves/Leggings/Tome column, Boots bottom); empty slots rendered as pixel-art silhouette icons in
[72, 80, 105, 255]— visible but clearly unequipped; D-pad navigation viaLOADOUT_NAVdirectional table - Expansion column (POUCH / PACK / SASH): 3 locked expansion slots at right edge of LOADOUT tab; lock icons; corner-only borders distinguish them from active equipment slots
- Quick-use strip (STAMINA / HEALTH / FOOD): 3 templated quick-use slots on LOADOUT tab left edge; each has 3-line stacked label to the right — slot number (dim), item type (brightest), direction (dim); corner-only borders; silhouette icon until item is assigned
Changed
- Tab renamed INVENTORY: was BAG, then STASH; now
INVENTORY— matches in-game terminology - Expansion slot renamed SASH: third expansion slot was SATCHEL, now SASH
- Vertical affix stacking: item detail panel now renders each stat affix on its own line (one
+N STATper row) instead of a single horizontal string that ran off-screen on high-affix items - Tab bar spacing: 10px gap added between tab bar and first inventory icon row (
GRID_Y += 10) - Tab underline: moved 2px below text bottom and thickened to 3px (was 1px at
Q_LABEL_H - 3, overlapping the text descenders) - Silhouette icon visibility: corrected color from
[38-52, 42-58, 55-76](near-identical to background) to[72, 80, 105, 255]— icons are now visible as shapes while remaining clearly unequipped - Item count removed: bag capacity counter (
xx/100) removed from inventory display - Quick-use label order: type label (
STAMINA/HEALTH/FOOD) is now the brightest line; slot number and direction are secondary; label order is SLOT N → type → direction
Fixed
- Up scroll arrow was positioned at
GRID_Y - 12which overlapped the tab bar after the GRID_Y increase; repositioned toQ_LABEL_H + 2(sits in the gap) - Removed
R2label from LOADOUT tab top-left (was rendered unconditionally, not present on INVENTORY tab)
[v0.3.46] — 2026-05-08
Fixed
- Item drop position:
ClientMessage::DropItemnow carriestile_x/tile_yfrom the client's predicted position; server uses these directly instead of its UDP-lagged player coordinates — dropped items now land where the player is standing visually - Duplicate item ID on partial drop: ground item is assigned a fresh ID from
loot.next_item_id; previously the dropped stack shared the same ID as the remaining run_bag entry, causing the second drop to be unfindable
[v0.4.0-dev] — 2026-04-27 → 2026-05-06 (in progress)
Added
- Barrel loot drops: breaking barrels spawns ground items (60% nothing, 19% crux, 19% food, 1% health potion, 1% stamina potion); all drop as floor items picked up with A
- Crux as inventory item: crux is now a stackable floor/inventory item (stack to 100) rather than a HUD counter; crux and aether removed from Character tab and dungeon HUD
- Enemy crux drops: each enemy death has a 50% chance to drop 1–3 crux as a ground item (first-come-first-served), replacing the old all-players broadcast that gave 5–10× too much
- Stackable items:
Item.amount: u32(serde default 1);Slot::is_stackable()andstack_max(); server merges stacks on pickup and sends back the updated item — client updates existing entry by id - Food buff system:
FoodKind::ChickenLeg(25 HP over 10 seconds); genericActiveBuffstruct withhp_per_sec + stamina_per_sec + duration_secs— expandable for future tomes; R2 strip slot 1 now selects food (0x40 flag), wired toprocess_foodon server - New Slot variants:
Slot::Crux,Slot::HealthPotion,Slot::StaminaPotion,Slot::Food; each has pixel-art icons in 32×32 (floor), 64×64 (inventory grid), and 14×14 (equip list) sizes; stack count displayed in inventory grid corner - Stamina potion: new floor-droppable
Slot::StaminaPotionitem (instant stamina restore, stacks to 3)
Changed
- Dungeon inventory replaces run-bag overlay: Select now opens the full inventory screen (Equipment / Stash / Character tabs, equip/unequip support) instead of a read-only run-bag list. Items found during the run appear on the Stash tab as candidates to equip mid-run. Character summary (name, class, stats, currency) is threaded from hub → lobby → dungeon so the Character tab populates correctly.
Added (Phase 5.4 — Party System, Step 4)
- Party → lobby auto-start:
run_lobby_looptakesparty_size: usize; whenparty_size > 1and host,do_startflag fires as soon as the queue reaches the expected member count — no manual ReadyStart needed for party runs - Guaranteed same team: all party members who accepted the countdown enter the same lobby and dungeon instance;
do_startchecked immediately on join and on eachLobbyUpdatearrival (i.e. each new player joining) - Silent party dissolution: success path in
'qwaitloop callsdissolve_partybefore signaling non-leaders, eliminating spuriousPartyUpdate/PartyDisbandedmessages during lobby transition queue_proceed_txtype change:mpsc::UnboundedSender<PortalMode>→mpsc::UnboundedSender<(PortalMode, usize)>; non-leaders receive party size from leader so lobby knows expected count- Auto-leave on death/extraction: implicit — party is dissolved before lobby entry; dying/extracting players reconnect to hub fresh with no party
Added (Phase 5.4 — Party System, Step 3)
- Party queue countdown: leader queues at portal → server sends
PartyQueueStartedto all party members; non-leaders see 30s countdown overlay (A:accept / B:decline / auto-decline on timeout); leader sees "WAITING FOR PARTY..." overlay with B:cancel - Server queue coordination: hub
read_siderefactored totokio::select!with labeled'hubloop; leader'sEnterQueuetriggers inner'qwaitloop collecting responses viampscchannel inPartyState; all-accept fires each non-leader'squeue_proceed_txto exit hub and enter lobby; any decline/timeout sendsPartyQueueCanceledand dissolves the party - New wire messages (
shared):PartyQueueAccepted/PartyQueueDeclined(C→S);PartyQueueStarted { mode, timeout_secs, you_are_leader }/PartyQueueAllAccepted/PartyQueueCanceled(S→C) HubPlayerEntry.queue_proceed_tx: per-player channel that breaks a non-leader's hub task out of its blockingread_messageselect when all members have acceptedPartyState:PendingPartyQueue,start_queue/end_queue/dissolve_partymethods
Added (Phase 5.4 — Party System, Steps 0–2)
- Party panel HUD (
hub.rs): persistent top-right widget when in a party; shows member name, 3-char class abbrev (WAR/SKM/ARC), gold leader dot;X:LEAVE PARTYhint - Leave party: X button in hub sends
LeaveParty, clears panel immediately; server auto-disbands when party would drop to 1 member and sendsPartyDisbandedto last member - Party wire messages (
shared):PartyMemberstruct;ClientMessagegainsInviteToParty,AcceptPartyInvite,DeclinePartyInvite,LeaveParty;ServerMessagegainsPartyInvite,PartyInviteDeclined,PartyUpdate,PartyDisbanded; oldInviteToQueue/QueueInviteremoved server/src/party.rs:Party+PartyStatewith full invite/accept/leave/disband lifecycle;Arc<TokioMutex<PartyState>>shared across hub connections- Queue/lobby UI redesign (Step 0): full-screen layout, Large/MediumFull fonts, green "at portal" dot per player, portal mode panel resized to 312×210; lobby B returns to hub
Added (Phase 5.3 — Hub Multiplayer)
- Other players in hub:
HubWorld+HubPlayerEntryon server;HubSnapshotbroadcast at 20 Hz; other player sprites + name tags rendered in hub between mask/fringe passes - Queue lobby (
lobby.rs):LobbyStatewaiting room — player list with name/class/sprite, hostA:START,B:LEAVE;QueueStateaccumulates players perPortalMode - In-dungeon other player rendering:
RosterEntryinConnected;OtherPlayerAnimper player inDungeonState; correct sprite + floating name tag - Hub split read/write:
stream.split()+tokio::join!(read_side, write_side)+mpsc::unbounded_channelfor outgoing messages — fixes deadlock from concurrent TCP read+write - Hub proximity invite (invite overlay): A near another hub player →
InviteToPartysent; incoming invite shows name/class and A:ACCEPT / B:DECLINE
Added (Phase 5.2 — Gap Closure)
- Run bag:
RunBagItemtracked server-side per player; items looted during a run held separately from stash until extraction or death - Unstable death consequences: each run-bag item and equipped item rolls independently for destruction; random 0–100% of run Crux destroyed; survivors go to stash
- Chest states: per-player open/close state; per-player loot rolls on first open
- In-dungeon run bag overlay: Select tap toggles read-only run bag view; B closes; D-pad scrolls
Added (Phase 5.1 — Portal Mode Selection)
- Portal mode select overlay: opens on A at portal instead of immediately queuing; 3 rows (Unstable/Stable/Empowered); Stable/Empowered locked with cost shown;
B:CANCEL
Added (Phase 4.6 — Inventory & Equip UI)
- Tabbed inventory (
inventory.rs): Equipment / Stash / Character tabs; L1/R1 cycle; equip stash item → serverEquipItem→EquipResultwith displaced item returned to stash;RequestStash+RequestEquippedon Select in hub - Character tab: class, HP, summed ATK/DEF/SPD from equipped affixes, Crux, Aether
Slot::Tome: equippable tome slot; tomes drop in dungeons, permanently lost on death
Added (Phase 4.5 — Loot System)
- Item types (
shared):Item,Slot,Rarity,StatKind,Affix; 8 equipment slots; rarity tiers Common→Legendary; random affixes; 0–3 augment slots - Server loot rolls (
loot.rs): xorshift RNG, 50% drop chance, weighted rarity, affix rolling; drops generated intick_loop - Ground loot rendering: rarity-colored diamonds; A pickup within 1.5 tiles sends
PickupItem; proximity hint shows item name - Crux economy: 10 Crux/kill to all alive players;
CruxChangedTCP message; persisted on dungeon exit;$NNNshown in hub and dungeon HUDs - Equipped stats in combat:
AttackFlatin damage formula;DefenseFlatflat reduction inai.rs;db::load_equipped_statsat dungeon entry
[v0.4.0-dev] — 2026-04-27
Added
- Blackthorn Hollow hub world (
hub.rs): 96×96 tile map with 7 named POIs — Dungeon Portal, Reaver's Rest (spawn), The Ironvault, Crowe's Tradehouse, Aether Forge, Town Compactor, Bounty Board - Hub camera: tile-unit float camera with
clamp(half_vw, MAP_W - half_vw)— same approach as dungeon; map fills screen edge-to-edge with no black gaps - Unified player hitbox: hub and dungeon both use
x:8–24, y:10–26in logical px; map boundary acts as collision edge (no perimeter wall tiles needed) - Session persistence:
forget_session()on voluntary logout keeps token on disk for auto-login next launch;clear_session()reserved for server-rejected tokens only - Phase 4 account/character system: register, login, character creation (name + class + sprite picker), character select with delete confirmation,
HubReadyserver message - Character sprites: 32 variants selectable at character creation; animated preview in creator; loaded per-character at hub/dungeon start
- Keyboard improvements:
FontSize::MediumFullfor key labels; Space↔Enter Up/Down navigation fixed - Main menu transparency:
darken_rectdivisor 2 (title art visible at 50%); selected item uses divisor 3
Changed
- Hub walk animation switched from tick-counter (3.75fps) to dt-based timer at 8fps — matches dungeon player exactly
- Hub tiles render at
TILE_S = 32screen px (was 16) — fixes 2× scale mismatch vs dungeons - B on class selection screen returns to character list (skips keyboard); sprite preview offset +10px to account for weapon animation space at bottom of frames
Fixed
- Session token wiped on voluntary logout — token now preserved on disk across logout/login cycles
- Black space at hub map edges — camera clamping now uses tile-unit floats matching dungeon approach
- Hub hitbox inconsistency — unified to match dungeon player collision box exactly
[v0.3.0] — 2026-04-21
Added
- Phase 3 state machine: 7-state
AppStateenum (Boot → MainMenu → ClassSelect → Loading → Dungeon → Death → ExtractionSuccess) — full flow from title screen to dungeon confirmed on hardware - UDP game channel: server binds UDP on port 9877 alongside TCP 9876;
PlayerInputsent from client every frame (position, facing, seq),WorldSnapshotbroadcast from server at 30Hz to all connected clients - 30Hz server tick loop:
#[tokio::main]async server withGameWorld(Arc<Mutex) tracking all connected players; tick task fires every 33ms, sendsWorldSnapshotvia UDP; UDP recv task updates server-side positions from client input - Shared types:
EntityState,PlayerInput,WorldSnapshotadded tosharedcrate;ServerMessage::Connectednow includesplayer_id - Three playable classes in
shared:Warrior,Skirmisher,Arcanistwith distinct base stats; class selection screen with D-pad navigation; class transmitted to server before dungeon generation deploy.sh: unified build-and-deploy script for both Miyoo Mini Plus (SSH/rsync) and Miyoo Mini Flip (HTTP + wget); handles binary + assets + tileset configs atomically- Enemy pathfinding: tile-locked A* chase movement — enemies move center-to-center, eliminating sub-tile corner clipping; cardinal-only moves prevent canal corner shortcuts; reactive repath on every player tile change; aggro/leash ranges (
DETECT_RANGE_SQ120px,LEASH_RANGE_SQ240px) with persistentis_chasingflag - Enemy AI quality: staggered repath timers by
id % 7to prevent lock-step sync; A* start/goal always treated as walkable so enemies can reach wall-adjacent players; enemies skip spawn tiles occupied by chests/breakables - Enemy animation hysteresis: facing direction requires 4 consistent frames before committing — eliminates single-frame directional flicker at tile transitions
- Player-enemy collision: server holds player position on enemy overlap (no wall-slide); client mirrors server enemy hitboxes in
try_moveso prediction agrees with server — no jitter - Spawn point safety: re-validated after chest and breakable placement with a second BFS pass; fixes rare stuck-at-spawn bug when objects landed adjacent to the spawn tile
- Basic combat loop: server-authoritative hit detection (A button), damage calculation scaled by class
damage_multiplier, enemy melee attack on contact with cooldown; floating damage numbers on server-confirmed hits; HP bars on all entities (color-graded green→red) - Starter abilities (Y): Second Wind (Warrior — heal + 50% damage reduction), Shadow Mend (Skirmisher — heal + speed), Arcane Restore (Arcanist — heal + damage shield); server-side cooldown tracking
- Potions (R1): 3 per run (server-authoritative), 40% max HP heal, cooldown between uses
- Enemy sprites: monster sprite sheets loaded by kind+variant from
assets/monster_sprites/; enemies rendered as animated sprites in the world - Player HUD: HP bar (top-left, green→red), ability cooldown indicator (Y READY / Y ACTIVE / Y CD), potion count
- Death + extraction flow: server sends
PlayerDied/PlayerExtractedvia TCP; client transitions to Death or ExtractionSuccess screen respectively; extraction triggered when player center enters portal AABB
[v0.2.6] — 2026-04-19
Added
- Software audio mixer (
client/src/audio.rs): single ALSA thread mixes looping music + up to 4 simultaneous one-shot SFX;AudioMixer::play_music/play_sfxAPI ready for phase 3 - Chest system: 8 chest type variants as sprites (server assigns random type on generation, client renders per-type frame from
chests.png) - Title screen asset (
assets/title_screen.png) — "Reaver's Rest" dark fantasy design at 320×240 logical resolution .cargo/config.toml: cross-compile linker config for ARM targets committed to repo
Changed
- Working title renamed to "Reaver's Rest"
- Asset organisation: active/deployed assets moved to
assets/(tilesets, sprites, music, portal frames, chests);assets_gif/is now a staging/review area for downloaded assets not yet in use asset_basepath in client updated fromassets_gif→assets.gitignore: added__pycache__/andtools/maps/*_raw.json(debug dungeon dumps)- CLAUDE.md: documented audio system architecture, hardware constraints, and asset folder conventions
Fixed
- Audio playback at correct speed: MI ALSA stub always runs at 8000 Hz mono regardless of configured rate; all audio now resampled to 8000 Hz mono before submission (previous stereo submission caused 0.5× speed)
- Dead code removed:
COLOR_LEDGE,COLOR_FLOOR,COLOR_DOOR,COLOR_BORDERconstants;Framebuffer::in_bounds(); unusedplatform_setparameter ondraw_map_layer; duplicate#[inline]attribute portal_activeuninitialized-read warning resolved- Phase 3 placeholder fields (
breakable_density,sound,loot_table,play_sfx) annotated with#[allow(dead_code)]to keep warning list clean
[v0.2.5] — 2026-04-14
Added
- Canal generation: procedural water features inside dungeons using L, Z/S, U/C, and Staircase shapes; width configurable (default 2 tiles)
- Canal bank tiles: 12 assignable roles (N/S/E/W straight banks, NE/NW/SE/SW outer corners, NE/NW/SE/SW inner corners) resolved using geographic convention —
bank_n= tile is north of the water - Canal water tile and all 12 bank roles assignable in tile mapper config panel with real-time preview
CanalConfigstruct inTilesetConfig: all canal tile roles loaded from JSONcanal.*fieldscanal_bank_uv()intile_engine.rs: per-cell bank overlay resolution with outer-corner priority over straight over inner-cornerTileCache.bank_uv: precomputed bank tile per floor cell, rendered as overlay in the correct draw layer- Canal cells block player movement (server-authoritative; canal set passed through
try_move) - Config deploy commands documented in CLAUDE.md and CHANGELOG (deploy config JSON to both devices whenever tileset config changes)
Fixed
- Canal generation minimum perpendicular separation: parallel canal arms now require
width + 3tiles of clearance, guaranteeing ≥ 3 walkable floor tiles between arms (previously could produce 1-tile gaps, e.g. seed ending in 82159)
[v0.2.4] — 2026-04-10
Added
- Floating damage numbers: world-space position, random upward drift direction, alpha fade over 1.4 seconds — foundation for in-game combat feedback
- Camera clamped to map bounds: viewport never scrolls past the dungeon edge; player moves off-centre when near a boundary
Changed
blit_spriteoptimised: row-invariantsyanddst_rowhoisted out of the inner column loop; column clip range computed once per blit so no per-pixel bounds check is needed in the hot path
Fixed
- Screen tearing:
FBIO_WAITFORVSYNCioctl was using0x4600(FBIOGET_VSCREENINFO) instead of the correct0x40044620 - Screen tearing: framebuffer write direction now matches display scan direction (forward through mmap), keeping the write ahead of the scan line
[v0.2.3] — 2026-04-09
Added
- Autotile engine (
client/src/tile_engine.rs): full tileset tile selection for every dungeon cell based on north depth, face rows (3 depths), side-wall strips, cap tiles, diagonal edge detection, and side-wall transition tiles - Peninsula cleanup pass in dungeon generator: wall tiles with 3+ cardinal floor neighbours are converted to floor (catches wall stubs the excess-intersection pass misses when their only wall neighbour is pure void)
- Config-driven tile rendering:
TilesetConfigstruct loaded from JSON at startup; all tile roles (floor base, variations, bridges, 14 wall roles) are now data-driven rather than hardcoded - Floor variation hash in client matches tile mapper tool (Murmur-style: same seed → same variation pattern on both)
- Collision mode in tile mapper tool (P cycles to it): yellow outlines show collision cells, left-click adds, right-click removes, Ctrl+S saves override JSON
- Wall config section in tile mapper config panel: caps, side walls, face rows 1–3 all assignable per tileset
Changed
- Excess intersection and peninsula cleanup passes now run inside a shared outer loop until both are quiescent — prevents peninsula conversions from leaving new excess tiles behind
- Server dungeon seed restored to nanosecond-timestamp random seed (was hardcoded to a test value)
- Collision rule: wall tiles are solid only if no cardinal neighbour is floor (void walls only). Border walls — caps, face rows, side-wall strips — are now passable, letting the player walk up to the visual wall face
- Player hitbox tuned to 18×22 px (source) — wider and taller than before, better fitting the sprite's body
- Dungeon Base Generation design doc updated to reflect current 64×64 grid, room parameters, and the full 5-pass cleanup pipeline
Fixed
- Orange (excess) wall tiles occasionally surviving generation when the peninsula pass ran first and created new excess conditions that the already-completed excess pass never saw
- Floor variation hash changed from XOR to Murmur-style mixing — eliminates visible grid pattern in floor tile distribution
[v0.2.1] — 2026-04-08
Added
- On-screen FPS counter in bottom-right corner using embedded 5×7 bitmap font (no extra dependencies)
- Bitmap font extended to full uppercase A–Z for UI text rendering
- In-game menu overlay (Start button): translucent panel with EXIT GAME / CANCEL options, game continues running behind it
- 30 FPS framelock with hybrid sleep + spin-wait to work around Miyoo kernel's 10ms scheduler granularity (HZ=100)
Changed
- Dungeon corridors widened from 2 to 3 tiles; doors removed entirely
- Added sliver wall cleanup pass: 1-tile-wide wall columns/rows between open spaces are converted to floor
- Dungeon size set to 64×64 tiles for Unstable mode
- Player walk cycle changed to 4-step sequence (0→1→2→1) for smoother animation
- Horizontal walk frames now play in reverse (2→1→0→1) to match sprite sheet layout
fill_rectrewritten to fill first row thencopy_withinsubsequent rows — faster on ARM- Removed redundant
clear()call each frame;draw_mapcovers the full viewport already
Fixed
- Corrected horizontal walk animation direction (was moonwalking left and right)
[v0.2.0] — 2026-04-08
Added
- Procedural dungeon generator: random rooms + L-shaped corridors + door placement on a 64×64 tile grid
shared:Tileenum (Wall/Floor/Door),DungeonMapstruct with spawn point- Server generates a fresh dungeon on each client connect and sends the full map
- Client renders dungeon with solid colored tiles (wall, floor, door, red border walls)
- Smooth sub-tile scrolling camera centered on the player
- Debug grid overlay
- Walking animation using
character_1_base.pngspritesheet (3 cols × 4 rows, 8 FPS) - 8-directional free pixel movement with wall-sliding collision
- Hitbox tuned to lower portion of sprite for natural top-down feel
- Direct
/dev/fb0mmap renderer — bypasses SDL2 renderer pipeline entirely - 180° framebuffer flip to compensate for Miyoo's physically rotated screen
- Confirmed running at ~50 FPS on Miyoo Mini Plus hardware in release mode
- Cross-compilation via
armv7-unknown-linux-gnueabihftarget +cargo-zigbuildtargeting glibc 2.17 (compatible with Miyoo's glibc 2.28) - Onion OS app structure with
launch.sh,config.json, and icon placeholder
[v0.1.0] — 2026-04-05
Added
- Development plan (Phases 0–5) as HTML documentation
CLAUDE.md— project instructions, game design rules, and versioning policyCHANGELOG.md— this file- Cargo workspace with
server,client, andsharedcrates - Core dependencies:
tokio,serde,bincodeacross all crates shared:ClientMessageandServerMessageenums — typed network contract between server and clientserver: TCP listener on port 9876; deserializesConnect, replies withConnectedclient: TCP client; sendsConnect { username }, receives and printsConnectedwelcome message- ARM cross-compilation via
armv7-unknown-linux-musleabihftarget with musl libc (statically linked — no glibc dependency) - First successful server ↔ client handshake over WiFi from real Miyoo Mini Plus hardware