diff --git a/README.md b/README.md index 0cb169fa..05fb7e25 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ This is a fork of the ultrasm64 repo by CrashOveride which includes the followin - **Fazana**: PuppyLib, ucode swapping, audio load time optimisations (with Arctic), general hacker qol improvements, visual debug - **Reonu**: Starting the project/repo, widescreen, reonucam, various defines for hacker QoL - **JoshDuMan**: Decomp guy, general assistance -- **Arceveti**: Silhouette, shadow optimisation, better hanging, breath meter +- **Arceveti**: Silhouette, shadow optimisation, better hanging, breath meter, 4 controller support - **axollyon**: Console testing, bugfixes, idea-guying, and had a hand in silhouettes - **Wiseguy**: World scale reimplementation, silhouette, graph node optimisations, instant input patch, cake screen fix, segmented code support, and various optimizations/fixes - **Kaze**: Graph node optimisations, automatic optimal collision distance diff --git a/src/boot/main.c b/src/boot/main.c index b22639b7..f42b7bad 100644 --- a/src/boot/main.c +++ b/src/boot/main.c @@ -84,8 +84,8 @@ UNUSED static u16 sDebugTextKeySequence[] = { }; static s16 sDebugTextKey = 0; UNUSED void handle_debug_key_sequences(void) { - if (gPlayer3Controller->buttonPressed != 0) { - if (sDebugTextKeySequence[sDebugTextKey++] == gPlayer3Controller->buttonPressed) { + if (gPlayer1Controller->buttonPressed != 0) { + if (sDebugTextKeySequence[sDebugTextKey++] == gPlayer1Controller->buttonPressed) { if (sDebugTextKey == ARRAY_COUNT(sDebugTextKeySequence)) { sDebugTextKey = 0; gShowDebugText ^= 1; diff --git a/src/game/behaviors/hoot.inc.c b/src/game/behaviors/hoot.inc.c index 942a839c..48073fc2 100644 --- a/src/game/behaviors/hoot.inc.c +++ b/src/game/behaviors/hoot.inc.c @@ -71,8 +71,8 @@ void hoot_player_set_yaw(void) { s16 turnSpeed = gMarioState->intendedMag * 0x20; o->oMoveAngleYaw = approach_s16_symmetric(o->oMoveAngleYaw, gMarioState->intendedYaw, turnSpeed); #else - s16 stickX = gPlayer3Controller->rawStickX; - s16 stickY = gPlayer3Controller->rawStickY; + s16 stickX = gPlayer1Controller->rawStickX; + s16 stickY = gPlayer1Controller->rawStickY; if (stickX < 10 && stickX > -10) stickX = 0; if (stickY < 10 && stickY > -10) stickY = 0; o->oMoveAngleYaw -= 5 * stickX; diff --git a/src/game/game_init.c b/src/game/game_init.c index cb451539..67e760fc 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -32,9 +32,6 @@ #include "vc_ultra.h" #include "profiling.h" -// First 3 controller slots -struct Controller gControllers[3]; - // Gfx handlers struct SPTask *gGfxSPTask; Gfx *gDisplayListHead; @@ -42,6 +39,7 @@ u8 *gGfxPoolEnd; struct GfxPool *gGfxPool; // OS Controllers +struct Controller gControllers[4]; OSContStatus gControllerStatuses[4]; OSContPadEx gControllerPads[4]; u8 gControllerBits; @@ -91,7 +89,8 @@ void (*gGoddardVblankCallback)(void) = NULL; // Defined controller slots struct Controller *gPlayer1Controller = &gControllers[0]; struct Controller *gPlayer2Controller = &gControllers[1]; -struct Controller *gPlayer3Controller = &gControllers[2]; // Probably debug only, see note below +struct Controller *gPlayer3Controller = &gControllers[2]; +struct Controller *gPlayer4Controller = &gControllers[3]; // Title Screen Demo Handler struct DemoInput *gCurrDemoInput = NULL; @@ -605,7 +604,7 @@ void read_controller_inputs(s32 threadID) { run_demo_inputs(); #endif - for (i = 0; i < 2; i++) { + for (i = 0; i < 4; i++) { struct Controller *controller = &gControllers[i]; // if we're receiving inputs, update the controller struct with the new button info. if (controller->controllerData != NULL) { @@ -639,18 +638,6 @@ void read_controller_inputs(s32 threadID) { controller->stickMag = 0; } } - - // For some reason, player 1's inputs are copied to player 3's port. - // This potentially may have been a way the developers "recorded" - // the inputs for demos, despite record_demo existing. - gPlayer3Controller->rawStickX = gPlayer1Controller->rawStickX; - gPlayer3Controller->rawStickY = gPlayer1Controller->rawStickY; - gPlayer3Controller->stickX = gPlayer1Controller->stickX; - gPlayer3Controller->stickY = gPlayer1Controller->stickY; - gPlayer3Controller->stickMag = gPlayer1Controller->stickMag; - gPlayer3Controller->buttonPressed = gPlayer1Controller->buttonPressed; - gPlayer3Controller->buttonReleased = gPlayer1Controller->buttonReleased; - gPlayer3Controller->buttonDown = gPlayer1Controller->buttonDown; } /** @@ -676,12 +663,8 @@ void init_controllers(void) { gSramProbe = nuPiInitSram(); #endif - // Loop over the 4 ports and link the controller structs to the appropriate - // status and pad. Interestingly, although there are pointers to 3 controllers, - // only 2 are connected here. The third seems to have been reserved for debug - // purposes and was never connected in the retail ROM, thus gPlayer3Controller - // cannot be used, despite being referenced in various code. - for (cont = 0, port = 0; port < 4 && cont < 2; port++) { + // Loop over the 4 ports and link the controller structs to the appropriate status and pad. + for (cont = 0, port = 0; port < 4 && cont < 4; port++) { // Is controller plugged in? if (gControllerBits & (1 << port)) { // The game allows you to have just 1 controller plugged diff --git a/src/game/game_init.h b/src/game/game_init.h index 4eb2d021..354a85ac 100644 --- a/src/game/game_init.h +++ b/src/game/game_init.h @@ -30,7 +30,7 @@ enum ZBmodes { CLEAR_ZBUFFER = 1, }; -extern struct Controller gControllers[3]; +extern struct Controller gControllers[4]; extern OSContStatus gControllerStatuses[4]; extern OSContPadEx gControllerPads[4]; extern OSMesgQueue gGameVblankQueue; @@ -67,6 +67,7 @@ extern void (*gGoddardVblankCallback)(void); extern struct Controller *gPlayer1Controller; extern struct Controller *gPlayer2Controller; extern struct Controller *gPlayer3Controller; +extern struct Controller *gPlayer4Controller; extern struct DemoInput *gCurrDemoInput; extern u16 gDemoInputListID; extern struct DemoInput gRecordedDemoInput; diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index e83daead..bf509e7d 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -581,11 +581,11 @@ void handle_menu_scrolling(s8 scrollDirection, s8 *currentIndex, s8 minIndex, s8 u8 index = 0; if (scrollDirection == MENU_SCROLL_VERTICAL) { - if ((gPlayer3Controller->rawStickY > 60) || (gPlayer3Controller->buttonDown & (U_CBUTTONS | U_JPAD))) index++; - if ((gPlayer3Controller->rawStickY < -60) || (gPlayer3Controller->buttonDown & (D_CBUTTONS | D_JPAD))) index += 2; + if ((gPlayer1Controller->rawStickY > 60) || (gPlayer1Controller->buttonDown & (U_CBUTTONS | U_JPAD))) index++; + if ((gPlayer1Controller->rawStickY < -60) || (gPlayer1Controller->buttonDown & (D_CBUTTONS | D_JPAD))) index += 2; } else if (scrollDirection == MENU_SCROLL_HORIZONTAL) { - if ((gPlayer3Controller->rawStickX > 60) || (gPlayer3Controller->buttonDown & (R_CBUTTONS | R_JPAD))) index += 2; - if ((gPlayer3Controller->rawStickX < -60) || (gPlayer3Controller->buttonDown & (L_CBUTTONS | L_JPAD))) index++; + if ((gPlayer1Controller->rawStickX > 60) || (gPlayer1Controller->buttonDown & (R_CBUTTONS | R_JPAD))) index += 2; + if ((gPlayer1Controller->rawStickX < -60) || (gPlayer1Controller->buttonDown & (L_CBUTTONS | L_JPAD))) index++; } if (((index ^ gMenuHoldKeyIndex) & index) == 2) { @@ -1174,7 +1174,7 @@ void render_dialog_entries(void) { case DIALOG_STATE_VERTICAL: gDialogBoxOpenTimer = 0.0f; - if (gPlayer3Controller->buttonPressed & (A_BUTTON | B_BUTTON | START_BUTTON | D_CBUTTONS | R_CBUTTONS | D_JPAD | R_JPAD)) { + if (gPlayer1Controller->buttonPressed & (A_BUTTON | B_BUTTON | START_BUTTON | D_CBUTTONS | R_CBUTTONS | D_JPAD | R_JPAD)) { if (gLastDialogPageStrPos == -1) { handle_special_dialog_text(gDialogID); gDialogBoxState = DIALOG_STATE_CLOSING; @@ -1888,7 +1888,7 @@ s32 render_pause_courses_and_castle(void) { } #endif - if (gPlayer3Controller->buttonPressed & (A_BUTTON | START_BUTTON)) { + if (gPlayer1Controller->buttonPressed & (A_BUTTON | START_BUTTON)) { level_set_transition(0, NULL); play_sound(SOUND_MENU_PAUSE_CLOSE, gGlobalSoundSource); gDialogBoxState = DIALOG_STATE_OPENING; @@ -1910,7 +1910,7 @@ s32 render_pause_courses_and_castle(void) { render_pause_castle_menu_box(160, 143); render_pause_castle_main_strings(104, 60); - if (gPlayer3Controller->buttonPressed & (A_BUTTON | START_BUTTON | Z_TRIG)) { + if (gPlayer1Controller->buttonPressed & (A_BUTTON | START_BUTTON | Z_TRIG)) { level_set_transition(0, NULL); play_sound(SOUND_MENU_PAUSE_CLOSE, gGlobalSoundSource); gMenuMode = MENU_MODE_NONE; @@ -2149,7 +2149,7 @@ s32 render_course_complete_screen(void) { render_course_complete_lvl_info_and_hud_str(); render_save_confirmation(100, 86, &gDialogLineNum, 20); - if (gCourseDoneMenuTimer > 110 && (gPlayer3Controller->buttonPressed & (A_BUTTON | START_BUTTON))) { + if (gCourseDoneMenuTimer > 110 && (gPlayer1Controller->buttonPressed & (A_BUTTON | START_BUTTON))) { level_set_transition(0, NULL); play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource); gDialogBoxState = DIALOG_STATE_OPENING; diff --git a/src/game/obj_behaviors.c b/src/game/obj_behaviors.c index fd5a685e..f1191bc9 100644 --- a/src/game/obj_behaviors.c +++ b/src/game/obj_behaviors.c @@ -710,11 +710,11 @@ UNUSED s32 debug_sequence_tracker(s16 debugInputSequence[]) { } // If the third controller button pressed is next in sequence, reset timer and progress to next value. - if (debugInputSequence[sDebugSequenceTracker] & gPlayer3Controller->buttonPressed) { + if (debugInputSequence[sDebugSequenceTracker] & gPlayer1Controller->buttonPressed) { sDebugSequenceTracker++; sDebugTimer = 0; // If wrong input or timer reaches 10, reset sequence progress. - } else if (sDebugTimer == 10 || gPlayer3Controller->buttonPressed != 0) { + } else if (sDebugTimer == 10 || gPlayer1Controller->buttonPressed != 0) { sDebugSequenceTracker = 0; sDebugTimer = 0; return FALSE; diff --git a/src/menu/file_select.c b/src/menu/file_select.c index 2b152aba..8b8c55ae 100644 --- a/src/menu/file_select.c +++ b/src/menu/file_select.c @@ -1166,16 +1166,16 @@ void handle_cursor_button_input(void) { if (sSelectedButtonID == MENU_BUTTON_SCORE_FILE_A || sSelectedButtonID == MENU_BUTTON_SCORE_FILE_B || sSelectedButtonID == MENU_BUTTON_SCORE_FILE_C || sSelectedButtonID == MENU_BUTTON_SCORE_FILE_D) { - if (gPlayer3Controller->buttonPressed & (B_BUTTON | START_BUTTON | Z_TRIG)) { + if (gPlayer1Controller->buttonPressed & (B_BUTTON | START_BUTTON | Z_TRIG)) { sClickPos[0] = sCursorPos[0]; sClickPos[1] = sCursorPos[1]; sCursorClickingTimer = 1; - } else if (gPlayer3Controller->buttonPressed & A_BUTTON) { + } else if (gPlayer1Controller->buttonPressed & A_BUTTON) { sScoreFileCoinScoreMode = 1 - sScoreFileCoinScoreMode; play_sound(SOUND_MENU_CLICK_FILE_SELECT, gGlobalSoundSource); } } else { // If cursor is clicked - if (gPlayer3Controller->buttonPressed + if (gPlayer1Controller->buttonPressed & (A_BUTTON | B_BUTTON | START_BUTTON)) { sClickPos[0] = sCursorPos[0]; sClickPos[1] = sCursorPos[1]; @@ -1188,8 +1188,8 @@ void handle_cursor_button_input(void) { * Cursor function that handles analog stick input and button presses with a function near the end. */ void handle_controller_cursor_input(void) { - s16 rawStickX = gPlayer3Controller->rawStickX; - s16 rawStickY = gPlayer3Controller->rawStickY; + s16 rawStickX = gPlayer1Controller->rawStickX; + s16 rawStickY = gPlayer1Controller->rawStickY; // Handle deadzone if (rawStickY > -2 && rawStickY < 2) { diff --git a/src/menu/star_select.c b/src/menu/star_select.c index 3a160c6b..eece371b 100644 --- a/src/menu/star_select.c +++ b/src/menu/star_select.c @@ -428,7 +428,7 @@ s32 lvl_init_act_selector_values_and_stars(UNUSED s32 arg, UNUSED s32 unused) { s32 lvl_update_obj_and_load_act_button_actions(UNUSED s32 arg, UNUSED s32 unused) { if (sActSelectorMenuTimer > 10) { // If any of these buttons are pressed, play sound and go to course act - if ((gPlayer3Controller->buttonPressed & (A_BUTTON | START_BUTTON | B_BUTTON | Z_TRIG))) { + if ((gPlayer1Controller->buttonPressed & (A_BUTTON | START_BUTTON | B_BUTTON | Z_TRIG))) { play_sound(SOUND_MENU_STAR_SOUND_LETS_A_GO, gGlobalSoundSource); #if ENABLE_RUMBLE queue_rumble_data(60, 70); diff --git a/src/menu/title_screen.c b/src/menu/title_screen.c index 67628845..88308127 100644 --- a/src/menu/title_screen.c +++ b/src/menu/title_screen.c @@ -110,7 +110,7 @@ s32 intro_level_select(void) { if (((index ^ gLevelSelectHoldKeyIndex) & index) == 2) { if (gCurrLevelNum > LEVEL_MAX) { gCurrLevelNum = LEVEL_MIN; - } else if (gPlayer3Controller->buttonDown & B_BUTTON) { + } else if (gPlayer1Controller->buttonDown & B_BUTTON) { play_sound(SOUND_GENERAL_LEVEL_SELECT_CHANGE, gGlobalSoundSource); gCurrLevelNum += 10; } else { @@ -123,7 +123,7 @@ s32 intro_level_select(void) { if (gCurrLevelNum < LEVEL_MIN) { // Same applies to here as above gCurrLevelNum = LEVEL_MAX; - } else if (gPlayer3Controller->buttonDown & B_BUTTON) { + } else if (gPlayer1Controller->buttonDown & B_BUTTON) { play_sound(SOUND_GENERAL_LEVEL_SELECT_CHANGE, gGlobalSoundSource); gCurrLevelNum -= 10; } else { @@ -187,7 +187,7 @@ s32 intro_regular(void) { } print_intro_text(); #ifdef DEBUG_LEVEL_SELECT - if (gPlayer3Controller->buttonDown & L_TRIG) { + if (gPlayer1Controller->buttonDown & L_TRIG) { gDebugLevelSelect = TRUE; } #endif @@ -263,7 +263,7 @@ s32 lvl_intro_update(s16 arg, UNUSED s32 unusedArg) { #else case LVL_INTRO_REGULAR: #ifdef DEBUG_LEVEL_SELECT - if (gPlayer3Controller->buttonDown & L_TRIG) { + if (gPlayer1Controller->buttonDown & L_TRIG) { gDebugLevelSelect = TRUE; } #endif