mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
2004 lines
46 KiB
C++
2004 lines
46 KiB
C++
/* EQEMu: Everquest Server Emulator
|
|
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
are required to give you total support for your newly bought product;
|
|
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "inventory_profile.h"
|
|
#include "../common/data_verification.h"
|
|
//#include "classes.h"
|
|
//#include "global_define.h"
|
|
//#include "item_instance.h"
|
|
//#include "races.h"
|
|
#include "rulesys.h"
|
|
#include "shareddb.h"
|
|
#include "strings.h"
|
|
#include "evolving_items.h"
|
|
|
|
//#include "../common/light_source.h"
|
|
|
|
#include <limits.h>
|
|
|
|
//#include <iostream>
|
|
|
|
int32 next_item_serial_number = 1;
|
|
std::unordered_set<uint64> guids{};
|
|
|
|
static inline int32 GetNextItemInstSerialNumber()
|
|
{
|
|
// The Bazaar relies on each item a client has up for Trade having a unique
|
|
// identifier. This 'SerialNumber' is sent in Serialized item packets and
|
|
// is used in Bazaar packets to identify the item a player is buying or inspecting.
|
|
//
|
|
// E.g. A trader may have 3 Five dose cloudy potions, each with a different number of remaining charges
|
|
// up for sale with different prices.
|
|
//
|
|
// NextItemInstSerialNumber is the next one to hand out.
|
|
//
|
|
// It is very unlikely to reach 2,147,483,647. Maybe we should call abort(), rather than wrapping back to 1.
|
|
if (next_item_serial_number >= INT32_MAX) {
|
|
next_item_serial_number = 1;
|
|
}
|
|
else {
|
|
next_item_serial_number++;
|
|
}
|
|
|
|
while (guids.contains(next_item_serial_number)) {
|
|
next_item_serial_number++;
|
|
}
|
|
|
|
return next_item_serial_number;
|
|
}
|
|
|
|
//
|
|
// class EQ::ItemInstance
|
|
//
|
|
EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
|
|
|
|
if (item) {
|
|
m_item = new ItemData(*item);
|
|
}
|
|
|
|
m_charges = charges;
|
|
|
|
if (m_item && m_item->IsClassCommon()) {
|
|
m_color = m_item->Color;
|
|
}
|
|
|
|
if (IsEvolving()) {
|
|
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
|
|
}
|
|
|
|
m_SerialNumber = GetNextItemInstSerialNumber();
|
|
}
|
|
|
|
EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges) {
|
|
|
|
m_item = db->GetItem(item_id);
|
|
|
|
if (m_item) {
|
|
m_item = new ItemData(*m_item);
|
|
}
|
|
|
|
m_charges = charges;
|
|
|
|
if (m_item && m_item->IsClassCommon()) {
|
|
m_color = m_item->Color;
|
|
} else {
|
|
m_color = 0;
|
|
}
|
|
|
|
if (IsEvolving()) {
|
|
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
|
|
}
|
|
|
|
m_SerialNumber = GetNextItemInstSerialNumber();
|
|
}
|
|
|
|
EQ::ItemInstance::ItemInstance(ItemInstTypes use_type) {
|
|
m_use_type = use_type;
|
|
}
|
|
|
|
// Make a copy of an EQ::ItemInstance object
|
|
EQ::ItemInstance::ItemInstance(const ItemInstance& copy)
|
|
{
|
|
m_use_type = copy.m_use_type;
|
|
|
|
if (copy.m_item) {
|
|
m_item = new ItemData(*copy.m_item);
|
|
} else {
|
|
m_item = nullptr;
|
|
}
|
|
|
|
m_charges = copy.m_charges;
|
|
m_price = copy.m_price;
|
|
m_color = copy.m_color;
|
|
m_merchantslot = copy.m_merchantslot;
|
|
m_currentslot = copy.m_currentslot;
|
|
m_attuned = copy.m_attuned;
|
|
m_merchantcount = copy.m_merchantcount;
|
|
|
|
// Copy container contents
|
|
for (auto it = copy.m_contents.begin(); it != copy.m_contents.end(); ++it) {
|
|
ItemInstance* inst_old = it->second;
|
|
ItemInstance* inst_new = nullptr;
|
|
|
|
if (inst_old) {
|
|
inst_new = inst_old->Clone();
|
|
}
|
|
|
|
if (inst_new) {
|
|
m_contents[it->first] = inst_new;
|
|
}
|
|
}
|
|
|
|
std::map<std::string, std::string>::const_iterator iter;
|
|
for (iter = copy.m_custom_data.begin(); iter != copy.m_custom_data.end(); ++iter) {
|
|
m_custom_data[iter->first] = iter->second;
|
|
}
|
|
|
|
m_SerialNumber = copy.m_SerialNumber;
|
|
m_custom_data = copy.m_custom_data;
|
|
m_timers = copy.m_timers;
|
|
|
|
m_exp = copy.m_exp;
|
|
m_evolveLvl = copy.m_evolveLvl;
|
|
|
|
if (copy.m_scaledItem) {
|
|
m_scaledItem = new ItemData(*copy.m_scaledItem);
|
|
} else {
|
|
m_scaledItem = nullptr;
|
|
}
|
|
|
|
m_evolving_details = copy.m_evolving_details;
|
|
m_scaling = copy.m_scaling;
|
|
m_ornamenticon = copy.m_ornamenticon;
|
|
m_ornamentidfile = copy.m_ornamentidfile;
|
|
m_ornament_hero_model = copy.m_ornament_hero_model;
|
|
m_recast_timestamp = copy.m_recast_timestamp;
|
|
m_new_id_file = copy.m_new_id_file;
|
|
}
|
|
|
|
// Clean up container contents
|
|
EQ::ItemInstance::~ItemInstance()
|
|
{
|
|
Clear();
|
|
safe_delete(m_item);
|
|
safe_delete(m_scaledItem);
|
|
}
|
|
|
|
// Query item type
|
|
bool EQ::ItemInstance::IsType(item::ItemClass item_class) const
|
|
{
|
|
// IsType(<ItemClassTypes>) does not protect against 'm_item = nullptr'
|
|
|
|
// Check usage type
|
|
if (m_use_type == ItemInstWorldContainer && item_class == item::ItemClassBag) {
|
|
return true;
|
|
}
|
|
|
|
if (!m_item) {
|
|
return false;
|
|
}
|
|
|
|
return (m_item->ItemClass == item_class);
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsClassCommon() const
|
|
{
|
|
return (m_item && m_item->IsClassCommon());
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsClassBag() const
|
|
{
|
|
return (m_item && m_item->IsClassBag());
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsClassBook() const
|
|
{
|
|
return (m_item && m_item->IsClassBook());
|
|
}
|
|
|
|
// Is item stackable?
|
|
bool EQ::ItemInstance::IsStackable() const
|
|
{
|
|
return (m_item && m_item->Stackable);
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsCharged() const
|
|
{
|
|
if (!m_item) {
|
|
return false;
|
|
}
|
|
|
|
if (m_item->MaxCharges > 1) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Can item be equipped?
|
|
bool EQ::ItemInstance::IsEquipable(uint16 race, uint16 class_) const
|
|
{
|
|
if (!m_item || !m_item->Slots) {
|
|
return false;
|
|
}
|
|
|
|
return m_item->IsEquipable(race, class_);
|
|
}
|
|
|
|
// Can item be equipped by Class?
|
|
bool EQ::ItemInstance::IsClassEquipable(uint16 class_) const
|
|
{
|
|
if (!m_item || !m_item->Slots) {
|
|
return false;
|
|
}
|
|
|
|
return m_item->IsClassEquipable(class_);
|
|
}
|
|
|
|
// Can item be equipped by Race?
|
|
bool EQ::ItemInstance::IsRaceEquipable(uint16 race) const
|
|
{
|
|
if (!m_item || !m_item->Slots) {
|
|
return false;
|
|
}
|
|
|
|
return m_item->IsRaceEquipable(race);
|
|
}
|
|
|
|
// Can equip at this slot?
|
|
bool EQ::ItemInstance::IsEquipable(int16 slot_id) const
|
|
{
|
|
if (!m_item || !m_item->Slots) {
|
|
return false;
|
|
}
|
|
|
|
if (slot_id < EQ::invslot::EQUIPMENT_BEGIN || slot_id > EQ::invslot::EQUIPMENT_END) {
|
|
return false;
|
|
}
|
|
|
|
return ((m_item->Slots & (1 << slot_id)) != 0);
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsAugmentable() const
|
|
{
|
|
if (!m_item) {
|
|
return false;
|
|
}
|
|
|
|
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
|
if (m_item->AugSlotType[index] != 0) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool EQ::ItemInstance::AvailableWearSlot(uint32 aug_wear_slots) const {
|
|
if (!m_item || !m_item->IsClassCommon()) {
|
|
return false;
|
|
}
|
|
|
|
int index = invslot::EQUIPMENT_BEGIN;
|
|
for (; index <= invslot::EQUIPMENT_END; ++index) {
|
|
if (m_item->Slots & (1 << index)) {
|
|
if (aug_wear_slots & (1 << index)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (index <= EQ::invslot::EQUIPMENT_END);
|
|
}
|
|
|
|
int8 EQ::ItemInstance::AvailableAugmentSlot(int32 augment_type) const
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon()) {
|
|
return INVALID_INDEX;
|
|
}
|
|
|
|
for (int16 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; ++slot_id) {
|
|
if (IsAugmentSlotAvailable(augment_type, slot_id)) {
|
|
return slot_id;
|
|
}
|
|
}
|
|
|
|
return INVALID_INDEX;
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augment_type, uint8 slot) const
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon() || GetItem(slot)) {
|
|
return false;
|
|
}
|
|
|
|
return (
|
|
(
|
|
augment_type == -1 ||
|
|
(
|
|
m_item->AugSlotType[slot] &&
|
|
((1 << (m_item->AugSlotType[slot] - 1)) & augment_type)
|
|
)
|
|
) &&
|
|
(
|
|
RuleB(Items, AugmentItemAllowInvisibleAugments) ||
|
|
m_item->AugSlotVisible[slot]
|
|
)
|
|
);
|
|
}
|
|
|
|
// Retrieve item inside container
|
|
EQ::ItemInstance* EQ::ItemInstance::GetItem(uint8 index) const
|
|
{
|
|
auto it = m_contents.find(index);
|
|
if (it != m_contents.end()) {
|
|
return it->second;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
uint32 EQ::ItemInstance::GetItemID(uint8 slot) const
|
|
{
|
|
const auto item = GetItem(slot);
|
|
if (item) {
|
|
return item->GetID();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void EQ::ItemInstance::PutItem(uint8 index, const ItemInstance& inst)
|
|
{
|
|
// Clean up item already in slot (if exists)
|
|
DeleteItem(index);
|
|
|
|
// Delegate to internal method
|
|
_PutItem(index, inst.Clone());
|
|
}
|
|
|
|
// Remove item inside container
|
|
void EQ::ItemInstance::DeleteItem(uint8 index)
|
|
{
|
|
ItemInstance* inst = PopItem(index);
|
|
safe_delete(inst);
|
|
}
|
|
|
|
// Remove item from container without memory delete
|
|
// Hands over memory ownership to client of this function call
|
|
EQ::ItemInstance* EQ::ItemInstance::PopItem(uint8 index)
|
|
{
|
|
auto iter = m_contents.find(index);
|
|
if (iter != m_contents.end()) {
|
|
ItemInstance* inst = iter->second;
|
|
m_contents.erase(index);
|
|
return inst; // Return pointer that needs to be deleted (or otherwise managed)
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// Remove all items from container
|
|
void EQ::ItemInstance::Clear()
|
|
{
|
|
// Destroy container contents
|
|
for (auto iter = m_contents.begin(); iter != m_contents.end(); ++iter) {
|
|
safe_delete(iter->second);
|
|
}
|
|
m_contents.clear();
|
|
}
|
|
|
|
// Remove all items from container
|
|
void EQ::ItemInstance::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent)
|
|
{
|
|
// TODO: This needs work...
|
|
|
|
// Destroy container contents
|
|
std::map<uint8, ItemInstance*>::const_iterator cur, end, del;
|
|
cur = m_contents.begin();
|
|
end = m_contents.end();
|
|
for (; cur != end;) {
|
|
ItemInstance* inst = cur->second;
|
|
if (inst == nullptr) {
|
|
cur = m_contents.erase(cur);
|
|
continue;
|
|
}
|
|
|
|
const ItemData* item = inst->GetItem();
|
|
if (item == nullptr) {
|
|
cur = m_contents.erase(cur);
|
|
continue;
|
|
}
|
|
|
|
del = cur;
|
|
++cur;
|
|
|
|
switch (is_nodrop) {
|
|
case byFlagSet:
|
|
if (item->NoDrop == 0) {
|
|
safe_delete(inst);
|
|
m_contents.erase(del->first);
|
|
continue;
|
|
}
|
|
// no 'break;' deletes 'byFlagNotSet' type - can't add at the moment because it really *breaks* the process somewhere
|
|
case byFlagNotSet:
|
|
if (item->NoDrop != 0) {
|
|
safe_delete(inst);
|
|
m_contents.erase(del->first);
|
|
continue;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (is_norent) {
|
|
case byFlagSet:
|
|
if (item->NoRent == 0) {
|
|
safe_delete(inst);
|
|
m_contents.erase(del->first);
|
|
continue;
|
|
}
|
|
// no 'break;' deletes 'byFlagNotSet' type - can't add at the moment because it really *breaks* the process somewhere
|
|
case byFlagNotSet:
|
|
if (item->NoRent != 0) {
|
|
safe_delete(inst);
|
|
m_contents.erase(del->first);
|
|
continue;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8 EQ::ItemInstance::FirstOpenSlot() const
|
|
{
|
|
if (!m_item)
|
|
return INVALID_INDEX;
|
|
|
|
uint8 slots = m_item->BagSlots, i;
|
|
for (i = invbag::SLOT_BEGIN; i < slots; i++) {
|
|
if (!GetItem(i))
|
|
break;
|
|
}
|
|
|
|
return (i < slots) ? i : INVALID_INDEX;
|
|
}
|
|
|
|
uint8 EQ::ItemInstance::GetTotalItemCount() const
|
|
{
|
|
if (!m_item) {
|
|
return 0;
|
|
}
|
|
|
|
uint8 item_count = 1;
|
|
|
|
if (!m_item->IsClassBag()) {
|
|
return item_count;
|
|
}
|
|
|
|
for (int index = invbag::SLOT_BEGIN; index < m_item->BagSlots; ++index) {
|
|
if (GetItem(index)) {
|
|
++item_count;
|
|
}
|
|
}
|
|
|
|
return item_count;
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsNoneEmptyContainer()
|
|
{
|
|
if (!m_item || !m_item->IsClassBag())
|
|
return false;
|
|
|
|
for (int index = invbag::SLOT_BEGIN; index < m_item->BagSlots; ++index) {
|
|
if (GetItem(index))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Retrieve augment inside item
|
|
EQ::ItemInstance* EQ::ItemInstance::GetAugment(uint8 augment_index) const
|
|
{
|
|
if (m_item && m_item->IsClassCommon()) {
|
|
return GetItem(augment_index);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsOrnamentationAugment(EQ::ItemInstance* augment) const
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon() || !augment) {
|
|
return false;
|
|
}
|
|
|
|
const auto augment_item = augment->GetItem();
|
|
if (!augment_item) {
|
|
return false;
|
|
}
|
|
|
|
const std::string& idfile = augment_item->IDFile;
|
|
|
|
if (
|
|
EQ::ValueWithin(
|
|
augment->GetAugmentType(),
|
|
OrnamentationAugmentTypes::StandardOrnamentation,
|
|
OrnamentationAugmentTypes::SpecialOrnamentation
|
|
) ||
|
|
(
|
|
idfile != "IT63" &&
|
|
idfile != "IT64"
|
|
) ||
|
|
augment_item->HerosForgeModel
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAugment() const
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon()) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++) {
|
|
const auto augment = GetAugment(i);
|
|
if (augment && IsOrnamentationAugment(augment)) {
|
|
return augment;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const
|
|
{
|
|
// Not a Hero Forge item.
|
|
if (m_ornament_hero_model == 0) {
|
|
return 0;
|
|
}
|
|
|
|
// Item is using an explicit Hero Forge ID
|
|
if (m_ornament_hero_model >= 1000) {
|
|
return m_ornament_hero_model;
|
|
}
|
|
|
|
// Item is using a shorthand ID
|
|
return (m_ornament_hero_model * 100) + material_slot;
|
|
}
|
|
|
|
bool EQ::ItemInstance::UpdateOrnamentationInfo()
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon()) {
|
|
return false;
|
|
}
|
|
|
|
const auto augment = GetOrnamentationAugment();
|
|
|
|
if (augment) {
|
|
const auto augment_item = GetOrnamentationAugment()->GetItem();
|
|
|
|
if (augment_item) {
|
|
SetOrnamentIcon(augment_item->Icon);
|
|
SetOrnamentHeroModel(augment_item->HerosForgeModel);
|
|
|
|
if (strlen(augment_item->IDFile) > 2) {
|
|
SetOrnamentationIDFile(Strings::ToUnsignedInt(&augment_item->IDFile[2]));
|
|
} else {
|
|
SetOrnamentationIDFile(0);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
SetOrnamentIcon(0);
|
|
SetOrnamentHeroModel(0);
|
|
SetOrnamentationIDFile(0);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool EQ::ItemInstance::CanTransform(const ItemData *ItemToTry, const ItemData *Container, bool AllowAll) {
|
|
if (!ItemToTry || !Container) return false;
|
|
|
|
if (ItemToTry->ItemType == item::ItemTypeArrow || strnlen(Container->CharmFile, 30) == 0)
|
|
return false;
|
|
|
|
if (AllowAll && strncasecmp(Container->CharmFile, "ITEMTRANSFIGSHIELD", 18) && strncasecmp(Container->CharmFile, "ITEMTransfigBow", 15)) {
|
|
switch (ItemToTry->ItemType) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 35:
|
|
case 45:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static std::map<std::string, int> types;
|
|
types["itemtransfig1hp"] = 2;
|
|
types["itemtransfig1hs"] = 0;
|
|
types["itemtransfig2hb"] = 4;
|
|
types["itemtransfig2hp"] = 35;
|
|
types["itemtransfig2hs"] = 1;
|
|
types["itemtransfigblunt"] = 3;
|
|
types["itemtransfig1hb"] = 3;
|
|
types["itemtransfigbow"] = 5;
|
|
types["itemtransfighth"] = 45;
|
|
types["itemtransfigshield"] = 8;
|
|
types["itemtransfigslashing"] = 0;
|
|
|
|
auto i = types.find(MakeLowerString(Container->CharmFile));
|
|
if (i != types.end() && i->second == ItemToTry->ItemType)
|
|
return true;
|
|
|
|
static std::map<std::string, int> typestwo;
|
|
typestwo["itemtransfigblunt"] = 4;
|
|
typestwo["itemtransfigslashing"] = 1;
|
|
|
|
i = typestwo.find(MakeLowerString(Container->CharmFile));
|
|
if (i != typestwo.end() && i->second == ItemToTry->ItemType)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
uint32 EQ::ItemInstance::GetAugmentItemID(uint8 augment_index) const
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon()) {
|
|
return 0;
|
|
}
|
|
|
|
return GetItemID(augment_index);
|
|
}
|
|
|
|
// Add an augment to the item
|
|
void EQ::ItemInstance::PutAugment(uint8 slot, const ItemInstance& augment)
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon())
|
|
return;
|
|
|
|
PutItem(slot, augment);
|
|
}
|
|
|
|
void EQ::ItemInstance::PutAugment(SharedDatabase *db, uint8 slot, uint32 item_id)
|
|
{
|
|
if (item_id == 0) { return; }
|
|
if (db == nullptr) { return; /* TODO: add log message for nullptr */ }
|
|
|
|
const ItemInstance* aug = db->CreateItem(item_id);
|
|
if (aug) {
|
|
PutAugment(slot, *aug);
|
|
safe_delete(aug);
|
|
}
|
|
}
|
|
|
|
// Remove augment from item and destroy it
|
|
void EQ::ItemInstance::DeleteAugment(uint8 index)
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon())
|
|
return;
|
|
|
|
DeleteItem(index);
|
|
}
|
|
|
|
// Remove augment from item and return it
|
|
EQ::ItemInstance* EQ::ItemInstance::RemoveAugment(uint8 index)
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon())
|
|
return nullptr;
|
|
|
|
return PopItem(index);
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsAugmented()
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon()) {
|
|
return false;
|
|
}
|
|
|
|
for (uint8 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; ++slot_id) {
|
|
if (GetAugmentItemID(slot_id)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool EQ::ItemInstance::ContainsAugmentByID(uint32 item_id)
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon()) {
|
|
return false;
|
|
}
|
|
|
|
if (!item_id) {
|
|
return false;
|
|
}
|
|
|
|
for (uint8 augment_slot = invaug::SOCKET_BEGIN; augment_slot <= invaug::SOCKET_END; ++augment_slot) {
|
|
if (GetAugmentItemID(augment_slot) == item_id) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int EQ::ItemInstance::CountAugmentByID(uint32 item_id)
|
|
{
|
|
int quantity = 0;
|
|
if (!m_item || !m_item->IsClassCommon()) {
|
|
return quantity;
|
|
}
|
|
|
|
if (!item_id) {
|
|
return quantity;
|
|
}
|
|
|
|
for (uint8 augment_slot = invaug::SOCKET_BEGIN; augment_slot <= invaug::SOCKET_END; ++augment_slot) {
|
|
if (GetAugmentItemID(augment_slot) == item_id) {
|
|
quantity++;
|
|
}
|
|
}
|
|
|
|
return quantity;
|
|
}
|
|
|
|
// Has attack/delay?
|
|
bool EQ::ItemInstance::IsWeapon() const
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon())
|
|
return false;
|
|
|
|
if (m_item->ItemType == item::ItemTypeArrow && m_item->Damage != 0)
|
|
return true;
|
|
else
|
|
return ((m_item->Damage != 0) && (m_item->Delay != 0));
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsAmmo() const
|
|
{
|
|
if (!m_item)
|
|
return false;
|
|
|
|
if ((m_item->ItemType == item::ItemTypeArrow) ||
|
|
(m_item->ItemType == item::ItemTypeLargeThrowing) ||
|
|
(m_item->ItemType == item::ItemTypeSmallThrowing)
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const EQ::ItemData* EQ::ItemInstance::GetItem() const
|
|
{
|
|
if (!m_item)
|
|
return nullptr;
|
|
|
|
if (m_scaledItem)
|
|
return m_scaledItem;
|
|
|
|
return m_item;
|
|
}
|
|
|
|
const EQ::ItemData* EQ::ItemInstance::GetUnscaledItem() const
|
|
{
|
|
// No operator calls and defaults to nullptr
|
|
return m_item;
|
|
}
|
|
|
|
std::string EQ::ItemInstance::GetCustomDataString() const {
|
|
std::string ret_val;
|
|
auto iter = m_custom_data.begin();
|
|
while (iter != m_custom_data.end()) {
|
|
if (ret_val.length() > 0) {
|
|
ret_val += "^";
|
|
}
|
|
ret_val += iter->first;
|
|
ret_val += "^";
|
|
ret_val += iter->second;
|
|
++iter;
|
|
|
|
if (ret_val.length() > 0) {
|
|
ret_val += "^";
|
|
}
|
|
}
|
|
return ret_val;
|
|
}
|
|
|
|
void EQ::ItemInstance::SetCustomDataString(const std::string& str)
|
|
{
|
|
auto components = Strings::Split(str, "^");
|
|
auto value_count = components.size() / 2;
|
|
|
|
for (auto i = 0; i < value_count; i++) {
|
|
auto identifier = components[i * 2];
|
|
auto value = components[(i * 2) + 1];
|
|
|
|
SetCustomData(identifier, value);
|
|
}
|
|
}
|
|
|
|
std::string EQ::ItemInstance::GetCustomData(const std::string& identifier) {
|
|
std::map<std::string, std::string>::const_iterator iter = m_custom_data.find(identifier);
|
|
if (iter != m_custom_data.end()) {
|
|
return iter->second;
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
void EQ::ItemInstance::SetCustomData(const std::string& identifier, const std::string& value) {
|
|
DeleteCustomData(identifier);
|
|
m_custom_data[identifier] = value;
|
|
}
|
|
|
|
void EQ::ItemInstance::SetCustomData(const std::string& identifier, int value) {
|
|
DeleteCustomData(identifier);
|
|
std::stringstream ss;
|
|
ss << value;
|
|
m_custom_data[identifier] = ss.str();
|
|
}
|
|
|
|
void EQ::ItemInstance::SetCustomData(const std::string& identifier, float value) {
|
|
DeleteCustomData(identifier);
|
|
std::stringstream ss;
|
|
ss << value;
|
|
m_custom_data[identifier] = ss.str();
|
|
}
|
|
|
|
void EQ::ItemInstance::SetCustomData(const std::string& identifier, bool value) {
|
|
DeleteCustomData(identifier);
|
|
std::stringstream ss;
|
|
ss << value;
|
|
m_custom_data[identifier] = ss.str();
|
|
}
|
|
|
|
void EQ::ItemInstance::DeleteCustomData(const std::string& identifier) {
|
|
auto iter = m_custom_data.find(identifier);
|
|
if (iter != m_custom_data.end()) {
|
|
m_custom_data.erase(iter);
|
|
}
|
|
}
|
|
|
|
// Clone a type of EQ::ItemInstance object
|
|
// c++ doesn't allow a polymorphic copy constructor,
|
|
// so we have to resort to a polymorphic Clone()
|
|
EQ::ItemInstance* EQ::ItemInstance::Clone() const
|
|
{
|
|
// Pseudo-polymorphic copy constructor
|
|
return new ItemInstance(*this);
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsSlotAllowed(int16 slot_id) const {
|
|
if (!m_item) { return false; }
|
|
else if (InventoryProfile::SupportsContainers(slot_id)) { return true; }
|
|
else if (m_item->Slots & (1 << slot_id)) { return true; }
|
|
else if (slot_id > invslot::EQUIPMENT_END) { return true; } // why do we call 'InventoryProfile::SupportsContainers' with this here?
|
|
else { return false; }
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsDroppable(bool recurse) const
|
|
{
|
|
if (!m_item) {
|
|
return false;
|
|
}
|
|
/*if (m_ornamentidfile) // not implemented
|
|
return false;*/
|
|
if (m_attuned) {
|
|
return false;
|
|
}
|
|
|
|
if (RuleI(World, FVNoDropFlag) == FVNoDropFlagRule::Enabled && m_item->FVNoDrop == 0) {
|
|
return true;
|
|
}
|
|
|
|
if (m_item->NoDrop == 0) {
|
|
return false;
|
|
}
|
|
|
|
if (recurse) {
|
|
for (auto iter: m_contents) {
|
|
if (!iter.second) {
|
|
continue;
|
|
}
|
|
|
|
if (!iter.second->IsDroppable(recurse)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void EQ::ItemInstance::Initialize(SharedDatabase *db) {
|
|
// if there's no actual item, don't do anything
|
|
if (!m_item) {
|
|
return;
|
|
}
|
|
|
|
// initialize scaling items
|
|
if (m_item->CharmFileID != 0) {
|
|
m_scaling = true;
|
|
ScaleItem();
|
|
}
|
|
|
|
// initialize evolving items
|
|
else if (db && m_item->LoreGroup >= 1000) {
|
|
// not complete yet
|
|
}
|
|
}
|
|
|
|
void EQ::ItemInstance::ScaleItem() {
|
|
if (!m_item)
|
|
return;
|
|
|
|
if (m_scaledItem) {
|
|
memcpy(m_scaledItem, m_item, sizeof(ItemData));
|
|
}
|
|
else {
|
|
m_scaledItem = new ItemData(*m_item);
|
|
}
|
|
|
|
float Mult = (float)(GetExp()) / 10000; // scaling is determined by exp, with 10,000 being full stats
|
|
|
|
m_scaledItem->AStr = (int8)((float)m_item->AStr*Mult);
|
|
m_scaledItem->ASta = (int8)((float)m_item->ASta*Mult);
|
|
m_scaledItem->AAgi = (int8)((float)m_item->AAgi*Mult);
|
|
m_scaledItem->ADex = (int8)((float)m_item->ADex*Mult);
|
|
m_scaledItem->AInt = (int8)((float)m_item->AInt*Mult);
|
|
m_scaledItem->AWis = (int8)((float)m_item->AWis*Mult);
|
|
m_scaledItem->ACha = (int8)((float)m_item->ACha*Mult);
|
|
|
|
m_scaledItem->MR = (int8)((float)m_item->MR*Mult);
|
|
m_scaledItem->PR = (int8)((float)m_item->PR*Mult);
|
|
m_scaledItem->DR = (int8)((float)m_item->DR*Mult);
|
|
m_scaledItem->CR = (int8)((float)m_item->CR*Mult);
|
|
m_scaledItem->FR = (int8)((float)m_item->FR*Mult);
|
|
|
|
m_scaledItem->HP = (int32)((float)m_item->HP*Mult);
|
|
m_scaledItem->Mana = (int32)((float)m_item->Mana*Mult);
|
|
m_scaledItem->AC = (int32)((float)m_item->AC*Mult);
|
|
|
|
// check these..some may not need to be modified (really need to check all stats/bonuses)
|
|
//m_scaledItem->SkillModValue = (int32)((float)m_item->SkillModValue*Mult);
|
|
//m_scaledItem->BaneDmgAmt = (int8)((float)m_item->BaneDmgAmt*Mult); // watch (10 entries with charmfileid)
|
|
m_scaledItem->BardValue = (int32)((float)m_item->BardValue*Mult); // watch (no entries with charmfileid)
|
|
m_scaledItem->ElemDmgAmt = (uint8)((float)m_item->ElemDmgAmt*Mult); // watch (no entries with charmfileid)
|
|
m_scaledItem->Damage = (uint32)((float)m_item->Damage*Mult); // watch
|
|
|
|
m_scaledItem->CombatEffects = (int8)((float)m_item->CombatEffects*Mult);
|
|
m_scaledItem->Shielding = (int8)((float)m_item->Shielding*Mult);
|
|
m_scaledItem->StunResist = (int8)((float)m_item->StunResist*Mult);
|
|
m_scaledItem->StrikeThrough = (int8)((float)m_item->StrikeThrough*Mult);
|
|
m_scaledItem->ExtraDmgAmt = (uint32)((float)m_item->ExtraDmgAmt*Mult);
|
|
m_scaledItem->SpellShield = (int8)((float)m_item->SpellShield*Mult);
|
|
m_scaledItem->Avoidance = (int8)((float)m_item->Avoidance*Mult);
|
|
m_scaledItem->Accuracy = (int8)((float)m_item->Accuracy*Mult);
|
|
|
|
m_scaledItem->FactionAmt1 = (int32)((float)m_item->FactionAmt1*Mult);
|
|
m_scaledItem->FactionAmt2 = (int32)((float)m_item->FactionAmt2*Mult);
|
|
m_scaledItem->FactionAmt3 = (int32)((float)m_item->FactionAmt3*Mult);
|
|
m_scaledItem->FactionAmt4 = (int32)((float)m_item->FactionAmt4*Mult);
|
|
|
|
m_scaledItem->Endur = (uint32)((float)m_item->Endur*Mult);
|
|
m_scaledItem->DotShielding = (uint32)((float)m_item->DotShielding*Mult);
|
|
m_scaledItem->Attack = (uint32)((float)m_item->Attack*Mult);
|
|
m_scaledItem->Regen = (uint32)((float)m_item->Regen*Mult);
|
|
m_scaledItem->ManaRegen = (uint32)((float)m_item->ManaRegen*Mult);
|
|
m_scaledItem->EnduranceRegen = (uint32)((float)m_item->EnduranceRegen*Mult);
|
|
m_scaledItem->Haste = (uint32)((float)m_item->Haste*Mult);
|
|
m_scaledItem->DamageShield = (uint32)((float)m_item->DamageShield*Mult);
|
|
|
|
m_scaledItem->Purity = (uint32)((float)m_item->Purity*Mult);
|
|
m_scaledItem->BackstabDmg = (uint32)((float)m_item->BackstabDmg*Mult);
|
|
m_scaledItem->DSMitigation = (uint32)((float)m_item->DSMitigation*Mult);
|
|
m_scaledItem->HeroicStr = (int32)((float)m_item->HeroicStr*Mult);
|
|
m_scaledItem->HeroicInt = (int32)((float)m_item->HeroicInt*Mult);
|
|
m_scaledItem->HeroicWis = (int32)((float)m_item->HeroicWis*Mult);
|
|
m_scaledItem->HeroicAgi = (int32)((float)m_item->HeroicAgi*Mult);
|
|
m_scaledItem->HeroicDex = (int32)((float)m_item->HeroicDex*Mult);
|
|
m_scaledItem->HeroicSta = (int32)((float)m_item->HeroicSta*Mult);
|
|
m_scaledItem->HeroicCha = (int32)((float)m_item->HeroicCha*Mult);
|
|
m_scaledItem->HeroicMR = (int32)((float)m_item->HeroicMR*Mult);
|
|
m_scaledItem->HeroicFR = (int32)((float)m_item->HeroicFR*Mult);
|
|
m_scaledItem->HeroicCR = (int32)((float)m_item->HeroicCR*Mult);
|
|
m_scaledItem->HeroicDR = (int32)((float)m_item->HeroicDR*Mult);
|
|
m_scaledItem->HeroicPR = (int32)((float)m_item->HeroicPR*Mult);
|
|
m_scaledItem->HeroicSVCorrup = (int32)((float)m_item->HeroicSVCorrup*Mult);
|
|
m_scaledItem->HealAmt = (int32)((float)m_item->HealAmt*Mult);
|
|
m_scaledItem->SpellDmg = (int32)((float)m_item->SpellDmg*Mult);
|
|
m_scaledItem->Clairvoyance = (uint32)((float)m_item->Clairvoyance*Mult);
|
|
|
|
m_scaledItem->CharmFileID = 0; // this stops the client from trying to scale the item itself.
|
|
}
|
|
|
|
void EQ::ItemInstance::SetTimer(std::string name, uint32 time) {
|
|
Timer t(time);
|
|
t.Start(time, false);
|
|
m_timers[name] = t;
|
|
}
|
|
|
|
void EQ::ItemInstance::StopTimer(std::string name) {
|
|
auto iter = m_timers.find(name);
|
|
if(iter != m_timers.end()) {
|
|
m_timers.erase(iter);
|
|
}
|
|
}
|
|
|
|
void EQ::ItemInstance::ClearTimers() {
|
|
m_timers.clear();
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemArmorClass(bool augments) const
|
|
{
|
|
int ac = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
ac = item->AC;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
ac += GetAugment(i)->GetItemArmorClass();
|
|
}
|
|
return ac;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemElementalDamage(int &magic, int &fire, int &cold, int &poison, int &disease, int &chromatic, int &prismatic, int &physical, int &corruption, bool augments) const
|
|
{
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
switch (item->ElemDmgType) {
|
|
case RESIST_MAGIC:
|
|
magic += item->ElemDmgAmt;
|
|
break;
|
|
case RESIST_FIRE:
|
|
fire += item->ElemDmgAmt;
|
|
break;
|
|
case RESIST_COLD:
|
|
cold += item->ElemDmgAmt;
|
|
break;
|
|
case RESIST_POISON:
|
|
poison += item->ElemDmgAmt;
|
|
break;
|
|
case RESIST_DISEASE:
|
|
disease += item->ElemDmgAmt;
|
|
break;
|
|
case RESIST_CHROMATIC:
|
|
chromatic += item->ElemDmgAmt;
|
|
break;
|
|
case RESIST_PRISMATIC:
|
|
prismatic += item->ElemDmgAmt;
|
|
break;
|
|
case RESIST_PHYSICAL:
|
|
physical += item->ElemDmgAmt;
|
|
break;
|
|
case RESIST_CORRUPTION:
|
|
corruption += item->ElemDmgAmt;
|
|
break;
|
|
}
|
|
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
GetAugment(i)->GetItemElementalDamage(magic, fire, cold, poison, disease, chromatic, prismatic, physical, corruption);
|
|
}
|
|
return magic + fire + cold + poison + disease + chromatic + prismatic + physical + corruption;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemElementalFlag(bool augments) const
|
|
{
|
|
int flag = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
flag = item->ElemDmgType;
|
|
if (flag)
|
|
return flag;
|
|
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
if (GetAugment(i))
|
|
flag = GetAugment(i)->GetItemElementalFlag();
|
|
if (flag)
|
|
return flag;
|
|
}
|
|
}
|
|
}
|
|
return flag;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemElementalDamage(bool augments) const
|
|
{
|
|
int64 damage = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
damage = item->ElemDmgAmt;
|
|
if (damage)
|
|
return damage;
|
|
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
if (GetAugment(i))
|
|
damage = GetAugment(i)->GetItemElementalDamage();
|
|
if (damage)
|
|
return damage;
|
|
}
|
|
}
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemRecommendedLevel(bool augments) const
|
|
{
|
|
int level = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
level = item->RecLevel;
|
|
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
int temp = 0;
|
|
if (GetAugment(i)) {
|
|
temp = GetAugment(i)->GetItemRecommendedLevel();
|
|
if (temp > level)
|
|
level = temp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return level;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemRequiredLevel(bool augments) const
|
|
{
|
|
int level = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
level = item->ReqLevel;
|
|
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
int temp = 0;
|
|
if (GetAugment(i)) {
|
|
temp = GetAugment(i)->GetItemRequiredLevel();
|
|
if (temp > level)
|
|
level = temp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return level;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemWeaponDamage(bool augments) const
|
|
{
|
|
int64 damage = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
damage = item->Damage;
|
|
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
damage += GetAugment(i)->GetItemWeaponDamage();
|
|
}
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemBackstabDamage(bool augments) const
|
|
{
|
|
int64 damage = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
damage = item->BackstabDmg;
|
|
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
damage += GetAugment(i)->GetItemBackstabDamage();
|
|
}
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemBaneDamageBody(bool augments) const
|
|
{
|
|
int body = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
body = item->BaneDmgBody;
|
|
if (body)
|
|
return body;
|
|
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i)) {
|
|
body = GetAugment(i)->GetItemBaneDamageBody();
|
|
if (body)
|
|
return body;
|
|
}
|
|
}
|
|
}
|
|
return body;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemBaneDamageRace(bool augments) const
|
|
{
|
|
int race = Race::Doug;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
race = item->BaneDmgRace;
|
|
if (race)
|
|
return race;
|
|
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i)) {
|
|
race = GetAugment(i)->GetItemBaneDamageRace();
|
|
if (race)
|
|
return race;
|
|
}
|
|
}
|
|
}
|
|
return race;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemBaneDamageBody(uint8 against, bool augments) const
|
|
{
|
|
int64 damage = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
if (item->BaneDmgBody == against)
|
|
damage += item->BaneDmgAmt;
|
|
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
damage += GetAugment(i)->GetItemBaneDamageBody(against);
|
|
}
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemBaneDamageRace(uint16 against, bool augments) const
|
|
{
|
|
int64 damage = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
if (item->BaneDmgRace == against)
|
|
damage += item->BaneDmgRaceAmt;
|
|
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
damage += GetAugment(i)->GetItemBaneDamageRace(against);
|
|
}
|
|
}
|
|
return damage;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemMagical(bool augments) const
|
|
{
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
if (item->Magic)
|
|
return 1;
|
|
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i) && GetAugment(i)->GetItemMagical())
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHP(bool augments) const
|
|
{
|
|
int hp = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
hp = item->HP;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
hp += GetAugment(i)->GetItemHP();
|
|
}
|
|
return hp;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemMana(bool augments) const
|
|
{
|
|
int mana = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
mana = item->Mana;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
mana += GetAugment(i)->GetItemMana();
|
|
}
|
|
return mana;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemEndur(bool augments) const
|
|
{
|
|
int endur = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
endur = item->Endur;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
endur += GetAugment(i)->GetItemEndur();
|
|
}
|
|
return endur;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemAttack(bool augments) const
|
|
{
|
|
int atk = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
atk = item->Attack;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
atk += GetAugment(i)->GetItemAttack();
|
|
}
|
|
return atk;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemStr(bool augments) const
|
|
{
|
|
int str = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
str = item->AStr;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
str += GetAugment(i)->GetItemStr();
|
|
}
|
|
return str;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemSta(bool augments) const
|
|
{
|
|
int sta = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
sta = item->ASta;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
sta += GetAugment(i)->GetItemSta();
|
|
}
|
|
return sta;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemDex(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->ADex;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemDex();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemAgi(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->AAgi;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemAgi();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemInt(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->AInt;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemInt();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemWis(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->AWis;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemWis();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemCha(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->ACha;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemCha();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemMR(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->MR;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemMR();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemFR(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->FR;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemFR();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemCR(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->CR;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemCR();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemPR(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->PR;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemPR();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemDR(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->DR;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemDR();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemCorrup(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->SVCorruption;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemCorrup();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicStr(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicStr;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicStr();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicSta(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicSta;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicSta();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicDex(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicDex;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicDex();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicAgi(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicAgi;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicAgi();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicInt(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicInt;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicInt();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicWis(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicWis;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicWis();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicCha(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicCha;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicCha();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicMR(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicMR;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicMR();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicFR(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicFR;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicFR();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicCR(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicCR;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicCR();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicPR(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicPR;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicPR();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicDR(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicDR;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicDR();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHeroicCorrup(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->HeroicSVCorrup;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i))
|
|
total += GetAugment(i)->GetItemHeroicCorrup();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHaste(bool augments) const
|
|
{
|
|
int total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
total = item->Haste;
|
|
if (augments)
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i)
|
|
if (GetAugment(i)) {
|
|
int temp = GetAugment(i)->GetItemHaste();
|
|
if (temp > total)
|
|
total = temp;
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int EQ::ItemInstance::RemoveTaskDeliveredItems()
|
|
{
|
|
int count = IsStackable() ? GetCharges() : 1;
|
|
count -= GetTaskDeliveredCount();
|
|
if (IsStackable())
|
|
{
|
|
SetCharges(count);
|
|
}
|
|
SetTaskDeliveredCount(0);
|
|
return count;
|
|
}
|
|
|
|
uint32 EQ::ItemInstance::GetItemGuildFavor() const
|
|
{
|
|
uint32 total = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
return total = item->GuildFavor;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
std::vector<uint32> EQ::ItemInstance::GetAugmentIDs() const
|
|
{
|
|
std::vector<uint32> augments;
|
|
|
|
for (uint8 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; slot_id++) {
|
|
augments.push_back(GetAugment(slot_id) ? GetAugmentItemID(slot_id) : 0);
|
|
}
|
|
|
|
return augments;
|
|
}
|
|
|
|
std::vector<std::string> EQ::ItemInstance::GetAugmentNames() const
|
|
{
|
|
std::vector<std::string> augment_names;
|
|
|
|
for (uint8 slot_id = invaug::SOCKET_BEGIN; slot_id <= invaug::SOCKET_END; slot_id++) {
|
|
const auto augment = GetAugment(slot_id);
|
|
augment_names.push_back(augment ? augment->GetItem()->Name : "");
|
|
}
|
|
|
|
return augment_names;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemRegen(bool augments) const
|
|
{
|
|
int stat = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
stat = item->Regen;
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
if (GetAugment(i)) {
|
|
stat += GetAugment(i)->GetItemRegen();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemManaRegen(bool augments) const
|
|
{
|
|
int stat = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
stat = item->ManaRegen;
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
if (GetAugment(i)) {
|
|
stat += GetAugment(i)->GetItemManaRegen();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemDamageShield(bool augments) const
|
|
{
|
|
int stat = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
stat = item->DamageShield;
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
if (GetAugment(i)) {
|
|
stat += GetAugment(i)->GetItemDamageShield();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemDSMitigation(bool augments) const
|
|
{
|
|
int stat = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
stat = item->DSMitigation;
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
if (GetAugment(i)) {
|
|
stat += GetAugment(i)->GetItemDSMitigation();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemHealAmt(bool augments) const
|
|
{
|
|
int stat = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
stat = item->HealAmt;
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
if (GetAugment(i)) {
|
|
stat += GetAugment(i)->GetItemHealAmt();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemSpellDamage(bool augments) const
|
|
{
|
|
int stat = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
stat = item->SpellDmg;
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
if (GetAugment(i)) {
|
|
stat += GetAugment(i)->GetItemSpellDamage();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemClairvoyance(bool augments) const
|
|
{
|
|
int stat = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
stat = item->Clairvoyance;
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
if (GetAugment(i)) {
|
|
stat += GetAugment(i)->GetItemClairvoyance();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
int EQ::ItemInstance::GetItemSkillsStat(EQ::skills::SkillType skill, bool augments) const
|
|
{
|
|
int stat = 0;
|
|
const auto item = GetItem();
|
|
if (item) {
|
|
stat = item->ExtraDmgSkill == skill ? item->ExtraDmgAmt : 0;
|
|
if (augments) {
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; ++i) {
|
|
if (GetAugment(i)) {
|
|
stat += GetAugment(i)->GetItemSkillsStat(skill);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
void EQ::ItemInstance::AddGUIDToMap(uint64 existing_serial_number)
|
|
{
|
|
guids.emplace(existing_serial_number);
|
|
}
|
|
|
|
void EQ::ItemInstance::ClearGUIDMap()
|
|
{
|
|
guids.clear();
|
|
}
|
|
|
|
bool EQ::ItemInstance::TransferOwnership(Database &db, const uint32 to_char_id) const
|
|
{
|
|
if (!to_char_id || !IsEvolving()) {
|
|
return false;
|
|
}
|
|
|
|
SetEvolveCharID(to_char_id);
|
|
CharacterEvolvingItemsRepository::UpdateCharID(db, GetEvolveUniqueID(), to_char_id);
|
|
return true;
|
|
}
|
|
|
|
uint32 EQ::ItemInstance::GetAugmentEvolveUniqueID(uint8 augment_index) const
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon()) {
|
|
return 0;
|
|
}
|
|
|
|
const auto item = GetItem(augment_index);
|
|
if (item) {
|
|
return item->GetEvolveUniqueID();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void EQ::ItemInstance::SetTimer(std::string name, uint32 time) const{
|
|
Timer t(time);
|
|
t.Start(time, false);
|
|
m_timers[name] = t;
|
|
}
|
|
|
|
void EQ::ItemInstance::SetEvolveEquipped(const bool in) const
|
|
{
|
|
if (!IsEvolving()) {
|
|
return;
|
|
}
|
|
|
|
m_evolving_details.equipped = in;
|
|
if (in && !GetTimers().contains("evolve")) {
|
|
SetTimer("evolve", RuleI(EvolvingItems, DelayUponEquipping));
|
|
return;
|
|
}
|
|
|
|
if (in) {
|
|
GetTimers().at("evolve").SetTimer(RuleI(EvolvingItems, DelayUponEquipping));
|
|
return;
|
|
}
|
|
|
|
GetTimers().at("evolve").Disable();
|
|
}
|