diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Updates/UpdateFields.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Updates/UpdateFields.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Updates/ViewerDependentValues.h | 76 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 85 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 3 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 38 | ||||
-rw-r--r-- | src/server/game/Handlers/QuestHandler.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Maps/SpawnData.h | 2 |
10 files changed, 179 insertions, 55 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 8e982a78800..964c6862faf 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -629,7 +629,9 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/, ReplaceAllDynamicFlags(UNIT_DYNFLAG_NONE); - SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::StateWorldEffectsQuestObjectiveID), data ? data->spawnTrackingQuestObjectiveId : 0); + // Set StateWorldEffectsQuestObjectiveID if there is only one linked objective for this creature + if (data && data->spawnTrackingQuestObjectives.size() == 1) + SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::StateWorldEffectsQuestObjectiveID), data->spawnTrackingQuestObjectives.front()); SetCanDualWield(cInfo->flags_extra & CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK); @@ -3207,9 +3209,9 @@ SpawnTrackingStateData const* Creature::GetSpawnTrackingStateDataForPlayer(Playe if (CreatureData const* data = GetCreatureData()) { - if (data->spawnTrackingQuestObjectiveId && data->spawnTrackingData) + if (data->spawnTrackingData && !data->spawnTrackingQuestObjectives.empty()) { - SpawnTrackingState state = player->GetSpawnTrackingStateByObjective(data->spawnTrackingData->SpawnTrackingId, data->spawnTrackingQuestObjectiveId); + SpawnTrackingState state = player->GetSpawnTrackingStateByObjectives(data->spawnTrackingData->SpawnTrackingId, data->spawnTrackingQuestObjectives); return &data->spawnTrackingStates[AsUnderlyingType(state)]; } } diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 731bc5c7991..7e15231016a 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1967,7 +1967,9 @@ bool GameObject::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap PhasingHandler::InitDbPhaseShift(GetPhaseShift(), data->phaseUseFlags, data->phaseId, data->phaseGroup); PhasingHandler::InitDbVisibleMapId(GetPhaseShift(), data->terrainSwapMap); - SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::StateWorldEffectsQuestObjectiveID), data ? data->spawnTrackingQuestObjectiveId : 0); + // Set StateWorldEffectsQuestObjectiveID if there is only one linked objective for this gameobject + if (data && data->spawnTrackingQuestObjectives.size() == 1) + SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::StateWorldEffectsQuestObjectiveID), data->spawnTrackingQuestObjectives.front()); if (data->spawntimesecs >= 0) { @@ -3592,9 +3594,9 @@ SpawnTrackingStateData const* GameObject::GetSpawnTrackingStateDataForPlayer(Pla if (GameObjectData const* data = GetGameObjectData()) { - if (data->spawnTrackingQuestObjectiveId && data->spawnTrackingData) + if (data->spawnTrackingData && !data->spawnTrackingQuestObjectives.empty()) { - SpawnTrackingState state = player->GetSpawnTrackingStateByObjective(data->spawnTrackingData->SpawnTrackingId, data->spawnTrackingQuestObjectiveId); + SpawnTrackingState state = player->GetSpawnTrackingStateByObjectives(data->spawnTrackingData->SpawnTrackingId, data->spawnTrackingQuestObjectives); return &data->spawnTrackingStates[AsUnderlyingType(state)]; } } diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.cpp b/src/server/game/Entities/Object/Updates/UpdateFields.cpp index 7986d550120..419e2eca445 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.cpp +++ b/src/server/game/Entities/Object/Updates/UpdateFields.cpp @@ -939,7 +939,7 @@ void UnitData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fieldVisi data << uint32(ViewerDependentValue<StateAnimKitIDTag>::GetValue(this, owner, receiver)); stateWorldEffectIDs = ViewerDependentValue<StateWorldEffectIDsTag>::GetValue(this, owner, receiver); data << uint32(stateWorldEffectIDs->size()); - data << uint32(StateWorldEffectsQuestObjectiveID); + data << uint32(ViewerDependentValue<StateWorldEffectsQuestObjectiveIDTag>::GetValue(this, owner, receiver)); data << int32(SpellOverrideNameID); for (uint32 i = 0; i < stateWorldEffectIDs->size(); ++i) { @@ -1275,7 +1275,7 @@ void UnitData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool ignor } if (changesMask[12]) { - data << uint32(StateWorldEffectsQuestObjectiveID); + data << uint32(ViewerDependentValue<StateWorldEffectsQuestObjectiveIDTag>::GetValue(this, owner, receiver)); } if (changesMask[13]) { @@ -6496,7 +6496,7 @@ void GameObjectData::WriteCreate(ByteBuffer& data, EnumFlag<UpdateFieldFlag> fie data << uint32(ViewerDependentValue<SpawnTrackingStateAnimKitIDTag>::GetValue(this, owner, receiver)); stateWorldEffectIDs = ViewerDependentValue<StateWorldEffectIDsTag>::GetValue(this, owner, receiver); data << uint32(stateWorldEffectIDs->size()); - data << uint32(StateWorldEffectsQuestObjectiveID); + data << uint32(ViewerDependentValue<StateWorldEffectsQuestObjectiveIDTag>::GetValue(this, owner, receiver)); for (uint32 i = 0; i < stateWorldEffectIDs->size(); ++i) { data << uint32((*stateWorldEffectIDs)[i]); @@ -6617,7 +6617,7 @@ void GameObjectData::WriteUpdate(ByteBuffer& data, Mask const& changesMask, bool } if (changesMask[9]) { - data << uint32(StateWorldEffectsQuestObjectiveID); + data << uint32(ViewerDependentValue<StateWorldEffectsQuestObjectiveIDTag>::GetValue(this, owner, receiver)); } if (changesMask[10]) { diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.h b/src/server/game/Entities/Object/Updates/UpdateFields.h index 853fc374f76..f14700d4940 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.h +++ b/src/server/game/Entities/Object/Updates/UpdateFields.h @@ -279,6 +279,7 @@ struct UnitData : public IsUpdateFieldStructureTag, public HasChangesMask<222> UpdateField<uint32, 0, 11> StateAnimKitID; struct StateAnimKitIDTag : ViewerDependentValueTag<uint32> {}; UpdateField<uint32, 0, 12> StateWorldEffectsQuestObjectiveID; + struct StateWorldEffectsQuestObjectiveIDTag : ViewerDependentValueTag<uint32> {}; UpdateField<int32, 0, 13> SpellOverrideNameID; UpdateField<ObjectGuid, 0, 14> Charm; UpdateField<ObjectGuid, 0, 15> Summon; @@ -1213,6 +1214,7 @@ struct GameObjectData : public IsUpdateFieldStructureTag, public HasChangesMask< UpdateField<uint32, 0, 8> SpawnTrackingStateAnimKitID; struct SpawnTrackingStateAnimKitIDTag : ViewerDependentValueTag<uint32> {}; UpdateField<uint32, 0, 9> StateWorldEffectsQuestObjectiveID; + struct StateWorldEffectsQuestObjectiveIDTag : ViewerDependentValueTag<uint32> {}; UpdateField<ObjectGuid, 0, 10> CreatedBy; UpdateField<ObjectGuid, 0, 11> GuildGUID; UpdateField<uint32, 0, 12> Flags; diff --git a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h index 73400ed23d1..dacf78b0b3f 100644 --- a/src/server/game/Entities/Object/Updates/ViewerDependentValues.h +++ b/src/server/game/Entities/Object/Updates/ViewerDependentValues.h @@ -145,8 +145,8 @@ public: dynFlags |= GO_DYNFLAG_LO_NO_INTERACT; if (SpawnMetadata const* data = sObjectMgr->GetSpawnMetadata(SPAWN_TYPE_GAMEOBJECT, gameObject->GetSpawnId())) - if (data->spawnTrackingQuestObjectiveId && data->spawnTrackingData) - if (receiver->GetSpawnTrackingStateByObjective(data->spawnTrackingData->SpawnTrackingId, data->spawnTrackingQuestObjectiveId) != SpawnTrackingState::Active) + if (data->spawnTrackingData && !data->spawnTrackingQuestObjectives.empty()) + if (receiver->GetSpawnTrackingStateByObjectives(data->spawnTrackingData->SpawnTrackingId, data->spawnTrackingQuestObjectives) != SpawnTrackingState::Active) dynFlags &= ~GO_DYNFLAG_LO_ACTIVATE; } @@ -278,6 +278,42 @@ public: }; template<> +class ViewerDependentValue<UF::UnitData::StateWorldEffectsQuestObjectiveIDTag> +{ +public: + using value_type = UF::UnitData::StateWorldEffectsQuestObjectiveIDTag::value_type; + + static value_type GetValue(UF::UnitData const* unitData, Unit const* unit, Player const* receiver) + { + value_type stateWorldEffectsQuestObjectiveId = unitData->StateWorldEffectsQuestObjectiveID; + + if (!stateWorldEffectsQuestObjectiveId && unit->IsCreature()) + { + if (CreatureData const* data = unit->ToCreature()->GetCreatureData()) + { + auto itr = data->spawnTrackingQuestObjectives.begin(); + auto end = data->spawnTrackingQuestObjectives.end(); + if (itr != end) + { + // If there is no valid objective for player, fill UF with first objective (if any) + stateWorldEffectsQuestObjectiveId = *itr; + while (++itr != end) + { + if (receiver->GetSpawnTrackingStateByObjective(data->spawnTrackingData->SpawnTrackingId, *itr) != SpawnTrackingState::Active) + continue; + + stateWorldEffectsQuestObjectiveId = *itr; + break; + } + } + } + } + + return stateWorldEffectsQuestObjectiveId; + } +}; + +template<> class ViewerDependentValue<UF::UnitData::FactionTemplateTag> { public: @@ -539,6 +575,42 @@ public: }; template<> +class ViewerDependentValue<UF::GameObjectData::StateWorldEffectsQuestObjectiveIDTag> +{ +public: + using value_type = UF::GameObjectData::StateWorldEffectsQuestObjectiveIDTag::value_type; + + static value_type GetValue(UF::GameObjectData const* gameObjectData, GameObject const* gameObject, Player const* receiver) + { + value_type stateWorldEffectsQuestObjectiveId = gameObjectData->StateWorldEffectsQuestObjectiveID; + + if (!stateWorldEffectsQuestObjectiveId) + { + if (::GameObjectData const* data = gameObject->GetGameObjectData()) + { + auto itr = data->spawnTrackingQuestObjectives.begin(); + auto end = data->spawnTrackingQuestObjectives.end(); + if (itr != end) + { + // If there is no valid objective for player, fill UF with first objective (if any) + stateWorldEffectsQuestObjectiveId = *itr; + while (++itr != end) + { + if (receiver->GetSpawnTrackingStateByObjective(data->spawnTrackingData->SpawnTrackingId, *itr) != SpawnTrackingState::Active) + continue; + + stateWorldEffectsQuestObjectiveId = *itr; + break; + } + } + } + } + + return stateWorldEffectsQuestObjectiveId; + } +}; + +template<> class ViewerDependentValue<UF::GameObjectData::FlagsTag> { public: diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f05a69123f1..351a4758222 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -16852,38 +16852,40 @@ void Player::UpdateQuestObjectiveProgress(QuestObjectiveType objectiveType, int3 } } - if (data && data->spawnTrackingQuestObjectiveId && data->spawnTrackingData) + if (data && data->spawnTrackingData && !data->spawnTrackingQuestObjectives.empty()) { - if (objective->ID == data->spawnTrackingQuestObjectiveId) + for (uint32 spawnTrackingQuestObjectiveId : data->spawnTrackingQuestObjectives) { - // Store spawn tracking to return correct state in Player::GetSpawnTrackingStateByObjective - QuestStatusData& questStatus = objectiveItr.second.QuestStatusItr->second; - questStatus.SpawnTrackingList.insert(std::make_pair(objective->StorageIndex, data->spawnTrackingData->SpawnTrackingId)); - - // Send QuestPOIUpdateResponse for every spawn linked to same SpawnTrackingId - for (auto const& [spawnTrackingId, data] : sObjectMgr->GetSpawnMetadataForSpawnTracking(data->spawnTrackingData->SpawnTrackingId)) + if (objective->ID == spawnTrackingQuestObjectiveId) { - SpawnData const* spawnData = data->ToSpawnData(); - if (!spawnData) - continue; + // Store spawn tracking to return correct state in Player::GetSpawnTrackingStateByObjective + QuestStatusData& questStatus = objectiveItr.second.QuestStatusItr->second; + questStatus.SpawnTrackingList.insert(std::make_pair(objective->StorageIndex, data->spawnTrackingData->SpawnTrackingId)); - WorldPackets::Quest::QuestPOIUpdateResponse response; + // Send QuestPOIUpdateResponse for every spawn linked to same SpawnTrackingId + for (auto const& [spawnTrackingId, data] : sObjectMgr->GetSpawnMetadataForSpawnTracking(data->spawnTrackingData->SpawnTrackingId)) + { + SpawnData const* spawnData = data->ToSpawnData(); + if (!spawnData) + continue; - WorldPackets::Quest::SpawnTrackingResponseInfo responseInfo; - responseInfo.SpawnTrackingID = data->spawnTrackingData->SpawnTrackingId; - responseInfo.ObjectID = spawnData->id; - responseInfo.PhaseID = spawnData->phaseId; - responseInfo.PhaseGroupID = spawnData->phaseGroup; - responseInfo.PhaseUseFlags = spawnData->phaseUseFlags; + WorldPackets::Quest::QuestPOIUpdateResponse response; - SpawnTrackingState state = GetSpawnTrackingStateByObjective(data->spawnTrackingData->SpawnTrackingId, objective->ID); - responseInfo.Visible = data->spawnTrackingStates[AsUnderlyingType(state)].Visible; + WorldPackets::Quest::SpawnTrackingResponseInfo& responseInfo = response.SpawnTrackingResponses.emplace_back(); + responseInfo.SpawnTrackingID = data->spawnTrackingData->SpawnTrackingId; + responseInfo.ObjectID = spawnData->id; + responseInfo.PhaseID = spawnData->phaseId; + responseInfo.PhaseGroupID = spawnData->phaseGroup; + responseInfo.PhaseUseFlags = spawnData->phaseUseFlags; - response.SpawnTrackingResponses.push_back(std::move(responseInfo)); - SendDirectMessage(response.Write()); - } + SpawnTrackingState state = GetSpawnTrackingStateByObjectives(data->spawnTrackingData->SpawnTrackingId, data->spawnTrackingQuestObjectives); + responseInfo.Visible = data->spawnTrackingStates[AsUnderlyingType(state)].Visible; - anyObjectiveChangedSpawnTrackingState = true; + SendDirectMessage(response.Write()); + } + + anyObjectiveChangedSpawnTrackingState = true; + } } } @@ -17508,16 +17510,38 @@ void Player::SendForceSpawnTrackingUpdate(uint32 questId) const } } -QuestObjective const* Player::GetActiveQuestObjectiveForForSpawnTracking(uint32 spawnTrackingId) const +QuestObjective const* Player::GetActiveQuestObjectiveForSpawnTracking(uint32 spawnTrackingId) const { if (std::vector<QuestObjective const*> const* questObjectiveList = sObjectMgr->GetSpawnTrackingQuestObjectiveList(spawnTrackingId)) for (QuestObjective const* questObjective : *questObjectiveList) - if (FindQuestSlot(questObjective->QuestID) < MAX_QUEST_LOG_SIZE) + if (IsQuestObjectiveCompletable(questObjective->QuestID, questObjective->ID)) return questObjective; return nullptr; } +SpawnTrackingState Player::GetSpawnTrackingStateByObjectives(uint32 spawnTrackingId, std::vector<uint32> const& questObjectives) const +{ + if (spawnTrackingId && !questObjectives.empty()) + { + bool hasAnyQuestObjectiveCompletable = false; + for (uint32 questObjectiveId : questObjectives) + { + SpawnTrackingState state = GetSpawnTrackingStateByObjective(spawnTrackingId, questObjectiveId); + if (state == SpawnTrackingState::Complete) + return SpawnTrackingState::Complete; + + if (state == SpawnTrackingState::Active) + hasAnyQuestObjectiveCompletable = true; + } + + if (hasAnyQuestObjectiveCompletable) + return SpawnTrackingState::Active; + } + + return SpawnTrackingState::None; +} + SpawnTrackingState Player::GetSpawnTrackingStateByObjective(uint32 spawnTrackingId, uint32 questObjectiveId) const { if (spawnTrackingId && questObjectiveId && sObjectMgr->IsQuestObjectiveForSpawnTracking(spawnTrackingId, questObjectiveId)) @@ -17526,7 +17550,8 @@ SpawnTrackingState Player::GetSpawnTrackingStateByObjective(uint32 spawnTracking { if (IsQuestRewarded(questObjective->QuestID) || IsQuestObjectiveComplete(questObjective->QuestID, questObjective->ID)) return SpawnTrackingState::Complete; - else if (GetQuestStatus(questObjective->QuestID) != QUEST_STATUS_NONE && IsQuestObjectiveCompletable(questObjective->QuestID, questObjective->ID)) + + if (GetQuestStatus(questObjective->QuestID) != QUEST_STATUS_NONE && IsQuestObjectiveCompletable(questObjective->QuestID, questObjective->ID)) { auto itr = m_QuestStatus.find(questObjective->QuestID); if (itr != m_QuestStatus.end() && itr->second.Slot < MAX_QUEST_LOG_SIZE) @@ -25742,13 +25767,14 @@ void Player::UpdateVisibleObjectInteractions(bool allUnits, bool onlySpellClicks UF::GameObjectData::Base goMask; SpawnMetadata const* data = sObjectMgr->GetSpawnMetadata(SPAWN_TYPE_GAMEOBJECT, gameObject->GetSpawnId()); - if (data && data->spawnTrackingQuestObjectiveId && data->spawnTrackingData) + if (data && data->spawnTrackingData && !data->spawnTrackingQuestObjectives.empty()) { objMask.MarkChanged(&UF::ObjectData::DynamicFlags); goMask.MarkChanged(&UF::GameObjectData::StateWorldEffectIDs); goMask.MarkChanged(&UF::GameObjectData::StateSpellVisualID); goMask.MarkChanged(&UF::GameObjectData::SpawnTrackingStateAnimID); goMask.MarkChanged(&UF::GameObjectData::SpawnTrackingStateAnimKitID); + goMask.MarkChanged(&UF::GameObjectData::StateWorldEffectsQuestObjectiveID); } else if (m_questObjectiveStatus.contains({ QUEST_OBJECTIVE_GAMEOBJECT, int32(gameObject->GetEntry()) }) || gameObject->GetGOInfo()->GetConditionID1()) objMask.MarkChanged(&UF::ObjectData::DynamicFlags); @@ -25789,13 +25815,14 @@ void Player::UpdateVisibleObjectInteractions(bool allUnits, bool onlySpellClicks unitMask.MarkChanged(&UF::UnitData::NpcFlags2); SpawnMetadata const* data = sObjectMgr->GetSpawnMetadata(SPAWN_TYPE_CREATURE, creature->GetSpawnId()); - if (data && data->spawnTrackingQuestObjectiveId && data->spawnTrackingData) + if (data && data->spawnTrackingData && !data->spawnTrackingQuestObjectives.empty()) { objMask.MarkChanged(&UF::ObjectData::DynamicFlags); unitMask.MarkChanged(&UF::UnitData::StateWorldEffectIDs); unitMask.MarkChanged(&UF::UnitData::StateSpellVisualID); unitMask.MarkChanged(&UF::UnitData::StateAnimID); unitMask.MarkChanged(&UF::UnitData::StateAnimKitID); + unitMask.MarkChanged(&UF::UnitData::StateWorldEffectsQuestObjectiveID); } if (objMask.GetChangesMask().IsAnySet() || unitMask.GetChangesMask().IsAnySet()) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 2d21399464d..cd457d24ca0 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1797,7 +1797,8 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> bool HasPvPForcingQuest() const; void SendForceSpawnTrackingUpdate(uint32 questId) const; - QuestObjective const* GetActiveQuestObjectiveForForSpawnTracking(uint32 spawnTrackingId) const; + QuestObjective const* GetActiveQuestObjectiveForSpawnTracking(uint32 spawnTrackingId) const; + SpawnTrackingState GetSpawnTrackingStateByObjectives(uint32 spawnTrackingId, std::vector<uint32> const& questObjectives) const; SpawnTrackingState GetSpawnTrackingStateByObjective(uint32 spawnTrackingId, uint32 questObjectiveId) const; /*********************************************************/ diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index d47d494a313..ba7f7d79edc 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -11811,7 +11811,7 @@ void ObjectMgr::LoadSpawnTrackings() _spawnTrackingMapStore.clear(); // 0 1 2 3 - QueryResult result = WorldDatabase.Query("SELECT SpawnTrackingId, SpawnType, SpawnId, QuestObjectiveId FROM spawn_tracking"); + QueryResult result = WorldDatabase.Query("SELECT SpawnTrackingId, SpawnType, SpawnId, QuestObjectiveIds FROM spawn_tracking"); if (!result) { @@ -11827,7 +11827,6 @@ void ObjectMgr::LoadSpawnTrackings() uint32 spawnTrackingId = fields[0].GetUInt32(); SpawnObjectType spawnType = SpawnObjectType(fields[1].GetUInt8()); ObjectGuid::LowType spawnId = fields[2].GetUInt64(); - uint32 objectiveId = fields[3].GetUInt32(); if (!SpawnData::TypeIsValid(spawnType)) { @@ -11860,12 +11859,6 @@ void ObjectMgr::LoadSpawnTrackings() continue; } - if (!IsQuestObjectiveForSpawnTracking(spawnTrackingId, objectiveId)) - { - TC_LOG_ERROR("sql.sql", "Table `spawn_tracking` has spawn tracking {} assigned to spawn ({},{}), but spawn tracking is not linked to quest objective {}. Skipped.", spawnTrackingId, uint32(spawnType), spawnId, objectiveId); - continue; - } - if (spawnTrackingTemplateData->MapId != data->mapId) { TC_LOG_ERROR("sql.sql", "Table `spawn_tracking` has spawn tracking {} (map {}) assigned to spawn ({},{}), but spawn has map {} - spawn NOT added to spawn tracking!", @@ -11883,8 +11876,33 @@ void ObjectMgr::LoadSpawnTrackings() continue; } + std::vector<uint32> objectiveList; + if (Optional<std::string_view> objectivesStr = fields[3].GetStringViewOrNull()) + { + for (std::string_view objectiveStr : Trinity::Tokenize(*objectivesStr, ',', false)) + { + Optional<uint32> objectiveId = Trinity::StringTo<uint32>(objectiveStr); + if (!objectiveId) + continue; + + if (!IsQuestObjectiveForSpawnTracking(spawnTrackingId, *objectiveId)) + { + TC_LOG_ERROR("sql.sql", "Table `spawn_tracking` has spawn tracking {} assigned to spawn ({},{}), but spawn tracking is not linked to quest objective {}. Skipped.", spawnTrackingId, uint32(spawnType), spawnId, objectiveId); + continue; + } + + objectiveList.push_back(*objectiveId); + } + + if (objectiveList.empty()) + { + TC_LOG_ERROR("sql.sql", "Table `spawn_tracking` has spawn tracking {} assigned to spawn ({},{}), but spawn tracking is not linked to any quest objective - spawn NOT added to spawn tracking!", spawnTrackingId, uint32(spawnType), spawnId); + continue; + } + } + const_cast<SpawnMetadata*>(data)->spawnTrackingData = spawnTrackingTemplateData; - const_cast<SpawnMetadata*>(data)->spawnTrackingQuestObjectiveId = objectiveId; + const_cast<SpawnMetadata*>(data)->spawnTrackingQuestObjectives = std::move(objectiveList); _spawnTrackingMapStore.emplace(spawnTrackingId, data); ++count; @@ -11981,7 +11999,7 @@ void ObjectMgr::LoadSpawnTrackingStates() if (!sWorldEffectStore.HasRecord(*worldEffectId)) { - TC_LOG_ERROR("sql.sql", "Table `spawn_tracking_state` references invalid StateAnimKitId {} for spawn ({},{}). Skipped.", + TC_LOG_ERROR("sql.sql", "Table `spawn_tracking_state` references invalid WorldEffectId {} for spawn ({},{}). Skipped.", *worldEffectId, uint32(spawnType), spawnId); continue; } diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index d69cd4829a9..c8d41b9dc78 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -892,7 +892,7 @@ void WorldSession::HandleSpawnTrackingUpdate(WorldPackets::Quest::SpawnTrackingU responseInfo.ObjectID = requestInfo.ObjectID; SpawnTrackingTemplateData const* spawnTrackingTemplateData = sObjectMgr->GetSpawnTrackingData(requestInfo.SpawnTrackingID); - QuestObjective const* activeQuestObjective = _player->GetActiveQuestObjectiveForForSpawnTracking(requestInfo.SpawnTrackingID); + QuestObjective const* activeQuestObjective = _player->GetActiveQuestObjectiveForSpawnTracking(requestInfo.SpawnTrackingID); // Send phase info if map is the same or spawn tracking related quests are taken or completed if (spawnTrackingTemplateData && (_player->GetMapId() == spawnTrackingTemplateData->MapId || activeQuestObjective)) @@ -920,7 +920,7 @@ void WorldSession::HandleSpawnTrackingUpdate(WorldPackets::Quest::SpawnTrackingU if (activeQuestObjective) { - SpawnTrackingState state = _player->GetSpawnTrackingStateByObjective(spawnTrackingId, activeQuestObjective->ID); + SpawnTrackingState state = _player->GetSpawnTrackingStateByObjectives(spawnTrackingId, data->spawnTrackingQuestObjectives); responseInfo.Visible = data->spawnTrackingStates[AsUnderlyingType(state)].Visible; break; } diff --git a/src/server/game/Maps/SpawnData.h b/src/server/game/Maps/SpawnData.h index d9bae3bddfe..5964bc6fdd5 100644 --- a/src/server/game/Maps/SpawnData.h +++ b/src/server/game/Maps/SpawnData.h @@ -123,7 +123,7 @@ struct SpawnMetadata bool dbData = true; SpawnGroupTemplateData const* spawnGroupData = nullptr; SpawnTrackingTemplateData const* spawnTrackingData = nullptr; - uint32 spawnTrackingQuestObjectiveId = 0; + std::vector<uint32> spawnTrackingQuestObjectives; std::array<SpawnTrackingStateData, size_t(SpawnTrackingState::Max)> spawnTrackingStates; protected: |