Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions soh/soh/Enhancements/Fixes/FixTwoHandedIdleAnim.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ShipInit.hpp"

extern "C" {
#include "macros.h"
#include "functions.h"
}

#define FIDGET_SWORD_SWING 9
#define FIDGET_ADJUST_SHIELD 12

static constexpr int32_t CVAR_FIX_TWO_HANDED_IDLE_DEFAULT = 0;
#define CVAR_FIX_TWO_HANDED_IDLE_NAME CVAR_ENHANCEMENT("TwoHandedIdle")
#define CVAR_FIX_TWO_HANDED_IDLE_VALUE CVarGetInteger(CVAR_FIX_TWO_HANDED_IDLE_NAME, CVAR_FIX_TWO_HANDED_IDLE_DEFAULT)

// clang-format off
static RegisterShipInitFunc initFunc([]() {
COND_VB_SHOULD(VB_SET_IDLE_ANIM, CVAR_FIX_TWO_HANDED_IDLE_VALUE, {
Player* player = va_arg(args, Player*);
s32 commonType = va_arg(args, s32);

// Fixes a bug here where the condition for reaching two-handed idle animation was impossible. Original condition:
/*
(
(
(commonType + FIDGET_SWORD_SWING != FIDGET_SWORD_SWING) &&
(commonType + FIDGET_SWORD_SWING != FIDGET_ADJUST_SHIELD)
) ||
(
(player->rightHandType == PLAYER_MODELTYPE_RH_SHIELD) &&
(
(commonType + FIDGET_SWORD_SWING == FIDGET_ADJUST_SHIELD) ||
// This should not have been grouped here, because two handed melee weapons do not have shield.
(Player_GetMeleeWeaponHeld2(player) != 0)
)
)
)
*/

*should = (
// Animation is not FIDGET_SWORD_SWING and FIDGET_ADJUST_SHIELD (So it's either FIDGET_ADJUST_TUNIC or FIDGET_TAP_FEET)
(
(commonType + FIDGET_SWORD_SWING != FIDGET_SWORD_SWING) &&
(commonType + FIDGET_SWORD_SWING != FIDGET_ADJUST_SHIELD)
) ||
// Animation is FIDGET_ADJUST_SHIELD and player is holding a shield in right hand
(
(player->rightHandType == PLAYER_MODELTYPE_RH_SHIELD) &&
(commonType + FIDGET_SWORD_SWING == FIDGET_ADJUST_SHIELD)
) ||
// Animation is FIDGET_SWORD_SWING and player is holding a melee weapon
(
(commonType + FIDGET_SWORD_SWING == FIDGET_SWORD_SWING) &&
(Player_GetMeleeWeaponHeld(player) != 0)
)
);
});
}, { CVAR_FIX_TWO_HANDED_IDLE_NAME });
// clang-format on
Original file line number Diff line number Diff line change
Expand Up @@ -2327,6 +2327,27 @@ typedef enum {
// - `*Player`
VB_SET_STATIC_FLOOR_TYPE,

// #### `result`
// ```c
// (
// (
// (commonType + FIDGET_SWORD_SWING != FIDGET_SWORD_SWING) &&
// (commonType + FIDGET_SWORD_SWING != FIDGET_ADJUST_SHIELD)
// ) ||
// (
// (player->rightHandType == PLAYER_MODELTYPE_RH_SHIELD) &&
// (
// (commonType + FIDGET_SWORD_SWING == FIDGET_ADJUST_SHIELD) ||
// (Player_GetMeleeWeaponHeld2(player) != 0)
// )
// )
// )
// ```
// #### `args`
// - `Player*`
// - `s32` commonType
VB_SET_IDLE_ANIM,

} GIVanillaBehavior;

#endif
15 changes: 8 additions & 7 deletions soh/src/overlays/actors/ovl_player_actor/z_player.c
Original file line number Diff line number Diff line change
Expand Up @@ -8293,19 +8293,20 @@ void Player_ChooseNextIdleAnim(PlayState* play, Player* this) {
//
// Note that `FIDGET_SWORD_SWING` is the first common fidget type, which is why
// all operations are done relative to this type.
if (((commonType + FIDGET_SWORD_SWING != FIDGET_SWORD_SWING) &&
(commonType + FIDGET_SWORD_SWING != FIDGET_ADJUST_SHIELD)) ||
((this->rightHandType == PLAYER_MODELTYPE_RH_SHIELD) &&
((commonType + FIDGET_SWORD_SWING == FIDGET_ADJUST_SHIELD) ||
(Player_GetMeleeWeaponHeld2(this) != 0)))) {
if (GameInteractor_Should(VB_SET_IDLE_ANIM,
(((commonType + FIDGET_SWORD_SWING != FIDGET_SWORD_SWING) &&
(commonType + FIDGET_SWORD_SWING != FIDGET_ADJUST_SHIELD)) ||
((this->rightHandType == PLAYER_MODELTYPE_RH_SHIELD) &&
((commonType + FIDGET_SWORD_SWING == FIDGET_ADJUST_SHIELD) ||
(Player_GetMeleeWeaponHeld2(this) != 0)))),
this, commonType)) {
//! @bug It is possible for `FIDGET_ADJUST_SHIELD` to be used even if
//! a shield is not currently equipped. This is because of how being shieldless
//! is implemented. There is no sword-only model type, only
//! `PLAYER_MODELGROUP_SWORD_AND_SHIELD` exists. Therefore, the right hand type will be
//! `PLAYER_MODELTYPE_RH_SHIELD` if sword is in hand, even if no shield is equipped.
if ((commonType + FIDGET_SWORD_SWING == FIDGET_SWORD_SWING) &&
Player_HoldsTwoHandedWeapon(this) &&
CVarGetInteger(CVAR_ENHANCEMENT("TwoHandedIdle"), 0) == 1) {
Player_HoldsTwoHandedWeapon(this)) {
//! @bug This code is unreachable.
//! The check above groups the `Player_GetMeleeWeaponHeld2` check and
//! `PLAYER_MODELTYPE_RH_SHIELD` conditions together, meaning sword and shield must be
Expand Down