summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlunarsoap5 <40438826+lunarsoap5@users.noreply.github.com>2020-08-12 07:19:26 -0500
committerGitHub <noreply@github.com>2020-08-12 07:19:26 -0500
commitd7e5a110b12eb9bc0868213114e52c5627690f11 (patch)
tree4914d6d08edee399bbc22ba964d9bcf51cde8005
parent84254034027b7aa9f0e8ff71ebdc4c7f13fa9302 (diff)
Adding Framework for customizationsdebug
Framework added for BGM Shuffle, Audio Stream Shuffle, Field Model Replacement, and Custom Field Models
-rw-r--r--include/array.h12
-rw-r--r--include/chestRando.h2
-rw-r--r--include/defines.h2
-rw-r--r--include/game_patches.h5
-rw-r--r--include/item.h2
-rw-r--r--include/mod.h20
-rw-r--r--include/singleton.h2
-rw-r--r--include/tools.h26
-rw-r--r--include/tp.us.lst6
-rw-r--r--include/tp/Z2SeqMgr.h13
-rw-r--r--include/tp/d_a_shop_item_static.h2
-rw-r--r--include/tp/d_item_data.h4
-rw-r--r--include/tp/d_stage.h2
-rw-r--r--include/tp/dzx.h36
-rw-r--r--include/tp/f_op_actor_mng.h13
-rw-r--r--source/array.cpp168
-rw-r--r--source/chestRando.cpp55
-rw-r--r--source/game_patches.cpp94
-rw-r--r--source/item.cpp107
-rw-r--r--source/mod.cpp159
-rw-r--r--source/singleton.cpp2
-rw-r--r--source/tools.cpp47
22 files changed, 673 insertions, 106 deletions
diff --git a/include/array.h b/include/array.h
index 37cb27c..500e36b 100644
--- a/include/array.h
+++ b/include/array.h
@@ -1,9 +1,11 @@
#pragma once
#include "defines.h"
+#include "mod.h"
namespace mod::array
{
+
extern "C"
{
/**
@@ -15,5 +17,15 @@ namespace mod::array
* @returns If successful the index of needle inside the array, otherwise -1
*/
s32 indexOf(u16 needle, u16* haystack, size_t count);
+
+ u32 getRandomBgmId(u32 originalId);
+ u32 getRandomAudioStreamId(u32 originalId);
+
+ extern u8 bgmIndexArray[0xAA];
+ extern u8 audioStreamingIndexArray[0x81];
+ extern u8 invalidBgmIndexArray[0x51];
+ extern u8 bgmFanfareArray[0x8];
+ extern bool checkIfBgmIdIsFanfare(u8 bgmId);
+ extern bool checkIfBgmIdIsValid(u8 bgmId);
}
} \ No newline at end of file
diff --git a/include/chestRando.h b/include/chestRando.h
index a030d77..b897de8 100644
--- a/include/chestRando.h
+++ b/include/chestRando.h
@@ -144,5 +144,7 @@ namespace mod
* check if the check gotten in a grotto is the right one
*/
bool isGrottoCheckOk(u16 checkID);
+
+ void setAudioArrayValues();
};
} \ No newline at end of file
diff --git a/include/defines.h b/include/defines.h
index e44f1d4..75f3b1a 100644
--- a/include/defines.h
+++ b/include/defines.h
@@ -39,7 +39,7 @@ union typeTransform {
// Mnemonics
#define AUTHOR "ZTPR"
-#define VERSION "v0.16.1b"
+#define VERSION "v0.16.2b"
#define RAND_SEED mod::tools::randomSeed
#define gameInfo tp::d_com_inf_game::dComIfG_gameInfo
#define getPlayerPos tp::d_map_path_dmap::getMapPlayerPos
diff --git a/include/game_patches.h b/include/game_patches.h
index 357613d..de7ec0d 100644
--- a/include/game_patches.h
+++ b/include/game_patches.h
@@ -2,6 +2,7 @@
#include "defines.h"
#include <tp/d_com_inf_game.h>
+#include <tp/d_stage.h>
@@ -225,4 +226,8 @@ namespace mod::game_patch
void setToTBossFlag();
void setCiTSDungeonFlag();
void setCiTSBossFlag();
+
+ void changeFieldModels();
+ void modifyFieldItems(tp::d_stage::dzxChunkTypeInfo* chunkTypeInfo);
+
} \ No newline at end of file
diff --git a/include/item.h b/include/item.h
index cd9964e..c213ba1 100644
--- a/include/item.h
+++ b/include/item.h
@@ -82,5 +82,5 @@ namespace mod::item
* Contains the values for the flags to be set to skip the animations of first getting specific items
*/
extern u8 itemGetAnimationFlags[10];
- extern u8 itemsWithNoFieldModel[2];
+ extern u8 itemsWithNoFieldModel[0x69];
} \ No newline at end of file
diff --git a/include/mod.h b/include/mod.h
index 9a650ba..dfc0ea4 100644
--- a/include/mod.h
+++ b/include/mod.h
@@ -4,6 +4,7 @@
#include <tp/d_com_inf_game.h>
#include <tp/DynamicLink.h>
#include <tp/dzx.h>
+#include <tp/d_stage.h>
#include "eventListener.h"
#include "chestRando.h"
#include "HUDConsole.h"
@@ -221,6 +222,10 @@ namespace mod
void fixFTTotemMonkey();
+ void(*bgmStart_trampoline)(void* Z2SeqMgr, u32 bgmId, u32 unk3, s32 unk4) = nullptr;
+ void(*subBgmStart_trampoline)(void* Z2SeqMgr, u32 bgmId) = nullptr;
+ void(*bgmStreamPrepare_trampoline)(void* Z2SeqMgr, u32 audioStreamingId) = nullptr;
+
//void setFieldModels();
//bool procActorCommonLayerInit(void* mStatus_roomControl, tp::d_stage::dzxChunkTypeInfo* chunkTypeInfo, s32 unk3, void* unk4);
@@ -244,15 +249,18 @@ namespace mod
bool (*actorCommonLayerInit_trampoline)(void* mStatus_roomControl, tp::d_stage::dzxChunkTypeInfo* chunkTypeInfo, int unk3, void* unk4) = nullptr;
+ bool(*actorInit_trampoline)(void* mStatus_roomControl, tp::d_stage::dzxChunkTypeInfo* chunkTypeInfo, int unk3, void* unk4) = nullptr;
+
void (*putSave_trampoline)(tp::d_com_inf_game::GameInfo* gameInfoPtr, s32 areaID) = nullptr;
// Item functions
- s32 (*createItemForPresentDemo_trampoline)(const float pos[3], s32 item, u8 unk3, s32 unk4, s32 unk5, const float unk6[3], const float unk7[3]) = nullptr;
- s32 (*createItemForTrBoxDemo_trampoline)(const float pos[3], s32 item, s32 unk3, s32 unk4, const float unk5[3], const float unk6[3]) = nullptr;
- s32 (*createItemForBoss_trampoline)(const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], float unk6, float unk7, s32 unk8) = nullptr;
- s32 (*createItemForMidBoss_trampoline)(const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], s32 unk6, s32 unk7) = nullptr;
- s32 (*createItemForDirectGet_trampoline)(const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], float unk6, float unk7) = nullptr;
- s32(*createItemForSimpleDemo_trampoline)(const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], float unk6, float unk7) = nullptr;
+ s32(*createItemForPresentDemo_trampoline)(const float pos[3], s32 item, u8 unk3, s32 unk4, s32 unk5, const s16 rot[3], const float scale[3]) = nullptr;
+ s32(*createItemForTrBoxDemo_trampoline)(const float pos[3], s32 item, s32 itemPickupFlag, s32 roomNo, const s16 rot[3], const float scale[3]) = nullptr;
+ s32(*createItemForBoss_trampoline)(const float pos[3], s32 item, s32 roomNo, const s16 rot[3], const float scale[3], float unk6, float unk7, s32 parameters) = nullptr;
+ s32(*createItemForMidBoss_trampoline)(const float pos[3], s32 item, s32 roomNo, const s16 rot[3], const float scale[3], s32 unk6, s32 itemPickupFlag) = nullptr;
+ s32(*createItemForDirectGet_trampoline)(const float pos[3], s32 item, s32 unk3, const s16 rot[3], const float scale[3], float unk6, float unk7) = nullptr;
+ s32(*createItemForSimpleDemo_trampoline)(const float pos[3], s32 item, s32 unk3, const s16 rot[3], const float scale[3], float unk6, float unk7) = nullptr;
+
s32(*createItem_trampoline)(const float pos[3], s32 item, s32 unk3, s32 unk4, const float unk5[3], const float unk6[3], s32 unk7) = nullptr;
void(*setItemBombNumCount_trampoline)(u32 unk1, u8 bagNb, short amount) = nullptr;
diff --git a/include/singleton.h b/include/singleton.h
index 8ae4523..8e243c4 100644
--- a/include/singleton.h
+++ b/include/singleton.h
@@ -36,6 +36,8 @@ namespace mod
u8 isGMStoryPatch;
u8 isEarlyHCEnabled;
u8 startWithCrystal;
+ u8 isRainbowLanternEnabled;
+ u8 isCustomMusicEnabled;
//dungeon flags
u8 hasFTBeenBeaten;
diff --git a/include/tools.h b/include/tools.h
index 7162985..39e6fa8 100644
--- a/include/tools.h
+++ b/include/tools.h
@@ -11,6 +11,8 @@ namespace mod::tools
{
extern u64 randomSeed;
+ extern u64 bgmSeed;
+
/**
* Generates a simple random number (not perfectly random but good enough for most purposes)
* Note: It's best to use with a clock that advances randomSeed
@@ -21,6 +23,10 @@ namespace mod::tools
*/
u32 getRandom(u32 max);
+ u32 getRandomMain(u32 max, u64* seed);
+
+ u32 getRandomBgm(u32 max);
+
/**
* Triggers the generator function which is a member function
* (This is a wrapper)
@@ -73,5 +79,25 @@ namespace mod::tools
* Checks if a specific bit/flag in the itemFlags variable in tp::d_com_inf_game::gameInfo.scratchPad.itemFlags is set
*/
bool checkItemFlag(ItemFlags flag);
+
+ /**
+ * Shuffles any given u8 array
+ * Uses the Fisher–Yates shuffle algorithm
+ *
+ * @param array The array to shuffle
+ * @param numItems The total number of elements in the array
+ */
+ void shuffleByteArray(u8* array, u32 numItems);
+
+ /**
+ * Fills any u8 array incrementally
+ *
+ * @param array The array to fill
+ * @param numItems The total number of elements in the array
+ * @param incrementAmount The amount to increment by
+ */
+ void fillArrayIncrement(u8* array, u32 numItems, u8 incrementAmount);
+
+ bool checkIfBgmIdIsValid(u8 bgmId);
}
} \ No newline at end of file
diff --git a/include/tp.us.lst b/include/tp.us.lst
index 8ba6c1c..2436c8e 100644
--- a/include/tp.us.lst
+++ b/include/tp.us.lst
@@ -151,6 +151,7 @@
80368994:strcmp
80368B2C:strcpy
80368AE8:strncpy
+80368954:strncmp
//currentState
803A66B3:current_state
@@ -194,3 +195,8 @@
//d_meter2_info.o
804301A4:wZButtonPtr
+
+//Z2SeqMgr.o
+802af010:bgmStart
+802af49c:subBgmStart
+802afb94:bgmStreamPrepare \ No newline at end of file
diff --git a/include/tp/Z2SeqMgr.h b/include/tp/Z2SeqMgr.h
new file mode 100644
index 0000000..3b82029
--- /dev/null
+++ b/include/tp/Z2SeqMgr.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "defines.h"
+
+namespace tp::z2seqmgr
+{
+ extern "C"
+ {
+ void bgmStart(void* Z2SeqMgr, u32 bgmId, u32 unk3, s32 unk4);
+ void subBgmStart(void* Z2SeqMgr, u32 bgmId);
+ void bgmStreamPrepare(void* Z2SeqMgr, u32 audioStreamingId);
+ }
+} \ No newline at end of file
diff --git a/include/tp/d_a_shop_item_static.h b/include/tp/d_a_shop_item_static.h
index 548b04d..99400ed 100644
--- a/include/tp/d_a_shop_item_static.h
+++ b/include/tp/d_a_shop_item_static.h
@@ -33,7 +33,7 @@ namespace tp::d_a_shop_item_static
struct ShopItemData
{
- char* arcName;
+ const char* arcName;
s16 modelResIdx;
s16 wBtkResIdx;
s16 unk_8;
diff --git a/include/tp/d_item_data.h b/include/tp/d_item_data.h
index c5bd746..e0a79fa 100644
--- a/include/tp/d_item_data.h
+++ b/include/tp/d_item_data.h
@@ -39,6 +39,10 @@ namespace tp::d_item_data
u8 mFlags;
} __attribute__((__packed__));
+
+
+
+
static_assert(sizeof(ItemResource) == 0x18);
static_assert(sizeof(FieldItemRes) == 0x10);
static_assert(sizeof(ItemInfo) == 0x4);
diff --git a/include/tp/d_stage.h b/include/tp/d_stage.h
index 873abb1..0d51db6 100644
--- a/include/tp/d_stage.h
+++ b/include/tp/d_stage.h
@@ -24,6 +24,8 @@ namespace tp::d_stage
u16 enemyNum;
} __attribute__((__packed__));
+
+
static_assert(sizeof(Item) == 0x20);
extern "C"
diff --git a/include/tp/dzx.h b/include/tp/dzx.h
index 2833981..5177ee3 100644
--- a/include/tp/dzx.h
+++ b/include/tp/dzx.h
@@ -19,23 +19,6 @@ namespace tp::d_stage
* 0001
* 80401234 = 1 TRES Chunk at this address
*/
-
- struct Actr
- {
- char objectName[8];
- u32 parameters;
- float pos[3];
- s16 rot[3];
- u16 enemyNum;
- } __attribute__((__packed__));
- static_assert(sizeof(Actr) == 0x20);
-
- struct dzxChunkTypeInfo
- {
- char tag[4];
- u32 numChunks;
- void* chunkDataPtr;
- } __attribute__((__packed__));
struct TRES
{
@@ -53,6 +36,25 @@ namespace tp::d_stage
TRES() { memset(this, 0xFF, sizeof(TRES)); }
} __attribute__((__packed__));
+
+ struct Actr
+ {
+ char objectName[8];
+ u32 parameters;
+ float pos[3];
+ s16 rot[3];
+ u16 enemyNum;
+ } __attribute__((__packed__));
+
+ struct dzxChunkTypeInfo
+ {
+ char tag[4];
+ u32 numChunks;
+ Actr* chunkDataPtr;
+ } __attribute__((__packed__));
+
static_assert(sizeof(TRES) == 0x20);
+ static_assert(sizeof(Actr) == 0x20);
+ static_assert(sizeof(dzxChunkTypeInfo) == 0xC);
} // namespace tp \ No newline at end of file
diff --git a/include/tp/f_op_actor_mng.h b/include/tp/f_op_actor_mng.h
index d0ca47c..ba240f4 100644
--- a/include/tp/f_op_actor_mng.h
+++ b/include/tp/f_op_actor_mng.h
@@ -6,12 +6,11 @@ namespace tp::f_op_actor_mng
{
extern "C"
{
- s32 createItemForPresentDemo(const float pos[3], s32 item, u8 unk3, s32 unk4, s32 unk5, const float unk6[3], const float unk7[3]);
- s32 createItemForTrBoxDemo(const float pos[3], s32 item, s32 unk3, s32 unk4, const float unk5[3], const float unk6[3]);
- s32 createDemoItem(const float pos[3], s32 item, s32 unk3, const float unk4[3], s32 unk5, const float unk6[3], u8 unk7);
- s32 createItemForBoss(const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], float unk6, float unk7, s32 unk8);
- s32 createItemForMidBoss(const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], s32 unk6, s32 unk7);
- s32 createItemForDirectGet(const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], float unk6, float unk7);
- s32 createItemForSimpleDemo(const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], float unk6, float unk7);
+ s32 createItemForPresentDemo(const float pos[3], s32 item, u8 unk3, s32 unk4, s32 unk5, const s16 rot[3], const float scale[3]);
+ s32 createItemForTrBoxDemo(const float pos[3], s32 item, s32 itemPickupFlag, s32 roomNo, const s16 rot[3], const float scale[3]);
+ s32 createItemForBoss(const float pos[3], s32 item, s32 roomNo, const s16 rot[3], const float scale[3], float unk6, float unk7, s32 parameters);
+ s32 createItemForMidBoss(const float pos[3], s32 item, s32 roomNo, const s16 rot[3], const float scale[3], s32 unk6, s32 itemPickupFlag);
+ s32 createItemForDirectGet(const float pos[3], s32 item, s32 unk3, const s16 rot[3], const float scale[3], float unk6, float unk7);
+ s32 createItemForSimpleDemo(const float pos[3], s32 item, s32 unk3, const s16 rot[3], const float scale[3], float unk6, float unk7);
}
} \ No newline at end of file
diff --git a/source/array.cpp b/source/array.cpp
index 76cbebe..2300e46 100644
--- a/source/array.cpp
+++ b/source/array.cpp
@@ -1,5 +1,7 @@
#include "array.h"
#include "memory.h"
+#include "mod.h"
+#include "singleton.h"
#include <cstring>
@@ -16,4 +18,170 @@ namespace mod::array
}
return -1;
}
+
+ u8 bgmIndexArray[0xAA];
+ u8 audioStreamingIndexArray[0x81];
+
+ u8 invalidBgmIndexArray[0x51] =
+ {
+ 0x1,
+ 0x3,
+ 0x9,
+ 0xA,
+ 0xB,
+ 0x12,
+ 0x14,
+ 0x18,
+ 0x1C,
+ 0x21,
+ 0x24,
+ 0x2B,
+ 0x2D,
+ 0x33,
+ 0x34,
+ 0x3C,
+ 0x3D,
+ 0x3E,
+ 0x40,
+ 0x43,
+ 0x44,
+ 0x45,
+ 0x46,
+ 0x4A,
+ 0x4B,
+ 0x4D,
+ 0x4E,
+ 0x4F,
+ 0x50,
+ 0x51,
+ 0x52,
+ 0x53,
+ 0x54,
+ 0x56,
+ 0x57,
+ 0x5B,
+ 0x5C,
+ 0x5F,
+ 0x60,
+ 0x63,
+ 0x66,
+ 0x67,
+ 0x68,
+ 0x69,
+ 0x6A,
+ 0x6B,
+ 0x71,
+ 0x72,
+ 0x73,
+ 0x74,
+ 0x75,
+ 0x76,
+ 0x77,
+ 0x79,
+ 0x7B,
+ 0x7C,
+ 0x7D,
+ 0x7E,
+ 0x7F,
+ 0x80,
+ 0x81,
+ 0x82,
+ 0x83,
+ 0x84,
+ 0x89,
+ 0x8A,
+ 0x8D,
+ 0x8E,
+ 0x92,
+ 0x93,
+ 0x98,
+ 0x99,
+ 0x9C,
+ 0x9D,
+ 0xA0,
+ 0xA1,
+ 0xA2,
+ 0xA3,
+ 0xA4,
+ 0xA6,
+ 0xA7
+ };
+
+ u8 bgmFanfareArray[0x8] =
+ {
+ 0xA,
+ 0xB,
+ 0x81,
+ 0x82,
+ 0x83,
+ 0x99,
+ 0xA0,
+ 0xA6
+ };
+
+ u32 getRandomBgmId(u32 originalId)
+ {
+ if (/*mod::Mod::randoEnabled == 0 || */Singleton::getInstance()->isCustomMusicEnabled == 0x0)
+ {
+ return originalId;
+ }
+
+ // Make sure the original id is valid
+ if ((originalId < 0x1000000) || (originalId > 0x10000A9))
+ {
+ return originalId;
+ }
+
+ // Get the id out of the full value
+ u32 tempId = originalId - 0x1000000;
+
+ // Get the new id
+ return bgmIndexArray[tempId] + 0x1000000;
+ }
+
+ u32 getRandomAudioStreamId(u32 originalId)
+ {
+ if (/*mod::Mod::randoEnabled == 0 || */Singleton::getInstance()->isCustomMusicEnabled == 0x0)
+ {
+ return originalId;
+ }
+
+ // Make sure the original id is valid
+ if ((originalId < 0x2000000) || (originalId > 0x2000080))
+ {
+ return originalId;
+ }
+
+ // Get the id out of the full value
+ u32 tempId = originalId - 0x2000000;
+
+ // Get the new id
+ return audioStreamingIndexArray[tempId] + 0x2000000;
+ }
+
+ bool checkIfBgmIdIsValid(u8 bgmId)
+ {
+ u32 invalidBgmIndexArraySize = sizeof(array::invalidBgmIndexArray) / sizeof(array::invalidBgmIndexArray[0]);
+ for (u32 i = 0; i < invalidBgmIndexArraySize; i++)
+ {
+ if (bgmId == array::invalidBgmIndexArray[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool checkIfBgmIdIsFanfare(u8 bgmId)
+ {
+ u32 bgmFanfareArraySize = sizeof(array::bgmFanfareArray) / sizeof(array::bgmFanfareArray[0]);
+ for (u32 i = 0; i < bgmFanfareArraySize; i++)
+ {
+ if (bgmId == array::bgmFanfareArray[i])
+ {
+ return true;
+ }
+ }
+ return false;
+ }
} \ No newline at end of file
diff --git a/source/chestRando.cpp b/source/chestRando.cpp
index dd60741..0f73467 100644
--- a/source/chestRando.cpp
+++ b/source/chestRando.cpp
@@ -211,8 +211,12 @@ namespace mod
delete[] itemOrder;
+ setAudioArrayValues();
+
// Reset seed if the player wanted to lock it (otherwise it advances anyways)
tools::randomSeed = currentSeed;
+
+
}
void ChestRandomizer::placeCheck(item::ItemCheck* sourceCheck, item::ItemCheck* destCheck)
@@ -2295,4 +2299,55 @@ namespace mod
return true;
}
}
+
+ void ChestRandomizer::setAudioArrayValues()
+ {
+ // Reinitialize bgmIndexArray
+ u8* tempBgmIndexArray = array::bgmIndexArray;
+ u32 bgmIndexArrayTotalElements = sizeof(array::bgmIndexArray) / sizeof(array::bgmIndexArray[0]);
+ tools::fillArrayIncrement(tempBgmIndexArray, bgmIndexArrayTotalElements, 1);
+
+ // Reinitialize audioStreamingIndexArray
+ u8* tempAudioStreamingIndexArray = array::audioStreamingIndexArray;
+ u32 audioStreamingIndexArrayTotalElements = sizeof(array::audioStreamingIndexArray) / sizeof(array::audioStreamingIndexArray[0]);
+ tools::fillArrayIncrement(tempAudioStreamingIndexArray, audioStreamingIndexArrayTotalElements, 1);
+
+ // Reinitialize bgmFanfareArray
+ u8* tempBgmFanfareArray = array::bgmFanfareArray;
+ u32 bgmFanfareArrayTotalElements = sizeof(array::bgmFanfareArray) / sizeof(array::bgmFanfareArray[0]);
+ tools::fillArrayIncrement(tempBgmFanfareArray, bgmFanfareArrayTotalElements, 1);
+
+ if (Singleton::getInstance()->isCustomMusicEnabled == 0x1)
+ {
+ // Shuffle bgmIndexArray
+ tools::shuffleByteArray(tempBgmIndexArray, bgmIndexArrayTotalElements);
+
+ // Since we are shuffling bgm, we will shuffle bgmFanfareArray as well
+ tools::shuffleByteArray(tempBgmFanfareArray, bgmFanfareArrayTotalElements);
+
+ int j = 0;
+ for (u32 i = 0; i < bgmIndexArrayTotalElements; i++)
+ {
+ if (!array::checkIfBgmIdIsValid(array::bgmIndexArray[i]))
+ {
+ u8 tempId;
+ u8 const maxId = 0xAA;
+ do
+ {
+ tempId = tools::getRandomBgm(maxId);
+ } while (!array::checkIfBgmIdIsValid(tempId));
+
+ array::bgmIndexArray[i] = tempId;
+ }
+
+ if (array::checkIfBgmIdIsFanfare(i))
+ {
+ array::bgmIndexArray[i] = array::bgmFanfareArray[j];
+ j++;
+ }
+ }
+ // Shuffle audioStreamingIndexArray
+ tools::shuffleByteArray(tempAudioStreamingIndexArray, audioStreamingIndexArrayTotalElements);
+ }
+ }
} \ No newline at end of file
diff --git a/source/game_patches.cpp b/source/game_patches.cpp
index 25d8632..4f02428 100644
--- a/source/game_patches.cpp
+++ b/source/game_patches.cpp
@@ -5,6 +5,8 @@
#include "singleton.h"
#include "items.h"
#include "itemChecks.h"
+#include "patch.h"
+
#include <tp/d_menu_collect.h>
#include <tp/d_a_alink.h>
@@ -17,6 +19,7 @@
#include <tp/d_a_shop_item_static.h>
#include <tp/d_item_data.h>
#include <tp/d_item.h>
+#include <tp/dzx.h>
#include <cstring>
#include <cstdio>
@@ -964,6 +967,15 @@ namespace mod::game_patch
gameInfo.scratchPad.unk_1F[0x11] |= 0x8; //Midna on Back
}
}
+
+ Singleton::getInstance()->hasFTBeenBeaten = 0;
+ Singleton::getInstance()->hasGMBeenBeaten = 0;
+ Singleton::getInstance()->hasLBTBeenBeaten = 0;
+ Singleton::getInstance()->hasAGBeenBeaten = 0;
+ Singleton::getInstance()->hasSPRBeenBeaten = 0;
+ Singleton::getInstance()->hasToTBeenBeaten = 0;
+ Singleton::getInstance()->hasCiTSBeenBeaten = 0;
+
if (Singleton::getInstance()->isIntroSkipped == 1)
@@ -1112,7 +1124,7 @@ namespace mod::game_patch
}
}
- /*void setFieldModels()
+ void changeFieldModels()
{
tp::d_item_data::ItemResource* itemResPtr = &tp::d_item_data::item_resource[0];
tp::d_item_data::FieldItemRes* fieldItemResPtr = &tp::d_item_data::field_item_res[0];
@@ -1130,7 +1142,6 @@ namespace mod::game_patch
tp::d_item_data::ItemInfo* itemInfoPtr = &tp::d_item_data::item_info[0];
tp::d_item_data::ItemInfo* yellowRupeeInfoPtr = &tp::d_item_data::item_info[items::Yellow_Rupee];
- loopCount = sizeof(item::itemsWithNoFieldModel) / sizeof(item::itemsWithNoFieldModel[0]);
for (u32 i = 0; i < loopCount; i++)
{
u32 item = item::itemsWithNoFieldModel[i]; // Retrieve as u32 to prevent rlwinm shenanigans
@@ -1144,60 +1155,45 @@ namespace mod::game_patch
// If you already have the item it gives you, then itll act like a rupee and appear over your head. This could be changed though.
u32 address_US = 0x8015CF64;
*reinterpret_cast<u32*>(address_US) = 0x48000018; // b 0x18
-
- // Hook dStage_actorCommonLayerInit to search for field items (probably only rupees) to replace based on object name
- bool procActorCommonLayerInit(void* mStatus_roomControl, tp::d_stage::dzxChunkTypeInfo* chunkTypeInfo, s32 unk3, void* unk4)
+ }
+
+ void modifyFieldItems(tp::d_stage::dzxChunkTypeInfo* chunkTypeInfo)
+ {
+ tp::d_stage::Item* itemActrPtr = reinterpret_cast<tp::d_stage::Item*>(chunkTypeInfo->chunkDataPtr);
+ u32 numChunks = chunkTypeInfo->numChunks;
+ for (u32 i = 0; i < numChunks; i++)
{
- Actr* actrPtr = chunkTypeInfo->chunkDataPtr;
- u32 numChunks = chunkTypeInfo->numChunks;
- for (u32 i = 0; i < numChunks; i++)
+ // Check for "item", as that seems to be whats used for rupees
+ // Would check for chests and whatnot as well when changing the contents of those
+ if (strcmp(itemActrPtr->objectName, "item") == 0)
{
- // Check for "item", as that seems to be whats used for rupees
- // Would check for chests and whatnot as well when changing the contents of those
- if (strncmp(actrPtr->objectName, "item", sizeof(Actr.objectName)))
- {
- // Change the item id
- u8* tempParamBytes = reinterpret_cast<u8*>(&actrPtr->parameters);
- tempParamBytes[3] = newItemId;
+ // Change the item id
+ itemActrPtr->item = 0xA;
- // Changing the parameters probably isnt necessary for "item", but I'll add them anyway
- // Refer to Winditor for what the parameters do
- tempParamBytes[0] = 0xF3;
- tempParamBytes[1] = 0xFF;
- tempParamBytes[2] = 0x80;
- actrPtr->rot[2] = 0x3F;
- }
+ // Changing the parameters probably isnt necessary for "item", but I'll add them anyway
+ // Refer to Winditor for what the parameters do
+ itemActrPtr->rot[2] = 0x3F;
+ itemActrPtr->paramOne = 0xF3;
+ itemActrPtr->paramTwo = 0xFF;
}
- }
- // hook dStage_actorInit to search for field items (probably only heart containers) to replace based on object name
- // Not sure what is passed into dStage_actorInit, but r4 seems to be the same as dStage_actorCommonLayerInit
- bool procActorCommonLayerInit(void* mStatus_roomControl, tp::d_stage::dzxChunkTypeInfo* chunkTypeInfo, s32 unk3, void* unk4)
- {
- Actr* actrPtr = chunkTypeInfo->chunkDataPtr;
- u32 numChunks = chunkTypeInfo->numChunks;
- for (u32 i = 0; i < numChunks; i++)
+ // Check for "htPiece", as that seems to be whats used for heart pieces
+ // Not sure what name heart containers use
+ else if (strcmp(itemActrPtr->objectName, "Npc_ne") == 0)
{
- // Check for "htPiece", as that seems to be whats used for heart pieces
- // Not sure what name heart containers use
- if (strncmp(actrPtr->objectName, "htPiece", sizeof(Actr.objectName)))
- {
- // Change the object name to "item"
- strncpy(actrPtr->objectName, "item", sizeof(Actr.objectName));
+ // Change the object name to "item"
+ strcpy(itemActrPtr->objectName, "item");
- // Change the item id
- u8* tempParamBytes = reinterpret_cast<u8*>(&actrPtr->parameters);
- tempParamBytes[3] = newItemId;
+ // Change the item id
+ itemActrPtr->item = 0xA;
- // Changing the parameters is necessary for this, as its being changed to use rupee parameters
- // Currently allows the item to respawn, so need to look into what handles that
- // Refer to Winditor for what the parameters do
- tempParamBytes[0] = 0xF3;
- tempParamBytes[1] = 0xFF;
- tempParamBytes[2] = 0x80;
- actrPtr->rot[2] = 0x3F;
- }
+ // Changing the parameters is necessary for this, as its being changed to use rupee parameters
+ // Currently allows the item to respawn, so need to look into what handles that
+ // Refer to Winditor for what the parameters do
+ itemActrPtr->rot[2] = 0x3F;
+ itemActrPtr->paramOne = 0xF3;
+ itemActrPtr->paramTwo = 0xFF;
}
- }
- }*/
+ }
+ }
} \ No newline at end of file
diff --git a/source/item.cpp b/source/item.cpp
index f0f57fe..4849535 100644
--- a/source/item.cpp
+++ b/source/item.cpp
@@ -116,9 +116,112 @@ namespace mod::item
return flags;
}
- u8 itemsWithNoFieldModel[2] =
+ u8 itemsWithNoFieldModel[0x69] =
{
+ 0xA,
+ 0xB,
+ 0xC,
+ 0xD,
+ 0x16,
+ 0x17,
+ 0x18,
+ 0x19,
+ 0x1A,
+ 0x1B,
+ 0x1C,
+ 0x1D,
+ 0x2B,
+ 0x2C,
0x32,
- 0x40
+ 0x35,
+ 0x36,
+ 0x3D,
+ 0x3E,
+ 0x40,
+ 0x41,
+ 0x42,
+ 0x43,
+ 0x44,
+ 0x45,
+ 0x46,
+ 0x47,
+ 0x49,
+ 0x4A,
+ 0x4B,
+ 0x4C,
+ 0x4F,
+ 0x50,
+ 0x51,
+ 0x55,
+ 0x56,
+ 0x60,
+ 0x61,
+ 0x63,
+ 0x64,
+ 0x65,
+ 0x66,
+ 0x67,
+ 0x6D,
+ 0x6F,
+ 0x75,
+ 0x80,
+ 0x81,
+ 0x83,
+ 0x84,
+ 0x90,
+ 0x91,
+ 0x9D,
+ 0x9E,
+ 0xA1,
+ 0xA2,
+ 0xA3,
+ 0xA5,
+ 0xA6,
+ 0xA7,
+ 0xB0,
+ 0xB1,
+ 0xB2,
+ 0xB3,
+ 0xB4,
+ 0xB5,
+ 0xC0,
+ 0xC1,
+ 0xC2,
+ 0xC3,
+ 0xC4,
+ 0xC5,
+ 0xC6,
+ 0xC7,
+ 0xC8,
+ 0xC9,
+ 0xCA,
+ 0xCB,
+ 0xCC,
+ 0xCD,
+ 0xCE,
+ 0xCF,
+ 0xD0,
+ 0xD1,
+ 0xD2,
+ 0xD3,
+ 0xD4,
+ 0xD5,
+ 0xD6,
+ 0xD7,
+ 0xE0,
+ 0xE9,
+ 0xEA,
+ 0xEB,
+ 0xED,
+ 0xEE,
+ 0xF3,
+ 0xF4,
+ 0xF5,
+ 0xF6,
+ 0xF9,
+ 0xFA,
+ 0xFB,
+ 0xFD,
+ 0xFE
};
} \ No newline at end of file
diff --git a/source/mod.cpp b/source/mod.cpp
index 2dd5de5..5163af3 100644
--- a/source/mod.cpp
+++ b/source/mod.cpp
@@ -35,6 +35,7 @@
#include <tp/d_item.h>
#include <tp/d_item_data.h>
#include <tp/d_meter2_info.h>
+#include <tp/Z2SeqMgr.h>
#include <cstdio>
#include <cstring>
@@ -72,6 +73,7 @@ namespace mod
game_patch::assemblyOverwrites();
game_patch::increaseWalletSize();
game_patch::increaseClimbSpeed();
+ game_patch::changeFieldModels();
// Causes issues right now (argarok cannot be beaten)
@@ -216,7 +218,7 @@ namespace mod
hudConsole->addOption(page, "Early PoT?", &Singleton::getInstance()->isEarlyPoTEnabled, 0x1);
hudConsole->addOption(page, "Open HC?", &Singleton::getInstance()->isEarlyHCEnabled, 0x1);
//color
- /*page = hudConsole->addPage("Tunic Color1");
+ page = hudConsole->addPage("Tunic Color1");
hudConsole->addOption(page, "Top toggle:", &topToggle, 0x1);
hudConsole->addOption(page, "Red top:", &redTop, 0xFF);
@@ -225,7 +227,7 @@ namespace mod
hudConsole->addOption(page, "Bottom toggle:", &bottomToggle, 0x1);
hudConsole->addOption(page, "Red bottom:", &redBottom, 0xFF);
hudConsole->addOption(page, "Green bottom:", &greenBottom, 0xFF);
- hudConsole->addOption(page, "Blue bottom:", &blueBottom, 0xFF); */
+ hudConsole->addOption(page, "Blue bottom:", &blueBottom, 0xFF);
//buttons
/*page = hudConsole->addPage("Button texts");
@@ -266,6 +268,7 @@ namespace mod
//hudConsole->addOption(page, "Coords as hex?", &coordsAreInHex, 0x1);
hudConsole->addOption(page, "GM Story Flag?", &Singleton::getInstance()->isGMStoryPatch, 0x1);
hudConsole->addOption(page, "Start w/ Crstl?", &Singleton::getInstance()->startWithCrystal, 0x1);
+ hudConsole->addOption(page, "Shuffle BGM?", &Singleton::getInstance()->isCustomMusicEnabled, 0x1);
hudConsole->addWatch(page, "CurrentEventID:", &gameInfo.eventSystem.currentEventID, 'x', WatchInterpretation::_u8);
hudConsole->addWatch(page, "NextEventID:", &gameInfo.eventSystem.nextEventID, 'x', WatchInterpretation::_u8);
@@ -276,6 +279,7 @@ namespace mod
//Cosmetic Changes
page = hudConsole->addPage("Cosmetic");
+ hudConsole->addOption(page, "Rainbow Lantern?", &Singleton::getInstance()->isRainbowLanternEnabled, 0x1);
hudConsole->addOption(page, "LTN In Rd:", &innerRed, 0xFF);
hudConsole->addOption(page, "LTN In Green:", &innerGreen, 0xFF);
hudConsole->addOption(page, "LTN In Blue:", &innerBlue, 0xFF);
@@ -558,10 +562,23 @@ namespace mod
{
global::modPtr->doCustomTRESActor(mStatus_roomControl);
}
+
+ game_patch::modifyFieldItems(chunkTypeInfo);
+
return global::modPtr->actorCommonLayerInit_trampoline(mStatus_roomControl, chunkTypeInfo, unk3, unk4);
}
);
+ actorInit_trampoline = patch::hookFunction(tp::d_stage::actorInit,
+ [](void* mStatus_roomControl, tp::d_stage::dzxChunkTypeInfo* chunkTypeInfo, int unk3, void* unk4)
+ {
+ // Modify field items in certain rooms
+ game_patch::modifyFieldItems(chunkTypeInfo);
+
+ // Call original function
+ return global::modPtr->actorInit_trampoline(mStatus_roomControl, chunkTypeInfo, unk3, unk4);
+ });
+
putSave_trampoline = patch::hookFunction(tp::d_save::putSave,
[](tp::d_com_inf_game::GameInfo* gameInfoPtr, s32 areaID)
@@ -579,7 +596,7 @@ namespace mod
);
createItemForPresentDemo_trampoline = patch::hookFunction(tp::f_op_actor_mng::createItemForPresentDemo,
- [](const float pos[3], s32 item, u8 unk3, s32 unk4, s32 unk5, const float unk6[3], const float unk7[3])
+ [](const float pos[3], s32 item, u8 unk3, s32 unk4, s32 unk5, const s16 rot[3], const float scale[3])
{
// Call replacement function
/*char txt[50];
@@ -588,59 +605,59 @@ namespace mod
item = global::modPtr->procItemCreateFunc(pos, item, "createItemForPresentDemo");
- return global::modPtr->createItemForPresentDemo_trampoline(pos, item, unk3, unk4, unk5, unk6, unk7);
+ return global::modPtr->createItemForPresentDemo_trampoline(pos, item, unk3, unk4, unk5, rot, scale);
}
);
createItemForTrBoxDemo_trampoline = patch::hookFunction(tp::f_op_actor_mng::createItemForTrBoxDemo,
- [](const float pos[3], s32 item, s32 unk3, s32 unk4, const float unk5[3], const float unk6[3])
+ [](const float pos[3], s32 item, s32 itemPickupFlag, s32 roomNo, const s16 rot[3], const float scale[3])
{
// Call replacement function
item = global::modPtr->procItemCreateFunc(pos, item, "createItemForTrBoxDemo");
- return global::modPtr->createItemForTrBoxDemo_trampoline(pos, item, unk3, unk4, unk5, unk6);
+ return global::modPtr->createItemForTrBoxDemo_trampoline(pos, item, itemPickupFlag, roomNo, rot, scale);
}
);
//this function is called when the heart spawns, not when link gets it
//createItemForTrBoxDemo is called when heart container is gotten
createItemForBoss_trampoline = patch::hookFunction(tp::f_op_actor_mng::createItemForBoss,
- [](const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], float unk6, float unk7, s32 unk8)
+ [](const float pos[3], s32 item, s32 roomNo, const s16 rot[3], const float scale[3], float unk6, float unk7, s32 parameters)
{
// Call replacement function
item = global::modPtr->procItemCreateFunc(pos, item, "createItemForBoss");
- return global::modPtr->createItemForBoss_trampoline(pos, item, unk3, unk4, unk5, unk6, unk7, unk8);
+ return global::modPtr->createItemForBoss_trampoline(pos, item, roomNo, rot, scale, unk6, unk7, parameters);
}
);
createItemForMidBoss_trampoline = patch::hookFunction(tp::f_op_actor_mng::createItemForMidBoss,
- [](const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], s32 unk6, s32 unk7)
+ [](const float pos[3], s32 item, s32 roomNo, const s16 rot[3], const float scale[3], s32 unk6, s32 itemPickupFlag)
{
// Call replacement function
item = global::modPtr->procItemCreateFunc(pos, item, "createItemForMidBoss");
- return global::modPtr->createItemForMidBoss_trampoline(pos, item, unk3, unk4, unk5, unk6, unk7);
+ return global::modPtr->createItemForMidBoss_trampoline(pos, item, roomNo, rot, scale, unk6, itemPickupFlag);
}
);
createItemForDirectGet_trampoline = patch::hookFunction(tp::f_op_actor_mng::createItemForDirectGet,
- [](const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], float unk6, float unk7)
+ [](const float pos[3], s32 item, s32 unk3, const s16 rot[3], const float scale[3], float unk6, float unk7)
{
// Call replacement function
item = global::modPtr->procItemCreateFunc(pos, item, "createItemForDirectGet");
- return global::modPtr->createItemForDirectGet_trampoline(pos, item, unk3, unk4, unk5, unk6, unk7);
+ return global::modPtr->createItemForDirectGet_trampoline(pos, item, unk3, rot, scale, unk6, unk7);
}
);
createItemForSimpleDemo_trampoline = patch::hookFunction(tp::f_op_actor_mng::createItemForSimpleDemo,
- [](const float pos[3], s32 item, s32 unk3, const float unk4[3], const float unk5[3], float unk6, float unk7)
+ [](const float pos[3], s32 item, s32 unk3, const s16 rot[3], const float scale[3], float unk6, float unk7)
{
// Call replacement function
item = global::modPtr->procItemCreateFunc(pos, item, "createItemForSimpleDemo");
- return global::modPtr->createItemForSimpleDemo_trampoline(pos, item, unk3, unk4, unk5, unk6, unk7);
+ return global::modPtr->createItemForSimpleDemo_trampoline(pos, item, unk3, rot, scale, unk6, unk7);
}
);
@@ -765,6 +782,41 @@ namespace mod
return global::modPtr->setItemBombNumCount_trampoline(unk1, bagNb, amount);
}
);
+
+ bgmStart_trampoline = patch::hookFunction(tp::z2seqmgr::bgmStart,
+ [](void* Z2SeqMgr, u32 bgmId, u32 unk3, s32 unk4)
+ {
+ // Get the new bgmId
+ bgmId = array::getRandomBgmId(bgmId);
+ return global::modPtr->bgmStart_trampoline(Z2SeqMgr, bgmId, unk3, unk4);
+ }
+ );
+
+ subBgmStart_trampoline = patch::hookFunction(tp::z2seqmgr::subBgmStart,
+ [](void* Z2SeqMgr, u32 bgmId)
+ {
+ // Get the new bgmId
+ bgmId = array::getRandomBgmId(bgmId);
+ return global::modPtr->subBgmStart_trampoline(Z2SeqMgr, bgmId);
+ }
+ );
+
+ bgmStreamPrepare_trampoline = patch::hookFunction(tp::z2seqmgr::bgmStreamPrepare,
+ [](void* Z2SeqMgr, u32 audioStreamingId)
+ {
+ // Get the new audioStreamingId
+ audioStreamingId = array::getRandomAudioStreamId(audioStreamingId);
+ return global::modPtr->bgmStreamPrepare_trampoline(Z2SeqMgr, audioStreamingId);
+ }
+ );
+
+ // Initialize bgmIndexArray
+ u32 bgmIndexArrayTotalElements = sizeof(array::bgmIndexArray) / sizeof(array::bgmIndexArray[0]);
+ tools::fillArrayIncrement(array::bgmIndexArray, bgmIndexArrayTotalElements, 1);
+
+ // Initialize audioStreamingIndexArray
+ u32 audioStreamingIndexArrayTotalElements = sizeof(array::audioStreamingIndexArray) / sizeof(array::audioStreamingIndexArray[0]);
+ tools::fillArrayIncrement(array::audioStreamingIndexArray, audioStreamingIndexArrayTotalElements, 1);
}
void Mod::procNewFrame()
@@ -1038,6 +1090,7 @@ namespace mod
frame_counter = 0;
}
}
+
checkSearchID = (checkSearchID2 * 0x100) + checkSearchID1;
checkReverseSearchID = (checkReverseSearchID2 * 0x100) + checkReverseSearchID1;
if (checkSearchID != lastCheckSearchID)
@@ -1895,7 +1948,7 @@ namespace mod
tp::d_stage::dzxChunkTypeInfo chunkInfo;
strcpy(chunkInfo.tag, "ACTR"); // has to be ACTR for the function we use
chunkInfo.numChunks = checkCount;
- chunkInfo.chunkDataPtr = TRES;
+ chunkInfo.chunkDataPtr = reinterpret_cast<tp::d_stage::Actr*>(TRES);
// Populate TRES array with data
for (u32 i = 0; i < checkCount; i++)
@@ -1937,7 +1990,80 @@ namespace mod
void Mod::changeLanternColor()
{
-
+ if (Singleton::getInstance()->isRainbowLanternEnabled == 0x1)
+ {
+
+ if (innerRed != 0xFF && innerRed != 0x0)
+ {
+ innerRed = innerRed + 0xD;
+ }
+ if (innerRed == 0xFF || innerRed == 0x0)
+ {
+ innerRed = 0x0;
+ if (innerGreen != 0xFF && innerGreen != 0x0)
+ {
+ innerGreen = innerGreen + 0xD;
+ }
+ }
+ if (innerRed == 0xFF || innerRed == 0x0)
+ {
+ if (innerGreen == 0xFF || innerGreen == 0x0)
+ {
+ innerGreen = 0x0;
+ if (innerBlue != 0xFF)
+ {
+ innerBlue = innerBlue + 0xD;
+ }
+ }
+ }
+ if (innerRed == 0xFF || innerRed == 0x0)
+ {
+ if (innerGreen == 0xFF || innerGreen == 0x0)
+ {
+ if (innerBlue == 0xFF)
+ {
+ innerRed = 0x1;
+ innerGreen = 0x1;
+ innerBlue = 0x1;
+ }
+ }
+ }
+ if (outerRed != 0xFF && outerRed != 0x0)
+ {
+ outerRed = outerRed + 0xD;
+ }
+ if (outerRed == 0xFF || outerRed == 0x0)
+ {
+ outerRed = 0x0;
+ if (outerGreen != 0xFF && outerGreen != 0x0)
+ {
+ outerGreen = outerGreen + 0xD;
+ }
+ }
+ if (outerRed == 0xFF || outerRed == 0x0)
+ {
+ if (outerGreen == 0xFF || outerGreen == 0x0)
+ {
+ outerGreen = 0x0;
+ if (outerBlue != 0xFF)
+ {
+ outerBlue = outerBlue + 0xD;
+ }
+ }
+ }
+ if (outerRed == 0xFF || outerRed == 0x0)
+ {
+ if (outerGreen == 0xFF || outerGreen == 0x0)
+ {
+ if (outerBlue == 0xFF)
+ {
+ outerRed = 0x1;
+ outerGreen = 0x1;
+ outerBlue = 0x1;
+ }
+ }
+ }
+ }
// set lantern variables
u32 lanternVariableAddress = reinterpret_cast<u32>(&tp::d_a_alink::lanternVariables);
*reinterpret_cast<u8*>(lanternVariableAddress + 0x3D) = reinterpret_cast<u8>(innerRed);
@@ -2082,5 +2208,4 @@ namespace mod
}
return true;
}
-
} // namespace mod \ No newline at end of file
diff --git a/source/singleton.cpp b/source/singleton.cpp
index 74dc31f..376b7c3 100644
--- a/source/singleton.cpp
+++ b/source/singleton.cpp
@@ -40,6 +40,8 @@ namespace mod
isGMStoryPatch = 0;
isEarlyHCEnabled = 0;
startWithCrystal = 0;
+ isRainbowLanternEnabled = 0;
+ isCustomMusicEnabled = 0;
//dungeon fixes
hasFTBeenBeaten = 0;
diff --git a/source/tools.cpp b/source/tools.cpp
index 8b30184..6555ae7 100644
--- a/source/tools.cpp
+++ b/source/tools.cpp
@@ -12,13 +12,25 @@ namespace mod::tools
{
u64 randomSeed = 0x9e3779b97f4a7c15;
+ u64 bgmSeed = randomSeed;
+
+ u32 getRandomMain(u32 max, u64* seed)
+ {
+ u64 z = (*seed += 0x9e3779b97f4a7c15);
+ z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
+ z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
+
+ return (z % max);
+ }
+
u32 getRandom(u32 max)
{
- u64 z = (randomSeed += 0x9e3779b97f4a7c15);
- z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
- z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
-
- return (z % max);
+ return getRandomMain(max, &randomSeed);
+ }
+
+ u32 getRandomBgm(u32 max)
+ {
+ return getRandomMain(max, &bgmSeed);
}
void triggerRandomGenerator()
@@ -109,4 +121,29 @@ namespace mod::tools
u32* tempItemFlagsArray = gameInfo.scratchPad.itemFlags;
return tempItemFlagsArray[tempFlagVar / flagsPerVar] & (1 << (tempFlagVar % flagsPerVar));
}
+
+ void shuffleByteArray(u8* array, u32 numItems) // Fisher–Yates shuffle
+ {
+ for (s32 i = numItems - 1; i > 0; i--)
+ {
+ // Get a random index
+ u32 tempIndex = getRandom(numItems) % (i + 1);
+
+ // Swap array[i] with array[tempIndex]
+ u8 tempByte = array[i];
+ array[i] = array[tempIndex];
+ array[tempIndex] = tempByte;
+ }
+ }
+
+ void fillArrayIncrement(u8* array, u32 numItems, u8 incrementAmount)
+ {
+ u8 val = 0;
+ for (u32 i = 0; i < numItems; i++)
+ {
+ array[i] = val;
+ val += incrementAmount;
+ }
+ }
+
} \ No newline at end of file