Support using 4 controllers at once

This commit is contained in:
Arceveti
2022-10-23 00:40:24 -07:00
parent c76c5824e3
commit 169e9cff2e
10 changed files with 33 additions and 49 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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