TrinityCore
Loading...
Searching...
No Matches
Item.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Item.h"
19#include "ArtifactPackets.h"
21#include "AzeriteItem.h"
22#include "Bag.h"
23#include "ClientBuildInfo.h"
24#include "CollectionMgr.h"
25#include "Common.h"
26#include "ConditionMgr.h"
27#include "DB2Stores.h"
28#include "DatabaseEnv.h"
29#include "GameTables.h"
30#include "GameTime.h"
31#include "ItemBonusMgr.h"
32#include "ItemEnchantmentMgr.h"
33#include "ItemPackets.h"
34#include "Log.h"
35#include "Loot.h"
36#include "LootItemStorage.h"
37#include "LootMgr.h"
38#include "Map.h"
39#include "MapUtils.h"
40#include "ObjectAccessor.h"
41#include "ObjectMgr.h"
42#include "Player.h"
43#include "RealmList.h"
44#include "ScriptMgr.h"
45#include "SpellInfo.h"
46#include "SpellMgr.h"
47#include "StringConvert.h"
48#include "TradeData.h"
49#include "TransmogMgr.h"
50#include "UpdateData.h"
51#include "World.h"
52#include "WorldSession.h"
53#include <sstream>
54
56{
57 if (proto->GetInventoryType() == INVTYPE_BAG)
58 return new Bag();
59
60 if (sDB2Manager.IsAzeriteItem(proto->GetId()))
61 return new AzeriteItem();
62
63 if (sDB2Manager.GetAzeriteEmpoweredItem(proto->GetId()))
64 return new AzeriteEmpoweredItem();
65
66 return new Item();
67}
68
70{
72 std::unordered_set<Item const*> EquippedItems;
73 std::unordered_set<ItemSetSpellEntry const*> SetBonuses;
74};
75
76void AddItemsSetItem(Player* player, Item const* item)
77{
78 ItemTemplate const* proto = item->GetTemplate();
79 uint32 setid = proto->GetItemSet();
80
81 ItemSetEntry const* set = sItemSetStore.LookupEntry(setid);
82
83 if (!set)
84 {
85 TC_LOG_ERROR("sql.sql", "Item set {} for item (id {}) not found, mods not applied.", setid, proto->GetId());
86 return;
87 }
88
89 if (set->RequiredSkill && player->GetSkillValue(set->RequiredSkill) < set->RequiredSkillRank)
90 return;
91
93 return;
94
95 // Check player level for heirlooms
96 if (sDB2Manager.GetHeirloomByItemId(item->GetEntry()))
97 {
99 {
100 uint32 maxLevel = sDB2Manager.GetCurveXAxisRange(item->GetBonus()->PlayerLevelToItemLevelCurveId).second;
101
102 if (Optional<ContentTuningLevels> contentTuning = sDB2Manager.GetContentTuningData(item->GetBonus()->ContentTuningId, player->m_playerData->CtrOptions->ConditionalFlags, true))
103 maxLevel = std::min<uint32>(maxLevel, contentTuning->MaxLevel);
104
105 if (player->GetLevel() > maxLevel)
106 return;
107 }
108 }
109
110 ItemSetEffect* eff = nullptr;
111
112 for (size_t x = 0; x < player->ItemSetEff.size(); ++x)
113 {
114 if (player->ItemSetEff[x] && player->ItemSetEff[x]->ItemSetID == setid)
115 {
116 eff = player->ItemSetEff[x];
117 break;
118 }
119 }
120
121 if (!eff)
122 {
123 eff = new ItemSetEffect();
124 eff->ItemSetID = setid;
125
126 size_t x = 0;
127 for (; x < player->ItemSetEff.size(); ++x)
128 if (!player->ItemSetEff[x])
129 break;
130
131 if (x < player->ItemSetEff.size())
132 player->ItemSetEff[x] = eff;
133 else
134 player->ItemSetEff.push_back(eff);
135 }
136
137 eff->EquippedItems.insert(item);
138
139 if (std::vector<ItemSetSpellEntry const*> const* itemSetSpells = sDB2Manager.GetItemSetSpells(setid))
140 {
141 for (ItemSetSpellEntry const* itemSetSpell : *itemSetSpells)
142 {
143 //not enough for spell
144 if (itemSetSpell->Threshold > eff->EquippedItems.size())
145 continue;
146
147 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemSetSpell->SpellID, DIFFICULTY_NONE);
148 if (!spellInfo)
149 {
150 TC_LOG_ERROR("entities.player.items", "WORLD: unknown spell id {} in items set {} effects", itemSetSpell->SpellID, setid);
151 continue;
152 }
153
154 if (!eff->SetBonuses.insert(itemSetSpell).second)
155 continue;
156
157 // spell cast only if fit form requirement, in other case will cast at form change
158 if (itemSetSpell->ChrSpecID && ChrSpecialization(itemSetSpell->ChrSpecID) != player->GetPrimarySpecialization())
159 continue;
160
161 if (itemSetSpell->TraitSubTreeID && int32(itemSetSpell->TraitSubTreeID) != player->m_playerData->CurrentCombatTraitConfigSubTreeID)
162 continue;
163
164 player->ApplyEquipSpell(spellInfo, nullptr, true);
165 }
166 }
167}
168
169void RemoveItemsSetItem(Player* player, Item const* item)
170{
171 uint32 setid = item->GetTemplate()->GetItemSet();
172
173 ItemSetEntry const* set = sItemSetStore.LookupEntry(setid);
174
175 if (!set)
176 {
177 TC_LOG_ERROR("sql.sql", "Item set #{} for item #{} not found, mods not removed.", setid, item->GetEntry());
178 return;
179 }
180
181 ItemSetEffect* eff = nullptr;
182 size_t setindex = 0;
183 for (; setindex < player->ItemSetEff.size(); setindex++)
184 {
185 if (player->ItemSetEff[setindex] && player->ItemSetEff[setindex]->ItemSetID == setid)
186 {
187 eff = player->ItemSetEff[setindex];
188 break;
189 }
190 }
191
192 // can be in case now enough skill requirement for set appling but set has been appliend when skill requirement not enough
193 if (!eff)
194 return;
195
196 eff->EquippedItems.erase(item);
197
198 if (std::vector<ItemSetSpellEntry const*> const* itemSetSpells = sDB2Manager.GetItemSetSpells(setid))
199 {
200 for (ItemSetSpellEntry const* itemSetSpell : *itemSetSpells)
201 {
202 // enough for spell
203 if (itemSetSpell->Threshold <= eff->EquippedItems.size())
204 continue;
205
206 if (!eff->SetBonuses.erase(itemSetSpell))
207 continue;
208
209 player->ApplyEquipSpell(sSpellMgr->AssertSpellInfo(itemSetSpell->SpellID, DIFFICULTY_NONE), nullptr, false);
210 }
211 }
212
213 if (eff->EquippedItems.empty()) //all items of a set were removed
214 {
215 ASSERT(eff == player->ItemSetEff[setindex]);
216 delete eff;
217 player->ItemSetEff[setindex] = nullptr;
218 }
219}
220
221void UpdateItemSetAuras(Player* player, bool formChange)
222{
223 // item set bonuses not dependent from item broken state
224 for (ItemSetEffect* eff : player->ItemSetEff)
225 {
226 if (!eff)
227 continue;
228
229 for (ItemSetSpellEntry const* itemSetSpell : eff->SetBonuses)
230 {
231 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itemSetSpell->SpellID, DIFFICULTY_NONE);
232
233 if ((itemSetSpell->ChrSpecID && ChrSpecialization(itemSetSpell->ChrSpecID) != player->GetPrimarySpecialization())
234 || (itemSetSpell->TraitSubTreeID && int32(itemSetSpell->TraitSubTreeID) != player->m_playerData->CurrentCombatTraitConfigSubTreeID))
235 player->ApplyEquipSpell(spellInfo, nullptr, false, false); // item set aura is not for current spec
236 else
237 {
238 player->ApplyEquipSpell(spellInfo, nullptr, false, formChange); // remove spells that not fit to form - removal is skipped if shapeshift condition is satisfied
239 player->ApplyEquipSpell(spellInfo, nullptr, true, formChange); // add spells that fit form but not active
240 }
241 }
242 }
243}
244
246{
247 delete itemSetEffect;
248}
249
250bool ItemCanGoIntoBag(ItemTemplate const* pProto, ItemTemplate const* pBagProto)
251{
252 if (!pProto || !pBagProto)
253 return false;
254
255 switch (pBagProto->GetClass())
256 {
258 switch (pBagProto->GetSubClass())
259 {
261 return true;
263 if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_SOUL_SHARDS))
264 return false;
265 return true;
267 if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_HERBS))
268 return false;
269 return true;
272 return false;
273 return true;
275 if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_MINING_SUPP))
276 return false;
277 return true;
280 return false;
281 return true;
283 if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_GEMS))
284 return false;
285 return true;
288 return false;
289 return true;
292 return false;
293 return true;
296 return false;
297 return true;
300 return false;
301 return true;
303 return pProto->IsCraftingReagent();
304 default:
305 return false;
306 }
308 switch (pBagProto->GetSubClass())
309 {
311 if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_ARROWS))
312 return false;
313 return true;
315 if (!(pProto->GetBagFamily() & BAG_FAMILY_MASK_BULLETS))
316 return false;
317 return true;
318 default:
319 return false;
320 }
321 }
322 return false;
323}
324
333
342
351
352void ItemAdditionalLoadInfo::Init(std::unordered_map<ObjectGuid::LowType, ItemAdditionalLoadInfo>* loadInfo,
353 PreparedQueryResult artifactResult, PreparedQueryResult azeriteItemResult,
354 PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult,
355 PreparedQueryResult azeriteEmpoweredItemResult)
356{
357 // 0 1 2 3 4 5
358 // SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid ...
359 if (artifactResult)
360 {
361 do
362 {
363 Field* fields = artifactResult->Fetch();
364 ItemAdditionalLoadInfo& info = (*loadInfo)[fields[0].GetUInt64()];
365 if (!info.Artifact)
366 info.Artifact.emplace();
367 info.Artifact->Xp = fields[1].GetUInt64();
368 info.Artifact->ArtifactAppearanceId = fields[2].GetUInt32();
369 info.Artifact->ArtifactTierId = fields[3].GetUInt32();
370 ArtifactPowerData artifactPowerData;
371 artifactPowerData.ArtifactPowerId = fields[4].GetUInt32();
372 artifactPowerData.PurchasedRank = fields[5].GetUInt8();
373 if (ArtifactPowerEntry const* artifactPower = sArtifactPowerStore.LookupEntry(artifactPowerData.ArtifactPowerId))
374 {
375 uint32 maxRank = artifactPower->MaxPurchasableRank;
376 // allow ARTIFACT_POWER_FLAG_FINAL to overflow maxrank here - needs to be handled in Item::CheckArtifactUnlock (will refund artifact power)
377 if (artifactPower->Flags & ARTIFACT_POWER_FLAG_MAX_RANK_WITH_TIER && uint32(artifactPower->Tier) < info.Artifact->ArtifactTierId)
378 maxRank += info.Artifact->ArtifactTierId - artifactPower->Tier;
379
380 if (artifactPowerData.PurchasedRank > maxRank)
381 artifactPowerData.PurchasedRank = maxRank;
382
383 artifactPowerData.CurrentRankWithBonus = (artifactPower->Flags & ARTIFACT_POWER_FLAG_FIRST) == ARTIFACT_POWER_FLAG_FIRST ? 1 : 0;
384
385 info.Artifact->ArtifactPowers.push_back(artifactPowerData);
386 }
387
388 } while (artifactResult->NextRow());
389 }
390
391 // 0 1 2 3
392 // SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel,
393 // 4 5 6 7 8
394 // iz.selectedAzeriteEssences1specId, iz.selectedAzeriteEssences1azeriteEssenceId1, iz.selectedAzeriteEssences1azeriteEssenceId2, iz.selectedAzeriteEssences1azeriteEssenceId3, iz.selectedAzeriteEssences1azeriteEssenceId4,
395 // 9 10 11 12 13
396 // iz.selectedAzeriteEssences2specId, iz.selectedAzeriteEssences2azeriteEssenceId1, iz.selectedAzeriteEssences2azeriteEssenceId2, iz.selectedAzeriteEssences2azeriteEssenceId3, iz.selectedAzeriteEssences2azeriteEssenceId4,
397 // 14 15 16 17 18
398 // iz.selectedAzeriteEssences3specId, iz.selectedAzeriteEssences3azeriteEssenceId1, iz.selectedAzeriteEssences3azeriteEssenceId2, iz.selectedAzeriteEssences3azeriteEssenceId3, iz.selectedAzeriteEssences3azeriteEssenceId4,
399 // 19 20 21 22 23
400 // iz.selectedAzeriteEssences4specId, iz.selectedAzeriteEssences4azeriteEssenceId1, iz.selectedAzeriteEssences4azeriteEssenceId2, iz.selectedAzeriteEssences4azeriteEssenceId3, iz.selectedAzeriteEssences4azeriteEssenceId4
401 // FROM item_instance_azerite iz INNER JOIN ...
402 if (azeriteItemResult)
403 {
404 do
405 {
406 Field* fields = azeriteItemResult->Fetch();
407 ItemAdditionalLoadInfo& info = (*loadInfo)[fields[0].GetUInt64()];
408 if (!info.AzeriteItem)
409 info.AzeriteItem.emplace();
410 info.AzeriteItem->Xp = fields[1].GetUInt64();
411 info.AzeriteItem->Level = fields[2].GetUInt32();
412 info.AzeriteItem->KnowledgeLevel = fields[3].GetUInt32();
413 for (std::size_t i = 0; i < info.AzeriteItem->SelectedAzeriteEssences.size(); ++i)
414 {
415 uint32 specializationId = fields[4 + i * 4].GetUInt32();
416 if (!sChrSpecializationStore.LookupEntry(specializationId))
417 continue;
418
419 info.AzeriteItem->SelectedAzeriteEssences[i].SpecializationId = specializationId;
420 for (std::size_t j = 0; j < MAX_AZERITE_ESSENCE_SLOT; ++j)
421 {
422 AzeriteEssenceEntry const* azeriteEssence = sAzeriteEssenceStore.LookupEntry(fields[5 + i * 5 + j].GetUInt32());
423 if (!azeriteEssence || !sDB2Manager.IsSpecSetMember(azeriteEssence->SpecSetID, specializationId))
424 continue;
425
426 info.AzeriteItem->SelectedAzeriteEssences[i].AzeriteEssenceId[j] = azeriteEssence->ID;
427 }
428 }
429
430 } while (azeriteItemResult->NextRow());
431 }
432
433 // 0 1
434 // SELECT iamp.itemGuid, iamp.azeriteItemMilestonePowerId FROM item_instance_azerite_milestone_power iamp INNER JOIN ...
435 if (azeriteItemMilestonePowersResult)
436 {
437 do
438 {
439 Field* fields = azeriteItemMilestonePowersResult->Fetch();
440 ItemAdditionalLoadInfo& info = (*loadInfo)[fields[0].GetUInt64()];
441 if (!info.AzeriteItem)
442 info.AzeriteItem.emplace();
443 info.AzeriteItem->AzeriteItemMilestonePowers.push_back(fields[1].GetUInt32());
444 }
445 while (azeriteItemMilestonePowersResult->NextRow());
446 }
447
448 // 0 1 2
449 // SELECT iaue.itemGuid, iaue.azeriteEssenceId, iaue.`rank` FROM item_instance_azerite_unlocked_essence iaue INNER JOIN ...
450 if (azeriteItemUnlockedEssencesResult)
451 {
452 do
453 {
454 Field* fields = azeriteItemUnlockedEssencesResult->Fetch();
455 if (AzeriteEssencePowerEntry const* azeriteEssencePower = sDB2Manager.GetAzeriteEssencePower(fields[1].GetUInt32(), fields[2].GetUInt32()))
456 {
457 ItemAdditionalLoadInfo& info = (*loadInfo)[fields[0].GetUInt64()];
458 if (!info.AzeriteItem)
459 info.AzeriteItem.emplace();
460
461 info.AzeriteItem->UnlockedAzeriteEssences.push_back(azeriteEssencePower);
462 }
463 }
464 while (azeriteItemUnlockedEssencesResult->NextRow());
465 }
466
467 // 0 1 2 3 4 5
468 // SELECT iae.itemGuid, iae.azeritePowerId1, iae.azeritePowerId2, iae.azeritePowerId3, iae.azeritePowerId4, iae.azeritePowerId5 FROM item_instance_azerite_empowered iae INNER JOIN ...
469 if (azeriteEmpoweredItemResult)
470 {
471 do
472 {
473 Field* fields = azeriteEmpoweredItemResult->Fetch();
474 ItemAdditionalLoadInfo& info = (*loadInfo)[fields[0].GetUInt64()];
475 if (!info.AzeriteEmpoweredItem)
476 info.AzeriteEmpoweredItem.emplace();
477
478 for (uint32 i = 0; i < MAX_AZERITE_EMPOWERED_TIER; ++i)
479 if (sAzeritePowerStore.LookupEntry(fields[1 + i].GetInt32()))
480 info.AzeriteEmpoweredItem->SelectedAzeritePowers[i] = fields[1 + i].GetInt32();
481
482 } while (azeriteEmpoweredItemResult->NextRow());
483 }
484}
485
487{
489
491
492 m_slot = 0;
494 uQueuePos = -1;
495 m_container = nullptr;
496 m_lootGenerated = false;
497 mb_in_trade = false;
498
499 m_paidMoney = 0;
501
503 m_gemScalingLevels = { };
504
505 memset(&_bonusData, 0, sizeof(_bonusData));
506}
507
508Item::~Item() = default;
509
510bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemId, ItemContext context, Player const* owner)
511{
512 _Create(ObjectGuid::Create<HighGuid::Item>(guidlow));
513
514 SetEntry(itemId);
515 SetObjectScale(1.0f);
516
517 if (owner)
518 {
519 SetOwnerGUID(owner->GetGUID());
520 SetContainedIn(owner->GetGUID());
521 }
522
523 ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(itemId);
524 if (!itemProto)
525 return false;
526
527 _bonusData.Initialize(itemProto);
528 SetCount(1);
530 SetDurability(itemProto->MaxDurability);
531
532 for (ItemEffectEntry const* effect : GetEffects())
533 SetSpellCharges(effect, effect->Charges);
534
535 SetExpiration(itemProto->GetDuration());
538 SetContext(context);
539
540 if (itemProto->GetArtifactID())
541 {
542 InitArtifactPowers(itemProto->GetArtifactID(), 0);
543 for (ArtifactAppearanceEntry const* artifactAppearance : sArtifactAppearanceStore)
544 {
545 if (ArtifactAppearanceSetEntry const* artifactAppearanceSet = sArtifactAppearanceSetStore.LookupEntry(artifactAppearance->ArtifactAppearanceSetID))
546 {
547 if (itemProto->GetArtifactID() != artifactAppearanceSet->ArtifactID)
548 continue;
549
550 if (!owner || !ConditionMgr::IsPlayerMeetingCondition(owner, artifactAppearance->UnlockPlayerConditionID))
551 continue;
552
553 SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, artifactAppearance->ID);
554 SetAppearanceModId(artifactAppearance->ItemAppearanceModifierID);
555 break;
556 }
557 }
558
559 CheckArtifactRelicSlotUnlock(owner ? owner : GetOwner());
560 }
561
562 return true;
563}
564
566{
567 ItemTemplate const* itemTemplate = GetTemplate();
569 return Trinity::StringFormat("{} {}", itemTemplate->GetName(locale), suffix->Description[locale]);
570
571 return itemTemplate->GetName(locale);
572}
573
574// Returns true if Item is a bag AND it is not empty.
575// Returns false if Item is not a bag OR it is an empty bag.
577{
578 if (Bag const* bag = ToBag())
579 return !bag->IsEmpty();
580 return false;
581}
582
584{
585 uint32 duration = m_itemData->Expiration;
586 if (!duration)
587 return;
588
589 TC_LOG_DEBUG("entities.player.items", "Item::UpdateDuration Item (Entry: {} Duration {} Diff {})", GetEntry(), duration, diff);
590
591 if (duration <= diff)
592 {
593 sScriptMgr->OnItemExpire(owner, GetTemplate());
594 owner->DestroyItem(GetBagSlot(), GetSlot(), true);
595 return;
596 }
597
598 SetExpiration(duration - diff);
599 SetState(ITEM_CHANGED, owner); // save new time in database
600}
601
602static uint32 FindSpellChargesSlot(BonusData const& bonusData, ItemEffectEntry const* effect)
603{
604 static constexpr uint32 MaxSpellChargesSlot = UF::size<decltype(UF::ItemData::SpellCharges)>();
605
606 if (!effect)
607 {
608 // return fist effect that has charges
609 for (uint32 i = 0; i < bonusData.EffectCount && i < MaxSpellChargesSlot; ++i)
610 if (bonusData.Effects[i] && bonusData.Effects[i]->Charges != 0)
611 return i;
612
613 return MaxSpellChargesSlot;
614 }
615
616 for (uint32 i = 0; i < bonusData.EffectCount && i < MaxSpellChargesSlot; ++i)
617 if (bonusData.Effects[i] == effect)
618 return i;
619
620 return MaxSpellChargesSlot;
621}
622
623int32 Item::GetSpellCharges(ItemEffectEntry const* effect /*= nullptr*/) const
624{
625 uint32 slot = FindSpellChargesSlot(_bonusData, effect);
626 if (slot < m_itemData->SpellCharges.size())
627 return m_itemData->SpellCharges[slot];
628
629 return 0;
630}
631
633{
634 uint32 slot = FindSpellChargesSlot(_bonusData, effect);
635 if (slot < m_itemData->SpellCharges.size())
637}
638
640{
641 bool isInTransaction = bool(trans);
642 if (!isInTransaction)
643 trans = CharacterDatabase.BeginTransaction();
644
645 switch (uState)
646 {
647 case ITEM_NEW:
648 case ITEM_CHANGED:
649 {
650 uint8 index = 0;
652 stmt->setUInt32( index, GetEntry());
653 stmt->setUInt64(++index, GetOwnerGUID().GetCounter());
654 stmt->setUInt64(++index, GetCreator().GetCounter());
655 stmt->setUInt64(++index, GetGiftCreator().GetCounter());
656 stmt->setUInt32(++index, GetCount());
657 stmt->setUInt32(++index, m_itemData->Expiration);
658
659 std::ostringstream ssSpells;
660 for (uint8 i = 0; i < m_itemData->SpellCharges.size() && i < _bonusData.EffectCount; ++i)
661 ssSpells << m_itemData->SpellCharges[i] << ' ';
662 stmt->setString(++index, ssSpells.str());
663
664 stmt->setUInt32(++index, m_itemData->DynamicFlags);
665
666 std::ostringstream ssEnchants;
667 for (uint8 i = 0; i < MAX_ENCHANTMENT_SLOT; ++i)
668 {
670 enchantment && !enchantment->GetFlags().HasFlag(SpellItemEnchantmentFlags::DoNotSaveToDB))
671 {
672 ssEnchants << GetEnchantmentId(EnchantmentSlot(i)) << ' ';
673 ssEnchants << GetEnchantmentDuration(EnchantmentSlot(i)) << ' ';
674 ssEnchants << GetEnchantmentCharges(EnchantmentSlot(i)) << ' ';
675 }
676 else
677 {
678 ssEnchants << "0 0 0 ";
679 }
680 }
681 stmt->setString(++index, ssEnchants.str());
682
683 stmt->setUInt32(++index, m_randomBonusListId);
684 stmt->setUInt16(++index, m_itemData->Durability);
685 stmt->setUInt32(++index, m_itemData->CreatePlayedTime);
686 stmt->setInt64(++index, m_itemData->CreateTime);
687 stmt->setString(++index, m_text);
692 stmt->setUInt8(++index, uint8(m_itemData->Context));
693
694 std::ostringstream bonusListIDs;
695 for (int32 bonusListID : GetBonusListIDs())
696 bonusListIDs << bonusListID << ' ';
697 stmt->setString(++index, bonusListIDs.str());
698
699 stmt->setUInt64(++index, GetGUID().GetCounter());
700
701 trans->Append(stmt);
702
703 if ((uState == ITEM_CHANGED) && IsWrapped())
704 {
705 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GIFT_OWNER);
706 stmt->setUInt64(0, GetOwnerGUID().GetCounter());
707 stmt->setUInt64(1, GetGUID().GetCounter());
708 trans->Append(stmt);
709 }
710
711 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_GEMS);
712 stmt->setUInt64(0, GetGUID().GetCounter());
713 trans->Append(stmt);
714
715 if (m_itemData->Gems.size())
716 {
717 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_GEMS);
718 stmt->setUInt64(0, GetGUID().GetCounter());
719 uint32 i = 0;
720 uint32 const gemFields = 4;
721 for (UF::SocketedGem const& gemData : m_itemData->Gems)
722 {
723 if (gemData.ItemID)
724 {
725 stmt->setUInt32(1 + i * gemFields, gemData.ItemID);
726 std::ostringstream gemBonusListIDs;
727 for (uint16 bonusListID : gemData.BonusListIDs)
728 if (bonusListID)
729 gemBonusListIDs << bonusListID << ' ';
730 stmt->setString(2 + i * gemFields, gemBonusListIDs.str());
731 stmt->setUInt8(3 + i * gemFields, gemData.Context);
732 stmt->setUInt32(4 + i * gemFields, m_gemScalingLevels[i]);
733 }
734 else
735 {
736 stmt->setUInt32(1 + i * gemFields, 0);
737 stmt->setString(2 + i * gemFields, ""sv);
738 stmt->setUInt8(3 + i * gemFields, 0);
739 stmt->setUInt32(4 + i * gemFields, 0);
740 }
741 ++i;
742 }
743 for (; i < MAX_GEM_SOCKETS; ++i)
744 {
745 stmt->setUInt32(1 + i * gemFields, 0);
746 stmt->setString(2 + i * gemFields, ""sv);
747 stmt->setUInt8(3 + i * gemFields, 0);
748 stmt->setUInt32(4 + i * gemFields, 0);
749 }
750 trans->Append(stmt);
751 }
752
753 static ItemModifier const transmogMods[18] =
754 {
761
768
775 };
776
777 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_TRANSMOG);
778 stmt->setUInt64(0, GetGUID().GetCounter());
779 trans->Append(stmt);
780
781 if (std::find_if(std::begin(transmogMods), std::end(transmogMods), [this](ItemModifier modifier) { return GetModifier(modifier) != 0; }) != std::end(transmogMods))
782 {
783 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_TRANSMOG);
784 stmt->setUInt64(0, GetGUID().GetCounter());
803 trans->Append(stmt);
804 }
805
806 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT);
807 stmt->setUInt64(0, GetGUID().GetCounter());
808 trans->Append(stmt);
809
811 stmt->setUInt64(0, GetGUID().GetCounter());
812 trans->Append(stmt);
813
814 if (GetTemplate()->GetArtifactID())
815 {
816 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT);
817 stmt->setUInt64(0, GetGUID().GetCounter());
818 stmt->setUInt64(1, m_itemData->ArtifactXP);
821 trans->Append(stmt);
822
823 for (UF::ArtifactPower const& artifactPower : m_itemData->ArtifactPowers)
824 {
826 stmt->setUInt64(0, GetGUID().GetCounter());
827 stmt->setUInt32(1, artifactPower.ArtifactPowerID);
828 stmt->setUInt8(2, artifactPower.PurchasedRank);
829 trans->Append(stmt);
830 }
831 }
832
833 static ItemModifier const modifiersTable[] =
834 {
837 };
838
839 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS);
840 stmt->setUInt64(0, GetGUID().GetCounter());
841 trans->Append(stmt);
842
843 if (std::find_if(std::begin(modifiersTable), std::end(modifiersTable), [this](ItemModifier modifier) { return GetModifier(modifier) != 0; }) != std::end(modifiersTable))
844 {
845 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_MODIFIERS);
846 stmt->setUInt64(0, GetGUID().GetCounter());
849 trans->Append(stmt);
850 }
851
852 break;
853 }
854 case ITEM_REMOVED:
855 {
857 stmt->setUInt64(0, GetGUID().GetCounter());
858 trans->Append(stmt);
859
860 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_GEMS);
861 stmt->setUInt64(0, GetGUID().GetCounter());
862 trans->Append(stmt);
863
864 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_TRANSMOG);
865 stmt->setUInt64(0, GetGUID().GetCounter());
866 trans->Append(stmt);
867
868 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT);
869 stmt->setUInt64(0, GetGUID().GetCounter());
870 trans->Append(stmt);
871
873 stmt->setUInt64(0, GetGUID().GetCounter());
874 trans->Append(stmt);
875
876 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS);
877 stmt->setUInt64(0, GetGUID().GetCounter());
878 trans->Append(stmt);
879
880 if (IsWrapped())
881 {
882 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT);
883 stmt->setUInt64(0, GetGUID().GetCounter());
884 trans->Append(stmt);
885 }
886
887 if (!isInTransaction)
888 CharacterDatabase.CommitTransaction(trans);
889
890 // Delete the items if this is a container
891 if (m_loot && !m_loot->isLooted())
892 sLootItemStorage->RemoveStoredLootForContainer(GetGUID().GetCounter());
893
894 delete this;
895 return;
896 }
897 case ITEM_UNCHANGED:
898 break;
899 }
900
902
903 if (!isInTransaction)
904 CharacterDatabase.CommitTransaction(trans);
905}
906
907bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fields, uint32 entry)
908{
909 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13
910 // SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomBonusListId, durability, playedTime, createTime, text,
911 // 14 15 16 17 18 19
912 // battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, context, bonusListIDs,
913 // 20 21 22 23 24 25
914 // itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4, itemModifiedAppearanceSpec5,
915 // 26 27 28 29 30 31
916 // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, spellItemEnchantmentSpec5,
917 // 32 33 34
918 // secondaryItemModifiedAppearanceAllSpecs, secondaryItemModifiedAppearanceSpec1, secondaryItemModifiedAppearanceSpec2,
919 // 35 36 37
920 // secondaryItemModifiedAppearanceSpec3, secondaryItemModifiedAppearanceSpec4, secondaryItemModifiedAppearanceSpec5,
921 // 38 39 40 41 42 43 44 45 46 47 48 49
922 // gemItemId1, gemBonuses1, gemContext1, gemScalingLevel1, gemItemId2, gemBonuses2, gemContext2, gemScalingLevel2, gemItemId3, gemBonuses3, gemContext3, gemScalingLevel3
923 // 50 51
924 // fixedScalingLevel, artifactKnowledgeLevel FROM item_instance
925
926 // create item before any checks for store correct guid
927 // and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB
928 _Create(ObjectGuid::Create<HighGuid::Item>(guid));
929
930 // Set entry, MUST be before proto check
931 SetEntry(entry);
932 SetObjectScale(1.0f);
933
934 ItemTemplate const* proto = GetTemplate();
935 if (!proto)
936 {
937 TC_LOG_ERROR("entities.item", "Invalid entry {} for item {}. Refusing to load.", GetEntry(), GetGUID().ToString());
938 return false;
939 }
940
941 _bonusData.Initialize(proto);
942
943 // set owner (not if item is only loaded for gbank/auction/mail
944 if (!ownerGuid.IsEmpty())
945 SetOwnerGUID(ownerGuid);
946
947 uint32 itemFlags = fields[7].GetUInt32();
948 bool need_save = false; // need explicit save data at load fixes
949 if (uint64 creator = fields[2].GetUInt64())
950 {
951 if (!(itemFlags & ITEM_FIELD_FLAG_CHILD))
952 SetCreator(ObjectGuid::Create<HighGuid::Player>(creator));
953 else
954 SetCreator(ObjectGuid::Create<HighGuid::Item>(creator));
955 }
956 if (uint64 giftCreator = fields[3].GetUInt64())
957 SetGiftCreator(ObjectGuid::Create<HighGuid::Player>(giftCreator));
958 SetCount(fields[4].GetUInt32());
959
960 uint32 duration = fields[5].GetUInt32();
961 SetExpiration(duration);
962 // update duration if need, and remove if not need
963 if ((proto->GetDuration() == 0) != (duration == 0))
964 {
965 SetExpiration(proto->GetDuration());
966 need_save = true;
967 }
968
970
971 uint32 durability = fields[10].GetUInt16();
972 SetDurability(durability);
973 // update max durability (and durability) if need
975
976 // do not overwrite durability for wrapped items
977 if (durability > proto->MaxDurability && !IsWrapped())
978 {
980 need_save = true;
981 }
982
983 SetCreatePlayedTime(fields[11].GetUInt32());
984 SetCreateTime(fields[12].GetInt64());
985 SetText(fields[13].GetString());
986
987 SetModifier(ITEM_MODIFIER_BATTLE_PET_SPECIES_ID, fields[14].GetUInt32());
988 SetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA, fields[15].GetUInt32());
989 SetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL, fields[16].GetUInt16());
990 SetModifier(ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID, fields[17].GetUInt32());
991
992 SetContext(ItemContext(fields[18].GetUInt8()));
993
994 std::vector<std::string_view> bonusListString = Trinity::Tokenize(fields[19].GetStringView(), ' ', false);
995 std::vector<int32> bonusListIDs;
996 bonusListIDs.reserve(bonusListString.size());
997 for (std::string_view token : bonusListString)
998 if (Optional<int32> bonusListID = Trinity::StringTo<int32>(token))
999 bonusListIDs.push_back(*bonusListID);
1000 SetBonuses(std::move(bonusListIDs));
1001
1002 // load charges after bonuses, they can add more item effects
1003 std::vector<std::string_view> tokens = Trinity::Tokenize(fields[6].GetStringView(), ' ', false);
1004 for (uint8 i = 0; i < m_itemData->SpellCharges.size() && i < _bonusData.EffectCount && i < tokens.size(); ++i)
1005 SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::SpellCharges, i), Trinity::StringTo<int32>(tokens[i]).value_or(0));
1006
1013
1015 SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_1, fields[27].GetUInt32());
1016 SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_2, fields[28].GetUInt32());
1017 SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_3, fields[29].GetUInt32());
1018 SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_4, fields[30].GetUInt32());
1019 SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_5, fields[31].GetUInt32());
1020
1027
1028 uint32 const gemFields = 4;
1030 memset(gemData, 0, sizeof(gemData));
1031 for (uint32 i = 0; i < MAX_GEM_SOCKETS; ++i)
1032 {
1033 gemData[i].ItemId = fields[38 + i * gemFields].GetUInt32();
1034 std::vector<std::string_view> gemBonusListIDs = Trinity::Tokenize(fields[39 + i * gemFields].GetStringView(), ' ', false);
1035 uint32 b = 0;
1036 for (std::string_view token : gemBonusListIDs)
1037 if (Optional<uint16> bonusListID = Trinity::StringTo<uint16>(token))
1038 gemData[i].BonusListIDs[b++] = *bonusListID;
1039
1040 gemData[i].Context = fields[40 + i * gemFields].GetUInt8();
1041 if (gemData[i].ItemId)
1042 SetGem(i, &gemData[i], fields[41 + i * gemFields].GetUInt32());
1043 }
1044
1045 SetModifier(ITEM_MODIFIER_TIMEWALKER_LEVEL, fields[50].GetUInt32());
1046 SetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL, fields[51].GetUInt32());
1047
1048 // Enchants must be loaded after all other bonus/scaling data
1049 std::vector<std::string_view> enchantmentTokens = Trinity::Tokenize(fields[8].GetStringView(), ' ', false);
1050 if (enchantmentTokens.size() == MAX_ENCHANTMENT_SLOT * MAX_ENCHANTMENT_OFFSET)
1051 {
1052 for (uint32 i = 0; i < MAX_ENCHANTMENT_SLOT; ++i)
1053 {
1054 auto enchantmentField = m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::Enchantment, i);
1055 SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::ID), Trinity::StringTo<int32>(enchantmentTokens[i * MAX_ENCHANTMENT_OFFSET + 0]).value_or(0));
1056 SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::Duration), Trinity::StringTo<uint32>(enchantmentTokens[i * MAX_ENCHANTMENT_OFFSET + 1]).value_or(0));
1057 SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::Charges), Trinity::StringTo<int16>(enchantmentTokens[i * MAX_ENCHANTMENT_OFFSET + 2]).value_or(0));
1058 }
1059 }
1060 m_randomBonusListId = fields[9].GetUInt32();
1061
1062 // Remove bind flag for items vs BIND_NONE set
1063 if (IsSoulBound() && GetBonding() == BIND_NONE)
1064 {
1066 need_save = true;
1067 }
1068
1069 if (need_save) // normal item changed state set not work at loading
1070 {
1071 uint8 index = 0;
1073 stmt->setUInt32(index++, m_itemData->Expiration);
1074 stmt->setUInt32(index++, m_itemData->DynamicFlags);
1075 stmt->setUInt32(index++, m_itemData->Durability);
1076 stmt->setUInt64(index++, guid);
1077 CharacterDatabase.Execute(stmt);
1078 }
1079
1080 return true;
1081}
1082
1084{
1085 if (GetTemplate()->GetArtifactID() && addionalData->Artifact)
1086 LoadArtifactData(owner, addionalData->Artifact->Xp, addionalData->Artifact->ArtifactAppearanceId,
1087 addionalData->Artifact->ArtifactTierId, addionalData->Artifact->ArtifactPowers);
1088
1089 if (addionalData->AzeriteItem)
1090 if (AzeriteItem* azeriteItem = ToAzeriteItem())
1091 azeriteItem->LoadAzeriteItemData(owner, *addionalData->AzeriteItem);
1092
1093 if (addionalData->AzeriteEmpoweredItem)
1094 if (AzeriteEmpoweredItem* azeriteEmpoweredItem = ToAzeriteEmpoweredItem())
1095 azeriteEmpoweredItem->LoadAzeriteEmpoweredItemData(owner, *addionalData->AzeriteEmpoweredItem);
1096}
1097
1098void Item::LoadArtifactData(Player const* owner, uint64 xp, uint32 artifactAppearanceId, uint32 artifactTier, std::vector<ArtifactPowerData>& powers)
1099{
1100 for (uint8 i = 0; i <= artifactTier; ++i)
1101 InitArtifactPowers(GetTemplate()->GetArtifactID(), i);
1102
1106
1107 if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifactAppearanceId))
1108 SetAppearanceModId(artifactAppearance->ItemAppearanceModifierID);
1109
1110 uint8 totalPurchasedRanks = 0;
1111 for (ArtifactPowerData& power : powers)
1112 {
1113 power.CurrentRankWithBonus += power.PurchasedRank;
1114 totalPurchasedRanks += power.PurchasedRank;
1115
1116 ArtifactPowerEntry const* artifactPower = sArtifactPowerStore.AssertEntry(power.ArtifactPowerId);
1118 {
1120 {
1121 for (uint32 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i)
1122 {
1123 switch (enchant->Effect[i])
1124 {
1126 if (uint32(artifactPower->Label) == enchant->EffectArg[i])
1127 power.CurrentRankWithBonus += enchant->EffectPointsMin[i];
1128 break;
1130 if (artifactPower->ID == enchant->EffectArg[i])
1131 power.CurrentRankWithBonus += enchant->EffectPointsMin[i];
1132 break;
1135 {
1136 ArtifactPowerPickerEntry const* artifactPowerPicker = sArtifactPowerPickerStore.LookupEntry(enchant->EffectArg[i]);
1137 if (artifactPowerPicker && owner && ConditionMgr::IsPlayerMeetingCondition(owner, artifactPowerPicker->PlayerConditionID))
1138 if (artifactPower->Label == _bonusData.GemRelicType[e - SOCK_ENCHANTMENT_SLOT])
1139 power.CurrentRankWithBonus += enchant->EffectPointsMin[i];
1140 }
1141 break;
1142 default:
1143 break;
1144 }
1145 }
1146 }
1147 }
1148
1149 SetArtifactPower(power.ArtifactPowerId, power.PurchasedRank, power.CurrentRankWithBonus);
1150 }
1151
1152 for (ArtifactPowerData& power : powers)
1153 {
1154 ArtifactPowerEntry const* scaledArtifactPowerEntry = sArtifactPowerStore.AssertEntry(power.ArtifactPowerId);
1155 if (!(scaledArtifactPowerEntry->Flags & ARTIFACT_POWER_FLAG_SCALES_WITH_NUM_POWERS))
1156 continue;
1157
1158 SetArtifactPower(power.ArtifactPowerId, power.PurchasedRank, totalPurchasedRanks + 1);
1159 }
1160
1162}
1163
1165{
1166 if (!owner)
1167 return;
1168
1169 uint8 artifactId = GetTemplate()->GetArtifactID();
1170 if (!artifactId)
1171 return;
1172
1173 for (ArtifactUnlockEntry const* artifactUnlock : sArtifactUnlockStore)
1174 if (artifactUnlock->ArtifactID == artifactId)
1175 if (owner->MeetPlayerCondition(artifactUnlock->PlayerConditionID))
1176 AddBonuses(artifactUnlock->ItemBonusListID);
1177}
1178
1179/*static*/
1181{
1183 stmt->setUInt64(0, itemGuid);
1184 CharacterDatabase.ExecuteOrAppend(trans, stmt);
1185
1186 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_GEMS);
1187 stmt->setUInt64(0, itemGuid);
1188 CharacterDatabase.ExecuteOrAppend(trans, stmt);
1189
1190 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_TRANSMOG);
1191 stmt->setUInt64(0, itemGuid);
1192 CharacterDatabase.ExecuteOrAppend(trans, stmt);
1193
1194 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT);
1195 stmt->setUInt64(0, itemGuid);
1196 CharacterDatabase.ExecuteOrAppend(trans, stmt);
1197
1198 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS);
1199 stmt->setUInt64(0, itemGuid);
1200 CharacterDatabase.ExecuteOrAppend(trans, stmt);
1201
1202 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS);
1203 stmt->setUInt64(0, itemGuid);
1204 CharacterDatabase.ExecuteOrAppend(trans, stmt);
1205
1206 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT);
1207 stmt->setUInt64(0, itemGuid);
1208 CharacterDatabase.ExecuteOrAppend(trans, stmt);
1209}
1210
1212{
1213 DeleteFromDB(trans, GetGUID().GetCounter());
1214
1215 // Delete the items if this is a container
1216 if (m_loot && !m_loot->isLooted())
1217 sLootItemStorage->RemoveStoredLootForContainer(GetGUID().GetCounter());
1218}
1219
1220/*static*/
1222{
1224 stmt->setUInt64(0, itemGuid);
1225 trans->Append(stmt);
1226}
1227
1232
1234{
1235 return sObjectMgr->GetItemTemplate(GetEntry());
1236}
1237
1242
1243// Just a "legacy shortcut" for proto->GetSkill()
1245{
1246 ItemTemplate const* proto = GetTemplate();
1247 return proto->GetSkill();
1248}
1249
1251{
1252 if (!bonusListId)
1253 return;
1254
1255 AddBonuses(bonusListId);
1256}
1257
1259{
1260 if (uState == ITEM_NEW && state == ITEM_REMOVED)
1261 {
1262 // pretend the item never existed
1263 if (forplayer)
1264 {
1265 RemoveItemFromUpdateQueueOf(this, forplayer);
1266 forplayer->DeleteRefundReference(GetGUID());
1267 }
1268 delete this;
1269 return;
1270 }
1271 if (state != ITEM_UNCHANGED)
1272 {
1273 // new items must stay in new state until saved
1274 if (uState != ITEM_NEW)
1275 uState = state;
1276
1277 if (forplayer)
1278 AddItemToUpdateQueueOf(this, forplayer);
1279 }
1280 else
1281 {
1282 // unset in queue
1283 // the item must be removed from the queue manually
1284 uQueuePos = -1;
1286 }
1287}
1288
1290{
1291 if (item->IsInUpdateQueue())
1292 return;
1293
1294 ASSERT(player != nullptr);
1295
1296 if (player->GetGUID() != item->GetOwnerGUID())
1297 {
1298 TC_LOG_DEBUG("entities.player.items", "AddItemToUpdateQueueOf - Owner's guid ({}) and player's guid ({}) don't match!",
1299 item->GetOwnerGUID().ToString(), player->GetGUID().ToString());
1300 return;
1301 }
1302
1303 if (player->m_itemUpdateQueueBlocked)
1304 return;
1305
1306 player->m_itemUpdateQueue.push_back(item);
1307 item->uQueuePos = player->m_itemUpdateQueue.size() - 1;
1308}
1309
1311{
1312 if (!item->IsInUpdateQueue())
1313 return;
1314
1315 ASSERT(player != nullptr);
1316
1317 if (player->GetGUID() != item->GetOwnerGUID())
1318 {
1319 TC_LOG_DEBUG("entities.player.items", "RemoveItemFromUpdateQueueOf - Owner's guid ({}) and player's guid ({}) don't match!",
1320 item->GetOwnerGUID().ToString(), player->GetGUID().ToString());
1321 return;
1322 }
1323
1324 if (player->m_itemUpdateQueueBlocked)
1325 return;
1326
1327 player->m_itemUpdateQueue[item->uQueuePos] = nullptr;
1328 item->uQueuePos = -1;
1329}
1330
1335
1337{
1338 return !IsInBag() && (m_slot < EQUIPMENT_SLOT_END
1340}
1341
1342bool Item::CanBeTraded(bool mail, bool trade) const
1343{
1344 if (m_lootGenerated)
1345 return false;
1346
1347 if ((!mail || !IsBoundAccountWide()) && (IsSoulBound() && (!IsBOPTradeable() || !trade)))
1348 return false;
1349
1350 if (IsBag() && (Player::IsBagPos(GetPos()) || !ToBag()->IsEmpty()))
1351 return false;
1352
1353 if (Player* owner = GetOwner())
1354 {
1355 if (owner->CanUnequipItem(GetPos(), false) != EQUIP_ERR_OK)
1356 return false;
1357 if (owner->GetLootGUID() == GetGUID())
1358 return false;
1359 }
1360
1361 if (IsBoundByEnchant())
1362 return false;
1363
1364 return true;
1365}
1366
1368{
1370
1371 if (Player* player = GetOwner())
1372 {
1373 if (TradeData* tradeData = player->GetTradeData())
1374 {
1375 TradeSlots slot = tradeData->GetTradeSlotForItem(GetGUID());
1376
1377 if (slot != TRADE_SLOT_INVALID)
1378 tradeData->SetItem(slot, this, true);
1379 }
1380 }
1381}
1382
1384{
1385 uint32 maxDurability = m_itemData->MaxDurability;
1386 if (!maxDurability)
1387 return 0;
1388
1389 uint32 curDurability = m_itemData->Durability;
1390 ASSERT(maxDurability >= curDurability);
1391
1392 uint32 lostDurability = maxDurability - curDurability;
1393 if (!lostDurability)
1394 return 0;
1395
1396 ItemTemplate const* itemTemplate = GetTemplate();
1397
1398 DurabilityCostsEntry const* durabilityCost = sDurabilityCostsStore.LookupEntry(GetItemLevel(GetOwner()));
1399 if (!durabilityCost)
1400 return 0;
1401
1402 uint32 durabilityQualityEntryId = (GetQuality() + 1) * 2;
1403 DurabilityQualityEntry const* durabilityQualityEntry = sDurabilityQualityStore.LookupEntry(durabilityQualityEntryId);
1404 if (!durabilityQualityEntry)
1405 return 0;
1406
1407 uint32 dmultiplier = 0;
1408 if (itemTemplate->GetClass() == ITEM_CLASS_WEAPON)
1409 dmultiplier = durabilityCost->WeaponSubClassCost[itemTemplate->GetSubClass()];
1410 else if (itemTemplate->GetClass() == ITEM_CLASS_ARMOR)
1411 dmultiplier = durabilityCost->ArmorSubClassCost[itemTemplate->GetSubClass()];
1412
1413 uint64 cost = std::round(lostDurability * dmultiplier * durabilityQualityEntry->Data * GetRepairCostMultiplier());
1414 cost = uint64(cost * discount * sWorld->getRate(RATE_REPAIRCOST));
1415
1416 if (cost == 0) // Fix for ITEM_QUALITY_ARTIFACT
1417 cost = 1;
1418
1419 return cost;
1420}
1421
1422bool Item::HasEnchantRequiredSkill(Player const* player) const
1423{
1424 // Check all enchants for required skill
1425 for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot)
1426 if (uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot)))
1427 if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id))
1428 if (enchantEntry->RequiredSkillID && player->GetSkillValue(enchantEntry->RequiredSkillID) < enchantEntry->RequiredSkillRank)
1429 return false;
1430
1431 return true;
1432}
1433
1435{
1436 uint32 level = 0;
1437
1438 // Check all enchants for required level
1439 for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot)
1440 if (uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot)))
1441 if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id))
1442 if (enchantEntry->MinLevel > level)
1443 level = enchantEntry->MinLevel;
1444
1445 return level;
1446}
1447
1449{
1450 // Check all enchants for soulbound
1451 for (uint32 enchant_slot = PERM_ENCHANTMENT_SLOT; enchant_slot < MAX_ENCHANTMENT_SLOT; ++enchant_slot)
1452 if (uint32 enchant_id = GetEnchantmentId(EnchantmentSlot(enchant_slot)))
1453 if (SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id))
1454 if (enchantEntry->GetFlags().HasFlag(SpellItemEnchantmentFlags::Soulbound))
1455 return true;
1456
1457 return false;
1458}
1459
1461{
1462 // not allow merge looting currently items
1463 if (m_lootGenerated)
1464 return EQUIP_ERR_LOOT_GONE;
1465
1466 // check item type
1467 if (GetEntry() != proto->GetId())
1468 return EQUIP_ERR_CANT_STACK;
1469
1470 // check free space (full stacks can't be target of merge
1471 if (GetCount() >= proto->GetMaxStackSize())
1472 return EQUIP_ERR_CANT_STACK;
1473
1474 return EQUIP_ERR_OK;
1475}
1476
1477bool Item::IsFitToSpellRequirements(SpellInfo const* spellInfo) const
1478{
1479 ItemTemplate const* proto = GetTemplate();
1480
1482 if (spellInfo->EquippedItemClass != -1) // -1 == any item class
1483 {
1484 if (isEnchantSpell && proto->HasFlag(ITEM_FLAG3_CAN_STORE_ENCHANTS))
1485 return true;
1486
1487 if (spellInfo->EquippedItemClass != int32(proto->GetClass()))
1488 return false; // wrong item class
1489
1490 if (spellInfo->EquippedItemSubClassMask != 0) // 0 == any subclass
1491 {
1492 if ((spellInfo->EquippedItemSubClassMask & (1 << proto->GetSubClass())) == 0)
1493 return false; // subclass not present in mask
1494 }
1495 }
1496
1497 if (isEnchantSpell && spellInfo->EquippedItemInventoryTypeMask != 0) // 0 == any inventory type
1498 {
1499 // Special case - accept weapon type for main and offhand requirements
1500 if (proto->GetInventoryType() == INVTYPE_WEAPON &&
1503 return true;
1504 else if ((spellInfo->EquippedItemInventoryTypeMask & (1 << proto->GetInventoryType())) == 0)
1505 return false; // inventory type not present in mask
1506 }
1507
1508 return true;
1509}
1510
1511void Item::SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint32 charges, ObjectGuid caster /*= ObjectGuid::Empty*/)
1512{
1513 // Better lost small time at check in comparison lost time at item save to DB.
1514 if ((GetEnchantmentId(slot) == id) && (GetEnchantmentDuration(slot) == duration) && (GetEnchantmentCharges(slot) == charges))
1515 return;
1516
1517 Player* owner = GetOwner();
1519 {
1520 if (SpellItemEnchantmentEntry const* oldEnchant = sSpellItemEnchantmentStore.LookupEntry(GetEnchantmentId(slot)))
1521 if (!oldEnchant->GetFlags().HasFlag(SpellItemEnchantmentFlags::DoNotLog))
1522 owner->GetSession()->SendEnchantmentLog(GetOwnerGUID(), ObjectGuid::Empty, GetGUID(), GetEntry(), oldEnchant->ID, slot);
1523
1524 if (SpellItemEnchantmentEntry const* newEnchant = sSpellItemEnchantmentStore.LookupEntry(id))
1525 if (!newEnchant->GetFlags().HasFlag(SpellItemEnchantmentFlags::DoNotLog))
1526 owner->GetSession()->SendEnchantmentLog(GetOwnerGUID(), caster, GetGUID(), GetEntry(), id, slot);
1527 }
1528
1529 ApplyArtifactPowerEnchantmentBonuses(slot, GetEnchantmentId(slot), false, owner);
1530 ApplyArtifactPowerEnchantmentBonuses(slot, id, true, owner);
1531
1532 auto enchantmentField = m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::Enchantment, slot);
1533 SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::ID), id);
1534 SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::Duration), duration);
1535 SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::Charges), charges);
1536 SetState(ITEM_CHANGED, owner);
1537}
1538
1540{
1541 if (GetEnchantmentDuration(slot) == duration)
1542 return;
1543
1545 SetState(ITEM_CHANGED, owner);
1546 // Cannot use GetOwner() here, has to be passed as an argument to avoid freeze due to hashtable locking
1547}
1548
1550{
1551 if (GetEnchantmentCharges(slot) == charges)
1552 return;
1553
1556}
1557
1559{
1560 if (!GetEnchantmentId(slot))
1561 return;
1562
1563 auto enchantmentField = m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::Enchantment, slot);
1564 SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::ID), 0);
1565 SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::Duration), 0);
1566 SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::Charges), 0);
1567 SetUpdateFieldValue(enchantmentField.ModifyValue(&UF::ItemEnchantment::Inactive), 0);
1569}
1570
1572{
1573 ASSERT(slot < MAX_GEM_SOCKETS);
1574 return slot < m_itemData->Gems.size() ? &m_itemData->Gems[slot] : nullptr;
1575}
1576
1577void Item::SetGem(uint16 slot, ItemDynamicFieldGems const* gem, uint32 gemScalingLevel)
1578{
1579 ASSERT(slot < MAX_GEM_SOCKETS);
1580 m_gemScalingLevels[slot] = gemScalingLevel;
1581 _bonusData.GemItemLevelBonus[slot] = 0;
1582 if (ItemTemplate const* gemTemplate = sObjectMgr->GetItemTemplate(gem->ItemId))
1583 {
1584 if (GemPropertiesEntry const* gemProperties = sGemPropertiesStore.LookupEntry(gemTemplate->GetGemProperties()))
1585 {
1586 if (SpellItemEnchantmentEntry const* gemEnchant = sSpellItemEnchantmentStore.LookupEntry(gemProperties->EnchantId))
1587 {
1588 BonusData gemBonus;
1589 gemBonus.Initialize(gemTemplate);
1590 for (uint16 bonusListId : gem->BonusListIDs)
1591 gemBonus.AddBonusList(bonusListId);
1592
1593 uint32 gemBaseItemLevel = gemBonus.ItemLevel;
1594 if (gemBonus.PlayerLevelToItemLevelCurveId)
1595 if (uint32 scaledIlvl = uint32(sDB2Manager.GetCurveValueAt(gemBonus.PlayerLevelToItemLevelCurveId, gemScalingLevel)))
1596 gemBaseItemLevel = scaledIlvl;
1597
1598 _bonusData.GemRelicType[slot] = gemBonus.RelicType;
1599
1600 for (uint32 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i)
1601 {
1602 switch (gemEnchant->Effect[i])
1603 {
1605 {
1606 for (ItemBonusEntry const* itemBonus : ItemBonusMgr::GetItemBonuses(gemEnchant->EffectArg[i]))
1607 if (itemBonus->Type == ITEM_BONUS_ITEM_LEVEL)
1608 _bonusData.GemItemLevelBonus[slot] += itemBonus->Value[0];
1609 break;
1610 }
1612 {
1614 for (ItemBonusEntry const* itemBonus : ItemBonusMgr::GetItemBonuses(bonusListId))
1615 if (itemBonus->Type == ITEM_BONUS_ITEM_LEVEL)
1616 _bonusData.GemItemLevelBonus[slot] += itemBonus->Value[0];
1617 break;
1618 }
1619 default:
1620 break;
1621 }
1622 }
1623 }
1624 }
1625 }
1626
1627 auto gemField = m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::Gems, slot);
1628 SetUpdateFieldValue(gemField.ModifyValue(&UF::SocketedGem::ItemID), gem->ItemId);
1629 SetUpdateFieldValue(gemField.ModifyValue(&UF::SocketedGem::Context), gem->Context);
1630 for (uint32 i = 0; i < 16; ++i)
1631 SetUpdateFieldValue(gemField.ModifyValue(&UF::SocketedGem::BonusListIDs, i), gem->BonusListIDs[i]);
1632}
1633
1635{
1636 for (uint32 gemSlot = 0; gemSlot < MAX_ITEM_PROTO_SOCKETS; ++gemSlot)
1637 {
1639
1640 if (!SocketColor) // no socket slot
1641 continue;
1642
1643 if (gemSlot >= m_itemData->Gems.size()) // no gems on this socket
1644 return false;
1645
1646 uint8 GemColor = 0;
1647
1648 uint32 gemid = m_itemData->Gems[gemSlot].ItemID;
1649 if (gemid)
1650 {
1651 ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemid);
1652 if (gemProto)
1653 {
1654 GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gemProto->GetGemProperties());
1655 if (gemProperty)
1656 GemColor = gemProperty->Type;
1657 }
1658 }
1659
1660 if (!(GemColor & SocketColorToGemTypeMask[SocketColor])) // bad gem color on this socket
1661 return false;
1662 }
1663 return true;
1664}
1665
1667{
1668 return uint8(std::count_if(m_itemData->Gems.begin(), m_itemData->Gems.end(), [GemID](UF::SocketedGem const& gemData)
1669 {
1670 return gemData.ItemID == int32(GemID);
1671 }));
1672}
1673
1675{
1676 return uint8(std::count_if(m_itemData->Gems.begin(), m_itemData->Gems.end(), [limitCategory](UF::SocketedGem const& gemData)
1677 {
1678 ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemData.ItemID);
1679 if (!gemProto)
1680 return false;
1681
1682 BonusData gemBonus;
1683 gemBonus.Initialize(gemProto);
1684
1685 for (uint16 bonusListID : gemData.BonusListIDs)
1686 gemBonus.AddBonusList(bonusListID);
1687
1688 return gemBonus.LimitCategory == limitCategory;
1689 }));
1690}
1691
1692bool Item::IsLimitedToAnotherMapOrZone(uint32 cur_mapId, uint32 cur_zoneId) const
1693{
1694 ItemTemplate const* proto = GetTemplate();
1695 return proto && ((proto->GetMap() && proto->GetMap() != cur_mapId) ||
1696 ((proto->GetArea(0) && proto->GetArea(0) != cur_zoneId) && (proto->GetArea(1) && proto->GetArea(1) != cur_zoneId)));
1697}
1698
1700{
1702 socketGems.Item = GetGUID();
1703 GetOwner()->GetSession()->SendPacket(socketGems.Write());
1704}
1705
1706// Though the client has the information in the item's data field,
1707// we have to send SMSG_ITEM_TIME_UPDATE to display the remaining
1708// time.
1710{
1711 uint32 duration = m_itemData->Expiration;
1712 if (!duration)
1713 return;
1714
1716 itemTimeUpdate.ItemGuid = GetGUID();
1717 itemTimeUpdate.DurationLeft = duration;
1718 owner->GetSession()->SendPacket(itemTimeUpdate.Write());
1719}
1720
1721Item* Item::CreateItem(uint32 itemEntry, uint32 count, ItemContext context, Player const* player /*= nullptr*/, bool addDefaultBonuses /*= true*/)
1722{
1723 if (count < 1)
1724 return nullptr; //don't create item at zero count
1725
1726 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry);
1727 if (proto)
1728 {
1729 if (count > proto->GetMaxStackSize())
1730 count = proto->GetMaxStackSize();
1731
1732 ASSERT_NODEBUGINFO(count != 0, "proto->Stackable == 0 but checked at loading already");
1733
1734 Item* item = NewItemOrBag(proto);
1735 if (item->Create(sObjectMgr->GetGenerator<HighGuid::Item>().Generate(), itemEntry, context, player))
1736 {
1737 item->SetCount(count);
1738 if (addDefaultBonuses)
1739 item->SetBonuses(ItemBonusMgr::GetBonusListsForItem(itemEntry, context));
1740
1741 return item;
1742 }
1743 else
1744 delete item;
1745 }
1746 else
1747 ABORT();
1748 return nullptr;
1749}
1750
1751Item* Item::CloneItem(uint32 count, Player const* player /*= nullptr*/) const
1752{
1753 Item* newItem = CreateItem(GetEntry(), count, GetContext(), player, false);
1754 if (!newItem)
1755 return nullptr;
1756
1757 newItem->SetCreator(GetCreator());
1758 newItem->SetGiftCreator(GetGiftCreator());
1760 newItem->SetExpiration(m_itemData->Expiration);
1761 newItem->SetBonuses(m_itemData->ItemBonusKey->BonusListIDs);
1763 // player CAN be NULL in which case we must not update random properties because that accesses player's item update queue
1764 if (player)
1766 return newItem;
1767}
1768
1769bool Item::IsBindedNotWith(Player const* player) const
1770{
1771 // not binded item
1772 if (!IsSoulBound())
1773 return false;
1774
1775 // own item
1776 if (GetOwnerGUID() == player->GetGUID())
1777 return false;
1778
1779 if (IsBOPTradeable())
1780 if (allowedGUIDs.find(player->GetGUID()) != allowedGUIDs.end())
1781 return false;
1782
1783 // BOA item case
1784 if (IsBoundAccountWide())
1785 return false;
1786
1787 return true;
1788}
1789
1791{
1793
1794 if (Player* owner = GetOwner())
1795 BuildFieldsUpdate(owner, data_map);
1796 ClearUpdateMask(false);
1797}
1798
1800{
1801 if (target->GetGUID() == GetOwnerGUID())
1803
1805}
1806
1808{
1809 m_objectData->WriteCreate(flags, data, target, this);
1810 m_itemData->WriteCreate(flags, data, target, this);
1811}
1812
1814{
1816
1818 m_objectData->WriteUpdate(flags, data, target, this);
1819
1821 m_itemData->WriteUpdate(flags, data, target, this);
1822}
1823
1825{
1827 valuesMask.Set(TYPEID_ITEM);
1828
1829 data << uint32(valuesMask.GetBlock(0));
1830
1831 UF::ItemData::Mask mask;
1833 m_itemData->WriteUpdate(mask, data, target, this, true);
1834}
1835
1837 UF::ItemData::Mask const& requestedItemMask, Player const* target, bool ignoreNestedChangesMask) const
1838{
1841 if (requestedObjectMask.IsAnySet())
1842 valuesMask.Set(TYPEID_OBJECT);
1843
1844 UF::ItemData::Mask itemMask = requestedItemMask;
1846 if (itemMask.IsAnySet())
1847 valuesMask.Set(TYPEID_ITEM);
1848
1849 ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
1850 std::size_t sizePos = buffer.wpos();
1851 buffer << uint32(0);
1853 buffer << uint32(valuesMask.GetBlock(0));
1854
1855 if (valuesMask[TYPEID_OBJECT])
1856 m_objectData->WriteUpdate(requestedObjectMask, buffer, target, this, ignoreNestedChangesMask);
1857
1858 if (valuesMask[TYPEID_ITEM])
1859 m_itemData->WriteUpdate(itemMask, buffer, target, this, ignoreNestedChangesMask);
1860
1861 buffer.put<uint32>(sizePos, buffer.wpos() - sizePos - 4);
1862
1863 data->AddUpdateBlock();
1864}
1865
1867{
1868 UpdateData udata(player->GetMapId());
1869 WorldPacket packet;
1870
1872
1873 udata.BuildPacket(&packet);
1874 player->SendDirectMessage(&packet);
1875}
1876
1882
1884{
1885 if (Player* owner = GetOwner())
1886 {
1887 owner->GetMap()->AddUpdateObject(this);
1888 return true;
1889 }
1890
1891 return false;
1892}
1893
1895{
1896 if (Player* owner = GetOwner())
1897 owner->GetMap()->RemoveUpdateObject(this);
1898}
1899
1901{
1902 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1903
1905 stmt->setUInt64(0, GetGUID().GetCounter());
1906 trans->Append(stmt);
1907
1908 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_REFUND_INSTANCE);
1909 stmt->setUInt64(0, GetGUID().GetCounter());
1910 stmt->setUInt64(1, GetRefundRecipient().GetCounter());
1911 stmt->setUInt64(2, GetPaidMoney());
1913 trans->Append(stmt);
1914
1915 CharacterDatabase.CommitTransaction(trans);
1916}
1917
1919{
1920 if (trans)
1921 {
1923 stmt->setUInt64(0, GetGUID().GetCounter());
1924 (*trans)->Append(stmt);
1925
1926 }
1927}
1928
1929void Item::SetNotRefundable(Player* owner, bool changestate /*= true*/, CharacterDatabaseTransaction* trans /*= nullptr*/, bool addToCollection /*= true*/)
1930{
1931 if (!IsRefundable())
1932 return;
1933
1934 WorldPackets::Item::ItemExpirePurchaseRefund itemExpirePurchaseRefund;
1935 itemExpirePurchaseRefund.ItemGUID = GetGUID();
1936 owner->SendDirectMessage(itemExpirePurchaseRefund.Write());
1937
1939 // Following is not applicable in the trading procedure
1940 if (changestate)
1941 SetState(ITEM_CHANGED, owner);
1942
1944 SetPaidMoney(0);
1947
1949 if (addToCollection)
1951}
1952
1954{
1955 return *m_itemData->CreatePlayedTime;
1956}
1957
1959{
1960 return *m_itemData->CreateTime + 2 * HOUR <= GameTime::GetGameTime();
1961}
1962
1963void Item::SetSoulboundTradeable(GuidSet const& allowedLooters)
1964{
1966 allowedGUIDs = allowedLooters;
1967}
1968
1970{
1972 if (allowedGUIDs.empty())
1973 return;
1974
1975 currentOwner->GetSession()->GetCollectionMgr()->AddItemAppearance(this);
1976 allowedGUIDs.clear();
1977 SetState(ITEM_CHANGED, currentOwner);
1979 stmt->setUInt64(0, GetGUID().GetCounter());
1980 CharacterDatabase.Execute(stmt);
1981}
1982
1984{
1985 // called from owner's update - GetOwner() MUST be valid
1986 if (m_itemData->CreatePlayedTime + 4 * HOUR < GetOwner()->GetTotalPlayedTime())
1987 {
1989 return true; // remove from tradeable list
1990 }
1991
1992 return false;
1993}
1994
1996{
1997 ItemTemplate const* proto = GetTemplate();
1998 if (!proto)
1999 return false;
2000
2001 if (proto->GetClass() != ITEM_CLASS_ARMOR &&
2002 proto->GetClass() != ITEM_CLASS_WEAPON)
2003 return false;
2004
2006 return false;
2007
2009 return false;
2010
2011 return true;
2012}
2013
2015{
2016 -1, // INVTYPE_NON_EQUIP
2017 EQUIPMENT_SLOT_HEAD, // INVTYPE_HEAD
2018 -1, // INVTYPE_NECK
2019 EQUIPMENT_SLOT_SHOULDERS, // INVTYPE_SHOULDERS
2020 EQUIPMENT_SLOT_BODY, // INVTYPE_BODY
2021 EQUIPMENT_SLOT_CHEST, // INVTYPE_CHEST
2022 EQUIPMENT_SLOT_WAIST, // INVTYPE_WAIST
2023 EQUIPMENT_SLOT_LEGS, // INVTYPE_LEGS
2024 EQUIPMENT_SLOT_FEET, // INVTYPE_FEET
2025 EQUIPMENT_SLOT_WRISTS, // INVTYPE_WRISTS
2026 EQUIPMENT_SLOT_HANDS, // INVTYPE_HANDS
2027 -1, // INVTYPE_FINGER
2028 -1, // INVTYPE_TRINKET
2029 EQUIPMENT_SLOT_MAINHAND, // INVTYPE_WEAPON
2030 EQUIPMENT_SLOT_OFFHAND, // INVTYPE_SHIELD
2031 EQUIPMENT_SLOT_MAINHAND, // INVTYPE_RANGED
2032 EQUIPMENT_SLOT_BACK, // INVTYPE_CLOAK
2033 EQUIPMENT_SLOT_MAINHAND, // INVTYPE_2HWEAPON
2034 -1, // INVTYPE_BAG
2035 EQUIPMENT_SLOT_TABARD, // INVTYPE_TABARD
2036 EQUIPMENT_SLOT_CHEST, // INVTYPE_ROBE
2037 EQUIPMENT_SLOT_MAINHAND, // INVTYPE_WEAPONMAINHAND
2038 EQUIPMENT_SLOT_MAINHAND, // INVTYPE_WEAPONOFFHAND
2039 EQUIPMENT_SLOT_OFFHAND, // INVTYPE_HOLDABLE
2040 -1, // INVTYPE_AMMO
2041 -1, // INVTYPE_THROWN
2042 EQUIPMENT_SLOT_MAINHAND, // INVTYPE_RANGEDRIGHT
2043 -1, // INVTYPE_QUIVER
2044 -1, // INVTYPE_RELIC
2045 -1, // INVTYPE_PROFESSION_TOOL
2046 -1, // INVTYPE_PROFESSION_GEAR
2047 -1, // INVTYPE_EQUIPABLE_SPELL_OFFENSIVE
2048 -1, // INVTYPE_EQUIPABLE_SPELL_UTILITY
2049 -1, // INVTYPE_EQUIPABLE_SPELL_DEFENSIVE
2050 -1 // INVTYPE_EQUIPABLE_SPELL_MOBILITY
2051};
2052
2053bool Item::CanTransmogrifyItemWithItem(Item const* item, ItemModifiedAppearanceEntry const* itemModifiedAppearance)
2054{
2055 ItemTemplate const* source = sObjectMgr->GetItemTemplate(itemModifiedAppearance->ItemID); // source
2056 ItemTemplate const* target = item->GetTemplate(); // dest
2057
2058 if (!source || !target)
2059 return false;
2060
2061 if (itemModifiedAppearance == item->GetItemModifiedAppearance())
2062 return false;
2063
2065 return false;
2066
2067 if (source->GetClass() != target->GetClass())
2068 return false;
2069
2070 if (source->GetInventoryType() == INVTYPE_BAG ||
2071 source->GetInventoryType() == INVTYPE_RELIC ||
2072 source->GetInventoryType() == INVTYPE_FINGER ||
2073 source->GetInventoryType() == INVTYPE_TRINKET ||
2074 source->GetInventoryType() == INVTYPE_AMMO ||
2075 source->GetInventoryType() == INVTYPE_QUIVER)
2076 return false;
2077
2078 if (source->GetSubClass() != target->GetSubClass())
2079 {
2080 switch (source->GetClass())
2081 {
2082 case ITEM_CLASS_WEAPON:
2084 return false;
2085 break;
2086 case ITEM_CLASS_ARMOR:
2088 return false;
2089 if (source->GetInventoryType() != target->GetInventoryType())
2091 return false;
2092 break;
2093 default:
2094 return false;
2095 }
2096 }
2097
2098 return true;
2099}
2100
2101uint32 Item::GetBuyPrice(Player const* owner, bool& standardPrice) const
2102{
2103 return Item::GetBuyPrice(GetTemplate(), GetQuality(), GetItemLevel(owner), standardPrice);
2104}
2105
2106uint32 Item::GetBuyPrice(ItemTemplate const* proto, uint32 quality, uint32 itemLevel, bool& standardPrice)
2107{
2108 standardPrice = false;
2109
2111 return proto->GetBuyPrice();
2112
2113 ImportPriceQualityEntry const* qualityPrice = sImportPriceQualityStore.LookupEntry(quality + 1);
2114 if (!qualityPrice)
2115 return 0;
2116
2117 ItemPriceBaseEntry const* basePrice = sItemPriceBaseStore.LookupEntry(itemLevel);
2118 if (!basePrice)
2119 return 0;
2120
2121 float qualityFactor = qualityPrice->Data;
2122 float baseFactor = 0.0f;
2123
2124 uint32 inventoryType = proto->GetInventoryType();
2125
2126 if (inventoryType == INVTYPE_WEAPON ||
2127 inventoryType == INVTYPE_2HWEAPON ||
2128 inventoryType == INVTYPE_WEAPONMAINHAND ||
2129 inventoryType == INVTYPE_WEAPONOFFHAND ||
2130 inventoryType == INVTYPE_RANGED ||
2131 inventoryType == INVTYPE_THROWN ||
2132 inventoryType == INVTYPE_RANGEDRIGHT)
2133 baseFactor = basePrice->Weapon;
2134 else
2135 baseFactor = basePrice->Armor;
2136
2137 if (inventoryType == INVTYPE_ROBE)
2138 inventoryType = INVTYPE_CHEST;
2139
2141 {
2142 inventoryType = INVTYPE_WEAPON;
2143 baseFactor = basePrice->Weapon / 3.0f;
2144 }
2145
2146 float typeFactor = 0.0f;
2147 int8 weapType = -1;
2148
2149 switch (inventoryType)
2150 {
2151 case INVTYPE_HEAD:
2152 case INVTYPE_NECK:
2153 case INVTYPE_SHOULDERS:
2154 case INVTYPE_CHEST:
2155 case INVTYPE_WAIST:
2156 case INVTYPE_LEGS:
2157 case INVTYPE_FEET:
2158 case INVTYPE_WRISTS:
2159 case INVTYPE_HANDS:
2160 case INVTYPE_FINGER:
2161 case INVTYPE_TRINKET:
2162 case INVTYPE_CLOAK:
2163 case INVTYPE_HOLDABLE:
2164 {
2165 ImportPriceArmorEntry const* armorPrice = sImportPriceArmorStore.LookupEntry(inventoryType);
2166 if (!armorPrice)
2167 return 0;
2168
2169 switch (proto->GetSubClass())
2170 {
2173 typeFactor = armorPrice->ClothModifier;
2174 break;
2176 typeFactor = armorPrice->LeatherModifier;
2177 break;
2179 typeFactor = armorPrice->ChainModifier;
2180 break;
2182 typeFactor = armorPrice->PlateModifier;
2183 break;
2184 default:
2185 typeFactor = 1.0f;
2186 break;
2187 }
2188
2189 break;
2190 }
2191 case INVTYPE_SHIELD:
2192 {
2193 ImportPriceShieldEntry const* shieldPrice = sImportPriceShieldStore.LookupEntry(2);
2194 if (!shieldPrice)
2195 return 0;
2196
2197 typeFactor = shieldPrice->Data;
2198 break;
2199 }
2201 weapType = 0;
2202 break;
2204 weapType = 1;
2205 break;
2206 case INVTYPE_WEAPON:
2207 weapType = 2;
2208 break;
2209 case INVTYPE_2HWEAPON:
2210 weapType = 3;
2211 break;
2212 case INVTYPE_RANGED:
2214 case INVTYPE_RELIC:
2215 weapType = 4;
2216 break;
2217 default:
2218 return proto->GetBuyPrice();
2219 }
2220
2221 if (weapType != -1)
2222 {
2223 ImportPriceWeaponEntry const* weaponPrice = sImportPriceWeaponStore.LookupEntry(weapType + 1);
2224 if (!weaponPrice)
2225 return 0;
2226
2227 typeFactor = weaponPrice->Data;
2228 }
2229
2230 standardPrice = true;
2231 return uint32(proto->GetPriceVariance() * typeFactor * baseFactor * qualityFactor * proto->GetPriceRandomValue());
2232}
2233
2235{
2237}
2238
2239uint32 Item::GetSellPrice(ItemTemplate const* proto, uint32 quality, uint32 itemLevel)
2240{
2242 return proto->GetSellPrice();
2243 else
2244 {
2245 bool standardPrice;
2246 uint32 cost = Item::GetBuyPrice(proto, quality, itemLevel, standardPrice);
2247
2248 if (standardPrice)
2249 {
2250 if (ItemClassEntry const* classEntry = sDB2Manager.GetItemClassByOldEnum(proto->GetClass()))
2251 {
2252 uint32 buyCount = std::max(proto->GetBuyCount(), 1u);
2253 return cost * classEntry->PriceModifier / buyCount;
2254 }
2255
2256 return 0;
2257 }
2258 else
2259 return proto->GetSellPrice();
2260 }
2261
2262 return 0;
2263}
2264
2266{
2267 ItemTemplate const* itemTemplate = GetTemplate();
2268 uint32 minItemLevel = owner->m_unitData->MinItemLevel;
2269 uint32 minItemLevelCutoff = owner->m_unitData->MinItemLevelCutoff;
2270 bool pvpBonus = owner->IsUsingPvpItemLevels();
2271 uint32 maxItemLevel = pvpBonus && itemTemplate->HasFlag(ITEM_FLAG3_IGNORE_ITEM_LEVEL_CAP_IN_PVP) ? 0 : owner->m_unitData->MaxItemLevel;
2272 uint32 azeriteLevel = 0;
2273 if (AzeriteItem const* azeriteItem = ToAzeriteItem())
2274 azeriteLevel = azeriteItem->GetEffectiveLevel();
2276 minItemLevel, minItemLevelCutoff, maxItemLevel, pvpBonus, azeriteLevel);
2277}
2278
2279uint32 Item::GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bonusData, uint32 level, uint32 fixedLevel,
2280 uint32 minItemLevel, uint32 minItemLevelCutoff, uint32 maxItemLevel, bool pvpBonus, uint32 azeriteLevel)
2281{
2282 if (!itemTemplate)
2283 return MIN_ITEM_LEVEL;
2284
2285 uint32 itemLevel = bonusData.ItemLevel;
2286 if (AzeriteLevelInfoEntry const* azeriteLevelInfo = sAzeriteLevelInfoStore.LookupEntry(azeriteLevel))
2287 itemLevel = azeriteLevelInfo->ItemLevel;
2288
2289 if (!bonusData.ItemLevelOffsetCurveId)
2290 {
2291 if (bonusData.PlayerLevelToItemLevelCurveId)
2292 {
2293 if (fixedLevel)
2294 level = fixedLevel;
2295 else if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(bonusData.ContentTuningId, {}, true))
2296 level = std::min(std::max(int16(level), levels->MinLevel), levels->MaxLevel);
2297
2298 itemLevel = uint32(sDB2Manager.GetCurveValueAt(bonusData.PlayerLevelToItemLevelCurveId, level));
2299 }
2300
2301 itemLevel += bonusData.ItemLevelBonus;
2302 }
2303 else
2304 itemLevel = bonusData.ItemLevelOffset + uint32(sDB2Manager.GetCurveValueAt(bonusData.ItemLevelOffsetCurveId, bonusData.ItemLevelOffsetItemLevel));
2305
2306 for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i)
2307 itemLevel += bonusData.GemItemLevelBonus[i];
2308
2309 uint32 itemLevelBeforeUpgrades = itemLevel;
2310
2311 if (pvpBonus)
2312 {
2313 if (bonusData.PvpItemLevel)
2314 itemLevel = bonusData.PvpItemLevel;
2315
2316 itemLevel += bonusData.PvpItemLevelBonus;
2317 }
2318
2319 if (!bonusData.IgnoreSquish)
2320 {
2321 if (std::shared_ptr<Realm const> currentRealm = sRealmList->GetCurrentRealm())
2322 {
2323 int32 currentBuild = ClientBuild::GetMinorMajorBugfixVersionForBuild(currentRealm->Build);
2324
2325 // apply all squishes between items_squish and server_squish
2326 for (uint32 squishId = bonusData.ItemSquishEraID; squishId < sItemSquishEraStore.GetNumRows(); ++squishId)
2327 {
2328 ItemSquishEraEntry const* squish = sItemSquishEraStore.LookupEntry(squishId);
2329 if (!squish)
2330 continue;
2331
2332 if (squish->Patch > currentBuild)
2333 break;
2334
2335 if (squish->CurveID)
2336 itemLevel = uint32(sDB2Manager.GetCurveValueAt(squish->CurveID, itemLevel));
2337 }
2338 }
2339 }
2340
2341 if (itemTemplate->GetInventoryType() != INVTYPE_NON_EQUIP)
2342 {
2343 if (minItemLevel && (!minItemLevelCutoff || itemLevelBeforeUpgrades >= minItemLevelCutoff) && itemLevel < minItemLevel)
2344 itemLevel = minItemLevel;
2345
2346 if (maxItemLevel && itemLevel > maxItemLevel)
2347 itemLevel = maxItemLevel;
2348 }
2349
2350 return std::min(std::max(itemLevel, uint32(MIN_ITEM_LEVEL)), uint32(MAX_ITEM_LEVEL));
2351}
2352
2353float Item::GetItemStatValue(uint32 index, Player const* owner) const
2354{
2356 switch (GetItemStatType(index))
2357 {
2360 return _bonusData.StatPercentEditor[index];
2361 default:
2362 break;
2363 }
2364
2365 uint32 itemLevel = GetItemLevel(owner);
2366 if (float randomPropPoints = GetRandomPropertyPoints(itemLevel, GetQuality(), GetTemplate()->GetInventoryType(), GetTemplate()->GetSubClass()))
2367 {
2368 float statValue = float(_bonusData.StatPercentEditor[index] * randomPropPoints) * 0.0001f;
2369 if (GtItemSocketCostPerLevelEntry const* gtCost = sItemSocketCostPerLevelGameTable.GetRow(itemLevel))
2370 statValue -= float(int32(_bonusData.ItemStatSocketCostMultiplier[index] * gtCost->SocketCost));
2371
2372 return statValue;
2373 }
2374
2375 return 0.0f;
2376}
2377
2379{
2381 return {};
2382
2385
2386 // ignore temporary item level scaling (pvp or timewalking)
2388
2389 ItemDisenchantLootEntry const* disenchantLoot = GetBaseDisenchantLoot(GetTemplate(), GetQuality(), itemLevel);
2390 if (!disenchantLoot)
2391 return {};
2392
2393 return disenchantLoot->ID;
2394}
2395
2397{
2399 return {};
2400
2401 // ignore temporary item level scaling (pvp or timewalking)
2403
2404 ItemDisenchantLootEntry const* disenchantLoot = GetBaseDisenchantLoot(GetTemplate(), GetQuality(), itemLevel);
2405 if (!disenchantLoot)
2406 return {};
2407
2408 return disenchantLoot->SkillRequired;
2409}
2410
2412{
2413 if (itemTemplate->HasFlag(ITEM_FLAG_CONJURED) || itemTemplate->HasFlag(ITEM_FLAG_NO_DISENCHANT) || itemTemplate->GetBonding() == BIND_QUEST)
2414 return nullptr;
2415
2416 if (itemTemplate->GetArea(0) || itemTemplate->GetArea(1) || itemTemplate->GetMap() || itemTemplate->GetMaxStackSize() > 1)
2417 return nullptr;
2418
2419 if (!Item::GetSellPrice(itemTemplate, quality, itemLevel) && !sDB2Manager.HasItemCurrencyCost(itemTemplate->GetId()))
2420 return nullptr;
2421
2422 uint32 itemClass = itemTemplate->GetClass();
2423 int8 itemSubClass = itemTemplate->GetSubClass();
2424 uint8 expansion = itemTemplate->GetRequiredExpansion();
2425 for (ItemDisenchantLootEntry const* disenchant : sItemDisenchantLootStore)
2426 {
2427 if (disenchant->Class != itemClass)
2428 continue;
2429
2430 if (disenchant->Subclass >= 0 && itemSubClass)
2431 continue;
2432
2433 if (disenchant->Quality != quality)
2434 continue;
2435
2436 if (disenchant->MinLevel > itemLevel || disenchant->MaxLevel < itemLevel)
2437 continue;
2438
2439 if (disenchant->ExpansionID != -2 && disenchant->ExpansionID != expansion)
2440 continue;
2441
2442 return disenchant;
2443 }
2444
2445 return nullptr;
2446}
2447
2449{
2450 uint32 itemModifiedAppearanceId = GetModifier(AppearanceModifierSlotBySpec[owner->GetActiveTalentGroup()]);
2451 if (!itemModifiedAppearanceId)
2452 itemModifiedAppearanceId = GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS);
2453
2454 ItemModifiedAppearanceEntry const* itemModifiedAppearance = sItemModifiedAppearanceStore.LookupEntry(itemModifiedAppearanceId);
2455 if (!itemModifiedAppearance)
2456 itemModifiedAppearance = GetItemModifiedAppearance();
2457
2458 if (itemModifiedAppearance)
2459 if (ItemAppearanceEntry const* itemAppearance = sItemAppearanceStore.LookupEntry(itemModifiedAppearance->ItemAppearanceID))
2460 return itemAppearance->ItemDisplayInfoID;
2461
2462 return 0;
2463}
2464
2469
2471{
2472 int32 modifierIndex = m_itemData->Modifiers->Values.FindIndexIf([modifier](UF::ItemMod mod)
2473 {
2474 return mod.Type == modifier;
2475 });
2476
2477 if (modifierIndex != -1)
2478 return m_itemData->Modifiers->Values[modifierIndex].Value;
2479
2480 return 0;
2481}
2482
2484{
2485 int32 modifierIndex = m_itemData->Modifiers->Values.FindIndexIf([modifier](UF::ItemMod mod)
2486 {
2487 return mod.Type == modifier;
2488 });
2489
2490 if (value)
2491 {
2492 if (modifierIndex == -1)
2493 {
2495 .ModifyValue(&UF::ItemData::Modifiers).ModifyValue(&UF::ItemModList::Values));
2496
2497 mod.Value = value;
2498 mod.Type = modifier;
2499 }
2500 else
2502 .ModifyValue(&UF::ItemData::Modifiers)
2503 .ModifyValue(&UF::ItemModList::Values, modifierIndex)
2504 .ModifyValue(&UF::ItemMod::Value), value);
2505 }
2506 else
2507 {
2508 if (modifierIndex == -1)
2509 return;
2510
2512 }
2513}
2514
2516{
2517 uint32 itemModifiedAppearanceId = GetModifier(AppearanceModifierSlotBySpec[owner->GetActiveTalentGroup()]);
2518 if (!itemModifiedAppearanceId)
2519 itemModifiedAppearanceId = GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS);
2520
2521 if (ItemModifiedAppearanceEntry const* transmog = sItemModifiedAppearanceStore.LookupEntry(itemModifiedAppearanceId))
2522 return transmog->ItemID;
2523
2524 return GetEntry();
2525}
2526
2528{
2529 uint32 itemModifiedAppearanceId = GetModifier(AppearanceModifierSlotBySpec[owner->GetActiveTalentGroup()]);
2530 if (!itemModifiedAppearanceId)
2531 itemModifiedAppearanceId = GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS);
2532
2533 if (ItemModifiedAppearanceEntry const* transmog = sItemModifiedAppearanceStore.LookupEntry(itemModifiedAppearanceId))
2534 return transmog->ItemAppearanceModifierID;
2535
2536 return uint16(GetAppearanceModId());
2537}
2538
2540{
2541 uint32 itemModifiedAppearanceId = GetModifier(AppearanceModifierSlotBySpec[owner->GetActiveTalentGroup()]);
2542 if (!itemModifiedAppearanceId)
2543 itemModifiedAppearanceId = GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS);
2544
2545 if (!itemModifiedAppearanceId)
2546 if (ItemModifiedAppearanceEntry const* itemModifiedAppearance = GetItemModifiedAppearance())
2547 itemModifiedAppearanceId = itemModifiedAppearance->ID;
2548
2549 return itemModifiedAppearanceId;
2550}
2551
2553{
2555 if (!itemModifiedAppearanceId)
2557
2558 return itemModifiedAppearanceId;
2559}
2560
2562{
2564 if (!enchantmentId)
2566
2567 if (!enchantmentId)
2568 enchantmentId = GetEnchantmentId(PERM_ENCHANTMENT_SLOT);
2569
2570 return enchantmentId;
2571}
2572
2574{
2575 if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(GetVisibleEnchantmentId(owner)))
2576 return enchant->ItemVisual;
2577
2578 return 0;
2579}
2580
2581void Item::AddBonuses(uint32 bonusListID)
2582{
2583 if (advstd::ranges::contains(GetBonusListIDs(), int32(bonusListID)))
2584 return;
2585
2587 itemBonusKey.ItemID = GetEntry();
2588 itemBonusKey.BonusListIDs = GetBonusListIDs();
2589 itemBonusKey.BonusListIDs.push_back(bonusListID);
2591 for (ItemBonusEntry const* bonus : ItemBonusMgr::GetItemBonuses(bonusListID))
2592 _bonusData.AddBonus(bonus->Type, bonus->Value);
2594}
2595
2596void Item::SetBonuses(std::vector<int32> bonusListIDs)
2597{
2599 itemBonusKey.ItemID = GetEntry();
2600 itemBonusKey.BonusListIDs = std::move(bonusListIDs);
2602
2603 for (int32 bonusListID : GetBonusListIDs())
2604 _bonusData.AddBonusList(bonusListID);
2605
2607}
2608
2617
2619{
2620 if (ArtifactEntry const* artifact = sArtifactStore.LookupEntry(GetTemplate()->GetArtifactID()))
2621 return artifact->ArtifactCategoryID != 2; // fishing artifact
2622
2623 return true;
2624}
2625
2627{
2628 return m_itemData->ArtifactPowers.FindIndexIf([artifactPowerId](UF::ArtifactPower const& artifactPower)
2629 {
2630 return uint32(artifactPower.ArtifactPowerID) == artifactPowerId;
2631 });
2632}
2633
2635{
2636 int32 index = GetArtifactPowerIndex(artifactPowerId);
2637 if (index >= 0)
2638 return &m_itemData->ArtifactPowers[index];
2639
2640 return nullptr;
2641}
2642
2644{
2646 powerField.ArtifactPowerID = artifactPower->ArtifactPowerId;
2647 powerField.PurchasedRank = artifactPower->PurchasedRank;
2648 powerField.CurrentRankWithBonus = artifactPower->CurrentRankWithBonus;
2649}
2650
2651void Item::SetArtifactPower(uint16 artifactPowerId, uint8 purchasedRank, uint8 currentRankWithBonus)
2652{
2653 int32 index = GetArtifactPowerIndex(artifactPowerId);
2654 if (index >= 0)
2655 {
2657 .ModifyValue(&UF::ItemData::ArtifactPowers, index)
2658 .ModifyValue(&UF::ArtifactPower::PurchasedRank), purchasedRank);
2659
2661 .ModifyValue(&UF::ItemData::ArtifactPowers, index)
2662 .ModifyValue(&UF::ArtifactPower::CurrentRankWithBonus), currentRankWithBonus);
2663 }
2664}
2665
2666void Item::InitArtifactPowers(uint8 artifactId, uint8 artifactTier)
2667{
2668 std::unordered_set<uint32> knownPowers;
2669 for (UF::ArtifactPower const& power : m_itemData->ArtifactPowers)
2670 knownPowers.insert(power.ArtifactPowerID);
2671
2672 for (ArtifactPowerEntry const* artifactPower : sDB2Manager.GetArtifactPowers(artifactId))
2673 {
2674 if (artifactPower->Tier != artifactTier)
2675 continue;
2676
2677 if (knownPowers.contains(artifactPower->ID))
2678 continue;
2679
2680 ArtifactPowerData powerData;
2681 powerData.ArtifactPowerId = artifactPower->ID;
2682 powerData.PurchasedRank = 0;
2683 powerData.CurrentRankWithBonus = (artifactPower->Flags & ARTIFACT_POWER_FLAG_FIRST) == ARTIFACT_POWER_FLAG_FIRST ? 1 : 0;
2684 AddArtifactPower(&powerData);
2685 }
2686}
2687
2689{
2691 uint64 artifactXp = m_itemData->ArtifactXP;
2692 uint32 currentArtifactTier = GetModifier(ITEM_MODIFIER_ARTIFACT_TIER);
2693 uint32 extraUnlocked = 0;
2694 do
2695 {
2696 uint64 xpCost = 0;
2697 if (GtArtifactLevelXPEntry const* cost = sArtifactLevelXPGameTable.GetRow(purchased + extraUnlocked + 1))
2698 xpCost = uint64(currentArtifactTier == MAX_ARTIFACT_TIER ? cost->XP2 : cost->XP);
2699
2700 if (artifactXp < xpCost)
2701 break;
2702
2703 artifactXp -= xpCost;
2704 ++extraUnlocked;
2705
2706 } while (true);
2707
2708 return purchased + extraUnlocked;
2709}
2710
2712{
2713 uint32 purchasedRanks = 0;
2714 for (UF::ArtifactPower const& power : m_itemData->ArtifactPowers)
2715 purchasedRanks += power.PurchasedRank;
2716
2717 return purchasedRanks;
2718}
2719
2721{
2722 if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId))
2723 {
2724 for (uint32 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i)
2725 {
2726 switch (enchant->Effect[i])
2727 {
2729 for (uint32 artifactPowerIndex = 0; artifactPowerIndex < m_itemData->ArtifactPowers.size(); ++artifactPowerIndex)
2730 {
2731 UF::ArtifactPower const& artifactPower = m_itemData->ArtifactPowers[artifactPowerIndex];
2732 if (uint32(sArtifactPowerStore.AssertEntry(artifactPower.ArtifactPowerID)->Label) == enchant->EffectArg[i])
2733 {
2734 uint8 newRank = artifactPower.CurrentRankWithBonus;
2735 if (apply)
2736 newRank += enchant->EffectPointsMin[i];
2737 else
2738 newRank -= enchant->EffectPointsMin[i];
2739
2741 .ModifyValue(&UF::ItemData::ArtifactPowers, artifactPowerIndex)
2742 .ModifyValue(&UF::ArtifactPower::CurrentRankWithBonus), newRank);
2743
2744 if (IsEquipped())
2745 if (ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower.ArtifactPowerID, newRank ? newRank - 1 : 0))
2746 owner->ApplyArtifactPowerRank(this, artifactPowerRank, newRank != 0);
2747 }
2748 }
2749 break;
2751 {
2752 if (int32 artifactPowerIndex = GetArtifactPowerIndex(enchant->EffectArg[i]); artifactPowerIndex >= 0)
2753 {
2754 uint8 newRank = m_itemData->ArtifactPowers[artifactPowerIndex].CurrentRankWithBonus;
2755 if (apply)
2756 newRank += enchant->EffectPointsMin[i];
2757 else
2758 newRank -= enchant->EffectPointsMin[i];
2759
2761 .ModifyValue(&UF::ItemData::ArtifactPowers, artifactPowerIndex)
2762 .ModifyValue(&UF::ArtifactPower::CurrentRankWithBonus), newRank);
2763
2764 if (IsEquipped())
2765 if (ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(m_itemData->ArtifactPowers[artifactPowerIndex].ArtifactPowerID, newRank ? newRank - 1 : 0))
2766 owner->ApplyArtifactPowerRank(this, artifactPowerRank, newRank != 0);
2767 }
2768 break;
2769 }
2772 {
2773 if (ArtifactPowerPickerEntry const* artifactPowerPicker = sArtifactPowerPickerStore.LookupEntry(enchant->EffectArg[i]))
2774 {
2775 if (ConditionMgr::IsPlayerMeetingCondition(owner, artifactPowerPicker->PlayerConditionID))
2776 {
2777 for (uint32 artifactPowerIndex = 0; artifactPowerIndex < m_itemData->ArtifactPowers.size(); ++artifactPowerIndex)
2778 {
2779 UF::ArtifactPower const& artifactPower = m_itemData->ArtifactPowers[artifactPowerIndex];
2780 if (sArtifactPowerStore.AssertEntry(artifactPower.ArtifactPowerID)->Label == _bonusData.GemRelicType[slot - SOCK_ENCHANTMENT_SLOT])
2781 {
2782 uint8 newRank = artifactPower.CurrentRankWithBonus;
2783 if (apply)
2784 newRank += enchant->EffectPointsMin[i];
2785 else
2786 newRank -= enchant->EffectPointsMin[i];
2787
2789 .ModifyValue(&UF::ItemData::ArtifactPowers, artifactPowerIndex)
2790 .ModifyValue(&UF::ArtifactPower::CurrentRankWithBonus), newRank);
2791
2792 if (IsEquipped())
2793 if (ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower.ArtifactPowerID, newRank ? newRank - 1 : 0))
2794 owner->ApplyArtifactPowerRank(this, artifactPowerRank, newRank != 0);
2795 }
2796 }
2797 }
2798 }
2799 }
2800 break;
2801 default:
2802 break;
2803 }
2804 }
2805 }
2806}
2807
2814
2815void Item::GiveArtifactXp(uint64 amount, Item* sourceItem, uint32 artifactCategoryId)
2816{
2817 Player* owner = GetOwner();
2818 if (!owner)
2819 return;
2820
2821 if (artifactCategoryId)
2822 {
2823 uint32 artifactKnowledgeLevel = 1;
2824 if (sourceItem && sourceItem->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL))
2825 artifactKnowledgeLevel = sourceItem->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL);
2826
2827 if (GtArtifactKnowledgeMultiplierEntry const* artifactKnowledge = sArtifactKnowledgeMultiplierGameTable.GetRow(artifactKnowledgeLevel))
2828 amount = uint64(amount * artifactKnowledge->Multiplier);
2829
2830 if (amount >= 5000)
2831 amount = 50 * (amount / 50);
2832 else if (amount >= 1000)
2833 amount = 25 * (amount / 25);
2834 else if (amount >= 50)
2835 amount = 5 * (amount / 5);
2836 }
2837
2838 SetArtifactXP(m_itemData->ArtifactXP + amount);
2839
2841 artifactXpGain.ArtifactGUID = GetGUID();
2842 artifactXpGain.Amount = amount;
2843 owner->SendDirectMessage(artifactXpGain.Write());
2844
2845 SetState(ITEM_CHANGED, owner);
2846
2848}
2849
2851{
2853 return;
2854
2856 {
2857 if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(_bonusData.ContentTuningId, {}, true))
2858 level = std::min(std::max(int16(level), levels->MinLevel), levels->MaxLevel);
2859
2861 }
2862}
2863
2875
2876std::string Item::GetDebugInfo() const
2877{
2878 std::stringstream sstr;
2879 sstr << Object::GetDebugInfo() << "\n"
2880 << std::boolalpha
2881 << "Owner: " << GetOwnerGUID().ToString() << " Count: " << GetCount()
2882 << " BagSlot: " << std::to_string(GetBagSlot()) << " Slot: " << std::to_string(GetSlot()) << " Equipped: " << IsEquipped();
2883 return sstr.str();
2884}
2885
2887{
2888 Quality = proto->GetQuality();
2889 ItemLevel = proto->GetBaseItemLevel();
2890 ItemLevelBonus = 0;
2891 RequiredLevel = proto->GetBaseRequiredLevel();
2892 for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
2893 {
2894 ItemStatType[i] = proto->GetStatModifierBonusStat(i);
2895 StatPercentEditor[i] = proto->GetStatPercentEditor(i);
2896 ItemStatSocketCostMultiplier[i] = proto->GetStatPercentageOfSocket(i);
2897 }
2898
2899 for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i)
2900 {
2901 SocketColor[i] = proto->GetSocketColor(i);
2902 GemItemLevelBonus[i] = 0;
2903 GemRelicType[i] = -1;
2904 GemRelicRankBonus[i] = 0;
2905 }
2906
2907 Bonding = proto->GetBonding();
2908
2909 AppearanceModID = 0;
2910 RepairCostMultiplier = 1.0f;
2911 ContentTuningId = proto->GetScalingStatContentTuning();
2912 PlayerLevelToItemLevelCurveId = proto->GetPlayerLevelToItemLevelCurveId();
2913 DisenchantLootId = 0;
2914 RelicType = -1;
2915 HasFixedLevel = false;
2916 RequiredLevelOverride = 0;
2917 AzeriteTierUnlockSetId = 0;
2918 if (AzeriteEmpoweredItemEntry const* azeriteEmpoweredItem = sDB2Manager.GetAzeriteEmpoweredItem(proto->GetId()))
2919 AzeriteTierUnlockSetId = azeriteEmpoweredItem->AzeriteTierUnlockSetID;
2920
2921 Suffix = 0;
2922 RequiredLevelCurve = 0;
2923
2924 PvpItemLevel = 0;
2925 PvpItemLevelBonus = 0;
2926
2927 ItemLevelOffsetCurveId = proto->GetItemLevelOffsetCurveId();
2928 ItemLevelOffsetItemLevel = proto->GetItemLevelOffsetItemLevel();
2929 ItemLevelOffset = 0;
2930 ItemSquishEraID = proto->GetItemSquishEraId();
2931
2932 EffectCount = 0;
2933 for (ItemEffectEntry const* itemEffect : proto->Effects)
2934 Effects[EffectCount++] = itemEffect;
2935
2936 for (std::size_t i = EffectCount; i < Effects.size(); ++i)
2937 Effects[i] = nullptr;
2938
2939 LimitCategory = proto->GetItemLimitCategory();
2940
2941 CanDisenchant = !proto->HasFlag(ITEM_FLAG_NO_DISENCHANT);
2942 CanScrap = proto->HasFlag(ITEM_FLAG4_SCRAPABLE);
2943 CanSalvage = !proto->HasFlag(ITEM_FLAG4_NO_SALVAGE);
2944 CanRecraft = proto->HasFlag(ITEM_FLAG4_RECRAFTABLE);
2945 CannotTradeBindOnPickup = proto->HasFlag(ITEM_FLAG2_NO_TRADE_BIND_ON_ACQUIRE);
2946 IgnoreSquish = false;
2947
2948 _state.SuffixPriority = std::numeric_limits<int32>::max();
2949 _state.AppearanceModPriority = std::numeric_limits<int32>::max();
2950 _state.DisenchantLootPriority = std::numeric_limits<int32>::max();
2951 _state.ScalingStatDistributionPriority = std::numeric_limits<int32>::max();
2952 _state.AzeriteTierUnlockSetPriority = std::numeric_limits<int32>::max();
2953 _state.RequiredLevelCurvePriority = std::numeric_limits<int32>::max();
2954 _state.ItemLevelPriority = std::numeric_limits<int32>::max();
2955 _state.PvpItemLevelPriority = std::numeric_limits<int32>::max();
2956 _state.BondingPriority = std::numeric_limits<int32>::max();
2957 _state.HasQualityBonus = false;
2958 _state.HasItemLimitCategory = false;
2959}
2960
2962{
2963 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemInstance.ItemID);
2964 if (!proto)
2965 return;
2966
2967 Initialize(proto);
2968
2969 if (itemInstance.ItemBonus)
2970 for (uint32 bonusListID : itemInstance.ItemBonus->BonusListIDs)
2971 AddBonusList(bonusListID);
2972}
2973
2975{
2976 for (ItemBonusEntry const* bonus : ItemBonusMgr::GetItemBonuses(bonusListId))
2977 AddBonus(bonus->Type, bonus->Value);
2978}
2979
2980void BonusData::AddBonus(uint32 type, std::array<int32, 4> const& values)
2981{
2982 switch (type)
2983 {
2985 ItemLevelBonus += values[0];
2986 break;
2987 case ITEM_BONUS_STAT:
2988 {
2989 uint32 statIndex = 0;
2990 for (statIndex = 0; statIndex < MAX_ITEM_PROTO_STATS; ++statIndex)
2991 if (ItemStatType[statIndex] == values[0] || ItemStatType[statIndex] == -1)
2992 break;
2993
2994 if (statIndex < MAX_ITEM_PROTO_STATS)
2995 {
2996 ItemStatType[statIndex] = values[0];
2997 StatPercentEditor[statIndex] += values[1];
2998 }
2999 break;
3000 }
3001 case ITEM_BONUS_QUALITY:
3002 if (!_state.HasQualityBonus)
3003 {
3004 Quality = static_cast<uint32>(values[0]);
3005 _state.HasQualityBonus = true;
3006 }
3007 else if (Quality < static_cast<uint32>(values[0]))
3008 Quality = static_cast<uint32>(values[0]);
3009 break;
3010 case ITEM_BONUS_SUFFIX:
3011 if (values[1] < _state.SuffixPriority)
3012 {
3013 Suffix = static_cast<uint32>(values[0]);
3014 _state.SuffixPriority = values[1];
3015 }
3016 break;
3017 case ITEM_BONUS_SOCKET:
3018 {
3019 uint32 socketCount = values[0];
3020 for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS && socketCount; ++i)
3021 {
3022 if (!SocketColor[i])
3023 {
3024 SocketColor[i] = values[1];
3025 --socketCount;
3026 }
3027 }
3028 break;
3029 }
3031 if (values[1] < _state.AppearanceModPriority)
3032 {
3033 AppearanceModID = static_cast<uint32>(values[0]);
3034 _state.AppearanceModPriority = values[1];
3035 }
3036 break;
3038 RequiredLevel += values[0];
3039 break;
3041 RepairCostMultiplier *= static_cast<float>(values[0]) * 0.01f;
3042 break;
3045 if (values[1] < _state.ScalingStatDistributionPriority)
3046 {
3047 ContentTuningId = static_cast<uint32>(values[2]);
3048 PlayerLevelToItemLevelCurveId = static_cast<uint32>(values[3]);
3049 _state.ScalingStatDistributionPriority = values[1];
3050 HasFixedLevel = type == ITEM_BONUS_SCALING_STAT_DISTRIBUTION_FIXED;
3051 }
3052 break;
3054 if (values[1] < _state.DisenchantLootPriority)
3055 {
3056 DisenchantLootId = values[0];
3057 _state.DisenchantLootPriority = values[1];
3058 }
3059 break;
3060 case ITEM_BONUS_BONDING:
3061 Bonding = ItemBondingType(values[0]);
3062 break;
3064 RelicType = values[0];
3065 break;
3067 RequiredLevelOverride = values[0];
3068 break;
3070 if (values[1] < _state.AzeriteTierUnlockSetPriority)
3071 {
3072 AzeriteTierUnlockSetId = values[0];
3073 _state.AzeriteTierUnlockSetPriority = values[1];
3074 }
3075 break;
3077 CanDisenchant = values[0] != 0;
3078 break;
3080 CanScrap = values[0] != 0;
3081 break;
3083 if (ItemEffectEntry const* itemEffect = sItemEffectStore.LookupEntry(values[0]))
3084 Effects[EffectCount++] = itemEffect;
3085 break;
3087 if (values[2] < _state.RequiredLevelCurvePriority)
3088 {
3089 RequiredLevelCurve = values[0];
3090 _state.RequiredLevelCurvePriority = values[2];
3091 if (values[1])
3092 ContentTuningId = static_cast<uint32>(values[1]);
3093 }
3094 break;
3096 if (!_state.HasItemLimitCategory)
3097 {
3098 LimitCategory = values[0];
3099 _state.HasItemLimitCategory = true;
3100 }
3101 break;
3103 PvpItemLevelBonus += values[0];
3104 break;
3106 CanSalvage = values[0] != 0;
3107 break;
3109 CanRecraft = values[0] != 0;
3110 break;
3112 if (values[1] < _state.ItemLevelPriority)
3113 {
3114 ItemLevel = values[0];
3115 _state.ItemLevelPriority = values[1];
3116 }
3117 break;
3119 if (values[1] < _state.PvpItemLevelPriority)
3120 {
3121 PvpItemLevel = values[0];
3122 _state.PvpItemLevelPriority = values[1];
3123 }
3124 break;
3126 CannotTradeBindOnPickup = values[0] != 0;
3127 break;
3129 if (values[1] < _state.BondingPriority)
3130 {
3131 Bonding = static_cast<ItemBondingType>(values[0]);
3132 _state.BondingPriority = values[1];
3133 }
3134 break;
3136 if (values[3] < _state.ScalingStatDistributionPriority)
3137 {
3138 ItemLevelOffsetCurveId = values[0];
3139 ItemLevelOffsetItemLevel = values[1];
3140 _state.ScalingStatDistributionPriority = values[3];
3141 }
3142 break;
3144 if (values[1] < _state.ScalingStatDistributionPriority)
3145 {
3146 if (ItemScalingConfigEntry const* scalingConfig = sItemScalingConfigStore.LookupEntry(values[0]))
3147 {
3148 if (ItemOffsetCurveEntry const* itemOffsetCurve = sItemOffsetCurveStore.LookupEntry(scalingConfig->ItemOffsetCurveID))
3149 {
3150 ItemLevelOffsetCurveId = itemOffsetCurve->CurveID;
3151 ItemLevelOffset = itemOffsetCurve->Offset;
3152 }
3153
3154 ItemLevelOffsetItemLevel = scalingConfig->ItemLevel;
3155 ItemSquishEraID = scalingConfig->ItemSquishEraID;
3156 if (scalingConfig->Flags & 0x1)
3157 IgnoreSquish = true;
3158
3159 if (values[1] < _state.RequiredLevelCurvePriority)
3160 {
3161 RequiredLevelOverride = scalingConfig->RequiredLevel;
3162 RequiredLevelCurve = 0;
3163 }
3164 }
3165 }
3166 break;
3168 AddBonusList(values[0]);
3169 break;
3171 if (values[1] < _state.ScalingStatDistributionPriority)
3172 {
3173 if (ItemScalingConfigEntry const* scalingConfig = sItemScalingConfigStore.LookupEntry(values[0]))
3174 {
3175 if (ItemOffsetCurveEntry const* itemOffsetCurve = sItemOffsetCurveStore.LookupEntry(scalingConfig->ItemOffsetCurveID))
3176 {
3177 ItemLevelOffsetCurveId = itemOffsetCurve->CurveID;
3178 ItemLevelOffset = itemOffsetCurve->Offset;
3179 }
3180
3181 ItemLevelOffsetItemLevel = 0;
3182 ItemSquishEraID = scalingConfig->ItemSquishEraID;
3183 if (scalingConfig->Flags & 0x1)
3184 IgnoreSquish = true;
3185 }
3186 }
3187 break;
3188 }
3189}
std::unordered_map< Player *, UpdateData > UpdateDataMapType
Definition BaseEntity.h:32
@ CHAR_UPD_ITEM_INSTANCE
@ CHAR_UPD_ITEM_INSTANCE_ON_LOAD
@ CHAR_DEL_ITEM_INSTANCE_GEMS
@ CHAR_DEL_ITEM_INSTANCE_ARTIFACT
@ CHAR_DEL_ITEM_INSTANCE_TRANSMOG
@ CHAR_DEL_ITEM_INSTANCE
@ CHAR_DEL_CHAR_INVENTORY_BY_ITEM
@ CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS
@ CHAR_INS_ITEM_INSTANCE_ARTIFACT_POWERS
@ CHAR_DEL_ITEM_BOP_TRADE
@ CHAR_DEL_ITEM_INSTANCE_MODIFIERS
@ CHAR_DEL_ITEM_REFUND_INSTANCE
@ CHAR_INS_ITEM_INSTANCE_MODIFIERS
@ CHAR_INS_ITEM_INSTANCE_TRANSMOG
@ CHAR_INS_ITEM_INSTANCE_ARTIFACT
@ CHAR_UPD_GIFT_OWNER
@ CHAR_INS_ITEM_INSTANCE_GEMS
@ CHAR_DEL_GIFT
@ CHAR_REP_ITEM_INSTANCE
@ CHAR_INS_ITEM_REFUND_INSTANCE
LocaleConstant
Definition Common.h:51
@ HOUR
Definition Common.h:33
DB2Storage< ArtifactAppearanceEntry > sArtifactAppearanceStore("ArtifactAppearance.db2", &ArtifactAppearanceLoadInfo::Instance)
DB2Storage< ItemNameDescriptionEntry > sItemNameDescriptionStore("ItemNameDescription.db2", &ItemNameDescriptionLoadInfo::Instance)
DB2Storage< ArtifactEntry > sArtifactStore("Artifact.db2", &ArtifactLoadInfo::Instance)
DB2Storage< ArtifactPowerPickerEntry > sArtifactPowerPickerStore("ArtifactPowerPicker.db2", &ArtifactPowerPickerLoadInfo::Instance)
DB2Storage< ImportPriceWeaponEntry > sImportPriceWeaponStore("ImportPriceWeapon.db2", &ImportPriceWeaponLoadInfo::Instance)
DB2Storage< DurabilityQualityEntry > sDurabilityQualityStore("DurabilityQuality.db2", &DurabilityQualityLoadInfo::Instance)
DB2Storage< ArtifactPowerEntry > sArtifactPowerStore("ArtifactPower.db2", &ArtifactPowerLoadInfo::Instance)
DB2Storage< ItemScalingConfigEntry > sItemScalingConfigStore("ItemScalingConfig.db2", &ItemScalingConfigLoadInfo::Instance)
DB2Storage< ItemPriceBaseEntry > sItemPriceBaseStore("ItemPriceBase.db2", &ItemPriceBaseLoadInfo::Instance)
DB2Storage< ArtifactUnlockEntry > sArtifactUnlockStore("ArtifactUnlock.db2", &ArtifactUnlockLoadInfo::Instance)
DB2Storage< ChrSpecializationEntry > sChrSpecializationStore("ChrSpecialization.db2", &ChrSpecializationLoadInfo::Instance)
DB2Storage< ItemSetEntry > sItemSetStore("ItemSet.db2", &ItemSetLoadInfo::Instance)
DB2Storage< ItemEffectEntry > sItemEffectStore("ItemEffect.db2", &ItemEffectLoadInfo::Instance)
DB2Storage< ItemSquishEraEntry > sItemSquishEraStore("ItemSquishEra.db2", &ItemSquishEraLoadInfo::Instance)
DB2Storage< ImportPriceShieldEntry > sImportPriceShieldStore("ImportPriceShield.db2", &ImportPriceShieldLoadInfo::Instance)
DB2Storage< ItemOffsetCurveEntry > sItemOffsetCurveStore("ItemOffsetCurve.db2", &ItemOffsetCurveLoadInfo::Instance)
DB2Storage< ItemModifiedAppearanceEntry > sItemModifiedAppearanceStore("ItemModifiedAppearance.db2", &ItemModifiedAppearanceLoadInfo::Instance)
DB2Storage< ItemDisenchantLootEntry > sItemDisenchantLootStore("ItemDisenchantLoot.db2", &ItemDisenchantLootLoadInfo::Instance)
DB2Storage< AzeriteLevelInfoEntry > sAzeriteLevelInfoStore("AzeriteLevelInfo.db2", &AzeriteLevelInfoLoadInfo::Instance)
DB2Storage< ImportPriceQualityEntry > sImportPriceQualityStore("ImportPriceQuality.db2", &ImportPriceQualityLoadInfo::Instance)
DB2Storage< GemPropertiesEntry > sGemPropertiesStore("GemProperties.db2", &GemPropertiesLoadInfo::Instance)
DB2Storage< ImportPriceArmorEntry > sImportPriceArmorStore("ImportPriceArmor.db2", &ImportPriceArmorLoadInfo::Instance)
DB2Storage< SpellItemEnchantmentEntry > sSpellItemEnchantmentStore("SpellItemEnchantment.db2", &SpellItemEnchantmentLoadInfo::Instance)
DB2Storage< AzeritePowerEntry > sAzeritePowerStore("AzeritePower.db2", &AzeritePowerLoadInfo::Instance)
DB2Storage< ItemAppearanceEntry > sItemAppearanceStore("ItemAppearance.db2", &ItemAppearanceLoadInfo::Instance)
DB2Storage< AzeriteEssenceEntry > sAzeriteEssenceStore("AzeriteEssence.db2", &AzeriteEssenceLoadInfo::Instance)
DB2Storage< ArtifactAppearanceSetEntry > sArtifactAppearanceSetStore("ArtifactAppearanceSet.db2", &ArtifactAppearanceSetLoadInfo::Instance)
DB2Storage< DurabilityCostsEntry > sDurabilityCostsStore("DurabilityCosts.db2", &DurabilityCostsLoadInfo::Instance)
#define sDB2Manager
Definition DB2Stores.h:569
#define MAX_ITEM_ENCHANTMENT_EFFECTS
@ ITEM_BONUS_SCALING_CONFIG
Definition DBCEnums.h:1295
@ ITEM_BONUS_ITEM_OFFSET_CURVE
Definition DBCEnums.h:1292
@ ITEM_BONUS_APPEARANCE
Definition DBCEnums.h:1256
@ ITEM_BONUS_OVERRIDE_CAN_RECRAFT
Definition DBCEnums.h:1285
@ ITEM_BONUS_RELIC_TYPE
Definition DBCEnums.h:1266
@ ITEM_BONUS_BONDING
Definition DBCEnums.h:1265
@ ITEM_BONUS_SOCKET
Definition DBCEnums.h:1255
@ ITEM_BONUS_SUFFIX
Definition DBCEnums.h:1254
@ ITEM_BONUS_REQUIRED_LEVEL
Definition DBCEnums.h:1257
@ ITEM_BONUS_AZERITE_TIER_UNLOCK_SET
Definition DBCEnums.h:1268
@ ITEM_BONUS_SCALING_STAT_DISTRIBUTION
Definition DBCEnums.h:1260
@ ITEM_BONUS_BONDING_WITH_PRIORITY
Definition DBCEnums.h:1291
@ ITEM_BONUS_SCALING_STAT_DISTRIBUTION_FIXED
Definition DBCEnums.h:1262
@ ITEM_BONUS_OVERRIDE_CAN_DISENCHANT
Definition DBCEnums.h:1270
@ ITEM_BONUS_PVP_ITEM_LEVEL_BASE
Definition DBCEnums.h:1287
@ ITEM_BONUS_ITEM_LEVEL
Definition DBCEnums.h:1250
@ ITEM_BONUS_REQUIRED_LEVEL_CURVE
Definition DBCEnums.h:1274
@ ITEM_BONUS_QUALITY
Definition DBCEnums.h:1252
@ ITEM_BONUS_OVERRIDE_CAN_SALVAGE
Definition DBCEnums.h:1284
@ ITEM_BONUS_ITEM_LEVEL_BASE
Definition DBCEnums.h:1286
@ ITEM_BONUS_REPAIR_COST_MULTIPLIER
Definition DBCEnums.h:1259
@ ITEM_BONUS_OVERRIDE_REQUIRED_LEVEL
Definition DBCEnums.h:1267
@ ITEM_BONUS_PVP_ITEM_LEVEL_INCREMENT
Definition DBCEnums.h:1281
@ ITEM_BONUS_SCALING_CONFIG_AND_REQ_LEVEL
Definition DBCEnums.h:1293
@ ITEM_BONUS_ITEM_LIMIT_CATEGORY
Definition DBCEnums.h:1280
@ ITEM_BONUS_OVERRIDE_CANNOT_TRADE_BOP
Definition DBCEnums.h:1290
@ ITEM_BONUS_OVERRIDE_CAN_SCRAP
Definition DBCEnums.h:1271
@ ITEM_BONUS_STAT
Definition DBCEnums.h:1251
@ ITEM_BONUS_ITEM_EFFECT_ID
Definition DBCEnums.h:1272
@ ITEM_BONUS_ITEM_BONUS_LIST
Definition DBCEnums.h:1294
@ ITEM_BONUS_DISENCHANT_LOOT_ID
Definition DBCEnums.h:1261
#define MAX_AZERITE_EMPOWERED_TIER
Definition DBCEnums.h:227
@ ITEM_ENCHANTMENT_TYPE_BONUS_LIST_CURVE
Definition DBCEnums.h:1234
@ ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_TYPE
Definition DBCEnums.h:1231
@ ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_ID
Definition DBCEnums.h:1232
@ ITEM_ENCHANTMENT_TYPE_BONUS_LIST_ID
Definition DBCEnums.h:1233
@ ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_PICKER
Definition DBCEnums.h:1235
#define MAX_ITEM_PROTO_SOCKETS
Definition DBCEnums.h:1210
ItemContext
Definition DBCEnums.h:1315
@ CURVE_ID_ARTIFACT_RELIC_ITEM_LEVEL_BONUS
Definition DBCEnums.h:916
ChrSpecialization
Definition DBCEnums.h:398
@ DIFFICULTY_NONE
Definition DBCEnums.h:933
@ ARTIFACT_POWER_FLAG_SCALES_WITH_NUM_POWERS
Definition DBCEnums.h:218
@ ARTIFACT_POWER_FLAG_MAX_RANK_WITH_TIER
Definition DBCEnums.h:220
@ ARTIFACT_POWER_FLAG_FIRST
Definition DBCEnums.h:222
@ ITEM_SET_FLAG_LEGACY_INACTIVE
Definition DBCEnums.h:1514
#define MAX_AZERITE_ESSENCE_SLOT
Definition DBCEnums.h:229
#define MAX_ITEM_PROTO_STATS
Definition DBCEnums.h:1211
#define MAX_ARTIFACT_TIER
Definition DBCEnums.h:225
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:156
int16_t int16
Definition Define.h:151
int8_t int8
Definition Define.h:152
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
uint16 flags
#define ABORT
Definition Errors.h:87
#define ASSERT_NODEBUGINFO
Definition Errors.h:81
#define ASSERT
Definition Errors.h:80
GameTable< GtItemSocketCostPerLevelEntry > sItemSocketCostPerLevelGameTable
GameTable< GtArtifactKnowledgeMultiplierEntry > sArtifactKnowledgeMultiplierGameTable
GameTable< GtArtifactLevelXPEntry > sArtifactLevelXPGameTable
EnchantmentSlot
@ PERM_ENCHANTMENT_SLOT
@ SOCK_ENCHANTMENT_SLOT_3
@ MAX_ENCHANTMENT_SLOT
@ SOCK_ENCHANTMENT_SLOT
@ MAX_INSPECTED_ENCHANTMENT_SLOT
InventoryResult
Definition ItemDefines.h:25
@ EQUIP_ERR_OK
Definition ItemDefines.h:26
@ EQUIP_ERR_LOOT_GONE
Definition ItemDefines.h:76
@ EQUIP_ERR_CANT_STACK
Definition ItemDefines.h:45
ItemModifier
@ ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_3
@ ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_5
@ ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_2
@ ITEM_MODIFIER_ENCHANT_ILLUSION_ALL_SPECS
@ ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_ALL_SPECS
@ ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_4
@ ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_1
@ ITEM_MODIFIER_TIMEWALKER_LEVEL
@ ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID
@ ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_5
@ ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_4
@ ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_5
@ ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_4
@ ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_1
@ ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID
@ ITEM_MODIFIER_ENCHANT_ILLUSION_SPEC_3
@ ITEM_MODIFIER_BATTLE_PET_BREED_DATA
@ ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL
@ ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_2
@ ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_3
@ ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS
@ ITEM_MODIFIER_TRANSMOG_SECONDARY_APPEARANCE_SPEC_2
@ ITEM_MODIFIER_ARTIFACT_TIER
@ ITEM_MODIFIER_BATTLE_PET_SPECIES_ID
@ ITEM_MODIFIER_BATTLE_PET_LEVEL
@ ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_1
TC_GAME_API float GetRandomPropertyPoints(uint32 itemLevel, uint32 quality, uint32 inventoryType, uint32 subClass)
uint32 ItemRandomBonusListId
int32 const SocketColorToGemTypeMask[31]
@ ITEM_CLASS_QUIVER
@ ITEM_CLASS_CONTAINER
@ ITEM_CLASS_GEM
@ ITEM_CLASS_ARMOR
@ ITEM_CLASS_WEAPON
@ ITEM_FLAG2_NO_TRADE_BIND_ON_ACQUIRE
@ ITEM_FLAG2_NO_ALTER_ITEM_VISUAL
@ ITEM_FLAG2_OVERRIDE_GOLD_COST
@ ITEM_SUBCLASS_WEAPON_FISHING_POLE
ItemFieldFlags
@ ITEM_FIELD_FLAG_REFUNDABLE
@ ITEM_FIELD_FLAG_CHILD
@ ITEM_FIELD_FLAG_SOULBOUND
@ ITEM_FIELD_FLAG_BOP_TRADEABLE
@ BAG_FAMILY_MASK_MINING_SUPP
@ BAG_FAMILY_MASK_HERBS
@ BAG_FAMILY_MASK_ENCHANTING_SUPP
@ BAG_FAMILY_MASK_SOUL_SHARDS
@ BAG_FAMILY_MASK_INSCRIPTION_SUPP
@ BAG_FAMILY_MASK_GEMS
@ BAG_FAMILY_MASK_ARROWS
@ BAG_FAMILY_MASK_BULLETS
@ BAG_FAMILY_MASK_ENGINEERING_SUPP
@ BAG_FAMILY_MASK_COOKING_SUPP
@ BAG_FAMILY_MASK_FISHING_SUPP
@ BAG_FAMILY_MASK_LEATHERWORKING_SUPP
@ ITEM_SUBCLASS_CONTAINER
@ ITEM_SUBCLASS_REAGENT_CONTAINER
@ ITEM_SUBCLASS_COOKING_CONTAINER
@ ITEM_SUBCLASS_INSCRIPTION_CONTAINER
@ ITEM_SUBCLASS_LEATHERWORKING_CONTAINER
@ ITEM_SUBCLASS_TACKLE_CONTAINER
@ ITEM_SUBCLASS_GEM_CONTAINER
@ ITEM_SUBCLASS_SOUL_CONTAINER
@ ITEM_SUBCLASS_ENCHANTING_CONTAINER
@ ITEM_SUBCLASS_MINING_CONTAINER
@ ITEM_SUBCLASS_HERB_CONTAINER
@ ITEM_SUBCLASS_ENGINEERING_CONTAINER
@ ITEM_SUBCLASS_QUIVER
@ ITEM_SUBCLASS_AMMO_POUCH
@ ITEM_FLAG_NO_DISENCHANT
@ ITEM_FLAG_CONJURED
@ ITEM_FLAG3_CAN_STORE_ENCHANTS
@ ITEM_FLAG3_IGNORE_ITEM_LEVEL_CAP_IN_PVP
@ ITEM_MOD_CORRUPTION_RESISTANCE
@ ITEM_MOD_CORRUPTION
@ ITEM_SUBCLASS_ARMOR_MAIL
@ ITEM_SUBCLASS_ARMOR_CLOTH
@ ITEM_SUBCLASS_ARMOR_LEATHER
@ ITEM_SUBCLASS_ARMOR_PLATE
@ ITEM_SUBCLASS_ARMOR_MISCELLANEOUS
@ ITEM_SUBCLASS_ARMOR_COSMETIC
@ ITEM_FLAG4_RECRAFTABLE
@ ITEM_FLAG4_NO_SALVAGE
@ ITEM_FLAG4_SCRAPABLE
#define MAX_INVTYPE
@ MIN_ITEM_LEVEL
@ MAX_ITEM_LEVEL
SocketColor
@ ITEM_SUBCLASS_GEM_ARTIFACT_RELIC
ItemBondingType
@ BIND_QUEST
@ BIND_NONE
@ INVTYPE_FINGER
@ INVTYPE_HEAD
@ INVTYPE_CLOAK
@ INVTYPE_ROBE
@ INVTYPE_HOLDABLE
@ INVTYPE_TRINKET
@ INVTYPE_RELIC
@ INVTYPE_RANGED
@ INVTYPE_THROWN
@ INVTYPE_WAIST
@ INVTYPE_RANGEDRIGHT
@ INVTYPE_WRISTS
@ INVTYPE_WEAPON
@ INVTYPE_WEAPONMAINHAND
@ INVTYPE_WEAPONOFFHAND
@ INVTYPE_2HWEAPON
@ INVTYPE_BAG
@ INVTYPE_NECK
@ INVTYPE_SHOULDERS
@ INVTYPE_FEET
@ INVTYPE_NON_EQUIP
@ INVTYPE_AMMO
@ INVTYPE_QUIVER
@ INVTYPE_SHIELD
@ INVTYPE_LEGS
@ INVTYPE_CHEST
@ INVTYPE_HANDS
void RemoveItemsSetItem(Player *player, Item const *item)
Definition Item.cpp:169
bool ItemCanGoIntoBag(ItemTemplate const *pProto, ItemTemplate const *pBagProto)
Definition Item.cpp:250
ItemModifier const AppearanceModifierSlotBySpec[MAX_SPECIALIZATIONS]
Definition Item.cpp:325
void UpdateItemSetAuras(Player *player, bool formChange)
Definition Item.cpp:221
ItemModifier const SecondaryAppearanceModifierSlotBySpec[MAX_SPECIALIZATIONS]
Definition Item.cpp:343
void RemoveItemFromUpdateQueueOf(Item *item, Player *player)
Definition Item.cpp:1310
Item * NewItemOrBag(ItemTemplate const *proto)
Definition Item.cpp:55
ItemModifier const IllusionModifierSlotBySpec[MAX_SPECIALIZATIONS]
Definition Item.cpp:334
static uint32 FindSpellChargesSlot(BonusData const &bonusData, ItemEffectEntry const *effect)
Definition Item.cpp:602
void AddItemsSetItem(Player *player, Item const *item)
Definition Item.cpp:76
void DeleteItemSetEffects(ItemSetEffect *itemSetEffect)
Definition Item.cpp:245
void AddItemToUpdateQueueOf(Item *item, Player *player)
Definition Item.cpp:1289
ItemModifier const AppearanceModifierSlotBySpec[MAX_SPECIALIZATIONS]
Definition Item.cpp:325
ItemModifier const SecondaryAppearanceModifierSlotBySpec[MAX_SPECIALIZATIONS]
Definition Item.cpp:343
#define MAX_GEM_SOCKETS
Definition Item.h:40
#define MAX_ENCHANTMENT_OFFSET
Definition Item.h:42
Item * NewItemOrBag(ItemTemplate const *proto)
Definition Item.cpp:55
ItemUpdateState
Definition Item.h:45
@ ITEM_CHANGED
Definition Item.h:47
@ ITEM_REMOVED
Definition Item.h:49
@ ITEM_NEW
Definition Item.h:48
@ ITEM_UNCHANGED
Definition Item.h:46
ItemModifier const IllusionModifierSlotBySpec[MAX_SPECIALIZATIONS]
Definition Item.cpp:334
int32 const ItemTransmogrificationSlots[MAX_INVTYPE]
Definition Item.cpp:2014
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define sLootItemStorage
@ TYPEID_OBJECT
Definition ObjectGuid.h:38
@ TYPEID_ITEM
Definition ObjectGuid.h:39
std::set< ObjectGuid > GuidSet
Definition ObjectGuid.h:432
#define sObjectMgr
Definition ObjectMgr.h:1885
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ EQUIPMENT_SLOT_SHOULDERS
Definition Player.h:731
@ EQUIPMENT_SLOT_BODY
Definition Player.h:732
@ EQUIPMENT_SLOT_HANDS
Definition Player.h:738
@ EQUIPMENT_SLOT_MAINHAND
Definition Player.h:744
@ EQUIPMENT_SLOT_TABARD
Definition Player.h:747
@ EQUIPMENT_SLOT_END
Definition Player.h:748
@ EQUIPMENT_SLOT_HEAD
Definition Player.h:729
@ EQUIPMENT_SLOT_LEGS
Definition Player.h:735
@ EQUIPMENT_SLOT_BACK
Definition Player.h:743
@ EQUIPMENT_SLOT_OFFHAND
Definition Player.h:745
@ EQUIPMENT_SLOT_WAIST
Definition Player.h:734
@ EQUIPMENT_SLOT_FEET
Definition Player.h:736
@ EQUIPMENT_SLOT_CHEST
Definition Player.h:733
@ EQUIPMENT_SLOT_WRISTS
Definition Player.h:737
@ PROFESSION_SLOT_START
Definition Player.h:766
@ PROFESSION_SLOT_END
Definition Player.h:765
#define INVENTORY_SLOT_BAG_0
Definition Player.h:723
#define sRealmList
Definition RealmList.h:93
#define sScriptMgr
Definition ScriptMgr.h:1449
#define MAX_SPECIALIZATIONS
@ SPELL_EFFECT_ENCHANT_ITEM
@ SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
@ SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
#define sSpellMgr
Definition SpellMgr.h:812
TradeSlots
Definition TradeData.h:24
@ TRADE_SLOT_INVALID
Definition TradeData.h:28
Definition Bag.h:27
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
void BuildUpdateChangesMask()
void SetUpdateFieldValue(UF::UpdateFieldPrivateSetter< T > setter, typename UF::UpdateFieldPrivateSetter< T >::value_type value)
Definition BaseEntity.h:221
WowCS::EntityFragmentsHolder m_entityFragments
Definition BaseEntity.h:353
void RemoveDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter< T > setter, uint32 index)
Definition BaseEntity.h:256
UF::UpdateFieldHolder m_values
Definition BaseEntity.h:205
void _Create(ObjectGuid const &guid)
Definition BaseEntity.h:218
void ClearUpdateMask(bool remove)
UF::DynamicUpdateFieldSetter< T >::insert_result AddDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter< T > setter)
Definition BaseEntity.h:242
ByteBuffer & PrepareValuesUpdateBuffer(UpdateData *data) const
TypeID m_objectTypeId
Definition BaseEntity.h:351
void BuildFieldsUpdate(Player *player, UpdateDataMapType &data_map) const
size_t wpos() const
Definition ByteBuffer.h:461
void put(std::size_t pos, T value)
Definition ByteBuffer.h:260
void AddItemAppearance(Item *item)
static bool IsPlayerMeetingCondition(Player const *player, uint32 conditionId)
Class used to access individual fields of database query result.
Definition Field.h:94
uint64 GetUInt64() const noexcept
Definition Field.cpp:71
uint32 GetUInt32() const noexcept
Definition Field.cpp:57
uint16 GetUInt16() const noexcept
Definition Field.cpp:43
uint8 GetUInt8() const noexcept
Definition Field.cpp:29
int32 GetInt32() const noexcept
Definition Field.cpp:64
Definition Item.h:179
std::string GetDebugInfo() const override
Definition Item.cpp:2876
uint32 GetEnchantRequiredLevel() const
Definition Item.cpp:1434
static void DeleteFromInventoryDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType itemGuid)
Definition Item.cpp:1221
void SetState(ItemUpdateState state, Player *forplayer=nullptr)
Definition Item.cpp:1258
uint32 GetPaidExtendedCost() const
Definition Item.h:376
uint8 GetSlot() const
Definition Item.h:290
void SetItemFlag(ItemFieldFlags flags)
Definition Item.h:218
std::span< ItemEffectEntry const *const > GetEffects() const
Definition Item.h:365
static bool CanTransmogrifyItemWithItem(Item const *item, ItemModifiedAppearanceEntry const *itemModifiedAppearance)
Definition Item.cpp:2053
void LoadAdditionalDataFromDB(Player const *owner, ItemAdditionalLoadInfo *addionalData)
Definition Item.cpp:1083
bool IsWrapped() const
Definition Item.h:260
bool AddToObjectUpdate() override
Definition Item.cpp:1883
void SetText(std::string const &text)
Definition Item.h:315
void SetArtifactPower(uint16 artifactPowerId, uint8 purchasedRank, uint8 currentRankWithBonus)
Definition Item.cpp:2651
void UpdateDuration(Player *owner, uint32 diff)
Definition Item.cpp:583
void BuildValuesUpdateForPlayerWithMask(UpdateData *data, UF::ObjectData::Mask const &requestedObjectMask, UF::ItemData::Mask const &requestedItemMask, Player const *target, bool ignoreNestedChangesMask) const
Definition Item.cpp:1836
virtual void SaveToDB(CharacterDatabaseTransaction trans)
Definition Item.cpp:639
void SetFixedLevel(uint8 level)
Definition Item.cpp:2850
uint32 GetBuyPrice(Player const *owner, bool &standardPrice) const
Definition Item.cpp:2101
void ReplaceAllItemFlags(ItemFieldFlags flags)
Definition Item.h:220
void BuildUpdate(UpdateDataMapType &) override
Definition Item.cpp:1790
bool IsLimitedToAnotherMapOrZone(uint32 cur_mapId, uint32 cur_zoneId) const
Definition Item.cpp:1692
void RemoveItemFlag(ItemFieldFlags flags)
Definition Item.h:219
Item()
Definition Item.cpp:486
ItemBondingType GetBonding() const
Definition Item.h:209
int32 GetArtifactPowerIndex(uint32 artifactPowerId) const
Definition Item.cpp:2626
void DeleteRefundDataFromDB(CharacterDatabaseTransaction *trans)
Definition Item.cpp:1918
static ItemDisenchantLootEntry const * GetBaseDisenchantLoot(ItemTemplate const *itemTemplate, uint32 quality, uint32 itemLevel)
Definition Item.cpp:2411
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition Item.h:308
void SetPaidMoney(uint64 money)
Definition Item.h:371
Item * CloneItem(uint32 count, Player const *player=nullptr) const
Definition Item.cpp:1751
void AddBonuses(uint32 bonusListID)
Definition Item.cpp:2581
Bag * m_container
Definition Item.h:467
uint8 GetGemCountWithID(uint32 GemID) const
Definition Item.cpp:1666
bool IsBoundAccountWide() const
Definition Item.h:228
bool mb_in_trade
Definition Item.h:470
Bag * ToBag()
Definition Item.h:251
std::string m_text
Definition Item.h:465
void InitArtifactPowers(uint8 artifactId, uint8 artifactTier)
Definition Item.cpp:2666
AzeriteItem * ToAzeriteItem()
Definition Item.h:253
int32 GetItemStatType(uint32 index) const
Definition Item.h:352
bool CanBeTraded(bool mail=false, bool trade=false) const
Definition Item.cpp:1342
uint32 GetEnchantmentDuration(EnchantmentSlot slot) const
Definition Item.h:309
void ClearValuesChangesMask() override
Definition Item.cpp:1877
void ClearBonuses()
Definition Item.cpp:2609
void SetContext(ItemContext context)
Definition Item.h:452
uint32 GetQuality() const
Definition Item.h:347
uint64 m_paidMoney
Definition Item.h:472
std::array< uint32, MAX_ITEM_PROTO_SOCKETS > m_gemScalingLevels
Definition Item.h:477
void GiveArtifactXp(uint64 amount, Item *sourceItem, uint32 artifactCategoryId)
Definition Item.cpp:2815
UF::SocketedGem const * GetGem(uint16 slot) const
Definition Item.cpp:1571
void SetCount(uint32 value)
Definition Item.cpp:1367
void SetModifier(ItemModifier modifier, uint32 value)
Definition Item.cpp:2483
void SetDurability(uint32 durability)
Definition Item.h:268
void SetCreateTime(int64 createTime)
Definition Item.h:322
ObjectGuid GetCreator() const
Definition Item.h:201
ItemTemplate const * GetTemplate() const
Definition Item.cpp:1233
void ApplyArtifactPowerEnchantmentBonuses(EnchantmentSlot slot, uint32 enchantId, bool apply, Player *owner)
Definition Item.cpp:2720
UF::UpdateField< UF::ItemData, uint32(WowCS::EntityFragment::CGObject), TYPEID_ITEM > m_itemData
Definition Item.h:459
std::vector< int32 > const & GetBonusListIDs() const
Definition Item.h:239
bool IsBOPTradeable() const
Definition Item.h:259
bool IsInBag() const
Definition Item.h:297
void SetGem(uint16 slot, ItemDynamicFieldGems const *gem, uint32 gemScalingLevel)
Definition Item.cpp:1577
bool IsSoulBound() const
Definition Item.h:227
void SaveRefundDataToDB()
Definition Item.cpp:1900
ItemContext GetContext() const
Definition Item.h:451
void SetNotRefundable(Player *owner, bool changestate=true, CharacterDatabaseTransaction *trans=nullptr, bool addToCollection=true)
Definition Item.cpp:1929
ItemRandomBonusListId m_randomBonusListId
Definition Item.h:475
uint32 GetVisibleEnchantmentId(Player const *owner) const
Definition Item.cpp:2561
friend void RemoveItemFromUpdateQueueOf(Item *item, Player *player)
Definition Item.cpp:1310
bool IsBindedNotWith(Player const *player) const
Definition Item.cpp:1769
bool IsEquipped() const
Definition Item.cpp:1336
void SendTimeUpdate(Player *owner)
Definition Item.cpp:1709
Optional< uint16 > GetDisenchantSkillRequired() const
Definition Item.cpp:2396
virtual bool Create(ObjectGuid::LowType guidlow, uint32 itemId, ItemContext context, Player const *owner)
Definition Item.cpp:510
void SetSpellCharges(ItemEffectEntry const *effect, int32 value)
Definition Item.cpp:632
BonusData const * GetBonus() const
Definition Item.h:195
void SetItemRandomBonusList(ItemRandomBonusListId bonusListId)
Definition Item.cpp:1250
Player * GetOwner() const
Definition Item.cpp:1238
bool IsValidTransmogrificationTarget() const
Definition Item.cpp:1995
ObjectGuid GetOwnerGUID() const
Definition Item.h:197
uint32 GetAppearanceModId() const
Definition Item.h:355
uint32 GetDisplayId(Player const *owner) const
Definition Item.cpp:2448
BonusData _bonusData
Definition Item.h:462
uint64 GetPaidMoney() const
Definition Item.h:375
bool HasEnchantRequiredSkill(Player const *player) const
Definition Item.cpp:1422
int32 GetVisibleSecondaryModifiedAppearanceId(Player const *owner) const
Definition Item.cpp:2552
uint32 GetSkill()
Definition Item.cpp:1244
bool IsRefundable() const
Definition Item.h:258
uint16 GetPos() const
Definition Item.h:294
Optional< uint32 > GetDisenchantLootId() const
Definition Item.cpp:2378
ItemModifiedAppearanceEntry const * GetItemModifiedAppearance() const
Definition Item.cpp:2465
float GetItemStatValue(uint32 index, Player const *owner) const
Definition Item.cpp:2353
bool GemsFitSockets() const
Definition Item.cpp:1634
uint64 CalculateDurabilityRepairCost(float discount) const
Definition Item.cpp:1383
bool IsBoundByEnchant() const
Definition Item.cpp:1448
void SetSoulboundTradeable(GuidSet const &allowedLooters)
Definition Item.cpp:1963
int16 uQueuePos
Definition Item.h:469
void SetContainedIn(ObjectGuid guid)
Definition Item.h:200
uint32 GetVisibleEntry(Player const *owner) const
Definition Item.cpp:2515
ObjectGuid GetGiftCreator() const
Definition Item.h:203
void CheckArtifactRelicSlotUnlock(Player const *owner)
Definition Item.cpp:1164
void BuildValuesUpdateWithFlag(UF::UpdateFieldFlag flags, ByteBuffer &data, Player const *target) const override
Definition Item.cpp:1824
UF::ArtifactPower const * GetArtifactPower(uint32 artifactPowerId) const
Definition Item.cpp:2634
void SetEnchantmentCharges(EnchantmentSlot slot, uint32 charges)
Definition Item.cpp:1549
uint32 GetVisibleModifiedAppearanceId(Player const *owner) const
Definition Item.cpp:2539
bool IsArtifactDisabled() const
Definition Item.cpp:2618
UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const *target) const final
Definition Item.cpp:1799
uint32 GetTotalUnlockedArtifactPowers() const
Definition Item.cpp:2688
uint32 m_paidExtendedCost
Definition Item.h:473
bool IsBag() const
Definition Item.h:262
void RemoveFromObjectUpdate() override
Definition Item.cpp:1894
void ClearEnchantment(EnchantmentSlot slot)
Definition Item.cpp:1558
uint32 GetPlayedTime() const
Definition Item.cpp:1953
bool IsRefundExpired() const
Definition Item.cpp:1958
void SetArtifactXP(uint64 xp)
Definition Item.h:448
std::unique_ptr< Loot > m_loot
Definition Item.h:328
void SetCreator(ObjectGuid guid)
Definition Item.h:202
uint32 GetItemLevel(Player const *owner) const
Definition Item.cpp:2265
ObjectGuid const & GetRefundRecipient() const
Definition Item.h:374
void SetCreatePlayedTime(uint32 createPlayedTime)
Definition Item.h:321
void SendUpdateSockets()
Definition Item.cpp:1699
void SetEnchantmentDuration(EnchantmentSlot slot, uint32 duration, Player *owner)
Definition Item.cpp:1539
InventoryResult CanBeMergedPartlyWith(ItemTemplate const *proto) const
Definition Item.cpp:1460
void SetPaidExtendedCost(uint32 iece)
Definition Item.h:372
uint32 GetEnchantmentCharges(EnchantmentSlot slot) const
Definition Item.h:310
void SetBonuses(std::vector< int32 > bonusListIDs)
Definition Item.cpp:2596
void SetAppearanceModId(uint32 appearanceModId)
Definition Item.h:356
std::string GetNameForLocaleIdx(LocaleConstant locale) const override
Definition Item.cpp:565
void SetRefundRecipient(ObjectGuid const &guid)
Definition Item.h:370
void BuildValuesUpdate(UF::UpdateFieldFlag flags, ByteBuffer &data, Player const *target) const override
Definition Item.cpp:1813
uint32 GetSellPrice(Player const *owner) const
Definition Item.cpp:2234
uint8 GetGemCountWithLimitCategory(uint32 limitCategory) const
Definition Item.cpp:1674
void ClearSoulboundTradeable(Player *currentOwner)
Definition Item.cpp:1969
bool IsNotEmptyBag() const
Definition Item.cpp:576
virtual bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field *fields, uint32 entry)
Definition Item.cpp:907
bool m_lootGenerated
Definition Item.h:329
uint32 GetCount() const
Definition Item.h:283
void SetExpiration(uint32 expiration)
Definition Item.h:207
bool CheckSoulboundTradeExpire()
Definition Item.cpp:1983
void SetOwnerGUID(ObjectGuid guid)
Definition Item.h:198
AzeriteEmpoweredItem * ToAzeriteEmpoweredItem()
Definition Item.h:255
float GetRepairCostMultiplier() const
Definition Item.h:359
uint16 GetVisibleItemVisual(Player const *owner) const
Definition Item.cpp:2573
void BuildValuesCreate(UF::UpdateFieldFlag flags, ByteBuffer &data, Player const *target) const override
Definition Item.cpp:1807
uint16 GetVisibleAppearanceModId(Player const *owner) const
Definition Item.cpp:2527
uint8 GetBagSlot() const
Definition Item.cpp:1331
void SetGiftCreator(ObjectGuid guid)
Definition Item.h:204
uint32 GetModifier(ItemModifier modifier) const
Definition Item.cpp:2470
void SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint32 charges, ObjectGuid caster=ObjectGuid::Empty)
Definition Item.cpp:1511
static void DeleteFromDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType itemGuid)
Definition Item.cpp:1180
void AddArtifactPower(ArtifactPowerData const *artifactPower)
Definition Item.cpp:2643
uint32 GetTotalPurchasedArtifactPowers() const
Definition Item.cpp:2711
uint8 m_slot
Definition Item.h:466
void CopyArtifactDataFromParent(Item *parent)
Definition Item.cpp:2808
friend void AddItemToUpdateQueueOf(Item *item, Player *player)
Definition Item.cpp:1289
bool IsInUpdateQueue() const
Definition Item.h:335
int32 GetRequiredLevel() const
Definition Item.cpp:2864
static Item * CreateItem(uint32 itemEntry, uint32 count, ItemContext context, Player const *player=nullptr, bool addDefaultBonuses=true)
Definition Item.cpp:1721
void LoadArtifactData(Player const *owner, uint64 xp, uint32 artifactAppearanceId, uint32 artifactTier, std::vector< ArtifactPowerData > &powers)
Definition Item.cpp:1098
bool IsFitToSpellRequirements(SpellInfo const *spellInfo) const
Definition Item.cpp:1477
GuidSet allowedGUIDs
Definition Item.h:474
int32 GetSpellCharges(ItemEffectEntry const *effect=nullptr) const
Definition Item.cpp:623
ItemUpdateState uState
Definition Item.h:468
LowType GetCounter() const
Definition ObjectGuid.h:336
static ObjectGuid const Empty
Definition ObjectGuid.h:314
bool IsEmpty() const
Definition ObjectGuid.h:362
std::string ToString() const
uint64 LowType
Definition ObjectGuid.h:321
std::string GetDebugInfo() const override
Definition Object.cpp:160
uint32 GetEntry() const
Definition Object.h:89
void BuildEntityFragmentsForValuesUpdateForPlayerWithMask(ByteBuffer &data, EnumFlag< UF::UpdateFieldFlag > flags) const
Definition Object.cpp:113
void SetEntry(uint32 entry)
Definition Object.h:90
virtual void ClearValuesChangesMask()
Definition Object.cpp:130
virtual void SetObjectScale(float scale)
Definition Object.h:93
UF::UpdateField< UF::ObjectData, int32(WowCS::EntityFragment::CGObject), TYPEID_OBJECT > m_objectData
Definition Object.h:161
ChrSpecialization GetPrimarySpecialization() const
Definition Player.h:2008
UF::UpdateField< UF::PlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_PLAYER > m_playerData
Definition Player.h:3061
std::vector< Item * > m_itemUpdateQueue
Definition Player.h:3224
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6283
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:6010
bool MeetPlayerCondition(uint32 conditionId) const
Definition Player.cpp:30309
WorldSession * GetSession() const
Definition Player.h:2272
void DestroyItem(uint8 bag, uint8 slot, bool update)
Definition Player.cpp:12121
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition Player.cpp:27588
bool IsUsingPvpItemLevels() const
Definition Player.h:2752
std::vector< ItemSetEffect * > ItemSetEff
Definition Player.h:2571
static bool IsBagPos(uint16 pos)
Definition Player.cpp:9783
uint8 GetActiveTalentGroup() const
Definition Player.h:2010
void ApplyEquipSpell(SpellInfo const *spellInfo, Item *item, bool apply, bool formChange=false)
Definition Player.cpp:8409
void DeleteRefundReference(ObjectGuid it)
Definition Player.cpp:29559
void ApplyArtifactPowerRank(Item *artifact, ArtifactPowerRankEntry const *artifactPowerRank, bool apply)
Definition Player.cpp:8508
bool m_itemUpdateQueueBlocked
Definition Player.h:3225
void setUInt16(uint8 index, uint16 value)
void setString(uint8 index, std::string &&value)
void setUInt32(uint8 index, uint32 value)
void setInt64(uint8 index, int64 value)
void setUInt64(uint8 index, uint64 value)
void setUInt8(uint8 index, uint8 value)
bool HasEffect(SpellEffectName effect) const
int32 EquippedItemClass
Definition SpellInfo.h:402
int32 EquippedItemSubClassMask
Definition SpellInfo.h:403
int32 EquippedItemInventoryTypeMask
Definition SpellInfo.h:404
Mask const & GetChangesMask() const
MutableFieldReference< T, false > ModifyValue(UpdateField< T, BlockBit, Bit >(Derived::*field))
void ClearChangesMask(UpdateField< T, BlockBit, Bit >(Derived::*field))
bool HasChanged(uint32 index) const
Definition BaseEntity.h:83
uint32 GetChangedObjectTypeMask() const
Definition BaseEntity.h:81
UF::UpdateField< UF::UnitData, int32(WowCS::EntityFragment::CGObject), TYPEID_UNIT > m_unitData
Definition Unit.h:1881
uint8 GetLevel() const
Definition Unit.h:757
bool BuildPacket(WorldPacket *packet)
void AddUpdateBlock()
Definition UpdateData.h:46
constexpr uint32 GetBlock(uint32 index) const
Definition UpdateMask.h:59
constexpr void Set(uint32 index)
Definition UpdateMask.h:91
constexpr uint32 GetMapId() const
Definition Position.h:216
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
CollectionMgr * GetCollectionMgr() const
void SendEnchantmentLog(ObjectGuid owner, ObjectGuid caster, ObjectGuid itemGuid, uint32 itemId, uint32 enchantId, uint32 enchantSlot)
#define sWorld
Definition World.h:916
@ RATE_REPAIRCOST
Definition World.h:481
uint32 GetMinorMajorBugfixVersionForBuild(uint32 build)
time_t GetGameTime()
Definition GameTime.cpp:52
std::vector< int32 > GetBonusListsForItem(uint32 itemId, ItemBonusGenerationParams const &params)
std::span< ItemBonusEntry const * > GetItemBonuses(uint32 bonusListId)
uint32 GetItemBonusListForItemLevelDelta(int16 delta)
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
ItemModifiedAppearanceEntry const * GetItemModifiedAppearance(uint32 itemId, uint32 appearanceModId)
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition Util.cpp:57
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
UpdateFieldFlag
Definition UpdateField.h:37
struct advstd::ranges::Contains contains
uint32 ArtifactPowerId
Definition Item.h:125
uint8 CurrentRankWithBonus
Definition Item.h:127
uint8 PurchasedRank
Definition Item.h:126
int32 RequiredLevel
Definition Item.h:65
int32 RequiredLevelOverride
Definition Item.h:80
std::array< ItemEffectEntry const *, 13 > Effects
Definition Item.h:90
int16 PvpItemLevelBonus
Definition Item.h:85
void AddBonus(uint32 type, std::array< int32, 4 > const &values)
Definition Item.cpp:2980
std::size_t EffectCount
Definition Item.h:91
uint32 DisenchantLootId
Definition Item.h:75
bool CanDisenchant
Definition Item.h:93
int32 RelicType
Definition Item.h:79
uint32 PlayerLevelToItemLevelCurveId
Definition Item.h:74
uint32 ItemSquishEraID
Definition Item.h:89
int32 GemRelicType[MAX_ITEM_PROTO_SOCKETS]
Definition Item.h:77
uint32 AppearanceModID
Definition Item.h:71
bool IgnoreSquish
Definition Item.h:99
uint32 ItemLevelOffsetCurveId
Definition Item.h:86
int32 ItemLevelBonus
Definition Item.h:64
int32 StatPercentEditor[MAX_ITEM_PROTO_STATS]
Definition Item.h:67
uint32 Suffix
Definition Item.h:82
bool HasFixedLevel
Definition Item.h:97
uint16 PvpItemLevel
Definition Item.h:84
uint32 ItemLevelOffset
Definition Item.h:88
void AddBonusList(uint32 bonusListId)
Definition Item.cpp:2974
uint32 GemItemLevelBonus[MAX_ITEM_PROTO_SOCKETS]
Definition Item.h:76
uint32 ItemLevelOffsetItemLevel
Definition Item.h:87
uint32 ItemLevel
Definition Item.h:63
float ItemStatSocketCostMultiplier[MAX_ITEM_PROTO_STATS]
Definition Item.h:68
uint32 ContentTuningId
Definition Item.h:73
void Initialize(ItemTemplate const *proto)
Definition Item.cpp:2886
int32 RequiredLevelCurve
Definition Item.h:83
std::array< uint16, 8 > ArmorSubClassCost
std::array< uint16, 21 > WeaponSubClassCost
Optional< ArtifactData > Artifact
Definition Item.h:164
Optional< AzeriteEmpoweredItemData > AzeriteEmpoweredItem
Definition Item.h:166
static void Init(std::unordered_map< ObjectGuid::LowType, ItemAdditionalLoadInfo > *loadInfo, PreparedQueryResult artifactResult, PreparedQueryResult azeriteItemResult, PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult, PreparedQueryResult azeriteEmpoweredItemResult)
Definition Item.cpp:352
Optional< AzeriteItemData > AzeriteItem
Definition Item.h:165
uint16 BonusListIDs[16]
Definition Item.h:172
std::unordered_set< ItemSetSpellEntry const * > SetBonuses
Definition Item.cpp:73
std::unordered_set< Item const * > EquippedItems
Definition Item.cpp:72
uint32 ItemSetID
Definition Item.cpp:71
uint16 RequiredSkillRank
uint32 RequiredSkill
uint32 GetBaseItemLevel() const
uint32 GetArea(uint32 index) const
uint32 GetQuality() const
int32 GetStatModifierBonusStat(uint32 index) const
uint32 GetDuration() const
uint32 GetBuyCount() const
float GetPriceRandomValue() const
TransmogOutfitSlotOption GetWeaponTransmogOutfitSlotOption() const
uint32 GetGemProperties() const
uint32 GetId() const
uint32 GetMaxStackSize() const
InventoryType GetInventoryType() const
SocketColor GetSocketColor(uint32 index) const
uint32 GetBuyPrice() const
ItemBondingType GetBonding() const
uint32 GetItemSet() const
float GetStatPercentageOfSocket(uint32 index) const
uint32 GetScalingStatContentTuning() const
uint32 GetItemLevelOffsetItemLevel() const
uint8 GetArtifactID() const
uint32 GetMap() const
std::vector< ItemEffectEntry const * > Effects
bool IsCraftingReagent() const
uint32 GetItemSquishEraId() const
uint32 GetItemLimitCategory() const
int32 GetBaseRequiredLevel() const
uint32 GetItemLevelOffsetCurveId() const
bool HasFlag(ItemFlags flag) const
uint32 GetSubClass() const
uint32 GetSellPrice() const
uint32 MaxDurability
char const * GetName(LocaleConstant locale) const
uint8 GetRequiredExpansion() const
int32 GetStatPercentEditor(uint32 index) const
uint32 GetClass() const
float GetPriceVariance() const
uint32 GetPlayerLevelToItemLevelCurveId() const
uint32 GetSkill() const
uint32 GetBagFamily() const
void operator()(Player const *player) const
Definition Item.cpp:1866
UF::ObjectData::Base ObjectMask
Definition Item.h:404
EnumFlag< SpellItemEnchantmentFlags > GetFlags() const
static void AppendAllowedFieldsMaskForFlag(Mask &allowedMaskForTarget, EnumFlag< UpdateFieldFlag > fieldVisibilityFlags)
UpdateFieldArray< UF::ItemEnchantment, 13, 27, 28 > Enchantment
static void FilterDisallowedFieldsMaskForFlag(Mask &changesMask, EnumFlag< UpdateFieldFlag > fieldVisibilityFlags)
UpdateField< UF::ItemModList, 0, 17 > Modifiers
DynamicUpdateField< UF::SocketedGem, 0, 2 > Gems
UpdateField< WorldPackets::Item::ItemBonusKey, 0, 19 > ItemBonusKey
UpdateField< uint32, 0, 11 > MaxDurability
UpdateFieldArray< int32, 5, 21, 22 > SpellCharges
UpdateField< uint8, 0, 16 > ItemAppearanceModID
UpdateField< uint64, 0, 15 > ArtifactXP
UpdateField< uint32, 0, 7 > StackCount
DynamicUpdateField< UF::ArtifactPower, 0, 1 > ArtifactPowers
UpdateField< int16, 0, 3 > Charges
UpdateField< int32, 0, 1 > ID
UpdateField< uint16, 0, 4 > Inactive
UpdateField< uint32, 0, 2 > Duration
DynamicUpdateField< UF::ItemMod, -1, 0 > Values
UpdateFieldArray< uint16, 16, 3, 4 > BonusListIDs
UpdateField< uint8, 0, 2 > Context
UpdateField< int32, 0, 1 > ItemID
Optional< ItemBonuses > ItemBonus
void Add(EntityFragment fragment, bool update, void const *data=nullptr)