diff --git a/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL
new file mode 100644
index 000000000..939042daa
--- /dev/null
+++ b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_tri_0 b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_tri_0
new file mode 100644
index 000000000..8c320d243
--- /dev/null
+++ b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_tri_0
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_tri_1 b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_tri_1
new file mode 100644
index 000000000..0990859d5
--- /dev/null
+++ b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_tri_1
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_vtx_0 b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_vtx_0
new file mode 100644
index 000000000..37e6186e9
--- /dev/null
+++ b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_vtx_0
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_vtx_1 b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_vtx_1
new file mode 100644
index 000000000..4360eedc5
--- /dev/null
+++ b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_vtx_1
@@ -0,0 +1,416 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_vtx_cull b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_vtx_cull
new file mode 100644
index 000000000..cedf6351d
--- /dev/null
+++ b/soh/assets/custom/objects/object_mystery_item/gMysteryItemDL_vtx_cull
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_mystery_item/mat_gMysteryItemDL_f3dlite_mysteryItem_light_material b/soh/assets/custom/objects/object_mystery_item/mat_gMysteryItemDL_f3dlite_mysteryItem_light_material
new file mode 100644
index 000000000..4dc39e811
--- /dev/null
+++ b/soh/assets/custom/objects/object_mystery_item/mat_gMysteryItemDL_f3dlite_mysteryItem_light_material
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_mystery_item/mat_gMysteryItemDL_f3dlite_mysteryItem_material b/soh/assets/custom/objects/object_mystery_item/mat_gMysteryItemDL_f3dlite_mysteryItem_material
new file mode 100644
index 000000000..6941bb55f
--- /dev/null
+++ b/soh/assets/custom/objects/object_mystery_item/mat_gMysteryItemDL_f3dlite_mysteryItem_material
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/soh/assets/custom/objects/object_mystery_item/noise_tex b/soh/assets/custom/objects/object_mystery_item/noise_tex
new file mode 100644
index 000000000..aaf4e331f
Binary files /dev/null and b/soh/assets/custom/objects/object_mystery_item/noise_tex differ
diff --git a/soh/assets/soh_assets.h b/soh/assets/soh_assets.h
index 2b193053c..181ebd434 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 dgMysteryItemDL "__OTR__objects/object_mystery_item/gMysteryItemDL"
+static const ALIGN_ASSET(2) char gMysteryItemDL[] = dgMysteryItemDL;
+
// overlays
#define dgOptionsDividerChangeLangVtx "__OTR__overlays/ovl_file_choose/gOptionsDividerChangeLangVtx"
static const ALIGN_ASSET(2) char gOptionsDividerChangeLangVtx[] = dgOptionsDividerChangeLangVtx;
diff --git a/soh/include/variables.h b/soh/include/variables.h
index 9fd6b7247..2c226f2c6 100644
--- a/soh/include/variables.h
+++ b/soh/include/variables.h
@@ -172,7 +172,8 @@ extern "C"
extern u8 gWalkSpeedToggle2;
extern f32 iceTrapScale;
extern f32 triforcePieceScale;
-
+ extern f32 mysteryItemScale;
+
extern const s16 D_8014A6C0[];
#define gTatumsPerBeat (D_8014A6C0[1])
extern const AudioContextInitSizes D_8014A6C4;
diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp
index b932d24cc..4badd8279 100644
--- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp
+++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp
@@ -323,6 +323,7 @@ static std::map cosmeticOptions = {
COSMETIC_OPTION("World.Moon", "Moon", COSMETICS_GROUP_WORLD, ImVec4(240, 255, 180, 255), false, true, true),
COSMETIC_OPTION("World.GossipStone", "Gossip Stone", COSMETICS_GROUP_WORLD, ImVec4(200, 200, 200, 255), false, true, true),
COSMETIC_OPTION("World.RedIce", "Red Ice", COSMETICS_GROUP_WORLD, ImVec4(255, 0, 0, 255), false, true, false),
+ COSMETIC_OPTION("World.MysteryItem", "Mystery Item", COSMETICS_GROUP_WORLD, ImVec4(0, 60, 100, 255), false, true, false),
COSMETIC_OPTION("Navi.IdlePrimary", "Idle Primary", COSMETICS_GROUP_NAVI, ImVec4(255, 255, 255, 255), false, true, false),
COSMETIC_OPTION("Navi.IdleSecondary", "Idle Secondary", COSMETICS_GROUP_NAVI, ImVec4( 0, 0, 255, 0), false, true, true),
diff --git a/soh/soh/Enhancements/randomizer/draw.cpp b/soh/soh/Enhancements/randomizer/draw.cpp
index 4fbe489d2..7a970b895 100644
--- a/soh/soh/Enhancements/randomizer/draw.cpp
+++ b/soh/soh/Enhancements/randomizer/draw.cpp
@@ -248,7 +248,7 @@ extern "C" void Randomizer_DrawTriforcePieceGI(PlayState* play, GetItemEntry get
if (triforcePieceScale < 0.0001f) {
triforcePieceScale += 0.00003f;
}
-
+
// Animation. When not the completed triforce, create delay before showing the piece to bypass interpolation.
// If the completed triforce, make it grow slowly.
if (current != required) {
@@ -275,5 +275,28 @@ extern "C" void Randomizer_DrawTriforcePieceGI(PlayState* play, GetItemEntry get
} else if (current == required && triforcePieceScale > 0.00008f) {
gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gTriforcePieceCompletedDL);
}
+
+ CLOSE_DISPS(play->state.gfxCtx);
+}
+
+extern "C" void Randomizer_DrawMysteryItem(PlayState* play, GetItemEntry getItemEntry) {
+ Color_RGB8 color = { 0, 60, 100 };
+ if (CVarGetInteger(CVAR_COSMETIC("World.MysteryItem.Changed"), 0)) {
+ color = CVarGetColor24(CVAR_COSMETIC("World.MysteryItem.Value"), color);
+ }
+
+ 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);
+
+ gDPSetGrayscaleColor(POLY_XLU_DISP++, color.r, color.g, color.b, 255);
+ gSPGrayscale(POLY_XLU_DISP++, true);
+
+ gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gMysteryItemDL);
+
+ gSPGrayscale(POLY_XLU_DISP++, false);
+
CLOSE_DISPS(play->state.gfxCtx);
}
diff --git a/soh/soh/Enhancements/randomizer/draw.h b/soh/soh/Enhancements/randomizer/draw.h
index d9134573d..8c152a4f9 100644
--- a/soh/soh/Enhancements/randomizer/draw.h
+++ b/soh/soh/Enhancements/randomizer/draw.h
@@ -16,6 +16,10 @@ void Randomizer_DrawDoubleDefense(PlayState* play, GetItemEntry getItemEntry);
void Randomizer_DrawMasterSword(PlayState* play, GetItemEntry getItemEntry);
void Randomizer_DrawTriforcePiece(PlayState* play, GetItemEntry getItemEntry);
void Randomizer_DrawTriforcePieceGI(PlayState* play, GetItemEntry getItemEntry);
+void Randomizer_DrawMysteryItem(PlayState* play, GetItemEntry getItemEntry);
+
+#define GET_ITEM_MYSTERY \
+ { ITEM_NONE, 0, 0, 0, 0, 0, 0, 0, 0, false, ITEM_FROM_NPC, ITEM_CATEGORY_JUNK, Randomizer_DrawMysteryItem }
#ifdef __cplusplus
};
#endif
diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp
index f5c522ddc..107e23e83 100644
--- a/soh/soh/Enhancements/randomizer/randomizer.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer.cpp
@@ -5412,12 +5412,20 @@ CustomMessage Randomizer::GetMerchantMessage(RandomizerInf randomizerInf, u16 te
RandomizerCheck rc = GetCheckFromRandomizerInf(randomizerInf);
RandomizerGet shopItemGet = this->itemLocations[rc].rgID;
std::array shopItemName;
- if (mysterious) {
- shopItemName = {
- "mysterious item",
- "mysteriösen Gegenstand",
- "objet mystérieux"
- };
+ if (mysterious || CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0)) {
+ if (randomizerInf >= RAND_INF_SHOP_ITEMS_KF_SHOP_ITEM_1 && randomizerInf <= RAND_INF_SHOP_ITEMS_MARKET_BOMBCHU_SHOP_ITEM_8) {
+ shopItemName = {
+ "Mysterious Item",
+ "Mysteriösen Gegenstand",
+ "Objet Mystérieux"
+ };
+ } else {
+ shopItemName = {
+ "mysterious item",
+ "mysteriösen Gegenstand",
+ "objet mystérieux"
+ };
+ }
// TODO: This should eventually be replaced with a full fledged trick model & trick name system
} else if (shopItemGet == RG_ICE_TRAP) {
shopItemGet = this->itemLocations[rc].fakeRgID;
diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h
index a726cecde..ce8f5c45b 100644
--- a/soh/soh/Enhancements/randomizer/randomizer.h
+++ b/soh/soh/Enhancements/randomizer/randomizer.h
@@ -9,6 +9,7 @@
#include
#include
#include "soh/Enhancements/randomizer/randomizer_check_objects.h"
+#include "soh/Enhancements/randomizer/randomizer_check_tracker.h"
#include "soh/Enhancements/randomizer/randomizer_tricks.h"
#include
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
index 4ca8c7993..a53b838f3 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
+++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp
@@ -1223,7 +1223,7 @@ void LoadSettings() {
}
}
-bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
+bool IsCheckShuffled(RandomizerCheckObject rcObj) {
if (IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LOGIC_RULES) != RO_LOGIC_VANILLA) {
return
(rcObj.rcArea != RCAREA_INVALID) && // don't show Invalid locations
@@ -1236,7 +1236,7 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
rcObj.vOrMQ == RCVORMQ_MQ && OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId) ||
rcObj.vOrMQ == RCVORMQ_VANILLA && !OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId)
) &&
- (rcObj.rcType != RCTYPE_SHOP || (showShops && (!hideShopRightChecks || hideShopRightChecks && rcObj.actorParams > 0x03))) &&
+ (rcObj.rcType != RCTYPE_SHOP || (showShops && rcObj.actorParams > 0x03)) &&
(rcObj.rcType != RCTYPE_SCRUB ||
showScrubs ||
rcObj.rc == RC_LW_DEKU_SCRUB_NEAR_BRIDGE || // The 3 scrubs that are always randomized
@@ -1245,7 +1245,7 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
) &&
(rcObj.rcType != RCTYPE_MERCHANT || showMerchants) &&
(rcObj.rcType != RCTYPE_OCARINA || showOcarinas) &&
- (rcObj.rcType != RCTYPE_SKULL_TOKEN || alwaysShowGS ||
+ (rcObj.rcType != RCTYPE_SKULL_TOKEN ||
(showOverworldTokens && RandomizerCheckObjects::AreaIsOverworld(rcObj.rcArea)) ||
(showDungeonTokens && RandomizerCheckObjects::AreaIsDungeon(rcObj.rcArea))
) &&
@@ -1265,6 +1265,7 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
(rcObj.rcType != RCTYPE_BOSS_KEY || showBossKeysanity) &&
(rcObj.rcType != RCTYPE_GANON_BOSS_KEY || showGanonBossKey) &&
(rcObj.rc != RC_KAK_100_GOLD_SKULLTULA_REWARD || show100SkullReward) &&
+ (rcObj.rc != RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS) &&
(rcObj.rcType != RCTYPE_GF_KEY && rcObj.rc != RC_GF_GERUDO_MEMBERSHIP_CARD ||
(showGerudoCard && rcObj.rc == RC_GF_GERUDO_MEMBERSHIP_CARD) ||
(fortressNormal && showGerudoFortressKeys && rcObj.rcType == RCTYPE_GF_KEY) ||
@@ -1280,6 +1281,10 @@ bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
return false;
}
+bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
+ return IsCheckShuffled(rcObj) || (rcObj.rcType == RCTYPE_SKULL_TOKEN && alwaysShowGS) || (rcObj.rcType == RCTYPE_SHOP && (showShops && (!hideShopRightChecks)));
+}
+
void UpdateInventoryChecks() {
//For all the areas with maps, if you have one, spoil the area
for (auto [scene, area] : DungeonRCAreasBySceneID) {
@@ -1444,6 +1449,8 @@ void DrawLocation(RandomizerCheckObject rcObj) {
//Draw the extra info
txt = "";
+ bool mystery = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && OTRGlobals::Instance->gRandomizer->merchantPrices.contains(rcObj.rc);
+
if (checkData.hintItem != 0) {
// TODO hints
} else if (status != RCSHOW_UNCHECKED) {
@@ -1466,16 +1473,16 @@ void DrawLocation(RandomizerCheckObject rcObj) {
case RCSHOW_IDENTIFIED:
case RCSHOW_SEEN:
if (IS_RANDO) {
- if (gSaveContext.itemLocations[rcObj.rc].get.rgID == RG_ICE_TRAP) {
+ if (gSaveContext.itemLocations[rcObj.rc].get.rgID == RG_ICE_TRAP && !mystery) {
if (status == RCSHOW_IDENTIFIED) {
txt = gSaveContext.itemLocations[rcObj.rc].get.trickName;
} else {
txt = OTRGlobals::Instance->gRandomizer->EnumToSpoilerfileGetName[gSaveContext.itemLocations[rcObj.rc].get.fakeRgID][gSaveContext.language];
}
- } else {
+ } else if (!mystery) {
txt = OTRGlobals::Instance->gRandomizer->EnumToSpoilerfileGetName[gSaveContext.itemLocations[rcObj.rc].get.rgID][gSaveContext.language];
}
- if (status == RCSHOW_IDENTIFIED) {
+ if (!IsVisibleInCheckTracker(rcObj) && status == RCSHOW_IDENTIFIED && !mystery) {
txt += fmt::format(" - {}", gSaveContext.checkTrackerData[rcObj.rc].price);
}
} else {
diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h
index 216da367f..be1ae441c 100644
--- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h
+++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.h
@@ -47,6 +47,7 @@ void DefaultCheckData(RandomizerCheck rc);
void Teardown();
void UpdateAllOrdering();
bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj);
+bool IsCheckShuffled(RandomizerCheckObject check);
void InitTrackerData(bool isDebug);
RandomizerCheckArea GetCheckArea();
void UpdateCheck(uint32_t, RandomizerCheckTrackerData);
diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp
index b61bb65cc..518e9c1f3 100644
--- a/soh/soh/OTRGlobals.cpp
+++ b/soh/soh/OTRGlobals.cpp
@@ -84,6 +84,7 @@ GameInteractorSail* GameInteractorSail::Instance;
#include "Enhancements/mods.h"
#include "Enhancements/game-interactor/GameInteractor.h"
+#include "Enhancements/randomizer/draw.h"
#include
// Resource Types/Factories
@@ -2437,6 +2438,14 @@ extern "C" ItemObtainability Randomizer_GetItemObtainabilityFromRandomizerCheck(
return OTRGlobals::Instance->gRandomizer->GetItemObtainabilityFromRandomizerCheck(randomizerCheck);
}
+extern "C" bool Randomizer_IsCheckShuffled(RandomizerCheck randomizerCheck) {
+ return CheckTracker::IsCheckShuffled(RandomizerCheckObjects::GetAllRCObjects().find(randomizerCheck)->second);
+}
+
+extern "C" GetItemEntry GetItemMystery() {
+ return { ITEM_NONE_FE, 0, 0, 0, 0, 0, 0, ITEM_NONE_FE, 0, false, ITEM_FROM_NPC, ITEM_CATEGORY_JUNK, NULL, MOD_RANDOMIZER, (CustomDrawFunc)Randomizer_DrawMysteryItem };
+}
+
CustomMessage Randomizer_GetCustomGetItemMessage(Player* player) {
s16 giid;
if (player->getItemEntry.objectId != OBJECT_INVALID) {
diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h
index 73cb58d97..e0b5c7a38 100644
--- a/soh/soh/OTRGlobals.h
+++ b/soh/soh/OTRGlobals.h
@@ -179,6 +179,8 @@ GetItemEntry Randomizer_GetItemFromActor(s16 actorId, s16 sceneNum, s16 actorPar
GetItemEntry Randomizer_GetItemFromActorWithoutObtainabilityCheck(s16 actorId, s16 sceneNum, s16 actorParams, GetItemID ogId);
GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
GetItemEntry Randomizer_GetItemFromKnownCheckWithoutObtainabilityCheck(RandomizerCheck randomizerCheck, GetItemID ogId);
+bool Randomizer_IsCheckShuffled(RandomizerCheck check);
+GetItemEntry GetItemMystery();
ItemObtainability Randomizer_GetItemObtainabilityFromRandomizerCheck(RandomizerCheck randomizerCheck);
int CustomMessage_RetrieveIfExists(PlayState* play);
void Overlay_DisplayText(float duration, const char* text);
diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp
index c396de738..35274e5ac 100644
--- a/soh/soh/SohMenuBar.cpp
+++ b/soh/soh/SohMenuBar.cpp
@@ -1972,6 +1972,11 @@ void DrawRandomizerMenu() {
"Play unique fanfares when obtaining quest items "
"(medallions/stones/songs). Note that these fanfares are longer than usual."
);
+ UIWidgets::PaddedEnhancementCheckbox("Mysterious Shuffled Items", CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), true, false);
+ UIWidgets::Tooltip(
+ "Displays a \"Mystery Item\" model in place of any freestanding/GS/shop items that were shuffled, "
+ "and replaces item names for them and scrubs and merchants, regardless of hint settings, "
+ "so you never know what you're getting.");
ImGui::EndMenu();
}
diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c
index db344d39e..772817716 100644
--- a/soh/src/code/z_en_item00.c
+++ b/soh/src/code/z_en_item00.c
@@ -1366,17 +1366,19 @@ void EnItem00_DrawCollectible(EnItem00* this, PlayState* play) {
if (IS_RANDO && (this->getItemId != GI_NONE || this->actor.params == ITEM00_SMALL_KEY)) {
RandomizerCheck randoCheck =
Randomizer_GetCheckFromActor(this->actor.id, play->sceneNum, this->ogParams);
+ GetItemEntry giEntry = this->randoGiEntry;
if (randoCheck != RC_UNKNOWN_CHECK) {
- this->randoGiEntry =
- Randomizer_GetItemFromKnownCheck(randoCheck, GI_NONE);
- this->randoGiEntry.getItemFrom = ITEM_FROM_FREESTANDING;
+ this->randoGiEntry = Randomizer_GetItemFromKnownCheck(randoCheck, GI_NONE);
+ giEntry = (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && Randomizer_IsCheckShuffled(randoCheck))
+ ? GetItemMystery() : this->randoGiEntry;
+ giEntry.getItemFrom = ITEM_FROM_FREESTANDING;
}
-
- f32 mtxScale = 10.67f;
+
+ f32 mtxScale = 16.0f;
Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY);
- EnItem00_CustomItemsParticles(&this->actor, play, this->randoGiEntry);
- GetItemEntry_Draw(play, this->randoGiEntry);
+ EnItem00_CustomItemsParticles(&this->actor, play, giEntry);
+ GetItemEntry_Draw(play, giEntry);
} else if (this->actor.params == ITEM00_BOMBCHU) {
OPEN_DISPS(play->state.gfxCtx);
@@ -1460,17 +1462,19 @@ void EnItem00_DrawHeartPiece(EnItem00* this, PlayState* play) {
if (IS_RANDO) {
RandomizerCheck randoCheck =
Randomizer_GetCheckFromActor(this->actor.id, play->sceneNum, this->ogParams);
+ GetItemEntry giEntry = this->randoGiEntry;
if (randoCheck != RC_UNKNOWN_CHECK) {
- this->randoGiEntry =
- Randomizer_GetItemFromKnownCheck(randoCheck, GI_NONE);
- this->randoGiEntry.getItemFrom = ITEM_FROM_FREESTANDING;
+ this->randoGiEntry = Randomizer_GetItemFromKnownCheck(randoCheck, GI_NONE);
+ giEntry = (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && Randomizer_IsCheckShuffled(randoCheck))
+ ? GetItemMystery() : this->randoGiEntry;
+ giEntry.getItemFrom = ITEM_FROM_FREESTANDING;
}
f32 mtxScale = 16.0f;
Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY);
- EnItem00_CustomItemsParticles(&this->actor, play, this->randoGiEntry);
- GetItemEntry_Draw(play, this->randoGiEntry);
+ EnItem00_CustomItemsParticles(&this->actor, play, giEntry);
+ GetItemEntry_Draw(play, giEntry);
} else {
s32 pad;
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 149c176c7..edab23ae8 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
@@ -2088,7 +2088,8 @@ void DemoEffect_DrawGetItem(Actor* thisx, PlayState* play) {
return;
}
if (IS_RANDO && play->sceneNum == SCENE_JABU_JABU) {
- GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_BARINADE, RG_ZORA_SAPPHIRE);
+ GetItemEntry getItemEntry = (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && Randomizer_IsCheckShuffled(RC_BARINADE))
+ ? GetItemMystery() : Randomizer_GetItemFromKnownCheck(RC_BARINADE, RG_ZORA_SAPPHIRE);
this->getItem.drawId = getItemEntry.gid;
func_8002EBCC(thisx, play, 0);
func_8002ED80(thisx, play, 0);
diff --git a/soh/src/overlays/actors/ovl_En_Ex_Item/z_en_ex_item.c b/soh/src/overlays/actors/ovl_En_Ex_Item/z_en_ex_item.c
index a3a196e31..b2d23984c 100644
--- a/soh/src/overlays/actors/ovl_En_Ex_Item/z_en_ex_item.c
+++ b/soh/src/overlays/actors/ovl_En_Ex_Item/z_en_ex_item.c
@@ -515,14 +515,17 @@ void EnExItem_DrawItems(EnExItem* this, PlayState* play) {
switch (this->type) {
case EXITEM_BOMB_BAG_BOWLING:
case EXITEM_BOMB_BAG_COUNTER:
- randoGetItem = Randomizer_GetItemFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, GI_BOMB_BAG_20);
+ randoGetItem = (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && Randomizer_IsCheckShuffled(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE))
+ ? GetItemMystery()
+ : Randomizer_GetItemFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, GI_BOMB_BAG_20);
break;
case EXITEM_BOMBCHUS_BOWLING:
case EXITEM_BOMBCHUS_COUNTER:
randoGetItem = Randomizer_GetItemFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, GI_BOMBCHUS_10);
break;
case EXITEM_BULLET_BAG:
- randoGetItem = Randomizer_GetItemFromKnownCheck(RC_LW_TARGET_IN_WOODS, GI_BULLET_BAG_50);
+ randoGetItem = (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && Randomizer_IsCheckShuffled(RC_LW_TARGET_IN_WOODS))
+ ? GetItemMystery() : Randomizer_GetItemFromKnownCheck(RC_LW_TARGET_IN_WOODS, GI_BULLET_BAG_50);
break;
}
@@ -540,8 +543,8 @@ void EnExItem_DrawHeartPiece(EnExItem* this, PlayState* play) {
func_8002ED80(&this->actor, play, 0);
if (IS_RANDO) {
- GetItemEntry randoGetItem =
- Randomizer_GetItemFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, GI_HEART_PIECE);
+ GetItemEntry randoGetItem = (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && Randomizer_IsCheckShuffled(RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE))
+ ? GetItemMystery() : Randomizer_GetItemFromKnownCheck(RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, GI_HEART_PIECE);
EnItem00_CustomItemsParticles(&this->actor, play, randoGetItem);
GetItemEntry_Draw(play, randoGetItem);
} else {
diff --git a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c
index 11c29227f..0382735a3 100644
--- a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c
+++ b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c
@@ -1286,8 +1286,8 @@ void EnGirlA_InitializeItemAction(EnGirlA* this, PlayState* play) {
this->basePrice = shopItemIdentity.itemPrice;
this->giDrawId = getItemEntry.gid;
- // Correct the rotation for spiritual stones
- if (getItemEntry.getItemId >= RG_KOKIRI_EMERALD && getItemEntry.getItemId <= RG_ZORA_SAPPHIRE) {
+ // Correct the rotation for spiritual stones, but only if mysterious shuffle isn't on, else it's obvious what's there in shops
+ if (!CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && (getItemEntry.getItemId >= RG_KOKIRI_EMERALD && getItemEntry.getItemId <= RG_ZORA_SAPPHIRE)) {
this->actor.shape.rot.y = this->actor.shape.rot.y + 20000;
}
}
@@ -1332,7 +1332,8 @@ void EnGirlA_Draw(Actor* thisx, PlayState* play) {
if (this->actor.params == SI_RANDOMIZED_ITEM) {
ShopItemIdentity shopItemIdentity = Randomizer_IdentifyShopItem(play->sceneNum, this->randoSlotIndex);
- GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheckWithoutObtainabilityCheck(shopItemIdentity.randomizerCheck, shopItemIdentity.ogItemId);
+ GetItemEntry getItemEntry = (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && this->actor.params == SI_RANDOMIZED_ITEM) ? GetItemMystery() :
+ Randomizer_GetItemFromKnownCheckWithoutObtainabilityCheck(shopItemIdentity.randomizerCheck, shopItemIdentity.ogItemId);
EnItem00_CustomItemsParticles(&this->actor, play, getItemEntry);
GetItemEntry_Draw(play, getItemEntry);
diff --git a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c
index 185a39c51..98e8f4116 100644
--- a/soh/src/overlays/actors/ovl_En_Si/z_en_si.c
+++ b/soh/src/overlays/actors/ovl_En_Si/z_en_si.c
@@ -214,7 +214,8 @@ void EnSi_Draw(Actor* thisx, PlayState* play) {
if (!IS_RANDO) {
GetItem_Draw(play, GID_SKULL_TOKEN_2);
} else {
- getItem = Randomizer_GetItemFromActor(this->actor.id, play->sceneNum, this->actor.params, GI_SKULL_TOKEN);
+ RandomizerCheck check = Randomizer_GetCheckFromActor(this->actor.id, play->sceneNum, this->actor.params);
+ getItem = (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && Randomizer_IsCheckShuffled(check)) ? GetItemMystery() : Randomizer_GetItemFromKnownCheck(check, GI_SKULL_TOKEN);
EnItem00_CustomItemsParticles(&this->actor, play, getItem);
if (getItem.itemId != ITEM_SKULL_TOKEN) {
f32 mtxScale = 1.5f;
diff --git a/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c b/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c
index abb65c191..bea2f608f 100644
--- a/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c
+++ b/soh/src/overlays/actors/ovl_Item_B_Heart/z_item_b_heart.c
@@ -99,8 +99,8 @@ void ItemBHeart_Draw(Actor* thisx, PlayState* play) {
}
if (IS_RANDO) {
- GetItemEntry_Draw(play, Randomizer_GetItemFromActor(this->actor.id,
- play->sceneNum,this->actor.params, GI_HEART_CONTAINER_2));
+ RandomizerCheck check = Randomizer_GetCheckFromActor(this->actor.id, play->sceneNum, this->actor.params);
+ GetItemEntry_Draw(play, (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && Randomizer_IsCheckShuffled(check)) ? GetItemMystery() : Randomizer_GetItemFromKnownCheck(check, GI_HEART_CONTAINER_2));
} else {
if (flag) {
Gfx_SetupDL_25Xlu(play->state.gfxCtx);
diff --git a/soh/src/overlays/actors/ovl_Item_Etcetera/z_item_etcetera.c b/soh/src/overlays/actors/ovl_Item_Etcetera/z_item_etcetera.c
index b12d7b4b0..fb93702ab 100644
--- a/soh/src/overlays/actors/ovl_Item_Etcetera/z_item_etcetera.c
+++ b/soh/src/overlays/actors/ovl_Item_Etcetera/z_item_etcetera.c
@@ -230,7 +230,8 @@ void ItemEtcetera_DrawThroughLens(Actor* thisx, PlayState* play) {
func_8002ED80(&this->actor, play, 0);
if(IS_RANDO && play->sceneNum == SCENE_TREASURE_BOX_SHOP) {
- GetItemEntry randoGetItem = GetChestGameRandoGetItem(this->actor.room, this->giDrawId, play);
+ RandomizerCheck check = RC_MAX;
+ GetItemEntry randoGetItem = GetChestGameRandoGetItem(this->actor.room, this->giDrawId, play); //TODO Rando: add mysterious shuffle when chest minigame keys get shuffled
EnItem00_CustomItemsParticles(&this->actor, play, randoGetItem);
if (randoGetItem.itemId != ITEM_NONE) {
GetItemEntry_Draw(play, randoGetItem);
@@ -249,9 +250,9 @@ void ItemEtcetera_Draw(Actor* thisx, PlayState* play) {
if (IS_RANDO) {
GetItemEntry randoGetItem = (GetItemEntry)GET_ITEM_NONE;
if (type == ITEM_ETC_ARROW_FIRE) {
- randoGetItem = Randomizer_GetItemFromKnownCheck(RC_LH_SUN, GI_ARROW_FIRE);
+ randoGetItem = (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && Randomizer_IsCheckShuffled(RC_LH_SUN)) ? GetItemMystery() : Randomizer_GetItemFromKnownCheck(RC_LH_SUN, GI_ARROW_FIRE);
} else if (type == ITEM_ETC_LETTER) {
- randoGetItem = Randomizer_GetItemFromKnownCheck(RC_LH_UNDERWATER_ITEM, GI_LETTER_RUTO);
+ randoGetItem = (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && Randomizer_IsCheckShuffled(RC_LH_UNDERWATER_ITEM)) ? GetItemMystery() : Randomizer_GetItemFromKnownCheck(RC_LH_UNDERWATER_ITEM, GI_LETTER_RUTO);
}
EnItem00_CustomItemsParticles(&this->actor, play, randoGetItem);
diff --git a/soh/src/overlays/actors/ovl_Item_Ocarina/z_item_ocarina.c b/soh/src/overlays/actors/ovl_Item_Ocarina/z_item_ocarina.c
index a9cd36446..c1a0d67ec 100644
--- a/soh/src/overlays/actors/ovl_Item_Ocarina/z_item_ocarina.c
+++ b/soh/src/overlays/actors/ovl_Item_Ocarina/z_item_ocarina.c
@@ -215,7 +215,7 @@ void ItemOcarina_Draw(Actor* thisx, PlayState* play) {
func_8002ED80(thisx, play, 0);
if (IS_RANDO) {
- GetItemEntry randoGetItem = Randomizer_GetItemFromKnownCheck(RC_HF_OCARINA_OF_TIME_ITEM, GI_OCARINA_OOT);
+ GetItemEntry randoGetItem = (CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && Randomizer_IsCheckShuffled(RC_HF_OCARINA_OF_TIME_ITEM)) ? GetItemMystery() : Randomizer_GetItemFromKnownCheck(RC_HF_OCARINA_OF_TIME_ITEM, GI_OCARINA_OOT);
EnItem00_CustomItemsParticles(&this->actor, play, randoGetItem);
GetItemEntry_Draw(play, randoGetItem);
return;