Files
Diddy-Kong-Racing/src/save_data.c
T
FazanaandGitHub 83f9b88e86 Further gfx matches (#288)
* match func_800A4154

* match func_800A497C

* nonmatching func_800A8474

* match func_800A3884

* Update game_ui.h

* quick fixes

* match func_800A4F50 and func_800A45F0

* Update game_ui.h

* prelim

* match func_8009CD7C and func_800AAFD0

* nonmatching func_800AC5A4

* warning

* smilng emote

* match func_800AC5A4

* Update weather.h

* Update weather.c

* fix a buncha warnings

* Update game_ui.c

* match func_80092E94

* I know what menu_5 is now :)

* Update game_ui.c

* Update menu.c

* match func_80068514

* match func_800B695C and func_800B69FC

* match func_8000FC6C

* quick fixes

* match func_80072718

* f

* fixing particles.c

* match print_debug_strings and render_3d_billboard

* Update objects.c

* Update printf.c

* name a few vars

* match func_80011960

* match func_8002D670

* match render_floor_decal

* Update unknown_0255E0.c

* style fix

* warning sweep

* Update unknown_0255E0.c

* match func_8002AC00

* Update save_data.c

* quick fixes

* FIX BUILD

* Update unknown_0255E0.c

* screaming and paining
2022-11-17 22:25:32 +00:00

1460 lines
44 KiB
C

