useOn was a plain Lua local: every result ItemEffects.use returned fell
through to one unconditional showMessages with no seam a mod could
reach, unlike menu.lua/boxmark.lua/formview.lua's screens, which wrap
their own default behavior as a table field or a Runtime hook. A mod
could not suppress a message, delay it behind a screen of its own, or
substitute a different outcome for one item id -- exactly the gap noted
against Ultra Burst's item-driven fusion, which had nowhere left to
attach a bespoke animation once TextBox.new turned out to be the only
other reachable seam.
This wraps the whole dispatch in a Runtime.call("item.use", ...) hook,
the same mechanism "battle.overlay", "ui.party.submenu" and the rest of
src/ui already use, rather than exporting BagMenu.useOn as a table
field. A hook is the smaller commitment: it is additive (a fresh
Runtime.call site needs no schema or manifest change and costs nothing
unsubscribed -- see tests/engine/gate_hooks.lua's null-object case) and
a mod can still run the vanilla flow unchanged by calling the handed-in
vanilla function, whereas a table field would fix useOn's exact
signature as public API the moment it shipped. If the maintainer would
rather match the sibling screens' convention directly, exporting
BagMenu.useOn is the alternative and does not conflict with this hook
existing alongside it.
vanillaUseOn keeps the original function body; useOn is now the thin
wrapper mods observe through, and every internal caller in this file
still goes through useOn so the hook fires on every path into it.
Selecting a start-menu row pops the start menu before the submenu is
pushed (Menu's generic A handler), so B in a submenu had no parent to
return to and dropped straight to the overworld. pokered redisplays
the start menu instead (RedisplayStartMenu from the party/item/
trainer-card/option handlers), so give each vanilla submenu an
onCancel that re-opens the start menu; the saved cursor row
(wBattleAndStartSavedMenuItem) restores on re-entry.
- PokedexMenu/BagMenu forward opts.onCancel into their ListMenu
- TrainerCard dismisses back via onCancel on A or B
(WaitForTextScrollButtonPress then RedisplayStartMenu)
- OptionsMenu fires onCancel from both B/START and the CANCEL row
- PlayerPC rows are keepOpen so B in WITHDRAW/DEPOSIT/TOSS returns to
the PC root menu (players_pc.asm), matching the BoxMenu pattern
The SAVE flow is untouched: StartMenu_SaveReset falls through to
HoldTextDisplayOpen and never redisplays the menu. Battle-opened
party/bag screens get no onCancel, so mid-battle cancel behavior is
unchanged.
Co-authored-by: johnjohto <johnjohto@users.noreply.github.com>
CLOSES#28: PC in the beginning of the game isn't interactable (The one in your house)
CLOSES#34: Bug when calculating exp after one or many fainted team members.
CLOSES#37: No Grass Cutting
CLOSES#38: Blind TMs
CLOSES#53: Portable Mode
CLOSES#55: changing palletes with hot key
CLOSES#62: Poison status damage issue.