Under pipefail, unzip|grep -q exits 141 when grep closes early on a
match and aborts mac pack. List once to a file, then grep the listing.
Co-authored-by: Cursor <cursoragent@cursor.com>
OLED pass at 2699c9a: physical A confirms, B cancels; game.love
a208b21e… recorded. T19 suspend×10 still open.
Co-authored-by: Cursor <cursoragent@cursor.com>
SDL labels south as a and east as b; on Switch remap so physical A
confirms and physical B cancels in launcher and NamingScreen.
Co-authored-by: Cursor <cursoragent@cursor.com>
love-nx emits gamepad+raw on one press; NamingScreen saw a+b and always
erased. Skip raw when isGamepad(); align NX Y→a/X→b; prefer A if both.
Co-authored-by: Cursor <cursoragent@cursor.com>
Layout interactive UI against love.window.getSafeArea so notch, Dynamic Island, and home-indicator insets no longer clip controls, while keeping the game framebuffer edge-to-edge.
Co-authored-by: Cursor <cursoragent@cursor.com>
Pressing Import ROM on iOS takes the whole app down:
src/import/RomImporter.lua: attempt to call field 'pickFile' (a nil value)
love.system.pickFile is a NATIVE BRIDGE, not part of LOVE. It exists only on
builds that compiled one -- Android, and iOS builds patched by
mobile/ios/patch_love_src.py -- so on a build without it the field is simply
nil. RomImporter:546 routes iOS down the same path as Android
(`mobileOS == "Android" or mobileOS == "iOS"`), and all three mobile pick
sites called the field unguarded.
That is why the reports say "any version": nothing about it is version
specific. Red, Blue and Yellow all reach the same call.
Every one of those call sites already handles a device with no document
picker -- Choose falls back to "No picker available, copy your ROM into:"
plus the save directory, and the mod / save rows have their own notices --
and love.system.createFile at its single call site was already guarded this
way. These three were not, so the fallback that was written for exactly this
case could never be reached.
Route them through one small helper that answers false when the bridge is
absent. A build without a picker now degrades to the copy-into-the-save-folder
flow, which on iOS is a working path: the Files app exposes the app's
Documents folder and GRBootstrap sweeps what lands there into the save dir.
tests/rom_importer_no_picker_test.lua covers Import ROM, Import mod and
Import save with the bridge missing, and asserts the picker is still used
when it is present. Reverting the fix reproduces the reported error exactly.
Reported in #482 (confirmed by three people) and #512.
love.system.syncHealthSteps() now exists on Android, matching the iOS
Health bridge merged in #452 and using the same JNI route as the SAF
picker (wrap_System.cpp -> System.cpp -> common/android.cpp ->
GameActivity over JNI):
- GameActivity.syncHealthSteps: one-shot read of the hardware
TYPE_STEP_COUNTER sensor (cumulative since boot, counted by the OS
whether or not any app runs). The reading is anchored in
SharedPreferences so a walk is never credited twice; a reading below
the anchor means the phone rebooted, which re-anchors without
crediting. Deltas (50k clamp) merge into steps_pending.json in the
save identity dir - the same contract as the iOS GRHealthBridge, so
the Pokewalker mod works unchanged on both platforms.
- ACTIVITY_RECOGNITION declared in the app manifest (Android 10+
runtime prompt on first sync; granted -> the sensor read runs
immediately via onRequestPermissionsResult). The build script's
permission trim leaves it alone.
- Nothing in the base game calls the new seam; without a consumer mod
the only cost is one dormant manifest permission.
- build_android.sh: shadow-build from a space-free temp dir when the
checkout path contains spaces - ndk-build is GNU make underneath and
cannot cope with paths like "xCode Projects".
- mobile/ANDROID.md: step-bridge dev notes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Introduce a tuned .luacheckrc and scripts/lint.sh so the engine has a
standing static-analysis baseline -- the tool that would have caught both
bugs in the previous commit before they shipped.
The config is high-signal by design: it keeps the categories that catch
real defects (undefined globals/locals, unused values, unreachable code)
and mutes the cosmetic ones the codebase deliberately lives with (a self/dt
an interface requires but a method ignores, documented empty fall-through
branches, long lines). It marks `love` mutable (games assign callbacks onto
it) and teaches it LuaJIT's table.unpack.
.luacheckrc is tracked via a .gitignore exception, matching how .github and
.gitignore opt out of the blanket dotfile ignore.
`luacheck src` now reports 7 benign warnings and 0 errors, down from 185.
Also drop one dead `require` (ItemEffects loaded src.pokemon.Pokemon and
never used it).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q6bFAiQyZ5jDmewsbB4LG9