Merge pull request #595 from Arceveti/develop/2.1.0-four-controllers-base

4 controllers support + osContCh optimization
This commit is contained in:
thecozies
2023-09-22 16:56:23 -05:00
committed by GitHub
17 changed files with 198 additions and 233 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

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

View File

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

View File

@@ -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];
/**************************************************************************
*

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

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