diff --git a/sql/updates/world/4.3.4/2023_11_29_01_world_quest_abandon_spells.sql b/sql/updates/world/4.3.4/2023_11_29_01_world_quest_abandon_spells.sql new file mode 100644 index 0000000000..2d7f643bbc --- /dev/null +++ b/sql/updates/world/4.3.4/2023_11_29_01_world_quest_abandon_spells.sql @@ -0,0 +1,10 @@ +-- +CREATE TABLE `quest_abandon_spells` ( + `QuestID` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `SpellID` INT(10) UNSIGNED NOT NULL DEFAULT '0', + `Description` TEXT NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci', + PRIMARY KEY (`QuestID`) USING BTREE +) +COLLATE='utf8mb4_unicode_ci' +ENGINE=InnoDB +; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 41bb98efaf..43d3eb43e3 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -14595,6 +14595,10 @@ void Player::AbandonQuest(uint32 questId) if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i])) if (quest->ItemDropQuantity[i] > 0 && itemTemplate->GetBonding() == BIND_QUEST) DestroyItemCount(quest->ItemDrop[i], 9999, true); + + // If Quest has a Abandon Spell cast it now + if (quest->GetQuestAbandonSpell() != 0) + CastSpell(this, quest->GetQuestAbandonSpell(), true) } } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index d92c32ce2c..ed90a03e4a 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -4096,7 +4096,10 @@ void ObjectMgr::LoadQuests() " RequiredSkillID, RequiredSkillPoints, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, ProvidedItemCount, SpecialFlags, AllowableRaces, TimeAllowed", "quest_template_addon", "template addons", &Quest::LoadQuestTemplateAddon }, // 0 1 - { "QuestId, RewardMailSenderEntry", "quest_mail_sender", "mail sender entries", &Quest::LoadQuestMailSender } + { "QuestId, RewardMailSenderEntry", "quest_mail_sender", "mail sender entries", &Quest::LoadQuestMailSender }, + + // 0 1 + { "QuestID, SpellID", "quest_abandon_spells", "abandon spells", &Quest::LoadQuestAbandonSpells } }; for (QuestLoaderHelper const& loader : QuestLoaderHelpers) @@ -4757,6 +4760,23 @@ void ObjectMgr::LoadQuests() } } + if (qinfo->_questAbandonSpell) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->_questAbandonSpell); + if (!spellInfo) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `QuestAbandonSpell` = %u but spell %u doesn't exist, quest abandon Spell can't be work.", + qinfo->GetQuestId(), qinfo->_questAbandonSpell, qinfo->_questAbandonSpell); + qinfo->_questAbandonSpell = 0; // quest can't be done for this requirement + } + else if (!SpellMgr::IsSpellValid(spellInfo)) + { + TC_LOG_ERROR("sql.sql", "Quest %u has `QuestAbandonSpell` = %u but spell %u is broken, quest abandon Spell can't be work", + qinfo->GetQuestId(), qinfo->_questAbandonSpell, qinfo->_questAbandonSpell); + qinfo->_questAbandonSpell = 0; // quest can't be done for this requirement + } + } + // fill additional data stores if (uint32 prevQuestId = std::abs(qinfo->_prevQuestId)) { diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index 65cd610339..2c2aecd71b 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -239,6 +239,11 @@ void Quest::LoadQuestMailSender(Field* fields) _rewardMailSenderEntry = fields[1].GetUInt32(); } +void Quest::LoadQuestAbandonSpells(Field* fields) +{ + _questAbandonSpell = fields[1].GetUInt32(); +} + uint32 Quest::GetXPReward(Player const* player) const { if (!player) diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index cb110c808a..b681d4f6af 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -235,6 +235,7 @@ class TC_GAME_API Quest void LoadQuestOfferReward(Field* fields); void LoadQuestTemplateAddon(Field* fields); void LoadQuestMailSender(Field* fields); + void LoadQuestAbandonSpells(Field* fields); uint32 GetXPReward(Player const* player) const; static uint32 CalcXPReward(uint8 playerLevel, int32 targetLevel, uint8 xpDifficulty); @@ -371,6 +372,7 @@ class TC_GAME_API Quest uint32 GetRewItemsCount() const { return _rewItemsCount; } uint32 GetRewCurrencyCount() const { return _rewCurrencyCount; } uint32 GetReqCurrencyCount() const { return _reqCurrencyCount; } + uint32 GetQuestAbandonSpell() const { return _questAbandonSpell; } void SetEventIdForQuest(uint16 eventId) { _eventIdForQuest = eventId; } uint16 GetEventIdForQuest() const { return _eventIdForQuest; } @@ -475,6 +477,7 @@ class TC_GAME_API Quest uint32 _specialFlags = 0; // custom flags, not sniffed/WDB uint32 _allowableRaces = 0; uint32 _timeAllowed = 0; + uint32 _questAbandonSpell = 0; }; struct QuestStatusData