Importing Red unpacked data/generated, assets/generated and
rom-cache.complete straight into the save-dir root, while Blue and
Yellow land under blue/ and yellow/. Red now uses cachePrefix red/
like the others.
CacheFs.migrateLegacyRedCache moves a pre-existing root cache into
red/ on first boot, from RomImporter.new before the readiness loop
and from mountVersion, so existing installs keep their import instead
of being asked for the ROM again. The move only runs when the root
marker resolves to the save directory, so a dev checkout's source
tree is never touched, and the portable game folder is skipped when
it is the physfs source.
Closes#899
Scan asset objects by brace bounds instead of an 800-byte window so
browser_download_url survives fat uploader blocks; mirror logic in Lua
and add realistic API fixtures.
The modkit validate and pack drivers run the real loader under plain
luajit, with no love global. With --base imported, Data:load falls
back to CacheFs.readActive for a generated module require cannot find
(an optional module like data/generated/audio.lua is legitimately
absent from developer and stale caches), and CacheFs.read indexed
love.filesystem once there was no portable root, so validate and pack
died with MK100 before the mod was even looked at. Headless there is
no save directory to read from, so return nil like any other cache
miss.
Refs #850
Ships a dual-NRO native launcher that checks GitHub Releases, updates both NROs from gen1recomp-*-switch.zip with matching NACP versions, and stays silent unless an update needs confirm.
The SAVE FILES card only accepted saves of exactly 32768 bytes and
refused anything else. importToSlot now classifies a non-32768 file by
the integrity of its main-data checksum instead:
- Oversize + valid checksum -> an emulator RTC footer, so the launcher
asks for confirmation, then truncates to 32768 on force.
- Oversize + invalid checksum -> rejected.
- Undersize + valid checksum -> imports zero-padded; otherwise refused.
Adds the "Oversized save file" confirm modal, a new vendor-oracle test
built by gen1lib (PKHeX-derived) run as its own Lua 5.4 tier, oversize/
truncated policy tests, and the LUA54 wiring in test.sh.
# Conflicts:
# src/import/LauncherView.lua
The launcher spent ~9ms per frame building and drawing, and the Find Mods
tab could hang the window for minutes. Both had the same root cause: a
retained UI tree rebuilt every frame, and blocking curl calls made from the
draw path.
Replace the vendored FlexLove engine (28.5k lines) with src/ui/kit/ (Kit,
Theme, Layout, Loader). The kit caches Text objects and all measurement,
allocates nothing in the steady state, and draws flat. Build+draw is now
under 1ms at every window size and on every tab (POKEPORT_LAUNCHER_PROF).
Move every network call off the render thread onto a love.thread pool
(src/net/Fetch.lua): mod index fetches, per-mod release checks, find-tab
stats, thumbnails and mod installs. Mod indexes prewarm at boot so the
Find Mods tab is populated before it is opened.
Paginate every list -- mods, find, save slots, settings, release notes,
versions -- with the page size derived from the real viewport height, so a
500-mod index costs what a 10-mod one does. Scrolling is gone.
Anything that waits now raises a non-dismissable loader; per-row background
work shows an inline spinner instead. The in-app updater moves to the top
right beside the settings gear and pulses when an update is waiting.
Theme is black with white outlines, no gradients or glows, and solid
colour-coded embossed buttons with bold labels. The game tabs keep their
cartridge colours. Everything is 1.3x larger. The save editor shares the
theme, and adding an item there is now a searchable pop-up like adding a
Pokemon.
Also:
- Reset rebinds, in Settings and under Touch Controls. Rebinds are additive
(Input:applyBindings layers them over the defaults), so there was no
in-game way to undo one.
- Launch options: --game red [--slot N] / POKEPORT_GAME boots straight into
a game for shortcuts and frontends, falling back to that game's tab when
its ROM is not imported.
Fixes found while porting:
- Ellipsis and letterspacing truncated bytes, not codepoints, so a
multi-byte mod name crashed the first frame on a Japanese index.
Measurement no longer throws on malformed input either.
- The new font set missed UiFont's kana fallback, rendering translated
builds as tofu.
- Fetch workers idle in Channel:demand() and LOVE waits for live threads at
exit, so the process outlived the window; quitting mid-download also
waited on curl's 300s ceiling. Shut the pool down in love.quit and bound
its transfer timeouts.
- In one column the save-slot card drew below the fold, over the footer,
with no scrollbar left to reach it.
The two FlexLove engine tests guarded a scroll manager and an auto-height
propagation bug that no longer exist; replace them with a kit suite covering
page bounds, viewport sizing and UTF-8 truncation, and retarget the NX test
to assert the dependency is gone rather than that its perf guards are set.
A focus flip, visibility flip, joystick add/remove, or resume reset all
held input, and a still-held direction never re-fires keypressed, so any
spurious reset (macOS Bluetooth re-enumeration fires joystickadded with
no hotplug) parked the player until every direction was re-pressed.
Reconcile from device ground truth after each reset; only what is
physically down comes back, so swallowed releases still clear.
The originals run GiveItem before printing the received texts, and when
the bag can't hold the TM they print a make-room line instead and leave
EVENT_GOT_TM* unset, so talking to the leader again retries the give.
The victory reward path added the TM straight into the inventory, so a
full bag went to 21/20.
Route the gym TM give through Bag.add, split the TM lines out of the
victory dialogue table into tmPre/tmDialogue/noRoom, and port the
beaten-leader middle branch that re-runs the ReceiveTM script. Saves
that already hold the TM without the flag count as received so they
don't collect a second copy.
Refs #797
In pokered, MainInBattleLoop calls HandlePoisonBurnLeechSeed right
after every Execute*Move (core.asm:426-464), so a seeded, poisoned or
burned mon takes its residual before the slower side acts. The port
ran the whole sweep in endOfTurn, which made leech seed behave like
Gen 3+ and never showed the drain animation (#784).
The residual sweep now runs per action under the gen1_faithful
ruleset, gated by a new residualAfterMove flag; modern_clean keeps
the end of round sweep. The leech seed drain plays the ABSORB
animation from the healing side, the way the original flips
hWhoseTurn before PlayMoveAnimation. Item, ball, failed run and
ghost-fear turns still tick the player's residual, matching
ExecutePlayerMoveDone.