From 0aae0eed9a74a463852f6548e282c10b6c632cf2 Mon Sep 17 00:00:00 2001
From: Treeki <treeki@gmail.com>
Date: Mon, 28 Mar 2011 00:04:21 +0200
Subject: Pa1/2/3 tilesets can now be swapped into any slot, except for
 animations

---
 NewerProject.yaml    |  1 +
 include/game.h       |  1 +
 kamek_ntsc.x         |  6 ++++
 kamek_ntsc2.x        |  6 ++++
 kamek_pal.x          |  6 ++++
 kamek_pal2.x         |  6 ++++
 src/tilesetfixer.cpp | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 tilesetfixer.yaml    |  9 +++++
 8 files changed, 129 insertions(+)
 create mode 100644 src/tilesetfixer.cpp
 create mode 100644 tilesetfixer.yaml

diff --git a/NewerProject.yaml b/NewerProject.yaml
index ffe9cf8..20a7d9a 100644
--- a/NewerProject.yaml
+++ b/NewerProject.yaml
@@ -12,6 +12,7 @@ modules:
 #  - processed/heapbar.yaml
   - processed/tilegod.yaml
   - processed/linegod.yaml
+  - processed/tilesetfixer.yaml
 #  - processed/msgbox.yaml
 #  - processed/replay.yaml
 
diff --git a/include/game.h b/include/game.h
index ac5318d..b26842b 100755
--- a/include/game.h
+++ b/include/game.h
@@ -35,6 +35,7 @@ inline void *GetDVDClass2() {
 }
 
 void *DVD_GetFile(void *dvdclass2, const char *arc, const char *file);
+void *DVD_GetFile(void *dvdclass2, const char *arc, const char *file, u32 *length);
 
 
 extern int Player_Active[4];
