From 22b9284240292f30a1a1ebaaa414006ff5f68e12 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Mon, 15 Jan 2024 16:20:57 +0100 Subject: [PATCH] Rando: Shuffle Swim (Rando V3) (#3795) * Shuffle Swim * Fix build --- .../Enhancements/debugger/debugSaveEditor.h | 2 + soh/soh/Enhancements/mods.cpp | 74 +++++++++++++++++++ .../randomizer/3drando/item_pool.cpp | 4 + .../locacc_bottom_of_the_well.cpp | 2 +- .../location_access/locacc_deku_tree.cpp | 29 +++++--- .../location_access/locacc_gerudo_valley.cpp | 4 +- .../locacc_jabujabus_belly.cpp | 8 +- .../location_access/locacc_water_temple.cpp | 4 +- .../location_access/locacc_zoras_domain.cpp | 2 +- soh/soh/Enhancements/randomizer/draw.cpp | 35 +++++++++ soh/soh/Enhancements/randomizer/draw.h | 1 + soh/soh/Enhancements/randomizer/item.cpp | 4 + soh/soh/Enhancements/randomizer/item_list.cpp | 3 + soh/soh/Enhancements/randomizer/logic.cpp | 11 ++- soh/soh/Enhancements/randomizer/logic.h | 1 + .../randomizer/option_descriptions.cpp | 7 ++ .../Enhancements/randomizer/randomizer.cpp | 12 ++- .../Enhancements/randomizer/randomizerTypes.h | 7 +- .../Enhancements/randomizer/randomizer_inf.h | 2 + soh/soh/Enhancements/randomizer/savefile.cpp | 4 + soh/soh/Enhancements/randomizer/settings.cpp | 7 ++ soh/src/code/z_parameter.c | 5 ++ 22 files changed, 199 insertions(+), 29 deletions(-) diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.h b/soh/soh/Enhancements/debugger/debugSaveEditor.h index eb1dde10a..b0650bfa0 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.h +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.h @@ -523,6 +523,8 @@ const std::vector 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_CAN_SWIM, "RAND_INF_CAN_SWIM" }, + { RAND_INF_HAS_WALLET, "RAND_INF_HAS_WALLET" }, { RAND_INF_BEEHIVE_KF_STORMS_GROTTO_LEFT, "RAND_INF_BEEHIVE_KF_STORMS_GROTTO_LEFT" }, diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index cb36db76f..0edda9c9d 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -1284,6 +1284,79 @@ void RegisterToTMedallions() { }); } +//from z_player.c +typedef struct { + /* 0x00 */ Vec3f pos; + /* 0x0C */ s16 yaw; +} SpecialRespawnInfo; // size = 0x10 + +//special respawns used when voided out without swim to prevent infinite loops +std::map swimSpecialRespawnInfo = { + { + 0x1D9,//hf to zr in water + { { -1455.443, -20, 1384.826 }, 28761 } + }, + { + 0x311,//zr to hf in water + { { 5830.209, -92.16, 3925.911 }, -20025 } + }, + { + 0x4DA,//zr to lw + { { 1978.718, -36.908, -855 }, -16384 } + }, + { + 0x1DD,//lw to zr + { { 4082.366, 860.442, -1018.949 }, -32768 } + }, + { + 0x219,//gv to lh + { { -3276.416, -1033, 2908.421 }, 11228 } + }, + { + 0x10,//lh to water temple + { { -182, 780, 759.5 }, -32768 } + }, + { + 0x21D,//water temple to lh + { { -955.028, -1306.9, 6768.954 }, -32768 } + }, + { + 0x328,//lh to zd + { { -109.86, 11.396, -9.933 }, -29131 } + }, + { + 0x560,//zd to lh + { { -912, -1326.967, 3391 }, 0 } + } +}; + +void RegisterNoSwim() { + GameInteractor::Instance->RegisterGameHook([]() { + if ( + IS_RANDO && + (GET_PLAYER(gPlayState)->stateFlags1 & PLAYER_STATE1_IN_WATER) && + !Flags_GetRandomizerInf(RAND_INF_CAN_SWIM) && + CUR_EQUIP_VALUE(EQUIP_TYPE_BOOTS) != EQUIP_VALUE_BOOTS_IRON + ) { + //if you void out in water temple without swim you get instantly kicked out to prevent softlocks + if (gPlayState->sceneNum == SCENE_WATER_TEMPLE) { + GameInteractor::RawAction::TeleportPlayer(Entrance_OverrideNextIndex(ENTR_LAKE_HYLIA_2));//lake hylia from water temple + return; + } + + if (swimSpecialRespawnInfo.find(gSaveContext.entranceIndex) != swimSpecialRespawnInfo.end()) { + SpecialRespawnInfo* respawnInfo = &swimSpecialRespawnInfo.at(gSaveContext.entranceIndex); + + Play_SetupRespawnPoint(gPlayState, RESPAWN_MODE_DOWN, 0xDFF); + gSaveContext.respawn[RESPAWN_MODE_DOWN].pos = respawnInfo->pos; + gSaveContext.respawn[RESPAWN_MODE_DOWN].yaw = respawnInfo->yaw; + } + + Play_TriggerVoidOut(gPlayState); + } + }); +} + void RegisterNoWallet() { GameInteractor::Instance->RegisterGameHook([]() { if (IS_RANDO && !Flags_GetRandomizerInf(RAND_INF_HAS_WALLET)) { @@ -1475,6 +1548,7 @@ void InitMods() { RegisterBossSouls(); RegisterRandomizedEnemySizes(); RegisterToTMedallions(); + RegisterNoSwim(); RegisterNoWallet(); RegisterFishsanity(); NameTag_RegisterHooks(); diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index 55144d237..a54f522aa 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -782,6 +782,10 @@ void GenerateItemPool() { ctx->possibleIceTrapModels.push_back(RG_OCARINA_C_RIGHT_BUTTON); } + if (ctx->GetOption(RSK_SHUFFLE_SWIM)) { + AddItemToMainPool(RG_PROGRESSIVE_SCALE); + } + if (ctx->GetOption(RSK_SHUFFLE_BEEHIVES)) { //32 total beehive locations AddItemToMainPool(RG_RED_RUPEE, 23); diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp index 47afc1244..37312b84b 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp @@ -31,7 +31,7 @@ void AreaTable_Init_BottomOfTheWell() { LocationAccess(RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST, {[]{return randoCtx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}}), LocationAccess(RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, {[]{return randoCtx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}}), LocationAccess(RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, {[]{return (randoCtx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->HasExplosives;}}), - LocationAccess(RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY, {[]{return logic->Sticks || logic->CanUse(RG_DINS_FIRE);}}), + LocationAccess(RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY, {[]{return (logic->Swim || logic->CanUse(RG_ZELDAS_LULLABY)) && logic->Sticks || logic->CanUse(RG_DINS_FIRE);}}), LocationAccess(RC_BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, {[]{return logic->CanUse(RG_ZELDAS_LULLABY) && (logic->KokiriSword || (logic->Sticks && randoCtx->GetTrickOption(RT_BOTW_CHILD_DEADHAND)));}}), LocationAccess(RC_BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, {[]{return logic->CanUse(RG_ZELDAS_LULLABY) && (randoCtx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH));}}), LocationAccess(RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, {[]{return logic->CanUse(RG_ZELDAS_LULLABY);}}), diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp index 4c27646f2..af71727d4 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp @@ -86,14 +86,20 @@ void AreaTable_Init_DekuTree() { areaTable[RR_DEKU_TREE_BASEMENT_SCRUB_ROOM] = Area("Deku Tree Basement Scrub Room", "Deku Tree", RA_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits - Entrance(RR_DEKU_TREE_BASEMENT_LOWER, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM, {[]{return Here(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, []{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW);});}}), + Entrance(RR_DEKU_TREE_BASEMENT_LOWER, {[]{return true;}}), + Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT, {[]{return Here(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, []{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW);});}}), }); - areaTable[RR_DEKU_TREE_BASEMENT_WATER_ROOM] = Area("Deku Tree Basement Water Room", "Deku Tree", RA_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + areaTable[RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT] = Area("Deku Tree Basement Water Room Front", "Deku Tree", RA_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits - Entrance(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, {[]{return true;}}), + Entrance(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, {[]{return true;}}), + Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_BACK, {[]{return logic->Swim || randoCtx->GetTrickOption(RT_DEKU_B1_BACKFLIP_OVER_SPIKED_LOG);}}), + }); + + areaTable[RR_DEKU_TREE_BASEMENT_WATER_ROOM_BACK] = Area("Deku Tree Basement Water Room Back", "Deku Tree", RA_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT, {[]{return logic->Swim || randoCtx->GetTrickOption(RT_DEKU_B1_BACKFLIP_OVER_SPIKED_LOG);}}), + Entrance(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, {[]{return true;}}), }); areaTable[RR_DEKU_TREE_BASEMENT_TORCH_ROOM] = Area("Deku Tree Basement Torch Room", "Deku Tree", RA_DEKU_TREE, NO_DAY_NIGHT_CYCLE, { @@ -102,8 +108,8 @@ void AreaTable_Init_DekuTree() { EventAccess(&logic->DekuBabaNuts, {[]{return logic->DekuBabaNuts || (logic->CanJumpslash || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives || logic->CanUse(RG_DINS_FIRE));}}), }, {}, { //Exits - Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return Here(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, []{return logic->HasFireSourceWithTorch || logic->CanUse(RG_FAIRY_BOW);});}}), + Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_BACK, {[]{return true;}}), + Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return Here(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, []{return logic->HasFireSourceWithTorch || logic->CanUse(RG_FAIRY_BOW);});}}), }); areaTable[RR_DEKU_TREE_BASEMENT_BACK_LOBBY] = Area("Deku Tree Basement Back Lobby", "Deku Tree", RA_DEKU_TREE, NO_DAY_NIGHT_CYCLE, { @@ -141,7 +147,7 @@ void AreaTable_Init_DekuTree() { areaTable[RR_DEKU_TREE_OUTSIDE_BOSS_ROOM] = Area("Deku Tree Outside Boss Room", "Deku Tree", RA_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits Entrance(RR_DEKU_TREE_BASEMENT_UPPER, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, {[]{return Here(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return logic->HasShield;});}}), + Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, {[]{return (logic->Swim || Here(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return logic->CanUse(RG_IRON_BOOTS);})) && Here(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return logic->HasShield;});}}), }); } @@ -192,7 +198,7 @@ void AreaTable_Init_DekuTree() { Entrance(RR_DEKU_TREE_MQ_LOBBY, {[]{return true;}}), }); - areaTable[RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK] = Area("Deku Tree MQ Basement Water Room Front", "Deku Tree", RA_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + areaTable[RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK] = Area("Deku Tree MQ Basement Water Room Back", "Deku Tree", RA_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { //Locations LocationAccess(RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, {[]{return logic->CanUse(RG_SONG_OF_TIME);}}), }, { @@ -229,9 +235,8 @@ void AreaTable_Init_DekuTree() { Area("Deku Tree MQ Outside Boss Room", "Deku Tree", RA_DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { // Exits - Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, { [] { return true; } }), - Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, - { [] { return Here(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, [] { return logic->HasShield; }); } }), + Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{ return true; }}), + Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, {[]{return (logic->Swim || Here(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, []{return logic->CanUse(RG_IRON_BOOTS);})) && Here(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, [] { return logic->HasShield; }); } }), }); } diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp index e7a6f045e..a81627656 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp @@ -25,7 +25,7 @@ void AreaTable_Init_GerudoValley() { EventAccess(&logic->BeanPlantFairy, {[]{return logic->BeanPlantFairy || (CanPlantBean(RR_GV_UPPER_STREAM) && logic->CanUse(RG_SONG_OF_STORMS));}}), }, { //Locations - LocationAccess(RC_GV_WATERFALL_FREESTANDING_POH, {[]{return true;}}), + LocationAccess(RC_GV_WATERFALL_FREESTANDING_POH, {[]{return logic->IsChild || logic->Swim;}}),//can use cucco as child LocationAccess(RC_GV_GS_BEAN_PATCH, {[]{return logic->CanPlantBugs && logic->CanChildAttack;}}), LocationAccess(RC_GV_COW, {[]{return logic->IsChild && logic->CanUse(RG_EPONAS_SONG);}}), LocationAccess(RC_GV_GOSSIP_STONE, {[]{return true;}}), @@ -36,7 +36,7 @@ void AreaTable_Init_GerudoValley() { areaTable[RR_GV_LOWER_STREAM] = Area("GV Lower Stream", "Gerudo Valley", RA_GERUDO_VALLEY, DAY_NIGHT_CYCLE, {}, {}, { //Exits - Entrance(RR_LAKE_HYLIA, {[]{return true;}}), + Entrance(RR_LAKE_HYLIA, {[]{return logic->IsChild || logic->Swim;}}),//can use cucco as child }); areaTable[RR_GV_GROTTO_LEDGE] = Area("GV Grotto Ledge", "Gerudo Valley", RA_GERUDO_VALLEY, DAY_NIGHT_CYCLE, {}, {}, { diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp index fe0fc3640..c54911a09 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp @@ -60,8 +60,8 @@ void AreaTable_Init_JabuJabusBelly() { LocationAccess(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, {[]{return true;}}), }, { //Exits - Entrance(RR_JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_LIFT_LOWER, {[]{return logic->CanUseProjectile;}}), + Entrance(RR_JABU_JABUS_BELLY_MAIN_LOWER, {[]{return logic->Swim;}}), + Entrance(RR_JABU_JABUS_BELLY_LIFT_LOWER, {[]{return logic->Swim && logic->CanUseProjectile;}}), }); areaTable[RR_JABU_JABUS_BELLY_LOWER_SIDE_ROOM] = Area("Jabu Jabus Belly Lower Side Room", "Jabu Jabus Belly", RA_JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { @@ -74,7 +74,7 @@ void AreaTable_Init_JabuJabusBelly() { areaTable[RR_JABU_JABUS_BELLY_LIFT_LOWER] = Area("Jabu Jabus Belly Lift Lower", "Jabu Jabus Belly", RA_JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { //Locations - LocationAccess(RC_JABU_JABUS_BELLY_DEKU_SCRUB, {[]{return (logic->IsChild || logic->CanDive || randoCtx->GetTrickOption(RT_JABU_ALCOVE_JUMP_DIVE) || logic->CanUse(RG_IRON_BOOTS)) && logic->CanStunDeku;}}), + LocationAccess(RC_JABU_JABUS_BELLY_DEKU_SCRUB, {[]{return logic->Swim && (logic->IsChild || logic->CanDive || randoCtx->GetTrickOption(RT_JABU_ALCOVE_JUMP_DIVE) || logic->CanUse(RG_IRON_BOOTS)) && logic->CanStunDeku;}}), }, { //Exits Entrance(RR_JABU_JABUS_BELLY_SHABOMB_CORRIDOR, {[]{return true;}}), @@ -193,7 +193,7 @@ void AreaTable_Init_JabuJabusBelly() { areaTable[RR_JABU_JABUS_BELLY_MQ_DEPTHS] = Area("Jabu Jabus Belly MQ Depths", "Jabu Jabus Belly", RA_JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { //Locations LocationAccess(RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, {[]{return true;}}), - LocationAccess(RC_JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, {[]{return logic->Sticks || logic->CanUse(RG_DINS_FIRE);}}), + LocationAccess(RC_JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, {[]{return logic->Swim && (logic->Sticks || logic->CanUse(RG_DINS_FIRE));}}), LocationAccess(RC_JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, {[]{return (randoCtx->GetTrickOption(RT_LENS_JABU_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) || Here(RR_JABU_JABUS_BELLY_MQ_MAIN, []{return logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_HOOKSHOT);});}}), }, { //Exits diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp index e4d6a4ab2..001984ee7 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp @@ -10,8 +10,8 @@ void AreaTable_Init_WaterTemple() { ---------------------------*/ areaTable[RR_WATER_TEMPLE_ENTRYWAY] = Area("Water Temple Entryway", "Water Temple", RA_WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return randoCtx->GetDungeon(WATER_TEMPLE)->IsVanilla();}}), - Entrance(RR_WATER_TEMPLE_MQ_LOBBY, {[]{return randoCtx->GetDungeon(WATER_TEMPLE)->IsMQ();}}), + Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return logic->Swim && randoCtx->GetDungeon(WATER_TEMPLE)->IsVanilla();}}), + Entrance(RR_WATER_TEMPLE_MQ_LOBBY, {[]{return logic->Swim && randoCtx->GetDungeon(WATER_TEMPLE)->IsMQ();}}), Entrance(RR_LAKE_HYLIA, {[]{return true;}}), }); diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp index 803c261f4..c20667c47 100644 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp @@ -93,7 +93,7 @@ void AreaTable_Init_ZorasDomain() { EventAccess(&logic->DeliverLetter, {[]{return logic->DeliverLetter || (logic->RutosLetter && logic->IsChild && randoCtx->GetOption(RSK_ZORAS_FOUNTAIN).IsNot(RO_ZF_OPEN));}}), }, { //Locations - LocationAccess(RC_ZD_DIVING_MINIGAME, {[]{return logic->ChildsWallet && logic->IsChild;}}), + LocationAccess(RC_ZD_DIVING_MINIGAME, {[]{return logic->Swim && logic->ChildsWallet && logic->IsChild;}}), LocationAccess(RC_ZD_CHEST, {[]{return logic->IsChild && logic->CanUse(RG_STICKS);}}), LocationAccess(RC_ZD_KING_ZORA_THAWED, {[]{return logic->KingZoraThawed;}}), LocationAccess(RC_ZD_TRADE_PRESCRIPTION, {[]{return logic->KingZoraThawed && logic->Prescription;}}), diff --git a/soh/soh/Enhancements/randomizer/draw.cpp b/soh/soh/Enhancements/randomizer/draw.cpp index 51841ffcd..646d99456 100644 --- a/soh/soh/Enhancements/randomizer/draw.cpp +++ b/soh/soh/Enhancements/randomizer/draw.cpp @@ -10,6 +10,7 @@ #include "objects/object_gi_key/object_gi_key.h" #include "objects/object_gi_bosskey/object_gi_bosskey.h" #include "objects/object_gi_hearts/object_gi_hearts.h" +#include "objects/object_gi_scale/object_gi_scale.h" #include "objects/object_gi_fire/object_gi_fire.h" #include "objects/object_fish/object_fish.h" #include "objects/object_toki_objects/object_toki_objects.h" @@ -393,6 +394,40 @@ extern "C" void Randomizer_DrawOcarinaButton(PlayState* play, GetItemEntry* getI CLOSE_DISPS(play->state.gfxCtx); } +static Gfx gGiBronzeScaleWaterColorDL[] = { + gsDPPipeSync(), + gsDPSetPrimColor(0, 0x60, 255, 255, 255, 255), + gsDPSetEnvColor(255, 123, 0, 255), + gsSPEndDisplayList(), +}; + +static Gfx gGiBronzeScaleColorDL[] = { + gsDPPipeSync(), + gsDPSetPrimColor(0, 0x80, 255, 255, 255, 255), + gsDPSetEnvColor(91, 51, 18, 255), + gsSPEndDisplayList(), +}; + +extern "C" void Randomizer_DrawBronzeScale(PlayState* play, GetItemEntry* getItemEntry) { + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL_25Xlu(play->state.gfxCtx); + + gSPSegment(POLY_XLU_DISP++, 0x08, + (uintptr_t)Gfx_TwoTexScroll(play->state.gfxCtx, 0, 1 * (play->state.frames * 2), + -1 * (play->state.frames * 2), 64, 64, 1, 1 * (play->state.frames * 4), + 1 * -(play->state.frames * 4), 32, 32)); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__), G_MTX_MODELVIEW | G_MTX_LOAD); + + gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gGiBronzeScaleColorDL); + gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gGiScaleDL); + gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gGiBronzeScaleWaterColorDL); + gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gGiScaleWaterDL); + + CLOSE_DISPS(play->state.gfxCtx); +} + extern "C" void Randomizer_DrawFishingPoleGI(PlayState* play, GetItemEntry* getItemEntry) { Vec3f pos; OPEN_DISPS(play->state.gfxCtx); diff --git a/soh/soh/Enhancements/randomizer/draw.h b/soh/soh/Enhancements/randomizer/draw.h index 59f173b17..0e8a3e3b5 100644 --- a/soh/soh/Enhancements/randomizer/draw.h +++ b/soh/soh/Enhancements/randomizer/draw.h @@ -18,6 +18,7 @@ void Randomizer_DrawMasterSword(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawTriforcePiece(PlayState* play, GetItemEntry getItemEntry); void Randomizer_DrawTriforcePieceGI(PlayState* play, GetItemEntry getItemEntry); void Randomizer_DrawOcarinaButton(PlayState* play, GetItemEntry* getItemEntry); +void Randomizer_DrawBronzeScale(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawFishingPoleGI(PlayState* play, GetItemEntry* getItemEntry); #ifdef __cplusplus }; diff --git a/soh/soh/Enhancements/randomizer/item.cpp b/soh/soh/Enhancements/randomizer/item.cpp index 6c0fe4bbe..970d7a347 100644 --- a/soh/soh/Enhancements/randomizer/item.cpp +++ b/soh/soh/Enhancements/randomizer/item.cpp @@ -259,6 +259,10 @@ std::shared_ptr Item::GetGIEntry() const { // NOLINT(*-no-recursio } break; case RG_PROGRESSIVE_SCALE: + if (!Flags_GetRandomizerInf(RAND_INF_CAN_SWIM)) { + actual = RG_BRONZE_SCALE; + break; + } switch (CUR_UPG_VALUE(UPG_SCALE)) { case 0: actual = RG_SILVER_SCALE; diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp index 8e85cb165..a64d62d40 100644 --- a/soh/soh/Enhancements/randomizer/item_list.cpp +++ b/soh/soh/Enhancements/randomizer/item_list.cpp @@ -275,6 +275,9 @@ void Rando::StaticData::InitItemTable() { itemTable[RG_OCARINA_C_RIGHT_BUTTON] = Item(RG_OCARINA_C_RIGHT_BUTTON, Text{ "Ocarina C Right Button", "Touche C-Droit de l'Ocarina", "Botón C derecho de Ocarina" }, ITEMTYPE_ITEM, GI_MAP, true, &logic->OcarinaCRightButton, RHT_OCARINA_C_RIGHT_BUTTON, RG_OCARINA_C_RIGHT_BUTTON, OBJECT_GI_MAP, GID_STONE_OF_AGONY, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); itemTable[RG_OCARINA_C_RIGHT_BUTTON].SetCustomDrawFunc(Randomizer_DrawOcarinaButton); + itemTable[RG_BRONZE_SCALE] = Item(RG_BRONZE_SCALE, Text{ "Bronze Scale", "!!!", "!!!" }, ITEMTYPE_ITEM, GI_SCALE_SILVER, true, &logic->ProgressiveWallet, RHT_BRONZE_SCALE, RG_BRONZE_SCALE, OBJECT_GI_SCALE, GID_SCALE_SILVER, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_BRONZE_SCALE].SetCustomDrawFunc(Randomizer_DrawBronzeScale); + itemTable[RG_TRIFORCE] = Item(RG_TRIFORCE, Text{ "Triforce", "Triforce", "Triforce" }, ITEMTYPE_EVENT, RG_TRIFORCE, false, &logic->noVariable, RHT_NONE); itemTable[RG_HINT] = Item(RG_HINT, Text{ "Hint", "Indice", "Hinweis" }, ITEMTYPE_EVENT, RG_HINT, false, &logic->noVariable, RHT_NONE); // Individual stages of progressive items (only here for GetItemEntry purposes, not for use in seed gen) diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index 3f6f0a079..a0b3ae378 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -255,8 +255,9 @@ namespace Rando { GoronBracelet = ProgressiveStrength >= 1; SilverGauntlets = ProgressiveStrength >= 2; GoldenGauntlets = ProgressiveStrength >= 3; - SilverScale = ProgressiveScale >= 1; - GoldScale = ProgressiveScale >= 2; + Swim = ProgressiveScale >= 1; + SilverScale = ProgressiveScale >= 2; + GoldScale = ProgressiveScale >= 3; ChildsWallet = ProgressiveWallet >= 1; AdultsWallet = ProgressiveWallet >= 2; BiggoronSword = BiggoronSword || ProgressiveGiantKnife >= 2; @@ -313,7 +314,7 @@ namespace Rando { CanAdultDamage = IsAdult && (CanUse(RG_FAIRY_BOW) || CanUse(RG_STICKS) || CanUse(RG_KOKIRI_SWORD) || HasExplosives || CanUse(RG_DINS_FIRE) || MasterSword || Hammer || BiggoronSword); CanStunDeku = CanAdultAttack || CanChildAttack || Nuts || HasShield; CanCutShrubs = CanUse(RG_KOKIRI_SWORD) || CanUse(RG_BOOMERANG) || HasExplosives || CanUse(RG_MASTER_SWORD) || CanUse(RG_MEGATON_HAMMER) || CanUse(RG_BIGGORON_SWORD); - CanDive = ProgressiveScale >= 1; + CanDive = ProgressiveScale >= 2; CanLeaveForest = ctx->GetOption(RSK_FOREST).IsNot(RO_FOREST_CLOSED) || IsAdult || DekuTreeClear || ctx->GetOption(RSK_SHUFFLE_INTERIOR_ENTRANCES) || ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES); CanPlantBugs = IsChild && Bugs; CanRideEpona = IsAdult && Epona && CanUse(RG_EPONAS_SONG); @@ -608,7 +609,8 @@ namespace Rando { ProgressiveBulletBag = 0; ProgressiveBombBag = 0; ProgressiveMagic = 0; - ProgressiveScale = 0; + //If we're not shuffling swim, we start with it (scale 1) + ProgressiveScale = ctx->GetOption(RSK_SHUFFLE_SWIM).Is(true) ? 0 : 1; ProgressiveHookshot = 0; ProgressiveBow = 0; //If we're not shuffling child's wallet, we start with it (wallet 1) @@ -711,6 +713,7 @@ namespace Rando { GoronBracelet = false; SilverGauntlets = false; GoldenGauntlets = false; + Swim = false; SilverScale = false; GoldScale = false; ChildsWallet = false; diff --git a/soh/soh/Enhancements/randomizer/logic.h b/soh/soh/Enhancements/randomizer/logic.h index b72c3cb47..8cccdbbf8 100644 --- a/soh/soh/Enhancements/randomizer/logic.h +++ b/soh/soh/Enhancements/randomizer/logic.h @@ -237,6 +237,7 @@ class Logic { bool GoronBracelet = false; bool SilverGauntlets = false; bool GoldenGauntlets = false; + bool Swim = false; bool SilverScale = false; bool GoldScale = false; bool ChildsWallet = false; diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index 123b83edb..95db75e55 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -223,6 +223,13 @@ void Settings::CreateOptionDescriptions() { "Enabling this shuffles the Ocarina buttons into the item pool.\n" "\n" "This will require finding the buttons before being able to use them in songs."; + + mOptionDescriptions[RSK_SHUFFLE_SWIM] = + "Shuffles the ability to Swim into the item pool.\n" + "The ability to swim has to be found as an item (you can still be underwater if you use iron boots).\n" + "\n" + "If you enter a water entrance without swim you will be respawned on land to prevent infinite death loops.\n" + "If you void out in Water Temple you will immediately be kicked out to prevent a softlock."; mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG] = "Shuffles the Weird Egg from Malon in to the item pool. Enabling " "\"Skip Child Zelda\" disables this feature.\n" "\n" diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index f053e3674..b2d9c7866 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -1210,6 +1210,9 @@ GetItemID Randomizer::GetItemIdFromRandomizerGet(RandomizerGet randoGet, GetItem return tycoonWallet ? (GetItemID)RG_TYCOON_WALLET : GI_WALLET_GIANT; } case RG_PROGRESSIVE_SCALE: + if (!Flags_GetRandomizerInf(RAND_INF_CAN_SWIM)) { + return (GetItemID)RG_BRONZE_SCALE; + } switch (CUR_UPG_VALUE(UPG_SCALE)) { case 0: return GI_SCALE_SILVER; @@ -1324,7 +1327,6 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_PROGRESSIVE_BOMB_BAG: case RG_PROGRESSIVE_BOW: case RG_PROGRESSIVE_SLINGSHOT: - case RG_PROGRESSIVE_SCALE: case RG_PROGRESSIVE_NUT_UPGRADE: case RG_PROGRESSIVE_STICK_UPGRADE: case RG_PROGRESSIVE_OCARINA: @@ -1391,6 +1393,11 @@ bool Randomizer::IsItemVanilla(RandomizerGet randoGet) { case RG_BUY_RED_POTION_40: case RG_BUY_RED_POTION_50: return true; + case RG_PROGRESSIVE_SCALE: + if (!Flags_GetRandomizerInf(RAND_INF_CAN_SWIM)) { + return false; + } + return true; case RG_PROGRESSIVE_WALLET: if (!Flags_GetRandomizerInf(RAND_INF_HAS_WALLET)) { return false; @@ -3239,7 +3246,7 @@ CustomMessage Randomizer::GetGoronMessage(u16 index) { void Randomizer::CreateCustomMessages() { // RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED // with GIMESSAGE(getItemID, itemID, english, german, french). - const std::array getItemMessages = {{ + const std::array getItemMessages = {{ GIMESSAGE(RG_GREG_RUPEE, ITEM_MASK_GORON, "You found %gGreg%w!", "%gGreg%w! Du hast ihn wirklich gefunden!", @@ -3509,6 +3516,7 @@ void Randomizer::CreateCustomMessages() { "You got the %y\xa6%r button for the&Ocarina%w! You can now use it&while playing songs!", "Der %y\xa6%r Knopf%w!&Du kannst ihn nun zum Spielen&von Liedern auf der %rOkarina%w&verwenden!", "Vous trouvez la %rtouche %y\xa6%r de&l'Ocarina%w! Vous pouvez&maintenant l'utiliser lorsque&vous en jouez!"), + GIMESSAGE_UNTRANSLATED(RG_BRONZE_SCALE, ITEM_SCALE_SILVER, "You got the %rBronze Scale%w!&The power of buoyancy is yours!"), GIMESSAGE_UNTRANSLATED(RG_FISHING_POLE, ITEM_FISHING_POLE, "You found a lost %rFishing Pole%w!&Time to hit the pond!"), }}; CreateGetItemMessages(&getItemMessages); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 4f75118cd..a86dc82c4 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -333,7 +333,8 @@ typedef enum { RR_DEKU_TREE_COMPASS_ROOM, RR_DEKU_TREE_BASEMENT_LOWER, RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, - RR_DEKU_TREE_BASEMENT_WATER_ROOM, + RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT, + RR_DEKU_TREE_BASEMENT_WATER_ROOM_BACK, RR_DEKU_TREE_BASEMENT_TORCH_ROOM, RR_DEKU_TREE_BASEMENT_BACK_LOBBY, RR_DEKU_TREE_BASEMENT_BACK_ROOM, @@ -1552,6 +1553,7 @@ typedef enum { RT_DEKU_BASEMENT_GS, RT_DEKU_B1_SKIP, RT_DEKU_B1_BOW_WEBS, + RT_DEKU_B1_BACKFLIP_OVER_SPIKED_LOG, RT_DEKU_MQ_COMPASS_GS, RT_DEKU_MQ_LOG, RT_DC_SCARECROW_GS, @@ -1959,6 +1961,7 @@ typedef enum { RG_FISHING_POLE, RG_HINT, RG_TYCOON_WALLET, + RG_BRONZE_SCALE, RG_CHILD_WALLET, RG_FAIRY_OCARINA, RG_OCARINA_OF_TIME, @@ -3202,6 +3205,7 @@ typedef enum { RHT_OCARINA_C_DOWN_BUTTON, RHT_OCARINA_C_LEFT_BUTTON, RHT_OCARINA_C_RIGHT_BUTTON, + RHT_BRONZE_SCALE, RHT_FISHING_POLE, RHT_EPONA, // Entrances @@ -3514,6 +3518,7 @@ typedef enum { RSK_STARTING_OCARINA, RSK_SHUFFLE_OCARINA, RSK_SHUFFLE_OCARINA_BUTTONS, + RSK_SHUFFLE_SWIM, RSK_STARTING_DEKU_SHIELD, RSK_STARTING_KOKIRI_SWORD, RSK_STARTING_MASTER_SWORD, diff --git a/soh/soh/Enhancements/randomizer/randomizer_inf.h b/soh/soh/Enhancements/randomizer/randomizer_inf.h index ad8f95a7b..c61f933bf 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_inf.h +++ b/soh/soh/Enhancements/randomizer/randomizer_inf.h @@ -212,6 +212,8 @@ typedef enum { RAND_INF_HAS_OCARINA_C_LEFT, RAND_INF_HAS_OCARINA_C_RIGHT, + RAND_INF_CAN_SWIM, + RAND_INF_HAS_WALLET, RAND_INF_BEEHIVE_KF_STORMS_GROTTO_LEFT, diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index faf8dca0b..fc892bcbb 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -301,6 +301,10 @@ extern "C" void Randomizer_InitSaveFile() { Flags_SetRandomizerInf(RAND_INF_HAS_OCARINA_C_DOWN); } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_SWIM) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_CAN_SWIM); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_CHILD_WALLET) == RO_GENERIC_OFF) { Flags_SetRandomizerInf(RAND_INF_HAS_WALLET); } diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index e6f825056..f3f5b1c10 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -108,6 +108,7 @@ void Settings::CreateOptions() { mOptions[RSK_SHUFFLE_CHILD_WALLET] = Option::Bool("Shuffle Child's Wallet", "gRandomizeShuffleChildWallet", mOptionDescriptions[RSK_SHUFFLE_CHILD_WALLET]); mOptions[RSK_SHUFFLE_OCARINA] = Option::Bool("Shuffle Ocarinas", "gRandomizeShuffleOcarinas", mOptionDescriptions[RSK_SHUFFLE_OCARINA]); mOptions[RSK_SHUFFLE_OCARINA_BUTTONS] = Option::Bool("Shuffle Ocarina Buttons", "gRandomizeShuffleOcarinaButtons", mOptionDescriptions[RSK_SHUFFLE_OCARINA_BUTTONS]); + mOptions[RSK_SHUFFLE_SWIM] = Option::Bool("Shuffle Swim", "gRandomizeShuffleSwim", mOptionDescriptions[RSK_SHUFFLE_SWIM]); mOptions[RSK_SHUFFLE_WEIRD_EGG] = Option::Bool("Shuffle Weird Egg", "gRandomizeShuffleWeirdEgg", mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG]); mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD] = Option::Bool("Shuffle Gerudo Membership Card", "gRandomizeShuffleGerudoToken", mOptionDescriptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD]); mOptions[RSK_SHUFFLE_FISHING_POLE] = Option::Bool("Shuffle Fishing Pole", "gRandomizeShuffleFishingPole", mOptionDescriptions[RSK_SHUFFLE_FISHING_POLE]); @@ -287,6 +288,7 @@ void Settings::CreateOptions() { mTrickOptions[RT_DEKU_BASEMENT_GS] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DEKU_TREE, {Tricks::Tag::NOVICE}, false, "Deku Tree Basement Vines GS with Jump Slash", "Can be defeated by doing a precise jump slash."); mTrickOptions[RT_DEKU_B1_SKIP] = TrickOption::LogicTrick(RCQUEST_BOTH, RA_DEKU_TREE, {Tricks::Tag::INTERMEDIATE}, false, "Deku Tree Basement without Slingshot", "A precise jump can be used to skip needing to use the Slingshot to go around B1 of the Deku Tree. If used with the \"Closed Forest\" setting, a Slingshot will not be guaranteed to exist somewhere inside the Forest. This trick applies to both Vanilla and Master Quest."); mTrickOptions[RT_DEKU_B1_BOW_WEBS] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DEKU_TREE, {Tricks::Tag::NOVICE}, false, "Deku Tree Basement Web to Gohma with Bow", "All spider web walls in the Deku Tree basement can be burnt as adult with just a bow by shooting through torches. This trick only applies to the circular web leading to Gohma; the two vertical webs are always in logic. Backflip onto the chest near the torch at the bottom of the vine wall. With precise positioning you can shoot through the torch to the right edge of the circular web. This allows completion of adult Deku Tree with no fire source."); + mTrickOptions[RT_DEKU_B1_BACKFLIP_OVER_SPIKED_LOG] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DEKU_TREE, {Tricks::Tag::NOVICE}, false, "Deku Tree Basement Backflip over Spiked Log", "Allows backflipping over the spiked log in the deku tree basement in vanilla. Only relevant if \"Shuffle Swim\" is enabled."); mTrickOptions[RT_DEKU_MQ_COMPASS_GS] = TrickOption::LogicTrick(RCQUEST_MQ, RA_DEKU_TREE, {Tricks::Tag::NOVICE}, false, "Deku Tree MQ Compass Room GS Boulders with Just Hammer", "Climb to the top of the vines, then let go and jump slash immediately to destroy the boulders using the Hammer, without needing to spawn a Song of Time block."); mTrickOptions[RT_DEKU_MQ_LOG] = TrickOption::LogicTrick(RCQUEST_MQ, RA_DEKU_TREE, {Tricks::Tag::NOVICE}, false, "Deku Tree MQ Roll Under the Spiked Log", "You can get past the spiked log by rolling to briefly shrink your hitbox. As adult, the timing is a bit more precise."); mTrickOptions[RT_DC_SCARECROW_GS] = TrickOption::LogicTrick(RCQUEST_VANILLA, RA_DODONGOS_CAVERN, {Tricks::Tag::NOVICE}, false, "Dodongo\'s Cavern Scarecrow GS with Armos Statue", "You can jump off an Armos Statue to reach the alcove with the Gold Skulltula. It takes quite a long time to pull the statue the entire way. The jump to the alcove can be a bit picky when done as child."); @@ -466,6 +468,7 @@ void Settings::CreateOptions() { &mTrickOptions[RT_DEKU_BASEMENT_GS], &mTrickOptions[RT_DEKU_B1_SKIP], &mTrickOptions[RT_DEKU_B1_BOW_WEBS], + &mTrickOptions[RT_DEKU_B1_BACKFLIP_OVER_SPIKED_LOG], &mTrickOptions[RT_DEKU_MQ_COMPASS_GS], &mTrickOptions[RT_DEKU_MQ_LOG], &mTrickOptions[RT_DC_SCARECROW_GS], @@ -653,6 +656,7 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_CHILD_WALLET], &mOptions[RSK_SHUFFLE_OCARINA], &mOptions[RSK_SHUFFLE_OCARINA_BUTTONS], + &mOptions[RSK_SHUFFLE_SWIM], &mOptions[RSK_SHUFFLE_WEIRD_EGG], &mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD], &mOptions[RSK_SHUFFLE_FISHING_POLE], @@ -869,6 +873,7 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_KOKIRI_SWORD], &mOptions[RSK_SHUFFLE_OCARINA], &mOptions[RSK_SHUFFLE_OCARINA_BUTTONS], + &mOptions[RSK_SHUFFLE_SWIM], &mOptions[RSK_SHUFFLE_WEIRD_EGG], &mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD], &mOptions[RSK_SHUFFLE_MAGIC_BEANS], @@ -1091,6 +1096,7 @@ void Settings::CreateOptions() { { "Shuffle Settings:Tokensanity", RSK_SHUFFLE_TOKENS }, { "Shuffle Settings:Shuffle Ocarinas", RSK_SHUFFLE_OCARINA }, { "Shuffle Settings:Shuffle Ocarina Buttons", RSK_SHUFFLE_OCARINA_BUTTONS }, + { "Shuffle Settings:Shuffle Swim", RSK_SHUFFLE_SWIM }, { "Shuffle Settings:Shuffle Adult Trade", RSK_SHUFFLE_ADULT_TRADE }, { "Shuffle Settings:Shuffle Magic Beans", RSK_SHUFFLE_MAGIC_BEANS }, { "Shuffle Settings:Shuffle Kokiri Sword", RSK_SHUFFLE_KOKIRI_SWORD }, @@ -2244,6 +2250,7 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) { case RSK_SHUFFLE_100_GS_REWARD: case RSK_SHUFFLE_OCARINA: case RSK_SHUFFLE_OCARINA_BUTTONS: + case RSK_SHUFFLE_SWIM: case RSK_SHUFFLE_CHILD_WALLET: case RSK_STARTING_DEKU_SHIELD: case RSK_STARTING_KOKIRI_SWORD: diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index e9bbf9ef8..0ac3d6ead 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -2684,6 +2684,11 @@ u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { return Return_Item_Entry(giEntry, RG_NONE); } + if (item == RG_BRONZE_SCALE) { + Flags_SetRandomizerInf(RAND_INF_CAN_SWIM); + return Return_Item_Entry(giEntry, RG_NONE); + } + temp = gSaveContext.inventory.items[slot]; osSyncPrintf("Item_Register(%d)=%d %d\n", slot, item, temp); INV_CONTENT(item) = item;