diff --git a/src/common/Common.h b/src/common/Common.h index 0cdb95bc..ce64a197 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -21,6 +21,13 @@ namespace Sapphire::Common const int32_t INVALID_GAME_OBJECT_ID = 0xE0000000; const uint64_t INVALID_GAME_OBJECT_ID64 = 0xE0000000; + /*! + * @brief The maximum length (in ms) of a combo before it is canceled/voided. + * + * The client has a combo timer of about 12 seconds, with a 0.5 second grace on top for latency considerations. + */ + const uint16_t MAX_COMBO_LENGTH = 12500; + struct FFXIVARR_POSITION3_U16 { uint16_t x; diff --git a/src/world/Actor/Chara.cpp b/src/world/Actor/Chara.cpp index 68decd9e..46edf96e 100644 --- a/src/world/Actor/Chara.cpp +++ b/src/world/Actor/Chara.cpp @@ -662,9 +662,18 @@ int64_t Sapphire::Entity::Chara::getLastUpdateTime() const void Sapphire::Entity::Chara::setLastComboActionId( uint32_t actionId ) { m_lastComboActionId = actionId; + m_lastComboActionTime = Util::getTimeMs(); } uint32_t Sapphire::Entity::Chara::getLastComboActionId() const { + // initially check for the time passed first, if it's more than the threshold just return 0 for the combo + // we can hide the implementation detail this way and it just works:tm: for anything that uses it + + if( std::difftime( Util::getTimeMs(), m_lastComboActionTime ) > Common::MAX_COMBO_LENGTH ) + { + return 0; + } + return m_lastComboActionId; } diff --git a/src/world/Actor/Chara.h b/src/world/Actor/Chara.h index eb5e5b45..97acfa09 100644 --- a/src/world/Actor/Chara.h +++ b/src/world/Actor/Chara.h @@ -103,8 +103,17 @@ namespace Sapphire::Entity uint64_t m_targetId; /*! Ptr to a queued action */ Action::ActionPtr m_pCurrentAction; - /*! the id of the last combo action used (IgnoresCombo) */ + + /*! + * @brief the id of the last combo action used (IgnoresCombo) + */ uint32_t m_lastComboActionId; + + /*! + * @brief when the last combo action was used in ms + */ + uint64_t m_lastComboActionTime; + /*! Invincibility type */ Common::InvincibilityType m_invincibilityType;