From fe7aedc80d5e53b7c1b3ccc2b507b465bdb208a4 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 24 Aug 2022 15:44:31 -0400 Subject: [PATCH 01/30] Adds getItemEntry for Magic Bean Pack --- .../Enhancements/randomizer/randomizer.cpp | 170 +++++++++++------- soh/src/code/z_parameter.c | 15 +- 2 files changed, 120 insertions(+), 65 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index d13792714..5b6012e1a 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3878,72 +3878,119 @@ void Randomizer::CreateCustomMessages() { const std::vector getItemMessages = { GIMESSAGE(RG_ICE_TRAP, ITEM_NONE, "\x08\x06\x30You are a %bFOWL%w!\x0E\x20", "\x08\x06\x15 Du bist ein %bDUMMKOPF%w!\x0E\x20", "\x08\x06\x50%bIDIOT%w\x0E\x20"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, - "You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!", - "Vous obtenez une %rBouteille avec&une Flamme Bleue%w! Utilisez-la&pour faire fondre la %rGlace&Rouge%w!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, "You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!", + "Vous obtenez une %rBouteille avec&une Flamme Bleue%w! Utilisez-la&pour faire fondre la %rGlace&Rouge%w!"), GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BIG_POE, ITEM_BIG_POE, - "You got a %rBig Poe in a Bottle%w!&Sell it to the Ghost Shop!", - "Vous obtenez une %rBouteille avec&une Âme%w! Vendez-la au Marchand&d'Âme"), + "You got a %rBig Poe in a Bottle%w!&Sell it to the Ghost Shop!", + "Vous obtenez une %rBouteille avec&une Âme%w! Vendez-la au Marchand&d'Âme"), GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BLUE_POTION, ITEM_POTION_BLUE, - "You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!", - "Vous obtenez une %rBouteille avec&une Potion Bleue%w! Buvez-la pour&restaurer votre %rénergie vitale%w&ainsi que votre %gmagie%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_FISH, ITEM_FISH, - "You got a %rFish in a Bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!", - "Vous obtenez une %rBouteille avec&un Poisson%w! Il a l'air délicieux!&Il paraîtrait que %bJabu-Jabu %wen&serait friand!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_BUGS, ITEM_BUG, - "You got a %rBug in a Bottle%w!&They love to burrow in&dirt holes!", - "Vous obtenez une %rBouteille avec&des Insectes%w! Ils adorent creuser&dans la terre meuble!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_FAIRY, ITEM_FAIRY, - "You got a %rFairy in a Bottle%w!&Use it wisely!", - "Vous obtenez une %rBouteille avec&une Fée%w! Faites-en bon usage!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, - "You got a %rBottle of Red Potion%w!&Drink it to replenish your&%ghealth%w!", - "Vous obtenez une %rBouteille avec&une Potion Rouge%w! Buvez-la pour&restaurer votre %rénergie vitale%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN, - "You got a %rBottle of Green Potion%w!&Drink it to replenish your&%bmagic%w!", - "Vous obtenez une %rBouteille avec&une Potion Verte%w! Buvez-la pour&restaurer votre %gmagie%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_POE, ITEM_POE, - "You got a %rPoe in a Bottle%w!&That creepy Ghost Shop might&be interested in this...", - "Vous obtenez une %rBouteille avec&un Esprit%w! Ça intéresserait&peut-être le vendeur d'Âme "), + "You got a %rBottle of Blue Potion%w!&Drink it to replenish your&%ghealth%w and %bmagic%w!", + "Vous obtenez une %rBouteille avec&une Potion Bleue%w! Buvez-la pour&restaurer votre " + "%rénergie vitale%w&ainsi que votre %gmagie%w!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_FISH, ITEM_FISH, + "You got a %rFish in a Bottle%w!&It looks fresh and delicious!&They say Jabu-Jabu loves them!", + "Vous obtenez une %rBouteille avec&un Poisson%w! Il a l'air délicieux!&Il paraîtrait que %bJabu-Jabu " + "%wen&serait friand!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_BUGS, ITEM_BUG, "You got a %rBug in a Bottle%w!&They love to burrow in&dirt holes!", + "Vous obtenez une %rBouteille avec&des Insectes%w! Ils adorent creuser&dans la terre meuble!"), + GIMESSAGE_NO_GERMAN(RG_BOTTLE_WITH_FAIRY, ITEM_FAIRY, "You got a %rFairy in a Bottle%w!&Use it wisely!", + "Vous obtenez une %rBouteille avec&une Fée%w! Faites-en bon usage!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_RED_POTION, ITEM_POTION_RED, + "You got a %rBottle of Red Potion%w!&Drink it to replenish your&%ghealth%w!", + "Vous obtenez une %rBouteille avec&une Potion Rouge%w! Buvez-la pour&restaurer votre %rénergie vitale%w!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_GREEN_POTION, ITEM_POTION_GREEN, + "You got a %rBottle of Green Potion%w!&Drink it to replenish your&%bmagic%w!", + "Vous obtenez une %rBouteille avec&une Potion Verte%w! Buvez-la pour&restaurer votre %gmagie%w!"), + GIMESSAGE_NO_GERMAN( + RG_BOTTLE_WITH_POE, ITEM_POE, + "You got a %rPoe in a Bottle%w!&That creepy Ghost Shop might&be interested in this...", + "Vous obtenez une %rBouteille avec&un Esprit%w! Ça intéresserait&peut-être le vendeur d'Âme "), - GIMESSAGE_NO_GERMAN(RG_GERUDO_FORTRESS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yThieves Hideout &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yRepaire des Voleurs%w!"), - GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %gForest Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %gTemple de la Forêt%w!"), - GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rFire Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %rTemple du Feu%w!"), - GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %bWater Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %bTemple de l'Eau%w!"), - GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %ySpirit Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yTemple de l'Esprit%w!"), - GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pShadow Temple &%wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %pTemple de l'Ombre%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pBottom of the &Well %wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %Puits%w!"), - GIMESSAGE_NO_GERMAN(RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yGerudo Training &Grounds %wSmall Key!", "Vous obtenez une %rPetite Clé %w&du %yGymnase Gerudo%w!"), - 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_SMALL_KEY, ITEM_KEY_SMALL, "You found a %yThieves Hideout &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %yRepaire des Voleurs%w!"), + GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %gForest Temple &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %rFire Temple &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %bWater Temple &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %ySpirit Temple &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_SMALL_KEY, ITEM_KEY_SMALL, "You found a %pShadow Temple &%wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_SMALL_KEY, ITEM_KEY_SMALL, + "You found a %pBottom of the &Well %wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %Puits%w!"), + GIMESSAGE_NO_GERMAN(RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, ITEM_KEY_SMALL, + "You found a %yGerudo Training &Grounds %wSmall Key!", + "Vous obtenez une %rPetite Clé %w&du %yGymnase Gerudo%w!"), + 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_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!", "Vous obtenez la %rClé d'or %wdu&%rTemple du Feu%w!"), - GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %bWater Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%bTemple de l'Eau%w!"), - GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %ySpirit Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%yTemple de l'Esprit%w!"), - GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %pShadow Temple &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%pTemple de l'Ombre%w!"), - GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rGanon's Castle &%wBoss Key!", "Vous obtenez la %rClé d'or %wdu&%rChâteau de Ganon%w!"), - - GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_MAP, ITEM_DUNGEON_MAP, "You found the %gDeku Tree &%wMap!", "Vous obtenez la %rCarte %wde&l'%gArbre Mojo%w!"), - GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %rDodongo's Cavern &%wMap!", "Vous obtenez la %rCarte %wde la&%rCaverne Dodongo%w!"), - GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_MAP, ITEM_DUNGEON_MAP, "You found the %bJabu Jabu's Belly &%wMap!", "Vous obtenez la %rCarte %wdu &%bVentre de Jabu-Jabu%w!"), - GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %gForest Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%gTemple de la Forêt%w!"), - GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %rFire Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%rTemple du Feu%w!"), - GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %bWater Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%bTemple de l'Eau%w!"), - GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %ySpirit Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%yTemple de l'Esprit%w!"), - GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %pShadow Temple &%wMap!", "Vous obtenez la %rCarte %wdu &%pTemple de l'Ombre%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_MAP, ITEM_DUNGEON_MAP, "You found the %pBottom of the &Well %wMap!", "Vous obtenez la %rCarte %wdu &%pPuits%w!"), - GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %cIce Cavern &%wMap!", "Vous obtenez la %rCarte %wde &la %cCaverne Polaire%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!", + "Vous obtenez la %rClé d'or %wdu&%rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %bWater Temple &%wBoss Key!", + "Vous obtenez la %rClé d'or %wdu&%bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %ySpirit Temple &%wBoss Key!", + "Vous obtenez la %rClé d'or %wdu&%yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %pShadow Temple &%wBoss Key!", + "Vous obtenez la %rClé d'or %wdu&%pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(RG_GANONS_CASTLE_BOSS_KEY, ITEM_KEY_BOSS, "You found the %rGanon's Castle &%wBoss Key!", + "Vous obtenez la %rClé d'or %wdu&%rChâteau de Ganon%w!"), - GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_COMPASS, ITEM_COMPASS, "You found the %gDeku Tree &%wCompass!", "Vous obtenez la %rBoussole %wde&l'%gArbre Mojo%w!"), - GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_COMPASS, ITEM_COMPASS, "You found the %rDodongo's Cavern &%wCompass!", "Vous obtenez la %rBoussole %wde la&%rCaverne Dodongo%w!"), - GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_COMPASS, ITEM_COMPASS, "You found the %bJabu Jabu's Belly &%wCompass!", "Vous obtenez la %rBoussole %wdu &%bVentre de Jabu-Jabu%w!"), - GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %gForest Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%gTemple de la Forêt%w!"), - GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %rFire Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%rTemple du Feu%w!"), - GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %bWater Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%bTemple de l'Eau%w!"), - GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %ySpirit Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%yTemple de l'Esprit%w!"), - GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %pShadow Temple &%wCompass!", "Vous obtenez la %rBoussole %wdu &%pTemple de l'Ombre%w!"), - GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_COMPASS, ITEM_COMPASS, "You found the %pBottom of the &Well %wCompass!", "Vous obtenez la %rBoussole %wdu &%pPuits%w!"), - GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_COMPASS, ITEM_COMPASS, "You found the %cIce Cavern &%wCompass!", "Vous obtenez la %rBoussole %wde &la %cCaverne Polaire%w!"), + GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_MAP, ITEM_DUNGEON_MAP, "You found the %gDeku Tree &%wMap!", + "Vous obtenez la %rCarte %wde&l'%gArbre Mojo%w!"), + GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %rDodongo's Cavern &%wMap!", + "Vous obtenez la %rCarte %wde la&%rCaverne Dodongo%w!"), + GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_MAP, ITEM_DUNGEON_MAP, "You found the %bJabu Jabu's Belly &%wMap!", + "Vous obtenez la %rCarte %wdu &%bVentre de Jabu-Jabu%w!"), + GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %gForest Temple &%wMap!", + "Vous obtenez la %rCarte %wdu &%gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %rFire Temple &%wMap!", + "Vous obtenez la %rCarte %wdu &%rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %bWater Temple &%wMap!", + "Vous obtenez la %rCarte %wdu &%bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %ySpirit Temple &%wMap!", + "Vous obtenez la %rCarte %wdu &%yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_MAP, ITEM_DUNGEON_MAP, "You found the %pShadow Temple &%wMap!", + "Vous obtenez la %rCarte %wdu &%pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_MAP, ITEM_DUNGEON_MAP, "You found the %pBottom of the &Well %wMap!", + "Vous obtenez la %rCarte %wdu &%pPuits%w!"), + GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_MAP, ITEM_DUNGEON_MAP, "You found the %cIce Cavern &%wMap!", + "Vous obtenez la %rCarte %wde &la %cCaverne Polaire%w!"), + + GIMESSAGE_NO_GERMAN(RG_DEKU_TREE_COMPASS, ITEM_COMPASS, "You found the %gDeku Tree &%wCompass!", + "Vous obtenez la %rBoussole %wde&l'%gArbre Mojo%w!"), + GIMESSAGE_NO_GERMAN(RG_DODONGOS_CAVERN_COMPASS, ITEM_COMPASS, "You found the %rDodongo's Cavern &%wCompass!", + "Vous obtenez la %rBoussole %wde la&%rCaverne Dodongo%w!"), + GIMESSAGE_NO_GERMAN(RG_JABU_JABUS_BELLY_COMPASS, ITEM_COMPASS, "You found the %bJabu Jabu's Belly &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%bVentre de Jabu-Jabu%w!"), + GIMESSAGE_NO_GERMAN(RG_FOREST_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %gForest Temple &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%gTemple de la Forêt%w!"), + GIMESSAGE_NO_GERMAN(RG_FIRE_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %rFire Temple &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%rTemple du Feu%w!"), + GIMESSAGE_NO_GERMAN(RG_WATER_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %bWater Temple &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%bTemple de l'Eau%w!"), + GIMESSAGE_NO_GERMAN(RG_SPIRIT_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %ySpirit Temple &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%yTemple de l'Esprit%w!"), + GIMESSAGE_NO_GERMAN(RG_SHADOW_TEMPLE_COMPASS, ITEM_COMPASS, "You found the %pShadow Temple &%wCompass!", + "Vous obtenez la %rBoussole %wdu &%pTemple de l'Ombre%w!"), + GIMESSAGE_NO_GERMAN(RG_BOTTOM_OF_THE_WELL_COMPASS, ITEM_COMPASS, + "You found the %pBottom of the &Well %wCompass!", + "Vous obtenez la %rBoussole %wdu &%pPuits%w!"), + GIMESSAGE_NO_GERMAN(RG_ICE_CAVERN_COMPASS, ITEM_COMPASS, "You found the %cIce Cavern &%wCompass!", + "Vous obtenez la %rBoussole %wde &la %cCaverne Polaire%w!"), + GIMESSAGE(RG_MAGIC_BEAN_PACK, ITEM_BEAN, + "You got a %rPack of Magic Beans%w!&Find a suitable spot for a garden&and plant them. Then, wait for&something fun to happen!", + "Du hast eine %rPackung&Magic Beans%w! Finde&einen geeigneten Platz fur einen&Garten und pflanze sie. Dann^warte auf etwas Lustiges passiert!", + "Vous avez un %rPack de&haricots magiques%w ! Trouvez&un endroit convenable pour un&jardin et plantez-les.^Ensuite, attendez quelque&chose d'amusant doit arriver !") }; CreateGetItemMessages(getItemMessages); CreateScrubMessages(); @@ -4043,6 +4090,7 @@ void InitRandoItemTable() { GET_ITEM(RG_SHADOW_TEMPLE_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_SHADOW_TEMPLE_COMPASS), GET_ITEM(RG_BOTTOM_OF_THE_WELL_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_BOTTOM_OF_THE_WELL_COMPASS), GET_ITEM(RG_ICE_CAVERN_COMPASS, OBJECT_GI_COMPASS, GID_COMPASS, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_ICE_CAVERN_COMPASS), + GET_ITEM(RG_MAGIC_BEAN_PACK, OBJECT_GI_BEAN, GID_BEAN, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, MOD_RANDOMIZER, RG_MAGIC_BEAN_PACK) }; ItemTableManager::Instance->AddItemTable(MOD_RANDOMIZER); for (int i = 0; i < ARRAY_COUNT(extendedVanillaGetItemTable); i++) { diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index bc8fa8149..acad4d874 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2177,6 +2177,14 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { return RG_NONE; } + if (item == RG_MAGIC_BEAN_PACK) { + if (gSaveContext.inventory.items[SLOT(ITEM_BEAN)] == ITEM_NONE) { + INV_CONTENT(ITEM_BEAN) = ITEM_BEAN; + AMMO(ITEM_BEAN) = 10; + BEANS_BOUGHT = 10; + } + } + if (item == RG_DOUBLE_DEFENSE) { gSaveContext.doubleDefense = true; gSaveContext.inventory.defenseHearts = 20; @@ -2223,9 +2231,9 @@ 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_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)) { + (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; switch (item) { case RG_DEKU_TREE_MAP: @@ -2323,7 +2331,6 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { return temp; } - u8 Item_CheckObtainability(u8 item) { s16 i; s16 slot = SLOT(item); From adf465c1a05f8179dc6cf6a56f53334ba72bc927 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 24 Aug 2022 17:20:45 -0400 Subject: [PATCH 02/30] Sets up Magic Bean Salesman to sell a rando check for 60 rupees. --- .../Enhancements/randomizer/randomizerTypes.h | 3 ++- soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c | 21 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 21635278c..14e5ae34a 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -1013,5 +1013,6 @@ typedef enum { RSK_COMPLETE_MASK_QUEST, RSK_ENABLE_GLITCH_CUTSCENES, RSK_SKULLS_SUNS_SONG, - RSK_SHUFFLE_ADULT_TRADE + RSK_SHUFFLE_ADULT_TRADE, + RSK_SHUFFLE_MAGIC_BEANS } RandomizerSettingKey; diff --git a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c index 04919761e..dc4dc61ca 100644 --- a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c +++ b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c @@ -125,11 +125,19 @@ void EnMs_Talk(EnMs* this, GlobalContext* globalCtx) { } else if (Message_ShouldAdvance(globalCtx)) { switch (globalCtx->msgCtx.choiceIndex) { case 0: // yes - if (gSaveContext.rupees < sPrices[BEANS_BOUGHT]) { + if (gSaveContext.rupees < + ((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) + ? 60 + : sPrices[BEANS_BOUGHT])) { Message_ContinueTextbox(globalCtx, 0x4069); // not enough rupees text return; } - func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f); + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) { + GiveItemEntryFromActor(&this->actor, globalCtx, + Randomizer_GetItemFromKnownCheck(RC_ZR_MAGIC_BEAN_SALESMAN, GI_BEAN), 90.0f, 10.0f); + } else { + func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f); + } this->actionFunc = EnMs_Sell; return; case 1: // no @@ -142,11 +150,16 @@ void EnMs_Talk(EnMs* this, GlobalContext* globalCtx) { void EnMs_Sell(EnMs* this, GlobalContext* globalCtx) { if (Actor_HasParent(&this->actor, globalCtx)) { - Rupees_ChangeBy(-sPrices[BEANS_BOUGHT]); + Rupees_ChangeBy((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? 60 : -sPrices[BEANS_BOUGHT]); this->actor.parent = NULL; this->actionFunc = EnMs_TalkAfterPurchase; } else { - func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f); + if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) { + GiveItemEntryFromActor(&this->actor, globalCtx, + Randomizer_GetItemFromKnownCheck(RC_ZR_MAGIC_BEAN_SALESMAN, GI_BEAN), 90.0f, 10.0f); + } else { + func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f); + } } } From c4de29b7f1aeeeb96a1337b1020b7558c0e21022 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 24 Aug 2022 17:24:50 -0400 Subject: [PATCH 03/30] Correctly sets `BEANS_BOUGHT` as a "flag" for the bean salesman --- soh/src/code/z_parameter.c | 1 - soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index acad4d874..7548c0fa7 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2181,7 +2181,6 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { if (gSaveContext.inventory.items[SLOT(ITEM_BEAN)] == ITEM_NONE) { INV_CONTENT(ITEM_BEAN) = ITEM_BEAN; AMMO(ITEM_BEAN) = 10; - BEANS_BOUGHT = 10; } } diff --git a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c index dc4dc61ca..5c8a1807b 100644 --- a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c +++ b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c @@ -157,6 +157,7 @@ void EnMs_Sell(EnMs* this, GlobalContext* globalCtx) { if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) { GiveItemEntryFromActor(&this->actor, globalCtx, Randomizer_GetItemFromKnownCheck(RC_ZR_MAGIC_BEAN_SALESMAN, GI_BEAN), 90.0f, 10.0f); + BEANS_BOUGHT = 10; } else { func_8002F434(&this->actor, globalCtx, GI_BEAN, 90.0f, 10.0f); } From db6a39719501c76bc256896be73ed67ac78454b9 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Wed, 24 Aug 2022 17:58:01 -0400 Subject: [PATCH 04/30] Adds new text for the bean salesman --- soh/soh/Enhancements/randomizer/randomizer.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 5b6012e1a..69da8fa03 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3734,6 +3734,17 @@ void CreateScrubMessages() { std::to_string(price) + " Rubis%w!\x07\x10\xA3" }); } + customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, 0x405E, + { + TEXTBOX_TYPE_BLACK, + TEXTBOX_POS_BOTTOM, + "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" + "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" + "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" + "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + }); } void CreateRupeeMessages() { From ef1b662bf4eac3ae5d3d9c3d57ef10c46f4341f3 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 09:42:15 -0400 Subject: [PATCH 05/30] Finishes wiring up bean salesman settings and text. --- soh/soh/Enhancements/custom-message/CustomMessageTypes.h | 3 ++- soh/soh/Enhancements/randomizer/3drando/settings.cpp | 1 + soh/soh/Enhancements/randomizer/randomizer.cpp | 8 ++++++++ soh/soh/OTRGlobals.cpp | 2 ++ soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c | 3 ++- 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index b38b5fc80..d82cd84a9 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -15,7 +15,8 @@ typedef enum { TEXT_BLUE_RUPEE = 0xCC, TEXT_RED_RUPEE = 0xF0, TEXT_PURPLE_RUPEE = 0xF1, - TEXT_HUGE_RUPEE = 0xF2 + TEXT_HUGE_RUPEE = 0xF2, + TEXT_BEAN_SALESEMAN = 0x405E } TextIDs; #ifdef __cplusplus diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 51eaff18b..7df0be90a 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2551,6 +2551,7 @@ namespace Settings { ShuffleFrogSongRupees.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_FROG_SONG_RUPEES]); ShuffleAdultTradeQuest.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_ADULT_TRADE]); + ShuffleMagicBeans.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_MAGIC_BEANS]); // the checkbox works because 0 is "Off" and 1 is "Fairy Ocarina" StartingOcarina.SetSelectedIndex(cvarSettings[RSK_STARTING_OCARINA]); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 69da8fa03..528527922 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -548,6 +548,7 @@ std::unordered_map SpoilerfileSettingNameToEn { "Shuffle Settings:Shuffle Cows", RSK_SHUFFLE_COWS }, { "Shuffle Settings:Tokensanity", RSK_SHUFFLE_TOKENS }, { "Shuffle Settings:Shuffle Adult Trade", RSK_SHUFFLE_ADULT_TRADE }, + { "Shuffle Settings:Shuffle Magic Beans", RSK_SHUFFLE_MAGIC_BEANS}, { "Start with Deku Shield", RSK_STARTING_DEKU_SHIELD }, { "Start with Kokiri Sword", RSK_STARTING_KOKIRI_SWORD }, { "Start with Fairy Ocarina", RSK_STARTING_OCARINA }, @@ -774,6 +775,7 @@ void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { case RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD: case RSK_SHUFFLE_COWS: case RSK_SHUFFLE_ADULT_TRADE: + case RSK_SHUFFLE_MAGIC_BEANS: case RSK_RANDOM_TRIALS: case RSK_STARTING_DEKU_SHIELD: case RSK_STARTING_KOKIRI_SWORD: @@ -2616,6 +2618,7 @@ void GenerateRandomizerImgui() { cvarSettings[RSK_SHUFFLE_TOKENS] = CVar_GetS32("gRandomizeShuffleTokens", 0); cvarSettings[RSK_SHUFFLE_COWS] = CVar_GetS32("gRandomizeShuffleCows", 0); cvarSettings[RSK_SHUFFLE_ADULT_TRADE] = CVar_GetS32("gRandomizeShuffleAdultTrade", 0); + cvarSettings[RSK_SHUFFLE_MAGIC_BEANS] = CVar_GetS32("gRandomizeShuffleBeans", 0); cvarSettings[RSK_SKIP_CHILD_ZELDA] = CVar_GetS32("gRandomizeSkipChildZelda", 0); // if we skip child zelda, we start with zelda's letter, and malon starts @@ -3149,6 +3152,11 @@ void DrawRandoEditor(bool& open) { "If disabled, only the Claim Check will be found in the pool."); PaddedSeparator(); + SohImGui::EnhancementCheckbox(Settings::ShuffleMagicBeans.GetName().c_str(), "gRandomizeShuffleBeans"); + InsertHelpHoverText("Enabling this adds a pack of 10 beans to the item pool and changes the Magic Bean Salesman to sell a" + "random item at a price of 60 rupees."); + PaddedSeparator(); + if (CVar_GetS32("gRandomizeStartingKokiriSword", 0) == 0) { // Shuffle Kokiri Sword SohImGui::EnhancementCheckbox(Settings::ShuffleKokiriSword.GetName().c_str(), diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 18d20ee00..f2d3c4844 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1727,6 +1727,8 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) { // In rando, replace Navi's general overworld hints with rando-related gameplay tips } else if (CVar_GetS32("gRandoRelevantNavi", 1) && textId >= 0x0140 && textId <= 0x015F) { messageEntry = Randomizer_GetNaviMessage(); + } else if (Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS) && textId == TEXT_BEAN_SALESEMAN) { + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, TEXT_BEAN_SALESEMAN); } } if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) { diff --git a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c index 5c8a1807b..d90e54244 100644 --- a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c +++ b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c @@ -152,7 +152,8 @@ void EnMs_Sell(EnMs* this, GlobalContext* globalCtx) { if (Actor_HasParent(&this->actor, globalCtx)) { Rupees_ChangeBy((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? 60 : -sPrices[BEANS_BOUGHT]); this->actor.parent = NULL; - this->actionFunc = EnMs_TalkAfterPurchase; + this->actionFunc = + (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? EnMs_Wait : EnMs_TalkAfterPurchase; } else { if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) { GiveItemEntryFromActor(&this->actor, globalCtx, From 5842beeb55d447b28af2204bb002fe633dfda06b Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 10:11:35 -0400 Subject: [PATCH 06/30] Fixes Bean Pack item from chest. --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 528527922..0f37eee73 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1198,8 +1198,6 @@ s16 Randomizer::GetItemFromGet(RandomizerGet randoGet, GetItemID ogItemId) { case RG_MAGIC_BEAN: return GI_BEAN; - case RG_MAGIC_BEAN_PACK: - return GI_BEAN; //todo make it 10 of them case RG_WEIRD_EGG: return GI_WEIRD_EGG; From 00838cb5b60a123c4d06f220840e559f805b886a Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 12:39:34 -0400 Subject: [PATCH 07/30] Adds french text for the bean salesman --- soh/soh/Enhancements/randomizer/randomizer.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 0f37eee73..452112552 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3740,16 +3740,18 @@ void CreateScrubMessages() { std::to_string(price) + " Rubis%w!\x07\x10\xA3" }); } - customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, 0x405E, + customMessageManager->CreateMessage( + Randomizer::scrubMessageTableID, 0x405E, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, - "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" - "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" - "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, want to buy my&" - "%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " + "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " + "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "J'ai essayé d'être un vendeur de&haricots magiques, mais j'étais&mauvais au niveau du marketing et&ça me " + "courait sur le haricot...^Enfin bref, ça te dirait de m'acheter un&" + "%gobjet mystérieux%w pour 60 Rubis?\x1B&%gOui&Non%w", }); } From 6ab13f389b9e4371d0dd1dec08d1cdec719d3328 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 12:43:19 -0400 Subject: [PATCH 08/30] Fixes salesman to properly take 60 rupees from you. --- soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c index d90e54244..9f67a21fc 100644 --- a/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c +++ b/soh/src/overlays/actors/ovl_En_Ms/z_en_ms.c @@ -150,7 +150,7 @@ void EnMs_Talk(EnMs* this, GlobalContext* globalCtx) { void EnMs_Sell(EnMs* this, GlobalContext* globalCtx) { if (Actor_HasParent(&this->actor, globalCtx)) { - Rupees_ChangeBy((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? 60 : -sPrices[BEANS_BOUGHT]); + Rupees_ChangeBy((gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? -60 : -sPrices[BEANS_BOUGHT]); this->actor.parent = NULL; this->actionFunc = (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS)) ? EnMs_Wait : EnMs_TalkAfterPurchase; From efd4ceb636a5c953a633c7ea703799e866f90b9f Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 12:46:08 -0400 Subject: [PATCH 09/30] Colors keywords in bean salesman text. --- soh/soh/Enhancements/randomizer/randomizer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 452112552..66ecbc7d9 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3745,11 +3745,11 @@ void CreateScrubMessages() { { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, - "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " + "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "I tried to be a magic bean salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " + "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "J'ai essayé d'être un vendeur de&haricots magiques, mais j'étais&mauvais au niveau du marketing et&ça me " + "J'ai essayé d'être un vendeur de&%rharicots magiques%w, mais j'étais&mauvais au niveau du marketing et&ça me " "courait sur le haricot...^Enfin bref, ça te dirait de m'acheter un&" "%gobjet mystérieux%w pour 60 Rubis?\x1B&%gOui&Non%w", }); From 3da197f0cdd7ef7f6bcf6c651f73e75a97a25503 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 14:39:12 -0400 Subject: [PATCH 10/30] Removes some magic numbers --- soh/soh/Enhancements/custom-message/CustomMessageTypes.h | 2 +- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- soh/soh/OTRGlobals.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h index d82cd84a9..dff85f415 100644 --- a/soh/soh/Enhancements/custom-message/CustomMessageTypes.h +++ b/soh/soh/Enhancements/custom-message/CustomMessageTypes.h @@ -16,7 +16,7 @@ typedef enum { TEXT_RED_RUPEE = 0xF0, TEXT_PURPLE_RUPEE = 0xF1, TEXT_HUGE_RUPEE = 0xF2, - TEXT_BEAN_SALESEMAN = 0x405E + TEXT_BEAN_SALESMAN = 0x405E } TextIDs; #ifdef __cplusplus diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 66ecbc7d9..72533c3c4 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3741,7 +3741,7 @@ void CreateScrubMessages() { }); } customMessageManager->CreateMessage( - Randomizer::scrubMessageTableID, 0x405E, + Randomizer::scrubMessageTableID, TEXT_BEAN_SALESMAN, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index f2d3c4844..59d0bbad9 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1727,8 +1727,8 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) { // In rando, replace Navi's general overworld hints with rando-related gameplay tips } else if (CVar_GetS32("gRandoRelevantNavi", 1) && textId >= 0x0140 && textId <= 0x015F) { messageEntry = Randomizer_GetNaviMessage(); - } else if (Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS) && textId == TEXT_BEAN_SALESEMAN) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, TEXT_BEAN_SALESEMAN); + } else if (Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS) && textId == TEXT_BEAN_SALESMAN) { + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, TEXT_BEAN_SALESMAN); } } if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) { From 5043309c63f3d25afdf2e73951dfb0fe3e647da6 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 16:43:57 -0400 Subject: [PATCH 11/30] Adds basic german text for bean salesman --- soh/soh/Enhancements/randomizer/randomizer.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 72533c3c4..2557d84a7 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3745,12 +3745,11 @@ void CreateScrubMessages() { { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, - "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " - "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth beans!^Anyway, " - "want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "J'ai essayé d'être un vendeur de&%rharicots magiques%w, mais j'étais&mauvais au niveau du marketing et&ça me " - "courait sur le haricot...^Enfin bref, ça te dirait de m'acheter un&" + "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth " + "beans!^Anyway, want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", + "Möchten Sie einen geheimnisvollen& Gegenstand für 60 Rubine?\x1B&%gJa&Nein%w", + "J'ai essayé d'être un vendeur de&%rharicots magiques%w, mais j'étais&mauvais au niveau du marketing et&ça " + "me courait sur le haricot...^Enfin bref, ça te dirait de m'acheter un&" "%gobjet mystérieux%w pour 60 Rubis?\x1B&%gOui&Non%w", }); } From 71e7fb9d70cfe588de5bd2838e49d8d0c8fd32a2 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 18:02:00 -0400 Subject: [PATCH 12/30] Merge rando-next and rename scrub message table to merchant message table --- soh/soh/Enhancements/randomizer/randomizer.cpp | 14 +++++++------- soh/soh/Enhancements/randomizer/randomizer.h | 2 +- soh/soh/OTRGlobals.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index ac0072e3d..4fd2a123d 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -32,7 +32,7 @@ u8 generated; const std::string Randomizer::getItemMessageTableID = "Randomizer"; const std::string Randomizer::hintMessageTableID = "RandomizerHints"; -const std::string Randomizer::scrubMessageTableID = "RandomizerScrubs"; +const std::string Randomizer::merchantMessageTableID = "RandomizerScrubs"; const std::string Randomizer::rupeeMessageTableID = "RandomizerRupees"; const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi"; @@ -4030,10 +4030,10 @@ void CreateGetItemMessages(std::vector messageEntries) { // Currently these are generated at runtime, one for each price between 0-95. We're soon going to migrate this // to being generated at save load, with only messages specific to each scrub. -void CreateScrubMessages() { +void CreateMerchantMessages() { CustomMessageManager* customMessageManager = CustomMessageManager::Instance; - customMessageManager->AddCustomMessageTable(Randomizer::scrubMessageTableID); - customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, 0, + customMessageManager->AddCustomMessageTable(Randomizer::merchantMessageTableID); + customMessageManager->CreateMessage(Randomizer::merchantMessageTableID, 0, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, "\x12\x38\x82\All right! You win! In return for&sparing me, I will give you a&%gmysterious item%w!&Please, take it!\x07\x10\xA3", "\x12\x38\x82\In Ordnung! Du gewinnst! Im Austausch&dafür, dass du mich verschont hast,&werde ich dir einen %gmysteriösen&Gegenstand%w geben! Bitte nimm ihn!\x07\x10\xA3", @@ -4041,7 +4041,7 @@ void CreateScrubMessages() { }); for (u32 price = 5; price <= 95; price += 5) { - customMessageManager->CreateMessage(Randomizer::scrubMessageTableID, price, + customMessageManager->CreateMessage(Randomizer::merchantMessageTableID, price, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, "\x12\x38\x82\All right! You win! In return for&sparing me, I will sell you a&%gmysterious item%w!&%r" + std::to_string(price) + " Rupees%w it is!\x07\x10\xA3", @@ -4053,7 +4053,7 @@ void CreateScrubMessages() { }); } customMessageManager->CreateMessage( - Randomizer::scrubMessageTableID, TEXT_BEAN_SALESMAN, + Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN, { TEXTBOX_TYPE_BLACK, TEXTBOX_POS_BOTTOM, @@ -4323,7 +4323,7 @@ void Randomizer::CreateCustomMessages() { "Vous avez un %rPack de&haricots magiques%w ! Trouvez&un endroit convenable pour un&jardin et plantez-les.^Ensuite, attendez quelque&chose d'amusant doit arriver !") }; CreateGetItemMessages(getItemMessages); - CreateScrubMessages(); + CreateMerchantMessages(); CreateRupeeMessages(); CreateNaviRandoMessages(); } diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index c5df36e2c..8b467a699 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -34,7 +34,7 @@ class Randomizer { static const std::string getItemMessageTableID; static const std::string hintMessageTableID; - static const std::string scrubMessageTableID; + static const std::string merchantMessageTableID; static const std::string rupeeMessageTableID; static const std::string NaviRandoMessageTableID; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index e55f4d9fa..d6f20e9a4 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1583,7 +1583,7 @@ extern "C" ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, } extern "C" CustomMessageEntry Randomizer_GetScrubMessage(s16 itemPrice) { - return CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, itemPrice); + return CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, itemPrice); } extern "C" CustomMessageEntry Randomizer_GetNaviMessage() { @@ -1722,7 +1722,7 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) { } else if (CVar_GetS32("gRandoRelevantNavi", 1) && textId >= 0x0140 && textId <= 0x015F) { messageEntry = Randomizer_GetNaviMessage(); } else if (Randomizer_GetSettingValue(RSK_SHUFFLE_MAGIC_BEANS) && textId == TEXT_BEAN_SALESMAN) { - messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::scrubMessageTableID, TEXT_BEAN_SALESMAN); + messageEntry = CustomMessageManager::Instance->RetrieveMessage(Randomizer::merchantMessageTableID, TEXT_BEAN_SALESMAN); } } if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) { From 4a51ab31872468f0624ac56fad4d9c265e4a29ce Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 20:42:34 -0400 Subject: [PATCH 13/30] Fixes bug where Bean Pack was also granting blue potion --- soh/src/code/z_parameter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index be3bf8253..1c0a2db87 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2186,6 +2186,7 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { INV_CONTENT(ITEM_BEAN) = ITEM_BEAN; AMMO(ITEM_BEAN) = 10; } + return RG_NONE; } if (item == RG_DOUBLE_DEFENSE) { From 9148fa5aecac359d73df84875e0e93b6fd9208dd Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Thu, 25 Aug 2022 20:48:28 -0400 Subject: [PATCH 14/30] Adds custom particles to Freestanding Bean Pack item. --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- soh/src/code/z_en_item00.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 4fd2a123d..b3120c3c2 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -4059,7 +4059,7 @@ void CreateMerchantMessages() { TEXTBOX_POS_BOTTOM, "I tried to be a %rmagic bean%w salesman,&but it turns out my marketing skills&weren't worth " "beans!^Anyway, want to buy my&%gmysterious item%w for 60 Rupees?\x1B&%gYes&No%w", - "Möchten Sie einen geheimnisvollen& Gegenstand für 60 Rubine?\x1B&%gJa&Nein%w", + "Möchten Sie einen geheimnisvollen&Gegenstand für 60 Rubine?\x1B&%gJa&Nein%w", "J'ai essayé d'être un vendeur de&%rharicots magiques%w, mais j'étais&mauvais au niveau du marketing et&ça " "me courait sur le haricot...^Enfin bref, ça te dirait de m'acheter un&" "%gobjet mystérieux%w pour 60 Rubis?\x1B&%gOui&Non%w", diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c index 89e1c9df7..95375ea48 100644 --- a/soh/src/code/z_en_item00.c +++ b/soh/src/code/z_en_item00.c @@ -1290,6 +1290,7 @@ void EnItem00_CustomItemsParticles(Actor* Parent, GlobalContext* globalCtx, GetI switch (giEntry.itemId) { case RG_MAGIC_SINGLE: case RG_MAGIC_DOUBLE: + case RG_MAGIC_BEAN_PACK: color_slot = 0; break; case RG_DOUBLE_DEFENSE: From 53531c4481123e448f731f01d5152ac0bd5cf049 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Fri, 26 Aug 2022 01:17:51 -0400 Subject: [PATCH 15/30] Cleanup --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- soh/src/code/z_parameter.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index b3120c3c2..2d7798e20 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -32,7 +32,7 @@ u8 generated; const std::string Randomizer::getItemMessageTableID = "Randomizer"; const std::string Randomizer::hintMessageTableID = "RandomizerHints"; -const std::string Randomizer::merchantMessageTableID = "RandomizerScrubs"; +const std::string Randomizer::merchantMessageTableID = "RandomizerMerchants"; const std::string Randomizer::rupeeMessageTableID = "RandomizerRupees"; const std::string Randomizer::NaviRandoMessageTableID = "RandomizerNavi"; diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 1c0a2db87..73044df27 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2182,7 +2182,7 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) { } if (item == RG_MAGIC_BEAN_PACK) { - if (gSaveContext.inventory.items[SLOT(ITEM_BEAN)] == ITEM_NONE) { + if (INV_CONTENT(ITEM_BEAN) == ITEM_NONE) { INV_CONTENT(ITEM_BEAN) = ITEM_BEAN; AMMO(ITEM_BEAN) = 10; } From 83abf5776668a43d836fae1d0102a0bf32152f34 Mon Sep 17 00:00:00 2001 From: aMannus Date: Fri, 26 Aug 2022 23:51:36 +0200 Subject: [PATCH 16/30] Add skull token to links pocket --- soh/src/code/z_sram.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index f35123229..92dd215c4 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -309,6 +309,11 @@ void GiveLinkDekuNutUpgrade(GetItemID giid) { } } +void GiveLinkSkullToken() { + gSaveContext.inventory.questItems |= gBitFlags[QUEST_SKULL_TOKEN]; + gSaveContext.inventory.gsTokens++; +} + void GiveLinkMagic(GetItemID giid) { if (giid == RG_MAGIC_SINGLE) { gSaveContext.magicLevel = 1; @@ -849,6 +854,8 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { GiveLinkDekuStickUpgrade(giid); } else if (giid == GI_NUT_UPGRADE_30 || giid == GI_NUT_UPGRADE_40) { GiveLinkDekuNutUpgrade(giid); + } else if (giid == GI_SKULL_TOKEN) { + GiveLinkSkullToken(); } else { s32 iid = getItem.itemId; if (iid != -1) INV_CONTENT(iid) = iid; From 9f47099232a810d30e39360f9ad08d2b23d18912 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Fri, 26 Aug 2022 21:17:12 -0400 Subject: [PATCH 17/30] Properly handles starting link with adult trade items. --- soh/src/code/z_sram.c | 50 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 92dd215c4..d53055c93 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -4,6 +4,7 @@ #include #include #include +#include "soh/Enhancements/randomizer/adult_trade_shuffle.h" #define NUM_DUNGEONS 8 #define NUM_TRIALS 6 @@ -513,6 +514,53 @@ void GiveLinkDungeonItem(GetItemID getItemId) { } } +void GiveLinkAdultTradeItem(GetItemID giid) { + ItemID item; + switch (giid) { + case GI_POCKET_EGG: + item = ITEM_POCKET_EGG; + break; + case GI_POCKET_CUCCO: + item = ITEM_POCKET_CUCCO; + break; + case GI_COJIRO: + item = ITEM_COJIRO; + break; + case GI_ODD_MUSHROOM: + item = ITEM_ODD_MUSHROOM; + break; + case GI_ODD_POTION: + item = ITEM_ODD_POTION; + break; + case GI_SAW: + item = ITEM_SAW; + break; + case GI_SWORD_BROKEN: + item = ITEM_SWORD_BROKEN; + break; + case GI_PRESCRIPTION: + item = ITEM_PRESCRIPTION; + break; + case GI_FROG: + item = ITEM_FROG; + break; + case GI_EYEDROPS: + item = ITEM_EYEDROPS; + break; + case GI_CLAIM_CHECK: + item = ITEM_CLAIM_CHECK; + break; + } + if ((item == ITEM_SAW) && CVar_GetS32("gDekuNutUpgradeFix", 0) == 0) { + gSaveContext.itemGetInf[1] |= 0x8000; + } + + if (item >= ITEM_POCKET_EGG) { + gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(item); + } + INV_CONTENT(item) = item; +} + void GiveLinksPocketMedallion() { GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_LINKS_POCKET, RG_NONE); @@ -856,6 +904,8 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { GiveLinkDekuNutUpgrade(giid); } else if (giid == GI_SKULL_TOKEN) { GiveLinkSkullToken(); + } else if (giid >= GI_POCKET_EGG && giid <= GI_CLAIM_CHECK) { + GiveLinkAdultTradeItem(giid); } else { s32 iid = getItem.itemId; if (iid != -1) INV_CONTENT(iid) = iid; From 62aeac51b9b9d86be0ab5cae1510cecadd0d92ff Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Fri, 26 Aug 2022 22:14:49 -0400 Subject: [PATCH 18/30] ACTUALLY fixes adult trade items on save init this time. --- soh/src/code/z_sram.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index d53055c93..4bbbe726a 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -558,7 +558,7 @@ void GiveLinkAdultTradeItem(GetItemID giid) { if (item >= ITEM_POCKET_EGG) { gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(item); } - INV_CONTENT(item) = item; + INV_CONTENT(ITEM_TRADE_ADULT) = item; } void GiveLinksPocketMedallion() { @@ -788,6 +788,11 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.eventChkInf[3] |= 0x800; gSaveContext.eventChkInf[12] |= 1; + // shuffle adult trade quest + if (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) { + gSaveContext.adultTradeItems = 0; + } + // Give Link's pocket item GiveLinksPocketMedallion(); @@ -904,7 +909,7 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { GiveLinkDekuNutUpgrade(giid); } else if (giid == GI_SKULL_TOKEN) { GiveLinkSkullToken(); - } else if (giid >= GI_POCKET_EGG && giid <= GI_CLAIM_CHECK) { + } else if (giid >= GI_POCKET_EGG && giid <= GI_CLAIM_CHECK || giid == GI_COJIRO) { GiveLinkAdultTradeItem(giid); } else { s32 iid = getItem.itemId; @@ -1022,11 +1027,6 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { } } - // shuffle adult trade quest - if (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) { - gSaveContext.adultTradeItems = 0; - } - // complete mask quest if (Randomizer_GetSettingValue(RSK_COMPLETE_MASK_QUEST)) { gSaveContext.itemGetInf[3] |= 0x100; // Sold Keaton Mask From 7fbb381db74a0aa2405866b99f7daa31fae431a8 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 02:25:13 -0400 Subject: [PATCH 19/30] Changes Malon's behavior to so she won't leave Hyrule Castle until you've obtained her item. --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index 88c5b0724..5e6b363b5 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -90,7 +90,16 @@ static void* sEyeTextures[] = { gMalonChildEyeClosedTex, }; +bool Randomizer_ObtainedMalonHCReward() { + return Flags_GetEventChkInf(0x12); +} + u16 EnMa1_GetText(GlobalContext* globalCtx, Actor* thisx) { + // Special case for Malon Hyrule Castle Text. Placing it here at the beginning + // has the added benefit of circumventing mask text if wearing bunny hood. + if (gSaveContext.n64ddFlag && globalCtx->sceneNum == SCENE_SPOT15) { + return Randomizer_ObtainedMalonHCReward() ? 0x2044 : 0x2043; + } u16 faceReaction = Text_GetFaceReaction(globalCtx, 0x17); if (faceReaction != 0) { @@ -195,7 +204,8 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { !(gSaveContext.eventChkInf[1] & 0x10) && !(gSaveContext.infTable[8] & 0x800)) { return 1; } - if ((globalCtx->sceneNum == SCENE_SPOT15) && !(gSaveContext.eventChkInf[1] & 0x10)) { + if ((globalCtx->sceneNum == SCENE_SPOT15) && (!(gSaveContext.eventChkInf[1] & 0x10) || + (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()))) { if (gSaveContext.infTable[8] & 0x800) { return 1; } else { @@ -209,7 +219,7 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { if (globalCtx->sceneNum != SCENE_SPOT20) { return 0; } - if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10)) { + if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10) && ((gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()) || !gSaveContext.n64ddFlag)) { return 1; } return 0; @@ -290,7 +300,7 @@ void EnMa1_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.targetMode = 6; this->unk_1E8.unk_00 = 0; - if (!(gSaveContext.eventChkInf[1] & 0x10) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || + if (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || (gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F))) { this->actionFunc = func_80AA0D88; EnMa1_ChangeAnim(this, ENMA1_ANIM_2); @@ -322,9 +332,11 @@ void func_80AA0D88(EnMa1* this, GlobalContext* globalCtx) { } } - if ((globalCtx->sceneNum == SCENE_SPOT15) && (gSaveContext.eventChkInf[1] & 0x10)) { - Actor_Kill(&this->actor); - } else if (!(gSaveContext.eventChkInf[1] & 0x10) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { + if ((globalCtx->sceneNum == SCENE_SPOT15) && (gSaveContext.eventChkInf[1] & 0x10) && (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward())) { + if (!gSaveContext.n64ddFlag) { + Actor_Kill(&this->actor); + } + } else if ((!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward())) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { if (this->unk_1E8.unk_00 == 2) { this->actionFunc = func_80AA0EA0; globalCtx->msgCtx.stateTimer = 4; From bf1b327a955faa356a56e7ae02db13bf386628c5 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 02:50:44 -0400 Subject: [PATCH 20/30] Cleanup and Documentation --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index 5e6b363b5..d7dbea1f5 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -200,10 +200,14 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { if (!LINK_IS_CHILD) { return 0; } + // Causes Malon to appear in the market if you haven't met her yet. if (((globalCtx->sceneNum == SCENE_MARKET_NIGHT) || (globalCtx->sceneNum == SCENE_MARKET_DAY)) && !(gSaveContext.eventChkInf[1] & 0x10) && !(gSaveContext.infTable[8] & 0x800)) { return 1; } + // Causes Malon to appear at Hyrule Castle if you've met her already and either we're vanilla and Talon hasn't + // left Hyrule Castle, or if we're randomized and haven't obtained her check. If we haven't met Malon yet, this + // sets the flag for meeting her. if ((globalCtx->sceneNum == SCENE_SPOT15) && (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()))) { if (gSaveContext.infTable[8] & 0x800) { @@ -213,13 +217,18 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { return 0; } } + // Malon asleep in her bed if Talon has left Hyrule Castle and it is nighttime. if ((globalCtx->sceneNum == SCENE_SOUKO) && IS_NIGHT && (gSaveContext.eventChkInf[1] & 0x10)) { return 1; } + // Don't spawn Malon if none of the above are true and we are not in Lon Lon Ranch. if (globalCtx->sceneNum != SCENE_SPOT20) { return 0; } - if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10) && ((gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()) || !gSaveContext.n64ddFlag)) { + // If we've gotten this far, we're in Lon Lon Ranch. Spawn Malon if it is daytime, Talon has left Hyrule Castle, and + // either we are not randomized, or we are and we have received Malon's item at Hyrule Castle. + if ((this->actor.shape.rot.z == 3) && IS_DAY && (gSaveContext.eventChkInf[1] & 0x10) && + ((gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()) || !gSaveContext.n64ddFlag)) { return 1; } return 0; @@ -300,10 +309,14 @@ void EnMa1_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.targetMode = 6; this->unk_1E8.unk_00 = 0; + // If Talon has not left Hyrule Castle, we are randomized and ahve not obtained Malon's HC Check, we are not randomized + // and have Epona's Song, or we are randomized and have obtained Malon's Epona's Song Check. This sets Malon's idle + // singing animation in such a way that she has dialog but does not give items or respond to the Ocarina. if (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || (gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F))) { this->actionFunc = func_80AA0D88; EnMa1_ChangeAnim(this, ENMA1_ANIM_2); + // If none of the above conditions were true, set Malon up to teach Epona's Song. } else { if (gSaveContext.n64ddFlag) { // Skip straight to "let's sing it together" textbox in the ranch gSaveContext.eventChkInf[1] |= 0x40; @@ -332,10 +345,15 @@ void func_80AA0D88(EnMa1* this, GlobalContext* globalCtx) { } } - if ((globalCtx->sceneNum == SCENE_SPOT15) && (gSaveContext.eventChkInf[1] & 0x10) && (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward())) { + // If we're at Hyrule Castle, and either Talon has left or we're randomized and have obtained Malon's HC Check + if ((globalCtx->sceneNum == SCENE_SPOT15) && ((!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()))) { + // Only kill Malon's Actor here in vanilla. If we're in rando and speak to her we don't want her to pop + // out of existence immediately. The init function will properly kill her actor on the next scene load. if (!gSaveContext.n64ddFlag) { Actor_Kill(&this->actor); } + // If Talon has not run away, or we're randomized and have not received Malon's HC Check, or we're + // not randomized and have obtained Epona's Song, put Malon in the state to give Link the HC reward. } else if ((!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward())) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { if (this->unk_1E8.unk_00 == 2) { this->actionFunc = func_80AA0EA0; From 928a39fe9e21f43a2e322a9cdf06bed98c04b6fe Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 09:30:49 -0400 Subject: [PATCH 21/30] More Cleanup --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index d7dbea1f5..eaf4b1419 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -309,9 +309,11 @@ void EnMa1_Init(Actor* thisx, GlobalContext* globalCtx) { this->actor.targetMode = 6; this->unk_1E8.unk_00 = 0; - // If Talon has not left Hyrule Castle, we are randomized and ahve not obtained Malon's HC Check, we are not randomized - // and have Epona's Song, or we are randomized and have obtained Malon's Epona's Song Check. This sets Malon's idle - // singing animation in such a way that she has dialog but does not give items or respond to the Ocarina. + // To avoid missing a check, we want Malon to have the actionFunc for singing, but not reacting to Ocarina, if any of + // the following are true. + // 1. Talon has not left Hyrule Castle. + // 2. We are Randomized and have not obtained Malon's Weird Egg Check. + // 3. We are not Randomized and have obtained Epona's Song if (!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag) || (gSaveContext.n64ddFlag && Flags_GetTreasure(globalCtx, 0x1F))) { this->actionFunc = func_80AA0D88; @@ -345,15 +347,15 @@ void func_80AA0D88(EnMa1* this, GlobalContext* globalCtx) { } } - // If we're at Hyrule Castle, and either Talon has left or we're randomized and have obtained Malon's HC Check - if ((globalCtx->sceneNum == SCENE_SPOT15) && ((!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && Randomizer_ObtainedMalonHCReward()))) { - // Only kill Malon's Actor here in vanilla. If we're in rando and speak to her we don't want her to pop - // out of existence immediately. The init function will properly kill her actor on the next scene load. - if (!gSaveContext.n64ddFlag) { - Actor_Kill(&this->actor); - } - // If Talon has not run away, or we're randomized and have not received Malon's HC Check, or we're - // not randomized and have obtained Epona's Song, put Malon in the state to give Link the HC reward. + // We want to Kill Malon's Actor outside of randomizer when Talon is freed. In Randomizer we don't kill Malon's + // Actor here, otherwise if we wake up Talon first and then get her check she will spontaneously + // disappear. + if ((globalCtx->sceneNum == SCENE_SPOT15) && (!gSaveContext.n64ddFlag && gSaveContext.eventChkInf[1] & 0x10)) { + Actor_Kill(&this->actor); + // We want Malon to give the Weird Egg Check (see function below) in the following situations: + // 1. Talon as not left Hyrule Castle (Vanilla) OR + // 2. We haven't obtained Malon's Weird Egg Check (Randomizer only) OR + // 3. We have Epona's Song? (Vanilla only, not sure why it's here but I didn't write that one) } else if ((!(gSaveContext.eventChkInf[1] & 0x10) || (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward())) || (CHECK_QUEST_ITEM(QUEST_SONG_EPONA) && !gSaveContext.n64ddFlag)) { if (this->unk_1E8.unk_00 == 2) { this->actionFunc = func_80AA0EA0; From 1bf8423f75bd0b7abe77787831c1863b08105e6b Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 14:19:37 -0400 Subject: [PATCH 22/30] Reimplements selecting different amounts of Ganon's Trials. --- soh/include/functions.h | 1 + soh/include/macros.h | 1 + .../randomizer/3drando/settings.cpp | 18 +++--- .../randomizer/3drando/spoiler_log.cpp | 59 ++++++++++++------- .../Enhancements/randomizer/randomizer.cpp | 56 +++++++++++++++--- soh/soh/Enhancements/randomizer/randomizer.h | 6 +- soh/soh/OTRGlobals.cpp | 8 +++ soh/soh/OTRGlobals.h | 2 + soh/src/code/z_actor.c | 4 ++ soh/src/code/z_sram.c | 10 +++- .../actors/ovl_Demo_Kekkai/z_demo_kekkai.c | 28 ++++++++- .../ovl_Object_Kankyo/z_object_kankyo.c | 21 +++++++ .../ovl_file_choose/z_file_choose.c | 1 + 13 files changed, 174 insertions(+), 41 deletions(-) diff --git a/soh/include/functions.h b/soh/include/functions.h index 9047b6d3f..7d8b309a5 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -561,6 +561,7 @@ s32 Flags_GetInfTable(s32 flag); void Flags_SetInfTable(s32 flag); s32 Flags_GetRandomizerInf(RandomizerInf flag); void Flags_SetRandomizerInf(RandomizerInf flag); +void Flags_UnsetRandomizerInf(RandomizerInf flag); u16 func_80037C30(GlobalContext* globalCtx, s16 arg1); s32 func_80037D98(GlobalContext* globalCtx, Actor* actor, s16 arg2, s32* arg3); s32 func_80038290(GlobalContext* globalCtx, Actor* actor, Vec3s* arg2, Vec3s* arg3, Vec3f arg4); diff --git a/soh/include/macros.h b/soh/include/macros.h index 1822cb1d6..bcfb3fce5 100644 --- a/soh/include/macros.h +++ b/soh/include/macros.h @@ -260,5 +260,6 @@ extern GraphicsContext* __gfxCtx; #define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1) +#define NUM_TRIALS 6 #endif diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index fc02dfd6a..9e496598e 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2519,15 +2519,15 @@ namespace Settings { BridgeTokenCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_TOKEN_COUNT]); RandomGanonsTrials.SetSelectedIndex(cvarSettings[RSK_RANDOM_TRIALS]); // RANDTODO: Switch this back once Ganon's Trials Count is properly implemented. - //GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); - switch (cvarSettings[RSK_TRIAL_COUNT]) { - case 0: - GanonsTrialsCount.SetSelectedIndex(6); - break; - case 1: - GanonsTrialsCount.SetSelectedIndex(0); - break; - } + GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); + // switch (cvarSettings[RSK_TRIAL_COUNT]) { + // case 0: + // GanonsTrialsCount.SetSelectedIndex(6); + // break; + // case 1: + // GanonsTrialsCount.SetSelectedIndex(0); + // break; + // } ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]); ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]); diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 48ed607d2..332fbb9e1 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -501,27 +501,46 @@ static void WriteMasterQuestDungeons(tinyxml2::XMLDocument& spoilerLog) { } } -// Writes the required trails to the spoiler log, if there are any. -static void WriteRequiredTrials(tinyxml2::XMLDocument& spoilerLog) { - auto parentNode = spoilerLog.NewElement("required-trials"); - - for (const auto* trial : Trial::trialList) { - if (trial->IsSkipped()) { - continue; +// Writes the required trials to the spoiler log, if there are any. +static void WriteRequiredTrials() { + for (const auto& trial : Trial::trialList) { + if (trial->IsRequired()) { + std::string trialName; + switch (gSaveContext.language) { + case LANGUAGE_FRA: + trialName = trial->GetName().GetFrench(); + break; + case LANGUAGE_ENG: + default: + trialName = trial->GetName().GetEnglish(); + break; + } + jsonData["requiredTrials"].push_back(RemoveLineBreaks(trialName)); + } } - - auto node = parentNode->InsertNewChildElement("trial"); - // PURPLE TODO: LOCALIZATION - std::string name = trial->GetName().GetEnglish(); - name[0] = toupper(name[0]); // Capitalize T in "The" - node->SetAttribute("name", name.c_str()); - } - - if (!parentNode->NoChildren()) { - spoilerLog.RootElement()->InsertEndChild(parentNode); - } } +// Writes the required trails to the spoiler log, if there are any. +// static void WriteRequiredTrials(tinyxml2::XMLDocument& spoilerLog) { +// auto parentNode = spoilerLog.NewElement("required-trials"); + +// for (const auto* trial : Trial::trialList) { +// if (trial->IsSkipped()) { +// continue; +// } + +// auto node = parentNode->InsertNewChildElement("trial"); +// // PURPLE TODO: LOCALIZATION +// std::string name = trial->GetName().GetEnglish(); +// name[0] = toupper(name[0]); // Capitalize T in "The" +// node->SetAttribute("name", name.c_str()); +// } + +// if (!parentNode->NoChildren()) { +// spoilerLog.RootElement()->InsertEndChild(parentNode); +// } +// } + // Writes the intended playthrough to the spoiler log, separated into spheres. static void WritePlaythrough() { // auto playthroughNode = spoilerLog.NewElement("playthrough"); @@ -723,7 +742,7 @@ const char* SpoilerLog_Write(int language) { // WriteEnabledGlitches(spoilerLog); //} //WriteMasterQuestDungeons(spoilerLog); - //WriteRequiredTrials(spoilerLog); + WriteRequiredTrials(); WritePlaythrough(); //WriteWayOfTheHeroLocation(spoilerLog); @@ -773,7 +792,7 @@ bool PlacementLog_Write() { WriteEnabledTricks(placementLog); WriteEnabledGlitches(placementLog); WriteMasterQuestDungeons(placementLog); - WriteRequiredTrials(placementLog); + //WriteRequiredTrials(placementLog); placementtxt = "\n" + placementtxt; diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 2d7798e20..6dff5a627 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -107,6 +107,21 @@ Randomizer::~Randomizer() { this->randomizerMerchantPrices.clear(); } +std::unordered_map spoilerFileTrialToEnum = { + { "the Forest Trial", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, + { "l'épreuve de la forêt", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, + { "the Fire Trial", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, + { "l'épreuve du feu", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, + { "the Water Trial", RAND_INF_TRIALS_DONE_WATER_TRIAL }, + { "l'épreuve de l'eau", RAND_INF_TRIALS_DONE_WATER_TRIAL }, + { "the Spirit Trial", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, + { "l'épreuve de l'esprit", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, + { "the Shadow Trial", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, + { "l'épreuve de l'ombre", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, + { "the Light Trial", RAND_INF_TRIALS_DONE_LIGHT_TRIAL }, + { "l'épreuve de la lumière", RAND_INF_TRIALS_DONE_LIGHT_TRIAL } +}; + std::unordered_map getItemIdToItemId = { { GI_BOW, ITEM_BOW }, { GI_ARROW_FIRE, ITEM_ARROW_FIRE }, @@ -673,6 +688,12 @@ void Randomizer::LoadItemLocations(const char* spoilerFileName, bool silent) { itemLocations[RC_UNKNOWN_CHECK] = RG_NONE; } +void Randomizer::LoadRequiredTrials(const char* spoilerFileName) { + if (strcmp(spoilerFileName, "") != 0) { + ParseRequiredTrialsFile(spoilerFileName); + } +} + void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { std::ifstream spoilerFileStream(sanitize(spoilerFileName)); if (!spoilerFileStream) @@ -1091,6 +1112,25 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) { } } +void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) { + std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + if (!spoilerFileStream) { + return; + } + + try { + json spoilerFileJson; + spoilerFileStream >> spoilerFileJson; + json trialsJson = spoilerFileJson["requiredTrials"]; + + for (auto it = trialsJson.begin(); it != trialsJson.end(); it++) { + this->trialsRequired[spoilerFileTrialToEnum[it.value()]] = true; + } + } catch (const std::exception& e) { + return; + } +} + void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent) { std::ifstream spoilerFileStream(sanitize(spoilerFileName)); if (!spoilerFileStream) @@ -1141,6 +1181,10 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent } } +bool Randomizer::IsTrialRequired(RandomizerInf trial) { + return this->trialsRequired.contains(trial); +} + s16 Randomizer::GetRandomizedItemId(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum) { s16 itemId = GetItemFromActor(actorId, actorParams, sceneNum, ogId); return itemId; @@ -3355,21 +3399,17 @@ void DrawRandoEditor(bool& open) { PaddedSeparator(); // Random Ganon's Trials - /* ImGui::Text("Random Ganon's Trials"); + SohImGui::EnhancementCheckbox("Random Ganon's Trials", "gRandomizeGanonTrial"); InsertHelpHoverText("Sets a random number or required trials to enter\nGanon's Tower."); - SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 2, 0); if (CVar_GetS32("gRandomizeGanonTrial", 0) == 0) { - ImGui::PopItemWidth(); SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 0, 6, "", 6); InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); - RANDTODO: Switch back to slider when pre-completing some of Ganon's Trials is properly implemnted. } - */ - SohImGui::EnhancementCheckbox("Skip Ganon's Trials", "gRandomizeGanonTrialCount"); - InsertHelpHoverText( - "Sets whether or not Ganon's Castle Trials are required to enter Ganon's Tower."); + // SohImGui::EnhancementCheckbox("Skip Ganon's Trials", "gRandomizeGanonTrialCount"); + // InsertHelpHoverText( + // "Sets whether or not Ganon's Castle Trials are required to enter Ganon's Tower."); } // COLUMN 2 - Shuffle Settings diff --git a/soh/soh/Enhancements/randomizer/randomizer.h b/soh/soh/Enhancements/randomizer/randomizer.h index 8b467a699..2c87a5b03 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.h +++ b/soh/soh/Enhancements/randomizer/randomizer.h @@ -14,6 +14,7 @@ class Randomizer { private: std::unordered_map itemLocations; std::unordered_map hintLocations; + std::unordered_map trialsRequired; std::string childAltarText; std::string adultAltarText; std::string ganonHintText; @@ -24,6 +25,7 @@ class Randomizer { s16 GetItemFromActor(s16 actorId, s16 actorParams, s16 sceneNum, GetItemID ogItemId); void ParseRandomizerSettingsFile(const char* spoilerFileName); void ParseHintLocationsFile(const char* spoilerFileName); + void ParseRequiredTrialsFile(const char* spoilerFileName); void ParseItemLocationsFile(const char* spoilerFileName, bool silent); bool IsItemVanilla(RandomizerGet randoGet); @@ -44,7 +46,9 @@ class Randomizer { bool SpoilerFileExists(const char* spoilerFileName); void LoadRandomizerSettings(const char* spoilerFileName); void LoadHintLocations(const char* spoilerFileName); - void LoadItemLocations(const char* spoilerFileName, bool silent); + void LoadRequiredTrials(const char* spoilerFileName); + void LoadItemLocations(const char* spoilerFileName,bool silent); + bool IsTrialRequired(RandomizerInf trial); u8 GetRandoSettingValue(RandomizerSettingKey randoSettingKey); RandomizerCheck GetCheckFromActor(s16 sceneNum, s16 actorId, s16 actorParams); std::string GetChildAltarText() const; diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index d6f20e9a4..7d7a86268 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1562,10 +1562,18 @@ extern "C" void Randomizer_LoadHintLocations(const char* spoilerFileName) { OTRGlobals::Instance->gRandomizer->LoadHintLocations(spoilerFileName); } +extern "C" void Randomizer_LoadRequiredTrials(const char* spoilerFileName) { + OTRGlobals::Instance->gRandomizer->LoadRequiredTrials(spoilerFileName); +} + extern "C" void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent) { OTRGlobals::Instance->gRandomizer->LoadItemLocations(spoilerFileName, silent); } +extern "C" bool Randomizer_IsTrialRequired(RandomizerInf trial) { + return OTRGlobals::Instance->gRandomizer->IsTrialRequired(trial); +} + extern "C" bool SpoilerFileExists(const char* spoilerFileName) { return OTRGlobals::Instance->gRandomizer->SpoilerFileExists(spoilerFileName); } diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 3266b16eb..f81afdaea 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -98,7 +98,9 @@ u8 Randomizer_GetSettingValue(RandomizerSettingKey randoSettingKey); RandomizerCheck Randomizer_GetCheckFromActor(s16 actorId, s16 actorParams, s16 sceneNum); ScrubIdentity Randomizer_IdentifyScrub(s32 sceneNum, s32 actorParams, s32 respawnData); void Randomizer_LoadHintLocations(const char* spoilerFileName); +void Randomizer_LoadRequiredTrials(const char* spoilerFileName); void Randomizer_LoadItemLocations(const char* spoilerFileName, bool silent); +bool Randomizer_IsTrialRequired(RandomizerInf trial); GetItemEntry Randomizer_GetRandomizedItem(GetItemID ogId, s16 actorId, s16 actorParams, s16 sceneNum); GetItemEntry Randomizer_GetItemFromKnownCheck(RandomizerCheck randomizerCheck, GetItemID ogId); bool Randomizer_ObtainedFreestandingIceTrap(RandomizerCheck randomizerCheck, GetItemID ogId, Actor* actor); diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 5d7add53a..0f4808494 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -4719,6 +4719,10 @@ void Flags_SetRandomizerInf(RandomizerInf flag) { gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); } +void Flags_UnsetRandomizerInf(RandomizerInf flag) { + gSaveContext.randomizerInf[flag >> 4] &= ~(flag & 0xF); +} + u32 func_80035BFC(GlobalContext* globalCtx, s16 arg1) { u16 retTextId = 0; diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index 4bbbe726a..c8befa586 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -7,7 +7,6 @@ #include "soh/Enhancements/randomizer/adult_trade_shuffle.h" #define NUM_DUNGEONS 8 -#define NUM_TRIALS 6 #define NUM_COWS 10 #define NUM_SCRUBS 35 @@ -762,6 +761,15 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { gSaveContext.randomizerInf[i] = 0; } + // Set all trials to cleared if trial count is random or anything other than 6 + if (Randomizer_GetSettingValue(RSK_RANDOM_TRIALS) || (Randomizer_GetSettingValue(RSK_TRIAL_COUNT) != 6)) { + for (u16 i = RAND_INF_TRIALS_DONE_LIGHT_TRIAL; i <= RAND_INF_TRIALS_DONE_SHADOW_TRIAL; i++) { + if (!Randomizer_IsTrialRequired(i)) { + Flags_SetRandomizerInf(i); + } + } + } + // Set Cutscene flags to skip them gSaveContext.eventChkInf[0xC] |= 0x10; // returned to tot with medallions gSaveContext.eventChkInf[0xC] |= 0x20; //sheik at tot pedestal diff --git a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c index adc534a2d..dab59262c 100644 --- a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c +++ b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c @@ -64,12 +64,33 @@ static u8 sEnergyColors[] = { /* Forest prim */ 255, 255, 170, /* env */ 0, 200, 0, }; +// Translates from the barrier's actor params to their corresponding randInf flags. +RandomizerInf trialParamToRandInf(u16 params) { + switch (params) { + case KEKKAI_LIGHT: + return RAND_INF_TRIALS_DONE_LIGHT_TRIAL; + case KEKKAI_FOREST: + return RAND_INF_TRIALS_DONE_FOREST_TRIAL; + case KEKKAI_FIRE: + return RAND_INF_TRIALS_DONE_FIRE_TRIAL; + case KEKKAI_WATER: + return RAND_INF_TRIALS_DONE_WATER_TRIAL; + case KEKKAI_SPIRIT: + return RAND_INF_TRIALS_DONE_SPIRIT_TRIAL; + case KEKKAI_SHADOW: + return RAND_INF_TRIALS_DONE_SHADOW_TRIAL; + } +} + s32 DemoKekkai_CheckEventFlag(s32 params) { static s32 eventFlags[] = { 0xC3, 0xBC, 0xBF, 0xBE, 0xBD, 0xAD, 0xBB }; if ((params < KEKKAI_TOWER) || (params > KEKKAI_FOREST)) { return true; } + if (gSaveContext.n64ddFlag) { + return Flags_GetRandomizerInf(trialParamToRandInf(params)); + } return Flags_GetEventChkInf(eventFlags[params]); } @@ -128,8 +149,7 @@ void DemoKekkai_Init(Actor* thisx, GlobalContext* globalCtx) { this->collider2.dim.yShift = 300; if (gSaveContext.n64ddFlag) { - int trialsToComplete = Randomizer_GetSettingValue(RSK_TRIAL_COUNT); - if (trialsToComplete <= TrialsDoneCount()) { + if (TrialsDoneCount() == NUM_TRIALS) { Actor_Kill(thisx); return; } @@ -141,6 +161,10 @@ void DemoKekkai_Init(Actor* thisx, GlobalContext* globalCtx) { case KEKKAI_SHADOW: case KEKKAI_SPIRIT: case KEKKAI_FOREST: + if (gSaveContext.n64ddFlag && Flags_GetRandomizerInf(trialParamToRandInf(thisx->params))) { + Actor_Kill(thisx); + return; + } this->energyAlpha = 1.0f; this->orbScale = 1.0f; Actor_SetScale(thisx, 0.1f); diff --git a/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c b/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c index 22b796964..6aff36144 100644 --- a/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c +++ b/soh/src/overlays/actors/ovl_Object_Kankyo/z_object_kankyo.c @@ -135,6 +135,27 @@ void ObjectKankyo_Init(Actor* thisx, GlobalContext* globalCtx) { this->effects[5].size = 0.0f; } + if (gSaveContext.n64ddFlag) { + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_FOREST_TRIAL)) { + this->effects[0].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_WATER_TRIAL)) { + this->effects[1].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_SHADOW_TRIAL)) { + this->effects[2].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_FIRE_TRIAL)) { + this->effects[3].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_LIGHT_TRIAL)) { + this->effects[4].size = 0.0f; + } + if (Flags_GetRandomizerInf(RAND_INF_TRIALS_DONE_SPIRIT_TRIAL)) { + this->effects[5].size = 0.0f; + } + } + if (gSaveContext.cutsceneTrigger != 0) { if (gSaveContext.entranceIndex == 0x0538) { this->effects[0].size = 0.1f; diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 75cc7ca27..f363751ee 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -433,6 +433,7 @@ void FileChoose_UpdateMainMenu(GameState* thisx) { const char* fileLoc = CVar_GetString("gSpoilerLog", ""); Randomizer_LoadSettings(fileLoc); Randomizer_LoadHintLocations(fileLoc); + Randomizer_LoadRequiredTrials(fileLoc); Randomizer_LoadItemLocations(fileLoc, silent); fileSelectSpoilerFileLoaded = true; } From ff0ef4a6b472e9e11692b03cb24073826f27fab0 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 14:27:02 -0400 Subject: [PATCH 23/30] ImGui/Commented out code cleanup. --- soh/soh/Enhancements/randomizer/3drando/settings.cpp | 10 ---------- soh/soh/Enhancements/randomizer/randomizer.cpp | 6 +----- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index 9e496598e..cb9820cec 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2518,17 +2518,7 @@ namespace Settings { BridgeDungeonCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_DUNGEON_COUNT]); BridgeTokenCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_TOKEN_COUNT]); RandomGanonsTrials.SetSelectedIndex(cvarSettings[RSK_RANDOM_TRIALS]); - // RANDTODO: Switch this back once Ganon's Trials Count is properly implemented. GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); - // switch (cvarSettings[RSK_TRIAL_COUNT]) { - // case 0: - // GanonsTrialsCount.SetSelectedIndex(6); - // break; - // case 1: - // GanonsTrialsCount.SetSelectedIndex(0); - // break; - // } - ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]); ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]); Tokensanity.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_TOKENS]); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 6dff5a627..11335d275 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3399,17 +3399,13 @@ void DrawRandoEditor(bool& open) { PaddedSeparator(); // Random Ganon's Trials - ImGui::Text("Random Ganon's Trials"); SohImGui::EnhancementCheckbox("Random Ganon's Trials", "gRandomizeGanonTrial"); - InsertHelpHoverText("Sets a random number or required trials to enter\nGanon's Tower."); + InsertHelpHoverText("Sets a random number or required trials to enter Ganon's Tower."); if (CVar_GetS32("gRandomizeGanonTrial", 0) == 0) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 0, 6, "", 6); InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); } - // SohImGui::EnhancementCheckbox("Skip Ganon's Trials", "gRandomizeGanonTrialCount"); - // InsertHelpHoverText( - // "Sets whether or not Ganon's Castle Trials are required to enter Ganon's Tower."); } // COLUMN 2 - Shuffle Settings From 3d8b8066dadd584de71d17ba017ed6989d00041f Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 14:33:38 -0400 Subject: [PATCH 24/30] More comment cleanup --- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c index eaf4b1419..c2a19e621 100644 --- a/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c +++ b/soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c @@ -205,16 +205,15 @@ s32 func_80AA08C4(EnMa1* this, GlobalContext* globalCtx) { !(gSaveContext.eventChkInf[1] & 0x10) && !(gSaveContext.infTable[8] & 0x800)) { return 1; } - // Causes Malon to appear at Hyrule Castle if you've met her already and either we're vanilla and Talon hasn't - // left Hyrule Castle, or if we're randomized and haven't obtained her check. If we haven't met Malon yet, this - // sets the flag for meeting her. - if ((globalCtx->sceneNum == SCENE_SPOT15) && (!(gSaveContext.eventChkInf[1] & 0x10) || - (gSaveContext.n64ddFlag && !Randomizer_ObtainedMalonHCReward()))) { - if (gSaveContext.infTable[8] & 0x800) { - return 1; - } else { - gSaveContext.infTable[8] |= 0x800; - return 0; + if ((globalCtx->sceneNum == SCENE_SPOT15) && // if we're at hyrule castle + (!(gSaveContext.eventChkInf[1] & 0x10) || // and talon hasn't left + (gSaveContext.n64ddFlag && + !Randomizer_ObtainedMalonHCReward()))) { // or we're rando'd and haven't gotten malon's HC check + if (gSaveContext.infTable[8] & 0x800) { // if we've met malon + return 1; // make her appear at the castle + } else { // if we haven't met malon + gSaveContext.infTable[8] |= 0x800; // set the flag for meeting malon + return 0; // don't make her appear at the castle } } // Malon asleep in her bed if Talon has left Hyrule Castle and it is nighttime. From 4d8bfa97c0914d79c0b3e5bc8916aa6ff8656a2e Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 15:51:14 -0400 Subject: [PATCH 25/30] UI Changes (dropdown and slider rather than checkbox and slider) --- .../Enhancements/randomizer/3drando/settings.cpp | 12 ++++++++++-- soh/soh/Enhancements/randomizer/randomizer.cpp | 16 +++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp index cb9820cec..cb91e5334 100644 --- a/soh/soh/Enhancements/randomizer/3drando/settings.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -2517,8 +2517,16 @@ namespace Settings { BridgeRewardCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_REWARD_COUNT]); BridgeDungeonCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_DUNGEON_COUNT]); BridgeTokenCount.SetSelectedIndex(cvarSettings[RSK_RAINBOW_BRIDGE_TOKEN_COUNT]); - RandomGanonsTrials.SetSelectedIndex(cvarSettings[RSK_RANDOM_TRIALS]); - GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); + if (cvarSettings[RSK_RANDOM_TRIALS] == 2) { + RandomGanonsTrials.SetSelectedIndex(1); + } else { + RandomGanonsTrials.SetSelectedIndex(0); + } + if (cvarSettings[RSK_RANDOM_TRIALS] == 0) { + GanonsTrialsCount.SetSelectedIndex(0); + } else { + GanonsTrialsCount.SetSelectedIndex(cvarSettings[RSK_TRIAL_COUNT]); + } ShuffleRewards.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_DUNGEON_REWARDS]); ShuffleSongs.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_SONGS]); Tokensanity.SetSelectedIndex(cvarSettings[RSK_SHUFFLE_TOKENS]); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 11335d275..af83fe8e4 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3025,7 +3025,7 @@ void DrawRandoEditor(bool& open) { const char* randoGerudoFortress[3] = { "Normal", "Fast", "Open" }; const char* randoRainbowBridge[7] = { "Vanilla", "Always open", "Stones", "Medallions", "Dungeon rewards", "Dungeons", "Tokens" }; - const char* randoGanonsTrial[2] = { "Off", "On" }; + const char* randoGanonsTrial[3] = { "Skip", "Set Number", "Random Number" }; // World Settings const char* randoStartingAge[3] = { "Child", "Adult", "Random" }; @@ -3399,12 +3399,18 @@ void DrawRandoEditor(bool& open) { PaddedSeparator(); // Random Ganon's Trials - SohImGui::EnhancementCheckbox("Random Ganon's Trials", "gRandomizeGanonTrial"); - InsertHelpHoverText("Sets a random number or required trials to enter Ganon's Tower."); - if (CVar_GetS32("gRandomizeGanonTrial", 0) == 0) { + ImGui::Text("Ganon's Trials"); + InsertHelpHoverText("Sets the number of Ganon's Trials required to dispel the barrier\n\n" + "Skip - No Trials are required and the barrier is already dispelled.\n\n" + "Set Number - Select a number of trials that will be required from the" + "slider below. Which specific trials you need to complete will be random.\n\n" + "Random Number - A Random number and set of trials will be required."); + SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 3, 0); + if (CVar_GetS32("gRandomizeGanonTrial", 0) == 1) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 0, 6, "", 6); - InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); + InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower." + "The specific trials you need to complete will be randomly selected."); } } From dbd8909d2634d73e8da63d0ecb51ec4c3fa8b510 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 15:53:57 -0400 Subject: [PATCH 26/30] Forgot to limit slider from 1-6 rather than 0-6 --- soh/soh/Enhancements/randomizer/randomizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index af83fe8e4..4dea6642c 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3408,7 +3408,7 @@ void DrawRandoEditor(bool& open) { SohImGui::EnhancementCombobox("gRandomizeGanonTrial", randoGanonsTrial, 3, 0); if (CVar_GetS32("gRandomizeGanonTrial", 0) == 1) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", - "gRandomizeGanonTrialCount", 0, 6, "", 6); + "gRandomizeGanonTrialCount", 1, 6, "", 6); InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower." "The specific trials you need to complete will be randomly selected."); } From 404a637ebd2df655dd0d052ee4f419d23fa3f800 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 15:56:11 -0400 Subject: [PATCH 27/30] Removes added function that went unused. --- soh/include/functions.h | 1 - soh/src/code/z_actor.c | 4 ---- 2 files changed, 5 deletions(-) diff --git a/soh/include/functions.h b/soh/include/functions.h index 7d8b309a5..9047b6d3f 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -561,7 +561,6 @@ s32 Flags_GetInfTable(s32 flag); void Flags_SetInfTable(s32 flag); s32 Flags_GetRandomizerInf(RandomizerInf flag); void Flags_SetRandomizerInf(RandomizerInf flag); -void Flags_UnsetRandomizerInf(RandomizerInf flag); u16 func_80037C30(GlobalContext* globalCtx, s16 arg1); s32 func_80037D98(GlobalContext* globalCtx, Actor* actor, s16 arg2, s32* arg3); s32 func_80038290(GlobalContext* globalCtx, Actor* actor, Vec3s* arg2, Vec3s* arg3, Vec3f arg4); diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 0f4808494..5d7add53a 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -4719,10 +4719,6 @@ void Flags_SetRandomizerInf(RandomizerInf flag) { gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); } -void Flags_UnsetRandomizerInf(RandomizerInf flag) { - gSaveContext.randomizerInf[flag >> 4] &= ~(flag & 0xF); -} - u32 func_80035BFC(GlobalContext* globalCtx, s16 arg1) { u16 retTextId = 0; From 6aaef2179bbe26485973ab6552a9b22e514f12c6 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 18:26:25 -0400 Subject: [PATCH 28/30] More Cleanup --- .../randomizer/3drando/spoiler_log.cpp | 21 ------------------- .../Enhancements/randomizer/randomizer.cpp | 3 +-- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index 332fbb9e1..63230c2d1 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -520,27 +520,6 @@ static void WriteRequiredTrials() { } } -// Writes the required trails to the spoiler log, if there are any. -// static void WriteRequiredTrials(tinyxml2::XMLDocument& spoilerLog) { -// auto parentNode = spoilerLog.NewElement("required-trials"); - -// for (const auto* trial : Trial::trialList) { -// if (trial->IsSkipped()) { -// continue; -// } - -// auto node = parentNode->InsertNewChildElement("trial"); -// // PURPLE TODO: LOCALIZATION -// std::string name = trial->GetName().GetEnglish(); -// name[0] = toupper(name[0]); // Capitalize T in "The" -// node->SetAttribute("name", name.c_str()); -// } - -// if (!parentNode->NoChildren()) { -// spoilerLog.RootElement()->InsertEndChild(parentNode); -// } -// } - // Writes the intended playthrough to the spoiler log, separated into spheres. static void WritePlaythrough() { // auto playthroughNode = spoilerLog.NewElement("playthrough"); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 4dea6642c..a433f0b3c 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -3409,8 +3409,7 @@ void DrawRandoEditor(bool& open) { if (CVar_GetS32("gRandomizeGanonTrial", 0) == 1) { SohImGui::EnhancementSliderInt("Ganon's Trial Count: %d", "##RandoTrialCount", "gRandomizeGanonTrialCount", 1, 6, "", 6); - InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower." - "The specific trials you need to complete will be randomly selected."); + InsertHelpHoverText("Set the number of trials required to enter Ganon's Tower."); } } From fafd90482b37cd54e30fea7f5f38fe44864c5c3b Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 18:42:36 -0400 Subject: [PATCH 29/30] Refactor of some old rando code to use new functions. --- .../actors/ovl_Demo_Kekkai/z_demo_kekkai.c | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c index dab59262c..6d0b51db2 100644 --- a/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c +++ b/soh/src/overlays/actors/ovl_Demo_Kekkai/z_demo_kekkai.c @@ -271,27 +271,10 @@ void DemoKekkai_TrialBarrierDispel(Actor* thisx, GlobalContext* globalCtx) { DemoKekkai* this = (DemoKekkai*)thisx; if (gSaveContext.n64ddFlag) { - switch (thisx->params) { - case KEKKAI_WATER: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_WATER_TRIAL); - break; - case KEKKAI_LIGHT: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_LIGHT_TRIAL); - break; - case KEKKAI_FIRE: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_FIRE_TRIAL); - break; - case KEKKAI_SHADOW: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_SHADOW_TRIAL); - break; - case KEKKAI_SPIRIT: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_SPIRIT_TRIAL); - break; - case KEKKAI_FOREST: - Flags_SetRandomizerInf(RAND_INF_TRIALS_DONE_FOREST_TRIAL); - break; - } - Flags_SetEventChkInf(eventFlags[thisx->params]); + Flags_SetRandomizerInf(trialParamToRandInf(thisx->params)); + // May or may not be needed. Not sure if needed for anything + // that randoInf isn't already covering. Leaving it for safety. + Flags_SetEventChkInf(eventFlags[thisx->params]); } if (globalCtx->csCtx.frames == csFrames[this->actor.params]) { From 9c43f7225b97aa38b14cdfdfdc146f4135980f19 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sat, 27 Aug 2022 18:45:21 -0400 Subject: [PATCH 30/30] Adds captilization to French spoilerfile strings. --- soh/soh/Enhancements/randomizer/3drando/trial.cpp | 12 ++++++------ soh/soh/Enhancements/randomizer/randomizer.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/trial.cpp b/soh/soh/Enhancements/randomizer/3drando/trial.cpp index 1659673c9..e9ee31317 100644 --- a/soh/soh/Enhancements/randomizer/3drando/trial.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/trial.cpp @@ -7,12 +7,12 @@ TrialInfo::TrialInfo(Text name_) TrialInfo::~TrialInfo() = default; - TrialInfo ForestTrial = TrialInfo(Text{"the Forest Trial", /*french*/"l'épreuve de la forêt", /*spanish*/"la prueba del bosque"}); - TrialInfo FireTrial = TrialInfo(Text{"the Fire Trial", /*french*/"l'épreuve du feu", /*spanish*/"la prueba del fuego"}); - TrialInfo WaterTrial = TrialInfo(Text{"the Water Trial", /*french*/"l'épreuve de l'eau", /*spanish*/"la prueba del agua"}); - TrialInfo SpiritTrial = TrialInfo(Text{"the Spirit Trial", /*french*/"l'épreuve de l'esprit", /*spanish*/"la prueba del espíritu"}); - TrialInfo ShadowTrial = TrialInfo(Text{"the Shadow Trial", /*french*/"l'épreuve de l'ombre", /*spanish*/"la prueba de las sombras"}); - TrialInfo LightTrial = TrialInfo(Text{"the Light Trial", /*french*/"l'épreuve de la lumière", /*spanish*/"la prueba de la luz"}); + TrialInfo ForestTrial = TrialInfo(Text{"the Forest Trial", /*french*/"l'épreuve de la Forêt", /*spanish*/"la prueba del bosque"}); + TrialInfo FireTrial = TrialInfo(Text{"the Fire Trial", /*french*/"l'épreuve du Feu", /*spanish*/"la prueba del fuego"}); + TrialInfo WaterTrial = TrialInfo(Text{"the Water Trial", /*french*/"l'épreuve de l'Eau", /*spanish*/"la prueba del agua"}); + TrialInfo SpiritTrial = TrialInfo(Text{"the Spirit Trial", /*french*/"l'épreuve de l'Esprit", /*spanish*/"la prueba del espíritu"}); + TrialInfo ShadowTrial = TrialInfo(Text{"the Shadow Trial", /*french*/"l'épreuve de l'Ombre", /*spanish*/"la prueba de las sombras"}); + TrialInfo LightTrial = TrialInfo(Text{"the Light Trial", /*french*/"l'épreuve de la Lumière", /*spanish*/"la prueba de la luz"}); const TrialArray trialList = { &ForestTrial, diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index a433f0b3c..8f4ef7d3b 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -109,17 +109,17 @@ Randomizer::~Randomizer() { std::unordered_map spoilerFileTrialToEnum = { { "the Forest Trial", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, - { "l'épreuve de la forêt", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, + { "l'épreuve de la Forêt", RAND_INF_TRIALS_DONE_FOREST_TRIAL }, { "the Fire Trial", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, - { "l'épreuve du feu", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, + { "l'épreuve du Feu", RAND_INF_TRIALS_DONE_FIRE_TRIAL }, { "the Water Trial", RAND_INF_TRIALS_DONE_WATER_TRIAL }, - { "l'épreuve de l'eau", RAND_INF_TRIALS_DONE_WATER_TRIAL }, + { "l'épreuve de l'Eau", RAND_INF_TRIALS_DONE_WATER_TRIAL }, { "the Spirit Trial", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, - { "l'épreuve de l'esprit", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, + { "l'épreuve de l'Esprit", RAND_INF_TRIALS_DONE_SPIRIT_TRIAL }, { "the Shadow Trial", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, - { "l'épreuve de l'ombre", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, + { "l'épreuve de l'Ombre", RAND_INF_TRIALS_DONE_SHADOW_TRIAL }, { "the Light Trial", RAND_INF_TRIALS_DONE_LIGHT_TRIAL }, - { "l'épreuve de la lumière", RAND_INF_TRIALS_DONE_LIGHT_TRIAL } + { "l'épreuve de la Lumière", RAND_INF_TRIALS_DONE_LIGHT_TRIAL } }; std::unordered_map getItemIdToItemId = {