Implement keyrings (#1869)

* Implement keyrings

* ADD: French GIMessage

* Remove cvar include

* Rename maxKeys to numOfKeysOnKeyring

Co-authored-by: PurpleHato <linkvssangoku.jr@gmail.com>
This commit is contained in:
Garrett Cox 2022-11-02 10:36:02 -05:00 committed by GitHub
parent fb0b71ea54
commit dda4a13bc3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 207 additions and 15 deletions

View File

@ -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()) {

View File

@ -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<uint8_t> 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<uint8_t>() : 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();
}

View File

@ -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<RandomizerSettingKey, uint8_t> cvarSettin
extern Option LACSDungeonCount;
extern Option LACSTokenCount;
extern Option KeyRings;
extern Option KeyRingsRandomCount;
extern Option RingFortress;
extern Option RingForest;
extern Option RingFire;

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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)) {