diff --git a/.gitmodules b/.gitmodules
index 7098d9d08..f5b67b3ab 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -6,4 +6,4 @@
url = https://github.com/harbourmasters/ZAPDTR
[submodule "OTRExporter"]
path = OTRExporter
- url = https://github.com/harbourmasters/OTRExporter
+ url = https://github.com/harbourmasters/OTRExporter/
diff --git a/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL
new file mode 100644
index 000000000..6e3cbc204
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_0 b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_0
new file mode 100644
index 000000000..34ff33a71
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_0
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_1 b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_1
new file mode 100644
index 000000000..e406505e8
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_1
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_2 b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_2
new file mode 100644
index 000000000..d93755356
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_2
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_3 b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_3
new file mode 100644
index 000000000..87fb8da01
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_3
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_4 b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_4
new file mode 100644
index 000000000..6e436b142
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_tri_4
@@ -0,0 +1,245 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_0 b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_0
new file mode 100644
index 000000000..ed4b6e1c0
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_0
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_1 b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_1
new file mode 100644
index 000000000..d2728aae4
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_1
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_2 b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_2
new file mode 100644
index 000000000..eb0050c03
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_2
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_3 b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_3
new file mode 100644
index 000000000..f124650c8
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_3
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_4 b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_4
new file mode 100644
index 000000000..2bbe7895e
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/gGIBossSoulSkullDL_vtx_4
@@ -0,0 +1,267 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_Gem_eyes b/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_Gem_eyes
new file mode 100644
index 000000000..07364ba3a
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_Gem_eyes
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_black b/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_black
new file mode 100644
index 000000000..6aee093d9
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_black
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_eyes b/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_eyes
new file mode 100644
index 000000000..c08beb94a
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_eyes
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_horns b/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_horns
new file mode 100644
index 000000000..78d2a531c
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_horns
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_surface b/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_surface
new file mode 100644
index 000000000..e15a4dce4
--- /dev/null
+++ b/soh/assets/custom/objects/object_boss_soul/mat_gGIBossSoulSkullDL_skull_surface
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_boss_soul/noise_tex b/soh/assets/custom/objects/object_boss_soul/noise_tex
new file mode 100644
index 000000000..aaf4e331f
Binary files /dev/null and b/soh/assets/custom/objects/object_boss_soul/noise_tex differ
diff --git a/soh/assets/custom/objects/object_boss_soul/noise_tex_copy b/soh/assets/custom/objects/object_boss_soul/noise_tex_copy
new file mode 100644
index 000000000..a6d6cf945
Binary files /dev/null and b/soh/assets/custom/objects/object_boss_soul/noise_tex_copy differ
diff --git a/soh/assets/soh_assets.h b/soh/assets/soh_assets.h
index 2b193053c..16a2f5cd0 100644
--- a/soh/assets/soh_assets.h
+++ b/soh/assets/soh_assets.h
@@ -56,6 +56,9 @@ static const ALIGN_ASSET(2) char gTriforcePiece2DL[] = dgTriforcePiece2DL;
#define dgTriforcePieceCompletedDL "__OTR__objects/object_triforce_completed/gTriforcePieceCompletedDL"
static const ALIGN_ASSET(2) char gTriforcePieceCompletedDL[] = dgTriforcePieceCompletedDL;
+#define dgBossSoulSkullDL "__OTR__objects/object_boss_soul/gGIBossSoulSkullDL"
+static const ALIGN_ASSET(2) char gBossSoulSkullDL[] = dgBossSoulSkullDL;
+
// overlays
#define dgOptionsDividerChangeLangVtx "__OTR__overlays/ovl_file_choose/gOptionsDividerChangeLangVtx"
static const ALIGN_ASSET(2) char gOptionsDividerChangeLangVtx[] = dgOptionsDividerChangeLangVtx;
diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.h b/soh/soh/Enhancements/debugger/debugSaveEditor.h
index 42c9c91c0..1daddbf17 100644
--- a/soh/soh/Enhancements/debugger/debugSaveEditor.h
+++ b/soh/soh/Enhancements/debugger/debugSaveEditor.h
@@ -505,6 +505,16 @@ const std::vector flagTables = {
{ RAND_INF_CHILD_FISHING, "RAND_INF_CHILD_FISHING" },
{ RAND_INF_ADULT_FISHING, "RAND_INF_ADULT_FISHING" },
{ RAND_INF_10_BIG_POES, "RAND_INF_10_BIG_POES" },
+
+ { RAND_INF_GOHMA_SOUL, "RAND_INF_GOHMA_SOUL" },
+ { RAND_INF_KING_DODONGO_SOUL, "RAND_INF_KING_DODONGO_SOUL" },
+ { RAND_INF_BARINADE_SOUL, "RAND_INF_BARINADE_SOUL" },
+ { RAND_INF_PHANTOM_GANON_SOUL, "RAND_INF_PHANTOM_GANON_SOUL" },
+ { RAND_INF_VOLVAGIA_SOUL, "RAND_INF_VOLVAGIA_SOUL" },
+ { RAND_INF_MORPHA_SOUL, "RAND_INF_MORPHA_SOUL" },
+ { RAND_INF_BONGO_BONGO_SOUL, "RAND_INF_BONGO_BONGO_SOUL" },
+ { RAND_INF_TWINROVA_SOUL, "RAND_INF_TWINROVA_SOUL" },
+ { RAND_INF_GANON_SOUL, "RAND_INF_GANON_SOUL" },
} },
};
diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp
index 73110a7d6..34aa8af15 100644
--- a/soh/soh/Enhancements/mods.cpp
+++ b/soh/soh/Enhancements/mods.cpp
@@ -1039,6 +1039,64 @@ void RegisterRandomizerSheikSpawn() {
});
}
+//Boss souls require an additional item (represented by a RAND_INF) to spawn a boss in a particular lair
+void RegisterBossSouls() {
+ GameInteractor::Instance->RegisterGameHook([](void* actor) {
+ if (!gPlayState) return;
+ if (!IS_RANDO || !(OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BOSS_SOULS))) return;
+ RandomizerInf rand_inf = RAND_INF_MAX;
+ Actor* actual = (Actor*)actor;
+ switch (gPlayState->sceneNum){
+ case SCENE_DEKU_TREE_BOSS:
+ rand_inf = RAND_INF_GOHMA_SOUL;
+ break;
+ case SCENE_DODONGOS_CAVERN_BOSS:
+ rand_inf = RAND_INF_KING_DODONGO_SOUL;
+ break;
+ case SCENE_JABU_JABU_BOSS:
+ rand_inf = RAND_INF_BARINADE_SOUL;
+ break;
+ case SCENE_FOREST_TEMPLE_BOSS:
+ rand_inf = RAND_INF_PHANTOM_GANON_SOUL;
+ break;
+ case SCENE_FIRE_TEMPLE_BOSS:
+ rand_inf = RAND_INF_VOLVAGIA_SOUL;
+ break;
+ case SCENE_WATER_TEMPLE_BOSS:
+ rand_inf = RAND_INF_MORPHA_SOUL;
+ break;
+ case SCENE_SHADOW_TEMPLE_BOSS:
+ rand_inf = RAND_INF_BONGO_BONGO_SOUL;
+ break;
+ case SCENE_SPIRIT_TEMPLE_BOSS:
+ rand_inf = RAND_INF_TWINROVA_SOUL;
+ break;
+ case SCENE_GANONDORF_BOSS:
+ case SCENE_GANON_BOSS:
+ if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BOSS_SOULS) == RO_BOSS_SOULS_ON_PLUS_GANON) {
+ rand_inf = RAND_INF_GANON_SOUL;
+ }
+ break;
+ default: break;
+ }
+
+ //Deletes all actors in the boss category if the soul isn't found.
+ //Some actors, like Dark Link, Arwings, and Zora's Sapphire...?, are in this category despite not being actual bosses,
+ //so ignore any "boss" if `rand_inf` doesn't change from RAND_INF_MAX.
+ if (rand_inf != RAND_INF_MAX) {
+ if (!Flags_GetRandomizerInf(rand_inf) && actual->category == ACTORCAT_BOSS) {
+ Actor_Delete(&gPlayState->actorCtx, actual, gPlayState);
+ }
+ //Special case for Phantom Ganon's horse (and fake), as they're considered "background actors",
+ //but still control the boss fight flow.
+ if (!Flags_GetRandomizerInf(RAND_INF_PHANTOM_GANON_SOUL) && actual->id == ACTOR_EN_FHG) {
+ Actor_Delete(&gPlayState->actorCtx, actual, gPlayState);
+ }
+ }
+ });
+
+}
+
void InitMods() {
RegisterTTS();
RegisterInfiniteMoney();
@@ -1066,5 +1124,6 @@ void InitMods() {
RegisterEnemyDefeatCounts();
RegisterAltTrapTypes();
RegisterRandomizerSheikSpawn();
+ RegisterBossSouls();
NameTag_RegisterHooks();
}
diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp
index efe4a9424..0e460a024 100644
--- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp
@@ -1939,6 +1939,114 @@ void HintTable_Init_Item() {
Text{"a Piece of the Triforce", /*french*/"un fragment de la Triforce", /*spanish*/"un fragmento de la Trifuerza"}
);
+ hintTable[RHT_GOHMA_SOUL] = HintText::Item({
+ //obscure text
+ Text{"an invasive soul", "", ""},
+ Text{"some spider essence", "", ""},
+ }, {
+ //ambiguous text
+ Text{"something webbed", "", ""}
+ }, {
+ //clear text
+ Text{"the soul of Gohma", "", ""}}
+ );
+
+ hintTable[RHT_KING_DODONGO_SOUL] = HintText::Item({
+ //obscure text
+ Text{"a royal soul", "", ""},
+ Text{"some reptile essence", "", ""},
+ }, {
+ //ambiguous text
+ Text{"something explosive", "", ""}
+ }, {
+ //clear text
+ Text{"the soul of King Dodongo", "", ""}}
+ );
+
+ hintTable[RHT_BARINADE_SOUL] = HintText::Item({
+ //obscure text
+ Text{"an infectuous soul", "", ""},
+ Text{"some parasitic essence", "", ""},
+ }, {
+ //ambiguous text
+ Text{"something fishy", "", ""}
+ }, {
+ //clear text
+ Text("the soul of Barinade", "", "")}
+ );
+
+ hintTable[RHT_PHANTOM_GANON_SOUL] = HintText::Item({
+ //obscure text
+ Text{"a duplicate soul", "", ""},
+ Text{"some illusionary essence", "", ""},
+ }, {
+ //ambiguous text
+ Text{"something spectral", "", ""}
+ }, {
+ //clear text
+ Text{"the soul of Phantom Ganon", "", ""}}
+ );
+
+ hintTable[RHT_VOLVAGIA_SOUL] = HintText::Item({
+ //obscure text
+ Text{"a draconic soul", "", ""},
+ Text{"some magmatic essence", "", ""},
+ }, {
+ //ambiguous text
+ Text{"something hot", "", ""}
+ }, {
+ //clear text
+ Text{"the soul of Volvagia", "", ""}}
+ );
+
+ hintTable[RHT_MORPHA_SOUL] = HintText::Item({
+ //obscure text
+ Text{"an aquatic soul", "", ""},
+ Text{"some liquid essence", "", ""},
+ }, {
+ //ambiguous text
+ Text{"something wet", "", ""}
+ }, {
+ //clear text
+ Text{"the soul of Barinade", "", ""}}
+ );
+
+ hintTable[RHT_BONGO_BONGO_SOUL] = HintText::Item({
+ //obscure text
+ Text{"a shadowy soul", "", ""},
+ Text{"some handy essence", "", ""},
+ }, {
+ //ambiguous text
+ Text{"something dark", "", ""}
+ }, {
+ //clear text
+ Text{"the soul of Bongo Bongo", "", ""}}
+ );
+
+ hintTable[RHT_TWINROVA_SOUL] = HintText::Item({
+ //obscure text
+ Text{"old souls", "", ""},
+ Text{"twin essences", "", ""},
+ }, {
+ //ambiguous text
+ Text{"something spiritual", "", ""}
+ }, {
+ //clear text
+ Text{"the soul of Twinrova", "", ""}}
+ );
+
+ hintTable[RHT_GANON_SOUL] = HintText::Item({
+ //obscure text
+ Text{"an evil soul", "", ""},
+ Text{"some powerful essence", "", ""},
+ }, {
+ //ambiguous text
+ Text{"something strong", "", ""}
+ }, {
+ //clear text
+ Text{"the soul of Ganon", "", ""}}
+ );
+
hintTable[RHT_EPONA] = HintText::Item({
//obscure text
Text{"a horse", /*french*/"un fidèle destrier", /*spanish*/"una yegua"},
diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp
index 6a3c4d744..46d039f9b 100644
--- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp
@@ -829,6 +829,30 @@ void GenerateItemPool() {
ctx->PlaceItemInLocation(RC_KAK_100_GOLD_SKULLTULA_REWARD, RG_HUGE_RUPEE, false, true);
}
+ if (ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS)) {
+ AddItemToMainPool(RG_GOHMA_SOUL);
+ AddItemToMainPool(RG_KING_DODONGO_SOUL);
+ AddItemToMainPool(RG_BARINADE_SOUL);
+ AddItemToMainPool(RG_PHANTOM_GANON_SOUL);
+ AddItemToMainPool(RG_VOLVAGIA_SOUL);
+ AddItemToMainPool(RG_MORPHA_SOUL);
+ AddItemToMainPool(RG_BONGO_BONGO_SOUL);
+ AddItemToMainPool(RG_TWINROVA_SOUL);
+
+ ctx->possibleIceTrapModels.push_back(RG_GOHMA_SOUL);
+ ctx->possibleIceTrapModels.push_back(RG_KING_DODONGO_SOUL);
+ ctx->possibleIceTrapModels.push_back(RG_BARINADE_SOUL);
+ ctx->possibleIceTrapModels.push_back(RG_PHANTOM_GANON_SOUL);
+ ctx->possibleIceTrapModels.push_back(RG_VOLVAGIA_SOUL);
+ ctx->possibleIceTrapModels.push_back(RG_MORPHA_SOUL);
+ ctx->possibleIceTrapModels.push_back(RG_BONGO_BONGO_SOUL);
+ ctx->possibleIceTrapModels.push_back(RG_TWINROVA_SOUL);
+ if (ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS).Is(RO_BOSS_SOULS_ON_PLUS_GANON)) {
+ AddItemToMainPool(RG_GANON_SOUL);
+ ctx->possibleIceTrapModels.push_back(RG_GANON_SOUL);
+ }
+ }
+
if (ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC)) {
AddItemToMainPool(RG_PROGRESSIVE_BOMBCHUS, 5);
} else {
diff --git a/soh/soh/Enhancements/randomizer/3drando/keys.hpp b/soh/soh/Enhancements/randomizer/3drando/keys.hpp
new file mode 100644
index 000000000..e69de29bb
diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp
index fd0fbe6f0..c1bc935a7 100644
--- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp
@@ -254,9 +254,9 @@ void AreaTable_Init_DekuTree() {
{
// Events
EventAccess(&DekuTreeClear, { [] {
- return DekuTreeClear ||
+ return DekuTreeClear || (HasBossSoul(RG_GOHMA_SOUL) &&
(CanJumpslash && (Nuts || CanUse(RG_FAIRY_SLINGSHOT) || CanUse(RG_FAIRY_BOW) ||
- HookshotOrBoomerang));
+ HookshotOrBoomerang)));
}}),
},
{
diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp
index ed9502b77..b758be53e 100644
--- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp
@@ -294,10 +294,10 @@ void AreaTable_Init_DodongosCavern() {
// Events
EventAccess(&DodongosCavernClear,
{ [] {
- return DodongosCavernClear ||
+ return DodongosCavernClear || (HasBossSoul(RG_KING_DODONGO_SOUL) &&
(Here(RR_DODONGOS_CAVERN_BOSS_ROOM,
[] { return HasExplosives || (CanUse(RG_MEGATON_HAMMER) && randoCtx->GetTrickOption(RT_DC_HAMMER_FLOOR)); }) &&
- (Bombs || GoronBracelet) && CanJumpslash); /*todo add chu kill to tricks*/
+ (Bombs || GoronBracelet) && CanJumpslash)); /*todo add chu kill to tricks*/
}}),
},
{
diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp
index 9b43ecff4..df3ddbbf0 100644
--- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp
@@ -410,7 +410,7 @@ void AreaTable_Init_FireTemple() {
{
// Events
EventAccess(&FireTempleClear,
- { [] { return FireTempleClear || (FireTimer >= 64 && CanUse(RG_MEGATON_HAMMER)); }}),
+ { [] { return FireTempleClear || (HasBossSoul(RG_VOLVAGIA_SOUL) && (FireTimer >= 64 && CanUse(RG_MEGATON_HAMMER))); }}),
},
{
// Locations
diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp
index 1f542e0e9..285f759dc 100644
--- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp
@@ -421,8 +421,8 @@ void AreaTable_Init_ForestTemple() {
{
// Events
EventAccess(&ForestTempleClear, { [] {
- return ForestTempleClear || ((CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) &&
- (CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT)));
+ return ForestTempleClear || (HasBossSoul(RG_PHANTOM_GANON_SOUL) && ((CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) &&
+ (CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT))));
} }),
},
{
diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp
index 3538b567f..52c4b378b 100644
--- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp
@@ -117,7 +117,7 @@ void AreaTable_Init_GanonsCastle() {
//Locations
LocationAccess(RC_GANONS_TOWER_BOSS_KEY_CHEST, {[]{return CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD);}}),
LocationAccess(RC_GANONDORF_HINT, {[]{return BossKeyGanonsCastle && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD));}}),
- LocationAccess(RC_GANON, {[]{return BossKeyGanonsCastle && CanUse(RG_LIGHT_ARROWS) && CanUse(RG_MASTER_SWORD);}}),
+ LocationAccess(RC_GANON, {[]{return HasBossSoul(RG_GANON_SOUL) && BossKeyGanonsCastle && CanUse(RG_LIGHT_ARROWS) && CanUse(RG_MASTER_SWORD);}}),
}, {});
/*---------------------------
diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp
index 4ddcbf58f..32bba0660 100644
--- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp
@@ -235,7 +235,7 @@ void AreaTable_Init_JabuJabusBelly() {
{
// Events //todo: add pot kill trick
EventAccess(&JabuJabusBellyClear,
- { [] { return JabuJabusBellyClear || (CanUse(RG_BOOMERANG) && CanJumpslash); } }),
+ { [] { return JabuJabusBellyClear || (HasBossSoul(RG_BARINADE_SOUL) && (CanUse(RG_BOOMERANG) && CanJumpslash)); } }),
},
{
// Locations
diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp
index 5b935fe5e..addde6403 100644
--- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp
@@ -195,10 +195,10 @@ void AreaTable_Init_ShadowTemple() {
{
// Events
EventAccess(&ShadowTempleClear, { [] {
- return ShadowTempleClear ||
+ return ShadowTempleClear || (HasBossSoul(RG_BONGO_BONGO_SOUL) &&
((CanUse(RG_LENS_OF_TRUTH) || randoCtx->GetTrickOption(RT_LENS_BONGO)) &&
(CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)) &&
- (CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || randoCtx->GetTrickOption(RT_SHADOW_BONGO)));
+ (CanUse(RG_HOOKSHOT) || CanUse(RG_FAIRY_BOW) || CanUse(RG_FAIRY_SLINGSHOT) || randoCtx->GetTrickOption(RT_SHADOW_BONGO))));
} }),
},
{
diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp
index c5ab8348f..35efc3135 100644
--- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp
@@ -259,8 +259,8 @@ void AreaTable_Init_SpiritTemple() {
{
// Events
EventAccess(&SpiritTempleClear, { [] {
- return SpiritTempleClear || (CanUse(RG_MIRROR_SHIELD) &&
- (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)));
+ return SpiritTempleClear || (HasBossSoul(RG_TWINROVA_SOUL) && (CanUse(RG_MIRROR_SHIELD) &&
+ (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD))));
} }),
},
{
diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp
index 8b50289e1..75255a4d4 100644
--- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp
@@ -319,8 +319,8 @@ void AreaTable_Init_WaterTemple() {
{
// Events
EventAccess(&WaterTempleClear, { [] {
- return WaterTempleClear ||
- (CanUse(RG_HOOKSHOT) && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD)));
+ return WaterTempleClear || (HasBossSoul(RG_MORPHA_SOUL) &&
+ (CanUse(RG_HOOKSHOT) && (CanUse(RG_KOKIRI_SWORD) || CanUse(RG_MASTER_SWORD) || CanUse(RG_BIGGORON_SWORD))));
} }),
},
{
diff --git a/soh/soh/Enhancements/randomizer/3drando/logic.cpp b/soh/soh/Enhancements/randomizer/3drando/logic.cpp
index 5e16727b6..3376b1e80 100644
--- a/soh/soh/Enhancements/randomizer/3drando/logic.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/logic.cpp
@@ -315,6 +315,16 @@ namespace Logic {
uint8_t Age = 0;
bool CanCompleteTriforce = false;
+ bool CanSummonGohma = false;
+ bool CanSummonKingDodongo = false;
+ bool CanSummonBarinade = false;
+ bool CanSummonPhantomGanon = false;
+ bool CanSummonVolvagia = false;
+ bool CanSummonMorpha = false;
+ bool CanSummonBongoBongo = false;
+ bool CanSummonTwinrova = false;
+ bool CanSummonGanon = false;
+
//Events
bool ShowedMidoSwordAndShield = false;
bool CarpenterRescue = false;
@@ -466,6 +476,35 @@ namespace Logic {
(age == HasProjectileAge::Either && (Slingshot || Boomerang || Hookshot || Bow));
}
+ bool HasBossSoul(RandomizerGet itemName) {
+ auto ctx = Rando::Context::GetInstance();
+ if (!ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS)) {
+ return true;
+ }
+ switch(itemName) {
+ case RG_GOHMA_SOUL:
+ return CanSummonGohma; break;
+ case RG_KING_DODONGO_SOUL:
+ return CanSummonKingDodongo; break;
+ case RG_BARINADE_SOUL:
+ return CanSummonBarinade; break;
+ case RG_PHANTOM_GANON_SOUL:
+ return CanSummonPhantomGanon; break;
+ case RG_VOLVAGIA_SOUL:
+ return CanSummonVolvagia; break;
+ case RG_MORPHA_SOUL:
+ return CanSummonMorpha; break;
+ case RG_BONGO_BONGO_SOUL:
+ return CanSummonBongoBongo; break;
+ case RG_TWINROVA_SOUL:
+ return CanSummonTwinrova; break;
+ case RG_GANON_SOUL:
+ return ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS).Is(RO_BOSS_SOULS_ON_PLUS_GANON) ? CanSummonGanon : true;
+ break;
+ default: break;
+ }
+ }
+
uint8_t GetDifficultyValueFromString(Rando::Option& glitchOption) {
return 0;
}
@@ -892,6 +931,17 @@ namespace Logic {
//Triforce Pieces
TriforcePieces = 0;
+ //Boss Souls
+ CanSummonGohma = false;
+ CanSummonKingDodongo = false;
+ CanSummonBarinade = false;
+ CanSummonPhantomGanon = false;
+ CanSummonVolvagia = false;
+ CanSummonMorpha = false;
+ CanSummonBongoBongo = false;
+ CanSummonTwinrova = false;
+ CanSummonGanon = false;
+
//Drops and Bottle Contents Access
DekuNutDrop = false;
NutPot = false;
diff --git a/soh/soh/Enhancements/randomizer/3drando/logic.hpp b/soh/soh/Enhancements/randomizer/3drando/logic.hpp
index ad7639732..4452b3715 100644
--- a/soh/soh/Enhancements/randomizer/3drando/logic.hpp
+++ b/soh/soh/Enhancements/randomizer/3drando/logic.hpp
@@ -307,6 +307,16 @@ extern bool LinksCow;
extern uint8_t Age;
extern bool CanCompleteTriforce;
+extern bool CanSummonGohma;
+extern bool CanSummonKingDodongo;
+extern bool CanSummonBarinade;
+extern bool CanSummonPhantomGanon;
+extern bool CanSummonVolvagia;
+extern bool CanSummonMorpha;
+extern bool CanSummonBongoBongo;
+extern bool CanSummonTwinrova;
+extern bool CanSummonGanon;
+
// Events
extern bool ShowedMidoSwordAndShield;
extern bool CarpenterRescue;
@@ -371,6 +381,7 @@ void UpdateHelpers();
bool CanPlay(bool song);
bool CanUse(RandomizerGet itemName);
bool HasProjectile(HasProjectileAge age);
+bool HasBossSoul(RandomizerGet itemName);
bool SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmount);
bool SmallKeys(RandomizerRegion dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched);
bool CanDoGlitch(GlitchType glitch);
diff --git a/soh/soh/Enhancements/randomizer/3drando/shops.cpp b/soh/soh/Enhancements/randomizer/3drando/shops.cpp
index cd2c8004d..8e2206966 100644
--- a/soh/soh/Enhancements/randomizer/3drando/shops.cpp
+++ b/soh/soh/Enhancements/randomizer/3drando/shops.cpp
@@ -10,7 +10,7 @@
std::vector NonShopItems = {};
-static std::array, 0xE1> trickNameTable; // Table of trick names for ice traps
+static std::array, 0xF0> trickNameTable; // Table of trick names for ice traps
bool initTrickNames = false; //Indicates if trick ice trap names have been initialized yet
//Set vanilla shop item locations before potentially shuffling
@@ -703,6 +703,42 @@ void InitTrickNames() {
Text{"Piece of Cheese", "Morceau de Fromage", "Piece of Cheese"},
Text{"Triforce Shard", "Éclat de Triforce", "Triforce Shard"},
Text{"Shiny Rock", "Caiiloux Brillant", "Shiny Rock"}};
+ trickNameTable[RG_GOHMA_SOUL] = {
+ Text{"Spider Sense", "", ""},
+ Text{"Deku Spirit", "", ""},
+ Text("Ghost of Ghoma", "", "")};
+ trickNameTable[RG_KING_DODONGO_SOUL] = {
+ Text{"Lizard Soul", "", ""},
+ Text{"Regal Remains", "", ""},
+ Text{"Dodongo's Core", "", ""}};
+ trickNameTable[RG_BARINADE_SOUL] = {
+ Text{"Parasitic Poltergeist", "", ""},
+ Text{"Jabu Insides", "", ""},
+ Text{"Barinade Bacteria", "", ""}};
+ trickNameTable[RG_PHANTOM_GANON_SOUL] = {
+ Text{"Bigger Poe", "", ""},
+ Text{"Sacred Forest Pine Tree", "", ""},
+ Text{"Ganon's Phantom", "", ""}};
+ trickNameTable[RG_VOLVAGIA_SOUL] = {
+ Text{"Dragon Roast", "", ""},
+ Text{"Hot n' Ready", "", ""},
+ Text{"Volvagia's Vitality", "", ""}};
+ trickNameTable[RG_MORPHA_SOUL] = {
+ Text{"Dihydrogen Monoxide", "", ""},
+ Text{"Morpha Molecules", "", ""},
+ Text{"Wet Stuff", "", ""}};
+ trickNameTable[RG_BONGO_BONGO_SOUL] = {
+ Text{"Shadow Soul", "", ""},
+ Text{"Dark Essence", "", ""},
+ Text{"Bongo Bongo's Bongo", "", ""}};
+ trickNameTable[RG_TWINROVA_SOUL] = {
+ Text{"Sandy Ashes", "", ""},
+ Text{"Spiritual Spirit", "", ""},
+ Text{"Twin Rovers", "", ""}};
+ trickNameTable[RG_GANON_SOUL] = {
+ Text{"Pure Evil", "", ""},
+ Text{"Ganon's Ghost", "", ""},
+ Text{"Pork", "", ""}};
/*
//Names for individual upgrades, in case progressive names are replaced
diff --git a/soh/soh/Enhancements/randomizer/draw.cpp b/soh/soh/Enhancements/randomizer/draw.cpp
index 950af1634..6c6a4fd55 100644
--- a/soh/soh/Enhancements/randomizer/draw.cpp
+++ b/soh/soh/Enhancements/randomizer/draw.cpp
@@ -10,6 +10,7 @@
#include "objects/object_gi_key/object_gi_key.h"
#include "objects/object_gi_bosskey/object_gi_bosskey.h"
#include "objects/object_gi_hearts/object_gi_hearts.h"
+#include "objects/object_gi_fire/object_gi_fire.h"
#include "objects/object_toki_objects/object_toki_objects.h"
#include "objects/gameplay_field_keep/gameplay_field_keep.h"
#include "soh_assets.h"
@@ -277,3 +278,52 @@ extern "C" void Randomizer_DrawTriforcePieceGI(PlayState* play, GetItemEntry get
}
CLOSE_DISPS(play->state.gfxCtx);
}
+
+extern "C" void Randomizer_DrawBossSoul(PlayState* play, GetItemEntry* getItemEntry) {
+ s16 slot = getItemEntry->getItemId - RG_GOHMA_SOUL;
+ s16 flameColors[9][3] = {
+ { 0, 255, 0 }, // Gohma
+ { 255, 0, 100 }, // King Dodongo
+ { 50, 255, 255}, // Barinade
+ { 4, 195, 46 }, // Phantom Ganon
+ { 237, 95, 95 }, // Volvagia
+ { 85, 180, 223 }, // Morpha
+ { 126, 16, 177 }, // Bongo Bongo
+ { 222, 158, 47 }, // Twinrova
+ { 80, 80, 80 }, // Ganon/Dorf
+ };
+ OPEN_DISPS(play->state.gfxCtx);
+
+ Gfx_SetupDL_25Xlu(play->state.gfxCtx);
+ gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
+ G_MTX_MODELVIEW | G_MTX_LOAD);
+ if (slot == 8) { // For Ganon only...
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 0, 0, 255);
+ } else {
+ gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 255);
+ }
+ gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gBossSoulSkullDL);
+
+ if (slot >= 0) {
+ Gfx_SetupDL_25Xlu(play->state.gfxCtx);
+ gSPSegment(POLY_XLU_DISP++, 8, (uintptr_t)Gfx_TwoTexScroll(
+ play->state.gfxCtx, 0, 0 * (play->state.frames * 0),
+ 0 * (play->state.frames * 0), 16, 32, 1, 1 * (play->state.frames * 1),
+ -1 * (play->state.frames * 8), 16, 32
+ ));
+ Matrix_Push();
+ Matrix_Translate(0.0f, -70.0f, 0.0f, MTXMODE_APPLY);
+ Matrix_Scale(5.0f, 5.0f, 5.0f, MTXMODE_APPLY);
+ Matrix_ReplaceRotation(&play->billboardMtxF);
+ gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__),
+ G_MTX_MODELVIEW | G_MTX_LOAD);
+ gDPSetGrayscaleColor(POLY_XLU_DISP++, flameColors[slot][0], flameColors[slot][1], flameColors[slot][2], 255);
+ gSPGrayscale(POLY_XLU_DISP++, true);
+ gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gGiBlueFireFlameDL);
+ gSPGrayscale(POLY_XLU_DISP++, false);
+ Matrix_Pop();
+ }
+
+ CLOSE_DISPS(play->state.gfxCtx);
+
+}
diff --git a/soh/soh/Enhancements/randomizer/draw.h b/soh/soh/Enhancements/randomizer/draw.h
index 2ec521766..dcf146c28 100644
--- a/soh/soh/Enhancements/randomizer/draw.h
+++ b/soh/soh/Enhancements/randomizer/draw.h
@@ -12,6 +12,7 @@ extern "C" {
void Randomizer_DrawSmallKey(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawKeyRing(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawBossKey(PlayState* play, GetItemEntry* getItemEntry);
+void Randomizer_DrawBossSoul(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawDoubleDefense(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawMasterSword(PlayState* play, GetItemEntry* getItemEntry);
void Randomizer_DrawTriforcePiece(PlayState* play, GetItemEntry getItemEntry);
diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp
index c7df99e04..e2311cdf7 100644
--- a/soh/soh/Enhancements/randomizer/item_list.cpp
+++ b/soh/soh/Enhancements/randomizer/item_list.cpp
@@ -94,26 +94,26 @@ void Rando::StaticData::InitItemTable() {
itemTable[RG_REQUIEM_OF_SPIRIT] = Item(RG_REQUIEM_OF_SPIRIT, Text{ "Requiem of Spirit", "Requiem des Esprits", "Requiem des Geistes" }, ITEMTYPE_SONG, 0xBE, true, &Logic::RequiemOfSpirit, RHT_REQUIEM_OF_SPIRIT, ITEM_SONG_REQUIEM, OBJECT_GI_MELODY, GID_SONG_REQUIEM, 0x76, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE);
itemTable[RG_PRELUDE_OF_LIGHT] = Item(RG_PRELUDE_OF_LIGHT, Text{ "Prelude of Light", "Prélude de la Lumière", "Präludium des Lichts" }, ITEMTYPE_SONG, 0xC0, true, &Logic::PreludeOfLight, RHT_PRELUDE_OF_LIGHT, ITEM_SONG_PRELUDE, OBJECT_GI_MELODY, GID_SONG_PRELUDE, 0x78, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE);
// Maps and Compasses
- itemTable[RG_DEKU_TREE_MAP] = Item(RG_DEKU_TREE_MAP, Text{ "Great Deku Tree Map", "Carte de l'Arbre Mojo", "Karte des Deku-Baums" }, ITEMTYPE_MAP, 0xA5, false, &Logic::noVariable, RHT_DEKU_TREE_MAP, RG_DEKU_TREE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_DODONGOS_CAVERN_MAP] = Item(RG_DODONGOS_CAVERN_MAP, Text{ "Dodongo's Cavern Map", "Carte de la Caverne Dodongo", "Karte der Dodongo-Höhle" }, ITEMTYPE_MAP, 0xA6, false, &Logic::noVariable, RHT_DODONGOS_CAVERN_MAP, RG_DODONGOS_CAVERN_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_JABU_JABUS_BELLY_MAP] = Item(RG_JABU_JABUS_BELLY_MAP, Text{ "Jabu-Jabu's Belly Map", "Carte du Ventre de Jabu-Jabu", "Karte des Jabu-Jabu-Bauchs" }, ITEMTYPE_MAP, 0xA7, false, &Logic::noVariable, RHT_JABU_JABUS_BELLY_MAP, RG_JABU_JABUS_BELLY_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_FOREST_TEMPLE_MAP] = Item(RG_FOREST_TEMPLE_MAP, Text{ "Forest Temple Map", "Carte du Temple de la Forêt", "Waldtempel Karte" }, ITEMTYPE_MAP, 0xA8, false, &Logic::noVariable, RHT_FOREST_TEMPLE_MAP, RG_FOREST_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_FIRE_TEMPLE_MAP] = Item(RG_FIRE_TEMPLE_MAP, Text{ "Fire Temple Map", "Carte due Temple de Feu", "Feuertempel Karte" }, ITEMTYPE_MAP, 0xA9, false, &Logic::noVariable, RHT_FIRE_TEMPLE_MAP, RG_FIRE_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_WATER_TEMPLE_MAP] = Item(RG_WATER_TEMPLE_MAP, Text{ "Water Temple Map", "Carte du Temple de l'Eau", "Wassertempel-Karte" }, ITEMTYPE_MAP, 0xAA, false, &Logic::noVariable, RHT_WATER_TEMPLE_MAP, RG_WATER_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_SPIRIT_TEMPLE_MAP] = Item(RG_SPIRIT_TEMPLE_MAP, Text{ "Spirit Temple Map", "Carte due Temple de l'Esprit", "Geistertempel Karte" }, ITEMTYPE_MAP, 0xAB, false, &Logic::noVariable, RHT_SPIRIT_TEMPLE_MAP, RG_SPIRIT_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_SHADOW_TEMPLE_MAP] = Item(RG_SHADOW_TEMPLE_MAP, Text{ "Shadow Temple Map", "Carte du Temple de l'Ombre", "Karte des Schattentempels" }, ITEMTYPE_MAP, 0xAC, false, &Logic::noVariable, RHT_SHADOW_TEMPLE_MAP, RG_SHADOW_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_BOTTOM_OF_THE_WELL_MAP] = Item(RG_BOTTOM_OF_THE_WELL_MAP, Text{ "Bottom of the Well Map", "Carte du Puits", "Boden des Brunnens Karte" }, ITEMTYPE_MAP, 0xAD, false, &Logic::noVariable, RHT_BOTTOM_OF_THE_WELL_MAP, RG_BOTTOM_OF_THE_WELL_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_ICE_CAVERN_MAP] = Item(RG_ICE_CAVERN_MAP, Text{ "Ice Cavern Map", "Carte de la Caverne Polaire", "Eishöhle Karte" }, ITEMTYPE_MAP, 0xAE, false, &Logic::noVariable, RHT_ICE_CAVERN_MAP, RG_ICE_CAVERN_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_DEKU_TREE_COMPASS] = Item(RG_DEKU_TREE_COMPASS, Text{ "Great Deku Tree Compass", "Boussole de l'Arbre Mojo", "Kompass des Deku-Baums" }, ITEMTYPE_COMPASS, 0x9B, false, &Logic::noVariable, RHT_DEKU_TREE_COMPASS, RG_DEKU_TREE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_DODONGOS_CAVERN_COMPASS] = Item(RG_DODONGOS_CAVERN_COMPASS, Text{ "Dodongo's Cavern Compass", "Boussole de la Caverne Dodongo", "Kompass der Dodongo-Höhle" }, ITEMTYPE_COMPASS, 0x9C, false, &Logic::noVariable, RHT_DODONGOS_CAVERN_COMPASS,RG_DODONGOS_CAVERN_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_JABU_JABUS_BELLY_COMPASS] = Item(RG_JABU_JABUS_BELLY_COMPASS, Text{ "Jabu-Jabu's Belly Compass", "Boussole du Ventre de Jabu-Jabu", "Kompass des Jabu-Jabu-Bauchs" }, ITEMTYPE_COMPASS, 0x9D, false, &Logic::noVariable, RHT_JABU_JABUS_BELLY_COMPASS,RG_JABU_JABUS_BELLY_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_FOREST_TEMPLE_COMPASS] = Item(RG_FOREST_TEMPLE_COMPASS, Text{ "Forest Temple Compass", "Boussole du Temple de la Forêt", "Waldtempel-Kompass" }, ITEMTYPE_COMPASS, 0x9E, false, &Logic::noVariable, RHT_FOREST_TEMPLE_COMPASS, RG_FOREST_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_FIRE_TEMPLE_COMPASS] = Item(RG_FIRE_TEMPLE_COMPASS, Text{ "Fire Temple Compass", "Boussole du Temple du Feu", "Feuertempel-Kompass" }, ITEMTYPE_COMPASS, 0x9F, false, &Logic::noVariable, RHT_FIRE_TEMPLE_COMPASS, RG_FIRE_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_WATER_TEMPLE_COMPASS] = Item(RG_WATER_TEMPLE_COMPASS, Text{ "Water Temple Compass", "Boussole du Temple de l'Eau", "Wassertempel-Kompass" }, ITEMTYPE_COMPASS, 0xA0, false, &Logic::noVariable, RHT_WATER_TEMPLE_COMPASS, RG_WATER_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_SPIRIT_TEMPLE_COMPASS] = Item(RG_SPIRIT_TEMPLE_COMPASS, Text{ "Spirit Temple Compass", "Boussole due Temple de l'Esprit", "Geistiger Tempelkompass" }, ITEMTYPE_COMPASS, 0xA1, false, &Logic::noVariable, RHT_SPIRIT_TEMPLE_COMPASS, RG_SPIRIT_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_SHADOW_TEMPLE_COMPASS] = Item(RG_SHADOW_TEMPLE_COMPASS, Text{ "Shadow Temple Compass", "Boussole du Temple de l'Ombre", "Kompass des Schattentempels" }, ITEMTYPE_COMPASS, 0xA2, false, &Logic::noVariable, RHT_SHADOW_TEMPLE_COMPASS, RG_SHADOW_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_BOTTOM_OF_THE_WELL_COMPASS] = Item(RG_BOTTOM_OF_THE_WELL_COMPASS, Text{ "Bottom of the Well Compass", "Boussole du Puits", "Boden des Brunnenkompasses" }, ITEMTYPE_COMPASS, 0xA3, false, &Logic::noVariable, RHT_BOTTOM_OF_THE_WELL_COMPASS,RG_BOTTOM_OF_THE_WELL_COMPASS,OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
- itemTable[RG_ICE_CAVERN_COMPASS] = Item(RG_ICE_CAVERN_COMPASS, Text{ "Ice Cavern Compass", "Boussole de la Caverne Polaire", "Eishöhlenkompass" }, ITEMTYPE_COMPASS, 0xA4, false, &Logic::noVariable, RHT_ICE_CAVERN_COMPASS, RG_ICE_CAVERN_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_DEKU_TREE_MAP] = Item(RG_DEKU_TREE_MAP, Text{ "Great Deku Tree Map", "Carte de l'Arbre Mojo", "Karte des Deku-Baums" }, ITEMTYPE_MAP, 0xA5, false, &Logic::noVariable, RHT_DEKU_TREE_MAP, RG_DEKU_TREE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_DODONGOS_CAVERN_MAP] = Item(RG_DODONGOS_CAVERN_MAP, Text{ "Dodongo's Cavern Map", "Carte de la Caverne Dodongo", "Karte der Dodongo-Höhle" }, ITEMTYPE_MAP, 0xA6, false, &Logic::noVariable, RHT_DODONGOS_CAVERN_MAP, RG_DODONGOS_CAVERN_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_JABU_JABUS_BELLY_MAP] = Item(RG_JABU_JABUS_BELLY_MAP, Text{ "Jabu-Jabu's Belly Map", "Carte du Ventre de Jabu-Jabu", "Karte des Jabu-Jabu-Bauchs" }, ITEMTYPE_MAP, 0xA7, false, &Logic::noVariable, RHT_JABU_JABUS_BELLY_MAP, RG_JABU_JABUS_BELLY_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_FOREST_TEMPLE_MAP] = Item(RG_FOREST_TEMPLE_MAP, Text{ "Forest Temple Map", "Carte du Temple de la Forêt", "Waldtempel Karte" }, ITEMTYPE_MAP, 0xA8, false, &Logic::noVariable, RHT_FOREST_TEMPLE_MAP, RG_FOREST_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_FIRE_TEMPLE_MAP] = Item(RG_FIRE_TEMPLE_MAP, Text{ "Fire Temple Map", "Carte due Temple de Feu", "Feuertempel Karte" }, ITEMTYPE_MAP, 0xA9, false, &Logic::noVariable, RHT_FIRE_TEMPLE_MAP, RG_FIRE_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_WATER_TEMPLE_MAP] = Item(RG_WATER_TEMPLE_MAP, Text{ "Water Temple Map", "Carte du Temple de l'Eau", "Wassertempel-Karte" }, ITEMTYPE_MAP, 0xAA, false, &Logic::noVariable, RHT_WATER_TEMPLE_MAP, RG_WATER_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_SPIRIT_TEMPLE_MAP] = Item(RG_SPIRIT_TEMPLE_MAP, Text{ "Spirit Temple Map", "Carte due Temple de l'Esprit", "Geistertempel Karte" }, ITEMTYPE_MAP, 0xAB, false, &Logic::noVariable, RHT_SPIRIT_TEMPLE_MAP, RG_SPIRIT_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_SHADOW_TEMPLE_MAP] = Item(RG_SHADOW_TEMPLE_MAP, Text{ "Shadow Temple Map", "Carte du Temple de l'Ombre", "Karte des Schattentempels" }, ITEMTYPE_MAP, 0xAC, false, &Logic::noVariable, RHT_SHADOW_TEMPLE_MAP, RG_SHADOW_TEMPLE_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_BOTTOM_OF_THE_WELL_MAP] = Item(RG_BOTTOM_OF_THE_WELL_MAP, Text{ "Bottom of the Well Map", "Carte du Puits", "Boden des Brunnens Karte" }, ITEMTYPE_MAP, 0xAD, false, &Logic::noVariable, RHT_BOTTOM_OF_THE_WELL_MAP, RG_BOTTOM_OF_THE_WELL_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_ICE_CAVERN_MAP] = Item(RG_ICE_CAVERN_MAP, Text{ "Ice Cavern Map", "Carte de la Caverne Polaire", "Eishöhle Karte" }, ITEMTYPE_MAP, 0xAE, false, &Logic::noVariable, RHT_ICE_CAVERN_MAP, RG_ICE_CAVERN_MAP, OBJECT_GI_MAP, GID_DUNGEON_MAP, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_DEKU_TREE_COMPASS] = Item(RG_DEKU_TREE_COMPASS, Text{ "Great Deku Tree Compass", "Boussole de l'Arbre Mojo", "Kompass des Deku-Baums" }, ITEMTYPE_COMPASS, 0x9B, false, &Logic::noVariable, RHT_DEKU_TREE_COMPASS, RG_DEKU_TREE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_DUNGEON_MAP, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_DODONGOS_CAVERN_COMPASS] = Item(RG_DODONGOS_CAVERN_COMPASS, Text{ "Dodongo's Cavern Compass", "Boussole de la Caverne Dodongo", "Kompass der Dodongo-Höhle" }, ITEMTYPE_COMPASS, 0x9C, false, &Logic::noVariable, RHT_DODONGOS_CAVERN_COMPASS,RG_DODONGOS_CAVERN_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_COMPASS, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_JABU_JABUS_BELLY_COMPASS] = Item(RG_JABU_JABUS_BELLY_COMPASS, Text{ "Jabu-Jabu's Belly Compass", "Boussole du Ventre de Jabu-Jabu", "Kompass des Jabu-Jabu-Bauchs" }, ITEMTYPE_COMPASS, 0x9D, false, &Logic::noVariable, RHT_JABU_JABUS_BELLY_COMPASS,RG_JABU_JABUS_BELLY_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_COMPASS, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_FOREST_TEMPLE_COMPASS] = Item(RG_FOREST_TEMPLE_COMPASS, Text{ "Forest Temple Compass", "Boussole du Temple de la Forêt", "Waldtempel-Kompass" }, ITEMTYPE_COMPASS, 0x9E, false, &Logic::noVariable, RHT_FOREST_TEMPLE_COMPASS, RG_FOREST_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_COMPASS, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_FIRE_TEMPLE_COMPASS] = Item(RG_FIRE_TEMPLE_COMPASS, Text{ "Fire Temple Compass", "Boussole du Temple du Feu", "Feuertempel-Kompass" }, ITEMTYPE_COMPASS, 0x9F, false, &Logic::noVariable, RHT_FIRE_TEMPLE_COMPASS, RG_FIRE_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_COMPASS, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_WATER_TEMPLE_COMPASS] = Item(RG_WATER_TEMPLE_COMPASS, Text{ "Water Temple Compass", "Boussole du Temple de l'Eau", "Wassertempel-Kompass" }, ITEMTYPE_COMPASS, 0xA0, false, &Logic::noVariable, RHT_WATER_TEMPLE_COMPASS, RG_WATER_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_COMPASS, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_SPIRIT_TEMPLE_COMPASS] = Item(RG_SPIRIT_TEMPLE_COMPASS, Text{ "Spirit Temple Compass", "Boussole due Temple de l'Esprit", "Geistiger Tempelkompass" }, ITEMTYPE_COMPASS, 0xA1, false, &Logic::noVariable, RHT_SPIRIT_TEMPLE_COMPASS, RG_SPIRIT_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_COMPASS, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_SHADOW_TEMPLE_COMPASS] = Item(RG_SHADOW_TEMPLE_COMPASS, Text{ "Shadow Temple Compass", "Boussole du Temple de l'Ombre", "Kompass des Schattentempels" }, ITEMTYPE_COMPASS, 0xA2, false, &Logic::noVariable, RHT_SHADOW_TEMPLE_COMPASS, RG_SHADOW_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_COMPASS, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_BOTTOM_OF_THE_WELL_COMPASS] = Item(RG_BOTTOM_OF_THE_WELL_COMPASS, Text{ "Bottom of the Well Compass", "Boussole du Puits", "Boden des Brunnenkompasses" }, ITEMTYPE_COMPASS, 0xA3, false, &Logic::noVariable, RHT_BOTTOM_OF_THE_WELL_COMPASS,RG_BOTTOM_OF_THE_WELL_COMPASS,OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_COMPASS, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
+ itemTable[RG_ICE_CAVERN_COMPASS] = Item(RG_ICE_CAVERN_COMPASS, Text{ "Ice Cavern Compass", "Boussole de la Caverne Polaire", "Eishöhlenkompass" }, ITEMTYPE_COMPASS, 0xA4, false, &Logic::noVariable, RHT_ICE_CAVERN_COMPASS, RG_ICE_CAVERN_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_ITEM_COMPASS, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER);
// Boss Keys
itemTable[RG_FOREST_TEMPLE_BOSS_KEY] = Item(RG_FOREST_TEMPLE_BOSS_KEY, Text{ "Forest Temple Boss Key", "Clé d'Or du Temple de la Forêt", "Waldtempel-Boss-Schlüssel" }, ITEMTYPE_BOSSKEY, 0x95, true, &Logic::BossKeyForestTemple, RHT_FOREST_TEMPLE_BOSS_KEY, RG_FOREST_TEMPLE_BOSS_KEY, OBJECT_GI_BOSSKEY, GID_KEY_BOSS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_BOSS_KEY,MOD_RANDOMIZER);
itemTable[RG_FOREST_TEMPLE_BOSS_KEY].SetCustomDrawFunc(Randomizer_DrawBossKey);
@@ -240,6 +240,25 @@ void Rando::StaticData::InitItemTable() {
itemTable[RG_BUY_RED_POTION_40] = Item(RG_BUY_RED_POTION_40, Text{ "Buy Red Potion [40]", "Acheter: Potion Rouge [40]", "Rotes Elixier kaufen [40]" }, ITEMTYPE_SHOP, GI_POTION_RED, false, &Logic::noVariable, RHT_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, OBJECT_GI_LIQUID, GID_POTION_RED, 0x43, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_JUNK, MOD_NONE, false, 40);
itemTable[RG_BUY_RED_POTION_50] = Item(RG_BUY_RED_POTION_50, Text{ "Buy Red Potion [50]", "Acheter: Potion Rouge [50]", "Rotes Elixier kaufen [50]" }, ITEMTYPE_SHOP, GI_POTION_RED, false, &Logic::noVariable, RHT_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, OBJECT_GI_LIQUID, GID_POTION_RED, 0x43, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_JUNK, MOD_NONE, false, 50);
// Misc.
+ itemTable[RG_GOHMA_SOUL] = Item(RG_GOHMA_SOUL, Text{ "Gohma's Soul", "", "" }, ITEMTYPE_ITEM, 0xE0, true, &Logic::CanSummonGohma, RHT_GOHMA_SOUL, RG_GOHMA_SOUL, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_GOHMA_SOUL].SetCustomDrawFunc(Randomizer_DrawBossSoul);
+ itemTable[RG_KING_DODONGO_SOUL] = Item(RG_KING_DODONGO_SOUL, Text{ "King Dodongo's Soul", "", "" }, ITEMTYPE_ITEM, 0xE1, true, &Logic::CanSummonKingDodongo,RHT_KING_DODONGO_SOUL, RG_KING_DODONGO_SOUL, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_KING_DODONGO_SOUL].SetCustomDrawFunc(Randomizer_DrawBossSoul);
+ itemTable[RG_BARINADE_SOUL] = Item(RG_BARINADE_SOUL, Text{ "Barinade's Soul", "", "" }, ITEMTYPE_ITEM, 0xE2, true, &Logic::CanSummonBarinade, RHT_BARINADE_SOUL, RG_BARINADE_SOUL, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_BARINADE_SOUL].SetCustomDrawFunc(Randomizer_DrawBossSoul);
+ itemTable[RG_PHANTOM_GANON_SOUL] = Item(RG_PHANTOM_GANON_SOUL, Text{ "Phantom Ganon's Soul", "", "" }, ITEMTYPE_ITEM, 0xE3, true, &Logic::CanSummonPhantomGanon,RHT_PHANTOM_GANON_SOUL, RG_PHANTOM_GANON_SOUL, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_PHANTOM_GANON_SOUL].SetCustomDrawFunc(Randomizer_DrawBossSoul);
+ itemTable[RG_VOLVAGIA_SOUL] = Item(RG_VOLVAGIA_SOUL, Text{ "Volvagia's Soul", "", "" }, ITEMTYPE_ITEM, 0xE4, true, &Logic::CanSummonVolvagia, RHT_VOLVAGIA_SOUL, RG_VOLVAGIA_SOUL, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_VOLVAGIA_SOUL].SetCustomDrawFunc(Randomizer_DrawBossSoul);
+ itemTable[RG_MORPHA_SOUL] = Item(RG_MORPHA_SOUL, Text{ "Morpha's Soul", "", "" }, ITEMTYPE_ITEM, 0xE5, true, &Logic::CanSummonMorpha, RHT_MORPHA_SOUL, RG_MORPHA_SOUL, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_MORPHA_SOUL].SetCustomDrawFunc(Randomizer_DrawBossSoul);
+ itemTable[RG_BONGO_BONGO_SOUL] = Item(RG_BONGO_BONGO_SOUL, Text{ "Bongo Bongo's Soul", "", "" }, ITEMTYPE_ITEM, 0xE6, true, &Logic::CanSummonBongoBongo, RHT_BONGO_BONGO_SOUL, RG_BONGO_BONGO_SOUL, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_BONGO_BONGO_SOUL].SetCustomDrawFunc(Randomizer_DrawBossSoul);
+ itemTable[RG_TWINROVA_SOUL] = Item(RG_TWINROVA_SOUL, Text{ "Twinrova's Soul", "", "" }, ITEMTYPE_ITEM, 0xE7, true, &Logic::CanSummonTwinrova, RHT_TWINROVA_SOUL, RG_TWINROVA_SOUL, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_TWINROVA_SOUL].SetCustomDrawFunc(Randomizer_DrawBossSoul);
+ itemTable[RG_GANON_SOUL] = Item(RG_GANON_SOUL, Text{ "Ganon's Soul", "", "" }, ITEMTYPE_ITEM, 0xE8, true, &Logic::CanSummonGanon, RHT_GANON_SOUL, RG_GANON_SOUL, OBJECT_GI_SUTARU, GID_SKULL_TOKEN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER);
+ itemTable[RG_GANON_SOUL].SetCustomDrawFunc(Randomizer_DrawBossSoul);
+
itemTable[RG_TRIFORCE] = Item(RG_TRIFORCE, Text{ "Triforce", "Triforce", "Triforce" }, ITEMTYPE_EVENT, RG_TRIFORCE, false, &Logic::noVariable, RHT_NONE);
itemTable[RG_HINT] = Item(RG_HINT, Text{ "Hint", "Indice", "Hinweis" }, ITEMTYPE_EVENT, RG_HINT, false, &Logic::noVariable, RHT_NONE);
// Individual stages of progressive items (only here for GetItemEntry purposes, not for use in seed gen)
diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp
index 3ca43436c..11e260cbe 100644
--- a/soh/soh/Enhancements/randomizer/randomizer.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer.cpp
@@ -1695,6 +1695,7 @@ void GenerateRandomizerImgui(std::string seed = "") {
cvarSettings[RSK_SHUFFLE_MAGIC_BEANS] = CVarGetInteger("gRandomizeShuffleBeans", 0);
cvarSettings[RSK_SHUFFLE_MERCHANTS] = CVarGetInteger("gRandomizeShuffleMerchants", RO_SHUFFLE_MERCHANTS_OFF);
cvarSettings[RSK_SHUFFLE_100_GS_REWARD] = CVarGetInteger("gRandomizeShuffle100GSReward", RO_GENERIC_OFF);
+ cvarSettings[RSK_SHUFFLE_BOSS_SOULS] = CVarGetInteger("gRandomizeShuffleBossSouls", RO_BOSS_SOULS_OFF);
cvarSettings[RSK_ENABLE_BOMBCHU_DROPS] = CVarGetInteger("gRandomizeEnableBombchuDrops", 0);
cvarSettings[RSK_BOMBCHUS_IN_LOGIC] = CVarGetInteger("gRandomizeBombchusInLogic", 0);
cvarSettings[RSK_SKIP_CHILD_ZELDA] = CVarGetInteger("gRandomizeSkipChildZelda", 0);
@@ -1926,6 +1927,7 @@ void RandomizerSettingsWindow::DrawElement() {
static const char* randoTokensanity[4] = { "Off", "Dungeons", "Overworld", "All Tokens" };
static const char* randoShuffleScrubs[4] = { "Off", "Affordable", "Expensive", "Random Prices" };
static const char* randoShuffleMerchants[3] = { "Off", "On (no hints)", "On (with hints)" };
+ static const char* randoShuffleBossSouls[3] = { "Off", "On", "On + Ganon"};
// Shuffle Dungeon Items Settings
static const char* randoShuffleMapsAndCompasses[6] = { "Start With", "Vanilla", "Own Dungeon",
@@ -2844,6 +2846,15 @@ void RandomizerSettingsWindow::DrawElement() {
UIWidgets::PaddedSeparator();
+ // Shuffle Boss Souls
+ // Forces players to find a boss's soul before defeating them in their lair.
+ ImGui::Text("%s", ctx->GetOption(RSK_SHUFFLE_BOSS_SOULS).GetName().c_str());
+ UIWidgets::InsertHelpHoverText("Shuffles 8 boss souls (one for each blue warp dungeon). A boss will not appear until you collect its respective soul."
+ "\n\"On + Ganon\" will also hide Ganon and Ganondorf behind a boss soul.");
+ UIWidgets::EnhancementCombobox("gRandomizeShuffleBossSouls", randoShuffleBossSouls, RO_BOSS_SOULS_OFF);
+
+ UIWidgets::PaddedSeparator();
+
ImGui::PopItemWidth();
ImGui::EndChild();
@@ -4725,7 +4736,7 @@ CustomMessage Randomizer::GetGoronMessage(u16 index) {
void Randomizer::CreateCustomMessages() {
// RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED
// with GIMESSAGE(getItemID, itemID, english, german, french).
- const std::array getItemMessages = {{
+ const std::array getItemMessages = {{
GIMESSAGE(RG_GREG_RUPEE, ITEM_MASK_GORON,
"You found %gGreg%w!",
"%gGreg%w! Du hast ihn wirklich gefunden!",
@@ -4959,7 +4970,18 @@ void Randomizer::CreateCustomMessages() {
GIMESSAGE(RG_TYCOON_WALLET, ITEM_WALLET_GIANT,
"You got a %rTycoon's Wallet%w!&It's gigantic! Now you can carry&up to %y999 rupees%w!",
"Du erhältst die %rGoldene&Geldbörse%w! Die größte aller&Geldbörsen! Jetzt kannst Du bis&zu %y999 Rubine%w mit dir führen!",
- "Vous obtenez la %rBourse de Magnat%w!&Elle peut contenir jusqu'à %y999 rubis%w!&C'est gigantesque!")
+ "Vous obtenez la %rBourse de Magnat%w!&Elle peut contenir jusqu'à %y999 rubis%w!&C'est gigantesque!"),
+
+ GIMESSAGE_UNTRANSLATED(RG_GOHMA_SOUL, ITEM_BIG_POE, "You found the soul for %gGohma%w!"),
+ GIMESSAGE_UNTRANSLATED(RG_KING_DODONGO_SOUL, ITEM_BIG_POE, "You found the soul for %rKing&Dodongo%w!"),
+ GIMESSAGE_UNTRANSLATED(RG_BARINADE_SOUL, ITEM_BIG_POE, "You found the soul for %bBarinade%w!"),
+ GIMESSAGE_UNTRANSLATED(RG_PHANTOM_GANON_SOUL, ITEM_BIG_POE, "You found the soul for %gPhantom&Ganon%w!"),
+ GIMESSAGE_UNTRANSLATED(RG_VOLVAGIA_SOUL, ITEM_BIG_POE, "You found the soul for %rVolvagia%w!"),
+ GIMESSAGE_UNTRANSLATED(RG_MORPHA_SOUL, ITEM_BIG_POE, "You found the soul for %bMorpha%w!"),
+ GIMESSAGE_UNTRANSLATED(RG_BONGO_BONGO_SOUL, ITEM_BIG_POE, "You found the soul for %pBongo&Bongo%w!"),
+ GIMESSAGE_UNTRANSLATED(RG_TWINROVA_SOUL, ITEM_BIG_POE, "You found the soul for %yTwinrova%w!"),
+ GIMESSAGE_UNTRANSLATED(RG_GANON_SOUL, ITEM_BIG_POE, "You found the soul for %cGanon%w!"),
+
}};
CreateGetItemMessages(&getItemMessages);
CreateRupeeMessages();
diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h
index 02652a83d..26464522c 100644
--- a/soh/soh/Enhancements/randomizer/randomizerTypes.h
+++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h
@@ -1814,6 +1814,15 @@ typedef enum {
RG_BUY_RED_POTION_50,
RG_TRIFORCE,
RG_TRIFORCE_PIECE,
+ RG_GOHMA_SOUL,
+ RG_KING_DODONGO_SOUL,
+ RG_BARINADE_SOUL,
+ RG_PHANTOM_GANON_SOUL,
+ RG_VOLVAGIA_SOUL,
+ RG_MORPHA_SOUL,
+ RG_BONGO_BONGO_SOUL,
+ RG_TWINROVA_SOUL,
+ RG_GANON_SOUL,
RG_HINT,
RG_TYCOON_WALLET,
RG_FAIRY_OCARINA,
@@ -3018,6 +3027,15 @@ typedef enum {
RHT_DEKU_STICK_CAPACITY_20,
RHT_DEKU_STICK_CAPACITY_30,
RHT_TRIFORCE_PIECE,
+ RHT_GOHMA_SOUL,
+ RHT_KING_DODONGO_SOUL,
+ RHT_BARINADE_SOUL,
+ RHT_PHANTOM_GANON_SOUL,
+ RHT_VOLVAGIA_SOUL,
+ RHT_MORPHA_SOUL,
+ RHT_BONGO_BONGO_SOUL,
+ RHT_TWINROVA_SOUL,
+ RHT_GANON_SOUL,
RHT_EPONA,
// Entrances
RHT_DESERT_COLOSSUS_TO_COLOSSUS_GROTTO,
@@ -3427,6 +3445,7 @@ typedef enum {
RSK_TRIFORCE_HUNT,
RSK_TRIFORCE_HUNT_PIECES_TOTAL,
RSK_TRIFORCE_HUNT_PIECES_REQUIRED,
+ RSK_SHUFFLE_BOSS_SOULS,
RSK_MAX
} RandomizerSettingKey;
@@ -3551,6 +3570,12 @@ typedef enum {
RO_AMMO_DROPS_OFF,
} RandoOptionAmmoDrops;
+typedef enum {
+ RO_BOSS_SOULS_OFF,
+ RO_BOSS_SOULS_ON,
+ RO_BOSS_SOULS_ON_PLUS_GANON,
+} RandoOptionBossSouls;
+
//Any Dungeon Item (start with, vanilla, own dungeon, any dungeon,
//overworld, anywhere)
typedef enum {
diff --git a/soh/soh/Enhancements/randomizer/randomizer_inf.h b/soh/soh/Enhancements/randomizer/randomizer_inf.h
index 33c206b47..d7e0c1dfe 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_inf.h
+++ b/soh/soh/Enhancements/randomizer/randomizer_inf.h
@@ -160,6 +160,16 @@ typedef enum {
RAND_INF_ADULT_FISHING,
RAND_INF_10_BIG_POES,
+ RAND_INF_GOHMA_SOUL,
+ RAND_INF_KING_DODONGO_SOUL,
+ RAND_INF_BARINADE_SOUL,
+ RAND_INF_PHANTOM_GANON_SOUL,
+ RAND_INF_VOLVAGIA_SOUL,
+ RAND_INF_MORPHA_SOUL,
+ RAND_INF_BONGO_BONGO_SOUL,
+ RAND_INF_TWINROVA_SOUL,
+ RAND_INF_GANON_SOUL,
+
// If you add anything to this list, you need to update the size of randomizerInf in z64save.h to be ceil(RAND_INF_MAX / 16)
RAND_INF_MAX,
diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
index f24ab818b..e5e633e74 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
@@ -84,6 +84,20 @@ std::vector triforcePieces = {
ITEM_TRACKER_ITEM(RG_TRIFORCE_PIECE, 0, DrawItem),
};
+std::vector bossSoulItems = {
+ //Hack for right now, just gonna draw souls as bottles/big poes.
+ //Will replace with other macro once we have a custom texture
+ ITEM_TRACKER_ITEM_CUSTOM(RG_GOHMA_SOUL, ITEM_BIG_POE, ITEM_BOTTLE, 0, DrawItem ),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_KING_DODONGO_SOUL, ITEM_BIG_POE, ITEM_BOTTLE, 0, DrawItem ),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_BARINADE_SOUL, ITEM_BIG_POE, ITEM_BOTTLE, 0, DrawItem ),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_PHANTOM_GANON_SOUL, ITEM_BIG_POE, ITEM_BOTTLE, 0, DrawItem ),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_VOLVAGIA_SOUL, ITEM_BIG_POE, ITEM_BOTTLE, 0, DrawItem ),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_MORPHA_SOUL, ITEM_BIG_POE, ITEM_BOTTLE, 0, DrawItem ),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_BONGO_BONGO_SOUL, ITEM_BIG_POE, ITEM_BOTTLE, 0, DrawItem ),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_TWINROVA_SOUL, ITEM_BIG_POE, ITEM_BOTTLE, 0, DrawItem ),
+ ITEM_TRACKER_ITEM_CUSTOM(RG_GANON_SOUL, ITEM_BIG_POE, ITEM_BOTTLE, 0, DrawItem ),
+};
+
std::vector itemTrackerDungeonsWithMapsHorizontal = {
{ SCENE_DEKU_TREE, { ITEM_DUNGEON_MAP, ITEM_COMPASS } },
{ SCENE_DODONGOS_CAVERN, { ITEM_DUNGEON_MAP, ITEM_COMPASS } },
@@ -154,6 +168,18 @@ std::map itemTrackerDungeonShortNames = {
{ SCENE_THIEVES_HIDEOUT, "HIDE" },
};
+std::map itemTrackerBossShortNames = {
+ { RG_GOHMA_SOUL, "GOHMA" },
+ { RG_KING_DODONGO_SOUL, "KD" },
+ { RG_BARINADE_SOUL, "BARI" },
+ { RG_PHANTOM_GANON_SOUL, "PG"},
+ { RG_VOLVAGIA_SOUL, "VOLV"},
+ { RG_MORPHA_SOUL, "MORPH"},
+ { RG_BONGO_BONGO_SOUL, "BONGO"},
+ { RG_TWINROVA_SOUL, "TWIN"},
+ { RG_GANON_SOUL, "GANON"},
+};
+
std::vector dungeonItems = {};
std::unordered_map actualItemTrackerItemMap = {
@@ -609,6 +635,53 @@ void DrawItem(ItemTrackerItem item) {
hasItem = IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT);
itemName = "Triforce Piece";
break;
+ case RG_GOHMA_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_GOHMA_SOUL);
+ itemName = "Gohma's Soul";
+ break;
+ case RG_KING_DODONGO_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_KING_DODONGO_SOUL);
+ itemName = "King Dodongo's Soul";
+ break;
+ case RG_BARINADE_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_BARINADE_SOUL);
+ itemName = "Barinade's Soul";
+ break;
+ case RG_PHANTOM_GANON_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_PHANTOM_GANON_SOUL);
+ itemName = "Phantom Ganon's Soul";
+ break;
+ case RG_VOLVAGIA_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_VOLVAGIA_SOUL);
+ itemName = "Volvagia's Soul";
+ break;
+ case RG_MORPHA_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_MORPHA_SOUL);
+ itemName = "Morpha's Soul";
+ break;
+ case RG_BONGO_BONGO_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_BONGO_BONGO_SOUL);
+ itemName = "Bongo Bongo's Soul";
+ break;
+ case RG_TWINROVA_SOUL:
+ actualItemId = item.id;
+ hasItem = Flags_GetRandomizerInf(RAND_INF_TWINROVA_SOUL);
+ itemName = "Twinrova's Soul";
+ break;
+ case RG_GANON_SOUL:
+ actualItemId = item.id;
+ hasItem = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_BOSS_SOULS) == RO_BOSS_SOULS_ON_PLUS_GANON ?
+ Flags_GetRandomizerInf(RAND_INF_GANON_SOUL) : true;
+
+ itemName = "Ganon's Soul";
+ break;
}
if (GameInteractor::IsSaveLoaded() && (hasItem && item.id != actualItemId && actualItemTrackerItemMap.find(actualItemId) != actualItemTrackerItemMap.end())) {
@@ -621,6 +694,16 @@ void DrawItem(ItemTrackerItem item) {
ImVec2(iconSize, iconSize), ImVec2(0, 0), ImVec2(1, 1));
DrawItemCount(item);
+
+ if (item.id >= RG_GOHMA_SOUL && item.id <= RG_GANON_SOUL) {
+ ImVec2 p = ImGui::GetCursorScreenPos();
+ std::string bossName = itemTrackerBossShortNames[item.id];
+ ImGui::SetCursorScreenPos(ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize(bossName.c_str()).x / 2), p.y - (iconSize + 13)));
+ ImGui::PushStyleColor(ImGuiCol_Text, IM_COL_WHITE);
+ ImGui::Text("%s", bossName.c_str());
+ ImGui::PopStyleColor();
+ }
+
ImGui::EndGroup();
if (itemName == "") {
@@ -956,6 +1039,17 @@ void UpdateVectors() {
mainWindowItems.insert(mainWindowItems.end(), triforcePieces.begin(), triforcePieces.end());
}
+ //If we're adding boss souls to the main window...
+ if (CVarGetInteger("gItemTrackerBossSoulsDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_MAIN_WINDOW) {
+ //...add empty items on the main window to get the souls on their own row. (Too many to sit with Greg/Triforce pieces)
+ while (mainWindowItems.size() % 6) {
+ mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem));
+ }
+
+ //Add boss souls
+ mainWindowItems.insert(mainWindowItems.end(), bossSoulItems.begin(), bossSoulItems.end());
+ }
+
shouldUpdateVectors = false;
}
@@ -1056,6 +1150,12 @@ void ItemTrackerWindow::DrawElement() {
EndFloatingWindows();
}
+ if (CVarGetInteger("gItemTrackerBossSoulsDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_SEPARATE) {
+ BeginFloatingWindows("Boss Soul Tracker");
+ DrawItemsInRows(bossSoulItems);
+ EndFloatingWindows();
+ }
+
if (CVarGetInteger("gItemTrackerNotesDisplayType", SECTION_DISPLAY_HIDDEN) == SECTION_DISPLAY_SEPARATE && CVarGetInteger("gItemTrackerDisplayType", TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_ALWAYS) {
ImGui::SetNextWindowSize(ImVec2(400,300), ImGuiCond_FirstUseEver);
BeginFloatingWindows("Personal Notes", ImGuiWindowFlags_NoFocusOnAppearing);
@@ -1195,6 +1295,10 @@ void ItemTrackerSettingsWindow::DrawElement() {
shouldUpdateVectors = true;
}
+ if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Boss Souls", "gItemTrackerBossSoulsDisplayType", displayTypes, SECTION_DISPLAY_HIDDEN)) {
+ shouldUpdateVectors = true;
+ }
+
if (CVarGetInteger("gItemTrackerDisplayType", TRACKER_DISPLAY_ALWAYS) == TRACKER_DISPLAY_ALWAYS) {
if (UIWidgets::LabeledRightAlignedEnhancementCombobox("Personal notes", "gItemTrackerNotesDisplayType", displayTypes, SECTION_DISPLAY_HIDDEN)) {
shouldUpdateVectors = true;
diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h
index 1fb4e1063..8a0b754a8 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h
+++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h
@@ -24,6 +24,11 @@ bool HasEquipment(ItemTrackerItem);
id, #id, #id "_Faded", data, drawFunc \
}
+#define ITEM_TRACKER_ITEM_CUSTOM(id, name, nameFaded, data, drawFunc)\
+ { \
+ id, #name, #nameFaded "_Faded", data, drawFunc \
+ }
+
typedef struct ItemTrackerDungeon {
uint32_t id;
std::vector items;
diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp
index 12deeba6b..ec4595f01 100644
--- a/soh/soh/Enhancements/randomizer/settings.cpp
+++ b/soh/soh/Enhancements/randomizer/settings.cpp
@@ -106,6 +106,7 @@ void Settings::CreateOptions() {
mOptions[RSK_SHUFFLE_ADULT_TRADE] = Option::Bool("Shuffle Adult Trade");
mOptions[RSK_SHUFFLE_CHEST_MINIGAME] = Option::U8("Shuffle Chest Minigame", {"Off", "On (Separate)", "On (Pack)"});
mOptions[RSK_SHUFFLE_100_GS_REWARD] = Option::Bool("Shuffle 100 GS Reward");
+ mOptions[RSK_SHUFFLE_BOSS_SOULS] = Option::U8("Shuffle Boss Souls", {"Off", "On", "On + Ganon"});
mOptions[RSK_SHUFFLE_MAPANDCOMPASS] = Option::U8("Maps/Compasses", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON);
mOptions[RSK_KEYSANITY] = Option::U8("Small Keys", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON);
mOptions[RSK_GERUDO_KEYS] = Option::U8("Gerudo Fortress Keys", {"Vanilla", "Any Dungeon", "Overworld", "Anywhere"});
@@ -616,6 +617,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHUFFLE_ADULT_TRADE],
&mOptions[RSK_SHUFFLE_CHEST_MINIGAME],
&mOptions[RSK_SHUFFLE_100_GS_REWARD],
+ &mOptions[RSK_SHUFFLE_BOSS_SOULS],
});
mOptionGroups[RSG_SHUFFLE_DUNGEON_ITEMS] = OptionGroup("Shuffle Dungeon Items", {
&mOptions[RSK_SHUFFLE_MAPANDCOMPASS],
@@ -821,6 +823,7 @@ void Settings::CreateOptions() {
{ "Shuffle Settings:Shuffle Frog Song Rupees", RSK_SHUFFLE_FROG_SONG_RUPEES },
{ "Shuffle Settings:Shuffle Merchants", RSK_SHUFFLE_MERCHANTS },
{ "Shuffle Settings:Shuffle 100 GS Reward", RSK_SHUFFLE_100_GS_REWARD },
+ { "Shuffle Settings:Shuffle Boss Souls", RSK_SHUFFLE_BOSS_SOULS },
{ "Start with Deku Shield", RSK_STARTING_DEKU_SHIELD },
{ "Start with Kokiri Sword", RSK_STARTING_KOKIRI_SWORD },
{ "Start with Fairy Ocarina", RSK_STARTING_OCARINA },
@@ -1520,6 +1523,14 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) {
mOptions[index].SetSelectedIndex(RO_AMMO_DROPS_OFF);
}
break;
+ case RSK_SHUFFLE_BOSS_SOULS:
+ if (it.value() == "Off") {
+ mOptions[index].SetSelectedIndex(RO_BOSS_SOULS_OFF);
+ } else if (it.value() == "On") {
+ mOptions[index].SetSelectedIndex(RO_BOSS_SOULS_ON);
+ } else if (it.value() == "On + Ganon") {
+ mOptions[index].SetSelectedIndex(RO_BOSS_SOULS_ON_PLUS_GANON);
+ }
case RSK_STARTING_OCARINA:
if (it.value() == "Off") {
mOptions[index].SetSelectedIndex(RO_STARTING_OCARINA_OFF);
diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c
index ec25d2062..73c8aebd1 100644
--- a/soh/src/code/z_parameter.c
+++ b/soh/src/code/z_parameter.c
@@ -2611,6 +2611,13 @@ u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) {
return Return_Item_Entry(giEntry, RG_NONE);
}
+ if (item >= RG_GOHMA_SOUL && item <= RG_GANON_SOUL) {
+ u8 index = item - RG_GOHMA_SOUL;
+ Flags_SetRandomizerInf(RAND_INF_GOHMA_SOUL + index);
+
+ return Return_Item_Entry(giEntry, RG_NONE);
+ }
+
if (item == RG_PROGRESSIVE_BOMBCHUS) {
if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_NONE) {
INV_CONTENT(ITEM_BOMBCHU) = ITEM_BOMBCHU;
diff --git a/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c b/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c
index ee62b141e..ca0d5d948 100644
--- a/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c
+++ b/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c
@@ -652,6 +652,9 @@ void BossVa_Init(Actor* thisx, PlayState* play2) {
this->actor.colChkInfo.damageTable = sDamageTable;
sPhase2Timer = 0xFFFF;
if (Flags_GetEventChkInf(EVENTCHKINF_BEGAN_BARINA_BATTLE)) {
+ if (Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_SOULS) && !Flags_GetRandomizerInf(RAND_INF_BARINADE_SOUL)) {
+ sCsState = BOSSVA_BATTLE;
+ } else {
sCsState = INTRO_CALL_BARI;
sDoorState = 100;
func_8002DF54(play, &this->actor, 1);
@@ -682,6 +685,7 @@ void BossVa_Init(Actor* thisx, PlayState* play2) {
}
sCameraAtMaxVel = sCameraEyeMaxVel = sZeroVec;
+ }
} else {
sCsState = INTRO_START;
diff --git a/soh/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c b/soh/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c
index 7125984e2..dc19f2d7d 100644
--- a/soh/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c
+++ b/soh/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c
@@ -495,7 +495,7 @@ void DemoEffect_Init(Actor* thisx, PlayState* play2) {
this->jewel.type = DEMO_EFFECT_JEWEL_ZORA;
this->jewel.isPositionInit = 0;
DemoEffect_InitJewel(play, this);
- Actor_ChangeCategory(play, &play->actorCtx, &this->actor, ACTOR_EN_DOOR);
+ Actor_ChangeCategory(play, &play->actorCtx, &this->actor, ACTORCAT_BOSS);
if ((play->sceneNum == SCENE_JABU_JABU) && (Flags_GetInfTable(INFTABLE_145))) {
Actor_Kill(&this->actor);
return;