sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

rumble_init.c (7374B)


      1 #include "config.h"
      2 
      3 #if ENABLE_RUMBLE
      4 
      5 #include <ultra64.h>
      6 #include <PR/os.h>
      7 #include "macros.h"
      8 
      9 #include "buffers/buffers.h"
     10 #include "main.h"
     11 #include "rumble_init.h"
     12 
     13 FORCE_BSS OSThread gRumblePakThread;
     14 
     15 FORCE_BSS OSPfs gRumblePakPfs;
     16 
     17 FORCE_BSS OSMesg gRumblePakSchedulerMesgBuf;
     18 FORCE_BSS OSMesgQueue gRumblePakSchedulerMesgQueue;
     19 FORCE_BSS OSMesg gRumbleThreadVIMesgBuf;
     20 FORCE_BSS OSMesgQueue gRumbleThreadVIMesgQueue;
     21 
     22 FORCE_BSS struct RumbleData gRumbleDataQueue[3];
     23 FORCE_BSS struct StructSH8031D9B0 gCurrRumbleSettings;
     24 
     25 s32 sRumblePakThreadActive = FALSE;
     26 s32 sRumblePakActive = FALSE;
     27 s32 sRumblePakErrorCount = 0;
     28 s32 gRumblePakTimer = 0;
     29 
     30 void init_rumble_pak_scheduler_queue(void) {
     31     osCreateMesgQueue(&gRumblePakSchedulerMesgQueue, &gRumblePakSchedulerMesgBuf, 1);
     32     osSendMesg(&gRumblePakSchedulerMesgQueue, (OSMesg) 0, OS_MESG_NOBLOCK);
     33 }
     34 
     35 void block_until_rumble_pak_free(void) {
     36     OSMesg msg;
     37     osRecvMesg(&gRumblePakSchedulerMesgQueue, &msg, OS_MESG_BLOCK);
     38 }
     39 
     40 void release_rumble_pak_control(void) {
     41     osSendMesg(&gRumblePakSchedulerMesgQueue, (OSMesg) 0, OS_MESG_NOBLOCK);
     42 }
     43 
     44 static void start_rumble(void) {
     45     if (!sRumblePakActive) {
     46         return;
     47     }
     48 
     49     block_until_rumble_pak_free();
     50 
     51 #ifdef VERSION_CN
     52     if (!__osMotorAccess(&gRumblePakPfs, MOTOR_START)) {
     53 #else
     54     if (!osMotorStart(&gRumblePakPfs)) {
     55 #endif
     56         sRumblePakErrorCount = 0;
     57     } else {
     58         sRumblePakErrorCount++;
     59     }
     60 
     61     release_rumble_pak_control();
     62 }
     63 
     64 static void stop_rumble(void) {
     65     if (!sRumblePakActive) {
     66         return;
     67     }
     68 
     69     block_until_rumble_pak_free();
     70 
     71 #ifdef VERSION_CN
     72     if (!__osMotorAccess(&gRumblePakPfs, MOTOR_STOP)) {
     73 #else
     74     if (!osMotorStop(&gRumblePakPfs)) {
     75 #endif
     76         sRumblePakErrorCount = 0;
     77     } else {
     78         sRumblePakErrorCount++;
     79     }
     80 
     81     release_rumble_pak_control();
     82 }
     83 
     84 static void update_rumble_pak(void) {
     85     if (gResetTimer > 0) {
     86         stop_rumble();
     87         return;
     88     }
     89 
     90     if (gCurrRumbleSettings.unk08 > 0) {
     91         gCurrRumbleSettings.unk08--;
     92         start_rumble();
     93     } else if (gCurrRumbleSettings.unk04 > 0) {
     94         gCurrRumbleSettings.unk04--;
     95 
     96         gCurrRumbleSettings.unk02 -= gCurrRumbleSettings.unk0E;
     97         if (gCurrRumbleSettings.unk02 < 0) {
     98             gCurrRumbleSettings.unk02 = 0;
     99         }
    100 
    101         if (gCurrRumbleSettings.unk00 == 1) {
    102             start_rumble();
    103         } else if (gCurrRumbleSettings.unk06 >= 0x100) {
    104             gCurrRumbleSettings.unk06 -= 0x100;
    105             start_rumble();
    106         } else {
    107             gCurrRumbleSettings.unk06 +=
    108                 ((gCurrRumbleSettings.unk02 * gCurrRumbleSettings.unk02 * gCurrRumbleSettings.unk02) / (1 << 9)) + 4;
    109 
    110             stop_rumble();
    111         }
    112     } else {
    113         gCurrRumbleSettings.unk04 = 0;
    114 
    115         if (gCurrRumbleSettings.unk0A >= 5) {
    116             start_rumble();
    117         } else if ((gCurrRumbleSettings.unk0A >= 2) && (gNumVblanks % gCurrRumbleSettings.unk0C == 0)) {
    118             start_rumble();
    119         } else {
    120             stop_rumble();
    121         }
    122     }
    123 
    124     if (gCurrRumbleSettings.unk0A > 0) {
    125         gCurrRumbleSettings.unk0A--;
    126     }
    127 }
    128 
    129 static void update_rumble_data_queue(void) {
    130     if (gRumbleDataQueue[0].unk00) {
    131         gCurrRumbleSettings.unk06 = 0;
    132         gCurrRumbleSettings.unk08 = 4;
    133         gCurrRumbleSettings.unk00 = gRumbleDataQueue[0].unk00;
    134         gCurrRumbleSettings.unk04 = gRumbleDataQueue[0].unk02;
    135         gCurrRumbleSettings.unk02 = gRumbleDataQueue[0].unk01;
    136         gCurrRumbleSettings.unk0E = gRumbleDataQueue[0].unk04;
    137     }
    138 
    139     gRumbleDataQueue[0] = gRumbleDataQueue[1];
    140     gRumbleDataQueue[1] = gRumbleDataQueue[2];
    141 
    142     gRumbleDataQueue[2].unk00 = 0;
    143 }
    144 
    145 void queue_rumble_data(s16 a0, s16 a1) {
    146     if (gCurrDemoInput != NULL) {
    147         return;
    148     }
    149 
    150     if (a1 > 70) {
    151         gRumbleDataQueue[2].unk00 = 1;
    152     } else {
    153         gRumbleDataQueue[2].unk00 = 2;
    154     }
    155 
    156     gRumbleDataQueue[2].unk01 = a1;
    157     gRumbleDataQueue[2].unk02 = a0;
    158     gRumbleDataQueue[2].unk04 = 0;
    159 }
    160 
    161 void func_sh_8024C89C(s16 a0) {
    162     gRumbleDataQueue[2].unk04 = a0;
    163 }
    164 
    165 u8 is_rumble_finished_and_queue_empty(void) {
    166     if (gCurrRumbleSettings.unk08 + gCurrRumbleSettings.unk04 >= 4) {
    167         return FALSE;
    168     }
    169 
    170     if (gRumbleDataQueue[0].unk00 != 0) {
    171         return FALSE;
    172     }
    173 
    174     if (gRumbleDataQueue[1].unk00 != 0) {
    175         return FALSE;
    176     }
    177 
    178     if (gRumbleDataQueue[2].unk00 != 0) {
    179         return FALSE;
    180     }
    181 
    182     return TRUE;
    183 }
    184 
    185 void reset_rumble_timers(void) {
    186     if (gCurrDemoInput != NULL) {
    187         return;
    188     }
    189 
    190     if (gCurrRumbleSettings.unk0A == 0) {
    191         gCurrRumbleSettings.unk0A = 7;
    192     }
    193 
    194     if (gCurrRumbleSettings.unk0A < 4) {
    195         gCurrRumbleSettings.unk0A = 4;
    196     }
    197 
    198     gCurrRumbleSettings.unk0C = 7;
    199 }
    200 
    201 void reset_rumble_timers_2(s32 a0) {
    202     if (gCurrDemoInput != NULL) {
    203         return;
    204     }
    205 
    206     if (gCurrRumbleSettings.unk0A == 0) {
    207         gCurrRumbleSettings.unk0A = 7;
    208     }
    209 
    210     if (gCurrRumbleSettings.unk0A < 4) {
    211         gCurrRumbleSettings.unk0A = 4;
    212     }
    213 
    214     if (a0 == 4) {
    215         gCurrRumbleSettings.unk0C = 1;
    216     }
    217 
    218     if (a0 == 3) {
    219         gCurrRumbleSettings.unk0C = 2;
    220     }
    221 
    222     if (a0 == 2) {
    223         gCurrRumbleSettings.unk0C = 3;
    224     }
    225 
    226     if (a0 == 1) {
    227         gCurrRumbleSettings.unk0C = 4;
    228     }
    229 
    230     if (a0 == 0) {
    231         gCurrRumbleSettings.unk0C = 5;
    232     }
    233 }
    234 
    235 void func_sh_8024CA04(void) {
    236     if (gCurrDemoInput != NULL) {
    237         return;
    238     }
    239 
    240     gCurrRumbleSettings.unk0A = 4;
    241     gCurrRumbleSettings.unk0C = 4;
    242 }
    243 
    244 static void thread6_rumble_loop(UNUSED void *a0) {
    245     OSMesg msg;
    246 
    247     CN_DEBUG_PRINTF(("start motor thread\n"));
    248 
    249     cancel_rumble();
    250     sRumblePakThreadActive = TRUE;
    251 
    252     CN_DEBUG_PRINTF(("go motor thread\n"));
    253 
    254     while (TRUE) {
    255         // Block until VI
    256         osRecvMesg(&gRumbleThreadVIMesgQueue, &msg, OS_MESG_BLOCK);
    257 
    258         update_rumble_data_queue();
    259         update_rumble_pak();
    260 
    261         if (sRumblePakActive) {
    262             if (sRumblePakErrorCount >= 30) {
    263                 sRumblePakActive = FALSE;
    264             }
    265         } else if (gNumVblanks % 60 == 0) {
    266             sRumblePakActive = osMotorInit(&gSIEventMesgQueue, &gRumblePakPfs, gPlayer1Controller->port) == 0;
    267             sRumblePakErrorCount = 0;
    268         }
    269 
    270         if (gRumblePakTimer > 0) {
    271             gRumblePakTimer--;
    272         }
    273     }
    274 }
    275 
    276 void cancel_rumble(void) {
    277     sRumblePakActive = osMotorInit(&gSIEventMesgQueue, &gRumblePakPfs, gPlayer1Controller->port) == 0;
    278 
    279     if (sRumblePakActive) {
    280 #ifdef VERSION_CN
    281         __osMotorAccess(&gRumblePakPfs, MOTOR_STOP);
    282 #else
    283         osMotorStop(&gRumblePakPfs);
    284 #endif
    285     }
    286 
    287     gRumbleDataQueue[0].unk00 = 0;
    288     gRumbleDataQueue[1].unk00 = 0;
    289     gRumbleDataQueue[2].unk00 = 0;
    290 
    291     gCurrRumbleSettings.unk04 = 0;
    292     gCurrRumbleSettings.unk0A = 0;
    293 
    294     gRumblePakTimer = 0;
    295 }
    296 
    297 void create_thread_6(void) {
    298     osCreateMesgQueue(&gRumbleThreadVIMesgQueue, &gRumbleThreadVIMesgBuf, 1);
    299     osCreateThread(&gRumblePakThread, 6, thread6_rumble_loop, NULL, gThread6Stack + 0x2000, 30);
    300     osStartThread(&gRumblePakThread);
    301 }
    302 
    303 void rumble_thread_update_vi(void) {
    304     if (!sRumblePakThreadActive) {
    305         return;
    306     }
    307 
    308 #pragma GCC diagnostic push
    309 #pragma GCC diagnostic ignored "-Wmultichar"
    310     osSendMesg(&gRumbleThreadVIMesgQueue, (OSMesg) 'VRTC', OS_MESG_NOBLOCK);
    311 #pragma GCC diagnostic pop
    312 }
    313 
    314 #endif