From 83388950dc82f84af50fb855bf48d58d1e789d3f Mon Sep 17 00:00:00 2001 From: Reonu Date: Sat, 24 Jul 2021 01:58:40 +0100 Subject: [PATCH] added reonucam3 as a patch file --- enhancements/reonucam3.patch | 554 +++++++++++++++++++++++++++++++++++ 1 file changed, 554 insertions(+) create mode 100644 enhancements/reonucam3.patch diff --git a/enhancements/reonucam3.patch b/enhancements/reonucam3.patch new file mode 100644 index 00000000..5305f7b7 --- /dev/null +++ b/enhancements/reonucam3.patch @@ -0,0 +1,554 @@ +diff --git a/include/text_strings.h.in b/include/text_strings.h.in +index d266058..4b12426 100644 +--- a/include/text_strings.h.in ++++ b/include/text_strings.h.in +@@ -34,6 +34,12 @@ + #define TEXT_HUD_WIDE_INFO2 _("STRETCH THE IMAGE TO 16:9") + #endif + ++#define TEXT_CAM_INFO_SLOWEST _("CAM SPEED: SLOWEST") ++#define TEXT_CAM_INFO_SLOW _("CAM SPEED: SLOW") ++#define TEXT_CAM_INFO_MEDIUM _("CAM SPEED: MEDIUM") ++#define TEXT_CAM_INFO_FAST _("CAM SPEED: FAST") ++#define TEXT_CAM_INFO_FASTEST _("CAM SPEED: FASTEST") ++ + #if defined(VERSION_JP) || defined(VERSION_SH) + + /** +diff --git a/src/game/camera.c b/src/game/camera.c +index dfcf16a..ffdc1b2 100644 +--- a/src/game/camera.c ++++ b/src/game/camera.c +@@ -98,6 +98,7 @@ Vec3f sPlayer2FocusOffset; + * The pitch used for the credits easter egg. + */ + s16 sCreditsPlayer2Pitch; ++s16 rButtonCounter2; + /** + * The yaw used for the credits easter egg. + */ +@@ -107,6 +108,7 @@ s16 sCreditsPlayer2Yaw; + */ + u8 sFramesPaused; + ++ + extern struct CameraFOVStatus sFOVState; + extern struct TransitionInfo sModeTransition; + extern struct PlayerGeometry sMarioGeometry; +@@ -259,6 +261,7 @@ s16 sCameraSoundFlags; + * Stores what C-Buttons are pressed this frame. + */ + u16 sCButtonsPressed; ++u16 rButtonCounter; + /** + * A copy of gDialogID, the dialog displayed during the cutscene. + */ +@@ -437,6 +440,7 @@ u8 sFramesSinceCutsceneEnded = 0; + * 3 = Dialog doesn't have a response + */ + u8 sCutsceneDialogResponse = DIALOG_RESPONSE_NONE; ++u8 stickReset = 1; + struct PlayerCameraState *sMarioCamState = &gPlayerCameraState[0]; + struct PlayerCameraState *sLuigiCamState = &gPlayerCameraState[1]; + u32 unused8032D008 = 0; +@@ -755,6 +759,7 @@ void set_camera_height(struct Camera *c, f32 goalHeight) { + UNUSED s16 action = sMarioCamState->action; + f32 baseOff = 125.f; + f32 camCeilHeight = find_ceil(c->pos[0], gLakituState.goalPos[1] - 50.f, c->pos[2], &surface); ++ f32 approachRate = 20.0f; + + if (sMarioCamState->action & ACT_FLAG_HANGING) { + marioCeilHeight = sMarioGeometry.currCeilHeight; +@@ -790,7 +795,8 @@ void set_camera_height(struct Camera *c, f32 goalHeight) { + c->pos[1] = goalHeight; + } + } +- approach_camera_height(c, goalHeight, 20.f); ++ approachRate += ABS(c->pos[1] - goalHeight) / 20; ++ approach_camera_height(c, goalHeight, approachRate); + if (camCeilHeight != CELL_HEIGHT_LIMIT) { + camCeilHeight -= baseOff; + if ((c->pos[1] > camCeilHeight && sMarioGeometry.currFloorHeight + baseOff < camCeilHeight) +@@ -934,9 +940,19 @@ s32 update_8_directions_camera(struct Camera *c, Vec3f focus, Vec3f pos) { + UNUSED f32 unused1; + UNUSED f32 unused2; + UNUSED f32 unused3; +- f32 yOff = 125.f; ++ f32 yOff; + f32 baseDist = 1000.f; + ++ if (gMarioState->action & ACT_FLAG_SWIMMING) { ++ yOff = -125.f; ++ } else { ++ yOff = 125.f; ++ } ++ ++ if ((gPlayer1Controller->buttonDown & L_TRIG) && !(gMarioState->action & ACT_FLAG_SWIMMING_OR_FLYING)) { ++ pitch = DEGREES(65); ++ } ++ + 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); +@@ -1170,6 +1186,28 @@ void mode_radial_camera(struct Camera *c) { + pan_ahead_of_player(c); + } + ++// Returns the camera speed based on the user's camera speed setting ++f32 set_camera_speed(void) { ++ switch(gCameraSpeed) { ++ case 0: ++ return 0.5f; ++ break; ++ case 1: ++ return 1; ++ break; ++ case 2: ++ return 1.5; ++ break; ++ case 3: ++ return 2; ++ break; ++ case 4: ++ return 3.5; ++ break; ++ } ++ return 0; ++} ++ + /** + * A mode that only has 8 camera angles, 45 degrees apart + */ +@@ -1177,42 +1215,59 @@ void mode_8_directions_camera(struct Camera *c) { + Vec3f pos; + UNUSED u8 unused[8]; + s16 oldAreaYaw = sAreaYaw; ++ // Get the camera speed based on the user's setting ++ f32 cameraSpeed = set_camera_speed(); + + radial_camera_input(c, 0.f); + +- if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { +- s8DirModeYawOffset += DEGREES(45); +- play_sound_cbutton_side(); ++ if ((gPlayer1Controller->buttonPressed & L_CBUTTONS) && !(gPlayer1Controller->buttonDown & R_TRIG)) { ++ s8DirModeBaseYaw -= DEGREES(45); ++ } else if ((gPlayer1Controller->buttonPressed & R_CBUTTONS) && !(gPlayer1Controller->buttonDown & R_TRIG)) { ++ s8DirModeBaseYaw += DEGREES(45); ++ } else if (gPlayer2Controller->rawStickX) { ++ s8DirModeBaseYaw += DEGREES(gPlayer2Controller->rawStickX * 4 / 64); // Analog camera support (Use the "Dual Analog" input mode in Parallel Launcher) + } +- if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { +- s8DirModeYawOffset -= DEGREES(45); +- play_sound_cbutton_side(); +- } +-#ifdef PARALLEL_LAKITU_CAM +- // extra functionality +- else if (gPlayer1Controller->buttonPressed & U_JPAD) { +- s8DirModeYawOffset = 0; +- s8DirModeYawOffset = gMarioState->faceAngle[1]-0x8000; +- } +- else if (gPlayer1Controller->buttonDown & L_JPAD) { +- s8DirModeYawOffset -= DEGREES(2); ++ ++ if (gPlayer1Controller->buttonDown & R_TRIG) { ++ if (gPlayer1Controller->buttonDown & L_CBUTTONS) { ++ s8DirModeBaseYaw -= DEGREES(cameraSpeed); ++ } else if (gPlayer1Controller->buttonDown & R_CBUTTONS) { ++ s8DirModeBaseYaw += DEGREES(cameraSpeed); ++ } ++ rButtonCounter++; // This increses whenever R is held. ++ } else { ++ if (rButtonCounter > 0 && rButtonCounter <= 5 && !((gPlayer1Controller->buttonDown & L_CBUTTONS) || (gPlayer1Controller->buttonDown & R_CBUTTONS))) { ++ // This centers the camera behind mario. It triggers when you let go of R in less than 5 frames. ++ s8DirModeYawOffset = 0; ++ s8DirModeBaseYaw = gMarioState->faceAngle[1]-0x8000; ++ gMarioState->area->camera->yaw = s8DirModeBaseYaw; ++ play_sound_rbutton_changed(); ++ } ++ rButtonCounter = 0; ++ } ++ if (gPlayer1Controller->buttonPressed & R_TRIG) { ++ if (rButtonCounter2 <= 5) { ++ set_cam_angle(CAM_ANGLE_MARIO); // Enter mario cam if R is pressed 2 times in less than 5 frames ++ rButtonCounter2 = 6; ++ } else { ++ rButtonCounter2 = 0; ++ } ++ } else { ++ rButtonCounter2++; + } +- else if (gPlayer1Controller->buttonDown & R_JPAD) { +- s8DirModeYawOffset += DEGREES(2); ++ if (gPlayer1Controller->buttonPressed & D_JPAD) { ++ s8DirModeBaseYaw = (s8DirModeBaseYaw + 0x1000) & 0xE000; // Lock the camera to the nearest 45deg axis + } +- else if (gPlayer1Controller->buttonPressed & D_JPAD) { +- s8DirModeYawOffset = s8DirModeYawOffset&0xE000; +- } +-#endif + + lakitu_zoom(400.f, 0x900); + c->nextYaw = update_8_directions_camera(c, c->focus, pos); ++ set_camera_height(c, pos[1]); + c->pos[0] = pos[0]; + c->pos[2] = pos[2]; + sAreaYawChange = sAreaYaw - oldAreaYaw; +- set_camera_height(c, pos[1]); + } + ++ + /** + * Updates the camera in outward radial mode. + * sModeOffsetYaw is calculated in radial_camera_move, which calls offset_yaw_outward_radial +@@ -3036,20 +3091,21 @@ void update_lakitu(struct Camera *c) { + void update_camera(struct Camera *c) { + UNUSED u8 unused[24]; + ++ extern s16 s8DirModeBaseYaw; ++ + gCamera = c; + update_camera_hud_status(c); + if (c->cutscene == 0) { + // Only process R_TRIG if 'fixed' is not selected in the menu + if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) { + if (gPlayer1Controller->buttonPressed & R_TRIG) { +- if (set_cam_angle(0) == CAM_ANGLE_LAKITU) { +- set_cam_angle(CAM_ANGLE_MARIO); +- } else { ++ if (set_cam_angle(0) == CAM_ANGLE_MARIO) { ++ s8DirModeBaseYaw = ((gMarioState->faceAngle[1]-0x8000) + 0x1000) & 0xE000; + set_cam_angle(CAM_ANGLE_LAKITU); + } + } + } +- play_sound_if_cam_switched_to_lakitu_or_mario(); ++ //play_sound_if_cam_switched_to_lakitu_or_mario(); + } + + // Initialize the camera +@@ -4849,15 +4905,15 @@ void play_camera_buzz_if_c_sideways(void) { + } + + void play_sound_cbutton_up(void) { +- play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); ++ //play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); + } + + void play_sound_cbutton_down(void) { +- play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); ++ //play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); + } + + void play_sound_cbutton_side(void) { +- play_sound(SOUND_MENU_CAMERA_TURN, gGlobalSoundSource); ++ //play_sound(SOUND_MENU_CAMERA_TURN, gGlobalSoundSource); + } + + void play_sound_button_change_blocked(void) { +@@ -4961,7 +5017,7 @@ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { + } + + // Zoom in / enter C-Up +- if (gPlayer1Controller->buttonPressed & U_CBUTTONS) { ++ if (((gPlayer1Controller->buttonPressed & U_CBUTTONS) || (gPlayer2Controller->rawStickY > 40)) && (stickReset)) { + if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { + gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT; + play_sound_cbutton_up(); +@@ -4971,7 +5027,7 @@ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { + } + + // Zoom out +- if (gPlayer1Controller->buttonPressed & D_CBUTTONS) { ++ if ((gPlayer1Controller->buttonPressed & D_CBUTTONS) || (gPlayer2Controller->rawStickY < -40)) { + if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { + gCameraMovementFlags |= CAM_MOVE_ALREADY_ZOOMED_OUT; + #ifndef VERSION_JP +@@ -4983,6 +5039,12 @@ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { + } + } + ++ if ((gPlayer2Controller->rawStickY > 40) || (gPlayer2Controller->rawStickY < -40)) { ++ stickReset = 0; ++ } else { ++ stickReset = 1; ++ } ++ + //! returning uninitialized variable + return dummy; + } +@@ -5548,7 +5610,7 @@ void set_camera_mode_8_directions(struct Camera *c) { + if (c->mode != CAMERA_MODE_8_DIRECTIONS) { + c->mode = CAMERA_MODE_8_DIRECTIONS; + sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT; +- s8DirModeBaseYaw = 0; ++ s8DirModeBaseYaw = ((gMarioState->faceAngle[1]-0x8000) + 0x1000) & 0xE000; + s8DirModeYawOffset = 0; + } + } +diff --git a/src/game/game_init.c b/src/game/game_init.c +index 6cfa8f5..238378c 100644 +--- a/src/game/game_init.c ++++ b/src/game/game_init.c +@@ -46,6 +46,9 @@ OSContPad gControllerPads[4]; + u8 gControllerBits; + u8 gIsConsole; + u8 gBorderHeight; ++u8 gCameraSpeed = 2; ++u8 gWaterCamOverride; ++u8 gFlyingCamOverride; + #ifdef EEP + s8 gEepromProbe; + #endif +@@ -715,6 +718,7 @@ void thread5_game_loop(UNUSED void *arg) { + + play_music(SEQ_PLAYER_SFX, SEQUENCE_ARGS(0, SEQ_SOUND_PLAYER), 0); + set_sound_mode(save_file_get_sound_mode()); ++ gCameraSpeed = (save_file_get_camera_speed()); + #ifdef WIDE + gWidescreen = save_file_get_widescreen_mode(); + #endif +diff --git a/src/game/game_init.h b/src/game/game_init.h +index 87386ce..1d69560 100644 +--- a/src/game/game_init.h ++++ b/src/game/game_init.h +@@ -45,6 +45,9 @@ extern u8 gIsConsole; + #ifdef WIDE + extern u8 gWidescreen; + #endif ++extern u8 gCameraSpeed; ++extern u8 gWaterCamOverride; ++extern u8 gFlyingCamOverride; + extern u8 gBorderHeight; + #ifdef EEP + extern s8 gEepromProbe; +diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c +index 9cd458a..ac2d18c 100644 +--- a/src/game/ingame_menu.c ++++ b/src/game/ingame_menu.c +@@ -39,6 +39,12 @@ u8 textWideInfo[] = { TEXT_HUD_WIDE_INFO }; + u8 textWideInfo2[] = { TEXT_HUD_WIDE_INFO2 }; + #endif + ++u8 textCamInfoSlowest[] = { TEXT_CAM_INFO_SLOWEST }; ++u8 textCamInfoSlow[] = { TEXT_CAM_INFO_SLOW }; ++u8 textCamInfoMedium[] = { TEXT_CAM_INFO_MEDIUM }; ++u8 textCamInfoFast[] = { TEXT_CAM_INFO_FAST}; ++u8 textCamInfoFastest[] = { TEXT_CAM_INFO_FASTEST }; ++ + extern u8 gLastCompletedCourseNum; + extern u8 gLastCompletedStarNum; + +@@ -1350,6 +1356,45 @@ void reset_red_coins_collected(void) { + gRedCoinsCollected = 0; + } + ++void render_camera_speed_setting(void) { ++ gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); ++ gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); ++ switch (gCameraSpeed) { ++ case 0: ++ print_generic_string(190, 20, textCamInfoSlowest); ++ break; ++ case 1: ++ print_generic_string(190, 20, textCamInfoSlow); ++ break; ++ case 2: ++ print_generic_string(190, 20, textCamInfoMedium); ++ break; ++ case 3: ++ print_generic_string(190, 20, textCamInfoFast); ++ break; ++ case 4: ++ print_generic_string(190, 20, textCamInfoFastest); ++ break; ++ } ++ gSPDisplayList(gDisplayListHead++, dl_ia_text_end); ++ ++ if (gPlayer1Controller->buttonPressed & R_JPAD) { ++ if (gCameraSpeed < 4) { ++ gCameraSpeed += 1; ++ } else { ++ gCameraSpeed = 0; ++ } ++ save_file_set_camera_speed(gCameraSpeed); ++ } else if (gPlayer1Controller->buttonPressed & L_JPAD) { ++ if (gCameraSpeed > 0) { ++ gCameraSpeed -= 1; ++ } else { ++ gCameraSpeed = 4; ++ } ++ save_file_set_camera_speed(gCameraSpeed); ++ } ++} ++ + void change_dialog_camera_angle(void) { + if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) { + gDialogCameraAngleIndex = CAM_SELECTION_MARIO; +@@ -1779,6 +1824,7 @@ s16 render_pause_courses_and_castle(void) { + } + #ifdef WIDE + render_widescreen_setting(); ++ render_camera_speed_setting(); + if (gPlayer1Controller->buttonPressed & L_TRIG){ + gWidescreen ^= 1; + save_file_set_widescreen_mode(gWidescreen); +diff --git a/src/game/mario.c b/src/game/mario.c +index b381afa..d935245 100644 +--- a/src/game/mario.c ++++ b/src/game/mario.c +@@ -1443,32 +1443,39 @@ void update_mario_inputs(struct MarioState *m) { + void set_submerged_cam_preset_and_spawn_bubbles(struct MarioState *m) { + f32 heightBelowWater; + s16 camPreset; ++ extern s16 s8DirModeBaseYaw; ++ if (!gWaterCamOverride) { ++ if ((m->action & ACT_GROUP_MASK) == ACT_GROUP_SUBMERGED) { ++ heightBelowWater = (f32)(m->waterLevel - 80) - m->pos[1]; ++ camPreset = m->area->camera->mode; ++ if (m->action & ACT_FLAG_METAL_WATER) { ++ if (camPreset != CAMERA_MODE_CLOSE) { ++ set_camera_mode(m->area->camera, CAMERA_MODE_CLOSE, 1); ++ } ++ } else { ++ if ((heightBelowWater > 800.0f) && (camPreset != CAMERA_MODE_BEHIND_MARIO)) { ++ set_camera_mode(m->area->camera, CAMERA_MODE_BEHIND_MARIO, 1); ++ } + +- if ((m->action & ACT_GROUP_MASK) == ACT_GROUP_SUBMERGED) { +- heightBelowWater = (f32)(m->waterLevel - 80) - m->pos[1]; +- camPreset = m->area->camera->mode; +- +- if (m->action & ACT_FLAG_METAL_WATER) { +- if (camPreset != CAMERA_MODE_CLOSE) { +- set_camera_mode(m->area->camera, CAMERA_MODE_CLOSE, 1); +- } +- } else { +- if ((heightBelowWater > 800.0f) && (camPreset != CAMERA_MODE_BEHIND_MARIO)) { +- set_camera_mode(m->area->camera, CAMERA_MODE_BEHIND_MARIO, 1); +- } +- +- if ((heightBelowWater < 400.0f) && (camPreset != CAMERA_MODE_WATER_SURFACE)) { +- set_camera_mode(m->area->camera, CAMERA_MODE_WATER_SURFACE, 1); +- } ++ if ((heightBelowWater < 400.0f) && (camPreset != CAMERA_MODE_WATER_SURFACE)) { ++ set_camera_mode(m->area->camera, CAMERA_MODE_WATER_SURFACE, 1); ++ } + +- // As long as Mario isn't drowning or at the top +- // of the water with his head out, spawn bubbles. +- if (!(m->action & ACT_FLAG_INTANGIBLE)) { +- if ((m->pos[1] < (f32)(m->waterLevel - 160)) || (m->faceAngle[0] < -0x800)) { +- m->particleFlags |= PARTICLE_BUBBLE; ++ // As long as Mario isn't drowning or at the top ++ // of the water with his head out, spawn bubbles. ++ if (!(m->action & ACT_FLAG_INTANGIBLE)) { ++ if ((m->pos[1] < (f32)(m->waterLevel - 160)) || (m->faceAngle[0] < -0x800)) { ++ m->particleFlags |= PARTICLE_BUBBLE; ++ } + } + } + } ++ } else { ++ set_camera_mode(m->area->camera, CAMERA_MODE_8_DIRECTIONS, 1); ++ } ++ if (gPlayer1Controller->buttonPressed & L_TRIG) { ++ s8DirModeBaseYaw = ((gMarioState->faceAngle[1]-0x8000) + 0x1000) & 0xE000; ++ gWaterCamOverride ^= 1; + } + } + +diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c +index ce6467e..9ebb861 100644 +--- a/src/game/mario_actions_airborne.c ++++ b/src/game/mario_actions_airborne.c +@@ -1736,6 +1736,10 @@ s32 act_shot_from_cannon(struct MarioState *m) { + s32 act_flying(struct MarioState *m) { + s16 startPitch = m->faceAngle[0]; + ++ if (gPlayer1Controller->buttonPressed & L_TRIG) { ++ gFlyingCamOverride ^= 1; ++ } ++ + if (m->input & INPUT_Z_PRESSED) { + if (m->area->camera->mode == CAMERA_MODE_BEHIND_MARIO) { + set_camera_mode(m->area->camera, m->area->camera->defMode, 1); +@@ -1750,8 +1754,10 @@ s32 act_flying(struct MarioState *m) { + return set_mario_action(m, ACT_FREEFALL, 0); + } + +- if (m->area->camera->mode != CAMERA_MODE_BEHIND_MARIO) { ++ if (!gFlyingCamOverride) { + set_camera_mode(m->area->camera, CAMERA_MODE_BEHIND_MARIO, 1); ++ } else { ++ set_camera_mode(m->area->camera, CAMERA_MODE_8_DIRECTIONS, 1); + } + + if (m->actionState == 0) { +@@ -1933,7 +1939,7 @@ s32 act_flying_triple_jump(struct MarioState *m) { + } + + if (m->vel[1] < 4.0f) { +- if (m->area->camera->mode != CAMERA_MODE_BEHIND_MARIO) { ++ if ((m->area->camera->mode != CAMERA_MODE_BEHIND_MARIO) && (!gFlyingCamOverride)) { + set_camera_mode(m->area->camera, CAMERA_MODE_BEHIND_MARIO, 1); + } + +@@ -1944,7 +1950,7 @@ s32 act_flying_triple_jump(struct MarioState *m) { + set_mario_action(m, ACT_FLYING, 1); + } + +- if (m->actionTimer++ == 10 && m->area->camera->mode != CAMERA_MODE_BEHIND_MARIO) { ++ if (m->actionTimer++ == 10 && m->area->camera->mode != CAMERA_MODE_BEHIND_MARIO && (!gFlyingCamOverride)) { + set_camera_mode(m->area->camera, CAMERA_MODE_BEHIND_MARIO, 1); + } + +diff --git a/src/game/save_file.c b/src/game/save_file.c +index b27d869..7fbf045 100644 +--- a/src/game/save_file.c ++++ b/src/game/save_file.c +@@ -634,6 +634,12 @@ u8 save_file_get_widescreen_mode(void) { + return gSaveBuffer.menuData[0].wideMode; + } + ++void save_file_set_camera_speed(u8 speed) { ++ gSaveBuffer.menuData[0].cameraSpeedSetting = speed; ++ gMainMenuDataModified = TRUE; ++ save_main_menu_data(); ++} ++ + void save_file_set_widescreen_mode(u8 mode) { + gSaveBuffer.menuData[0].wideMode = mode; + +@@ -646,6 +652,10 @@ u16 save_file_get_sound_mode(void) { + return gSaveBuffer.menuData[0].soundMode; + } + ++u8 save_file_get_camera_speed(void) { ++ return gSaveBuffer.menuData[0].cameraSpeedSetting; ++} ++ + void save_file_move_cap_to_default_location(void) { + if (save_file_get_flags() & SAVE_FLAG_CAP_ON_GROUND) { + switch (gSaveBuffer.files[gCurrSaveFileNum - 1][0].capLevel) { +diff --git a/src/game/save_file.h b/src/game/save_file.h +index 00fc042..dd394a6 100644 +--- a/src/game/save_file.h ++++ b/src/game/save_file.h +@@ -62,6 +62,7 @@ struct MainMenuSaveData + #ifdef WIDE + u8 wideMode: 1; + #endif ++ u8 cameraSpeedSetting; + + #ifdef VERSION_EU + u16 language; +@@ -167,6 +168,8 @@ u16 save_file_get_sound_mode(void); + u8 save_file_get_widescreen_mode(void); + void save_file_set_widescreen_mode(u8 mode); + #endif ++u8 save_file_get_camera_speed(void); ++void save_file_set_camera_speed(u8 speed); + void save_file_move_cap_to_default_location(void); + + void disable_warp_checkpoint(void);