diff options
author | ModoX <moardox@gmail.com> | 2024-01-08 21:51:46 +0100 |
---|---|---|
committer | funjoker <funjoker109@gmail.com> | 2024-01-09 20:45:32 +0100 |
commit | 4fe41bba8e7ffaa514856c51218df26784ecb0f6 (patch) | |
tree | 70a77d4071a9536b4d8e5b272ece36f66fc280a1 | |
parent | 82b605645b96722b92b8200ed90503cb87bf7aa7 (diff) |
Core/Creatures: Added possibility to automatically despawn personal summons on quest remove (#29114)
(cherry picked from commit b3dce0ac08d4f740505037aff2cad7685444db15)
-rw-r--r-- | sql/updates/world/wotlk_classic/2024_01_09_06_world_2024_01_08_02_world.sql | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/CreatureData.h | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 21 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 1 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 30 | ||||
-rw-r--r-- | src/server/game/Handlers/QuestHandler.cpp | 1 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 1 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 3 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_quest.cpp | 1 |
9 files changed, 56 insertions, 4 deletions
diff --git a/sql/updates/world/wotlk_classic/2024_01_09_06_world_2024_01_08_02_world.sql b/sql/updates/world/wotlk_classic/2024_01_09_06_world_2024_01_08_02_world.sql new file mode 100644 index 00000000000..250c1f30b23 --- /dev/null +++ b/sql/updates/world/wotlk_classic/2024_01_09_06_world_2024_01_08_02_world.sql @@ -0,0 +1 @@ +ALTER TABLE `creature_summoned_data` ADD COLUMN `DespawnOnQuestsRemoved` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL AFTER `FlyingMountDisplayID`; diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index 91ae066041d..f38760f39c2 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -660,6 +660,7 @@ struct CreatureSummonedData Optional<uint32> CreatureIDVisibleToSummoner; Optional<uint32> GroundMountDisplayID; Optional<uint32> FlyingMountDisplayID; + Optional<std::vector<uint32>> DespawnOnQuestsRemoved; }; enum InhabitTypeValues diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 1ea6fd84276..5641d4cfbea 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -15864,6 +15864,25 @@ void Player::SkipQuests(std::vector<uint32> const& questIds) UpdateObjectVisibility(); } +void Player::DespawnPersonalSummonsForQuest(uint32 questId) +{ + std::list<Creature*> creatureList; + GetCreatureListWithOptionsInGrid(creatureList, 100.0f, { .IgnorePhases = true, .PrivateObjectOwnerGuid = GetGUID() }); // we might want to replace this with SummonList in Player at some point + + for (Creature* creature : creatureList) + { + CreatureSummonedData const* summonedData = sObjectMgr->GetCreatureSummonedData(creature->GetEntry()); + if (!summonedData) + continue; + + if (summonedData->DespawnOnQuestsRemoved) + { + if (std::find(summonedData->DespawnOnQuestsRemoved->begin(), summonedData->DespawnOnQuestsRemoved->end(), questId) != summonedData->DespawnOnQuestsRemoved->end()) + creature->DespawnOrUnsummon(); + } + } +} + // not used in Trinity, but used in scripting code uint16 Player::GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry) const { @@ -24134,6 +24153,7 @@ void Player::DailyReset() SetQuestSlot(slot, 0); AbandonQuest(questId); RemoveActiveQuest(questId); + DespawnPersonalSummonsForQuest(questId); if (quest->GetLimitTime()) RemoveTimedQuest(questId); @@ -24170,6 +24190,7 @@ void Player::ResetWeeklyQuestStatus() SetQuestSlot(slot, 0); AbandonQuest(questId); RemoveActiveQuest(questId); + DespawnPersonalSummonsForQuest(questId); if (quest->GetLimitTime()) RemoveTimedQuest(questId); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index c55b0b3dc16..f09b8d5c2c0 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1551,6 +1551,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void SendQuestUpdate(uint32 questId); QuestGiverStatus GetQuestDialogStatus(Object const* questGiver) const; void SkipQuests(std::vector<uint32> const& questIds); // removes quest from log, flags rewarded, but does not give any rewards to player + void DespawnPersonalSummonsForQuest(uint32 questId); void SetDailyQuestStatus(uint32 quest_id); bool IsDailyQuestDone(uint32 quest_id) const; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 8c14a95a2d2..78540a5c6eb 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -393,8 +393,6 @@ void ObjectMgr::LoadCreatureTemplates() // We load the creature models after loading but before checking LoadCreatureTemplateModels(); - LoadCreatureSummonedData(); - // Checking needs to be done after loading because of the difficulty self referencing for (auto const& ctPair : _creatureTemplateStore) CheckCreatureTemplate(&ctPair.second); @@ -676,8 +674,8 @@ void ObjectMgr::LoadCreatureSummonedData() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 - QueryResult result = WorldDatabase.Query("SELECT CreatureID, CreatureIDVisibleToSummoner, GroundMountDisplayID, FlyingMountDisplayID FROM creature_summoned_data"); + // 0 1 2 3 4 + QueryResult result = WorldDatabase.Query("SELECT CreatureID, CreatureIDVisibleToSummoner, GroundMountDisplayID, FlyingMountDisplayID, DespawnOnQuestsRemoved FROM creature_summoned_data"); if (!result) { @@ -731,6 +729,30 @@ void ObjectMgr::LoadCreatureSummonedData() } } + if (!fields[4].IsNull()) + { + std::vector<uint32> questList; + for (std::string_view questStr : Trinity::Tokenize(fields[4].GetStringView(), ',', false)) + { + Optional<uint32> questId = Trinity::StringTo<uint32>(questStr); + if (!questId) + continue; + + Quest const* quest = GetQuestTemplate(*questId); + if (!quest) + { + TC_LOG_ERROR("sql.sql", "Table `creature_summoned_data` references non-existing quest {} in DespawnOnQuestsRemoved for creature {}, skipping", + *questId, creatureId); + continue; + } + + questList.push_back(*questId); + } + + if (!questList.empty()) + summonedData.DespawnOnQuestsRemoved = std::move(questList); + } + } while (result->NextRow()); TC_LOG_INFO("server.loading", ">> Loaded {} creature summoned data definitions in {} ms", _creatureSummonedDataStore.size(), GetMSTimeDiffToNow(oldMSTime)); diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index 5cd6cb11557..88fafda8609 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -471,6 +471,7 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPackets::Quest::QuestLogRemove _player->TakeQuestSourceItem(questId, true); // remove quest src item from player _player->AbandonQuest(questId); // remove all quest items player received before abandoning quest. Note, this does not remove normal drop items that happen to be quest requirements. _player->RemoveActiveQuest(questId); + _player->DespawnPersonalSummonsForQuest(questId); TC_LOG_INFO("network", "Player {} abandoned quest {}", _player->GetGUID().ToString(), questId); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 94f829086b5..450bcfd7757 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4038,6 +4038,7 @@ void Spell::EffectQuestClear() player->RemoveActiveQuest(quest_id, false); player->RemoveRewardedQuest(quest_id); + player->DespawnPersonalSummonsForQuest(quest_id); sScriptMgr->OnQuestStatusChange(player, quest_id); sScriptMgr->OnQuestStatusChange(player, quest, oldStatus, QUEST_STATUS_NONE); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index bece9fcfb1f..cd1ebc11478 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2087,6 +2087,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Game Event Data..."); // must be after loading pools fully sGameEventMgr->LoadFromDB(); + TC_LOG_INFO("server.loading", "Loading creature summoned data..."); + sObjectMgr->LoadCreatureSummonedData(); // must be after LoadCreatureTemplates() and LoadQuests() + TC_LOG_INFO("server.loading", "Loading UNIT_NPC_FLAG_SPELLCLICK Data..."); // must be after LoadQuests sObjectMgr->LoadNPCSpellClickSpells(); diff --git a/src/server/scripts/Commands/cs_quest.cpp b/src/server/scripts/Commands/cs_quest.cpp index 22ff3c39bd7..3dd04ef8eea 100644 --- a/src/server/scripts/Commands/cs_quest.cpp +++ b/src/server/scripts/Commands/cs_quest.cpp @@ -137,6 +137,7 @@ public: } player->RemoveActiveQuest(quest->GetQuestId(), false); player->RemoveRewardedQuest(quest->GetQuestId()); + player->DespawnPersonalSummonsForQuest(quest->GetQuestId()); sScriptMgr->OnQuestStatusChange(player, quest->GetQuestId()); sScriptMgr->OnQuestStatusChange(player, quest, oldStatus, QUEST_STATUS_NONE); |