Loading…
a327ex.com

SNKRX Merging and Inventory

Opus 4.8

Summary

Built the SNKRX party merge system end-to-end on the SNKRX-update project (the secret SNKRX-on-Anchor-2 rebuild) — the level/reserve logic, the ×2/×4 damage+HP scaling, and the full F6 inventory visual it drives — then iterated the inventory through several rounds of feedback into a live, always-on overlay with per-sub-cell hover cards and a faithful SNKRX merge effect + sound. Roster is still 5/28 ported (archer, swordsman, magician, outlaw, cannoneer); this session added the merge mechanic those units' ability-ladder cards were built in anticipation of. Ended by picking the next direction: resume porting more units, redesigning Lv.3 passives per-unit as each lands.

Orientation:

  • Confirmed state from memory + the vault logs: last SNKRX-update session was nda-project-6 "SNKRX UI Cards and Keywords" (the 2-tier ability-ladder cards + glossary-hover). Repo clean at 94ea604, test_unit = 'cannoneer'. (Noted the vault interleaves two secret projects — nda-project-5/7 are 062026 sessions.)
  • Laid out next-step options (merge system / class set-bonuses / a subsystem to unblock units / name polish); user picked the merge system, specifically wanting it "working logically but also physically" — the SNKRX F6 snake visual that shows merge progress intuitively.

Merge research (SNKRX-ref):

  • Merge logic lives in buy_screen.lua (the shop), not a merge function. A party unit is {character, level, reserve={r1,r2}} (line 327). BuyScreen:buy (286-310) is a purchase accumulator: at Lv.1 each dup reserve[1]++, >1 → reset, level=2; at Lv.2 reserve[1]++, >2 → bank a reserve[2] or (if one banked) → level=3. So 3×Lv.1→Lv.2, 3×Lv.2→Lv.3, 9 total→Lv.3, cap 3.
  • The visual (CharacterPart, 1142-1248): each party cell is a colored square with its level number; the reserve is drawn as smaller mini-unit "parts" beside it (a banked Lv.2 part at full size + a 0.9-scale Lv.1 part per reserve[1]) — the partial-merge progress made physical. A landed merge fires SpawnEffect.
  • Damage/HP law (stat_port_proposal.md Part 8, authoritative): merge 1/2/3 = base / 2× / 4×, integer doubling; merge couples both HP tier and the attack's damage tier. Cooldown/range do NOT scale. self.level == 3 gates the Lv.3 passive.

Merge logic (snake.lua + units.lua):

  • snake_unit gained reserve = {0,0} and a level-coupled max_hp.
  • unit_merge_add(u) — SNKRX's reserve roll verbatim; returns true on a level-up. snake_unit_set_level(u, lv) sets level + re-couples HP (tops to full).
  • merge_dmg_mult(level) + unit_damage(u, base) (units.lua) scale damage; wired into all 5 attack fns (archer, magician, cannoneer direct+splash, outlaw, swordsman incl. its flat crowd bonus).
  • The card (unit_card_v2) scales via a thin __index override-proxy sdef (damage/direct_damage/damage_per_enemy × mult) so the DMG chip AND the yellow description numbers reflect the hovered unit's level with zero per-unit edits.

Design-brief workflow: every non-trivial change went through a brief-then-approve loop per the project's ⛔ rule (verified SNKRX behavior before coding each time). User approved each with "Go ahead" / "Yes".

Iteration round 1 (user feedback):

  • "Change C so that it adds a unit randomly to one of the existing ones." → the c debug key is now hover-independent: picks a random eligible unit (ability-ladder, level<3) and runs unit_merge_add.
  • "The visual for the mini-units looks wrong as the number is bigger than the unit itself." → reserve parts now draw a FULL cell under a layer_push scale so the level digit shrinks WITH the square (SNKRX scales the whole part the same way). draw_reserve_part added.
  • "The effects you added are also not the same as in SNKRX, you created new ones yourself, make sure to match SNKRX perfectly, even when it comes to sound." → removed the invented white-flash; researched + ported the real effect/sound (below).

