Both call sites -- Game2:usePartyItem (the field pack) and
BattleState:useItem (the battle pack) -- asked ItemEffects.partyAction
for an item's family with no `data` argument, even though every other
call in the same functions (useOnMon, usePpItem, applyPartyItem) passed
it through correctly. partyAction resolves through recordFor, which
reads data.gen2ItemEffects when given a dataset and falls back to the
module's own built-in RECORDS table when not -- so with no data, a
mod's own item_effects record was invisible and every mod-defined Gen 2
field or battle item resolved to a nil action, falling straight through
to "isn't going to help here" / "isn't going to help here" without ever
opening the party picker.
Both now pass the live dataset (self.data on Game2, self.game.data on
the battle screen) the same way their sibling calls already did.
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.
DAYS (SUNDAY..SATURDAY), the MORN/DAY/NITE word PrintHour prints, and the
"o'clock"/"min." suffixes bypassed src/core/Strings.lua entirely -- they
were plain Lua literals with no lookup, so a translation mod's `strings`
registry had nothing to catch and Oak's clock screens, the day-of-week
wheel, the main menu clock box and the Pokegear's clock card kept printing
English regardless of the loaded language (reported from a real Spanish
Gold build).
Both live in src/core/gen2/Clock.lua, which already owns weekday/hour
arithmetic and is already required by InitClock.lua, MainMenu.lua and
Pokegear.lua: Clock.DAY_NAMES + Clock.weekdayName(day) is the one place the
three screens read a weekday's name from, so a fix to it cannot land on one
screen and silently miss the other two. Clock.daytimeLabel(hour) is the
translated counterpart to Palettes.clockDaytime, which keeps answering the
untranslated MORN/DAY/NITE key every FORCED_DAYTIME lookup in Palettes.lua
compares against -- src/world/gen2/Palettes.lua itself is untouched, so
that module stays pure table/color math with no Strings coupling.
- Auto-recover save slots: Scan saves/<version>/ on boot to re-index orphaned slot files if options.lua is reset or loses its slot registry.
- Fix Gen 2 field moves: Make PartyMenu field actions (Strength, Surf, Cut, Flash) generation-aware so they execute safely in Gold.
- Fortify platform stability: Guard native controller/hidapi init against Android 14 receiver exceptions and ensure safe Windows file replacement.
- Add unit test coverage for slot auto-recovery in save_editor_gen2_tests.lua.
The save editor now routes Gold vs RBY through a generation adapter so boxes, items, events, and maps write the right fields. The launcher layout is shuffled a bit, and patch notes can come from the updater, a packed file, or the iOS sidecar.
Selecting a TM in the mart's SELL pack (and the item PC's DEPOSIT pack) opened the teach-party screen: PackMenu:useSelected taught any item carrying `teaches`, even when the pack was built as a chooser (DepositSellPack, world = {}). On the cart that chooser's jumptable is four ScrollingMenus and never reaches tmhm.asm, so the row must hand back to the caller instead.
Gate the teach and field-NOUSE branches behind world.useFieldItem so only the real field PACK teaches; choosers now hand TMs to onChoose. Selling then prices a TM at half its ItemAttributes price -- exactly half of what the Goldenrod/Celadon TM shelves charge, and half of the hidden price for the rest, the way SelectQuantityToSell -> GetItemPrice -> Sell_HalvePrice does on the cart.
Closes#1243