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 eb1dde10ab..b0650bfa0f 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 cb36db76fc..0edda9c9df 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 55144d2372..a54f522aa9 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 47afc1244a..37312b84bb 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 4c27646f24..af71727d42 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 e7a6f045ea..a816276560 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 fe0fc36403..c54911a096 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 e4d6a4ab29..001984ee70 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 803c261f40..c20667c47d 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 51841ffcdc..646d994564 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 59f173b179..0e8a3e3b5f 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 6c0fe4bbec..970d7a3478 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 8e85cb165c..a64d62d40c 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 3f6f0a079a..a0b3ae3782 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 b72c3cb47b..8cccdbbf81 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 123b83edbb..95db75e555 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 f053e3674c..b2d9c78668 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 4f75118cdf..a86dc82c47 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 ad8f95a7b7..c61f933bfd 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 faf8dca0bd..fc892bcbb3 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 e6f8250562..f3f5b1c101 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 e9bbf9ef89..0ac3d6ead1 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;