mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 01:11:29 +00:00
This restores sending items to EVENT_TRADE that are updated by source
controlled delivery tasks which was removed in 7cf96ca2d8.
That patch filtered out items consumed by task updates to fix a few bugs
with items being returned despite incrementing a task:
- If an npc without a quest trade event handler was the target of a
delivery task for a NoDrop/non-Quest item, the npc would auto return
it due to the `ReturnNonQuestNoDropItems` rule.
- If an npc without a quest trade event handler was the target of a
delivery task for a non-NoDrop item, the item would be added to the
npc's loot.
- If an npc with an EVENT_ITEM/EVENT_TRADE quest handler used the Lua
or Perl trade plugins, the plugins would return task items unless
specific checks for the turned in slots existed.
The quest plugin item returns are problematic for this since they just
summon to return items not handled by the script
e.g. For a task to deliver N Large Fruit Bat Wings (item id 19616),
if a player turned in 1 Wing in slot 1 and a stack of 20 Wings in slot
2, the task would be incremented 21 times and the following Lua trade
handler would return the stack of 20 from the 2nd trade slot:
```lua
function event_trade(e)
local item_lib = require("items")
if item_lib.check_turn_in(e.trade, { item1 = 19616 }) then
eq.debug("Lua consumed 1 slot and will return other slots")
end
item_lib.return_items(e.self, e.other, e.trade)
end
```
This also occured with the perl plugin though slightly differently
since that plugin returns all slots unless the exact handin slot count
matches (requiring check_handin conditions for all slots):
```perl
sub EVENT_ITEM {
if (plugin::check_handin(\%itemcount, 19616 => 1)) {
# No issue if only one slot used for trade (item not returned)
}
# Perl fails handin check if multiple slots not checked and returns all
plugin::return_items(\%itemcount);
}
```
While that patch solved the issue, it's inconvenient and wrong to not
receive items in trade events used in a source task update. It breaks
existing trade scripts for tasks that aren't quest controlled and it
forces tasks to be changed to quest controlled and manually updated to
script any extra behavior.
This patch stores the task update count on the item instance before
dispatching it to quests. The burden is now on quests and plugins to
use that value in order to prevent returning items consumed by tasks.
`ItemInstance::RemoveTaskDeliveredItems` has been added to simplify
handling this in plugins which is also used for non-quest item returns.
1761 lines
42 KiB
C++
1761 lines
42 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 "classes.h"
|
|
//#include "global_define.h"
|
|
//#include "item_instance.h"
|
|
//#include "races.h"
|
|
#include "rulesys.h"
|
|
#include "shareddb.h"
|
|
#include "strings.h"
|
|
|
|
//#include "../common/light_source.h"
|
|
|
|
#include <limits.h>
|
|
|
|
//#include <iostream>
|
|
|
|
int32 NextItemInstSerialNumber = 1;
|
|
|
|
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(NextItemInstSerialNumber >= INT_MAX)
|
|
NextItemInstSerialNumber = 1;
|
|
else
|
|
NextItemInstSerialNumber++;
|
|
|
|
return NextItemInstSerialNumber;
|
|
}
|
|
|
|
//
|
|
// class EQ::ItemInstance
|
|
//
|
|
EQ::ItemInstance::ItemInstance(const ItemData* item, int16 charges) {
|
|
m_use_type = ItemInstNormal;
|
|
if(item) {
|
|
m_item = new ItemData(*item);
|
|
} else {
|
|
m_item = nullptr;
|
|
}
|
|
m_charges = charges;
|
|
m_price = 0;
|
|
m_attuned = false;
|
|
m_merchantslot = 0;
|
|
if (m_item && m_item->IsClassCommon())
|
|
m_color = m_item->Color;
|
|
else
|
|
m_color = 0;
|
|
m_merchantcount = 1;
|
|
m_SerialNumber = GetNextItemInstSerialNumber();
|
|
|
|
m_exp = 0;
|
|
m_evolveLvl = 0;
|
|
m_activated = false;
|
|
m_scaledItem = nullptr;
|
|
m_evolveInfo = nullptr;
|
|
m_scaling = false;
|
|
m_ornamenticon = 0;
|
|
m_ornamentidfile = 0;
|
|
m_ornament_hero_model = 0;
|
|
m_recast_timestamp = 0;
|
|
m_new_id_file = 0;
|
|
}
|
|
|
|
EQ::ItemInstance::ItemInstance(SharedDatabase *db, uint32 item_id, int16 charges) {
|
|
m_use_type = ItemInstNormal;
|
|
m_item = db->GetItem(item_id);
|
|
if(m_item) {
|
|
m_item = new ItemData(*m_item);
|
|
}
|
|
else {
|
|
m_item = nullptr;
|
|
}
|
|
|
|
m_charges = charges;
|
|
m_price = 0;
|
|
m_merchantslot = 0;
|
|
m_attuned=false;
|
|
if (m_item && m_item->IsClassCommon())
|
|
m_color = m_item->Color;
|
|
else
|
|
m_color = 0;
|
|
m_merchantcount = 1;
|
|
m_SerialNumber = GetNextItemInstSerialNumber();
|
|
|
|
m_exp = 0;
|
|
m_evolveLvl = 0;
|
|
m_activated = false;
|
|
m_scaledItem = nullptr;
|
|
m_evolveInfo = nullptr;
|
|
m_scaling = false;
|
|
m_ornamenticon = 0;
|
|
m_ornamentidfile = 0;
|
|
m_ornament_hero_model = 0;
|
|
m_recast_timestamp = 0;
|
|
m_new_id_file = 0;
|
|
}
|
|
|
|
EQ::ItemInstance::ItemInstance(ItemInstTypes use_type) {
|
|
m_use_type = use_type;
|
|
m_item = nullptr;
|
|
m_charges = 0;
|
|
m_price = 0;
|
|
m_attuned = false;
|
|
m_merchantslot = 0;
|
|
m_color = 0;
|
|
|
|
m_exp = 0;
|
|
m_evolveLvl = 0;
|
|
m_activated = false;
|
|
m_scaledItem = nullptr;
|
|
m_evolveInfo = nullptr;
|
|
m_scaling = false;
|
|
m_ornamenticon = 0;
|
|
m_ornamentidfile = 0;
|
|
m_ornament_hero_model = 0;
|
|
m_recast_timestamp = 0;
|
|
m_new_id_file = 0;
|
|
}
|
|
|
|
// 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 != nullptr) {
|
|
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;
|
|
m_activated = copy.m_activated;
|
|
if (copy.m_scaledItem)
|
|
m_scaledItem = new ItemData(*copy.m_scaledItem);
|
|
else
|
|
m_scaledItem = nullptr;
|
|
|
|
if(copy.m_evolveInfo)
|
|
m_evolveInfo = new EvolveInfo(*copy.m_evolveInfo);
|
|
else
|
|
m_evolveInfo = nullptr;
|
|
|
|
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);
|
|
safe_delete(m_evolveInfo);
|
|
}
|
|
|
|
// 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
|
|
{
|
|
if (!m_item)
|
|
return false;
|
|
|
|
return 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 == 0))
|
|
return false;
|
|
|
|
return m_item->IsEquipable(race, class_);
|
|
}
|
|
|
|
// Can equip at this slot?
|
|
bool EQ::ItemInstance::IsEquipable(int16 slot_id) const
|
|
{
|
|
if (!m_item)
|
|
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 augtype) const
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon())
|
|
return INVALID_INDEX;
|
|
|
|
int index = invaug::SOCKET_BEGIN;
|
|
for (; index <= invaug::SOCKET_END; ++index) {
|
|
if (GetItem(index)) { continue; }
|
|
if (augtype == -1 || (m_item->AugSlotType[index] && ((1 << (m_item->AugSlotType[index] - 1)) & augtype)))
|
|
break;
|
|
}
|
|
|
|
return (index <= invaug::SOCKET_END) ? index : INVALID_INDEX;
|
|
}
|
|
|
|
bool EQ::ItemInstance::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon())
|
|
return false;
|
|
|
|
if ((!GetItem(slot) && m_item->AugSlotVisible[slot]) && augtype == -1 || (m_item->AugSlotType[slot] && ((1 << (m_item->AugSlotType[slot] - 1)) & augtype))) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// 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
|
|
{
|
|
ItemInstance *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 && !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 slot) const
|
|
{
|
|
if (m_item && m_item->IsClassCommon())
|
|
return GetItem(slot);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
EQ::ItemInstance* EQ::ItemInstance::GetOrnamentationAug(int32 ornamentationAugtype) const
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon()) { return nullptr; }
|
|
if (ornamentationAugtype == 0) { return nullptr; }
|
|
|
|
for (int i = invaug::SOCKET_BEGIN; i <= invaug::SOCKET_END; i++)
|
|
{
|
|
if (GetAugment(i) && m_item->AugSlotType[i] == ornamentationAugtype)
|
|
{
|
|
const char *item_IDFile = GetAugment(i)->GetItem()->IDFile;
|
|
if (
|
|
(strncmp(item_IDFile, "IT64", strlen(item_IDFile)) == 0
|
|
|| strncmp(item_IDFile, "IT63", strlen(item_IDFile)) == 0)
|
|
&& GetAugment(i)->GetItem()->HerosForgeModel == 0
|
|
)
|
|
{
|
|
continue;
|
|
}
|
|
return GetAugment(i);
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
uint32 EQ::ItemInstance::GetOrnamentHeroModel(int32 material_slot) const {
|
|
// Not a Hero Forge item.
|
|
if (m_ornament_hero_model == 0 || material_slot < 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;
|
|
|
|
bool ornamentSet = false;
|
|
|
|
int32 ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
|
|
if (GetOrnamentationAug(ornamentationAugtype))
|
|
{
|
|
const ItemData* ornamentItem;
|
|
ornamentItem = GetOrnamentationAug(ornamentationAugtype)->GetItem();
|
|
if (ornamentItem != nullptr)
|
|
{
|
|
SetOrnamentIcon(ornamentItem->Icon);
|
|
SetOrnamentHeroModel(ornamentItem->HerosForgeModel);
|
|
if (strlen(ornamentItem->IDFile) > 2)
|
|
{
|
|
SetOrnamentationIDFile(atoi(&ornamentItem->IDFile[2]));
|
|
}
|
|
else
|
|
{
|
|
SetOrnamentationIDFile(0);
|
|
}
|
|
ornamentSet = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetOrnamentIcon(0);
|
|
SetOrnamentHeroModel(0);
|
|
SetOrnamentationIDFile(0);
|
|
}
|
|
|
|
return ornamentSet;
|
|
}
|
|
|
|
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 slot) const
|
|
{
|
|
if (!m_item || !m_item->IsClassCommon())
|
|
return 0;
|
|
|
|
return GetItemID(slot);
|
|
}
|
|
|
|
// 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 (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
|
if (GetAugmentItemID(index))
|
|
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;
|
|
}
|
|
|
|
std::string EQ::ItemInstance::GetCustomData(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(std::string identifier, std::string value) {
|
|
DeleteCustomData(identifier);
|
|
m_custom_data[identifier] = value;
|
|
}
|
|
|
|
void EQ::ItemInstance::SetCustomData(std::string identifier, int value) {
|
|
DeleteCustomData(identifier);
|
|
std::stringstream ss;
|
|
ss << value;
|
|
m_custom_data[identifier] = ss.str();
|
|
}
|
|
|
|
void EQ::ItemInstance::SetCustomData(std::string identifier, float value) {
|
|
DeleteCustomData(identifier);
|
|
std::stringstream ss;
|
|
ss << value;
|
|
m_custom_data[identifier] = ss.str();
|
|
}
|
|
|
|
void EQ::ItemInstance::SetCustomData(std::string identifier, bool value) {
|
|
DeleteCustomData(identifier);
|
|
std::stringstream ss;
|
|
ss << value;
|
|
m_custom_data[identifier] = ss.str();
|
|
}
|
|
|
|
void EQ::ItemInstance::DeleteCustomData(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 (m_item->FVNoDrop != 0) // not implemented
|
|
return false;*/
|
|
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 && m_item->LoreGroup != -1) {
|
|
// 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.
|
|
}
|
|
|
|
bool EQ::ItemInstance::EvolveOnAllKills() const {
|
|
return (m_evolveInfo && m_evolveInfo->AllKills);
|
|
}
|
|
|
|
int8 EQ::ItemInstance::GetMaxEvolveLvl() const {
|
|
if (m_evolveInfo)
|
|
return m_evolveInfo->MaxLvl;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
uint32 EQ::ItemInstance::GetKillsNeeded(uint8 currentlevel) {
|
|
uint32 kills = -1; // default to -1 (max uint32 value) because this value is usually divided by, so we don't want to ever return zero.
|
|
if (m_evolveInfo)
|
|
if (currentlevel != m_evolveInfo->MaxLvl)
|
|
kills = m_evolveInfo->LvlKills[currentlevel - 1];
|
|
|
|
if (kills == 0)
|
|
kills = -1;
|
|
|
|
return kills;
|
|
}
|
|
|
|
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 = 0;
|
|
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(bodyType 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;
|
|
}
|
|
|
|
//
|
|
// class EvolveInfo
|
|
//
|
|
EvolveInfo::EvolveInfo() {
|
|
// nothing here yet
|
|
}
|
|
|
|
EvolveInfo::EvolveInfo(uint32 first, uint8 max, bool allkills, uint32 L2, uint32 L3, uint32 L4, uint32 L5, uint32 L6, uint32 L7, uint32 L8, uint32 L9, uint32 L10) {
|
|
FirstItem = first;
|
|
MaxLvl = max;
|
|
AllKills = allkills;
|
|
LvlKills[0] = L2;
|
|
LvlKills[1] = L3;
|
|
LvlKills[2] = L4;
|
|
LvlKills[3] = L5;
|
|
LvlKills[4] = L6;
|
|
LvlKills[5] = L7;
|
|
LvlKills[6] = L8;
|
|
LvlKills[7] = L9;
|
|
LvlKills[8] = L10;
|
|
}
|
|
|
|
EvolveInfo::~EvolveInfo() {
|
|
|
|
}
|