From 463df67005499f8ca974189978d1a01d9ea56987 Mon Sep 17 00:00:00 2001 From: William Emerison Six Date: Sun, 26 Apr 2026 17:05:19 -0400 Subject: [PATCH 1/8] cheat - always fly on triple jump --- src/game/mario.c | 7 +++++-- src/game/mario_actions_airborne.c | 5 ++++- src/game/mario_actions_moving.c | 6 +++++- src/port/hooks/list/PlayerEvent.h | 15 ++++++++++++++ src/port/mods/PortEnhancements.cpp | 25 +++++++++++++++++++++++ src/port/ui/GhostshipMenuEnhancements.cpp | 8 ++++++++ 6 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/game/mario.c b/src/game/mario.c index a8cd78ddb..89dbee6ec 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -789,9 +789,12 @@ static u32 set_mario_action_airborne(struct MarioState *m, u32 action, u32 actio m->forwardVel *= 0.8f; break; - case ACT_FLYING_TRIPLE_JUMP: - set_mario_y_vel_based_on_fspeed(m, 82.0f, 0.0f); + case ACT_FLYING_TRIPLE_JUMP: { + f32 launchVelocity = 82.0f; + CALL_EVENT(FlyingTripleJumpLaunch, m, &launchVelocity); + set_mario_y_vel_based_on_fspeed(m, launchVelocity, 0.0f); break; + } case ACT_WATER_JUMP: case ACT_HOLD_WATER_JUMP: diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 165f94fe3..e5c43cc7d 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -14,6 +14,7 @@ #include "save_file.h" #include "rumble_init.h" #include "seq_ids.h" +#include "port/hooks/list/PlayerEvent.h" void play_flip_sounds(struct MarioState *m, s16 frame1, s16 frame2, s16 frame3) { s32 animFrame = m->marioObj->header.gfx.animInfo.animFrame; @@ -1708,7 +1709,9 @@ s32 act_flying(struct MarioState *m) { return set_mario_action(m, ACT_GROUND_POUND, 1); } - if (!(m->flags & MARIO_WING_CAP)) { + bool canFly = (m->flags & MARIO_WING_CAP) != 0; + CALL_EVENT(FlyingActionUpdate, m, &canFly); + if (!canFly) { if (m->area->camera->mode == CAMERA_MODE_BEHIND_MARIO) { set_camera_mode(m->area->camera, m->area->camera->defMode, 1); } diff --git a/src/game/mario_actions_moving.c b/src/game/mario_actions_moving.c index 884a23ede..07f6df1c6 100644 --- a/src/game/mario_actions_moving.c +++ b/src/game/mario_actions_moving.c @@ -13,6 +13,7 @@ #include "behavior_data.h" #include "rumble_init.h" #include "seq_ids.h" +#include "port/hooks/list/PlayerEvent.h" struct LandingAction { s16 numFrames; @@ -146,7 +147,10 @@ void slide_bonk(struct MarioState *m, u32 fastAction, u32 slowAction) { } s32 set_triple_jump_action(struct MarioState *m, UNUSED u32 action, UNUSED u32 actionArg) { - if (m->flags & MARIO_WING_CAP) { + bool useFlyingVariant = (m->flags & MARIO_WING_CAP) != 0; + CALL_EVENT(SetTripleJumpAction, m, &useFlyingVariant); + + if (useFlyingVariant) { return set_mario_action(m, ACT_FLYING_TRIPLE_JUMP, 0); } else if (m->forwardVel > 20.0f) { return set_mario_action(m, ACT_TRIPLE_JUMP, 0); diff --git a/src/port/hooks/list/PlayerEvent.h b/src/port/hooks/list/PlayerEvent.h index 7f0c274c9..4c5190904 100644 --- a/src/port/hooks/list/PlayerEvent.h +++ b/src/port/hooks/list/PlayerEvent.h @@ -43,6 +43,21 @@ DEFINE_EVENT(PlayerExecuteAction, u32 arg; ); +DEFINE_EVENT(SetTripleJumpAction, + struct MarioState* m; + bool* useFlyingVariant; +); + +DEFINE_EVENT(FlyingActionUpdate, + struct MarioState* m; + bool* canFly; +); + +DEFINE_EVENT(FlyingTripleJumpLaunch, + struct MarioState* m; + f32* launchVelocity; +); + DEFINE_EVENT(ItemCollected, int16_t type; struct MarioState* marioState; diff --git a/src/port/mods/PortEnhancements.cpp b/src/port/mods/PortEnhancements.cpp index a942679e8..38c0558fa 100644 --- a/src/port/mods/PortEnhancements.cpp +++ b/src/port/mods/PortEnhancements.cpp @@ -84,6 +84,28 @@ void PortEnhancements_Init() { } }); + REGISTER_LISTENER(SetTripleJumpAction, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + if (CVarGetInteger("gCheats.AlwaysFlyTripleJump", 0) == 0) { + return; + } + SetTripleJumpAction* ev = (SetTripleJumpAction*)event; + *ev->useFlyingVariant = true; + }); + REGISTER_LISTENER(FlyingActionUpdate, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + if (CVarGetInteger("gCheats.AlwaysFlyTripleJump", 0) == 0) { + return; + } + FlyingActionUpdate* ev = (FlyingActionUpdate*)event; + *ev->canFly = true; + }); + REGISTER_LISTENER(FlyingTripleJumpLaunch, EVENT_PRIORITY_NORMAL, [](IEvent* event) { + if (CVarGetInteger("gCheats.FlyingTripleJumpHighLaunch", 0) == 0) { + return; + } + FlyingTripleJumpLaunch* ev = (FlyingTripleJumpLaunch*)event; + *ev->launchVelocity = 246.0f; + }); + auto OnDistanceFunc = [](IEvent* event) { if (CVarGetInteger("gEnhancements.DisableDrawDistance", 0) == 0) { return; @@ -117,6 +139,9 @@ void PortEnhancements_Register() { REGISTER_EVENT(PlayerStartedDialog); REGISTER_EVENT(PlayerDeath); REGISTER_EVENT(PlayerExecuteAction); + REGISTER_EVENT(SetTripleJumpAction); + REGISTER_EVENT(FlyingActionUpdate); + REGISTER_EVENT(FlyingTripleJumpLaunch); // Register Rando Events REGISTER_EVENT(ItemCollected); diff --git a/src/port/ui/GhostshipMenuEnhancements.cpp b/src/port/ui/GhostshipMenuEnhancements.cpp index e6b1ff7f2..1ef19f16e 100644 --- a/src/port/ui/GhostshipMenuEnhancements.cpp +++ b/src/port/ui/GhostshipMenuEnhancements.cpp @@ -177,6 +177,14 @@ void GhostshipMenu::AddMenuEnhancements() { .CVar(CVAR_CHEAT("PlayInDemo")) .RaceDisable(false) .Options(CheckboxOptions().Tooltip("Allows normal gameplay when a demo is playing.")); + AddWidget(path, "Always Fly on Triple Jump", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("AlwaysFlyTripleJump")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Triple jumping always starts flying, as if you always have the Wing Cap.")); + AddWidget(path, "Triple Jump High Launch", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_CHEAT("FlyingTripleJumpHighLaunch")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Flying triple jump launches 3x higher than normal.")); } } // namespace GhostshipGui From 8a0f3fd4b0f8bf1543a33ca726ca90592181ec4e Mon Sep 17 00:00:00 2001 From: Wellington Dias Date: Thu, 14 May 2026 00:26:05 -0300 Subject: [PATCH 2/8] setting up variables and settings screen widgets --- include/types.h | 5 ++ src/game/camera.h | 1 + src/game/camera_settings.h | 26 +++++++++ src/game/game_init.c | 43 +++++++++++++- src/port/ui/GhostshipMenuEnhancements.cpp | 71 +++++++++++++++++++++++ 5 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 src/game/camera_settings.h diff --git a/include/types.h b/include/types.h index 501a506c2..968f17b3a 100644 --- a/include/types.h +++ b/include/types.h @@ -28,6 +28,11 @@ struct Controller { #if ENABLE_RUMBLE /*0x1C*/ s32 port; #endif + /*0x20*/ s16 rawStick2X; + /*0x22*/ s16 rawStick2Y; + /*0x24*/ float stick2X; // [-64, 64] positive is right + /*0x28*/ float stick2Y; // [-64, 64] positive is up + /*0x2C*/ float stick2Mag; // distance from center [0, 64] }; typedef f32 Vec2f[2]; diff --git a/src/game/camera.h b/src/game/camera.h index b8bcf2def..8cd43ae2b 100644 --- a/src/game/camera.h +++ b/src/game/camera.h @@ -9,6 +9,7 @@ #include "engine/graph_node.h" #include "level_table.h" +#include "camera_settings.h" /** * @file camera.h diff --git a/src/game/camera_settings.h b/src/game/camera_settings.h new file mode 100644 index 000000000..1654a14e5 --- /dev/null +++ b/src/game/camera_settings.h @@ -0,0 +1,26 @@ +#ifndef CAMERA_SETTINGS_H +#define CAMERA_SETTINGS_H + +#define DEFAULT_CAMERA_MODE CVarGetInteger("gEnhancements.Camera.DefaultMode", 0) +#define ALTERNATE_CAMERA_MODE CVarGetInteger("gEnhancements.Camera.AlternateMode", 0) +#define HORIZONTAL_ANALOG_CAMERA CVarGetInteger("gEnhancements.Camera.HorizontalAnalog", 0) +#define VERTICAL_ANALOG_CAMERA CVarGetInteger("gEnhancements.Camera.VerticalAnalog", 0) +#define IMPROVED_C_BUTTON_CAMERA CVarGetInteger("gEnhancements.Camera.ImprovedCButtonCamera", 0) +#define CENTER_CAMERA_BUTTON CVarGetInteger("gEnhancements.Camera.CenterCameraButton", 0) +#define INVERTED_HORIZONTAL_CAMERA CVarGetInteger("gEnhancements.Camera.InvertedHorizontalCamera", 0) +#define INVERTED_VERTICAL_CAMERA CVarGetInteger("gEnhancements.Camera.InvertedVerticalCamera", 0) +#define CAMERA_SPEED CVarGetFloat("gEnhancements.Camera.CameraSpeed", 32.0) +#define CAMERA_DISTANCE CVarGetFloat("gEnhancements.Camera.CameraDistance", 100) +#define CAMERA_DISTANCE_ZOOMED_OUT CVarGetFloat("gEnhancements.Camera.CameraDistanceZoomedOut", 150) +#define ADDITIONAL_CAMERA_DISTANCE CVarGetFloat("gEnhancements.Camera.AdditionalCameraDistance", 0) + +#define ANALOG_AMOUNT (12 * (1 - INVERTED_HORIZONTAL_CAMERA * 2)) +#define ANALOG_AMOUNT_VERTICAL (12 * (1 - INVERTED_VERTICAL_CAMERA * 2)) +#define LROTATE_SPEED 0x400 + +#define VERTICAL_MIN 6144.0f +#define VERTICAL_MAX 12288.0f +#define VERTICAL_MAX_LIMITED 8192.0f +#define VERTICAL_MAX_PITCH 9216.0f + +#endif // CAMERA_SETTINGS_H diff --git a/src/game/game_init.c b/src/game/game_init.c index 0295054c8..5f5611c04 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -438,8 +438,10 @@ void adjust_analog_stick(struct Controller *controller) { // Reset the controller's x and y floats. controller->stickX = 0; controller->stickY = 0; + controller->stick2X = 0; + controller->stick2Y = 0; - // Modulate the rawStickX and rawStickY to be the new f32 values by adding/subtracting 6. + // Modulate the rawStickX, rawStickY, rawStick2X and rawStick2Y to be the new f32 values by adding/subtracting 6. if (controller->rawStickX <= -8) { controller->stickX = controller->rawStickX + 6; } @@ -456,10 +458,29 @@ void adjust_analog_stick(struct Controller *controller) { controller->stickY = controller->rawStickY - 6; } + if (controller->rawStick2X <= -8) { + controller->stick2X = controller->rawStick2X + 6; + } + + if (controller->rawStick2X >= 8) { + controller->stick2X = controller->rawStick2X - 6; + } + + if (controller->rawStick2Y <= -8) { + controller->stick2Y = controller->rawStick2Y + 6; + } + + if (controller->rawStick2Y >= 8) { + controller->stick2Y = controller->rawStick2Y - 6; + } + // Calculate f32 magnitude from the center by vector length. controller->stickMag = sqrtf(controller->stickX * controller->stickX + controller->stickY * controller->stickY); + controller->stick2Mag = + sqrtf(controller->stick2X * controller->stick2X + controller->stick2Y * controller->stick2Y); + // Magnitude cannot exceed 64.0f: if it does, modify the values // appropriately to flatten the values down to the allowed maximum value. if (controller->stickMag > 64) { @@ -467,6 +488,12 @@ void adjust_analog_stick(struct Controller *controller) { controller->stickY *= 64 / controller->stickMag; controller->stickMag = 64; } + + if (controller->stick2Mag > 64) { + controller->stick2X *= 64 / controller->stick2Mag; + controller->stick2Y *= 64 / controller->stick2Mag; + controller->stick2Mag = 64; + } } /** @@ -551,6 +578,8 @@ void read_controller_inputs(void) { if (controller->controllerData != NULL) { controller->rawStickX = controller->controllerData->stick_x; controller->rawStickY = controller->controllerData->stick_y; + controller->rawStick2X = controller->controllerData->right_stick_x; + controller->rawStick2Y = controller->controllerData->right_stick_y; controller->buttonPressed = controller->controllerData->button & (controller->controllerData->button ^ controller->buttonDown); // 0.5x A presses are a good meme @@ -559,11 +588,16 @@ void read_controller_inputs(void) { } else { // otherwise, if the controllerData is NULL, 0 out all of the inputs. controller->rawStickX = 0; controller->rawStickY = 0; + controller->rawStick2X = 0; + controller->rawStick2Y = 0; controller->buttonPressed = 0; controller->buttonDown = 0; controller->stickX = 0; controller->stickY = 0; controller->stickMag = 0; + controller->stick2X = 0; + controller->stick2Y = 0; + controller->stick2Mag = 0; } } @@ -575,6 +609,11 @@ void read_controller_inputs(void) { gPlayer3Controller->stickX = gPlayer1Controller->stickX; gPlayer3Controller->stickY = gPlayer1Controller->stickY; gPlayer3Controller->stickMag = gPlayer1Controller->stickMag; + gPlayer3Controller->rawStick2X = gPlayer1Controller->rawStick2X; + gPlayer3Controller->rawStick2Y = gPlayer1Controller->rawStick2Y; + gPlayer3Controller->stick2X = gPlayer1Controller->stick2X; + gPlayer3Controller->stick2Y = gPlayer1Controller->stick2Y; + gPlayer3Controller->stick2Mag = gPlayer1Controller->stick2Mag; gPlayer3Controller->buttonPressed = gPlayer1Controller->buttonPressed; gPlayer3Controller->buttonDown = gPlayer1Controller->buttonDown; } @@ -726,4 +765,4 @@ void thread5_iteration(void){ #if ENABLE_RUMBLE create_thread_6(); #endif -} \ No newline at end of file +} diff --git a/src/port/ui/GhostshipMenuEnhancements.cpp b/src/port/ui/GhostshipMenuEnhancements.cpp index 1ef19f16e..d5c476c22 100644 --- a/src/port/ui/GhostshipMenuEnhancements.cpp +++ b/src/port/ui/GhostshipMenuEnhancements.cpp @@ -20,6 +20,12 @@ static std::unordered_map hudAspects = { { 6, "Ultrawide (21:9)" }, }; +static std::unordered_map cameraModes = { + { 0, "Lakitu" }, + { 1, "Mario" }, + { 2, "Manual" }, +}; + using namespace UIWidgets; void GhostshipMenu::AddMenuEnhancements() { @@ -124,6 +130,71 @@ void GhostshipMenu::AddMenuEnhancements() { AddSidebarEntry("Enhancements", path.sidebarName, 1); path.column = SECTION_COLUMN_1; + AddWidget(path, "Camera", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "Default Camera Mode", WIDGET_CVAR_COMBOBOX) + .CVar(CVAR_ENHANCEMENT("Camera.DefaultMode")) + .RaceDisable(false) + .Options(ComboboxOptions() + .Tooltip("Primary camera mode.") + .ComboMap(cameraModes) + .DefaultIndex(0)); + AddWidget(path, "Alternate Camera Mode", WIDGET_CVAR_COMBOBOX) + .CVar(CVAR_ENHANCEMENT("Camera.AlternateMode")) + .RaceDisable(false) + .Options(ComboboxOptions() + .Tooltip("Alternate camera (R-trigger toggle)") + .ComboMap(cameraModes) + .DefaultIndex(0)); + AddWidget(path, "Horizontal Analog Camera", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Camera.HorizontalAnalog")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Enable horizontal analog camera")); + AddWidget(path, "Vertical analog camera", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Camera.VerticalAnalog")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Enable vertical analog camera")); + AddWidget(path, "Improved C-button Camera", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Camera.ImprovedCButtonCamera")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Enables smooth C-button rotation (hold = continuous)")); + AddWidget(path, "Center camera button", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Camera.CenterCameraButton")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("L-trigger centers camera behind Mario")); + AddWidget(path, "Inverted horizontal camera", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Camera.InvertedHorizontalCamera")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Invert horizontal camera")); + AddWidget(path, "Inverted vertical camera", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Camera.InvertedVerticalCamera")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Invert vertical camera")); + AddWidget(path, "Camera Speed", WIDGET_CVAR_SLIDER_FLOAT) + .CVar(CVAR_ENHANCEMENT("Camera.CameraSpeed")) + .RaceDisable(false) + .Options( + FloatSliderOptions().Min(1.0).Max(100.0).DefaultValue(32.0).ShowButtons(true) + .Tooltip("Analog camera sensitivity multiplier")); + AddWidget(path, "Camera distance", WIDGET_CVAR_SLIDER_FLOAT) + .CVar(CVAR_ENHANCEMENT("Camera.CameraDistance")) + .RaceDisable(false) + .Options( + FloatSliderOptions().Min(1.0).Max(1000.0).DefaultValue(100.0).ShowButtons(true) + .Tooltip("Normal zoom distance")); + AddWidget(path, "Camera distance zoomed out", WIDGET_CVAR_SLIDER_FLOAT) + .CVar(CVAR_ENHANCEMENT("Camera.CameraDistanceZoomedOut")) + .RaceDisable(false) + .Options( + FloatSliderOptions().Min(1.0).Max(1000.0).DefaultValue(150.0).ShowButtons(true) + .Tooltip("Zoomed-out distance")); + AddWidget(path, "Additional camera distance", WIDGET_CVAR_SLIDER_FLOAT) + .CVar(CVAR_ENHANCEMENT("Camera.AdditionalCameraDistance")) + .RaceDisable(false) + .Options( + FloatSliderOptions().Min(1.0).Max(1000.0).DefaultValue(0.0).ShowButtons(true) + .Tooltip("Extra uniform distance offset")); + + AddWidget(path, "Miscellaneous", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Disable LoD", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("DisableLOD")) .RaceDisable(false) From 29f6f0abe3e7040e2861af1c63be59b30f1ed0ce Mon Sep 17 00:00:00 2001 From: Wellington Dias Date: Fri, 15 May 2026 13:51:27 -0300 Subject: [PATCH 3/8] rough port of the sm64plus manual camera controls functionality --- src/game/camera.c | 298 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 225 insertions(+), 73 deletions(-) diff --git a/src/game/camera.c b/src/game/camera.c index f054dccb7..ac29d5199 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -839,7 +839,7 @@ s16 look_down_slopes(s16 camYaw) { * * Since this function only affects the camera's focus, Mario's movement direction isn't affected. */ -void pan_ahead_of_player(struct Camera *c) { +void pan_ahead_of_player(struct Camera *c, u32 panLess) { f32 dist; s16 pitch; s16 yaw; @@ -849,7 +849,7 @@ void pan_ahead_of_player(struct Camera *c) { vec3f_get_dist_and_angle(c->pos, sMarioCamState->pos, &dist, &pitch, &yaw); // The camera will pan ahead up to about 30% of the camera's distance to Mario. - pan[2] = sins(0xC00) * dist; + pan[2] = sins(panLess ? 0x600 : 0xC00) * dist; rotate_in_xz(pan, pan, sMarioCamState->faceAngle[1]); // rotate in the opposite direction @@ -937,7 +937,7 @@ s32 update_8_directions_camera(struct Camera *c, Vec3f focus, Vec3f pos) { sAreaYaw = camYaw; calc_y_to_curr_floor(&posY, 1.f, 200.f, &focusY, 0.9f, 200.f); focus_on_mario(focus, pos, posY + yOff, focusY + yOff, sLakituDist + baseDist, pitch, camYaw); - pan_ahead_of_player(c); + pan_ahead_of_player(c, FALSE); if (gCurrLevelArea == AREA_DDD_SUB) { camYaw = clamp_positions_and_find_yaw(pos, focus, 6839.f, 995.f, 5994.f, -3945.f); } @@ -945,6 +945,31 @@ s32 update_8_directions_camera(struct Camera *c, Vec3f focus, Vec3f pos) { return camYaw; } +/** + * Update the camera position/focus for manual (custom) camera mode. + * Computes distance based on zoom state and pitch angle, then focuses on Mario. + */ +s32 update_custom_camera(struct Camera *c, Vec3f focus, Vec3f pos, f32 yOff, f32 additionalDistance, s8 dynamic) { + s16 camYaw = sModeOffsetYaw; + s16 pitch = 0.0f; + f32 posY; + f32 focusY; + + f32 dist = (sLakituDist + (((gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) ? CAMERA_DISTANCE_ZOOMED_OUT : CAMERA_DISTANCE) + ADDITIONAL_CAMERA_DISTANCE) * 10.0f + additionalDistance) + * (((MIN(sLakituPitch, VERTICAL_MAX_PITCH) + VERTICAL_MIN) / (VERTICAL_MIN + VERTICAL_MAX_PITCH)) * 1.25f + 0.5f); + + sAreaYaw = camYaw; + + calc_y_to_curr_floor(&posY, 1.f, 200.f, &focusY, 0.9f, 200.f); + focus_on_mario(focus, pos, posY + yOff, focusY + yOff, dist, pitch, camYaw); + + if (dynamic) { + pan_ahead_of_player(c, TRUE); + } + + return camYaw; +} + /** * Moves the camera for the radial and outward radial camera modes. * @@ -1105,17 +1130,22 @@ void lakitu_zoom(f32 rangeDist, s16 rangePitch) { } } - if (gCurrLevelArea == AREA_SSL_PYRAMID && gCamera->mode == CAMERA_MODE_OUTWARD_RADIAL) { - rangePitch /= 2; - } - - if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { - if ((sLakituPitch += rangePitch / 13) > rangePitch) { - sLakituPitch = rangePitch; - } + // When rangePitch is 0, use right analog stick for free vertical control + if (rangePitch == 0) { + sLakituPitch = MIN(MAX(sLakituPitch + ANALOG_AMOUNT_VERTICAL * (gPlayer1Controller->stick2Y / 48.0f) * CAMERA_SPEED, -VERTICAL_MIN), VERTICAL_MAX); } else { - if ((sLakituPitch -= rangePitch / 13) < 0) { - sLakituPitch = 0; + if (gCurrLevelArea == AREA_SSL_PYRAMID && gCamera->mode == CAMERA_MODE_OUTWARD_RADIAL) { + rangePitch /= 2; + } + + if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { + if ((sLakituPitch += rangePitch / 13) > rangePitch) { + sLakituPitch = rangePitch; + } + } else { + if ((sLakituPitch -= rangePitch / 13) < 0) { + sLakituPitch = 0; + } } } } @@ -1164,7 +1194,7 @@ void mode_radial_camera(struct Camera *c) { pos[1] += 500.f; } set_camera_height(c, pos[1]); - pan_ahead_of_player(c); + pan_ahead_of_player(c, FALSE); } /** @@ -1194,6 +1224,83 @@ void mode_8_directions_camera(struct Camera *c) { set_camera_height(c, pos[1]); } +/** + * Manual/free camera mode input processing. + * Handles C-button rotation, right analog stick, L-trigger centering, + * auto-rotation, vertical control, and wall avoidance. + */ +void mode_custom_camera(struct Camera *c, f32 yOff, f32 additionalDistance, s8 limitedAngle, s8 autoRotate, s8 dynamic) { + Vec3f pos; + s16 oldAreaYaw = sAreaYaw; + s16 avoidYaw; + + radial_camera_input(c, 0.f); + + if (IMPROVED_C_BUTTON_CAMERA) { + if (gPlayer1Controller->buttonPressed & L_CBUTTONS || gPlayer1Controller->buttonPressed & R_CBUTTONS) { + play_sound_cbutton_side(); + } + if (gPlayer1Controller->buttonDown & L_CBUTTONS) { + sModeOffsetYaw -= ANALOG_AMOUNT * CAMERA_SPEED * 2.0f; + } + if (gPlayer1Controller->buttonDown & R_CBUTTONS) { + sModeOffsetYaw += ANALOG_AMOUNT * CAMERA_SPEED * 2.0f; + } + } else { + if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { + sModeOffsetYaw += DEGREES(22.5); + play_sound_cbutton_side(); + } + if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { + sModeOffsetYaw -= DEGREES(22.5); + play_sound_cbutton_side(); + } + } + + // Right analog stick horizontal rotation + if (gPlayer1Controller->stick2X != 0 && gCurrDemoInput == NULL) { + sModeOffsetYaw -= ANALOG_AMOUNT * (gPlayer1Controller->stick2X / 32.0f) * CAMERA_SPEED; + } + + // L-trigger centers camera behind Mario + if (CENTER_CAMERA_BUTTON) { + if (gPlayer1Controller->buttonPressed & L_TRIG) { + sModeOffsetYaw = sMarioCamState->faceAngle[1] + DEGREES(180); + play_sound_rbutton_changed(); + } + if (gPlayer1Controller->buttonDown & L_TRIG) { + camera_approach_s16_symmetric_bool(&sModeOffsetYaw, sMarioCamState->faceAngle[1] + DEGREES(180), LROTATE_SPEED); + } + } + + // Auto-rotate camera to follow Mario's movement direction + if (autoRotate) { + camera_approach_s16_symmetric_bool(&sModeOffsetYaw, sMarioCamState->faceAngle[1] + DEGREES(180), + ABS(gMarioState->forwardVel + * ((gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) ? 8.0f : 12.0f) + * (1.0f - MIN(MAX(sqrt((sLakituPitch + VERTICAL_MIN) / (VERTICAL_MAX + VERTICAL_MIN)), 0.0f), 0.75f)) + * (MIN(MAX(sqr(abs_angle_diff(sModeOffsetYaw, sMarioCamState->faceAngle[1] + DEGREES(180)) / 180), 0.0f), 1.0f)) + )); + } + + lakitu_zoom(0, VERTICAL_ANALOG_CAMERA ? 0 : 0x900); + + if (limitedAngle) { + sLakituPitch = MIN(MAX(sLakituPitch, -VERTICAL_MIN), VERTICAL_MAX_LIMITED); + } + + c->nextYaw = update_custom_camera(c, c->focus, pos, yOff, additionalDistance, dynamic); + c->pos[0] = pos[0]; + c->pos[1] = pos[1]; + c->pos[2] = pos[2]; + sAreaYawChange = sAreaYaw - oldAreaYaw; + set_camera_height(c, pos[1]); + + if (dynamic && rotate_camera_around_walls(c, c->pos, &avoidYaw, 0x400) > 0) { + camera_approach_s16_symmetric_bool(&sModeOffsetYaw, avoidYaw, 0x400); + } +} + /** * Updates the camera in outward radial mode. * sModeOffsetYaw is calculated in radial_camera_move, which calls offset_yaw_outward_radial @@ -1237,7 +1344,7 @@ void mode_outward_radial_camera(struct Camera *c) { pos[1] += 500.f; } set_camera_height(c, pos[1]); - pan_ahead_of_player(c); + pan_ahead_of_player(c, FALSE); } /** @@ -1738,7 +1845,7 @@ void mode_fixed_camera(struct Camera *c) { } c->nextYaw = update_fixed_camera(c, c->focus, c->pos); c->yaw = c->nextYaw; - pan_ahead_of_player(c); + pan_ahead_of_player(c, FALSE); vec3f_set(sCastleEntranceOffset, 0.f, 0.f, 0.f); } @@ -1936,7 +2043,7 @@ s32 mode_behind_mario(struct Camera *c) { distCamToFocus = 800.f; vec3f_set_dist_and_angle(c->focus, c->pos, distCamToFocus, camPitch, camYaw); } - pan_ahead_of_player(c); + pan_ahead_of_player(c, FALSE); return yaw; } @@ -2382,7 +2489,7 @@ s16 update_default_camera(struct Camera *c) { void mode_default_camera(struct Camera *c) { set_fov_function(CAM_FOV_DEFAULT); c->nextYaw = update_default_camera(c); - pan_ahead_of_player(c); + pan_ahead_of_player(c, FALSE); } /** @@ -3001,6 +3108,33 @@ void update_lakitu(struct Camera *c) { } +/** + * Dispatcher for manual camera mode. + * Routes to mode_custom_camera with per-context parameters. + */ +void manual_cam_modes(struct Camera *c) { + switch (c->mode) { + case CAMERA_MODE_8_DIRECTIONS: + mode_custom_camera(c, 150.0f, 256.0f, TRUE, FALSE, TRUE); + break; + case CAMERA_MODE_BEHIND_MARIO: + mode_custom_camera(c, -75.0f, 0.0f, FALSE, TRUE, TRUE); + break; + case CAMERA_MODE_C_UP: + mode_c_up_camera(c); + break; + case CAMERA_MODE_WATER_SURFACE: + mode_custom_camera(c, 75.0f, 0.0f, FALSE, TRUE, TRUE); + break; + case CAMERA_MODE_INSIDE_CANNON: + mode_cannon_camera(c); + break; + default: + mode_custom_camera(c, 150.0f, 0.0f, FALSE, TRUE, TRUE); + break; + } +} + /** * The main camera update function. * Gets controller input, checks for cutscenes, handles mode changes, and moves the camera @@ -3074,81 +3208,99 @@ void update_camera(struct Camera *c) { sYawSpeed = 0x400; if (sSelectionFlags & CAM_MODE_MARIO_ACTIVE) { - switch (c->mode) { - case CAMERA_MODE_BEHIND_MARIO: - mode_behind_mario_camera(c); + // Alternate camera mode (R-trigger toggled) + switch (ALTERNATE_CAMERA_MODE) { + case 2: + manual_cam_modes(c); break; + case 1: + default: + switch (c->mode) { + case CAMERA_MODE_BEHIND_MARIO: + mode_behind_mario_camera(c); + break; - case CAMERA_MODE_C_UP: - mode_c_up_camera(c); - break; + case CAMERA_MODE_C_UP: + mode_c_up_camera(c); + break; - case CAMERA_MODE_WATER_SURFACE: - mode_water_surface_camera(c); - break; + case CAMERA_MODE_WATER_SURFACE: + mode_water_surface_camera(c); + break; - case CAMERA_MODE_INSIDE_CANNON: - mode_cannon_camera(c); - break; + case CAMERA_MODE_INSIDE_CANNON: + mode_cannon_camera(c); + break; - default: - mode_mario_camera(c); + default: + mode_mario_camera(c); + } + break; } } else { - switch (c->mode) { - case CAMERA_MODE_BEHIND_MARIO: - mode_behind_mario_camera(c); + // Default camera mode + switch (DEFAULT_CAMERA_MODE) { + case 2: + manual_cam_modes(c); break; + case 1: + default: + switch (c->mode) { + case CAMERA_MODE_BEHIND_MARIO: + mode_behind_mario_camera(c); + break; - case CAMERA_MODE_C_UP: - mode_c_up_camera(c); - break; + case CAMERA_MODE_C_UP: + mode_c_up_camera(c); + break; - case CAMERA_MODE_WATER_SURFACE: - mode_water_surface_camera(c); - break; + case CAMERA_MODE_WATER_SURFACE: + mode_water_surface_camera(c); + break; - case CAMERA_MODE_INSIDE_CANNON: - mode_cannon_camera(c); - break; + case CAMERA_MODE_INSIDE_CANNON: + mode_cannon_camera(c); + break; - case CAMERA_MODE_8_DIRECTIONS: - mode_8_directions_camera(c); - break; + case CAMERA_MODE_8_DIRECTIONS: + mode_8_directions_camera(c); + break; - case CAMERA_MODE_RADIAL: - mode_radial_camera(c); - break; + case CAMERA_MODE_RADIAL: + mode_radial_camera(c); + break; - case CAMERA_MODE_OUTWARD_RADIAL: - mode_outward_radial_camera(c); - break; + case CAMERA_MODE_OUTWARD_RADIAL: + mode_outward_radial_camera(c); + break; - case CAMERA_MODE_CLOSE: - mode_lakitu_camera(c); - break; + case CAMERA_MODE_CLOSE: + mode_lakitu_camera(c); + break; - case CAMERA_MODE_FREE_ROAM: - mode_lakitu_camera(c); - break; - case CAMERA_MODE_BOSS_FIGHT: - mode_boss_fight_camera(c); - break; + case CAMERA_MODE_FREE_ROAM: + mode_lakitu_camera(c); + break; + case CAMERA_MODE_BOSS_FIGHT: + mode_boss_fight_camera(c); + break; - case CAMERA_MODE_PARALLEL_TRACKING: - mode_parallel_tracking_camera(c); - break; + case CAMERA_MODE_PARALLEL_TRACKING: + mode_parallel_tracking_camera(c); + break; - case CAMERA_MODE_SLIDE_HOOT: - mode_slide_camera(c); - break; + case CAMERA_MODE_SLIDE_HOOT: + mode_slide_camera(c); + break; - case CAMERA_MODE_FIXED: - mode_fixed_camera(c); - break; + case CAMERA_MODE_FIXED: + mode_fixed_camera(c); + break; - case CAMERA_MODE_SPIRAL_STAIRS: - mode_spiral_stairs_camera(c); + case CAMERA_MODE_SPIRAL_STAIRS: + mode_spiral_stairs_camera(c); + break; + } break; } } From f992baef589bb5cc6e1ccd5958fe8f79d8e5c39d Mon Sep 17 00:00:00 2001 From: Wellington Dias Date: Fri, 15 May 2026 13:52:00 -0300 Subject: [PATCH 4/8] prevent sound to play when using the right stick for the manual cameral --- src/game/camera.c | 10 ++++------ src/game/camera_settings.h | 1 + src/port/ui/GhostshipMenuEnhancements.cpp | 4 ++++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/game/camera.c b/src/game/camera.c index ac29d5199..3494fe4d2 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -1234,10 +1234,8 @@ void mode_custom_camera(struct Camera *c, f32 yOff, f32 additionalDistance, s8 l s16 oldAreaYaw = sAreaYaw; s16 avoidYaw; - radial_camera_input(c, 0.f); - if (IMPROVED_C_BUTTON_CAMERA) { - if (gPlayer1Controller->buttonPressed & L_CBUTTONS || gPlayer1Controller->buttonPressed & R_CBUTTONS) { + if (MANUAL_CAMERA_SOUNDS && (gPlayer1Controller->buttonPressed & L_CBUTTONS || gPlayer1Controller->buttonPressed & R_CBUTTONS)) { play_sound_cbutton_side(); } if (gPlayer1Controller->buttonDown & L_CBUTTONS) { @@ -1249,11 +1247,11 @@ void mode_custom_camera(struct Camera *c, f32 yOff, f32 additionalDistance, s8 l } else { if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { sModeOffsetYaw += DEGREES(22.5); - play_sound_cbutton_side(); + if (MANUAL_CAMERA_SOUNDS) play_sound_cbutton_side(); } if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { sModeOffsetYaw -= DEGREES(22.5); - play_sound_cbutton_side(); + if (MANUAL_CAMERA_SOUNDS) play_sound_cbutton_side(); } } @@ -1266,7 +1264,7 @@ void mode_custom_camera(struct Camera *c, f32 yOff, f32 additionalDistance, s8 l if (CENTER_CAMERA_BUTTON) { if (gPlayer1Controller->buttonPressed & L_TRIG) { sModeOffsetYaw = sMarioCamState->faceAngle[1] + DEGREES(180); - play_sound_rbutton_changed(); + if (MANUAL_CAMERA_SOUNDS) play_sound_rbutton_changed(); } if (gPlayer1Controller->buttonDown & L_TRIG) { camera_approach_s16_symmetric_bool(&sModeOffsetYaw, sMarioCamState->faceAngle[1] + DEGREES(180), LROTATE_SPEED); diff --git a/src/game/camera_settings.h b/src/game/camera_settings.h index 1654a14e5..03b578962 100644 --- a/src/game/camera_settings.h +++ b/src/game/camera_settings.h @@ -13,6 +13,7 @@ #define CAMERA_DISTANCE CVarGetFloat("gEnhancements.Camera.CameraDistance", 100) #define CAMERA_DISTANCE_ZOOMED_OUT CVarGetFloat("gEnhancements.Camera.CameraDistanceZoomedOut", 150) #define ADDITIONAL_CAMERA_DISTANCE CVarGetFloat("gEnhancements.Camera.AdditionalCameraDistance", 0) +#define MANUAL_CAMERA_SOUNDS CVarGetInteger("gEnhancements.Camera.ManualCameraSounds", 1) #define ANALOG_AMOUNT (12 * (1 - INVERTED_HORIZONTAL_CAMERA * 2)) #define ANALOG_AMOUNT_VERTICAL (12 * (1 - INVERTED_VERTICAL_CAMERA * 2)) diff --git a/src/port/ui/GhostshipMenuEnhancements.cpp b/src/port/ui/GhostshipMenuEnhancements.cpp index d5c476c22..adf58a9e6 100644 --- a/src/port/ui/GhostshipMenuEnhancements.cpp +++ b/src/port/ui/GhostshipMenuEnhancements.cpp @@ -193,6 +193,10 @@ void GhostshipMenu::AddMenuEnhancements() { .Options( FloatSliderOptions().Min(1.0).Max(1000.0).DefaultValue(0.0).ShowButtons(true) .Tooltip("Extra uniform distance offset")); + AddWidget(path, "Manual camera sounds", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("Camera.ManualCameraSounds")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Play sounds when using manual camera controls (C-buttons, L-trigger)")); AddWidget(path, "Miscellaneous", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Disable LoD", WIDGET_CVAR_CHECKBOX) From 115e6b757a0d333fc4e57ffe67968f43360ef9be Mon Sep 17 00:00:00 2001 From: Wellington Dias Date: Fri, 15 May 2026 15:01:12 -0300 Subject: [PATCH 5/8] fix stick2 horizontal jerking motion when switching camera directions --- src/game/camera.c | 50 +++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/game/camera.c b/src/game/camera.c index 3494fe4d2..9ed417cca 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -1234,32 +1234,40 @@ void mode_custom_camera(struct Camera *c, f32 yOff, f32 additionalDistance, s8 l s16 oldAreaYaw = sAreaYaw; s16 avoidYaw; - if (IMPROVED_C_BUTTON_CAMERA) { - if (MANUAL_CAMERA_SOUNDS && (gPlayer1Controller->buttonPressed & L_CBUTTONS || gPlayer1Controller->buttonPressed & R_CBUTTONS)) { - play_sound_cbutton_side(); - } - if (gPlayer1Controller->buttonDown & L_CBUTTONS) { - sModeOffsetYaw -= ANALOG_AMOUNT * CAMERA_SPEED * 2.0f; - } - if (gPlayer1Controller->buttonDown & R_CBUTTONS) { - sModeOffsetYaw += ANALOG_AMOUNT * CAMERA_SPEED * 2.0f; - } - } else { - if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { - sModeOffsetYaw += DEGREES(22.5); - if (MANUAL_CAMERA_SOUNDS) play_sound_cbutton_side(); - } - if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { - sModeOffsetYaw -= DEGREES(22.5); - if (MANUAL_CAMERA_SOUNDS) play_sound_cbutton_side(); - } - } + // Right stick is often mapped to C-buttons at the controller config level. + // To avoid double-processing, only handle C-button L/R rotation when the + // right stick is idle (allows keyboard C-buttons to still work). + s8 rightStickActive = (gPlayer1Controller->stick2X != 0 || gPlayer1Controller->stick2Y != 0); - // Right analog stick horizontal rotation + // Right analog stick horizontal rotation (primary input) if (gPlayer1Controller->stick2X != 0 && gCurrDemoInput == NULL) { sModeOffsetYaw -= ANALOG_AMOUNT * (gPlayer1Controller->stick2X / 32.0f) * CAMERA_SPEED; } + // C-button L/R rotation (fallback for keyboard users, skipped when right stick is active) + if (!rightStickActive) { + if (IMPROVED_C_BUTTON_CAMERA) { + if (MANUAL_CAMERA_SOUNDS && (gPlayer1Controller->buttonPressed & (L_CBUTTONS | R_CBUTTONS))) { + play_sound_cbutton_side(); + } + if (gPlayer1Controller->buttonDown & L_CBUTTONS) { + sModeOffsetYaw -= ANALOG_AMOUNT * CAMERA_SPEED * 2.0f; + } + if (gPlayer1Controller->buttonDown & R_CBUTTONS) { + sModeOffsetYaw += ANALOG_AMOUNT * CAMERA_SPEED * 2.0f; + } + } else { + if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { + sModeOffsetYaw += DEGREES(22.5); + if (MANUAL_CAMERA_SOUNDS) play_sound_cbutton_side(); + } + if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { + sModeOffsetYaw -= DEGREES(22.5); + if (MANUAL_CAMERA_SOUNDS) play_sound_cbutton_side(); + } + } + } + // L-trigger centers camera behind Mario if (CENTER_CAMERA_BUTTON) { if (gPlayer1Controller->buttonPressed & L_TRIG) { From 1ef374aa2134fd7bb6bfb4a6441816066f41783e Mon Sep 17 00:00:00 2001 From: Wellington Dias Date: Fri, 15 May 2026 15:32:59 -0300 Subject: [PATCH 6/8] fix manual camera getting stuck on walls in tight places --- src/game/camera.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/game/camera.c b/src/game/camera.c index 9ed417cca..3ef2b783f 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -948,12 +948,15 @@ s32 update_8_directions_camera(struct Camera *c, Vec3f focus, Vec3f pos) { /** * Update the camera position/focus for manual (custom) camera mode. * Computes distance based on zoom state and pitch angle, then focuses on Mario. + * Steps the camera closer to Mario if walls obstruct the view. */ s32 update_custom_camera(struct Camera *c, Vec3f focus, Vec3f pos, f32 yOff, f32 additionalDistance, s8 dynamic) { s16 camYaw = sModeOffsetYaw; s16 pitch = 0.0f; f32 posY; f32 focusY; + struct WallCollisionData colData; + s32 i; f32 dist = (sLakituDist + (((gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) ? CAMERA_DISTANCE_ZOOMED_OUT : CAMERA_DISTANCE) + ADDITIONAL_CAMERA_DISTANCE) * 10.0f + additionalDistance) * (((MIN(sLakituPitch, VERTICAL_MAX_PITCH) + VERTICAL_MIN) / (VERTICAL_MIN + VERTICAL_MAX_PITCH)) * 1.25f + 0.5f); @@ -963,6 +966,27 @@ s32 update_custom_camera(struct Camera *c, Vec3f focus, Vec3f pos, f32 yOff, f32 calc_y_to_curr_floor(&posY, 1.f, 200.f, &focusY, 0.9f, 200.f); focus_on_mario(focus, pos, posY + yOff, focusY + yOff, dist, pitch, camYaw); + // Walk from camera toward Mario checking for walls. If a wall is found, + // pull the camera closer to avoid clipping through geometry. + for (i = 0; i < 5; i++) { + f32 checkDist = dist * (1.0f - (f32)i / 5.0f); + colData.x = sMarioCamState->pos[0] + (pos[0] - sMarioCamState->pos[0]) * (checkDist / dist); + colData.y = sMarioCamState->pos[1] + (pos[1] - sMarioCamState->pos[1]) * (checkDist / dist); + colData.z = sMarioCamState->pos[2] + (pos[2] - sMarioCamState->pos[2]) * (checkDist / dist); + colData.radius = 150.0f; + colData.offsetY = 100.0f; + + if (find_wall_collisions(&colData) != 0) { + // Found a wall — pull camera to just before the collision point + f32 pullDist = checkDist * 0.85f; + if (pullDist < dist) { + dist = pullDist; + focus_on_mario(focus, pos, posY + yOff, focusY + yOff, dist, pitch, camYaw); + } + break; + } + } + if (dynamic) { pan_ahead_of_player(c, TRUE); } @@ -1302,8 +1326,15 @@ void mode_custom_camera(struct Camera *c, f32 yOff, f32 additionalDistance, s8 l sAreaYawChange = sAreaYaw - oldAreaYaw; set_camera_height(c, pos[1]); - if (dynamic && rotate_camera_around_walls(c, c->pos, &avoidYaw, 0x400) > 0) { - camera_approach_s16_symmetric_bool(&sModeOffsetYaw, avoidYaw, 0x400); + if (dynamic) { + s32 wallStatus = rotate_camera_around_walls(c, c->pos, &avoidYaw, 0x600); + if (wallStatus == 3) { + // Wall is directly blocking Mario — rotate aggressively + approach_s16_asymptotic_bool(&sModeOffsetYaw, avoidYaw, 10); + } else if (wallStatus > 0) { + // Wall is nearby — rotate gently + camera_approach_s16_symmetric_bool(&sModeOffsetYaw, avoidYaw, 0x600); + } } } @@ -3117,6 +3148,7 @@ void update_lakitu(struct Camera *c) { /** * Dispatcher for manual camera mode. * Routes to mode_custom_camera with per-context parameters. + * Clamps pitch in enclosed/indoor areas to prevent wall clipping. */ void manual_cam_modes(struct Camera *c) { switch (c->mode) { @@ -3135,6 +3167,14 @@ void manual_cam_modes(struct Camera *c) { case CAMERA_MODE_INSIDE_CANNON: mode_cannon_camera(c); break; + // Indoor/enclosed area modes — limit pitch to prevent excessive zoom + case CAMERA_MODE_CLOSE: + case CAMERA_MODE_FIXED: + case CAMERA_MODE_SPIRAL_STAIRS: + case CAMERA_MODE_PARALLEL_TRACKING: + sLakituPitch = MIN(MAX(sLakituPitch, -VERTICAL_MIN), VERTICAL_MAX_LIMITED); + mode_custom_camera(c, 150.0f, 0.0f, TRUE, TRUE, TRUE); + break; default: mode_custom_camera(c, 150.0f, 0.0f, FALSE, TRUE, TRUE); break; From 589bef603e360831c28bb5cad538b259c289a675 Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Thu, 28 May 2026 01:54:14 -0600 Subject: [PATCH 7/8] Fixed clang-format --- src/port/ui/GhostshipMenuEnhancements.cpp | 31 ++++++++--------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/port/ui/GhostshipMenuEnhancements.cpp b/src/port/ui/GhostshipMenuEnhancements.cpp index adf58a9e6..b2a555875 100644 --- a/src/port/ui/GhostshipMenuEnhancements.cpp +++ b/src/port/ui/GhostshipMenuEnhancements.cpp @@ -134,17 +134,12 @@ void GhostshipMenu::AddMenuEnhancements() { AddWidget(path, "Default Camera Mode", WIDGET_CVAR_COMBOBOX) .CVar(CVAR_ENHANCEMENT("Camera.DefaultMode")) .RaceDisable(false) - .Options(ComboboxOptions() - .Tooltip("Primary camera mode.") - .ComboMap(cameraModes) - .DefaultIndex(0)); + .Options(ComboboxOptions().Tooltip("Primary camera mode.").ComboMap(cameraModes).DefaultIndex(0)); AddWidget(path, "Alternate Camera Mode", WIDGET_CVAR_COMBOBOX) .CVar(CVAR_ENHANCEMENT("Camera.AlternateMode")) .RaceDisable(false) - .Options(ComboboxOptions() - .Tooltip("Alternate camera (R-trigger toggle)") - .ComboMap(cameraModes) - .DefaultIndex(0)); + .Options( + ComboboxOptions().Tooltip("Alternate camera (R-trigger toggle)").ComboMap(cameraModes).DefaultIndex(0)); AddWidget(path, "Horizontal Analog Camera", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Camera.HorizontalAnalog")) .RaceDisable(false) @@ -172,27 +167,23 @@ void GhostshipMenu::AddMenuEnhancements() { AddWidget(path, "Camera Speed", WIDGET_CVAR_SLIDER_FLOAT) .CVar(CVAR_ENHANCEMENT("Camera.CameraSpeed")) .RaceDisable(false) - .Options( - FloatSliderOptions().Min(1.0).Max(100.0).DefaultValue(32.0).ShowButtons(true) - .Tooltip("Analog camera sensitivity multiplier")); + .Options(FloatSliderOptions().Min(1.0).Max(100.0).DefaultValue(32.0).ShowButtons(true).Tooltip( + "Analog camera sensitivity multiplier")); AddWidget(path, "Camera distance", WIDGET_CVAR_SLIDER_FLOAT) .CVar(CVAR_ENHANCEMENT("Camera.CameraDistance")) .RaceDisable(false) - .Options( - FloatSliderOptions().Min(1.0).Max(1000.0).DefaultValue(100.0).ShowButtons(true) - .Tooltip("Normal zoom distance")); + .Options(FloatSliderOptions().Min(1.0).Max(1000.0).DefaultValue(100.0).ShowButtons(true).Tooltip( + "Normal zoom distance")); AddWidget(path, "Camera distance zoomed out", WIDGET_CVAR_SLIDER_FLOAT) .CVar(CVAR_ENHANCEMENT("Camera.CameraDistanceZoomedOut")) .RaceDisable(false) - .Options( - FloatSliderOptions().Min(1.0).Max(1000.0).DefaultValue(150.0).ShowButtons(true) - .Tooltip("Zoomed-out distance")); + .Options(FloatSliderOptions().Min(1.0).Max(1000.0).DefaultValue(150.0).ShowButtons(true).Tooltip( + "Zoomed-out distance")); AddWidget(path, "Additional camera distance", WIDGET_CVAR_SLIDER_FLOAT) .CVar(CVAR_ENHANCEMENT("Camera.AdditionalCameraDistance")) .RaceDisable(false) - .Options( - FloatSliderOptions().Min(1.0).Max(1000.0).DefaultValue(0.0).ShowButtons(true) - .Tooltip("Extra uniform distance offset")); + .Options(FloatSliderOptions().Min(1.0).Max(1000.0).DefaultValue(0.0).ShowButtons(true).Tooltip( + "Extra uniform distance offset")); AddWidget(path, "Manual camera sounds", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("Camera.ManualCameraSounds")) .RaceDisable(false) From 3508d9a96cf076991336107d62e9a4a2858eb70e Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Thu, 28 May 2026 02:11:46 -0600 Subject: [PATCH 8/8] Fixed compile error --- src/game/mario_actions_airborne.c | 2 +- src/game/mario_actions_moving.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 497e159c4..e5ce0556b 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -14,7 +14,7 @@ #include "save_file.h" #include "rumble_init.h" #include "seq_ids.h" -#include "port/hooks/list/PlayerEvent.h" +#include "port/events/list/PlayerEvent.h" void play_flip_sounds(struct MarioState *m, s16 frame1, s16 frame2, s16 frame3) { s32 animFrame = m->marioObj->header.gfx.animInfo.animFrame; diff --git a/src/game/mario_actions_moving.c b/src/game/mario_actions_moving.c index 07f6df1c6..413201e6c 100644 --- a/src/game/mario_actions_moving.c +++ b/src/game/mario_actions_moving.c @@ -13,7 +13,7 @@ #include "behavior_data.h" #include "rumble_init.h" #include "seq_ids.h" -#include "port/hooks/list/PlayerEvent.h" +#include "port/events/list/PlayerEvent.h" struct LandingAction { s16 numFrames;