diff --git a/dGame/dBehaviors/ApplyBuffBehavior.cpp b/dGame/dBehaviors/ApplyBuffBehavior.cpp index 9ee48375d..627252a1c 100644 --- a/dGame/dBehaviors/ApplyBuffBehavior.cpp +++ b/dGame/dBehaviors/ApplyBuffBehavior.cpp @@ -27,7 +27,9 @@ void ApplyBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext b if (buffComponent == nullptr) return; - buffComponent->RemoveBuff(m_BuffId); + // UnCast only runs when the item (or item set) that cast the buff is unequipped. Live servers sent those + // removals with bFromUnEquip set (2014 captures: buffs 3, 4, 5, 50 and 61, all cancel_on_unequip). + buffComponent->RemoveBuff(m_BuffId, true); } void ApplyBuffBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { diff --git a/dGame/dComponents/BuffComponent.cpp b/dGame/dComponents/BuffComponent.cpp index 82b856ce0..46dd64534 100644 --- a/dGame/dComponents/BuffComponent.cpp +++ b/dGame/dComponents/BuffComponent.cpp @@ -229,6 +229,10 @@ void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity // If the buff is already scheduled to be removed, don't do it again if (iter == m_Buffs.end() || m_BuffsToRemove.contains(id)) return; + // The client only removes a buff for an unequip when it was applied with cancelOnUnequip + // (LWOBuffComponent::RemoveBuffIcon @ 00cf99b0 in 1.10.64); keep the server's copy in step with it. + if (fromUnEquip && !iter->second.cancelOnUnequip) return; + if (!ignoreRefCount && !iter->second.cancelOnRemoveBuff) { iter->second.refCount--; LOG_DEBUG("refCount for buff %i is now %i", id, iter->second.refCount); diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index d2639a3c5..ed4d60cb3 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -1160,7 +1160,7 @@ void InventoryComponent::ApplyBuff(Item* item) const { } } -// TODO Something needs to send the remove buff GameMessage as well when it is unequipping items that would remove buffs. +// Uncasting the item's equip skills sends RemoveBuff (with bFromUnEquip) for the buffs they applied, see ApplyBuffBehavior::UnCast. void InventoryComponent::RemoveBuff(Item* item) const { const auto buffs = FindBuffs(item, false); diff --git a/dGame/dGameMessages/CombatMessages.h b/dGame/dGameMessages/CombatMessages.h index 1d0df4b96..05af863f1 100644 --- a/dGame/dGameMessages/CombatMessages.h +++ b/dGame/dGameMessages/CombatMessages.h @@ -223,7 +223,8 @@ namespace GameMessages { void Serialize(RakNet::BitStream& bitStream) const override; bool Deserialize(RakNet::BitStream& bitStream) override; - // DLU always sends false: setting it makes the client ignore the message. + // With either flag set the client only removes a buff that was added with the matching cancelOnRemoveBuff / + // cancelOnUnEquip (LWOBuffComponent::RemoveBuffIcon @ 00cf99b0 in 1.10.64). bool bFromRemoveBehavior{ false }; bool bFromUnEquip{ false }; bool bRemoveImmunity{ false };