Core/Creatures: Added possibility to automatically despawn personal summons on quest remove (#29114)

(cherry picked from commit b3dce0ac08)
This commit is contained in:
ModoX
2024-01-08 21:51:46 +01:00
committed by funjoker
parent 82b605645b
commit 4fe41bba8e
9 changed files with 56 additions and 4 deletions

View File

@@ -0,0 +1 @@
ALTER TABLE `creature_summoned_data` ADD COLUMN `DespawnOnQuestsRemoved` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL AFTER `FlyingMountDisplayID`;

View File

@@ -660,6 +660,7 @@ struct CreatureSummonedData
Optional<uint32> CreatureIDVisibleToSummoner;
Optional<uint32> GroundMountDisplayID;
Optional<uint32> FlyingMountDisplayID;
Optional<std::vector<uint32>> DespawnOnQuestsRemoved;
};
enum InhabitTypeValues

View File

@@ -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);

View File

@@ -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;

View File

@@ -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));

View File

@@ -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);

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);