diff --git a/README.md b/README.md index 07eadafb..b5fc2ae9 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,9 @@ This repo needs gcc in order to be able to build it. To install it, run `sudo ap This is a fork of the ultrasm64 repo by CrashOveride which includes the following commonly used patches (patches marked with `*` are toggleable in `config.h`): +**About Puppycam** +- Puppycam is available **on a dedicated branch**. If you want puppycam in your hack, clone the `puppycamera2` branch instead of `master`. + **Collision:** - Slope fix and exposed ceilings fix - No false ledgegrabs fix * @@ -29,6 +32,8 @@ This is a fork of the ultrasm64 repo by CrashOveride which includes the followin - You can increase the number of frames that you have to perform a firsty * - Ability to set Mario's movement speed when hanging from a ceiling * - Tighter hanging controls (mario will face the direction of the analog stick directly while hanging from a ceiling) * +- reonucam3: custom camera by me. This is included as a .patch file in the enhancements folder, you need to apply it if you want this camera. + This video shows a rundown of the features: https://youtu.be/TQNkznX9Z3k **Hacker QOL:** - Global, non-level based, star IDs (off by default) * @@ -46,6 +51,7 @@ This is a fork of the ultrasm64 repo by CrashOveride which includes the followin - The internal ROM name is now set with a define in `config.h` to make it simpler - There is a `gIsConsole` variable that is 1 when running on console and 0 when running on emulator. This way you can wrap your code in a console check. - Expanded audio heap allows for a larger concurrent note count and the importing of more m64 sequences and sound banks (By ArcticJaguar725) * +- You can set a test level in config.h in order to boot straight into it, so you can quickly test the level you're working on. * **Other Bugfixes:** - Castle music fix (Fixes the castle music sometimes triggering after getting a dialog) * diff --git a/enhancements/reonu_cam.patch b/enhancements/reonu_cam.patch deleted file mode 100644 index 4e210fe9..00000000 --- a/enhancements/reonu_cam.patch +++ /dev/null @@ -1,183 +0,0 @@ -diff --git a/src/game/camera.c b/src/game/camera.c -index 13d3fe2..be49880 100644 ---- a/src/game/camera.c -+++ b/src/game/camera.c -@@ -259,6 +259,7 @@ s16 sCameraSoundFlags; - * Stores what C-Buttons are pressed this frame. - */ - u16 sCButtonsPressed; -+u16 stoppedMovingCamera; - /** - * A copy of gDialogID, the dialog displayed during the cutscene. - */ -@@ -433,6 +434,9 @@ u8 sFramesSinceCutsceneEnded = 0; - * 3 = Dialog doesn't have a response - */ - u8 sCutsceneDialogResponse = 0; -+u8 stickReset = 1; -+u8 cButtonCounter; -+u8 lastCameraMove; - struct PlayerCameraState *sMarioCamState = &gPlayerCameraState[0]; - struct PlayerCameraState *sLuigiCamState = &gPlayerCameraState[1]; - u32 unused8032D008 = 0; -@@ -442,6 +446,9 @@ Vec3f sUnusedModeBasePosition_3 = { 646.0f, 143.0f, -1513.0f }; - Vec3f sUnusedModeBasePosition_4 = { 646.0f, 143.0f, -1513.0f }; - Vec3f sUnusedModeBasePosition_5 = { 646.0f, 143.0f, -1513.0f }; - -+#define MOVED_LEFT 1 -+#define MOVED_RIGHT 2 -+ - s32 update_radial_camera(struct Camera *c, Vec3f, Vec3f); - s32 update_outward_radial_camera(struct Camera *c, Vec3f, Vec3f); - s32 update_behind_mario_camera(struct Camera *c, Vec3f, Vec3f); -@@ -1176,14 +1183,39 @@ void mode_8_directions_camera(struct Camera *c) { - - radial_camera_input(c, 0.f); - -- if (gPlayer1Controller->buttonPressed & R_CBUTTONS) { -- s8DirModeYawOffset += DEGREES(45); -- play_sound_cbutton_side(); -- } -- if (gPlayer1Controller->buttonPressed & L_CBUTTONS) { -- s8DirModeYawOffset -= DEGREES(45); -- play_sound_cbutton_side(); -+ if (gPlayer1Controller->buttonDown & L_CBUTTONS) { -+ s8DirModeYawOffset -= DEGREES(4); -+ cButtonCounter++; -+ stoppedMovingCamera = 0; -+ lastCameraMove = MOVED_LEFT; -+ -+ } -+ else if (gPlayer1Controller->buttonDown & R_CBUTTONS) { -+ s8DirModeYawOffset += DEGREES(4); -+ cButtonCounter++; -+ stoppedMovingCamera = 0; -+ lastCameraMove = MOVED_RIGHT; -+ } -+ else if (gPlayer2Controller->rawStickX) { -+ s8DirModeYawOffset += DEGREES(gPlayer2Controller->rawStickX * 4 / 64); -+ } else { -+ stoppedMovingCamera = 1; -+ } -+ -+ if (stoppedMovingCamera == 1) { -+ if ((cButtonCounter < 5) && (cButtonCounter > 0)) { -+ if (lastCameraMove == MOVED_RIGHT) { -+ s8DirModeYawOffset += DEGREES(45); -+ cButtonCounter = 0; -+ } else { -+ s8DirModeYawOffset -= DEGREES(45); -+ cButtonCounter = 0; -+ } -+ } else { -+ cButtonCounter = 0; -+ } - } -+ - - lakitu_zoom(400.f, 0x900); - c->nextYaw = update_8_directions_camera(c, c->focus, pos); -@@ -2760,7 +2792,7 @@ s32 mode_c_up_camera(struct Camera *c) { - sPanDistance = 0.f; - - // Exit C-Up mode -- if (gPlayer1Controller->buttonPressed & (A_BUTTON | B_BUTTON | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS)) { -+ if ((gPlayer1Controller->buttonPressed & (A_BUTTON | B_BUTTON | D_CBUTTONS | L_CBUTTONS | R_CBUTTONS)) || (gPlayer2Controller->rawStickY < -10)) { - exit_c_up(c); - } - return 0; -@@ -3015,14 +3047,11 @@ void update_camera(struct Camera *c) { - // 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 { -- set_cam_angle(CAM_ANGLE_LAKITU); -- } -+ s8DirModeYawOffset = gMarioState->faceAngle[1]-0x8000; -+ play_sound_rbutton_changed(); - } - } -- play_sound_if_cam_switched_to_lakitu_or_mario(); -+ //play_sound_if_cam_switched_to_lakitu_or_mario(); - } - - // Initialize the camera -@@ -3865,7 +3894,7 @@ s32 find_c_buttons_pressed(u16 currentState, u16 buttonsPressed, u16 buttonsDown - currentState &= ~R_CBUTTONS; - } - -- if (buttonsPressed & U_CBUTTONS) { -+ if ((buttonsPressed & U_CBUTTONS)) { - currentState |= U_CBUTTONS; - currentState &= ~D_CBUTTONS; - } -@@ -4816,19 +4845,19 @@ 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_IN, 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) { -- play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource); -+ //play_sound(SOUND_MENU_CAMERA_BUZZ, gGlobalSoundSource); - } - - void play_sound_rbutton_changed(void) { -@@ -4925,7 +4954,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(); -@@ -4935,7 +4964,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 -@@ -4946,7 +4975,11 @@ s32 radial_camera_input(struct Camera *c, UNUSED f32 unused) { - play_sound_cbutton_down(); - } - } -- -+ if ((gPlayer2Controller->rawStickY > 40) || (gPlayer2Controller->rawStickY < -40)) { -+ stickReset = 0; -+ } else { -+ stickReset = 1; -+ } - //! returning uninitialized variable - return dummy; - } -diff --git a/src/game/hud.c b/src/game/hud.c -index f11b626..003a634 100644 ---- a/src/game/hud.c -+++ b/src/game/hud.c -@@ -506,7 +506,7 @@ void render_hud(void) { - - if (hudDisplayFlags & HUD_DISPLAY_FLAG_CAMERA_AND_POWER) { - render_hud_power_meter(); -- render_hud_camera_status(); -+ //render_hud_camera_status(); - } - - if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIMER) { diff --git a/enhancements/reonucam3.patch b/enhancements/reonucam3.patch new file mode 100644 index 00000000..d99eb14f --- /dev/null +++ b/enhancements/reonucam3.patch @@ -0,0 +1,572 @@ +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..e56f8c0 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,25 @@ 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 & R_TRIG) && (gPlayer1Controller->buttonDown & U_CBUTTONS)) { ++ gKeepCliffCam = 1; ++ pitch = DEGREES(60); ++ } else if (((gPlayer1Controller->buttonDown & U_CBUTTONS) || (gPlayer1Controller->buttonDown & R_TRIG)) && gKeepCliffCam) { ++ pitch = DEGREES(60); ++ } else { ++ gKeepCliffCam = 0; ++ } ++ ++ + 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 +1192,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 +1221,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) || (gMarioState->action & ACT_FLAG_SWIMMING_OR_FLYING))) { ++ // 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 +@@ -2116,7 +2177,7 @@ s16 update_default_camera(struct Camera *c) { + gLakituState.goalPos[1], + gLakituState.goalPos[2], &ceil); + s16 yawDir; +- ++ + handle_c_button_movement(c); + vec3f_get_dist_and_angle(sMarioCamState->pos, c->pos, &dist, &pitch, &yaw); + +@@ -3036,20 +3097,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 +4911,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 +5023,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) && !(gPlayer1Controller->buttonDown & R_TRIG)) { + if (gCameraMovementFlags & CAM_MOVE_ZOOMED_OUT) { + gCameraMovementFlags &= ~CAM_MOVE_ZOOMED_OUT; + play_sound_cbutton_up(); +@@ -4971,7 +5033,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 +5045,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 +5616,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..63158e1 100644 +--- a/src/game/game_init.c ++++ b/src/game/game_init.c +@@ -46,6 +46,11 @@ OSContPad gControllerPads[4]; + u8 gControllerBits; + u8 gIsConsole; + u8 gBorderHeight; ++u8 gCameraSpeed = 2; ++u8 gWaterCamOverride; ++u8 gFlyingCamOverride; ++u8 gKeepCliffCam; ++s32 gCliffTimer; + #ifdef EEP + s8 gEepromProbe; + #endif +@@ -715,6 +720,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..47e9724 100644 +--- a/src/game/game_init.h ++++ b/src/game/game_init.h +@@ -45,6 +45,10 @@ extern u8 gIsConsole; + #ifdef WIDE + extern u8 gWidescreen; + #endif ++extern u8 gCameraSpeed; ++extern u8 gWaterCamOverride; ++extern u8 gFlyingCamOverride; ++extern u8 gKeepCliffCam; + 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..7cb9549 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 & R_TRIG) && (m->action & ACT_FLAG_SWIMMING)) { ++ 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..c7e998c 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 & R_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..7062ead 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: 3; + + #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); diff --git a/include/config.h b/include/config.h index db9c20ee..66c99565 100644 --- a/include/config.h +++ b/include/config.h @@ -54,6 +54,12 @@ // -- ultrasm64-extbounds specific settings -- +// TEST LEVEL +// Uncomment this define and set a test level in order to boot straight into said level. +// This allows you to quickly test the level you're working on. +// If you want the game to boot normally, just comment out the define again. +//#define TEST_LEVEL LEVEL_BOB + // COMMON HACK CHANGES // Internal ROM name. NEEDS TO BE **EXACTLY** 20 CHARACTERS. Can't be 19 characters, can't be 21 characters. You can fill it with spaces. // The end quote should be here: " @@ -79,7 +85,7 @@ // Number of coins to spawn the "100 coin" star. If you remove the define altogether, then there won't be a 100 coin star at all. #define X_COIN_STAR 100 // Platform displacement 2 also known as momentum patch. Makes Mario keep the momemtum from moving platforms. Breaks treadmills. -#define PLATFORM_DISPLACEMENT_2 +//#define PLATFORM_DISPLACEMENT_2 // Stars don't kick you out of the level // #define NON_STOP_STARS // Uncomment this if you want global star IDs (useful for creating an open world hack ala MVC) @@ -88,25 +94,15 @@ //#define SKIP_TITLE_SCREEN // Uncomment this if you want to keep the mario head and not skip it //#define KEEP_MARIO_HEAD -// Makes the coins ia8 64x64 instead of ia16 32x32. Uses new ia8 textures so that vanilla coins look better. -#define IA8_COINS // Enables "parallel lakitu camera" or "aglab cam" which lets you move the camera smoothly with the dpad #define PARALLEL_LAKITU_CAM +// Allows Mario to ledgegrab sloped floors +#define NO_FALSE_LEDGEGRABS // HACKER QOL -// Enable widescreen (16:9) support -#define WIDE -// When this option is enabled, LODs will ONLY work on console. -// When this option is disabled, LODs will work regardless of whether console or emulator is used. -// Regardless of whether this setting is enabled or not, you can use gIsConsole to wrap your own code in a console check. -#define AUTO_LOD // Increase the maximum pole length (it will treat bparam1 and bparam2 as a single value) #define LONGER_POLES -// Disable AA (Recommended: it changes nothing on emulator, and it makes console run better) -#define DISABLE_AA -// Allows Mario to ledgegrab sloped floors -#define NO_FALSE_LEDGEGRABS // Number of possible unique model ID's (keep it higher than 256) #define MODEL_ID_COUNT 256 // Increase audio heap size to allow for more concurrent notes to be played and for more custom sequences/banks to be imported (does nothing with EU and SH versions) @@ -141,10 +137,20 @@ #define EXIT_COURSE_NODE 0x1F // OTHER ENHANCEMENTS +// Enable widescreen (16:9) support +#define WIDE // Skybox size modifier, changing this will add support for larger skybox images. NOTE: Vanilla skyboxes may break if you change this option. Be sure to rescale them accordingly. // Whenever you change this, make sure to run "make -C tools clean" to rebuild the skybox tool (alternatively go into skyconv.c and change the file in any way (like adding/deleting a space) to specifically rebuild that tool). // When increasing this, you should probably also increase the GFX pool size. (the GFX_POOL_SIZE define in src/game/game_init.h) #define SKYBOX_SIZE 1 +// When this option is enabled, LODs will ONLY work on console. +// When this option is disabled, LODs will work regardless of whether console or emulator is used. +// Regardless of whether this setting is enabled or not, you can use gIsConsole to wrap your own code in a console check. +#define AUTO_LOD +// Disable AA (Recommended: it changes nothing on emulator, and it makes console run better) +#define DISABLE_AA +// Makes the coins ia8 64x64 instead of ia16 32x32. Uses new ia8 textures so that vanilla coins look better. +#define IA8_COINS // If you want to change the extended boundaries mode, go to engine/extended_bounds.h and change EXTENDED_BOUNDS_MODE diff --git a/levels/entry.c b/levels/entry.c index 17c773ed..a7bc8209 100644 --- a/levels/entry.c +++ b/levels/entry.c @@ -7,11 +7,19 @@ #include "make_const_nonconst.h" +#include "config.h" + +extern const LevelScript level_main_scripts_entry[]; const LevelScript level_script_entry[] = { INIT_LEVEL(), SLEEP(/*frames*/ 2), BLACKOUT(/*active*/ FALSE), - SET_REG(/*value*/ 0), + #ifdef TEST_LEVEL + SET_REG(TEST_LEVEL), + EXECUTE(/*seg*/ 0x15, _scriptsSegmentRomStart, _scriptsSegmentRomEnd, level_main_scripts_entry), + #else + SET_REG(0), EXECUTE(/*seg*/ 0x14, /*script*/ _introSegmentRomStart, /*scriptEnd*/ _introSegmentRomEnd, /*entry*/ level_intro_splash_screen), + #endif JUMP(/*target*/ level_script_entry), -}; +}; \ No newline at end of file diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index b8682cd8..8b98e350 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -1498,6 +1498,10 @@ void render_widescreen_setting(void) { print_generic_string(10, 200, textWideInfo2); } gSPDisplayList(gDisplayListHead++, dl_ia_text_end); + if (gPlayer1Controller->buttonPressed & L_TRIG){ + gWidescreen ^= 1; + save_file_set_widescreen_mode(gWidescreen); + } } #endif @@ -1854,10 +1858,6 @@ s16 render_pause_courses_and_castle(void) { } #ifdef WIDE render_widescreen_setting(); - if (gPlayer1Controller->buttonPressed & L_TRIG){ - gWidescreen ^= 1; - save_file_set_widescreen_mode(gWidescreen); - } #endif if (gDialogTextAlpha < 250) { gDialogTextAlpha += 25; diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 3886a0de..1a42958f 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -15,8 +15,6 @@ #include "config.h" -#define WIDESCREEN - /** * This file contains the code that processes the scene graph for rendering. * The scene graph is responsible for drawing everything except the HUD / text boxes. @@ -297,14 +295,9 @@ static void geo_process_perspective(struct GraphNodePerspective *node) { u16 perspNorm; Mtx *mtx = alloc_display_list(sizeof(*mtx)); #ifdef WIDE - if (gWidescreen){ - if (gCurrLevelNum == 0x01) { - aspect = 1.33333f; - } else { - aspect = 1.775f; - } - } - else{ + if (gWidescreen && (gCurrLevelNum != 0x01)){ + aspect = 1.775f; + } else { aspect = 1.33333f; } #else @@ -836,11 +829,10 @@ static s32 obj_is_in_view(struct GraphNodeObject *node, Mat4 matrix) { // the amount of units between the center of the screen and the horizontal edge // given the distance from the object to the camera. -#ifdef WIDESCREEN // This multiplication should really be performed on 4:3 as well, // but the issue will be more apparent on widescreen. + // HackerSM64: This multiplication is done regardless of aspect ratio to fix object pop-in on the edges of the screen (which happens at 4:3 too) hScreenEdge *= GFX_DIMENSIONS_ASPECT_RATIO; -#endif if (geo != NULL && geo->type == GRAPH_NODE_TYPE_CULLING_RADIUS) { cullingRadius = diff --git a/src/game/save_file.h b/src/game/save_file.h index 00fc042b..3ac0c4d9 100644 --- a/src/game/save_file.h +++ b/src/game/save_file.h @@ -64,7 +64,7 @@ struct MainMenuSaveData #endif #ifdef VERSION_EU - u16 language; + u8 language: 2; #define SUBTRAHEND 8 #else #define SUBTRAHEND 6 diff --git a/src/menu/star_select.c b/src/menu/star_select.c index af55ae76..8bfacca7 100644 --- a/src/menu/star_select.c +++ b/src/menu/star_select.c @@ -53,8 +53,7 @@ static s8 sSelectableStarIndex = 0; // Act Selector menu timer that keeps counting until you choose an act. static s32 sActSelectorMenuTimer = 0; -#ifdef WIDE -#endif + /** * Act Selector Star Type Loop Action * Defines a select type for a star in the act selector. @@ -95,11 +94,10 @@ void render_100_coin_star(u8 stars) { if (stars & (1 << 6)) { // If the 100 coin star has been collected, create a new star selector next to the coin score. #ifdef WIDE - if (gWidescreen){ + if (gWidescreen) { sStarSelectorModels[6] = spawn_object_abs_with_rot(gCurrentObject, 0, MODEL_STAR, bhvActSelectorStarType, ((370*4.0f)/3), 24, -300, 0, 0, 0); - } - else{ + } else { sStarSelectorModels[6] = spawn_object_abs_with_rot(gCurrentObject, 0, MODEL_STAR, bhvActSelectorStarType, 370, 24, -300, 0, 0, 0); } @@ -169,8 +167,7 @@ void bhv_act_selector_init(void) { (((75 + sVisibleStars * -75 + i * 152)*4.0f)/3), 248, -300, 0, 0, 0); sStarSelectorModels[i]->oStarSelectorSize = 1.0f; } - } - else { + } else { for (i = 0; i < sVisibleStars; i++) { sStarSelectorModels[i] = spawn_object_abs_with_rot(gCurrentObject, 0, selectorModelIDs[i], bhvActSelectorStarType,