mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-24 14:16:31 +00:00
351 lines
16 KiB
C++
351 lines
16 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-GPL2
|
|
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
|
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
|
*/
|
|
|
|
#ifndef AZEROTHCORE_ITEM_H
|
|
#define AZEROTHCORE_ITEM_H
|
|
|
|
#include "Common.h"
|
|
#include "Object.h"
|
|
#include "LootMgr.h"
|
|
#include "ItemTemplate.h"
|
|
#include "DatabaseEnv.h"
|
|
|
|
class SpellInfo;
|
|
class Bag;
|
|
class Unit;
|
|
|
|
struct ItemSetEffect
|
|
{
|
|
uint32 setid;
|
|
uint32 item_count;
|
|
SpellInfo const* spells[8];
|
|
};
|
|
|
|
enum InventoryResult
|
|
{
|
|
EQUIP_ERR_OK = 0,
|
|
EQUIP_ERR_CANT_EQUIP_LEVEL_I = 1,
|
|
EQUIP_ERR_CANT_EQUIP_SKILL = 2,
|
|
EQUIP_ERR_ITEM_DOESNT_GO_TO_SLOT = 3,
|
|
EQUIP_ERR_BAG_FULL = 4,
|
|
EQUIP_ERR_NONEMPTY_BAG_OVER_OTHER_BAG = 5,
|
|
EQUIP_ERR_CANT_TRADE_EQUIP_BAGS = 6,
|
|
EQUIP_ERR_ONLY_AMMO_CAN_GO_HERE = 7,
|
|
EQUIP_ERR_NO_REQUIRED_PROFICIENCY = 8,
|
|
EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE = 9,
|
|
EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM = 10,
|
|
EQUIP_ERR_YOU_CAN_NEVER_USE_THAT_ITEM2 = 11,
|
|
EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE2 = 12,
|
|
EQUIP_ERR_CANT_EQUIP_WITH_TWOHANDED = 13,
|
|
EQUIP_ERR_CANT_DUAL_WIELD = 14,
|
|
EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG = 15,
|
|
EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG2 = 16,
|
|
EQUIP_ERR_CANT_CARRY_MORE_OF_THIS = 17,
|
|
EQUIP_ERR_NO_EQUIPMENT_SLOT_AVAILABLE3 = 18,
|
|
EQUIP_ERR_ITEM_CANT_STACK = 19,
|
|
EQUIP_ERR_ITEM_CANT_BE_EQUIPPED = 20,
|
|
EQUIP_ERR_ITEMS_CANT_BE_SWAPPED = 21,
|
|
EQUIP_ERR_SLOT_IS_EMPTY = 22,
|
|
EQUIP_ERR_ITEM_NOT_FOUND = 23,
|
|
EQUIP_ERR_CANT_DROP_SOULBOUND = 24,
|
|
EQUIP_ERR_OUT_OF_RANGE = 25,
|
|
EQUIP_ERR_TRIED_TO_SPLIT_MORE_THAN_COUNT = 26,
|
|
EQUIP_ERR_COULDNT_SPLIT_ITEMS = 27,
|
|
EQUIP_ERR_MISSING_REAGENT = 28,
|
|
EQUIP_ERR_NOT_ENOUGH_MONEY = 29,
|
|
EQUIP_ERR_NOT_A_BAG = 30,
|
|
EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS = 31,
|
|
EQUIP_ERR_DONT_OWN_THAT_ITEM = 32,
|
|
EQUIP_ERR_CAN_EQUIP_ONLY1_QUIVER = 33,
|
|
EQUIP_ERR_MUST_PURCHASE_THAT_BAG_SLOT = 34,
|
|
EQUIP_ERR_TOO_FAR_AWAY_FROM_BANK = 35,
|
|
EQUIP_ERR_ITEM_LOCKED = 36,
|
|
EQUIP_ERR_YOU_ARE_STUNNED = 37,
|
|
EQUIP_ERR_YOU_ARE_DEAD = 38,
|
|
EQUIP_ERR_CANT_DO_RIGHT_NOW = 39,
|
|
EQUIP_ERR_INT_BAG_ERROR = 40,
|
|
EQUIP_ERR_CAN_EQUIP_ONLY1_BOLT = 41,
|
|
EQUIP_ERR_CAN_EQUIP_ONLY1_AMMOPOUCH = 42,
|
|
EQUIP_ERR_STACKABLE_CANT_BE_WRAPPED = 43,
|
|
EQUIP_ERR_EQUIPPED_CANT_BE_WRAPPED = 44,
|
|
EQUIP_ERR_WRAPPED_CANT_BE_WRAPPED = 45,
|
|
EQUIP_ERR_BOUND_CANT_BE_WRAPPED = 46,
|
|
EQUIP_ERR_UNIQUE_CANT_BE_WRAPPED = 47,
|
|
EQUIP_ERR_BAGS_CANT_BE_WRAPPED = 48,
|
|
EQUIP_ERR_ALREADY_LOOTED = 49,
|
|
EQUIP_ERR_INVENTORY_FULL = 50,
|
|
EQUIP_ERR_BANK_FULL = 51,
|
|
EQUIP_ERR_ITEM_IS_CURRENTLY_SOLD_OUT = 52,
|
|
EQUIP_ERR_BAG_FULL3 = 53,
|
|
EQUIP_ERR_ITEM_NOT_FOUND2 = 54,
|
|
EQUIP_ERR_ITEM_CANT_STACK2 = 55,
|
|
EQUIP_ERR_BAG_FULL4 = 56,
|
|
EQUIP_ERR_ITEM_SOLD_OUT = 57,
|
|
EQUIP_ERR_OBJECT_IS_BUSY = 58,
|
|
EQUIP_ERR_NONE = 59,
|
|
EQUIP_ERR_NOT_IN_COMBAT = 60,
|
|
EQUIP_ERR_NOT_WHILE_DISARMED = 61,
|
|
EQUIP_ERR_BAG_FULL6 = 62,
|
|
EQUIP_ERR_CANT_EQUIP_RANK = 63,
|
|
EQUIP_ERR_CANT_EQUIP_REPUTATION = 64,
|
|
EQUIP_ERR_TOO_MANY_SPECIAL_BAGS = 65,
|
|
EQUIP_ERR_LOOT_CANT_LOOT_THAT_NOW = 66,
|
|
EQUIP_ERR_ITEM_UNIQUE_EQUIPABLE = 67,
|
|
EQUIP_ERR_VENDOR_MISSING_TURNINS = 68,
|
|
EQUIP_ERR_NOT_ENOUGH_HONOR_POINTS = 69,
|
|
EQUIP_ERR_NOT_ENOUGH_ARENA_POINTS = 70,
|
|
EQUIP_ERR_ITEM_MAX_COUNT_SOCKETED = 71,
|
|
EQUIP_ERR_MAIL_BOUND_ITEM = 72,
|
|
EQUIP_ERR_NO_SPLIT_WHILE_PROSPECTING = 73,
|
|
EQUIP_ERR_ITEM_MAX_COUNT_EQUIPPED_SOCKETED = 75,
|
|
EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED = 76,
|
|
EQUIP_ERR_TOO_MUCH_GOLD = 77,
|
|
EQUIP_ERR_NOT_DURING_ARENA_MATCH = 78,
|
|
EQUIP_ERR_CANNOT_TRADE_THAT = 79,
|
|
EQUIP_ERR_PERSONAL_ARENA_RATING_TOO_LOW = 80,
|
|
EQUIP_ERR_EVENT_AUTOEQUIP_BIND_CONFIRM = 81,
|
|
EQUIP_ERR_ARTEFACTS_ONLY_FOR_OWN_CHARACTERS = 82,
|
|
// no output = 83,
|
|
EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED = 84,
|
|
EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED = 85,
|
|
EQUIP_ERR_SCALING_STAT_ITEM_LEVEL_EXCEEDED = 86,
|
|
EQUIP_ERR_PURCHASE_LEVEL_TOO_LOW = 87,
|
|
EQUIP_ERR_CANT_EQUIP_NEED_TALENT = 88,
|
|
EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED = 89
|
|
};
|
|
|
|
enum BuyResult
|
|
{
|
|
BUY_ERR_CANT_FIND_ITEM = 0,
|
|
BUY_ERR_ITEM_ALREADY_SOLD = 1,
|
|
BUY_ERR_NOT_ENOUGHT_MONEY = 2,
|
|
BUY_ERR_SELLER_DONT_LIKE_YOU = 4,
|
|
BUY_ERR_DISTANCE_TOO_FAR = 5,
|
|
BUY_ERR_ITEM_SOLD_OUT = 7,
|
|
BUY_ERR_CANT_CARRY_MORE = 8,
|
|
BUY_ERR_RANK_REQUIRE = 11,
|
|
BUY_ERR_REPUTATION_REQUIRE = 12
|
|
};
|
|
|
|
enum SellResult
|
|
{
|
|
SELL_ERR_CANT_FIND_ITEM = 1,
|
|
SELL_ERR_CANT_SELL_ITEM = 2, // merchant doesn't like that item
|
|
SELL_ERR_CANT_FIND_VENDOR = 3, // merchant doesn't like you
|
|
SELL_ERR_YOU_DONT_OWN_THAT_ITEM = 4, // you don't own that item
|
|
SELL_ERR_UNK = 5, // nothing appears...
|
|
SELL_ERR_ONLY_EMPTY_BAG = 6 // can only do with empty bags
|
|
};
|
|
|
|
// -1 from client enchantment slot number
|
|
enum EnchantmentSlot
|
|
{
|
|
PERM_ENCHANTMENT_SLOT = 0,
|
|
TEMP_ENCHANTMENT_SLOT = 1,
|
|
SOCK_ENCHANTMENT_SLOT = 2,
|
|
SOCK_ENCHANTMENT_SLOT_2 = 3,
|
|
SOCK_ENCHANTMENT_SLOT_3 = 4,
|
|
BONUS_ENCHANTMENT_SLOT = 5,
|
|
PRISMATIC_ENCHANTMENT_SLOT = 6, // added at apply special permanent enchantment
|
|
MAX_INSPECTED_ENCHANTMENT_SLOT = 7,
|
|
|
|
PROP_ENCHANTMENT_SLOT_0 = 7, // used with RandomSuffix and RandomProperty
|
|
PROP_ENCHANTMENT_SLOT_1 = 8, // used with RandomSuffix and RandomProperty
|
|
PROP_ENCHANTMENT_SLOT_2 = 9, // used with RandomSuffix and RandomProperty
|
|
PROP_ENCHANTMENT_SLOT_3 = 10, // used with RandomSuffix and RandomProperty
|
|
PROP_ENCHANTMENT_SLOT_4 = 11, // used with RandomSuffix and RandomProperty
|
|
MAX_ENCHANTMENT_SLOT = 12
|
|
};
|
|
|
|
#define MAX_VISIBLE_ITEM_OFFSET 2 // 2 fields per visible item (entry+enchantment)
|
|
|
|
#define MAX_GEM_SOCKETS MAX_ITEM_PROTO_SOCKETS// (BONUS_ENCHANTMENT_SLOT-SOCK_ENCHANTMENT_SLOT) and item proto size, equal value expected
|
|
|
|
enum EnchantmentOffset
|
|
{
|
|
ENCHANTMENT_ID_OFFSET = 0,
|
|
ENCHANTMENT_DURATION_OFFSET = 1,
|
|
ENCHANTMENT_CHARGES_OFFSET = 2 // now here not only charges, but something new in wotlk
|
|
};
|
|
|
|
#define MAX_ENCHANTMENT_OFFSET 3
|
|
|
|
enum EnchantmentSlotMask
|
|
{
|
|
ENCHANTMENT_CAN_SOULBOUND = 0x01,
|
|
ENCHANTMENT_UNK1 = 0x02,
|
|
ENCHANTMENT_UNK2 = 0x04,
|
|
ENCHANTMENT_UNK3 = 0x08
|
|
};
|
|
|
|
enum ItemUpdateState
|
|
{
|
|
ITEM_UNCHANGED = 0,
|
|
ITEM_CHANGED = 1,
|
|
ITEM_NEW = 2,
|
|
ITEM_REMOVED = 3
|
|
};
|
|
|
|
#define MAX_ITEM_SPELLS 5
|
|
|
|
bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto);
|
|
|
|
class Item : public Object
|
|
{
|
|
public:
|
|
static Item* CreateItem(uint32 item, uint32 count, Player const* player = NULL, bool clone = false, uint32 randomPropertyId = 0);
|
|
Item* CloneItem(uint32 count, Player const* player = nullptr) const;
|
|
|
|
Item();
|
|
|
|
virtual bool Create(uint32 guidlow, uint32 itemid, Player const* owner);
|
|
|
|
ItemTemplate const* GetTemplate() const;
|
|
|
|
uint64 GetOwnerGUID() const { return GetUInt64Value(ITEM_FIELD_OWNER); }
|
|
void SetOwnerGUID(uint64 guid) { SetUInt64Value(ITEM_FIELD_OWNER, guid); }
|
|
Player* GetOwner() const;
|
|
|
|
void SetBinding(bool val) { ApplyModFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND, val); }
|
|
bool IsSoulBound() const { return HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_SOULBOUND); }
|
|
bool IsBoundAccountWide() const { return (GetTemplate()->Flags & ITEM_FLAG_IS_BOUND_TO_ACCOUNT) != 0; }
|
|
bool IsBindedNotWith(Player const* player) const;
|
|
bool IsBoundByEnchant() const;
|
|
bool IsBoundByTempEnchant() const;
|
|
virtual void SaveToDB(SQLTransaction& trans);
|
|
virtual bool LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entry);
|
|
static void DeleteFromDB(SQLTransaction& trans, uint32 itemGuid);
|
|
virtual void DeleteFromDB(SQLTransaction& trans);
|
|
static void DeleteFromInventoryDB(SQLTransaction& trans, uint32 itemGuid);
|
|
void DeleteFromInventoryDB(SQLTransaction& trans);
|
|
void SaveRefundDataToDB();
|
|
void DeleteRefundDataFromDB(SQLTransaction* trans);
|
|
|
|
Bag* ToBag() { if (IsBag()) return reinterpret_cast<Bag*>(this); else return nullptr; }
|
|
const Bag* ToBag() const { if (IsBag()) return reinterpret_cast<const Bag*>(this); else return nullptr; }
|
|
|
|
bool IsLocked() const { return !HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_UNLOCKED); }
|
|
bool IsBag() const { return GetTemplate()->InventoryType == INVTYPE_BAG; }
|
|
bool IsCurrencyToken() const { return GetTemplate()->IsCurrencyToken(); }
|
|
bool IsNotEmptyBag() const;
|
|
bool IsBroken() const { return GetUInt32Value(ITEM_FIELD_MAXDURABILITY) > 0 && GetUInt32Value(ITEM_FIELD_DURABILITY) == 0; }
|
|
bool CanBeTraded(bool mail = false, bool trade = false) const;
|
|
void SetInTrade(bool b = true) { mb_in_trade = b; }
|
|
bool IsInTrade() const { return mb_in_trade; }
|
|
|
|
bool HasEnchantRequiredSkill(const Player* player) const;
|
|
uint32 GetEnchantRequiredLevel() const;
|
|
|
|
bool IsFitToSpellRequirements(SpellInfo const* spellInfo) const;
|
|
bool IsLimitedToAnotherMapOrZone(uint32 cur_mapId, uint32 cur_zoneId) const;
|
|
bool GemsFitSockets() const;
|
|
|
|
uint32 GetCount() const { return GetUInt32Value(ITEM_FIELD_STACK_COUNT); }
|
|
void SetCount(uint32 value) { SetUInt32Value(ITEM_FIELD_STACK_COUNT, value); }
|
|
uint32 GetMaxStackCount() const { return GetTemplate()->GetMaxStackSize(); }
|
|
// Checks if this item has sockets, whether built-in or added by an upgrade.
|
|
bool HasSocket() const;
|
|
uint8 GetGemCountWithID(uint32 GemID) const;
|
|
uint8 GetGemCountWithLimitCategory(uint32 limitCategory) const;
|
|
InventoryResult CanBeMergedPartlyWith(ItemTemplate const* proto) const;
|
|
|
|
uint8 GetSlot() const {return m_slot;}
|
|
Bag* GetContainer() { return m_container; }
|
|
uint8 GetBagSlot() const;
|
|
void SetSlot(uint8 slot) { m_slot = slot; }
|
|
uint16 GetPos() const { return uint16(GetBagSlot()) << 8 | GetSlot(); }
|
|
void SetContainer(Bag* container) { m_container = container; }
|
|
|
|
bool IsInBag() const { return m_container != nullptr; }
|
|
bool IsEquipped() const;
|
|
|
|
uint32 GetSkill();
|
|
uint32 GetSpell();
|
|
|
|
// RandomPropertyId (signed but stored as unsigned)
|
|
int32 GetItemRandomPropertyId() const { return GetInt32Value(ITEM_FIELD_RANDOM_PROPERTIES_ID); }
|
|
uint32 GetItemSuffixFactor() const { return GetUInt32Value(ITEM_FIELD_PROPERTY_SEED); }
|
|
void SetItemRandomProperties(int32 randomPropId);
|
|
void UpdateItemSuffixFactor();
|
|
static int32 GenerateItemRandomPropertyId(uint32 item_id);
|
|
void SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint32 charges, uint64 caster = 0);
|
|
void SetEnchantmentDuration(EnchantmentSlot slot, uint32 duration, Player* owner);
|
|
void SetEnchantmentCharges(EnchantmentSlot slot, uint32 charges);
|
|
void ClearEnchantment(EnchantmentSlot slot);
|
|
uint32 GetEnchantmentId(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_ID_OFFSET);}
|
|
uint32 GetEnchantmentDuration(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET);}
|
|
uint32 GetEnchantmentCharges(EnchantmentSlot slot) const { return GetUInt32Value(ITEM_FIELD_ENCHANTMENT_1_1 + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET);}
|
|
|
|
std::string const& GetText() const { return m_text; }
|
|
void SetText(std::string const& text) { m_text = text; }
|
|
|
|
void SendUpdateSockets();
|
|
|
|
void SendTimeUpdate(Player* owner);
|
|
void UpdateDuration(Player* owner, uint32 diff);
|
|
|
|
// spell charges (signed but stored as unsigned)
|
|
int32 GetSpellCharges(uint8 index/*0..5*/ = 0) const { return GetInt32Value(ITEM_FIELD_SPELL_CHARGES + index); }
|
|
void SetSpellCharges(uint8 index/*0..5*/, int32 value) { SetInt32Value(ITEM_FIELD_SPELL_CHARGES + index, value); }
|
|
|
|
Loot loot;
|
|
bool m_lootGenerated;
|
|
|
|
// Update States
|
|
ItemUpdateState GetState() const { return uState; }
|
|
void SetState(ItemUpdateState state, Player* forplayer = nullptr);
|
|
void AddToUpdateQueueOf(Player* player);
|
|
void RemoveFromUpdateQueueOf(Player* player);
|
|
bool IsInUpdateQueue() const { return uQueuePos != -1; }
|
|
uint32 GetQueuePos() const { return uQueuePos; }
|
|
void FSetState(ItemUpdateState state) // forced
|
|
{
|
|
uState = state;
|
|
}
|
|
|
|
bool hasQuest(uint32 quest_id) const override { return GetTemplate()->StartQuest == quest_id; }
|
|
bool hasInvolvedQuest(uint32 /*quest_id*/) const override { return false; }
|
|
bool IsPotion() const { return GetTemplate()->IsPotion(); }
|
|
bool IsWeaponVellum() const { return GetTemplate()->IsWeaponVellum(); }
|
|
bool IsArmorVellum() const { return GetTemplate()->IsArmorVellum(); }
|
|
bool IsConjuredConsumable() const { return GetTemplate()->IsConjuredConsumable(); }
|
|
|
|
// Item Refund system
|
|
void SetNotRefundable(Player* owner, bool changestate = true, SQLTransaction* trans = nullptr);
|
|
void SetRefundRecipient(uint32 pGuidLow) { m_refundRecipient = pGuidLow; }
|
|
void SetPaidMoney(uint32 money) { m_paidMoney = money; }
|
|
void SetPaidExtendedCost(uint32 iece) { m_paidExtendedCost = iece; }
|
|
uint32 GetRefundRecipient() { return m_refundRecipient; }
|
|
uint32 GetPaidMoney() { return m_paidMoney; }
|
|
uint32 GetPaidExtendedCost() { return m_paidExtendedCost; }
|
|
|
|
void UpdatePlayedTime(Player* owner);
|
|
uint32 GetPlayedTime();
|
|
bool IsRefundExpired();
|
|
|
|
// Soulbound trade system
|
|
void SetSoulboundTradeable(AllowedLooterSet& allowedLooters);
|
|
void ClearSoulboundTradeable(Player* currentOwner);
|
|
bool CheckSoulboundTradeExpire();
|
|
|
|
void BuildUpdate(UpdateDataMapType& data_map, UpdatePlayerSet&) override;
|
|
|
|
uint32 GetScriptId() const { return GetTemplate()->ScriptId; }
|
|
private:
|
|
std::string m_text;
|
|
uint8 m_slot;
|
|
Bag* m_container;
|
|
ItemUpdateState uState;
|
|
int32 uQueuePos;
|
|
bool mb_in_trade; // true if item is currently in trade-window
|
|
time_t m_lastPlayedTimeUpdate;
|
|
uint32 m_refundRecipient;
|
|
uint32 m_paidMoney;
|
|
uint32 m_paidExtendedCost;
|
|
AllowedLooterSet allowedGUIDs;
|
|
};
|
|
#endif
|