Core/Items: Implemented child equipment
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user