aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2025-05-23 20:09:09 +0200
committerShauren <shauren.trinity@gmail.com>2025-05-23 20:09:09 +0200
commitb610048f892e36aadabe2c75c13b2e84f4796f64 (patch)
tree47bf7104a7a7c31e53b7f37c0c0bce946c022b9e /src
parent77d20d6aba6aaa3e8413146156c3a3ea92b7bea4 (diff)
Core/Players: Fix Titan's Grip weapon type restrictions
Closes #20972 Closes #30747
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Player/Player.cpp121
-rw-r--r--src/server/game/Entities/Player/Player.h8
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
3 files changed, 72 insertions, 59 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index ff4f91cc297..739d19806bd 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -279,6 +279,8 @@ Player::Player(WorldSession* session): Unit(true)
m_canParry = false;
m_canBlock = false;
m_canTitanGrip = false;
+ m_titanGripWeaponSubclasses = 0;
+ m_titanGripArmorSubclasses = 0;
m_titanGripPenaltySpellId = 0;
m_ammoDPS = 0.0f;
@@ -9370,15 +9372,10 @@ void Player::SetSheath(SheathState sheathed)
Unit::SetSheath(sheathed); // this must visualize Sheath changing for other players...
}
-uint8 Player::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) const
+uint8 Player::FindEquipSlot(Item const* item, uint32 slot, bool swap) const
{
- uint8 playerClass = GetClass();
-
- uint8 slots[4];
- slots[0] = NULL_SLOT;
- slots[1] = NULL_SLOT;
- slots[2] = NULL_SLOT;
- slots[3] = NULL_SLOT;
+ std::array<uint8, 4> slots = { NULL_SLOT, NULL_SLOT, NULL_SLOT, NULL_SLOT };
+ ItemTemplate const* proto = item->GetTemplate();
switch (proto->InventoryType)
{
case INVTYPE_HEAD:
@@ -9443,27 +9440,7 @@ uint8 Player::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) c
break;
case INVTYPE_2HWEAPON:
slots[0] = EQUIPMENT_SLOT_MAINHAND;
- if (Item* mhWeapon = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND))
- {
- if (ItemTemplate const* mhWeaponProto = mhWeapon->GetTemplate())
- {
- if (mhWeaponProto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM || mhWeaponProto->SubClass == ITEM_SUBCLASS_WEAPON_STAFF)
- {
- const_cast<Player*>(this)->AutoUnequipOffhandIfNeed(true);
- break;
- }
- }
- }
-
- if (GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
- {
- if (proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM || proto->SubClass == ITEM_SUBCLASS_WEAPON_STAFF)
- {
- const_cast<Player*>(this)->AutoUnequipOffhandIfNeed(true);
- break;
- }
- }
- if (CanDualWield() && CanTitanGrip() && proto->SubClass != ITEM_SUBCLASS_WEAPON_POLEARM && proto->SubClass != ITEM_SUBCLASS_WEAPON_STAFF)
+ if (CanDualWield() && CanTitanGrip(item))
slots[1] = EQUIPMENT_SLOT_OFFHAND;
break;
case INVTYPE_TABARD:
@@ -9485,13 +9462,11 @@ uint8 Player::FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) c
slots[0] = EQUIPMENT_SLOT_RANGED;
break;
case INVTYPE_BAG:
- slots[0] = INVENTORY_SLOT_BAG_START + 0;
- slots[1] = INVENTORY_SLOT_BAG_START + 1;
- slots[2] = INVENTORY_SLOT_BAG_START + 2;
- slots[3] = INVENTORY_SLOT_BAG_START + 3;
+ slots = { INVENTORY_SLOT_BAG_START + 0, INVENTORY_SLOT_BAG_START + 1, INVENTORY_SLOT_BAG_START + 2, INVENTORY_SLOT_BAG_START + 3 };
break;
case INVTYPE_RELIC:
{
+ uint8 playerClass = GetClass();
switch (proto->SubClass)
{
case ITEM_SUBCLASS_ARMOR_LIBRAM:
@@ -11204,7 +11179,7 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool
if (ssd && ssd->Maxlevel < DEFAULT_MAX_LEVEL && ssd->Maxlevel < GetLevel())
return EQUIP_ERR_NOT_EQUIPPABLE;
- uint8 eslot = FindEquipSlot(pProto, slot, swap);
+ uint8 eslot = FindEquipSlot(pItem, slot, swap);
if (eslot == NULL_SLOT)
return EQUIP_ERR_NOT_EQUIPPABLE;
@@ -11274,7 +11249,7 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool
}
else if (type == INVTYPE_2HWEAPON)
{
- if (!CanDualWield() || !CanTitanGrip())
+ if (!CanDualWield() || !CanTitanGrip(pItem))
return EQUIP_ERR_2HSKILLNOTFOUND;
}
@@ -11283,17 +11258,9 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool
}
// equip two-hand weapon case (with possible unequip 2 items)
- if (type == INVTYPE_2HWEAPON)
+ if (eslot == EQUIPMENT_SLOT_MAINHAND)
{
- if (eslot == EQUIPMENT_SLOT_OFFHAND)
- {
- if (!CanTitanGrip())
- return EQUIP_ERR_NOT_EQUIPPABLE;
- }
- else if (eslot != EQUIPMENT_SLOT_MAINHAND)
- return EQUIP_ERR_NOT_EQUIPPABLE;
-
- if (!CanTitanGrip())
+ if (!CanTitanGrip(pItem))
{
// offhand item must can be stored in inventory for offhand item and it also must be unequipped
Item* offItem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
@@ -13309,18 +13276,58 @@ bool Player::IsUseEquipedWeapon(bool mainhand) const
return !IsInFeralForm() && (!mainhand || !HasUnitFlag(UNIT_FLAG_DISARMED));
}
-void Player::SetCanTitanGrip(bool value, uint32 penaltySpellId /*= 0*/)
+bool Player::CanTitanGrip(Item const* item) const
{
- if (value == m_canTitanGrip)
- return;
+ if (!m_canTitanGrip)
+ return false;
+
+ ItemTemplate const* itemTemplate = item->GetTemplate();
+ uint32 subClassMask = [&]
+ {
+ switch (itemTemplate->Class)
+ {
+ case ITEM_CLASS_WEAPON:
+ return m_titanGripWeaponSubclasses;
+ case ITEM_CLASS_ARMOR:
+ return m_titanGripArmorSubclasses;
+ default:
+ break;
+ }
+ return 0u;
+ }();
+
+ return !subClassMask || subClassMask & (1 << itemTemplate->SubClass);
+}
+
+void Player::SetCanTitanGrip(bool value, uint32 penaltySpellId /*= 0*/, int32 allowedItemClass /*= 0*/, int32 allowedItemSubClassMask /*= 0*/)
+{
m_canTitanGrip = value;
+ if (value)
+ {
+ switch (allowedItemClass)
+ {
+ case ITEM_CLASS_WEAPON:
+ m_titanGripWeaponSubclasses = allowedItemSubClassMask;
+ break;
+ case ITEM_CLASS_ARMOR:
+ m_titanGripArmorSubclasses = allowedItemSubClassMask;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ m_titanGripWeaponSubclasses = 0;
+ m_titanGripArmorSubclasses = 0;
+ }
m_titanGripPenaltySpellId = penaltySpellId;
}
void Player::CheckTitanGripPenalty()
{
- if (!CanTitanGrip())
+ if (!m_titanGripPenaltySpellId)
return;
bool apply = IsUsingTwoHandedWeaponInOneHand();
@@ -13336,7 +13343,7 @@ void Player::CheckTitanGripPenalty()
bool Player::IsTwoHandUsed() const
{
Item* mainItem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
- return mainItem && mainItem->GetTemplate()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip();
+ return mainItem && mainItem->GetTemplate()->InventoryType == INVTYPE_2HWEAPON && !CanTitanGrip(mainItem);
}
bool Player::IsUsingTwoHandedWeaponInOneHand() const
@@ -23521,13 +23528,17 @@ void Player::AutoUnequipOffhandIfNeed(bool force /*= false*/)
if (!offItem)
return;
- // unequip offhand weapon if player doesn't have dual wield anymore
- if (!CanDualWield() && (offItem->GetTemplate()->InventoryType == INVTYPE_WEAPONOFFHAND || offItem->GetTemplate()->InventoryType == INVTYPE_WEAPON))
- force = true;
+ // unequip offhand weapon if player doesn't have dual wield anymore
+ if (!CanDualWield() && (offItem->GetTemplate()->InventoryType == INVTYPE_WEAPONOFFHAND || offItem->GetTemplate()->InventoryType == INVTYPE_WEAPON))
+ force = true;
// need unequip offhand for 2h-weapon without TitanGrip (in any from hands)
- if (!force && (CanTitanGrip() || (offItem->GetTemplate()->InventoryType != INVTYPE_2HWEAPON && !IsTwoHandUsed())))
- return;
+ if (!force && CanTitanGrip(offItem))
+ {
+ Item* mainItem = GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
+ if (!mainItem || CanTitanGrip(mainItem))
+ return;
+ }
ItemPosCountVec off_dest;
if (CanStoreItem(NULL_BAG, NULL_SLOT, off_dest, offItem, false) == EQUIP_ERR_OK)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index fdb042894f8..29c98bb71d2 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1088,7 +1088,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void SetVirtualItemSlot(uint8 i, Item* item);
void SetSheath(SheathState sheathed) override; // overwrite Unit version
- uint8 FindEquipSlot(ItemTemplate const* proto, uint32 slot, bool swap) const;
+ uint8 FindEquipSlot(Item const* item, uint32 slot, bool swap) const;
uint32 GetItemCount(uint32 item, bool inBankAlso = false, Item* skipItem = nullptr) const;
uint32 GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipItem = nullptr) const;
Item* GetItemByGuid(ObjectGuid guid) const;
@@ -1875,8 +1875,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void SetCanParry(bool value);
bool CanBlock() const { return m_canBlock; }
void SetCanBlock(bool value);
- bool CanTitanGrip() const { return m_canTitanGrip; }
- void SetCanTitanGrip(bool value, uint32 penaltySpellId = 0);
+ bool CanTitanGrip(Item const* item) const;
+ void SetCanTitanGrip(bool value, uint32 penaltySpellId = 0, int32 allowedItemClass = 0, int32 allowedItemSubClassMask = 0);
void CheckTitanGripPenalty();
bool CanTameExoticPets() const { return IsGameMaster() || HasAuraType(SPELL_AURA_ALLOW_TAME_PET_TYPE); }
@@ -2440,6 +2440,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool m_canParry;
bool m_canBlock;
bool m_canTitanGrip;
+ uint32 m_titanGripWeaponSubclasses;
+ uint32 m_titanGripArmorSubclasses;
uint32 m_titanGripPenaltySpellId;
uint8 m_swingErrorMsg;
float m_ammoDPS;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 93bfda549b1..b878dbe45c1 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -5162,7 +5162,7 @@ void Spell::EffectTitanGrip()
return;
if (m_caster->GetTypeId() == TYPEID_PLAYER)
- m_caster->ToPlayer()->SetCanTitanGrip(true, effectInfo->MiscValue);
+ m_caster->ToPlayer()->SetCanTitanGrip(true, effectInfo->MiscValue, m_spellInfo->EquippedItemClass, m_spellInfo->EquippedItemSubClassMask);
}
void Spell::EffectRedirectThreat()