diff --git a/README.md b/README.md index 29472bc6d..b97dc4722 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/asm/rom_header.s b/asm/rom_header.s index 13b25108d..9b193302e 100644 --- a/asm/rom_header.s +++ b/asm/rom_header.s @@ -15,14 +15,14 @@ .word 0x00000000 /* Unknown */ .word 0x00000000 /* Unknown */ .ascii INTERNAL_ROM_NAME /* Internal ROM name */ -#if defined(USE_GAMECUBE_CONTROLLER) +#if defined(EMU_DEFAULT_TO_GCN) /* Advanced homebrew ROM header bytes: https://n64brew.dev/wiki/ROM_Header#Advanced_Homebrew_ROM_Header */ .word 0x82000000 #else .word 0x00000000 /* Unknown */ #endif .word 0x0000004E /* Cartridge */ -#if defined(EEP4K) && !defined(USE_GAMECUBE_CONTROLLER) +#if defined(EEP4K) && !defined(EMU_DEFAULT_TO_GCN) .ascii "SM" /* Cartridge ID */ #else .ascii "ED" /* Cartridge ID */ diff --git a/include/config/config_rom.h b/include/config/config_rom.h index a5927c3d6..85e2c935b 100644 --- a/include/config/config_rom.h +++ b/include/config/config_rom.h @@ -10,12 +10,32 @@ */ #define INTERNAL_ROM_NAME "HackerSM64 " +/** + * Force the game to delete any existing save data originating from a different hack. This requires INTERNAL_ROM_NAME to be unique to work properly. + * It is recommended to enable this if any significant changes to the save file are made that could cause issues with this or other hacks. + * NOTE: Using save editors with this define will likely just end up wiping your save, since SM64 specific save editors most likely use hardcoded save magic. + */ +// #define UNIQUE_SAVE_DATA + /** * Enables Rumble Pak Support. * Currently not recommended, as it may cause random crashes. */ // #define ENABLE_RUMBLE (1 || VERSION_SH) +/** + * The maximum number of supported players/controllers. 1-4. + * This will save performance if the player has extra unused controllers plugged in. + * NOTE: Default is 2, maximum is 4. + * NOTE: This needs to be at least 2 for now for gamecube controller swap to work. + */ +#define MAX_NUM_PLAYERS 2 + +/** + * Informs supported emulators to default to GameCube controller inputs. + */ +// #define EMU_DEFAULT_TO_GCN + /** * Screen Size Defines. */ @@ -29,18 +49,6 @@ #define BORDER_HEIGHT_CONSOLE 0 #define BORDER_HEIGHT_EMULATOR 0 -/** - * Force the game to delete any existing save data originating from a different hack. This requires INTERNAL_ROM_NAME to be unique to work properly. - * It is recommended to enable this if any significant changes to the save file are made that could cause issues with this or other hacks. - * NOTE: Using save editors with this define will likely just end up wiping your save, since SM64 specific save editors most likely use hardcoded save magic. - */ -// #define UNIQUE_SAVE_DATA - -/** - * Informs supported emulators to default to gamecube controller inputs. - */ -// #define USE_GAMECUBE_CONTROLLER - /** * RCVI hack. Increases performance on emulator, and does nothing on console. * Might break on some emulators. Use at your own risk, and don't use it unless you actually need the extra performance. diff --git a/include/n64/PR/os_cont.h b/include/n64/PR/os_cont.h index 442994645..7af3072a2 100644 --- a/include/n64/PR/os_cont.h +++ b/include/n64/PR/os_cont.h @@ -112,6 +112,11 @@ typedef struct { /* Controller type */ +// Console ID: +#define CONT_CONSOLE_MASK (0x3 << 3) // 0x0018 | 0: N64, 1: Dolphin +#define CONT_CONSOLE_N64 ( 0 << 3) // 0x0000 +#define CONT_CONSOLE_GCN ( 1 << 3) // 0x0008 + #define CONT_ABSOLUTE 0x0001 #define CONT_RELATIVE 0x0002 #define CONT_JOYPORT 0x0004 @@ -194,9 +199,6 @@ typedef struct { #define CONT_ERR_VOICE_WORD 14 #define CONT_ERR_VOICE_NO_RESPONSE 15 -#define CONT_TYPE_N64 0 -#define CONT_TYPE_GCN 1 - #if defined(_LANGUAGE_C) || defined(_LANGUAGE_C_PLUS_PLUS) @@ -213,7 +215,6 @@ typedef struct { * */ -extern u8 __osControllerTypes[MAXCONTROLLERS]; /************************************************************************** * diff --git a/include/types.h b/include/types.h index cd9dcd57c..2d5edbf70 100644 --- a/include/types.h +++ b/include/types.h @@ -32,21 +32,19 @@ struct Config { u8 tvType; }; -struct Controller { - /*0x00*/ s16 rawStickX; // - /*0x02*/ s16 rawStickY; // - /*0x04*/ f32 stickX; // [-64, 64] positive is right - /*0x08*/ f32 stickY; // [-64, 64] positive is up - /*0x0C*/ f32 stickMag; // distance from center [0, 64] - /*0x10*/ u16 buttonDown; - /*0x12*/ u16 buttonPressed; - /*0x14*/ u16 buttonReleased; - /*0x18*/ OSContStatus *statusData; - /*0x1C*/ OSContPadEx *controllerData; -#if ENABLE_RUMBLE - /*0x20*/ s32 port; -#endif -}; +typedef struct Controller { + /*0x00*/ s16 rawStickX; // Analog stick [-128, 128] positive is right. Used for menus. + /*0x02*/ s16 rawStickY; // Analog stick [-128, 128] positive is up. Used for menus. + /*0x04*/ f32 stickX; // Analog stick [-64, 64] positive is right. Used for gameplay. + /*0x08*/ f32 stickY; // Analog stick [-64, 64] positive is up. Used for gameplay. + /*0x0C*/ f32 stickMag; // Analog stick distance from center [0, 64]. Used for gameplay. + /*0x10*/ u16 buttonDown; // Buttons held down on the current frame. + /*0x12*/ u16 buttonPressed; // Buttons pressed on the current frame but not held on the previous frame. + /*0x14*/ u16 buttonReleased; // Burrons released on the current frame and held on the previous frame. + /*0x18*/ OSContStatus* statusData; // Pointer to the controller status data in gControllerStatuses. + /*0x1C*/ OSContPadEx* controllerData; // Pointer to the raw input data in gControllerPads. + /*0x20*/ s32 port; // The port index this controller is plugged into [0, 3]. +} Controller; /*0x24*/ // -- Booleans -- diff --git a/sm64.ld b/sm64.ld index e9f92c746..ebb6af13e 100755 --- a/sm64.ld +++ b/sm64.ld @@ -184,8 +184,6 @@ SECTIONS lib/PR/audio/n_aspMain.o(.text*); lib/PR/hvqm/hvqm2sp1.o(.text*); _mainSegmentTextEnd = .; - /* Overwrite a libultra function with its modified counterpart for GCN controller support */ - __osContGetInitData = __osContGetInitDataEx; /* data */ BUILD_DIR/asm/n64_assert.o(.*data*); diff --git a/src/boot/main.c b/src/boot/main.c index 985b82432..9d812aadc 100644 --- a/src/boot/main.c +++ b/src/boot/main.c @@ -82,8 +82,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 942a839cf..48073fc2a 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 202f6a31d..9b964bb91 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -35,9 +35,6 @@ // Emulators that the Instant Input patch should not be applied to #define INSTANT_INPUT_BLACKLIST (EMU_CONSOLE | EMU_WIIVC | EMU_ARES | EMU_SIMPLE64 | EMU_CEN64) -// First 3 controller slots -struct Controller gControllers[3]; - // Gfx handlers struct SPTask *gGfxSPTask; Gfx *gDisplayListHead; @@ -45,10 +42,10 @@ u8 *gGfxPoolEnd; struct GfxPool *gGfxPool; // OS Controllers -OSContStatus gControllerStatuses[4]; -OSContPadEx gControllerPads[4]; -u8 gControllerBits; -s8 gGamecubeControllerPort = -1; // HackerSM64: This is set to -1 if there's no GC controller, 0 if there's one in the first port and 1 if there's one in the second port. +struct Controller gControllers[MAXCONTROLLERS]; +OSContStatus gControllerStatuses[MAXCONTROLLERS]; +OSContPadEx gControllerPads[MAXCONTROLLERS]; +u8 gControllerBits = 0b0000; u8 gBorderHeight; #ifdef VANILLA_STYLE_CUSTOM_DEBUG u8 gCustomDebugMode; @@ -89,10 +86,11 @@ u16 sRenderingFramebuffer = 0; // Goddard Vblank Function Caller 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 +// Defined player slots. Anything above MAX_NUM_PLAYERS should not be used. +struct Controller* const gPlayer1Controller = &gControllers[0]; +struct Controller* const gPlayer2Controller = &gControllers[1]; +struct Controller* const gPlayer3Controller = &gControllers[2]; +struct Controller* const gPlayer4Controller = &gControllers[3]; // Title Screen Demo Handler struct DemoInput *gCurrDemoInput = NULL; @@ -498,36 +496,25 @@ UNUSED static void record_demo(void) { */ void run_demo_inputs(void) { // Eliminate the unused bits. - gControllers[0].controllerData->button &= VALID_BUTTONS; + gPlayer1Controller->controllerData->button &= VALID_BUTTONS; // Check if a demo inputs list exists and if so, // run the active demo input list. if (gCurrDemoInput != NULL) { - // Clear player 2's inputs if they exist. Player 2's controller - // cannot be used to influence a demo. At some point, Nintendo - // may have planned for there to be a demo where 2 players moved - // around instead of just one, so clearing player 2's influence from - // the demo had to have been necessary to perform this. Co-op mode, perhaps? - if (gControllers[1].controllerData != NULL) { - gControllers[1].controllerData->stick_x = 0; - gControllers[1].controllerData->stick_y = 0; - gControllers[1].controllerData->button = 0; - } - // The timer variable being 0 at the current input means the demo is over. // Set the button to the END_DEMO mask to end the demo. if (gCurrDemoInput->timer == 0) { - gControllers[0].controllerData->stick_x = 0; - gControllers[0].controllerData->stick_y = 0; - gControllers[0].controllerData->button = END_DEMO; + gPlayer1Controller->controllerData->stick_x = 0; + gPlayer1Controller->controllerData->stick_y = 0; + gPlayer1Controller->controllerData->button = END_DEMO; } else { // Backup the start button if it is pressed, since we don't want the // demo input to override the mask where start may have been pressed. - u16 startPushed = gControllers[0].controllerData->button & START_BUTTON; + u16 startPushed = (gPlayer1Controller->controllerData->button & START_BUTTON); // Perform the demo inputs by assigning the current button mask and the stick inputs. - gControllers[0].controllerData->stick_x = gCurrDemoInput->rawStickX; - gControllers[0].controllerData->stick_y = gCurrDemoInput->rawStickY; + gPlayer1Controller->controllerData->stick_x = gCurrDemoInput->rawStickX; + gPlayer1Controller->controllerData->stick_y = gCurrDemoInput->rawStickY; // To assign the demo input, the button information is stored in // an 8-bit mask rather than a 16-bit mask. this is because only @@ -536,11 +523,11 @@ void run_demo_inputs(void) { // upper 4 bits (A, B, Z, and Start) and shift then left by 8 to // match the correct input mask. We then add this to the masked // lower 4 bits to get the correct button mask. - gControllers[0].controllerData->button = + gPlayer1Controller->controllerData->button = ((gCurrDemoInput->buttonMask & 0xF0) << 8) + ((gCurrDemoInput->buttonMask & 0xF)); // If start was pushed, put it into the demo sequence being input to end the demo. - gControllers[0].controllerData->button |= startPushed; + gPlayer1Controller->controllerData->button |= startPushed; // Run the current demo input's timer down. if it hits 0, advance the demo input list. if (--gCurrDemoInput->timer == 0) { @@ -594,14 +581,12 @@ void adjust_analog_stick(struct Controller *controller) { * Update the controller struct with available inputs if present. */ void read_controller_inputs(s32 threadID) { - s32 i; - // If any controllers are plugged in, update the controller information. if (gControllerBits) { if (threadID == THREAD_5_GAME_LOOP) { osRecvMesg(&gSIEventMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK); } - osContGetReadDataEx(&gControllerPads[0]); + osContGetReadDataEx(gControllerPads); #if ENABLE_RUMBLE release_rumble_pak_control(); #endif @@ -610,65 +595,67 @@ void read_controller_inputs(s32 threadID) { run_demo_inputs(); #endif - for (i = 0; i < 2; i++) { - struct Controller *controller = &gControllers[i]; + for (s32 cont = 0; cont < MAX_NUM_PLAYERS; cont++) { + struct Controller* controller = &gControllers[cont]; + OSContPadEx* controllerData = controller->controllerData; + // if we're receiving inputs, update the controller struct with the new button info. if (controller->controllerData != NULL) { // HackerSM64: Swaps Z and L, only on console, and only when playing with a GameCube controller. - if ((gEmulator & EMU_CONSOLE) && i == gGamecubeControllerPort) { - u32 oldButton = controller->controllerData->button; + if (controller->statusData->type & CONT_CONSOLE_GCN) { + u32 oldButton = controllerData->button; u32 newButton = oldButton & ~(Z_TRIG | L_TRIG); if (oldButton & Z_TRIG) { newButton |= L_TRIG; } - if (controller->controllerData->l_trig > 85) { // How far the player has to press the L trigger for it to be considered a Z press. 64 is about 25%. 127 would be about 50%. + if (controllerData->l_trig > 85) { // How far the player has to press the L trigger for it to be considered a Z press. 64 is about 25%. 127 would be about 50%. newButton |= Z_TRIG; } - controller->controllerData->button = newButton; + controllerData->button = newButton; } - controller->rawStickX = controller->controllerData->stick_x; - controller->rawStickY = controller->controllerData->stick_y; - controller->buttonPressed = ~controller->buttonDown & controller->controllerData->button; - controller->buttonReleased = ~controller->controllerData->button & controller->buttonDown; + controller->rawStickX = controllerData->stick_x; + controller->rawStickY = controllerData->stick_y; + controller->buttonPressed = (~controller->buttonDown & controllerData->button); + controller->buttonReleased = (~controllerData->button & controller->buttonDown); // 0.5x A presses are a good meme - controller->buttonDown = controller->controllerData->button; + controller->buttonDown = controllerData->button; adjust_analog_stick(controller); } else { // otherwise, if the controllerData is NULL, 0 out all of the inputs. - controller->rawStickX = 0; - controller->rawStickY = 0; - controller->buttonPressed = 0; - controller->buttonReleased = 0; - controller->buttonDown = 0; - controller->stickX = 0; - controller->stickY = 0; - controller->stickMag = 0; + controller->rawStickX = 0; + controller->rawStickY = 0; + controller->buttonPressed = 0x0000; + controller->buttonReleased = 0x0000; + controller->buttonDown = 0x0000; + controller->stickX = 0.0f; + controller->stickY = 0.0f; + controller->stickMag = 0.0f; } } +} - // 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; +/** + * @brief Links a controller struct to the appropriate status and pad. + * + * @param[out] controller The controller to link. + * @param[in ] port The port to get the data from. + */ +static void assign_controller_data_to_port(struct Controller* controller, int port) { + controller->statusData = &gControllerStatuses[port]; + controller->controllerData = &gControllerPads[port]; + controller->port = port; } /** * Initialize the controller structs to point at the OSCont information. */ void init_controllers(void) { - s16 port, cont; + int port, cont = 0; + int lastUsedPort = -1; // Set controller 1 to point to the set of status/pads for input 1 and // init the controllers. - gControllers[0].statusData = &gControllerStatuses[0]; - gControllers[0].controllerData = &gControllerPads[0]; - osContInit(&gSIEventMesgQueue, &gControllerBits, &gControllerStatuses[0]); + assign_controller_data_to_port(&gControllers[0], 0); + osContInit(&gSIEventMesgQueue, &gControllerBits, gControllerStatuses); #ifdef EEP // strangely enough, the EEPROM probe for save data is done in this function. @@ -681,34 +668,43 @@ 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 (port = 0; port < MAXCONTROLLERS; port++) { + if (cont >= MAX_NUM_PLAYERS) { + break; + } + // Is controller plugged in? if (gControllerBits & (1 << port)) { // The game allows you to have just 1 controller plugged // into any port in order to play the game. this was probably // so if any of the ports didn't work, you can have controllers // plugged into any of them and it will work. -#if ENABLE_RUMBLE - gControllers[cont].port = port; + assign_controller_data_to_port(&gControllers[cont], port); + + lastUsedPort = port; + + cont++; + } + } + +#if (MAX_NUM_PLAYERS >= 2) + //! Some flashcarts (eg. ED64p) don't let you start a ROM with a GameCube controller in port 1, + // so if port 1 is an N64 controller and port 2 is a GC controller, swap them. + if ( + (gEmulator & EMU_CONSOLE) && + ((gControllerBits & 0b11) == 0b11) && // Only swap if the first two ports both have controllers plugged in. + ((gControllerStatuses[0].type & CONT_CONSOLE_MASK) == CONT_CONSOLE_N64) && // If the first port's controller is N64. + ((gControllerStatuses[1].type & CONT_CONSOLE_MASK) == CONT_CONSOLE_GCN) // If the second port's controller is GCN. + ) { + struct Controller temp = gControllers[0]; + gControllers[0] = gControllers[1]; + gControllers[1] = temp; + } #endif - gControllers[cont].statusData = &gControllerStatuses[port]; - gControllers[cont++].controllerData = &gControllerPads[port]; - } - } - if ((__osControllerTypes[1] == CONT_TYPE_GCN) && (gEmulator & EMU_CONSOLE)) { - gGamecubeControllerPort = 1; - gPlayer1Controller = &gControllers[1]; - } else { - if (__osControllerTypes[0] == CONT_TYPE_GCN) { - gGamecubeControllerPort = 0; - } - gPlayer1Controller = &gControllers[0]; - } + + // Disable the ports after the last used one. + osContSetCh(lastUsedPort + 1); } // Game thread core diff --git a/src/game/game_init.h b/src/game/game_init.h index fbb572f6d..1258d7374 100644 --- a/src/game/game_init.h +++ b/src/game/game_init.h @@ -30,9 +30,9 @@ enum ZBmodes { CLEAR_ZBUFFER = 1, }; -extern struct Controller gControllers[3]; -extern OSContStatus gControllerStatuses[4]; -extern OSContPadEx gControllerPads[4]; +extern struct Controller gControllers[MAXCONTROLLERS]; +extern OSContStatus gControllerStatuses[MAXCONTROLLERS]; +extern OSContPadEx gControllerPads[MAXCONTROLLERS]; extern OSMesgQueue gGameVblankQueue; extern OSMesgQueue gGfxVblankQueue; extern OSMesg gGameMesgBuf[1]; @@ -47,7 +47,6 @@ extern Gfx *gDisplayListHead; extern u8 *gGfxPoolEnd; extern struct GfxPool *gGfxPool; extern u8 gControllerBits; -extern s8 gGamecubeControllerPort; extern u8 gBorderHeight; #ifdef VANILLA_STYLE_CUSTOM_DEBUG extern u8 gCustomDebugMode; @@ -62,9 +61,10 @@ extern s8 gSramProbe; #endif extern void (*gGoddardVblankCallback)(void); -extern struct Controller *gPlayer1Controller; -extern struct Controller *gPlayer2Controller; -extern struct Controller *gPlayer3Controller; +extern struct Controller* const gPlayer1Controller; +extern struct Controller* const gPlayer2Controller; +extern struct Controller* const gPlayer3Controller; +extern struct Controller* const gPlayer4Controller; extern struct DemoInput *gCurrDemoInput; extern u16 gDemoInputListID; extern struct DemoInput gRecordedDemoInput; diff --git a/src/game/gamecube_controller.c b/src/game/gamecube_controller.c index 20f5afb16..05ca0f571 100644 --- a/src/game/gamecube_controller.c +++ b/src/game/gamecube_controller.c @@ -1,5 +1,7 @@ #include "PR/os_internal.h" +#include "game_init.h" + ///////////////////////////////////////////////// // Libultra structs and macros (from ultralib) // ///////////////////////////////////////////////// @@ -168,7 +170,6 @@ typedef struct /* 0xD */ u8 r_trig; } __OSContGCNShortPollFormat; extern u8 __osContLastCmd; -u8 __osControllerTypes[MAXCONTROLLERS]; u8 __osGamecubeRumbleEnabled[MAXCONTROLLERS]; typedef struct @@ -216,50 +217,47 @@ void osContGetReadDataEx(OSContPadEx* data) { int i; for (i = 0; i < __osMaxControllers; i++, data++) { - if (__osControllerTypes[i] == CONT_TYPE_GCN) { + if (gControllerStatuses[i].type & CONT_CONSOLE_GCN) { s32 stick_x, stick_y, c_stick_x, c_stick_y; readformatgcn = *(__OSContGCNShortPollFormat*)ptr; data->errno = CHNL_ERR(readformatgcn); - if (data->errno != 0) { + if (data->errno == 0) { + if (!gGamecubeControllerCenters[i].initialized) { + gGamecubeControllerCenters[i].initialized = TRUE; + gGamecubeControllerCenters[i].stick_x = readformatgcn.stick_x; + gGamecubeControllerCenters[i].stick_y = readformatgcn.stick_y; + gGamecubeControllerCenters[i].c_stick_x = readformatgcn.c_stick_x; + gGamecubeControllerCenters[i].c_stick_y = readformatgcn.c_stick_y; + } + + stick_x = CLAMP_S8(((s32)readformatgcn.stick_x) - gGamecubeControllerCenters[i].stick_x); + stick_y = CLAMP_S8(((s32)readformatgcn.stick_y) - gGamecubeControllerCenters[i].stick_y); + data->stick_x = stick_x; + data->stick_y = stick_y; + c_stick_x = CLAMP_S8(((s32)readformatgcn.c_stick_x) - gGamecubeControllerCenters[i].c_stick_x); + c_stick_y = CLAMP_S8(((s32)readformatgcn.c_stick_y) - gGamecubeControllerCenters[i].c_stick_y); + data->c_stick_x = c_stick_x; + data->c_stick_y = c_stick_y; + data->button = __osTranslateGCNButtons(readformatgcn.button, c_stick_x, c_stick_y); + data->l_trig = readformatgcn.l_trig; + data->r_trig = readformatgcn.r_trig; + } else { gGamecubeControllerCenters[i].initialized = FALSE; - continue; } - - if (!gGamecubeControllerCenters[i].initialized) { - gGamecubeControllerCenters[i].initialized = TRUE; - gGamecubeControllerCenters[i].stick_x = readformatgcn.stick_x; - gGamecubeControllerCenters[i].stick_y = readformatgcn.stick_y; - gGamecubeControllerCenters[i].c_stick_x = readformatgcn.c_stick_x; - gGamecubeControllerCenters[i].c_stick_y = readformatgcn.c_stick_y; - } - - stick_x = CLAMP_S8(((s32)readformatgcn.stick_x) - gGamecubeControllerCenters[i].stick_x); - stick_y = CLAMP_S8(((s32)readformatgcn.stick_y) - gGamecubeControllerCenters[i].stick_y); - data->stick_x = stick_x; - data->stick_y = stick_y; - c_stick_x = CLAMP_S8(((s32)readformatgcn.c_stick_x) - gGamecubeControllerCenters[i].c_stick_x); - c_stick_y = CLAMP_S8(((s32)readformatgcn.c_stick_y) - gGamecubeControllerCenters[i].c_stick_y); - data->c_stick_x = c_stick_x; - data->c_stick_y = c_stick_y; - data->button = __osTranslateGCNButtons(readformatgcn.button, c_stick_x, c_stick_y); - data->l_trig = readformatgcn.l_trig; - data->r_trig = readformatgcn.r_trig; ptr += sizeof(__OSContGCNShortPollFormat); } else { readformat = *(__OSContReadFormat*)ptr; data->errno = CHNL_ERR(readformat); - if (data->errno != 0) { - continue; + if (data->errno == 0) { + data->stick_x = readformat.stick_x; + data->stick_y = readformat.stick_y; + data->button = readformat.button; + data->c_stick_x = 0; + data->c_stick_y = 0; + data->l_trig = 0; + data->r_trig = 0; } - - data->stick_x = readformat.stick_x; - data->stick_y = readformat.stick_y; - data->button = readformat.button; - data->c_stick_x = 0; - data->c_stick_y = 0; - data->l_trig = 0; - data->r_trig = 0; ptr += sizeof(__OSContReadFormat); } } @@ -295,7 +293,7 @@ static void __osPackReadData(void) { readformatgcn.stick_y = -1; for (i = 0; i < __osMaxControllers; i++) { - if (__osControllerTypes[i] == CONT_TYPE_GCN) { + if (gControllerStatuses[i].type & CONT_CONSOLE_GCN) { readformatgcn.rumble = __osGamecubeRumbleEnabled[i]; *(__OSContGCNShortPollFormat*)ptr = readformatgcn; ptr += sizeof(__OSContGCNShortPollFormat); @@ -379,44 +377,12 @@ extern s32 __osContinitialized; extern OSPifRam __osContPifRam; extern u8 __osContLastCmd; extern u8 __osMaxControllers; -extern u8 __osControllerTypes[MAXCONTROLLERS]; extern u8 __osGamecubeRumbleEnabled[MAXCONTROLLERS]; extern OSTimer __osEepromTimer; extern OSMesgQueue __osEepromTimerQ; extern OSMesg __osEepromTimerMsg; -// Linker script will resolve references to the original function with this one instead -void __osContGetInitDataEx(u8* pattern, OSContStatus* data) { - u8* ptr; - __OSContRequesFormat requestHeader; - s32 i; - u8 bits; - - bits = 0; - ptr = (u8*)__osContPifRam.ramarray; - for (i = 0; i < __osMaxControllers; i++, ptr += sizeof(requestHeader), data++) { - requestHeader = *(__OSContRequesFormat*)ptr; - data->error = CHNL_ERR(requestHeader); - if (data->error == 0) { - data->type = requestHeader.typel << 8 | requestHeader.typeh; - - // Check if the input type is a gamecube controller - // Some mupen cores seem to send back a controller type of 0xFFFF if the core doesn't initialize the input plugin quickly enough, - // so check for that and set the input type as N64 controller if so. - if ((data->type & CONT_GCN) && (s16)data->type != -1) { - __osControllerTypes[i] = CONT_TYPE_GCN; - } else { - __osControllerTypes[i] = CONT_TYPE_N64; - } - - data->status = requestHeader.status; - - bits |= 1 << i; - } - } - *pattern = bits; -} ///////////// // motor.c // @@ -435,7 +401,7 @@ s32 __osMotorAccessEx(OSPfs* pfs, s32 flag) { return 5; } - if (__osControllerTypes[pfs->channel] == CONT_TYPE_GCN) { + if (gControllerStatuses[pfs->channel].type & CONT_CONSOLE_GCN) { __osGamecubeRumbleEnabled[pfs->channel] = flag; __osContLastCmd = CONT_CMD_END; } else { @@ -506,7 +472,7 @@ s32 osMotorInitEx(OSMesgQueue *mq, OSPfs *pfs, int channel) pfs->activebank = 0xFF; pfs->status = 0; - if (__osControllerTypes[pfs->channel] != CONT_TYPE_GCN) { + if (gControllerStatuses[pfs->channel].type & CONT_CONSOLE_GCN) { ret = __osPfsSelectBank(pfs, 0xFE); if (ret == PFS_ERR_NEW_PACK) { diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 8d1dbeaa2..1bd615ce5 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)) { + if (gPlayer1Controller->buttonPressed & (A_BUTTON | B_BUTTON)) { if (gLastDialogPageStrPos == -1) { handle_special_dialog_text(gDialogID); gDialogBoxState = DIALOG_STATE_CLOSING; @@ -1910,7 +1910,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; @@ -1932,7 +1932,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; @@ -2171,7 +2171,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/mario.c b/src/game/mario.c index b9ba22f97..b2603c0e9 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -32,7 +32,6 @@ #include "save_file.h" #include "sound_init.h" #include "rumble_init.h" -#include "emutest.h" /************************************************** @@ -1712,7 +1711,10 @@ s32 execute_mario_action(UNUSED struct Object *obj) { if (gMarioState->action) { #ifdef ENABLE_DEBUG_FREE_MOVE - if (gPlayer1Controller->buttonDown & U_JPAD && !(gPlayer1Controller->buttonDown & L_TRIG)) { + if ( + (gMarioState->controller->buttonDown & U_JPAD) && + !(gMarioState->controller->buttonDown & L_TRIG) + ) { set_camera_mode(gMarioState->area->camera, CAMERA_MODE_8_DIRECTIONS, 1); set_mario_action(gMarioState, ACT_DEBUG_FREE_MOVE, 0); } @@ -1874,12 +1876,8 @@ void init_mario_from_save_file(void) { gMarioState->spawnInfo = &gPlayerSpawnInfos[0]; gMarioState->statusForCamera = &gPlayerCameraState[0]; gMarioState->marioBodyState = &gBodyStates[0]; + gMarioState->controller = &gControllers[0]; gMarioState->animList = &gMarioAnimsBuf; - if ((gEmulator & EMU_CONSOLE) && __osControllerTypes[1] == CONT_TYPE_GCN) { - gMarioState->controller = &gControllers[1]; - } else { - gMarioState->controller = &gControllers[0]; - } gMarioState->numCoins = 0; gMarioState->numStars = save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1); diff --git a/src/game/obj_behaviors.c b/src/game/obj_behaviors.c index c554d4599..46c699df0 100644 --- a/src/game/obj_behaviors.c +++ b/src/game/obj_behaviors.c @@ -712,12 +712,12 @@ UNUSED s32 debug_sequence_tracker(s16 debugInputSequence[]) { return TRUE; } - // If the third controller button pressed is next in sequence, reset timer and progress to next value. - if (debugInputSequence[sDebugSequenceTracker] & gPlayer3Controller->buttonPressed) { + // If the button pressed is next in sequence, reset timer and progress to next value. + 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 751e9c956..f3edc68a0 100644 --- a/src/menu/file_select.c +++ b/src/menu/file_select.c @@ -1181,16 +1181,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]; @@ -1203,8 +1203,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 3a160c6bb..eece371bc 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 67628845a..88308127b 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