summaryrefslogtreecommitdiff
path: root/src/code/z_rumble.c
blob: 52267f6a281f82314730af9ef7eca64ce32f91cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*
 * File: z_rumble.c
 * Description: Rumble request system
 *
 * Provides a simple interface to allow scheduling up to RUMBLE_REQUEST_BUFFER_SIZE rumble requests to the RumblePak.
 * There's an additional Override type of rumble request for requests which should take priorities over any other
 * scheduled request.
 */

#include "global.h"
#include "z64rumble.h"

#pragma increment_block_number "n64-us:128"

static s32 sBssPad[4];
RumbleManager gRumbleMgr;

void Rumble_Update(void* arg0) {
    RumbleManager_Update(&gRumbleMgr);
    PadMgr_RumbleSet(gRumbleMgr.rumbleEnabled);
}

// Used by some bosses (and fishing)
void Rumble_Override(f32 distSq, u8 sourceIntensity, u8 decayTimer, u8 decayStep) {
    s32 intensity;
    s32 distance;

    if (SQ(1000.0f) < distSq) {
        distance = 1000;
    } else {
        distance = sqrtf(distSq);
    }

    if ((distance < 1000) && (sourceIntensity != 0) && (decayStep != 0)) {
        intensity = sourceIntensity - (distance * 255) / 1000;

        if (intensity > 0) {
            gRumbleMgr.overrideIntensity = intensity;
            gRumbleMgr.overrideDecayTimer = decayTimer;
            gRumbleMgr.overrideDecayStep = decayStep;
        }
    }
}

void Rumble_Request(f32 distSq, u8 sourceIntensity, u8 decayTimer, u8 decayStep) {
    s32 intensity;
    s32 distance;
    s32 i;

    if (SQ(1000.0f) < distSq) {
        distance = 1000;
    } else {
        distance = sqrtf(distSq);
    }

    if ((distance < 1000) && (sourceIntensity != 0) && (decayStep != 0)) {
        intensity = sourceIntensity - (distance * 255) / 1000;

        for (i = 0; i < RUMBLE_REQUEST_BUFFER_SIZE; i++) {
            if (gRumbleMgr.requestIntensities[i] == 0) {
                if (intensity > 0) {
                    gRumbleMgr.requestIntensities[i] = intensity;
                    gRumbleMgr.requestDecayTimers[i] = decayTimer;
                    gRumbleMgr.requestDecaySteps[i] = decayStep;
                }
                break;
            }
        }
    }
}

void Rumble_Init(void) {
    RumbleManager_Init(&gRumbleMgr);
    PadMgr_SetRumbleRetraceCallback(Rumble_Update, NULL);
}

void Rumble_Destroy(void) {
    PadMgr_UnsetRumbleRetraceCallback(Rumble_Update, NULL);
    RumbleManager_Destroy(&gRumbleMgr);
}

s32 Rumble_ControllerOneHasRumblePak(void) {
    return PadMgr_ControllerHasRumblePak(0);
}

/**
 * Wipes every old request for a fresh start, then proceeds to process them as normal
 */
void Rumble_StateReset(void) {
    gRumbleMgr.state = RUMBLEMANAGER_STATE_INITIAL;
}

/**
 * Changes the state of the manager to WIPE
 *
 * In this state, every request is deleted
 */
void Rumble_StateWipeRequests(void) {
    gRumbleMgr.state = RUMBLEMANAGER_STATE_WIPE;
}

/**
 * Request processing is paused if updateEnabled is set to false
 */
void Rumble_SetUpdateEnabled(s32 updateEnabled) {
    gRumbleMgr.updateEnabled = !!updateEnabled;
}