diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index 0dc1cb095cd..66983a3f181 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -9,6 +9,7 @@ #include "spoiler_log.hpp" #include "soh/Enhancements/randomizer/Traps.h" #include "z64item.h" +#include "../static_data.h" #include #include @@ -267,42 +268,29 @@ void GenerateItemPool() { // add extra songs only if song shuffle is anywhere if (ctx->GetOption(RSK_SHUFFLE_SONGS).IsNot(RO_SONG_SHUFFLE_OFF)) { bool songAnywhere = ctx->GetOption(RSK_SHUFFLE_SONGS).Is(RO_SONG_SHUFFLE_ANYWHERE); - if (!ctx->GetOption(RSK_STARTING_ZELDAS_LULLABY).Get()) { - AddItemToPool(RG_ZELDAS_LULLABY, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } - if (!ctx->GetOption(RSK_STARTING_EPONAS_SONG).Get()) { - AddItemToPool(RG_EPONAS_SONG, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } - if (!ctx->GetOption(RSK_STARTING_SARIAS_SONG).Get()) { - AddItemToPool(RG_SARIAS_SONG, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } - if (!ctx->GetOption(RSK_STARTING_SUNS_SONG).Get()) { - AddItemToPool(RG_SUNS_SONG, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } - if (!ctx->GetOption(RSK_STARTING_SONG_OF_TIME).Get()) { - AddItemToPool(RG_SONG_OF_TIME, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } - if (!ctx->GetOption(RSK_STARTING_SONG_OF_STORMS).Get()) { - AddItemToPool(RG_SONG_OF_STORMS, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } - if (!ctx->GetOption(RSK_STARTING_MINUET_OF_FOREST).Get()) { - AddItemToPool(RG_MINUET_OF_FOREST, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } - if (!ctx->GetOption(RSK_STARTING_BOLERO_OF_FIRE).Get()) { - AddItemToPool(RG_BOLERO_OF_FIRE, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } - if (!ctx->GetOption(RSK_STARTING_SERENADE_OF_WATER).Get()) { - AddItemToPool(RG_SERENADE_OF_WATER, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } - if (!ctx->GetOption(RSK_STARTING_REQUIEM_OF_SPIRIT).Get()) { - AddItemToPool(RG_REQUIEM_OF_SPIRIT, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } - if (!ctx->GetOption(RSK_STARTING_NOCTURNE_OF_SHADOW).Get()) { - AddItemToPool(RG_NOCTURNE_OF_SHADOW, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } - if (!ctx->GetOption(RSK_STARTING_PRELUDE_OF_LIGHT).Get()) { - AddItemToPool(RG_PRELUDE_OF_LIGHT, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); - } + auto addShuffledSong = [&](RandomizerGet progSong, bool hasStarting) { + SongData song = Rando::StaticData::songData[progSong]; + if (hasStarting) { + return; + } + if (!ctx->GetOption(RSK_SPLIT_OCARINA_SONGS).Get()) { + AddItemToPool(song.realSong, songAnywhere ? 2 : 1, 1, 1, 1, songAnywhere); + } else { + AddItemToPool(progSong, 3, 2, 2, 2, songAnywhere); + } + }; + addShuffledSong(RG_PROGRESSIVE_ZELDAS_LULLABY, ctx->GetOption(RSK_STARTING_ZELDAS_LULLABY).Get()); + addShuffledSong(RG_PROGRESSIVE_EPONAS_SONG, ctx->GetOption(RSK_STARTING_EPONAS_SONG).Get()); + addShuffledSong(RG_PROGRESSIVE_SARIAS_SONG, ctx->GetOption(RSK_STARTING_SARIAS_SONG).Get()); + addShuffledSong(RG_PROGRESSIVE_SUNS_SONG, ctx->GetOption(RSK_STARTING_SUNS_SONG).Get()); + addShuffledSong(RG_PROGRESSIVE_SONG_OF_TIME, ctx->GetOption(RSK_STARTING_SONG_OF_TIME).Get()); + addShuffledSong(RG_PROGRESSIVE_SONG_OF_STORMS, ctx->GetOption(RSK_STARTING_SONG_OF_STORMS).Get()); + addShuffledSong(RG_PROGRESSIVE_MINUET_OF_FOREST, ctx->GetOption(RSK_STARTING_MINUET_OF_FOREST).Get()); + addShuffledSong(RG_PROGRESSIVE_BOLERO_OF_FIRE, ctx->GetOption(RSK_STARTING_BOLERO_OF_FIRE).Get()); + addShuffledSong(RG_PROGRESSIVE_SERENADE_OF_WATER, ctx->GetOption(RSK_STARTING_SERENADE_OF_WATER).Get()); + addShuffledSong(RG_PROGRESSIVE_REQUIEM_OF_SPIRIT, ctx->GetOption(RSK_STARTING_REQUIEM_OF_SPIRIT).Get()); + addShuffledSong(RG_PROGRESSIVE_NOCTURNE_OF_SHADOW, ctx->GetOption(RSK_STARTING_NOCTURNE_OF_SHADOW).Get()); + addShuffledSong(RG_PROGRESSIVE_PRELUDE_OF_LIGHT, ctx->GetOption(RSK_STARTING_PRELUDE_OF_LIGHT).Get()); } else { ctx->PlaceItemInLocation(RC_SHEIK_IN_FOREST, RG_MINUET_OF_FOREST, false, true); ctx->PlaceItemInLocation(RC_SHEIK_IN_CRATER, RG_BOLERO_OF_FIRE, false, true); diff --git a/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp b/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp index a7fe551020b..53edf74c579 100644 --- a/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp @@ -115,6 +115,20 @@ void GenerateStartingInventory() { if (ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG)) { AddItemToInventory(RG_WEIRD_EGG, ctx->GetOption(RSK_STARTING_WEIRD_EGG) ? 1 : 0); } + if (!ctx->GetOption(RSK_SPLIT_OCARINA_SONGS)) { + AddItemToInventory(RG_PROGRESSIVE_ZELDAS_LULLABY, 1); + AddItemToInventory(RG_PROGRESSIVE_EPONAS_SONG, 1); + AddItemToInventory(RG_PROGRESSIVE_SARIAS_SONG, 1); + AddItemToInventory(RG_PROGRESSIVE_SUNS_SONG, 1); + AddItemToInventory(RG_PROGRESSIVE_SONG_OF_TIME, 1); + AddItemToInventory(RG_PROGRESSIVE_SONG_OF_STORMS, 1); + AddItemToInventory(RG_PROGRESSIVE_MINUET_OF_FOREST, 1); + AddItemToInventory(RG_PROGRESSIVE_BOLERO_OF_FIRE, 1); + AddItemToInventory(RG_PROGRESSIVE_SERENADE_OF_WATER, 1); + AddItemToInventory(RG_PROGRESSIVE_REQUIEM_OF_SPIRIT, 1); + AddItemToInventory(RG_PROGRESSIVE_NOCTURNE_OF_SHADOW, 1); + AddItemToInventory(RG_PROGRESSIVE_PRELUDE_OF_LIGHT, 1); + } AddItemToInventory(RG_BUNNY_HOOD, ctx->GetOption(RSK_STARTING_BUNNY_HOOD) ? 1 : 0); AddItemToInventory(RG_CLAIM_CHECK, ctx->GetOption(RSK_STARTING_CLAIM_CHECK) ? 1 : 0); AddItemToInventory(RG_PROGRESSIVE_OCARINA, ctx->GetOption(RSK_STARTING_OCARINA).Get()); diff --git a/soh/soh/Enhancements/randomizer/Traps.cpp b/soh/soh/Enhancements/randomizer/Traps.cpp index 3e06735039d..009f1635376 100644 --- a/soh/soh/Enhancements/randomizer/Traps.cpp +++ b/soh/soh/Enhancements/randomizer/Traps.cpp @@ -4,6 +4,7 @@ #include "soh/Enhancements/randomizer/static_data.h" #include "soh/ShipUtils.h" +#include #include "soh/Enhancements/randomizer/3drando/random.hpp" #include @@ -359,6 +360,69 @@ static void InitTrickNames() { Text{ "Progressive Flute", "Flûte (prog.)", "Flöte (prog.)" }, // "Flauta progresiva" Text{ "Progressive Recorder", "Harmonica (prog.)", "Rekorder (prog.)" }, // "Armónica progresiva" }; + trickNameTable[RG_PROGRESSIVE_ZELDAS_LULLABY] = { + Text{ "Progressive Ballad of the Goddess", "Berceuse (prog.)", "Progressives Wiegenlied" }, + Text{ "Progressive Song of Healing", "Chant de l'apaisement (prog.)", "Progressives Heilungslied" }, + Text{ "Progressive Song of the Hero", "Chant du héros (prog.)", "Progressives Heldenlied" }, + }; + trickNameTable[RG_PROGRESSIVE_EPONAS_SONG] = { + Text{ "Progressive Song of Birds", "Chant d'Epona (prog.)", "Progressives Eponas Lied" }, + Text{ "Progressive Song of Soaring", "Chant de l'envol (prog.)", "Progressives Lied der Schwingen" }, + Text{ "Progressive Song of Horse", "Chant du cheval (prog.)", "Progressives Pferdelied" }, + }; + trickNameTable[RG_PROGRESSIVE_SARIAS_SONG] = { + Text{ "Progressive Mido's Song", "Chant de Saria (prog.)", "Progressives Salias Lied" }, + Text{ "Progressive Kass' Theme", "Chant de Kass (prog.)", "Progressives Kashiwas Thema" }, + Text{ "Progressive Tune of Echoes", "Chant des Échos (prog.)", "Progressive Melodie des Echos" }, + }; + trickNameTable[RG_PROGRESSIVE_SUNS_SONG] = { + Text{ "Progressive Song of Passing", "Chant du Soleil (prog.)", "Progressiver Hymne der Sonne" }, + Text{ "Progressive Command Melody", "Mambo (prog.)", "Progressive Tag- und Nachtmusik" }, + Text{ "Progressive Moon's Song", "Chant de la lune (prog.)", "Progressives Mondlied" }, + }; + trickNameTable[RG_PROGRESSIVE_SONG_OF_TIME] = { + Text{ "Progressive Song of Double Time", "Chant du Temps (prog.)", "Progressiver Hymne der Zeit" }, + Text{ "Progressive Inverted Song of Time", "Chant du temps inversé (prog.)", "Progressive Ballade des Kronos" }, + Text{ "Progressive Tune of Ages", "Chant du Temps (prog.)", "Progressive Melodie der Zeit" }, + }; + trickNameTable[RG_PROGRESSIVE_SONG_OF_STORMS] = { + Text{ "Progressive Ballad of Gales", "Chant des Tempêtes (prog.)", "Progressiver Hymne des Sturms" }, + Text{ "Progressive Frog's Song of Soul", "Rap des grenouilles (prog.)", "Progressiver Krötenrap" }, + Text{ "Progressive Wind's Requiem", "Mélodie du vent (prog.)", "Progressives Lied des Windes" }, + }; + trickNameTable[RG_PROGRESSIVE_MINUET_OF_FOREST] = { + Text{ "Progressive Saria's Karaoke", "Menuet des Bois (prog.)", "Progressives Menuett des Waldes" }, + Text{ "Progressive Sonata of Awakening", "Sonate de l'éveil (prog.)", "Progressive Sonate des Erwachens" }, + Text{ "Progressive Wind God's Aria", "Hymne du dieu du vent (prog.)", "Progressive Hymne des Zephirgottes" }, + }; + trickNameTable[RG_PROGRESSIVE_BOLERO_OF_FIRE] = { + Text{ "Progressive Darunia's Tango", "Boléro du Feu (prog.)", "Progressives Bolero des Feuers" }, + Text{ "Progressive Tune of Currents", "Chants des Flux (prog.)", "Progressives Lied des Zeitstroms" }, + Text{ "Progressive Goron Lullaby", "Berceuse des Gorons (prog.)", "Progressives Goronisches Schlummerlied" }, + }; + trickNameTable[RG_PROGRESSIVE_SERENADE_OF_WATER] = { + Text{ "Progressive Ruto's Blues", "Sérénade de l'Eau (prog.)", "Progressive Serenade des Wassers" }, + Text{ "Progressive New Wave Bossa Nova", "Bossa-nova des flots (prog.)", + "Progressive Bossa Nova der Kaskaden" }, + Text{ "Progressive Manbo's Mambo", "Mambo de Manbo (prog.)", "Progressives Manbos Mambo" }, + }; + trickNameTable[RG_PROGRESSIVE_REQUIEM_OF_SPIRIT] = { + Text{ "Progressive Nabooru's Reggae", "Requiem des Esprits (prog.)", "Progressives Requiem der Geister" }, + Text{ "Progressive Elegy of Emptiness", "Hymne du vide (prog.)", "Progressive Elegie des leeren Herzens" }, + Text{ "Progressive Earth God's Lyric", "Hymne du dieu de la terre (prog.)", + "Progressive Hymne des Terragottes" }, + }; + trickNameTable[RG_PROGRESSIVE_NOCTURNE_OF_SHADOW] = { + Text{ "Progressive Impa's Death Metal", "Nocturne de l'Ombre (prog.)", "Progressive Nocturne des Schattens" }, + Text{ "Progressive Oath to Order", "Ode de l'appel (prog.)", "Progressiver Gesang des Himmels" }, + Text{ "Progressive Song of Discovery", "Chant des secrets (prog.)", "Progressives Schatzsucherlied" }, + }; + trickNameTable[RG_PROGRESSIVE_PRELUDE_OF_LIGHT] = { + Text{ "Progressive Rauru's Sing-Along", "Prélude de la Lumière (prog.)", "Progressive Kantate des Lichts" }, + Text{ "Progressive Ballad of the Wind Fish", "Ballade sur Poisson-Rêve (prog.)", + "Progressive Ballade vom Windfisch" }, + Text{ "Progressive Song of Light", "Chant de la lumière (prog.)", "Progressives Lied des Lichts" }, + }; trickNameTable[RG_PROGRESSIVE_GORONSWORD] = { Text{ "Progressive Titan Blade", "Lame des Titans (prog.)", "Titanenklinge (prog.)" }, // "Hoja del Titán progresiva" diff --git a/soh/soh/Enhancements/randomizer/item.cpp b/soh/soh/Enhancements/randomizer/item.cpp index 14a35a8d299..c5127cd6d06 100644 --- a/soh/soh/Enhancements/randomizer/item.cpp +++ b/soh/soh/Enhancements/randomizer/item.cpp @@ -374,6 +374,26 @@ std::shared_ptr Item::GetGIEntry() const { // NOLINT(*-no-recursio case RG_PROGRESSIVE_GORONSWORD: // todo progressive? actual = RG_BIGGORON_SWORD; break; + case RG_PROGRESSIVE_ZELDAS_LULLABY: + case RG_PROGRESSIVE_EPONAS_SONG: + case RG_PROGRESSIVE_SARIAS_SONG: + case RG_PROGRESSIVE_SUNS_SONG: + case RG_PROGRESSIVE_SONG_OF_TIME: + case RG_PROGRESSIVE_SONG_OF_STORMS: + case RG_PROGRESSIVE_MINUET_OF_FOREST: + case RG_PROGRESSIVE_BOLERO_OF_FIRE: + case RG_PROGRESSIVE_SERENADE_OF_WATER: + case RG_PROGRESSIVE_REQUIEM_OF_SPIRIT: + case RG_PROGRESSIVE_NOCTURNE_OF_SHADOW: + case RG_PROGRESSIVE_PRELUDE_OF_LIGHT: { + const SongData* song = &StaticData::songData[randomizerGet]; + if (logic->CheckRandoInf(song->randInf)) { + actual = song->realSong; + } else { + actual = song->part; + } + break; + } case RG_PROGRESSIVE_BOMBCHU_BAG: if (OTRGlobals::Instance->gRandoContext->GetOption(RSK_BOMBCHU_BAG).Is(RO_BOMBCHU_BAG_SINGLE)) { if (logic->CurrentInventory(ITEM_BOMBCHU) != ITEM_NONE) { diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp index 378df39b5eb..76919c6ed67 100644 --- a/soh/soh/Enhancements/randomizer/item_list.cpp +++ b/soh/soh/Enhancements/randomizer/item_list.cpp @@ -73,6 +73,18 @@ void Rando::StaticData::InitItemTable() { itemTable[RG_PROGRESSIVE_MAGIC_METER] = Item(RG_PROGRESSIVE_MAGIC_METER, Text{ "Progressive Magic Meter", "Jauge de Magie (prog.)", "Progressives Magisches Maß" }, ITEMTYPE_ITEM, 0x8A, true, LOGIC_PROGRESSIVE_MAGIC, RHT_PROGRESSIVE_MAGIC_METER, ITEM_CATEGORY_MAJOR, {"a ", "une ", "ein "}, "%g", true).CustomIcon(gQuestIconMagicJarBigTex, ICON_SIZE_24); itemTable[RG_PROGRESSIVE_OCARINA] = Item(RG_PROGRESSIVE_OCARINA, Text{ "Progressive Ocarina", "Ocarina (prog.)", "Progressive Okarina" }, ITEMTYPE_ITEM, 0x8B, true, LOGIC_PROGRESSIVE_OCARINA, RHT_PROGRESSIVE_OCARINA, ITEM_CATEGORY_MAJOR, {"a ", "un ", "eine "}, "%g", true); itemTable[RG_PROGRESSIVE_GORONSWORD] = Item(RG_PROGRESSIVE_GORONSWORD, Text{ "Progressive Goron Sword", "Épée Goron (prog.)", "Progressives Goronen-Schwert" }, ITEMTYPE_ITEM, 0xD4, true, LOGIC_PROGRESSIVE_GIANT_KNIFE, RHT_PROGRESSIVE_GORONSWORD, ITEM_CATEGORY_MAJOR, {"a ", "une ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_ZELDAS_LULLABY] = Item(RG_PROGRESSIVE_ZELDAS_LULLABY, Text{ "Progressive Zelda's Lullaby", "Berceuse de Zelda (prog.)", "Progressives Zeldas Wiegenlied" }, ITEMTYPE_ITEM, 0xE1, true, LOGIC_NONE, RHT_ZELDAS_LULLABY, RG_PROGRESSIVE_ZELDAS_LULLABY, OBJECT_GI_MELODY, GID_SONG_ZELDA, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "une ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_EPONAS_SONG] = Item(RG_PROGRESSIVE_EPONAS_SONG, Text{ "Progressive Epona's Song", "Chant d'Epona (prog.)", "Progressives Eponas Lied" }, ITEMTYPE_ITEM, 0xE2, true, LOGIC_NONE, RHT_EPONAS_SONG, RG_PROGRESSIVE_EPONAS_SONG, OBJECT_GI_MELODY, GID_SONG_EPONA, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "un ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_SARIAS_SONG] = Item(RG_PROGRESSIVE_SARIAS_SONG, Text{ "Progressive Saria's Song", "Chant de Saria (prog.)", "Progressives Salias Lied" }, ITEMTYPE_ITEM, 0xE3, true, LOGIC_NONE, RHT_SARIAS_SONG, RG_PROGRESSIVE_SARIAS_SONG, OBJECT_GI_MELODY, GID_SONG_SARIA, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "un ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_SUNS_SONG] = Item(RG_PROGRESSIVE_SUNS_SONG, Text{ "Progressive Sun's Song", "Chant du Soleil (prog.)", "Progressives Hymne der Sonne" }, ITEMTYPE_ITEM, 0xE4, true, LOGIC_NONE, RHT_SUNS_SONG, RG_PROGRESSIVE_SUNS_SONG, OBJECT_GI_MELODY, GID_SONG_SUN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "un ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_SONG_OF_TIME] = Item(RG_PROGRESSIVE_SONG_OF_TIME, Text{ "Progressive Song of Time", "Chant du Temps (prog.)", "Progressives Hymne der Zeit" }, ITEMTYPE_ITEM, 0xE5, true, LOGIC_NONE, RHT_SONG_OF_TIME, RG_PROGRESSIVE_SONG_OF_TIME, OBJECT_GI_MELODY, GID_SONG_TIME, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "un ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_SONG_OF_STORMS] = Item(RG_PROGRESSIVE_SONG_OF_STORMS, Text{ "Progressive Song of Storms", "Chant des Tempêtes (prog.)", "Progressives Hymne des Sturms" }, ITEMTYPE_ITEM, 0xE6, true, LOGIC_NONE, RHT_SONG_OF_STORMS, RG_PROGRESSIVE_SONG_OF_STORMS, OBJECT_GI_MELODY, GID_SONG_STORM, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "un ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_MINUET_OF_FOREST] = Item(RG_PROGRESSIVE_MINUET_OF_FOREST, Text{ "Progressive Minuet of Forest", "Menuet des Bois (prog.)", "Progressives Menuett des Waldes" }, ITEMTYPE_ITEM, 0xE7, true, LOGIC_NONE, RHT_MINUET_OF_FOREST, RG_PROGRESSIVE_MINUET_OF_FOREST, OBJECT_GI_MELODY, GID_SONG_MINUET, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "un ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_BOLERO_OF_FIRE] = Item(RG_PROGRESSIVE_BOLERO_OF_FIRE, Text{ "Progressive Bolero of Fire", "Boléro du Feu (prog.)", "Progressives Bolero des Feuers" }, ITEMTYPE_ITEM, 0xE8, true, LOGIC_NONE, RHT_BOLERO_OF_FIRE, RG_PROGRESSIVE_BOLERO_OF_FIRE, OBJECT_GI_MELODY, GID_SONG_BOLERO, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "un ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_SERENADE_OF_WATER] = Item(RG_PROGRESSIVE_SERENADE_OF_WATER, Text{ "Progressive Serenade of Water", "Sérénade de l'Eau (prog.)", "Progressive Serenade des Wassers" }, ITEMTYPE_ITEM, 0xE9, true, LOGIC_NONE, RHT_SERENADE_OF_WATER, RG_PROGRESSIVE_SERENADE_OF_WATER, OBJECT_GI_MELODY, GID_SONG_SERENADE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "une ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_REQUIEM_OF_SPIRIT] = Item(RG_PROGRESSIVE_REQUIEM_OF_SPIRIT, Text{ "Progressive Requiem of Spirit", "Requiem des Esprits (prog.)", "Progressives Requiem der Geister" }, ITEMTYPE_ITEM, 0xEA, true, LOGIC_NONE, RHT_REQUIEM_OF_SPIRIT, RG_PROGRESSIVE_REQUIEM_OF_SPIRIT, OBJECT_GI_MELODY, GID_SONG_REQUIEM, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "un ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_NOCTURNE_OF_SHADOW] = Item(RG_PROGRESSIVE_NOCTURNE_OF_SHADOW, Text{ "Progressive Nocturne of Shadow", "Nocturne de l'Ombre (prog.)", "Progressive Nocturne des Schattens" }, ITEMTYPE_ITEM, 0xEB, true, LOGIC_NONE, RHT_NOCTURNE_OF_SHADOW, RG_PROGRESSIVE_NOCTURNE_OF_SHADOW, OBJECT_GI_MELODY, GID_SONG_NOCTURNE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "une ", "ein "}, "%g", true); + itemTable[RG_PROGRESSIVE_PRELUDE_OF_LIGHT] = Item(RG_PROGRESSIVE_PRELUDE_OF_LIGHT, Text{ "Progressive Prelude of Light", "Prélude de la Lumière (prog.)", "Progressive Kantate des Lichts" }, ITEMTYPE_ITEM, 0xEC, true, LOGIC_NONE, RHT_PRELUDE_OF_LIGHT, RG_PROGRESSIVE_PRELUDE_OF_LIGHT, OBJECT_GI_MELODY, GID_SONG_PRELUDE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "un ", "ein "}, "%g", true); // Bottles itemTable[RG_EMPTY_BOTTLE] = Item(RG_EMPTY_BOTTLE, Text{ "Empty Bottle", "Bouteille Vide", "Leere Flasche" }, ITEMTYPE_ITEM, GI_BOTTLE, true, LOGIC_BOTTLES, RHT_BOTTLE_WITH_MILK, ITEM_BOTTLE, OBJECT_GI_BOTTLE, GID_BOTTLE, 0x42, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE, {"an ", "une ", "eine "}); itemTable[RG_BOTTLE_WITH_MILK] = Item(RG_BOTTLE_WITH_MILK, Text{ "Bottle with Milk", "Bouteille avec du Lait", "Flasche mit Milch" }, ITEMTYPE_ITEM, GI_MILK_BOTTLE, true, LOGIC_BOTTLES, RHT_BOTTLE_WITH_MILK, ITEM_MILK_BOTTLE, OBJECT_GI_MILK, GID_MILK, 0x98, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_NONE, {"a ", "une ", "eine "}); @@ -453,6 +465,19 @@ void Rando::StaticData::InitItemTable() { itemTable[RG_DEKU_STICK_CAPACITY_30] = Item(RG_DEKU_STICK_CAPACITY_30, Text{ "Deku Stick Capacity (30)", "Capacité de Bâtons Mojo (30)", "Deku-Stab-Kapazität (30)" }, ITEMTYPE_ITEM, GI_STICK_UPGRADE_30, true, LOGIC_PROGRESSIVE_STICK_BAG, RHT_DEKU_STICK_CAPACITY_30, ITEM_STICK_UPGRADE_30, OBJECT_GI_STICK, GID_STICK, 0x91, 0x80, CHEST_ANIM_SHORT, ITEM_CATEGORY_LESSER, MOD_NONE).CustomIcon(gItemIconDekuStickTex); itemTable[RG_MAGIC_SINGLE] = Item(RG_MAGIC_SINGLE, Text{ "Magic Meter", "Jauge de Magie", "Magisches Maß" }, ITEMTYPE_ITEM, 0x8A, true, LOGIC_PROGRESSIVE_MAGIC, RHT_MAGIC_SINGLE, RG_MAGIC_SINGLE, OBJECT_GI_MAGICPOT, GID_MAGIC_SMALL, 0xE4, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"the ", "la ", "das "}).CustomIcon(gQuestIconMagicJarSmallTex, ICON_SIZE_24); itemTable[RG_MAGIC_DOUBLE] = Item(RG_MAGIC_DOUBLE, Text{ "Enhanced Magic Meter", "Jauge de Magie améliorée", "Verbessertes Magisches Maß" }, ITEMTYPE_ITEM, 0x8A, true, LOGIC_PROGRESSIVE_MAGIC, RHT_MAGIC_DOUBLE, RG_MAGIC_DOUBLE, OBJECT_GI_MAGICPOT, GID_MAGIC_LARGE, 0xE8, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_LESSER, MOD_RANDOMIZER, {"the ", "la ", "das "}).CustomIcon(gQuestIconMagicJarBigTex, ICON_SIZE_24); + itemTable[RG_PART_OF_ZELDAS_LULLABY] = Item(RG_PART_OF_ZELDAS_LULLABY, Text{ "Part of Zelda's Lullaby", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xC1, true, LOGIC_ZELDAS_LULLABY, RHT_ZELDAS_LULLABY, RG_PART_OF_ZELDAS_LULLABY, OBJECT_GI_MELODY, GID_SONG_ZELDA, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_PART_OF_EPONAS_SONG] = Item(RG_PART_OF_EPONAS_SONG, Text{ "Part of Epona's Song", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xC2, true, LOGIC_EPONAS_SONG, RHT_EPONAS_SONG, RG_PART_OF_EPONAS_SONG, OBJECT_GI_MELODY, GID_SONG_EPONA, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_PART_OF_SARIAS_SONG] = Item(RG_PART_OF_SARIAS_SONG, Text{ "Part of Saria's Song", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xC3, true, LOGIC_SARIAS_SONG, RHT_SARIAS_SONG, RG_PART_OF_SARIAS_SONG, OBJECT_GI_MELODY, GID_SONG_SARIA, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_PART_OF_SUNS_SONG] = Item(RG_PART_OF_SUNS_SONG, Text{ "Part of Sun's Song", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xC4, true, LOGIC_SUNS_SONG, RHT_SUNS_SONG, RG_PART_OF_SUNS_SONG, OBJECT_GI_MELODY, GID_SONG_SUN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_PART_OF_SONG_OF_TIME] = Item(RG_PART_OF_SONG_OF_TIME, Text{ "Part of Song of Time", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xC5, true, LOGIC_SONG_OF_TIME, RHT_SONG_OF_TIME, RG_PART_OF_SONG_OF_TIME, OBJECT_GI_MELODY, GID_SONG_TIME, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_PART_OF_SONG_OF_STORMS] = Item(RG_PART_OF_SONG_OF_STORMS, Text{ "Part of Song of Storms", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xC6, true, LOGIC_SONG_OF_STORMS, RHT_SONG_OF_STORMS, RG_PART_OF_SONG_OF_STORMS, OBJECT_GI_MELODY, GID_SONG_STORM, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_PART_OF_MINUET_OF_FOREST] = Item(RG_PART_OF_MINUET_OF_FOREST, Text{ "Part of Minuet of Forest", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xBB, true, LOGIC_MINUET_OF_FOREST, RHT_MINUET_OF_FOREST, RG_PART_OF_MINUET_OF_FOREST, OBJECT_GI_MELODY, GID_SONG_MINUET, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_PART_OF_BOLERO_OF_FIRE] = Item(RG_PART_OF_BOLERO_OF_FIRE, Text{ "Part of Bolero of Fire", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xBC, true, LOGIC_BOLERO_OF_FIRE, RHT_BOLERO_OF_FIRE, RG_PART_OF_BOLERO_OF_FIRE, OBJECT_GI_MELODY, GID_SONG_BOLERO, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_PART_OF_SERENADE_OF_WATER] = Item(RG_PART_OF_SERENADE_OF_WATER, Text{ "Part of Serenade of Water", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xBD, true, LOGIC_SERENADE_OF_WATER, RHT_SERENADE_OF_WATER, RG_PART_OF_SERENADE_OF_WATER, OBJECT_GI_MELODY, GID_SONG_SERENADE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_PART_OF_NOCTURNE_OF_SHADOW] = Item(RG_PART_OF_NOCTURNE_OF_SHADOW, Text{ "Part of Nocturne of Shadow", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xBF, true, LOGIC_NOCTURNE_OF_SHADOW, RHT_NOCTURNE_OF_SHADOW, RG_PART_OF_NOCTURNE_OF_SHADOW, OBJECT_GI_MELODY, GID_SONG_NOCTURNE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_PART_OF_REQUIEM_OF_SPIRIT] = Item(RG_PART_OF_REQUIEM_OF_SPIRIT, Text{ "Part of Requiem of Spirit", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xBE, true, LOGIC_REQUIEM_OF_SPIRIT, RHT_REQUIEM_OF_SPIRIT, RG_PART_OF_REQUIEM_OF_SPIRIT, OBJECT_GI_MELODY, GID_SONG_REQUIEM, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_PART_OF_PRELUDE_OF_LIGHT] = Item(RG_PART_OF_PRELUDE_OF_LIGHT, Text{ "Part of Prelude of Light", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, 0xC0, true, LOGIC_PRELUDE_OF_LIGHT, RHT_PRELUDE_OF_LIGHT, RG_PART_OF_PRELUDE_OF_LIGHT, OBJECT_GI_MELODY, GID_SONG_PRELUDE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"", "", ""}); + itemTable[RG_TRIFORCE_PIECE] = Item(RG_TRIFORCE_PIECE, Text{ "Triforce Piece", "Morceau de Triforce", "Triforce-Fragment" }, ITEMTYPE_ITEM, 0xDF, true, LOGIC_TRIFORCE_PIECES, RHT_TRIFORCE_PIECE, RG_TRIFORCE_PIECE, OBJECT_GI_BOMB_2, GID_TRIFORCE_PIECE, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "un ", "ein "}).CustomIcon(gTriforcePieceTex); itemTable[RG_ROCS_FEATHER] = Item(RG_ROCS_FEATHER, Text{ "Roc's Feather", "Plume de Roc", "Grefenfeider" }, ITEMTYPE_ITEM, 0xE0, true, LOGIC_ROCS_FEATHER, RHT_ROCS_FEATHER, RG_ROCS_FEATHER, OBJECT_GI_BOMB_2, GID_STONE_OF_AGONY, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "la ", "ein "}).CustomIcon(gRocsFeatherTex); itemTable[RG_ROCS_FEATHER].SetCustomDrawFunc(Randomizer_DrawRocsFeather); diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index 30daebc8abd..6060f4fe247 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -1835,6 +1835,18 @@ std::map StaticData::RandoGetToRandInf = { { RG_BACK_TOWER_KEY, RAND_INF_BACK_TOWER_KEY_OBTAINED }, { RG_HYLIA_LAB_KEY, RAND_INF_HYLIA_LAB_KEY_OBTAINED }, { RG_FISHING_HOLE_KEY, RAND_INF_FISHING_HOLE_KEY_OBTAINED }, + { RG_PART_OF_ZELDAS_LULLABY, RAND_INF_SPLIT_ZL_PART }, + { RG_PART_OF_EPONAS_SONG, RAND_INF_SPLIT_EPONA_PART }, + { RG_PART_OF_SARIAS_SONG, RAND_INF_SPLIT_SARIA_PART }, + { RG_PART_OF_SUNS_SONG, RAND_INF_SPLIT_SUN_PART }, + { RG_PART_OF_SONG_OF_TIME, RAND_INF_SPLIT_TIME_PART }, + { RG_PART_OF_SONG_OF_STORMS, RAND_INF_SPLIT_STORMS_PART }, + { RG_PART_OF_MINUET_OF_FOREST, RAND_INF_SPLIT_MINUET_PART }, + { RG_PART_OF_BOLERO_OF_FIRE, RAND_INF_SPLIT_BOLERO_PART }, + { RG_PART_OF_SERENADE_OF_WATER, RAND_INF_SPLIT_SERENADE_PART }, + { RG_PART_OF_REQUIEM_OF_SPIRIT, RAND_INF_SPLIT_REQUIEM_PART }, + { RG_PART_OF_NOCTURNE_OF_SHADOW, RAND_INF_SPLIT_NOCTURNE_PART }, + { RG_PART_OF_PRELUDE_OF_LIGHT, RAND_INF_SPLIT_PRELUDE_PART }, }; std::map Logic::RandoGetToDungeonScene = { @@ -2169,6 +2181,25 @@ void Logic::ApplyItemEffect(Item& item, bool state) { } SetInventory(ITEM_OCARINA_FAIRY, OcarinaLookup[i]); } break; + case RG_PROGRESSIVE_ZELDAS_LULLABY: + case RG_PROGRESSIVE_EPONAS_SONG: + case RG_PROGRESSIVE_SARIAS_SONG: + case RG_PROGRESSIVE_SONG_OF_TIME: + case RG_PROGRESSIVE_SUNS_SONG: + case RG_PROGRESSIVE_SONG_OF_STORMS: + case RG_PROGRESSIVE_MINUET_OF_FOREST: + case RG_PROGRESSIVE_BOLERO_OF_FIRE: + case RG_PROGRESSIVE_SERENADE_OF_WATER: + case RG_PROGRESSIVE_REQUIEM_OF_SPIRIT: + case RG_PROGRESSIVE_NOCTURNE_OF_SHADOW: + case RG_PROGRESSIVE_PRELUDE_OF_LIGHT: { + const SongData* song = &StaticData::songData[randoGet]; + if (CheckRandoInf(song->randInf)) { + SetQuestItem(song->quest, state); + } else { + SetRandoInf(song->randInf, state); + } + } case RG_HEART_CONTAINER: mSaveContext->healthCapacity += (!state ? -16 : 16); break; diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index a6b4b5a12c0..e02a98f1076 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -222,6 +222,10 @@ void Settings::CreateOptionDescriptions() { " - Gerudo Training Ground's Ice Arrows location\n" "\n" "Anywhere - Songs can appear at any location."; + mOptionDescriptions[RSK_SPLIT_OCARINA_SONGS] = + "Each ocarina song is shuffled as a progressive item, (2 Pieces). The first pickup marks progress for that " + "song. The second pickup grants the full song.\n\n" + "Requires Shuffle Songs set to Anywhere."; mOptionDescriptions[RSK_SHUFFLE_TOKENS] = "Shuffles Golden Skulltula Tokens into the item pool. This means " "Golden Skulltulas can contain other items as well.\n" "\n" diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index b5376c5c20f..21c205637bc 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -511,28 +511,40 @@ ItemObtainability Randomizer::GetItemObtainabilityFromRandomizerGet(RandomizerGe return !Flags_GetRandomizerInf(RAND_INF_FISHING_POLE_FOUND) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; // Songs + case RG_PROGRESSIVE_ZELDAS_LULLABY: case RG_ZELDAS_LULLABY: return !CHECK_QUEST_ITEM(QUEST_SONG_LULLABY) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_EPONAS_SONG: case RG_EPONAS_SONG: return !CHECK_QUEST_ITEM(QUEST_SONG_EPONA) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_SARIAS_SONG: case RG_SARIAS_SONG: return !CHECK_QUEST_ITEM(QUEST_SONG_SARIA) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_SUNS_SONG: case RG_SUNS_SONG: return !CHECK_QUEST_ITEM(QUEST_SONG_SUN) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_SONG_OF_TIME: case RG_SONG_OF_TIME: return !CHECK_QUEST_ITEM(QUEST_SONG_TIME) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_SONG_OF_STORMS: case RG_SONG_OF_STORMS: return !CHECK_QUEST_ITEM(QUEST_SONG_STORMS) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_MINUET_OF_FOREST: case RG_MINUET_OF_FOREST: return !CHECK_QUEST_ITEM(QUEST_SONG_MINUET) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_BOLERO_OF_FIRE: case RG_BOLERO_OF_FIRE: return !CHECK_QUEST_ITEM(QUEST_SONG_BOLERO) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_SERENADE_OF_WATER: case RG_SERENADE_OF_WATER: return !CHECK_QUEST_ITEM(QUEST_SONG_SERENADE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_REQUIEM_OF_SPIRIT: case RG_REQUIEM_OF_SPIRIT: return !CHECK_QUEST_ITEM(QUEST_SONG_REQUIEM) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_NOCTURNE_OF_SHADOW: case RG_NOCTURNE_OF_SHADOW: return !CHECK_QUEST_ITEM(QUEST_SONG_NOCTURNE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; + case RG_PROGRESSIVE_PRELUDE_OF_LIGHT: case RG_PRELUDE_OF_LIGHT: return !CHECK_QUEST_ITEM(QUEST_SONG_PRELUDE) ? CAN_OBTAIN : CANT_OBTAIN_ALREADY_HAVE; diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerGet.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerGet.h index 3b7806385f6..99ec9441c53 100644 --- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerGet.h +++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerGet.h @@ -66,6 +66,30 @@ RANDO_ENUM_ITEM(RG_MAGIC_SINGLE) // Added for refactor of GetItemEntries RANDO_ENUM_ITEM(RG_MAGIC_DOUBLE) // Added for refactor of GetItemEntries RANDO_ENUM_ITEM(RG_PROGRESSIVE_OCARINA) RANDO_ENUM_ITEM(RG_PROGRESSIVE_GORONSWORD) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_ZELDAS_LULLABY) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_EPONAS_SONG) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_SARIAS_SONG) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_SUNS_SONG) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_SONG_OF_TIME) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_SONG_OF_STORMS) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_MINUET_OF_FOREST) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_BOLERO_OF_FIRE) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_SERENADE_OF_WATER) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_REQUIEM_OF_SPIRIT) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_NOCTURNE_OF_SHADOW) +RANDO_ENUM_ITEM(RG_PROGRESSIVE_PRELUDE_OF_LIGHT) +RANDO_ENUM_ITEM(RG_PART_OF_ZELDAS_LULLABY) +RANDO_ENUM_ITEM(RG_PART_OF_EPONAS_SONG) +RANDO_ENUM_ITEM(RG_PART_OF_SARIAS_SONG) +RANDO_ENUM_ITEM(RG_PART_OF_SUNS_SONG) +RANDO_ENUM_ITEM(RG_PART_OF_SONG_OF_TIME) +RANDO_ENUM_ITEM(RG_PART_OF_SONG_OF_STORMS) +RANDO_ENUM_ITEM(RG_PART_OF_MINUET_OF_FOREST) +RANDO_ENUM_ITEM(RG_PART_OF_BOLERO_OF_FIRE) +RANDO_ENUM_ITEM(RG_PART_OF_SERENADE_OF_WATER) +RANDO_ENUM_ITEM(RG_PART_OF_REQUIEM_OF_SPIRIT) +RANDO_ENUM_ITEM(RG_PART_OF_NOCTURNE_OF_SHADOW) +RANDO_ENUM_ITEM(RG_PART_OF_PRELUDE_OF_LIGHT) RANDO_ENUM_ITEM(RG_EMPTY_BOTTLE) RANDO_ENUM_ITEM(RG_BOTTLE_WITH_MILK) RANDO_ENUM_ITEM(RG_BOTTLE_WITH_RED_POTION) diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h index 6dc342aa1a1..b01bdeec044 100644 --- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h +++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h @@ -2642,6 +2642,18 @@ RANDO_ENUM_ITEM(RAND_INF_OBTAINED_RUTOS_LETTER) RANDO_ENUM_ITEM(RAND_INF_OBTAINED_NAYRUS_LOVE) RANDO_ENUM_ITEM(RAND_INF_OBTAINED_ROCS_FEATHER) RANDO_ENUM_ITEM(RAND_INF_TALON_SENT_MALON_HOME) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_ZL_PART) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_EPONA_PART) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_SARIA_PART) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_SUN_PART) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_TIME_PART) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_STORMS_PART) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_MINUET_PART) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_BOLERO_PART) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_SERENADE_PART) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_REQUIEM_PART) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_NOCTURNE_PART) +RANDO_ENUM_ITEM(RAND_INF_SPLIT_PRELUDE_PART) // Overworld Signs RANDO_ENUM_ITEM(RAND_INF_KF_DEKU_TREE_RECTANGLE_SIGN) diff --git a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h index 6f6ea57ee71..e735cde51fd 100644 --- a/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h +++ b/soh/soh/Enhancements/randomizer/randomizerEnums/RandomizerSettingKey.h @@ -287,6 +287,7 @@ RANDO_ENUM_ITEM(RSK_LOCK_OVERWORLD_DOORS) RANDO_ENUM_ITEM(RSK_SHUFFLE_GRASS) RANDO_ENUM_ITEM(RSK_SHUFFLE_SIGNS) RANDO_ENUM_ITEM(RSK_ROCS_FEATHER) +RANDO_ENUM_ITEM(RSK_SPLIT_OCARINA_SONGS) RANDO_ENUM_ITEM(RSK_SHUFFLE_ICICLES) RANDO_ENUM_ITEM(RSK_SHUFFLE_RED_ICE) RANDO_ENUM_ITEM(RSK_STARTING_BUNNY_HOOD) diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 92bba438bcb..efc18ec886f 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -44,6 +44,13 @@ typedef struct ShopItemIdentity { int32_t itemPrice; } ShopItemIdentity; +struct SongData { + RandomizerGet realSong; + RandomizerGet part; + RandomizerInf randInf; + QuestItem quest; +}; + #define ENTRANCE_GROTTO_LOAD_START 0x0700 #define ENTRANCE_GROTTO_EXIT_START 0x0800 diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp index bc527bc4f81..e3e56c28a4a 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp @@ -1,6 +1,8 @@ #include +#include #include #include +#include #include #include @@ -9,6 +11,8 @@ #include "randomizer_check_tracker.h" #include "randomizer_item_tracker.h" #include "randomizerTypes.h" +#include "static_data.h" +#include "soh/SohGui/ImGuiUtils.h" #include "soh/cvar_prefixes.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/OTRGlobals.h" @@ -478,8 +482,8 @@ bool IsValidSaveFile() { return validSave; } -bool HasSong(ItemTrackerItem item) { - return GameInteractor::IsSaveLoaded() ? ((1 << item.id) & gSaveContext.inventory.questItems) : false; +bool HasSong(QuestItem item) { + return GameInteractor::IsSaveLoaded() ? ((1 << item) & gSaveContext.inventory.questItems) : false; } bool HasQuestItem(ItemTrackerItem item) { @@ -1362,13 +1366,35 @@ void DrawDungeonItem(ItemTrackerItem item) { } void DrawSong(ItemTrackerItem item) { + const SongData* song = &Rando::StaticData::songData[Rando::StaticData::songQuestToProg[(QuestItem)item.id]]; + const bool hasSong = HasSong((QuestItem)item.id); + float iconSize = static_cast(CVarGetInteger(CVAR_TRACKER_ITEM("IconSize"), 36)); + ImGui::BeginGroup(); ImVec2 p = ImGui::GetCursorScreenPos(); - bool hasSong = HasSong(item); ImGui::SetCursorScreenPos(ImVec2(p.x + 6, p.y)); ImGui::Image(std::dynamic_pointer_cast(Ship::Context::GetRawInstance()->GetWindow()->GetGui()) ->GetTextureByName(hasSong && IsValidSaveFile() ? item.name : item.nameFaded), ImVec2(iconSize / 1.5f, iconSize), ImVec2(0, 0), ImVec2(1, 1)); + + // RANDOTODO merge the ammo printing pipelines + if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SPLIT_OCARINA_SONGS) != 0) { + const char* progressLabel = "0/2"; + if (hasSong) { + progressLabel = "2/2"; + } else if (Flags_GetRandomizerInf(song->randInf)) { + progressLabel = "1/2"; + } + const ImVec2 iconMin = ImGui::GetItemRectMin(); + const ImVec2 iconMax = ImGui::GetItemRectMax(); + const ImVec2 textSize = ImGui::CalcTextSize(progressLabel); + const ImVec2 textPos(iconMin.x + ((iconMax.x - iconMin.x) - textSize.x) * 0.5f, iconMax.y - textSize.y - 2.0f); + ImDrawList* dl = ImGui::GetWindowDrawList(); + dl->AddText(ImVec2(textPos.x + 1.0f, textPos.y + 1.0f), IM_COL32(0, 0, 0, 220), progressLabel); + dl->AddText(textPos, IM_COL32(255, 255, 255, 255), progressLabel); + } + + ImGui::EndGroup(); Tooltip(SohUtils::GetQuestItemName(item.id).c_str()); } diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h index 0538e9f71ad..1d0e1d96700 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.h @@ -15,7 +15,7 @@ typedef struct ItemTrackerItem { void (*drawFunc)(ItemTrackerItem); } ItemTrackerItem; -bool HasSong(ItemTrackerItem); +bool HasSong(QuestItem); bool HasQuestItem(ItemTrackerItem); bool HasEquipment(ItemTrackerItem); diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index f668ec799c8..21c49e91dfe 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -524,6 +524,21 @@ extern "C" void Randomizer_InitSaveFile() { Flags_SetRandomizerInf(RAND_INF_HAS_WALLET); } + if (Randomizer_GetSettingValue(RSK_SPLIT_OCARINA_SONGS) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_SPLIT_ZL_PART); + Flags_SetRandomizerInf(RAND_INF_SPLIT_EPONA_PART); + Flags_SetRandomizerInf(RAND_INF_SPLIT_SARIA_PART); + Flags_SetRandomizerInf(RAND_INF_SPLIT_SUN_PART); + Flags_SetRandomizerInf(RAND_INF_SPLIT_TIME_PART); + Flags_SetRandomizerInf(RAND_INF_SPLIT_STORMS_PART); + Flags_SetRandomizerInf(RAND_INF_SPLIT_MINUET_PART); + Flags_SetRandomizerInf(RAND_INF_SPLIT_BOLERO_PART); + Flags_SetRandomizerInf(RAND_INF_SPLIT_SERENADE_PART); + Flags_SetRandomizerInf(RAND_INF_SPLIT_REQUIEM_PART); + Flags_SetRandomizerInf(RAND_INF_SPLIT_NOCTURNE_PART); + Flags_SetRandomizerInf(RAND_INF_SPLIT_PRELUDE_PART); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_FISHING_POLE) == RO_GENERIC_OFF) { Flags_SetRandomizerInf(RAND_INF_FISHING_POLE_FOUND); } diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 78988f63591..f5926f70d59 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -608,6 +608,22 @@ void Settings::CreateOptions() { }); OPT_U8(RSK_LINKS_POCKET_REWARD, "Link's Pocket Reward Type", {"Any Reward", "Any Stone", "Any Medallion", "Light Medallion"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("LinksPocketReward"), mOptionDescriptions[RSK_LINKS_POCKET_REWARD], WIDGET_CVAR_COMBOBOX, RO_LINKS_POCKET_ANY_REWARD); OPT_U8(RSK_SHUFFLE_SONGS, "Shuffle Songs", {"Off", "Song Locations", "Dungeon Rewards", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleSongs"), mOptionDescriptions[RSK_SHUFFLE_SONGS], WIDGET_CVAR_COMBOBOX, RO_SONG_SHUFFLE_SONG_LOCATIONS); + OPT_CALLBACK(RSK_SHUFFLE_SONGS, { + const int shuffleSongs = + CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleSongs"), RO_SONG_SHUFFLE_SONG_LOCATIONS); + if (shuffleSongs == RO_SONG_SHUFFLE_ANYWHERE) { + mOptions[RSK_SPLIT_OCARINA_SONGS].Enable(); + } else if (shuffleSongs != RO_SONG_SHUFFLE_OFF) { + mOptions[RSK_SPLIT_OCARINA_SONGS].Disable( + "Split Ocarina Songs only works when Shuffle Songs is set to Anywhere. Other shuffle modes keep the " + "usual 12 song checks."); + } else { + mOptions[RSK_SPLIT_OCARINA_SONGS].Disable( + "Turn on Shuffle Songs and set it to Anywhere to use Split Ocarina Songs."); + } + }); + OPT_BOOL(RSK_SPLIT_OCARINA_SONGS, "Split Ocarina Songs", CVAR_RANDOMIZER_SETTING("SplitOcarinaSongs"), + mOptionDescriptions[RSK_SPLIT_OCARINA_SONGS]); OPT_U8(RSK_SHOPSANITY, "Shop Shuffle", {"Off", "Specific Count", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Shopsanity"), mOptionDescriptions[RSK_SHOPSANITY], WIDGET_CVAR_COMBOBOX, RO_SHOPSANITY_OFF); OPT_CALLBACK(RSK_SHOPSANITY, { // Hide shopsanity prices if shopsanity is off or zero @@ -1924,6 +1940,7 @@ void Settings::CreateOptions() { OptionGroup::SubGroup("Shuffle Items", { &mOptions[RSK_SHUFFLE_SONGS], + &mOptions[RSK_SPLIT_OCARINA_SONGS], &mOptions[RSK_SHUFFLE_TOKENS], &mOptions[RSK_SHUFFLE_KOKIRI_SWORD], &mOptions[RSK_SHUFFLE_MASTER_SWORD], @@ -2140,6 +2157,7 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_DUNGEON_REWARDS], &mOptions[RSK_LINKS_POCKET], &mOptions[RSK_SHUFFLE_SONGS], + &mOptions[RSK_SPLIT_OCARINA_SONGS], &mOptions[RSK_SHOPSANITY], &mOptions[RSK_SHOPSANITY_COUNT], &mOptions[RSK_SHOPSANITY_PRICES], @@ -2623,6 +2641,10 @@ void Context::FinalizeSettings(const std::set& excludedLocation mOptions[RSK_STARTING_BOTTLE_4].Set(RO_STARTING_BOTTLE_OFF); } + if (mOptions[RSK_SHUFFLE_SONGS].IsNot(RO_SONG_SHUFFLE_ANYWHERE)) { + mOptions[RSK_SPLIT_OCARINA_SONGS].Set(0); + } + // RANDOTODO implement chest shuffle with keysanity // ShuffleChestMinigame.Set(cvarSettings[RSK_SHUFFLE_CHEST_MINIGAME]); mOptions[RSK_SHUFFLE_CHEST_MINIGAME].Set(RO_CHEST_GAME_OFF); diff --git a/soh/soh/Enhancements/randomizer/static_data.cpp b/soh/soh/Enhancements/randomizer/static_data.cpp index 390febf5e80..8ced7446989 100644 --- a/soh/soh/Enhancements/randomizer/static_data.cpp +++ b/soh/soh/Enhancements/randomizer/static_data.cpp @@ -537,4 +537,55 @@ std::vector StaticData::overworldKeys = { RG_HYLIA_LAB_KEY, RG_FISHING_HOLE_KEY, }; + +std::unordered_map StaticData::songData = { + { RG_PROGRESSIVE_ZELDAS_LULLABY, + { RG_ZELDAS_LULLABY, RG_PART_OF_ZELDAS_LULLABY, RAND_INF_SPLIT_ZL_PART, QUEST_SONG_LULLABY } }, + { RG_PROGRESSIVE_EPONAS_SONG, + { RG_EPONAS_SONG, RG_PART_OF_EPONAS_SONG, RAND_INF_SPLIT_EPONA_PART, QUEST_SONG_EPONA } }, + { RG_PROGRESSIVE_SARIAS_SONG, + { RG_SARIAS_SONG, RG_PART_OF_SARIAS_SONG, RAND_INF_SPLIT_SARIA_PART, QUEST_SONG_SARIA } }, + { RG_PROGRESSIVE_SUNS_SONG, { RG_SUNS_SONG, RG_PART_OF_SUNS_SONG, RAND_INF_SPLIT_SUN_PART, QUEST_SONG_SUN } }, + { RG_PROGRESSIVE_SONG_OF_TIME, + { RG_SONG_OF_TIME, RG_PART_OF_SONG_OF_TIME, RAND_INF_SPLIT_TIME_PART, QUEST_SONG_TIME } }, + { RG_PROGRESSIVE_SONG_OF_STORMS, + { RG_SONG_OF_STORMS, RG_PART_OF_SONG_OF_STORMS, RAND_INF_SPLIT_STORMS_PART, QUEST_SONG_STORMS } }, + { RG_PROGRESSIVE_MINUET_OF_FOREST, + { RG_MINUET_OF_FOREST, RG_PART_OF_MINUET_OF_FOREST, RAND_INF_SPLIT_MINUET_PART, QUEST_SONG_MINUET } }, + { RG_PROGRESSIVE_BOLERO_OF_FIRE, + { RG_BOLERO_OF_FIRE, RG_PART_OF_BOLERO_OF_FIRE, RAND_INF_SPLIT_BOLERO_PART, QUEST_SONG_BOLERO } }, + { RG_PROGRESSIVE_SERENADE_OF_WATER, + { RG_SERENADE_OF_WATER, RG_PART_OF_SERENADE_OF_WATER, RAND_INF_SPLIT_SERENADE_PART, QUEST_SONG_SERENADE } }, + { RG_PROGRESSIVE_REQUIEM_OF_SPIRIT, + { RG_REQUIEM_OF_SPIRIT, RG_PART_OF_REQUIEM_OF_SPIRIT, RAND_INF_SPLIT_REQUIEM_PART, QUEST_SONG_REQUIEM } }, + { RG_PROGRESSIVE_NOCTURNE_OF_SHADOW, + { RG_NOCTURNE_OF_SHADOW, RG_PART_OF_NOCTURNE_OF_SHADOW, RAND_INF_SPLIT_NOCTURNE_PART, QUEST_SONG_NOCTURNE } }, + { RG_PROGRESSIVE_PRELUDE_OF_LIGHT, + { RG_PRELUDE_OF_LIGHT, RG_PART_OF_PRELUDE_OF_LIGHT, RAND_INF_SPLIT_PRELUDE_PART, QUEST_SONG_PRELUDE } }, +}; + +std::unordered_map StaticData::songQuestToProg = { + { QUEST_SONG_LULLABY, RG_PROGRESSIVE_ZELDAS_LULLABY }, + { + QUEST_SONG_EPONA, + RG_PROGRESSIVE_EPONAS_SONG, + }, + { + QUEST_SONG_SARIA, + RG_PROGRESSIVE_SARIAS_SONG, + }, + { + QUEST_SONG_SUN, + RG_PROGRESSIVE_SUNS_SONG, + }, + { QUEST_SONG_TIME, RG_PROGRESSIVE_SONG_OF_TIME }, + { QUEST_SONG_STORMS, RG_PROGRESSIVE_SONG_OF_STORMS }, + { QUEST_SONG_MINUET, RG_PROGRESSIVE_MINUET_OF_FOREST }, + { QUEST_SONG_BOLERO, RG_PROGRESSIVE_BOLERO_OF_FIRE }, + { QUEST_SONG_SERENADE, RG_PROGRESSIVE_SERENADE_OF_WATER }, + { QUEST_SONG_REQUIEM, RG_PROGRESSIVE_REQUIEM_OF_SPIRIT }, + { QUEST_SONG_NOCTURNE, RG_PROGRESSIVE_NOCTURNE_OF_SHADOW }, + { QUEST_SONG_PRELUDE, RG_PROGRESSIVE_PRELUDE_OF_LIGHT } +}; + } // namespace Rando diff --git a/soh/soh/Enhancements/randomizer/static_data.h b/soh/soh/Enhancements/randomizer/static_data.h index 5390c9ba1e7..c1522fdcf9e 100644 --- a/soh/soh/Enhancements/randomizer/static_data.h +++ b/soh/soh/Enhancements/randomizer/static_data.h @@ -102,6 +102,8 @@ class StaticData { static std::set restrictTrade; static std::set allowMasks; static std::set allowBottleMaskTrade; + static std::unordered_map songData; + static std::unordered_map songQuestToProg; StaticData(); ~StaticData();