From 7d4e4c0b34a613dd3c0220475ae4e448197522c1 Mon Sep 17 00:00:00 2001 From: Treeki Date: Sat, 12 Mar 2011 23:17:12 +0100 Subject: initial commit. now I can start playing with stuff! --- src/animtiles.cpp | 61 +++ src/anotherhax.S | 23 + src/asmlib.S | 182 +++++++ src/fileload.cpp | 134 +++++ src/fileload.h | 74 +++ src/g3dwrap.cpp | 90 ++++ src/gakenoko.S | 220 ++++++++ src/heapbar.S | 118 +++++ src/heapbar.cpp | 147 ++++++ src/layoutlib.S | 131 +++++ src/layoutlib.h | 149 ++++++ src/levelinfo.cpp | 36 ++ src/levelinfo.h | 56 ++ src/levelnames.cpp | 83 +++ src/linegod.S | 53 ++ src/linegod.cpp | 213 ++++++++ src/msgbox.S | 37 ++ src/msgbox.cpp | 227 +++++++++ src/poweruphax.S | 689 +++++++++++++++++++++++++ src/randomcrap.S | 8 + src/randtiles.cpp | 22 + src/randtiles.h | 63 +++ src/replay.S | 799 +++++++++++++++++++++++++++++ src/scene.S | 149 ++++++ src/spritetex.S | 75 +++ src/tilegod.S | 65 +++ src/wm_player.cpp | 192 +++++++ src/wmresourcemng.cpp | 78 +++ src/world_camera.cpp | 94 ++++ src/worldmap.cpp | 245 +++++++++ src/worldmap.h | 211 ++++++++ src/worldmap_new.cpp | 1358 +++++++++++++++++++++++++++++++++++++++++++++++++ src/worldmapdata.cpp | 93 ++++ src/worldmapdata.h | 149 ++++++ 34 files changed, 6324 insertions(+) create mode 100644 src/animtiles.cpp create mode 100644 src/anotherhax.S create mode 100644 src/asmlib.S create mode 100644 src/fileload.cpp create mode 100644 src/fileload.h create mode 100644 src/g3dwrap.cpp create mode 100644 src/gakenoko.S create mode 100644 src/heapbar.S create mode 100644 src/heapbar.cpp create mode 100644 src/layoutlib.S create mode 100644 src/layoutlib.h create mode 100644 src/levelinfo.cpp create mode 100644 src/levelinfo.h create mode 100644 src/levelnames.cpp create mode 100644 src/linegod.S create mode 100644 src/linegod.cpp create mode 100644 src/msgbox.S create mode 100644 src/msgbox.cpp create mode 100644 src/poweruphax.S create mode 100644 src/randomcrap.S create mode 100644 src/randtiles.cpp create mode 100644 src/randtiles.h create mode 100644 src/replay.S create mode 100644 src/scene.S create mode 100644 src/spritetex.S create mode 100644 src/tilegod.S create mode 100644 src/wm_player.cpp create mode 100644 src/wmresourcemng.cpp create mode 100644 src/world_camera.cpp create mode 100644 src/worldmap.cpp create mode 100644 src/worldmap.h create mode 100644 src/worldmap_new.cpp create mode 100644 src/worldmapdata.cpp create mode 100644 src/worldmapdata.h (limited to 'src') diff --git a/src/animtiles.cpp b/src/animtiles.cpp new file mode 100644 index 0000000..26cdbf8 --- /dev/null +++ b/src/animtiles.cpp @@ -0,0 +1,61 @@ +#include +#include +#include "fileload.h" + +struct AnimDef_Header { + u32 magic; + u32 entryCount; +}; + +struct AnimDef_Entry { + u16 texNameOffset; + u16 frameDelayOffset; + u16 tileNum; + u8 tilesetNum; + u8 reverse; +}; + +FileHandle fh; + +void DoTiles(void* self) { + //OSReport("fucker\n"); + AnimDef_Header *header; + + header = (AnimDef_Header*)LoadFile(&fh, "/NewerRes/AnimTiles.bin"); + + if (!header) { + OSReport("anim load fail\n"); + return; + } + + if (header->magic != 'NWRa') { + OSReport("anim info incorrect\n"); + FreeFile(&fh); + return; + } + + AnimDef_Entry *entries = (AnimDef_Entry*)(header+1); + + OSReport("Loading animated tiles\n"); + + for (int i = 0; i < header->entryCount; i++) { + AnimDef_Entry *entry = &entries[i]; + char *name = (char*)fh.filePtr+entry->texNameOffset; + char *frameDelays = (char*)fh.filePtr+entry->frameDelayOffset; + + char realName[0x40]; + snprintf(realName, 0x40, "BG_tex/%s", name); + + void *blah = BgTexMng__LoadAnimTile(self, entry->tilesetNum, entry->tileNum, realName, frameDelays, entry->reverse); + + OSReport("[%d] %s %08x\n", i, name, blah); + //OSReport("Returned: %08x\n", blah); + } + + OSReport("Animated tiles complete\n"); +} + + +void DestroyTiles(void *self) { + FreeFile(&fh); +} diff --git a/src/anotherhax.S b/src/anotherhax.S new file mode 100644 index 0000000..ca0a658 --- /dev/null +++ b/src/anotherhax.S @@ -0,0 +1,23 @@ +.set sp, 1 + +.extern continueFromFlagObjCheck +.extern returnFromFlagObjCheck + +.global fix38WithJumpCoin + +.text + +fix38WithJumpCoin: + # hacky fix because I can't figure out how to do it the right way + + # check actor type for EN_COIN_JUMP + lhz r0, 8(r3) + cmplwi r0, 403 + bne dontContinue + b continueFromFlagObjCheck +dontContinue: + + # it wasn't that, so just return 0 + li r3, 0 + b returnFromFlagObjCheck + diff --git a/src/asmlib.S b/src/asmlib.S new file mode 100644 index 0000000..80cf4eb --- /dev/null +++ b/src/asmlib.S @@ -0,0 +1,182 @@ +#undef DEBUG + +.text + +.extern _savegpr_21 +.extern _restgpr_21 +.extern OSReport + +.set data, 31 +.set inp_top, 30 +.set outp, 29 +.set inp, 28 +.set outp_save, 27 +.set flag, 26 +.set count8, 25 +.set index, 24 +.set len, 23 +.set t_temp, 22 + +.set sp, 1 + +.global UncompressBackward +UncompressBackward: + stwu sp, -0x40(sp) + mflr r0 + stw r0, 0x44(sp) + addi r11, sp, 0x40 + bl _savegpr_21 + + cmpwi r3, 0 + beq exit + + # endianness issues are annoying. + li r9, -4 + lwbrx outp, r3, r9 + + li r9, -8 + lwbrx inp_top, r3, r9 + + #lbz r6, -4(r3) + #lbz r7, -3(r3) + #lbz r8, -2(r3) + #lbz r9, -1(r3) + #slwi r9, r9, 24 + #slwi r8, r8, 16 + #slwi r7, r6, 8 + #or r9, r9, r8 + #or r9, r9, r7 + #or inp_top, r9, r6 + + #lbz r6, -8(r3) + #lbz r7, -7(r3) + #lbz r8, -6(r3) + #lbz r9, -5(r3) + #slwi r9, r9, 24 + #slwi r8, r8, 16 + #slwi r7, r6, 8 + #or r9, r9, r8 + #or r9, r9, r7 + #or outp, r9, r6 + + add outp, r3, outp + srwi t_temp, inp_top, 24 + sub inp, r3, t_temp + + clrlwi inp_top, inp_top, 8 + sub inp_top, r3, inp_top + mr outp_save, outp + +#ifdef DEBUG + crclr 4*cr0+eq + lis r3, Start@h + ori r3, r3, Start@l + mr r4, outp + mr r5, inp + bl OSReport +#endif + +loop: + cmpw inp, inp_top + ble end_loop + lbzu flag, -1(inp) + +#ifdef DEBUG + crclr 4*cr0+eq + lis r3, MFlag@h + ori r3, r3, MFlag@l + mr r4, outp + mr r5, inp + mr r6, flag + bl OSReport +#endif + + li count8, 8 +loop8: + subi count8, count8, 1 + cmpwi count8, 0 + blt loop + + andi. r12, flag, 0x80 + bne blockcopy +bytecopy: +#ifdef DEBUG + crclr 4*cr0+eq + lis r3, MOne@h + ori r3, r3, MOne@l + mr r4, outp + mr r5, inp + lbz r6, -1(inp) + lbz r7, -1(inp) + bl OSReport +#endif + + lbzu data, -1(inp) + stbu data, -1(outp) + b joinhere + +blockcopy: + lbz len, -1(inp) + lbz index, -2(inp) + slwi t_temp, len, 8 + or index, index, t_temp + clrlwi index, index, 20 + addi index, index, 2 + srwi len, len, 4 + addi len, len, 2 + +#ifdef DEBUG + crclr 4*cr0+eq + lis r3, MTwo@h + ori r3, r3, MTwo@l + mr r4, outp + mr r5, inp + mr r6, len + mr r7, index + bl OSReport +#endif + + subi inp, inp, 2 + +patterncopy: + lbzx data, outp, index + stbu data, -1(outp) + subi len, len, 1 + cmpwi len, 0 + bge patterncopy + +joinhere: + cmpw inp, inp_top + slwi flag, flag, 1 + bgt loop8 + +end_loop: +exit: +#ifdef DEBUG + crclr 4*cr0+eq + lis r3, Done@h + ori r3, r3, Done@l + mr r4, outp + mr r5, inp + bl OSReport +#endif + + addi r11, sp, 0x40 + bl _restgpr_21 + lwz r0, 0x44(sp) + mtlr r0 + addi sp, sp, 0x40 + blr + + + + +.data +Start: .string "[O=%p I=%p] START\n" +MFlag: .string "[O=%p I=%p] Flag: %02x\n" +MOne: .string "[O=%p I=%p] Copy: %02x [%c]\n" +MTwo: .string "[O=%p I=%p] Copy: %02x bytes from offset %06x\n" +Done: .string "[O=%p I=%p] END\n" + +.align 4 + diff --git a/src/fileload.cpp b/src/fileload.cpp new file mode 100644 index 0000000..5f60e8c --- /dev/null +++ b/src/fileload.cpp @@ -0,0 +1,134 @@ +#include "fileload.h" + +extern "C" void UncompressBackward(void *bottom); + + +void *LoadFile(FileHandle *handle, const char *name) { + OSReport("[LoadFile %s]\n", name); + + int entryNum = DVDConvertPathToEntrynum(name); + + DVDHandle dvdhandle; + if (!DVDFastOpen(entryNum, &dvdhandle)) { + OSReport("Cannot open file %s [%d]\n", name, entryNum); + return 0; + } + + handle->length = dvdhandle.length; + handle->filePtr = EGG__Heap__alloc((handle->length+0x1F) & ~0x1F, 0x20, GetArchiveHeap()); + + int ret = DVDReadPrio(&dvdhandle, handle->filePtr, (handle->length+0x1F) & ~0x1F, 0, 2); + + DVDClose(&dvdhandle); + + OSReport("[Success %p]\n", handle->filePtr); + + return handle->filePtr; +} + +void *LoadCompressedFile(FileHandle *handle, const char *name) { + OSReport("[LoadCompressedFile %s]\n", name); + + int entryNum = DVDConvertPathToEntrynum(name); + + DVDHandle dvdhandle; + if (!DVDFastOpen(entryNum, &dvdhandle)) { + OSReport("Cannot open file %s [%d]\n", name, entryNum); + return 0; + } + + u32 infoBlock[0x20 / sizeof(u32)] __attribute__ ((aligned(32))); + DVDReadPrio(&dvdhandle, infoBlock, 0x20, dvdhandle.length - 8, 2); + + // Reverse it! + infoBlock[1] = (infoBlock[1] >> 24) | ((infoBlock[1] >> 8) & 0xFF00) | ((infoBlock[1] & 0xFF00) << 8) | ((infoBlock[1] & 0xFF) << 24); + + u32 uncompSize = dvdhandle.length + infoBlock[1]; + OSReport("[Comp:%d UnComp:%d]\n", dvdhandle.length, uncompSize); + handle->length = uncompSize; + handle->filePtr = EGG__Heap__alloc((uncompSize+0x1F) & ~0x1F, 0x20, GetArchiveHeap()); + + int ret = DVDReadPrio(&dvdhandle, handle->filePtr, (dvdhandle.length+0x1F) & ~0x1F, 0, 2); + + DVDClose(&dvdhandle); + + UncompressBackward((void*)((u32)handle->filePtr + dvdhandle.length)); + + OSReport("[Success %p]\n", handle->filePtr); + + return handle->filePtr; +} + +bool FreeFile(FileHandle *handle) { + if (!handle) return false; + + if (handle->filePtr) { + OSReport("[FreeFile %p]\n", handle->filePtr); + EGG__Heap__free(handle->filePtr, GetArchiveHeap()); + } + + handle->filePtr = 0; + handle->length = 0; + + return true; +} + + + + +File::File() { + m_loaded = false; +} + +File::~File() { + close(); +} + +bool File::open(const char *filename) { + if (m_loaded) + close(); + + void *ret = LoadFile(&m_handle, filename); + if (ret != 0) + m_loaded = true; + + return (ret != 0); +} + +bool File::openCompressed(const char *filename) { + if (m_loaded) + close(); + + void *ret = LoadCompressedFile(&m_handle, filename); + if (ret != 0) + m_loaded = true; + + return (ret != 0); +} + +void File::close() { + if (!m_loaded) + return; + + m_loaded = false; + FreeFile(&m_handle); +} + +bool File::isOpen() { + return m_loaded; +} + +void *File::ptr() { + if (m_loaded) + return m_handle.filePtr; + else + return 0; +} + +u32 File::length() { + if (m_loaded) + return m_handle.length; + else + return 0xFFFFFFFF; +} + diff --git a/src/fileload.h b/src/fileload.h new file mode 100644 index 0000000..5dcdb2b --- /dev/null +++ b/src/fileload.h @@ -0,0 +1,74 @@ +#ifndef __NEWER_FILELOAD_H +#define __NEWER_FILELOAD_H + +#include + +struct FileHandle { + void *filePtr; + int length; +}; + +struct DVDHandle { + int unk1; // 00 + int unk2; // 04 + int unk3; // 08 + int unk4; // 0C + int unk5; // 10 + int unk6; // 14 + int unk7; // 18 + int unk8; // 1C + int unk9; // 20 + int unk10; // 24 + int unk11; // 28 + int unk12; // 2C + int address; // 30 + int length; // 34 + int unk13; // 38 +}; + + +int DVDConvertPathToEntrynum(const char *path); +bool DVDFastOpen(int entrynum, DVDHandle *handle); +int DVDReadPrio(DVDHandle *handle, void *buffer, int length, int offset, int unk); +bool DVDClose(DVDHandle *handle); + +// EGG::Heap +void *EGG__Heap__alloc(unsigned long size, int unk, void *heap); +void EGG__Heap__free(void *ptr, void *heap); + +void *LoadFile(FileHandle *handle, const char *name); +void *LoadCompressedFile(FileHandle *handle, const char *name); +bool FreeFile(FileHandle *handle); + +void inline *GetArchiveHeap() { + return ArchiveHeap; + +} + + +// C++ interface +class File { +public: + File(); + ~File(); + + bool open(const char *filename); + void close(); + + bool openCompressed(const char *filename); + + bool isOpen(); + + void *ptr(); + u32 length(); + +private: + FileHandle m_handle; + bool m_loaded; +}; + + +// Todo: input stream maybe? + +#endif + diff --git a/src/g3dwrap.cpp b/src/g3dwrap.cpp new file mode 100644 index 0000000..644c5e8 --- /dev/null +++ b/src/g3dwrap.cpp @@ -0,0 +1,90 @@ +// nw4r::g3d wrapper + +namespace nw4r { +namespace g3d { + +class ResFile { + void * /*ResFileData*/ data; + + ResFile(void *p = NULL); + + void Init(); + bool CheckRevision() const; + + void * /*ResMdl*/ GetResMdl(const char *str) const; + void * /*ResPltt*/ GetResPltt(const ResName n) const; + void * /*ResTex*/ GetResTex(const char *str) const; + void * /*ResTex*/ GetResTex(const ResName n) const; + void * /*ResTex*/ GetResTex(u32 idx) const; + void * /*ResAnmChr*/ GetResAnmChr(const char *str) const; + void * /*ResAnmVis*/ GetResAnmVis(const char *str) const; + void * /*ResAnmClr*/ GetResAnmClr(const char *str) const; + void * /*ResAnmTexPat*/ GetResAnmTexPat(const char *str) const; + void * /*ResAnmTexSrt*/ GetResAnmTexSrt(const char *str) const; + void * /*ResAnmScn*/ GetResAnmScn(const char *str) const; + + bool Bind(ResFile rhs); +}; + +void *__ScnMdl__Construct( + void * /*MEMAllocator*/ pHeap, + u32 *pSize, + void * /*ResMdl*/ mdl, + u32 bufferOption, + int nView = 1); + + +void *__AnmObjChrRes__Construct( + void * /*MEMAllocator*/ pHeap, + u32 *pSize, + void * /*ResAnmChr*/ resAnm, + void * /*ResMdl*/ resMdl, + bool bHasCache); + + +void *__AnmObjVisRes__Construct( + void * /*MEMAllocator*/ pHeap, + u32 *pSize, + void * /*ResAnmVis*/ resAnm, + void * /*ResMdl*/ resMdl); + + +void *__AnmObjTexPatRes__Construct( + void * /*MEMAllocator*/ pHeap, + u32 *pSize, + void * /*ResAnmTexPat*/ resAnm, + void * /*ResMdl*/ resMdl, + bool bHasCache); + + +void *__AnmObjTexSrtRes__Construct( + void * /*MEMAllocator*/ pHeap, + u32 *pSize, + void * /*ResAnmTexSrt*/ resAnm, + void * /*ResMdl*/ resMdl, + bool bHasCache); + + +void *__AnmObjMatClrRes__Construct( + void * /*MEMAllocator*/ pHeap, + u32 *pSize, + void * /*ResAnmMatClr*/ resAnm, + void * /*ResMdl*/ resMdl, + bool bHasCache); + + +void *__AnmObjShpRes__Construct( + void * /*MEMAllocator*/ pHeap, + u32 *pSize, + void * /*ResAnmShp*/ resAnm, + void * /*ResMdl*/ resMdl, + bool bHasCache); + + + +bool InsertIntoScene(void *scnObj); // 80164F90 + + + +} +} \ No newline at end of file diff --git a/src/gakenoko.S b/src/gakenoko.S new file mode 100644 index 0000000..9443ce4 --- /dev/null +++ b/src/gakenoko.S @@ -0,0 +1,220 @@ +# GAKE CLASS LAYOUT +# +# 524: SomeMHeapAllocatorSubclass +# 540: 0 [[ResFile maybe?]] +# 544: mdl_c +# 584: SomeModelAnimationClass +# 5BC: ResAnmTexPat (maybe?) +# 5C0: Some type of animation: 80329890 +# 5C4: Set to 0 in ctor +# 5C8: Set to 0 in ctor +# 5CC: mAllocator_c +# 5F4: EGG::Effect subclass 80329CA0 +# +# +# NET CLASS LAYOUT +# +# 524: 0 +# 528: SomeMHeapAllocatorSubclass +# 544: ResFile +# 548: mdl_c +# 588: SomeModelAnimationClass +# 5C0: ResAnmTexPat +# 5C4: Some type of animation: 80329890 +# 5C8: Set to 0 in ctor +# 5CC: Set to 0 in ctor +# 5D0: mAllocator_c + +.extern mHeapAllocatorSubclass_Link +.extern mHeapAllocatorSubclass_UnLink +.extern RetrieveFileFromArc +.extern GetResMdl +.extern m3d__mdl_c__DoStuff +.extern sub_80064BD0 +.extern GetResAnmChr +.extern SomeModelAnimationClass_Setup +.extern GetResAnmTexPat +.extern sub_80166970 +.extern sub_80166D10 +.extern daEnGakeNoko_c__StateID_FoolMove + +#ifndef __MWERKS__ +.set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3 +#endif + +.set sp,1 +.set rtoc,2 +.set this,31 + +.text + +.align 4 +.global gakenoko_create + +.set AnmTexPat,0x24 +.set ResMdlForTexPat,0x20 +.set AnmChr,0x1C +.set ResMdlForChr,0x18 +.set ResMdlForScnMdl,0x14 +.set AnmTexPatAgain,0x10 + +# Stack layout: +# 0x34 : LR +# 0x30 : SP +# 0x2C : save this +# 0x28 : save r30 +# 0x24 : AnmTexPat +# 0x20 : ResMdlForTexPat +# 0x1C : AnmChr +# 0x18 : ResMdlForChr +# 0x14 : ResMdlForScnMdl +# 0x10 : AnmTexPatAgain + +# Local register vars: +# r31 = this +# r30 = resmdl + +gakenoko_create: + stwu r1, -0x30(sp) + mflr r0 + stw r0, 0x34(sp) + stw this, 0x2C(sp) + stw r30, 0x28(sp) + + mr this, r3 + + # Create a heap + addi r3, r3, 0x524 # SomeMHeapAllocatorSubclass + li r4, -1 + lis r5, 0x8037 + lwz r5, 0x7F48(r5) + bl mHeapAllocatorSubclass_Link + + # Get ResFile + lwz r3, -0x5668(r13) + addi r3, r3, 4 + lis r4, arcName@h + ori r4, r4, arcName@l + lis r5, fileName@h + ori r5, r5, fileName@l + bl RetrieveFileFromArc + + stw r3, 0x540(this) + + # Get model + addi r3, this, 0x540 # ResFile + lis r4, arcName@h + ori r4, r4, arcName@l + bl GetResMdl + + mr r30, r3 + stw r3, ResMdlForScnMdl(sp) # store resmdl + + # Do scnmdl stuff + addi r3, this, 0x544 # mdl_c + addi r4, sp, ResMdlForScnMdl + addi r5, this, 0x524 # SomeMHeapAllocatorSubclass + li r6, 0x7fff + li r7, 1 + li r8, 0 + bl m3d__mdl_c__DoStuff + + addi r3, this, 0x544 # mdl_c + bl sub_80064BD0 + + # Handle anim + addi r3, this, 0x540 # ResFile + lis r4, animName@h + ori r4, r4, animName@l + bl GetResAnmChr + + stw r3, AnmChr(sp) + + # Set it up + stw r30, ResMdlForChr(sp) + + addi r3, this, 0x584 # SomeModelAnimationClass + addi r4, sp, ResMdlForChr + addi r5, sp, AnmChr + addi r6, this, 0x524 # SomeMHeapAllocatorSubclass + li r7, 0 + bl SomeModelAnimationClass_Setup + + # Now handle the texpat anim + addi r3, this, 0x540 # ResFile + lis r4, arcName@h + ori r4, r4, arcName@l + bl GetResAnmTexPat + + stw r3, 0x5BC(this) # ResAnmTexPat + stw r3, AnmTexPat(sp) + + # Set it up + stw r30, ResMdlForTexPat(sp) + + addi r3, this, 0x5C0 # Weird Animation + addi r4, sp, ResMdlForTexPat + addi r5, sp, AnmTexPat + addi r6, this, 0x524 # SomeMHeapAllocatorSubclass + li r7, 0 + li r8, 1 + bl sub_80166970 + + + lwz r0, 0x5BC(this) + stw r0, AnmTexPatAgain(sp) + + addi r3, this, 0x5C0 # Weird Animation + addi r4, this, 0x544 # mdl_c + addi r5, sp, AnmTexPatAgain + li r6, 0 + li r7, 1 + bl sub_80166D10 + + # Unbind the MHeapAllocatorSubclass + addi r3, this, 0x524 # SomeMHeapAllocatorSubclass + bl mHeapAllocatorSubclass_UnLink + + + # Model's done + # Set a state + mr r3, this + lis r4, daEnGakeNoko_c__StateID_FoolMove@h + ori r4, r4, daEnGakeNoko_c__StateID_FoolMove@l + + lwz r12, 0x60(this) + lwz r12, 0xD4(r12) + mtctr r12 + + + li r3, 1 + + # Clean up stack + lwz r0, 0x34(sp) + lwz this, 0x2C(sp) + lwz r30, 0x28(sp) + mtlr r0 + addi sp, sp, 0x30 + + blr + + +.data + +fileName: + .string "g3d/nokonokoB.brres" + +arcName: + .string "nokonokoB" + +animName: + .string "net_walk2" + +debugString: + .string "X> %08x\n" diff --git a/src/heapbar.S b/src/heapbar.S new file mode 100644 index 0000000..35d45e5 --- /dev/null +++ b/src/heapbar.S @@ -0,0 +1,118 @@ +# memory debugger - fun! +# GX stuff is implemented in C++, this just gets the lowlevel info + +#ifndef __MWERKS__ +.set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3 +#endif + +#define HEAP_EGGRootMEM1 1 +#define HEAP_EGGRootMEM2 2 + +.extern cppGXStart +.extern cppGXEnd +.extern cppProcessHeap +.extern MEMGetTotalFreeSizeForExpHeap +.extern GameHeap1 +.extern GameHeap2 + +.set sp,1 +.set rtoc,2 +.set this,31 + +.text + +.align 4 + +.global doHeapBar + +doHeapBar: + blr + + stwu sp, -0x10(sp) + mflr r0 + stw r0, 0x14(sp) + + stw this, 0xC(sp) + + #lis r3, EGGTSystem_Pointer@h + #ori r3, r3, EGGTSystem_Pointer@l + #lwz this, 0(r3) + + bl cppGXStart + + #lwz r3, 0x18(this) + #lis r3, dSys_c__RootHeapMEM1@h + #ori r3, r3, dSys_c__RootHeapMEM1@l + lis r3, GameHeap1@h + ori r3, r3, GameHeap1@l + lwz r3, 0(r3) + li r4, HEAP_EGGRootMEM1 + bl asmProcessHeap + + #lwz r3, 0x1C(this) + #lis r3, dSys_c__RootHeapMEM2@h + #ori r3, r3, dSys_c__RootHeapMEM2@l + lis r3, GameHeap2@h + ori r3, r3, GameHeap2@l + lwz r3, 0(r3) + li r4, HEAP_EGGRootMEM2 + bl asmProcessHeap + + bl cppGXEnd + + lwz this, 0xC(sp) + lwz r0, 0x14(sp) + mtlr r0 + addi sp, sp, 0x10 + blr + + + +asmProcessHeap: + + stwu sp, -0x10(sp) + mflr r0 + stw r0, 0x14(sp) + + stw r31, 0xC(sp) + stw r30, 0x8(sp) + + mr r31, r3 + mr r30, r4 + + # get all the required data from the heap + # cppProcessHeap(u32 freeSize, u32 heapSize, int heapID, char *name) + + # get free size first so the function doesn't destroy our volatile regs + # because I'm too lazy to save them >.> + lwz r3, 0x10(r31) + bl MEMGetTotalFreeSizeForExpHeap + + # get name + lwz r6, 0x34(r31) + + # get heapID + mr r5, r30 + + # get heap size + # this was a fucking pain to figure out -_- + lwz r4, 0x10(r31) # get the MEMiHeapHead* + lwz r7, 0x18(r4) # get heapStart + lwz r8, 0x1C(r4) # get heapEnd + sub r4, r8, r7 # heapSize = heapEnd - heapStart probably + + # now do it + bl cppProcessHeap + + lwz r30, 0x8(sp) + lwz r31, 0xC(sp) + lwz r0, 0x14(sp) + mtlr r0 + addi sp, sp, 0x10 + blr diff --git a/src/heapbar.cpp b/src/heapbar.cpp new file mode 100644 index 0000000..3759b22 --- /dev/null +++ b/src/heapbar.cpp @@ -0,0 +1,147 @@ +#define GEKKO + +#include +#include "rvl/mtx.h" +#include "rvl/GXEnum.h" +#include "rvl/GXStruct.h" +#include "rvl/GXTransform.h" +#include "rvl/GXGeometry.h" +#include "rvl/GXDispList.h" +#include "rvl/GXLighting.h" +#include "rvl/GXTev.h" +#include "rvl/GXTexture.h" +#include "rvl/GXCull.h" +#include "rvl/GXPixel.h" +#include "rvl/GXBump.h" +//#include "rvl/GXVert.h" +#include "rvl/vifuncs.h" + +extern u32 Global5758; + +#define GXPosition3f32(x,y,z) \ + *((volatile float*)0xCC008000) = (x); \ + *((volatile float*)0xCC008000) = (y); \ + *((volatile float*)0xCC008000) = (z); + +#define GXColor1u32(x) \ + *((volatile u32*)0xCC008000) = (x); + + +extern "C" { + + +void cppGXStart() { + Mtx44 ortho; + + MTXOrtho(ortho, 0, 456, 0, 686, 0.0F, 1.0F); + GXSetProjection(ortho, GX_ORTHOGRAPHIC); + + Mtx identity; + MTXIdentity(identity); + + GXLoadPosMtxImm(identity, GX_PNMTX0); + + GXSetNumTevStages(1); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GXSetTevDirect(GX_TEVSTAGE0); + + GXSetNumChans(1); + GXSetChanCtrl(GX_COLOR0A0, GX_DISABLE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); + + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBX8, 0); + + GXSetZMode(GX_TRUE, GX_ALWAYS, GX_TRUE); +} + +void cppGXEnd() { +} + + + +float y_positions[] = { + -1, + 0.0, + 16.0 +}; + +u32 colours[] = { + -1, + 0x0000ffff, + 0xff0000ff +}; + +u32 col_5758[] = { + 0x00ff00ff, + 0xffff00ff, + 0x00ffffff, + 0xf0ff0fff +}; + +void cppProcessHeap(u32 freeSize, u32 heapSize, int heapID, char *name) { + // get the info needed + float y_pos = y_positions[heapID]; + u32 colour = colours[heapID]; + + // width: 686 + + //OSReport("%s => size %d, free %d\n", name, heapSize, freeSize); + + float left = 0; + float right = ((heapSize - freeSize) * 686.0f) / heapSize; + float top = y_pos; + float bottom = y_pos+16; + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + + GXPosition3f32(left, top, 0.0); + GXColor1u32(colour); + GXPosition3f32(right, top, 0.0); + GXColor1u32(colour); + GXPosition3f32(right, bottom, 0.0); + GXColor1u32(colour); + GXPosition3f32(left, bottom, 0.0); + GXColor1u32(colour); + + GXEnd(); + + + GXBegin(GX_QUADS, GX_VTXFMT0, 16); + + for (int i = 0; i < 4; i++) { + GXPosition3f32(16*i, 32, 0.0); + GXColor1u32(col_5758[i]); + GXPosition3f32(16*i+16, 32, 0.0); + GXColor1u32(col_5758[i]); + GXPosition3f32(16*i+16, 48, 0.0); + GXColor1u32(col_5758[i]); + GXPosition3f32(16*i, 48, 0.0); + GXColor1u32(col_5758[i]); + } + + GXEnd(); + + for (int i = 0; i < 4; i++) { + if (Global5758 & (1 << i)) { + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + + GXPosition3f32(16*i, 48, 0.0); + GXColor1u32(0xffffffff); + GXPosition3f32(16*i+16, 48, 0.0); + GXColor1u32(0xffffffff); + GXPosition3f32(16*i+16, 56, 0.0); + GXColor1u32(0xffffffff); + GXPosition3f32(16*i, 56, 0.0); + GXColor1u32(0xffffffff); + + GXEnd(); + } + } +} + + +}; diff --git a/src/layoutlib.S b/src/layoutlib.S new file mode 100644 index 0000000..2fae70a --- /dev/null +++ b/src/layoutlib.S @@ -0,0 +1,131 @@ +.extern LayoutHelper_Link + +#ifndef __MWERKS__ +.extern _Z8LoadFileP10FileHandlePc +.extern _Z8FreeFileP10FileHandle +#define LoadFileFunc _Z8LoadFileP10FileHandlePc +#define FreeFileFunc _Z8FreeFileP10FileHandle +.set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3 +#else +.extern LoadFile__FP10FileHandlePCc +.extern FreeFile__FP10FileHandle +#define LoadFileFunc LoadFile__FP10FileHandlePCc +#define FreeFileFunc FreeFile__FP10FileHandle +#endif + +.text + +.set sp,1 +.set rtoc,2 +.set this,31 + + + + +.global EmbeddedLayout_LoadArc +EmbeddedLayout_LoadArc: + # stack setup + stwu sp, -0x20(sp) + mflr r0 + stw r0, 0x24(sp) + stw r31, 0x1C(sp) + stw r30, 0x18(sp) + + # r31 is a pointer to the LayoutHelper (must be converted) + # r30 stores the filename + addi r31, r3, 0xAC + mr r30, r4 + + # check to see if an arc has already been loaded + lwz r0, 0xBC(r3) + cmpwi r0, 0 + bne return_0 + + # ok, no + # create a FileHandle where a NSMBWFile would be + # don't know if this will work but it's worth a try + addi r3, r31, 0xC0 + mr r4, r30 + bl LoadFileFunc + + # check retval + cmpwi r3, 0 + stw r3, 0xBC(r31) + beq return_0 + + # link it + mr r4, r3 + mr r3, r31 + lis r5, arcString@h + ori r5, r5, arcString@l + bl LayoutHelper_Link + + # now add a pointer to the LayoutHelper into the Layout at offset 0x84 + # turn r3 into an EmbeddedLayout pointer + subi r3, r31, 0xAC + stw r31, 0x84(r3) + + b return_1 + +return_0: + li r3, 0 + b return + +return_1: + li r3, 1 + +return: + lwz r30, 0x18(sp) + lwz r31, 0x1C(sp) + lwz r0, 0x24(sp) + mtlr r0 + addi sp, sp, 0x20 + blr + +.align 4 + +.global EmbeddedLayout_FreeArc +EmbeddedLayout_FreeArc: + # stack setup + stwu sp, -0x10(sp) + mflr r0 + stw r0, 0x14(sp) + stw r31, 0xC(sp) + + # r31 is a pointer to the LayoutHelper (must be converted) + addi r31, r3, 0xAC + + # - if an arc has been loaded, then free the NSMBWFile + lwz r0, 0xBC(r3) + cmpwi r0, 0 + beq xreturn_1 + + # no, so free it + addi r3, r31, 0xC0 + bl FreeFileFunc + + li r3, 0 + stw r3, 0xBC(r31) + +xreturn_1: + li r3, 1 + lwz r31, 0xC(sp) + lwz r0, 0x14(sp) + mtlr r0 + addi sp, sp, 0x10 + blr + + + +.data +arcString: + .string "arc" + +.align 4 + diff --git a/src/layoutlib.h b/src/layoutlib.h new file mode 100644 index 0000000..6b7d275 --- /dev/null +++ b/src/layoutlib.h @@ -0,0 +1,149 @@ +#ifndef __NEWER_LAYOUTLIB_H +#define __NEWER_LAYOUTLIB_H + +/* Treeki's LayoutLib for New Super Mario Bros Wii */ +#include + +typedef float MTX[3][4]; + +struct nw4r__lyt__Layout { + void *vtable; + void *field_04; + void *field_08; + void *field_0C; + void *rootPane; + void *field_14; + void *field_18; + void *field_1C; +}; + +struct nw4r__lyt__DrawInfo { + // 0x00 + void *vtable; + MTX matrix; + + // 0x34 + float left; + float top; + float right; + + // 0x40 + float bottom; + float scale_x; + float scale_y; + float opacity; + + // 0x50 + unsigned char widescreenFlag; +}; + +struct FrameCtrl_c { + +}; + +struct Anm_c { + FrameCtrl_c *fc_ptr; + void *brlanHandler; + void *field_08; + char field_0C; + char pad[3]; + FrameCtrl_c fc; +}; + +struct Layout { + void *field_00; + void *field_04; + void *vtable; + unsigned char drawOrder; // 0x0C + char pad1[3]; + + // offset 0x10 + nw4r__lyt__Layout layout; // Actually m2d::Layout_c, but the struct is the same + + // offset 0x30 + nw4r__lyt__DrawInfo drawInfo; + + // offset 0x84 + //LayoutHelper *field_84; + void *field_84; + float posX; // 0x88 + float posY; // 0x8C + float clipX; // 0x90 + float clipY; // 0x94 + float clipWidth; // 0x98 + float clipHeight; // 0x9C + unsigned char clipEnabled; // 0xA0 + char pad2[3]; + unsigned int animEnabled; // 0xA4 + void *field_A8; + + // offset 0xAC + //LayoutHelper lh; // actually a m2d::ResAccLoader_c + char lh[0xD4]; // don't feel like figuring this one out -_- + + // offset 0x180 + //BrlanHandler *brlanHandlers; // 0x180, points to brlan handlers + void *brlanHandlers; + //GrpHandler *grpHandlers; // 0x184 + void *grpHandlers; + char *field_188; // char array, probably "anim enabled" + int brlanCount; // 0x18C + int grpCount; // 0x190 + int field_194; // no idea +}; + + +void EmbeddedLayout_ctor(Layout *self); // 0x800C89A0 +void EmbeddedLayout_dtor(Layout *self, bool del); // 0x800C89F0 +void EmbeddedLayout_Free(Layout *self); // 0x800C9A20 +bool EmbeddedLayout_LoadArcOld(Layout *self, const char *path, bool isLangSpecific); // 0x800C8D00 + +extern "C" { +bool EmbeddedLayout_LoadArc(Layout *self, const char *path); // custom +bool EmbeddedLayout_FreeArc(Layout *self); // custom +}; + +void EmbeddedLayout_LoadBrlans(Layout *self, const char **names, int count); // 0x800C90A0 +void EmbeddedLayout_LoadGroups(Layout *self, const char **names, int *brlanLinkIDs, int count); // 0x800C91E0 + +void EmbeddedLayout_AddToDrawList(Layout *self); // 0x80163990 + +void *EmbeddedLayout_FindPaneByName(Layout *self, const char *name); +void *EmbeddedLayout_FindTextBoxByName(Layout *self, const char *name); +void *EmbeddedLayout_FindPictureByName(Layout *self, const char *name); +void *EmbeddedLayout_FindWindowByName(Layout *self, const char *name); + +void EmbeddedLayout_EnableNonLoopAnim(Layout *self, int animNum, bool pointlessShit); // 0x800C93E0 +void EmbeddedLayout_EnableLoopAnim(Layout *self, int animNum); // 0x800C9470 +void EmbeddedLayout_ResetAnimToInitialState(Layout *self, int animNum, bool isLoop_maybe); // 0x800C94C0 +void EmbeddedLayout_DisableAnim(Layout *self, int animNum); // 0x800C9580 +void EmbeddedLayout_DisableAllAnims(Layout *self); // 0x800C95F0 +void EmbeddedLayout_Process(Layout *self); // 0x800C9650 +bool EmbeddedLayout_CheckIfAnimationIsOn(Layout *self, int animNum); // 0x800C9700 +bool EmbeddedLayout_CheckIfAnyAnimationsAreOn(Layout *self); // 0x800C9730 + + +typedef bool (*__EmbeddedLayout_Build_type)(Layout*, const char*, void*); +inline bool EmbeddedLayout_Build(Layout *self, const char *brlytName, void *lh) { + VF_BEGIN(__EmbeddedLayout_Build_type, self, 5, 8) + return VF_CALL(self, brlytName, lh); + VF_END; +} + +typedef void (*__EmbeddedLayout_UpdateMatrix_type)(Layout*); +inline void EmbeddedLayout_UpdateMatrix(Layout *self) { + VF_BEGIN(__EmbeddedLayout_UpdateMatrix_type, self, 4, 8) + VF_CALL(self); + VF_END; +} + +typedef void (*__TextBox_SetString_type)(void*, unsigned short const *, unsigned short); +inline void TextBox_SetString(void *self, unsigned short const *str, unsigned short unk) { + VF_BEGIN(__TextBox_SetString_type, self, 31, 0) + VF_CALL(self, str, unk); + VF_END; +} + +#define PANE_FLAGS(pane) (*((u8*)(((u32)(pane))+0xBB))) + +#endif diff --git a/src/levelinfo.cpp b/src/levelinfo.cpp new file mode 100644 index 0000000..9807fc4 --- /dev/null +++ b/src/levelinfo.cpp @@ -0,0 +1,36 @@ +#include "levelinfo.h" + +void LevelInfo_Prepare(FileHandle *fh) { + void *file = fh->filePtr; + + // decrypt all the level names + for (int sect = 0; sect < LevelInfo_GetSectionCount(file); sect++) { + // parse this section + LevelInfo_Section *thisSect = LevelInfo_GetSection(file, sect); + LevelInfo_Entry *levels = LevelInfo_GetLevels(file, thisSect); + + for (int lev = 0; lev < thisSect->levelCount; lev++) { + LevelInfo_Entry *level = &levels[lev]; + + char *name = LevelInfo_GetName(file, level); + + for (int i = 0; i < level->nameLength+1; i++) { + name[i] -= 0xD0; + } + } + } +} + +LevelInfo_Entry *LevelInfo_Search(void *file, int world, int level) { + for (int i = 0; i < LevelInfo_GetSectionCount(file); i++) { + LevelInfo_Section *sect = LevelInfo_GetSection(file, i); + + for (int j = 0; j < sect->levelCount; j++) { + LevelInfo_Entry *entry = &LevelInfo_GetLevels(file, sect)[j]; + if (entry->world == world && entry->level == level) + return entry; + } + } + + return 0; +} diff --git a/src/levelinfo.h b/src/levelinfo.h new file mode 100644 index 0000000..1b75275 --- /dev/null +++ b/src/levelinfo.h @@ -0,0 +1,56 @@ +#ifndef __NEWER_LEVELINFO_H +#define __NEWER_LEVELINFO_H + +#include +#include "fileload.h" + +struct LevelInfo_Header { + u32 magic; + u32 sectionCount; +}; + +struct LevelInfo_Section { + u32 levelCount; +}; + +struct LevelInfo_Entry { + u8 world; + u8 level; + u8 reserved1; + u8 reserved2; + u8 nameLength; + u8 reserved3; + u16 flags; + u32 nameOffset; +}; + +inline u32 LevelInfo_GetSectionCount(void *file) { + return ((LevelInfo_Header*)file)->sectionCount; +} + +inline u32 *LevelInfo_GetOffsets(void *file) { + return (u32*)(((LevelInfo_Header*)file)+1); +} + +inline LevelInfo_Section *LevelInfo_GetSection(void *file, int id) { + u32 offs = LevelInfo_GetOffsets(file)[id]; + return (LevelInfo_Section*)(((char*)file)+offs); +}; + +inline LevelInfo_Entry *LevelInfo_GetLevels(void *file, LevelInfo_Section *section) { + return (LevelInfo_Entry*)(section+1); +} + +inline LevelInfo_Entry *LevelInfo_GetLevels(void *file, int sectionID) { + return (LevelInfo_Entry*)(LevelInfo_GetSection(file, sectionID)+1); +} + +inline char *LevelInfo_GetName(void *file, LevelInfo_Entry *entry) { + return ((char*)file)+entry->nameOffset; +} + +void LevelInfo_Prepare(FileHandle *fh); +LevelInfo_Entry *LevelInfo_Search(void *file, int world, int level); + + +#endif diff --git a/src/levelnames.cpp b/src/levelnames.cpp new file mode 100644 index 0000000..b6f440e --- /dev/null +++ b/src/levelnames.cpp @@ -0,0 +1,83 @@ +#include +#include +#include +#include "levelinfo.h" +#include "fileload.h" +#include "layoutlib.h" + +//#define DEBUG_NAMES + +#ifndef DEBUG_NAMES +#define OSReport(...) +#endif + +extern char CurrentLevel; +extern char CurrentWorld; + +int DoNames(int state) { + OSReport("DoNames called - State param is %d\n", state); + int wnum = (int)CurrentWorld; + int lnum = (int)CurrentLevel; + OSReport("Current Level: %d-%d\n", wnum+1, lnum+1); + + // Skip the title screen + // and only process the code if the State is set to 1 + // (the screen has been initialised) + if (state == 1 && lnum != STAGE_TITLE) { + OSReport("Processing\n"); + // grab the CRSIN object + Actor *ptr = FindActorByType(CRSIN, 0); + //OSReport("CRSIN actor found at : %08X\n", ptr); + + // FIX !!!!! + + if (ptr != 0) { + void *worldObj = EmbeddedLayout_FindTextBoxByName((Layout*)((u32)ptr+0xB0), "TXT_WorldName"); + void *levelObj = EmbeddedLayout_FindTextBoxByName((Layout*)((u32)ptr+0xB0), "TXT_LevelName"); + //OSReport("WorldObj TextBox : %08X; LevelObj TextBox : %08X\n", worldObj, levelObj); + if (worldObj == 0 || levelObj == 0) return state; + + /*char *file = RetrieveFileFromArc(ARC_TABLE, "Mario", "newer/names.bin"); + //OSReport("RetrieveFileFromArc returned : %08X\n", file); + char *worldname = file + (wnum * 0x40); + char *levelname = file + 0x280 + (wnum * 0xA80) + (lnum * 0x40);*/ + OSReport("Loading file...\n"); + FileHandle fh; + void *info = LoadFile(&fh, "/NewerRes/LevelInfo.bin"); + + LevelInfo_Prepare(&fh); + LevelInfo_Entry *entry = LevelInfo_Search(info, wnum, lnum); + char *worldname = LevelInfo_GetName(info, entry); + char *levelname = ""; + OSReport("Got name : %s\n", worldname); + + void *vtable = *((void**)levelObj); + void *funcaddr = *((void**)((u32)vtable+0x7C)); + int (*SetString)(void*, unsigned short*, unsigned short); + SetString = (int(*)(void*, unsigned short*, unsigned short))funcaddr; + + unsigned short wbuffer[0x40], lbuffer[0x40]; + for (int i = 0; i < 0x40; i++) { + wbuffer[i] = (unsigned short)worldname[i]; + lbuffer[i] = (unsigned short)levelname[i]; + } + + SetString(worldObj, wbuffer, 0); + SetString(levelObj, lbuffer, 0); + + OSReport("Freeing file\n"); + FreeFile(&fh); + OSReport("Inserted strings\n"); + } + } else { + OSReport("Skipped\n"); + } + + OSReport("Reached the end of DoNames\n"); + return state; +} + +int DoNamesTest2(int state, u32 ptr) { + OSReport("TEST 1:%08X 2:%08X\n", state, ptr); + return DoNames(state); +} diff --git a/src/linegod.S b/src/linegod.S new file mode 100644 index 0000000..ed636dd --- /dev/null +++ b/src/linegod.S @@ -0,0 +1,53 @@ +.text + +#ifndef __MWERKS__ +.set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3 +#endif + +.align 4 +.extern ContinueBgActorSpawn +.global BgActorSpawnFix +BgActorSpawnFix: + mr 30, 3 + + #lis 3, TestStr@h + #ori 3, 3, TestStr@l + #mr 4, 30 + #crclr 4*cr1+eq + #bl OSReport + + lbz 0, 7(30) + cmpwi 0, 1 + beq JustRet + b ContinueBgActorSpawn +JustRet: + + lwz 31, 0x3C(1) + lwz 30, 0x38(1) + lwz 0, 0x44(1) + mtlr 0 + addi 1, 1, 0x40 + blr + + +.global BgActorSetInfoFix +BgActorSetInfoFix: + sth 4, 0(3) + sth 5, 2(3) + sth 6, 4(3) + stb 7, 6(3) + li 4, 0 + stb 4, 7(3) + blr + + +#.data +#TestStr: +# .string "Spawning actor %p\n" +# .align 4 diff --git a/src/linegod.cpp b/src/linegod.cpp new file mode 100644 index 0000000..de08fa0 --- /dev/null +++ b/src/linegod.cpp @@ -0,0 +1,213 @@ +#include +#include + +// TODO: make "No Deactivation" + +struct BgActor { + u16 def_id; // 0x00 + u16 x; // 0x02 + u16 y; // 0x04 + u8 layer; // 0x06 + u8 EXTRA_off; // 0x07 + u32 actor_id; // 0x08 +}; + +struct BgActorDef { + u32 tilenum; + u16 actor; + u8 _06[2]; + float x; + float y; + float z; + float another_x; + float another_y; + u32 extra_var; +}; + +struct dBgActorManager_c { + u32 vtable; // 0x00 + u8 _04[0x34]; // 0x04 + BgActor *array; // 0x38 + u32 count; // 0x3C + u32 type; // 0x40 +}; + +extern dBgActorManager_c *dBgActorManager; + +extern BgActorDef *BgActorDefs; + +struct BG_GM_hax { + u8 _00[0x8FE64]; + float _0x8FE64; + float _0x8FE68; + float _0x8FE6C; + float _0x8FE70; +}; + +extern BG_GM_hax *BG_GM_ptr; + +// Regular class is 0x3D0. +// Let's add stuff to the end just to be safe. +// Size is now 0x400 +// 80898798 38600400 + +#define LINEGOD_FUNC_ACTIVATE 0 +#define LINEGOD_FUNC_DEACTIVATE 1 + +struct LineGod { + u32 id; // 0x00 + u32 settings; // 0x04 + u16 name; // 0x08 + u8 _0A[6]; // 0x0A + u8 _10[0x9C]; // 0x10 + float x; // 0xAC + float y; // 0xB0 + float z; // 0xB4 + u8 _B8[0x318]; // 0xB8 + u64 eventFlag; // 0x3D0 + u8 func; // 0x3D4 + u8 width; // 0x3D5 + u8 height; // 0x3D6 + u8 lastEvState; // 0x3D7 + BgActor *ac[8]; // 0x3D8 +}; + +struct EventTable_t { + u64 events; + // ... +}; + +extern EventTable_t *EventTable; + +fBase_c *FindActorByID(u32 id); + +u16 *GetPointerToTile(BG_GM_hax *self, u16 x, u16 y, u16 layer, short *blockID_p, bool unused); + + + +void LineGod_BuildList(LineGod *self); +bool LineGod_AppendToList(LineGod *self, BgActor *ac); +void LineGod_Update(LineGod *self); + + +bool LineGod_Create(LineGod *self) { + char eventNum = (self->settings >> 24) & 0xFF; + self->eventFlag = (u64)1 << (eventNum - 1); + + OSReport("LineGod created @%p event %d\n", self, eventNum); + + //OSReport("Eventnum: %d. Event flag: %08x %08x\n", eventNum, self->eventFlag >> 32, self->eventFlag & 0xFFFFFFFF); + + self->func = (self->settings) & 1; + self->width = (self->settings >> 4) & 15; + self->height = (self->settings >> 8) & 15; + + self->lastEvState = 0xFF; + + LineGod_BuildList(self); + LineGod_Update(self); + + return true; +} + +bool LineGod_Execute(LineGod *self) { + LineGod_Update(self); + return true; +} + +void LineGod_BuildList(LineGod *self) { + for (int clearIdx = 0; clearIdx < 8; clearIdx++) { + self->ac[clearIdx] = 0; + } + + + u16 x1 = self->x / 16; + u16 x2 = x1 + self->width - 1; + u16 y1 = (-self->y) / 16; + u16 y2 = y1 + self->height - 1; + OSReport("Searching ... %d,%d - %d,%d\n", x1, y1, x2, y2); + + x1 -= (BG_GM_ptr->_0x8FE64 / 16); + x2 -= (BG_GM_ptr->_0x8FE64 / 16); + y1 += (BG_GM_ptr->_0x8FE6C / 16); + y2 += (BG_GM_ptr->_0x8FE6C / 16); + OSReport("Manipulated offsets ... %d,%d - %d,%d\n", x1, y1, x2, y2); + + OSReport("My array: %p\n", &self->ac[0]); + + for (int i = 0; i < dBgActorManager->count; i++) { + BgActor *ac = &dBgActorManager->array[i]; + //OSReport("Actor %p: %d,%d", ac, ac->x, ac->y); + + if (ac->x >= x1 && ac->x <= x2 && ac->y >= y1 && ac->y <= y2) + LineGod_AppendToList(self, ac); + } +} + +bool LineGod_AppendToList(LineGod *self, BgActor *ac) { + OSReport("Adding %p to the list (pos: %d,%d)\n", ac, ac->x, ac->y); + + for (int search = 0; search < 8; search++) { + if (self->ac[search] == 0) { + self->ac[search] = ac; + return true; + } + } + + return false; +} + +void LineGod_Update(LineGod *self) { + //OSReport("%08x%08x", EventTable->events >> 32, EventTable->events & 0xFFFFFFFF); + + u8 newEvState = 0; + if (EventTable->events & self->eventFlag) + newEvState = 1; + + if (newEvState == self->lastEvState) + return; + + u16 x_bias = (BG_GM_ptr->_0x8FE64 / 16); + u16 y_bias = -(BG_GM_ptr->_0x8FE6C / 16); + + OSReport("Event state changed from %d to %d\n", self->lastEvState, newEvState); + + u8 offState; + if (self->func == LINEGOD_FUNC_ACTIVATE) + offState = (newEvState == 1) ? 1 : 0; + else + offState = (newEvState == 1) ? 0 : 1; + + //OSReport("offState is %d\n", offState); + + for (int i = 0; i < 8; i++) { + if (self->ac[i] != 0) { + BgActor *ac = self->ac[i]; + + //OSReport("Assigning %d to %p->EXTRA_off (actor ID is %d)\n", offState, ac, ac->actor_id); + + ac->EXTRA_off = offState; + if (offState == 1 && ac->actor_id != 0) { + fBase_c *assoc_ac = FindActorByID(ac->actor_id); + //OSReport("Got actor: %p\n", assoc_ac); + if (assoc_ac != 0) + assoc_ac->Delete(); + ac->actor_id = 0; + } + + u16 *tile = GetPointerToTile(BG_GM_ptr, (ac->x + x_bias) * 16, (ac->y + y_bias) * 16, 0, 0, 0); + if (offState == 1) + *tile = 0; + else + *tile = BgActorDefs[ac->def_id].tilenum; + + //OSReport("def_id: %d; def_ptr: %p\n", ac->def_id, &(BgActorDefs[ac->def_id])); + //OSReport("Placed tile %d at %p [%d,%d]\n", *tile, tile, ac->x+x_bias, ac->y+y_bias); + } + } + + //OSReport("Success!\n"); + + + self->lastEvState = newEvState; +} diff --git a/src/msgbox.S b/src/msgbox.S new file mode 100644 index 0000000..db0021c --- /dev/null +++ b/src/msgbox.S @@ -0,0 +1,37 @@ +.text + +#ifndef __MWERKS__ +.set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3 +#endif + +.extern Global5758 + +# -if param & 1 /and/ messagebox is on, +# otherwise, return Global5758 & param + +.global Query5758Replacement +Query5758Replacement: + mr 5, 3 # save param + lis 4, Global5758@h + ori 4, 4, Global5758@l + lwz 0, 0(4) # get 5758 + and 3, 0, 3 # AND with param + andi. 5, 5, 1 # if param & 1 == 0.. + beqlr # then return + + lis 4, MessageBoxIsShowing@h + ori 4, 4, MessageBoxIsShowing@l + lwz 4, 0(4) + or 3, 3, 4 # otherwise, OR with MessageBoxIsShowing + blr # then return + + +.data +MessageBoxIsShowing: + .long 0 diff --git a/src/msgbox.cpp b/src/msgbox.cpp new file mode 100644 index 0000000..63eb994 --- /dev/null +++ b/src/msgbox.cpp @@ -0,0 +1,227 @@ +#include +#include +#include "layoutlib.h" +#include "fileload.h" + + +struct MsgData_Header { + u32 magic; + u32 msgCount; +}; + +struct MsgData_Entry { + u32 number; + u32 titleOffset; + u32 msgOffset; +}; + + + +struct dMsgBoxManager_c { + // 0x00 + int ID; + unsigned int Settings; + short Type; + char Unk_0A; + char Unk_0B; + char Unk_0C; + char Unk_0D; + char Unk_0E; + char Unk_0F; + + // 0x10 + void *CONNECT_parent; + void *CONNECT_child; + void *CONNECT_prev; + void *CONNECT_next; + + // 0x20 + void *CONNECT_thisObj; + void *EXECUTE_prev; + void *EXECUTE_next; + void *EXECUTE_thisObj; + + // 0x30 + short Unk_30; + short Unk_32; + void *DRAW_prev; + void *DRAW_next; + void *DRAW_thisObj; + + // 0x40 + short Unk_40; + short Unk_42; + void *IDLookup_prev; + void *IDLookup_next; + void *IDLookup_thisObj; + + // 0x50 + void *Unk_50; + int Unk_54; + int Unk_58; + void *Unk_5C; + + // 0x60 + void *vtable; + int Unk_64; // dBase_c starts here + char *weirdTypeString; + char *actorName; + + // dMsgBoxManager_c starts here (offset 0x70) + Layout *layout; + int state; + FileHandle msgDataFH; + + // 0x80 + void *msgData; + + // current allocated class size: 0xD0 +}; + + +#define STATE_NULL 0 +#define STATE_BOX_APPEAR_WAIT 1 +#define STATE_BUTTON_APPEAR_WAIT 2 +#define STATE_SHOWN 3 +#define STATE_BUTTON_DISAPPEAR_WAIT 4 +#define STATE_BOX_DISAPPEAR_WAIT 5 + +#define animBoxAppear 0 +#define animBoxDisappear 1 +#define animButtonAppear 2 +#define animButtonDisappear 3 + +extern int MessageBoxIsShowing; +dMsgBoxManager_c *CurrentMsgBoxManager; + +const char *brlan_BoxAppear = "BoxAppear.brlan"; +const char *brlan_BoxDisappear = "BoxDisappear.brlan"; +const char *brlan_ButtonAppear = "ButtonAppear.brlan"; +const char *brlan_ButtonDisappear = "ButtonDisappear.brlan"; + +const char *group_Box = "G_Box"; +const char *group_Button = "G_Button"; + +bool dMsgBoxManager_c__Create(dMsgBoxManager_c *self) { + self->layout = (Layout*)AllocFromGameHeap1(sizeof(Layout)); + + if (!self->layout) { + OSReport("memalloc fail\n"); + InfiniteLoop; + } + + EmbeddedLayout_ctor(self->layout); + EmbeddedLayout_LoadArc(self->layout, "NewerRes/msgbox.arc"); + + if (!EmbeddedLayout_Build(self->layout, "MessageBox.brlyt", 0)) { + OSReport("build fail\n"); + InfiniteLoop; + } + + + const char *anims[4] = {brlan_BoxAppear, brlan_BoxDisappear, brlan_ButtonAppear, brlan_ButtonDisappear}; + EmbeddedLayout_LoadBrlans(self->layout, anims, 4); + + const char *groups[4] = {group_Box, group_Box, group_Button, group_Button}; + + int mappings[4] = {0, 1, 2, 3}; + EmbeddedLayout_LoadGroups(self->layout, groups, mappings, 4); + + EmbeddedLayout_DisableAllAnims(self->layout); + + for (int i = 0; i < 4; i++) { + EmbeddedLayout_ResetAnimToInitialState(self->layout, i, false); + } + + self->msgData = LoadFile(&self->msgDataFH, "/NewerRes/MsgData.bin"); + + self->state = STATE_NULL; + self->layout->drawOrder = 0xA0; + + CurrentMsgBoxManager = self; + + return true; +} + +bool dMsgBoxManager_c__Execute(dMsgBoxManager_c *self) { + if (self->state == STATE_NULL) + return true; + + + switch (self->state) { + /**************************************************************************/ + case STATE_BOX_APPEAR_WAIT: + if (!EmbeddedLayout_CheckIfAnimationIsOn(self->layout, animBoxAppear)) { + EmbeddedLayout_EnableNonLoopAnim(self->layout, animButtonAppear, false); + self->state = STATE_BUTTON_APPEAR_WAIT; + } + + break; + + /**************************************************************************/ + case STATE_BUTTON_APPEAR_WAIT: + if (!EmbeddedLayout_CheckIfAnimationIsOn(self->layout, animButtonAppear)) { + self->state = STATE_SHOWN; + } + + break; + + /**************************************************************************/ + case STATE_SHOWN: + if (false) { + EmbeddedLayout_EnableNonLoopAnim(self->layout, animButtonDisappear, false); + self->state = STATE_BUTTON_DISAPPEAR_WAIT; + } + + break; + + /**************************************************************************/ + case STATE_BUTTON_DISAPPEAR_WAIT: + if (!EmbeddedLayout_CheckIfAnimationIsOn(self->layout, animButtonDisappear)) { + EmbeddedLayout_EnableNonLoopAnim(self->layout, animBoxDisappear, false); + self->state = STATE_BOX_DISAPPEAR_WAIT; + } + + break; + + /**************************************************************************/ + case STATE_BOX_DISAPPEAR_WAIT: + if (!EmbeddedLayout_CheckIfAnimationIsOn(self->layout, animBoxDisappear)) { + self->state = STATE_NULL; + + EmbeddedLayout_DisableAllAnims(self->layout); + + for (int i = 0; i < 4; i++) { + EmbeddedLayout_ResetAnimToInitialState(self->layout, i, false); + } + } + break; + } + + + EmbeddedLayout_Process(self->layout); + EmbeddedLayout_UpdateMatrix(self->layout); + + return true; +} + +bool dMsgBoxManager_c__Draw(dMsgBoxManager_c *self) { + if (self->state != STATE_NULL) { + EmbeddedLayout_AddToDrawList(self->layout); + } + + return true; +} + +bool dMsgBoxManager_c__Delete(dMsgBoxManager_c *self) { + EmbeddedLayout_FreeArc(self->layout); + EmbeddedLayout_Free(self->layout); + EmbeddedLayout_dtor(self->layout, false); + FreeFromGameHeap1(self->layout); + + CurrentMsgBoxManager = 0; + + return true; +} + + diff --git a/src/poweruphax.S b/src/poweruphax.S new file mode 100644 index 0000000..bfd8c83 --- /dev/null +++ b/src/poweruphax.S @@ -0,0 +1,689 @@ +.text +.align 4 +.set sp, 1 + +.extern returnFromGPSFASixth +.extern daEnItem_c__GetWhetherPlayerCanGetPowerupOrNot +.extern dAcPy_c__ChangePowerupWithAnimation +.extern PlayPlayerSound +.extern CreateActor +.extern PlayerProjectileShooting +.extern Actor_SearchByName +.extern SomeTable_802F5440 +.extern SomeTable_802F5580 +.extern SomeTable_802F56C0 +.extern BlahTable +.extern continuePlumberSetPowerupTexture +.extern doneSettingThePowerupTexture +.extern doneSettingThePowerupTexture2 + +#ifndef __MWERKS__ +.set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3 +.set f1,1; .set f30,30; .set f31,31 +#endif + +.global GetInfoFromDumbTable +GetInfoFromDumbTable: + lis r3, SomeTable@h + ori r3, r3, SomeTable@l + + slwi r4, r4, 2 + slwi r0, r5, 6 + + lwzx r3, r3, r4 + add r3, r3, r0 + blr + + + + +.global FukidashiFix +FukidashiFix: + lis r7, ZeroFloat@h + ori r7, r7, ZeroFloat@l + + lis r8, FukidashiTable2@h + ori r8, r8, FukidashiTable2@l + + mulli r6, r4, 0x20 + slwi r0, r5, 2 + add r0, r0, r6 + + lfs f0, 0(r7) + lfsx f1, r8, r0 + + stfs f0, 0x1DC(r3) + stfs f1, 0x1E0(r3) + stfs f0, 0x1E4(r3) + + blr + + + + +.global PlayerGetHeight +PlayerGetHeight: + lwz r0, 0x14D4(r3) + + lwz r4, 0x1090(r3) + slwi r4, r4, 3 + + cmpwi r0, 0 + beq useNormal + cmpwi r0, 1 + bne useDucking + +useNormal: + lis r3, PlayerHeightsNormal@h + ori r3, r3, PlayerHeightsNormal@l + b gotOffset + +useDucking: + lis r3, PlayerHeightsDucking@h + ori r3, r3, PlayerHeightsDucking@l + +gotOffset: + lfsx f1, r3, r4 + blr + + + +.global WtfEver +WtfEver: + lis r3, WtfEverTable@h + ori r3, r3, WtfEverTable@l + lfsx f0, r3, r0 + blr + + + +.global YetAnother +YetAnother: + lis r3, YetAnotherTable@h + ori r3, r3, YetAnotherTable@l + lfsx f0, r3, r0 + blr + + + + +.global GetWeirdScaleTable +GetWeirdScaleTable: + lis r5, WeirdScaleTable@h + ori r5, r5, WeirdScaleTable@l + lfsx f1, r5, r0 + blr + + + + + +.global GetAsdfTable +GetAsdfTable: + extsb r0, r4 + cmpwi r0, -1 + bne dontGetThisOne + + lwz r0, 0x1090(r3) + extsb r4, r0 + +dontGetThisOne: + extsb r0, r4 + + lis r3, AsdfTable@h + ori r3, r3, AsdfTable@l + lbzx r3, r3, r0 + + blr + + + + + +.global GetBlahTableOffset +GetBlahTableOffset: + lis r5, BlahTableOffsets@h + ori r5, r5, BlahTableOffsets@l + lwzx r30, r5, r4 + blr + + +.global DealWithBlahTable +DealWithBlahTable: + lis r5, BlahTableOffsets@h + ori r5, r5, BlahTableOffsets@l + + # points to BlahTable + lis r4, BlahTable@h + ori r4, r4, BlahTable@l + + # get blahtableoffset entry based on powerup + lwz r0, 0x1090(r3) + slwi r0, r0, 2 + lwzx r0, r5, r0 + + # now get the entry from the blahtable + slwi r0, r0, 2 + lwzx r4, r4, r0 + + # do shit here + + lfs f3, 0(r4) + stfs f3, 0x14E4(r3) + stfs f3, 0x164(r3) + + lfs f1, 0x2A70(r3) + lfs f0, 0x2A74(r3) + + lfs f2, 4(r4) + fadds f1, f2, f1 + fadds f0, f0, f1 + stfs f0, 0x14E8(r3) + stfs f0, 0x168(r3) + + lfs f0, 0x8(r4) + lfs f1, 0xC(r4) + stfs f0, 0x16C(r3) + stfs f1, 0x170(r3) + + # hope I did this right + blr + + + + + +.global GetPowerupScaleFloatAddr_r6_trash_r0_valshl2_r4_dest +GetPowerupScaleFloatAddr_r6_trash_r0_valshl2_r4_dest: + lis r6, PowerupScaleFloats@h + ori r6, r6, PowerupScaleFloats@l + add r4, r6, r0 + blr + +.global GetPowerupScaleFloatAddr_r6_trash_r0_valshl2_r3_dest +GetPowerupScaleFloatAddr_r6_trash_r0_valshl2_r3_dest: + lis r6, PowerupScaleFloats@h + ori r6, r6, PowerupScaleFloats@l + add r3, r6, r0 + blr + +.global GetPowerupScaleFloatAddr_r8_trash_r0_valshl2_r7_dest +GetPowerupScaleFloatAddr_r8_trash_r0_valshl2_r7_dest: + lis r8, PowerupScaleFloats@h + ori r8, r8, PowerupScaleFloats@l + add r7, r8, r0 + blr + +.global GetPowerupScaleFloatAddr_fixForSixth +GetPowerupScaleFloatAddr_fixForSixth: + lis r5, PowerupScaleFloats@h + ori r5, r5, PowerupScaleFloats@l + add r4, r5, r4 + b returnFromGPSFASixth + + + +.global PlumberSetPowerupFix +PlumberSetPowerupFix: + lbz r0, 0x152(r31) # get powerup id + + cmpwi r0, 2 + beq doFireTex + + cmpwi r0, 6 + beq doIceTex + + cmpwi r0, 7 + beq doHammerTex + + li r4, 0 + b gotTexID + +doFireTex: + li r4, 1 + b gotTexID + +doIceTex: + li r4, 2 + b gotTexID + +doHammerTex: + li r4, 3 + +gotTexID: + lwz r12, 0(r31) + mr r3, r31 + lwz r12, 0x34(r12) + mtctr r12 + bctrl + + b doneSettingThePowerupTexture + + + +.global PlumberSetPowerupFix2 +PlumberSetPowerupFix2: + cmpwi r31, 2 + beq doFireTex2 + + cmpwi r31, 6 + beq doIceTex2 + + cmpwi r31, 7 + beq doHammerTex2 + + li r4, 0 + b gotTexID2 + +doFireTex2: + li r4, 1 + b gotTexID2 + +doIceTex2: + li r4, 2 + b gotTexID2 + +doHammerTex2: + li r4, 3 + +gotTexID2: + lwz r3, 0x2A64(r30) + lwz r12, 0(r3) + lwz r12, 0x34(r12) + mtctr r12 + bctrl + + b doneSettingThePowerupTexture2 + + + + +.global PlumberSetPowerupTextureDebug +.extern OSReport +.extern continuePlumberSetPowerupTextureDebug +PlumberSetPowerupTextureDebug: + stwu sp, -0x30(sp) + mflr r0 + stw r0, 0x34(sp) + stw r3, 0x20(sp) + stw r4, 0x24(sp) + + mr r6, r0 + mr r5, r4 + mr r4, r3 + lis r3, PowerupTexDebugStr@h + ori r3, r3, PowerupTexDebugStr@l + crclr 4*cr1+eq + bl OSReport + + lwz r3, 0x20(sp) + lwz r4, 0x24(sp) + lwz r0, 0x34(sp) + mtlr r0 + addi sp, sp, 0x30 + + stwu sp, -0x30(sp) + + b continuePlumberSetPowerupTextureDebug + + + + + +.global PlumberSetPowerupTextureFix +PlumberSetPowerupTextureFix: + stb r4, 0x153(r3) + + lis r5, PowerupTextures@h + ori r5, r5, PowerupTextures@l + + slwi r4, r4, 2 + lfsx f31, r5, r4 + + b continuePlumberSetPowerupTexture + + + +.global SetHammerToEnItemDCA +SetHammerToEnItemDCA: + bl daEnItem_c__GetWhetherPlayerCanGetPowerupOrNot + cmpwi r3, 1 + bne DontSetHammer + + li r0, 5 + sth r0, 0xDCA(r31) + +DontSetHammer: + lwz r0, 0x14(sp) + lwz r31, 0xC(sp) + mtlr r0 + addi sp, sp, 0x10 + blr + + +#.global EnItem_BindAnimation_Fix +#EnItem_BindAnimation_Fix: +# lhz r0, 0xDCA(r3) +# cmpwi r0, 5 +# beqlr +# stwu sp, -0x20(sp) +# b EnItem_BindAnimation_Continued + + +.global WeirdAnimLoadHack +WeirdAnimLoadHack: + cmplwi r4, 5 #hammersuit + beqlr + cmplwi r4, 6 #1up + beqlr + # neither of those succeeded + crclr 4*cr0+eq + blr + + + +.global TryToGiveMarioHammerSuit +TryToGiveMarioHammerSuit: + stwu sp, -0x10(sp) + mflr r0 + stw r0, 0x14(sp) + + # check the obtained item number + cmplwi r3, 5 + bne IsntGettingHammerSuit + + # check the current player powerup + cmplwi r4, 7 + bne DontHaveHammerSuit + + li r28, 0 + li r29, 2 + b ReturnFromTTGMHS + +DontHaveHammerSuit: + mr r3, r30 + li r4, 7 + bl dAcPy_c__ChangePowerupWithAnimation + + cmpwi r3, 0 + beq ReturnFromTTGMHS + + li r29, 1 + +IsntGettingHammerSuit: +ReturnFromTTGMHS: + # end of function + lwz r0, 0x14(sp) + mtlr r0 + addi sp, sp, 0x10 + + # leftover instruction from what we replaced to add the bl + cmpwi r29, 0 + blr + + + +.global ThrowHammer +ThrowHammer: + # continues on from PlayerProjectileShooting + + # get powerup + lwz r3, 0x1090(r30) + cmplwi r3, 7 + bne ReturnFromThrowHammer + + mr r3, r30 + li r4, 498 + li r5, 0 + bl PlayPlayerSound + + li r3, 0x73 # Hammer + li r4, 0 # Settings + addi r5, sp, 0x2C # Position + li r6, 0 # Rotation + lbz r7, 0x38F(r30) # Layer + bl CreateActor + + # Store player ID + lwz r4, 0(r30) + stw r4, 0x450(r3) + + # store player number, but add 0x100 to differentiate it from 0 + lbz r4, 0x38D(r30) + addi r4, r4, 0x100 + stw r4, 0x458(r3) + + # Fix scale + lis r4, OneFloat@h + ori r4, r4, OneFloat@l + lfs f0, 0(r4) + stfs f0, 0xDC(r3) + stfs f0, 0xE0(r3) + stfs f0, 0xE4(r3) + + mr r4, r30 + lwz r12, 0x60(r3) + lwz r12, 0x8C(r12) + mtctr r12 + bctrl + +ReturnFromThrowHammer: + lwz r0, 0xC4(sp) + psq_l f31, 0xB8(sp), 1, 0 + lfd f31, 0xB0(sp) + psq_l f30, 0xA8(sp), 1, 0 + lfd f30, 0xA0(sp) + lwz r31, 0x9C(sp) + lwz r30, 0x98(sp) + mtlr r0 + addi sp, sp, 0xC0 + blr + + + +.global MoreProjectileStuff_Fix +MoreProjectileStuff_Fix: + lwz r3, 0x1090(r31) + cmplwi r3, 7 + bne ReturnFromMPSFix + + mr r3, r31 + li r4, 1 + bl PlayerProjectileShooting + +ReturnFromMPSFix: + lwz r0, 0x14(sp) + lwz r31, 0xC(sp) + mtlr r0 + addi sp, sp, 0x10 + blr + + + +.global ProjectileShootCheck_Fix +ProjectileShootCheck_Fix: + lwz r3, 0x1090(r31) + cmplwi r3, 7 + bne Return0fromPSCFix + + lbz r3, 0x38D(r31) + li r4, 0 + extsb r3, r3 + bl CheckHammerLimit + + cmpwi r3, 0 + beq Return0fromPSCFix + + b Return1fromPSCFix + +Return0fromPSCFix: + li r3, 0 + b ReturnFromPSCFix + +Return1fromPSCFix: + li r3, 1 + +ReturnFromPSCFix: + lwz r0, 0x14(sp) + lwz r31, 0xC(sp) + mtlr r0 + addi sp, sp, 0x10 + blr + + +.global CheckHammerLimit +CheckHammerLimit: + stwu sp, -0x10(sp) + mflr r0 + stw r0, 0x14(sp) + stw r31, 0xC(sp) + stw r30, 0x8(sp) + + # r30 = player number + mr r30, r3 + addi r30, r30, 0x100 + + # r31 = hammer count so far + li r31, 0 + + # search for every Hammer + + li r3, 0 + b startOrContinueLoop +loop: + + lwz r4, 0x458(r3) + cmpw r4, r30 + bne startOrContinueLoop + + addi r31, r31, 1 + +startOrContinueLoop: + mr r4, r3 + li r3, 0x73 + bl Actor_SearchByName + + cmpwi r3, 0 + bne loop + + # now if the current count is >= 2, return 0 + # otherwise return 1 + cmpwi r31, 2 + bge tooManyHammers + + li r3, 1 + b gotHammerStatus + +tooManyHammers: + li r3, 0 + +gotHammerStatus: + lwz r0, 0x14(sp) + lwz r31, 0xC(sp) + lwz r30, 0x8(sp) + mtlr r0 + addi sp, sp, 0x10 + blr + + + + + + +.data + +SomeTable: + .long SomeTable_802F5580 + .long SomeTable_802F56C0 + .long SomeTable_802F56C0 + .long SomeTable_802F5440 + .long SomeTable_802F56C0 + .long SomeTable_802F56C0 + .long SomeTable_802F56C0 + .long SomeTable_802F56C0 + +ZeroFloat: + .float 0.0 + +OneFloat: + .float 1.0 + +FukidashiTable2: + .float 20.0, 32.0, 32.0, 12.0, 38.0, 33.0, 32.0, 32.0 + .float 20.0, 34.0, 34.0, 12.0, 39.0, 35.0, 34.0, 34.0 + .float 20.0, 29.0, 29.0, 11.0, 34.0, 29.0, 29.0, 29.0 + .float 20.0, 29.0, 29.0, 11.0, 34.0, 29.0, 29.0, 29.0 + +PlayerHeightsNormal: + .float 16.0, 27.0, 27.0, 12.0, 27.0, 27.0, 27.0, 27.0 + +PlayerHeightsDucking: + .float 13.0, 21.0, 21.0, 9.0, 21.0, 21.0, 21.0, 21.0 + +WtfEverTable: + .float 4.5, 10.0, 10.0, 1.0, 10.0, 9.0, 10.0, 10.0 + +YetAnotherTable: + .float 0.0, -4.0, -4.0, 4.0, -6.0, -2.0, -4.0, -4.0 + +WeirdScaleTable: + .float 16.0, 31.0, 31.0, 6.0, 34.0, 31.0, 31.0, 31.0 + +AsdfTable: + .byte 1, 2, 2, 0, 2, 2, 2, 2 + +BlahTableOffsets: + .long 1, 2, 2, 0, 3, 2, 2, 2 + +PowerupScaleFloats: + .long 0xDEADBEEF, 0xDEADBEEF # padding + .float 1.0 + .float 1.0 + .float 1.0 + .float 0.6 + .float 1.0 + .float 1.0 + .float 1.0 + .float 1.0 + +PowerupTextures: + .float 0.0 + .float 1.0 + .float 2.0 + .float 3.0 + +.global BrosArcFileName +BrosArcFileName: + .string "bros" + +.global I_hammerArcFilename +I_hammerArcFilename: + .string "I_hammer" + +.global I_hammerResFile +I_hammerResFile: +# .string "g3d/I_hammer.brres" + .string "g3d/I_fireflower.brres" + +.global I_hammerModelName +I_hammerModelName: +# .string "I_hammer" + .string "I_fireflower" + + +PowerupTexDebugStr: + .string "Plumber::SetPowerupTexture() called on class %p with texnum %d lr=%p\n" + +#.global BrosModelFilename +#BrosModelFilename: +# .string "g3d/bros.brres" + +#.global HammerModelName +#HammerModelName: +# .string "bros_hammer" diff --git a/src/randomcrap.S b/src/randomcrap.S new file mode 100644 index 0000000..e7b6451 --- /dev/null +++ b/src/randomcrap.S @@ -0,0 +1,8 @@ +.text +.global HeapChangeAttempt +HeapChangeAttempt: + lis 4, 0x8037 + ori 4, 4, 0x7F50 + lwz 4, 0(4) + blr + diff --git a/src/randtiles.cpp b/src/randtiles.cpp new file mode 100644 index 0000000..c7388dd --- /dev/null +++ b/src/randtiles.cpp @@ -0,0 +1,22 @@ +#include "randtiles.h" + +u32 djb2(u8 *str) { + u32 hash = 5381; + int c; + + while (c = *str++) + hash = ((hash << 5) + hash) + c; + + return hash; +} + +RandTiles_Section *RandTiles_Search(void *file, u32 nameHash) { + for (int i = 0; i < RandTiles_GetSectionCount(file); i++) { + RandTiles_Section *sect = RandTiles_GetSection(file, i); + + if (sect->nameHash == nameHash) + return sect; + } + + return 0; +} diff --git a/src/randtiles.h b/src/randtiles.h new file mode 100644 index 0000000..ab2553d --- /dev/null +++ b/src/randtiles.h @@ -0,0 +1,63 @@ +#ifndef __NEWER_RANDTILES_H +#define __NEWER_RANDTILES_H + +#include +#include "fileload.h" + +#define RAND_CHECK_HORZ +#define RAND_CHECK_VERT +#define RAND_CHECK_BOTH + +struct RandTiles_Header { + u32 magic; + u32 sectionCount; +}; + +struct RandTiles_Section { + u32 nameHash; + u32 entryCount; +}; + +struct RandTiles_Entry { + u16 startTile; + u16 endTile; + u8 count; + u8 type; + u16 reserved; + u32 dataOffset; +}; + +inline u32 RandTiles_GetSectionCount(void *file) { + return ((RandTiles_Header*)file)->sectionCount; +} + +inline u32 *RandTiles_GetOffsets(void *file) { + return (u32*)(((RandTiles_Header*)file)+1); +} + +inline RandTiles_Section *RandTiles_GetSection(void *file, int id) { + u32 offs = RandTiles_GetOffsets(file)[id]; + return (RandTiles_Section*)(((char*)file)+offs); +}; + +inline RandTiles_Entry *RandTiles_GetTiles(void *file, RandTiles_Section *section) { + return (RandTiles_Entry*)(section+1); +} + +inline RandTiles_Entry *RandTiles_GetTiles(void *file, int sectionID) { + return (RandTiles_Entry*)(RandTiles_GetSection(file, sectionID)+1); +} + +inline char *RandTiles_GetName(void *file, RandTiles_Section *section) { + return ((char*)file)+section->nameOffset; +} + +inline u16 *RandTiles_GetData(void *file, RandTiles_Entry *entry) { + return (u16*)(((char*)file)+entry->dataOffset); +} + +u32 djb2(u8 *str); +RandTiles_Section *RandTiles_Search(void *file, u32 nameHash); + + +#endif diff --git a/src/replay.S b/src/replay.S new file mode 100644 index 0000000..8c3f6c7 --- /dev/null +++ b/src/replay.S @@ -0,0 +1,799 @@ +# Fucking Nintendo, how do they work + +.extern IOS_Open +.extern IOS_Close +.extern IOS_Read +.extern IOS_Write +.extern OSGetTime +.extern OSTicksToCalendarTime +.extern OSReport +.extern CurrentWorld +.extern CurrentLevel +.extern CurrentStartedArea +.extern CurrentStartedEntrance +.extern snprintf +.extern GetSomeGlobalClass +.extern SomeUnknownClass5408 +.extern SomeWipeClass +.extern continueFromReplayHookStart +.extern continueFromReplayEndHook +.extern returnFromRecorder +.extern QueryGlobal5758 +.extern GetRandomSeed +.extern Player_ID +.extern Player_Powerup +.extern Player_Flags +.extern EGG__Heap__alloc__FUliPv +.extern EGG__Heap__free__FPvPv +.extern GameHeap2 +.extern EggControllerClassPtrMaybe +.extern GameMgr +.extern StrangeReplayValue1 +.extern StrangeReplayValue2 +.extern StrangeReplayValue3 +.extern WiimotePtr1 +.extern Player_ID +.extern RandomSeed + +.set sp, 1 + +# mode 1 = read, 2 = write? + +.text +.align 4 + +.global replayStart +.global replayEnd +.global replayRecord + +.global luigiOverride +luigiOverride: + #blr + lis r3, Player_ID@h + ori r3, r3, Player_ID@l + li r4, 1 + stw r4, 0(r3) + blr + +.global getAndSaveRandomSeed +getAndSaveRandomSeed: # b from 8091F930 + lis r3, RandomSeed@h + ori r3, r3, RandomSeed@l + lwz r3, 0(r3) + lis r4, saveRandomSeed@h + ori r4, r4, saveRandomSeed@l + stw r3, 0(r4) + + mr r4, r3 + lis r3, str_gotSeed@h + ori r3, r3, str_gotSeed@l + crclr 4*cr1+eq + bl OSReport + + lwz r0, 0x74(sp) + mtlr r0 + addi sp, sp, 0x70 + blr + + +replayStart: # b from 809246E0 + bl OSGetTime + lis r5, replayTime@h + ori r5, r5, replayTime@l + bl OSTicksToCalendarTime + + li r29, 0 + li r30, 0 + +replayStartLoop: + + lis r3, str_replayFileNameBuffer@h + ori r3, r3, str_replayFileNameBuffer@l + + li r4, 64 + + lis r5, str_replayFileNameFormat@h + ori r5, r5, str_replayFileNameFormat@l + + lis r6, CurrentWorld@h + ori r6, r6, CurrentWorld@l + lbz r6, 0(r6) + addi r6, r6, 1 + + lis r7, CurrentLevel@h + ori r7, r7, CurrentLevel@l + lbz r7, 0(r7) + addi r7, r7, 1 + + lis r8, replayTime_hour@h + ori r8, r8, replayTime_hour@l + lwz r8, 0(r8) + + lis r9, replayTime_min@h + ori r9, r9, replayTime_min@l + lwz r9, 0(r9) + + mr r10, r29 + + crclr 4*cr1+eq + bl snprintf + + lis r4, str_replayFileNameBuffer@h + ori r4, r4, str_replayFileNameBuffer@l + lis r3, str_startMsg@h + ori r3, r3, str_startMsg@l + crclr 4*cr1+eq + bl OSReport + + lis r3, str_replayFileNameBuffer@h + ori r3, r3, str_replayFileNameBuffer@l + + li r4, 0x602 # O_WRITE | O_CREAT | O_TRUNC + + bl IOS_Open + + cmpwi r3, 0 + blt iosOpenFail + + lis r4, replayHandles@h + ori r4, r4, replayHandles@l + stwx r3, r4, r30 + + mr r4, r3 + lis r3, str_iosOpenMsg@h + ori r3, r3, str_iosOpenMsg@l + crclr 4*cr1+eq + bl OSReport + + # now write the header + lis r4, replayHeaders@h + ori r4, r4, replayHeaders@l + lwzx r4, r4, r30 + + lis r6, CurrentWorld@h + ori r6, r6, CurrentWorld@l + lis r7, CurrentLevel@h + ori r7, r7, CurrentLevel@l + lis r8, CurrentStartedArea@h + ori r8, r8, CurrentStartedArea@l # WRONG + lis r9, CurrentStartedEntrance@h + ori r9, r9, CurrentStartedEntrance@l # WRONG + + lbz r6, 0(r6) + lbz r7, 0(r7) + + stb r6, 0(r4) + stb r7, 1(r4) + stb r8, 2(r4) + stb r9, 3(r4) + + lis r3, saveRandomSeed@h + ori r3, r3, saveRandomSeed@l + lwz r3, 0(r3) + stw r3, 4(r4) + + # player ID specific stuff + mr r5, r29 + slwi r5, r5, 2 + + lis r3, Player_ID@h + ori r3, r3, Player_ID@l + lwzx r3, r3, r5 + slwi r6, r3, 2 # store this so we can get the powerup and flags + stw r3, 0x10(r4) + + lis r3, Player_Powerup@h + ori r3, r3, Player_Powerup@l + lwzx r3, r3, r6 + stw r3, 0x14(r4) + + lis r3, Player_Flags@h + ori r3, r3, Player_Flags@l + lwzx r3, r3, r6 + stw r3, 0x18(r4) + + lis r3, GameMgr@h + ori r3, r3, GameMgr@l + lwz r3, 0(r3) + lbz r3, 0x380(r3) + stb r3, 0x21(r4) + + # now set up variables + lis r4, replayFrameCounts@h + ori r4, r4, replayFrameCounts@l + li r3, 0 + stwx r3, r4, r30 + + lis r3, replayFlags@h + ori r3, r3, replayFlags@l + li r4, 1 + not r0, r4 + lhz r4, 0(r3) + clrlwi r0, r0, 16 + and r4, r4, r0 + slwi r5, r29, 1 # player ID * 2 + sthx r4, r3, r5 + + li r3, 0 + lis r4, keepTiltValues@h + ori r4, r4, keepTiltValues@l + stwx r3, r4, r30 + + lis r4, replayDataBufferSize@h + ori r4, r4, replayDataBufferSize@l + lwz r3, 0(r4) + + # alloc the memory + li r4, 4 + lis r5, GameHeap2@h + ori r5, r5, GameHeap2@l + lwz r5, 0(r5) + bl EGG__Heap__alloc__FUliPv + + lis r4, replayDataBuffers@h + ori r4, r4, replayDataBuffers@l + stwx r3, r4, r30 + + lis r4, replayDataBufferPointers@h + ori r4, r4, replayDataBufferPointers@l + stwx r3, r4, r30 + + mr r4, r3 + lis r3, str_bufferObtained@h + ori r3, r3, str_bufferObtained@l + crclr 4*cr1+eq + bl OSReport + + b startNextReplay + +iosOpenFail: + mr r4, r3 + lis r3, str_iosOpenFailed@h + ori r3, r3, str_iosOpenFailed@l + crclr 4*cr1+eq + bl OSReport + +startNextReplay: + + # the loop + addi r29, r29, 1 + addi r30, r30, 4 + cmpwi r29, 4 + blt replayStartLoop + + # and done! + li r3, 1 + b continueFromReplayHookStart # 809246E4 + + + +magicalReplayCheck: + stwu sp, -0x10(sp) + mflr r0 + stw r0, 0x14(sp) + stw r31, 0x0C(sp) + mr r31, r3 + + bl GetSomeGlobalClass + + lwz r0, 0x1D0(r3) + cmpwi r0, 2 + bne no_flag_20 + + ori r31, r31, 0x20 + b done_flag_20 + +no_flag_20: + li r4, 0x20 + not r4, r4 + and r31, r31, r4 + +done_flag_20: + lis r3, SomeUnknownClass5408@h # 8042A578 + ori r3, r3, SomeUnknownClass5408@l + lwz r3, 0(r3) + lbz r3, 4(r3) + + cmpwi r3, 0 + beq no_flag_40 + + ori r31, r31, 0x40 + b done_flag_40 + +no_flag_40: + li r4, 0x40 + not r4, r4 + and r31, r31, r4 + +done_flag_40: + lis r3, SomeWipeClass@h # 8042A720 + ori r3, r3, SomeWipeClass@l + lwz r3, 0(r3) + lwz r12, 0(r3) + lwz r12, 0x10(r12) + mtctr r12 + bctrl + + subi r0, r3, 1 + cntlzw r0, r0 + srwi. r0, r0, 5 + beq set_flag_2 + + li r4, 2 + not r4, r4 + and r31, r31, r4 + b done_flag_2 + +set_flag_2: + ori r31, r31, 2 + +done_flag_2: + li r3, 1 + bl QueryGlobal5758 + + cmpwi r3, 0 + beq no_flag_4 + + ori r31, r31, 4 + b done_flag_4 + +no_flag_4: + li r4, 4 + not r4, r4 + and r31, r31, r4 + +done_flag_4: + li r3, 4 + bl QueryGlobal5758 + + cmpwi r3, 0 + beq no_flag_100 + + ori r31, r31, 0x100 + b done_flag_100 + +no_flag_100: + li r4, 0x100 + not r4, r4 + and r31, r31, r4 + +done_flag_100: + li r3, 2 + bl QueryGlobal5758 + + cmpwi r3, 0 + beq no_flag_8 + + ori r31, r31, 8 + b done_flag_8 + +no_flag_8: + li r4, 8 + not r4, r4 + and r31, r31, r4 + +done_flag_8: + # okay, we're done + mr r3, r31 + + lwz r0, 0x14(sp) + lwz r31, 0x0C(sp) + mtlr r0 + addi sp, sp, 0x10 + blr + + + + + +replayEnd: # bl from 80102238 + stwu sp, -0x20(sp) + mflr r0 + stw r0, 0x24(sp) + stw r31, 0x1C(sp) + stw r30, 0x18(sp) + stw r29, 0x14(sp) + + cmpwi r3, 1 + bne justLeave + + li r29, 0 + li r30, 0 + +replayEndLoop: + lis r31, replayHandles@h + ori r31, r31, replayHandles@l + add r31, r31, r30 # becomes a pointer to the handle, not the handle itself + + lwz r3, 0(r31) + cmpwi r3, 0 + beq dontEndThisReplay + + lis r4, replayHeaders@h + ori r4, r4, replayHeaders@l + lwzx r4, r4, r30 + li r5, 0x40 + bl IOS_Write + + lwz r3, 0(r31) + lis r4, replayDataBuffers@h + ori r4, r4, replayDataBuffers@l + lwzx r4, r4, r30 + lis r5, replayDataBufferPointers@h # calc written size + ori r5, r5, replayDataBufferPointers@l + lwzx r5, r5, r30 + subf r5, r4, r5 + bl IOS_Write + + lwz r3, 0(r31) + lis r4, replayFooter@h + ori r4, r4, replayFooter@l + li r5, 4 + bl IOS_Write + + lwz r3, 0(r31) + bl IOS_Close + + li r3, 0 + stw r3, 0(r31) + + lis r4, replayDataBuffers@h + ori r4, r4, replayDataBuffers@l + lwzx r3, r4, r30 + li r4, 0 + bl EGG__Heap__free__FPvPv + + lis r4, replayDataBuffers@h + ori r4, r4, replayDataBuffers@l + li r0, 0 + stwx r0, r4, r30 + + lis r3, str_endMsg@h + ori r3, r3, str_endMsg@l + lis r4, replayFrameCounts@h + ori r4, r4, replayFrameCounts@l + lwzx r4, r4, r30 + crclr 4*cr1+eq + bl OSReport + + # before we leave, set the flag again + lis r3, replayFlags@h + ori r3, r3, replayFlags@l + add r3, r3, r29 + add r3, r3, r29 + lhz r4, 0(r3) + ori r4, r4, 1 + sth r4, 0(r3) + +dontEndThisReplay: + + # now loop + addi r29, r29, 1 + addi r30, r30, 4 + cmpwi r29, 4 + blt replayEndLoop + + li r3, 1 + +justLeave: + + lwz r0, 0x24(sp) + lwz r31, 0x1C(sp) + lwz r30, 0x18(sp) + lwz r29, 0x14(sp) + mtlr r0 + addi sp, sp, 0x20 + blr + #b continueFromReplayEndHook # 8010223C + + + + +replayRecord: + # fun shit. + stwu sp, -0x10(sp) + mflr r0 + stw r0, 0x14(sp) + stw r31, 0xC(sp) + stw r30, 8(sp) + + li r30, 0 + +recordLoop: + # get the controller class + lis r31, EggControllerClassPtrMaybe@h + ori r31, r31, EggControllerClassPtrMaybe@l + lwz r31, 0(r31) + slwi r3, r30, 2 + addi r3, r3, 4 + lwzx r31, r31, r3 + + # get player number + mr r4, r30 + + lis r3, replayFlags@h + ori r3, r3, replayFlags@l + add r3, r3, r4 + add r3, r3, r4 # get pointer to flags + lhz r3, 0(r3) + + bl magicalReplayCheck + lwz r5, 4(r31) + lis r4, replayFlags@h + ori r4, r4, replayFlags@l + add r4, r4, r5 + add r4, r4, r5 + sth r3, 0(r4) + + #mr r4, r3 + #lis r3, str_debugFlags@h + #ori r3, r3, str_debugFlags@l + #crclr 4*cr1+eq + #bl OSReport + + #lis r3, replayFlags@h + #ori r3, r3, replayFlags@l + #lhz r3, 0(r3) + cmpwi r3, 0 + bne goToNextRecorder + + # set this to player number * 4 + # r31 is our controller class + lwz r9, 4(r31) + slwi r9, r9, 2 + + lis r3, replayFrameCounts@h + ori r3, r3, replayFrameCounts@l + lwzx r4, r3, r9 + addi r4, r4, 1 + stwx r4, r3, r9 + + # put together the data + # first grab a pointer + lis r7, replayDataBufferPointers@h + ori r7, r7, replayDataBufferPointers@l + lwzx r6, r7, r9 + + cmpwi r6, 0 + beq goToNextRecorder + + # first off, grab the initial flags + li r3, 0 + + lbz r4, 0x8C(r31) # shake flag + cmpwi r4, 1 + bne dontShake + oris r3, r3, 0x2000 +dontShake: + + # now do the tilt stuff + lis r4, keepTiltValues@h + ori r4, r4, keepTiltValues@l + lwzx r0, r4, r9 # last value + lhz r5, 0x8E(r31) # new value + stwx r5, r4, r9 # store new value + cmpw r5, r0 + beq tiltDidntChange + oris r3, r3, 0x80 +tiltDidntChange: + + # ok, so we decided that, now write the flags + weird value + etc! + stw r3, 0(r6) + + # calculate the weird value + li r3, 0 + + lis r10, StrangeReplayValue1@h + ori r10, r10, StrangeReplayValue1@l + lhz r10, 0(r10) + slwi r10, r10, 16 + or r3, r3, r10 + + lis r10, StrangeReplayValue2@h + ori r10, r10, StrangeReplayValue2@l + lbz r10, 0(r10) + slwi r10, r10, 8 + or r3, r3, r10 + + lis r10, StrangeReplayValue3@h + ori r10, r10, StrangeReplayValue3@l + lbz r10, 0(r10) + or r3, r3, r10 + + stw r3, 4(r6) + + # buttons + lwz r3, 0xC(r31) + li r4, 0x0F0F + and r3, r3, r4 + stw r3, 8(r6) + + addi r6, r6, 0xC # we wrote 0xC bytes + + # now the tilt segment + beq dontWriteTilt + sth r5, 0(r6) + li r3, 0 + sth r3, 2(r6) + addi r6, r6, 4 + +dontWriteTilt: + # are we done now?! + # I hope so. + + lis r7, replayDataBufferPointers@h + ori r7, r7, replayDataBufferPointers@l + stwx r6, r7, r9 + + # before we do this. check if we should end the replay + # the raw button presses are at 0x18 in the Wiimote class + lis r5, WiimotePtr1@h + ori r5, r5, WiimotePtr1@l + lwzx r3, r5, r9 + lwz r3, 0x18(r3) + li r4, 0x0400 # B button mask + and. r3, r3, r4 + beq goToNextRecorder + + # end it! + li r3, 1 + bl replayEnd + b leaveRecordLoop + +goToNextRecorder: + + addi r30, r30, 1 + cmpwi r30, 4 + blt recordLoop + +leaveRecordLoop: + + lwz r31, 0xC(sp) + lwz r30, 8(sp) + lwz r0, 0x14(sp) + mtlr r0 + addi sp, sp, 0x10 + blr + + +.data + +replayFlags: .short 1, 1, 1, 1 +.align 4 + +replayHandles: .long 0, 0, 0, 0 + +replayFrameCounts: .long 0, 0, 0, 0 + +replayTime: +replayTime_sec: .long 0 +replayTime_min: .long 0 +replayTime_hour: .long 0 +replayTime_mday: .long 0 +replayTime_mon: .long 0 +replayTime_year: .long 0 +replayTime_wday: .long 0 +replayTime_yday: .long 0 +replayTime_msec: .long 0 +replayTime_usec: .long 0 + +str_replayFileNameFormat: + .string "file/Replay_%02d-%02d_from_%02d-%02d_p%d.bin" + +str_replayFileNameBuffer: + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + .byte 0,0,0,0,0,0,0,0 + +str_startMsg: + .string "*** Replay Recorder by Treeki -- Starting to record. Filename: %s\n" + +str_iosOpenMsg: + .string "*** Replay Recorder -- IOS_Open returned: %d\n" + +str_iosOpenFailed: + .string "*** Replay Recorder -- IOS_Open failed! It returned: %d -- The replay will not be saved.\n" + +str_bufferObtained: + .string "*** Replay Recorder -- Allocated replay buffer at %p\n" + +str_endMsg: + .string "*** Replay Recorder -- Recording complete. %d frames saved.\n" + +str_debugFlags: + .string "DEBUG:%04x\n" + +str_gotSeed: + .string "Got random seed: %08x\n" + +.align 4 + +replayHeaders: + .long replayHeader0 + .long replayHeader1 + .long replayHeader2 + .long replayHeader3 + +replayHeader0: +replayHeader0_world: .byte 0 +replayHeader0_level: .byte 0 +replayHeader0_area: .byte 0 +replayHeader0_entrance: .byte 0 +replayHeader0_seed: .long 0 +replayHeader0_padding08: .long 0xFFFFFFFF, 0xFFFFFFFF +replayHeader0_playerID: .long 0 +replayHeader0_powerup: .long 0 +replayHeader0_playerFlg: .long 0 +replayHeader0_padding1C: .long 0xFFFFFFFF +replayHeader0_padding20: .byte 0xFF +replayHeader0_switchFlg: .byte 0 +replayHeader0_padding22: .byte 0xFF, 0xFF +replayHeader0_padding24: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader0_padding30: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader1: +replayHeader1_world: .byte 0 +replayHeader1_level: .byte 0 +replayHeader1_area: .byte 0 +replayHeader1_entrance: .byte 0 +replayHeader1_seed: .long 0 +replayHeader1_padding08: .long 0xFFFFFFFF, 0xFFFFFFFF +replayHeader1_playerID: .long 0 +replayHeader1_powerup: .long 0 +replayHeader1_playerFlg: .long 0 +replayHeader1_padding1C: .long 0xFFFFFFFF +replayHeader1_padding20: .byte 0xFF +replayHeader1_switchFlg: .byte 0 +replayHeader1_padding22: .byte 0xFF, 0xFF +replayHeader1_padding24: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader1_padding30: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader2: +replayHeader2_world: .byte 0 +replayHeader2_level: .byte 0 +replayHeader2_area: .byte 0 +replayHeader2_entrance: .byte 0 +replayHeader2_seed: .long 0 +replayHeader2_padding08: .long 0xFFFFFFFF, 0xFFFFFFFF +replayHeader2_playerID: .long 0 +replayHeader2_powerup: .long 0 +replayHeader2_playerFlg: .long 0 +replayHeader2_padding1C: .long 0xFFFFFFFF +replayHeader2_padding20: .byte 0xFF +replayHeader2_switchFlg: .byte 0 +replayHeader2_padding22: .byte 0xFF, 0xFF +replayHeader2_padding24: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader2_padding30: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader3: +replayHeader3_world: .byte 0 +replayHeader3_level: .byte 0 +replayHeader3_area: .byte 0 +replayHeader3_entrance: .byte 0 +replayHeader3_seed: .long 0 +replayHeader3_padding08: .long 0xFFFFFFFF, 0xFFFFFFFF +replayHeader3_playerID: .long 0 +replayHeader3_powerup: .long 0 +replayHeader3_playerFlg: .long 0 +replayHeader3_padding1C: .long 0xFFFFFFFF +replayHeader3_padding20: .byte 0xFF +replayHeader3_switchFlg: .byte 0 +replayHeader3_padding22: .byte 0xFF, 0xFF +replayHeader3_padding24: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +replayHeader3_padding30: .long 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF + +# header size is 0x40 bytes + +replayFooter: .long 0xFFFFFFFF + +replayDataBuffers: .long 0, 0, 0, 0 +replayDataBufferPointers: .long 0, 0, 0, 0 +replayDataBufferSize: .long 0x80000 + +saveRandomSeed: .long 0 + + +keepTiltValues: .long 0, 0, 0, 0 + diff --git a/src/scene.S b/src/scene.S new file mode 100644 index 0000000..8a8404c --- /dev/null +++ b/src/scene.S @@ -0,0 +1,149 @@ +.extern currentHeap +.extern MakeScene +.extern DVDClass +.extern GetSceneLightInfo +.extern GetRes +.extern GetAnmScn +.extern BindAnmScn +.extern AssignAnmScnToLightInfo +.extern LoadBlight +.extern LoadBlmap + + +.text + +.set sp,1 +.set rtoc,2 + +.global LoadMapScene +LoadMapScene: + stwu sp, -0x30(sp) + mflr r0 + stw r0, 0x34(sp) + + stw r31, 0x2C(sp) + + + + lis r3, currentHeap@h + ori r3, r3, currentHeap@l + lwz r3, 0(r3) + + li r4, 36 #Light count + li r5, 8 #Ambient light count + li r6, 2 #Dunno + li r7, 0 #Make fog (bool) + li r8, 0 #Scene ID + + bl MakeScene + + + # Now make the actual scene! + # Get light info + li r3, 0 + bl GetSceneLightInfo + mr r31, r3 + + # Get scene/scene.brres + lis r3, DVDClass@h + ori r3, r3, DVDClass@l + addi r3, r3, 4 + + lis r4, EnvWorld@h + ori r4, r4, EnvWorld@l + + lis r5, SceneBrres@h + ori r5, r5, SceneBrres@l + + bl GetRes + + # Got that, now get the AnmScn we want (MainSelect) + stw r3, 0x0C(sp) #ResFile + + addi r3, sp, 0xC + lis r4, MainSelect@h + ori r4, r4, MainSelect@l + bl GetAnmScn + stw r3, 0x10(sp) + + # Bind it + addi r3, sp, 0x10 + addi r4, sp, 0x10 + bl BindAnmScn + + # Add it to lightinfo + mr r3, r31 #This + addi r4, sp, 0x10 #AnmScn pointer + li r5, -1 #Dunno + li r6, 3 #Dunno + + lis r9, Zero@h + ori r9, r9, Zero@l + lfs f1, 0(r9) #Dunno + + bl AssignAnmScnToLightInfo + + + # Now set up the rest of the scene + # Get blight + lis r3, DVDClass@h + ori r3, r3, DVDClass@l + addi r3, r3, 4 + + lis r4, EnvWorld@h + ori r4, r4, EnvWorld@l + + lis r5, BlightW1@h + ori r5, r5, BlightW1@l + + bl GetRes + + # Load it into lightinfo + mr r4, r3 + mr r3, r31 + bl LoadBlight + + + + # Do the same for blmap + lis r3, DVDClass@h + ori r3, r3, DVDClass@l + addi r3, r3, 4 + + lis r4, EnvWorld@h + ori r4, r4, EnvWorld@l + + lis r5, BlmapW1@h + ori r5, r5, BlmapW1@l + + bl GetRes + + # Load it into its class + mr r4, r3 + lwz r3, 0x14(r31) + bl LoadBlmap + + + # DONE!! + lwz r31, 0x2C(sp) + + lwz r0, 0x34(sp) + mtlr r0 + addi sp, sp, 0x30 + blr + + + + + + +.data +EnvWorld: .string "Env_world" +SceneBrres: .string "scene/scene.brres" +MainSelect: .string "MainSelect" +Zero: .float 0.0 +BlightW1: .string "light/W8.blight" +BlmapW1: .string "light/W8.blmap" + +.align 4 + diff --git a/src/spritetex.S b/src/spritetex.S new file mode 100644 index 0000000..681f763 --- /dev/null +++ b/src/spritetex.S @@ -0,0 +1,75 @@ +.extern sprintf + +#ifndef __MWERKS__ +.set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3 +#endif + +.text +.align 4 +.global GetTexFilenameForR5, TexFilenameBuffer, TexFormatString + +.set sp, 1 + +GetTexFilenameForR5: + # obj number should be put into r5 + # returned filename is in r5 + # this makes it easy to use with dRes_c::GetResource + + stwu sp, -0x10(sp) + mflr r0 + stw r0, 0x14(sp) + stw r3, 0xC(sp) + stw r4, 0x8(sp) + + lis r3, TexFilenameBuffer@h + ori r3, r3, TexFilenameBuffer@l + + lis r4, TexFormatString@h + ori r4, r4, TexFormatString@l + + crclr 4*cr1+eq + bl sprintf + + lis r5, TexFilenameBuffer@h + ori r5, r5, TexFilenameBuffer@l + + lwz r0, 0x14(sp) + lwz r3, 0xC(sp) + lwz r4, 0x8(sp) + mtlr r0 + addi sp, sp, 0x10 + blr + + + + + +.global TEX_WoodBox +TEX_WoodBox: + lwz r5, 4(r30) + srwi r5, r5, 24 + b GetTexFilenameForR5 + + +.global TEX_Bush +TEX_Bush: + srwi r5, r27, 28 + b GetTexFilenameForR5 + + + + + +.data +TexFilenameBuffer: + .long 0,0,0,0 + +TexFormatString: + .string "g3d/t%02d.brres" + diff --git a/src/tilegod.S b/src/tilegod.S new file mode 100644 index 0000000..248b3dc --- /dev/null +++ b/src/tilegod.S @@ -0,0 +1,65 @@ +.text + +#ifndef __MWERKS__ +.set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3 +#endif + +.align 4 +.extern ExitFromTileGodHack +.extern TileTable + +.global NEW_GetTileFromTileTable +NEW_GetTileFromTileTable: + andi. r0, r3, 0x8000 + beq UseRegular + + li r4, 0x7FFF + and r3, r3, r4 + blr + +UseRegular: + lis r4, TileTable@h + ori r4, r4, TileTable@l + + clrlslwi r0, r3, 16, 1 + lhzx r3, r4, r0 + blr + + +.global TileGodHack +TileGodHack: + lwz r4, 4(r3) # Load settings + extrwi. r0, r4, 1, 16 # Get and check the "use regular tile" flag + extrwi r4, r4, 3, 17 # Get the tile number OR tileset number + bne Special + + lis r3, TileGodTiles@h + ori r3, r3, TileGodTiles@l + slwi r4, r4, 1 + lhzx r25, r3, r4 + + b ExitFromTileGodHack + +Special: + lwz r3, 4(r3) # Load settings + srwi r3, r3, 20 # Get tile number + andi. r3, r3, 0xFF # Cut off top nybble + slwi r4, r4, 8 # Shift tileset number + or r3, r3, r4 # Add tileset number + ori r25, r3, 0x8000 # Add "get regular tile" flag + + b ExitFromTileGodHack + + + +.data +TileGodTiles: + .short 0x7C, 0x02, 0x0C, 0x7B, 0x0F, 0x00 + + diff --git a/src/wm_player.cpp b/src/wm_player.cpp new file mode 100644 index 0000000..39dc0a5 --- /dev/null +++ b/src/wm_player.cpp @@ -0,0 +1,192 @@ +#include "worldmap.h" + +daWMPlayer_c *daWMPlayer_c::instance; + +int daWMPlayer_c::onCreate() { + OSReport("* dWMPlayer_c created\n"); + + OSReport("Init handler...\n"); + this->modelHandler = new dPlayerModelHandler_c(0); + this->modelHandler->loadModel(0, 3, 2); + this->modelHandler->mdlClass->startAnimation(0, 1.2, 10.0, 0.0); + this->modelHandler->setSRT((Vec){0.0,100.0,-100.0}, (S16Vec){0,0,0}, (Vec){2.0,2.0,2.0}); + this->modelHandler->draw(); + OSReport("Init done!\n"); + + pos = (Vec){0.0f,0.0f,0.0f}; + rot = (S16Vec){0,0,0}; + scale = (Vec){1.5f,1.5f,1.5f}; + + current_param = 0; + + /*//#define BRRES_NAME "fruits_kusa_gake" + //#define MODEL_NAME "fruits_kusa_gake_S" + + #define BRRES_NAME "bgB_4502" + #define MODEL_NAME BRRES_NAME + + OSReport("Loading nw4r model\n"); + //LoadFile(&this->nw4rMdlFH, "/Object/" BRRES_NAME ".arc"); + LoadFile(&this->nw4rMdlFH, "/Object/CrapMap.arc"); + OSReport("Loaded. Reading arc\n"); + ARCHandle arc; + ARCFileInfo keyinfo; + ARCInitHandle(this->nw4rMdlFH.filePtr, &arc); + //bool arcres = ARCOpen(&arc, "g3d/" BRRES_NAME ".brres", &keyinfo); + bool arcres = ARCOpen(&arc, "g3d/model.brres", &keyinfo); + OSReport(arcres ? "Success\n" : "Fail\n"); + + OSReport("Getting nw4r model\n"); + //void *brres = DVD_GetFile(GetDVDClass2(), "fruits_kusa_gake", "g3d/fruits_kusa_gake.brres"); + + OSReport("Done. Constructing model\n"); + void *brres = ARCGetStartAddrInMem(&keyinfo); + OSReport("brres @ %p\n", brres); + nw4r::g3d::ResFile resfile(brres); + OSReport(resfile.CheckRevision() ? "Success\n" : "Fail\n"); + resfile.Init(); + OSReport(resfile.Bind(resfile) ? "Success\n" : "Fail\n"); + //void *mdl = resfile.GetResMdl(MODEL_NAME); + void *mdl = resfile.GetResMdl("CrapMap"); + OSReport("MDL @ %p, %d\n", mdl, 1099); + //this->nw4rMdlTest = nw4r::g3d::ConstructScnMdl(mdl, 0x20, 1); + //this->nw4rMdlTest = nw4r::g3d::ConstructScnMdlSimple(mdl, 1); + OSReport(this->allocator.link(-1, GameHeaps[0], 0, 0x20) ? "Success\n" : "Fail\n"); + OSReport(this->nw4rMdl.setup(&mdl, &this->allocator, 0, 1, 0) ? "Success\n" : "Fail\n"); + //this->nw4rMdl.sub_80064BF0(); + //this->nw4rMdl.oneSetupType(); + OSReport("Unlink returned %d\n", this->allocator.unlink()); + OSReport("Done!\n"); + + Mtx asdf; + MTXIdentity(asdf); + this->nw4rMdl.setDrawMatrix(asdf); + + ARCClose(&keyinfo);*/ + + return true; +} + +int daWMPlayer_c::onDelete() { + delete modelHandler; + OSReport("* dWMPlayer_c deleted\n"); + + return true; +} + + +int daWMPlayer_c::onExecute() { + this->modelHandler->update(); + this->modelHandler->setSRT(this->pos, this->rot, this->scale); + +#ifdef MARIO_OPTIONS + // Before we leave, do the debug movement stuff + int heldButtons = Remocon_GetButtons(GetActiveRemocon()); + int nowPressed = Remocon_GetPressed(GetActiveRemocon()); + char buf[100]; + bool updated = false; + + if (nowPressed & WPAD_LEFT) { + current_param--; + updated = true; + } + + if (nowPressed & WPAD_RIGHT) { + current_param++; + updated = true; + } + + if (current_param < 0) + current_param = 8; + + if (current_param > 8) + current_param = 0; + + float pos_mod = 0.0f; + short rot_mod = 0.0f; + float scale_mod = 0.0f; + if (nowPressed & WPAD_ONE) { + pos_mod -= 5.0f; + rot_mod -= 0x1000; + scale_mod -= 0.1f; + updated = true; + } else if (nowPressed & WPAD_TWO) { + pos_mod += 5.0f; + rot_mod += 0x1000; + scale_mod += 0.1f; + updated = true; + } + + if (!updated) return true; + + if (current_param == 0) { + pos.x += pos_mod; + sprintf(buf, "X position: %f", pos.x); + } else if (current_param == 1) { + pos.y += pos_mod; + sprintf(buf, "Y position: %f", pos.y); + } else if (current_param == 2) { + pos.z += pos_mod; + sprintf(buf, "Z position: %f", pos.z); + } else if (current_param == 3) { + rot.x += rot_mod; + sprintf(buf, "X rotation: 0x%04x", rot.x); + } else if (current_param == 4) { + rot.y += rot_mod; + sprintf(buf, "Y rotation: 0x%04x", rot.y); + } else if (current_param == 5) { + rot.z += rot_mod; + sprintf(buf, "Z rotation: 0x%04x", rot.z); + } else if (current_param == 6) { + scale.x += scale_mod; + sprintf(buf, "X scale: %f", scale.x); + } else if (current_param == 7) { + scale.y += scale_mod; + sprintf(buf, "Y scale: %f", scale.y); + } else if (current_param == 8) { + scale.z += scale_mod; + sprintf(buf, "Z scale: %f", scale.z); + } + + dScNewerWorldMap_c::instance->SetTitle(buf); +#endif + + return true; +} + +int daWMPlayer_c::onDraw() { + this->modelHandler->draw(); + + //OSReport("Adding to scene\n"); + //this->nw4rMdl.scheduleForDrawing(); + //OSReport("done\n"); + + return true; +} + + +void daWMPlayer_c::startAnimation(int id, float frame, float unk, float updateRate) { + if (id == currentAnim && frame == currentFrame && unk == currentUnk && updateRate == currentUpdateRate) + return; + + currentAnim = id; + currentFrame = frame; + currentUnk = unk; + currentUpdateRate = updateRate; + this->modelHandler->mdlClass->startAnimation(id, frame, unk, updateRate); +} + + + +daWMPlayer_c *daWMPlayer_c::build() { + OSReport("Creating WMPlayer\n"); + + void *buffer = AllocFromGameHeap1(sizeof(daWMPlayer_c)); + daWMPlayer_c *c = new(buffer) daWMPlayer_c; + + OSReport("Created WMPlayer @ %p\n", c); + + instance = c; + return c; +} + diff --git a/src/wmresourcemng.cpp b/src/wmresourcemng.cpp new file mode 100644 index 0000000..4a71753 --- /dev/null +++ b/src/wmresourcemng.cpp @@ -0,0 +1,78 @@ +#include "worldmap.h" + + + + +dWMResourceMng_c::dWMResourceMng_c() { + hasSetPath = false; + isSetLoaded = false; + isLoadingComplete = false; +} + +dWMResourceMng_c::~dWMResourceMng_c() { + if (isSetLoaded) { + for (int i = 0; i < setData->count; i++) { + resLoaders[i].unload(); + } + + delete[] resLoaders; + } + + setLoader.unload(); +} + + + +bool dWMResourceMng_c::isLoaded() { + return isLoadingComplete; +} + + +bool dWMResourceMng_c::loadSet(const char *setName) { + if (isLoadingComplete) + return true; + + // only start the loading process if we haven't done that already + if (!isSetLoaded) { + if (!hasSetPath) { + snprintf(setPath, sizeof(setPath), "/Maps/%s.fileset", setName); + hasSetPath = true; + } + + void *result = setLoader.load(setPath); + if (result == 0) + return false; + + // cool, we've got it, now load everything here + setData = (WMResSetHeader*)result; + + resLoaders = new dDvdLoader_c[setData->count]; + + isSetLoaded = true; + } + + // now try to load every resource + // if even ONE of them fails, then don't return true + bool isLoadingComplete = true; + + for (int i = 0; i < setData->count; i++) { + isLoadingComplete &= (resLoaders[i].load(setData->getName(i)) != 0); + } + + // if they are ALL loaded, then we'll return true! + return isLoadingComplete; +} + + +void *dWMResourceMng_c::operator[](u32 key) { + if (!isLoadingComplete) + return 0; + + for (int i = 0; i < setData->count; i++) { + if (key == setData->entries[i].key) + return resLoaders[i].buffer; + } + + return 0; +} + diff --git a/src/world_camera.cpp b/src/world_camera.cpp new file mode 100644 index 0000000..1fc3a5a --- /dev/null +++ b/src/world_camera.cpp @@ -0,0 +1,94 @@ +#include "worldmap.h" + +dWorldCamera_c *dWorldCamera_c::instance = 0; + +dWorldCamera_c *dWorldCamera_c::build() { + OSReport("Creating WorldCamera\n"); + + void *buffer = AllocFromGameHeap1(sizeof(dWorldCamera_c)); + dWorldCamera_c *c = new(buffer) dWorldCamera_c; + + OSReport("Created WorldCamera @ %p\n", c); + + instance = c; + return c; +} + + + + +int dWorldCamera_c::onCreate() { + this->camPos = (Point3d){0.0f, 400.0f, 400.0f}; + this->camRotate = (Point3d){-40.0f, 0.0f, 0.0f}; // ZXY order + + return true; +} + + +int dWorldCamera_c::onDelete() { + return true; +} + + +int dWorldCamera_c::onExecute() { + int heldButtons = Remocon_GetButtons(GetActiveRemocon()); + + if (heldButtons & WPAD_LEFT) + this->camPos.x -= 5.0f; + if (heldButtons & WPAD_RIGHT) + this->camPos.x += 5.0f; + + if (heldButtons & WPAD_UP) + this->camPos.z -= 5.0f; + if (heldButtons & WPAD_DOWN) + this->camPos.z += 5.0f; + + if (heldButtons & WPAD_MINUS) + this->camRotate.y -= 2.0f; + if (heldButtons & WPAD_PLUS) + this->camRotate.y += 2.0f; + + return true; +} + + +int dWorldCamera_c::onDraw() { + // fixup camera shit + GXRenderModeObj *rmode = nw4r::g3d::G3DState::GetRenderModeObj(); + + // 2D camera + nw4r::g3d::Camera cam2d(GetCameraByID(1)); + + if (rmode->field_rendering != 0) + cam2d.SetViewportJitter(VIGetNextField()); + + cam2d.SetOrtho(rmode->efbHeight, 0.0f, 0.0f, rmode->fbWidth * (IsWideScreen() ? 1.3333334f : 1.0f), -100000.0f, 100000.0f); + + // 3D camera + nw4r::g3d::Camera cam3d(GetCameraByID(0)); + + if (rmode->field_rendering != 0) + cam3d.SetViewportJitter(VIGetNextField()); + + cam3d.SetPerspective(45, (f32)rmode->viWidth / (f32)rmode->viHeight, 0.1f, 2400.0f); + + nw4r::g3d::Camera::PostureInfo posture; + posture.tp = nw4r::g3d::Camera::POSTURE_ROTATE; + posture.cameraRotate = this->camRotate; + + cam3d.SetPosition(this->camPos); + cam3d.SetPosture(posture); + + /*nw4r::g3d::Camera::PostureInfo posture; + posture.tp = nw4r::g3d::Camera::POSTURE_LOOKAT; + posture.cameraUp = (Point3d){0,1,0}; + posture.cameraTarget = (Point3d){0,0,0}; + + cam3d.SetPosition((Point3d){-3,2,3}); + cam3d.SetPosture(posture);*/ + + //cam3d.GetCameraMtx(&T3D::Camera.view_matrix); + + return true; +} + diff --git a/src/worldmap.cpp b/src/worldmap.cpp new file mode 100644 index 0000000..97d1b73 --- /dev/null +++ b/src/worldmap.cpp @@ -0,0 +1,245 @@ +/* + * Newer Super Mario Bros. Wii + * 2D World Maps + * + * Wish me luck. That's all I'm saying. --Treeki + * Started: 03/06/2010; 11:52pm + */ + +#include "worldmap.h" + +/* Code */ +void PaneSetAllVisible(void *pane, int flag, bool value) { + //OSReport("%08X {\n", pane); + if (value) + ((char*)pane)[0xBB] &= ~(1 << flag); + else + ((char*)pane)[0xBB] |= (1 << flag); + + nw4rLinkListNode *firstNode = (nw4rLinkListNode*)(pane+0x14); + nw4rLinkListNode *currentNode = (nw4rLinkListNode*)(firstNode->prev); + + while (currentNode != firstNode) { + PaneSetAllVisible(((void*)currentNode) - 4, flag, value); + currentNode = (nw4rLinkListNode*)currentNode->prev; + } + //OSReport("} %08X\n", pane); +} + +void LayoutSetAllVisible(void *layout, int flag, bool value) { + // get the rootpane from offset 0x10 + PaneSetAllVisible(*((void**)(layout+0x10)), flag, value); +} + + +void *LoadFile(FileHandle *handle, char *name) { + int entryNum = DVDConvertPathToEntrynum(name); + + DVDHandle dvdhandle; + if (!DVDFastOpen(entryNum, &dvdhandle)) { + OSReport("Cannot open file %s\n", name); + return 0; + } + + handle->length = dvdhandle.length; + handle->filePtr = EGG__Heap__alloc((handle->length+0x1F) & ~0x1F, 0x20, GetArchiveHeap()); + + int ret = DVDReadPrio(&dvdhandle, handle->filePtr, (handle->length+0x1F) & ~0x1F, 0, 2); + //OSReport("retval: %x\n", ret); + + DVDClose(&dvdhandle); + + return handle->filePtr; +} + +bool FreeFile(FileHandle *handle) { + if (!handle) return false; + + if (handle->filePtr) + EGG__Heap__free(handle->filePtr, GetArchiveHeap()); + + return true; +} + +void d2DWorldMap_c__LoadLayout(d2DWorldMap_c *self, char *arcName, char *prefix, char *brlytName) { + //char *arc = NSMBWLoadFile(&self->fileHandle, arcName, 0, *((void**)0x8042A72C)); + //char *arc = NSMBWLoadFile(&self->fileHandle, arcName, 0, 0); + char *arc = (char*)LoadFile(&self->fileHandle, arcName); + if (arc == 0) { + OSReport("Can't load %s :(\n", arcName); + while (true) { } + } + + // allocate 0xC0 space for the ArcResourceAccessor + // unsure what the actual size is, but we should be safe with that + self->ResAcc = AllocFromGameHeap1(0xC0); + nsmbw__ArcResourceAccessor__ArcResourceAccessor(self->ResAcc); +#ifdef REGION_NTSC + *((void**)self->ResAcc) = (void*)0x802FE410; // replace vtable with NSMB's version +#endif +#ifdef REGION_PAL + *((void**)self->ResAcc) = (void*)0x802FE710; // replace vtable with NSMB's version +#endif + nsmbw__ArcResourceAccessor__Set(self->ResAcc, arc, prefix); + + char *brlyt = nsmbw__ArcResourceAccessor__GetResource(self->ResAcc, 0x626C7974, brlytName, 0); + + // allocate 0x20 space for the Layout + self->Layout = AllocFromGameHeap1(0x20); + lyt__Layout__Layout(self->Layout); + lyt__Layout__Build(self->Layout, brlyt, self->ResAcc); + + // allocate 0x54 space for the DrawInfo + self->DrawInfo = (nw4r__lyt__DrawInfo*)AllocFromGameHeap1(0x54); + lyt__DrawInfo__DrawInfo(self->DrawInfo); + + // set up the anims + self->BrlanArray = 0; + self->BrlanCount = 0; + + //PSMTXTransApply(self->DrawInfo->matrix, self->DrawInfo->matrix, 304, 228, 0); + + /*self->DrawInfo->left = 0; + self->DrawInfo->top = 0; + self->DrawInfo->right = 608; + self->DrawInfo->bottom = 456;*/ +} + +void d2DWorldMap_c__LoadAnims(d2DWorldMap_c *self, const char **brlanNames, int brlanCount) { + //OSReport("Loading anims\n"); + void *buf = __nwa(brlanCount*0x1C + 0x10); + //OSReport("Alloced buffer: %08X\n", buf); + // function params are BrlanHandler_ctor, BrlanHandler_dtor + self->BrlanArray = construct_new_array(buf, (void*)0x800C9150, (void*)0x800C91A0, 0x1C, brlanCount); + //OSReport("Constructed array: %08X\n", self->BrlanArray); + + // huge hack coming up + struct TrickClass_t { + void *pad1; + void *resacc; + void *pad2; + void *pad3; + void *pad4; + void *pad5; + void *pad6; + void *pad7; + } TrickClass; + TrickClass.resacc = self->ResAcc; + //OSReport("Created TrickClass\n"); + + for (int i = 0; i < brlanCount; i++) { + //OSReport("b@%08X\n", self->BrlanArray+(0x1C*i)); + //OSReport("Loading brlan %d %s\n", i, brlanNames[i]); + NSMBWBrlan__Load(self->BrlanArray+(0x1C*i), brlanNames[i], (void*)(&TrickClass), self->Layout, 1); + //OSReport("Done loading brlan %d %s\n", i, brlanNames[i]); + //OSReport("a@%08X\n", self->BrlanArray+(0x1C*i)); + } + OSReport("Done loading brlans\n"); + + /*char *brlan = nsmbw__ArcResourceAccessor__GetResource(self->ResAcc, 0x616e696d, brlanName, 0); + OSReport("grabbed brlan %s to %08X\n", brlanName, brlan); + + // call CreateAnimTransform + CreateAnimTransformFunc CreateAnimTransform = (*((CreateAnimTransformFunc**)self->Layout))[5]; + void *atf = CreateAnimTransform(self->Layout, brlan, self->ResAcc); + + // call BindAnimation + BindAnimationFunc BindAnimation = (*((BindAnimationFunc**)self->Layout))[7]; + BindAnimation(self->Layout, atf); + + return atf;*/ +} + +void d2DWorldMap_c__SetAnimationEnable(d2DWorldMap_c *self, void *anim, bool val) { + SetAnimationEnableFunc SetAnimationEnable = (*((SetAnimationEnableFunc**)self->Layout))[11]; + SetAnimationEnable(self->Layout, anim, val); +} + + +void d2DWorldMap_c__FreeLayout(d2DWorldMap_c *self) { + if (self->BrlanArray) { + for (int i = 0; i < self->BrlanCount; i++) { + NSMBWBrlan__Free(self->BrlanArray+(0x1C*i)); + } + + // function param is BrlanHandler_dtor + DeleteArray(self->BrlanArray, (void*)0x800C91A0); + } + + lyt__Layout__dt(self->Layout, 0); + nsmbw__ArcResourceAccessor__dt(self->ResAcc, 0); + lyt__DrawInfo__dt(self->DrawInfo, 0); + + FreeFromGameHeap1(self->ResAcc); + FreeFromGameHeap1(self->Layout); + FreeFromGameHeap1(self->DrawInfo); + + //NSMBWFreeFile(&self->fileHandle); + FreeFile(&self->fileHandle); +} + + + +const char *bannerStart = "banner_start.brlan"; +const char *bannerLoop = "banner_loop.brlan"; + +bool d2DWorldMap_c__onCreate(d2DWorldMap_c *self) { + OSReport("Starting\n"); + //d2DWorldMap_c__LoadLayout(self, testArc, "arc", "messageWindow_02.brlyt"); + d2DWorldMap_c__LoadLayout(self, "/NewerRes/wmap.arc", "arc", "banner.brlyt"); + OSReport("Loaded\n"); + //d2DWorldMap_c__LoadLayout(self, "/NewerRes/wmap.arc", "arc", "openingTitle_EU_00.brlyt"); + //d2DWorldMap_c__LoadLayout(self, "/NewerRes/wmap.arc", "arc", "pauseMenu_16.brlyt"); + //self->StartAnim = d2DWorldMap_c__LoadAnim(self, "banner_start.brlan"); + //OSReport("startanim: %X\n", self->StartAnim); + //self->LoopAnim = d2DWorldMap_c__LoadAnim(self, "banner_loop.brlan"); + + const char* anims[2]; + anims[0] = bannerStart; + anims[1] = bannerLoop; + OSReport("Set anims\n"); + + d2DWorldMap_c__LoadAnims(self, anims, 2); + OSReport("Loaded anims\n"); + OSReport("layout is at %8X\n", self->Layout); // 815e7450 + OSReport("Enabled anims\n"); + d2DWorldMap_c__SetAnimationEnable(self, (void*)0x815ED040, true); + + //LayoutMakeAllVisible(self->Layout, true); + + /*bool (*idk)(int) = (bool(*)(int))0x800B0DB0; + idk(0); + + bool (*idk2)(int*) = (bool(*)(int*))0x800E4940; + int blah = 0xFF; + idk2(&blah);*/ + + return true; +} + +bool d2DWorldMap_c__onDelete(d2DWorldMap_c *self) { + //d2DWorldMap_c__FreeLayout(self); + return true; +} + +bool d2DWorldMap_c__onExecute(d2DWorldMap_c *self) { + // call Animate() + AnimateFunc Animate = (*((AnimateFunc**)self->Layout))[14]; + Animate(self->Layout, true); + return true; +} + +bool d2DWorldMap_c__onDraw(d2DWorldMap_c *self) { + MTX44 matrix; + MTXOrtho(matrix, 228, -228, -304, 304, 0, 1); + GXSetProjection(matrix, GX_ORTHOGRAPHIC); + + // call CalculateMtx() + CalculateMtxFunc CalculateMtx = (*((CalculateMtxFunc**)self->Layout))[12]; + CalculateMtx(self->Layout, self->DrawInfo); + // call Draw() + DrawFunc Draw = (*((DrawFunc**)self->Layout))[13]; + Draw(self->Layout, self->DrawInfo); + return true; +} + diff --git a/src/worldmap.h b/src/worldmap.h new file mode 100644 index 0000000..1f8a9a3 --- /dev/null +++ b/src/worldmap.h @@ -0,0 +1,211 @@ +/* + * Newer Super Mario Bros. Wii + * World Maps + * + * Wish me luck. That's all I'm saying. --Treeki + * Started: 03/06/2010; 11:52pm + */ + +// TODO: add Save Error state + +//#define MARIO_OPTIONS +//#define WM_DEBUGGING +//#define LEVEL_MENU + +#include +#include + +#ifdef LEVEL_MENU +#include "layoutlib.h" +#endif + +#include "fileload.h" +#include "levelinfo.h" +#include "3dlib/treeki3d.h" +#include "worldmapdata.h" +#include + +enum WMDirection { + LEFT, + RIGHT, + UP, + DOWN +}; + +#ifdef WM_DEBUGGING +#define MapReport OSReport +#else +inline void MapReport(const char *str, ...) { } +#endif + +void NewerMapDrawFunc(); + + +struct WMResSetEntry { + u32 key; + u32 offset; +}; + +struct WMResSetHeader { + u32 magic; + u32 count; + WMResSetEntry entries[1]; // dynamic size + + char *getName(int index) { + return (char*)((u32)this + entries[index].offset); + } +}; + +class dWMResourceMng_c { +private: + bool hasSetPath; + bool isSetLoaded; + bool isLoadingComplete; + + char setPath[0x40]; + dDvdLoader_c setLoader; + dDvdLoader_c *resLoaders; + + WMResSetHeader *setData; + +public: + dWMResourceMng_c(); + ~dWMResourceMng_c(); + + bool loadSet(const char *setName); + void *operator[](u32 key); + + bool isLoaded(); + + + u32 resCount() { + return setData->count; + } + + u32 keyForIndex(u32 index) { + return setData->entries[index].key; + } + + void *dataForIndex(u32 index) { + return resLoaders[index].buffer; + } +}; + + +class dWMMap_c : public dBase_c { +public: + int onCreate(); + int onDelete(); + int onExecute(); + int onDraw(); + + static dWMMap_c *build(); + static dWMMap_c *instance; +}; + + +class dWorldCamera_c : public dBase_c { +public: + int onCreate(); + int onDelete(); + int onExecute(); + int onDraw(); + + Point3d camPos; + Vec camRotate; + + static dWorldCamera_c *build(); + static dWorldCamera_c *instance; +}; + + +class daWMPlayer_c : public dActor_c { +public: + dPlayerModelHandler_c *modelHandler; + + int onCreate(); + int onDelete(); + int onExecute(); + int onDraw(); + + int current_param; + + int currentAnim; + float currentFrame; + float currentUnk; + float currentUpdateRate; + + void startAnimation(int id, float frame, float unk, float updateRate); + + static daWMPlayer_c *build(); + static daWMPlayer_c *instance; +}; + +// WORLD MAP CLASS LAYOUT +class dScNewerWorldMap_c : public dScene_c { +public: + #ifdef LEVEL_MENU + Layout *layout; + int currentPage; + int *selections; + #endif + int state; + void *csMenu; + void *selectCursor; + void *numPeopleChange; + void *yesNoWindow; + void *continueObj; + void *stockItem; + void *stockItemShadow; + void *easyPairing; + + void *levelInfo; + FileHandle levelInfoFH; + + #ifndef LEVEL_MENU + mHeapAllocator_c allocator; + File modelFile; + m3d::mdl_c model; + + void LoadModel(); + + daWMPlayer_c *player; + + WorldMapData wmData; + + bool isMoving; + WMPathPoint *currentPoint; + WMPathPoint *nextPoint; + + WMPathDef *currentPath; + WMPathSegment *currentSegment; + int currentSegmentID; + bool reverseThroughPath; // direction we are going through the path + + void HandleMovement(); + + void StartMovementTo(WMDirection direction); + void MoveToSegment(int id); + + void MoveThroughPath(); + + void ActivatePoint(); + #endif + + void StartLevel(LevelInfo_Entry *entry); + + #ifdef LEVEL_MENU + void StartLevel(); + void GenText(); + void SetTitle(const char *text); + #endif + + int onCreate(); + int onDelete(); + int onExecute(); + int onDraw(); + + static dScNewerWorldMap_c *build(); + static dScNewerWorldMap_c *instance; +}; + diff --git a/src/worldmap_new.cpp b/src/worldmap_new.cpp new file mode 100644 index 0000000..2db382a --- /dev/null +++ b/src/worldmap_new.cpp @@ -0,0 +1,1358 @@ +#include "worldmap.h" + +extern "C" void LoadMapScene(); + +dScNewerWorldMap_c *dScNewerWorldMap_c::instance = 0; + + +dScNewerWorldMap_c *dScNewerWorldMap_c::build() { + // return new dScNewerWorldMap_c; + OSReport("Creating WorldMap\n"); + + void *buffer = AllocFromGameHeap1(sizeof(dScNewerWorldMap_c)); + dScNewerWorldMap_c *c = new(buffer) dScNewerWorldMap_c; + + OSReport("Created WorldMap @ %p\n", c); + + instance = c; + return c; +} + + +#define SELC_SETUP_DONE(sc) (*((bool*)(((u32)(sc))+0xD38))) + +#define EASYP_SETUP_DONE(ep) (*((bool*)(((u32)(ep))+0x278))) +#define EASYP_ACTIVE(ep) (*((bool*)(((u32)(ep))+0x279))) + +#define CSMENU_SETUP_DONE(csm) (*((bool*)(((u32)(csm))+0x270))) +#define CSMENU_ACTIVE(csm) (*((bool*)(((u32)(csm))+0x271))) +#define CSMENU_CHOICE_OK(csm) (*((bool*)(((u32)(csm))+0x272))) +#define CSMENU_UNK(csm) (*((bool*)(((u32)(csm))+0x273))) +#define CSMENU_CURRENT(csm) (*((int*)(((u32)(csm))+0x268))) + +#define YESNO_SETUP_DONE(ynw) (*((bool*)(((u32)(ynw))+0x294))) +#define YESNO_VISIBLE(ynw) (*((bool*)(((u32)(ynw))+0x295))) +#define YESNO_CLOSE(ynw) (*((bool*)(((u32)(ynw))+0x296))) +#define YESNO_OPENING(ynw) (*((bool*)(((u32)(ynw))+0x297))) +#define YESNO_REFUSED(ynw) (*((bool*)(((u32)(ynw))+0x298))) +#define YESNO_CANCELLED(ynw) (*((bool*)(((u32)(ynw))+0x299))) +#define YESNO_CANCELLED2(ynw) (*((bool*)(((u32)(ynw))+0x29A))) +#define YESNO_CURRENT(ynw) (*((int*)(((u32)(ynw))+0x284))) +#define YESNO_TYPE(ynw) (*((int*)(((u32)(ynw))+0x28C))) + +#define NPCHG_SETUP_DONE(npc) (*((bool*)(((u32)(npc))+0x67C))) +#define NPCHG_ACTIVE(npc) (*((bool*)(((u32)(npc))+0x67E))) +#define NPCHG_HIDE_FOR_EASYP(npc) (*((bool*)(((u32)(npc))+0x67F))) +#define NPCHG_READY(npc) (*((bool*)(((u32)(npc))+0x680))) +#define NPCHG_CCSB(npc,idx) (((void**)(((u32)(npc))+0x74))[(idx)]) +#define NPCHG_CCSC(npc,idx) (((void**)(((u32)(npc))+0x84))[(idx)]) +#define NPCHG_CCSA(npc,idx) (((void**)(((u32)(npc))+0x94))[(idx)]) +#define NPCHG_CCI(npc,idx) (((void**)(((u32)(npc))+0xA4))[(idx)]) +#define NPCHG_2DPLAYER(npc,idx) (((void**)(((u32)(npc))+0x64C))[(idx)]) + +#define STKI_SETUP_DONE(si) (*((bool*)(((u32)(si))+0x310))) +#define STKI_SHADOW(si) (*((void**)(((u32)(si))+0x310))) +#define STKI_2DPLAYER(si,idx) (((void**)(((u32)(si))+0x2E4))[(idx)]) +#define STKI_ITEM(si,idx) (((void**)(((u32)(si))+0x2F4))[(idx)]) +#define STKI_SHOW(si) (*((bool*)(((u32)(si))+0x8DD))) + +#define SIS_SETUP_DONE(sis) (*((bool*)(((u32)(sis))+0x260))) + +#define CCSB_ACTIVE(ccsb) (*((bool*)(((u32)(ccsb))+0x29C))) + +#define CCSC_ACTIVE(ccsc) (*((bool*)(((u32)(ccsc))+0x2A1))) + +#define PLAYER2D_SHOW_EASY_PAIRING(p2d) (*((bool*)(((u32)(p2d))+0x264))) + +#define CONT_LIVES(cont,idx) (((int*)(((u32)(cont))+0x2B8))[(idx)]) +#define CONT_SETUP_DONE(cont) (*((bool*)(((u32)(cont))+0x2D4))) +#define CONT_UNK1(cont) (*((bool*)(((u32)(cont))+0x2D5))) +#define CONT_UNK2(cont) (*((bool*)(((u32)(cont))+0x2D6))) +#define CONT_DONE(cont) (*((bool*)(((u32)(cont))+0x2D7))) +#define CONT_UNK3(cont) (*((bool*)(((u32)(cont))+0x2E0))) + +#define STATE_START_DVD 0 +#define STATE_LOAD_RES 1 +#define STATE_END_DVD 2 +#define STATE_SETUP_WAIT 3 +#define STATE_LIMBO 4 +#define STATE_CONTINUE_WAIT 5 +#define STATE_NORMAL 6 +#define STATE_OPT_CHANGE_WAIT 7 +#define STATE_CSMENU 8 +#define STATE_TITLE_CONFIRM_OPEN_WAIT 9 +#define STATE_TITLE_CONFIRM_SELECT 10 +#define STATE_TITLE_CONFIRM_HIT_WAIT 11 +#define STATE_PLAYER_CHANGE_WAIT 12 +#define STATE_EASY_PAIRING_WAIT 13 +#define STATE_POWERUPS_WAIT 14 +#define STATE_SAVE_OPEN 15 +#define STATE_SAVE_SELECT 16 +#define STATE_SAVE_WINDOW_CLOSE 17 +#define STATE_SAVE_DO 18 +#define STATE_SAVE_END_WINDOW 19 +#define STATE_SAVE_END_CLOSE_WAIT 20 +#define STATE_QUICKSAVE_OPEN 21 +#define STATE_QUICKSAVE_SELECT 22 +#define STATE_QUICKSAVE_WINDOW_CLOSE 23 +#define STATE_QUICKSAVE_DO 24 +#define STATE_QUICKSAVE_END_WINDOW 25 +#define STATE_QUICKSAVE_END_CLOSE_WAIT 26 +#define STATE_SAVE_ERROR 27 + +#define MENU_HEIGHT 15 + +const char *anim1 = "optionActivated.brlan"; +const char *anim2 = "optionDeactivated.brlan"; + +const char *group1 = "G_opt00"; +const char *group2 = "G_opt01"; +const char *group3 = "G_opt02"; +const char *group4 = "G_opt03"; +const char *group5 = "G_opt04"; +const char *group6 = "G_opt05"; +const char *group7 = "G_opt06"; +const char *group8 = "G_opt07"; +const char *group9 = "G_opt08"; +const char *group10 = "G_opt09"; +const char *group11 = "G_opt10"; +const char *group12 = "G_opt11"; +const char *group13 = "G_opt12"; +const char *group14 = "G_opt13"; +const char *group15 = "G_opt14"; + +//void *EGG__Heap__alloc(unsigned long size, int unk, void *heap); + +#ifdef LEVEL_MENU +void dScNewerWorldMap_c::StartLevel() { + LevelInfo_Entry *level = LevelInfo_GetLevels(this->levelInfo, this->currentPage); + level += this->selections[this->currentPage]; + StartLevel(level); +} +#endif + +void dScNewerWorldMap_c::StartLevel(LevelInfo_Entry *entry) { + for (int i = 0; i < 4; i++) { + bool isThere = QueryPlayerAvailability(i); + int id = Player_ID[i]; + Player_Active[i] = isThere ? 1 : 0; + if (!isThere) Player_Flags[i] = 0; + } + + StartLevelInfo sl; + sl.unk1 = 0; + sl.unk2 = 0xFF; + sl.unk3 = 0; + sl.unk4 = 0; + sl.purpose = 0; + + sl.world1 = entry->world; + sl.world2 = entry->world; + sl.level1 = entry->level; + sl.level2 = entry->level; + + // hopefully this will fix the Star Coin issues + SetSomeConditionShit(entry->world, entry->level, 2); + + ActivateWipe(WIPE_MARIO); + + DoStartLevel(GetGameMgr(), &sl); +} + +#ifdef LEVEL_MENU +void dScNewerWorldMap_c::SetTitle(const char *text) { + unsigned short conv_buf[0x1FF]; + int length = strlen(text); + if (length > 0x1FF) + length = 0x1FF; + + for (int i = 0; i < length; i++) { + conv_buf[i] = text[i]; + } + + void *textBox = EmbeddedLayout_FindTextBoxByName(this->layout, "ScreenTitle"); + TextBox_SetString(textBox, conv_buf, 0); +} + +void dScNewerWorldMap_c::GenText() { + char buf[0x1FF]; + char paneNameBuf[0x20]; + char textBoxNameBuf[0x20]; + unsigned short wchars[0x1FF]; + + SaveBlock *save = GetSaveFile()->GetBlock(-1); + + LevelInfo_Section *section = LevelInfo_GetSection(this->levelInfo, this->currentPage); + LevelInfo_Entry *levels = LevelInfo_GetLevels(this->levelInfo, section); + + int count = section->levelCount; + + for (int i = 0; i < MENU_HEIGHT; i++) { + sprintf(paneNameBuf, "Opt%02d", i); + sprintf(textBoxNameBuf, "OptText%02d", i); + void *pane = EmbeddedLayout_FindPaneByName(this->layout, paneNameBuf); + void *textBox = EmbeddedLayout_FindTextBoxByName(this->layout, textBoxNameBuf); + + if (i < count) { + // valid level + PANE_FLAGS(pane) |= 1; + + u32 conds = save->GetLevelCondition(levels[i].world, levels[i].level); + + char cond1, cond2, cond3, cond4, cond5; + cond1 = (conds & COND_NORMAL ? 'x' : '.'); + cond2 = (conds & COND_SECRET ? 'x' : '.'); + cond3 = (conds & COND_COIN1 ? 'x' : '.'); + cond4 = (conds & COND_COIN2 ? 'x' : '.'); + cond5 = (conds & COND_COIN3 ? 'x' : '.'); + + sprintf(buf, "%s %c%c %c%c%c", LevelInfo_GetName(this->levelInfo, &levels[i]), cond1, cond2, cond3, cond4, cond5); + + for (int i = 0; i < 0x1FF; i++) { + wchars[i] = buf[i]; + if (buf[i] == 0) break; + } + + TextBox_SetString(textBox, wchars, 0); + } else { + // invalid, hide the pane + PANE_FLAGS(pane) &= ~1; + } + } +} +#endif + +int dScNewerWorldMap_c::onCreate() { + LoadMapScene(); + GameSetup__LoadScene(0); // lol, stolen from GAME_SETUP + + #ifdef LEVEL_MENU + this->layout = (Layout*)AllocFromGameHeap1(sizeof(Layout)); + if (!this->layout) { + OSReport("memalloc fail\n"); + InfiniteLoop; + } + + EmbeddedLayout_ctor(this->layout); + EmbeddedLayout_LoadArc(this->layout, "NewerRes/wmap.arc"); + + if (!EmbeddedLayout_Build(this->layout, "levelSelect.brlyt", 0)) { + OSReport("build fail\n"); + InfiniteLoop; + } + + + const char *anims[2] = {anim1, anim2}; + EmbeddedLayout_LoadBrlans(this->layout, anims, 2); + + const char *groups[30] = { + group1, group2, group3, group4, group5, + group6, group7, group8, group9, group10, + group11, group12, group13, group14, group15, + group1, group2, group3, group4, group5, + group6, group7, group8, group9, group10, + group11, group12, group13, group14, group15, + }; + + int mappings[30] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + EmbeddedLayout_LoadGroups(this->layout, groups, mappings, 30); + + EmbeddedLayout_DisableAllAnims(this->layout); + + for (int i = 0; i < 15; i++) { + EmbeddedLayout_ResetAnimToInitialState(this->layout, i, false); + } + #endif + + + this->selectCursor = CreateParentedObject(SELECT_CURSOR, this, 0, 0); + this->csMenu = CreateParentedObject(COURSE_SELECT_MENU, this, 0, 0); + this->yesNoWindow = CreateParentedObject(YES_NO_WINDOW, this, 0, 0); + this->numPeopleChange = CreateParentedObject(NUMBER_OF_PEOPLE_CHANGE, this, 0, 0); + + for (int i = 0; i < 4; i++) { + void *ccsb = CreateParentedObject(CHARACTER_CHANGE_SELECT_BASE, this, i, 0); + void *ccsc = CreateParentedObject(CHARACTER_CHANGE_SELECT_CONTENTS, this, i, 0); + void *ccsa = CreateParentedObject(CHARACTER_CHANGE_SELECT_ARROW, this, i, 0); + void *cci = CreateParentedObject(CHARACTER_CHANGE_INDICATOR, this, i, 0); + + NPCHG_CCSB(this->numPeopleChange, i) = ccsb; + NPCHG_CCSC(this->numPeopleChange, i) = ccsc; + NPCHG_CCSA(this->numPeopleChange, i) = ccsa; + NPCHG_CCI(this->numPeopleChange, i) = cci; + } + + this->continueObj = CreateParentedObject(CONTINUE, this, 0, 0); + + this->stockItem = CreateParentedObject(STOCK_ITEM, this, 0, 0); + this->stockItemShadow = CreateParentedObject(STOCK_ITEM_SHADOW, this, 0, 0); + STKI_SHADOW(this->stockItem) = this->stockItemShadow; + + this->easyPairing = CreateParentedObject(EASY_PAIRING, this, 0, 0); + + //this->player = (daWMPlayer_c*)CreateParentedObject(WM_PLAYER, this, 0, 2); + + CreateParentedObject(WORLD_CAMERA, this, 0, 0); + + this->state = STATE_START_DVD; + + #ifdef LEVEL_MENU + this->layout->drawOrder = 0; + #endif + + *CurrentDrawFunc = NewerMapDrawFunc; + + // level info + this->levelInfo = LoadFile(&this->levelInfoFH, "/NewerRes/LevelInfo.bin"); + LevelInfo_Prepare(&this->levelInfoFH); + + // load the menu info + SaveBlock *save = GetSaveFile()->GetBlock(-1); + + #ifdef LEVEL_MENU + this->currentPage = save->current_world; + + // bounds check + if (save->current_path_node >= 15) + save->current_path_node = 0; + + int sCount = LevelInfo_GetSectionCount(this->levelInfo); + this->selections = (int*)AllocFromGameHeap1(sizeof(int) * sCount); + + for (int i = 0; i < sCount; i++) { + this->selections[i] = 0; + } + + this->selections[this->currentPage] = save->current_path_node; + + // show button anim + EmbeddedLayout_EnableNonLoopAnim(this->layout, save->current_path_node, false); + #endif + + LoadModel(); + + wmData.load("/NewerRes/TestMap.wm"); + + + WMDataHeader *hdr = (WMDataHeader*)wmData.fh.filePtr; + if (save->current_path_node >= hdr->pointCount) { + this->currentPoint = wmData.getPath(0)->startPoint; + } else { + this->currentPoint = hdr->pointList[save->current_path_node]; + } + + #ifdef LEVEL_MENU + this->GenText(); + #endif + + + return true; +} + +int dScNewerWorldMap_c::onDelete() { + #ifdef LEVEL_MENU + EmbeddedLayout_FreeArc(this->layout); + EmbeddedLayout_Free(this->layout); + EmbeddedLayout_dtor(this->layout, false); + FreeFromGameHeap1(this->layout); + + FreeFromGameHeap1(this->selections); + #endif + + FreeFile(&this->levelInfoFH); + + FreeScene(0); + FreeScene(1); + + DVD_FreeFile(GetDVDClass2(), "SI_kinoko"); + DVD_FreeFile(GetDVDClass2(), "SI_fireflower"); + DVD_FreeFile(GetDVDClass2(), "SI_iceflower"); + DVD_FreeFile(GetDVDClass2(), "SI_penguin"); + DVD_FreeFile(GetDVDClass2(), "SI_propeller"); + DVD_FreeFile(GetDVDClass2(), "SI_star"); + + return true; +} + +int dScNewerWorldMap_c::onExecute() { + + if (QueryGlobal5758(0xFFFFFFFF)) return true; + if (CheckIfWeCantDoStuff()) return true; + + /**************************************************************************/ + // Read Wiimote Buttons + + int heldButtons = Remocon_GetButtons(GetActiveRemocon()); + int nowPressed = Remocon_GetPressed(GetActiveRemocon()); + + /**************************************************************************/ + // State Specific + + switch (this->state) { + /**********************************************************************/ + // STATE_START_DVD : Set up DVD + case STATE_START_DVD: + + DVD_Start(); + this->state = STATE_LOAD_RES; + + break; + + /**********************************************************************/ + // STATE_LOAD_RES : Load extra stuff we need + case STATE_LOAD_RES: + + DVD_LoadFile(GetDVDClass(), "WorldMap", "SI_kinoko", 0); + DVD_LoadFile(GetDVDClass(), "WorldMap", "SI_fireflower", 0); + DVD_LoadFile(GetDVDClass(), "WorldMap", "SI_iceflower", 0); + DVD_LoadFile(GetDVDClass(), "WorldMap", "SI_penguin", 0); + DVD_LoadFile(GetDVDClass(), "WorldMap", "SI_propeller", 0); + DVD_LoadFile(GetDVDClass(), "WorldMap", "SI_star", 0); + //DVD_LoadFile(GetDVDClass(), "Object", "fruits_kusa_gake", 0); + + this->state = STATE_END_DVD; + + break; + + /**********************************************************************/ + // STATE_END_DVD : Wait for files to load, end DVD + case STATE_END_DVD: + + if (!DVD_StillLoading(GetDVDClass2())) { + if (DVD_End()) { + this->state = STATE_SETUP_WAIT; + } + } + + break; + + /**********************************************************************/ + // STATE_SETUP_WAIT : Waiting for the world map managers to be set up + case STATE_SETUP_WAIT: { + + bool success = true; + + success &= CSMENU_SETUP_DONE(this->csMenu); + success &= SELC_SETUP_DONE(this->selectCursor); + success &= NPCHG_SETUP_DONE(this->numPeopleChange); + success &= YESNO_SETUP_DONE(this->yesNoWindow); + success &= CONT_SETUP_DONE(this->continueObj); + success &= STKI_SETUP_DONE(this->stockItem); + success &= SIS_SETUP_DONE(this->stockItemShadow); + success &= EASYP_SETUP_DONE(this->easyPairing); + + if (success) { + // ok, now we can set up other required shit + + // first up: player models for Stocked Items + for (int i = 0; i < 4; i++) { + void *obj = CreateChildObject(WM_2D_PLAYER, this, i, 0, 0); + STKI_2DPLAYER(this->stockItem,i) = obj; + NPCHG_2DPLAYER(this->numPeopleChange,i) = obj; + } + + // next: items for the Powerup screen + for (int i = 0; i < 7; i++) { + void *obj = CreateChildObject(WM_ITEM, this, i, 0, 0); + STKI_ITEM(this->stockItem,i) = obj; + } + + // now, check if we need to handle Continue + if (CheckIfContinueShouldBeActivated()) { + this->state = STATE_CONTINUE_WAIT; + CONT_UNK1(this->continueObj) = true; + CONT_UNK2(this->continueObj) = true; + CONT_UNK3(this->continueObj) = false; + } else { + #ifdef LEVEL_MENU + this->state = STATE_OPT_CHANGE_WAIT; + #else + this->state = STATE_NORMAL; + #endif + } + + // and now Player setup + #ifndef LEVEL_MENU + this->player = (daWMPlayer_c*)CreateParentedObject(WM_PLAYER, this, 0, 2); + this->player->modelHandler->mdlClass->setPowerup(2); + this->player->modelHandler->mdlClass->startAnimation(0, 1.2f, 10.0f, 0.0f); + this->player->pos = this->currentPoint->position; + #endif + } + + } break; + + /**********************************************************************/ + // STATE_CONTINUE_WAIT : Waiting for the Continue anim to finish + case STATE_CONTINUE_WAIT: + + if (CONT_DONE(this->continueObj)) { + CONT_UNK1(this->continueObj) = 0; + CONT_UNK2(this->continueObj) = 0; + CONT_UNK3(this->continueObj) = 0; + + for (int i = 0; i < 4; i++) { + int idx = SearchForIndexOfPlayerID(i); + Player_Lives[Player_ID[idx]] = CONT_LIVES(this->continueObj, i); + } + + this->state = STATE_OPT_CHANGE_WAIT; + } + + break; + + /**********************************************************************/ + // STATE_NORMAL : Nothing related to the menu is going on + case STATE_NORMAL: { + + #ifndef LEVEL_MENU + HandleMovement(); + #endif + +#ifdef LEVEL_MENU + int currentPage = this->currentPage; + int currentSelection = this->selections[currentPage]; + int newPage = currentPage; + int newSelection = currentSelection; + + // Activate the menu + if (nowPressed & WPAD_PLUS) { + CSMENU_ACTIVE(this->csMenu) = true; + this->state = STATE_CSMENU; + } + + + // Change the current level + if ((nowPressed & WPAD_UP) && currentSelection > 0) { + newSelection = currentSelection - 1; + } + + if ((nowPressed & WPAD_DOWN) && currentSelection < (LevelInfo_GetSection(this->levelInfo, currentPage)->levelCount - 1)) { + newSelection = currentSelection + 1; + } + + // Change the current world + if ((nowPressed & WPAD_LEFT) && currentPage > 0) { + newPage = currentPage - 1; + } + + if ((nowPressed & WPAD_RIGHT) && currentPage < (LevelInfo_GetSectionCount(this->levelInfo) - 1)) { + newPage = currentPage + 1; + } + + + if (newPage != currentPage) { + this->currentPage = newPage; + this->GenText(); + + // do this to let the rest of the code handle animations + newSelection = this->selections[newPage]; + } + + if (newSelection != currentSelection) { + EmbeddedLayout_DisableAllAnims(this->layout); + + // enable On animation + EmbeddedLayout_EnableNonLoopAnim(this->layout, newSelection, false); + + // enable Off animation + EmbeddedLayout_EnableNonLoopAnim(this->layout, currentSelection+15, false); + + this->selections[newPage] = newSelection; + this->state = STATE_OPT_CHANGE_WAIT; + } + + + // save the info to the file + if (currentSelection != newSelection || currentPage != newPage) { + SaveBlock *save = GetSaveFile()->GetBlock(-1); + save->current_world = newPage; + save->current_path_node = newSelection; + } +#endif + + + // Enter the current level +#ifndef MARIO_OPTIONS +#ifdef LEVEL_MENU + if (Wiimote_TestButtons(GetActiveWiimote(), WPAD_A | WPAD_TWO)) { + this->StartLevel(); + this->state = STATE_LIMBO; // just in case + } +#endif + + if (nowPressed & WPAD_ONE) { + STKI_SHOW(this->stockItem) = true; + this->state = STATE_POWERUPS_WAIT; + } +#endif + } break; + + /**********************************************************************/ + // STATE_OPT_CHANGE_WAIT : Waiting for the option change animation to + // finish playing + #ifdef LEVEL_MENU + case STATE_OPT_CHANGE_WAIT: + + if (!EmbeddedLayout_CheckIfAnimationIsOn(this->layout, -1)) { + this->state = STATE_NORMAL; + } + + break; + #endif + /**********************************************************************/ + // STATE_CSMENU : The course select menu is currently being shown + case STATE_CSMENU: + + // First off, check to see if it's been hidden + if (!CSMENU_ACTIVE(this->csMenu)) { + // That means something happened + if (CSMENU_CHOICE_OK(this->csMenu)) { + // Player pressed a button + + switch (CSMENU_CURRENT(this->csMenu)) { + case 0: + // Star Coins + //OSReport("Star Coins was pressed\n"); + this->state = STATE_NORMAL; + break; + + case 1: + // Add/Drop Players + //OSReport("Add/Drop Players was pressed\n"); + this->state = STATE_PLAYER_CHANGE_WAIT; + NPCHG_ACTIVE(this->numPeopleChange) = true; + WpadShit(10); + + break; + + case 2: + // Save or Quick Save + //OSReport("Save or Quick Save was pressed\n"); + if (GetSaveFile()->GetBlock(-1)->bitfield & 2) { + this->state = STATE_SAVE_OPEN; + YESNO_TYPE(this->yesNoWindow) = 1; + YESNO_VISIBLE(this->yesNoWindow) = 1; + + } else { + this->state = STATE_QUICKSAVE_OPEN; + YESNO_TYPE(this->yesNoWindow) = 15; + YESNO_VISIBLE(this->yesNoWindow) = 1; + + } + + break; + + case 3: + // Title Screen + //OSReport("Title Screen was pressed\n"); + this->state = STATE_TITLE_CONFIRM_OPEN_WAIT; + YESNO_VISIBLE(this->yesNoWindow) = true; + YESNO_TYPE(this->yesNoWindow) = 10; + break; + } + + } else { + // Ok, change back to STATE_NORMAL + this->state = STATE_NORMAL; + } + } + + break; + + /**********************************************************************/ + // STATE_TITLE_CONFIRM_OPEN_WAIT : Waiting for the "Go to Title Screen" + // YesNoWindow to finish opening + case STATE_TITLE_CONFIRM_OPEN_WAIT: + + if (!YESNO_OPENING(this->yesNoWindow)) { + this->state = STATE_TITLE_CONFIRM_SELECT; + } + + break; + + /**********************************************************************/ + // STATE_TITLE_CONFIRM_SELECT : Let the user choose an option on the + // "Go to Title Screen" YesNoWindow. + case STATE_TITLE_CONFIRM_SELECT: + + if (nowPressed & WPAD_LEFT) { + // Select "OK!" + YESNO_CURRENT(this->yesNoWindow) = 1; + + } else if (nowPressed & WPAD_RIGHT) { + // Select "Cancel" + YESNO_CURRENT(this->yesNoWindow) = 0; + + } else if (Wiimote_TestButtons(GetActiveWiimote(), WPAD_A | WPAD_TWO)) { + // Pick the current option + YESNO_CLOSE(this->yesNoWindow) = true; + if (YESNO_CURRENT(this->yesNoWindow) != 1) + YESNO_REFUSED(this->yesNoWindow) = true; + this->state = STATE_TITLE_CONFIRM_HIT_WAIT; + + } else { + // Cancel using B or 1 + if (CheckIfMenuShouldBeCancelledForSpecifiedWiimote(0)) { + YESNO_CANCELLED(this->yesNoWindow) = true; + YESNO_CURRENT(this->yesNoWindow) = true; + this->state = STATE_TITLE_CONFIRM_HIT_WAIT; + } + } + + break; + + /**********************************************************************/ + // STATE_TITLE_CONFIRM_HIT_WAIT : Process the user's chosen option on + // the "Go to Title Screen" YesNoWindow. Also, wait for the + // animation to be complete. + case STATE_TITLE_CONFIRM_HIT_WAIT: + + if (!YESNO_OPENING(this->yesNoWindow)) { + if (YESNO_CURRENT(this->yesNoWindow) == 1) { + this->state = STATE_NORMAL; + } else { + this->state = STATE_LIMBO; + StartTitleScreenStage(false, 0); + } + } + + break; + + /**********************************************************************/ + // STATE_PLAYER_CHANGE_WAIT : Wait for the user to do something on the + // Add/Drop Players screen. + case STATE_PLAYER_CHANGE_WAIT: + + if (NPCHG_READY(this->numPeopleChange)) { + if (nowPressed & WPAD_PLUS) { + // activate easy pairing. FUN !! + NPCHG_HIDE_FOR_EASYP(this->numPeopleChange) = 1; + + for (int i = 0; i < 4; i++) { + void *obj = NPCHG_2DPLAYER(this->numPeopleChange, i); + void *ccsb = NPCHG_CCSB(this->numPeopleChange, i); + void *ccsc = NPCHG_CCSC(this->numPeopleChange, i); + + PLAYER2D_SHOW_EASY_PAIRING(obj) = 1; + CCSB_ACTIVE(ccsb) = 1; + CCSC_ACTIVE(ccsc) = 1; + } + + EASYP_ACTIVE(this->easyPairing) = 1; + this->state = STATE_EASY_PAIRING_WAIT; + } + } else { + if (!NPCHG_ACTIVE(this->numPeopleChange)) { + this->state = STATE_NORMAL; + } + } + + break; + + /**********************************************************************/ + // STATE_EASY_PAIRING_WAIT : Wait for the user to exit Easy Pairing. + case STATE_EASY_PAIRING_WAIT: + + if (!EASYP_ACTIVE(this->easyPairing)) { + NPCHG_HIDE_FOR_EASYP(this->numPeopleChange) = 0; + + for (int i = 0; i < 4; i++) { + void *obj = NPCHG_2DPLAYER(this->numPeopleChange, i); + void *ccsb = NPCHG_CCSB(this->numPeopleChange, i); + void *ccsc = NPCHG_CCSC(this->numPeopleChange, i); + + PLAYER2D_SHOW_EASY_PAIRING(obj) = 0; + CCSB_ACTIVE(ccsb) = 0; + CCSC_ACTIVE(ccsc) = 0; + } + + this->state = STATE_PLAYER_CHANGE_WAIT; + WpadShit(10); + } + + break; + + /**********************************************************************/ + // STATE_POWERUPS_WAIT : Wait for the user to exit the Powerups screen. + case STATE_POWERUPS_WAIT: + + if (!STKI_SHOW(this->stockItem)) { + this->state = STATE_NORMAL; + } + + break; + + /**********************************************************************/ + // STATE_SAVE_OPEN : Waiting for the "Save?" YesNoWindow to open + case STATE_SAVE_OPEN: + + if (!YESNO_OPENING(this->yesNoWindow)) { + this->state = STATE_SAVE_SELECT; + } + + break; + + /**********************************************************************/ + // STATE_SAVE_SELECT : Let the user choose an option on the + // "Save?" YesNoWindow. + case STATE_SAVE_SELECT: + + if (nowPressed & WPAD_LEFT) { + // Select "OK!" + YESNO_CURRENT(this->yesNoWindow) = 1; + + } else if (nowPressed & WPAD_RIGHT) { + // Select "Cancel" + YESNO_CURRENT(this->yesNoWindow) = 0; + + } else if (Wiimote_TestButtons(GetActiveWiimote(), WPAD_A | WPAD_TWO)) { + // Pick the current option + YESNO_CLOSE(this->yesNoWindow) = true; + + if (YESNO_CURRENT(this->yesNoWindow) != 1) + YESNO_CANCELLED2(this->yesNoWindow) = true; + this->state = STATE_SAVE_WINDOW_CLOSE; + + } else { + // Cancel using B or 1 + if (CheckIfMenuShouldBeCancelledForSpecifiedWiimote(0)) { + YESNO_CANCELLED(this->yesNoWindow) = true; + YESNO_CURRENT(this->yesNoWindow) = 1; + this->state = STATE_SAVE_WINDOW_CLOSE; + } + } + + break; + + /**********************************************************************/ + // STATE_SAVE_WINDOW_CLOSE : Process the user's chosen option on the + // "Save?" YesNoWindow. Also, wait for the animation to be complete. + case STATE_SAVE_WINDOW_CLOSE: + + if (!YESNO_VISIBLE(this->yesNoWindow)) { + if (YESNO_CURRENT(this->yesNoWindow) == 1) { + this->state = STATE_NORMAL; + } else { + this->state = STATE_SAVE_DO; + SaveGame(0, false); + } + } + + break; + + /**********************************************************************/ + // STATE_SAVE_DO : Save the game. + case STATE_SAVE_DO: + + if (!GetSaveFile()->CheckIfWriting()) { + if (GetSaveHandler()->CurrentError == 0) { + YESNO_TYPE(this->yesNoWindow) = 2; + YESNO_VISIBLE(this->yesNoWindow) = true; + this->state = STATE_SAVE_END_WINDOW; + } else { + this->state = STATE_SAVE_ERROR; + } + } + + break; + + /**********************************************************************/ + // STATE_SAVE_END_WINDOW : Handle the Save End window. + case STATE_SAVE_END_WINDOW: + + if (!YESNO_OPENING(this->yesNoWindow)) { + if (Wiimote_TestButtons(GetActiveWiimote(), WPAD_A | WPAD_TWO)) { + YESNO_CLOSE(this->yesNoWindow) = true; + this->state = STATE_SAVE_END_CLOSE_WAIT; + } + } + + break; + + /**********************************************************************/ + // STATE_SAVE_END_CLOSE_WAIT : Wait for the Save End window to close. + case STATE_SAVE_END_CLOSE_WAIT: + + if (!YESNO_OPENING(this->yesNoWindow)) { + this->state = STATE_NORMAL; + } + + break; + + /**********************************************************************/ + // STATE_QUICKSAVE_OPEN : Waiting for the "Save?" YesNoWindow to open + case STATE_QUICKSAVE_OPEN: + + if (!YESNO_OPENING(this->yesNoWindow)) { + this->state = STATE_QUICKSAVE_SELECT; + } + + break; + + /**********************************************************************/ + // STATE_QUICKSAVE_SELECT : Let the user choose an option on the + // "Save?" YesNoWindow. + case STATE_QUICKSAVE_SELECT: + + if (nowPressed & WPAD_LEFT) { + // Select "OK!" + YESNO_CURRENT(this->yesNoWindow) = 1; + + } else if (nowPressed & WPAD_RIGHT) { + // Select "Cancel" + YESNO_CURRENT(this->yesNoWindow) = 0; + + } else if (Wiimote_TestButtons(GetActiveWiimote(), WPAD_A | WPAD_TWO)) { + // Pick the current option + YESNO_CLOSE(this->yesNoWindow) = true; + + if (YESNO_CURRENT(this->yesNoWindow) != 1) + YESNO_CANCELLED2(this->yesNoWindow) = true; + this->state = STATE_QUICKSAVE_WINDOW_CLOSE; + + } else { + // Cancel using B or 1 + if (CheckIfMenuShouldBeCancelledForSpecifiedWiimote(0)) { + YESNO_CANCELLED(this->yesNoWindow) = true; + YESNO_CURRENT(this->yesNoWindow) = 1; + this->state = STATE_QUICKSAVE_WINDOW_CLOSE; + } + } + + break; + + /**********************************************************************/ + // STATE_QUICKSAVE_WINDOW_CLOSE : Process the user's chosen option on + // the "Save?" YesNoWindow. Also, wait for the animation to be complete + case STATE_QUICKSAVE_WINDOW_CLOSE: + + if (!YESNO_VISIBLE(this->yesNoWindow)) { + if (YESNO_CURRENT(this->yesNoWindow) == 1) { + this->state = STATE_NORMAL; + } else { + this->state = STATE_QUICKSAVE_DO; + SaveGame(0, true); + } + } + + break; + + /**********************************************************************/ + // STATE_QUICKSAVE_DO : Save the game. + case STATE_QUICKSAVE_DO: + + if (!GetSaveFile()->CheckIfWriting()) { + if (GetSaveHandler()->CurrentError == 0) { + YESNO_TYPE(this->yesNoWindow) = 16; + YESNO_VISIBLE(this->yesNoWindow) = true; + this->state = STATE_QUICKSAVE_END_WINDOW; + } else { + this->state = STATE_SAVE_ERROR; + } + } + + break; + + /**********************************************************************/ + // STATE_QUICKSAVE_END_WINDOW : Handle the Save End window. + case STATE_QUICKSAVE_END_WINDOW: + + if (!YESNO_OPENING(this->yesNoWindow)) { + if (Wiimote_TestButtons(GetActiveWiimote(), WPAD_A | WPAD_TWO)) { + YESNO_CLOSE(this->yesNoWindow) = true; + YESNO_REFUSED(this->yesNoWindow) = true; + this->state = STATE_QUICKSAVE_END_CLOSE_WAIT; + } + } + + break; + + /**********************************************************************/ + // STATE_QUICKSAVE_END_CLOSE_WAIT : Wait for Save End window to close + case STATE_QUICKSAVE_END_CLOSE_WAIT: + + if (!YESNO_OPENING(this->yesNoWindow)) { + if (YESNO_CURRENT(this->yesNoWindow) == 1) { + this->state = STATE_NORMAL; + } else { + this->state = STATE_LIMBO; + StartTitleScreenStage(false, 0); + } + } + + break; + + } + + #ifdef LEVEL_MENU + if (this->state >= STATE_NORMAL) { + EmbeddedLayout_Process(this->layout); + EmbeddedLayout_UpdateMatrix(this->layout); + } + #endif + + return true; +} + +int dScNewerWorldMap_c::onDraw() { +#ifdef LEVEL_MENU + EmbeddedLayout_AddToDrawList(this->layout); +#endif + +#ifndef LEVEL_MENU + this->model.scheduleForDrawing(); + + //Mtx matrix; + //MTXIdentity(matrix); + + //this->testModel.addToDrawList(matrix); +#endif + + return true; +} + + + +#ifndef LEVEL_MENU +// Todo: move to .LZ files and dDvd::loader_c + +void dScNewerWorldMap_c::LoadModel() { + OSReport("Loading Goldwood model...\n"); + modelFile.openCompressed("/NewerRes/Maps/SMGoldwood.brres"); + + //LoadFile(&this->modelFH, "/Object/GoldwoodBase.arc"); + //LoadFile(&this->modelFH, "/WorldMap/CS_W1.arc"); + + /*ARCHandle arc; + ARCFileInfo keyinfo; + ARCInitHandle(this->modelFH.filePtr, &arc); + ARCOpen(&arc, "g3d/GoldwoodBase.brres", &keyinfo); + //ARCOpen(&arc, "g3d/model.brres", &keyinfo); + + nw4r::g3d::ResFile resfile(ARCGetStartAddrInMem(&keyinfo));*/ + + nw4r::g3d::ResFile resfile(modelFile.ptr()); + + if (!resfile.CheckRevision()) + OSReport("Warning: Revision check failed!\n"); + + resfile.Init(); + + if (!resfile.Bind(resfile)) + OSReport("Warning: ResFile bind failed!\n"); + + void *mdl = resfile.GetResMdl("GoldwoodBase"); + //void *mdl = resfile.GetResMdl("CS_W1"); + OSReport("Obtained ResMdl: %p\n", mdl); + + OSReport(this->allocator.link(-1, GameHeaps[0], 0, 0x20) ? "Success\n" : "Fail\n"); + OSReport(this->model.setup(&mdl, &this->allocator, 0, 1, 0) ? "Success\n" : "Fail\n"); + + SetupTextures_Map(&model, 1); + + //this->nw4rMdl.sub_80064BF0(); + //this->nw4rMdl.oneSetupType(); + + this->allocator.unlink(); + OSReport("Done loading model!\n"); + + Mtx asdf; + //MTXScale(asdf, 0.1, 0.1, 0.1); + MTXIdentity(asdf); + this->model.setDrawMatrix(asdf); + + //ARCClose(&keyinfo); +} + + +void dScNewerWorldMap_c::HandleMovement() { + int heldButtons = Remocon_GetButtons(GetActiveRemocon()); + int nowPressed = Remocon_GetPressed(GetActiveRemocon()); + + if (isMoving) { + MoveThroughPath(); + } else { + if (nowPressed & WPAD_LEFT && currentPoint->exits.asDirection.left.isValid()) + StartMovementTo(LEFT); + else if (nowPressed & WPAD_RIGHT && currentPoint->exits.asDirection.right.isValid()) + StartMovementTo(RIGHT); + else if (nowPressed & WPAD_UP && currentPoint->exits.asDirection.up.isValid()) + StartMovementTo(UP); + else if (nowPressed & WPAD_DOWN && currentPoint->exits.asDirection.down.isValid()) + StartMovementTo(DOWN); + + if (nowPressed & WPAD_TWO) + ActivatePoint(); + } +} + +void dScNewerWorldMap_c::MoveThroughPath() { + // figure out how much to move on each step + Vec from, to; + if (this->reverseThroughPath) { + from = this->currentSegment->end; + to = this->currentSegment->start; + } else { + from = this->currentSegment->start; + to = this->currentSegment->end; + } + + //float xMove = this->currentSegment->stepsPerFrame * cos(this->movementAngle); + //float zMove = this->currentSegment->stepsPerFrame * sin(this->movementAngle); + Vec move; + move.x = to.x - from.x; + move.y = to.y - from.y; + move.z = to.z - from.z; + + VECNormalize(&move, &move); + VECScale(&move, &move, this->currentSegment->stepsPerFrame); + + this->player->pos.x += move.x; + this->player->pos.y += move.y; + this->player->pos.z += move.z; + + // have we reached the end? + bool xAtEnd = false; + bool yAtEnd = false; + bool zAtEnd = false; + + if (move.x > 0) { + xAtEnd = (this->player->pos.x >= to.x); + } else { + xAtEnd = (this->player->pos.x <= to.x); + } + + if (move.y > 0) { + yAtEnd = (this->player->pos.y >= to.y); + } else { + yAtEnd = (this->player->pos.y <= to.y); + } + + if (move.z > 0) { + zAtEnd = (this->player->pos.z >= to.z); + } else { + zAtEnd = (this->player->pos.z <= to.z); + } + + if (xAtEnd && yAtEnd && zAtEnd) { + MapReport("reached end of segment %d\n", this->currentSegmentID); + + int nextSegment = this->currentSegmentID + (this->reverseThroughPath ? -1 : 1); + if (nextSegment == -1 || nextSegment == this->currentPath->segCount) { + MapReport("reached end of path\n"); + this->currentPoint = this->nextPoint; + this->player->pos = this->currentPoint->position; + this->player->startAnimation(0, 1.2, 10.0, 0.0); + this->isMoving = false; + + SaveBlock *save = GetSaveFile()->GetBlock(-1); + //save->current_world = newPage; ? + save->current_path_node = wmData.getPointID(this->currentPoint); + } else { + this->MoveToSegment(nextSegment); + } + } +} + +void dScNewerWorldMap_c::StartMovementTo(WMDirection direction) { + this->isMoving = true; + + WMPathEntrance *thisExit = ¤tPoint->exits.asArray[direction]; + MapReport("Using an exit in direction %d\n", direction); + + this->currentPath = thisExit->path; + if (thisExit->isEndSide) { + this->nextPoint = thisExit->path->startPoint; + this->reverseThroughPath = true; + this->MoveToSegment(thisExit->path->segCount - 1); + } else { + this->nextPoint = thisExit->path->endPoint; + this->reverseThroughPath = false; + this->MoveToSegment(0); + } +} + +void dScNewerWorldMap_c::MoveToSegment(int id) { + MapReport("Moving to segment %d\n", id); + + this->currentSegmentID = id; + this->currentSegment = this->currentPath->segments[id]; + + // calculate rotation + Vec from, to; + if (this->reverseThroughPath) { + from = this->currentSegment->end; + to = this->currentSegment->start; + } else { + from = this->currentSegment->start; + to = this->currentSegment->end; + } + + MapReport("From: %f,%f,%f To: %f,%f,%f\n", from.x, from.y, from.z, to.x, to.y, to.z); + + /*float xDiff = to.x - from.x; + float zDiff = to.z - from.z; + this->movementAngle = atan2(zDiff, xDiff); + float rotValue = ((int)(90.0f - MTXRadToDeg(this->movementAngle)) % 360); + + MapReport("Calculated rotation value: %f\n", rotValue);*/ + + this->player->pos = from; + + // update rotation + if (!this->currentSegment->useLastDir) { + this->player->rot.x = 0; + this->player->rot.y = this->currentSegment->direction; + this->player->rot.z = 0; + + if (this->reverseThroughPath && !this->currentSegment->alwaysSameDir) { + this->player->rot.y = ((this->currentSegment->direction) + 0x8000) & 0xFFFF; + } + } + + this->player->startAnimation(this->currentSegment->animationType, this->currentSegment->animationSpeed, 10.0, 0.0); +} + +void dScNewerWorldMap_c::ActivatePoint() { + MapReport("Point activated!\n"); + this->player->startAnimation(170, 1.2, 10.0, 0.0); + + if (this->currentPoint->type == WMPathPoint::LEVEL_TYPE) { + int w = this->currentPoint->params[0] - 1; + int l = this->currentPoint->params[1] - 1; + LevelInfo_Entry *level = LevelInfo_Search(this->levelInfo, w, l); + StartLevel(level); + } +} +#endif + + +void NewerMapDrawFunc() { + int keepCamera = GetCurrentCameraID(); + + /*// Based off WorldMapDrawFunc. + + LinkScene(1); + SceneCalcWorld(1); + SceneCameraStuff(1); + ChangeAlphaUpdate(false); + DrawOpa(); + DrawXlu(); + UnlinkScene(0); + + SetupLYTDrawing(); + DrawAllLayoutsBeforeX(129); + RenderEffects(0, 3); + RenderEffects(0, 2); + GXDrawDone(); + + RemoveAllFromScnRoot(); + Reset3DState(); + SetCurrentCameraID(1); + DoSpecialDrawing1(); + LinkScene(1); + SceneCalcWorld(1); + SceneCameraStuff(1); + CalcMaterial(); + DrawOpa(); + DrawXlu(); + UnlinkScene(1); + GXDrawDone(); + + RemoveAllFromScnRoot(); + Reset3DState(); + GXSetZMode(0, GX_ALWAYS, 0); + DrawAllLayoutsAfterXandBeforeY(128, 146); + SetCurrentCameraID(1); + DoSpecialDrawing2(); + LinkScene(1); + SceneCalcWorld(1); + SceneCameraStuff(1); + CalcMaterial(); + DrawOpa(); + DrawXlu(); + UnlinkScene(1); + + if (GAMEMGR_GET_AFC(GameMgr)) { + for (int i = 0; i < 4; i++) { + RenderEffects(0, 11+i); + } + + for (int i = 0; i < 4; i++) { + RenderEffects(0, 7+i); + } + } + + GXDrawDone(); + RemoveAllFromScnRoot(); + Reset3DState(); + DrawAllLayoutsAfterX(145); + ClearLayoutDrawList(); + SetCurrentCameraID(0);*/ + + + // All drawing uses scene 1, since that's the only one loaded by GAME_SETUP. + // Todo: Newer-specific scenes? + + // Stage 1 + SetupLYTDrawing(); + DrawAllLayoutsBeforeX(129); + GXDrawDone(); // is all GXDrawDone really needed..? + + // Stage 2 + Reset3DState(); + SetCurrentCameraID(0); + LinkScene(0); + SceneCalcWorld(0); + SceneCameraStuff(0); + ChangeAlphaUpdate(false); + CalcMaterial(); + DrawOpa(); + DrawXlu(); + UnlinkScene(0); + GXDrawDone(); + + //Reset3DState(); + //T3D::DrawQueue(); + + // Stage 3 + Reset3DState(); + SetupLYTDrawing(); + DrawAllLayoutsAfterXandBeforeY(128, 146); + GXDrawDone(); + + // Stage 4 + RemoveAllFromScnRoot(); + Reset3DState(); + SetCurrentCameraID(1); + DoSpecialDrawing1(); + LinkScene(1); + SceneCalcWorld(1); + SceneCameraStuff(1); + CalcMaterial(); + DrawOpa(); + DrawXlu(); + + // Stage 5 + if (GAMEMGR_GET_AFC(GameMgr)) { + for (int i = 0; i < 4; i++) { + RenderEffects(0, 11+i); + } + + for (int i = 0; i < 4; i++) { + RenderEffects(0, 7+i); + } + } + + RenderEffects(0, 2); // need to investigate how this thing works + + DrawAllLayoutsAfterX(145); + ClearLayoutDrawList(); // this is REALLY IMPORTANT! + + UnlinkScene(1); + + // End + SetCurrentCameraID(0); +} + diff --git a/src/worldmapdata.cpp b/src/worldmapdata.cpp new file mode 100644 index 0000000..0473bbb --- /dev/null +++ b/src/worldmapdata.cpp @@ -0,0 +1,93 @@ +#include "worldmapdata.h" + +WorldMapData::WorldMapData() { + +} + +WorldMapData::~WorldMapData() { + FreeFile(&this->fh); +} + +bool WorldMapData::load(const char *filename) { + OSReport("Loading WM Data file: %s\n", filename); + + u32 ptr = (u32)LoadFile(&this->fh, filename); + WMDataHeader *header = (WMDataHeader*)ptr; + + OSReport("Loaded WM Data file @ %p\n", ptr); + + // first off, fix the list pointers + header->pathList = (WMPathDef**)((u32)header->pathList + ptr); + header->pointList = (WMPathPoint**)((u32)header->pointList + ptr); + header->segmentList = (WMPathSegment**)((u32)header->segmentList + ptr); + header->actionList = (WMPathAction**)((u32)header->actionList + ptr); + + // now, fix every pointer in the lists + OSReport("Fixing up list pointers\n"); + for (int i = 0; i < header->pathCount; i++) + header->pathList[i] = (WMPathDef*)((u32)header->pathList[i] + ptr); + + for (int i = 0; i < header->pointCount; i++) + header->pointList[i] = (WMPathPoint*)((u32)header->pointList[i] + ptr); + + for (int i = 0; i < header->segmentCount; i++) + header->segmentList[i] = (WMPathSegment*)((u32)header->segmentList[i] + ptr); + + for (int i = 0; i < header->actionCount; i++) + header->actionList[i] = (WMPathAction*)((u32)header->actionList[i] + ptr); + + // next up, fix every pointer in these structs + OSReport("Fixing up path pointers [%d]\n", header->pathCount); + for (int i = 0; i < header->pathCount; i++) { + WMPathDef *thisPath = header->pathList[i]; + //OSReport("Path @ %p - Index: %d - Segments: %d\n", thisPath, i, thisPath->segCount); + + thisPath->startPoint = header->pointList[(u32)thisPath->startPoint]; + thisPath->endPoint = header->pointList[(u32)thisPath->endPoint]; + + for (int j = 0; j < thisPath->segCount; j++) { + thisPath->segments[j] = header->segmentList[(u32)thisPath->segments[j]]; + } + } + + OSReport("Fixing up point pointers [%d]\n", header->pointCount); + for (int i = 0; i < header->pointCount; i++) { + WMPathPoint *thisPoint = header->pointList[i]; + + for (int j = 0; j < 4; j++) { + if ((u32)thisPoint->exits.asArray[j].path == -1) { + thisPoint->exits.asArray[j].path = 0; + } else { + thisPoint->exits.asArray[j].path = header->pathList[(u32)thisPoint->exits.asArray[j].path]; + } + } + } + + OSReport("Fixing up segment pointers [%d]\n", header->segmentCount); + for (int i = 0; i < header->segmentCount; i++) { + WMPathSegment *thisSegment = header->segmentList[i]; + + if ((u32)thisSegment->action == -1) { + thisSegment->action = 0; + } else { + thisSegment->action = header->actionList[(u32)thisSegment->action]; + } + } + + OSReport("Load complete\n"); + + return true; +} + + + +int WorldMapData::getPointID(WMPathPoint *point) { + WMDataHeader *header = (WMDataHeader*)this->fh.filePtr; + + for (int i = 0; i < header->pointCount; i++) { + if (header->pointList[i] == point) + return i; + } + + return -1; +} diff --git a/src/worldmapdata.h b/src/worldmapdata.h new file mode 100644 index 0000000..1d6a305 --- /dev/null +++ b/src/worldmapdata.h @@ -0,0 +1,149 @@ +#ifndef __NEWER_WORLDMAPDATA_H +#define __NEWER_WORLDMAPDATA_H + +#include "fileload.h" +#include + +// Forward declarations +struct WMPathPoint; +struct WMPathAction; +struct WMPathSegment; +struct WMPathDef; + +// here's a note: while most of these structs contain pointers to other structs, +// in the data file these fields actually contain an index into the lists +// (defined in WMDataHeader) +// WorldMapData::load() fixes these offsets. + +/******************************************************************************/ +// Definition for an entrance onto one side of a path +// (TODO: Maybe rename this struct?) + +// Note: a null WMPathEntrance has no path defined +// since the path pointer is stored as an index in the data file, the index for +// a null path becomes -1 + +struct WMPathEntrance { + WMPathDef *path; + bool isEndSide; + + bool isValid() { return (this->path != 0); } +}; + + +/******************************************************************************/ +// Definition for one point on the map + +struct WMPathPoint { + enum PointType { + NONE_TYPE, + LEVEL_TYPE + }; + + // Paths you arrive on when you press a direction when at this point + union { + struct { + WMPathEntrance left; + WMPathEntrance right; + WMPathEntrance up; + WMPathEntrance down; + } asDirection; + WMPathEntrance asArray[4]; + } exits; + + // Point metadata + PointType type; + int params[4]; + + Vec position; +}; + + +/******************************************************************************/ +// Definition for an action that can be triggered when the player reaches a +// specific point + +struct WMPathAction { + enum ActionType { + TELEPORT_TYPE // teleports to another submap + }; + + // Action metadata + ActionType type; + int params[4]; +}; + + +/******************************************************************************/ +// Definition for one part of a path + +struct WMPathSegment { + // Segment metadata + Vec start; + Vec end; + float stepsPerFrame; + int animationType; + float animationSpeed; + short direction; + bool useLastDir; + bool alwaysSameDir; + + // Optional Action that's triggered when the player touches this segment + WMPathAction *action; +}; + + +/******************************************************************************/ +// Definition for one path + +struct WMPathDef { + // Path metadata + WMPathPoint *startPoint; + WMPathPoint *endPoint; + + int segCount; + WMPathSegment *segments[1]; // variable-length array +}; + + + + +struct WMDataHeader { + u32 magic; + + WMPathDef **pathList; + int pathCount; + + WMPathPoint **pointList; + int pointCount; + + WMPathSegment **segmentList; + int segmentCount; + + // todo: remove action list? + WMPathAction **actionList; + int actionCount; +}; + + +class WorldMapData { +public: + WorldMapData(); + ~WorldMapData(); + + bool load(const char *filename); + + FileHandle fh; + + int getPathCount() { + return ((WMDataHeader*)fh.filePtr)->pathCount; + } + + WMPathDef *getPath(int idx) { + return ((WMDataHeader*)fh.filePtr)->pathList[idx]; + } + + int getPointID(WMPathPoint *point); +}; + +#endif // __NEWER_WORLDMAPDATA_H -- cgit v1.2.3