The reporter labels runs by abusing the in-game player name; give slots
a real label instead. SaveData.renameSlot persists a trimmed label in
the options registry (options.saveSlots[version].names) -- never in the
save file, so renaming needs no save rewrite and an empty slot can be
labeled too -- listSlots rows carry it as `label`, and deleteSlot
drops it with the slot.
In the launcher, right-clicking a slot row opens an inline rename modal
(Enter commits, Esc cancels, empty clears; 24 whole-codepoint cap via
local UTF-8 helpers, since plain luajit has no utf8 library). The row
title shows the label over the player name; badges/time/caught stay on
the meta line. Desktop-only: touch has no secondary button. main.lua
now forwards love.textinput to the importer while it is up.
Backend covered by a new renameSlot block in tests/engine/save_slots.lua
(78/78); docs/launcher.md's registry section documents the label.
Auditing the reporter's PKHeX screenshots against the emitted bytes
turned up three fidelity bugs in the .sav export:
- Name fields on a templateless export stayed zero-filled after the
$50 terminator; every real save the naming screen wrote $50-pads
the tail, and the zero tail is what PKHeX rendered as "JOHN{}".
encodeName now pads zero tail bytes with $50 (nonzero template
bytes still survive untouched).
- wOptions was never written, dropping text speed / battle style /
battle effects on export. Templateless exports now pack it from
save.options (the recomp's textSpeed 1/3/5 are pokered's exact
values); with a template the cartridge's own byte still wins.
- The party/box catch-rate byte was always re-derived from the
current species, but Gen1 freezes it at catch time (evolution does
not update it), which is why PKHeX demanded "a preevolution catch
rate". Pokemon.new now stamps the as-caught catchRate and
Evolution.apply's in-place mutation preserves it.
The reported emulator crash itself is not addressed here: the encoder
is byte-identical to the reporter's version, and a byte-level audit
(offsets vs Bulbapedia's save map, all three checksums, a real
gameplay save round-trip, pokered's LoadMapData regenerating every
zeroed cache) shows the current export is structurally valid.
OverworldLoop (home/overworld.asm) jumps straight to .moveAhead while
wWalkCounter is nonzero: JoypadOverworld -- the START check, the A
check, and direction initiation -- only ever runs while the player
stands on a tile, and a button pressed mid-step is simply never seen.
The port ran handleInput() every frame regardless, so a mid-step
A/START pushed its TextBox/StartMenu right there and froze Red between
tiles, mid-animation (the Nurse Joy run-up in the report).
Gate handleInput on player.moving like the original. The port-invented
wall-bonk SFX cooldown is hoisted above the gate so it keeps ticking on
held-direction frames mid-step exactly as before.
Adds tests/parity_midstep_buttons.lua: mid-step and last-frame A/START
presses are swallowed and the step completes, and both buttons work
again once the player stands on the tile.
HoFDisplayPlayerStats prints its three dex texts (seen/owned, the
POKéDEX Rating: header, the tier line) through HoFPrintTextAndDelay ->
PrintText, the standard two-row bottom box, each followed by 120
DelayFrames. The port hand-drew a 6-row box and flattened the tier
text's cont (\v) rows into plain newlines, so a 3+ row rating painted
its third row over the box's bottom border and dropped the rest.
Push the three texts as a chain of auto-advancing TextBox states
instead: the cont rows scroll inside the two-row box with the original's
A/B wait (_ContText -> ManualTextScroll), and each box closes itself
after the 120-frame hold.
Adds tests/parity_hof_rating.lua: box order/content and the auto-close
hold are asserted over a full headless induction.
The vanilla surf/strength flow closed the menu, showed the overworld,
then fired a solid-white blink on the empty map, and set the surfing
sprite while the player was still on land. pokered's
GBPalWhiteOutWithDelay3 runs while the text is still up, so the blink
reads as a text flash.
The blink now sits under the textbox on the stack (only the top state
updates, so it holds its frames until the text closes), and surfing
applies only when the step onto the water happens. Same reorder for
the party-menu STRENGTH texts. The parity surf tests now dismiss the
got-on text before asserting the mount, matching the new order.
The Windows pickers shell out to PowerShell, which writes the chosen
path in the console's OEM codepage (CP437 on en-US): a file named
"Pokémon ...zip" came back as Pok\x82mon. The import then failed and
the error notice carrying those bytes hard-crashed the mods panel's
UTF-8-validating text draw.
- All three Windows picker scripts (ROM, mod, save) now force
[Console]::OutputEncoding to UTF-8, so returned paths and any notice
built from them are valid.
- The mod picker also copies the pick to a plain-ASCII temp name and
returns that, so a non-ASCII filename actually imports instead of
failing the io.open (Windows io.open needs ANSI bytes).
The intro API upgrade left six player-visible literals in OakSpeech's
FALLBACKS table outside the Strings routing, so the strings-coverage
gate failed on dev. Mark them with Strings.source, the catalog idiom
for declaration-site literals, and the gate is green again.
The zone pass composited two copies of the baked canvas on shake
frames: a base copy and the offset copy. The canvas holds window-layer
content (HUD names, the text box), so the vacated strip showed a full
second copy of the enemy name. Draw only the shifted copy and fill the
strip blank, like the hardware revealing empty BG.
main carried #299 (api upgrades, windows dev tools, android fixes) as a
single squash, while the same work reached dev through #297/#298/#269 and
was refined afterwards. Every conflicting hunk is dev already being ahead
of that squash:
- src/import/RomImporter.lua, src/ui/OakSpeech.lua: dev routes the launcher
and intro literals through src/core/Strings.lua, main still inlines them.
- src/pokemon/Sprites.lua: dev adds the Sprites.playerPath seam over
field.playerPics; OakSpeech's player pic resolves through it instead of
hardcoding trainer_card/red.png.
- tests/fs_io.lua: dev adds FsIo.globPrefix.
- tests/mod_qol_hooks_tests.lua, tests/mod_ui_tests.lua: dev adds the
player.sprite, #270 submenu-cancel and #308 finish-once coverage.
Resolved to dev on all six; the merged tree is byte-identical to dev, so
this only records the ancestry. T1/T2/T4 pass.
The shrink timeline called finish() every frame once past its end.
finish() emits finished and then pops the stack, so a listener that
pushes a screen (a warp, a menu) had that screen popped in the speech's
place: the speech stayed alive and re-fired the event every frame,
repeating the listener's side effects each time. Clear the shrink
state before finishing so the timeline cannot run finish() twice.
Co-authored-by: johnjohto <johnjohto@users.noreply.github.com>
Mods that widen field-move rules (use an HM without teaching it, a
rental mon) had to monkey-patch partyKnows, the one function every
field-move path funnels through. Wrap the vanilla check in a hook
instead: next_ is the whole badge-and-knows-move check, so a wrapper
that calls it first keeps vanilla answers winning and only fills the
cases vanilla denies. No hook, no behavior change.
Co-authored-by: johnjohto <johnjohto@users.noreply.github.com>
The battle textbox redraws its text every frame, but only while a
message was current. Once the player dismissed "Enemy X used GUST!"
and the move animation started, nothing drew the text, so the box sat
empty for the whole animation. The original game's animations never
touch the textbox, so the text stays up. Draw the held lines while an
animation is playing; everything else is unchanged.
Co-authored-by: johnjohto <johnjohto@users.noreply.github.com>
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>
* Make ROM-free test tiers actually run on Windows
Suite discovery, the extension-point catalog scan, mod test-dir pickup,
and the meta-coverage corpus all shelled out to ls/find/test -d, which do
not exist in cmd.exe. Every listing came back empty on Windows, so tiers
ran 0 suites and still reported ALL TESTS PASSED.
Add portable probes to tests/fs_io.lua (same Unix commands on
Linux/macOS; dir /b and a shell-free rename-self existence check on
Windows) and rewire the four call sites to them. 15/15 engine suites and
2/2 modkit suites now genuinely run and pass on Windows.
Fixes#266
* Make the T3 content tier run on Windows
The content tier had the same Unix-shell assumptions as the tier
discovery fixed in #267, one level down:
- run_tests.lua redirected to /dev/null when chaining tier runners
- mod_runtime_tests.lua called ffi setenv/unsetenv, which msvcrt lacks
(_putenv with an empty value unsets)
- modkit_tests.lua captured exit codes with POSIX '; echo 0' (cmd
needs /v:on and !errorlevel!), called python3 (python on Windows),
and used mkdir -p / rm -rf; cmd mkdir makes parents on its own and
read -p as a directory name
- the save-editor suites globbed save backups with ls
- tools/save-editor/Catalog.lua scraped mod flags with ls; this one
affects the real editor on Windows, not just tests
With a ROM imported, run_tests.lua goes from 12 failures to the 3 that
track the missing audio.lua generation (#268), which fails on any OS
and needs a maintainer decision.
---------
Co-authored-by: johnjohto <johnjohto@users.noreply.github.com>
* pop up a fake save
* add CI to dev branch
* Make ROM-free test tiers actually run on Windows (#267)
Suite discovery, the extension-point catalog scan, mod test-dir pickup,
and the meta-coverage corpus all shelled out to ls/find/test -d, which do
not exist in cmd.exe. Every listing came back empty on Windows, so tiers
ran 0 suites and still reported ALL TESTS PASSED.
Add portable probes to tests/fs_io.lua (same Unix commands on
Linux/macOS; dir /b and a shell-free rename-self existence check on
Windows) and rewire the four call sites to them. 15/15 engine suites and
2/2 modkit suites now genuinely run and pass on Windows.
Fixes#266
Co-authored-by: johnjohto <johnjohto@users.noreply.github.com>
* intro api upgrade (#294)
* intro api upgrade
* api updates
* fix tests
* updated templates
* android fixes for mods and saves (#297)
* Android SCALING fixes (#298)
* android fixes for mods and saves
* perhaps this is the true scaling android issue fix
---------
Co-authored-by: johnjohto <johtoboy@atomicmail.io>
Co-authored-by: johnjohto <johnjohto@users.noreply.github.com>
Suite discovery, the extension-point catalog scan, mod test-dir pickup,
and the meta-coverage corpus all shelled out to ls/find/test -d, which do
not exist in cmd.exe. Every listing came back empty on Windows, so tiers
ran 0 suites and still reported ALL TESTS PASSED.
Add portable probes to tests/fs_io.lua (same Unix commands on
Linux/macOS; dir /b and a shell-free rename-self existence check on
Windows) and rewire the four call sites to them. 15/15 engine suites and
2/2 modkit suites now genuinely run and pass on Windows.
Fixes#266
Co-authored-by: johnjohto <johnjohto@users.noreply.github.com>