perfect_dark/src/lib/lib_13900.c

1073 lines
26 KiB
C

#include <ultra64.h>
#include "constants.h"
#include "game/data/data_000000.h"
#include "game/data/data_0083d0.h"
#include "game/data/data_00e460.h"
#include "game/data/data_0160b0.h"
#include "game/data/data_01a3a0.h"
#include "game/data/data_020df0.h"
#include "game/data/data_02da90.h"
#include "game/pak/pak.h"
#include "gvars/gvars.h"
#include "lib/lib_04a80.h"
#include "lib/main.h"
#include "lib/lib_13900.h"
#include "lib/lib_4f5e0.h"
#include "types.h"
/**
* PD uses use a separate thread (than the main game) for controller polling.
* This thread polls the controllers as frequently as possible and stores its
* results inside g_ContData->samples. This allows the main thread to access a
* history of controller states since the last rendered frame. For example,
* under laggy conditions the player might press and release a button between
* two frames and the main thread can tell that this has happened even if the
* button was unpressed during both the previous and current frame.
*
* The samples array contains 20 elements and is written to in a cyclic manner.
* These samples are split into two partitions: cur and next. cur refers to
* samples which are currently visible to the main thread on this frame, and
* samples in next are samples which have been added since the start of the
* current frame and will be made visible on the next frame.
*
* At the start of a frame, the main thread informs the cont system that it's
* ready to consume more samples. The cont system then moves the partition
* boundaries so that the old next partition becomes the new cur, and everything
* else becomes available for next.
*
* If all 20 samples are in use, the cont system will overwrite the most recent
* sample in the next partition.
*/
const char var70054080[] = "joyReset\n";
const char var7005408c[] = "joyReset: doing nothing\n";
struct contdata *g_ContDataPtr = &g_ContData[0];
bool g_ContBusy = false;
u32 var8005ee68 = 0;
// Number of times per pad that different inputs were attempted to be read
// when controller was disconnected or not ready.
u32 g_ContBadReadsStickX[4] = {0};
u32 g_ContBadReadsStickY[4] = {0};
u32 g_ContBadReadsButtons[4] = {0};
u32 g_ContBadReadsButtonsPressed[4] = {0};
u8 g_ConnectedControllers = 0;
bool g_ContQueuesCreated = false;
bool g_ContInitDone = false;
bool g_ContNeedsInit = true;
u32 var8005eebc = 0;
u32 var8005eec0 = 1;
s32 (*var8005eec4)(struct contsample *samples, s32 samplenum) = NULL;
void (*var8005eec8)(struct contsample *samples, s32 samplenum, s32 samplenum2) = NULL;
s32 g_ContNextPfsStateIndex = 0;
u32 var8005eed0 = 0;
u32 var8005eed4 = 0;
u8 var8005eed8 = 0;
u32 var8005eedc = 1;
s32 var8005eee0 = 0;
s32 var8005eee4 = -1;
u32 var8005eee8 = 0;
u32 var8005eeec = 0;
u32 var8005eef0 = 1;
void func00013900(void)
{
if (var8005eef0) {
func000150e8();
var8005eef0 = false;
}
}
void func00013938(void)
{
if (!var8005eef0) {
func00015144();
var8005eef0 = true;
}
}
void func00013974(u32 value)
{
var8005eeec = value;
}
u32 func00013980(void)
{
return var8005eeec;
}
void func0001398c(s32 value)
{
var8005eee4 = var8005eee0 = value * 11000;
}
void func000139c8(void)
{
func0001398c(10);
}
/**
* Remove an item from the beginning of the g_ContPfsStates array,
* shift the rest of the array back and return the removed item.
*/
s32 contShiftPfsStates(void)
{
s32 pfsstate = 0;
s32 i;
if (g_ContNextPfsStateIndex) {
pfsstate = g_ContPfsStates[0];
if (g_ContNextPfsStateIndex > 1) {
for (i = 0; i < g_ContNextPfsStateIndex; i++) {
g_ContPfsStates[i] = g_ContPfsStates[i + 1];
}
g_ContNextPfsStateIndex--;
}
}
return pfsstate;
}
void contRecordPfsState(u8 pfsstate)
{
if (g_ContNextPfsStateIndex + 1 >= 100) {
contShiftPfsStates();
}
if (g_ContNextPfsStateIndex == 0 || pfsstate != g_ContPfsStates[g_ContNextPfsStateIndex - 1]) {
g_ContPfsStates[g_ContNextPfsStateIndex] = pfsstate;
g_ContNextPfsStateIndex++;
}
}
/**
* Scan controllers for controller paks, but only under certain conditions.
* Seems to be timer based, or can be forced by passing 2 as arg0.
*/
void contCheckPfs(s32 arg0)
{
static u32 thiscount = 0; // 8005eef4
static u32 prevcount = 0; // 8005eef8
static u32 doingit = false; // 8005eefc
u32 diffcount;
u32 value;
if (var8005eedc
&& (arg0 == 2 || (var8005eee0 && (arg0 || ((var8005eebc == 0 || var8005eef0 == 0) && var8005eeec))))
&& !doingit) {
doingit = true;
prevcount = thiscount;
thiscount = osGetCount();
diffcount = (thiscount - prevcount) / 256;
value = var8005eee0 * 2;
if (diffcount > value) {
diffcount = value;
}
var8005eee4 -= diffcount;
if (var8005eee4 < 0
|| arg0 == 2
|| (arg0 == 1 && var8005eee4 < 0 && var8005eee0 < -var8005eee4)) {
u8 bitpattern = 0;
var8005eee8++;
if (arg0) {
func000150e8();
}
osPfsIsPlug(&var80099e78, &bitpattern);
if (arg0) {
func00015144();
}
bitpattern |= 0x10;
contRecordPfsState(bitpattern);
var8005eee4 = var8005eee0;
}
doingit = false;
}
if (arg0) {
// empty
}
}
/**
* "Temporarily" because the next time contCheckPfs runs, the true state will be
* recorded.
*
* Note that var8005eed8 is always zero, so this record will suggest that this
* pak is the only one connected.
*/
void contSetPfsTemporarilyPlugged(s8 index)
{
u8 bitpattern = var8005eed8 & ~(1 << index);
contRecordPfsState(bitpattern);
}
void contSystemInit(void)
{
s32 i;
s32 j;
osCreateMesgQueue(&var80099ec0, &var80099eb8, 1);
osCreateMesgQueue(&var80099ee0, &var80099ed8, 1);
osCreateMesgQueue(&var80099f00, &var80099ef8, 1);
osCreateMesgQueue(&var80099f20, &var80099f18, 1);
osCreateMesgQueue(&var80099e78, &var80099e90, 10);
osSetEventMesg(OS_EVENT_SI, &var80099e78, NULL);
g_ContQueuesCreated = true;
var8005eec4 = NULL;
var8005eec8 = NULL;
for (i = 0; i < 2; i++) {
g_ContData[i].curlast = 0;
g_ContData[i].curstart = 0;
g_ContData[i].nextlast = 0;
g_ContData[i].nextsecondlast = 0;
g_ContData[i].unk200 = -1;
for (j = 0; j < 4; j++) {
g_ContData[i].samples[0].pads[j].button = 0;
g_ContData[i].samples[0].pads[j].stick_x = 0;
g_ContData[i].samples[0].pads[j].stick_y = 0;
g_ContData[i].samples[0].pads[j].errno = 0;
}
}
for (i = 0; i < 4; i++) {
g_ContDisableCooldown[i] = 0;
}
}
/**
* Disable all input on all controllers for 60 frames, or until the player has
* released all inputs.
*
* It's used to prevent the player from accidentally skipping cutscenes and
* progressing past endscreens if they are holding buttons when they are
* started.
*/
void contDisableTemporarily(void)
{
s32 i;
for (i = 0; i < 4; i++) {
g_ContDisableCooldown[i] = 60;
}
}
void func00013dfc(void)
{
OSMesg msg;
if (g_ContQueuesCreated) {
osSendMesg(&var80099ec0, &msg, OS_MESG_NOBLOCK);
osRecvMesg(&var80099ee0, &msg, OS_MESG_BLOCK);
func00013e84();
osSendMesg(&var80099f00, &msg, OS_MESG_NOBLOCK);
osRecvMesg(&var80099f20, &msg, OS_MESG_BLOCK);
var8005eec0 = 1;
}
}
void func00013e84(void)
{
static u8 var8005ef00 = 0xff;
// osContInit should be called only once. The first time this function is
// called it'll take the first branch here, and all subsequent calls will
// take the second branch.
if (g_ContNeedsInit) {
s32 i;
g_ContNeedsInit = false;
osContInit(&var80099e78, &g_ConnectedControllers, var80099f38);
g_ContInitDone = true;
for (i = 0; i < 4; i++) {
func000153c4(i, 0);
}
} else {
u32 slots = 0xf;
s32 i;
osContStartQuery(&var80099e78);
osRecvMesg(&var80099e78, NULL, OS_MESG_BLOCK);
osContGetQuery(var80099f38);
for (i = 0; i < 4; i++) {
if (var80099f38[i].errno & CONT_NO_RESPONSE_ERROR) {
slots -= 1 << i;
}
}
g_ConnectedControllers = slots;
}
if (var8005ef00 != g_ConnectedControllers) {
s32 i = 0;
s32 index = 0;
for (; i < 4; i++) {
if (g_ConnectedControllers & (1 << i)) {
g_Vars.playertojoymap[index++] = i;
}
}
var8005ef00 = g_ConnectedControllers;
}
}
s8 contGetFreeSlot(void)
{
s32 i;
if (g_ContDataPtr->unk200 >= 0) {
return g_ContDataPtr->unk200;
}
for (i = 0; i < 4; i++) {
if ((g_ConnectedControllers & (1 << i)) == 0) {
return i;
}
}
return 4;
}
u32 contGetConnectedControllers(void)
{
return g_ConnectedControllers;
}
GLOBAL_ASM(
glabel contConsumeSamples
/* 14058: 27bdfff8 */ addiu $sp,$sp,-8
/* 1405c: afb00004 */ sw $s0,0x4($sp)
/* 14060: 8c8e01e0 */ lw $t6,0x1e0($a0)
/* 14064: 8c8f01e8 */ lw $t7,0x1e8($a0)
/* 14068: 24100014 */ addiu $s0,$zero,0x14
/* 1406c: 00001025 */ or $v0,$zero,$zero
/* 14070: ac8e01e4 */ sw $t6,0x1e4($a0)
/* 14074: ac8f01e0 */ sw $t7,0x1e0($a0)
/* 14078: 0002c040 */ sll $t8,$v0,0x1
.L0001407c:
/* 1407c: 00981821 */ addu $v1,$a0,$t8
/* 14080: a46001f0 */ sh $zero,0x1f0($v1)
/* 14084: a46001f8 */ sh $zero,0x1f8($v1)
/* 14088: 8c9901e0 */ lw $t9,0x1e0($a0)
/* 1408c: 8c8501e4 */ lw $a1,0x1e4($a0)
/* 14090: 3c18800a */ lui $t8,%hi(g_ContDisableCooldown)
/* 14094: 27189e68 */ addiu $t8,$t8,%lo(g_ContDisableCooldown)
/* 14098: 10b9005e */ beq $a1,$t9,.L00014214
/* 1409c: 24ae0001 */ addiu $t6,$a1,0x1
/* 140a0: 01d0001a */ div $zero,$t6,$s0
/* 140a4: 00023880 */ sll $a3,$v0,0x2
/* 140a8: 00003010 */ mfhi $a2
/* 140ac: 00e23823 */ subu $a3,$a3,$v0
/* 140b0: 00027880 */ sll $t7,$v0,0x2
/* 140b4: 01f86021 */ addu $t4,$t7,$t8
/* 140b8: 00073840 */ sll $a3,$a3,0x1
/* 140bc: 16000002 */ bnez $s0,.L000140c8
/* 140c0: 00000000 */ nop
/* 140c4: 0007000d */ break 0x7
.L000140c8:
/* 140c8: 2401ffff */ addiu $at,$zero,-1
/* 140cc: 16010004 */ bne $s0,$at,.L000140e0
/* 140d0: 3c018000 */ lui $at,0x8000
/* 140d4: 15c10002 */ bne $t6,$at,.L000140e0
/* 140d8: 00000000 */ nop
/* 140dc: 0006000d */ break 0x6
.L000140e0:
/* 140e0: 24cf0013 */ addiu $t7,$a2,0x13
.L000140e4:
/* 140e4: 01f0001a */ div $zero,$t7,$s0
/* 140e8: 0006c880 */ sll $t9,$a2,0x2
/* 140ec: 0326c823 */ subu $t9,$t9,$a2
/* 140f0: 0019c8c0 */ sll $t9,$t9,0x3
/* 140f4: 00997021 */ addu $t6,$a0,$t9
/* 140f8: 0000c010 */ mfhi $t8
/* 140fc: 0018c880 */ sll $t9,$t8,0x2
/* 14100: 0338c823 */ subu $t9,$t9,$t8
/* 14104: 01c74021 */ addu $t0,$t6,$a3
/* 14108: 0019c8c0 */ sll $t9,$t9,0x3
/* 1410c: 00997021 */ addu $t6,$a0,$t9
/* 14110: 95050000 */ lhu $a1,0x0($t0)
/* 14114: 16000002 */ bnez $s0,.L00014120
/* 14118: 00000000 */ nop
/* 1411c: 0007000d */ break 0x7
.L00014120:
/* 14120: 2401ffff */ addiu $at,$zero,-1
/* 14124: 16010004 */ bne $s0,$at,.L00014138
/* 14128: 3c018000 */ lui $at,0x8000
/* 1412c: 15e10002 */ bne $t7,$at,.L00014138
/* 14130: 00000000 */ nop
/* 14134: 0006000d */ break 0x6
.L00014138:
/* 14138: 01c77821 */ addu $t7,$t6,$a3
/* 1413c: 95e90000 */ lhu $t1,0x0($t7)
/* 14140: 947801f0 */ lhu $t8,0x1f0($v1)
/* 14144: 00a05025 */ or $t2,$a1,$zero
/* 14148: 0120c827 */ nor $t9,$t1,$zero
/* 1414c: 00b97024 */ and $t6,$a1,$t9
/* 14150: 030e7825 */ or $t7,$t8,$t6
/* 14154: 947901f8 */ lhu $t9,0x1f8($v1)
/* 14158: 00a0c027 */ nor $t8,$a1,$zero
/* 1415c: a46f01f0 */ sh $t7,0x1f0($v1)
/* 14160: 03097024 */ and $t6,$t8,$t1
/* 14164: 032e7825 */ or $t7,$t9,$t6
/* 14168: a46f01f8 */ sh $t7,0x1f8($v1)
/* 1416c: 8d8d0000 */ lw $t5,0x0($t4)
/* 14170: 01205825 */ or $t3,$t1,$zero
/* 14174: 59a00017 */ blezl $t5,.L000141d4
/* 14178: 8c8e01e0 */ lw $t6,0x1e0($a0)
/* 1417c: 95180000 */ lhu $t8,0x0($t0)
/* 14180: 57000012 */ bnezl $t8,.L000141cc
/* 14184: 25b9ffff */ addiu $t9,$t5,-1
/* 14188: 81050002 */ lb $a1,0x2($t0)
/* 1418c: 28a1000f */ slti $at,$a1,0xf
/* 14190: 5020000e */ beqzl $at,.L000141cc
/* 14194: 25b9ffff */ addiu $t9,$t5,-1
/* 14198: 28a1fff2 */ slti $at,$a1,-14
/* 1419c: 5420000b */ bnezl $at,.L000141cc
/* 141a0: 25b9ffff */ addiu $t9,$t5,-1
/* 141a4: 81050003 */ lb $a1,0x3($t0)
/* 141a8: 28a1000f */ slti $at,$a1,0xf
/* 141ac: 50200007 */ beqzl $at,.L000141cc
/* 141b0: 25b9ffff */ addiu $t9,$t5,-1
/* 141b4: 28a1fff2 */ slti $at,$a1,-14
/* 141b8: 54200004 */ bnezl $at,.L000141cc
/* 141bc: 25b9ffff */ addiu $t9,$t5,-1
/* 141c0: 10000003 */ b .L000141d0
/* 141c4: ad800000 */ sw $zero,0x0($t4)
/* 141c8: 25b9ffff */ addiu $t9,$t5,-1
.L000141cc:
/* 141cc: ad990000 */ sw $t9,0x0($t4)
.L000141d0:
/* 141d0: 8c8e01e0 */ lw $t6,0x1e0($a0)
.L000141d4:
/* 141d4: 50ce0010 */ beql $a2,$t6,.L00014218
/* 141d8: 24420001 */ addiu $v0,$v0,0x1
/* 141dc: 24cf0001 */ addiu $t7,$a2,0x1
/* 141e0: 01f0001a */ div $zero,$t7,$s0
/* 141e4: 00003010 */ mfhi $a2
/* 141e8: 16000002 */ bnez $s0,.L000141f4
/* 141ec: 00000000 */ nop
/* 141f0: 0007000d */ break 0x7
.L000141f4:
/* 141f4: 2401ffff */ addiu $at,$zero,-1
/* 141f8: 16010004 */ bne $s0,$at,.L0001420c
/* 141fc: 3c018000 */ lui $at,0x8000
/* 14200: 15e10002 */ bne $t7,$at,.L0001420c
/* 14204: 00000000 */ nop
/* 14208: 0006000d */ break 0x6
.L0001420c:
/* 1420c: 1000ffb5 */ b .L000140e4
/* 14210: 24cf0013 */ addiu $t7,$a2,0x13
.L00014214:
/* 14214: 24420001 */ addiu $v0,$v0,0x1
.L00014218:
/* 14218: 0002c600 */ sll $t8,$v0,0x18
/* 1421c: 00181603 */ sra $v0,$t8,0x18
/* 14220: 28410004 */ slti $at,$v0,0x4
/* 14224: 5420ff95 */ bnezl $at,.L0001407c
/* 14228: 0002c040 */ sll $t8,$v0,0x1
/* 1422c: 8fb00004 */ lw $s0,0x4($sp)
/* 14230: 03e00008 */ jr $ra
/* 14234: 27bd0008 */ addiu $sp,$sp,0x8
);
// Mismatch because goal calculates &g_ContDisableCooldown before the % 20 on
// the marked line, but the below does it after.
//void contConsumeSamples(struct contdata *contdata)
//{
// s8 i;
// s32 samplenum;
// u16 buttons1;
// u16 buttons2;
//
// contdata->curstart = contdata->curlast;
// contdata->curlast = contdata->nextlast;
//
// for (i = 0; i < 4; i++) {
// contdata->buttonspressed[i] = 0;
// contdata->buttonsreleased[i] = 0;
//
// if (contdata->curlast != contdata->curstart) {
// // Mismatch here
// samplenum = (contdata->curstart + 1) % 20;
//
// while (true) {
// buttons1 = contdata->samples[samplenum].pads[i].button;
// buttons2 = contdata->samples[(samplenum + 19) % 20].pads[i].button;
//
// contdata->buttonspressed[i] |= buttons1 & ~buttons2;
// contdata->buttonsreleased[i] |= ~buttons1 & buttons2;
//
// if (g_ContDisableCooldown[i] > 0) {
// if (contdata->samples[samplenum].pads[i].button == 0
// && contdata->samples[samplenum].pads[i].stick_x < 15
// && contdata->samples[samplenum].pads[i].stick_x > -15
// && contdata->samples[samplenum].pads[i].stick_y < 15
// && contdata->samples[samplenum].pads[i].stick_y > -15) {
// g_ContDisableCooldown[i] = 0;
// } else {
// g_ContDisableCooldown[i]--;
// }
// }
//
// if (samplenum == contdata->curlast) {
// break;
// }
//
// samplenum = (samplenum + 1) % 20;
// }
// }
// }
//}
/**
* The use of the static variable suggests that the function is able to be
* called recursively, but its behaviour should not be run when recursing.
*/
void func00014238(void)
{
static bool doingit = false;
s32 i;
if (doingit == false) {
doingit = true;
for (i = 0; i < 4; i++) {
if (func000155f4(i) == 13) {
func0f116db0(i, 11);
}
}
if (var8005eec4 == NULL) {
func0001561c();
}
doingit = false;
}
}
u32 var8005ef08 = 0;
void contDebugJoy(void)
{
func0000db30("debugjoy", &var8005ef08);
if (g_Vars.paksconnected) {
contCheckPfs(1);
}
if (var8005eec4) {
g_ContData[1].nextlast = var8005eec4(g_ContData[1].samples, g_ContData[1].curlast);
contConsumeSamples(&g_ContData[1]);
}
contConsumeSamples(&g_ContData[0]);
if (var8005eec8) {
var8005eec8(g_ContData[0].samples, g_ContData[0].curstart, g_ContData[0].curlast);
}
if (func000150c4() && var8005eec0 && contGetNumSamples() <= 0) {
func000150e8();
#if VERSION >= VERSION_NTSC_FINAL
func00014238();
func00015144();
contConsumeSamples(&g_ContData[0]);
#else
func00015144();
contConsumeSamples(&g_ContData[0]);
func00014238();
#endif
}
}
const char var700540b4[] = "JOY : g_EnableCyclicPolling=%d";
const char var700540d4[] = "JOY : g_JoyReCheckInterval=%d";
const char var700540f4[] = "JOY : g_JoyReCheckEventIn=%d";
const char var70054114[] = "JOY : g_JoyRecheckDone=%d";
const char var70054130[] = "osContStartReadData -> Failed - CONT_NO_RESPONSE_ERROR\n";
const char var70054168[] = "osContStartReadData -> Failed - CONT_OVERRUN_ERROR\n";
const char var7005419c[] = "joyTickRetrace:joy%derrno%d->%d\n";
const char var700541c0[] = "joyTickRetrace:joy%derrno%d->%d\n";
s32 contStartReadData(OSMesgQueue *mq)
{
return osContStartReadData(mq);
}
void contReadData(void)
{
s32 index = (g_ContData[0].nextlast + 1) % 20;
if (index == g_ContData[0].curstart) {
// If the sample queue is full, don't overwrite the oldest sample.
// Instead, overwrite the most recent.
index = g_ContData[0].nextlast;
}
osContGetReadData(g_ContData[0].samples[index].pads);
g_ContData[0].nextlast = index;
g_ContData[0].nextsecondlast = (g_ContData[0].nextlast + 19) % 20;
}
void contPoll(void)
{
OSMesg msg;
s8 i;
if (osRecvMesg(&var80099ec0, &msg, OS_MESG_NOBLOCK) == 0) {
if (g_ContBusy) {
osRecvMesg(&var80099e78, &msg, OS_MESG_BLOCK);
g_ContBusy = false;
contReadData();
// Check if error state has changed for any controller
for (i = 0; i < 4; i++) {
if ((g_ContData[0].samples[g_ContData[0].nextlast].pads[i].errno == 0 && g_ContData[0].samples[g_ContData[0].nextsecondlast].pads[i].errno != 0)
|| (g_ContData[0].samples[g_ContData[0].nextlast].pads[i].errno != 0 && g_ContData[0].samples[g_ContData[0].nextsecondlast].pads[i].errno == 0)) {
func00013e84();
break;
}
}
}
osSendMesg(&var80099ee0, &msg, OS_MESG_NOBLOCK);
var8005ee68++;
contCheckPfs(0);
return;
}
if (osRecvMesg(&var80099f00, &msg, OS_MESG_NOBLOCK) == 0) {
var8005ee68--;
if (var8005ee68 == 0) {
contStartReadData(&var80099e78);
g_ContBusy = true;
}
osSendMesg(&var80099f20, &msg, OS_MESG_NOBLOCK);
return;
}
if (g_ContInitDone) {
if (var8005ee68) {
contCheckPfs(0);
return;
}
if (osRecvMesg(&var80099e78, &msg, OS_MESG_NOBLOCK) == 0) {
static s32 count = 0;
g_ContBusy = false;
contReadData();
// Check if error state has changed for any controller
for (i = 0; i < 4; i++) {
if ((g_ContData[0].samples[g_ContData[0].nextlast].pads[i].errno == 0 && g_ContData[0].samples[g_ContData[0].nextsecondlast].pads[i].errno != 0)
|| (g_ContData[0].samples[g_ContData[0].nextlast].pads[i].errno != 0 && g_ContData[0].samples[g_ContData[0].nextsecondlast].pads[i].errno == 0)) {
func00013e84();
break;
}
}
func00014238();
contCheckPfs(0);
contStartReadData(&var80099e78);
g_ContBusy = true;
count++;
if (count >= 60) {
s32 i;
for (i = 0; i < 4; i++) {
if (g_ContBadReadsStickX[i] || g_ContBadReadsStickY[i] || g_ContBadReadsButtons[i] || g_ContBadReadsButtonsPressed[i]) {
g_ContBadReadsStickX[i] = 0;
g_ContBadReadsStickY[i] = 0;
g_ContBadReadsButtons[i] = 0;
g_ContBadReadsButtonsPressed[i] = 0;
}
}
count = 0;
}
}
}
}
void func00014810(bool value)
{
var8005eec0 = value;
}
s32 contGetNumSamples(void)
{
return (g_ContDataPtr->curlast - g_ContDataPtr->curstart + 20) % 20;
}
s32 contGetStickXOnSample(s32 samplenum, s8 contpadnum)
{
if (g_ContDataPtr->unk200 < 0 && (g_ConnectedControllers >> contpadnum & 1) == 0) {
g_ContBadReadsStickX[contpadnum]++;
return 0;
}
if (g_ContDisableCooldown[contpadnum] > 0) {
return 0;
}
return g_ContDataPtr->samples[(g_ContDataPtr->curstart + samplenum + 1) % 20].pads[contpadnum].stick_x;
}
s32 contGetStickYOnSample(s32 samplenum, s8 contpadnum)
{
if (g_ContDataPtr->unk200 < 0 && (g_ConnectedControllers >> contpadnum & 1) == 0) {
g_ContBadReadsStickY[contpadnum]++;
return 0;
}
if (g_ContDisableCooldown[contpadnum] > 0) {
return 0;
}
return g_ContDataPtr->samples[(g_ContDataPtr->curstart + samplenum + 1) % 20].pads[contpadnum].stick_y;
}
s32 contGetStickYOnSampleIndex(s32 samplenum, s8 contpadnum)
{
if (g_ContDataPtr->unk200 < 0 && (g_ConnectedControllers >> contpadnum & 1) == 0) {
g_ContBadReadsStickY[contpadnum]++;
return 0;
}
if (g_ContDisableCooldown[contpadnum] > 0) {
return 0;
}
return g_ContDataPtr->samples[(g_ContDataPtr->curstart + samplenum) % 20].pads[contpadnum].stick_y;
}
u16 contGetButtonsOnSample(s32 samplenum, s8 contpadnum, u16 mask)
{
u16 button;
if (g_ContDataPtr->unk200 < 0 && (g_ConnectedControllers >> contpadnum & 1) == 0) {
g_ContBadReadsButtons[contpadnum]++;
return 0;
}
if (g_ContDisableCooldown[contpadnum] > 0) {
return 0;
}
button = g_ContDataPtr->samples[(g_ContDataPtr->curstart + samplenum + 1) % 20].pads[contpadnum].button;
return button & mask;
}
u16 contGetButtonsPressedOnSample(s32 samplenum, s8 contpadnum, u16 mask)
{
u16 button1;
u16 button2;
if (g_ContDataPtr->unk200 < 0 && (g_ConnectedControllers >> contpadnum & 1) == 0) {
g_ContBadReadsButtonsPressed[contpadnum]++;
return 0;
}
if (g_ContDisableCooldown[contpadnum] > 0) {
return 0;
}
button1 = g_ContDataPtr->samples[(g_ContDataPtr->curstart + samplenum + 1) % 20].pads[contpadnum].button;
button2 = g_ContDataPtr->samples[(g_ContDataPtr->curstart + samplenum) % 20].pads[contpadnum].button;
return (button1 & ~button2) & mask;
}
/**
* Count the number of times the buttons specified by mask were held during the
* specific samples given in checksamples.
*
* For example, if checksamples[5] is nonzero and a button was pressed on
* samplenum 5 which matches the mask, count is incremented.
*/
s32 contCountButtonsOnSpecificSamples(u32 *checksamples, s8 contpadnum, u16 mask)
{
s32 count = 0;
s32 index = 0;
s32 i;
u16 button;
if (g_ContDataPtr->unk200 < 0 && (g_ConnectedControllers >> contpadnum & 1) == 0) {
g_ContBadReadsButtons[contpadnum]++;
return 0;
}
if (g_ContDisableCooldown[contpadnum] > 0) {
return 0;
}
i = (g_ContDataPtr->curstart + 1) % 20;
while (true) {
if (checksamples == NULL || checksamples[index]) {
button = g_ContDataPtr->samples[i].pads[contpadnum].button;
if (button & mask) {
count++;
}
}
if (i == g_ContDataPtr->curlast) {
break;
}
i = (i + 1) % 20;
index++;
}
return count;
}
s8 contGetStickX(s8 contpadnum)
{
if (g_ContDataPtr->unk200 < 0 && (g_ConnectedControllers >> contpadnum & 1) == 0) {
g_ContBadReadsStickX[contpadnum]++;
return 0;
}
if (g_ContDisableCooldown[contpadnum] > 0) {
return 0;
}
return g_ContDataPtr->samples[g_ContDataPtr->curlast].pads[contpadnum].stick_x;
}
s8 contGetStickY(s8 contpadnum)
{
if (g_ContDataPtr->unk200 < 0 && (g_ConnectedControllers >> contpadnum & 1) == 0) {
g_ContBadReadsStickY[contpadnum]++;
return 0;
}
if (g_ContDisableCooldown[contpadnum] > 0) {
return 0;
}
return g_ContDataPtr->samples[g_ContDataPtr->curlast].pads[contpadnum].stick_y;
}
u16 contGetButtons(s8 contpadnum, u16 mask)
{
if (g_ContDataPtr->unk200 < 0 && (g_ConnectedControllers >> contpadnum & 1) == 0) {
g_ContBadReadsButtons[contpadnum]++;
return 0;
}
if (g_ContDisableCooldown[contpadnum] > 0) {
return 0;
}
return g_ContDataPtr->samples[g_ContDataPtr->curlast].pads[contpadnum].button & mask;
}
u16 contGetButtonsPressedThisFrame(s8 contpadnum, u16 mask)
{
if (g_ContDataPtr->unk200 < 0 && (g_ConnectedControllers >> contpadnum & 1) == 0) {
g_ContBadReadsButtonsPressed[contpadnum]++;
return 0;
}
if (g_ContDisableCooldown[contpadnum] > 0) {
return 0;
}
return g_ContDataPtr->buttonspressed[contpadnum] & mask;
}
s32 func000150c4(void)
{
return var8005eebc ? false : true;
}
void func000150e8(void)
{
OSMesg msg;
if (var8005eebc == 0) {
osSendMesg(&var80099ec0, &msg, OS_MESG_NOBLOCK);
osRecvMesg(&var80099ee0, &msg, OS_MESG_BLOCK);
}
var8005eebc++;
}
void func00015144(void)
{
OSMesg msg;
var8005eebc--;
if (var8005eebc == 0) {
osSendMesg(&var80099f00, &msg, OS_MESG_NOBLOCK);
osRecvMesg(&var80099f20, &msg, OS_MESG_BLOCK);
}
}
void func0001519c(void)
{
s32 i;
osCreateMesgQueue(&var80099e78, &var80099e90, 10);
osSetEventMesg(OS_EVENT_SI, &var80099e78, 0);
for (i = 0; i < 4; i++) {
if (!func0004f854(&var80099e78, (i == 4 ? NULL : &var800a3180[i]), i)) {
func0004f5e0((i == 4 ? NULL : &var800a3180[i]), 0);
func0004f5e0((i == 4 ? NULL : &var800a3180[i]), 0);
func0004f5e0((i == 4 ? NULL : &var800a3180[i]), 0);
}
}
}
void func000152d0(s8 playernum, s32 *arg1, s32 *arg2)
{
if (g_Vars.normmplayerisrunning) {
*arg1 = g_Vars.playerstats[playernum].mpindex;
*arg2 = -1;
return;
}
*arg1 = playernum;
if (g_MpPlayers[g_Vars.playerstats[playernum].mpindex].base.controlmode >= CONTROLMODE_21) {
*arg2 = PLAYERCOUNT() + playernum;
return;
}
*arg2 = -1;
}
void func000153c4(s8 arg0, s32 arg1)
{
u32 stack;
if (arg0 != 4) {
if (var800a2380[arg0].unk000 != 2 && var800a2380[arg0].unk000 != 3) {
if (arg1) {
func000150e8();
}
if (func0004f854(&var80099e78, arg0 == 4 ? NULL : &var800a3180[arg0], arg0) == 0) {
func0004f5e0(arg0 == 4 ? NULL : &var800a3180[arg0], 0);
func0004f5e0(arg0 == 4 ? NULL : &var800a3180[arg0], 0);
func0004f5e0(arg0 == 4 ? NULL : &var800a3180[arg0], 0);
}
if (arg1) {
func00015144();
}
if (var800a2380[arg0].unk004 != 6 && var800a2380[arg0].unk004 != 7) {
var800a2380[arg0].unk004 = 5;
}
var800a2380[arg0].unk2b4 = -1;
}
}
if (arg0) {
// empty
}
}
s32 func000155b4(s8 index)
{
return var800a2380[index].unk010;
}
s32 func000155f4(s8 index)
{
return func000155b4(index);
}
void func0001561c(void)
{
s32 i;
for (i = 0; i < 4; i++) {
if (var800a2380[i].unk010 == 11 && var800a2380[i].unk000 == 1) {
switch (var800a2380[i].unk004) {
case 3:
var800a2380[i].unk004 = 4;
func0004f5e0(i == 4 ? NULL : &var800a3180[i], 1);
break;
case 4:
if (var800a2380[i].unk284 != -1) {
if (var800a2380[i].unk28c == 0) {
func0004f5e0(i == 4 ? NULL : &var800a3180[i], 1);
} else if (var800a2380[i].unk284 == var800a2380[i].unk28c) {
func0004f5e0(i == 4 ? NULL : &var800a3180[i], 0);
}
var800a2380[i].unk28c++;
if (var800a2380[i].unk288 == var800a2380[i].unk28c) {
var800a2380[i].unk28c = 0;
}
}
var800a2380[i].unk2b4--;
if (var800a2380[i].unk2b4 < 0) {
var800a2380[i].unk004 = 5;
}
break;
case 5:
var800a2380[i].unk004 = 2;
func0004f5e0(i == 4 ? NULL : &var800a3180[i], 0);
break;
case 6:
func0004f5e0(i == 4 ? NULL : &var800a3180[i], 0);
var800a2380[i].unk004 = 7;
break;
case 8:
var800a2380[i].unk004 = 2;
var800a2380[i].unk2b4 = -1;
break;
}
}
}
}