findPendingRom answered with the first dump in the save directory whose SHA-1
mapped to any not-yet-ready version. On a device with no file picker that
scan IS the import, so with four dumps in the folder, choosing Red imported
and decoded Blue (#1274).
It now takes an optional version and narrows to it. The two Choose paths
pass self.chooseVersion, since a Choose names the cart it is for. The two
Android USB-drop scans pass nothing and still take the first pending cart of
any version, which is what they are for.
A chosen version with no dump present now imports nothing rather than the
wrong cart, and falls through to the notice that says where to put the file.
Drives a real turn per case and compares the emitted line to the label in
data/text/battle.asm. Six of the eleven checks fail against the text as it
stood.
The tail case wraps each changed line through Chrome.wrap at the box's own
width and holds it to the two rows printMessage draws. That is the check
that caught SpikesText needing a third row, which is why Spikes is not in
this change.
Five messages in the Gen 2 battle code are written by hand rather than taken
from data/text/battle.asm, and each has drifted from what the game prints:
SuperEffectiveText lost its hyphen and its line break
NotVeryEffectiveText ended on three periods, not the
ellipsis glyph the charmap carries
BattleText_TheresNoPPLeftForThisMove dropped "There's"
PlayerHitTimesText/EnemyHitTimesText printed "Hit 3 time(s)!", showing
the parenthetical on screen; Gen 1
already prints "Hit 3 times!" via
_HitXTimesText
StartPerishText printed a sentence no cart prints
The break is \n, which is what RomExtractorGen2 decodes the cart's own $4e
into, so these read as an extracted line would. Each goes through Strings
now, which is what the rest of this file already does with its messages.
SpikesText is left alone and the reason is written down beside it: its third
row is a `cont`, and engine messages set self.message directly rather than
going through showPages, so printMessage would cut the row carrying <TARGET>.
battle.exp_award hands a mod ctx.applyShare(mon, split, announce) on both
generations, and on Gen 1 the third argument decides whether the mon's
GainedText box is printed -- which is how a mod paying the whole party
prints ONE summary line instead of a box per recipient. Gold accepted
the argument and ignored it, so the same mod source printed one line on
Red and one per party member on Gold.
The Exp Share mod is the live case: it declares games gen1+gen2 and its
description promises "a single shared-exp line instead of one message per
Pokemon", passing true for the fighters and nil for the bench exactly as
the Gen 1 seam asks. On Gold every nil call announced anyway, so a
five-mon party turned every KO into six boxes. There was no mod-side
fix: the emit sits behind no hook, and the argument meaning "quietly" was
discarded.
Gold now reads it, and ONLY when it is actually passed -- by argument
count, not by value. select("#", ...) counts an explicit nil, so
applyShare(mon, split) is distinguishable from applyShare(mon, split,
nil); the first is a Gen 2-era call written against a seam that always
announced and keeps announcing, the second is a deliberate "pay this one
quietly" and is now silent on both games. No mod that exists today
changes behaviour, and a mod that passes the argument gets parity.
Only the { kind = "experience" } event is affected. A silent award is
still a whole award: exp, stat exp, battle.exp_gained, "grew to level",
learned moves and the forget prompt are untouched, in the same order.
giveExperiencePass takes a sixth `silent` parameter that defaults to
announcing, so both of the cart's own passes are unchanged.
RFC: docs/rfcs/0012-gen2-exp-award-announce.md
Docs: docs/mod-api-gen2-compat.md gains the reading and the residual
omitted-argument difference beside the existing payload note.
Tests: tests/gen2_exp_share_test.lua grows the two Route B tests -- the
no-mod parity case and the seam driven through hooks:wrap -- and
its 23 existing checks are unchanged.
Implemented a new deinterleave function in ImageWriter to restore row-major order for PNGs. Updated RomExtractorGen2 to utilize this function for extracting Slot Machine graphics, and added new functions for padding and writing graphics sheets. Updated the ROM manifests to include necessary symbols for Slots and Card Flip assets.
Added functions to write raw graphics assets for the Slot Machine and Card Flip games, ensuring that the necessary files are generated when the corresponding symbols are present in the ROM. Updated the manifest to include required symbols for these assets, preventing fallback to labelled cells when graphics are missing.