diff --git a/kamek_ntsc.x b/kamek_ntsc.x
index 865402e..e93be35 100644
--- a/kamek_ntsc.x
+++ b/kamek_ntsc.x
@@ -233,6 +233,9 @@ SECTIONS {
 
 	GameHeaps = 0x80377C48;
 
+	BGDatClass = 0x80429DF0;
+	GetTilesetName__FPvii = 0x800813F0;
+
 	IsWideScreen__Fv = 0x800B54B0;
 
 	Player_Active = 0x80354E50;
@@ -249,6 +252,8 @@ SECTIONS {
 	GetObjectParent = 0x80162590;
 	OSReport = 0x8015F730;
 
+	StagePtr = 0x8042A1C8;
+
 	_Z20CreateParentedObjectsPvic = 0x80162B00;
 	_Z47CheckIfMenuShouldBeCancelledForSpecifiedWiimotei = 0x800B53A0;
 	_Z21StartTitleScreenStagebi = 0x801017D0;
@@ -288,6 +293,7 @@ SECTIONS {
 	DVD_StillLoading__FPv = 0x800DF4E0;
 	DVD_End__Fv = 0x8006A760;
 	DVD_GetFile__FPvPCcPCc = 0x800DF180;
+	DVD_GetFile__FPvPCcPCcPUi = 0x800DF1E0;
 
 	__ct__12dDvdLoader_cFv = 0x8008F140;
 	__dt__12dDvdLoader_cFv = 0x8008F170;
diff --git a/kamek_ntsc2.x b/kamek_ntsc2.x
index b0956d0..2d48f72 100644
--- a/kamek_ntsc2.x
+++ b/kamek_ntsc2.x
@@ -233,6 +233,9 @@ SECTIONS {
 
 	GameHeaps = 0x80377C48;
 
+	BGDatClass = 0x80429DF0;
+	GetTilesetName__FPvii = 0x800813F0;
+
 	IsWideScreen__Fv = 0x800B54B0;
 
 	Player_Active = 0x80354E50;
@@ -249,6 +252,8 @@ SECTIONS {
 	GetObjectParent = 0x80162590;
 	OSReport = 0x8015F730;
 
+	StagePtr = 0x8042A1C8;
+
 	_Z20CreateParentedObjectsPvic = 0x80162B00;
 	_Z47CheckIfMenuShouldBeCancelledForSpecifiedWiimotei = 0x800B53A0;
 	_Z21StartTitleScreenStagebi = 0x801017D0;
@@ -288,6 +293,7 @@ SECTIONS {
 	DVD_StillLoading__FPv = 0x800DF4E0;
 	DVD_End__Fv = 0x8006A760;
 	DVD_GetFile__FPvPCcPCc = 0x800DF180;
+	DVD_GetFile__FPvPCcPCcPUi = 0x800DF1E0;
 
 	__ct__12dDvdLoader_cFv = 0x8008F140;
 	__dt__12dDvdLoader_cFv = 0x8008F170;
diff --git a/kamek_pal.x b/kamek_pal.x
index a078e12..34bbba8 100644
--- a/kamek_pal.x
+++ b/kamek_pal.x
@@ -233,6 +233,9 @@ SECTIONS {
 
 	GameHeaps = 0x80377F48;
 
+	BGDatClass = 0x8042A0D0;
+	GetTilesetName__FPvii = 0x800813F0;
+
 	IsWideScreen__Fv = 0x800B5500;
 
 	Player_Active = 0x80355150;
@@ -249,6 +252,8 @@ SECTIONS {
 	GetObjectParent = 0x801626D0;
 	OSReport = 0x8015F870;
 
+	StagePtr = 0x8042A4A8;
+
 	_Z20CreateParentedObjectsPvic = 0x80162C40;
 	_Z47CheckIfMenuShouldBeCancelledForSpecifiedWiimotei = 0x800B53F0;
 	_Z21StartTitleScreenStagebi = 0x801018E0;
@@ -288,6 +293,7 @@ SECTIONS {
 	DVD_StillLoading__FPv = 0x800DF5D0;
 	DVD_End__Fv = 0x8006A760;
 	DVD_GetFile__FPvPCcPCc = 0x800DF270;
+	DVD_GetFile__FPvPCcPCcPUi = 0x800DF2D0;
 
 	__ct__12dDvdLoader_cFv = 0x8008F140;
 	__dt__12dDvdLoader_cFv = 0x8008F170;
diff --git a/kamek_pal2.x b/kamek_pal2.x
index 5807478..c18de20 100644
--- a/kamek_pal2.x
+++ b/kamek_pal2.x
@@ -233,6 +233,9 @@ SECTIONS {
 
 	GameHeaps = 0xDEADBEEF;
 
+	BGDatClass = 0xDEADBEEF;
+	GetTilesetName__FPvii = 0xDEADBEEF;
+
 	IsWideScreen__Fv = 0xDEADBEEF;
 
 	Player_Active = 0xDEADBEEF;
@@ -249,6 +252,8 @@ SECTIONS {
 	GetObjectParent = 0xDEADBEEF;
 	OSReport = 0xDEADBEEF;
 
+	StagePtr = 0xDEADBEEF;
+
 	_Z20CreateParentedObjectsPvic = 0xDEADBEEF;
 	_Z47CheckIfMenuShouldBeCancelledForSpecifiedWiimotei = 0xDEADBEEF;
 	_Z21StartTitleScreenStagebi = 0xDEADBEEF;
@@ -288,6 +293,7 @@ SECTIONS {
 	DVD_StillLoading__FPv = 0xDEADBEEF;
 	DVD_End__Fv = 0xDEADBEEF;
 	DVD_GetFile__FPvPCcPCc = 0xDEADBEEF;
+	DVD_GetFile__FPvPCcPCcPUi = 0xDEADBEEF;
 
 	__ct__12dDvdLoader_cFv = 0xDEADBEEF;
 	__dt__12dDvdLoader_cFv = 0xDEADBEEF;
diff --git a/src/tilesetfixer.cpp b/src/tilesetfixer.cpp
new file mode 100644
index 0000000..a66fc14
--- /dev/null
+++ b/src/tilesetfixer.cpp
@@ -0,0 +1,94 @@
+#include <common.h>
+#include <game.h>
+
+extern void *BGDatClass, *StagePtr;
+const char *GetTilesetName(void *cls, int areaNum, int slotNum);
+
+asm int GetAreaNum() {
+	nofralloc
+	lis r9, StagePtr@h
+	ori r9, r9, StagePtr@l
+	lwz r9, 0(r9)
+	lbz r3, 0x120E(r9)
+	blr
+}
+
+
+void DoFixes(int slotNumber);
+void SwapObjData(u8 *data, int slotNumber);
+
+// Main hook
+void TilesetFixerHack() {
+	for (int i = 1; i < 4; i++) {
+		DoFixes(i);
+	}
+}
+
+
+
+// File format definitions
+struct ObjLookupEntry {
+	u16 offset;
+	u8 width;
+	u8 height;
+};
+
+
+void DoFixes(int slotNumber) {
+	// This is where it all starts
+	const char *tsName = GetTilesetName(BGDatClass, GetAreaNum(), slotNumber);
+
+	if (tsName == 0 || tsName[0] == 0) {
+		OSReport("Skipping set %d\n", slotNumber);
+		return;
+	}
+
+	OSReport("Processing %d = %s\n", slotNumber, tsName);
+
+	char untHDname[64], untname[64];
+	snprintf(untHDname, 64, "BG_unt/%s_hd.bin", tsName);
+	snprintf(untname, 64, "BG_unt/%s.bin", tsName);
+
+	u32 unt_hd_length;
+	void *bg_unt_hd_data = DVD_GetFile(GetDVDClass2(), tsName, untHDname, &unt_hd_length);
+	void *bg_unt = DVD_GetFile(GetDVDClass2(), tsName, untname);
+
+	OSReport("Unt: %p - Unt_HD: %p\n", bg_unt, bg_unt_hd_data);
+
+	ObjLookupEntry *lookups = (ObjLookupEntry*)bg_unt_hd_data;
+
+	int objCount = unt_hd_length / sizeof(ObjLookupEntry);
+	OSReport("%d objects\n", objCount);
+
+	for (int i = 0; i < objCount; i++) {
+		// process each object
+		u8 *thisObj = (u8*)((u32)bg_unt + lookups[i].offset);
+		//OSReport("processing %d[%p][%04x]\n", i, thisObj, lookups[i].offset);
+
+		SwapObjData(thisObj, slotNumber);
+	}
+}
+
+
+void SwapObjData(u8 *data, int slotNumber) {
+	// rudimentary parser which will hopefully work
+
+	while (*data != 0xFF) {
+		u8 cmd = *data;
+		//OSReport("Command: %02x\n", cmd);
+
+		if (cmd == 0xFE || (cmd & 0x80) != 0) {
+			data++;
+			continue;
+		}
+
+		if ((data[2] & 3) != 0) {
+			data[2] &= 0xFC;
+			data[2] |= slotNumber;
+		}
+		data += 3;
+	}
+
+	//OSReport("Ended @ %p\n", data);
+}
+
diff --git a/tilesetfixer.yaml b/tilesetfixer.yaml
new file mode 100644
index 0000000..409c443
--- /dev/null
+++ b/tilesetfixer.yaml
@@ -0,0 +1,9 @@
+---
+source_files: [../src/tilesetfixer.cpp]
+hooks:
+  - name: TilesetFixHack
+    type: branch_insn
+    branch_type: b
+    src_addr_pal: 0x80081694
+    target_func: 'TilesetFixerHack(void)'
+
-- 
cgit v1.2.3