Core/Items: Implemented child equipment

This commit is contained in:
Shauren
2016-07-16 13:52:12 +02:00
parent 49202ba93c
commit 64de4b38ef
13 changed files with 764 additions and 64 deletions
@@ -0,0 +1,12 @@
--
-- Table structure for table `item_child_equipment`
--
DROP TABLE IF EXISTS `item_child_equipment`;
CREATE TABLE `item_child_equipment` (
`ID` int(10) unsigned NOT NULL DEFAULT '0',
`ItemID` int(10) unsigned NOT NULL DEFAULT '0',
`AltItemID` int(10) unsigned NOT NULL DEFAULT '0',
`AltEquipmentSlot` tinyint(3) unsigned NOT NULL DEFAULT '0',
`VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
@@ -382,6 +382,9 @@ void HotfixDatabaseConnection::DoPrepareStatements()
PrepareStatement(HOTFIX_SEL_ITEM_CLASS, "SELECT ID, PriceMod, Name, Flags FROM item_class ORDER BY ID DESC", CONNECTION_SYNCH);
PREPARE_LOCALE_STMT(HOTFIX_SEL_ITEM_CLASS, "SELECT ID, Name_lang FROM item_class_locale WHERE locale = ?", CONNECTION_SYNCH);
// ItemChildEquipment.db2
PrepareStatement(HOTFIX_SEL_ITEM_CHILD_EQUIPMENT, "SELECT ID, ItemID, AltItemID, AltEquipmentSlot FROM item_child_equipment ORDER BY ID DESC", CONNECTION_SYNCH);
// ItemCurrencyCost.db2
PrepareStatement(HOTFIX_SEL_ITEM_CURRENCY_COST, "SELECT ID, ItemId FROM item_currency_cost ORDER BY ID DESC", CONNECTION_SYNCH);
@@ -218,6 +218,8 @@ enum HotfixDatabaseStatements
HOTFIX_SEL_ITEM_CLASS,
HOTFIX_SEL_ITEM_CLASS_LOCALE,
HOTFIX_SEL_ITEM_CHILD_EQUIPMENT,
HOTFIX_SEL_ITEM_CURRENCY_COST,
HOTFIX_SEL_ITEM_DAMAGE_AMMO,
+17
View File
@@ -101,6 +101,7 @@ DB2Storage<ItemBagFamilyEntry> sItemBagFamilyStore("ItemBagFami
DB2Storage<ItemBonusEntry> sItemBonusStore("ItemBonus.db2", ItemBonusMeta::Instance(), HOTFIX_SEL_ITEM_BONUS);
DB2Storage<ItemBonusTreeNodeEntry> sItemBonusTreeNodeStore("ItemBonusTreeNode.db2", ItemBonusTreeNodeMeta::Instance(), HOTFIX_SEL_ITEM_BONUS_TREE_NODE);
DB2Storage<ItemClassEntry> sItemClassStore("ItemClass.db2", ItemClassMeta::Instance(), HOTFIX_SEL_ITEM_CLASS);
DB2Storage<ItemChildEquipmentEntry> sItemChildEquipmentStore("ItemChildEquipment.db2", ItemChildEquipmentMeta::Instance(), HOTFIX_SEL_ITEM_CHILD_EQUIPMENT);
DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore("ItemCurrencyCost.db2", ItemCurrencyCostMeta::Instance(), HOTFIX_SEL_ITEM_CURRENCY_COST);
DB2Storage<ItemDamageAmmoEntry> sItemDamageAmmoStore("ItemDamageAmmo.db2", ItemDamageAmmoMeta::Instance(), HOTFIX_SEL_ITEM_DAMAGE_AMMO);
DB2Storage<ItemDamageOneHandEntry> sItemDamageOneHandStore("ItemDamageOneHand.db2", ItemDamageOneHandMeta::Instance(), HOTFIX_SEL_ITEM_DAMAGE_ONE_HAND);
@@ -362,6 +363,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sItemBonusStore);
LOAD_DB2(sItemBonusTreeNodeStore);
LOAD_DB2(sItemClassStore);
LOAD_DB2(sItemChildEquipmentStore);
LOAD_DB2(sItemCurrencyCostStore);
LOAD_DB2(sItemDamageAmmoStore);
LOAD_DB2(sItemDamageOneHandStore);
@@ -600,6 +602,12 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
}
}
for (ItemChildEquipmentEntry const* itemChildEquipment : sItemChildEquipmentStore)
{
ASSERT(_itemChildEquipment.find(itemChildEquipment->ItemID) == _itemChildEquipment.end(), "Item must have max 1 child item.");
_itemChildEquipment[itemChildEquipment->ItemID] = itemChildEquipment;
}
for (ItemCurrencyCostEntry const* itemCurrencyCost : sItemCurrencyCostStore)
_itemsWithCurrencyCost.insert(itemCurrencyCost->ItemId);
@@ -1062,6 +1070,15 @@ std::set<uint32> DB2Manager::GetItemBonusTree(uint32 itemId, uint32 itemBonusTre
return bonusListIDs;
}
ItemChildEquipmentEntry const* DB2Manager::GetItemChildEquipment(uint32 itemId) const
{
auto itr = _itemChildEquipment.find(itemId);
if (itr != _itemChildEquipment.end())
return itr->second;
return nullptr;
}
uint32 DB2Manager::GetItemDisplayId(uint32 itemId, uint32 appearanceModId) const
{
if (ItemModifiedAppearanceEntry const* modifiedAppearance = GetItemModifiedAppearance(itemId, appearanceModId))
+3
View File
@@ -235,6 +235,7 @@ public:
typedef std::vector<ItemBonusEntry const*> ItemBonusList;
typedef std::unordered_map<uint32 /*bonusListId*/, ItemBonusList> ItemBonusListContainer;
typedef std::unordered_multimap<uint32 /*itemId*/, uint32 /*bonusTreeId*/> ItemToBonusTreeContainer;
typedef std::unordered_map<uint32 /*itemId*/, ItemChildEquipmentEntry const*> ItemChildEquipmentContainer;
typedef std::unordered_map<uint32 /*itemId | appearanceMod << 24*/, ItemModifiedAppearanceEntry const*> ItemModifiedAppearanceByItemContainer;
typedef std::unordered_map<uint32, std::set<ItemBonusTreeNodeEntry const*>> ItemBonusTreeContainer;
typedef std::unordered_map<uint32, std::vector<ItemSetSpellEntry const*>> ItemSetSpellContainer;
@@ -283,6 +284,7 @@ public:
HeirloomEntry const* GetHeirloomByItemId(uint32 itemId) const;
ItemBonusList const* GetItemBonusList(uint32 bonusListId) const;
std::set<uint32> GetItemBonusTree(uint32 itemId, uint32 itemBonusTreeMod) const;
ItemChildEquipmentEntry const* GetItemChildEquipment(uint32 itemId) const;
bool HasItemCurrencyCost(uint32 itemId) const { return _itemsWithCurrencyCost.count(itemId) > 0; }
uint32 GetItemDisplayId(uint32 itemId, uint32 appearanceModId) const;
ItemModifiedAppearanceEntry const* GetItemModifiedAppearance(uint32 itemId, uint32 appearanceModId) const;
@@ -333,6 +335,7 @@ private:
HeirloomCurvesContainer _heirloomCurvePoints;
ItemBonusListContainer _itemBonusLists;
ItemBonusTreeContainer _itemBonusTrees;
ItemChildEquipmentContainer _itemChildEquipment;
std::unordered_set<uint32> _itemsWithCurrencyCost;
ItemModifiedAppearanceByItemContainer _itemModifiedAppearancesByItem;
ItemToBonusTreeContainer _itemToBonusTree;
@@ -1182,6 +1182,14 @@ struct ItemBonusTreeNodeEntry
uint8 BonusTreeModID;
};
struct ItemChildEquipmentEntry
{
uint32 ID;
uint32 ItemID;
uint32 AltItemID;
uint8 AltEquipmentSlot;
};
struct ItemClassEntry
{
uint32 ID;
+8 -2
View File
@@ -551,9 +551,15 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
if (!ownerGuid.IsEmpty())
SetOwnerGUID(ownerGuid);
uint32 itemFlags = fields[7].GetUInt32();
bool need_save = false; // need explicit save data at load fixes
if (uint64 creator = fields[2].GetUInt64())
SetGuidValue(ITEM_FIELD_CREATOR, ObjectGuid::Create<HighGuid::Player>(creator));
{
if (!(itemFlags & ITEM_FIELD_FLAG_CHILD))
SetGuidValue(ITEM_FIELD_CREATOR, ObjectGuid::Create<HighGuid::Player>(creator));
else
SetGuidValue(ITEM_FIELD_CREATOR, ObjectGuid::Create<HighGuid::Item>(creator));
}
if (uint64 giftCreator = fields[3].GetUInt64())
SetGuidValue(ITEM_FIELD_GIFTCREATOR, ObjectGuid::Create<HighGuid::Player>(giftCreator));
SetCount(fields[4].GetUInt32());
@@ -572,7 +578,7 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
for (uint8 i = 0; i < proto->Effects.size(); ++i)
SetSpellCharges(i, atoi(tokens[i]));
SetUInt32Value(ITEM_FIELD_FLAGS, fields[7].GetUInt32());
SetUInt32Value(ITEM_FIELD_FLAGS, itemFlags);
// Remove bind flag for items vs NO_BIND set
if (IsSoulBound() && proto->GetBonding() == NO_BIND)
{
+4
View File
@@ -477,6 +477,9 @@ class TC_GAME_API Item : public Object
uint32 GetModifier(ItemModifier modifier) const;
void SetModifier(ItemModifier modifier, uint32 value);
ObjectGuid GetChildItem() const { return m_childItem; }
void SetChildItem(ObjectGuid childItem) { m_childItem = childItem; }
protected:
BonusData _bonusData;
@@ -492,5 +495,6 @@ class TC_GAME_API Item : public Object
uint32 m_paidMoney;
uint32 m_paidExtendedCost;
GuidSet allowedGUIDs;
ObjectGuid m_childItem;
};
#endif
+3 -4
View File
@@ -152,7 +152,7 @@ enum ItemFieldFlags : uint32
ITEM_FIELD_FLAG_UNK11 = 0x00010000,
ITEM_FIELD_FLAG_UNK12 = 0x00020000,
ITEM_FIELD_FLAG_UNK13 = 0x00040000,
ITEM_FIELD_FLAG_UNK14 = 0x00080000,
ITEM_FIELD_FLAG_CHILD = 0x00080000,
ITEM_FIELD_FLAG_UNK15 = 0x00100000,
ITEM_FIELD_FLAG_UNK16 = 0x00200000,
ITEM_FIELD_FLAG_UNK17 = 0x00400000,
@@ -164,9 +164,7 @@ enum ItemFieldFlags : uint32
ITEM_FIELD_FLAG_UNK23 = 0x10000000,
ITEM_FIELD_FLAG_UNK24 = 0x20000000,
ITEM_FIELD_FLAG_UNK25 = 0x40000000,
ITEM_FIELD_FLAG_UNK26 = 0x80000000,
ITEM_FIELD_FLAG_MAIL_TEXT_MASK = ITEM_FIELD_FLAG_READABLE | ITEM_FIELD_FLAG_UNK13 | ITEM_FIELD_FLAG_UNK14
ITEM_FIELD_FLAG_UNK26 = 0x80000000
};
enum ItemFlags : uint32
@@ -789,6 +787,7 @@ struct TC_GAME_API ItemTemplate
bool IsPotion() const { return GetClass() == ITEM_CLASS_CONSUMABLE && GetSubClass() == ITEM_SUBCLASS_POTION; }
bool IsVellum() const { return GetClass() == ITEM_CLASS_TRADE_GOODS && GetSubClass() == ITEM_SUBCLASS_ENCHANTMENT; }
bool IsConjuredConsumable() const { return GetClass() == ITEM_CLASS_CONSUMABLE && (GetFlags() & ITEM_FLAG_CONJURED); }
bool IsCraftingReagent() const { return (GetFlags2() & ITEM_FLAG2_CRAFTING_MATERIAL) != 0; }
bool IsRangedWeapon() const
{
+611 -15
View File
@@ -3581,6 +3581,22 @@ void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c
m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
}
for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
{
if (m_items[i] == nullptr)
continue;
m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
}
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
{
if (m_items[i] == nullptr)
continue;
m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
}
}
Unit::BuildCreateUpdateBlockForPlayer(data, target);
@@ -3607,6 +3623,22 @@ void Player::DestroyForPlayer(Player* target) const
m_items[i]->DestroyForPlayer(target);
}
for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
{
if (m_items[i] == nullptr)
continue;
m_items[i]->DestroyForPlayer(target);
}
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
{
if (m_items[i] == nullptr)
continue;
m_items[i]->DestroyForPlayer(target);
}
}
}
@@ -9296,6 +9328,24 @@ InventoryResult Player::CanUnequipItems(uint32 item, uint32 count) const
}
for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem->GetEntry() == item)
{
tempcount += pItem->GetCount();
if (tempcount >= count)
return EQUIP_ERR_OK;
}
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem->GetEntry() == item)
{
tempcount += pItem->GetCount();
if (tempcount >= count)
return EQUIP_ERR_OK;
}
for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
if (Bag* pBag = GetBagByPos(i))
for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
@@ -9348,6 +9398,28 @@ uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const
count += pItem->GetGemCountWithID(item);
}
for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem != skipItem && pItem->GetEntry() == item)
count += pItem->GetCount();
if (skipItem && skipItem->GetTemplate()->GetGemProperties())
for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem != skipItem && pItem->GetSocketColor(0))
count += pItem->GetGemCountWithID(item);
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem != skipItem && pItem->GetEntry() == item)
count += pItem->GetCount();
if (skipItem && skipItem->GetTemplate()->GetGemProperties())
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem != skipItem && pItem->GetSocketColor(0))
count += pItem->GetGemCountWithID(item);
return count;
}
@@ -9376,6 +9448,20 @@ uint32 Player::GetItemCountWithLimitCategory(uint32 limitCategory, Item* skipIte
if (Bag* pBag = GetBagByPos(i))
count += pBag->GetItemCountWithLimitCategory(limitCategory, skipItem);
for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem != skipItem)
if (ItemTemplate const* pProto = pItem->GetTemplate())
if (pProto->GetItemLimitCategory() == limitCategory)
count += pItem->GetCount();
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem != skipItem)
if (ItemTemplate const* pProto = pItem->GetTemplate())
if (pProto->GetItemLimitCategory() == limitCategory)
count += pItem->GetCount();
return count;
}
@@ -9386,7 +9472,17 @@ Item* Player::GetItemByGuid(ObjectGuid guid) const
if (pItem->GetGUID() == guid)
return pItem;
for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem->GetGUID() == guid)
return pItem;
for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem->GetGUID() == guid)
return pItem;
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem->GetGUID() == guid)
return pItem;
@@ -9417,7 +9513,7 @@ Item* Player::GetItemByPos(uint16 pos) const
Item* Player::GetItemByPos(uint8 bag, uint8 slot) const
{
if (bag == INVENTORY_SLOT_BAG_0 && slot < BANK_SLOT_BAG_END)
if (bag == INVENTORY_SLOT_BAG_0 && slot < PLAYER_SLOT_END && (slot < BUYBACK_SLOT_START || slot >= BUYBACK_SLOT_END))
return m_items[slot];
if (Bag* pBag = GetBagByPos(bag))
return pBag->GetItemByPos(slot);
@@ -9494,6 +9590,21 @@ Item* Player::GetShield(bool useable) const
return item;
}
Item* Player::GetChildItemByGuid(ObjectGuid guid) const
{
for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem->GetGUID() == guid)
return pItem;
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem->GetGUID() == guid)
return pItem;
return nullptr;
}
uint8 Player::GetAttackBySlot(uint8 slot, InventoryType inventoryType)
{
switch (slot)
@@ -9512,6 +9623,10 @@ bool Player::IsInventoryPos(uint8 bag, uint8 slot)
return true;
if (bag >= INVENTORY_SLOT_BAG_START && bag < INVENTORY_SLOT_BAG_END)
return true;
if (bag == INVENTORY_SLOT_BAG_0 && (slot >= REAGENT_SLOT_START && slot < REAGENT_SLOT_END))
return true;
if (bag == INVENTORY_SLOT_BAG_0 && (slot >= CHILD_EQUIPMENT_SLOT_START && slot < CHILD_EQUIPMENT_SLOT_END))
return true;
return false;
}
@@ -9546,6 +9661,11 @@ bool Player::IsBagPos(uint16 pos)
return false;
}
bool Player::IsChildEquipmentPos(uint8 bag, uint8 slot)
{
return bag == INVENTORY_SLOT_BAG_0 && (slot >= CHILD_EQUIPMENT_SLOT_START && slot < CHILD_EQUIPMENT_SLOT_END);
}
bool Player::IsValidPos(uint8 bag, uint8 slot, bool explicit_pos) const
{
// post selected
@@ -9657,6 +9777,28 @@ bool Player::HasItemCount(uint32 item, uint32 count, bool inBankAlso) const
}
}
for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; i++)
{
Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
{
tempcount += pItem->GetCount();
if (tempcount >= count)
return true;
}
}
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; i++)
{
Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i);
if (pItem && pItem->GetEntry() == item && !pItem->IsInTrade())
{
tempcount += pItem->GetCount();
if (tempcount >= count)
return true;
}
}
return false;
}
@@ -9826,6 +9968,20 @@ bool Player::HasItemTotemCategory(uint32 TotemCategory) const
}
}
for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
{
item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, i);
if (item && DB2Manager::IsTotemCategoryCompatibleWith(item->GetTemplate()->GetTotemCategory(), TotemCategory))
return true;
}
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
{
item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, i);
if (item && DB2Manager::IsTotemCategoryCompatibleWith(item->GetTemplate()->GetTotemCategory(), TotemCategory))
return true;
}
return false;
}
@@ -9839,8 +9995,17 @@ InventoryResult Player::CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemP
uint32 need_space;
if (pSrcItem && pSrcItem->IsNotEmptyBag() && !IsBagPos(uint16(bag) << 8 | slot))
return EQUIP_ERR_DESTROY_NONEMPTY_BAG;
if (pSrcItem)
{
if (pSrcItem->IsNotEmptyBag() && !IsBagPos(uint16(bag) << 8 | slot))
return EQUIP_ERR_DESTROY_NONEMPTY_BAG;
if (pSrcItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD) && !IsEquipmentPos(bag, slot) && !IsChildEquipmentPos(bag, slot))
return EQUIP_ERR_WRONG_BAG_TYPE_3;
if (!pSrcItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD) && IsChildEquipmentPos(bag, slot))
return EQUIP_ERR_WRONG_BAG_TYPE_3;
}
// empty specific slot - check item fit to slot
if (!pItem2 || swap)
@@ -9906,8 +10071,14 @@ InventoryResult Player::CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, Ite
if (!pBag || pBag == pSrcItem)
return EQUIP_ERR_WRONG_BAG_TYPE;
if (pSrcItem && pSrcItem->IsNotEmptyBag())
return EQUIP_ERR_DESTROY_NONEMPTY_BAG;
if (pSrcItem)
{
if (pSrcItem->IsNotEmptyBag())
return EQUIP_ERR_DESTROY_NONEMPTY_BAG;
if (pSrcItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD))
return EQUIP_ERR_WRONG_BAG_TYPE_3;
}
ItemTemplate const* pBagProto = pBag->GetTemplate();
if (!pBagProto)
@@ -10090,6 +10261,42 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des
{
if (bag == INVENTORY_SLOT_BAG_0) // inventory
{
res = CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, dest, pProto, count, true, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
{
if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
if (count == 0)
{
if (no_similar_count == 0)
return EQUIP_ERR_OK;
if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_ITEM_MAX_COUNT;
}
res = CanStoreItem_InInventorySlots(REAGENT_SLOT_START, REAGENT_SLOT_END, dest, pProto, count, true, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
{
if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
if (count == 0)
{
if (no_similar_count == 0)
return EQUIP_ERR_OK;
if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_ITEM_MAX_COUNT;
}
res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
{
@@ -10137,6 +10344,47 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des
// search free slot in bag for place to
if (bag == INVENTORY_SLOT_BAG_0) // inventory
{
if (pItem && pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD))
{
res = CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, dest, pProto, count, false, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
{
if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
if (count == 0)
{
if (no_similar_count == 0)
return EQUIP_ERR_OK;
if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_ITEM_MAX_COUNT;
}
}
else if (pProto->IsCraftingReagent() && HasFlag(PLAYER_FLAGS_EX, PLAYER_FLAGS_EX_REAGENT_BANK_UNLOCKED))
{
res = CanStoreItem_InInventorySlots(REAGENT_SLOT_START, REAGENT_SLOT_END, dest, pProto, count, false, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
{
if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
if (count == 0)
{
if (no_similar_count == 0)
return EQUIP_ERR_OK;
if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_ITEM_MAX_COUNT;
}
}
res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
{
@@ -10185,6 +10433,42 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des
// search stack for merge to
if (pProto->GetMaxStackSize() != 1)
{
res = CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, dest, pProto, count, true, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
{
if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
if (count == 0)
{
if (no_similar_count == 0)
return EQUIP_ERR_OK;
if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_ITEM_MAX_COUNT;
}
res = CanStoreItem_InInventorySlots(REAGENT_SLOT_START, REAGENT_SLOT_END, dest, pProto, count, true, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
{
if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
if (count == 0)
{
if (no_similar_count == 0)
return EQUIP_ERR_OK;
if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_ITEM_MAX_COUNT;
}
res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, true, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
{
@@ -10265,6 +10549,47 @@ InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &des
if (pItem && pItem->IsNotEmptyBag())
return EQUIP_ERR_BAG_IN_BAG;
if (pItem && pItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD))
{
res = CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, dest, pProto, count, false, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
{
if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
if (count == 0)
{
if (no_similar_count == 0)
return EQUIP_ERR_OK;
if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_ITEM_MAX_COUNT;
}
}
else if (pProto->IsCraftingReagent() && HasFlag(PLAYER_FLAGS_EX, PLAYER_FLAGS_EX_REAGENT_BANK_UNLOCKED))
{
res = CanStoreItem_InInventorySlots(REAGENT_SLOT_START, REAGENT_SLOT_END, dest, pProto, count, false, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
{
if (no_space_count)
*no_space_count = count + no_similar_count;
return res;
}
if (count == 0)
{
if (no_similar_count == 0)
return EQUIP_ERR_OK;
if (no_space_count)
*no_space_count = count + no_similar_count;
return EQUIP_ERR_ITEM_MAX_COUNT;
}
}
// search free slot
res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, INVENTORY_SLOT_ITEM_END, dest, pProto, count, false, pItem, bag, slot);
if (res != EQUIP_ERR_OK)
@@ -10662,6 +10987,46 @@ InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool
return !swap ? EQUIP_ERR_ITEM_NOT_FOUND : EQUIP_ERR_CANT_SWAP;
}
InventoryResult Player::CanEquipChildItem(Item* parentItem) const
{
Item* childItem = GetChildItemByGuid(parentItem->GetChildItem());
if (!childItem)
return EQUIP_ERR_OK;
ItemChildEquipmentEntry const* childEquipement = sDB2Manager.GetItemChildEquipment(parentItem->GetEntry());
if (!childItem)
return EQUIP_ERR_OK;
Item* dstItem = GetItemByPos(INVENTORY_SLOT_BAG_0, childEquipement->AltEquipmentSlot);
if (!dstItem)
return EQUIP_ERR_OK;
uint16 childDest = (INVENTORY_SLOT_BAG_0 << 8) | childEquipement->AltEquipmentSlot;
InventoryResult msg = CanUnequipItem(childDest, !childItem->IsBag());
if (msg != EQUIP_ERR_OK)
return msg;
// check dest->src move possibility
uint16 src = parentItem->GetPos();
ItemPosCountVec dest;
if (IsInventoryPos(src))
{
msg = CanStoreItem(parentItem->GetBagSlot(), NULL_SLOT, dest, dstItem, true);
if (msg != EQUIP_ERR_OK)
msg = CanStoreItem(NULL_BAG, NULL_SLOT, dest, dstItem, true);
}
else if (IsBankPos(src))
{
msg = CanBankItem(parentItem->GetBagSlot(), NULL_SLOT, dest, dstItem, true);
if (msg != EQUIP_ERR_OK)
msg = CanBankItem(NULL_BAG, NULL_SLOT, dest, dstItem, true);
}
else if (IsEquipmentPos(src))
return EQUIP_ERR_CANT_SWAP;
return msg;
}
InventoryResult Player::CanUnequipItem(uint16 pos, bool swap) const
{
// Applied only to equipped items and bank bags
@@ -11110,6 +11475,20 @@ Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool updat
if (addToCollection)
GetSession()->GetCollectionMgr()->OnItemAdded(item);
if (ItemChildEquipmentEntry const* childItemEntry = sDB2Manager.GetItemChildEquipment(itemId))
{
if (ItemTemplate const* childTemplate = sObjectMgr->GetItemTemplate(childItemEntry->AltItemID))
{
ItemPosCountVec childDest;
CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, childDest, childTemplate, count, false, nullptr, NULL_BAG, NULL_SLOT);
if (Item* childItem = StoreNewItem(childDest, childTemplate->GetId(), update, 0, {}, {}, addToCollection))
{
childItem->SetGuidValue(ITEM_FIELD_CREATOR, item->GetGUID());
childItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD);
}
}
}
}
return item;
}
@@ -11135,6 +11514,9 @@ Item* Player::StoreItem(ItemPosCountVec const& dest, Item* pItem, bool update)
lastItem = _StoreItem(pos, pItem, count, true, update);
}
AutoUnequipChildItem(pItem);
return lastItem;
}
@@ -11368,6 +11750,105 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
return pItem;
}
void Player::EquipChildItem(uint8 parentBag, uint8 parentSlot, Item* parentItem)
{
if (ItemChildEquipmentEntry const* itemChildEquipment = sDB2Manager.GetItemChildEquipment(parentItem->GetEntry()))
{
if (Item* childItem = GetChildItemByGuid(parentItem->GetChildItem()))
{
uint16 childDest = (INVENTORY_SLOT_BAG_0 << 8) | itemChildEquipment->AltEquipmentSlot;
if (childItem->GetPos() != childDest)
{
Item* dstItem = GetItemByPos(childDest);
if (!dstItem) // empty slot, simple case
{
RemoveItem(childItem->GetBagSlot(), childItem->GetSlot(), true);
EquipItem(childDest, childItem, true);
AutoUnequipOffhandIfNeed();
}
else // have currently equipped item, not simple case
{
uint8 dstbag = dstItem->GetBagSlot();
uint8 dstslot = dstItem->GetSlot();
InventoryResult msg = CanUnequipItem(childDest, !childItem->IsBag());
if (msg != EQUIP_ERR_OK)
{
SendEquipError(msg, dstItem);
return;
}
// check dest->src move possibility but try to store currently equipped item in the bag where the parent item is
ItemPosCountVec sSrc;
uint16 eSrc = 0;
if (IsInventoryPos(parentBag, parentSlot))
{
msg = CanStoreItem(parentBag, NULL_SLOT, sSrc, dstItem, true);
if (msg != EQUIP_ERR_OK)
msg = CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
}
else if (IsBankPos(parentBag, parentSlot))
{
msg = CanBankItem(parentBag, NULL_SLOT, sSrc, dstItem, true);
if (msg != EQUIP_ERR_OK)
msg = CanBankItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
}
else if (IsEquipmentPos(parentBag, parentSlot))
{
msg = CanEquipItem(parentSlot, eSrc, dstItem, true);
if (msg == EQUIP_ERR_OK)
msg = CanUnequipItem(eSrc, true);
}
if (msg != EQUIP_ERR_OK)
{
SendEquipError(msg, dstItem, childItem);
return;
}
// now do moves, remove...
RemoveItem(dstbag, dstslot, false);
RemoveItem(childItem->GetBagSlot(), childItem->GetSlot(), false);
// add to dest
EquipItem(childDest, childItem, true);
// add to src
if (IsInventoryPos(parentBag, parentSlot))
StoreItem(sSrc, dstItem, true);
else if (IsBankPos(parentBag, parentSlot))
BankItem(sSrc, dstItem, true);
else if (IsEquipmentPos(parentBag, parentSlot))
EquipItem(eSrc, dstItem, true);
AutoUnequipOffhandIfNeed();
}
}
}
}
}
void Player::AutoUnequipChildItem(Item* parentItem)
{
if (ItemChildEquipmentEntry const* itemChildEquipment = sDB2Manager.GetItemChildEquipment(parentItem->GetEntry()))
{
if (Item* childItem = GetChildItemByGuid(parentItem->GetChildItem()))
{
if (IsChildEquipmentPos(childItem->GetPos()))
return;
ItemPosCountVec dest;
uint32 count = childItem->GetCount();
InventoryResult result = CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, dest, childItem->GetTemplate(), count, false, childItem, NULL_BAG, NULL_SLOT);
if (result != EQUIP_ERR_OK)
return;
RemoveItem(childItem->GetBagSlot(), childItem->GetSlot(), true);
StoreItem(dest, childItem, true);
}
}
}
void Player::QuickEquipItem(uint16 pos, Item* pItem)
{
if (pItem)
@@ -11515,6 +11996,8 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update)
pItem->SetSlot(NULL_SLOT);
if (IsInWorld() && update)
pItem->SendUpdateToPlayer(this);
AutoUnequipChildItem(pItem);
}
}
@@ -11825,6 +12308,63 @@ void Player::DestroyItemCount(uint32 itemEntry, uint32 count, bool update, bool
}
}
}
for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
{
if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
if (item->GetEntry() == itemEntry && !item->IsInTrade())
{
if (item->GetCount() + remcount <= count)
{
// all keys can be unequipped
remcount += item->GetCount();
DestroyItem(INVENTORY_SLOT_BAG_0, i, update);
if (remcount >= count)
return;
}
else
{
ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
item->SetCount(item->GetCount() - count + remcount);
if (IsInWorld() && update)
item->SendUpdateToPlayer(this);
item->SetState(ITEM_CHANGED, this);
return;
}
}
}
}
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
{
if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
if (item->GetEntry() == itemEntry && !item->IsInTrade())
{
if (item->GetCount() + remcount <= count)
{
// all keys can be unequipped
remcount += item->GetCount();
DestroyItem(INVENTORY_SLOT_BAG_0, i, update);
if (remcount >= count)
return;
}
else
{
ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
item->SetCount(item->GetCount() - count + remcount);
if (IsInWorld() && update)
item->SendUpdateToPlayer(this);
item->SetState(ITEM_CHANGED, this);
return;
}
}
}
}
}
void Player::DestroyZoneLimitedItem(bool update, uint32 new_zone)
@@ -11901,6 +12441,11 @@ Item* Player::GetItemByEntry(uint32 entry) const
if (pItem->GetEntry() == entry)
return pItem;
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (pItem->GetEntry() == entry)
return pItem;
return nullptr;
}
@@ -11933,6 +12478,11 @@ std::vector<Item*> Player::GetItemListByEntry(uint32 entry, bool inBankAlso) con
itemList.push_back(item);
}
for (uint8 i = CHILD_EQUIPMENT_SLOT_START; i < CHILD_EQUIPMENT_SLOT_END; ++i)
if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
if (item->GetEntry() == entry)
itemList.push_back(item);
return itemList;
}
@@ -12091,6 +12641,33 @@ void Player::SwapItem(uint16 src, uint16 dst)
if (!pSrcItem)
return;
if (pSrcItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD))
{
if (Item* parentItem = GetItemByGuid(pSrcItem->GetGuidValue(ITEM_FIELD_CREATOR)))
{
if (IsEquipmentPos(src))
{
AutoUnequipChildItem(parentItem); // we need to unequip child first since it cannot go into whatever is going to happen next
SwapItem(dst, src); // src is now empty
SwapItem(parentItem->GetPos(), dst);// dst is now empty
return;
}
}
}
else if (pDstItem && pDstItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD))
{
if (Item* parentItem = GetItemByGuid(pDstItem->GetGuidValue(ITEM_FIELD_CREATOR)))
{
if (IsEquipmentPos(dst))
{
AutoUnequipChildItem(parentItem); // we need to unequip child first since it cannot go into whatever is going to happen next
SwapItem(src, dst); // dst is now empty
SwapItem(parentItem->GetPos(), src);// src is now empty
return;
}
}
}
TC_LOG_DEBUG("entities.player.items", "Player::SwapItem: Player '%s' (%s), Bag: %u, Slot: %u, Item: %u",
GetName().c_str(), GetGUID().ToString().c_str(), dstbag, dstslot, pSrcItem->GetEntry());
@@ -12129,7 +12706,6 @@ void Player::SwapItem(uint16 src, uint16 dst)
}
// DST checks
if (pDstItem)
{
// check unequip potability for equipped items and bank bags
@@ -12213,6 +12789,9 @@ void Player::SwapItem(uint16 src, uint16 dst)
else
return;
if (msg == EQUIP_ERR_OK && IsEquipmentPos(dst) && !pSrcItem->GetChildItem().IsEmpty())
msg = CanEquipChildItem(pSrcItem);
// can be merge/fill
if (msg == EQUIP_ERR_OK)
{
@@ -12227,6 +12806,9 @@ void Player::SwapItem(uint16 src, uint16 dst)
else if (IsEquipmentPos(dst))
{
EquipItem(eDest, pSrcItem, true);
if (!pSrcItem->GetChildItem().IsEmpty())
EquipChildItem(srcbag, srcslot, pSrcItem);
AutoUnequipOffhandIfNeed();
}
}
@@ -12284,6 +12866,9 @@ void Player::SwapItem(uint16 src, uint16 dst)
msg = CanUnequipItem(eDest2, true);
}
if (msg == EQUIP_ERR_OK && IsEquipmentPos(dst) && !pSrcItem->GetChildItem().IsEmpty())
msg = CanEquipChildItem(pSrcItem);
if (msg != EQUIP_ERR_OK)
{
SendEquipError(msg, pDstItem, pSrcItem);
@@ -12367,7 +12952,11 @@ void Player::SwapItem(uint16 src, uint16 dst)
else if (IsBankPos(dst))
BankItem(sDest, pSrcItem, true);
else if (IsEquipmentPos(dst))
{
EquipItem(eDest, pSrcItem, true);
if (!pSrcItem->GetChildItem().IsEmpty())
EquipChildItem(srcbag, srcslot, pSrcItem);
}
// add to src
if (IsInventoryPos(src))
@@ -17353,6 +17942,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
std::map<ObjectGuid, Bag*> bagMap; // fast guid lookup for bags
std::map<ObjectGuid, Item*> invalidBagMap; // fast guid lookup for bags
std::vector<Item*> childItems;
std::list<Item*> problematicItems;
SQLTransaction trans = CharacterDatabase.BeginTransaction();
@@ -17439,9 +18029,14 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
}
// Item's state may have changed after storing
if (err == EQUIP_ERR_OK)
{
item->SetState(ITEM_UNCHANGED, this);
if (item->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD))
childItems.push_back(item);
}
else
{
TC_LOG_ERROR("entities.player", "Player::_LoadInventory: Player '%s' (%s) has item (%s, entry: %u) which can't be loaded into inventory (Bag %s, slot: %u) by reason %u. Item will be sent by mail.",
@@ -17467,6 +18062,15 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
}
draft.SendMailTo(trans, this, MailSender(this, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_COPIED);
}
for (Item* childItem : childItems)
{
if (Item* parent = GetItemByGuid(childItem->GetGuidValue(ITEM_FIELD_CREATOR)))
parent->SetChildItem(childItem->GetGUID());
else
childItem->SetState(ITEM_REMOVED, this);
}
CharacterDatabase.CommitTransaction(trans);
}
//if (IsAlive())
@@ -17516,14 +18120,6 @@ void Player::_LoadVoidStorage(PreparedQueryResult result)
continue;
}
std::string name;
if (!creatorGuid.IsEmpty() && !ObjectMgr::GetPlayerNameByGUID(creatorGuid, name))
{
TC_LOG_ERROR("entities.player", "Player::_LoadVoidStorage: Player '%s' (%s) has an item with an invalid creator guid, set to 0 (item id: " UI64FMTD ", entry: %u, creator: %s).",
GetName().c_str(), GetGUID().ToString().c_str(), itemId, itemEntry, creatorGuid.ToString().c_str());
creatorGuid.Clear();
}
_voidStorageItems[slot] = new VoidStorageItem(itemId, itemEntry, creatorGuid, randomProperty, suffixFactor, upgradeId, bonusListIDs);
WorldPackets::Item::ItemInstance voidInstance;
+15 -1
View File
@@ -726,7 +726,7 @@ enum PlayerSlots
// first slot for item stored (in any way in player m_items data)
PLAYER_SLOT_START = 0,
// last+1 slot for item stored (in any way in player m_items data)
PLAYER_SLOT_END = 184,
PLAYER_SLOT_END = 187,
PLAYER_SLOTS_COUNT = (PLAYER_SLOT_END - PLAYER_SLOT_START)
};
@@ -797,6 +797,12 @@ enum ReagentSlots
REAGENT_SLOT_END = 184,
};
enum ChildEquipmentSlots
{
CHILD_EQUIPMENT_SLOT_START = 184,
CHILD_EQUIPMENT_SLOT_END = 187,
};
enum EquipmentSetUpdateState
{
EQUIPMENT_SET_UNCHANGED = 0,
@@ -1325,6 +1331,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
Bag* GetBagByPos(uint8 slot) const;
Item* GetWeaponForAttack(WeaponAttackType attackType, bool useable = false) const;
Item* GetShield(bool useable = false) const;
Item* GetChildItemByGuid(ObjectGuid guid) const;
static uint8 GetAttackBySlot(uint8 slot, InventoryType inventoryType); // MAX_ATTACK if not weapon slot
std::vector<Item*> &GetItemUpdateQueue() { return m_itemUpdateQueue; }
static bool IsInventoryPos(uint16 pos) { return IsInventoryPos(pos >> 8, pos & 255); }
@@ -1334,6 +1341,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
static bool IsBagPos(uint16 pos);
static bool IsBankPos(uint16 pos) { return IsBankPos(pos >> 8, pos & 255); }
static bool IsBankPos(uint8 bag, uint8 slot);
static bool IsChildEquipmentPos(uint16 pos) { return IsChildEquipmentPos(pos >> 8, pos & 255); }
static bool IsChildEquipmentPos(uint8 bag, uint8 slot);
bool IsValidPos(uint16 pos, bool explicit_pos) const { return IsValidPos(pos >> 8, pos & 255, explicit_pos); }
bool IsValidPos(uint8 bag, uint8 slot, bool explicit_pos) const;
uint8 GetBankBagSlotCount() const { return GetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_BANK_BAG_SLOTS); }
@@ -1351,6 +1360,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
InventoryResult CanEquipNewItem(uint8 slot, uint16& dest, uint32 item, bool swap) const;
InventoryResult CanEquipItem(uint8 slot, uint16& dest, Item* pItem, bool swap, bool not_loading = true) const;
// This method must be called before equipping parent item!
InventoryResult CanEquipChildItem(Item* parentItem) const;
InventoryResult CanEquipUniqueItem(Item* pItem, uint8 except_slot = NULL_SLOT, uint32 limit_count = 1) const;
InventoryResult CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 except_slot = NULL_SLOT, uint32 limit_count = 1) const;
InventoryResult CanUnequipItems(uint32 item, uint32 count) const;
@@ -1365,6 +1377,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
Item* EquipNewItem(uint16 pos, uint32 item, bool update);
Item* EquipItem(uint16 pos, Item* pItem, bool update);
void AutoUnequipOffhandIfNeed(bool force = false);
void EquipChildItem(uint8 parentBag, uint8 parentSlot, Item* parentItem);
void AutoUnequipChildItem(Item* parentItem);
bool StoreNewItemInBestSlots(uint32 item_id, uint32 item_count);
void AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const& store, bool broadcast = false);
void AutoStoreLoot(uint32 loot_id, LootStore const& store, bool broadcast = false) { AutoStoreLoot(NULL_BAG, NULL_SLOT, loot_id, store, broadcast); }
+77 -41
View File
@@ -201,8 +201,21 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem&
Item* dstItem = _player->GetItemByPos(dest);
if (!dstItem) // empty slot, simple case
{
if (!srcItem->GetChildItem().IsEmpty())
{
InventoryResult childEquipResult = _player->CanEquipChildItem(srcItem);
if (childEquipResult != EQUIP_ERR_OK)
{
_player->SendEquipError(msg, srcItem);
return;
}
}
_player->RemoveItem(autoEquipItem.PackSlot, autoEquipItem.Slot, true);
_player->EquipItem(dest, srcItem, true);
if (!srcItem->GetChildItem().IsEmpty())
_player->EquipChildItem(autoEquipItem.PackSlot, autoEquipItem.Slot, srcItem);
_player->AutoUnequipOffhandIfNeed();
}
else // have currently equipped item, not simple case
@@ -217,52 +230,75 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem&
return;
}
// check dest->src move possibility
ItemPosCountVec sSrc;
uint16 eSrc = 0;
if (_player->IsInventoryPos(src))
if (!dstItem->HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD))
{
msg = _player->CanStoreItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true);
// check dest->src move possibility
ItemPosCountVec sSrc;
uint16 eSrc = 0;
if (_player->IsInventoryPos(src))
{
msg = _player->CanStoreItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true);
if (msg != EQUIP_ERR_OK)
msg = _player->CanStoreItem(autoEquipItem.PackSlot, NULL_SLOT, sSrc, dstItem, true);
if (msg != EQUIP_ERR_OK)
msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
}
else if (_player->IsBankPos(src))
{
msg = _player->CanBankItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true);
if (msg != EQUIP_ERR_OK)
msg = _player->CanBankItem(autoEquipItem.PackSlot, NULL_SLOT, sSrc, dstItem, true);
if (msg != EQUIP_ERR_OK)
msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
}
else if (_player->IsEquipmentPos(src))
{
msg = _player->CanEquipItem(autoEquipItem.Slot, eSrc, dstItem, true);
if (msg == EQUIP_ERR_OK)
msg = _player->CanUnequipItem(eSrc, true);
}
if (msg == EQUIP_ERR_OK && Player::IsEquipmentPos(dest) && !srcItem->GetChildItem().IsEmpty())
msg = _player->CanEquipChildItem(srcItem);
if (msg != EQUIP_ERR_OK)
msg = _player->CanStoreItem(autoEquipItem.PackSlot, NULL_SLOT, sSrc, dstItem, true);
if (msg != EQUIP_ERR_OK)
msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
{
_player->SendEquipError(msg, dstItem, srcItem);
return;
}
// now do moves, remove...
_player->RemoveItem(dstbag, dstslot, false);
_player->RemoveItem(autoEquipItem.PackSlot, autoEquipItem.Slot, false);
// add to dest
_player->EquipItem(dest, srcItem, true);
// add to src
if (_player->IsInventoryPos(src))
_player->StoreItem(sSrc, dstItem, true);
else if (_player->IsBankPos(src))
_player->BankItem(sSrc, dstItem, true);
else if (_player->IsEquipmentPos(src))
_player->EquipItem(eSrc, dstItem, true);
if (Player::IsEquipmentPos(dest) && !srcItem->GetChildItem().IsEmpty())
_player->EquipChildItem(autoEquipItem.PackSlot, autoEquipItem.Slot, srcItem);
}
else if (_player->IsBankPos(src))
else
{
msg = _player->CanBankItem(autoEquipItem.PackSlot, autoEquipItem.Slot, sSrc, dstItem, true);
if (msg != EQUIP_ERR_OK)
msg = _player->CanBankItem(autoEquipItem.PackSlot, NULL_SLOT, sSrc, dstItem, true);
if (msg != EQUIP_ERR_OK)
msg = _player->CanBankItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
if (Item* parentItem = _player->GetItemByGuid(dstItem->GetGuidValue(ITEM_FIELD_CREATOR)))
{
if (Player::IsEquipmentPos(dest))
{
_player->AutoUnequipChildItem(parentItem);
// dest is now empty
_player->SwapItem(src, dest);
// src is now empty
_player->SwapItem(parentItem->GetPos(), src);
}
}
}
else if (_player->IsEquipmentPos(src))
{
msg = _player->CanEquipItem(autoEquipItem.Slot, eSrc, dstItem, true);
if (msg == EQUIP_ERR_OK)
msg = _player->CanUnequipItem(eSrc, true);
}
if (msg != EQUIP_ERR_OK)
{
_player->SendEquipError(msg, dstItem, srcItem);
return;
}
// now do moves, remove...
_player->RemoveItem(dstbag, dstslot, false);
_player->RemoveItem(autoEquipItem.PackSlot, autoEquipItem.Slot, false);
// add to dest
_player->EquipItem(dest, srcItem, true);
// add to src
if (_player->IsInventoryPos(src))
_player->StoreItem(sSrc, dstItem, true);
else if (_player->IsBankPos(src))
_player->BankItem(sSrc, dstItem, true);
else if (_player->IsEquipmentPos(src))
_player->EquipItem(eSrc, dstItem, true);
_player->AutoUnequipOffhandIfNeed();
}
+1 -1
View File
@@ -635,7 +635,7 @@ void WorldSession::HandleMailCreateTextItem(WorldPackets::Mail::MailCreateTextIt
if (m->messageType == MAIL_NORMAL)
bodyItem->SetGuidValue(ITEM_FIELD_CREATOR, ObjectGuid::Create<HighGuid::Player>(m->sender));
bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_MAIL_TEXT_MASK);
bodyItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_READABLE);
ItemPosCountVec dest;
uint8 msg = _player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, bodyItem, false);