summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2011-03-12 23:17:12 +0100
committerTreeki <treeki@gmail.com>2011-03-12 23:17:12 +0100
commit7d4e4c0b34a613dd3c0220475ae4e448197522c1 (patch)
tree4f5cee367de3fdef4f9a7c84af59ffe76a2bb1c3 /src
downloadkamek-7d4e4c0b34a613dd3c0220475ae4e448197522c1.tar.gz
kamek-7d4e4c0b34a613dd3c0220475ae4e448197522c1.zip
initial commit. now I can start playing with stuff!
Diffstat (limited to 'src')
-rw-r--r--src/animtiles.cpp61
-rw-r--r--src/anotherhax.S23
-rw-r--r--src/asmlib.S182
-rw-r--r--src/fileload.cpp134
-rw-r--r--src/fileload.h74
-rw-r--r--src/g3dwrap.cpp90
-rw-r--r--src/gakenoko.S220
-rw-r--r--src/heapbar.S118
-rw-r--r--src/heapbar.cpp147
-rw-r--r--src/layoutlib.S131
-rw-r--r--src/layoutlib.h149
-rw-r--r--src/levelinfo.cpp36
-rw-r--r--src/levelinfo.h56
-rw-r--r--src/levelnames.cpp83
-rw-r--r--src/linegod.S53
-rw-r--r--src/linegod.cpp213
-rw-r--r--src/msgbox.S37
-rw-r--r--src/msgbox.cpp227
-rw-r--r--src/poweruphax.S689
-rw-r--r--src/randomcrap.S8
-rw-r--r--src/randtiles.cpp22
-rw-r--r--src/randtiles.h63
-rw-r--r--src/replay.S799
-rw-r--r--src/scene.S149
-rw-r--r--src/spritetex.S75
-rw-r--r--src/tilegod.S65
-rw-r--r--src/wm_player.cpp192
-rw-r--r--src/wmresourcemng.cpp78
-rw-r--r--src/world_camera.cpp94
-rw-r--r--src/worldmap.cpp245
-rw-r--r--src/worldmap.h211
-rw-r--r--src/worldmap_new.cpp1358
-rw-r--r--src/worldmapdata.cpp93
-rw-r--r--src/worldmapdata.h149
34 files changed, 6324 insertions, 0 deletions
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 <common.h>
+#include <game.h>
+#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 <common.h>
+
+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 <common.h>
+#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 <common.h>
+
+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 <common.h>
+#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 <common.h>
+#include <actors.h>
+#include <stage.h>
+#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 <common.h>
+#include <game.h>
+
+// 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 <common.h>
+#include <game.h>
+#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 <common.h>
+#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 <common.h>
+#include <game.h>
+
+#ifdef LEVEL_MENU
+#include "layoutlib.h"
+#endif
+
+#include "fileload.h"
+#include "levelinfo.h"
+#include "3dlib/treeki3d.h"
+#include "worldmapdata.h"
+#include <g3dhax.h>
+
+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 = &currentPoint->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 <rvl/mtx.h>
+
+// 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