diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 63fd6efc6..9b4482f23 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -242,6 +242,8 @@ const std::vector enhancementsCvars = { CVAR_ENHANCEMENT("AuthenticLogo"), CVAR_ENHANCEMENT("PauseLiveLinkRotationSpeed"), CVAR_ENHANCEMENT("BowReticle"), + CVAR_ENHANCEMENT("BoomerangFirstPerson"), + CVAR_ENHANCEMENT("BoomerangReticle"), CVAR_ENHANCEMENT("FixTexturesOOB"), CVAR_ENHANCEMENT("IvanCoopModeEnabled"), CVAR_ENHANCEMENT("EnemySpawnsOverWaterboxes"), diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 2435af1f8..cd9948092 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -872,6 +872,17 @@ void DrawEnhancementsMenu() { "Toggling while inside the shop will not change prices or restock any SOLD OUTs"); UIWidgets::PaddedEnhancementCheckbox("Aiming reticle for the bow/slingshot", CVAR_ENHANCEMENT("BowReticle"), true, false); UIWidgets::Tooltip("Aiming with a bow or slingshot will display a reticle as with the hookshot when the projectile is ready to fire."); + if (UIWidgets::PaddedEnhancementCheckbox("Aim boomerang in first-person mode", CVAR_ENHANCEMENT("BoomerangFirstPerson"), true, false)) { + if (!CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { + CVarSetInteger(CVAR_ENHANCEMENT("BoomerangReticle"), 0); + } + } + UIWidgets::Tooltip( + "Change aiming for the boomerang from third person to first person to see past Link's head"); + if (CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { + UIWidgets::PaddedEnhancementCheckbox("Aiming reticle for boomerang", CVAR_ENHANCEMENT("BoomerangReticle"), true, false); + UIWidgets::Tooltip("Aiming with the boomerang will display a reticle as with the hookshot"); + } if (UIWidgets::PaddedEnhancementCheckbox("Allow strength equipment to be toggled", CVAR_ENHANCEMENT("ToggleStrength"), true, false)) { if (!CVarGetInteger(CVAR_ENHANCEMENT("ToggleStrength"), 0)) { CVarSetInteger(CVAR_ENHANCEMENT("StrengthDisabled"), 0); diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index a50a49e2d..3207abaf6 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -887,6 +887,16 @@ s32 Player_HoldsSlingshot(Player* this) { return this->heldItemAction == PLAYER_IA_SLINGSHOT; } +// #region SOH [Enhancement] +s32 Player_HoldsBoomerang(Player* this) { + return this->heldItemAction == PLAYER_IA_BOOMERANG; +} + +s32 Player_AimsBoomerang(Player* this) { + return Player_HoldsBoomerang(this) && (this->unk_834 != 0); +} +// #endregion + s32 func_8008F128(Player* this) { return Player_HoldsHookshot(this) && (this->heldActor == NULL); } @@ -1789,6 +1799,9 @@ Vec3f sLeftRightFootLimbModelFootPos[] = { void Player_PostLimbDrawGameplay(PlayState* play, s32 limbIndex, Gfx** dList, Vec3s* rot, void* thisx) { Player* this = (Player*)thisx; + const Vec3s BoomerangViewAdult = { -31200, -9200, 17000 }; + const Vec3s BoomerangViewChild = { -31200, -8700, 17000 }; + if (*dList != NULL) { Matrix_MultVec3f(&sZeroVec, D_80160000); } @@ -1950,6 +1963,8 @@ void Player_PostLimbDrawGameplay(PlayState* play, s32 limbIndex, Gfx** dList, Ve play, this, ((this->heldItemAction == PLAYER_IA_HOOKSHOT) ? 38600.0f : 77600.0f) * CVarGetFloat(CVAR_CHEAT("HookshotReachMultiplier"), 1.0f)); } } + + // #region SOH [Enhancement] } else if (CVarGetInteger(CVAR_ENHANCEMENT("BowReticle"), 0) && ( (this->heldItemAction == PLAYER_IA_BOW_FIRE) || (this->heldItemAction == PLAYER_IA_BOW_ICE) || @@ -1968,6 +1983,21 @@ void Player_PostLimbDrawGameplay(PlayState* play, s32 limbIndex, Gfx** dList, Ve Player_DrawHookshotReticle(play, this, RETICLE_MAX); } } + } else if (CVarGetInteger(CVAR_ENHANCEMENT("BoomerangReticle"), 0) && (this->heldItemAction == PLAYER_IA_BOOMERANG)) { + if (Player_HoldsBoomerang(this)) { + if (LINK_IS_ADULT) { + Matrix_RotateZYX(BoomerangViewAdult.x, BoomerangViewAdult.y, BoomerangViewAdult.z, + MTXMODE_APPLY); + } else { + Matrix_RotateZYX(BoomerangViewChild.x, BoomerangViewChild.y, BoomerangViewChild.z, MTXMODE_APPLY); + } + + if (Player_AimsBoomerang(this)) { + Matrix_Translate(500.0f, 300.0f, 0.0f, MTXMODE_APPLY); + Player_DrawHookshotReticle(play, this, RETICLE_MAX); + } + } + // #endregion } if ((this->unk_862 != 0) || ((func_8002DD6C(this) == 0) && (heldActor != NULL))) { 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 135c66e89..16abaf568 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -3236,7 +3236,11 @@ s32 func_808358F0(Player* this, PlayState* play) { AnimationContext_SetCopyAll(play, this->skelAnime.limbCount, this->upperSkelAnime.jointTable, this->skelAnime.jointTable); } else { - LinkAnimation_Update(play, &this->upperSkelAnime); + // #region SOH [Enhancement] + if (!CVarGetInteger(CVAR_ENHANCEMENT("BoomerangReticle"), 0)) { + // #endregion + LinkAnimation_Update(play, &this->upperSkelAnime); + } } func_80834EB8(this, play); @@ -5823,7 +5827,13 @@ s32 func_8083AD4C(PlayState* play, Player* this) { camMode = shouldUseBowCamera ? CAM_MODE_BOWARROW : CAM_MODE_SLINGSHOT; } else { - camMode = CAM_MODE_BOOMERANG; + // #region SOH [Enhancement] + if (CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { + camMode = CAM_MODE_FIRSTPERSON; + // #endregion + } else { + camMode = CAM_MODE_BOOMERANG; + } } } else { camMode = CAM_MODE_FIRSTPERSON; @@ -11486,7 +11496,13 @@ void Player_UpdateCamAndSeqModes(PlayState* play, Player* this) { camMode = CAM_MODE_TALK; } else if (this->stateFlags1 & PLAYER_STATE1_FRIENDLY_ACTOR_FOCUS) { if (this->stateFlags1 & PLAYER_STATE1_BOOMERANG_THROWN) { - camMode = CAM_MODE_FOLLOWBOOMERANG; + // #region SOH [Enhancement] + if (CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { + camMode = CAM_MODE_TARGET; + // #endregion + } else { + camMode = CAM_MODE_FOLLOWBOOMERANG; + } } else { camMode = CAM_MODE_FOLLOWTARGET; } @@ -11497,7 +11513,13 @@ void Player_UpdateCamAndSeqModes(PlayState* play, Player* this) { } else if (this->stateFlags1 & PLAYER_STATE1_CHARGING_SPIN_ATTACK) { camMode = CAM_MODE_CHARGE; } else if (this->stateFlags1 & PLAYER_STATE1_BOOMERANG_THROWN) { - camMode = CAM_MODE_FOLLOWBOOMERANG; + // #region SOH [Enhancement] + if (CVarGetInteger(CVAR_ENHANCEMENT("BoomerangFirstPerson"), 0)) { + camMode = CAM_MODE_TARGET; + // #endregion + } else { + camMode = CAM_MODE_FOLLOWBOOMERANG; + } Camera_SetParam(Play_GetCamera(play, 0), 8, this->boomerangActor); } else if (this->stateFlags1 & (PLAYER_STATE1_HANGING_OFF_LEDGE | PLAYER_STATE1_CLIMBING_LEDGE)) { if (Player_FriendlyLockOnOrParallel(this)) {