Core/Misc: converted quest, creature and quest query packets to packet class and ported query data caching from 335 branch
This commit is contained in:
1 parent
8c4491f3a0
commit
64c4b4f529
22 files changed
+924
-387
No files matched your search
@@ -42,6 +42,7 @@
|
||||
#include "PhasingHandler.h"
|
||||
#include "Player.h"
|
||||
#include "PoolMgr.h"
|
||||
#include "QueryPackets.h"
|
||||
#include "QuestDef.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
@@ -164,6 +165,69 @@ uint32 CreatureTemplate::GetFirstVisibleModel() const
|
||||
return 17519;
|
||||
}
|
||||
|
||||
void CreatureTemplate::InitializeQueryData()
|
||||
{
|
||||
WorldPacket queryTemp;
|
||||
for (uint8 loc = LOCALE_enUS; loc < TOTAL_LOCALES; ++loc)
|
||||
{
|
||||
queryTemp = BuildQueryData(static_cast<LocaleConstant>(loc));
|
||||
QueryData[loc] = queryTemp;
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket CreatureTemplate::BuildQueryData(LocaleConstant loc) const
|
||||
{
|
||||
WorldPackets::Query::QueryCreatureResponse queryTemp;
|
||||
|
||||
std::string locName = Name;
|
||||
std::string locNameAlt = FemaleName;
|
||||
std::string locTitle = Title;
|
||||
if (CreatureLocale const* cl = sObjectMgr->GetCreatureLocale(Entry))
|
||||
{
|
||||
ObjectMgr::GetLocaleString(cl->Name, loc, locName);
|
||||
ObjectMgr::GetLocaleString(cl->FemaleName, loc, locNameAlt);
|
||||
ObjectMgr::GetLocaleString(cl->Title, loc, locTitle);
|
||||
}
|
||||
|
||||
queryTemp.CreatureID = Entry;
|
||||
queryTemp.Allow = true;
|
||||
|
||||
queryTemp.Stats.Name[0] = locName;
|
||||
queryTemp.Stats.NameAlt[0] = locNameAlt;
|
||||
queryTemp.Stats.Title = locTitle;
|
||||
queryTemp.Stats.CursorName = IconName;
|
||||
queryTemp.Stats.Flags[0] = type_flags;
|
||||
queryTemp.Stats.Flags[1] = type_flags2;
|
||||
queryTemp.Stats.CreatureType = type;
|
||||
queryTemp.Stats.CreatureFamily = family;
|
||||
queryTemp.Stats.Classification = rank;
|
||||
|
||||
for (uint8 i = 0; i < MAX_KILL_CREDIT; ++i)
|
||||
queryTemp.Stats.ProxyCreatureID[i] = KillCredit[i];
|
||||
|
||||
queryTemp.Stats.CreatureDisplayID[0] = Modelid1;
|
||||
queryTemp.Stats.CreatureDisplayID[1] = Modelid2;
|
||||
queryTemp.Stats.CreatureDisplayID[2] = Modelid3;
|
||||
queryTemp.Stats.CreatureDisplayID[3] = Modelid4;
|
||||
queryTemp.Stats.HpMulti = ModHealth;
|
||||
queryTemp.Stats.EnergyMulti = ModMana;
|
||||
queryTemp.Stats.Leader = RacialLeader;
|
||||
|
||||
for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
|
||||
queryTemp.Stats.QuestItems[i] = 0;
|
||||
|
||||
if (std::vector<uint32> const* items = sObjectMgr->GetCreatureQuestItemList(Entry))
|
||||
for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
|
||||
if (i < items->size())
|
||||
queryTemp.Stats.QuestItems[i] = (*items)[i];
|
||||
|
||||
queryTemp.Stats.CreatureMovementInfoID = movementId;
|
||||
queryTemp.Stats.RequiredExpansion = expansionUnknown;
|
||||
queryTemp.Write();
|
||||
queryTemp.ShrinkToFit();
|
||||
return queryTemp.Move();
|
||||
}
|
||||
|
||||
bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
|
||||
{
|
||||
if (Unit* victim = ObjectAccessor::GetUnit(m_owner, m_victim))
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "Duration.h"
|
||||
#include "Loot.h"
|
||||
#include "MapObject.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
class CreatureAI;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
class WorldPacket;
|
||||
struct ItemTemplate;
|
||||
enum class VisibilityDistanceType : uint8;
|
||||
|
||||
@@ -195,6 +196,7 @@ struct TC_GAME_API CreatureTemplate
|
||||
uint32 SpellSchoolImmuneMask;
|
||||
uint32 flags_extra;
|
||||
uint32 ScriptID;
|
||||
WorldPacket QueryData[TOTAL_LOCALES];
|
||||
uint32 GetRandomValidModelId() const;
|
||||
uint32 GetFirstValidModelId() const;
|
||||
uint32 GetFirstInvisibleModel() const;
|
||||
@@ -226,6 +228,9 @@ struct TC_GAME_API CreatureTemplate
|
||||
// if can tame exotic then can tame any tameable
|
||||
return canTameExotic || !IsExotic();
|
||||
}
|
||||
|
||||
void InitializeQueryData();
|
||||
WorldPacket BuildQueryData(LocaleConstant loc) const;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
@@ -246,7 +246,7 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, ObjectGuid objectGUID)
|
||||
ObjectMgr::GetLocaleString(localeData->Title, localeConstant, title);
|
||||
|
||||
if (questLevelInTitle)
|
||||
AddQuestLevelToTitle(title, quest->GetQuestLevel());
|
||||
Quest::AddQuestLevelToTitle(title, quest->GetQuestLevel());
|
||||
|
||||
data << title; // max 0x200
|
||||
}
|
||||
@@ -377,7 +377,7 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string
|
||||
ObjectMgr::GetLocaleString(questTemplateLocaleData->Title, localeConstant, title);
|
||||
|
||||
if (questLevelInTitle)
|
||||
AddQuestLevelToTitle(title, quest->GetQuestLevel());
|
||||
Quest::AddQuestLevelToTitle(title, quest->GetQuestLevel());
|
||||
|
||||
bool repeatable = quest->IsAutoComplete() && quest->IsRepeatable() && !quest->IsDailyOrWeekly() && !quest->IsMonthly();
|
||||
questList.QuestDataText.emplace_back(questID, questMenuItem.QuestIcon, quest->GetQuestLevel(), quest->GetFlags(), repeatable, title);
|
||||
@@ -428,7 +428,7 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU
|
||||
}
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
|
||||
AddQuestLevelToTitle(packet.QuestTitle, quest->GetQuestLevel());
|
||||
Quest::AddQuestLevelToTitle(packet.QuestTitle, quest->GetQuestLevel());
|
||||
|
||||
packet.QuestGiverGUID = npcGUID;
|
||||
packet.InformUnit = _session->GetPlayer()->GetPlayerSharingQuest();
|
||||
@@ -457,172 +457,14 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU
|
||||
|
||||
void PlayerMenu::SendQuestQueryResponse(Quest const* quest) const
|
||||
{
|
||||
std::string questTitle = quest->GetTitle();
|
||||
std::string questDetails = quest->GetDetails();
|
||||
std::string questObjectives = quest->GetObjectives();
|
||||
std::string questAreaDescription = quest->GetAreaDescription();
|
||||
std::string questCompletedText = quest->GetCompletedText();
|
||||
std::string questGiverTextWindow = quest->GetQuestGiverTextWindow();
|
||||
std::string questGiverTargetName = quest->GetQuestGiverTargetName();
|
||||
std::string questTurnTextWindow = quest->GetQuestTurnTextWindow();
|
||||
std::string questTurnTargetName = quest->GetQuestTurnTargetName();
|
||||
|
||||
std::string questObjectiveText[QUEST_OBJECTIVES_COUNT];
|
||||
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
|
||||
questObjectiveText[i] = quest->ObjectiveText[i];
|
||||
|
||||
LocaleConstant localeConstant = _session->GetSessionDbLocaleIndex();
|
||||
if (localeConstant != LOCALE_enUS)
|
||||
{
|
||||
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId()))
|
||||
{
|
||||
ObjectMgr::GetLocaleString(localeData->Title, localeConstant, questTitle);
|
||||
ObjectMgr::GetLocaleString(localeData->Details, localeConstant, questDetails);
|
||||
ObjectMgr::GetLocaleString(localeData->Objectives, localeConstant, questObjectives);
|
||||
ObjectMgr::GetLocaleString(localeData->AreaDescription, localeConstant, questAreaDescription);
|
||||
ObjectMgr::GetLocaleString(localeData->CompletedText, localeConstant, questCompletedText);
|
||||
ObjectMgr::GetLocaleString(localeData->QuestGiverTextWindow, localeConstant, questGiverTextWindow);
|
||||
ObjectMgr::GetLocaleString(localeData->QuestGiverTargetName, localeConstant, questGiverTargetName);
|
||||
ObjectMgr::GetLocaleString(localeData->QuestTurnTextWindow, localeConstant, questTurnTextWindow);
|
||||
ObjectMgr::GetLocaleString(localeData->QuestTurnTargetName, localeConstant, questTurnTargetName);
|
||||
|
||||
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
|
||||
ObjectMgr::GetLocaleString(localeData->ObjectiveText[i], localeConstant, questObjectiveText[i]);
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket data(SMSG_QUEST_QUERY_RESPONSE, 100); // guess size
|
||||
|
||||
data << uint32(quest->GetQuestId()); // quest id
|
||||
data << uint32(quest->GetQuestMethod()); // Accepted values: 0, 1 or 2. 0 == IsAutoComplete() (skip objectives/details)
|
||||
data << uint32(quest->GetQuestLevel()); // may be -1, static data, in other cases must be used dynamic level: Player::GetQuestLevel (0 is not known, but assuming this is no longer valid for quest intended for client)
|
||||
data << uint32(quest->GetMinLevel()); // min level
|
||||
data << uint32(quest->GetZoneOrSort()); // zone or sort to display in quest log
|
||||
|
||||
data << uint32(quest->GetType()); // quest type
|
||||
data << uint32(quest->GetSuggestedPlayers()); // suggested players count
|
||||
|
||||
data << uint32(quest->GetRepObjectiveFaction()); // shown in quest log as part of quest objective
|
||||
data << uint32(quest->GetRepObjectiveValue()); // shown in quest log as part of quest objective
|
||||
|
||||
data << uint32(quest->GetRepObjectiveFaction2()); // shown in quest log as part of quest objective OPPOSITE faction
|
||||
data << uint32(quest->GetRepObjectiveValue2()); // shown in quest log as part of quest objective OPPOSITE faction
|
||||
|
||||
data << uint32(quest->GetNextQuestInChain()); // client will request this quest from NPC, if not 0
|
||||
data << uint32(quest->GetXPId()); // used for calculating rewarded experience
|
||||
|
||||
if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
|
||||
data << uint32(0); // Hide money rewarded
|
||||
else
|
||||
data << uint32(quest->GetRewOrReqMoney(_session->GetPlayer())); // reward money (below max lvl)
|
||||
|
||||
data << uint32(quest->GetRewMoneyMaxLevel()); // used in XP calculation at client
|
||||
data << uint32(quest->GetRewSpell()); // reward spell, this spell will display (icon) (cast if RewSpellCast == 0)
|
||||
data << int32(quest->GetRewSpellCast()); // cast spell
|
||||
|
||||
// rewarded honor points
|
||||
data << uint32(quest->GetRewHonorAddition());
|
||||
data << float(quest->GetRewHonorMultiplier());
|
||||
data << uint32(quest->GetSrcItemId()); // source item id
|
||||
data << uint32(quest->GetFlags()); // quest flags
|
||||
data << uint32(quest->GetMinimapTargetMark()); // minimap target mark (skull, etc. missing enum)
|
||||
data << uint32(quest->GetCharTitleId()); // CharTitleId, new 2.4.0, player gets this title (id from CharTitles)
|
||||
data << uint32(quest->GetPlayersSlain()); // players slain
|
||||
data << uint32(quest->GetBonusTalents()); // bonus talents
|
||||
data << uint32(quest->GetRewArenaPoints()); // bonus arena points FIXME: arena points were removed, right?
|
||||
data << uint32(quest->GetRewardSkillId()); // reward skill id
|
||||
data << uint32(quest->GetRewardSkillPoints()); // reward skill points
|
||||
data << uint32(quest->GetRewardReputationMask()); // rep mask (unsure on what it does)
|
||||
data << uint32(quest->GetQuestGiverPortrait()); // quest giver entry ?
|
||||
data << uint32(quest->GetQuestTurnInPortrait()); // quest turnin entry ?
|
||||
|
||||
if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
|
||||
{
|
||||
for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
|
||||
data << uint32(0) << uint32(0);
|
||||
for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
|
||||
data << uint32(0) << uint32(0);
|
||||
}
|
||||
if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
|
||||
_session->SendPacket(&quest->QueryData[static_cast<uint32>(_session->GetSessionDbLocaleIndex())]);
|
||||
else
|
||||
{
|
||||
for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
|
||||
{
|
||||
data << uint32(quest->RewardItemId[i]);
|
||||
data << uint32(quest->RewardItemIdCount[i]);
|
||||
}
|
||||
for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
|
||||
{
|
||||
data << uint32(quest->RewardChoiceItemId[i]);
|
||||
data << uint32(quest->RewardChoiceItemCount[i]);
|
||||
}
|
||||
WorldPacket queryPacket = quest->BuildQueryData(_session->GetSessionDbLocaleIndex());
|
||||
_session->SendPacket(&queryPacket);
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward factions ids
|
||||
data << uint32(quest->RewardFactionId[i]);
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid+1 QuestFactionReward.dbc?
|
||||
data << int32(quest->RewardFactionValueId[i]);
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // unknown usage
|
||||
data << int32(quest->RewardFactionValueIdOverride[i]);
|
||||
|
||||
data << uint32(quest->GetPOIContinent());
|
||||
data << float(quest->GetPOIx());
|
||||
data << float(quest->GetPOIy());
|
||||
data << uint32(quest->GetPointOpt());
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
|
||||
AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
|
||||
|
||||
data << questTitle;
|
||||
data << questObjectives;
|
||||
data << questDetails;
|
||||
data << questAreaDescription;
|
||||
data << questCompletedText; // display in quest objectives window once all objectives are completed
|
||||
|
||||
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
|
||||
{
|
||||
if (quest->RequiredNpcOrGo[i] < 0)
|
||||
data << uint32((quest->RequiredNpcOrGo[i] * (-1)) | 0x80000000); // client expects gameobject template id in form (id|0x80000000)
|
||||
else
|
||||
data << uint32(quest->RequiredNpcOrGo[i]);
|
||||
|
||||
data << uint32(quest->RequiredNpcOrGoCount[i]);
|
||||
data << uint32(quest->ItemDrop[i]);
|
||||
data << uint32(quest->ItemDropQuantity[i]);
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
|
||||
{
|
||||
data << uint32(quest->RequiredItemId[i]);
|
||||
data << uint32(quest->RequiredItemCount[i]);
|
||||
}
|
||||
|
||||
data << uint32(quest->GetRequiredSpell()); // Is it required to be cast, learned or what?
|
||||
|
||||
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
|
||||
data << questObjectiveText[i];
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
|
||||
{
|
||||
data << uint32(quest->RewardCurrencyId[i]);
|
||||
data << uint32(quest->RewardCurrencyCount[i]);
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i)
|
||||
{
|
||||
data << uint32(quest->RequiredCurrencyId[i]);
|
||||
data << uint32(quest->RequiredCurrencyCount[i]);
|
||||
}
|
||||
|
||||
data << questGiverTextWindow;
|
||||
data << questGiverTargetName;
|
||||
data << questTurnTextWindow;
|
||||
data << questTurnTargetName;
|
||||
data << uint32(quest->GetSoundAccept());
|
||||
data << uint32(quest->GetSoundTurnIn());
|
||||
|
||||
_session->SendPacket(&data);
|
||||
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u", quest->GetQuestId());
|
||||
}
|
||||
|
||||
@@ -652,7 +494,7 @@ void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, ObjectGuid npcGUI
|
||||
}
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
|
||||
AddQuestLevelToTitle(packet.QuestTitle, quest->GetQuestLevel());
|
||||
Quest::AddQuestLevelToTitle(packet.QuestTitle, quest->GetQuestLevel());
|
||||
|
||||
WorldPackets::Quest::QuestGiverOfferReward& offer = packet.QuestData;
|
||||
|
||||
@@ -698,7 +540,7 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU
|
||||
}
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
|
||||
AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
|
||||
Quest::AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
|
||||
|
||||
WorldPackets::Quest::QuestGiverRequestItems packet;
|
||||
|
||||
@@ -765,13 +607,3 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU
|
||||
_session->SendPacket(packet.Write());
|
||||
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUEST_GIVER_REQUEST_ITEMS NPC=%s, questid=%u", npcGUID.ToString().c_str(), quest->GetQuestId());
|
||||
}
|
||||
|
||||
void PlayerMenu::AddQuestLevelToTitle(std::string &title, int32 level)
|
||||
{
|
||||
// Adds the quest level to the front of the quest title
|
||||
// example: [13] Westfall Stew
|
||||
|
||||
std::stringstream questTitlePretty;
|
||||
questTitlePretty << "[" << level << "] " << title;
|
||||
title = questTitlePretty.str();
|
||||
}
|
||||
@@ -303,8 +303,6 @@ class TC_GAME_API PlayerMenu
|
||||
void SendQuestGiverOfferReward(Quest const* quest, ObjectGuid npcGUID, bool autoLaunched) const;
|
||||
void SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGUID, bool canComplete, bool autoLaunched) const;
|
||||
|
||||
static void AddQuestLevelToTitle(std::string &title, int32 level);
|
||||
|
||||
private:
|
||||
GossipMenu _gossipMenu;
|
||||
QuestMenu _questMenu;
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "OutdoorPvPMgr.h"
|
||||
#include "PhasingHandler.h"
|
||||
#include "PoolMgr.h"
|
||||
#include "QueryPackets.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Transport.h"
|
||||
@@ -57,6 +58,60 @@ QuaternionData QuaternionData::fromEulerAnglesZYX(float Z, float Y, float X)
|
||||
return QuaternionData(quat.x, quat.y, quat.z, quat.w);
|
||||
}
|
||||
|
||||
void GameObjectTemplate::InitializeQueryData()
|
||||
{
|
||||
WorldPacket queryTemp;
|
||||
for (uint8 loc = LOCALE_enUS; loc < TOTAL_LOCALES; ++loc)
|
||||
{
|
||||
queryTemp = BuildQueryData(static_cast<LocaleConstant>(loc));
|
||||
QueryData[loc] = queryTemp;
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket GameObjectTemplate::BuildQueryData(LocaleConstant loc) const
|
||||
{
|
||||
WorldPackets::Query::QueryGameObjectResponse queryTemp;
|
||||
|
||||
std::string locName = name;
|
||||
std::string locIconName = IconName;
|
||||
std::string locCastBarCaption = castBarCaption;
|
||||
|
||||
if (GameObjectLocale const* gameObjectLocale = sObjectMgr->GetGameObjectLocale(entry))
|
||||
{
|
||||
ObjectMgr::GetLocaleString(gameObjectLocale->Name, loc, locName);
|
||||
ObjectMgr::GetLocaleString(gameObjectLocale->CastBarCaption, loc, locCastBarCaption);
|
||||
}
|
||||
|
||||
queryTemp.GameObjectID = entry;
|
||||
queryTemp.Allow = true;
|
||||
|
||||
queryTemp.Stats.Type = type;
|
||||
queryTemp.Stats.DisplayID = displayId;
|
||||
queryTemp.Stats.Name[0] = locName;
|
||||
queryTemp.Stats.IconName = locIconName;
|
||||
queryTemp.Stats.CastBarCaption = locCastBarCaption;
|
||||
queryTemp.Stats.UnkString = unk1;
|
||||
|
||||
for (uint8 i = 0; i < MAX_GAMEOBJECT_DATA; ++i)
|
||||
queryTemp.Stats.Data[i] = raw.data[i];
|
||||
|
||||
queryTemp.Stats.Size = size;
|
||||
|
||||
for (uint32 i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i)
|
||||
queryTemp.Stats.QuestItems[i] = 0;
|
||||
|
||||
if (std::vector<uint32> const* items = sObjectMgr->GetCreatureQuestItemList(entry))
|
||||
for (uint32 i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i)
|
||||
if (i < items->size())
|
||||
queryTemp.Stats.QuestItems[i] = (*items)[i];
|
||||
|
||||
queryTemp.Stats.RequiredLevel = RequiredLevel;
|
||||
|
||||
queryTemp.Write();
|
||||
queryTemp.ShrinkToFit();
|
||||
return queryTemp.Move();
|
||||
}
|
||||
|
||||
GameObject::GameObject() : WorldObject(false), MapObject(),
|
||||
m_model(nullptr), m_goValue(), m_AI(nullptr), m_respawnCompatibilityMode(false), _triggerJustAppeared(true)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
#define MAX_GAMEOBJECT_QUEST_ITEMS 6
|
||||
|
||||
class WorldPacket;
|
||||
|
||||
// from `gameobject_template`
|
||||
struct GameObjectTemplate
|
||||
{
|
||||
@@ -426,6 +428,7 @@ struct GameObjectTemplate
|
||||
|
||||
std::string AIName;
|
||||
uint32 ScriptId;
|
||||
WorldPacket QueryData[TOTAL_LOCALES];
|
||||
|
||||
// helpers
|
||||
bool IsDespawnAtAction() const
|
||||
@@ -594,6 +597,9 @@ struct GameObjectTemplate
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeQueryData();
|
||||
WorldPacket BuildQueryData(LocaleConstant loc) const;
|
||||
};
|
||||
|
||||
// From `gameobject_template_addon`
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
#include "PhasingHandler.h"
|
||||
#include "Player.h"
|
||||
#include "PoolMgr.h"
|
||||
#include "QuestDef.h"
|
||||
#include "QueryPackets.h"
|
||||
#include "Random.h"
|
||||
#include "ReputationMgr.h"
|
||||
#include "ScriptMgr.h"
|
||||
@@ -7741,7 +7743,6 @@ void ObjectMgr::LoadQuestPOI()
|
||||
|
||||
// 0 1 2 3 4 5 6 7
|
||||
QueryResult result = WorldDatabase.Query("SELECT QuestID, id, ObjectiveIndex, MapID, WorldMapAreaId, Floor, Priority, Flags FROM quest_poi order by QuestID");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
TC_LOG_ERROR("server.loading", ">> Loaded 0 quest POI definitions. DB table `quest_poi` is empty.");
|
||||
@@ -7751,7 +7752,7 @@ void ObjectMgr::LoadQuestPOI()
|
||||
// 0 1 2 3
|
||||
QueryResult points = WorldDatabase.Query("SELECT QuestID, Idx1, X, Y FROM quest_poi_points ORDER BY QuestID DESC, Idx2");
|
||||
|
||||
std::vector<std::vector<std::vector<QuestPOIPoint> > > POIs;
|
||||
std::vector<std::vector<std::vector<QuestPOIBlobPoint>>> POIs;
|
||||
|
||||
if (points)
|
||||
{
|
||||
@@ -7772,7 +7773,10 @@ void ObjectMgr::LoadQuestPOI()
|
||||
if (POIs[questId].size() <= id + 1)
|
||||
POIs[questId].resize(id + 10);
|
||||
|
||||
QuestPOIPoint point(x, y);
|
||||
QuestPOIBlobPoint point;
|
||||
point.X = x;
|
||||
point.Y = y;
|
||||
|
||||
POIs[questId][id].push_back(point);
|
||||
} while (points->NextRow());
|
||||
}
|
||||
@@ -7790,11 +7794,30 @@ void ObjectMgr::LoadQuestPOI()
|
||||
uint32 unk3 = fields[6].GetUInt32();
|
||||
uint32 unk4 = fields[7].GetUInt32();
|
||||
|
||||
QuestPOI POI(id, objIndex, mapId, WorldMapAreaId, FloorId, unk3, unk4);
|
||||
QuestPOIBlobData POI;
|
||||
POI.BlobIndex = id;
|
||||
POI.ObjectiveIndex = objIndex;
|
||||
POI.MapID = mapId;
|
||||
POI.WorldMapAreaID = WorldMapAreaId;
|
||||
POI.Floor = FloorId;
|
||||
POI.Unk3 = unk3;
|
||||
POI.Unk4 = unk4;
|
||||
|
||||
if (questId < POIs.size() && id < POIs[questId].size())
|
||||
{
|
||||
POI.points = POIs[questId][id];
|
||||
_questPOIStore[questId].push_back(POI);
|
||||
POI.QuestPOIBlobPointStats = POIs[questId][id];
|
||||
auto itr = _questPOIStore.find(questId);
|
||||
if (itr == _questPOIStore.end())
|
||||
{
|
||||
QuestPOIWrapper wrapper;
|
||||
QuestPOIData data;
|
||||
data.QuestID = questId;
|
||||
wrapper.POIData = data;
|
||||
|
||||
_questPOIStore.emplace(questId, std::move(wrapper));
|
||||
}
|
||||
|
||||
_questPOIStore.at(questId).POIData.QuestPOIBlobDataStats.push_back(POI);
|
||||
}
|
||||
else
|
||||
TC_LOG_ERROR("sql.sql", "Table quest_poi references unknown quest points for quest %u POI id %u", questId, id);
|
||||
@@ -10098,3 +10121,62 @@ uint32 ObjectMgr::GetGameObjectTypeByEntry(uint32 entry) const
|
||||
|
||||
return MAX_GAMEOBJECT_TYPE;
|
||||
}
|
||||
|
||||
void ObjectMgr::InitializeQueriesData(QueryDataGroup mask)
|
||||
{
|
||||
// cache disabled
|
||||
if (!sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
|
||||
return;
|
||||
|
||||
// Initialize Query data for creatures
|
||||
if (mask & QUERY_DATA_CREATURES)
|
||||
for (auto& creaturePair : _creatureTemplateStore)
|
||||
creaturePair.second.InitializeQueryData();
|
||||
|
||||
// Initialize Query Data for gameobjects
|
||||
if (mask & QUERY_DATA_GAMEOBJECTS)
|
||||
for (auto& gameobjectPair : _gameObjectTemplateStore)
|
||||
gameobjectPair.second.InitializeQueryData();
|
||||
|
||||
// Initialize Query Data for quests
|
||||
if (mask & QUERY_DATA_QUESTS)
|
||||
for (auto& questPair : _questTemplates)
|
||||
questPair.second.InitializeQueryData();
|
||||
|
||||
// Initialize Quest POI data
|
||||
if (mask & QUERY_DATA_POIS)
|
||||
for (auto& poiPair : _questPOIStore)
|
||||
poiPair.second.InitializeQueryData();
|
||||
}
|
||||
|
||||
void QuestPOIWrapper::InitializeQueryData()
|
||||
{
|
||||
QueryDataBuffer = BuildQueryData();
|
||||
}
|
||||
|
||||
ByteBuffer QuestPOIWrapper::BuildQueryData() const
|
||||
{
|
||||
ByteBuffer tempBuffer;
|
||||
tempBuffer << uint32(POIData.QuestID); // quest ID
|
||||
tempBuffer << uint32(POIData.QuestPOIBlobDataStats.size()); // POI count
|
||||
|
||||
for (QuestPOIBlobData const& questPOIBlobData : POIData.QuestPOIBlobDataStats)
|
||||
{
|
||||
tempBuffer << uint32(questPOIBlobData.BlobIndex); // POI index
|
||||
tempBuffer << int32(questPOIBlobData.ObjectiveIndex); // objective index
|
||||
tempBuffer << uint32(questPOIBlobData.MapID); // mapid
|
||||
tempBuffer << uint32(questPOIBlobData.WorldMapAreaID); // areaid
|
||||
tempBuffer << uint32(questPOIBlobData.Floor); // floorid
|
||||
tempBuffer << uint32(questPOIBlobData.Unk3); // unknown
|
||||
tempBuffer << uint32(questPOIBlobData.Unk4); // unknown
|
||||
tempBuffer << uint32(questPOIBlobData.QuestPOIBlobPointStats.size()); // POI points count
|
||||
|
||||
for (QuestPOIBlobPoint const& questPOIBlobPoint : questPOIBlobData.QuestPOIBlobPointStats)
|
||||
{
|
||||
tempBuffer << int32(questPOIBlobPoint.X); // POI point x
|
||||
tempBuffer << int32(questPOIBlobPoint.Y); // POI point y
|
||||
}
|
||||
}
|
||||
|
||||
return tempBuffer;
|
||||
}
|
||||
@@ -809,32 +809,42 @@ typedef std::multimap<uint32, GossipMenuItems> GossipMenuItemsContainer;
|
||||
typedef std::pair<GossipMenuItemsContainer::const_iterator, GossipMenuItemsContainer::const_iterator> GossipMenuItemsMapBounds;
|
||||
typedef std::pair<GossipMenuItemsContainer::iterator, GossipMenuItemsContainer::iterator> GossipMenuItemsMapBoundsNonConst;
|
||||
|
||||
struct QuestPOIPoint
|
||||
struct QuestPOIBlobPoint
|
||||
{
|
||||
int32 x;
|
||||
int32 y;
|
||||
|
||||
QuestPOIPoint() : x(0), y(0) { }
|
||||
QuestPOIPoint(int32 _x, int32 _y) : x(_x), y(_y) { }
|
||||
int32 X = 0;
|
||||
int32 Y = 0;
|
||||
};
|
||||
|
||||
struct QuestPOI
|
||||
struct QuestPOIBlobData
|
||||
{
|
||||
uint32 Id;
|
||||
int32 ObjectiveIndex;
|
||||
uint32 MapId;
|
||||
uint32 AreaId;
|
||||
uint32 FloorId;
|
||||
uint32 Unk3;
|
||||
uint32 Unk4;
|
||||
std::vector<QuestPOIPoint> points;
|
||||
|
||||
QuestPOI() : Id(0), ObjectiveIndex(0), MapId(0), AreaId(0), FloorId(0), Unk3(0), Unk4(0) { }
|
||||
QuestPOI(uint32 id, int32 objIndex, uint32 mapId, uint32 areaId, uint32 floorId, uint32 unk3, uint32 unk4) : Id(id), ObjectiveIndex(objIndex), MapId(mapId), AreaId(areaId), FloorId(floorId), Unk3(unk3), Unk4(unk4) { }
|
||||
uint32 BlobIndex = 0;
|
||||
int32 ObjectiveIndex = 0;
|
||||
uint32 MapID = 0;
|
||||
uint32 WorldMapAreaID = 0;
|
||||
uint32 Floor = 0;
|
||||
uint32 Unk3 = 0;
|
||||
uint32 Unk4 = 0;
|
||||
std::vector<QuestPOIBlobPoint> QuestPOIBlobPointStats;
|
||||
};
|
||||
|
||||
typedef std::vector<QuestPOI> QuestPOIVector;
|
||||
typedef std::unordered_map<uint32, QuestPOIVector> QuestPOIContainer;
|
||||
struct QuestPOIData
|
||||
{
|
||||
uint32 QuestID = 0;
|
||||
std::vector<QuestPOIBlobData> QuestPOIBlobDataStats;
|
||||
};
|
||||
|
||||
struct QuestPOIWrapper
|
||||
{
|
||||
QuestPOIData POIData;
|
||||
ByteBuffer QueryDataBuffer;
|
||||
|
||||
void InitializeQueryData();
|
||||
ByteBuffer BuildQueryData() const;
|
||||
|
||||
QuestPOIWrapper() : QueryDataBuffer(0) { }
|
||||
};
|
||||
|
||||
typedef std::unordered_map<uint32, QuestPOIWrapper> QuestPOIContainer;
|
||||
|
||||
struct QuestGreeting
|
||||
{
|
||||
@@ -934,6 +944,16 @@ struct PhaseAreaInfo
|
||||
ConditionContainer Conditions;
|
||||
};
|
||||
|
||||
enum QueryDataGroup
|
||||
{
|
||||
QUERY_DATA_CREATURES = 0x01,
|
||||
QUERY_DATA_GAMEOBJECTS = 0x02,
|
||||
QUERY_DATA_QUESTS = 0x04,
|
||||
QUERY_DATA_POIS = 0x08,
|
||||
|
||||
QUERY_DATA_ALL = 0xFF
|
||||
};
|
||||
|
||||
class PlayerDumpReader;
|
||||
|
||||
class TC_GAME_API ObjectMgr
|
||||
@@ -1103,7 +1123,7 @@ class TC_GAME_API ObjectMgr
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QuestPOIVector const* GetQuestPOIVector(uint32 questId)
|
||||
QuestPOIWrapper const* GetQuestPOIWrapper(uint32 questId)
|
||||
{
|
||||
QuestPOIContainer::const_iterator itr = _questPOIStore.find(questId);
|
||||
if (itr != _questPOIStore.end())
|
||||
@@ -1226,6 +1246,8 @@ class TC_GAME_API ObjectMgr
|
||||
void LoadTrainers();
|
||||
void LoadCreatureDefaultTrainers();
|
||||
|
||||
void InitializeQueriesData(QueryDataGroup mask);
|
||||
|
||||
void LoadPhases();
|
||||
void UnloadPhaseConditions();
|
||||
void LoadTerrainSwapDefaults();
|
||||
|
||||
@@ -90,152 +90,54 @@ void WorldSession::SendQueryTimeResponse()
|
||||
}
|
||||
|
||||
/// Only _static_ data is sent in this packet !!!
|
||||
void WorldSession::HandleCreatureQueryOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleCreatureQueryOpcode(WorldPackets::Query::QueryCreature& query)
|
||||
{
|
||||
uint32 entry;
|
||||
recvData >> entry;
|
||||
ObjectGuid guid;
|
||||
recvData >> guid;
|
||||
|
||||
CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(entry);
|
||||
if (creatureInfo)
|
||||
if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(query.CreatureID))
|
||||
{
|
||||
std::string Name, FemaleName, Title;
|
||||
Name = creatureInfo->Name;
|
||||
FemaleName = creatureInfo->FemaleName;
|
||||
Title = creatureInfo->Title;
|
||||
|
||||
LocaleConstant locale = GetSessionDbLocaleIndex();
|
||||
if (locale != LOCALE_enUS)
|
||||
{
|
||||
if (CreatureLocale const* creatureLocale = sObjectMgr->GetCreatureLocale(entry))
|
||||
{
|
||||
ObjectMgr::GetLocaleString(creatureLocale->Name, locale, Name);
|
||||
ObjectMgr::GetLocaleString(creatureLocale->FemaleName, locale, FemaleName);
|
||||
ObjectMgr::GetLocaleString(creatureLocale->Title, locale, Title);
|
||||
}
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("network", "WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", creatureInfo->Name.c_str(), entry);
|
||||
|
||||
WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 100); // guess size
|
||||
data << uint32(entry); // creature entry
|
||||
data << Name; // Name
|
||||
|
||||
for (uint8 i = 0; i < 3; i++)
|
||||
data << uint8(0); // name2, ..., name3
|
||||
|
||||
data << FemaleName; // FemaleName
|
||||
|
||||
for (uint8 i = 0; i < 3; i++)
|
||||
data << uint8(0); // name5, ..., name8
|
||||
|
||||
data << Title; // Title
|
||||
data << creatureInfo->IconName; // "Directions" for guard, string for Icons 2.3.0
|
||||
data << uint32(creatureInfo->type_flags); // flags
|
||||
data << uint32(creatureInfo->type_flags2); // unknown meaning
|
||||
data << uint32(creatureInfo->type); // CreatureType.dbc
|
||||
data << uint32(creatureInfo->family); // CreatureFamily.dbc
|
||||
data << uint32(creatureInfo->rank); // Creature Rank (elite, boss, etc)
|
||||
data << uint32(creatureInfo->KillCredit[0]); // new in 3.1, kill credit
|
||||
data << uint32(creatureInfo->KillCredit[1]); // new in 3.1, kill credit
|
||||
data << uint32(creatureInfo->Modelid1); // Modelid1
|
||||
data << uint32(creatureInfo->Modelid2); // Modelid2
|
||||
data << uint32(creatureInfo->Modelid3); // Modelid3
|
||||
data << uint32(creatureInfo->Modelid4); // Modelid4
|
||||
data << float(creatureInfo->ModHealth); // dmg/hp modifier
|
||||
data << float(creatureInfo->ModMana); // dmg/mana modifier
|
||||
data << uint8(creatureInfo->RacialLeader); // RacialLeader
|
||||
|
||||
std::vector<uint32> const* items = sObjectMgr->GetCreatureQuestItemList(entry);
|
||||
if (items)
|
||||
for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
|
||||
data << (i < items->size() ? uint32((*items)[i]) : uint32(0));
|
||||
TC_LOG_DEBUG("network", "WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name.c_str(), query.CreatureID);
|
||||
if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
|
||||
SendPacket(&ci->QueryData[static_cast<uint32>(GetSessionDbLocaleIndex())]);
|
||||
else
|
||||
for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
|
||||
data << uint32(0);
|
||||
|
||||
data << uint32(creatureInfo->movementId); // CreatureMovementInfo.dbc
|
||||
data << uint32(creatureInfo->expansionUnknown); // unknown meaning
|
||||
|
||||
SendPacket(&data);
|
||||
|
||||
{
|
||||
WorldPacket response = ci->BuildQueryData(GetSessionDbLocaleIndex());
|
||||
SendPacket(&response);
|
||||
}
|
||||
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");
|
||||
}
|
||||
else
|
||||
{
|
||||
TC_LOG_DEBUG("network", "WORLD: CMSG_CREATURE_QUERY - NO CREATURE INFO! (%s, ENTRY: %u)",
|
||||
guid.ToString().c_str(), entry);
|
||||
|
||||
WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 4);
|
||||
data << uint32(entry | 0x80000000);
|
||||
SendPacket(&data);
|
||||
query.GUID.ToString().c_str(), query.CreatureID);
|
||||
|
||||
WorldPackets::Query::QueryCreatureResponse response;
|
||||
response.CreatureID = query.CreatureID;
|
||||
SendPacket(response.Write());
|
||||
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");
|
||||
}
|
||||
}
|
||||
|
||||
/// Only _static_ data is sent in this packet !!!
|
||||
void WorldSession::HandleGameObjectQueryOpcode(WorldPacket& recvData)
|
||||
void WorldSession::HandleGameObjectQueryOpcode(WorldPackets::Query::QueryGameObject& query)
|
||||
{
|
||||
uint32 entry;
|
||||
recvData >> entry;
|
||||
ObjectGuid guid;
|
||||
recvData >> guid;
|
||||
|
||||
GameObjectTemplate const* info = sObjectMgr->GetGameObjectTemplate(entry);
|
||||
if (info)
|
||||
if (GameObjectTemplate const* info = sObjectMgr->GetGameObjectTemplate(query.GameObjectID))
|
||||
{
|
||||
std::string Name;
|
||||
std::string IconName;
|
||||
std::string CastBarCaption;
|
||||
|
||||
Name = info->name;
|
||||
IconName = info->IconName;
|
||||
CastBarCaption = info->castBarCaption;
|
||||
|
||||
LocaleConstant localeConstant = GetSessionDbLocaleIndex();
|
||||
if (localeConstant != LOCALE_enUS)
|
||||
{
|
||||
if (GameObjectLocale const* gameObjectLocale = sObjectMgr->GetGameObjectLocale(entry))
|
||||
{
|
||||
ObjectMgr::GetLocaleString(gameObjectLocale->Name, localeConstant, Name);
|
||||
ObjectMgr::GetLocaleString(gameObjectLocale->CastBarCaption, localeConstant, CastBarCaption);
|
||||
}
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("network", "WORLD: CMSG_GAMEOBJECT_QUERY '%s' - Entry: %u. ", info->name.c_str(), entry);
|
||||
WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 150);
|
||||
data << uint32(entry);
|
||||
data << uint32(info->type);
|
||||
data << uint32(info->displayId);
|
||||
data << Name;
|
||||
data << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4
|
||||
data << IconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword)
|
||||
data << CastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting")
|
||||
data << info->unk1; // 2.0.3, string
|
||||
data.append(info->raw.data, MAX_GAMEOBJECT_DATA);
|
||||
data << float(info->size); // go size
|
||||
data << int32(info->RequiredLevel); // 4.x, Required level
|
||||
|
||||
std::vector<uint32> const* items = sObjectMgr->GetGameObjectQuestItemList(entry);
|
||||
if (items)
|
||||
for (size_t i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i)
|
||||
data << (i < items->size() ? uint32((*items)[i]) : uint32(0));
|
||||
if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
|
||||
SendPacket(&info->QueryData[static_cast<uint32>(GetSessionDbLocaleIndex())]);
|
||||
else
|
||||
for (size_t i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i)
|
||||
data << uint32(0);
|
||||
|
||||
SendPacket(&data);
|
||||
{
|
||||
WorldPacket response = info->BuildQueryData(GetSessionDbLocaleIndex());
|
||||
SendPacket(&response);
|
||||
}
|
||||
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE");
|
||||
}
|
||||
else
|
||||
{
|
||||
TC_LOG_DEBUG("network", "WORLD: CMSG_GAMEOBJECT_QUERY - Missing gameobject info for (%s, ENTRY: %u)",
|
||||
guid.ToString().c_str(), entry);
|
||||
WorldPacket data (SMSG_GAMEOBJECT_QUERY_RESPONSE, 4);
|
||||
data << uint32(entry | 0x80000000);
|
||||
SendPacket(&data);
|
||||
query.GUID.ToString().c_str(), query.GameObjectID);
|
||||
|
||||
WorldPackets::Query::QueryGameObjectResponse response;
|
||||
response.GameObjectID = query.GameObjectID;
|
||||
SendPacket(response.Write());
|
||||
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_GAMEOBJECT_QUERY_RESPONSE");
|
||||
}
|
||||
}
|
||||
@@ -469,61 +371,31 @@ void WorldSession::HandleQuestNPCQuery(WorldPacket& recvData)
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestPOIQuery(WorldPacket& recvData)
|
||||
void WorldSession::HandleQuestPOIQuery(WorldPackets::Query::QuestPOIQuery& query)
|
||||
{
|
||||
uint32 count;
|
||||
recvData >> count; // quest count, max=25
|
||||
|
||||
if (count > MAX_QUEST_LOG_SIZE)
|
||||
{
|
||||
recvData.rfinish();
|
||||
if (query.MissingQuestCount > MAX_QUEST_LOG_SIZE)
|
||||
return;
|
||||
}
|
||||
|
||||
// Read quest ids and add the in a unordered_set so we don't send POIs for the same quest multiple times
|
||||
std::unordered_set<uint32> questIds;
|
||||
for (uint32 i = 0; i < count; ++i)
|
||||
questIds.insert(recvData.read<uint32>()); // quest id
|
||||
for (uint32 i = 0; i < query.MissingQuestCount; ++i)
|
||||
questIds.insert(query.MissingQuestPOIs[i]); // quest id
|
||||
|
||||
WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4 + (4 + 4)*questIds.size());
|
||||
WorldPacket data(SMSG_QUEST_POI_QUERY_RESPONSE, 4 + (4 + 4 + 40) * questIds.size());
|
||||
data << uint32(questIds.size()); // count
|
||||
|
||||
for (auto itr = questIds.begin(); itr != questIds.end(); ++itr)
|
||||
for (uint32 questId : questIds)
|
||||
{
|
||||
uint32 questId = *itr;
|
||||
|
||||
bool questOk = false;
|
||||
|
||||
uint16 questSlot = _player->FindQuestSlot(questId);
|
||||
|
||||
if (questSlot != MAX_QUEST_LOG_SIZE)
|
||||
questOk =_player->GetQuestSlotQuestId(questSlot) == questId;
|
||||
|
||||
if (questOk)
|
||||
uint16 const questSlot = _player->FindQuestSlot(questId);
|
||||
if (questSlot != MAX_QUEST_LOG_SIZE && _player->GetQuestSlotQuestId(questSlot) == questId)
|
||||
{
|
||||
QuestPOIVector const* POI = sObjectMgr->GetQuestPOIVector(questId);
|
||||
|
||||
if (POI)
|
||||
if (QuestPOIWrapper const* poiWrapper = sObjectMgr->GetQuestPOIWrapper(questId))
|
||||
{
|
||||
data << uint32(questId); // quest ID
|
||||
data << uint32(POI->size()); // POI count
|
||||
|
||||
for (QuestPOIVector::const_iterator itr = POI->begin(); itr != POI->end(); ++itr)
|
||||
if (sWorld->getBoolConfig(CONFIG_CACHE_DATA_QUERIES))
|
||||
data.append(poiWrapper->QueryDataBuffer);
|
||||
else
|
||||
{
|
||||
data << uint32(itr->Id); // POI index
|
||||
data << int32(itr->ObjectiveIndex); // objective index
|
||||
data << uint32(itr->MapId); // mapid
|
||||
data << uint32(itr->AreaId); // areaid
|
||||
data << uint32(itr->FloorId); // floorid
|
||||
data << uint32(itr->Unk3); // unknown
|
||||
data << uint32(itr->Unk4); // unknown
|
||||
data << uint32(itr->points.size()); // POI points count
|
||||
|
||||
for (std::vector<QuestPOIPoint>::const_iterator itr2 = itr->points.begin(); itr2 != itr->points.end(); ++itr2)
|
||||
{
|
||||
data << int32(itr2->x); // POI point x
|
||||
data << int32(itr2->y); // POI point y
|
||||
}
|
||||
ByteBuffer POIByteBuffer = poiWrapper->BuildQueryData();
|
||||
data.append(POIByteBuffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "Player.h"
|
||||
#include "QuestDef.h"
|
||||
#include "QuestPackets.h"
|
||||
#include "QueryPackets.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
@@ -238,14 +239,14 @@ void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPackets::Quest::QuestGi
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleQuestQueryOpcode(WorldPackets::Quest::QueryQuestInfo& packet)
|
||||
void WorldSession::HandleQuestQueryOpcode(WorldPackets::Quest::QueryQuestInfo& query)
|
||||
{
|
||||
if (!_player)
|
||||
return;
|
||||
|
||||
TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUERY_QUEST_INFO QuestID = %u", packet.QuestID);
|
||||
TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUEST_QUERY quest = %u", query.QuestID);
|
||||
|
||||
if (Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID))
|
||||
if (Quest const* quest = sObjectMgr->GetQuestTemplate(query.QuestID))
|
||||
_player->PlayerTalkClass->SendQuestQueryResponse(quest);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Field.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "QuestPackets.h"
|
||||
#include "QuestPools.h"
|
||||
@@ -418,3 +419,174 @@ uint32 Quest::RoundXPValue(uint32 xp)
|
||||
else
|
||||
return 50 * ((xp + 25) / 50);
|
||||
}
|
||||
|
||||
void Quest::InitializeQueryData()
|
||||
{
|
||||
WorldPacket queryTemp;
|
||||
for (uint8 loc = LOCALE_enUS; loc < TOTAL_LOCALES; ++loc)
|
||||
{
|
||||
queryTemp = BuildQueryData(static_cast<LocaleConstant>(loc));
|
||||
QueryData[loc] = queryTemp;
|
||||
}
|
||||
}
|
||||
|
||||
WorldPacket Quest::BuildQueryData(LocaleConstant loc) const
|
||||
{
|
||||
WorldPackets::Quest::QueryQuestInfoResponse response;
|
||||
|
||||
response.Info.QuestID = GetQuestId();
|
||||
|
||||
std::string locQuestTitle = GetTitle();
|
||||
std::string locQuestDetails = GetDetails();
|
||||
std::string locQuestObjectives = GetObjectives();
|
||||
std::string locQuestAreaDescription = GetAreaDescription();
|
||||
std::string locQuestCompletedText = GetCompletedText();
|
||||
std::string locQuestGiverTextWindow = GetQuestGiverTextWindow();
|
||||
std::string locQuestGiverTargetName = GetQuestGiverTargetName();
|
||||
std::string locQuestTurnTextWindow = GetQuestTurnTextWindow();
|
||||
std::string locQuestTurnTargetName = GetQuestTurnTargetName();
|
||||
|
||||
std::string locQuestObjectiveText[QUEST_OBJECTIVES_COUNT];
|
||||
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
|
||||
locQuestObjectiveText[i] = ObjectiveText[i];
|
||||
|
||||
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(GetQuestId()))
|
||||
{
|
||||
ObjectMgr::GetLocaleString(localeData->Title, loc, locQuestTitle);
|
||||
ObjectMgr::GetLocaleString(localeData->Details, loc, locQuestDetails);
|
||||
ObjectMgr::GetLocaleString(localeData->Objectives, loc, locQuestObjectives);
|
||||
ObjectMgr::GetLocaleString(localeData->AreaDescription, loc, locQuestAreaDescription);
|
||||
ObjectMgr::GetLocaleString(localeData->CompletedText, loc, locQuestCompletedText);
|
||||
ObjectMgr::GetLocaleString(localeData->QuestGiverTextWindow, loc, locQuestGiverTextWindow);
|
||||
ObjectMgr::GetLocaleString(localeData->QuestGiverTargetName, loc, locQuestGiverTargetName);
|
||||
ObjectMgr::GetLocaleString(localeData->QuestTurnTextWindow, loc, locQuestTurnTextWindow);
|
||||
ObjectMgr::GetLocaleString(localeData->QuestTurnTargetName, loc, locQuestTurnTargetName);
|
||||
|
||||
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
|
||||
ObjectMgr::GetLocaleString(localeData->ObjectiveText[i], loc, locQuestObjectiveText[i]);
|
||||
}
|
||||
|
||||
response.Info.QuestType = GetQuestMethod();
|
||||
response.Info.QuestLevel = GetQuestLevel();
|
||||
response.Info.QuestMinLevel = GetMinLevel();
|
||||
response.Info.QuestSortID = GetZoneOrSort();
|
||||
response.Info.QuestInfoID = GetType();
|
||||
|
||||
response.Info.SuggestedGroupNum = GetSuggestedPlayers();
|
||||
|
||||
response.Info.RequiredFactionId[0] = GetRepObjectiveFaction();
|
||||
response.Info.RequiredFactionValue[0] = GetRepObjectiveValue();
|
||||
|
||||
response.Info.RequiredFactionId[1] = GetRepObjectiveFaction2();
|
||||
response.Info.RequiredFactionValue[1] = GetRepObjectiveValue2();
|
||||
|
||||
response.Info.RewardNextQuest = GetNextQuestInChain();
|
||||
response.Info.RewardXPDifficulty = GetXPId();
|
||||
|
||||
response.Info.RewardMoney = GetRewOrReqMoney();
|
||||
response.Info.RewardBonusMoney = GetRewMoneyMaxLevel();
|
||||
response.Info.RewardDisplaySpell = GetRewSpell();
|
||||
response.Info.RewardSpell = GetRewSpellCast();
|
||||
|
||||
response.Info.RewardHonor = GetRewHonorAddition();
|
||||
response.Info.RewardKillHonor = GetRewHonorMultiplier();
|
||||
|
||||
response.Info.StartItem = GetSrcItemId();
|
||||
response.Info.Flags = GetFlags();
|
||||
response.Info.MinimapTargetMark = GetMinimapTargetMark();
|
||||
|
||||
response.Info.RewardTitle = GetCharTitleId();
|
||||
response.Info.RequiredPlayerKills = GetPlayersSlain();
|
||||
response.Info.RewardTalents = GetBonusTalents();
|
||||
response.Info.RewardArenaPoints = GetRewArenaPoints();
|
||||
response.Info.PortraitGiver = GetQuestGiverPortrait();
|
||||
response.Info.PortraitTurnIn = GetQuestTurnInPortrait();
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
|
||||
{
|
||||
response.Info.RewardItems[i] = RewardItemId[i];
|
||||
response.Info.RewardAmount[i] = RewardItemIdCount[i];
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
|
||||
{
|
||||
response.Info.UnfilteredChoiceItems[i].ItemID = RewardChoiceItemId[i];
|
||||
response.Info.UnfilteredChoiceItems[i].Quantity = RewardChoiceItemCount[i];
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward factions ids
|
||||
response.Info.RewardFactionID[i] = RewardFactionId[i];
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid+1 QuestFactionReward.dbc?
|
||||
response.Info.RewardFactionValue[i] = RewardFactionValueId[i];
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // unknown usage
|
||||
response.Info.RewardFactionValueOverride[i] = RewardFactionValueIdOverride[i];
|
||||
|
||||
response.Info.POIContinent = GetPOIContinent();
|
||||
response.Info.POIx = GetPOIx();
|
||||
response.Info.POIy = GetPOIy();
|
||||
response.Info.POIPriority = GetPointOpt();
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
|
||||
Quest::AddQuestLevelToTitle(locQuestTitle, GetQuestLevel());
|
||||
|
||||
response.Info.LogTitle = locQuestTitle;
|
||||
response.Info.LogDescription = locQuestObjectives;
|
||||
response.Info.QuestDescription = locQuestDetails;
|
||||
response.Info.AreaDescription = locQuestAreaDescription;
|
||||
response.Info.QuestCompletionLog = locQuestCompletedText;
|
||||
|
||||
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
|
||||
{
|
||||
response.Info.RequiredNpcOrGo[i] = RequiredNpcOrGo[i];
|
||||
response.Info.RequiredNpcOrGoCount[i] = RequiredNpcOrGoCount[i];
|
||||
response.Info.ItemDrop[i] = ItemDrop[i];
|
||||
response.Info.ItemDropQuantity[i] = ItemDropQuantity[i];
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
|
||||
{
|
||||
response.Info.RequiredItemId[i] = RequiredItemId[i];
|
||||
response.Info.RequiredItemCount[i] = RequiredItemCount[i];
|
||||
}
|
||||
|
||||
response.Info.RequiredSpell = GetRequiredSpell();
|
||||
|
||||
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
|
||||
response.Info.ObjectiveText[i] = locQuestObjectiveText[i];
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
|
||||
{
|
||||
response.Info.RewardCurrencyID[i] = RewardCurrencyId[i];
|
||||
response.Info.RewardCurrencyQty[i] = RewardCurrencyCount[i];
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i)
|
||||
{
|
||||
response.Info.RequiredCurrencyID[i] = RequiredCurrencyId[i];
|
||||
response.Info.RequiredCurrencyQty[i] = RequiredCurrencyCount[i];
|
||||
}
|
||||
|
||||
response.Info.PortraitGiverText = locQuestGiverTextWindow;
|
||||
response.Info.PortraitGiverName = locQuestGiverTargetName;
|
||||
response.Info.PortraitTurnintext = locQuestTurnTextWindow;
|
||||
response.Info.PortraitTurnInName = locQuestTurnTargetName;
|
||||
|
||||
response.Info.AcceptedSoundKitID = GetSoundAccept();
|
||||
response.Info.CompleteSoundKitID = GetSoundTurnIn();
|
||||
|
||||
response.Write();
|
||||
response.ShrinkToFit();
|
||||
return response.Move();
|
||||
}
|
||||
|
||||
void Quest::AddQuestLevelToTitle(std::string& title, int32 level)
|
||||
{
|
||||
// Adds the quest level to the front of the quest title
|
||||
// example: [13] Westfall Stew
|
||||
|
||||
std::stringstream questTitlePretty;
|
||||
questTitlePretty << "[" << level << "] " << title;
|
||||
title = questTitlePretty.str();
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <vector>
|
||||
|
||||
class Player;
|
||||
class WorldPacket;
|
||||
|
||||
namespace WorldPackets
|
||||
{
|
||||
@@ -371,8 +372,13 @@ class TC_GAME_API Quest
|
||||
|
||||
void BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player) const;
|
||||
|
||||
static void AddQuestLevelToTitle(std::string& title, int32 level);
|
||||
void InitializeQueryData();
|
||||
WorldPacket BuildQueryData(LocaleConstant loc) const;
|
||||
|
||||
std::vector<uint32> DependentPreviousQuests;
|
||||
std::vector<uint32> DependentBreadcrumbQuests;
|
||||
WorldPacket QueryData[TOTAL_LOCALES];
|
||||
|
||||
// cached data
|
||||
private:
|
||||
|
||||
@@ -19,6 +19,88 @@
|
||||
#include "Player.h"
|
||||
#include "QueryPackets.h"
|
||||
|
||||
void WorldPackets::Query::QueryCreature::Read()
|
||||
{
|
||||
_worldPacket >> CreatureID;
|
||||
_worldPacket >> GUID;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Query::QueryCreatureResponse::Write()
|
||||
{
|
||||
_worldPacket << uint32(CreatureID | (Allow ? 0x00000000 : 0x80000000)); // creature entry
|
||||
|
||||
if (Allow)
|
||||
{
|
||||
for (std::size_t i = 0; i < Stats.Name.size(); ++i)
|
||||
_worldPacket << Stats.Name[i];
|
||||
|
||||
for (std::size_t i = 0; i < Stats.NameAlt.size(); ++i)
|
||||
_worldPacket << Stats.NameAlt[i];
|
||||
|
||||
_worldPacket << Stats.Title;
|
||||
|
||||
_worldPacket << Stats.CursorName; // "Directions" for guard, string for Icons 2.3.0
|
||||
_worldPacket.append(Stats.Flags.data(), Stats.Flags.size()); // flags
|
||||
_worldPacket << uint32(Stats.CreatureType); // CreatureType.dbc
|
||||
_worldPacket << uint32(Stats.CreatureFamily); // CreatureFamily.dbc
|
||||
_worldPacket << uint32(Stats.Classification); // Creature Rank (elite, boss, etc)
|
||||
_worldPacket.append(Stats.ProxyCreatureID.data(), Stats.ProxyCreatureID.size());
|
||||
_worldPacket.append(Stats.CreatureDisplayID.data(), Stats.CreatureDisplayID.size()); // Modelid
|
||||
_worldPacket << float(Stats.HpMulti); // dmg/hp modifier
|
||||
_worldPacket << float(Stats.EnergyMulti); // dmg/mana modifier
|
||||
_worldPacket << uint8(Stats.Leader);
|
||||
_worldPacket.append(Stats.QuestItems.data(), Stats.QuestItems.size());
|
||||
_worldPacket << uint32(Stats.CreatureMovementInfoID); // CreatureMovementInfo.dbc
|
||||
_worldPacket << uint32(Stats.RequiredExpansion);
|
||||
}
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
void WorldPackets::Query::QueryGameObject::Read()
|
||||
{
|
||||
_worldPacket >> GameObjectID;
|
||||
_worldPacket >> GUID;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Query::QueryGameObjectResponse::Write()
|
||||
{
|
||||
_worldPacket << uint32(GameObjectID | (Allow ? 0x00000000 : 0x80000000));
|
||||
|
||||
if (Allow)
|
||||
{
|
||||
_worldPacket << uint32(Stats.Type);
|
||||
_worldPacket << uint32(Stats.DisplayID);
|
||||
|
||||
for (std::size_t i = 0; i < Stats.Name.size(); ++i)
|
||||
_worldPacket << Stats.Name[i];
|
||||
|
||||
_worldPacket << Stats.IconName; // 2.0.3, string. Icon name to use instead of default icon for go's (ex: "Attack" makes sword)
|
||||
_worldPacket << Stats.CastBarCaption; // 2.0.3, string. Text will appear in Cast Bar when using GO (ex: "Collecting")
|
||||
_worldPacket << Stats.UnkString; // 2.0.3, string
|
||||
_worldPacket.append(Stats.Data.data(), Stats.Data.size());
|
||||
_worldPacket << float(Stats.Size); // go size
|
||||
_worldPacket.append(Stats.QuestItems.data(), Stats.QuestItems.size());
|
||||
_worldPacket << int32(Stats.RequiredLevel);
|
||||
}
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
void WorldPackets::Query::QuestPOIQuery::Read()
|
||||
{
|
||||
_worldPacket >> MissingQuestCount;
|
||||
|
||||
MissingQuestPOIs.fill(0);
|
||||
if (MissingQuestCount <= MAX_QUEST_LOG_SIZE)
|
||||
{
|
||||
for (std::size_t i = 0; i < MissingQuestCount; ++i)
|
||||
_worldPacket >> MissingQuestPOIs[i];
|
||||
}
|
||||
else
|
||||
_worldPacket.rfinish();
|
||||
}
|
||||
|
||||
void WorldPackets::Query::DBQueryBulk::Read()
|
||||
{
|
||||
_worldPacket >> TableHash;
|
||||
|
||||
@@ -19,8 +19,11 @@
|
||||
#define QueryPackets_h__
|
||||
|
||||
#include "Packet.h"
|
||||
#include "CreatureData.h"
|
||||
#include "GameObjectData.h"
|
||||
#include "DB2Stores.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "QuestDef.h"
|
||||
#include "SharedDefines.h"
|
||||
|
||||
class Player;
|
||||
@@ -29,6 +32,97 @@ namespace WorldPackets
|
||||
{
|
||||
namespace Query
|
||||
{
|
||||
class QueryCreature final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
QueryCreature(WorldPacket&& packet) : ClientPacket(CMSG_CREATURE_QUERY, std::move(packet)) { }
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint32 CreatureID = 0;
|
||||
ObjectGuid GUID;
|
||||
};
|
||||
|
||||
struct CreatureStats
|
||||
{
|
||||
std::array<std::string, 4> Name;
|
||||
std::array<std::string, 4> NameAlt;
|
||||
std::string Title;
|
||||
std::string CursorName;
|
||||
std::array<uint32, 2> Flags;
|
||||
uint32 CreatureType = 0;
|
||||
uint32 CreatureFamily = 0;
|
||||
uint32 Classification = 0;
|
||||
std::array<uint32, MAX_KILL_CREDIT> ProxyCreatureID;
|
||||
std::array<uint32, MAX_CREATURE_MODELS> CreatureDisplayID;
|
||||
float HpMulti = 0.0f;
|
||||
float EnergyMulti = 0.0f;
|
||||
bool Leader = false;
|
||||
std::array<uint32, MAX_CREATURE_QUEST_ITEMS> QuestItems;
|
||||
uint32 CreatureMovementInfoID = 0;
|
||||
uint32 RequiredExpansion = 0;
|
||||
};
|
||||
|
||||
class QueryCreatureResponse final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
QueryCreatureResponse() : ServerPacket(SMSG_CREATURE_QUERY_RESPONSE, 100) { }
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
bool Allow = false;
|
||||
CreatureStats Stats;
|
||||
uint32 CreatureID = 0;
|
||||
};
|
||||
|
||||
class QueryGameObject final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
QueryGameObject(WorldPacket&& packet) : ClientPacket(CMSG_GAMEOBJECT_QUERY, std::move(packet)) { }
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint32 GameObjectID = 0;
|
||||
ObjectGuid GUID;
|
||||
};
|
||||
|
||||
struct GameObjectStats
|
||||
{
|
||||
std::array<std::string, 4> Name;
|
||||
std::string IconName;
|
||||
std::string CastBarCaption;
|
||||
std::string UnkString;
|
||||
uint32 Type = 0;
|
||||
uint32 DisplayID = 0;
|
||||
std::array<uint32, MAX_GAMEOBJECT_DATA> Data;
|
||||
float Size = 0.0f;
|
||||
std::array<uint32, MAX_GAMEOBJECT_QUEST_ITEMS> QuestItems;
|
||||
int32 RequiredLevel = 0;
|
||||
};
|
||||
|
||||
class QueryGameObjectResponse final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
QueryGameObjectResponse() : ServerPacket(SMSG_GAMEOBJECT_QUERY_RESPONSE, 150) { }
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
uint32 GameObjectID = 0;
|
||||
bool Allow = false;
|
||||
GameObjectStats Stats;
|
||||
};
|
||||
|
||||
class QuestPOIQuery final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
QuestPOIQuery(WorldPacket&& packet) : ClientPacket(CMSG_QUEST_POI_QUERY, std::move(packet)) { }
|
||||
|
||||
void Read() override;
|
||||
|
||||
uint32 MissingQuestCount = 0;
|
||||
std::array<uint32, MAX_QUEST_LOG_SIZE> MissingQuestPOIs;
|
||||
};
|
||||
|
||||
struct DBQueryRecord
|
||||
{
|
||||
ObjectGuid GUID;
|
||||
|
||||
@@ -297,6 +297,138 @@ WorldPacket const* WorldPackets::Quest::QuestGiverOfferRewardMessage::Write()
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Quest::QueryQuestInfoResponse::Write()
|
||||
{
|
||||
_worldPacket << uint32(Info.QuestID);
|
||||
_worldPacket << int32(Info.QuestType);
|
||||
_worldPacket << int32(Info.QuestLevel);
|
||||
_worldPacket << int32(Info.QuestMinLevel);
|
||||
_worldPacket << int32(Info.QuestSortID);
|
||||
_worldPacket << int32(Info.QuestInfoID);
|
||||
_worldPacket << uint32(Info.SuggestedGroupNum);
|
||||
|
||||
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i)
|
||||
{
|
||||
_worldPacket << uint32(Info.RequiredFactionId[i]);
|
||||
_worldPacket << int32(Info.RequiredFactionValue[i]);
|
||||
}
|
||||
|
||||
_worldPacket << int32(Info.RewardNextQuest);
|
||||
_worldPacket << uint32(Info.RewardXPDifficulty);
|
||||
|
||||
if ((Info.Flags & QUEST_FLAGS_HIDDEN_REWARDS) != 0)
|
||||
_worldPacket << int32(0);
|
||||
else
|
||||
_worldPacket << int32(Info.RewardMoney);
|
||||
|
||||
_worldPacket << uint32(Info.RewardBonusMoney);
|
||||
_worldPacket << int32(Info.RewardDisplaySpell);
|
||||
_worldPacket << int32(Info.RewardSpell);
|
||||
_worldPacket << int32(Info.RewardHonor);
|
||||
_worldPacket << float(Info.RewardKillHonor);
|
||||
_worldPacket << uint32(Info.StartItem);
|
||||
_worldPacket << uint32(Info.Flags);
|
||||
_worldPacket << uint32(Info.MinimapTargetMark);
|
||||
_worldPacket << uint32(Info.RewardTitle);
|
||||
_worldPacket << uint32(Info.RequiredPlayerKills);
|
||||
_worldPacket << uint32(Info.RewardTalents);
|
||||
_worldPacket << uint32(Info.RewardArenaPoints);
|
||||
_worldPacket << uint32(Info.RewardSkillLineID);
|
||||
_worldPacket << uint32(Info.RewardNumSkillUps);
|
||||
_worldPacket << uint32(Info.RewardReputationMask);
|
||||
_worldPacket << uint32(Info.PortraitGiver);
|
||||
_worldPacket << uint32(Info.PortraitTurnIn);
|
||||
|
||||
if ((Info.Flags & QUEST_FLAGS_HIDDEN_REWARDS) != 0)
|
||||
{
|
||||
for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
|
||||
_worldPacket << int32(0) << uint32(0);
|
||||
for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
|
||||
_worldPacket << int32(0) << uint32(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
|
||||
{
|
||||
_worldPacket << int32(Info.RewardItems[i]);
|
||||
_worldPacket << uint32(Info.RewardAmount[i]);
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
|
||||
{
|
||||
_worldPacket << int32(Info.UnfilteredChoiceItems[i].ItemID);
|
||||
_worldPacket << uint32(Info.UnfilteredChoiceItems[i].Quantity);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
|
||||
_worldPacket << uint32(Info.RewardFactionID[i]);
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
|
||||
_worldPacket << int32(Info.RewardFactionValue[i]);
|
||||
|
||||
for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
|
||||
_worldPacket << uint32(Info.RewardFactionValueOverride[i]);
|
||||
|
||||
_worldPacket << uint32(Info.POIContinent);
|
||||
_worldPacket << float(Info.POIx);
|
||||
_worldPacket << float(Info.POIy);
|
||||
_worldPacket << uint32(Info.POIPriority);
|
||||
|
||||
_worldPacket << Info.LogTitle;
|
||||
_worldPacket << Info.LogDescription;
|
||||
_worldPacket << Info.QuestDescription;
|
||||
_worldPacket << Info.AreaDescription;
|
||||
_worldPacket << Info.QuestCompletionLog;
|
||||
|
||||
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
|
||||
{
|
||||
if (Info.RequiredNpcOrGo[i] < 0)
|
||||
_worldPacket << uint32((Info.RequiredNpcOrGo[i] * (-1)) | 0x80000000); // client expects gameobject template id in form (id|0x80000000)
|
||||
else
|
||||
_worldPacket << uint32(Info.RequiredNpcOrGo[i]);
|
||||
|
||||
_worldPacket << uint32(Info.RequiredNpcOrGoCount[i]);
|
||||
|
||||
_worldPacket << int32(Info.ItemDrop[i]);
|
||||
_worldPacket << uint32(Info.ItemDropQuantity[i]);
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
|
||||
{
|
||||
_worldPacket << int32(Info.RequiredItemId[i]);
|
||||
_worldPacket << uint32(Info.RequiredItemCount[i]);
|
||||
}
|
||||
|
||||
_worldPacket << uint32(Info.RequiredSpell);
|
||||
|
||||
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
|
||||
_worldPacket << Info.ObjectiveText[i];
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
|
||||
{
|
||||
_worldPacket << uint32(Info.RewardCurrencyID[i]);
|
||||
_worldPacket << uint32(Info.RewardCurrencyQty[i]);
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i)
|
||||
{
|
||||
_worldPacket << uint32(Info.RequiredCurrencyID[i]);
|
||||
_worldPacket << uint32(Info.RequiredCurrencyQty[i]);
|
||||
}
|
||||
|
||||
_worldPacket << Info.PortraitGiverText;
|
||||
_worldPacket << Info.PortraitGiverName;
|
||||
_worldPacket << Info.PortraitTurnintext;
|
||||
_worldPacket << Info.PortraitTurnInName;
|
||||
|
||||
|
||||
_worldPacket << uint32(Info.AcceptedSoundKitID);
|
||||
_worldPacket << uint32(Info.CompleteSoundKitID);
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Quest::QuestRewards const& questRewards)
|
||||
{
|
||||
data << uint32(questRewards.ChoiceItemCount);
|
||||
|
||||
@@ -182,6 +182,102 @@ namespace WorldPackets
|
||||
int32 QuestID = 0;
|
||||
};
|
||||
|
||||
struct QuestInfoChoiceItem
|
||||
{
|
||||
int32 ItemID = 0;
|
||||
int32 Quantity = 0;
|
||||
int32 DisplayID = 0;
|
||||
};
|
||||
|
||||
struct QuestInfo
|
||||
{
|
||||
uint32 QuestID = 0;
|
||||
int32 QuestType = 0; // Accepted values: 0, 1 or 2. 0 == IsAutoComplete() (skip objectives/details)
|
||||
int32 QuestLevel = 0; // may be -1, static data, in other cases must be used dynamic level: Player::GetQuestLevel (0 is not known, but assuming this is no longer valid for quest intended for client)
|
||||
int32 QuestMinLevel = 0;
|
||||
int32 QuestSortID = 0; // zone or sort to display in quest log
|
||||
int32 QuestInfoID = 0;
|
||||
uint32 SuggestedGroupNum = 0;
|
||||
int32 AllowableRaces = -1;
|
||||
|
||||
std::array<uint32, BG_TEAMS_COUNT> RequiredFactionId; // shown in quest log as part of quest objective (same/opposite faction)
|
||||
std::array<int32, BG_TEAMS_COUNT> RequiredFactionValue; // shown in quest log as part of quest objective (same/opposite faction)
|
||||
|
||||
int32 RewardNextQuest = 0; // client will request this quest from NPC, if not 0
|
||||
uint32 RewardXPDifficulty = 0; // used for calculating rewarded experience
|
||||
int32 RewardMoney = 0; // reward money (below max lvl)
|
||||
uint32 RewardBonusMoney = 0; // used in XP calculation at client
|
||||
int32 RewardDisplaySpell = 0; // reward spell, this spell will be displayed (icon) (cast if RewSpellCast == 0)
|
||||
int32 RewardSpell = 0;
|
||||
int32 RewardHonor = 0;
|
||||
float RewardKillHonor = 0.0f;
|
||||
uint32 StartItem = 0;
|
||||
uint32 Flags = 0;
|
||||
uint32 MinimapTargetMark = 0;
|
||||
uint32 RewardTitle = 0; // new 2.4.0, player gets this title (id from CharTitles)
|
||||
uint32 RequiredPlayerKills = 0;
|
||||
uint32 RewardTalents = 0;
|
||||
int32 RewardArenaPoints = 0;
|
||||
uint32 RewardSkillLineID = 0;
|
||||
uint32 RewardNumSkillUps = 0;
|
||||
uint32 RewardReputationMask = 0;
|
||||
uint32 PortraitGiver = 0;
|
||||
uint32 PortraitTurnIn = 0;
|
||||
|
||||
std::array<int32, QUEST_REWARDS_COUNT> RewardItems;
|
||||
std::array<uint32, QUEST_REWARDS_COUNT> RewardAmount;
|
||||
std::array<QuestInfoChoiceItem, QUEST_REWARD_CHOICES_COUNT> UnfilteredChoiceItems;
|
||||
std::array<uint32, QUEST_REPUTATIONS_COUNT> RewardFactionID;
|
||||
std::array<int32, QUEST_REPUTATIONS_COUNT> RewardFactionValue;
|
||||
std::array<uint32, QUEST_REPUTATIONS_COUNT> RewardFactionValueOverride;
|
||||
|
||||
uint32 POIContinent = 0;
|
||||
float POIx = 0.0f;
|
||||
float POIy = 0.0f;
|
||||
uint32 POIPriority = 0;
|
||||
std::string LogTitle;
|
||||
std::string LogDescription;
|
||||
std::string QuestDescription;
|
||||
std::string AreaDescription;
|
||||
std::string QuestCompletionLog; // display in quest objectives window once all objectives are completed
|
||||
|
||||
std::array<int32, QUEST_OBJECTIVES_COUNT> RequiredNpcOrGo; // >0 Creature <0 Gameobject
|
||||
std::array<uint32, QUEST_OBJECTIVES_COUNT> RequiredNpcOrGoCount;
|
||||
|
||||
std::array<int32, QUEST_OBJECTIVES_COUNT> ItemDrop;
|
||||
std::array<uint32, QUEST_OBJECTIVES_COUNT> ItemDropQuantity;
|
||||
|
||||
std::array<uint32, QUEST_ITEM_OBJECTIVES_COUNT> RequiredItemId;
|
||||
std::array<uint32, QUEST_ITEM_OBJECTIVES_COUNT> RequiredItemCount;
|
||||
|
||||
uint32 RequiredSpell = 0;
|
||||
|
||||
std::array<std::string, QUEST_OBJECTIVES_COUNT> ObjectiveText;
|
||||
|
||||
std::array<uint32, QUEST_REWARD_CURRENCY_COUNT> RewardCurrencyID;
|
||||
std::array<uint32, QUEST_REWARD_CURRENCY_COUNT> RewardCurrencyQty;
|
||||
std::array<uint32, QUEST_REQUIRED_CURRENCY_COUNT> RequiredCurrencyID;
|
||||
std::array<uint32, QUEST_REQUIRED_CURRENCY_COUNT> RequiredCurrencyQty;
|
||||
|
||||
std::string PortraitGiverText;
|
||||
std::string PortraitGiverName;
|
||||
std::string PortraitTurnintext;
|
||||
std::string PortraitTurnInName;
|
||||
|
||||
uint32 AcceptedSoundKitID = 0;
|
||||
uint32 CompleteSoundKitID = 0;
|
||||
};
|
||||
|
||||
class QueryQuestInfoResponse final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
QueryQuestInfoResponse() : ServerPacket(SMSG_QUEST_QUERY_RESPONSE, 2000) { }
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
QuestInfo Info;
|
||||
};
|
||||
|
||||
struct GossipText
|
||||
{
|
||||
GossipText(uint32 questID, uint32 questType, int32 questLevel, uint32 questFlags, bool repeatable, std::string questTitle) :
|
||||
@@ -229,13 +325,6 @@ namespace WorldPackets
|
||||
QuestGiverInfo QuestGiver;
|
||||
};
|
||||
|
||||
struct QuestInfoChoiceItem
|
||||
{
|
||||
int32 ItemID = 0;
|
||||
int32 Quantity = 0;
|
||||
int32 DisplayID = 0;
|
||||
};
|
||||
|
||||
struct QuestRewards
|
||||
{
|
||||
int32 ChoiceItemCount = 0;
|
||||
|
||||
@@ -171,6 +171,9 @@ namespace WorldPackets
|
||||
|
||||
namespace Query
|
||||
{
|
||||
class QueryCreature;
|
||||
class QueryGameObject;
|
||||
class QuestPOIQuery;
|
||||
class DBQueryBulk;
|
||||
}
|
||||
|
||||
@@ -713,9 +716,9 @@ class TC_GAME_API WorldSession
|
||||
|
||||
void HandleQueryTimeOpcode(WorldPacket& recvPacket);
|
||||
|
||||
void HandleCreatureQueryOpcode(WorldPacket& recvPacket);
|
||||
void HandleCreatureQueryOpcode(WorldPackets::Query::QueryCreature& query);
|
||||
|
||||
void HandleGameObjectQueryOpcode(WorldPacket& recvPacket);
|
||||
void HandleGameObjectQueryOpcode(WorldPackets::Query::QueryGameObject& query);
|
||||
|
||||
void HandleMoveWorldportAckOpcode(WorldPacket& recvPacket);
|
||||
void HandleMoveWorldportAck(); // for server-side calls
|
||||
@@ -1177,7 +1180,7 @@ class TC_GAME_API WorldSession
|
||||
void HandleReadyForAccountDataTimes(WorldPacket& recvData);
|
||||
void HandleQueryQuestsCompleted(WorldPacket& recvData);
|
||||
void HandleQuestNPCQuery(WorldPacket& recvData);
|
||||
void HandleQuestPOIQuery(WorldPacket& recvData);
|
||||
void HandleQuestPOIQuery(WorldPackets::Query::QuestPOIQuery& query);
|
||||
void HandleEjectPassenger(WorldPacket& data);
|
||||
void HandleEnterPlayerVehicle(WorldPacket& data);
|
||||
void HandleUpdateProjectilePosition(WorldPacket& recvPacket);
|
||||
|
||||
@@ -1598,6 +1598,9 @@ void World::LoadConfigSettings(bool reload)
|
||||
// Whether to use LoS from game objects
|
||||
m_bool_configs[CONFIG_CHECK_GOBJECT_LOS] = sConfigMgr->GetBoolDefault("CheckGameObjectLoS", true);
|
||||
|
||||
// Allow to cache data queries
|
||||
m_bool_configs[CONFIG_CACHE_DATA_QUERIES] = sConfigMgr->GetBoolDefault("CacheDataQueries", true);
|
||||
|
||||
// call ScriptMgr if we're reloading the configuration
|
||||
if (reload)
|
||||
sScriptMgr->OnConfigLoad(reload);
|
||||
@@ -2181,6 +2184,9 @@ void World::SetInitialWorldSettings()
|
||||
TC_LOG_INFO("server.loading", "Loading Item loot...");
|
||||
sLootItemStorage->LoadStorageFromDB();
|
||||
|
||||
TC_LOG_INFO("server.loading", "Initialize query data...");
|
||||
sObjectMgr->InitializeQueriesData(QUERY_DATA_ALL);
|
||||
|
||||
///- Initialize game time and timers
|
||||
TC_LOG_INFO("server.loading", "Initialize game time and timers");
|
||||
GameTime::UpdateGameTimers();
|
||||
|
||||
@@ -185,6 +185,7 @@ enum WorldBoolConfigs
|
||||
CONFIG_HOTSWAP_PREFIX_CORRECTION_ENABLED,
|
||||
CONFIG_CHECK_GOBJECT_LOS,
|
||||
CONFIG_RESPAWN_DYNAMIC_ESCORTNPC,
|
||||
CONFIG_CACHE_DATA_QUERIES,
|
||||
BOOL_CONFIG_VALUE_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -453,6 +453,7 @@ public:
|
||||
sObjectMgr->CheckCreatureTemplate(cInfo);
|
||||
}
|
||||
|
||||
sObjectMgr->InitializeQueriesData(QUERY_DATA_CREATURES);
|
||||
handler->SendGlobalGMSysMessage("Creature template reloaded.");
|
||||
return true;
|
||||
}
|
||||
@@ -543,6 +544,7 @@ public:
|
||||
{
|
||||
TC_LOG_INFO("misc", "Re-Loading Quest Templates...");
|
||||
sObjectMgr->LoadQuests();
|
||||
sObjectMgr->InitializeQueriesData(QUERY_DATA_QUESTS);
|
||||
handler->SendGlobalGMSysMessage("DB table `quest_template` (quest definitions) reloaded.");
|
||||
|
||||
/// dependent also from `gameobject` but this table not reloaded anyway
|
||||
@@ -734,6 +736,7 @@ public:
|
||||
{
|
||||
TC_LOG_INFO("misc", "Re-Loading Quest POI ..." );
|
||||
sObjectMgr->LoadQuestPOI();
|
||||
sObjectMgr->InitializeQueriesData(QUERY_DATA_POIS);
|
||||
handler->SendGlobalGMSysMessage("DB Table `quest_poi` and `quest_poi_points` reloaded.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1277,6 +1277,17 @@ Account.PasswordChangeSecurity = 0
|
||||
|
||||
BirthdayTime = 1222964635
|
||||
|
||||
#
|
||||
# CacheDataQueries
|
||||
# Description: Server caches data queries at startup.
|
||||
# Can be disabled if not enough memory is available.
|
||||
# Default: 1 - (Enabled)
|
||||
# 0 - (Disabled)
|
||||
#
|
||||
#
|
||||
|
||||
CacheDataQueries = 1
|
||||
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
|
||||
Reference in new issue
Block a user