diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 7a260ccd6ad..22cab367710 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -342,6 +342,14 @@ typedef enum { // - None VB_CRAWL, + // #### `result` + // ```c + // true + // ``` + // #### `args` + // - None + VB_ROLL, + // #### `result` // ```c // true diff --git a/soh/soh/Enhancements/kaleido.cpp b/soh/soh/Enhancements/kaleido.cpp index e541be5a2c7..b846cbcb600 100644 --- a/soh/soh/Enhancements/kaleido.cpp +++ b/soh/soh/Enhancements/kaleido.cpp @@ -203,6 +203,11 @@ Kaleido::Kaleido() { 32, aButtonColor, FlagType::FLAG_RANDOMIZER_INF, RAND_INF_CAN_GRAB, "Grab")); } + if (ctx->GetOption(RSK_SHUFFLE_ROLL)) { + mEntries.push_back(std::make_shared(gButtonBackgroundTex, G_IM_FMT_IA, G_IM_SIZ_8b, 32, + 32, aButtonColor, FlagType::FLAG_RANDOMIZER_INF, + RAND_INF_CAN_ROLL, "Roll")); + } if (ctx->GetOption(RSK_SHUFFLE_OPEN_CHEST)) { mEntries.push_back(std::make_shared( gMapChestIconTex, G_IM_FMT_RGBA, G_IM_SIZ_16b, 8, 8, Color_RGBA8{ 255, 255, 255, 255 }, diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp index 4b347417f28..730cf881340 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp @@ -2121,6 +2121,9 @@ void StaticData::HintTable_Init_Item() { hintTextTable[RHT_CLIMB] = HintText(CustomMessage("the ability to climb", /*german*/TODO_TRANSLATE, /*french*/"la capacité de grimper")); hintTextTable[RHT_CRAWL] = HintText(CustomMessage("the ability to crawl", /*german*/TODO_TRANSLATE, /*french*/"la capacité de ramper")); hintTextTable[RHT_OPEN_CHEST] = HintText(CustomMessage("the ability to open chests", /*german*/TODO_TRANSLATE, /*french*/TODO_TRANSLATE)); + hintTextTable[RHT_ROLL] = HintText(CustomMessage("the ability to roll", /*german*/"die Fähigkeit zu rollen", /*french*/"la capacité de faire des roulades")); + + //RANDOTODO if these are ever used for anything other than name, they want abscure and ambiguous hints hintTextTable[RHT_QUIVER_INF] = HintText(CustomMessage("an infinite Quiver", /*german*/"der unendliche Köcher", /*french*/"un Carquois Infini")); diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp index cfa454be33f..e99e0e19b14 100644 --- a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -415,6 +415,10 @@ void GenerateItemPool() { AddItemToPool(RG_OPEN_CHEST, 2, 1, 1, 1); } + if (ctx->GetOption(RSK_SHUFFLE_ROLL)) { + AddItemToPool(RG_ROLL, 2, 1, 1, 1); + } + if (ctx->GetOption(RSK_SHUFFLE_BEEHIVES)) { PlaceItemsForType(RCTYPE_BEEHIVE, true, true); } diff --git a/soh/soh/Enhancements/randomizer/3drando/shops.cpp b/soh/soh/Enhancements/randomizer/3drando/shops.cpp index 10b1a6a7df4..d977702644b 100644 --- a/soh/soh/Enhancements/randomizer/3drando/shops.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/shops.cpp @@ -1005,6 +1005,10 @@ void InitTrickNames() { // TODO_TRANSLATE Text{ "Crouch" }, }; + trickNameTable[RG_ROLL] = { + // TODO_TRANSLATE + Text{ "Roll" }, + }; trickNameTable[RG_OPEN_CHEST] = { // TODO_TRANSLATE Text{ "Open Cheats" }, diff --git a/soh/soh/Enhancements/randomizer/animation_capture_tool.cpp b/soh/soh/Enhancements/randomizer/animation_capture_tool.cpp new file mode 100644 index 00000000000..a91936a7e03 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/animation_capture_tool.cpp @@ -0,0 +1,52 @@ +// I provide here the code which allowed me to have all the data for the roll animation for roll_animation_data.h +// I had temporarily put it in the Draw.cpp file and I called the function when Link performed a roll + +/* +#define NUM_FRAMES_TO_CAPTURE 10 +static Vec3s capturedRollFrames[NUM_FRAMES_TO_CAPTURE][LIMB_COUNT_LINK]; +static int captureFrameCount = 0; +static bool captureComplete = false; +static bool captureStarted = false; + +extern "C" void CaptureRollAnimation(PlayState* play) { + if (captureComplete) + return; + + Player* player = GET_PLAYER(play); + if (player == NULL || player->skelAnime.jointTable == NULL) + return; + + // Checks if the player is rolling | Vérifie si le joueur roule + bool isRolling = (player->actionFunc == Player_Action_Roll); + + if (isRolling) { + if (!captureStarted) { + captureStarted = true; + osSyncPrintf("\n========== DÉBUT CAPTURE ANIMATION ROLL ==========\n"); + } + + // Captures a frame every 2 game frames | Capture une frame toutes les 2 frames de jeu + if ((play->state.frames % 2) == 0 && captureFrameCount < NUM_FRAMES_TO_CAPTURE) { + osSyncPrintf("\n// Frame %d\n", captureFrameCount); + osSyncPrintf("{\n"); + + for (int i = 0; i < LIMB_COUNT_LINK; i++) { + Vec3s joint = player->skelAnime.jointTable[i]; + capturedRollFrames[captureFrameCount][i] = joint; + + osSyncPrintf(" { %d, %d, %d }, // Limb %d\n", joint.x, joint.y, joint.z, i); + } + + osSyncPrintf("},\n"); + + captureFrameCount++; + + if (captureFrameCount >= NUM_FRAMES_TO_CAPTURE) { + captureComplete = true; + osSyncPrintf("\n========== FIN CAPTURE - %d FRAMES CAPTURÉES ==========\n", NUM_FRAMES_TO_CAPTURE); + osSyncPrintf("Copie ces données et envoie-les moi !\n\n"); + } + } + } +} +*/ \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/draw.cpp b/soh/soh/Enhancements/randomizer/draw.cpp index cfc4a470595..ad7ddae9b78 100644 --- a/soh/soh/Enhancements/randomizer/draw.cpp +++ b/soh/soh/Enhancements/randomizer/draw.cpp @@ -37,6 +37,9 @@ extern "C" { #include "objects/object_tw/object_tw.h" #include "objects/object_ganon2/object_ganon2.h" #include "objects/object_gi_shield_1/object_gi_shield_1.h" +#include "objects/object_link_child/object_link_child.h" +#include "roll_animation_data.h" + extern PlayState* gPlayState; extern SaveContext gSaveContext; } @@ -1189,6 +1192,48 @@ extern "C" void Randomizer_DrawKneePads(PlayState* play, GetItemEntry* getItemEn CLOSE_DISPS(play->state.gfxCtx); } +extern "C" void Randomizer_DrawRollAbility(PlayState* play, GetItemEntry* getItemEntry) { + static bool initialized = false; + static SkelAnime skelAnime; + static Vec3s jointTable[ROLL_ANIMATION_LIMBS]; + static Vec3s morphTable[ROLL_ANIMATION_LIMBS]; + static u32 lastUpdate = 0; + static int currentFrame = 0; + + if (!initialized) { + initialized = true; + SkelAnime_InitFlex(play, &skelAnime, (FlexSkeletonHeader*)gLinkChildSkel, NULL, jointTable, morphTable, + ROLL_ANIMATION_LIMBS); + } + + // Manual animation with captured frames + if (lastUpdate != play->state.frames) { + lastUpdate = play->state.frames; + + // Advances one frame every 2 frames of play + if ((play->state.frames % 2) == 0) { + currentFrame = (currentFrame + 1) % ROLL_ANIMATION_FRAMES; + } + + // Copies data from current frame + for (int i = 0; i < ROLL_ANIMATION_LIMBS; i++) { + jointTable[i] = rollAnimationData[currentFrame][i]; + } + } + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL_25Opa(play->state.gfxCtx); + + Matrix_Translate(0.0f, -30.0f, 0.0f, MTXMODE_APPLY); + Matrix_RotateY(play->gameplayFrames * 0.05f, MTXMODE_APPLY); + Matrix_Scale(0.01f, 0.01f, 0.01f, MTXMODE_APPLY); + + SkelAnime_DrawFlexOpa(play, skelAnime.skeleton, jointTable, skelAnime.dListCount, NULL, NULL, NULL); + + CLOSE_DISPS(play->state.gfxCtx); +} + static Gfx* boxLidDL; static Gfx* boxBodyDL; extern "C" void EnBox_PostLimbDrawOverride(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) { diff --git a/soh/soh/Enhancements/randomizer/draw.h b/soh/soh/Enhancements/randomizer/draw.h index ce3a4564d0d..5ec3dc49f78 100644 --- a/soh/soh/Enhancements/randomizer/draw.h +++ b/soh/soh/Enhancements/randomizer/draw.h @@ -25,6 +25,7 @@ void Randomizer_DrawBronzeScale(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawPowerBracelet(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawLadder(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawKneePads(PlayState* play, GetItemEntry* getItemEntry); +void Randomizer_DrawRollAbility(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawOpenChest(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawFishingPoleGI(PlayState* play, GetItemEntry* getItemEntry); void Randomizer_DrawSkeletonKey(PlayState* play, GetItemEntry* getItemEntry); diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 5f6d7861776..7b632266c95 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -1,4 +1,4 @@ -#include +#include #include "soh/OTRGlobals.h" #include "soh/ResourceManagerHelpers.h" #include "soh/Enhancements/enhancementTypes.h" @@ -864,6 +864,9 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l case VB_CRAWL: *should = *should && Flags_GetRandomizerInf(RAND_INF_CAN_CRAWL); break; + case VB_ROLL: + *should = !RAND_GET_OPTION(RSK_SHUFFLE_ROLL) || Flags_GetRandomizerInf(RAND_INF_CAN_ROLL); + break; case VB_ALLOW_ENTRANCE_CS_FOR_EITHER_AGE: { s32 entranceIndex = va_arg(args, s32); diff --git a/soh/soh/Enhancements/randomizer/item_list.cpp b/soh/soh/Enhancements/randomizer/item_list.cpp index 7ae9956bbbb..16f3893c395 100644 --- a/soh/soh/Enhancements/randomizer/item_list.cpp +++ b/soh/soh/Enhancements/randomizer/item_list.cpp @@ -376,7 +376,9 @@ void Rando::StaticData::InitItemTable() { itemTable[RG_CRAWL].SetCustomDrawFunc(Randomizer_DrawKneePads); itemTable[RG_OPEN_CHEST] = Item(RG_OPEN_CHEST, Text{ "Open Chests", TODO_TRANSLATE, TODO_TRANSLATE }, ITEMTYPE_ITEM, GI_KEY_SMALL, true, LOGIC_NONE, RHT_OPEN_CHEST, RG_OPEN_CHEST, OBJECT_GI_KEY, GID_KEY_SMALL, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); itemTable[RG_OPEN_CHEST].SetCustomDrawFunc(Randomizer_DrawOpenChest); - + itemTable[RG_ROLL] = Item(RG_ROLL, Text{ "Roll", "Rouler", "Rolle" }, ITEMTYPE_ITEM, GI_SCALE_SILVER, true, LOGIC_NONE, RHT_ROLL, RG_ROLL, OBJECT_GI_SCALE, GID_SCALE_SILVER, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER); + itemTable[RG_ROLL].SetCustomDrawFunc(Randomizer_DrawRollAbility); + itemTable[RG_PROGRESSIVE_BOMBCHU_BAG] = Item(RG_PROGRESSIVE_BOMBCHU_BAG, Text{ "Bombchu Bag", "Sac de Missiles Teigneux", "Krabbelminentasche" }, ITEMTYPE_ITEM, RG_PROGRESSIVE_BOMBCHU_BAG, true, LOGIC_BOMBCHUS, RHT_BOMBCHU_BAG, RG_PROGRESSIVE_BOMBCHU_BAG, OBJECT_GI_BOMB_2, GID_BOMBCHU, TEXT_RANDOMIZER_CUSTOM_ITEM, 0x80, CHEST_ANIM_LONG, ITEM_CATEGORY_MAJOR, MOD_RANDOMIZER, {"a ", "eine ", "un "}); itemTable[RG_PROGRESSIVE_BOMBCHU_BAG].SetCustomDrawFunc(Randomizer_DrawBombchuBag); diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/water_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/water_temple.cpp index 4bf071024c8..e833fb2e42d 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/water_temple.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/water_temple.cpp @@ -1137,11 +1137,12 @@ void RegionTable_Init_WaterTemple() { areaTable[RR_WATER_TEMPLE_MQ_DRAGON_ROOM_TUNNEL] = Region("Water Temple MQ Dragon Room Tunnel", SCENE_WATER_TEMPLE, {}, { //Locations - LOCATION(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_1, logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_2, logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_3, logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_4, logic->CanBreakCrates()), - }, { + LOCATION(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_1, logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_2, logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_3, logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_DRAGON_ROOM_SUBMERGED_CRATE_4, logic->HasItem(RG_ROLL)), + }, + { //Exits Entrance(RR_WATER_TEMPLE_MQ_RIVER_POTS, []{return logic->CanUse(RG_LONGSHOT);}), Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_ALCOVE, []{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_HOOKSHOT);}), @@ -1225,14 +1226,12 @@ void RegionTable_Init_WaterTemple() { areaTable[RR_WATER_TEMPLE_MQ_TRIANGLE_TORCH_ROOM] = Region("Water Temple MQ Triangle Torch Room", SCENE_WATER_TEMPLE, {}, { //Locations - LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_1, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()) || - (logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_2, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()) || - (logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_3, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_4, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_5, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_6, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()), + LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_1, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_2, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_3, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_4, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_5, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_TRIPLE_TORCH_ROOM_SUBMERGED_CRATE_6, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), }, { //Exits Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return logic->Get(LOGIC_WATER_MQ_B1_SWITCH) && ((logic->WaterLevel(WL_LOW) && logic->HasItem(RG_GOLDEN_SCALE)) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 40 && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT))));}), @@ -1284,12 +1283,12 @@ void RegionTable_Init_WaterTemple() { //Locations LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_1, logic->CanBreakCrates()), LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_FRONT_CRATE_2, logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_1, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_2, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_3, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_4, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_5, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()), - LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_6, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanBreakCrates()), + LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_1, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_2, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_3, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_4, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_5, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), + LOCATION(RC_WATER_TEMPLE_MQ_WHIRLPOOL_SUBMERGED_CRATE_6, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->HasItem(RG_ROLL)), }, { //Exits Entrance(RR_WATER_TEMPLE_MQ_BEHIND_SPIKE_MOAT, []{return true;}), diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp index f35f60d1925..568167955e6 100644 --- a/soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp @@ -25,13 +25,13 @@ void RegionTable_Init_KokiriForest() { LOCATION(RC_KF_SOUTH_GRASS_EAST_RUPEE, logic->IsChild), LOCATION(RC_KF_NORTH_GRASS_WEST_RUPEE, logic->IsChild), LOCATION(RC_KF_NORTH_GRASS_EAST_RUPEE, logic->IsChild), - LOCATION(RC_KF_BEAN_RUPEE_1, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RUPEE_2, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RUPEE_3, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RUPEE_4, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RUPEE_5, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RUPEE_6, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RED_RUPEE, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RUPEE_1, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || (logic->CanUse(RG_HOVER_BOOTS) && logic->HasItem(RG_ROLL)) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RUPEE_2, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || (logic->CanUse(RG_HOVER_BOOTS) && logic->HasItem(RG_ROLL)) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RUPEE_3, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || (logic->CanUse(RG_HOVER_BOOTS) && logic->HasItem(RG_ROLL)) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RUPEE_4, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || (logic->CanUse(RG_HOVER_BOOTS) && logic->HasItem(RG_ROLL)) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RUPEE_5, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || (logic->CanUse(RG_HOVER_BOOTS) && logic->HasItem(RG_ROLL)) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RUPEE_6, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || (logic->CanUse(RG_HOVER_BOOTS) && logic->HasItem(RG_ROLL)) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RED_RUPEE, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST, RG_KOKIRI_FOREST_BEAN_SOUL) || (logic->CanUse(RG_HOVER_BOOTS) && logic->HasItem(RG_ROLL)) || logic->CanUse(RG_BOOMERANG))), LOCATION(RC_KF_SARIAS_ROOF_WEST_HEART, logic->IsChild), LOCATION(RC_KF_SARIAS_ROOF_EAST_HEART, logic->IsChild), LOCATION(RC_KF_SARIAS_ROOF_NORTH_HEART, logic->IsChild), diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp index f7b8802daeb..1af3012febb 100644 --- a/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp @@ -117,11 +117,11 @@ void RegionTable_Init_LakeHylia() { //Locations LOCATION(RC_LH_LAB_DIVE, logic->HasItem(RG_GOLDEN_SCALE) || (ctx->GetTrickOption(RT_LH_LAB_DIVING) && logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->HasItem(RG_BRONZE_SCALE))), LOCATION(RC_LH_TRADE_FROG, logic->IsAdult && logic->CanUse(RG_EYEBALL_FROG)), - LOCATION(RC_LH_GS_LAB_CRATE, logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->CanBreakCrates()), + LOCATION(RC_LH_GS_LAB_CRATE, logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->HasItem(RG_ROLL)), LOCATION(RC_LH_LAB_FRONT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)), LOCATION(RC_LH_LAB_LEFT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)), LOCATION(RC_LH_LAB_RIGHT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)), - LOCATION(RC_LH_LAB_CRATE, logic->CanUse(RG_IRON_BOOTS) && logic->CanBreakCrates()), + LOCATION(RC_LH_LAB_CRATE, logic->CanUse(RG_IRON_BOOTS) && logic->HasItem(RG_ROLL)), }, { //Exits Entrance(RR_LAKE_HYLIA, []{return true;}), diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp index c5de627221e..394bdec7de6 100644 --- a/soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp @@ -23,10 +23,10 @@ void RegionTable_Init_Market() { LOCATION(RC_MARKET_GRASS_6, logic->IsChild && (logic->CanUseSword() || logic->HasItem(RG_GORONS_BRACELET))), LOCATION(RC_MARKET_GRASS_7, logic->IsChild && (logic->CanUseSword() || logic->HasItem(RG_GORONS_BRACELET))), LOCATION(RC_MARKET_GRASS_8, logic->IsChild && (logic->CanUseSword() || logic->HasItem(RG_GORONS_BRACELET))), - LOCATION(RC_MK_NEAR_BAZAAR_CRATE_1, logic->IsChild /*&& logic->CanRoll()*/), - LOCATION(RC_MK_NEAR_BAZAAR_CRATE_2, logic->IsChild /*&& logic->CanRoll()*/), - LOCATION(RC_MK_SHOOTING_GALLERY_CRATE_1, logic->IsChild /*&& logic->CanRoll()*/), - LOCATION(RC_MK_SHOOTING_GALLERY_CRATE_2, logic->IsChild /*&& logic->CanRoll()*/), + LOCATION(RC_MK_NEAR_BAZAAR_CRATE_1, logic->IsChild && logic->HasItem(RG_ROLL)), + LOCATION(RC_MK_NEAR_BAZAAR_CRATE_2, logic->IsChild && logic->HasItem(RG_ROLL)), + LOCATION(RC_MK_SHOOTING_GALLERY_CRATE_1, logic->IsChild && logic->HasItem(RG_ROLL)), + LOCATION(RC_MK_SHOOTING_GALLERY_CRATE_2, logic->IsChild && logic->HasItem(RG_ROLL)), LOCATION(RC_MARKET_TREE, logic->IsChild && logic->CanBonkTrees()), }, { //Exits @@ -227,7 +227,7 @@ void RegionTable_Init_Market() { areaTable[RR_MARKET_DOG_LADY_HOUSE] = Region("Market Dog Lady House", SCENE_DOG_LADY_HOUSE, {}, { //Locations LOCATION(RC_MARKET_LOST_DOG, logic->IsChild && logic->AtNight), - LOCATION(RC_MK_LOST_DOG_HOUSE_CRATE, logic->CanBreakCrates()), + LOCATION(RC_MK_LOST_DOG_HOUSE_CRATE, logic->HasItem(RG_ROLL)), }, { //Exits Entrance(RR_MARKET_BACK_ALLEY, []{return true;}), diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index 9935d9f63a4..28f7ad3a0fc 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -257,6 +257,8 @@ bool Logic::HasItem(RandomizerGet itemName) { return CheckRandoInf(RAND_INF_CAN_CLIMB); case RG_CRAWL: return CheckRandoInf(RAND_INF_CAN_CRAWL); + case RG_ROLL: + return CheckRandoInf(RAND_INF_CAN_ROLL); case RG_OPEN_CHEST: return CheckRandoInf(RAND_INF_CAN_OPEN_CHEST); case RG_POCKET_EGG: @@ -1318,7 +1320,7 @@ bool Logic::CanBreakPots(EnemyDistance distance, bool wallOrFloor, bool inWater) } bool Logic::CanBreakCrates() { - return true; + return HasItem(RG_ROLL) || CanUse(RG_MEGATON_HAMMER) || CanUse(RG_BOMB_BAG) || CanUse(RG_BOMBCHU_5); } bool Logic::CanBreakSmallCrates() { @@ -1326,7 +1328,7 @@ bool Logic::CanBreakSmallCrates() { } bool Logic::CanBonkTrees() { - return true; + return HasItem(RG_ROLL); } bool Logic::HasExplosives() { @@ -1766,6 +1768,8 @@ void Logic::ApplyItemEffect(Item& item, bool state) { case RG_CRAWL: SetRandoInf(RAND_INF_CAN_CRAWL, state); break; + case RG_ROLL: + SetRandoInf(RAND_INF_CAN_ROLL, state); case RG_OPEN_CHEST: SetRandoInf(RAND_INF_CAN_OPEN_CHEST, state); break; @@ -2675,6 +2679,11 @@ void Logic::Reset(bool resetSaveContext /*= true*/) { SetRandoInf(RAND_INF_CAN_CRAWL, true); } + // If we're not shuffling roll, we start with it + if (ctx->GetOption(RSK_SHUFFLE_ROLL).Is(false)) { + SetRandoInf(RAND_INF_CAN_ROLL, true); + } + // If we're not shuffling open chest, we start with it if (ctx->GetOption(RSK_SHUFFLE_OPEN_CHEST).Is(false)) { SetRandoInf(RAND_INF_CAN_OPEN_CHEST, true); diff --git a/soh/soh/Enhancements/randomizer/option_descriptions.cpp b/soh/soh/Enhancements/randomizer/option_descriptions.cpp index f9146bf8b36..d7f9b0f243d 100644 --- a/soh/soh/Enhancements/randomizer/option_descriptions.cpp +++ b/soh/soh/Enhancements/randomizer/option_descriptions.cpp @@ -262,6 +262,7 @@ void Settings::CreateOptionDescriptions() { "Shuffle the ability to grab as a progressive upgrade before Goron Bracelet."; mOptionDescriptions[RSK_SHUFFLE_CLIMB] = "Shuffle the ability to climb ladders into the item pool."; mOptionDescriptions[RSK_SHUFFLE_CRAWL] = "Shuffles the ability to use crawlspaces into the item pool."; + mOptionDescriptions[RSK_SHUFFLE_ROLL] = "Shuffles the ability do a roll into the item pool."; mOptionDescriptions[RSK_SHUFFLE_OPEN_CHEST] = "Shuffles the ability to open chests into the item pool."; mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG] = "Shuffles the Weird Egg from Malon in to the item pool. Enabling " "\"Skip Child Zelda\" disables this feature.\n" diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index affc1c4978f..acfad5aff10 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -127,6 +127,7 @@ std::map randomizerGetToRandInf = { { RG_CLIMB, RAND_INF_CAN_CLIMB }, { RG_CRAWL, RAND_INF_CAN_CRAWL }, { RG_OPEN_CHEST, RAND_INF_CAN_OPEN_CHEST }, + { RG_ROLL, RAND_INF_CAN_ROLL }, { RG_QUIVER_INF, RAND_INF_HAS_INFINITE_QUIVER }, { RG_BOMB_BAG_INF, RAND_INF_HAS_INFINITE_BOMB_BAG }, { RG_BULLET_BAG_INF, RAND_INF_HAS_INFINITE_BULLET_BAG }, diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index b2211cad9c3..82f7ef4ed88 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -4635,6 +4635,7 @@ typedef enum { RG_POWER_BRACELET, RG_CLIMB, RG_CRAWL, + RG_ROLL, RG_OPEN_CHEST, RG_CHILD_WALLET, RG_PROGRESSIVE_BOMBCHU_BAG, @@ -5853,6 +5854,7 @@ typedef enum { RHT_MASK_TRUTH, RHT_CLIMB, RHT_CRAWL, + RHT_ROLL, RHT_OPEN_CHEST, RHT_FISHING_POLE, RHT_SKELETON_KEY, @@ -6452,6 +6454,7 @@ typedef enum { RSK_SHUFFLE_GRAB, RSK_SHUFFLE_CLIMB, RSK_SHUFFLE_CRAWL, + RSK_SHUFFLE_ROLL, RSK_SHUFFLE_OPEN_CHEST, RSK_STARTING_DEKU_SHIELD, RSK_STARTING_KOKIRI_SWORD, diff --git a/soh/soh/Enhancements/randomizer/randomizer_inf.h b/soh/soh/Enhancements/randomizer/randomizer_inf.h index de7b8750c29..96ccf07d0ca 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_inf.h +++ b/soh/soh/Enhancements/randomizer/randomizer_inf.h @@ -1141,6 +1141,7 @@ DEFINE_RAND_INF(RAND_INF_CAUGHT_LOACH) DEFINE_RAND_INF(RAND_INF_CAN_SWIM) DEFINE_RAND_INF(RAND_INF_CAN_CLIMB) DEFINE_RAND_INF(RAND_INF_CAN_CRAWL) +DEFINE_RAND_INF(RAND_INF_CAN_ROLL) DEFINE_RAND_INF(RAND_INF_CAN_GRAB) DEFINE_RAND_INF(RAND_INF_CAN_OPEN_CHEST) diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp index 525e5082cae..061e904163c 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp @@ -153,6 +153,10 @@ std::vector climbItems = { ITEM_TRACKER_ITEM(RG_CLIMB, 0, DrawItem), }; +std::vector rollItems = { + ITEM_TRACKER_ITEM(RG_ROLL, 0, DrawItem), +}; + std::vector grabItems = { ITEM_TRACKER_ITEM(RG_POWER_BRACELET, 0, DrawItem), }; @@ -1142,6 +1146,11 @@ void DrawItem(ItemTrackerItem item) { hasItem = Flags_GetRandomizerInf(RAND_INF_CAN_CLIMB); itemName = "Climb"; break; + case RG_ROLL: + actualItemId = item.id; + hasItem = Flags_GetRandomizerInf(RAND_INF_CAN_ROLL); + itemName = "Roll"; + break; case RG_POWER_BRACELET: actualItemId = item.id; hasItem = Flags_GetRandomizerInf(RAND_INF_CAN_GRAB); @@ -1578,6 +1587,9 @@ void UpdateVectors() { if (IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_CLIMB)) { mainWindowItems.insert(mainWindowItems.end(), climbItems.begin(), climbItems.end()); } + if (IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_ROLL)) { + mainWindowItems.insert(mainWindowItems.end(), rollItems.begin(), rollItems.end()); + } if (IS_RANDO && RAND_GET_OPTION(RSK_SHUFFLE_CRAWL)) { mainWindowItems.insert(mainWindowItems.end(), crawlItems.begin(), crawlItems.end()); } diff --git a/soh/soh/Enhancements/randomizer/roll_animation_data.h b/soh/soh/Enhancements/randomizer/roll_animation_data.h new file mode 100644 index 00000000000..5d0700721c0 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/roll_animation_data.h @@ -0,0 +1,348 @@ +#ifndef ROLL_ANIMATION_DATA_H +#define ROLL_ANIMATION_DATA_H + +#include "z64.h" + +#define ROLL_ANIMATION_FRAMES 20 +#define ROLL_ANIMATION_LIMBS 22 + +static const Vec3s rollAnimationData[ROLL_ANIMATION_FRAMES][ROLL_ANIMATION_LIMBS] = { + { + // Frame 0 + { 74, 3528, -37 }, + { 0, 0, 0 }, + { -16384, -626, -16384 }, + { 0, 0, 0 }, + { 135, 5446, -5887 }, + { 0, 0, 23451 }, + { 2115, 1887, -20292 }, + { 1024, -219, -1846 }, + { 0, 0, 5914 }, + { -443, -1625, -21253 }, + { 16384, 417, 16384 }, + { 476, -93, 19351 }, + { 0, 0, 23344 }, + { 0, 0, 0 }, + { -21137, -12435, -10526 }, + { 0, 0, -6675 }, + { -36, -503, -16171 }, + { 12851, 7298, -17081 }, + { 0, 0, -19713 }, + { 4373, 5305, -15750 }, + { -16384, 27240, -730 }, + { 0, 0, 0 }, + }, + { + // Frame 1 + { 54, 3227, -89 }, + { 2313, 0, 0 }, + { -16384, -685, -16384 }, + { 0, 0, 0 }, + { -152, 5099, -11115 }, + { 0, 0, 24427 }, + { 2059, 1815, -21046 }, + { -59, -710, -6843 }, + { 0, 0, 10860 }, + { -979, -1386, -22412 }, + { 16183, -133, 16490 }, + { 503, -59, 18352 }, + { 0, 0, 25530 }, + { 0, 0, 0 }, + { -20393, -12323, -12080 }, + { 0, 0, -6726 }, + { -25, -562, -16150 }, + { 14095, 8887, -16891 }, + { 0, 0, -18784 }, + { 3073, 5837, -17586 }, + { -15392, 27325, 1213 }, + { 0, 0, 0 }, + }, + { + // Frame 2 + { -25, 2218, -133 }, + { 7607, 0, 0 }, + { -16384, -781, -16384 }, + { 0, 0, 0 }, + { -654, 1069, -20519 }, + { 0, 0, 20760 }, + { 1304, 1666, -23774 }, + { -518, -3910, -15614 }, + { 0, 0, 22754 }, + { -1707, -1918, -22925 }, + { 16384, -4331, 16384 }, + { 641, 74, 13206 }, + { 0, 0, 30948 }, + { 0, 0, 0 }, + { -15708, -11590, -21423 }, + { 0, 0, -6949 }, + { 37, -880, -16032 }, + { -12778, 15014, 15677 }, + { 0, 0, -13974 }, + { -4182, 8702, -27734 }, + { -13006, 28312, 6371 }, + { 0, 0, 0 }, + }, + { + // Frame 3 + { -57, 2670, 558 }, { 13602, 0, 0 }, + { -16384, 0, -16384 }, { 0, 0, 0 }, + { 1852, 198, -7548 }, { 0, 0, 1654 }, + { 1472, 2843, -23780 }, { -2685, -3676, -6545 }, + { 0, 0, 15549 }, { 1676, -2089, -20933 }, + { -1427, -19182, -27019 }, { 698, -257, 10968 }, + { 0, 0, 18514 }, { 0, 0, 0 }, + { 23192, -22237, 548 }, { 0, 0, -6929 }, + { 86, -1131, -15938 }, { -11355, 7097, 10885 }, + { 0, 0, -11056 }, { -10661, 10872, 29098 }, + { -15580, 27296, 800 }, { 0, 0, 0 }, + }, + { + // Frame 4 + { -60, 2207, 382 }, { 20068, 0, 0 }, + { -16384, 2162, -16384 }, { 0, 0, 0 }, + { 219, 581, -17012 }, { 0, 0, 16199 }, + { 1446, 2552, -20834 }, { -1193, -3974, -12795 }, + { 0, 0, 22901 }, { 1355, -1424, -20722 }, + { -24738, -12007, -7558 }, { 462, -469, 19859 }, + { 0, 0, 17568 }, { 0, 0, 0 }, + { -1152, -8811, 22716 }, { 0, 0, -5124 }, + { 43, -913, -16019 }, { -2615, 21391, 18299 }, + { 0, 0, -20972 }, { -7167, 7353, -29571 }, + { -16740, 27249, -1447 }, { 0, 0, 0 }, + }, + { + // Frame 5 + { -60, 1477, 314 }, { 26774, 0, 0 }, + { -16384, 4992, -16384 }, { 0, 0, 0 }, + { 1331, 909, -8175 }, { 0, 0, 8190 }, + { 538, 2622, -21124 }, { -443, -603, -1212 }, + { 0, 0, 24711 }, { 491, -584, -20713 }, + { -21267, -11295, -7882 }, { 552, 479, 16219 }, + { 0, 0, 17341 }, { 0, 0, 0 }, + { 2866, -7762, 19771 }, { 0, 0, -3812 }, + { -416, 862, -16656 }, { -2940, 16895, 20702 }, + { 0, 0, -18661 }, { -5100, 10643, -25824 }, + { -15495, 27304, 1032 }, { 0, 0, 0 }, + }, + { + // Frame 6 + { -60, 771, 241 }, { -32044, 0, 0 }, { -16384, 7684, -16384 }, { 0, 0, 0 }, + { -27, 459, -14461 }, { 0, 0, 13541 }, { 63, 2434, -21507 }, { 140, -3557, -8362 }, + { 0, 0, 25043 }, { -525, 149, -20932 }, { -18194, -11230, -7652 }, { 519, 2089, 15610 }, + { 0, 0, 17631 }, { 0, 0, 0 }, { 3504, -7332, 22086 }, { 0, 0, -4207 }, + { -1489, 5198, -18222 }, { 967, 12936, 27541 }, { 0, 0, -17131 }, { -2949, 6188, -22075 }, + { -16864, 27258, -1679 }, { 0, 0, 0 }, + }, + { + // Frame 7 + { -60, 511, -4 }, { -25546, 0, 0 }, + { -16384, 8878, -16384 }, { 0, 0, 0 }, + { -799, 63, -16740 }, { 0, 0, 14954 }, + { 943, 1296, -21262 }, { 1564, -3136, -16443 }, + { 0, 0, 25526 }, { -1303, 490, -21402 }, + { -18554, -11994, -7123 }, { 464, 3612, 15275 }, + { 0, 0, 18235 }, { 0, 0, 0 }, + { 3231, -6977, 25545 }, { 0, 0, -4847 }, + { -321, 5196, -18440 }, { 2710, 9642, 31101 }, + { 0, 0, -15600 }, { -985, 4840, -20355 }, + { -16899, 27261, -1747 }, { 0, 0, 0 }, + }, + { + // Frame 8 + { -60, 771, -444 }, { -19497, 0, 0 }, + { -16384, 6684, -16384 }, { 0, 0, 0 }, + { -2556, 1051, -17674 }, { 0, 0, 27472 }, + { 1977, 423, -21477 }, { 1754, -2055, -18579 }, + { 0, 0, 25919 }, { -1681, 96, -22354 }, + { -20790, -12983, -5802 }, { 376, 4598, 14848 }, + { 0, 0, 18950 }, { 0, 0, 0 }, + { 3130, -6330, 27866 }, { 0, 0, -5576 }, + { 2725, 2012, -17715 }, { 4493, 6440, -31020 }, + { 0, 0, -14167 }, { 1055, 3881, -18845 }, + { -16739, 27250, -1432 }, { 0, 0, 0 }, + }, + { + // Frame 9 + { -59, 940, -590 }, { -16713, 0, 0 }, + { -16384, 5073, -16384 }, { 0, 0, 0 }, + { -2448, 996, -16808 }, { 0, 0, 26712 }, + { 2021, 695, -22206 }, { 1957, -1988, -18219 }, + { 0, 0, 26656 }, { -1789, -334, -23017 }, + { -22257, -13213, -4844 }, { 333, 4517, 14584 }, + { 0, 0, 19285 }, { 0, 0, 0 }, + { 2948, -5849, 28856 }, { 0, 0, -5925 }, + { 4383, 81, -17239 }, { 5329, 5036, -29493 }, + { 0, 0, -13518 }, { 1992, 3521, -18202 }, + { -16629, 27244, -1214 }, { 0, 0, 0 }, + }, + { + // Frame 10 + { -59, 1348, -649 }, { -11768, 0, 0 }, + { -16384, 1883, -16384 }, { 0, 0, 0 }, + { -2196, 778, -10577 }, { 0, 0, 28012 }, + { 1653, 2033, -24440 }, { 2855, -2524, -11436 }, + { 0, 0, 27911 }, { -1938, -1318, -24470 }, + { -25057, -12419, -3692 }, { 177, 3296, 14007 }, + { 0, 0, 19787 }, { 0, 0, 0 }, + { 2482, -4950, 30438 }, { 0, 0, -6494 }, + { 6915, -3159, -16394 }, { 6751, 2940, -27054 }, + { 0, 0, -12420 }, { 3479, 2992, -17208 }, + { -16434, 27240, -830 }, { 0, 0, 0 }, + }, + { + // Frame 11 + { -58, 1735, -542 }, { -7750, 0, 0 }, + { -16384, 184, -16384 }, { 0, 0, 0 }, + { -1205, 108, -8043 }, { 0, 0, 25981 }, + { 1346, 2790, -26757 }, { 2029, -1692, -8455 }, + { 0, 0, 25863 }, { -1961, -2047, -25988 }, + { -28048, -11954, -2090 }, { -470, 3031, 12591 }, + { 0, 0, 19948 }, { 0, 0, 0 }, + { 2309, -4596, 31084 }, { 0, 0, -6786 }, + { 7219, -4155, -16045 }, { 7656, 2711, -26079 }, + { 0, 0, -11861 }, { 4229, 2661, -16666 }, + { -16363, 27240, -688 }, { 0, 0, 0 }, + }, + { + // Frame 12 + { 74, 3528, -37 }, + { 0, 0, 0 }, + { -16384, -626, -16384 }, + { 0, 0, 0 }, + { 135, 5446, -5887 }, + { 0, 0, 23451 }, + { 2115, 1887, -20292 }, + { 1024, -219, -1846 }, + { 0, 0, 5914 }, + { -443, -1625, -21253 }, + { 16384, 417, 16384 }, + { 476, -93, 19351 }, + { 0, 0, 23344 }, + { 0, 0, 0 }, + { -21137, -12435, -10526 }, + { 0, 0, -6675 }, + { -36, -503, -16171 }, + { 12851, 7298, -17081 }, + { 0, 0, -19713 }, + { 4373, 5305, -15750 }, + { -16384, 27240, -730 }, + { 0, 0, 0 }, + }, + { + // Frame 13 + { 54, 3227, -89 }, + { 2313, 0, 0 }, + { -16384, -685, -16384 }, + { 0, 0, 0 }, + { -152, 5099, -11115 }, + { 0, 0, 24427 }, + { 2059, 1815, -21046 }, + { -59, -710, -6843 }, + { 0, 0, 10860 }, + { -979, -1386, -22412 }, + { 16183, -133, 16490 }, + { 503, -59, 18352 }, + { 0, 0, 25530 }, + { 0, 0, 0 }, + { -20393, -12323, -12080 }, + { 0, 0, -6726 }, + { -25, -562, -16150 }, + { 14095, 8887, -16891 }, + { 0, 0, -18784 }, + { 3073, 5837, -17586 }, + { -15392, 27325, 1213 }, + { 0, 0, 0 }, + }, + { + // Frame 14 + { -25, 2218, -133 }, + { 7607, 0, 0 }, + { -16384, -781, -16384 }, + { 0, 0, 0 }, + { -654, 1069, -20519 }, + { 0, 0, 20760 }, + { 1304, 1666, -23774 }, + { -518, -3910, -15614 }, + { 0, 0, 22754 }, + { -1707, -1918, -22925 }, + { 16384, -4331, 16384 }, + { 641, 74, 13206 }, + { 0, 0, 30948 }, + { 0, 0, 0 }, + { -15708, -11590, -21423 }, + { 0, 0, -6949 }, + { 37, -880, -16032 }, + { -12778, 15014, 15677 }, + { 0, 0, -13974 }, + { -4182, 8702, -27734 }, + { -13006, 28312, 6371 }, + { 0, 0, 0 }, + }, + { + // Frame 15 + { -57, 2670, 558 }, { 13602, 0, 0 }, + { -16384, 0, -16384 }, { 0, 0, 0 }, + { 1852, 198, -7548 }, { 0, 0, 1654 }, + { 1472, 2843, -23780 }, { -2685, -3676, -6545 }, + { 0, 0, 15549 }, { 1676, -2089, -20933 }, + { -1427, -19182, -27019 }, { 698, -257, 10968 }, + { 0, 0, 18514 }, { 0, 0, 0 }, + { 23192, -22237, 548 }, { 0, 0, -6929 }, + { 86, -1131, -15938 }, { -11355, 7097, 10885 }, + { 0, 0, -11056 }, { -10661, 10872, 29098 }, + { -15580, 27296, 800 }, { 0, 0, 0 }, + }, + { + // Frame 16 + { -60, 2207, 382 }, { 20068, 0, 0 }, + { -16384, 2162, -16384 }, { 0, 0, 0 }, + { 219, 581, -17012 }, { 0, 0, 16199 }, + { 1446, 2552, -20834 }, { -1193, -3974, -12795 }, + { 0, 0, 22901 }, { 1355, -1424, -20722 }, + { -24738, -12007, -7558 }, { 462, -469, 19859 }, + { 0, 0, 17568 }, { 0, 0, 0 }, + { -1152, -8811, 22716 }, { 0, 0, -5124 }, + { 43, -913, -16019 }, { -2615, 21391, 18299 }, + { 0, 0, -20972 }, { -7167, 7353, -29571 }, + { -16740, 27249, -1447 }, { 0, 0, 0 }, + }, + { + // Frame 17 + { -60, 1477, 314 }, { 26774, 0, 0 }, + { -16384, 4992, -16384 }, { 0, 0, 0 }, + { 1331, 909, -8175 }, { 0, 0, 8190 }, + { 538, 2622, -21124 }, { -443, -603, -1212 }, + { 0, 0, 24711 }, { 491, -584, -20713 }, + { -21267, -11295, -7882 }, { 552, 479, 16219 }, + { 0, 0, 17341 }, { 0, 0, 0 }, + { 2866, -7762, 19771 }, { 0, 0, -3812 }, + { -416, 862, -16656 }, { -2940, 16895, 20702 }, + { 0, 0, -18661 }, { -5100, 10643, -25824 }, + { -15495, 27304, 1032 }, { 0, 0, 0 }, + }, + { + // Frame 18 + { -60, 771, 241 }, { -32044, 0, 0 }, { -16384, 7684, -16384 }, { 0, 0, 0 }, + { -27, 459, -14461 }, { 0, 0, 13541 }, { 63, 2434, -21507 }, { 140, -3557, -8362 }, + { 0, 0, 25043 }, { -525, 149, -20932 }, { -18194, -11230, -7652 }, { 519, 2089, 15610 }, + { 0, 0, 17631 }, { 0, 0, 0 }, { 3504, -7332, 22086 }, { 0, 0, -4207 }, + { -1489, 5198, -18222 }, { 967, 12936, 27541 }, { 0, 0, -17131 }, { -2949, 6188, -22075 }, + { -16864, 27258, -1679 }, { 0, 0, 0 }, + }, + { + // Frame 19 + { -60, 511, -4 }, { -25546, 0, 0 }, + { -16384, 8878, -16384 }, { 0, 0, 0 }, + { -799, 63, -16740 }, { 0, 0, 14954 }, + { 943, 1296, -21262 }, { 1564, -3136, -16443 }, + { 0, 0, 25526 }, { -1303, 490, -21402 }, + { -18554, -11994, -7123 }, { 464, 3612, 15275 }, + { 0, 0, 18235 }, { 0, 0, 0 }, + { 3231, -6977, 25545 }, { 0, 0, -4847 }, + { -321, 5196, -18440 }, { 2710, 9642, 31101 }, + { 0, 0, -15600 }, { -985, 4840, -20355 }, + { -16899, 27261, -1747 }, { 0, 0, 0 }, + }, +}; + +#endif // ROLL_ANIMATION_DATA_H \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index 665ffedfe6c..b9fc298e6dd 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -325,6 +325,10 @@ extern "C" void Randomizer_InitSaveFile() { Flags_SetRandomizerInf(RAND_INF_CAN_CRAWL); } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_ROLL) == RO_GENERIC_OFF) { + Flags_SetRandomizerInf(RAND_INF_CAN_ROLL); + } + if (Randomizer_GetSettingValue(RSK_SHUFFLE_OPEN_CHEST) == RO_GENERIC_OFF) { Flags_SetRandomizerInf(RAND_INF_CAN_OPEN_CHEST); } diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index e9faf4fc218..78ead12dd64 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -787,6 +787,7 @@ void Settings::CreateOptions() { OPT_BOOL(RSK_SHUFFLE_SWIM, "Shuffle Swim", CVAR_RANDOMIZER_SETTING("ShuffleSwim"), mOptionDescriptions[RSK_SHUFFLE_SWIM]); OPT_BOOL(RSK_SHUFFLE_CLIMB, "Shuffle Climb", CVAR_RANDOMIZER_SETTING("ShuffleClimb"), mOptionDescriptions[RSK_SHUFFLE_CLIMB]); OPT_BOOL(RSK_SHUFFLE_CRAWL, "Shuffle Crawl", CVAR_RANDOMIZER_SETTING("ShuffleCrawl"), mOptionDescriptions[RSK_SHUFFLE_CRAWL]); + OPT_BOOL(RSK_SHUFFLE_ROLL, "Shuffle Roll", CVAR_RANDOMIZER_SETTING("ShuffleRoll"), mOptionDescriptions[RSK_SHUFFLE_ROLL]); OPT_BOOL(RSK_SHUFFLE_GRAB, "Shuffle Grab", CVAR_RANDOMIZER_SETTING("ShuffleGrab"), mOptionDescriptions[RSK_SHUFFLE_GRAB]); OPT_BOOL(RSK_SHUFFLE_OPEN_CHEST, "Shuffle Open Chest", CVAR_RANDOMIZER_SETTING("ShuffleOpenChest"), mOptionDescriptions[RSK_SHUFFLE_OPEN_CHEST]); OPT_BOOL(RSK_SHUFFLE_WEIRD_EGG, "Shuffle Weird Egg", CVAR_RANDOMIZER_SETTING("ShuffleWeirdEgg"), mOptionDescriptions[RSK_SHUFFLE_WEIRD_EGG]); @@ -2400,6 +2401,7 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_GRAB], &mOptions[RSK_SHUFFLE_CLIMB], &mOptions[RSK_SHUFFLE_CRAWL], + &mOptions[RSK_SHUFFLE_ROLL], &mOptions[RSK_SHUFFLE_OPEN_CHEST], &mOptions[RSK_SHUFFLE_BEAN_SOULS], &mOptions[RSK_ROCS_FEATHER], @@ -2622,6 +2624,7 @@ void Settings::CreateOptions() { &mOptions[RSK_SHUFFLE_GRAB], &mOptions[RSK_SHUFFLE_CLIMB], &mOptions[RSK_SHUFFLE_CRAWL], + &mOptions[RSK_SHUFFLE_ROLL], &mOptions[RSK_SHUFFLE_OPEN_CHEST], &mOptions[RSK_SHUFFLE_WEIRD_EGG], &mOptions[RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD], diff --git a/soh/soh/SohGui/ImGuiUtils.cpp b/soh/soh/SohGui/ImGuiUtils.cpp index eaf63c6eacb..143fc2bc356 100644 --- a/soh/soh/SohGui/ImGuiUtils.cpp +++ b/soh/soh/SohGui/ImGuiUtils.cpp @@ -154,6 +154,7 @@ std::map customItemsMapping = { std::map actionShuffleMapping = { { RG_CRAWL, { RG_CRAWL, "RG_CRAWL", "RG_CRAWL_Faded", gButtonBackgroundTex } }, { RG_CLIMB, { RG_CLIMB, "RG_CLIMB", "RG_CLIMB_Faded", gButtonBackgroundTex } }, + { RG_ROLL, { RG_ROLL, "RG_ROLL", "RG_ROLL_Faded", gButtonBackgroundTex } }, { RG_POWER_BRACELET, { RG_POWER_BRACELET, "RG_POWER_BRACELET", "RG_POWER_BRACELET_Faded", gButtonBackgroundTex } }, }; diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 5a027c32386..c481117aef3 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -6306,11 +6306,13 @@ s32 func_8083BBA0(Player* this, PlayState* play) { } void Player_SetupRoll(Player* this, PlayState* play) { - Player_SetupAction(play, this, Player_Action_Roll, 0); - LinkAnimation_PlayOnceSetSpeed(play, &this->skelAnime, - GET_PLAYER_ANIM(PLAYER_ANIMGROUP_landing_roll, this->modelAnimType), - 1.25f * sWaterSpeedFactor); - gSaveContext.ship.stats.count[COUNT_ROLLS]++; + if (GameInteractor_Should(VB_ROLL, true)) { + Player_SetupAction(play, this, Player_Action_Roll, 0); + LinkAnimation_PlayOnceSetSpeed(play, &this->skelAnime, + GET_PLAYER_ANIM(PLAYER_ANIMGROUP_landing_roll, this->modelAnimType), + 1.25f * sWaterSpeedFactor); + gSaveContext.ship.stats.count[COUNT_ROLLS]++; + } } s32 Player_TryRoll(Player* this, PlayState* play) {