diff --git a/soh/include/z64player.h b/soh/include/z64player.h index ff30cc17094..b71182ebccb 100644 --- a/soh/include/z64player.h +++ b/soh/include/z64player.h @@ -677,6 +677,7 @@ typedef struct Player { // Upstream TODO: Rename these to be more obviously SoH specific /* */ PendingFlag pendingFlag; /* */ GetItemEntry getItemEntry; + /* */ s8 rocUseCount; // #endregion // #region SOH [Enhancements] // Upstream TODO: Rename this to make it more obvious it is apart of an enhancement diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index eb7c34e2a54..03716772c59 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -180,6 +180,7 @@ const std::vector enhancementsCvars = { "gChestSizeDependsStoneOfAgony", "gSkipArrowAnimation", "gSeparateArrows", + "gRocsFeather", "gCustomizeShootingGallery", "gInstantShootingGalleryWin", "gConstantAdultGallery", diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index ade4f752380..04d12d630e6 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -596,6 +596,11 @@ void DrawEnhancementsMenu() { if (ImGui::BeginMenu("Items")) { + UIWidgets::PaddedEnhancementCheckbox("Turn Nayru's Love into Roc's Feather", "gRocsFeather", false, false); + UIWidgets::Tooltip( + "Nayru's Love acts like Roc's Feather from the Indigo romhack instead. Grants a jump that can even " + "be used in the air, " + "but needs to recharge by touching the ground afterwards. Does not require magic to use."); UIWidgets::PaddedEnhancementCheckbox("Instant Putaway", "gInstantPutaway", true, false); UIWidgets::Tooltip("Allow Link to put items away without having to wait around"); UIWidgets::PaddedEnhancementCheckbox("Instant Boomerang Recall", "gFastBoomerang", true, false); 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 f4a072c40e2..435e6383289 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -353,6 +353,8 @@ s32 Player_InflictDamage(PlayState* play, s32 damage); s32 Player_InflictDamageModified(PlayState* play, s32 damage, u8 modified); void func_80853148(PlayState* play, Actor* actor); +void func_80838940(Player* this, LinkAnimationHeader* anim, f32 arg2, PlayState* play, u16 sfxId); + // .bss part 1 static s32 D_80858AA0; static s32 D_80858AA4; @@ -2057,6 +2059,10 @@ void func_80833DF8(Player* this, PlayState* play) { s32 item; s32 i; + if (this->actor.bgCheckFlags & 1) { + this->rocUseCount = 0; + } + if (this->currentMask != PLAYER_MASK_NONE) { if (CVarGetInteger("gMMBunnyHood", BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) { s32 maskItem = this->currentMask - PLAYER_MASK_KEATON + ITEM_MASK_KEATON; @@ -2121,9 +2127,29 @@ void func_80833DF8(Player* this, PlayState* play) { if ((item < ITEM_NONE_FE) && (Player_ItemToItemAction(item) == this->heldItemAction)) { D_80853618 = true; } - } else { + } else if (item != ITEM_NAYRUS_LOVE || !CVarGetInteger("gRocsFeather", 0)) { this->heldItemButton = i; func_80835F44(play, this, item); + } else if (this->rocUseCount == 0) { + this->rocUseCount++; + this->linearVelocity = 5.0f; + this->actor.velocity.y = 8.0f; + this->actor.world.rot.y = this->currentYaw = this->actor.shape.rot.y; + + func_80838940(this, D_80853D4C[2][0], !(2 & 1) ? 5.8f : 3.5f, play, /* NA_SE_VO_LI_SWORD_N*/ 0); + + Vec3f effectsPos = this->actor.home.pos; + effectsPos.y += 3; + f32 effectsScale = 1; + if (!gSaveContext.linkAge) { + effectsScale = 1.5f; + } + EffectSsGRipple_Spawn(play, &effectsPos, 200 * effectsScale, 300 * effectsScale, 1); + EffectSsGSplash_Spawn(play, &effectsPos, NULL, NULL, 0, 150 * effectsScale); + + this->stateFlags2 &= ~(PLAYER_STATE2_HOPPING); + + Player_PlaySfx(&this->actor, NA_SE_PL_SKIP); } } }