/* The comment below is needed for this file to be picked up by generate_ld */
/* RAM_POS: 0x80072250 */
#include "save_data.h"
#include "memory.h"
#include "PR/pfs.h"
#include "PR/os_cont.h"
#include "macros.h"
#include "structs.h"
#include "camera.h"
#include "objects.h"
#include "game.h"
#include "unknown_0CEC50.h"
/************ .data ************/
s8 *D_800DE440 = 0;
u8 gN64FontCodes[] = "\0 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#'*+,-./:=?@";
u8 sControllerPaksPresent = 0; // Bits 0, 1, 2, and 3 of the bit pattern correspond to Controllers 1, 2, 3, and 4. 1 if a controller pak is present
s32 D_800DE48C = 0;
/*******************************/
/************ .rodata ************/
const char D_800E7590[] = "Region = %d loc = %x size = %x\t";
const char D_800E75B4[] = "FREE";
const char D_800E75BC[] = "ALLOCATED";
const char D_800E75C8[] = "ALLOCATED,FIXED";
const char D_800E75D8[] = "\n";
const char D_800E75DC[] = "\n";
const char D_800E75E0[] = "Region number = %d\t";
const char D_800E75F4[] = "maxSlots = %d\t";
const char D_800E7604[] = "slotsUsed = %d\t";
const char D_800E7614[] = "loc = %x\t";
const char D_800E7620[] = "size = %x\n";
const char D_800E762C[] = "\n";
const char D_800E7630[] = "DKRACING-ADV";
const char D_800E7640[] = "DKRACING-ADV";
const char D_800E7650[] = "DKRACING-TIMES";
const char D_800E7660[] = "DKRACING-TIMES";
const char D_800E7670[] = "DKRACING-ADV";
const char D_800E7680[] = "DKRACING-ADV";
const char D_800E7690[] = "DKRACING-TIMES";
const char D_800E76A0[] = "DKRACING-TIMES";
const char D_800E76B0[] = "WARNING : No Eprom\n";
const char D_800E76C4[] = "WARNING : No Eprom\n";
const char D_800E76D8[] = "WARNING : No Eprom\n";
const char D_800E76EC[] = "WARNING : No Eprom\n";
const char D_800E7700[] = "WARNING : No Eprom\n";
const char D_800E7714[] = "WARNING : No Eprom\n";
const char D_800E7728[] = "WARNING : No Eprom\n";
const char D_800E773C[] = "DKRACING-GHOSTS"; // Used in func_80074B34
const u8 D_800E774C[4] = { 0, 0, 0, 0 }; // Used in func_80074B34, but I'm confused to what this is for.
const char D_800E7750[] = "warning: corrupt ghost\n";
/*********************************/
/************ .bss ************/
OSMesgQueue *sControllerMesgQueue;
s32 D_80124014;
OSPfs pfs[MAXCONTROLLERS];
/* Size: 0xA bytes */
typedef struct unk_801241B8 {
/* 0x00 */ s16 unk0;
/* 0x02 */ s16 unk2;
/* 0x04 */ s16 unk4;
/* 0x06 */ s16 unk6;
/* 0x08 */ s16 unk8;
} unk_801241B8;
unk_801241B8 D_801241B8[MAXCONTROLLERS];
s16 *sUnkMiscAsset19; //Misc Asset 19
/**
* Values for Misc Asset 19
* 00 2D 00 12
* 00 46 00 0A
* 00 3C 00 3C
* 00 64 00 0F
* 00 3C 00 36
* 00 32 00 0F
* 00 32 00 34
* 00 46 00 3C
* 00 55 00 3C
* 00 46 00 16
* 00 50 00 4B
* 00 64 00 0C
* 00 3C 00 18
* 00 50 00 1E
* 00 64 00 2A
* 00 32 00 3C
* 00 28 00 0A
* 00 28 00 0A
* 00 64 00 0F
**/
u8 D_801241E4;
u8 sRumblePaksPresent; // Bits 0, 1, 2, and 3 of the bit pattern correspond to Controllers 1, 2, 3, and 4. 1 if a rumble pak is present
u8 D_801241E6;
u8 D_801241E7;
s32 gRumbleDetectionTimer;
s8 *D_801241EC;
s32 D_801241F0;
s32 D_801241F4;
/*******************************/
// Guessing, but maybe this gets player id from controller index,
// but it might check for something like jointventure and will return
// the same value for controllers one and two?
u8 func_80072250(s32 arg0) {
if ((arg0 == 0 || arg0 == 1) && func_8000E158()) {
arg0 = 1 - arg0;
}
return get_player_id(arg0);
}
void func_80072298(u8 arg0) {
D_801241E4 = arg0;
if (arg0 != 0) {
gRumbleDetectionTimer = 0x79;
D_801241E6 = 0xF;
return;
}
func_80072708();
}
UNUSED s32 func_800722E8(s16 controllerIndex) {
s32 temp;
if (controllerIndex < 0 || controllerIndex >= 4) {
return 0;
}
temp = ((1 << func_80072250(controllerIndex)) & 0xFF);
return sRumblePaksPresent & temp;
}
void func_80072348(s16 controllerIndex, u8 arg1) {
s32 index;
if (arg1 < 19 && controllerIndex >= 0 && controllerIndex < 4) {
index = (func_80072250(controllerIndex)) & 0xFFFF;
if (D_801241B8[index].unk0 == arg1) {
if (D_801241B8[index].unk8 < 0) {
D_801241B8[index].unk8 = -300;
}
D_801241B8[index].unk4 = sUnkMiscAsset19[(arg1 * 2) + 1];
} else {
D_801241B8[index].unk0 = arg1;
if (sUnkMiscAsset19[arg1 * 2] != 0) {
func_80072578(controllerIndex, sUnkMiscAsset19[arg1 * 2], sUnkMiscAsset19[(arg1 * 2) + 1]);
}
}
}
}
void func_80072424(s16 controllerIndex, u8 arg1, f32 arg2) {
s32 index;
if (arg1 < 19 && controllerIndex >= 0 && controllerIndex < 4) {
index = func_80072250(controllerIndex) & 0xFFFF;
if (arg1 == D_801241B8[index].unk0) {
if (D_801241B8[index].unk8 < 0) {
D_801241B8[index].unk8 = -300;
}
D_801241B8[index].unk4 = sUnkMiscAsset19[(arg1 * 2) + 1];
} else {
if (arg2 < 0.0f) {
arg2 = 0.0f;
}
if (arg2 > 1.0f) {
arg2 = 1.0f;
}
D_801241B8[index].unk0 = arg1;
if (sUnkMiscAsset19[arg1 * 2] != 0) {
func_80072578(controllerIndex, (sUnkMiscAsset19[arg1 * 2] * arg2), sUnkMiscAsset19[(arg1 * 2) + 1]);
}
}
}
}
void func_80072578(s16 controllerIndex, s16 arg1, s16 arg2) {
s16 index;
u8 new_var;
if (D_801241E4 != 0 && controllerIndex >= 0 && controllerIndex < 4) {
new_var = func_80072250(controllerIndex);
index = 0xFFFF;
index = index & new_var;
new_var = 1 << index;
D_801241E6 |= new_var;
D_801241E7 &= ~new_var;
D_801241B8[index].unk6 = ((arg1 * arg1) * 0.1);
D_801241B8[index].unk2 = ((arg1 * arg1) * 0.1);
D_801241B8[index].unk4 = arg2;
}
}
UNUSED void func_8007267C(s16 controllerIndex) {
s16 index;
if (controllerIndex >= 0 && controllerIndex < 4) {
index = func_80072250(controllerIndex);
D_801241E7 |= 1 << index;
D_801241B8[index].unk4 = -1;
D_801241B8[index].unk0 = -1;
D_801241B8[index].unk8 = 0;
}
}
void func_80072708(void) {
D_800DE48C = 3;
}
void rumble_controllers(s32 arg0) {
unk_801241B8 *temp;
s32 pfsStatus;
u8 i;
u8 controllerToCheck;
u8 pfsBitPattern;
if ((D_801241E6 != 0) || ((D_800DE48C != 0))) {
gRumbleDetectionTimer += arg0;
if (gRumbleDetectionTimer >= 121) {
gRumbleDetectionTimer = 0;
osPfsIsPlug(sControllerMesgQueue, &pfsBitPattern);
for (i = 0, controllerToCheck = 1; i < MAXCONTROLLERS; i++, controllerToCheck <<= 1) {
if ((pfsBitPattern & controllerToCheck) && !(~D_801241E6 & sRumblePaksPresent & controllerToCheck)) {
if (osMotorInit(sControllerMesgQueue, &pfs[i], i) != 0) {
D_801241E6 &= ~controllerToCheck;
D_801241E7 &= ~controllerToCheck;
sRumblePaksPresent &= ~controllerToCheck;
} else {
sRumblePaksPresent |= controllerToCheck;
}
}
}
}
if ((sRumblePaksPresent != 0) || (D_800DE48C != 0)) {
pfsStatus = 0;
if (D_800DE48C != 0) {
osPfsIsPlug(sControllerMesgQueue, &pfsBitPattern);
}
for (i = 0, controllerToCheck = 1, temp = D_801241B8; i < MAXCONTROLLERS; i++, controllerToCheck <<= 1, temp++) {
if (D_800DE48C != 0) {
temp->unk0 = temp->unk6 = temp->unk4 = -1;
if (!(pfsBitPattern & controllerToCheck)) {
continue;
} else if (osMotorInit(sControllerMesgQueue, &pfs[i], i) == 0) {
osMotorStop(&pfs[i]);
}
} else if (D_801241E6 & sRumblePaksPresent & controllerToCheck) {
if (temp->unk4 <= 0) {
D_801241E6 &= ~controllerToCheck;
temp->unk0 = -1;
temp->unk8 = 0;
osMotorStop(&pfs[i]);
} else {
temp->unk4 -= arg0;
temp->unk8 += arg0;
if (temp->unk8 < 0) {
continue;
} else if (temp->unk8 >= 601) {
D_801241E6 &= ~controllerToCheck;
temp->unk0 = -1;
temp->unk8 = -300;
osMotorStop(&pfs[i]);
} else {
if (temp->unk2 > 490.0) {
if (!(D_801241E7 & controllerToCheck)) {
pfsStatus |= osMotorStart(&pfs[i]);
D_801241E7 |= controllerToCheck;
}
} else if (temp->unk2 < 3.6) {
if (D_801241E7 & controllerToCheck) {
pfsStatus |= osMotorStop(&pfs[i]);
D_801241E7 &= ~controllerToCheck;
}
} else if (temp->unk6 >= 256) {
if (!(D_801241E7 & controllerToCheck)) {
pfsStatus |= osMotorStart(&pfs[i]);
D_801241E7 |= controllerToCheck;
}
temp->unk6 -= 256;
} else {
if (D_801241E7 & controllerToCheck) {
pfsStatus |= osMotorStop(&pfs[i]);
D_801241E7 &= ~controllerToCheck;
}
temp->unk6 += temp->unk2 + 4;
}
if (1) { } // fakematch
}
}
}
}
if (pfsStatus != 0) {
sRumblePaksPresent = 0;
}
if (D_800DE48C != 0) {
D_800DE48C--;
}
}
}
}
#ifdef NON_EQUIVALENT
u16 func_80072C54(s32 arg0) {
// v0 v1 a1 a2 a3 t0 t1 t2 t3 t4 t5 t6 t7 t8
u32 v0;
u32 v1;
s32 a1;
u32 a2;
u8 *a3;
s32 t0;
u32 *t1;
u32 *t2;
u8 **t3;
u32 t4;
u32 t5;
u32 t6;
u32 t7;
u32 t8;
u32 t9;
v1 = 0;
if (arg0 <= 0) {
return v1;
}
// L80072C64
v0 = 1 << (arg0 + 0x1F);
if (arg0 != 0) {
a1 = -(arg0 & 3);
t0 = a1 + arg0;
if (a1 != 0) {
// L80072CA0
do {
a2 = D_801241F4;
a1 = arg0 - 1;
t6 = v0 >> 1;
if (a2 == 0) {
a3 = D_801241EC;
a2 = 0x80;
t8 = *a3;
D_801241EC = a3 + 1;
D_801241F4 = 0x80;
D_801241F0 = t8;
}
// L80072CCC
arg0 = a1;
if (D_801241F0 & a2 != 0) {
v1 |= v0;
}
// L80072CE4
v0 = t6;
D_801241F4 = a2 >> 1;
} while (t0 != a1);
if (a1 == 0) {
return v1; // should jump to end
}
}
// L80072CF4
t1 = &D_801241F4;
t2 = &D_801241F0;
t3 = &D_801241EC;
t4 = 128;
// L80072D10
do {
a2 = *t1;
t6 = v0 >> 1;
arg0 -= 4;
if (a2 == 0) {
a3 = *t3;
a2 = t4;
t9 = *a3;
*t3 = a3 + 1;
*t1 = t4;
*t2 = t9;
}
// L80072D3C
a1 = *t2;
t8 = a2 << 1;
t7 = a1 & a2;
a2 = t8;
if (t7 != 0) {
v1 |= v0;
}
// L80072D54
v0 = t6;
*t1 = t8;
if (t8 == 0) {
a3 = *t3;
a2 = t4;
a1 = *a3;
*t3 = a3 + 1;
*t1 = t4;
*t2 = a1;
}
// L80072D7C
t7 = a1 & a2;
t6 = v0 >> 1;
if (t7 != 0) {
v1 |= v0;
}
// L80072D8C
t8 = a2 >> 1;
*t1 = t8;
a2 = t8;
v0 = t6;
if (t8 == 0) {
a3 = *t3;
a2 = t4;
a1 = *a3;
*t3 = a3 + 1;
*t1 = t4;
*t2 = a1;
}
// L80072DBC
t7 = a1 & a2;
t6 = v0 >> 1;
if (t7 != 0) {
v1 |= v0;
}
// L80072DCC
t8 = a2 >> 1;
*t1 = t8;
a2 = t8;
v0 = t6;
if (t8 == 0) {
a3 = *t3;
a2 = t4;
a1 = *a3;
*t3 = a3 + 1;
*t1 = t4;
*t2 = a1;
}
// L80072DFC
t7 = a1 & a2;
t6 = v0 >> 1;
if (t7 != 0) {
v1 |= v0;
}
// L80072E0C
t8 = a2 >> 1;
*t1 = t8;
v0 = t6;
} while (arg0 != 0);
}
// L80072E1C
return v1;
}
#else
GLOBAL_ASM("asm/non_matchings/save_data/func_80072C54.s")
#endif
GLOBAL_ASM("asm/non_matchings/save_data/func_80072E28.s")
GLOBAL_ASM("asm/non_matchings/save_data/func_8007306C.s")
GLOBAL_ASM("asm/non_matchings/save_data/func_800732E8.s")
//arg1 is eepromData, from read_eeprom_data
//arg2 seems to be a flag for either lap times or course initials?
GLOBAL_ASM("asm/non_matchings/save_data/func_80073588.s")
GLOBAL_ASM("asm/non_matchings/save_data/func_800738A4.s")
s32 get_game_data_file_size(void) {
return 256;
}
s32 get_time_data_file_size(void) {
return 512;
}
//Probably get_file_extension
//func_80073C5C(s32 controllerIndex, s32 fileType, char **fileExt);
GLOBAL_ASM("asm/non_matchings/save_data/func_80073C5C.s")
//Read DKRACING-ADV data into settings?
s32 read_game_data_from_controller_pak(s32 controllerIndex, char *fileExt, Settings *settings) {
s32 *alloc;
s32 ret;
s32 fileNumber;
s32 fileSize;
//Initialize controller pak
ret = get_si_device_status(controllerIndex);
if (ret != CONTROLLER_PAK_GOOD) {
start_reading_controller_data(controllerIndex);
return (controllerIndex << 30) | ret;
}
//D_800E7670 = "DKRACING-ADV"
ret = get_file_number(controllerIndex, (char *)D_800E7670, fileExt, &fileNumber);
if (ret == CONTROLLER_PAK_GOOD) {
ret = get_file_size(controllerIndex, fileNumber, &fileSize);
if (fileSize == 0) {
ret = CONTROLLER_PAK_BAD_DATA;
}
if (ret == CONTROLLER_PAK_GOOD) {
alloc = allocate_from_main_pool_safe(fileSize, COLOUR_TAG_BLACK);
ret = read_data_from_controller_pak(controllerIndex, fileNumber, (u8 *)alloc, fileSize);
if (ret == CONTROLLER_PAK_GOOD) {
if (*alloc == GAMD) {
func_8007306C(settings, (s32) (alloc + 1));
if (settings->newGame != 0) {
ret = CONTROLLER_PAK_CHANGED;
}
}
else {
ret = CONTROLLER_PAK_BAD_DATA;
}
}
free_from_memory_pool(alloc);
}
}
start_reading_controller_data(controllerIndex);
if (ret != CONTROLLER_PAK_GOOD) {
ret |= (controllerIndex << 30);
}
return ret;
}
s32 write_game_data_to_controller_pak(s32 controllerIndex, Settings *arg1) {
UNUSED s32 pad;
char *fileExt;
u8 *gameData; //Probably a struct where the first s32 is GAMD
s32 ret;
s32 fileSize;
fileSize = get_game_data_file_size(); // 256 bytes
gameData = allocate_from_main_pool_safe(fileSize, COLOUR_TAG_WHITE);
*((s32 *)gameData) = GAMD;
func_800732E8(arg1, gameData + 4);
ret = func_80073C5C(controllerIndex, 3, &fileExt);
if (ret == CONTROLLER_PAK_GOOD) {
// D_800E7680 = DKRACING-ADV
ret = write_controller_pak_file(controllerIndex, -1, (char *) D_800E7680, (char *)&fileExt, gameData, fileSize);
}
free_from_memory_pool(gameData);
if (ret != CONTROLLER_PAK_GOOD) {
ret |= (controllerIndex << 30);
}
return ret;
}
//Read time data from controller pak into settings
s32 read_time_data_from_controller_pak(s32 controllerIndex, char *fileExt, Settings *settings) {
s32 *cpakData;
s32 status;
s32 fileNumber;
s32 fileSize;
status = get_si_device_status(controllerIndex);
if (status != CONTROLLER_PAK_GOOD) {
start_reading_controller_data(controllerIndex);
return (controllerIndex << 30) | status;
}
//D_800E7690 = DKRACING-TIMES
status = get_file_number(controllerIndex, (char *)D_800E7690, fileExt, &fileNumber);
if (status == CONTROLLER_PAK_GOOD) {
status = get_file_size(controllerIndex, fileNumber, &fileSize);
if (fileSize == 0) {
status = CONTROLLER_PAK_BAD_DATA;
}
if (status == CONTROLLER_PAK_GOOD) {
cpakData = allocate_from_main_pool_safe(fileSize, COLOUR_TAG_BLACK);
status = read_data_from_controller_pak(controllerIndex, fileNumber, (u8 *)cpakData, fileSize);
if (status == CONTROLLER_PAK_GOOD) {
if (*cpakData == TIMD) {
func_80073588(settings, (u64 *) (cpakData + 1), 3);
} else {
status = CONTROLLER_PAK_BAD_DATA;
}
}
free_from_memory_pool(cpakData);
}
}
start_reading_controller_data(controllerIndex);
if (status != CONTROLLER_PAK_GOOD) {
status |= (controllerIndex << 30);
}
return status;
}
s32 write_time_data_to_controller_pak(s32 controllerIndex, Settings *arg1) {
u8 *timeData; //Should probably be a struct or maybe an array?
s32 ret;
s32 fileSize;
UNUSED s32 pad;
char *fileExt;
fileSize = get_time_data_file_size(); // 512 bytes
timeData = allocate_from_main_pool_safe(fileSize, COLOUR_TAG_WHITE);
*((s32 *)timeData) = TIMD;
func_800738A4(arg1, timeData + 4);
ret = func_80073C5C(controllerIndex, 4, &fileExt);
if (ret == CONTROLLER_PAK_GOOD) {
//D_800E76A0 = DKRACING-TIMES
ret = write_controller_pak_file(controllerIndex, -1, (char *)D_800E76A0, (char *)&fileExt, timeData, fileSize);
}
free_from_memory_pool(timeData);
if (ret != CONTROLLER_PAK_GOOD) {
ret |= (controllerIndex << 30);
}
return ret;
}
GLOBAL_ASM("asm/non_matchings/save_data/func_80074204.s")
GLOBAL_ASM("asm/non_matchings/save_data/func_8007431C.s")
/**
* Writes Eeprom in 5 block chunks of data starting at either 0x0, 0x5, or 0xA
* In Save File:
* 0x00 - 0x27 Save 1
* 0x28 - 0x4F Save 2
* 0x50 - 0x77 Save 3
*/
s32 write_save_data(s32 saveFileNum, Settings *settings) {
s32 startingAddress;
u64 *alloc;
s32 address;
s32 blocks;
s32 i;
if (osEepromProbe(get_si_mesg_queue()) == 0) {
return -1;
}
switch(saveFileNum) {
case 0:
startingAddress = 0;
break;
case 1:
startingAddress = 5;
break;
case 2:
startingAddress = 10;
break;
default:
startingAddress = 10;
break;
}
blocks = 5;
alloc = allocate_from_main_pool_safe(blocks * sizeof(u64), COLOUR_TAG_WHITE);
func_800732E8(settings, (u8 *)alloc);
if (!is_reset_pressed()) {
for (i = 0, address = startingAddress; i < blocks; i++, address++) {
osEepromWrite(get_si_mesg_queue(), address, (u8 *)&alloc[i]);
}
}
free_from_memory_pool(alloc);
return 0;
}
/**
* Read Eeprom Data for addresses 0x10 - 0x39
* arg1 is a flag
* arg1 is descended from (D_800DD37C & 3) so the first 2 bits of that value.
* bit 1 is for 0x10 - 0x27
* bit 2 is for 0x28 - 0x39
*/
s32 read_eeprom_data(Settings *arg0, u8 arg1) {
u64 *alloc;
s32 i;
if (osEepromProbe(get_si_mesg_queue()) == 0) {
return -1;
}
alloc = allocate_from_main_pool_safe(0x200, COLOUR_TAG_WHITE);
if (arg1 & 1) {
s32 blocks = 24;
for (i = 0; i < blocks; i++) {
osEepromRead(get_si_mesg_queue(), i + 0x10, (u8 *)&alloc[i]);
}
func_80073588(arg0, alloc, 1);
}
if (arg1 & 2) {
s32 blocks = 24;
for (i = 0; i < blocks; i++) {
osEepromRead(get_si_mesg_queue(), i + 0x28, (u8 *)(&alloc[24] + i));
}
func_80073588(arg0, alloc, 2);
}
free_from_memory_pool(alloc);
return 0;
}
/**
* Write Eeprom Data for addresses 0x10 - 0x39
* 0x80 - 0x1C8 in file
* arg1 is a flag
* bit 1 is for 0x10 - 0x27
* bit 2 is for 0x28 - 0x39
*/
s32 write_eeprom_data(Settings *arg0, u8 arg1) {
u64 *alloc;
s32 i;
if (osEepromProbe(get_si_mesg_queue()) == 0) {
return -1;
}
alloc = allocate_from_main_pool_safe(0x200, COLOUR_TAG_WHITE);
func_800738A4(arg0, (u8 *)alloc);
if (arg1 & 1) {
s32 size = 24;
if (1){} //Fake Match
if (!is_reset_pressed()) {
for (i = 0; i != size; i++) {
osEepromWrite(get_si_mesg_queue(), i + 16, (u8 *)&alloc[i]);
}
}
}
if (arg1 & 2) {
s32 size = 24;
if (!is_reset_pressed()) {
for (i = 0; i != size; i++) {
osEepromWrite(get_si_mesg_queue(), i + 40, (u8 *)(&alloc[24] + i));
}
}
}
free_from_memory_pool(alloc);
return 0;
}
/**
* Calculates a checksum for the game settings, and compares
* against this to validate the data on load.
*/
s32 calculate_eeprom_settings_checksum(u64 eepromSettings) {
s32 ret;
s32 i;
ret = 5;
for (i = 0; i <= 13; i++) {
ret += (u16)(eepromSettings >> (i << 2)) & 0xF;
}
return ret;
}
/**
* Reads eeprom address 0xF (15)
* This contains the settings data, and global unlocks like characters
* Address (0xF * sizeof(u64)) = 0x78 - 0x80 of the actual save data file
*/
s32 read_eeprom_settings(u64 *eepromSettings) {
s32 temp;
s32 sp20;
if (osEepromProbe(get_si_mesg_queue()) == 0) {
return -1;
}
osEepromRead(get_si_mesg_queue(), 0xF, (u8 *) eepromSettings);
sp20 = calculate_eeprom_settings_checksum(*eepromSettings);
temp = *eepromSettings >> 56;
if (sp20 != temp) {
//bit 24 = Unknown
//bit 25 = Seems to be a flag for whether subtitles are enabled or not.
*eepromSettings = 0x3000000; //Sets bits 24 and 25 high
*eepromSettings <<= 8;
*eepromSettings >>= 8;
*eepromSettings |= (u64)calculate_eeprom_settings_checksum(*eepromSettings) << 56;
}
return 1;
}
/**
* Writes eeprom address 0xF (15)
* This contains the settings data, and global unlocks like characters
* Address (0xF * sizeof(u64)) = 0x78 - 0x80 of the actual save data file
*/
s32 write_eeprom_settings(u64 *eepromSettings) {
if (osEepromProbe(get_si_mesg_queue()) == 0) {
return -1;
}
*eepromSettings <<= 8;
*eepromSettings >>= 8;
*eepromSettings |= (s64)(calculate_eeprom_settings_checksum(*eepromSettings)) << 56;
if (is_reset_pressed() == 0) {
osEepromWrite(get_si_mesg_queue(), 0xF, (u8 *) eepromSettings);
}
return 1;
}
s16 calculate_ghost_header_checksum(GhostHeader *ghostHeader) {
s16 i;
s16 len;
s16 sum;
sum = 0;
len = (s16)(ghostHeader->nodeCount * sizeof(GhostDataFrame)) + sizeof(GhostHeader);
for (i = 2; i < len; i++) {
sum += ((u8 *)ghostHeader)[i];
}
return sum;
}
void func_80074AA8(GhostHeader *ghostHeader, s16 characterID, s16 time, s16 nodeCount, u8 *dest) {
ghostHeader->checksum = 0;
ghostHeader->characterID = characterID;
ghostHeader->unk3 = 0;
ghostHeader->time = time;
ghostHeader->nodeCount = nodeCount;
bcopy(dest, (u8 *)ghostHeader + 8, nodeCount * sizeof(GhostDataFrame));
ghostHeader->checksum = calculate_ghost_header_checksum(ghostHeader);
}
//Seems to only be called when used as an argument for func_800860A8. Effectively just returns 0x6700
//get_ghost_data_file_size()?
s32 func_80074B1C(void) {
//func_80074EB8 Makes extensive use out of 0x1100, and even does a * 6 to it.
//func_80075000 Uses 0x1100 once as well.
//Another possibility for 0x1100, seems to be from func_8007BA5C which seems to do (0xF5101100 & 0xFFFF);
int x = 0x1100;
return (&x)[0] * 6 + 0x100;
}
GLOBAL_ASM("asm/non_matchings/save_data/func_80074B34.s")
GLOBAL_ASM("asm/non_matchings/save_data/func_80074EB8.s")
GLOBAL_ASM("asm/non_matchings/save_data/func_80075000.s")
GLOBAL_ASM("asm/non_matchings/save_data/func_800753D8.s")
GLOBAL_ASM("asm/non_matchings/save_data/func_800756D4.s")
SIDeviceStatus get_si_device_status(s32 controllerIndex) {
OSMesg unusedMsg;
s32 ret;
s32 bytes_not_used;
s32 i;
if (sControllerMesgQueue->validCount == 0) {
if (osMotorInit(sControllerMesgQueue, &pfs[controllerIndex], controllerIndex) == 0) {
return RUMBLE_PAK;
}
}
//Couldn't get a for loop to match this
i = 0;
while (sControllerMesgQueue->validCount != 0 && i < 10) {
osRecvMesg(sControllerMesgQueue, &unusedMsg, OS_MESG_NOBLOCK);
i++;
}
for (i = 0; i <= 4; i++) {
ret = osPfsFreeBlocks( &pfs[controllerIndex], &bytes_not_used);
if (ret == PFS_ERR_INVALID) {
ret = osPfsInit(sControllerMesgQueue, &pfs[controllerIndex], controllerIndex);
}
if (ret == PFS_ERR_ID_FATAL) {
if (osMotorInit(sControllerMesgQueue, &pfs[controllerIndex], controllerIndex) == 0) {
return RUMBLE_PAK;
}
}
if (ret == PFS_ERR_NEW_PACK) {
if ((osPfsInit(sControllerMesgQueue, &pfs[controllerIndex], controllerIndex) == PFS_ERR_ID_FATAL)
&& (osMotorInit(sControllerMesgQueue, &pfs[controllerIndex], controllerIndex) == 0)) {
return RUMBLE_PAK;
}
return CONTROLLER_PAK_CHANGED;
}
if (ret == PFS_ERR_NOPACK || ret == PFS_ERR_DEVICE) {
return NO_CONTROLLER_PAK;
}
if (ret == PFS_ERR_BAD_DATA) {
return CONTROLLER_PAK_BAD_DATA;
}
if (ret == PFS_ERR_ID_FATAL) {
return CONTROLLER_PAK_WITH_BAD_ID;
}
if (ret == PFS_ERR_INCONSISTENT) {
return CONTROLLER_PAK_INCONSISTENT;
}
if (ret == 0) {
return CONTROLLER_PAK_GOOD;
}
}
return NO_CONTROLLER_PAK;
}
s32 start_reading_controller_data(UNUSED s32 controllerIndex) {
osContStartReadData(sControllerMesgQueue);
return 0;
}
void init_controller_paks(void) {
s32 controllerIndex;
s32 ret;
u8 controllerBit;
u8 pakPattern;
s8 maxControllers;
sControllerMesgQueue = get_si_mesg_queue();
sUnkMiscAsset19 = (s16 *)get_misc_asset(ASSET_MISC_19);
D_801241E6 = D_801241E7 = 0xF;
D_801241E4 = 1;
gRumbleDetectionTimer = 0;
D_800DE48C = 1;
sControllerPaksPresent = sRumblePaksPresent = 0;
//pakPattern will set the first 4 bits representing each controller
//and it will be 1 if there's something attached.
osPfsIsPlug(sControllerMesgQueue, &pakPattern);
for (controllerIndex = 0, controllerBit = 1, maxControllers = MAXCONTROLLERS; (0, controllerIndex) != maxControllers; controllerIndex++, controllerBit <<= 1) {
D_801241B8[controllerIndex].unk2 = 0;
D_801241B8[controllerIndex].unk4 = -1;
D_801241B8[controllerIndex].unk0 = -1;
D_801241B8[controllerIndex].unk6 = D_801241B8[controllerIndex].unk2;
//If something is plugged into the controller
if (pakPattern & controllerBit) {
ret = osPfsInit(sControllerMesgQueue, &pfs[controllerIndex], controllerIndex);
if (ret == PFS_ERR_NEW_PACK) {
ret = osPfsInit(sControllerMesgQueue, &pfs[controllerIndex], controllerIndex);
}
if (ret == 0) {
//If we found a controller pak, set the bit that has one
sControllerPaksPresent |= controllerBit;
}
else if (ret == PFS_ERR_ID_FATAL) {
if (controllerIndex) { }
ret = osMotorInit(sControllerMesgQueue, &pfs[controllerIndex], controllerIndex);
if (ret == 0) {
//If we found a rumble pak, set the bit that has one
sRumblePaksPresent |= controllerBit;
}
}
}
}
osContStartReadData(sControllerMesgQueue);
}
UNUSED SIDeviceStatus check_for_rumble_pak(s32 controllerIndex) {
s32 ret;
ret = get_si_device_status(controllerIndex);
start_reading_controller_data(controllerIndex);
if (ret == RUMBLE_PAK) {
sRumblePaksPresent |= 1 << controllerIndex;
}
return ret;
}
//Inspects and repairs the Controller Pak's file system
SIDeviceStatus repair_controller_pak(s32 controllerIndex) {
s32 ret;
s32 status = get_si_device_status(controllerIndex);
if (status == CONTROLLER_PAK_GOOD || status == CONTROLLER_PAK_INCONSISTENT) {
status = osPfsChecker(&pfs[controllerIndex]);
if (status == 0) {
ret = CONTROLLER_PAK_GOOD;
} else if (status == PFS_ERR_NEW_PACK) {
ret = CONTROLLER_PAK_CHANGED;
} else {
ret = CONTROLLER_PAK_INCONSISTENT;
}
} else {
ret = CONTROLLER_PAK_GOOD;
}
start_reading_controller_data(controllerIndex);
return ret;
}
//Reformat Controller Pak
SIDeviceStatus reformat_controller_pak(s32 controllerIndex) {
s32 ret;
s32 status = get_si_device_status(controllerIndex);
if (status == CONTROLLER_PAK_GOOD || status == CONTROLLER_PAK_INCONSISTENT || status == CONTROLLER_PAK_WITH_BAD_ID) {
status = osPfsReFormat(&pfs[controllerIndex], sControllerMesgQueue, controllerIndex);
if (status == 0) {
ret = CONTROLLER_PAK_GOOD;
} else if (status == PFS_ERR_NEW_PACK) {
ret = CONTROLLER_PAK_CHANGED;
} else {
ret = CONTROLLER_PAK_INCONSISTENT;
}
} else {
ret = CONTROLLER_PAK_GOOD;
}
start_reading_controller_data(controllerIndex);
return ret;
}
s32 get_controller_pak_file_list(s32 controllerIndex, s32 maxNumOfFilesToGet, char **fileNames, char **fileExtensions, u32 *fileSizes, u8 *fileTypes) {
OSPfsState state;
s32 ret;
s32 maxNumOfFilesOnCpak;
s32 files_used;
s8 *temp_D_800DE440;
s32 i;
u32 gameCode;
ret = get_si_device_status(controllerIndex);
if (ret != CONTROLLER_PAK_GOOD) {
start_reading_controller_data(controllerIndex);
return (controllerIndex << 30) | ret;
}
if (osPfsNumFiles(&pfs[controllerIndex], &maxNumOfFilesOnCpak, &files_used) != 0) {
start_reading_controller_data(controllerIndex);
return (controllerIndex << 30) | CONTROLLER_PAK_BAD_DATA;
}
if (get_language() == LANGUAGE_JAPANESE) {
gameCode = JPN_GAME_CODE;
} else if (osTvType == TV_TYPE_PAL) {
gameCode = PAL_GAME_CODE;
} else {
gameCode = NTSC_GAME_CODE;
}
if (maxNumOfFilesToGet < maxNumOfFilesOnCpak) {
maxNumOfFilesOnCpak = maxNumOfFilesToGet;
}
if (D_800DE440 != NULL) {
free_from_memory_pool(D_800DE440);
}
files_used = maxNumOfFilesOnCpak * 24;
D_800DE440 = allocate_from_main_pool_safe(files_used, COLOUR_TAG_BLACK);
bzero(D_800DE440, files_used);
temp_D_800DE440 = D_800DE440;
//TODO: There's probably an unidentified struct here
for (i = 0; i < maxNumOfFilesOnCpak; i++) {
fileNames[i] = (char *) temp_D_800DE440;
temp_D_800DE440 += 0x12;
fileExtensions[i] = (char *) temp_D_800DE440;
fileSizes[i] = 0;
fileTypes[i] = -1;
temp_D_800DE440 += 6;
}
while (i < maxNumOfFilesToGet) {
fileExtensions[i] = 0;
fileNames[i] = 0;
fileSizes[i] = 0;
fileTypes[i] = -1;
i++;
}
for (i = 0; i < maxNumOfFilesOnCpak; i++) {
ret = osPfsFileState(&pfs[controllerIndex], i, &state);
if (ret == PFS_ERR_INVALID) {
fileNames[i] = 0;
continue;
}
if (ret != 0) {
start_reading_controller_data(controllerIndex);
return CONTROLLER_PAK_BAD_DATA;
}
font_codes_to_string((char *)&state.game_name, (char *)fileNames[i], PFS_FILE_NAME_LEN);
font_codes_to_string((char *)&state.ext_name, (char *)fileExtensions[i], PFS_FILE_EXT_LEN);
fileSizes[i] = state.file_size;
fileTypes[i] = 6; // Unknown file type? Possibly from another game?
if ((state.game_code == gameCode) && (state.company_code == COMPANY_CODE)) {
fileTypes[i] = get_file_type(controllerIndex, i);
}
}
start_reading_controller_data(controllerIndex);
return CONTROLLER_PAK_GOOD;
}
//Free D_800DE440
void func_80076164(void) {
if (D_800DE440 != 0) {
free_from_memory_pool(D_800DE440);
}
D_800DE440 = 0;
}
//Get Available Space in Controller Pak
s32 get_free_space(s32 controllerIndex, u32 *bytesFree, s32 *notesFree) {
s32 ret;
s32 bytesNotUsed;
s32 maxNotes;
s32 notesUsed;
ret = get_si_device_status(controllerIndex);
if (ret == CONTROLLER_PAK_GOOD) {
if (bytesFree != 0) {
ret = osPfsFreeBlocks(&pfs[controllerIndex], &bytesNotUsed);
if (ret != 0) {
start_reading_controller_data(controllerIndex);
return (controllerIndex << 30) | CONTROLLER_PAK_BAD_DATA;
}
*bytesFree = bytesNotUsed;
}
if (notesFree != 0) {
ret = osPfsNumFiles(&pfs[controllerIndex], &maxNotes, &notesUsed);
if (ret != 0) {
start_reading_controller_data(controllerIndex);
return (controllerIndex << 30) | CONTROLLER_PAK_BAD_DATA;
}
if (notesUsed >= 16) {
*notesFree = 0;
} else {
*notesFree = 16 - notesUsed;
}
}
} else {
ret |= controllerIndex << 30;
}
start_reading_controller_data(controllerIndex);
return ret;
}
s32 delete_file(s32 controllerIndex, s32 fileNum) {
OSPfsState state;
s32 ret;
ret = get_si_device_status(controllerIndex);
if (ret != CONTROLLER_PAK_GOOD) {
start_reading_controller_data(controllerIndex);
return (controllerIndex << 30) | ret;
}
ret = (controllerIndex << 30) | CONTROLLER_PAK_BAD_DATA;
if (osPfsFileState(&pfs[controllerIndex], fileNum, &state) == 0) {
if (osPfsDeleteFile(&pfs[controllerIndex], state.company_code, state.game_code, (u8 *)&state.game_name, (u8 *)&state.ext_name) == 0) {
ret = CONTROLLER_PAK_GOOD;
}
}
start_reading_controller_data(controllerIndex);
return ret;
}
// Copies a file from one controller pak to the other
s32 copy_controller_pak_data(s32 controllerIndex, s32 fileNumber, s32 secondControllerIndex) {
UNUSED s32 pad;
char fileName[PFS_FILE_NAME_LEN];
UNUSED s32 pad2;
char fileExt[PFS_FILE_EXT_LEN];
OSPfsState state;
s32 status;
u8 *alloc;
status = get_si_device_status(controllerIndex);
if (status != CONTROLLER_PAK_GOOD) {
start_reading_controller_data(controllerIndex);
return (controllerIndex << 30) | status;
}
if (osPfsFileState(&pfs[controllerIndex], fileNumber, &state) != 0) {
start_reading_controller_data(controllerIndex);
return (controllerIndex << 30) | CONTROLLER_PAK_BAD_DATA;
}
alloc = allocate_from_main_pool_safe(state.file_size, COLOUR_TAG_BLACK);
status = read_data_from_controller_pak(controllerIndex, fileNumber, alloc, state.file_size);
start_reading_controller_data(controllerIndex);
if (status != CONTROLLER_PAK_GOOD) {
free_from_memory_pool(alloc);
return (controllerIndex << 30) | status;
}
font_codes_to_string(state.game_name, fileName, PFS_FILE_NAME_LEN);
font_codes_to_string(state.ext_name, fileExt, PFS_FILE_EXT_LEN);
status = write_controller_pak_file(secondControllerIndex, -1, fileName, fileExt, alloc, state.file_size);
if (status != CONTROLLER_PAK_GOOD) {
status |= (secondControllerIndex << 30);
}
free_from_memory_pool(alloc);
return status;
}
// There is likely a struct that looks like this in here.
// typedef struct fileStruct {
// s32 fileType;
// u8 game_name[PFS_FILE_NAME_LEN];
// } fileStruct;
SIDeviceStatus get_file_number(s32 controllerIndex, char *fileName, char *fileExt, s32 *fileNumber) {
u32 gameCode;
char fileNameAsFontCodes[PFS_FILE_NAME_LEN];
UNUSED s32 pad;
char fileExtAsFontCodes[PFS_FILE_EXT_LEN];
UNUSED s32 pad2;
s32 ret;
string_to_font_codes(fileName, fileNameAsFontCodes, PFS_FILE_NAME_LEN);
string_to_font_codes(fileExt, fileExtAsFontCodes, PFS_FILE_EXT_LEN);
if (get_language() == LANGUAGE_JAPANESE) {
gameCode = JPN_GAME_CODE;
} else if (osTvType == TV_TYPE_PAL) {
gameCode = PAL_GAME_CODE;
} else {
gameCode = NTSC_GAME_CODE;
}
ret = osPfsFindFile(&pfs[controllerIndex], COMPANY_CODE, gameCode, (u8 *)fileNameAsFontCodes, (u8 *)fileExtAsFontCodes, fileNumber);
if (ret == 0) {
return CONTROLLER_PAK_GOOD;
}
if ((ret == PFS_ERR_NOPACK) || (ret == PFS_ERR_DEVICE)) {
return NO_CONTROLLER_PAK;
}
if (ret == PFS_ERR_INCONSISTENT) {
return CONTROLLER_PAK_INCONSISTENT;
}
if (ret == PFS_ERR_ID_FATAL) {
return CONTROLLER_PAK_WITH_BAD_ID;
}
if (ret == PFS_ERR_INVALID) {
return CONTROLLER_PAK_CHANGED;
}
return CONTROLLER_PAK_BAD_DATA;
}
SIDeviceStatus read_data_from_controller_pak(s32 controllerIndex, s32 fileNum, u8 *data, s32 dataLength) {
s32 readResult = osPfsReadWriteFile(&pfs[controllerIndex], fileNum, PFS_READ, 0, dataLength, data);
if (readResult == 0) {
return CONTROLLER_PAK_GOOD;
}
if ((readResult == PFS_ERR_NOPACK) || (readResult == PFS_ERR_DEVICE)) {
return NO_CONTROLLER_PAK;
}
if (readResult == PFS_ERR_INCONSISTENT) {
return CONTROLLER_PAK_INCONSISTENT;
}
if (readResult == PFS_ERR_ID_FATAL) {
return CONTROLLER_PAK_WITH_BAD_ID;
}
if (readResult == PFS_ERR_INVALID) {
return CONTROLLER_PAK_CHANGED;
}
return CONTROLLER_PAK_BAD_DATA;
}
//If fileNumber -1, it creates a new file?
SIDeviceStatus write_controller_pak_file(s32 controllerIndex, s32 fileNumber, char *fileName, char *fileExt, u8 *dataToWrite, s32 fileSize) {
s32 temp;
u8 fileNameAsFontCodes[PFS_FILE_NAME_LEN];
UNUSED s32 temp2;
u8 fileExtAsFontCodes[PFS_FILE_EXT_LEN];
s32 ret;
s32 file_number;
s32 bytesToSave;
u32 game_code;
ret = get_si_device_status(controllerIndex);
if (ret != 0) {
start_reading_controller_data(controllerIndex);
return ret;
}
bytesToSave = fileSize;
temp = fileSize & 0xFF;
if (temp != 0) {
bytesToSave = (fileSize - temp) + 0x100;
}
string_to_font_codes(fileName, (char *)fileNameAsFontCodes, PFS_FILE_NAME_LEN);
string_to_font_codes(fileExt, (char *)fileExtAsFontCodes, PFS_FILE_EXT_LEN);
if (get_language() == LANGUAGE_JAPANESE) {
game_code = JPN_GAME_CODE;
} else if (osTvType == TV_TYPE_PAL) {
game_code = PAL_GAME_CODE;
} else {
game_code = NTSC_GAME_CODE;
}
ret = get_file_number(controllerIndex, fileName, fileExt, &file_number);
if (ret == CONTROLLER_PAK_GOOD) {
if (fileNumber != -1 && fileNumber != file_number) {
ret = CONTROLLER_PAK_BAD_DATA;
}
} else if (ret == CONTROLLER_PAK_CHANGED) {
if (fileNumber != -1) {
ret = CONTROLLER_PAK_BAD_DATA;
} else {
temp = osPfsAllocateFile(&pfs[controllerIndex], COMPANY_CODE, game_code, fileNameAsFontCodes, fileExtAsFontCodes, bytesToSave, &file_number);
if (temp == 0) {
ret = CONTROLLER_PAK_GOOD;
} else if (temp == PFS_DATA_FULL || temp == PFS_DIR_FULL) {
ret = CONTROLLER_PAK_FULL;
}
else {
ret = CONTROLLER_PAK_BAD_DATA;
}
}
}
if (ret == CONTROLLER_PAK_GOOD) {
temp = osPfsReadWriteFile(&pfs[controllerIndex], file_number, PFS_WRITE, 0, bytesToSave, dataToWrite);
if (temp == 0) {
ret = CONTROLLER_PAK_GOOD;
} else if ((temp == PFS_ERR_NOPACK) || (temp == PFS_ERR_DEVICE)) {
ret = NO_CONTROLLER_PAK;
} else if (temp == PFS_ERR_INCONSISTENT) {
ret = CONTROLLER_PAK_INCONSISTENT;
} else if (temp == PFS_ERR_ID_FATAL) {
ret = CONTROLLER_PAK_WITH_BAD_ID;
}
else {
ret = CONTROLLER_PAK_BAD_DATA;
}
}
start_reading_controller_data(controllerIndex);
return ret;
}
//Get File size for given controller's Control Pak
SIDeviceStatus get_file_size(s32 controllerIndex, s32 fileNum, s32 *fileSize) {
OSPfsState state;
*fileSize = 0;
if (osPfsFileState(&pfs[controllerIndex], fileNum, &state) == 0) {
*fileSize = state.file_size;
return CONTROLLER_PAK_GOOD;
}
return CONTROLLER_PAK_BAD_DATA;
}
//Converts N64 Font codes used in controller pak file names, into C ASCII a coded string
char *font_codes_to_string(char *inString, char *outString, s32 stringLength) {
s32 index = *inString;
char *ret = outString;
while (index != 0 && stringLength != 0) {
// Less than sizeof(gN64FontCodes) - 3.
// So basically make sure it's a valid font code value
if (index <= 65) {
*outString = gN64FontCodes[index];
outString++;
} else {
//Replace invalid characters with a hyphen
*outString = '-';
outString++;
}
inString++;
stringLength--;
index = *inString;
}
//Pad any extra characters with NULL font code
while (stringLength != 0) {
*outString = 0;
stringLength--;
outString++;
}
*outString = 0;
return ret;
}
//Converts a C ASCII string into N64 Font codes for controller pak file names
char *string_to_font_codes(char *inString, char *outString, s32 stringLength) {
s32 i;
char currentChar;
char *ret = outString;
while (*inString != 0 && stringLength != 0) {
*outString = 0;
for (i = 0; i < 65; i++) {
currentChar = *inString;
if (currentChar == gN64FontCodes[i]) {
*outString = i;
outString++;
break;
}
}
inString++;
stringLength--;
}
while (stringLength != 0) {
*outString = 0;
stringLength--;
outString++;
}
*outString = 0;
return ret;
}
/**
* For the given controller, and file, this will return a value for which type of file it is.
* 3 = GAMD / Game Data
* 4 = TIMD / Time Data
* 5 = GHSS / Ghost Data
* 6 = Unknown? Possibly from another game?
*/
s32 get_file_type(s32 controllerIndex, s32 fileNum) {
s32 *data;
UNUSED s32 pad;
s32 ret;
ret = 6;
data = allocate_from_main_pool_safe(0x100, COLOUR_TAG_BLACK);
if (read_data_from_controller_pak(controllerIndex, fileNum, (u8 *)data, 0x100) == CONTROLLER_PAK_GOOD) {
switch (*data) {
case GAMD:
ret = 3;
break;
case TIMD:
ret = 4;
break;
case GHSS:
ret = 5;
break;
default:
ret = 6;
break;
}
}
free_from_memory_pool(data);
return ret;
}