Use the official SDL 3.4.16 AAR through Prefab and build SDL_mixer
3.2.4 from fixed source. Remove the bundled SDL2 Java sources and make
Android an SDL3-only target.
Remove the helper layer and unit tests added solely for simple gain and
time expressions. Keep these conversions directly in their SDL3_mixer
backends instead of shaping production code around testability.
Share SDL3_mixer gain and 10-millisecond time conversions across the
PCM, BGM, CD, and MIDI backends. Add SDL3 unit coverage for volume
clamping, combined gain, time units, and tick counter wraparound.
Do not force the Timidity decoder based on TIMIDITY_CFG. Leave decoder
selection to SDL3_mixer unless SDL_SOUNDFONTS requires FluidSynth for
SDL2_mixer-compatible SoundFont handling.
Play MIDI through the shared SDL3_mixer music track while preserving
the existing loop, pause, volume, position, and fade behavior. Support
FluidSynth SoundFonts and Timidity selection through their established
environment variables.
Load playlist tracks through SDL3_mixer and play them on the shared
owner-aware music track. Preserve the CD-specific loop convention,
volume valancer, and playback position reporting.
Add an owner-aware music track shared by the SDL3 BGM, CD, and MIDI
backends. Use it to preserve exclusive music playback while moving BGM
loading, looping, fades, and volume control to SDL3_mixer.
Create shared SDL3_mixer device ownership and map the 129 PCM slots to
MIX_Track objects. Decode left/right WAV data through the public decoder
API before combining channels.
Map SDL2 and SDL3 event names, keyboard fields, touch queries, joystick
device identifiers, message boxes, and text input APIs through the common
interface. Keep the deferred touch deadline on the millisecond clock so
SDL3's nanosecond event timestamps are not mixed with SDL_GetTicks().
Map system cursor shapes to their SDL2 and SDL3 names and hide the
cursor destruction API difference. Also include the allocation
declarations required by the SDL3 debug build.
Unify SDL2 RWops and SDL3 IOStream operations for files, memory,
font resources, and WAV decoding. Keep stream close ownership explicit
and cover memory stream reads in both SDL configurations.
Emulate SDL2's clipped destination rectangle output when using SDL3.
Cover source clipping, destination clipping, and empty blits in the
SDL compatibility tests.
Wrap mutexes, condition variables, and atomic integers with common SDL2
and SDL3 types and semantics. Normalize timed condition waits to report
whether the condition was signaled.
Add the compile-time SDL major version option and propagate it through
interface targets. Route SDL includes through C99 compatibility headers
while keeping SDL2 as the desktop and Emscripten default.
Do not update the internal mouse position when cursor warping is
unavailable / disabled. System 3.8 and later can disable mouse automatic
cursor movement from the menubar, so no games for these versions are
designed with the assumption that this feature is available.
Use half-pixel outline emboldening for font sizes up to 22 pixels to
better match GDI's synthetic bold rendering of MS Gothic and MS Mincho.
Keep the existing full-pixel strength for larger sizes.
Restore the saved area for opaque menus as well as translucent ones.
Painting over highlights with the background color could erase glyph
pixels in the selected row and the next row.
Also match the original engine's menu item text position.
The EC bug exists only in System 3.8 and later. System 3.5 / 3.6 games
(e.g. Atlach=Nacha) need the patched behavior.
This deviates from System39.exe, which has the buggy behavior for older
scenarios too.
The dialog edited and drew its field by hand because microui's textbox
cannot display IME composition text.
Teach microui about compositions instead, and split mu_textbox_raw()
into input and drawing halves so the MJ inline editor can share the
input path while keeping the game's own appearance.
ctx->focus is a transient "pressed with the mouse" state, so it cannot
serve as a keyboard focus. Add a persistent ctx->kb_focus alongside it.
Controls enter the focus cycle from mu_update_control(), which every
widget already calls, so this needs no per-widget code.
Tab and Down move the focus forward, Shift+Tab and Up backward, Enter or
Space activates the focused control, and Left/Right adjust a focused
slider. The focused control is outlined with the new MU_COLOR_FOCUSRING;
window chrome is excluded via MU_OPT_NOKBNAV.
Store unit map attributes as vmvar_t and derive VR/VW transfer sizes
from their element type. This prevents buffer overruns after vmvar_t
became uint16_t and fixes upward movement in Rance IV.
Add scenario coverage for both transfer directions and verify that
adjacent variables remain intact.
EM_ASYNC_JS stringifies its function body without expanding macros. Pass
the BGM and sound-effect channel values through C wrapper functions so
the generated JavaScript receives numeric channel arguments.
System 3.9 saturates compound addition and multiplication at 65535,
while an overflowing ascending loop stores the wrapped 16-bit result
after testing the wide value.
Update the scenario expectations and regenerated fixture to cover both
cases. The suite passes with xsystem35 and the original System39.exe.