SNKRX-faithful merge effect + sound:

  • Visual = a paused-safe port of SNKRX's SpawnEffect (shared.lua:367): white circle pops radius 0→6 (0.1s cubic_in_out) then 6→0 (0.25s), bleeding white→unit-color at 0.15s, bursting 6–8 unit-color particles (reusing fx_particle, the HitParticle port). The circle is hand-rolled (our fx_hit_circle only shrinks). Held in a local inv_fx_circles/inv_fx_particles list ticked by inventory_update(dt) and drawn on ui_layer at the cell, so it animates even though F6 paused at the time. Fires only on a level-up.
  • Sound = SNKRX's ShopCard buy stack (buy_screen.lua:1619): ui_switch1 (Switch.ogg) + a random coins1/2/3 (Coins 7/8/9.ogg) on every accepted acquire; error1 (Error 2.ogg) on a refused one. The merge SpawnEffect itself is silent in SNKRX.
  • Sourcing (per project rule — source from packs, not the SNKRX folder): found the files in E:/sound packs/Ultimate SFX Bundle (2020)/Magic Sounds Pro/Magical UI Sounds/ (durations matched SNKRX-ref's oggs exactly — the pack SNKRX drew from). ffmpeg -c:a libvorbis -q:a 10assets/, loaded in main.lua's GAME SOUNDS block before volumes_apply_overrides(), pitched ±5% / vol 0.5.

Live always-on inventory (de-pause):

  • "To make things simpler, just have the inventory UI visible without the game being paused, so I don't have to press F6." → dropped the early-out at main.lua:273 (if inventory_update(dt) then return endinventory_update(dt)); inventory_visible defaults true; inventory_update returns false (no pause signal). F6 kept as a non-pausing show/hide toggle.
  • Spring juice: confirmed cells already pop on hover/press/merge (ui_juice_hover/pull/scale). The missing SNKRX piece was the entrance pop — added a cascade (INV_ENTRANCE_STAGGER) that pops cells in one-after-another on the hidden→visible edge (incl. startup), mirroring CharacterPart:init's spring pull.

Spring-on-buy correction:

  • First made a buy pop the WHOLE party. User: "You made every single one spring, I mean every single one for that unit only." → scoped back to only the acquired unit, whose big cell + small reserve parts pop together.
  • Verified the original: SNKRX's set_party_and_sets() (called on every buy) destroys + recreates all CharacterParts, so each main + reserve part re-runs CharacterPart:initspring:pull(0.2). Implemented per-sub-cell springs (each sub-cell scales by its own key's juice); a buy pulls all of the acquired unit's sub-cell keys (pull_unit); entrance/drag pops do the same.

Uniform reserve size: "let's have all Lv.1 and Lv.2 units be the size Lv.2 units are now, instead of having 3 different sizes." → collapsed the three sizes (main 1.0 / Lv.2-reserve 0.8 / Lv.1-reserve 0.65) to two via a single inv_reserve_s = 0.8. Flagged the divergence: SNKRX actually draws Lv.2-reserve at full size + Lv.1 at 0.9.

Per-sub-cell hover cards: "The card hover should work individually for each unit, including the small ones." → generalized the card target from a unit entity-id to any sub-cell. New unit_cells(u, r) = the shared geometry (main + reserve parts, each with a stable key that doubles as juice id + card id), iterated by both draw and the hover hit-test. Each frame builds a targets list; the square under the cursor pops individually and shows its card AT THAT PART'S LEVEL. Card state keyed by inv_card_key (was inv_card_id), re-resolved each frame via find_target; keep-corridor changed to the direction-agnostic union bounding box of source + card (reserve parts can sit past where the card pops). Drag-reorder + 1/2/3 level-jump stay main-only.

Integer display fix: doubled/tripled values showed as "24.0" — 2^(level-1) returns a Lua 5.4 float. Changed merge_dmg_mult to 1 << (level-1) (integer 1/2/4) and routed snake.lua's HP scaling through it, so all scaled damage + HP render as integers (12/24/48).

Wrap-up: updated the project memory (project_snkrx_update.md) to record the merge system as BUILT (it had been marked unbuilt) plus the next-session plan. Next session (owner's call): resume porting more units one at a time per porting.md, redesigning quite a few of the Lv.3 passives per-unit as each is added — NOT as a separate up-front pass. Shop/economy, class set-bonuses, and a buff subsystem stay deferred behind that. Session sealed as an NDA log.

🔒 Only the summary of this log is public. Private because this is SNKRX update.