diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index d6676fa6c..6cca76be9 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -874,7 +874,7 @@ void GenerateItemPool() { //Keys //For key rings, need to add as many junk items as "missing" keys - if (KeyRings) { + if (KeyRings.IsNot(KEYRINGS_OFF)) { uint8_t ringJunkAmt = 0; for (auto dungeon : dungeonList) { if (dungeon->HasKeyRing()) { diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 07c12f292..4c199b929 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -208,7 +208,8 @@ namespace Settings { Option LACSRewardCount = Option::U8 ("Reward Count", {NumOpts(0, 9)}, {lacsRewardCountDesc}, OptionCategory::Setting, 1, true); Option LACSDungeonCount = Option::U8 ("Dungeon Count", {NumOpts(0, 8)}, {lacsDungeonCountDesc}, OptionCategory::Setting, 1, true); Option LACSTokenCount = Option::U8 ("Token Count", {NumOpts(0, 100)}, {lacsTokenCountDesc}, OptionCategory::Setting, 1, true); - Option KeyRings = Option::Bool("Key Rings", {"Off", "On"}, {keyRingDesc}); + Option KeyRings = Option::U8 ("Key Rings", {"Off", "Random", "Count", "Selection"}, {keyRingDesc}); + Option KeyRingsRandomCount = Option::U8 ("Keyring Dungeon Count", {NumOpts(0, 8)}, {keyRingDesc}, OptionCategory::Setting, 1); Option RingFortress = Option::Bool("Gerudo Fortress", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting); Option RingForest = Option::Bool("Forest Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting); Option RingFire = Option::Bool("Fire Temple", {"Off", "On"}, {keyRingDesc}, OptionCategory::Setting); @@ -232,6 +233,7 @@ namespace Settings { &LACSDungeonCount, &LACSTokenCount, &KeyRings, + &KeyRingsRandomCount, &RingFortress, &RingForest, &RingFire, @@ -2013,7 +2015,7 @@ namespace Settings { LACSTokenCount.Hide(); } - if (KeyRings) { + if (KeyRings.IsNot(KEYRINGS_OFF)) { for (Option *option : keyRingOptions) { option->Unhide(); } @@ -2614,6 +2616,17 @@ namespace Settings { LACSDungeonCount.SetSelectedIndex(cvarSettings[RSK_LACS_DUNGEON_COUNT]); LACSTokenCount.SetSelectedIndex(cvarSettings[RSK_LACS_TOKEN_COUNT]); + KeyRings.SetSelectedIndex(cvarSettings[RSK_KEYRINGS]); + KeyRingsRandomCount.SetSelectedIndex(cvarSettings[RSK_KEYRINGS_RANDOM_COUNT]); + RingForest.SetSelectedIndex(cvarSettings[RSK_KEYRINGS_FOREST_TEMPLE]); + RingFire.SetSelectedIndex(cvarSettings[RSK_KEYRINGS_FIRE_TEMPLE]); + RingWater.SetSelectedIndex(cvarSettings[RSK_KEYRINGS_WATER_TEMPLE]); + RingSpirit.SetSelectedIndex(cvarSettings[RSK_KEYRINGS_SPIRIT_TEMPLE]); + RingShadow.SetSelectedIndex(cvarSettings[RSK_KEYRINGS_SHADOW_TEMPLE]); + RingWell.SetSelectedIndex(cvarSettings[RSK_KEYRINGS_BOTTOM_OF_THE_WELL]); + RingGtg.SetSelectedIndex(cvarSettings[RSK_KEYRINGS_GTG]); + RingCastle.SetSelectedIndex(cvarSettings[RSK_KEYRINGS_GANONS_CASTLE]); + NumRequiredCuccos.SetSelectedIndex(cvarSettings[RSK_CUCCO_COUNT]); BigPoeTargetCount.SetSelectedIndex(cvarSettings[RSK_BIG_POE_COUNT]-1); @@ -2699,11 +2712,22 @@ namespace Settings { } } + std::vector randKeyRingDungeons = {}; //Set key ring for each dungeon for (size_t i = 0; i < dungeons.size(); i++) { dungeons[i]->ClearKeyRing(); + if (dungeons[i]->GetSmallKeyCount() > 0) { + randKeyRingDungeons.push_back(i); + } } - if (KeyRings) { + if (KeyRings.Is(KEYRINGS_RANDOM) || KeyRings.Is(KEYRINGS_RANDOM_COUNT)) { + int keyRingCount = KeyRings.Is(KEYRINGS_RANDOM_COUNT) ? KeyRingsRandomCount.Value() : Random(0, randKeyRingDungeons.size()); + Shuffle(randKeyRingDungeons); + + for (uint8_t i = 0; i < keyRingCount; i++) { + dungeons[randKeyRingDungeons[i]]->SetKeyRing(); + } + } else if (KeyRings.Is(KEYRINGS_SELECTION)) { if (RingWell) { BottomOfTheWell.SetKeyRing(); } diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.hpp b/soh/soh/Enhancements/randomizer/3drando/settings.hpp index 96c4a9e7c..6e23ca571 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.hpp @@ -202,6 +202,13 @@ typedef enum { GERUDOKEYS_ANYWHERE, } GerudoKeysSetting; +typedef enum { + KEYRINGS_OFF, + KEYRINGS_RANDOM, + KEYRINGS_RANDOM_COUNT, + KEYRINGS_SELECTION, +} KeyRingsSetting; + typedef enum { BOSSKEYSANITY_START_WITH, BOSSKEYSANITY_VANILLA, @@ -925,6 +932,7 @@ void UpdateSettings(std::unordered_map cvarSettin extern Option LACSDungeonCount; extern Option LACSTokenCount; extern Option KeyRings; + extern Option KeyRingsRandomCount; extern Option RingFortress; extern Option RingForest; extern Option RingFire; diff --git a/soh/soh/Enhancements/randomizer/draw.cpp b/soh/soh/Enhancements/randomizer/draw.cpp index 8e276d1a1..550d71104 100644 --- a/soh/soh/Enhancements/randomizer/draw.cpp +++ b/soh/soh/Enhancements/randomizer/draw.cpp @@ -88,6 +88,54 @@ extern "C" void Randomizer_DrawBossKey(GlobalContext* globalCtx, GetItemEntry* g CLOSE_DISPS(globalCtx->state.gfxCtx); } +extern "C" void Randomizer_DrawKeyRing(GlobalContext* globalCtx, GetItemEntry* getItemEntry) { + s32 pad; + + s16 color_slot = getItemEntry->getItemId - RG_FOREST_TEMPLE_KEY_RING; + s16 colors[9][3] = { + { 4, 195, 46 }, // Forest Temple + { 237, 95, 95 }, // Fire Temple + { 85, 180, 223 }, // Water Temple + { 222, 158, 47 }, // Spirit Temple + { 126, 16, 177 }, // Shadow Temple + { 227, 110, 255 }, // Bottom of the Well + { 221, 212, 60 }, // Gerudo Training Grounds + { 255, 255, 255 }, // Theive's Hideout (unused) + { 80, 80, 80 } // Ganon's Castle + }; + + OPEN_DISPS(globalCtx->state.gfxCtx); + + func_80093D18(globalCtx->state.gfxCtx); + + gsDPSetGrayscaleColor(POLY_OPA_DISP++, colors[color_slot][0], colors[color_slot][1], colors[color_slot][2], 255); + gsSPGrayscale(POLY_OPA_DISP++, true); + + Matrix_Scale(0.5f, 0.5f, 0.5f, MTXMODE_APPLY); + Matrix_RotateZ(0.8f, MTXMODE_APPLY); + Matrix_RotateX(-2.16f, MTXMODE_APPLY); + Matrix_RotateY(-0.56f, MTXMODE_APPLY); + Matrix_RotateZ(-0.86f, MTXMODE_APPLY); + Matrix_Translate(28.29f, 0, 0, MTXMODE_APPLY); + Matrix_Translate(-(3.12f * 2), -(-0.34f * 2), -(17.53f * 2), MTXMODE_APPLY); + Matrix_RotateX(-(-0.31f * 2), MTXMODE_APPLY); + Matrix_RotateY(-(0.19f * 2), MTXMODE_APPLY); + Matrix_RotateZ(-(0.20f * 2), MTXMODE_APPLY); + for (int i = 0; i < 5; i++) { + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, (char*)__FILE__, __LINE__), + G_MTX_MODELVIEW | G_MTX_LOAD); + Matrix_Translate(3.12f, -0.34f, 17.53f, MTXMODE_APPLY); + Matrix_RotateX(-0.31f, MTXMODE_APPLY); + Matrix_RotateY(0.19f, MTXMODE_APPLY); + Matrix_RotateZ(0.20f, MTXMODE_APPLY); + gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gGiSmallKeyDL); + } + + gsSPGrayscale(POLY_OPA_DISP++, false); + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + extern "C" void Randomizer_DrawDoubleDefense(GlobalContext* globalCtx, GetItemEntry getItemEntry) { s32 pad; OPEN_DISPS(globalCtx->state.gfxCtx); diff --git a/soh/soh/Enhancements/randomizer/draw.h b/soh/soh/Enhancements/randomizer/draw.h index b1a93bd92..71974342c 100644 --- a/soh/soh/Enhancements/randomizer/draw.h +++ b/soh/soh/Enhancements/randomizer/draw.h @@ -7,6 +7,7 @@ typedef struct GlobalContext GlobalContext; extern "C" void Randomizer_DrawSmallKey(GlobalContext* globalCtx, GetItemEntry* getItemEntry); +extern "C" void Randomizer_DrawKeyRing(GlobalContext* globalCtx, GetItemEntry* getItemEntry); extern "C" void Randomizer_DrawBossKey(GlobalContext* globalCtx, GetItemEntry* getItemEntry); extern "C" void Randomizer_DrawDoubleDefense(GlobalContext* globalCtx, GetItemEntry getItemEntry); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 6f86b5645..eddd4cfb7 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1133,16 +1133,6 @@ ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGe case RG_HINT: case RG_MAX: case RG_SOLD_OUT: - // TODO: Implement key rings - case RG_FOREST_TEMPLE_KEY_RING: - case RG_FIRE_TEMPLE_KEY_RING: - case RG_WATER_TEMPLE_KEY_RING: - case RG_SPIRIT_TEMPLE_KEY_RING: - case RG_SHADOW_TEMPLE_KEY_RING: - case RG_BOTTOM_OF_THE_WELL_KEY_RING: - case RG_GERUDO_TRAINING_GROUNDS_KEY_RING: - case RG_GERUDO_FORTRESS_KEY_RING: - case RG_GANONS_CASTLE_KEY_RING: return CANT_OBTAIN_MISC; // Equipment @@ -2450,6 +2440,16 @@ void GenerateRandomizerImgui() { cvarSettings[RSK_SUNLIGHT_ARROWS] = CVar_GetS32("gRandomizeSunlightArrows", 0); cvarSettings[RSK_KEYSANITY] = CVar_GetS32("gRandomizeKeysanity", 2); cvarSettings[RSK_GERUDO_KEYS] = CVar_GetS32("gRandomizeGerudoKeys", 0); + cvarSettings[RSK_KEYRINGS] = CVar_GetS32("gRandomizeShuffleKeyRings", 0); + cvarSettings[RSK_KEYRINGS_RANDOM_COUNT] = CVar_GetS32("gRandomizeShuffleKeyRingsRandomCount", 0); + cvarSettings[RSK_KEYRINGS_FOREST_TEMPLE] = CVar_GetS32("gRandomizeShuffleKeyRingsForestTemple", 0); + cvarSettings[RSK_KEYRINGS_FIRE_TEMPLE] = CVar_GetS32("gRandomizeShuffleKeyRingsFireTemple", 0); + cvarSettings[RSK_KEYRINGS_WATER_TEMPLE] = CVar_GetS32("gRandomizeShuffleKeyRingsWaterTemple", 0); + cvarSettings[RSK_KEYRINGS_SPIRIT_TEMPLE] = CVar_GetS32("gRandomizeShuffleKeyRingsSpiritTemple", 0); + cvarSettings[RSK_KEYRINGS_SHADOW_TEMPLE] = CVar_GetS32("gRandomizeShuffleKeyRingsShadowTemple", 0); + cvarSettings[RSK_KEYRINGS_BOTTOM_OF_THE_WELL] = CVar_GetS32("gRandomizeShuffleKeyRingsBottomOfTheWell", 0); + cvarSettings[RSK_KEYRINGS_GTG] = CVar_GetS32("gRandomizeShuffleKeyRingsGTG", 0); + cvarSettings[RSK_KEYRINGS_GANONS_CASTLE] = CVar_GetS32("gRandomizeShuffleKeyRingsGanonsCastle", 0); cvarSettings[RSK_BOSS_KEYSANITY] = CVar_GetS32("gRandomizeBossKeysanity", 2); cvarSettings[RSK_GANONS_BOSS_KEY] = CVar_GetS32("gRandomizeShuffleGanonBossKey", 1); cvarSettings[RSK_LACS_STONE_COUNT] = CVar_GetS32("gRandomizeLacsStoneCount", 3); @@ -2571,6 +2571,7 @@ void DrawRandoEditor(bool& open) { "Any Dungeon", "Overworld", "Anywhere", "LACS-Vanilla", "LACS-Medallions", "LACS-Stones", "LACS-Rewards", "LACS-Dungeons", "LACS-Tokens"}; + const char* randoShuffleKeyRings[4] = { "Off", "Random", "Count", "Selection" }; // Misc Settings const char* randoGossipStoneHints[4] = { "No Hints", "Need Nothing", "Mask of Truth", "Stone of Agony" }; @@ -2583,7 +2584,7 @@ void DrawRandoEditor(bool& open) { const char* randoItemPool[4] = { "Plentiful", "Balanced", "Scarce", "Minimal" }; const char* randoIceTraps[5] = { "Off", "Normal", "Extra", "Mayhem", "Onslaught" }; - ImGui::SetNextWindowSize(ImVec2(920, 563), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(920, 600), ImGuiCond_FirstUseEver); if (!ImGui::Begin("Randomizer Editor", &open, ImGuiWindowFlags_NoFocusOnAppearing)) { ImGui::End(); return; @@ -3152,6 +3153,44 @@ void DrawRandoEditor(bool& open) { ); UIWidgets::EnhancementCombobox("gRandomizeKeysanity", randoShuffleSmallKeys, 6, 2); + UIWidgets::PaddedSeparator(); + + // Key Rings + ImGui::Text(Settings::KeyRings.GetName().c_str()); + UIWidgets::InsertHelpHoverText( + "Keyrings will replace all small keys from a particular dungeon with a single keyring that awards all keys for it's associated dungeon\n" + "\n" + "Off - No dungeons will have their keys replaced with keyrings.\n" + "\n" + "Random - A random amount of dungeons(0-8) will have their keys replaced with keyrings.\n" + "\n" + "Count - A specified amount of randomly selected dungeons will have their keys replaced with keyrings.\n" + "\n" + "Selection - Hand select which dungeons will have their keys replaced with keyrings." + ); + UIWidgets::EnhancementCombobox("gRandomizeShuffleKeyRings", randoShuffleKeyRings, 4, 0); + ImGui::PopItemWidth(); + switch (CVar_GetS32("gRandomizeShuffleKeyRings", 0)) { + case 2: + ImGui::Dummy(ImVec2(0.0f, 0.0f)); + UIWidgets::EnhancementSliderInt("Key Ring Count: %d", "##RandomizeShuffleKeyRingsRandomCount", + "gRandomizeShuffleKeyRingsRandomCount", 1, 8, "", 8, true); + break; + case 3: + UIWidgets::EnhancementCheckbox("Forest Temple##RandomizeShuffleKeyRings", "gRandomizeShuffleKeyRingsForestTemple"); + UIWidgets::EnhancementCheckbox("Fire Temple##RandomizeShuffleKeyRings", "gRandomizeShuffleKeyRingsFireTemple"); + UIWidgets::EnhancementCheckbox("Water Temple##RandomizeShuffleKeyRings", "gRandomizeShuffleKeyRingsWaterTemple"); + UIWidgets::EnhancementCheckbox("Spirit Temple##RandomizeShuffleKeyRings", "gRandomizeShuffleKeyRingsSpiritTemple"); + UIWidgets::EnhancementCheckbox("Shadow Temple##RandomizeShuffleKeyRings", "gRandomizeShuffleKeyRingsShadowTemple"); + UIWidgets::EnhancementCheckbox("Bottom of the Well##RandomizeShuffleKeyRings", "gRandomizeShuffleKeyRingsBottomOfTheWell"); + UIWidgets::EnhancementCheckbox("GTG##RandomizeShuffleKeyRings", "gRandomizeShuffleKeyRingsGTG"); + UIWidgets::EnhancementCheckbox("Ganon's Castle##RandomizeShuffleKeyRings", "gRandomizeShuffleKeyRingsGanonsCastle"); + break; + default: + break; + } + ImGui::PushItemWidth(-FLT_MIN); + UIWidgets::PaddedSeparator(); // Gerudo Keys @@ -4066,6 +4105,34 @@ void Randomizer::CreateCustomMessages() { GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rGanon's Castle &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %Château de Ganon%w!"), + GIMESSAGE_NO_GERMAN(RG_GERUDO_FORTRESS_KEY_RING, ITEM_KEY_SMALL, + "You found a %yThieves Hideout &%wKeyring!", + "Vous obtenez un trousseau de&clés du %yRepaire des Voleurs%w!"), + GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_KEY_RING, ITEM_KEY_SMALL, + "You found a %gForest Temple &%wKeyring!", + "Vous obtenez un trousseau de&clés du %gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_KEY_RING, ITEM_KEY_SMALL, + "You found a %rFire Temple &%wKeyring!", + "Vous obtenez un trousseau de&clés du %rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_KEY_RING, ITEM_KEY_SMALL, + "You found a %bWater Temple &%wKeyring!", + "Vous obtenez un trousseau de&clés du %bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_KEY_RING, ITEM_KEY_SMALL, + "You found a %ySpirit Temple &%wKeyring!", + "Vous obtenez un trousseau de&clés du %yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_KEY_RING, ITEM_KEY_SMALL, + "You found a %pShadow Temple &%wKeyring!", + "Vous obtenez un trousseau de&clés du %pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_KEY_RING, ITEM_KEY_SMALL, + "You found a %pBottom of the &Well %wKeyring!", + "Vous obtenez un trousseau de&clés du %pPuits%w!"), + GIMESSAGE_NO_GERMAN(RG_GERUDO_TRAINING_GROUNDS_KEY_RING, ITEM_KEY_SMALL, + "You found a %yGerudo Training &Grounds %wKeyring!", + "Vous obtenez un trousseau de&clés du %yGymnase Gerudo%w!"), + GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_KEY_RING, ITEM_KEY_SMALL, + "You found a %rGanon's Castle &%wKeyring!", + "Vous obtenez un trousseau de&clés du %rChâteau de Ganon%w!"), + GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %gForest Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%gTemple de la Forêt%w!"), GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rFire Temple &%wBoss Key!", @@ -4201,6 +4268,15 @@ void InitRandoItemTable() { GET_ITEM(RG_BOTTOM_OF_THE_WELL_SMALL_KEY, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_BOTTOM_OF_THE_WELL_SMALL_KEY), GET_ITEM(RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY), GET_ITEM(RG_GANONS_CASTLE_SMALL_KEY, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_GANONS_CASTLE_SMALL_KEY), + GET_ITEM(RG_GERUDO_FORTRESS_KEY_RING, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_GERUDO_FORTRESS_KEY_RING), + GET_ITEM(RG_FOREST_TEMPLE_KEY_RING, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_FOREST_TEMPLE_KEY_RING), + GET_ITEM(RG_FIRE_TEMPLE_KEY_RING, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_FIRE_TEMPLE_KEY_RING), + GET_ITEM(RG_WATER_TEMPLE_KEY_RING, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_WATER_TEMPLE_KEY_RING), + GET_ITEM(RG_SPIRIT_TEMPLE_KEY_RING, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_SPIRIT_TEMPLE_KEY_RING), + GET_ITEM(RG_SHADOW_TEMPLE_KEY_RING, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_SHADOW_TEMPLE_KEY_RING), + GET_ITEM(RG_BOTTOM_OF_THE_WELL_KEY_RING, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_BOTTOM_OF_THE_WELL_KEY_RING), + GET_ITEM(RG_GERUDO_TRAINING_GROUNDS_KEY_RING, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_GERUDO_TRAINING_GROUNDS_KEY_RING), + GET_ITEM(RG_GANONS_CASTLE_KEY_RING, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_SMALL_KEY, MOD_RANDOMIZER, RG_GANONS_CASTLE_KEY_RING), GET_ITEM(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, RG_FOREST_TEMPLE_BOSS_KEY), GET_ITEM(RG_FIRE_TEMPLE_BOSS_KEY, OBJECT_GI_BOSSKEY, GID_KEY_BOSS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_BOSS_KEY, MOD_RANDOMIZER, RG_FIRE_TEMPLE_BOSS_KEY), GET_ITEM(RG_WATER_TEMPLE_BOSS_KEY, OBJECT_GI_BOSSKEY, GID_KEY_BOSS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_BOSS_KEY, MOD_RANDOMIZER, RG_WATER_TEMPLE_BOSS_KEY), @@ -4238,6 +4314,8 @@ void InitRandoItemTable() { if (randoGetItemTable[i].itemId >= RG_FOREST_TEMPLE_SMALL_KEY && randoGetItemTable[i].itemId <= RG_GANONS_CASTLE_SMALL_KEY && randoGetItemTable[i].itemId != RG_GERUDO_FORTRESS_SMALL_KEY) { randoGetItemTable[i].drawFunc = (CustomDrawFunc)Randomizer_DrawSmallKey; + } else if (randoGetItemTable[i].itemId >= RG_FOREST_TEMPLE_KEY_RING && randoGetItemTable[i].itemId <= RG_GANONS_CASTLE_KEY_RING) { + randoGetItemTable[i].drawFunc = (CustomDrawFunc)Randomizer_DrawKeyRing; } else if (randoGetItemTable[i].itemId >= RG_FOREST_TEMPLE_BOSS_KEY && randoGetItemTable[i].itemId <= RG_GANONS_CASTLE_BOSS_KEY) { randoGetItemTable[i].drawFunc = (CustomDrawFunc)Randomizer_DrawBossKey; } else if (randoGetItemTable[i].itemId == RG_DOUBLE_DEFENSE) { diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 2ddfc2f8f..c516a92d9 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1041,6 +1041,16 @@ typedef enum { RSK_LACS_REWARD_COUNT, RSK_LACS_DUNGEON_COUNT, RSK_LACS_TOKEN_COUNT, + RSK_KEYRINGS, + RSK_KEYRINGS_RANDOM_COUNT, + RSK_KEYRINGS_FOREST_TEMPLE, + RSK_KEYRINGS_FIRE_TEMPLE, + RSK_KEYRINGS_WATER_TEMPLE, + RSK_KEYRINGS_SPIRIT_TEMPLE, + RSK_KEYRINGS_SHADOW_TEMPLE, + RSK_KEYRINGS_BOTTOM_OF_THE_WELL, + RSK_KEYRINGS_GTG, + RSK_KEYRINGS_GANONS_CASTLE, RSK_MAX } RandomizerSettingKey; diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index f81d97381..b19ba1631 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2356,10 +2356,12 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { } } } else if ((item >= RG_FOREST_TEMPLE_SMALL_KEY && item <= RG_GANONS_CASTLE_SMALL_KEY) || + (item >= RG_FOREST_TEMPLE_KEY_RING && item <= RG_GANONS_CASTLE_KEY_RING) || (item >= RG_FOREST_TEMPLE_BOSS_KEY && item <= RG_GANONS_CASTLE_BOSS_KEY) || (item >= RG_DEKU_TREE_MAP && item <= RG_ICE_CAVERN_MAP) || (item >= RG_DEKU_TREE_COMPASS && item <= RG_ICE_CAVERN_COMPASS)) { int mapIndex = gSaveContext.mapIndex; + int numOfKeysOnKeyring = 0; switch (item) { case RG_DEKU_TREE_MAP: case RG_DEKU_TREE_COMPASS: @@ -2376,37 +2378,49 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { case RG_FOREST_TEMPLE_MAP: case RG_FOREST_TEMPLE_COMPASS: case RG_FOREST_TEMPLE_SMALL_KEY: + case RG_FOREST_TEMPLE_KEY_RING: case RG_FOREST_TEMPLE_BOSS_KEY: mapIndex = SCENE_BMORI1; + numOfKeysOnKeyring = FOREST_TEMPLE_SMALL_KEY_MAX; break; case RG_FIRE_TEMPLE_MAP: case RG_FIRE_TEMPLE_COMPASS: case RG_FIRE_TEMPLE_SMALL_KEY: + case RG_FIRE_TEMPLE_KEY_RING: case RG_FIRE_TEMPLE_BOSS_KEY: mapIndex = SCENE_HIDAN; + numOfKeysOnKeyring = FIRE_TEMPLE_SMALL_KEY_MAX; break; case RG_WATER_TEMPLE_MAP: case RG_WATER_TEMPLE_COMPASS: case RG_WATER_TEMPLE_SMALL_KEY: + case RG_WATER_TEMPLE_KEY_RING: case RG_WATER_TEMPLE_BOSS_KEY: mapIndex = SCENE_MIZUSIN; + numOfKeysOnKeyring = WATER_TEMPLE_SMALL_KEY_MAX; break; case RG_SPIRIT_TEMPLE_MAP: case RG_SPIRIT_TEMPLE_COMPASS: case RG_SPIRIT_TEMPLE_SMALL_KEY: + case RG_SPIRIT_TEMPLE_KEY_RING: case RG_SPIRIT_TEMPLE_BOSS_KEY: mapIndex = SCENE_JYASINZOU; + numOfKeysOnKeyring = SPIRIT_TEMPLE_SMALL_KEY_MAX; break; case RG_SHADOW_TEMPLE_MAP: case RG_SHADOW_TEMPLE_COMPASS: case RG_SHADOW_TEMPLE_SMALL_KEY: + case RG_SHADOW_TEMPLE_KEY_RING: case RG_SHADOW_TEMPLE_BOSS_KEY: mapIndex = SCENE_HAKADAN; + numOfKeysOnKeyring = SHADOW_TEMPLE_SMALL_KEY_MAX; break; case RG_BOTTOM_OF_THE_WELL_MAP: case RG_BOTTOM_OF_THE_WELL_COMPASS: case RG_BOTTOM_OF_THE_WELL_SMALL_KEY: + case RG_BOTTOM_OF_THE_WELL_KEY_RING: mapIndex = SCENE_HAKADANCH; + numOfKeysOnKeyring = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; break; case RG_ICE_CAVERN_MAP: case RG_ICE_CAVERN_COMPASS: @@ -2416,13 +2430,19 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { mapIndex = SCENE_GANON; break; case RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY: + case RG_GERUDO_TRAINING_GROUNDS_KEY_RING: mapIndex = SCENE_MEN; + numOfKeysOnKeyring = GERUDO_TRAINING_GROUNDS_SMALL_KEY_MAX; break; case RG_GERUDO_FORTRESS_SMALL_KEY: + case RG_GERUDO_FORTRESS_KEY_RING: mapIndex = SCENE_GERUDOWAY; + numOfKeysOnKeyring = GERUDO_FORTRESS_SMALL_KEY_MAX; break; case RG_GANONS_CASTLE_SMALL_KEY: + case RG_GANONS_CASTLE_KEY_RING: mapIndex = SCENE_GANONTIKA; + numOfKeysOnKeyring = GERUDO_FORTRESS_SMALL_KEY_MAX; break; } @@ -2434,6 +2454,9 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { gSaveContext.inventory.dungeonKeys[mapIndex]++; return RG_NONE; } + } else if ((item >= RG_FOREST_TEMPLE_KEY_RING) && (item <= RG_GANONS_CASTLE_KEY_RING)) { + gSaveContext.inventory.dungeonKeys[mapIndex] = numOfKeysOnKeyring; + return RG_NONE; } else { int bitmask; if ((item >= RG_DEKU_TREE_MAP) && (item <= RG_ICE_CAVERN_MAP)) {