aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/DataStores/DBCEnums.h4
-rw-r--r--src/server/game/Entities/Item/Item.cpp31
-rw-r--r--src/server/game/Entities/Item/Item.h17
-rw-r--r--src/server/game/Entities/Player/Player.cpp43
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp5
-rw-r--r--src/server/game/Handlers/SpellHandler.cpp4
-rw-r--r--src/server/game/Spells/Spell.cpp57
-rw-r--r--src/server/game/Spells/SpellEffects.cpp7
8 files changed, 87 insertions, 81 deletions
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 76375ae88fa..0c5e35af70f 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -1015,8 +1015,10 @@ enum ItemBonusType
ITEM_BONUS_RELIC_TYPE = 17,
ITEM_BONUS_OVERRIDE_REQUIRED_LEVEL = 18,
ITEM_BONUS_AZERITE_TIER_UNLOCK_SET = 19,
+ ITEM_BONUS_SCRAPPING_LOOT_ID = 20,
ITEM_BONUS_OVERRIDE_CAN_DISENCHANT = 21,
- ITEM_BONUS_OVERRIDE_CAN_SCRAP = 22
+ ITEM_BONUS_OVERRIDE_CAN_SCRAP = 22,
+ ITEM_BONUS_ITEM_EFFECT_ID = 23,
};
enum class ItemContext : uint8
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index c8245b14795..abe8914e48a 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -466,8 +466,8 @@ bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemId, ItemContext contex
SetDurability(itemProto->MaxDurability);
for (std::size_t i = 0; i < itemProto->Effects.size(); ++i)
- if (i < 5)
- SetSpellCharges(i, itemProto->Effects[i]->Charges);
+ if (itemProto->Effects[i]->LegacySlotIndex < 5)
+ SetSpellCharges(itemProto->Effects[i]->LegacySlotIndex, itemProto->Effects[i]->Charges);
SetExpiration(itemProto->GetDuration());
SetCreatePlayedTime(0);
@@ -557,9 +557,8 @@ void Item::SaveToDB(CharacterDatabaseTransaction& trans)
stmt->setUInt32(++index, m_itemData->Expiration);
std::ostringstream ssSpells;
- if (ItemTemplate const* itemProto = sObjectMgr->GetItemTemplate(GetEntry()))
- for (uint8 i = 0; i < itemProto->Effects.size(); ++i)
- ssSpells << GetSpellCharges(i) << ' ';
+ for (uint8 i = 0; i < m_itemData->SpellCharges.size() && i < _bonusData.EffectCount; ++i)
+ ssSpells << GetSpellCharges(i) << ' ';
stmt->setString(++index, ssSpells.str());
stmt->setUInt32(++index, m_itemData->DynamicFlags);
@@ -834,11 +833,6 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
need_save = true;
}
- Tokenizer tokens(fields[6].GetString(), ' ', proto->Effects.size());
- if (tokens.size() == proto->Effects.size())
- for (uint8 i = 0; i < proto->Effects.size(); ++i)
- SetSpellCharges(i, atoi(tokens[i]));
-
SetItemFlags(ItemFieldFlags(itemFlags));
uint32 durability = fields[10].GetUInt16();
@@ -870,6 +864,11 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
bonusListIDs.push_back(atoi(token));
SetBonuses(std::move(bonusListIDs));
+ // load charges after bonuses, they can add more item effects
+ Tokenizer tokens(fields[6].GetString(), ' ', proto->Effects.size());
+ for (uint8 i = 0; i < m_itemData->SpellCharges.size() && i < _bonusData.EffectCount && i < tokens.size(); ++i)
+ SetSpellCharges(i, atoi(tokens[i]));
+
SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS, fields[19].GetUInt32());
SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_1, fields[20].GetUInt32());
SetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_SPEC_2, fields[21].GetUInt32());
@@ -2661,6 +2660,14 @@ void BonusData::Initialize(ItemTemplate const* proto)
AzeriteTierUnlockSetId = azeriteEmpoweredItem->AzeriteTierUnlockSetID;
Suffix = 0;
+
+ EffectCount = 0;
+ for (ItemEffectEntry const* itemEffect : proto->Effects)
+ Effects[EffectCount++] = itemEffect;
+
+ for (std::size_t i = EffectCount; i < Effects.size(); ++i)
+ Effects[i] = nullptr;
+
CanDisenchant = (proto->GetFlags() & ITEM_FLAG_NO_DISENCHANT) == 0;
CanScrap = (proto->GetFlags4() & ITEM_FLAG4_SCRAPABLE) != 0;
@@ -2786,5 +2793,9 @@ void BonusData::AddBonus(uint32 type, int32 const (&values)[3])
case ITEM_BONUS_OVERRIDE_CAN_SCRAP:
CanScrap = values[0] != 0;
break;
+ case ITEM_BONUS_ITEM_EFFECT_ID:
+ if (ItemEffectEntry const* itemEffect = sItemEffectStore.LookupEntry(values[0]))
+ Effects[EffectCount++] = itemEffect;
+ break;
}
}
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index 007b9ef46c5..7e715f96e8e 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -24,6 +24,7 @@
#include "ItemDefines.h"
#include "ItemEnchantmentMgr.h"
#include "ItemTemplate.h"
+#include "IteratorPair.h"
#include "Loot.h"
class SpellInfo;
@@ -46,13 +47,6 @@ struct ItemSetEffect
#define MAX_GEM_SOCKETS MAX_ITEM_PROTO_SOCKETS// (BONUS_ENCHANTMENT_SLOT-SOCK_ENCHANTMENT_SLOT) and item proto size, equal value expected
-enum EnchantmentOffset
-{
- ENCHANTMENT_ID_OFFSET = 0,
- ENCHANTMENT_DURATION_OFFSET = 1,
- ENCHANTMENT_CHARGES_OFFSET = 2 // now here not only charges, but something new in wotlk
-};
-
#define MAX_ENCHANTMENT_OFFSET 3
enum ItemUpdateState
@@ -63,7 +57,6 @@ enum ItemUpdateState
ITEM_REMOVED = 3
};
-
#define MAX_ITEM_SPELLS 5
bool ItemCanGoIntoBag(ItemTemplate const* proto, ItemTemplate const* pBagProto);
@@ -93,6 +86,8 @@ struct BonusData
int32 RequiredLevelOverride;
int32 AzeriteTierUnlockSetId;
uint32 Suffix;
+ std::array<ItemEffectEntry const*, 13> Effects;
+ std::size_t EffectCount;
bool CanDisenchant;
bool CanScrap;
bool HasFixedLevel;
@@ -345,6 +340,12 @@ class TC_GAME_API Item : public Object
ItemDisenchantLootEntry const* GetDisenchantLoot(Player const* owner) const;
static ItemDisenchantLootEntry const* GetDisenchantLoot(ItemTemplate const* itemTemplate, uint32 quality, uint32 itemLevel);
void SetFixedLevel(uint8 level);
+ Trinity::IteratorPair<ItemEffectEntry const* const*> GetEffects() const { return { std::make_pair(&_bonusData.Effects[0], &_bonusData.Effects[0] + _bonusData.EffectCount) }; }
+ ItemEffectEntry const* GetEffect(std::size_t i) const
+ {
+ ASSERT(i < _bonusData.EffectCount, "Attempted to get effect at index " SZFMTD " but item has only " SZFMTD " effects!", i, _bonusData.EffectCount);
+ return _bonusData.Effects[i];
+ }
// Item Refund system
void SetNotRefundable(Player* owner, bool changestate = true, CharacterDatabaseTransaction* trans = nullptr, bool addToCollection = true);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 40c19caf8f6..597628b6f4c 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -7846,13 +7846,12 @@ void Player::CastAllObtainSpells()
void Player::ApplyItemObtainSpells(Item* item, bool apply)
{
- ItemTemplate const* itemTemplate = item->GetTemplate();
- for (uint8 i = 0; i < itemTemplate->Effects.size(); ++i)
+ for (ItemEffectEntry const* effect : item->GetEffects())
{
- if (itemTemplate->Effects[i]->TriggerType != ITEM_SPELLTRIGGER_ON_OBTAIN) // On obtain trigger
+ if (effect->TriggerType != ITEM_SPELLTRIGGER_ON_OBTAIN) // On obtain trigger
continue;
- int32 const spellId = itemTemplate->Effects[i]->SpellID;
+ int32 const spellId = effect->SpellID;
if (spellId <= 0)
continue;
@@ -7949,14 +7948,8 @@ void Player::ApplyItemEquipSpell(Item* item, bool apply, bool formChange /*= fal
if (!item)
return;
- ItemTemplate const* proto = item->GetTemplate();
- if (!proto)
- return;
-
- for (uint8 i = 0; i < proto->Effects.size(); ++i)
+ for (ItemEffectEntry const* effectData : item->GetEffects())
{
- ItemEffectEntry const* effectData = proto->Effects[i];
-
// wrong triggering type
if (apply && effectData->TriggerType != ITEM_SPELLTRIGGER_ON_EQUIP)
continue;
@@ -8294,10 +8287,8 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT
bool canTrigger = (damageInfo.GetHitMask() & (PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB)) != 0;
if (canTrigger)
{
- for (uint8 i = 0; i < proto->Effects.size(); ++i)
+ for (ItemEffectEntry const* effectData : item->GetEffects())
{
- ItemEffectEntry const* effectData = proto->Effects[i];
-
// wrong triggering type
if (effectData->TriggerType != ITEM_SPELLTRIGGER_CHANCE_ON_HIT)
continue;
@@ -8422,19 +8413,18 @@ void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemT
void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, ObjectGuid castCount, int32* misc)
{
- ItemTemplate const* proto = item->GetTemplate();
// special learning case
- if (proto->Effects.size() >= 2)
+ if (item->GetBonus()->EffectCount >= 2)
{
- if (proto->Effects[0]->SpellID == 483 || proto->Effects[0]->SpellID == 55884)
+ if (item->GetEffect(0)->SpellID == 483 || item->GetEffect(0)->SpellID == 55884)
{
- uint32 learn_spell_id = proto->Effects[0]->SpellID;
- uint32 learning_spell_id = proto->Effects[1]->SpellID;
+ uint32 learn_spell_id = item->GetEffect(0)->SpellID;
+ uint32 learning_spell_id = item->GetEffect(1)->SpellID;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(learn_spell_id);
if (!spellInfo)
{
- TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) has wrong spell id %u, ignoring", proto->GetId(), learn_spell_id);
+ TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) has wrong spell id %u, ignoring", item->GetEntry(), learn_spell_id);
SendEquipError(EQUIP_ERR_INTERNAL_BAG_ERROR, item, nullptr);
return;
}
@@ -8455,10 +8445,8 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, Objec
}
// item spells cast at use
- for (uint8 i = 0; i < proto->Effects.size(); ++i)
+ for (ItemEffectEntry const* effectData : item->GetEffects())
{
- ItemEffectEntry const* effectData = proto->Effects[i];
-
// wrong triggering type
if (effectData->TriggerType != ITEM_SPELLTRIGGER_ON_USE)
continue;
@@ -8466,7 +8454,7 @@ void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, Objec
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effectData->SpellID);
if (!spellInfo)
{
- TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) has wrong spell id %u, ignoring", proto->GetId(), effectData->SpellID);
+ TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: %u) has wrong spell id %u, ignoring", item->GetEntry(), effectData->SpellID);
continue;
}
@@ -24288,15 +24276,12 @@ void Player::SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint3
void Player::ApplyEquipCooldown(Item* pItem)
{
- ItemTemplate const* proto = pItem->GetTemplate();
- if (proto->GetFlags() & ITEM_FLAG_NO_EQUIP_COOLDOWN)
+ if (pItem->GetTemplate()->GetFlags() & ITEM_FLAG_NO_EQUIP_COOLDOWN)
return;
std::chrono::steady_clock::time_point now = GameTime::GetGameTimeSteadyPoint();
- for (uint8 i = 0; i < proto->Effects.size(); ++i)
+ for (ItemEffectEntry const* effectData : pItem->GetEffects())
{
- ItemEffectEntry const* effectData = proto->Effects[i];
-
// apply proc cooldown to equip auras if we have any
if (effectData->TriggerType == ITEM_SPELLTRIGGER_ON_EQUIP)
{
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index 514f315aae0..55373095a18 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -1190,11 +1190,10 @@ void WorldSession::HandleUseCritterItem(WorldPackets::Item::UseCritterItem& useC
if (!item)
return;
- if (item->GetTemplate()->Effects.size() < 2)
+ if (item->GetBonus()->EffectCount < 2)
return;
- int32 spellToLearn = item->GetTemplate()->Effects[1]->SpellID;
-
+ int32 spellToLearn = item->GetEffect(1)->SpellID;
if (BattlePetSpeciesEntry const* entry = sSpellMgr->GetBattlePetSpecies(uint32(spellToLearn)))
{
diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
index 1ae93079145..7c079d3a40a 100644
--- a/src/server/game/Handlers/SpellHandler.cpp
+++ b/src/server/game/Handlers/SpellHandler.cpp
@@ -95,9 +95,9 @@ void WorldSession::HandleUseItemOpcode(WorldPackets::Spells::UseItem& packet)
if (user->IsInCombat())
{
- for (uint32 i = 0; i < proto->Effects.size(); ++i)
+ for (ItemEffectEntry const* effect : item->GetEffects())
{
- if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Effects[i]->SpellID))
+ if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effect->SpellID))
{
if (!spellInfo->CanBeUsedInCombat())
{
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 290361471da..ada40659922 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -4530,22 +4530,25 @@ void Spell::TakeCastItem()
bool expendable = false;
bool withoutCharges = false;
- for (uint8 i = 0; i < proto->Effects.size() && i < 5; ++i)
+ for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
{
+ if (itemEffect->LegacySlotIndex >= m_CastItem->m_itemData->SpellCharges.size())
+ continue;
+
// item has limited charges
- if (proto->Effects[i]->Charges)
+ if (itemEffect->Charges)
{
- if (proto->Effects[i]->Charges < 0)
+ if (itemEffect->Charges < 0)
expendable = true;
- int32 charges = m_CastItem->GetSpellCharges(i);
+ int32 charges = m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex);
// item has charges left
if (charges)
{
(charges > 0) ? --charges : ++charges; // abs(charges) less at 1 after use
if (proto->GetMaxStackSize() == 1)
- m_CastItem->SetSpellCharges(i, charges);
+ m_CastItem->SetSpellCharges(itemEffect->LegacySlotIndex, charges);
m_CastItem->SetState(ITEM_CHANGED, player);
}
@@ -4695,10 +4698,8 @@ void Spell::TakeReagents()
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return;
- ItemTemplate const* castItemTemplate = m_CastItem ? m_CastItem->GetTemplate() : NULL;
-
// do not take reagents for these item casts
- if (castItemTemplate && castItemTemplate->GetFlags() & ITEM_FLAG_NO_REAGENT_COST)
+ if (m_CastItem && m_CastItem->GetTemplate()->GetFlags() & ITEM_FLAG_NO_REAGENT_COST)
return;
Player* p_caster = m_caster->ToPlayer();
@@ -4714,13 +4715,16 @@ void Spell::TakeReagents()
uint32 itemcount = m_spellInfo->ReagentCount[x];
// if CastItem is also spell reagent
- if (castItemTemplate && castItemTemplate->GetId() == itemid)
+ if (m_CastItem && m_CastItem->GetEntry() == itemid)
{
- for (uint8 s = 0; s < castItemTemplate->Effects.size() && s < 5; ++s)
+ for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
{
+ if (itemEffect->LegacySlotIndex >= m_CastItem->m_itemData->SpellCharges.size())
+ continue;
+
// CastItem will be used up and does not count as reagent
- int32 charges = m_CastItem->GetSpellCharges(s);
- if (castItemTemplate->Effects[s]->Charges < 0 && abs(charges) < 2)
+ int32 charges = m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex);
+ if (itemEffect->Charges < 0 && abs(charges) < 2)
{
++itemcount;
break;
@@ -6286,9 +6290,9 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
if (!proto)
return SPELL_FAILED_ITEM_NOT_READY;
- for (uint8 i = 0; i < proto->Effects.size() && i < 5; ++i)
- if (proto->Effects[i]->Charges)
- if (m_CastItem->GetSpellCharges(i) == 0)
+ for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
+ if (itemEffect->LegacySlotIndex < m_CastItem->m_itemData->SpellCharges.size() && itemEffect->Charges)
+ if (m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex) == 0)
return SPELL_FAILED_NO_CHARGES_REMAIN;
// consumable cast item checks
@@ -6388,11 +6392,15 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
ItemTemplate const* proto = m_CastItem->GetTemplate();
if (!proto)
return SPELL_FAILED_ITEM_NOT_READY;
- for (uint8 s = 0; s < proto->Effects.size() && s < 5; ++s)
+
+ for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
{
+ if (itemEffect->LegacySlotIndex >= m_CastItem->m_itemData->SpellCharges.size())
+ continue;
+
// CastItem will be used up and does not count as reagent
- int32 charges = m_CastItem->GetSpellCharges(s);
- if (proto->Effects[s]->Charges < 0 && abs(charges) < 2)
+ int32 charges = m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex);
+ if (itemEffect->Charges < 0 && abs(charges) < 2)
{
++itemcount;
break;
@@ -6521,10 +6529,9 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
return SPELL_FAILED_LOWLEVEL;
bool isItemUsable = false;
- ItemTemplate const* proto = targetItem->GetTemplate();
- for (uint8 e = 0; e < proto->Effects.size(); ++e)
+ for (ItemEffectEntry const* itemEffect : targetItem->GetEffects())
{
- if (proto->Effects[e]->SpellID && proto->Effects[e]->TriggerType == ITEM_SPELLTRIGGER_ON_USE)
+ if (itemEffect->SpellID && itemEffect->TriggerType == ITEM_SPELLTRIGGER_ON_USE)
{
isItemUsable = true;
break;
@@ -6718,11 +6725,11 @@ SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /
return SPELL_FAILED_ITEM_AT_MAX_CHARGES;
if (Item* item = player->GetItemByEntry(itemId))
- {
- for (uint8 x = 0; x < proto->Effects.size() && x < 5; ++x)
- if (proto->Effects[x]->Charges != 0 && item->GetSpellCharges(x) == proto->Effects[x]->Charges)
+ for (ItemEffectEntry const* itemEffect : item->GetEffects())
+ if (itemEffect->LegacySlotIndex <= item->m_itemData->SpellCharges.size()
+ && itemEffect->Charges != 0
+ && item->GetSpellCharges(itemEffect->LegacySlotIndex) == itemEffect->Charges)
return SPELL_FAILED_ITEM_AT_MAX_CHARGES;
- }
break;
}
case SPELL_EFFECT_RESPEC_AZERITE_EMPOWERED_ITEM:
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index f4f7befa2db..e7d78a0ec57 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -5392,9 +5392,10 @@ void Spell::EffectRechargeItem(SpellEffIndex /*effIndex*/)
if (Item* item = player->GetItemByEntry(effectInfo->ItemType))
{
- ItemTemplate const* proto = item->GetTemplate();
- for (size_t x = 0; x < proto->Effects.size() && x < 5; ++x)
- item->SetSpellCharges(x, proto->Effects[x]->Charges);
+ for (ItemEffectEntry const* itemEffect : item->GetEffects())
+ if (itemEffect->LegacySlotIndex <= item->m_itemData->SpellCharges.size())
+ item->SetSpellCharges(itemEffect->LegacySlotIndex, itemEffect->Charges);
+
item->SetState(ITEM_CHANGED, player);
}
}