When a scene-forced/fixed camera (e.g. the Spirit Temple boulder-room
alcoves, CAM_SET_PREREND_FIXED / Camera_Fixed3) drives the view, the Free
Look angles in play->camX/camY are left untouched while manualCamera stays
set. On exit, Camera_Free resumed from those stale pre-alcove angles, so
the camera snapped/reversed instead of following the player out.
This does NOT change the forced-camera behavior: the alcove still clamps
exactly as the game intends. It only fixes the hand-off back to Free Look:
when Camera_Free resumes after another camera function drove the previous
frame (detected via a frame-number gap), the free-look yaw/pitch are
re-seeded from the camera's current orientation so the view continues from
where it was left.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
GetAvailableAudioBackends()/GetAvailableWindowBackends() can report a backend
that has no entry in the static name maps (e.g. a newly added or platform-
specific backend), which made audioBackendsMap.at()/windowBackendsMap.at()
throw std::out_of_range and crash. Look up with find() (single lookup) and skip
backends that aren't named instead of dereferencing a missing key.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* Avoid `randomizer_check_tracker.h` in widely used `randomizer.h` due to transitive `libultraship.h`/`UIWidgets.hpp` inclusion
* Avoid `libultraship.h` inclusion in heavily used `GameInteractor.h` header
* Remove unused libultraship includes
* Break huge unneeded transitive include chain (via UIWidgets.hpp)
This avoids that changing just UIWidgets.hpp, for example, would retrigger a rebuild of like half the project.
There were a huge transitive include chains, mostly via MenuTypes.h and UIWidgets.hpp. Because of that, I'm splitting UIWidgets into a second header file UIWidgetOptions.hpp, which can be consumed by MenuTypes.h. MenuTypes.h is split into BackendTypes.h to avoid pulling in Fast3D/Windowing/GUI stuff into unrelated code.
Example chain, one of many:
libultraship.h <- UIWidgets.hpp <- MenuTypes.hpp <- randomizer/option.h <- randomizer/item_location.h <- trial.h <- static_data.h <- SeedContext <- (basically all randomizer related sources, lots of other sources in Enhancement, more...)
* Avoid libultraship.h in Notification.h and ObjectExtension.h; these headers are also heavily used
* Add missing include
* Remove unused libultraship includes
* Include only ship/window/GuiWindow.h in GUI-related headers instead of libultraship.h
* Cleanup ConfigUpdater.h and playthrough.cpp
* Remove libultraship.h from Anchor.h and fix transitive dependencies in OTRGlobals.cpp
* Remove unused libultraship.h includes in Anchor code
Adds new visuals for the open chest, climb, and crawl ability shuffles, including bespoke gi models more consistent with the rest of the game as well as unique icons for the item tracker
ImGui derives a control's ID from its visible label, and the menu search
page renders every widget in a single scope. Randomizer options that share
a label with an enhancement (e.g. "Blue Fire Arrows") therefore produced an
ID conflict on the search page.
Append a "##Randomizer" suffix to randomizer widget labels so their ImGui ID
is unique. The option's own name is left untouched since it is used as a
serialization key (spoiler logs, settings lookup); only the menu widget gets
the suffix.
SliderInt/SliderFloat draw their label themselves via ImGui::Text/CalcTextSize,
which (unlike ImGui's labeled widgets) don't strip a "##" suffix, so add a
visibleLabel with the suffix chopped off for display while keeping the full
label for the unique ID.
Co-authored-by: briaguya <70942617+briaguya0@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(camera): let free look release the door peek camera
After walking through a door, the door camera (CAM_SET_DOORC) held the view and
only handed control back once the player moved or pressed a button, so the right
stick did nothing until then. With free look the camera appeared frozen after
every door.
Treat right-stick movement as a release condition too, using the same stick
threshold as free-look activation.
* refactor(camera): move door-cam free-look release to a VB_SHOULD hook
Reimplements the door peek camera free-look release as a vanilla-behavior
hook instead of inline logic in z_camera.c, keeping the decomp file close
to upstream.
- Add VB_RELEASE_DOORC_CAMERA wrapping the existing Camera_Special9 release
condition; the vanilla button/xzSpeed expression is left untouched.
- Move the right-stick / free-look threshold logic into a new enhancement,
FreeLookDoorCamRelease.cpp, registered with COND_VB_SHOULD and gated on
FreeLook.Enabled so the hook only exists while Free Look is on.
Behavior is unchanged from the previous fix; this only relocates the logic.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Free Look pinned the camera to the fixed "Camera Distance" setting, so it never
pulled in or out the way the vanilla camera does for the current situation.
Add an opt-in "Follow Default Camera Distance" setting (FreeLook.UseGameDistance)
that uses the game's per-mode default distance instead. The fixed distance slider
is hidden while it is enabled.
Closes#4050
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The custom-sequence registration loop printed each assigned seqNum to
stdout via a bare printf, spamming the console with context-free numbers
on every launch. Convert it to LUSLOG_DEBUG and include the sequence name
so it is hidden by default yet useful for diagnosing music-pack loading.
The audio thread will now self-pump every 5 ms in case the rendering loop
takes too much time before waking up the audio thread, causing audio
starvation.
This is what was causing audio stutters/cuts during world loading.
I had the issue constantly the first time I pressed start to get the game
menu.
To avoid issues, the first wakeup of the audio thread is behind a `primed`
flag and will wait unconditionnally for the rendering loop to wake us up.
This is to make sure the game has initialized properly and avoid a crash
on boot.
The resolved replacement id (which can exceed 255) rode a single
per-player seqToPlay slot, written at enqueue but consumed
asynchronously on the audio thread; back-to-back starts and
priority-queue promotions clobbered it. sSeqFlags[0x6F] was also indexed
by raw id, reading out of bounds past the authentic range.
- func_800F9280 resolves the replacement and packs the full 16-bit id
into the 0x82/0x85 play command; the handler reads opArgs & 0xFFFF.
Audio_QueueSeqCmd no longer pre-writes the shared slot.
- SyncInitSeqPlayerInternal uses the command-carried id and bounds-checks
it against the calloc'd sequence map (+0xF headroom for reserved-range
skips).
- Route sSeqFlags reads through a bounded Audio_GetSeqFlags helper.
- Warn and skip gracefully past the 16-bit id limit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>