Proper fix for 2 handed idle animation (#6109)

This commit is contained in:
Garrett Cox
2026-01-08 12:20:16 -06:00
committed by GitHub
parent d62e8108fd
commit 8584ced40b
3 changed files with 88 additions and 7 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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