From fff0e1713393e69e2dfd43461df3d126e801883d Mon Sep 17 00:00:00 2001 From: Skjalf <47818697+Nyeriah@users.noreply.github.com> Date: Wed, 22 Feb 2023 23:00:18 -0300 Subject: [PATCH] =?UTF-8?q?fix(Core/Cooldown):=20Implement=20spell=20coold?= =?UTF-8?q?own=20overrides=20to=20address=20cha=E2=80=A6=20(#15143)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rev_1676897566022575900.sql | 10 +++ .../game/Entities/Creature/Creature.cpp | 10 +++ src/server/game/Entities/Unit/Unit.cpp | 18 +++++ src/server/game/Spells/SpellMgr.cpp | 72 ++++++++++++++++++- src/server/game/Spells/SpellMgr.h | 15 ++++ src/server/game/World/World.cpp | 3 + 6 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1676897566022575900.sql diff --git a/data/sql/updates/pending_db_world/rev_1676897566022575900.sql b/data/sql/updates/pending_db_world/rev_1676897566022575900.sql new file mode 100644 index 000000000..2071fcb89 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1676897566022575900.sql @@ -0,0 +1,10 @@ +-- +DROP TABLE IF EXISTS `spell_cooldown_overrides`; +CREATE TABLE `spell_cooldown_overrides` ( + `Id` INT UNSIGNED NOT NULL, + `RecoveryTime` INT UNSIGNED NOT NULL DEFAULT '0', + `CategoryRecoveryTime` INT UNSIGNED NOT NULL DEFAULT '0', + `StartRecoveryTime` INT UNSIGNED NOT NULL DEFAULT '0', + `StartRecoveryCategory` INT UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`Id`) +); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 987191e96..2d8e49251 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2804,6 +2804,16 @@ void Creature::AddSpellCooldown(uint32 spell_id, uint32 /*itemid*/, uint32 end_t { _AddCreatureSpellCooldown(spellInfo->Id, 0, spellcooldown); } + + if (sSpellMgr->HasSpellCooldownOverride(spellInfo->Id)) + { + if (IsCharmed() && GetCharmer()->IsPlayer()) + { + WorldPacket data; + BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spellInfo->Id, spellcooldown); + GetCharmer()->ToPlayer()->SendDirectMessage(&data); + } + } } uint32 Creature::GetSpellCooldown(uint32 spell_id) const diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 2c4cc920c..87555d8cd 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -15876,6 +15876,24 @@ bool CharmInfo::AddSpellToActionBar(SpellInfo const* spellInfo, ActiveStates new if (!PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell()) { SetActionBar(i, spell_id, newstate == ACT_DECIDE ? spellInfo->IsAutocastable() ? ACT_DISABLED : ACT_PASSIVE : newstate); + + if (_unit->GetCharmer() && _unit->GetCharmer()->IsPlayer()) + { + if (Creature* creature = _unit->ToCreature()) + { + // Processing this packet needs to be delayed + _unit->m_Events.AddEventAtOffset([creature, spell_id]() + { + if (uint32 cooldown = creature->GetSpellCooldown(spell_id)) + { + WorldPacket data; + creature->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spell_id, cooldown); + creature->GetCharmer()->ToPlayer()->SendDirectMessage(&data); + } + }, 500ms); + } + } + return true; } } diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 3729e7bfa..9b8aba867 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2725,6 +2725,48 @@ void SpellMgr::LoadSpellInfoStore() LOG_INFO("server.loading", " "); } +void SpellMgr::LoadSpellCooldownOverrides() +{ + uint32 oldMSTime = getMSTime(); + + mSpellCooldownOverrideMap.clear(); + + QueryResult result = WorldDatabase.Query("SELECT Id, RecoveryTime, CategoryRecoveryTime, StartRecoveryTime, StartRecoveryCategory FROM spell_cooldown_overrides"); + + uint32 count = 0; + + if (result) + { + do + { + Field* fields = result->Fetch(); + SpellCooldownOverride spellCooldown; + uint32 spellId = fields[0].Get(); + spellCooldown.RecoveryTime = fields[1].Get(); + spellCooldown.CategoryRecoveryTime = fields[2].Get(); + spellCooldown.StartRecoveryTime = fields[3].Get(); + spellCooldown.StartRecoveryCategory = fields[4].Get(); + mSpellCooldownOverrideMap[spellId] = spellCooldown; + + ++count; + } while (result->NextRow()); + } + + LOG_INFO("server.loading", ">> Loaded {} Spell Cooldown Overrides entries in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); + LOG_INFO("server.loading", " "); +} + +bool SpellMgr::HasSpellCooldownOverride(uint32 spellId) const +{ + return mSpellCooldownOverrideMap.find(spellId) != mSpellCooldownOverrideMap.end(); +} + +SpellCooldownOverride SpellMgr::GetSpellCooldownOverride(uint32 spellId) const +{ + auto range = mSpellCooldownOverrideMap.find(spellId); + return range->second; +} + void SpellMgr::UnloadSpellInfoStore() { for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) @@ -3412,9 +3454,35 @@ void SpellMgr::LoadSpellInfoCustomAttributes() } } } - spellInfo->_InitializeExplicitTargetMask(); - sScriptMgr->OnLoadSpellCustomAttr(spellInfo); + spellInfo->_InitializeExplicitTargetMask(); + + if (sSpellMgr->HasSpellCooldownOverride(spellInfo->Id)) + { + SpellCooldownOverride spellOverride = sSpellMgr->GetSpellCooldownOverride(spellInfo->Id); + + if (spellInfo->RecoveryTime != spellOverride.RecoveryTime) + { + spellInfo->RecoveryTime = spellOverride.RecoveryTime; + } + + if (spellInfo->CategoryRecoveryTime != spellOverride.CategoryRecoveryTime) + { + spellInfo->CategoryRecoveryTime = spellOverride.CategoryRecoveryTime; + } + + if (spellInfo->StartRecoveryTime != spellOverride.StartRecoveryTime) + { + spellInfo->RecoveryTime = spellOverride.RecoveryTime; + } + + if (spellInfo->StartRecoveryCategory != spellOverride.StartRecoveryCategory) + { + spellInfo->RecoveryTime = spellOverride.RecoveryTime; + } + } + + sScriptMgr->OnLoadSpellCustomAttr(spellInfo); } // Xinef: addition for binary spells, ommit spells triggering other spells diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 4c18ceecf..2ee19ecc3 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -596,6 +596,16 @@ typedef std::vector SpellInfoMap; typedef std::map > SpellLinkedMap; +struct SpellCooldownOverride +{ + uint32 RecoveryTime; + uint32 CategoryRecoveryTime; + uint32 StartRecoveryTime; + uint32 StartRecoveryCategory; +}; + +typedef std::map SpellCooldownOverrideMap; + bool IsPrimaryProfessionSkill(uint32 skill); inline bool IsProfessionSkill(uint32 skill) @@ -736,6 +746,9 @@ public: // Talent Additional Set [[nodiscard]] bool IsAdditionalTalentSpell(uint32 spellId) const; + [[nodiscard]] bool HasSpellCooldownOverride(uint32 spellId) const; + [[nodiscard]] SpellCooldownOverride GetSpellCooldownOverride(uint32 spellId) const; + private: SpellInfo* _GetSpellInfo(uint32 spellId) { return spellId < GetSpellInfoStoreSize() ? mSpellInfoMap[spellId] : nullptr; } @@ -764,6 +777,7 @@ public: void LoadPetDefaultSpells(); void LoadSpellAreas(); void LoadSpellInfoStore(); + void LoadSpellCooldownOverrides(); void UnloadSpellInfoStore(); void UnloadSpellInfoImplicitTargetConditionLists(); void LoadSpellInfoCustomAttributes(); @@ -797,6 +811,7 @@ private: PetLevelupSpellMap mPetLevelupSpellMap; PetDefaultSpellsMap mPetDefaultSpellsMap; // only spells not listed in related mPetLevelupSpellMap entry SpellInfoMap mSpellInfoMap; + SpellCooldownOverrideMap mSpellCooldownOverrideMap; TalentAdditionalSet mTalentSpellAdditionalSet; }; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index cbc2fb82d..9a74e7494 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1582,6 +1582,9 @@ void World::SetInitialWorldSettings() LOG_INFO("server.loading", "Loading SpellInfo Store..."); sSpellMgr->LoadSpellInfoStore(); + LOG_INFO("server.loading", "Loading Spell Cooldown Overrides..."); + sSpellMgr->LoadSpellCooldownOverrides(); + LOG_INFO("server.loading", "Loading SpellInfo Data Corrections..."); sSpellMgr->LoadSpellInfoCorrections();