lets a translation keep chosen characters on the rom tiles instead of the ttf.
needed for japanese: sizing the font for kana makes latin narrower, which
knocks the party menu numbers out of line.
A mod index can now publish three optional per-entry fields -- downloads
(total across every release), first_release and last_release (ISO days) --
which the FIND MODS listing shows in the same gold line the MODS tab uses.
The fields are additive by design: feeds that carry them stay readable by
every build that predates them (schema_version stays 1), and feeds that do
not render exactly as before. ModUpdate.statsLine builds the shared line;
the MODS tab reuses it. Parser, formatting, and parse coverage are tested.
The MODS tab now shows each installed mod's total GitHub downloads
(summed asset download_count across all releases), its first and latest
release dates, and a Sort row (Name / Popularity / Release date /
Last updated) persisted in options.modSort.
The launcher already fetched per-repo release lists for update checks, so
the data rides the same cached fetch: parseRelease keeps download_count
and published_at, writeCache persists them, and a cache entry written
before the fields existed is treated as stale and refetched once instead
of hiding the line behind an old cache.
Opening Touch Controls dropped the launcher virtual cursor and swallowed
gamepad input while touch still worked. Share PadCursor with the save
editor, forward pad events, and centralize overlay handoff/resume so both
hosts park and re-arm the pointer cleanly.
Co-authored-by: Cursor <cursoragent@cursor.com>
Source:getChannelCount could skip the #626 widen on love-nx, and keeping
8-bit depth into a stereo buffer still sounded wrong on audren. Decode the
file via newSoundData, always emit 16-bit stereo like ChipSynth, and write
fresh pika-cry WAVs as stereo at extract time so re-imports skip the hop.
Co-authored-by: Cursor <cursoragent@cursor.com>
The Yellow boot suite only recorded newSource, so a missing sound.newSoundData
wrap (the silent hole that motivated the full-surface overlay) could still go
green. Force mono on the Source stub, record newSoundData, and assert the cry
re-read lands on yellow/. Also pin the three NX suites in scripts/test.sh T0
and fix the seed_chunk global leak in the fallback suite.
Co-authored-by: Cursor <cursoragent@cursor.com>
The overlay only wrapped the five loaders the boot path needed, leaving a
silent-failure hole: any future state (or current code like Sound.lua's
widenMono, which re-reads the pika-cry WAV via love.sound.newSoundData
with the caller's bare path) could load a generated asset through an
unwrapped API and silently degrade on hardware.
NxAssetOverlay now wraps every read-side love function that accepts a
filesystem path (filesystem.read/load/lines/newFileData/getInfo,
graphics.newImage/newFont, image.newImageData, audio.newSource,
sound.newSoundData, font.newFontData), so new states and mods fall inside
the Blue/Yellow fallback with zero per-call-site work. Write-side
functions stay stock, proven by identity assertions in the fallback
suite. The static guard's forbidden-literal list covers the same APIs.
Co-authored-by: Cursor <cursoragent@cursor.com>
checkBoulderPush had an isWarpTileCell escape hatch that let a boulder
be pushed onto any door/warp tile, walkable or not. In pokered,
CheckForCollisionWhenPushingBoulder walks the same wTilesetCollisionPtr
list as player movement (CheckTilePassable) -- there is no hole/warp
exception, so a boulder can never land on a cell the player cannot walk
onto.
The known push targets (CAVERN holes, Victory Road switches) are
walkable tiles in their tileset's coll list already, so removing the
escape hatch only stops pushing boulders into walls.
Fixes#754
Three layers, all running without a ROM:
- nx_yellow_boot_test.lua: drives the real Yellow and Blue boot states
(TitleState, YellowIntro + IntroMovie pre-roll for Yellow, IntroMovie
direct for Blue, Sound.playPikaCry) against a broken-mount filesystem
where generated art exists only under yellow|blue/, and asserts no bare
assets/generated path ever reaches the raw love loaders. This is the
runtime complement to the static literal guard: data-driven manifest
paths and formatted paths (cry_%02d.wav) are exactly what a source scan
cannot see. love_stub gains Image:setFilter/getFilter so IntroMovie
constructs headless.
- CI path gate: switch-changes now also triggers on the NX runtime
(NxAssetOverlay, Platform, GameVersion, CacheFs) and the NX engine
suites, so src-side NX regressions rebuild the fused NRO instead of
slipping through with green headless-only checks.
- switch-selftest runs the three NX engine suites headlessly on the
fork-safe ubuntu runner, giving PR feedback before the self-hosted Mac
build. The content gate and switch-build.md docs were updated in sync.
Co-authored-by: Cursor <cursoragent@cursor.com>
The scattered per-call-site prefix rewrites were a parallel track that any
future newImage("assets/generated/...") would silently bypass. Replace
them with NxAssetOverlay: installed once from love.load on NX only, it
wraps newImage / newImageData / newSource / filesystem.read / getInfo so a
missing assets/generated path falls back to the active version's
blue|yellow copy. Call sites return to plain love loader calls, and
Assets.resolve goes back to being the platform-free mod-override point.
Two deliberate exceptions remain: the chip-audio worker (separate Lua
state) keeps receiving the prefix explicitly via audio.programPrefix, and
data/generated module loads keep using CacheFs.readActive.
A new guard test (tests/engine/nx_generated_guard_test.lua) fails CI on
any direct love loader call with a literal assets/generated path, so the
class of bug cannot regress by accident. scripts/test.sh --quick is
green across all tiers.
Co-authored-by: Cursor <cursoragent@cursor.com>
Five more places called love.graphics.newImage directly on
assets/generated paths, bypassing the NX prefix rewrite:
- TradeAnim: cable/ball/bubble art
- TownMap: Kanto background, cursor, nest icon
- SurfingMinigame: surf bg/ob sheets
- BattleState: party ball row, substitute doll
All now resolve through Assets.resolve, which maps to the versioned
blue/ or yellow/ save-dir prefix on NX only. Desktop and Android keep
the mountVersion overlay behavior unchanged.
Co-authored-by: Cursor <cursoragent@cursor.com>
Yellow music was still silent because the background worker thread loads
ChipSynth.lua in a fresh Lua state with no GameVersion/Platform context.
The main thread's prefix never reached it.
ChipAudio.slimAudio now resolves the versioned cache prefix on the main
thread and includes it in the audio payload as `programPrefix`.
ChipSynth.loadBanks prefers `audio.programPrefix` when present, falling
back to its own NX detection for the sync path. Blue and Yellow are
handled the same way.
Tests cover the worker prefix hand-off and Blue's programs.bin path.
Co-authored-by: Cursor <cursoragent@cursor.com>
The previous NX gate only rewrote image paths that go through Assets.resolve.
Pokemon Yellow still had no sound and a blank title screen because:
- ChipSynth reads programs.bin directly via love.filesystem.read, bypassing
Assets. On NX the unprefixed path is missing when the mount overlay fails,
so the engine never built and every song/SFX was silent.
- Sound.playPikaCry loads pika_cries WAVs with love.audio.newSource, also
bypassing Assets.resolve.
- TitleState, YellowIntro, and IntroMovie call love.graphics.newImage
directly on unprefixed assets/generated paths, so the Pikachu title and
intro atlases failed to load.
Fix: apply the same NX-only prefix rewrite in those four places.
Desktop/Android keep the existing mountVersion overlay behavior.
Also add ChipSynth._loadBanksForTest and tests covering the new paths.
Co-authored-by: Cursor <cursoragent@cursor.com>
Capture resolve paths and newImage open results for Yellow/Blue art
triage without enabling switch-debug.txt.
Co-authored-by: Cursor <cursoragent@cursor.com>
Desktop and Android keep mountVersion as the overlay; only love-nx
resolves assets/generated to yellow|blue/ save-dir paths.
Co-authored-by: Cursor <cursoragent@cursor.com>
NX fused mount often cannot expose assets/generated; open the real
yellow|blue/assets/generated file with newImage instead of FileData.
Co-authored-by: Cursor <cursoragent@cursor.com>
Probe generated canaries after mountVersion and always readActive for
prefixed caches so sprites are not blanked by empty PhysFS stubs.
Co-authored-by: Cursor <cursoragent@cursor.com>
Disable mouse-yield on NX where stick/touch moves the system pointer between sparse axis events, clamp pad dt, pixel-snap the overlay, and soften FlexLove GC so the launcher cursor stays steady.
Co-authored-by: Cursor <cursoragent@cursor.com>
Only resize when width/height change; love-nx flag mismatches were
recreating the EGL surface every frame.
Co-authored-by: Cursor <cursoragent@cursor.com>
Mirror Data:load's versioned CacheFs read in Assets so Yellow-only NX
Play survives intro without needing a Red root cache mask.
Co-authored-by: Cursor <cursoragent@cursor.com>
Unlock love-nx SDL dock/undock resizing and sync via NxDisplay so
booting docked is not stuck on the conf 720p hint.
Co-authored-by: Cursor <cursoragent@cursor.com>