/* EQEmu: EQEmulator Copyright (C) 2001-2026 EQEmu Development Team 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; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 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, see . */ #include "inventory_profile.h" #include "common/data_verification.h" #include "common/evolving_items.h" #include "common/rulesys.h" #include "common/shareddb.h" #include "common/strings.h" #include int32 next_item_serial_number = 1; std::unordered_set 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::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() 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::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 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 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::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 EQ::ItemInstance::GetAugmentIDs() const { std::vector 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 EQ::ItemInstance::GetAugmentNames() const { std::vector 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(); }