*WIP Patch fix. WIP patches should work now. Tested and confirmed for PoP.

WIP Patches will be only accepted in the following format (let's not invent thousands of different formats):
In 3x 4 bytes columns separated by a space (no ":" allowed)
offset | original address | overwrite address 

Example for PoP:
007AAC6A 7A6B6F6A 6F6A7A6B
007AAC75 7C7A6939 69397C7A
...

The original address is compared before patching and is not patched if it doesn't match. You can see the confirmation or fail of a patch on the Gecko Output.

*A few fix ups in different places
This commit is contained in:
dimok321 2010-05-29 15:43:19 +00:00
parent 8a4e192022
commit f0ca11506b
13 changed files with 195 additions and 177 deletions

View File

@ -2,8 +2,8 @@
<app version="1"> <app version="1">
<name> USB Loader GX</name> <name> USB Loader GX</name>
<coder>USB Loader GX Team</coder> <coder>USB Loader GX Team</coder>
<version>1.0 r931</version> <version>1.0 r932</version>
<release_date>201005290726</release_date> <release_date>201005290827</release_date>
<short_description>Loads games from USB-devices</short_description> <short_description>Loads games from USB-devices</short_description>
<long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times. <long_description>USB Loader GX is a libwiigui based USB iso loader with a wii-like GUI. You can install games to your HDDs and boot them with shorter loading times.
The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller. The interactive GUI is completely controllable with WiiMote, Classic Controller or GC Controller.

File diff suppressed because one or more lines are too long

View File

@ -19,7 +19,7 @@ void debug(int Line, const char* Format, ...)
if(debugLock==0) LWP_MutexInit(&debugLock, false); if(debugLock==0) LWP_MutexInit(&debugLock, false);
LWP_MutexLock(debugLock); LWP_MutexLock(debugLock);
FILE *fp = fopen("SD:/debug.txt", "a"); FILE *fp = fopen("SD:/debug.txt", "a");
if(fp) if(fp)
{ {
@ -38,7 +38,7 @@ void debug(int Line, const char* Format, ...)
LWP_MutexUnlock(debugLock); LWP_MutexUnlock(debugLock);
} }
//#define DEBUG(format, ...) debug(__LINE__, format, ##__VA_ARGS__) //#define DEBUG(format, ...) debug(__LINE__, format, ##__VA_ARGS__)
#define DEBUG(format, ...) #define DEBUG(format, ...)
static void *memdup(const void* src, size_t len) static void *memdup(const void* src, size_t len)
{ {
@ -103,7 +103,7 @@ static u32 GuiImageAsyncThreadInit()
CanSleep = false; CanSleep = false;
LWP_MutexInit(&ListLock, false); LWP_MutexInit(&ListLock, false);
LWP_MutexInit(&InUseLock, false); LWP_MutexInit(&InUseLock, false);
LWP_CreateThread(&Thread, GuiImageAsyncThread, NULL, NULL, 0, 75); LWP_CreateThread(&Thread, GuiImageAsyncThread, NULL, NULL, 16384, 75);
// while(!CanSleep) // while(!CanSleep)
// usleep(20); // usleep(20);
} }

View File

@ -44,7 +44,7 @@ GuiSoundDecoder *GuiSoundDecoder::GetDecoder(const u8 * snd, u32 len, bool snd_i
{ {
GuiSoundDecoder *d = NULL; GuiSoundDecoder *d = NULL;
try{ d = de->fnc(snd, len, snd_is_allocated); } try{ d = de->fnc(snd, len, snd_is_allocated); }
catch(const char *error){ catch(const char *error){
gprintf("%s", error); } gprintf("%s", error); }
catch(...){} catch(...){}
if(d) return d; if(d) return d;
@ -52,7 +52,7 @@ GuiSoundDecoder *GuiSoundDecoder::GetDecoder(const u8 * snd, u32 len, bool snd_i
return NULL; return NULL;
} }
/*************************************************************** /***************************************************************
* *
* D E C O D E R T H R E A D * D E C O D E R T H R E A D
@ -191,7 +191,7 @@ GuiSound::GuiSound(const u8 *s, int l, int v/*=100*/, bool r/*=true*/, bool a/*=
{ {
if(GuiSoundCount++ == 0 || GuiSoundDecoderThreadHandle == LWP_THREAD_NULL) if(GuiSoundCount++ == 0 || GuiSoundDecoderThreadHandle == LWP_THREAD_NULL)
{ {
LWP_CreateThread(&GuiSoundDecoderThreadHandle,GuiSoundDecoderThread,NULL,NULL,32*1024,80); LWP_CreateThread(&GuiSoundDecoderThreadHandle,GuiSoundDecoderThread,NULL,NULL,32768,80);
} }
voice = -1; voice = -1;
play_buffer[0] = (u8*)memalign(32, BUFFER_SIZE*3); // tripple-buffer first is played play_buffer[0] = (u8*)memalign(32, BUFFER_SIZE*3); // tripple-buffer first is played
@ -247,7 +247,7 @@ bool GuiSound::Load(const char *p)
{ {
Stop(); // stop playing Stop(); // stop playing
if(!play_buffer[0]) return false; if(!play_buffer[0]) return false;
bool ret = false; bool ret = false;
voice = -2; // -2 marks loading from file voice = -2; // -2 marks loading from file
u32 filesize = 0; u32 filesize = 0;
@ -300,15 +300,15 @@ void GuiSound::Play()
Stop(); // stop playing if it played Stop(); // stop playing if it played
if(!play_buffer[0]) return; if(!play_buffer[0]) return;
if(!decoder) return; // no decoder or no play_buffer -> no playing if(!decoder) return; // no decoder or no play_buffer -> no playing
// initialize the buffer // initialize the buffer
buffer_nr = 0; // allways starts with buffer 0 buffer_nr = 0; // allways starts with buffer 0
buffer_pos = 0; // reset position buffer_pos = 0; // reset position
buffer_ready = false; buffer_ready = false;
buffer_eof = false; buffer_eof = false;
decoder->Rewind(); // play from begin decoder->Rewind(); // play from begin
DecoderCallback(); // fill first buffer; DecoderCallback(); // fill first buffer;
if(!buffer_ready || buffer_eof) // if first buffer not ready -> no play if(!buffer_ready || buffer_eof) // if first buffer not ready -> no play
return; return;
voice = ASND_GetFirstUnusedVoice(); voice = ASND_GetFirstUnusedVoice();
if(voice >= 0) if(voice >= 0)
{ {
@ -387,7 +387,7 @@ void GuiSound::DecoderCallback()
{ {
if(loop) if(loop)
decoder->Rewind(); // if loop -> rewind and fill the buffer more decoder->Rewind(); // if loop -> rewind and fill the buffer more
else if(buffer_pos) else if(buffer_pos)
break; // has data in buffer -> play the buffer break; // has data in buffer -> play the buffer
else else
buffer_eof = true; // no data in buffer -> return EOF buffer_eof = true; // no data in buffer -> return EOF
@ -420,7 +420,7 @@ void GuiSound::DecoderCallback()
} }
void GuiSound::PlayerCallback() void GuiSound::PlayerCallback()
{ {
if(buffer_eof) // if EOF if(buffer_eof) // if EOF
{ {
if(ASND_TestPointer(voice, play_buffer[(buffer_nr+2)%3])==0) // test prev. Buffer if(ASND_TestPointer(voice, play_buffer[(buffer_nr+2)%3])==0) // test prev. Buffer
Stop(); Stop();
@ -429,7 +429,7 @@ void GuiSound::PlayerCallback()
{ {
if(ASND_AddVoice(voice, play_buffer[buffer_nr], buffer_pos)==SND_OK) // add buffer if(ASND_AddVoice(voice, play_buffer[buffer_nr], buffer_pos)==SND_OK) // add buffer
{ {
// next buffer // next buffer
buffer_nr = (buffer_nr+1)%3; buffer_nr = (buffer_nr+1)%3;
buffer_pos = 0; buffer_pos = 0;
buffer_ready= false; buffer_ready= false;

View File

@ -182,7 +182,7 @@ static void * UpdateGUI (void *arg) {
* Startup GUI threads * Startup GUI threads
***************************************************************************/ ***************************************************************************/
void InitGUIThreads() { void InitGUIThreads() {
LWP_CreateThread(&guithread, UpdateGUI, NULL, NULL, 0, LWP_PRIO_HIGHEST); LWP_CreateThread(&guithread, UpdateGUI, NULL, NULL, 32768, LWP_PRIO_HIGHEST);
InitProgressThread(); InitProgressThread();
InitNetworkThread(); InitNetworkThread();

View File

@ -391,7 +391,7 @@ static void * networkinitcallback(void *arg) {
* InitNetworkThread with priority 0 (idle) * InitNetworkThread with priority 0 (idle)
***************************************************************************/ ***************************************************************************/
void InitNetworkThread() { void InitNetworkThread() {
LWP_CreateThread (&networkthread, networkinitcallback, NULL, NULL, 0, 0); LWP_CreateThread (&networkthread, networkinitcallback, NULL, NULL, 16384, 0);
} }
/**************************************************************************** /****************************************************************************

View File

@ -26,6 +26,8 @@
#include "usbloader/apploader.h" #include "usbloader/apploader.h"
#include "patchcode.h" #include "patchcode.h"
#include "settings/cfg.h"
#include "listfiles.h"
//#include "sd.h" //#include "sd.h"
//#include "fwrite_patch.h" //#include "fwrite_patch.h"
@ -192,6 +194,16 @@ static const u32 newpatch002[3] = {
bool dogamehooks(void *addr, u32 len) bool dogamehooks(void *addr, u32 len)
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
{ {
//this is temporary since the screen freezes without a file loaded
char filepath[150];
char GameId[10];
memcpy(GameId, (u8 *) 0x80000000, 6);
GameId[6] = 0;
sprintf(filepath, "%s%s.gct", Settings.Cheatcodespath, GameId);
if(!checkfile(filepath))
return false;
//TODO for oggzee: when using Ocarina check if a hook as patched //TODO for oggzee: when using Ocarina check if a hook as patched
hooktype = 1; // TODO for oggzee: Create an option for hooktype hooktype = 1; // TODO for oggzee: Create an option for hooktype

View File

@ -1,128 +1,134 @@
#include <gccore.h> #include <gccore.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "gecko.h"
#include "settings/cfg.h"
#include "settings/cfg.h"
u32 doltableoffset[64];
u32 doltablelength[64]; typedef struct
u32 doltableentries; {
u32 offset;
void wipreset() u32 srcaddress;
{ u32 dstaddress;
doltableentries = 0; } WIP_Code;
}
static WIP_Code * CodeList = NULL;
void wipregisteroffset(u32 dst, u32 len) static u32 CodesCount = 0;
{ static u32 ProcessedLength = 0;
doltableoffset[doltableentries] = dst; static u32 Counter = 0;
doltablelength[doltableentries] = len;
doltableentries++; void do_wip_code(u8 * dst, u32 len)
} {
if(!CodeList)
void patchu8(u32 offset, u8 value) return;
{
u32 i = 0; if(Counter < 3)
u32 tempoffset = 0; {
Counter++;
while ((doltablelength[i] <= offset-tempoffset) && (i+1 < doltableentries)) return;
{ }
tempoffset+=doltablelength[i];
i++; int i = 0;
} int n = 0;
if (offset-tempoffset < doltablelength[i]) int offset = 0;
{
*(u8 *)(offset-tempoffset+doltableoffset[i]) = value; for(i = 0; i < CodesCount; i++)
} {
} for(n = 0; n < 4; n++)
{
void wipparsebuffer(u8 *buffer, u32 length) offset = CodeList[i].offset+n-ProcessedLength;
// The buffer needs a 0 at the end to properly terminate the string functions
{ if(offset < 0 || offset >= len)
u32 pos = 0; continue;
u32 offset;
char buf[10]; if(dst[offset] == ((u8 *)&CodeList[i].srcaddress)[n])
{
while (pos < length) dst[offset] = ((u8 *)&CodeList[i].dstaddress)[n];
{ gprintf("WIP: %08X Address Patched.\n", CodeList[i].offset+n);
if ( *(char *)(buffer + pos) != '#' && *(char *)(buffer + pos) != ';' && *(char *)(buffer + pos) != 10 && *(char *)(buffer + pos) != 13 && *(char *)(buffer + pos) != 32 && *(char *)(buffer + pos) != 0 ) }
{ else
memcpy(buf, (char *)(buffer + pos), 8); {
buf[8] = 0; gprintf("WIP: %08X Address does not match with WIP entrie.\n", CodeList[i].offset+n);
offset = strtol(buf,NULL,16); gprintf("Destination: %02X | Should be: %02X.\n", dst[offset], ((u8 *)&CodeList[i].srcaddress)[n]);
}
pos += (u32)strchr((char *)(buffer + pos), 32)-(u32)(buffer + pos) + 1; }
pos += (u32)strchr((char *)(buffer + pos), 32)-(u32)(buffer + pos) + 1; }
ProcessedLength += len;
while (*(char *)(buffer + pos) != 10 && *(char *)(buffer + pos) != 13 && *(char *)(buffer + pos) != 0) Counter++;
{ }
memcpy(buf, (char *)(buffer + pos), 2);
buf[2] = 0; void wip_reset_counter()
{
patchu8(offset, strtol(buf,NULL,16)); ProcessedLength = 0;
offset++; //alternative dols don't need a skip. only main.dol.
pos +=2; Counter = 3;
} }
}
if (strchr((char *)(buffer + pos), 10) == NULL) void free_wip()
{ {
return; if(CodeList)
} else free(CodeList);
{ CodeList = NULL;
pos += (u32)strchr((char *)(buffer + pos), 10)-(u32)(buffer + pos) + 1; CodesCount = 0;
} ProcessedLength = 0;
} }
}
int load_wip_code(u8 *gameid)
u32 do_wip_code(u8 *gameid) {
{ char filepath[150];
FILE *fp; char GameID[8];
u32 filesize; memset(GameID, 0, sizeof(GameID));
char filepath[150]; memcpy(GameID, gameid, 6);
memset(filepath, 0, 150); snprintf(filepath, sizeof(filepath), "%s%s.wip", Settings.WipCodepath, GameID);
u8 *wipCode;
FILE * fp = fopen(filepath, "rb");
sprintf(filepath, "%s%6s", Settings.WipCodepath, gameid); if (!fp)
filepath[strlen(Settings.WipCodepath)+6] = '.'; {
filepath[strlen(Settings.WipCodepath)+7] = 'w'; memset(GameID, 0, sizeof(GameID));
filepath[strlen(Settings.WipCodepath)+8] = 'i'; memcpy(GameID, gameid, 3);
filepath[strlen(Settings.WipCodepath)+9] = 'p'; snprintf(filepath, sizeof(filepath), "%s%s.wip", Settings.WipCodepath, GameID);
fp = fopen(filepath, "rb");
fp = fopen(filepath, "rb"); }
if (!fp) {
memset(filepath, 0, 150); if (!fp)
sprintf(filepath, "%s%3s", Settings.WipCodepath, gameid + 1); return -1;
filepath[strlen(Settings.WipCodepath)+3] = '.';
filepath[strlen(Settings.WipCodepath)+4] = 'w'; char line[255];
filepath[strlen(Settings.WipCodepath)+5] = 'i'; gprintf("\nLoading WIP code from %s.\n", filepath);
filepath[strlen(Settings.WipCodepath)+6] = 'p';
fp = fopen(filepath, "rb"); while (fgets(line, sizeof(line), fp))
{
if (!fp) { if (line[0] == '#') continue;
return -1;
} if(strlen(line) < 26) continue;
}
u32 offset = (u32) strtoul(line, NULL, 16);
if (fp) { u32 srcaddress = (u32) strtoul(line+9, NULL, 16);
u32 ret = 0; u32 dstaddress = (u32) strtoul(line+18, NULL, 16);
fseek(fp, 0, SEEK_END); if(!CodeList)
filesize = ftell(fp); CodeList = malloc(sizeof(WIP_Code));
wipCode = malloc(filesize + 1); WIP_Code * tmp = realloc(CodeList, (CodesCount+1)*sizeof(WIP_Code));
wipCode[filesize] = 0; // Wip code functions need a 0 termination if(!tmp)
{
fseek(fp, 0, SEEK_SET); if(CodeList)
ret = fread(wipCode, 1, filesize, fp); free(CodeList);
fclose(fp); CodeList = NULL;
fclose(fp);
if (ret == filesize) return -1;
{ }
// Apply wip patch
wipparsebuffer(wipCode, filesize + 1); CodeList = tmp;
return 0;
} CodeList[CodesCount].offset = offset;
} CodeList[CodesCount].srcaddress = srcaddress;
return -2; CodeList[CodesCount].dstaddress = dstaddress;
} CodesCount++;
}
fclose(fp);
gprintf("\n");
return 0;
}

View File

@ -1,6 +1,9 @@
#ifndef __WIP_H__ #ifndef __WIP_H__
#define __WIP_H__ #define __WIP_H__
u32 do_wip_code(u8 *gameid); int load_wip_code(u8 *gameid);
void do_wip_code(u8 * dst, u32 len);
#endif //__WIP_H__ void wip_reset_counter();
void free_wip();
#endif //__WIP_H__

View File

@ -402,7 +402,7 @@ void ShowProgress(const char *title, const char *msg1, char *dynmsg2, f32 done,
* Startup Progressthread in idle prio * Startup Progressthread in idle prio
***************************************************************************/ ***************************************************************************/
void InitProgressThread() { void InitProgressThread() {
LWP_CreateThread(&progressthread, ProgressThread, NULL, NULL, 0, 80); LWP_CreateThread(&progressthread, ProgressThread, NULL, NULL, 16384, 80);
} }
/**************************************************************************** /****************************************************************************

View File

@ -199,13 +199,13 @@ u32 Load_Dol_from_disc(u32 doloffset, u8 videoSelected, u8 patchcountrystring, u
} }
if (!mountMethod)ret = WDVD_Read(dol_header, sizeof(dolheader), (doloffset<<2)); if (!mountMethod)ret = WDVD_Read(dol_header, sizeof(dolheader), (doloffset<<2));
else{ else{
dvddone = 0; dvddone = 0;
ret = bwDVD_LowRead(dol_header, sizeof(dolheader), doloffset, __dvd_readidcb); ret = bwDVD_LowRead(dol_header, sizeof(dolheader), doloffset, __dvd_readidcb);
while(ret>=0 && dvddone==0); while(ret>=0 && dvddone==0);
} }
entrypoint = load_dol_start(dol_header); entrypoint = load_dol_start(dol_header);
if (entrypoint == 0) { if (entrypoint == 0) {
@ -216,13 +216,11 @@ u32 Load_Dol_from_disc(u32 doloffset, u8 videoSelected, u8 patchcountrystring, u
void *offset; void *offset;
u32 pos; u32 pos;
u32 len; u32 len;
while (load_dol_image_modified(&offset, &pos, &len)) { while (load_dol_image_modified(&offset, &pos, &len)) {
if (len != 0) { if (len != 0) {
ret = WDVD_Read(offset, len, (doloffset<<2) + pos); ret = WDVD_Read(offset, len, (doloffset<<2) + pos);
DCFlushRange(offset, len);
gamepatches(offset, len, videoSelected, patchcountrystring, vipatch, cheat); gamepatches(offset, len, videoSelected, patchcountrystring, vipatch, cheat);
DCFlushRange(offset, len); DCFlushRange(offset, len);

View File

@ -302,14 +302,14 @@ void gamepatches(void * dst, int len, u8 videoSelected, u8 patchcountrystring, u
Search_and_patch_Video_Modes(dst, len, table); Search_and_patch_Video_Modes(dst, len, table);
} }
dogamehooks(dst,len); if(cheat)
dogamehooks(dst,len);
//if (vipatch)//moved to degamehooks()
// vidolpatcher(dst,len);
if (vipatch)
vidolpatcher(dst,len);
/*LANGUAGE PATCH - FISHEARS*/ /*LANGUAGE PATCH - FISHEARS*/
//langpatcher(dst,len);//moved to degamehooks() langpatcher(dst,len);
/*Thanks to WiiPower*/ /*Thanks to WiiPower*/
if (patchcountrystring == 1) if (patchcountrystring == 1)
@ -317,15 +317,10 @@ void gamepatches(void * dst, int len, u8 videoSelected, u8 patchcountrystring, u
NewSuperMarioBrosPatch(dst, len); NewSuperMarioBrosPatch(dst, len);
do_wip_code((u8 *)0x80000000); do_wip_code((u8 *) dst, len);
//if(Settings.anti002fix == on)
if (fix002 == 2) if (fix002 == 2)
Anti_002_fix(dst, len); Anti_002_fix(dst, len);
//patchdebug(dst, len);
} }
s32 Apploader_Run(entry_point *entry, u8 cheat, u8 videoSelected, u8 vipatch, u8 patchcountrystring, u8 error002fix, u8 alternatedol, u32 alternatedoloffset) { s32 Apploader_Run(entry_point *entry, u8 cheat, u8 videoSelected, u8 vipatch, u8 patchcountrystring, u8 error002fix, u8 alternatedol, u32 alternatedoloffset) {
@ -383,7 +378,6 @@ s32 Apploader_Run(entry_point *entry, u8 cheat, u8 videoSelected, u8 vipatch, u8
WDVD_Read(dst, len, (u64)(offset << 2)); WDVD_Read(dst, len, (u64)(offset << 2));
gamepatches(dst, len, videoSelected, patchcountrystring, vipatch, cheat); gamepatches(dst, len, videoSelected, patchcountrystring, vipatch, cheat);
DCFlushRange(dst, len); DCFlushRange(dst, len);
} }
@ -392,6 +386,7 @@ s32 Apploader_Run(entry_point *entry, u8 cheat, u8 videoSelected, u8 vipatch, u8
/** Load alternate dol if set **/ /** Load alternate dol if set **/
if (alternatedol == 1) { if (alternatedol == 1) {
// gprintf("\n\talt dol from FAT"); // gprintf("\n\talt dol from FAT");
wip_reset_counter();
void *dolbuffer; void *dolbuffer;
int dollen; int dollen;
@ -399,8 +394,6 @@ s32 Apploader_Run(entry_point *entry, u8 cheat, u8 videoSelected, u8 vipatch, u8
if (dolloaded) { if (dolloaded) {
Remove_001_Protection(dolbuffer, dollen); Remove_001_Protection(dolbuffer, dollen);
DCFlushRange(dolbuffer, dollen);
gamepatches(dolbuffer, dollen, videoSelected, patchcountrystring, vipatch, cheat); gamepatches(dolbuffer, dollen, videoSelected, patchcountrystring, vipatch, cheat);
DCFlushRange(dolbuffer, dollen); DCFlushRange(dolbuffer, dollen);
@ -411,10 +404,10 @@ s32 Apploader_Run(entry_point *entry, u8 cheat, u8 videoSelected, u8 vipatch, u8
if(dolbuffer) if(dolbuffer)
free(dolbuffer); free(dolbuffer);
}
} else if (alternatedol == 2) { else if (alternatedol == 2)
// gprintf("\n\talt dol from WBFS"); {
wip_reset_counter();
FST_ENTRY *fst = (FST_ENTRY *)*(u32 *)0x80000038; FST_ENTRY *fst = (FST_ENTRY *)*(u32 *)0x80000038;
*entry = (entry_point) Load_Dol_from_disc(fst[alternatedoloffset].fileoffset, videoSelected, patchcountrystring, vipatch, cheat); *entry = (entry_point) Load_Dol_from_disc(fst[alternatedoloffset].fileoffset, videoSelected, patchcountrystring, vipatch, cheat);

View File

@ -6,6 +6,7 @@
#include <wiiuse/wpad.h> #include <wiiuse/wpad.h>
#include "patches/fst.h" #include "patches/fst.h"
#include "patches/wip.h"
#include "apploader.h" #include "apploader.h"
#include "disc.h" #include "disc.h"
#include "video.h" #include "video.h"
@ -287,6 +288,8 @@ s32 Disc_BootPartition(u64 offset, u8 videoselected, u8 cheat, u8 vipatch, u8 pa
memset(gameid, 0, 8); memset(gameid, 0, 8);
memcpy(gameid, (char*)Disc_ID, 6); memcpy(gameid, (char*)Disc_ID, 6);
load_wip_code((u8 *) &gameid);
/* Setup low memory */ /* Setup low memory */
__Disc_SetLowMem(); __Disc_SetLowMem();
@ -295,9 +298,12 @@ s32 Disc_BootPartition(u64 offset, u8 videoselected, u8 cheat, u8 vipatch, u8 pa
if (ret < 0) if (ret < 0)
return ret; return ret;
free_wip();
bool cheatloaded = false; bool cheatloaded = false;
if (cheat == 1) { if (cheat)
{
/* OCARINA STUFF - FISHEARS*/ /* OCARINA STUFF - FISHEARS*/
if(ocarina_load_code((u8 *) gameid) > 0) if(ocarina_load_code((u8 *) gameid) > 0)
{ {