mirror of
https://github.com/zeldaret/oot.git
synced 2025-07-04 06:54:33 +00:00
Rumble doc (#1375)
* Rumble doc * Fixes, suggested changes * Improve padmgr retrace callback related code * Name some rumble-adjacent things, further suggested changes * Further suggested changes * Suggested changes
This commit is contained in:
parent
82e04ede5f
commit
4f65d08eb5
59 changed files with 533 additions and 393 deletions
|
@ -1,91 +0,0 @@
|
|||
#include "global.h"
|
||||
|
||||
UnkRumbleStruct D_80160FD0;
|
||||
|
||||
void func_800A9F30(PadMgr* a, s32 b) {
|
||||
func_800D2E30(&D_80160FD0);
|
||||
PadMgr_RumbleSet(a, D_80160FD0.rumbleEnable);
|
||||
}
|
||||
|
||||
void func_800A9F6C(f32 a, u8 b, u8 c, u8 d) {
|
||||
s32 temp1;
|
||||
s32 temp2;
|
||||
|
||||
if (1000000.0f < a) {
|
||||
temp1 = 1000;
|
||||
} else {
|
||||
temp1 = sqrtf(a);
|
||||
}
|
||||
|
||||
if ((temp1 < 1000) && (b != 0) && (d != 0)) {
|
||||
temp2 = b - (temp1 * 255) / 1000;
|
||||
if (temp2 > 0) {
|
||||
D_80160FD0.unk_10A = temp2;
|
||||
D_80160FD0.unk_10B = c;
|
||||
D_80160FD0.unk_10C = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void func_800AA000(f32 a, u8 b, u8 c, u8 d) {
|
||||
s32 temp1;
|
||||
s32 temp2;
|
||||
s32 i;
|
||||
|
||||
if (1000000.0f < a) {
|
||||
temp1 = 1000;
|
||||
} else {
|
||||
temp1 = sqrtf(a);
|
||||
}
|
||||
|
||||
if (temp1 < 1000 && b != 0 && d != 0) {
|
||||
temp2 = b - (temp1 * 255) / 1000;
|
||||
|
||||
for (i = 0; i < 0x40; i++) {
|
||||
if (D_80160FD0.unk_04[i] == 0) {
|
||||
if (temp2 > 0) {
|
||||
D_80160FD0.unk_04[i] = temp2;
|
||||
D_80160FD0.unk_44[i] = c;
|
||||
D_80160FD0.unk_84[i] = d;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void func_800AA0B4(void) {
|
||||
func_800D3140(&D_80160FD0);
|
||||
|
||||
gPadMgr.retraceCallback = func_800A9F30;
|
||||
gPadMgr.retraceCallbackValue = 0;
|
||||
|
||||
if (1) {}
|
||||
}
|
||||
|
||||
void func_800AA0F0(void) {
|
||||
PadMgr* padmgr = &gPadMgr;
|
||||
|
||||
if ((padmgr->retraceCallback == func_800A9F30) && (padmgr->retraceCallbackValue == 0)) {
|
||||
padmgr->retraceCallback = NULL;
|
||||
padmgr->retraceCallbackValue = 0;
|
||||
}
|
||||
|
||||
func_800D3178(&D_80160FD0);
|
||||
}
|
||||
|
||||
u32 func_800AA148(void) {
|
||||
return gPadMgr.pakType[0] == 1;
|
||||
}
|
||||
|
||||
void func_800AA15C(void) {
|
||||
D_80160FD0.unk_104 = 2;
|
||||
}
|
||||
|
||||
void func_800AA16C(void) {
|
||||
D_80160FD0.unk_104 = 0;
|
||||
}
|
||||
|
||||
void func_800AA178(u32 a) {
|
||||
D_80160FD0.unk_105 = !!a;
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
#include "global.h"
|
||||
|
||||
void func_800D2E30(UnkRumbleStruct* arg0) {
|
||||
static u8 D_8012DBB0 = 1;
|
||||
s32 i;
|
||||
s32 unk_a3;
|
||||
s32 index = -1;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
arg0->rumbleEnable[i] = 0;
|
||||
}
|
||||
|
||||
if (arg0->unk_105 == 0) {
|
||||
if (D_8012DBB0 != 0) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
gPadMgr.pakType[i] = 0;
|
||||
}
|
||||
}
|
||||
D_8012DBB0 = arg0->unk_105;
|
||||
return;
|
||||
}
|
||||
|
||||
D_8012DBB0 = arg0->unk_105;
|
||||
|
||||
if (arg0->unk_104 == 2) {
|
||||
for (i = 0; i < 4; ++i) {
|
||||
gPadMgr.pakType[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 0x40; i++) {
|
||||
arg0->unk_C4[i] = 0;
|
||||
arg0->unk_84[i] = 0;
|
||||
arg0->unk_44[i] = 0;
|
||||
arg0->unk_04[i] = 0;
|
||||
}
|
||||
arg0->unk_106 = arg0->unk_108 = arg0->unk_10A = arg0->unk_10B = arg0->unk_10C = arg0->unk_10D = 0;
|
||||
arg0->unk_104 = 1;
|
||||
}
|
||||
if (arg0->unk_104 != 0) {
|
||||
for (i = 0; i < 0x40; i++) {
|
||||
if (arg0->unk_04[i] != 0) {
|
||||
if (arg0->unk_44[i] > 0) {
|
||||
arg0->unk_44[i]--;
|
||||
} else {
|
||||
unk_a3 = arg0->unk_04[i] - arg0->unk_84[i];
|
||||
if (unk_a3 > 0) {
|
||||
arg0->unk_04[i] = unk_a3;
|
||||
} else {
|
||||
arg0->unk_04[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unk_a3 = arg0->unk_C4[i] + arg0->unk_04[i];
|
||||
arg0->unk_C4[i] = unk_a3;
|
||||
if (index == -1) {
|
||||
index = i;
|
||||
arg0->rumbleEnable[0] = (unk_a3 >= 0x100);
|
||||
} else if (arg0->unk_04[index] < arg0->unk_04[i]) {
|
||||
index = i;
|
||||
arg0->rumbleEnable[0] = (unk_a3 >= 0x100);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (arg0->unk_10A != 0) {
|
||||
if (arg0->unk_10B > 0) {
|
||||
arg0->unk_10B--;
|
||||
} else {
|
||||
unk_a3 = arg0->unk_10A - arg0->unk_10C;
|
||||
if (unk_a3 > 0) {
|
||||
arg0->unk_10A = unk_a3;
|
||||
} else {
|
||||
arg0->unk_10A = 0;
|
||||
}
|
||||
}
|
||||
unk_a3 = arg0->unk_10D + arg0->unk_10A;
|
||||
arg0->unk_10D = unk_a3;
|
||||
arg0->rumbleEnable[0] = (unk_a3 >= 0x100);
|
||||
}
|
||||
if (arg0->unk_10A != 0) {
|
||||
unk_a3 = arg0->unk_10A;
|
||||
} else {
|
||||
if (index == -1) {
|
||||
unk_a3 = 0;
|
||||
} else {
|
||||
unk_a3 = arg0->unk_04[index];
|
||||
}
|
||||
}
|
||||
if (unk_a3 == 0) {
|
||||
if ((++arg0->unk_108) >= 6) {
|
||||
arg0->unk_106 = 0;
|
||||
arg0->unk_108 = 5;
|
||||
}
|
||||
} else {
|
||||
arg0->unk_108 = 0;
|
||||
if ((++arg0->unk_106) >= 0x1C21) {
|
||||
arg0->unk_104 = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < 0x40; i++) {
|
||||
arg0->unk_C4[i] = 0;
|
||||
arg0->unk_84[i] = 0;
|
||||
arg0->unk_44[i] = 0;
|
||||
arg0->unk_04[i] = 0;
|
||||
}
|
||||
|
||||
arg0->unk_106 = arg0->unk_108 = arg0->unk_10A = arg0->unk_10B = arg0->unk_10C = arg0->unk_10D = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void func_800D3140(UnkRumbleStruct* arg0) {
|
||||
bzero(arg0, sizeof(UnkRumbleStruct));
|
||||
arg0->unk_104 = 2;
|
||||
arg0->unk_105 = 1;
|
||||
}
|
||||
|
||||
void func_800D3178(UnkRumbleStruct* arg0) {
|
||||
bzero(arg0, sizeof(UnkRumbleStruct));
|
||||
}
|
|
@ -410,7 +410,7 @@ void GameState_Init(GameState* gameState, GameStateFunc init, GraphicsContext* g
|
|||
ViMode_Init(&sViMode);
|
||||
}
|
||||
SpeedMeter_Init(&D_801664D0);
|
||||
func_800AA0B4();
|
||||
Rumble_Init();
|
||||
osSendMesg(&gameState->gfxCtx->queue, NULL, OS_MESG_BLOCK);
|
||||
|
||||
endTime = osGetTime();
|
||||
|
@ -431,7 +431,7 @@ void GameState_Destroy(GameState* gameState) {
|
|||
if (gameState->destroy != NULL) {
|
||||
gameState->destroy(gameState);
|
||||
}
|
||||
func_800AA0F0();
|
||||
Rumble_Destroy();
|
||||
SpeedMeter_Destroy(&D_801664D0);
|
||||
func_800ACE90(&D_801664F0);
|
||||
func_800AD950(&D_80166500);
|
||||
|
|
|
@ -361,7 +361,7 @@ void PadMgr_HandleRetrace(PadMgr* padMgr) {
|
|||
|
||||
// Execute retrace callback
|
||||
if (padMgr->retraceCallback != NULL) {
|
||||
padMgr->retraceCallback(padMgr, padMgr->retraceCallbackValue);
|
||||
padMgr->retraceCallback(padMgr, padMgr->retraceCallbackArg);
|
||||
}
|
||||
|
||||
// Wait for controller data
|
||||
|
|
151
src/code/sys_rumble.c
Normal file
151
src/code/sys_rumble.c
Normal file
|
@ -0,0 +1,151 @@
|
|||
/**
|
||||
* @file sys_rumble.c
|
||||
*
|
||||
* This file implements a manager for storing and processing rumble pak requests made by the game state. Despite some
|
||||
* parts of the system appearing to accommodate all four controller ports, only controller 1 will rumble according to
|
||||
* the processed requests.
|
||||
* This file is half of the system that runs on the padmgr thread alongside controller communications. The rest of the
|
||||
* system that receives the requests from the game state runs on the graph thread and is implemented in `z_rumble.c`.
|
||||
*
|
||||
* @see RumbleMgr
|
||||
* @see z_rumble.c
|
||||
*
|
||||
* @note Original filename is likely sys_vibrate.c or similar as it is ordered after sys_ucode.c
|
||||
*/
|
||||
#include "global.h"
|
||||
|
||||
/**
|
||||
* Rumble manager update, runs on Vertical Retrace on the padmgr thread.
|
||||
*/
|
||||
void RumbleMgr_Update(RumbleMgr* rumbleMgr) {
|
||||
static u8 sWasEnabled = true;
|
||||
s32 i;
|
||||
s32 strength;
|
||||
s32 strongestIndex = -1;
|
||||
|
||||
// Clear enable status for all controllers
|
||||
for (i = 0; i < MAXCONTROLLERS; i++) {
|
||||
rumbleMgr->rumbleEnable[i] = false;
|
||||
}
|
||||
|
||||
if (!rumbleMgr->updateEnabled) {
|
||||
if (sWasEnabled) {
|
||||
// If it was previously enabled, reset pak type
|
||||
for (i = 0; i < MAXCONTROLLERS; i++) {
|
||||
gPadMgr.pakType[i] = CONT_PAK_NONE;
|
||||
}
|
||||
}
|
||||
sWasEnabled = rumbleMgr->updateEnabled;
|
||||
return;
|
||||
}
|
||||
|
||||
sWasEnabled = rumbleMgr->updateEnabled;
|
||||
|
||||
if (rumbleMgr->state == RUMBLE_STATE_RESET) {
|
||||
// Reset
|
||||
for (i = 0; i < MAXCONTROLLERS; i++) {
|
||||
gPadMgr.pakType[i] = CONT_PAK_NONE;
|
||||
}
|
||||
|
||||
for (i = 0; i < RUMBLE_MAX_REQUESTS; i++) {
|
||||
rumbleMgr->reqAccumulators[i] = 0;
|
||||
rumbleMgr->reqDecreaseRates[i] = 0;
|
||||
rumbleMgr->reqDurations[i] = 0;
|
||||
rumbleMgr->reqStrengths[i] = 0;
|
||||
}
|
||||
|
||||
rumbleMgr->onTimer = rumbleMgr->offTimer = rumbleMgr->overrideStrength = rumbleMgr->overrideDuration =
|
||||
rumbleMgr->overrideDecreaseRate = rumbleMgr->overrideAccumulator = 0;
|
||||
|
||||
rumbleMgr->state = RUMBLE_STATE_RUNNING;
|
||||
}
|
||||
|
||||
if (rumbleMgr->state != RUMBLE_STATE_CLEAR) {
|
||||
// Search for index with largest strength
|
||||
for (i = 0; i < RUMBLE_MAX_REQUESTS; i++) {
|
||||
if (rumbleMgr->reqStrengths[i] != 0) {
|
||||
// Non-empty request slot
|
||||
if (rumbleMgr->reqDurations[i] > 0) {
|
||||
rumbleMgr->reqDurations[i]--;
|
||||
} else {
|
||||
// After duration, decrease the strength by the decrease rate
|
||||
strength = rumbleMgr->reqStrengths[i] - rumbleMgr->reqDecreaseRates[i];
|
||||
rumbleMgr->reqStrengths[i] = MAX(strength, 0);
|
||||
}
|
||||
|
||||
// Increment accumulator by the strength
|
||||
strength = rumbleMgr->reqAccumulators[i] + rumbleMgr->reqStrengths[i];
|
||||
rumbleMgr->reqAccumulators[i] = strength;
|
||||
|
||||
if (strongestIndex == -1) {
|
||||
strongestIndex = i;
|
||||
// Rumble is enabled on the controller only when there is overflow of the accumulator, overflow
|
||||
// will happen more often for larger request strengths making it feel stronger to the player
|
||||
rumbleMgr->rumbleEnable[0] = strength > 255;
|
||||
} else if (rumbleMgr->reqStrengths[i] > rumbleMgr->reqStrengths[strongestIndex]) {
|
||||
strongestIndex = i;
|
||||
rumbleMgr->rumbleEnable[0] = strength > 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rumbleMgr->overrideStrength != 0) {
|
||||
// Set override
|
||||
if (rumbleMgr->overrideDuration > 0) {
|
||||
rumbleMgr->overrideDuration--;
|
||||
} else {
|
||||
// Once the duration is over, start decrementing the strength
|
||||
strength = rumbleMgr->overrideStrength - rumbleMgr->overrideDecreaseRate;
|
||||
rumbleMgr->overrideStrength = MAX(strength, 0);
|
||||
}
|
||||
// Increment accumulator, set rumble enabled on overflow
|
||||
strength = rumbleMgr->overrideAccumulator + rumbleMgr->overrideStrength;
|
||||
rumbleMgr->overrideAccumulator = strength;
|
||||
rumbleMgr->rumbleEnable[0] = strength > 255;
|
||||
}
|
||||
|
||||
if (rumbleMgr->overrideStrength != 0) {
|
||||
strength = rumbleMgr->overrideStrength;
|
||||
} else {
|
||||
strength = (strongestIndex == -1) ? 0 : rumbleMgr->reqStrengths[strongestIndex];
|
||||
}
|
||||
|
||||
if (strength == 0) {
|
||||
// No rumble
|
||||
if ((++rumbleMgr->offTimer) > 5) {
|
||||
// After 5 VIs with no rumble, reset the rumble on timer
|
||||
rumbleMgr->onTimer = 0;
|
||||
rumbleMgr->offTimer = 5;
|
||||
}
|
||||
} else {
|
||||
// Rumble
|
||||
rumbleMgr->offTimer = 0;
|
||||
if ((++rumbleMgr->onTimer) > 7200) { // 2 minutes at 60 VI/s, 2 minutes 24 seconds at 50 VI/s
|
||||
// Clear all requests if rumble has been on for too long
|
||||
rumbleMgr->state = RUMBLE_STATE_CLEAR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Clear all requests
|
||||
for (i = 0; i < RUMBLE_MAX_REQUESTS; i++) {
|
||||
rumbleMgr->reqAccumulators[i] = 0;
|
||||
rumbleMgr->reqDecreaseRates[i] = 0;
|
||||
rumbleMgr->reqDurations[i] = 0;
|
||||
rumbleMgr->reqStrengths[i] = 0;
|
||||
}
|
||||
|
||||
// Clear override request
|
||||
rumbleMgr->onTimer = rumbleMgr->offTimer = rumbleMgr->overrideStrength = rumbleMgr->overrideDuration =
|
||||
rumbleMgr->overrideDecreaseRate = rumbleMgr->overrideAccumulator = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RumbleMgr_Init(RumbleMgr* rumbleMgr) {
|
||||
bzero(rumbleMgr, sizeof(RumbleMgr));
|
||||
rumbleMgr->state = RUMBLE_STATE_RESET;
|
||||
rumbleMgr->updateEnabled = true;
|
||||
}
|
||||
|
||||
void RumbleMgr_Destroy(RumbleMgr* rumbleMgr) {
|
||||
bzero(rumbleMgr, sizeof(RumbleMgr));
|
||||
}
|
|
@ -3523,9 +3523,9 @@ void func_80033E1C(PlayState* play, s16 arg1, s16 arg2, s16 arg3) {
|
|||
|
||||
void func_80033E88(Actor* actor, PlayState* play, s16 arg2, s16 arg3) {
|
||||
if (arg2 >= 5) {
|
||||
func_800AA000(actor->xyzDistToPlayerSq, 0xFF, 0x14, 0x96);
|
||||
Rumble_Request(actor->xyzDistToPlayerSq, 255, 20, 150);
|
||||
} else {
|
||||
func_800AA000(actor->xyzDistToPlayerSq, 0xB4, 0x14, 0x64);
|
||||
Rumble_Request(actor->xyzDistToPlayerSq, 180, 20, 100);
|
||||
}
|
||||
|
||||
func_80033DB8(play, arg2, arg3);
|
||||
|
|
|
@ -595,9 +595,11 @@ void func_80111070(void) {
|
|||
VREG(87) = 64;
|
||||
VREG(88) = 66;
|
||||
VREG(89) = 0;
|
||||
VREG(90) = 126;
|
||||
VREG(91) = 124;
|
||||
VREG(92) = -63;
|
||||
R_GAME_OVER_RUMBLE_STRENGTH = 126;
|
||||
R_GAME_OVER_RUMBLE_DURATION = 124;
|
||||
//! @bug This is eventually cast to a u8 after some scaling in `GameOver_Update`, negative numbers typically
|
||||
//! become large (fast) decrease rates
|
||||
R_GAME_OVER_RUMBLE_DECREASE_RATE = -63;
|
||||
}
|
||||
|
||||
void func_80112098(PlayState* play) {
|
||||
|
|
|
@ -229,7 +229,7 @@ void func_8006390C(Input* input) {
|
|||
|
||||
if (iREG(0)) {
|
||||
iREG(0) = 0;
|
||||
func_800AA000(0, iREG(1), iREG(2), iREG(3));
|
||||
Rumble_Request(0.0f, iREG(1), iREG(2), iREG(3));
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -465,7 +465,7 @@ void Cutscene_Command_FadeBGM(PlayState* play, CutsceneContext* csCtx, CsCmdMusi
|
|||
// Command 9: ?
|
||||
void Cutscene_Command_09(PlayState* play, CutsceneContext* csCtx, CsCmdUnknown9* cmd) {
|
||||
if (csCtx->frames == cmd->startFrame) {
|
||||
func_800AA000(0.0f, cmd->unk_06, cmd->unk_07, cmd->unk_08);
|
||||
Rumble_Request(0.0f, cmd->unk_06, cmd->unk_07, cmd->unk_08);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ void GameOver_Update(PlayState* play) {
|
|||
GameOverContext* gameOverCtx = &play->gameOverCtx;
|
||||
s16 i;
|
||||
s16 j;
|
||||
s32 v90;
|
||||
s32 v91;
|
||||
s32 v92;
|
||||
s32 rumbleStrength;
|
||||
s32 rumbleDuration;
|
||||
s32 rumbleDecreaseRate;
|
||||
|
||||
switch (gameOverCtx->state) {
|
||||
case GAMEOVER_DEATH_START:
|
||||
|
@ -74,13 +74,15 @@ void GameOver_Update(PlayState* play) {
|
|||
|
||||
Environment_InitGameOverLights(play);
|
||||
gGameOverTimer = 20;
|
||||
if (1) {}
|
||||
v90 = VREG(90);
|
||||
v91 = VREG(91);
|
||||
v92 = VREG(92);
|
||||
|
||||
func_800AA000(0.0f, ((v90 > 0x64) ? 0xFF : (v90 * 0xFF) / 0x64), (CLAMP_MAX(v91 * 3, 0xFF)),
|
||||
((v92 > 0x64) ? 0xFF : (v92 * 0xFF) / 0x64));
|
||||
if (1) {}
|
||||
rumbleStrength = R_GAME_OVER_RUMBLE_STRENGTH;
|
||||
rumbleDuration = R_GAME_OVER_RUMBLE_DURATION;
|
||||
rumbleDecreaseRate = R_GAME_OVER_RUMBLE_DECREASE_RATE;
|
||||
|
||||
Rumble_Request(0.0f, ((rumbleStrength > 100) ? 255 : (rumbleStrength * 255) / 100),
|
||||
(CLAMP_MAX(rumbleDuration * 3, 255)),
|
||||
((rumbleDecreaseRate > 100) ? 255 : (rumbleDecreaseRate * 255) / 100));
|
||||
|
||||
gameOverCtx->state = GAMEOVER_DEATH_WAIT_GROUND;
|
||||
break;
|
||||
|
@ -94,7 +96,7 @@ void GameOver_Update(PlayState* play) {
|
|||
if (gGameOverTimer == 0) {
|
||||
play->pauseCtx.state = 8;
|
||||
gameOverCtx->state++;
|
||||
func_800AA15C();
|
||||
Rumble_Reset();
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -108,14 +110,15 @@ void GameOver_Update(PlayState* play) {
|
|||
case GAMEOVER_REVIVE_RUMBLE:
|
||||
gGameOverTimer = 50;
|
||||
gameOverCtx->state++;
|
||||
|
||||
if (1) {}
|
||||
rumbleStrength = R_GAME_OVER_RUMBLE_STRENGTH;
|
||||
rumbleDuration = R_GAME_OVER_RUMBLE_DURATION;
|
||||
rumbleDecreaseRate = R_GAME_OVER_RUMBLE_DECREASE_RATE;
|
||||
|
||||
v90 = VREG(90);
|
||||
v91 = VREG(91);
|
||||
v92 = VREG(92);
|
||||
|
||||
func_800AA000(0.0f, ((v90 > 0x64) ? 0xFF : (v90 * 0xFF) / 0x64), (CLAMP_MAX(v91 * 3, 0xFF)),
|
||||
((v92 > 0x64) ? 0xFF : (v92 * 0xFF) / 0x64));
|
||||
Rumble_Request(0.0f, ((rumbleStrength > 100) ? 255 : (rumbleStrength * 255) / 100),
|
||||
(CLAMP_MAX(rumbleDuration * 3, 255)),
|
||||
((rumbleDecreaseRate > 100) ? 255 : (rumbleDecreaseRate * 255) / 100));
|
||||
break;
|
||||
|
||||
case GAMEOVER_REVIVE_WAIT_GROUND:
|
||||
|
|
|
@ -437,7 +437,7 @@ void Environment_Init(PlayState* play2, EnvironmentContext* envCtx, s32 unused)
|
|||
}
|
||||
|
||||
gCustomLensFlareOn = false;
|
||||
func_800AA15C();
|
||||
Rumble_Reset();
|
||||
}
|
||||
|
||||
u8 Environment_SmoothStepToU8(u8* pvalue, u8 target, u8 scale, u8 step, u8 minStep) {
|
||||
|
@ -883,7 +883,7 @@ void Environment_Update(PlayState* play, EnvironmentContext* envCtx, LightContex
|
|||
|
||||
if ((((void)0, gSaveContext.gameMode) != GAMEMODE_NORMAL) &&
|
||||
(((void)0, gSaveContext.gameMode) != GAMEMODE_END_CREDITS)) {
|
||||
func_800AA16C();
|
||||
Rumble_ClearRequests();
|
||||
}
|
||||
|
||||
if (pauseCtx->state == 0) {
|
||||
|
|
|
@ -852,7 +852,7 @@ void Play_Update(PlayState* this) {
|
|||
PLAY_LOG(3580);
|
||||
|
||||
this->gameplayFrames++;
|
||||
func_800AA178(1);
|
||||
Rumble_SetUpdateEnabled(true);
|
||||
|
||||
if (this->actorCtx.freezeFlashTimer && (this->actorCtx.freezeFlashTimer-- < 5)) {
|
||||
osSyncPrintf("FINISH=%d\n", this->actorCtx.freezeFlashTimer);
|
||||
|
@ -902,7 +902,7 @@ void Play_Update(PlayState* this) {
|
|||
PLAY_LOG(3662);
|
||||
}
|
||||
} else {
|
||||
func_800AA178(0);
|
||||
Rumble_SetUpdateEnabled(false);
|
||||
}
|
||||
|
||||
PLAY_LOG(3672);
|
||||
|
|
135
src/code/z_rumble.c
Normal file
135
src/code/z_rumble.c
Normal file
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* @file z_rumble.c
|
||||
*
|
||||
* This file implements an interface for the game state to set up, manage and request use of the rumble pak. Despite
|
||||
* some parts of the system appearing to accommodate all four controller ports, only controller 1 can be instructed
|
||||
* to rumble.
|
||||
* This file is half of the system that runs on the graph thread alongside the game state. The rest of the system that
|
||||
* processes the requests runs on the padmgr thread and is implemented in `sys_rumble.c`.
|
||||
*
|
||||
* @see sys_rumble.c
|
||||
*
|
||||
* @note Original filename is likely z_vibrate.c or similar as it is ordered after z_ss_sram.c and before z_view.c
|
||||
*/
|
||||
#include "global.h"
|
||||
|
||||
RumbleMgr sRumbleMgr;
|
||||
|
||||
/**
|
||||
* Padmgr callback to update the state of rumble on Vertical Retrace.
|
||||
*
|
||||
* Unlike every other function in this file, this runs on the padmgr thread.
|
||||
*/
|
||||
void Rumble_Update(PadMgr* padMgr, void* arg) {
|
||||
RumbleMgr_Update(&sRumbleMgr);
|
||||
PadMgr_RumbleSet(padMgr, sRumbleMgr.rumbleEnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the rumble state to use the supplied parameters.
|
||||
* The parameters are the same as in `Rumble_Request`.
|
||||
*
|
||||
* @see Rumble_Request
|
||||
*/
|
||||
void Rumble_Override(f32 distSq, u8 sourceStrength, u8 duration, u8 decreaseRate) {
|
||||
s32 dist;
|
||||
s32 strength;
|
||||
|
||||
if (distSq > SQ(1000)) {
|
||||
dist = 1000;
|
||||
} else {
|
||||
dist = sqrtf(distSq);
|
||||
}
|
||||
|
||||
if (dist < 1000 && sourceStrength != 0 && decreaseRate != 0) {
|
||||
// Decrease the strength linearly with distance
|
||||
strength = sourceStrength - (dist * 255) / 1000;
|
||||
|
||||
if (strength > 0) {
|
||||
// Note: sRumbleMgr is a shared resource between the graph and padmgr threads, no locking is done
|
||||
// to ensure that the entire request is written before it is possibly used.
|
||||
sRumbleMgr.overrideStrength = strength;
|
||||
sRumbleMgr.overrideDuration = duration;
|
||||
sRumbleMgr.overrideDecreaseRate = decreaseRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits a request to the rumble manager with the properties given in the arguments. If there is no free request slot
|
||||
* the request is silently dropped.
|
||||
*
|
||||
* @param distSq
|
||||
* Squared distance, usually taken to be from an apparent source to the player in world coordinates.
|
||||
* @param sourceStrength
|
||||
* The strength of the rumble at 0 distance from the source.
|
||||
* The rumble source strength decreases linearly with distance, a distance of 0 results in the full source strength
|
||||
* while a distance of 1000 or greater is discarded. A source strength of 0 is discarded. A minimum source strength
|
||||
* of 1 drops to 0 at 3 units of distance from the source. A maximum source strength of 255 drops to 0 at 1000
|
||||
* units of distance from the source.
|
||||
* Note that, once the request has been submitted, if the distance to the source changes in subsequent frames while
|
||||
* the rumble request is still running, the request will not be updated with the new distance.
|
||||
* @param duration
|
||||
* The duration for which the rumble will sustain full strength. It is measured in Vertical Retraces rather than
|
||||
* game frames. There are ~60 Retraces/s on NTSC and 50 Retraces/s on PAL.
|
||||
* @param decreaseRate
|
||||
* The amount by which to lower the strength every Vertical Retrace once duration has hit 0.
|
||||
*/
|
||||
void Rumble_Request(f32 distSq, u8 sourceStrength, u8 duration, u8 decreaseRate) {
|
||||
s32 dist;
|
||||
s32 strength;
|
||||
s32 i;
|
||||
|
||||
if (distSq > SQ(1000)) {
|
||||
dist = 1000;
|
||||
} else {
|
||||
dist = sqrtf(distSq);
|
||||
}
|
||||
|
||||
if (dist < 1000 && sourceStrength != 0 && decreaseRate != 0) {
|
||||
// Decrease the strength linearly with distance
|
||||
strength = sourceStrength - (dist * 255) / 1000;
|
||||
|
||||
for (i = 0; i < RUMBLE_MAX_REQUESTS; i++) {
|
||||
// Search for an empty slot
|
||||
if (sRumbleMgr.reqStrengths[i] == 0) {
|
||||
if (strength > 0) {
|
||||
// Note: sRumbleMgr is a shared resource between the graph and padmgr threads, no locking is done
|
||||
// to ensure that the entire request is written before it is possibly used.
|
||||
sRumbleMgr.reqStrengths[i] = strength;
|
||||
sRumbleMgr.reqDurations[i] = duration;
|
||||
sRumbleMgr.reqDecreaseRates[i] = decreaseRate;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Rumble_Init(void) {
|
||||
RumbleMgr_Init(&sRumbleMgr);
|
||||
PADMGR_SET_RETRACE_CALLACK(&gPadMgr, Rumble_Update, NULL);
|
||||
}
|
||||
|
||||
void Rumble_Destroy(void) {
|
||||
PadMgr* padmgr = &gPadMgr;
|
||||
|
||||
PADMGR_UNSET_RETRACE_CALLACK(padmgr, Rumble_Update, NULL);
|
||||
RumbleMgr_Destroy(&sRumbleMgr);
|
||||
}
|
||||
|
||||
s32 Rumble_Controller1HasRumblePak(void) {
|
||||
return gPadMgr.pakType[0] == CONT_PAK_RUMBLE;
|
||||
}
|
||||
|
||||
void Rumble_Reset(void) {
|
||||
sRumbleMgr.state = RUMBLE_STATE_RESET;
|
||||
}
|
||||
|
||||
void Rumble_ClearRequests(void) {
|
||||
sRumbleMgr.state = RUMBLE_STATE_CLEAR;
|
||||
}
|
||||
|
||||
void Rumble_SetUpdateEnabled(u32 enable) {
|
||||
sRumbleMgr.updateEnabled = !!enable;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue