diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/DataStores/DBCEnums.h | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.cpp | 31 | ||||
-rw-r--r-- | src/server/game/Entities/Item/Item.h | 17 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 43 | ||||
-rw-r--r-- | src/server/game/Handlers/ItemHandler.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Handlers/SpellHandler.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 57 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 7 |
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); } } |