Rando: Shuffle Hyrule Loach (Rando V3) (#3805)

* Shuffle Hyrule Loach

* Remove rando specific loach text override

* Remove duplicated enhancement from fishsanity

* Re-run Build

* Re-run Build

* Changed to be an option within fishsanity

* Rename cvar and fix check tracker

* Fix build

* Re-run build

* Re-re-run build

* Update z_fishing.c

* Fix AllHyruleLoaches

* Fix static data

* Fix hint spacing

* Restrict loach hint to "Shuffle only Hyrule Loach"

* Update settings.cpp

* Address review
This commit is contained in:
Pepe20129 2024-07-23 17:56:44 +02:00 committed by GitHub
parent 3bcd93428e
commit c68cecec71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 144 additions and 68 deletions

View File

@ -138,7 +138,15 @@ typedef enum {
TEXT_BEAN_SALESMAN_SOLD_OUT = 0x406B,
TEXT_BEAN_SALESMAN_WANT_TO_PLANT = 0x406C,
TEXT_FISHING_POND_START = 0x407B,
TEXT_FISHING_TALK_ABOUT_SOMETHING = 0x4088,
TEXT_FISHING_TRY_ANOTHER_LURE = 0x408D,
TEXT_FISHING_SECRETS = 0x408E,
TEXT_FISHING_GOOD_FISHERMAN = 0x408F,
TEXT_FISHING_POND_START_MET = 0x4093,
TEXT_FISHING_DIFFERENT_POND = 0x4094,
TEXT_FISHING_SCRATCHING = 0x4095,
TEXT_FISHING_CLOUDY = 0x4096,
TEXT_FISHING_TRY_ANOTHER_LURE_WITH_SINKING_LURE = 0x40AF,
TEXT_DAMPES_DIARY = 0x5003,
TEXT_GRANNYS_SHOP = 0x500C,
TEXT_ANJU_PLEASE_BRING_MY_CUCCOS_BACK = 0x5036,

View File

@ -510,6 +510,8 @@ const std::vector<FlagTable> flagTables = {
{ RAND_INF_HAS_OCARINA_C_LEFT, "RAND_INF_HAS_OCARINA_C_LEFT"},
{ RAND_INF_HAS_OCARINA_C_RIGHT, "RAND_INF_HAS_OCARINA_C_RIGHT"},
{ RAND_INF_CAUGHT_LOACH, "RAND_INF_CAUGHT_LOACH" },
{ RAND_INF_CAN_SWIM, "RAND_INF_CAN_SWIM" },
{ RAND_INF_HAS_WALLET, "RAND_INF_HAS_WALLET" },

View File

@ -2752,6 +2752,9 @@ void StaticData::HintTable_Init() {
/*french*/ "As-tu récemment ressenti une vague de #puissance magique#? Un mystérieux hibou m'a dit qu'elle provenait du #[[1]]#. Tu devrais aller y jeter un coup d'oeil, @!\x0B",
{QM_GREEN, QM_RED}, {}, TEXTBOX_TYPE_BLUE));
hintTextTable[RHT_LOACH_HINT] = HintText(CustomMessage("What?^You wanna know about the&%rHyrule Loach%w?^It's a big fish, but it's so rare that I'll give my %g[[1]]%w to anyone who catches it. Seriously!",
{QM_RED}));
hintTextTable[RHT_FISHING_POLE_HINT] = HintText(CustomMessage("^If I remember correctly, I lost it somewhere in #[[1]]#...&Let me know if you find it!",
{QM_RED}));

View File

@ -836,6 +836,12 @@ void GenerateItemPool() {
} else {
PlaceVanillaOverworldFish();
}
if (fsMode.Is(RO_FISHSANITY_HYRULE_LOACH)) {
AddItemToMainPool(RG_PURPLE_RUPEE);
} else {
ctx->PlaceItemInLocation(RC_LH_HYRULE_LOACH, RG_PURPLE_RUPEE, false, true);
}
} else {
PlaceVanillaOverworldFish();
}

View File

@ -167,42 +167,43 @@ void AreaTable_Init_HyruleField() {
// TODO: should some of these helpers be done via events instead?
areaTable[RR_LH_FISHING_HOLE] = Area("LH Fishing Hole", "LH Fishing Hole", RA_NONE, DAY_NIGHT_CYCLE, {}, {
//Locations
LOCATION(RC_LH_CHILD_FISHING, logic->CanFish && logic->IsChild),
LOCATION(RC_LH_CHILD_FISH_1, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_2, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_3, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_4, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_5, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_6, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_7, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_8, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_9, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_10, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_11, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_12, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_13, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_14, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_15, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_LOACH_1, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_LOACH_2, logic->CanGetChildFish),
LOCATION(RC_LH_ADULT_FISHING, logic->CanFish && logic->IsAdult),
LOCATION(RC_LH_ADULT_FISH_1, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_2, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_3, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_4, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_5, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_6, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_7, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_8, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_9, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_10, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_11, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_12, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_13, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_14, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_15, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_LOACH, logic->CanGetAdultFish),
LOCATION(RC_FISHING_POLE_HINT,true),
LOCATION(RC_LH_CHILD_FISHING, logic->CanFish && logic->IsChild),
LOCATION(RC_LH_CHILD_FISH_1, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_2, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_3, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_4, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_5, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_6, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_7, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_8, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_9, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_10, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_11, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_12, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_13, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_14, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_FISH_15, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_LOACH_1, logic->CanGetChildFish),
LOCATION(RC_LH_CHILD_LOACH_2, logic->CanGetChildFish),
LOCATION(RC_LH_ADULT_FISHING, logic->CanFish && logic->IsAdult),
LOCATION(RC_LH_ADULT_FISH_1, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_2, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_3, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_4, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_5, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_6, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_7, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_8, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_9, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_10, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_11, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_12, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_13, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_14, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_FISH_15, logic->CanGetAdultFish),
LOCATION(RC_LH_ADULT_LOACH, logic->CanGetAdultFish),
LOCATION(RC_LH_HYRULE_LOACH, logic->CanFish),
LOCATION(RC_FISHING_POLE_HINT, true),
}, {
//Exits
Entrance(RR_LH_FISHING_ISLAND, {[]{return true;}}),

View File

@ -157,6 +157,7 @@ std::vector<RandomizerCheck> Rando::StaticData::overworldLocations = {
// Lake Hylia
RC_LH_CHILD_FISHING,
RC_LH_ADULT_FISHING,
RC_LH_HYRULE_LOACH,
RC_LH_LAB_DIVE,
RC_LH_TRADE_FROG,
RC_LH_UNDERWATER_ITEM,
@ -643,6 +644,7 @@ void Rando::StaticData::InitLocationTable() { //
// Lake Hylia
locationTable[RC_LH_CHILD_FISHING] = Location::Base(RC_LH_CHILD_FISHING, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_LAKE_HYLIA, ACTOR_ID_MAX, SCENE_FISHING_POND, 0x00, 0x3E, "Child Fishing", RHT_LH_CHILD_FISHING, RG_PIECE_OF_HEART, {}, SpoilerCollectionCheck::RandomizerInf(RAND_INF_CHILD_FISHING), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA, true);
locationTable[RC_LH_ADULT_FISHING] = Location::Base(RC_LH_ADULT_FISHING, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_LAKE_HYLIA, ACTOR_ID_MAX, SCENE_FISHING_POND, 0x00, 0x38, "Adult Fishing", RHT_LH_ADULT_FISHING, RG_PROGRESSIVE_SCALE, {}, SpoilerCollectionCheck::RandomizerInf(RAND_INF_ADULT_FISHING), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA, true);
locationTable[RC_LH_HYRULE_LOACH] = Location::Base(RC_LH_HYRULE_LOACH, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_LAKE_HYLIA, ACTOR_ID_MAX, SCENE_FISHING_POND, 0x00, 0x00, "Hyrule Loach Reward", RHT_LH_HYRULE_LOACH, RG_PURPLE_RUPEE, {}, SpoilerCollectionCheck::RandomizerInf(RAND_INF_CAUGHT_LOACH), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA);
locationTable[RC_LH_LAB_DIVE] = Location::Base(RC_LH_LAB_DIVE, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_LAKE_HYLIA, ACTOR_ID_MAX, SCENE_LAKESIDE_LABORATORY, 0x00, 0x3E, "Lab Dive", RHT_LH_LAB_DIVE, RG_PIECE_OF_HEART, {}, SpoilerCollectionCheck::ItemGetInf(16), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA, true);
locationTable[RC_LH_TRADE_FROG] = Location::Base(RC_LH_TRADE_FROG, RCQUEST_BOTH, RCTYPE_ADULT_TRADE, RCAREA_LAKE_HYLIA, ACTOR_ID_MAX, SCENE_LAKESIDE_LABORATORY, 0x00, 0x25, "Lab Trade Eyeball Frog", RHT_LH_TRADE_FROG, RG_EYEDROPS, { Category::cAdultTrade }, SpoilerCollectionCheck::RandomizerInf(RAND_INF_ADULT_TRADES_LH_TRADE_FROG), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA, true);
locationTable[RC_LH_UNDERWATER_ITEM] = Location::Base(RC_LH_UNDERWATER_ITEM, RCQUEST_BOTH, RCTYPE_STANDARD, RCAREA_LAKE_HYLIA, ACTOR_ID_MAX, SCENE_LAKE_HYLIA, 0x00, 0x15, "Underwater Item", RHT_LH_UNDERWATER_ITEM, RG_RUTOS_LETTER, {}, SpoilerCollectionCheck::EventChkInf(0x31), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA, true);

View File

@ -279,6 +279,7 @@ void Settings::CreateOptionDescriptions() {
"Affordable prices per tier: starter = 10, adult = 105, giant = 205, tycoon = 505\n\n"
"Use this to enable wallet tier locking, but make shop items not as expensive as they could be.";
mOptionDescriptions[RSK_FISHSANITY] = "Off - Fish will not be shuffled. No changes will be made to fishing behavior.\n\n"
"Shuffle only Hyrule Loach - Allows you to earn an item by catching the hyrule loach at the fishing pond and giving it to the owner.\n\n"
"Shuffle Fishing Pond - The fishing pond's fish will be shuffled. Catching a fish in the fishing pond will grant a reward.\n\n"
"Shuffle Overworld Fish - Fish in generic grottos and Zora's Domain will be shuffled. Catching a fish in a bottle will give a reward.\n\n"
"Shuffle Both - Both overworld fish and fish in the fishing pond will be shuffled.";
@ -526,6 +527,8 @@ void Settings::CreateOptionDescriptions() {
"Reading the diary of Dampé the gravekeeper as adult will tell you the location of one of the Hookshots.";
mOptionDescriptions[RSK_GREG_HINT] =
"Talking to the chest game owner after buying a key will tell you the location of Greg the Green Rupee.";
mOptionDescriptions[RSK_LOACH_HINT] =
"Talking to the fishing pond owner and asking to talk about something will tell you what's the reward for the Hyrule Loach.";
mOptionDescriptions[RSK_SARIA_HINT] = "Talking to Saria either in person or through Saria's Song will tell you the "
"location of a progressive magic meter.";
mOptionDescriptions[RSK_FISHING_POLE_HINT] = "Talking to the fishing pond owner without the fishing pole will tell you its location.";

View File

@ -86,7 +86,7 @@ static const char* englishRupeeNames[171] = {
"Frog Coins", "Gald", "Gekz", "Gems", "Geo",
"Gil", "Glimmer", "Glitches", "Gold", "Gold Dragons",
"Goober Dollars", "Green Herbs", "Greg Siblings", "Gummybears", "Hell",
"Hylian Loaches", "Ice Traps", "ISK", "Jiggies", "KF7 Ammo",
"Hyrule Loaches", "Ice Traps", "ISK", "Jiggies", "KF7 Ammo",
"Kinstones", "Kremcoins", "Kroner", "Leaves ", "Lemmings",
"Lien", "Lira", "Lumber", "Lungmen Dollars", "Macca",
"Mana", "Mann Co. Keys", "Meat", "Meat Stacks", "Medaparts",

View File

@ -945,6 +945,7 @@ typedef enum {
RC_LH_CHILD_LOACH_1,
RC_LH_CHILD_LOACH_2,
RC_LH_ADULT_FISHING,
RC_LH_HYRULE_LOACH,
RC_LH_ADULT_FISH_1,
RC_LH_ADULT_FISH_2,
RC_LH_ADULT_FISH_3,
@ -2076,6 +2077,7 @@ typedef enum {
RH_ALTAR_CHILD,
RH_ALTAR_ADULT,
RH_SARIA_HINT,
RH_LOACH_HINT,
RH_FISHING_POLE,
RH_MINUET_WARP_LOC,
RH_BOLERO_WARP_LOC,
@ -3448,6 +3450,7 @@ typedef enum {
RHT_GREG_HINT,
RHT_SARIA_TALK_HINT,
RHT_SARIA_SONG_HINT,
RHT_LOACH_HINT,
RHT_FISHING_POLE_HINT,
// Static Entrance Hints
RHT_WARP_SONG,
@ -3625,6 +3628,7 @@ typedef enum {
RSK_SHEIK_LA_HINT,
RSK_DAMPES_DIARY_HINT,
RSK_GREG_HINT,
RSK_LOACH_HINT,
RSK_SARIA_HINT,
RSK_FROGS_HINT,
RSK_OOT_HINT,
@ -3865,9 +3869,10 @@ typedef enum {
RO_BOSS_SOULS_ON_PLUS_GANON,
} RandoOptionBossSouls;
//Fishsanity settings (off, pond only, grottos only, both)
//Fishsanity settings (off, loach only, pond only, grottos only, both)
typedef enum {
RO_FISHSANITY_OFF,
RO_FISHSANITY_HYRULE_LOACH,
RO_FISHSANITY_POND,
RO_FISHSANITY_OVERWORLD,
RO_FISHSANITY_BOTH

View File

@ -161,6 +161,8 @@ void RandomizerCheckObjects::UpdateImGuiVisibility() {
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleAdultTrade"), RO_GENERIC_NO)) &&
(location.GetRandomizerCheck() != RC_KF_KOKIRI_SWORD_CHEST ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleKokiriSword"), RO_GENERIC_NO)) &&
(location.GetRandomizerCheck() != RC_LH_HYRULE_LOACH ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("Fishsanity"), RO_GENERIC_NO) == RO_FISHSANITY_HYRULE_LOACH) &&
(location.GetRandomizerCheck() != RC_ZR_MAGIC_BEAN_SALESMAN ||
CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleBeans"), RO_GENERIC_NO)) &&
(location.GetRandomizerCheck() != RC_HC_MALON_EGG ||

View File

@ -65,6 +65,7 @@ bool showCows;
bool showAdultTrade;
bool showKokiriSword;
bool showMasterSword;
bool showHyruleLoach;
bool showWeirdEgg;
bool showGerudoCard;
bool showFrogSongRupees;
@ -1167,6 +1168,9 @@ void LoadSettings() {
showMasterSword = IS_RANDO ?
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MASTER_SWORD) == RO_GENERIC_YES
: true;
showHyruleLoach = IS_RANDO ?
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_FISHSANITY) == RO_FISHSANITY_HYRULE_LOACH
: false;
showWeirdEgg = IS_RANDO ?
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_WEIRD_EGG) == RO_GENERIC_YES
: true;
@ -1287,6 +1291,7 @@ bool IsCheckShuffled(RandomizerCheck rc) {
) &&
(rc != RC_KF_KOKIRI_SWORD_CHEST || showKokiriSword) &&
(rc != RC_TOT_MASTER_SWORD || showMasterSword) &&
(rc != RC_LH_HYRULE_LOACH || showHyruleLoach) &&
(rc != RC_ZR_MAGIC_BEAN_SALESMAN || showBeans) &&
(rc != RC_HC_MALON_EGG || showWeirdEgg) &&
(loc->GetRCType() != RCTYPE_FROG_SONG || showFrogSongRupees) &&

View File

@ -202,6 +202,8 @@ typedef enum {
RAND_INF_HAS_OCARINA_C_LEFT,
RAND_INF_HAS_OCARINA_C_RIGHT,
RAND_INF_CAUGHT_LOACH,
RAND_INF_CAN_SWIM,
RAND_INF_HAS_WALLET,

View File

@ -122,7 +122,7 @@ void Settings::CreateOptions() {
mOptions[RSK_SHUFFLE_BOSS_SOULS] = Option::U8("Shuffle Boss Souls", {"Off", "On", "On + Ganon"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleBossSouls"), mOptionDescriptions[RSK_SHUFFLE_BOSS_SOULS], WidgetType::Combobox);
mOptions[RSK_SHUFFLE_DEKU_STICK_BAG] = Option::Bool("Shuffle Deku Stick Bag", CVAR_RANDOMIZER_SETTING("ShuffleDekuStickBag"), mOptionDescriptions[RSK_SHUFFLE_DEKU_STICK_BAG], IMFLAG_SEPARATOR_BOTTOM, WidgetType::Checkbox, RO_GENERIC_OFF);
mOptions[RSK_SHUFFLE_DEKU_NUT_BAG] = Option::Bool("Shuffle Deku Nut Bag", CVAR_RANDOMIZER_SETTING("ShuffleDekuNutBag"), mOptionDescriptions[RSK_SHUFFLE_DEKU_NUT_BAG], IMFLAG_SEPARATOR_BOTTOM, WidgetType::Checkbox, RO_GENERIC_OFF);
mOptions[RSK_FISHSANITY] = Option::U8("Fishsanity", {"Off", "Shuffle Fishing Pond", "Shuffle Overworld Fish", "Shuffle Both"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Fishsanity"), mOptionDescriptions[RSK_FISHSANITY], WidgetType::Combobox, RO_FISHSANITY_OFF);
mOptions[RSK_FISHSANITY] = Option::U8("Fishsanity", {"Off", "Shuffle only Hyrule Loach", "Shuffle Fishing Pond", "Shuffle Overworld Fish", "Shuffle Both"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("Fishsanity"), mOptionDescriptions[RSK_FISHSANITY], WidgetType::Combobox, RO_FISHSANITY_OFF);
mOptions[RSK_FISHSANITY_POND_COUNT] = Option::U8("Pond Fish Count", {NumOpts(0,17,1)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("FishsanityPondCount"), mOptionDescriptions[RSK_FISHSANITY_POND_COUNT], WidgetType::Slider, 0, true, IMFLAG_NONE);
mOptions[RSK_FISHSANITY_AGE_SPLIT] = Option::Bool("Pond Age Split", CVAR_RANDOMIZER_SETTING("FishsanityAgeSplit"), mOptionDescriptions[RSK_FISHSANITY_AGE_SPLIT]);
mOptions[RSK_SHUFFLE_MAPANDCOMPASS] = Option::U8("Maps/Compasses", {"Start With", "Vanilla", "Own Dungeon", "Any Dungeon", "Overworld", "Anywhere"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingMapsCompasses"), mOptionDescriptions[RSK_SHUFFLE_MAPANDCOMPASS], WidgetType::Combobox, RO_DUNGEON_ITEM_LOC_OWN_DUNGEON);
@ -163,6 +163,7 @@ void Settings::CreateOptions() {
mOptions[RSK_SHEIK_LA_HINT] = Option::Bool("Sheik Light Arrow Hint", {"Off", "On"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SheikLAHint"), mOptionDescriptions[RSK_SHEIK_LA_HINT], WidgetType::Checkbox, RO_GENERIC_ON, false, IMFLAG_NONE);
mOptions[RSK_DAMPES_DIARY_HINT] = Option::Bool("Dampe's Diary Hint", CVAR_RANDOMIZER_SETTING("DampeHint"), mOptionDescriptions[RSK_DAMPES_DIARY_HINT], IMFLAG_NONE);
mOptions[RSK_GREG_HINT] = Option::Bool("Greg the Green Rupee Hint", CVAR_RANDOMIZER_SETTING("GregHint"), mOptionDescriptions[RSK_GREG_HINT], IMFLAG_NONE);
mOptions[RSK_LOACH_HINT] = Option::Bool("Hyrule Loach Hint", CVAR_RANDOMIZER_SETTING("LoachHint"), mOptionDescriptions[RSK_LOACH_HINT], IMFLAG_NONE);
mOptions[RSK_SARIA_HINT] = Option::Bool("Saria's Hint", CVAR_RANDOMIZER_SETTING("SariaHint"), mOptionDescriptions[RSK_SARIA_HINT], IMFLAG_NONE);
mOptions[RSK_FISHING_POLE_HINT] = Option::Bool("Fishing Pole Hint", CVAR_RANDOMIZER_SETTING("FishingPoleHint"), mOptionDescriptions[RSK_FISHING_POLE_HINT], IMFLAG_NONE);
mOptions[RSK_FROGS_HINT] = Option::Bool("Frog Ocarina Game Hint", CVAR_RANDOMIZER_SETTING("FrogsHint"), mOptionDescriptions[RSK_FROGS_HINT], IMFLAG_NONE);
@ -738,6 +739,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHEIK_LA_HINT],
&mOptions[RSK_DAMPES_DIARY_HINT],
&mOptions[RSK_GREG_HINT],
&mOptions[RSK_LOACH_HINT],
&mOptions[RSK_SARIA_HINT],
&mOptions[RSK_FROGS_HINT],
&mOptions[RSK_OOT_HINT],
@ -974,6 +976,7 @@ void Settings::CreateOptions() {
&mOptions[RSK_SHEIK_LA_HINT],
&mOptions[RSK_DAMPES_DIARY_HINT],
&mOptions[RSK_GREG_HINT],
&mOptions[RSK_LOACH_HINT],
&mOptions[RSK_SARIA_HINT],
&mOptions[RSK_FROGS_HINT],
&mOptions[RSK_OOT_HINT],
@ -1198,6 +1201,7 @@ void Settings::CreateOptions() {
{ "Miscellaneous Settings:Sheik Light Arrow Hint", RSK_SHEIK_LA_HINT },
{ "Miscellaneous Settings:Dampe's Diary Hint", RSK_DAMPES_DIARY_HINT },
{ "Miscellaneous Settings:Greg the Rupee Hint", RSK_GREG_HINT },
{ "Miscellaneous Settings:Hyrule Loach Hint", RSK_LOACH_HINT },
{ "Miscellaneous Settings:Saria's Hint", RSK_SARIA_HINT },
{ "Miscellaneous Settings:Frog Ocarina Game Hint", RSK_FROGS_HINT },
{ "Miscellaneous Settings:Ocarina of Time Hint", RSK_OOT_HINT },
@ -1763,16 +1767,22 @@ void Settings::UpdateOptionProperties() {
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("ShuffleCows"), RO_GENERIC_OFF)) {
mOptions[RSK_MALON_HINT].Enable();
} else {
} else {
mOptions[RSK_MALON_HINT].Disable("Malon's hint points to a cow, so requires cows to be shuffled.");
}
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("Shuffle100GSReward"), RO_GENERIC_OFF)) {
mOptions[RSK_KAK_100_SKULLS_HINT].Enable();
} else {
} else {
mOptions[RSK_KAK_100_SKULLS_HINT].Disable("There is no point to hinting 100 skulls if it is not shuffled");
}
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("Fishsanity"), RO_FISHSANITY_OFF) == RO_FISHSANITY_HYRULE_LOACH) {
mOptions[RSK_LOACH_HINT].Enable();
} else {
mOptions[RSK_LOACH_HINT].Disable("Loach hint is only avaliable with \"Fishsanity\" set to \"Shuffle only Hyrule Loach\"\nas that's the only setting where you present the loach to the fishing pond owner");
}
if (CVarGetInteger(CVAR_RANDOMIZER_SETTING("CuccosToReturn"), 7) == 0) {
mOptions[RSK_CHICKENS_HINT].Disable("Anju will just give you the item instead with 0 chickens");
} else {
@ -2125,6 +2135,10 @@ void Settings::FinalizeSettings(const std::set<RandomizerCheck>& excludedLocatio
mOptions[RSK_KAK_100_SKULLS_HINT].SetSelectedIndex(RO_GENERIC_OFF);
}
if (mOptions[RSK_FISHSANITY].IsNot(RO_FISHSANITY_HYRULE_LOACH)) {
mOptions[RSK_LOACH_HINT].SetSelectedIndex(RO_FISHSANITY_OFF);
}
if (mOptions[RSK_CUCCO_COUNT].Is(0)) {
mOptions[RSK_CHICKENS_HINT].SetSelectedIndex(RO_GENERIC_OFF);
}
@ -2375,6 +2389,7 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) {
case RSK_SHEIK_LA_HINT:
case RSK_DAMPES_DIARY_HINT:
case RSK_GREG_HINT:
case RSK_LOACH_HINT:
case RSK_SARIA_HINT:
case RSK_FROGS_HINT:
case RSK_OOT_HINT:

View File

@ -71,6 +71,7 @@ std::unordered_map<uint32_t, CustomMessage> StaticData::hintNames = {
{RH_ALTAR_CHILD, CustomMessage("ToT Altar as Child")},
{RH_ALTAR_ADULT, CustomMessage("ToT Altar as Adult")},
{RH_SARIA_HINT, CustomMessage("Saria's Magic Hint")},
{RH_LOACH_HINT, CustomMessage("Loach Hint")},
{RH_FISHING_POLE, CustomMessage("Fishing Pole Hint")},
{RH_MINUET_WARP_LOC, CustomMessage("Minuet of Forest Destination")},
{RH_BOLERO_WARP_LOC, CustomMessage("Bolero of Fire Destination")},
@ -199,6 +200,7 @@ std::unordered_map<RandomizerHint, StaticHintInfo> StaticData::staticHintInfoMap
{RH_DAMPES_DIARY, StaticHintInfo(HINT_TYPE_AREA, {RHT_DAMPE_DIARY}, RSK_DAMPES_DIARY_HINT, true, {}, {RG_PROGRESSIVE_HOOKSHOT}, {RC_DAMPE_HINT})},
{RH_GREG_RUPEE, StaticHintInfo(HINT_TYPE_AREA, {RHT_GREG_HINT}, RSK_GREG_HINT, true, {}, {RG_GREG_RUPEE}, {RC_GREG_HINT})},
{RH_SARIA_HINT, StaticHintInfo(HINT_TYPE_AREA, {RHT_SARIA_TALK_HINT, RHT_SARIA_SONG_HINT}, RSK_SARIA_HINT, true, {}, {RG_PROGRESSIVE_MAGIC_METER}, {RC_SARIA_SONG_HINT, RC_SONG_FROM_SARIA}, true)},
{RH_LOACH_HINT, StaticHintInfo(HINT_TYPE_ITEM, {RHT_LOACH_HINT}, RSK_LOACH_HINT, true, {RC_LH_HYRULE_LOACH})},
{RH_FISHING_POLE, StaticHintInfo(HINT_TYPE_AREA, {RHT_FISHING_POLE_HINT}, RSK_FISHING_POLE_HINT, true, {}, {RG_FISHING_POLE}, {RC_FISHING_POLE_HINT}, true)},
{RH_MEDIGORON, StaticHintInfo(HINT_TYPE_MERCHANT, {RHT_MEDIGORON_HINT}, RSK_SHUFFLE_MERCHANTS, (uint8_t)RO_SHUFFLE_MERCHANTS_ON_HINT, {RC_GC_MEDIGORON})},
{RH_GRANNY, StaticHintInfo(HINT_TYPE_MERCHANT, {RHT_GRANNY_HINT}, RSK_SHUFFLE_MERCHANTS, (uint8_t)RO_SHUFFLE_MERCHANTS_ON_HINT, {RC_KAK_GRANNYS_SHOP})},

View File

@ -2707,7 +2707,21 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
else if (textId == TEXT_FROGS_UNDERWATER && ctx->GetOption(RSK_FROGS_HINT)) {
messageEntry = ctx->GetHint(RH_FROGS_HINT)->GetHintMessage(MF_AUTO_FORMAT), TEXTBOX_TYPE_BLUE;
}
else if ((textId == TEXT_FISHING_POND_START || textId == TEXT_FISHING_POND_START_MET) &&
else if (
Randomizer_GetSettingValue(RSK_LOACH_HINT) &&
(
textId == TEXT_FISHING_CLOUDY ||
textId == TEXT_FISHING_TRY_ANOTHER_LURE ||
textId == TEXT_FISHING_SECRETS ||
textId == TEXT_FISHING_GOOD_FISHERMAN ||
textId == TEXT_FISHING_DIFFERENT_POND ||
textId == TEXT_FISHING_SCRATCHING ||
textId == TEXT_FISHING_TRY_ANOTHER_LURE_WITH_SINKING_LURE
)
) {
messageEntry = ctx->GetHint(RH_LOACH_HINT)->GetHintMessage(MF_AUTO_FORMAT);
}
else if ((textId == TEXT_FISHING_POND_START || textId == TEXT_FISHING_POND_START_MET) &&
ctx->GetOption(RSK_SHUFFLE_FISHING_POLE) && !Flags_GetRandomizerInf(RAND_INF_FISHING_POLE_FOUND)) {
messageEntry = OTRGlobals::Instance->gRandomizer->GetFishingPondOwnerMessage(textId);
}

View File

@ -924,7 +924,6 @@ void DrawEnhancementsMenu() {
}
UIWidgets::Spacer(0);
if (ImGui::BeginMenu("Fishing")) {
UIWidgets::EnhancementCheckbox("Customize Behavior", CVAR_ENHANCEMENT("CustomizeFishing"));
UIWidgets::Tooltip("Turn on/off changes to the fishing behavior");
@ -944,6 +943,8 @@ void DrawEnhancementsMenu() {
UIWidgets::Tooltip("The minimum weight for the unique fishing reward as a child");
UIWidgets::PaddedEnhancementSliderInt("Adult Minimum Weight: %d", "##aMinimumWeight", CVAR_ENHANCEMENT("MinimumFishWeightAdult"), 6, 13, "", 13, true, true, false, disabled, disabledTooltip);
UIWidgets::Tooltip("The minimum weight for the unique fishing reward as an adult");
UIWidgets::PaddedEnhancementCheckbox("All fish are Hyrule Loaches", CVAR_ENHANCEMENT("AllHyruleLoaches"), true, false, disabled, disabledTooltip);
UIWidgets::Tooltip("Every fish in the fishing pond will always be a Hyrule Loach");
ImGui::EndMenu();
}
UIWidgets::Spacer(0);

View File

@ -17,6 +17,7 @@
#define WATER_SURFACE_Y(play) play->colCtx.colHeader->waterBoxes->ySurface
#define IS_FISHSANITY (IS_RANDO && Randomizer_GetPondFishShuffled())
#define FISHID(params) (Randomizer_IdentifyFish(play->sceneNum, params))
bool getShouldSpawnLoaches();
void Fishing_Init(Actor* thisx, PlayState* play);
void Fishing_Destroy(Actor* thisx, PlayState* play);
@ -26,8 +27,6 @@ void Fishing_DrawFish(Actor* thisx, PlayState* play);
void Fishing_DrawOwner(Actor* thisx, PlayState* play);
void Fishing_Reset(void);
bool getShouldSpawnLoaches();
typedef struct {
/* 0x00 */ u8 isLoach;
/* 0x02 */ Vec3s pos;
@ -436,6 +435,10 @@ static Vec3f sStreamSoundProjectedPos;
static s16 sFishOnHandParams;
static Color_RGBA16 fsPulseColor = { 30, 240, 200 };
u8 AllHyruleLoaches() {
return CVarGetInteger(CVAR_ENHANCEMENT("CustomizeFishing"), 0) && CVarGetInteger(CVAR_ENHANCEMENT("AllHyruleLoaches"), 0);
}
void Fishing_SetColliderElement(s32 index, ColliderJntSph* collider, Vec3f* pos, f32 scale) {
collider->elements[index].dim.worldSphere.center.x = pos->x;
collider->elements[index].dim.worldSphere.center.y = pos->y;
@ -1001,7 +1004,7 @@ void Fishing_Init(Actor* thisx, PlayState* play2) {
sFishInits[i].pos.z, 0, Rand_ZeroFloat(0x10000), 0, 100 + i, true);
}
} else {
if ((thisx->params < (EN_FISH_PARAM + 15)) || (thisx->params == EN_FISH_AQUARIUM)) {
if ((thisx->params < (EN_FISH_PARAM + 15) && !AllHyruleLoaches()) || (thisx->params == EN_FISH_AQUARIUM)) {
SkelAnime_InitFlex(play, &this->skelAnime, &gFishingFishSkel, &gFishingFishAnim, NULL, NULL, 0);
Animation_MorphToLoop(&this->skelAnime, &gFishingFishAnim, 0.0f);
} else {
@ -2847,7 +2850,7 @@ void Fishing_FishLeapSfx(Fishing* this, u8 outOfWater) {
s16 sfxId;
u8 length;
if (this->isLoach == 0) {
if (this->isLoach == 0 && !AllHyruleLoaches()) {
length = this->fishLength;
} else {
length = 2.0f * this->fishLength;
@ -2992,7 +2995,7 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
this->actor.uncullZoneForward = 700.0f;
this->actor.uncullZoneScale = 50.0f;
if (this->isLoach == 0) {
if (this->isLoach == 0 && !AllHyruleLoaches()) {
playerSpeedMod = (player->actor.speedXZ * 0.15f) + 0.25f;
} else {
playerSpeedMod = (player->actor.speedXZ * 0.3f) + 0.25f;
@ -3054,7 +3057,7 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
Math_ApproachS(&this->fishLimbDRotZDelta, 0, 5, 0x1F4);
if (this->isLoach == 0) {
if (this->isLoach == 0 && !AllHyruleLoaches()) {
Actor_SetScale(&this->actor, this->fishLength * 15.0f * 0.00001f);
this->fishLimbRotPhase += this->fishLimbRotPhaseStep;
@ -3223,7 +3226,7 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
break;
case 1:
if (this->isLoach == 1) {
if (this->isLoach == 1 || AllHyruleLoaches()) {
this->fishState = -1;
this->unk_1A4 = 20000;
this->unk_1A2 = 20000;
@ -3376,7 +3379,7 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
if (sLureEquipped == FS_LURE_SINKING) {
this->fishTargetPos.y = sLurePos.y;
} else if (this->isLoach == 0) {
} else if (this->isLoach == 0 && !AllHyruleLoaches()) {
this->fishTargetPos.y = sLurePos.y - 15.0f;
} else {
this->fishTargetPos.y = sLurePos.y - 5.0f;
@ -3451,8 +3454,8 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
}
if (getGuaranteeBite() == 1 ||
((this->timerArray[0] == 1) || (Rand_ZeroOne() < chance)) &&
((Rand_ZeroOne() < (this->perception * multiplier)) || ((this->isLoach + 1) == KREG(69)))) {
if (this->isLoach == 0) {
((Rand_ZeroOne() < (this->perception * multiplier)) || (((this->isLoach || AllHyruleLoaches()) + 1) == KREG(69)))) {
if (this->isLoach == 0 && !AllHyruleLoaches()) {
this->fishState = 3;
this->unk_190 = 1.2f;
this->unk_194 = 5000.0f;
@ -3673,7 +3676,7 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_ENEMY | 0x800);
sFishingMusicDelay = 0;
if (this->isLoach == 1) {
if (this->isLoach == 1 || AllHyruleLoaches()) {
rumbleStrength = (this->fishLength * 3.0f) + 120.0f;
} else {
rumbleStrength = (2.0f * this->fishLength) + 120.0f;
@ -3776,7 +3779,7 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
Math_ApproachF(&this->actor.speedXZ, 5.0f, 1.0f, 0.5f);
}
if (this->isLoach == 0) {
if (this->isLoach == 0 && !AllHyruleLoaches()) {
sRodReelingSpeed = 1.0f - (this->fishLength * 0.00899f);
} else {
sRodReelingSpeed = 1.0f - (this->fishLength * 0.00899f * 1.4f);
@ -3792,7 +3795,7 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
this->unk_190 = 1.0f;
this->unk_194 = 4500.0f;
if (this->isLoach == 0) {
if (this->isLoach == 0 && !AllHyruleLoaches()) {
sRodReelingSpeed = 1.3f - (this->fishLength * 0.00899f);
} else {
sRodReelingSpeed = 1.3f - (this->fishLength * 0.00899f * 1.4f);
@ -3946,7 +3949,7 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_HEART_GET | 0x900);
sFishingCaughtTextDelay = 40;
if (this->isLoach == 0) {
if (this->isLoach == 0 && !AllHyruleLoaches()) {
sFishLengthToWeigh = this->fishLength;
if (sFishLengthToWeigh >= 75) {
@ -3993,13 +3996,13 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
if (play->msgCtx.choiceIndex == 0) {
if (sFishOnHandLength == 0.0f) {
sFishOnHandLength = this->fishLength;
sFishOnHandIsLoach = this->isLoach;
sFishOnHandIsLoach = (this->isLoach || AllHyruleLoaches());
sLureCaughtWith = sLureEquipped;
if (IS_FISHSANITY) {
sFishOnHandParams = this->fishsanityParams;
}
Actor_Kill(&this->actor);
} else if (getShouldConfirmKeep() && (this->isLoach == 0) && (sFishOnHandIsLoach == 0) &&
} else if (getShouldConfirmKeep() && (this->isLoach == 0 && !AllHyruleLoaches()) && (sFishOnHandIsLoach == 0) &&
((s16)this->fishLength < (s16)sFishOnHandLength)) {
this->keepState = 1;
this->timerArray[0] = 0x3C;
@ -4061,7 +4064,7 @@ void Fishing_UpdateFish(Actor* thisx, PlayState* play2) {
this->unk_194 = 2000.0f;
SkelAnime_Free(&this->skelAnime, play);
if (this->isLoach == 0) {
if (this->isLoach == 0 && !AllHyruleLoaches()) {
SkelAnime_InitFlex(play, &this->skelAnime, &gFishingFishSkel, &gFishingFishAnim, 0, 0, 0);
Animation_MorphToLoop(&this->skelAnime, &gFishingFishAnim, 0.0f);
} else {
@ -4397,7 +4400,7 @@ void Fishing_DrawFish(Actor* thisx, PlayState* play) {
Matrix_RotateZ(((this->unk_164 + this->actor.shape.rot.z) / 32768.0f) * M_PI, MTXMODE_APPLY);
Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
if (this->isLoach == 0) {
if (this->isLoach == 0 && !AllHyruleLoaches()) {
Matrix_RotateY((this->fishLimb23RotYDelta * (M_PI / 32768)) - (M_PI / 2), MTXMODE_APPLY);
Matrix_Translate(0.0f, 0.0f, this->fishLimb23RotYDelta * 10.0f * 0.01f, MTXMODE_APPLY);
@ -4998,7 +5001,7 @@ void Fishing_HandleOwnerDialog(Fishing* this, PlayState* play) {
if (sFishOnHandLength == 0.0f) {
this->actor.textId = 0x408C;
this->stateAndTimer = 20;
} else if (sFishOnHandIsLoach == 0 && !IS_RANDO) {
} else if (sFishOnHandIsLoach == 0) {
sFishLengthToWeigh = sFishOnHandLength;
if ((s16)sFishingRecordLength < (s16)sFishOnHandLength) {
if (sLureCaughtWith == FS_LURE_SINKING) {
@ -5011,14 +5014,10 @@ void Fishing_HandleOwnerDialog(Fishing* this, PlayState* play) {
this->actor.textId = 0x408B;
this->stateAndTimer = 20;
}
} else if (!IS_RANDO) {
} else {
this->actor.textId = 0x409B;
this->stateAndTimer = 11;
}
else {
this->actor.textId = 0x4086;
this->stateAndTimer = 11;
}
Message_ContinueTextbox(play, this->actor.textId);
break;
case 1:
@ -5154,7 +5153,13 @@ void Fishing_HandleOwnerDialog(Fishing* this, PlayState* play) {
}
}
} else {
getItemId = GI_RUPEE_PURPLE;
if (IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_CAUGHT_LOACH)) {
Flags_SetRandomizerInf(RAND_INF_CAUGHT_LOACH);
getItemEntry = Randomizer_GetItemFromKnownCheck(RC_LH_HYRULE_LOACH, GI_RUPEE_PURPLE);
getItemId = getItemEntry.getItemId;
} else {
getItemId = GI_RUPEE_PURPLE;
}
sFishOnHandLength = 0.0f; // doesn't record loach
}