The right stick was never a second analog stick as far as the game is
concerned: bondmove.c reads it as contpad1's rstick, which is PD's own
two-controller look mode. That is a different scheme from the one the N64
shipped with, where the analog stick does all movement and the C buttons
handle looking and sidestepping.
The overlay now matches the hardware: one stick, plus the C buttons in their
diamond where the second stick used to be. How the stick divides between
walking and turning is the game's Control Style setting, as it should be.
The right-stick path is removed rather than left dormant -- touchSetStick and
touchGetStick lose their stick index, inputReadController stops writing
rstick, and the look-sensitivity slider goes with it, since it only ever
scaled the stick that no longer exists.
Verified on device: C-up pitches the view, and the stick still drives
movement and turning.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Tested on a Moto G 2025 (1604x720 landscape, Android 16), which is where all
of these showed up.
Look control was invisible. It was a transparent drag region rather than a
stick, and the scattered buttons sat on top of it, so there was nothing to
grab. It is now a real, drawn right stick mirroring the left one, and both
sticks are fixed rather than floating: deflection is measured from the
control's own centre, so what is under the thumb is what the game is told.
Layout was sized as a fraction of viewport height and positioned as a
fraction of width. On a 2.2:1 screen that made every button small and flung
them across the middle of the play area. Controls are now placed in dp from
the nearest corner, so they hold their physical size and grouping across
aspect ratios, and nothing sits over the centre of the screen.
Labels said Q, L, <, CR. They now say what the control does, with the N64
button underneath, auto-sized to fit the circle.
Quick taps could be dropped entirely: inputReadController() samples the pad
once a frame, so a press and release inside 16ms was never observed. Newly
pressed bits are latched in touch.c and reported for at least one frame.
Launcher showed a purple ActionBar over the title and ran under the status
and navigation bars. AppCompat reads the unprefixed windowActionBar and
windowNoTitle attributes, not the android: ones, so the theme now uses the
NoActionBar parent, and the content pads itself by the system bar and
display cutout insets -- which land on the short edges in landscape, exactly
where the buttons are.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
On-screen controls
* port/src/touch.c holds a virtual pad written by the Android UI thread and
read by inputReadController() on the SDL thread, so state is kept in
atomics and sticks in fixed point.
* inputReadController() folds it into player 1 before the gamepad section,
so a physical pad still fills in whatever the overlay is not deflecting.
* TouchControls is a transparent full-screen view above SDLSurface. It only
consumes a pointer that lands on a control and returns everything else to
the view below, so SDL still sees taps as mouse input in menus.
* Buttons are hit-tested ahead of the look area, so a press near a button
never spins the camera.
* Layout is normalised to the viewport and editable in place: tap the toggle
to hide/show, hold it to drag and pinch controls around. Saved per device.
* The overlay hides itself, and stops consuming touches, while a physical
controller is attached.
Mods
* Mods live in <externalFilesDir>/mods/<name>/ and the selected one is passed
as --moddir, which the port overlays on the ROM's files.
* The launcher imports a mod from a .zip, guarding against Zip Slip and
absurd unpacked sizes, and hoists a single wrapper folder if there is one.
Netplay
* INTERNET/ACCESS_NETWORK_STATE for enet.
* Keep the in-game console on Android: it is how netplay reports and chats,
and SDL raises the soft keyboard when the game asks for text.
* Predictive back is disabled for the game activity, since SDL routes Back
through the legacy onBackPressed() path.
Also removes GameView.java, which drove a GLSurfaceView path the port never
used, along with the no-op JNI stubs it called into.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Android:
* compileSdk/targetSdk 34 -> 36, minSdk 21 -> 30, ANDROID_PLATFORM android-30
* pin ndkVersion 27.2.12479018, AGP 8.1.2 -> 9.2.1, Gradle 8.0 -> 9.4.1
(Gradle 9.x is what runs on the JDK 25 that Android Studio now ships)
* Java 8 -> 17, javac encoding pinned to UTF-8
* drop the x86 ABI: no 32-bit x86 devices exist at minSdk 30, and it was
a third of the native build time
* refresh AndroidX dependencies
Fixes found while getting the above to build:
* AssetUtils invoked a bare `python` on Windows and Android, which does not
exist on distros that only ship `python3`. Use the interpreter CMake finds,
on every platform.
* os_libc.h re-declared bcopy/bcmp/bzero, which clashes with bionic's
fortified overloadable versions; include <strings.h> on Android instead,
the same way OSX is already special-cased.
* libultra.c defined those same wrappers, which bionic already provides.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Brings upstream netplay (enet, port/src/net/*, netmenu) onto the branch
carrying the Android port.
Conflict resolutions:
* system.c: sysLogPrintf levels now carry LOGFLAG_ bits, so mask them off
before indexing prefix[]. The in-game console is kept on Android too,
since netplay reports through it.
* main.c: keep conInit()/netInit() alongside the Android boot logging.
* menutick.c / constants.h: combine both sides.
Also fixes two build breaks found on the way:
* main.c called SDL_Init/SDL_GL_SetAttribute outside #ifdef ANDROID while
SDL.h was only included for Android, breaking every desktop build.
* net/netmsg.c used strcasecmp without <strings.h>.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This enables HIDAPI support for Steam Controller (Bluetooth only) and Steam Deck.
Note: while SteamDeck HIDAPI is enabled, it works best while in Desktop Mode and without Steam Client running in the background (will show the actual device name instead of "Steam Virtual Gamepad"). It may not support more advanced feature sets, and it only remains that case until Valve adds Motion Sensor passthru support to SDL2/SDL3 while using SteamInput.
- only load the MP setup file when loading the agent, instead of when entering CS
- "clear default" was cause the game setup to become invalid upon re-entering it
- all challenges were showing the same text