From 03f1e5a94efb772f4b223915efa9d53edd6ce999 Mon Sep 17 00:00:00 2001 From: Ovalord <1Don7H4v3@m41L.com> Date: Wed, 20 Dec 2017 20:20:52 +0100 Subject: [PATCH] Core/Spells: fixed armor specializations --- .../4.3.4/custom_2017_12_20_00_world.sql | 28 +++ src/server/game/Entities/Player/Player.cpp | 45 +++++ src/server/game/Entities/Player/Player.h | 11 +- .../game/Spells/Auras/SpellAuraEffects.cpp | 3 + src/server/scripts/Spells/spell_generic.cpp | 161 ++++++++++++++++++ 5 files changed, 246 insertions(+), 2 deletions(-) create mode 100644 sql/updates/world/4.3.4/custom_2017_12_20_00_world.sql diff --git a/sql/updates/world/4.3.4/custom_2017_12_20_00_world.sql b/sql/updates/world/4.3.4/custom_2017_12_20_00_world.sql new file mode 100644 index 0000000000..5b28d7a53c --- /dev/null +++ b/sql/updates/world/4.3.4/custom_2017_12_20_00_world.sql @@ -0,0 +1,28 @@ +-- Spell Scriptnames +DELETE FROM `spell_script_names` WHERE `ScriptName`= 'spell_gen_armor_specialization'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(86530, 'spell_gen_armor_specialization'), +(86531, 'spell_gen_armor_specialization'), +(86529, 'spell_gen_armor_specialization'), +(86528, 'spell_gen_armor_specialization'), +(86525, 'spell_gen_armor_specialization'), +(86524, 'spell_gen_armor_specialization'), +(86526, 'spell_gen_armor_specialization'); + +-- Correct wrong teaching spells +-- Warrior +UPDATE `npc_trainer` SET `SpellID`= 86526 WHERE `SpellID`= 87509; +-- Paladin +UPDATE `npc_trainer` SET `SpellID`= 86525 WHERE `SpellID`= 87511; +-- Death Knight +DELETE FROM `npc_trainer` WHERE `SpellID`= 86524; +INSERT INTO `npc_trainer` (`ID`, `SpellID`, `MoneyCost`, `ReqLevel`) VALUES +(200006, 86524, 22500, 50); +-- Shaman +UPDATE `npc_trainer` SET `SpellID`= 86529 WHERE `SpellID`= 87507; +-- Hunter +UPDATE `npc_trainer` SET `SpellID`= 86528 WHERE `SpellID`= 87506; +-- Rogue +UPDATE `npc_trainer` SET `SpellID`= 86531 WHERE `SpellID`= 87504; +-- Druid +UPDATE `npc_trainer` SET `SpellID`= 86530 WHERE `SpellID`= 87505; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 80f19411a1..500d8b9214 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -11969,6 +11969,8 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) else if (slot == EQUIPMENT_SLOT_OFFHAND) UpdateExpertise(OFF_ATTACK); + UpdateArmorSpecialization(); + switch (slot) { case EQUIPMENT_SLOT_MAINHAND: @@ -12005,6 +12007,8 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) ApplyEquipCooldown(pItem2); + UpdateArmorSpecialization(); + return pItem2; } @@ -12166,6 +12170,7 @@ void Player::RemoveItem(uint8 bag, uint8 slot, bool update) pItem->SetGuidValue(ITEM_FIELD_CONTAINED, ObjectGuid::Empty); // pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0); not clear owner at remove (it will be set at store). This used in mail and auction code pItem->SetSlot(NULL_SLOT); + UpdateArmorSpecialization(); if (IsInWorld() && update) pItem->SendUpdateToPlayer(this); } @@ -17862,6 +17867,9 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) SetAtLoginFlag(AT_LOGIN_RESET_TALENTS); // invalid tree, reset talents } + // We neeed to update the armor specialization after the talenttree was set + UpdateArmorSpecialization(); + TC_LOG_DEBUG("entities.player.loading", "The value of player %s after load item and aura is: ", m_name.c_str()); outDebugValues(); @@ -24215,6 +24223,21 @@ bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item cons return false; } +bool Player::HasAllItemsToFitToSpellRequirements(SpellInfo const* spellInfo) +{ + uint8 count = 0; + + for (uint8 slot = EQUIPMENT_SLOT_START; slot <= EQUIPMENT_SLOT_HANDS; ++slot) + if (Item* item = GetUseableItemByPos(INVENTORY_SLOT_BAG_0, slot)) + if (item->IsFitToSpellRequirements(spellInfo)) + ++count; + + if (count >= 8) + return true; + + return false; +} + bool Player::CanNoReagentCast(SpellInfo const* spellInfo) const { // don't take reagents for spells with SPELL_ATTR5_NO_REAGENT_WHILE_PREP @@ -27145,6 +27168,28 @@ bool Player::IsInWhisperWhiteList(ObjectGuid guid) return false; } +void Player::UpdateArmorSpecialization() +{ + // Remove Auras with SPELL_ATTR8_ARMOR_SPECIALIZATION + for (AuraApplicationMap::iterator itr = m_appliedAuras.begin(); itr != m_appliedAuras.end();) + { + SpellInfo const* spell = itr->second->GetBase()->GetSpellInfo(); + if (spell->AttributesEx8 & SPELL_ATTR8_ARMOR_SPECIALIZATION) + RemoveAura(itr); + else + ++itr; + } + + for (uint8 id = 0; id < MAX_ARMOR_SPECIALIZATION_IDS; id++) + { + if (HasSpell(ArmorSpecializationIds[id])) + { + CastSpell(this, ArmorSpecializationIds[id], TRIGGERED_FULL_MASK); + break; + } + } +} + uint8 Player::GetNextVoidStorageFreeSlot() const { for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 115601ca6b..d2fb52635d 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -155,6 +155,9 @@ enum TalentTree // talent tabs TALENT_TREE_DRUID_RESTORATION = 748 }; +#define MAX_ARMOR_SPECIALIZATION_IDS 7 +uint32 const ArmorSpecializationIds[MAX_ARMOR_SPECIALIZATION_IDS] = { 86530, 86531, 86529, 86528, 86525, 86524, 86526 }; + // Spell modifier (used for modify other spells) struct SpellModifier { @@ -1382,6 +1385,7 @@ class TC_GAME_API Player : public Unit, public GridObject void SetBankBagSlotCount(uint8 count) { SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_BANK_BAG_SLOTS, count); } bool HasItemCount(uint32 item, uint32 count = 1, bool inBankAlso = false) const; bool HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item const* ignoreItem = nullptr) const; + bool HasAllItemsToFitToSpellRequirements(SpellInfo const* spellInfo); bool CanNoReagentCast(SpellInfo const* spellInfo) const; bool HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot = NULL_SLOT) const; bool HasItemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot = NULL_SLOT) const; @@ -1807,9 +1811,9 @@ class TC_GAME_API Player : public Unit, public GridObject uint32 GetTalentResetTime() const { return _talentMgr->ResetTalentsTime; } void SetTalentResetTime(time_t time_) { _talentMgr->ResetTalentsTime = time_; } uint32 GetPrimaryTalentTree(uint8 spec) const { return _talentMgr->SpecInfo[spec].TalentTree; } - void SetPrimaryTalentTree(uint8 spec, uint32 tree) { _talentMgr->SpecInfo[spec].TalentTree = tree; } + void SetPrimaryTalentTree(uint8 spec, uint32 tree) { _talentMgr->SpecInfo[spec].TalentTree = tree; UpdateArmorSpecialization(); } uint8 GetActiveSpec() const { return _talentMgr->ActiveSpec; } - void SetActiveSpec(uint8 spec){ _talentMgr->ActiveSpec = spec; } + void SetActiveSpec(uint8 spec){ _talentMgr->ActiveSpec = spec; UpdateArmorSpecialization(); } uint8 GetSpecsCount() const { return _talentMgr->SpecsCount; } void SetSpecsCount(uint8 count) { _talentMgr->SpecsCount = count; } @@ -1825,6 +1829,9 @@ class TC_GAME_API Player : public Unit, public GridObject bool HasTalent(uint32 spell_id, uint8 spec) const; uint32 CalculateTalentsPoints() const; + // Armor Specializaion + void UpdateArmorSpecialization(); + // Dual Spec void UpdateSpecCount(uint8 count); void ActivateSpec(uint8 spec); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index a990705159..15e2201284 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1967,7 +1967,10 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo } if (target->GetTypeId() == TYPEID_PLAYER) + { target->ToPlayer()->InitDataForForm(); + target->ToPlayer()->UpdateArmorSpecialization(); + } if (target->getClass() == CLASS_DRUID) { diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index bc20433511..9756b8dbb4 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -4248,6 +4248,166 @@ class spell_gen_pony_mount_check : public SpellScriptLoader } }; +enum ArmorSpecializationSpells +{ + // Warrior + SPELL_ARMOR_SPEC_WAR_ARMS = 86110, + SPELL_ARMOR_SPEC_WAR_FURY = 86101, + SPELL_ARMOR_SPEC_WAR_PROTECTION = 86535, + + // Paladin + SPELL_ARMOR_SPEC_PAL_HOLY = 86103, + SPELL_ARMOR_SPEC_PAL_PROTECTOION = 86102, + SPELL_ARMOR_SPEC_PAL_RETRIBUTION = 86539, + + // Hunter + SPELL_ARMOR_SPEC_HUN = 86538, + + // Rogue + SPELL_ARMOR_SPEC_ROG = 86092, + + // Death Knight + SPELL_ARMOR_SPEC_DK_BLOOD = 86537, + SPELL_ARMOR_SPEC_DK_FROST = 86536, + SPELL_ARMOR_SPEC_DK_UNHOLY = 86113, + + // Shaman + SPELL_ARMOR_SPEC_SHA_ELEMENTAL = 86100, + SPELL_ARMOR_SPEC_SHA_ENHANCEMENT = 86099, + SPELL_ARMOR_SPEC_SHA_RESTORATION = 86108, + + // Druid + SPELL_ARMOR_SPEC_DRU_BALANCE = 86093, + SPELL_ARMOR_SPEC_DRU_FREAL_BEAR = 86096, + SPELL_ARMOR_SPEC_DRU_FERAL = 86097, + SPELL_ARMOR_SPEC_DRU_RESTORATION = 86104 +}; + +class spell_gen_armor_specialization : public SpellScriptLoader +{ + public: + spell_gen_armor_specialization() : SpellScriptLoader("spell_gen_armor_specialization") { } + + class spell_gen_armor_specialization_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gen_armor_specialization_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo( + { + SPELL_ARMOR_SPEC_WAR_ARMS, + SPELL_ARMOR_SPEC_WAR_FURY, + SPELL_ARMOR_SPEC_WAR_PROTECTION, + SPELL_ARMOR_SPEC_PAL_HOLY, + SPELL_ARMOR_SPEC_PAL_PROTECTOION, + SPELL_ARMOR_SPEC_PAL_RETRIBUTION, + SPELL_ARMOR_SPEC_HUN, + SPELL_ARMOR_SPEC_ROG, + SPELL_ARMOR_SPEC_DK_BLOOD, + SPELL_ARMOR_SPEC_DK_FROST, + SPELL_ARMOR_SPEC_DK_UNHOLY, + SPELL_ARMOR_SPEC_SHA_ELEMENTAL, + SPELL_ARMOR_SPEC_SHA_ENHANCEMENT, + SPELL_ARMOR_SPEC_SHA_RESTORATION, + SPELL_ARMOR_SPEC_DRU_BALANCE, + SPELL_ARMOR_SPEC_DRU_FREAL_BEAR, + SPELL_ARMOR_SPEC_DRU_FERAL, + SPELL_ARMOR_SPEC_DRU_RESTORATION + }); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Player* player = GetHitPlayer(); + if (!player) + return; + + uint32 spellId = 0; + + switch (player->GetPrimaryTalentTree(player->GetActiveSpec())) + { + case TALENT_TREE_WARRIOR_ARMS: + spellId = SPELL_ARMOR_SPEC_WAR_ARMS; + break; + case TALENT_TREE_WARRIOR_FURY: + spellId = SPELL_ARMOR_SPEC_WAR_FURY; + break; + case TALENT_TREE_WARRIOR_PROTECTION: + spellId = SPELL_ARMOR_SPEC_WAR_PROTECTION; + break; + case TALENT_TREE_PALADIN_HOLY: + spellId = SPELL_ARMOR_SPEC_PAL_HOLY; + break; + case TALENT_TREE_PALADIN_PROTECTION: + spellId = SPELL_ARMOR_SPEC_PAL_PROTECTOION; + break; + case TALENT_TREE_PALADIN_RETRIBUTION: + spellId = SPELL_ARMOR_SPEC_PAL_RETRIBUTION; + break; + case TALENT_TREE_HUNTER_BEAST_MASTERY: + case TALENT_TREE_HUNTER_MARKSMANSHIP: + case TALENT_TREE_HUNTER_SURVIVAL: + spellId = SPELL_ARMOR_SPEC_HUN; + break; + case TALENT_TREE_ROGUE_ASSASSINATION: + case TALENT_TREE_ROGUE_COMBAT: + case TALENT_TREE_ROGUE_SUBTLETY: + spellId = SPELL_ARMOR_SPEC_ROG; + break; + case TALENT_TREE_DEATH_KNIGHT_BLOOD: + spellId = SPELL_ARMOR_SPEC_DK_BLOOD; + break; + case TALENT_TREE_DEATH_KNIGHT_FROST: + spellId = SPELL_ARMOR_SPEC_DK_FROST; + break; + case TALENT_TREE_DEATH_KNIGHT_UNHOLY: + spellId = SPELL_ARMOR_SPEC_DK_UNHOLY; + break; + case TALENT_TREE_SHAMAN_ELEMENTAL: + spellId = SPELL_ARMOR_SPEC_SHA_ELEMENTAL; + break; + case TALENT_TREE_SHAMAN_ENHANCEMENT: + spellId = SPELL_ARMOR_SPEC_SHA_ENHANCEMENT; + break; + case TALENT_TREE_SHAMAN_RESTORATION: + spellId = SPELL_ARMOR_SPEC_SHA_RESTORATION; + break; + case TALENT_TREE_DRUID_BALANCE: + spellId = SPELL_ARMOR_SPEC_DRU_BALANCE; + break; + case TALENT_TREE_DRUID_FERAL_COMBAT: + { + if (player->GetShapeshiftForm() == FORM_BEAR) + spellId = SPELL_ARMOR_SPEC_DRU_FREAL_BEAR; + else + spellId = SPELL_ARMOR_SPEC_DRU_FERAL; + break; + } + case TALENT_TREE_DRUID_RESTORATION: + spellId = SPELL_ARMOR_SPEC_DRU_RESTORATION; + break; + default: + return; + } + + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId)) + if (player->HasAllItemsToFitToSpellRequirements(spellInfo)) + player->CastSpell(player, spellId, true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_gen_armor_specialization_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_gen_armor_specialization_SpellScript(); + } +}; + void AddSC_generic_spell_scripts() { new spell_gen_absorb0_hitlimit1(); @@ -4349,4 +4509,5 @@ void AddSC_generic_spell_scripts() new spell_gen_landmine_knockback_achievement(); new spell_gen_clear_debuffs(); new spell_gen_pony_mount_check(); + new spell_gen_armor_specialization(); }