aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Chat/ChatLink.cpp6
-rw-r--r--src/server/game/Entities/Creature/GossipDef.cpp383
-rw-r--r--src/server/game/Entities/Player/Player.cpp792
-rw-r--r--src/server/game/Entities/Player/Player.h84
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp553
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp6
-rw-r--r--src/server/game/Handlers/LFGHandler.cpp8
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp21
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp100
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h4
-rw-r--r--src/server/game/Quests/QuestDef.cpp381
-rw-r--r--src/server/game/Quests/QuestDef.h323
-rw-r--r--src/server/game/Server/Packets/QuestPackets.cpp278
-rw-r--r--src/server/game/Server/Packets/QuestPackets.h230
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp16
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h6
-rw-r--r--src/server/game/Server/WorldSession.h12
-rw-r--r--src/server/scripts/Commands/cs_lookup.cpp6
-rw-r--r--src/server/scripts/Commands/cs_quest.cpp104
-rw-r--r--src/server/scripts/Northrend/zone_borean_tundra.cpp2
-rw-r--r--src/server/scripts/Northrend/zone_sholazar_basin.cpp9
-rw-r--r--src/server/scripts/World/go_scripts.cpp2
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp9
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.h6
24 files changed, 2019 insertions, 1322 deletions
diff --git a/src/server/game/Chat/ChatLink.cpp b/src/server/game/Chat/ChatLink.cpp
index ed8c2598832..64c4a888af0 100644
--- a/src/server/game/Chat/ChatLink.cpp
+++ b/src/server/game/Chat/ChatLink.cpp
@@ -241,11 +241,11 @@ bool QuestChatLink::ValidateName(char* buffer, const char* context)
{
ChatLink::ValidateName(buffer, context);
- bool res = (_quest->GetTitle() == buffer);
+ bool res = (_quest->GetLogTitle() == buffer);
if (!res)
if (QuestLocale const* ql = sObjectMgr->GetQuestLocale(_quest->GetQuestId()))
- for (uint8 i = 0; i < ql->Title.size(); i++)
- if (ql->Title[i] == buffer)
+ for (uint8 i = 0; i < ql->LogTitle.size(); i++)
+ if (ql->LogTitle[i] == buffer)
{
res = true;
break;
diff --git a/src/server/game/Entities/Creature/GossipDef.cpp b/src/server/game/Entities/Creature/GossipDef.cpp
index 270b6b67349..f55174f3232 100644
--- a/src/server/game/Entities/Creature/GossipDef.cpp
+++ b/src/server/game/Entities/Creature/GossipDef.cpp
@@ -232,11 +232,11 @@ void PlayerMenu::SendGossipMenu(uint32 titleTextId, ObjectGuid objectGUID)
text.QuestFlags[1] = 0;
text.Repeatable = quest->IsRepeatable();
- std::string title = quest->GetTitle();
+ std::string title = quest->GetLogTitle();
int32 locale = _session->GetSessionDbLocaleIndex();
if (locale >= 0)
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID))
- ObjectMgr::GetLocaleString(localeData->Title, locale, title);
+ ObjectMgr::GetLocaleString(localeData->LogTitle, locale, title);
if (questLevelInTitle)
AddQuestLevelToTitle(title, quest->GetQuestLevel());
@@ -353,12 +353,12 @@ void PlayerMenu::SendQuestGiverQuestList(QEmote const& eEmote, const std::string
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questID))
{
++count;
- std::string title = quest->GetTitle();
+ std::string title = quest->GetLogTitle();
int32 locale = _session->GetSessionDbLocaleIndex();
if (locale >= 0)
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(questID))
- ObjectMgr::GetLocaleString(localeData->Title, locale, title);
+ ObjectMgr::GetLocaleString(localeData->LogTitle, locale, title);
if (questLevelInTitle)
AddQuestLevelToTitle(title, quest->GetQuestLevel());
@@ -389,45 +389,43 @@ void PlayerMenu::SendQuestGiverStatus(uint32 questStatus, ObjectGuid npcGUID) co
void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGUID, bool activateAccept) const
{
- std::string questTitle = quest->GetTitle();
- std::string questDetails = quest->GetDetails();
- std::string questObjectives = quest->GetObjectives();
- std::string questEndText = quest->GetEndText();
- std::string questGiverTextWindow = quest->GetQuestGiverTextWindow();
- std::string questGiverTargetName = quest->GetQuestGiverTargetName();
- std::string questTurnTextWindow = quest->GetQuestTurnTextWindow();
- std::string questTurnTargetName = quest->GetQuestTurnTargetName();
+ std::string questLogTitle = quest->GetLogTitle();
+ std::string questLogDescription = quest->GetLogDescription();
+ std::string questDescription = quest->GetQuestDescription();
+ std::string portraitGiverText = quest->GetPortraitGiverText();
+ std::string portraitGiverName = quest->GetPortraitGiverName();
+ std::string portraitTurnInText = quest->GetPortraitTurnInText();
+ std::string portraitTurnInName = quest->GetPortraitTurnInName();
int32 locale = _session->GetSessionDbLocaleIndex();
if (locale >= 0)
{
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId()))
{
- ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle);
- ObjectMgr::GetLocaleString(localeData->Details, locale, questDetails);
- ObjectMgr::GetLocaleString(localeData->Objectives, locale, questObjectives);
- ObjectMgr::GetLocaleString(localeData->EndText, locale, questEndText);
- ObjectMgr::GetLocaleString(localeData->QuestGiverTextWindow, locale, questGiverTextWindow);
- ObjectMgr::GetLocaleString(localeData->QuestGiverTargetName, locale, questGiverTargetName);
- ObjectMgr::GetLocaleString(localeData->QuestTurnTextWindow, locale, questTurnTextWindow);
- ObjectMgr::GetLocaleString(localeData->QuestTurnTargetName, locale, questTurnTargetName);
+ ObjectMgr::GetLocaleString(localeData->LogTitle, locale, questLogTitle);
+ ObjectMgr::GetLocaleString(localeData->LogDescription, locale, questLogDescription);
+ ObjectMgr::GetLocaleString(localeData->QuestDescription, locale, questDescription);
+ ObjectMgr::GetLocaleString(localeData->PortraitGiverText, locale, portraitGiverText);
+ ObjectMgr::GetLocaleString(localeData->PortraitGiverName, locale, portraitGiverName);
+ ObjectMgr::GetLocaleString(localeData->PortraitTurnInText, locale, portraitTurnInText);
+ ObjectMgr::GetLocaleString(localeData->PortraitTurnInName, locale, portraitTurnInName);
}
}
if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
- AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
+ AddQuestLevelToTitle(questLogTitle, quest->GetQuestLevel());
WorldPacket data(SMSG_QUESTGIVER_QUEST_DETAILS, 100); // guess size
data << npcGUID;
data << _session->GetPlayer()->GetDivider();
data << uint32(quest->GetQuestId());
- data << questTitle;
- data << questDetails;
- data << questObjectives;
- data << questGiverTextWindow; // 4.x
- data << questGiverTargetName; // 4.x
- data << questTurnTextWindow; // 4.x
- data << questTurnTargetName; // 4.x
+ data << questLogTitle;
+ data << questLogDescription;
+ data << questDescription;
+ data << portraitGiverText; // 4.x
+ data << portraitGiverName; // 4.x
+ data << portraitTurnInText; // 4.x
+ data << portraitTurnInName; // 4.x
data << uint32(quest->GetQuestGiverPortrait()); // 4.x
data << uint32(quest->GetQuestTurnInPortrait()); // 4.x
data << uint8(activateAccept ? 1 : 0); // auto finish
@@ -435,7 +433,7 @@ void PlayerMenu::SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGU
data << uint32(quest->GetSuggestedPlayers());
data << uint8(0); // IsFinished? value is sent back to server in quest accept packet
data << uint8(0); // 4.x FIXME: Starts at AreaTrigger
- data << uint32(quest->GetRequiredSpell()); // 4.x
+ data << uint32(quest->GetSrcSpell()); // 4.x
quest->BuildExtraQuestInfo(data, _session->GetPlayer());
@@ -452,236 +450,196 @@ 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 questEndText = quest->GetEndText();
- 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];
+ std::string questLogTitle = quest->GetLogTitle();
+ std::string questLogDescription = quest->GetLogDescription();
+ std::string questDescription = quest->GetQuestDescription();
+ std::string questCompletionLog = quest->GetQuestCompletionLog();
+ std::string portraitGiverText = quest->GetPortraitGiverText();
+ std::string portraitGiverName = quest->GetPortraitGiverName();
+ std::string portraitTurnInText = quest->GetPortraitTurnInText();
+ std::string portraitTurnInName = quest->GetPortraitTurnInName();
+
+ QuestObjectives const& objectives = quest->GetObjectives();
+
+ std::vector<std::string> questObjectiveDescription(objectives.size());
+ for (uint8 i = 0; i < objectives.size(); ++i)
+ questObjectiveDescription[i] = objectives[i].Description;
int32 locale = _session->GetSessionDbLocaleIndex();
if (locale >= 0)
{
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId()))
{
- ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle);
- ObjectMgr::GetLocaleString(localeData->Details, locale, questDetails);
- ObjectMgr::GetLocaleString(localeData->Objectives, locale, questObjectives);
- ObjectMgr::GetLocaleString(localeData->EndText, locale, questEndText);
- ObjectMgr::GetLocaleString(localeData->CompletedText, locale, questCompletedText);
- ObjectMgr::GetLocaleString(localeData->QuestGiverTextWindow, locale, questGiverTextWindow);
- ObjectMgr::GetLocaleString(localeData->QuestGiverTargetName, locale, questGiverTargetName);
- ObjectMgr::GetLocaleString(localeData->QuestTurnTextWindow, locale, questTurnTextWindow);
- ObjectMgr::GetLocaleString(localeData->QuestTurnTargetName, locale, questTurnTargetName);
-
- for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ObjectMgr::GetLocaleString(localeData->ObjectiveText[i], locale, questObjectiveText[i]);
+ ObjectMgr::GetLocaleString(localeData->LogTitle, locale, questLogTitle);
+ ObjectMgr::GetLocaleString(localeData->LogDescription, locale, questLogDescription);
+ ObjectMgr::GetLocaleString(localeData->QuestDescription, locale, questDescription);
+ ObjectMgr::GetLocaleString(localeData->QuestCompletionLog, locale, questCompletionLog);
+ ObjectMgr::GetLocaleString(localeData->PortraitGiverText, locale, portraitGiverText);
+ ObjectMgr::GetLocaleString(localeData->PortraitGiverName, locale, portraitGiverName);
+ ObjectMgr::GetLocaleString(localeData->PortraitTurnInText, locale, portraitTurnInText);
+ ObjectMgr::GetLocaleString(localeData->PortraitTurnInName, locale, portraitTurnInName);
+
+ for (uint8 i = 0; i < objectives.size(); ++i)
+ ObjectMgr::GetLocaleString(localeData->ObjectiveDescription[i], locale, questObjectiveDescription[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
+ WorldPackets::Quest::QueryQuestInfoResponse packet;
- 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
+ packet.Allow = true;
+ packet.QuestID = quest->GetQuestId();
- data << uint32(quest->GetNextQuestInChain()); // client will request this quest from NPC, if not 0
- data << uint32(quest->GetXPId()); // used for calculating rewarded experience
+ packet.Info.QuestID = quest->GetQuestId();
+ packet.Info.QuestType = quest->GetQuestMethod();
+ packet.Info.QuestLevel = quest->GetQuestLevel();
+ packet.Info.QuestPackageID = quest->GetQuestPackageID();
+ packet.Info.QuestMinLevel = quest->GetMinLevel();
+ packet.Info.QuestSortID = quest->GetZoneOrSort();
+ packet.Info.QuestInfoID = quest->GetType(); // quest type
+ packet.Info.SuggestedGroupNum = quest->GetSuggestedPlayers();
+ packet.Info.RewardNextQuest = quest->GetNextQuestInChain();
+ packet.Info.RewardXPDifficulty = quest->GetXPDifficulty();
if (quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
- data << uint32(0); // Hide money rewarded
- else
- data << uint32(quest->GetRewOrReqMoney()); // 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);
- }
- else
+ packet.Info.RewardMoney = quest->GetRewMoney();
+
+ packet.Info.RewardMoneyDifficulty = quest->GetRewMoneyDifficulty();
+ packet.Info.RewardBonusMoney = quest->GetRewMoneyMaxLevel();
+ packet.Info.RewardDisplaySpell = quest->GetRewDisplaySpell();
+ packet.Info.RewardSpell = quest->GetRewSpell();
+
+ packet.Info.RewardHonor = quest->GetRewHonor();
+ packet.Info.RewardKillHonor = quest->GetRewKillHonor();
+
+ packet.Info.StartItem = quest->GetSrcItemId();
+ packet.Info.Flags = quest->GetFlags();
+ packet.Info.FlagsEx = quest->GetFlagsEx();
+ packet.Info.RewardTitle = quest->GetRewTitle();
+ packet.Info.RewardTalents = quest->GetBonusTalents();
+ packet.Info.RewardArenaPoints = quest->GetRewArenaPoints();
+ packet.Info.RewardSkillLineID = quest->GetRewardSkillId();
+ packet.Info.RewardNumSkillUps = quest->GetRewardSkillPoints();
+ packet.Info.RewardFactionFlags = quest->GetRewardReputationMask();
+ packet.Info.PortraitGiver = quest->GetQuestGiverPortrait();
+ packet.Info.PortraitTurnIn = quest->GetQuestTurnInPortrait();
+
+ if (!quest->HasFlag(QUEST_FLAGS_HIDDEN_REWARDS))
{
- for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
+ for (uint8 i = 0; i < QUEST_REWARD_ITEM_COUNT; ++i)
{
- data << uint32(quest->RewardItemId[i]);
- data << uint32(quest->RewardItemIdCount[i]);
+ packet.Info.RewardItems[i] = quest->RewardItemId[i];
+ packet.Info.RewardAmount[i] = quest->RewardItemCount[i];
}
for (uint8 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
{
- data << uint32(quest->RewardChoiceItemId[i]);
- data << uint32(quest->RewardChoiceItemCount[i]);
+ packet.Info.UnfilteredChoiceItems[i].ItemID = quest->RewardChoiceItemId[i];
+ packet.Info.UnfilteredChoiceItems[i].Quantity = quest->RewardChoiceItemCount[i];
}
}
- 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->GetPointMapId());
- data << float(quest->GetPointX());
- data << float(quest->GetPointY());
- data << uint32(quest->GetPointOpt());
-
- if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
- AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
-
- data << questTitle;
- data << questObjectives;
- data << questDetails;
- data << questEndText;
- data << questCompletedText;
-
- for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
+ for (uint8 i = 0; i < QUEST_REWARD_REPUTATIONS_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->RequiredSourceItemId[i]);
- data << uint32(quest->RequiredSourceItemCount[i]);
+ packet.Info.RewardFactionID[i] = quest->RewardFactionId[i];
+ packet.Info.RewardFactionValue[i] = quest->RewardFactionValue[i];
+ packet.Info.RewardFactionOverride[i] = quest->RewardFactionOverride[i];
}
- for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
+ packet.Info.POIContinent = quest->GetPOIContinent();
+ packet.Info.POIx = quest->GetPOIx();
+ packet.Info.POIy = quest->GetPOIy();
+ packet.Info.POIPriority = quest->GetPOIPriority();
+
+ if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
+ AddQuestLevelToTitle(questLogTitle, quest->GetQuestLevel());
+
+ packet.Info.LogTitle = questLogTitle;
+ packet.Info.LogDescription = questLogDescription;
+ packet.Info.QuestDescription = questDescription;
+ packet.Info.QuestCompletionLog = questCompletionLog;
+
+ for (uint32 i = 0; i < quest->Objectives.size(); ++i)
{
- data << uint32(quest->RequiredItemId[i]);
- data << uint32(quest->RequiredItemCount[i]);
+ packet.Info.Objectives.push_back(quest->Objectives[i]);
+ packet.Info.Objectives.back().Description = questObjectiveDescription[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]);
+ packet.Info.RewardCurrencyID[i] = quest->RewardCurrencyId[i];
+ packet.Info.RewardCurrencyQty[i] = quest->RewardCurrencyCount[i];
}
- for (uint32 i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i)
- {
- data << uint32(quest->RequiredCurrencyId[i]);
- data << uint32(quest->RequiredCurrencyCount[i]);
- }
+ packet.Info.PortraitGiverText = portraitGiverText;
+ packet.Info.PortraitGiverName = portraitGiverName;
+ packet.Info.PortraitTurnInText = portraitTurnInText;
+ packet.Info.PortraitTurnInName = portraitTurnInName;
- data << questGiverTextWindow;
- data << questGiverTargetName;
- data << questTurnTextWindow;
- data << questTurnTargetName;
- data << uint32(quest->GetSoundAccept());
- data << uint32(quest->GetSoundTurnIn());
+ packet.Info.AcceptedSoundKitID = quest->GetSoundAccept();
+ packet.Info.CompleteSoundKitID = quest->GetSoundTurnIn();
+ packet.Info.AreaGroupID = quest->GetAreaGroupID();
+ packet.Info.TimeAllowed = quest->GetLimitTime();
+
+ _session->SendPacket(packet.Write());
- _session->SendPacket(&data);
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUEST_QUERY_RESPONSE questid=%u", quest->GetQuestId());
}
void PlayerMenu::SendQuestGiverOfferReward(Quest const* quest, ObjectGuid npcGUID, bool enableNext) const
{
- std::string questTitle = quest->GetTitle();
+ std::string questTitle = quest->GetLogTitle();
std::string questOfferRewardText = quest->GetOfferRewardText();
- std::string questGiverTextWindow = quest->GetQuestGiverTextWindow();
- std::string questGiverTargetName = quest->GetQuestGiverTargetName();
- std::string questTurnTextWindow = quest->GetQuestTurnTextWindow();
- std::string questTurnTargetName = quest->GetQuestTurnTargetName();
+ std::string portraitGiverText = quest->GetPortraitGiverText();
+ std::string portraitGiverName = quest->GetPortraitGiverName();
+ std::string portraitTurnInText = quest->GetPortraitTurnInText();
+ std::string portraitTurnInName = quest->GetPortraitTurnInName();
int32 locale = _session->GetSessionDbLocaleIndex();
if (locale >= 0)
{
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId()))
{
- ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle);
+ ObjectMgr::GetLocaleString(localeData->LogTitle, locale, questTitle);
ObjectMgr::GetLocaleString(localeData->OfferRewardText, locale, questOfferRewardText);
- ObjectMgr::GetLocaleString(localeData->QuestGiverTextWindow, locale, questGiverTextWindow);
- ObjectMgr::GetLocaleString(localeData->QuestGiverTargetName, locale, questGiverTargetName);
- ObjectMgr::GetLocaleString(localeData->QuestTurnTextWindow, locale, questTurnTextWindow);
- ObjectMgr::GetLocaleString(localeData->QuestTurnTargetName, locale, questTurnTargetName);
+ ObjectMgr::GetLocaleString(localeData->PortraitGiverText, locale, portraitGiverText);
+ ObjectMgr::GetLocaleString(localeData->PortraitGiverName, locale, portraitGiverName);
+ ObjectMgr::GetLocaleString(localeData->PortraitTurnInText, locale, portraitTurnInText);
+ ObjectMgr::GetLocaleString(localeData->PortraitTurnInName, locale, portraitTurnInName);
}
}
if (sWorld->getBoolConfig(CONFIG_UI_QUESTLEVELS_IN_DIALOGS))
AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
- WorldPacket data(SMSG_QUESTGIVER_OFFER_REWARD, 50); // guess size
- data << npcGUID;
- data << uint32(quest->GetQuestId());
- data << questTitle;
- data << questOfferRewardText;
+ WorldPackets::Quest::QuestGiverOfferRewardMessage packet;
+ WorldPackets::Quest::QuestGiverOfferReward& offer = packet.QuestData;
- data << questGiverTextWindow;
- data << questGiverTargetName;
- data << questTurnTextWindow;
- data << questTurnTargetName;
- data << uint32(quest->GetQuestGiverPortrait());
- data << uint32(quest->GetQuestTurnInPortrait());
+ quest->BuildQuestRewards(offer.Rewards, _session->GetPlayer());
+ offer.QuestGiverGUID = npcGUID;
- data << uint8(enableNext ? 1 : 0); // Auto Finish
- data << uint32(quest->GetFlags()); // 3.3.3 questFlags
- data << uint32(quest->GetSuggestedPlayers()); // SuggestedGroupNum
+ // Is there a better way? what about game objects?
+ if (Creature const* creature = sObjectAccessor->GetCreature(*_session->GetPlayer(), npcGUID))
+ offer.QuestGiverCreatureID = creature->GetCreatureTemplate()->Entry;
- uint32 emoteCount = 0;
- for (uint8 i = 0; i < QUEST_EMOTE_COUNT; ++i)
- {
- if (quest->OfferRewardEmote[i] <= 0)
- break;
- ++emoteCount;
- }
+ offer.QuestID = quest->GetQuestId();
+ offer.AutoLaunched = enableNext;
+ offer.SuggestedPartyMembers = quest->GetSuggestedPlayers();
- data << emoteCount; // Emote Count
- for (uint8 i = 0; i < emoteCount; ++i)
- {
- data << uint32(quest->OfferRewardEmoteDelay[i]); // Delay Emote
- data << uint32(quest->OfferRewardEmote[i]);
- }
+ for (uint32 i = 0; i < QUEST_EMOTE_COUNT && quest->OfferRewardEmote[i]; ++i)
+ offer.Emotes.push_back(WorldPackets::Quest::QuestDescEmote(quest->OfferRewardEmote[i], quest->OfferRewardEmoteDelay[i]));
- quest->BuildExtraQuestInfo(data, _session->GetPlayer());
+ offer.QuestFlags[0] = quest->GetFlags();
+ offer.QuestFlags[1] = quest->GetFlagsEx();
- _session->SendPacket(&data);
+ packet.QuestTitle = questTitle;
+ packet.PortraitTurnIn = quest->GetQuestTurnInPortrait();
+ packet.PortraitGiver = quest->GetQuestGiverPortrait();
+ packet.PortraitGiverText = portraitGiverText;
+ packet.PortraitGiverName = portraitGiverName;
+ packet.PortraitTurnInText = portraitTurnInText;
+ packet.PortraitTurnInName = portraitTurnInName;
+ packet.QuestPackageID = quest->GetQuestPackageID();
+
+ _session->SendPacket(packet.Write());
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_OFFER_REWARD NPC=%s, questid=%u", npcGUID.ToString().c_str(), quest->GetQuestId());
}
@@ -690,7 +648,7 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU
// We can always call to RequestItems, but this packet only goes out if there are actually
// items. Otherwise, we'll skip straight to the OfferReward
- std::string questTitle = quest->GetTitle();
+ std::string questTitle = quest->GetLogTitle();
std::string requestItemsText = quest->GetRequestItemsText();
int32 locale = _session->GetSessionDbLocaleIndex();
@@ -698,12 +656,12 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU
{
if (QuestLocale const* localeData = sObjectMgr->GetQuestLocale(quest->GetQuestId()))
{
- ObjectMgr::GetLocaleString(localeData->Title, locale, questTitle);
+ ObjectMgr::GetLocaleString(localeData->LogTitle, locale, questTitle);
ObjectMgr::GetLocaleString(localeData->RequestItemsText, locale, requestItemsText);
}
}
- if (!quest->GetReqItemsCount() && canComplete)
+ if (!quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER) && canComplete)
{
SendQuestGiverOfferReward(quest, npcGUID, true);
return;
@@ -713,7 +671,7 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU
AddQuestLevelToTitle(questTitle, quest->GetQuestLevel());
WorldPacket data(SMSG_QUESTGIVER_REQUEST_ITEMS, 50); // guess size
- data << npcGUID;
+ /*data << npcGUID;
data << uint32(quest->GetQuestId());
data << questTitle;
data << requestItemsText;
@@ -735,16 +693,17 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU
data << uint32(quest->GetRewOrReqMoney() < 0 ? -quest->GetRewOrReqMoney() : 0);
data << uint32(quest->GetReqItemsCount());
- for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
+ for (QuestObjective const& obj : quest->Objectives)
{
- if (!quest->RequiredItemId[i])
+ if (obj.Type != QUEST_OBJECTIVE_ITEM)
continue;
- data << uint32(quest->RequiredItemId[i]);
- data << uint32(quest->RequiredItemCount[i]);
+ data << uint32(obj.ObjectID);
+ data << uint32(obj.Amount);
+
+ if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(obj.ObjectID))
+ data << uint32(itemTemplate->DisplayInfoID);
- if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->RequiredItemId[i]))
- data << uint32(/*itemTemplate->DisplayInfoID*/);
else
data << uint32(0);
}
@@ -767,7 +726,7 @@ void PlayerMenu::SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGU
data << uint32(0x04);
data << uint32(0x08);
data << uint32(0x10);
- data << uint32(0x40);
+ data << uint32(0x40);*/
_session->SendPacket(&data);
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTGIVER_REQUEST_ITEMS NPC=%s, questid=%u", npcGUID.ToString().c_str(), quest->GetQuestId());
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 67ff5377c3e..99b9cc42159 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -90,6 +90,7 @@
#include "ChatPackets.h"
#include "MovementPackets.h"
#include "ItemPackets.h"
+#include "QuestPackets.h"
#define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS)
@@ -4607,6 +4608,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt64(0, guid);
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES);
+ stmt->setUInt64(0, guid);
+ trans->Append(stmt);
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED);
stmt->setUInt64(0, guid);
trans->Append(stmt);
@@ -6717,7 +6722,7 @@ void Player::RewardReputation(Unit* victim, float rate)
// Calculate how many reputation points player gain with the quest
void Player::RewardReputation(Quest const* quest)
{
- for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
+ for (uint8 i = 0; i < QUEST_REWARD_REPUTATIONS_COUNT; ++i)
{
if (!quest->RewardFactionId[i])
continue;
@@ -6725,17 +6730,17 @@ void Player::RewardReputation(Quest const* quest)
int32 rep = 0;
bool noQuestBonus = false;
- if (quest->RewardFactionValueIdOverride[i])
+ if (quest->RewardFactionOverride[i])
{
- rep = quest->RewardFactionValueIdOverride[i] / 100;
+ rep = quest->RewardFactionOverride[i] / 100;
noQuestBonus = true;
}
else
{
- uint32 row = ((quest->RewardFactionValueId[i] < 0) ? 1 : 0) + 1;
+ uint32 row = ((quest->RewardFactionValue[i] < 0) ? 1 : 0) + 1;
if (QuestFactionRewEntry const* questFactionRewEntry = sQuestFactionRewardStore.LookupEntry(row))
{
- uint32 field = abs(quest->RewardFactionValueId[i]);
+ uint32 field = abs(quest->RewardFactionValue[i]);
rep = questFactionRewEntry->QuestRewFactionValue[field];
}
}
@@ -14377,47 +14382,44 @@ bool Player::CanCompleteQuest(uint32 quest_id)
if (q_status.Status == QUEST_STATUS_INCOMPLETE)
{
- if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER))
+ for (uint32 i = 0; i < qInfo->Objectives.size(); ++i)
{
- for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++)
- {
- if (qInfo->RequiredItemCount[i]!= 0 && q_status.ItemCount[i] < qInfo->RequiredItemCount[i])
- return false;
- }
- }
+ QuestObjective const& obj = qInfo->Objectives[i];
- if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_SPEAKTO))
- {
- for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
+ switch (obj.Type)
{
- if (qInfo->RequiredNpcOrGo[i] == 0)
- continue;
-
- if (qInfo->RequiredNpcOrGoCount[i] != 0 && q_status.CreatureOrGOCount[i] < qInfo->RequiredNpcOrGoCount[i])
+ case QUEST_OBJECTIVE_MONSTER:
+ case QUEST_OBJECTIVE_ITEM:
+ case QUEST_OBJECTIVE_GAMEOBJECT:
+ case QUEST_OBJECTIVE_PLAYERKILLS:
+ if (q_status.ObjectiveData[i] < obj.Amount)
+ return false;
+ break;
+ case QUEST_OBJECTIVE_MIN_REPUTATION:
+ if (GetReputationMgr().GetReputation(obj.ObjectID) < obj.Amount)
+ return false;
+ break;
+ case QUEST_OBJECTIVE_MAX_REPUTATION:
+ if (GetReputationMgr().GetReputation(obj.ObjectID) > obj.Amount)
+ return false;
+ break;
+ case QUEST_OBJECTIVE_MONEY:
+ if (!HasEnoughMoney(uint64(obj.Amount)))
+ return false;
+ break;
+ case QUEST_OBJECTIVE_AREATRIGGER:
+ if (!q_status.ObjectiveData[i])
+ return false;
+ break;
+ default:
+ TC_LOG_ERROR("entities.player.quest", "Player::CanCompleteQuest unknown objective type %u", obj.Type);
return false;
}
}
- if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL))
- if (qInfo->GetPlayersSlain() != 0 && q_status.PlayerCount < qInfo->GetPlayersSlain())
- return false;
-
- if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT) && !q_status.Explored)
- return false;
-
if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED) && q_status.Timer == 0)
return false;
- if (qInfo->GetRewOrReqMoney() < 0)
- {
- if (!HasEnoughMoney(-int64(qInfo->GetRewOrReqMoney())))
- return false;
- }
-
- uint32 repFacId = qInfo->GetRepObjectiveFaction();
- if (repFacId && GetReputationMgr().GetReputation(repFacId) < qInfo->GetRepObjectiveValue())
- return false;
-
return true;
}
}
@@ -14433,8 +14435,8 @@ bool Player::CanCompleteRepeatableQuest(Quest const* quest)
return false;
if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER))
- for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++)
- if (quest->RequiredItemId[i] && quest->RequiredItemCount[i] && !HasItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i]))
+ for (uint8 i = 0; i < quest->Objectives.size(); i++)
+ if (quest->Objectives[i].Type == QUEST_OBJECTIVE_ITEM && quest->Objectives[i].Amount && !HasItemCount(quest->Objectives[i].ObjectID, quest->Objectives[i].Amount))
return false;
if (!CanRewardQuest(quest, false))
@@ -14460,25 +14462,34 @@ bool Player::CanRewardQuest(Quest const* quest, bool msg)
// prevent receive reward with quest items in bank
if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER))
{
- for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++)
+ for (uint8 i = 0; i < quest->Objectives.size(); i++)
{
- if (quest->RequiredItemCount[i]!= 0 &&
- GetItemCount(quest->RequiredItemId[i]) < quest->RequiredItemCount[i])
+ if (quest->Objectives[i].Type != QUEST_OBJECTIVE_ITEM)
+ continue;
+
+ if (GetItemCount(quest->Objectives[i].ObjectID) < uint32(quest->Objectives[i].Amount))
{
if (msg)
- SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL, quest->RequiredItemId[i]);
+ SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL, quest->Objectives[i].ObjectID);
return false;
}
}
}
- for (uint8 i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; i++)
- if (quest->RequiredCurrencyId[i] && !HasCurrency(quest->RequiredCurrencyId[i], quest->RequiredCurrencyCount[i]))
- return false;
-
- // prevent receive reward with low money and GetRewOrReqMoney() < 0
- if (quest->GetRewOrReqMoney() < 0 && !HasEnoughMoney(-int64(quest->GetRewOrReqMoney())))
- return false;
+ for (QuestObjective const& obj : quest->Objectives)
+ {
+ switch (obj.Type)
+ {
+ case QUEST_OBJECTIVE_CURRENCY:
+ if (!HasCurrency(obj.ObjectID, obj.Amount))
+ return false;
+ break;
+ case QUEST_OBJECTIVE_MONEY:
+ if (!HasEnoughMoney(uint64(obj.Amount)))
+ return false;
+ break;
+ }
+ }
return true;
}
@@ -14507,9 +14518,9 @@ void Player::AddQuestAndCheckCompletion(Quest const* quest, Object* questGiver)
// destroy not required for quest finish quest starting item
bool destroyItem = true;
- for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
+ for (QuestObjective const& obj : quest->Objectives)
{
- if (quest->RequiredItemId[i] == item->GetEntry() && item->GetTemplate()->GetMaxCount() > 0)
+ if (obj.Type == QUEST_OBJECTIVE_ITEM && uint32(obj.ObjectID) == item->GetEntry() && item->GetTemplate()->GetMaxCount() > 0)
{
destroyItem = false;
break;
@@ -14556,7 +14567,7 @@ bool Player::CanRewardQuest(Quest const* quest, uint32 reward, bool msg)
{
if (quest->RewardItemId[i])
{
- InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, quest->RewardItemId[i], quest->RewardItemIdCount[i]);
+ InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, quest->RewardItemId[i], quest->RewardItemCount[i]);
if (res != EQUIP_ERR_OK)
{
SendEquipError(res, NULL, NULL, quest->RewardItemId[i]);
@@ -14583,33 +14594,16 @@ void Player::AddQuest(Quest const* quest, Object* questGiver)
// check for repeatable quests status reset
questStatusData.Status = QUEST_STATUS_INCOMPLETE;
- questStatusData.Explored = false;
-
- if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER))
- {
- for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
- questStatusData.ItemCount[i] = 0;
- }
-
- if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_SPEAKTO))
- {
- for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- questStatusData.CreatureOrGOCount[i] = 0;
- }
-
- if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL))
- questStatusData.PlayerCount = 0;
+
+ questStatusData.ObjectiveData.resize(quest->Objectives.size(), 0);
GiveQuestSourceItem(quest);
- AdjustQuestReqItemCount(quest, questStatusData);
-
- if (quest->GetRepObjectiveFaction())
- if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(quest->GetRepObjectiveFaction()))
- GetReputationMgr().SetVisible(factionEntry);
+ AdjustQuestReqItemCount(quest);
- if (quest->GetRepObjectiveFaction2())
- if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(quest->GetRepObjectiveFaction2()))
- GetReputationMgr().SetVisible(factionEntry);
+ for (QuestObjective const& obj : quest->Objectives)
+ if (obj.Type == QUEST_OBJECTIVE_MIN_REPUTATION || obj.Type == QUEST_OBJECTIVE_MAX_REPUTATION)
+ if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(obj.ObjectID))
+ GetReputationMgr().SetVisible(factionEntry);
uint32 qtime = 0;
if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED))
@@ -14698,6 +14692,24 @@ void Player::IncompleteQuest(uint32 quest_id)
}
}
+uint32 Player::GetQuestXPReward(Quest const* quest)
+{
+ bool rewarded = (m_RewardedQuests.find(quest->GetQuestId()) != m_RewardedQuests.end());
+
+ // Not give XP in case already completed once repeatable quest
+ if (rewarded && !quest->IsDFQuest())
+ return 0;
+
+ uint32 XP = quest->XPValue(getLevel()) * sWorld->getRate(RATE_XP_QUEST);
+
+ // handle SPELL_AURA_MOD_XP_QUEST_PCT auras
+ Unit::AuraEffectList const& ModXPPctAuras = GetAuraEffectsByType(SPELL_AURA_MOD_XP_QUEST_PCT);
+ for (Unit::AuraEffectList::const_iterator i = ModXPPctAuras.begin(); i != ModXPPctAuras.end(); ++i)
+ AddPct(XP, (*i)->GetAmount());
+
+ return XP;
+}
+
void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool announce)
{
//this THING should be here to protect code from quest, which cast on player far teleport as a reward
@@ -14706,20 +14718,25 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
uint32 quest_id = quest->GetQuestId();
- for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
- if (quest->RequiredItemId[i])
- DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true);
-
- for (uint8 i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i)
- if (quest->RequiredCurrencyId[i])
- ModifyCurrency(quest->RequiredCurrencyId[i], -int32(quest->RequiredCurrencyCount[i]));
+ for (QuestObjective const& obj : quest->Objectives)
+ {
+ switch (obj.Type)
+ {
+ case QUEST_OBJECTIVE_ITEM:
+ DestroyItemCount(obj.ObjectID, obj.Amount, true);
+ break;
+ case QUEST_OBJECTIVE_CURRENCY:
+ ModifyCurrency(obj.ObjectID, -int32(obj.Amount));
+ break;
+ }
+ }
- for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
+ for (uint8 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i)
{
- if (quest->RequiredSourceItemId[i])
+ if (quest->ItemDrop[i])
{
- uint32 count = quest->RequiredSourceItemCount[i];
- DestroyItemCount(quest->RequiredSourceItemId[i], count ? count : 9999, true);
+ uint32 count = quest->ItemDropQuantity[i];
+ DestroyItemCount(quest->ItemDrop[i], count ? count : 9999, true);
}
}
@@ -14745,13 +14762,13 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
if (uint32 itemId = quest->RewardItemId[i])
{
ItemPosCountVec dest;
- if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, quest->RewardItemIdCount[i]) == EQUIP_ERR_OK)
+ if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, quest->RewardItemCount[i]) == EQUIP_ERR_OK)
{
Item* item = StoreNewItem(dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId));
- SendNewItem(item, quest->RewardItemIdCount[i], true, false);
+ SendNewItem(item, quest->RewardItemCount[i], true, false);
}
else if (quest->IsDFQuest())
- SendItemRetrievalMail(quest->RewardItemId[i], quest->RewardItemIdCount[i]);
+ SendItemRetrievalMail(quest->RewardItemId[i], quest->RewardItemCount[i]);
}
}
}
@@ -14769,15 +14786,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
if (log_slot < MAX_QUEST_LOG_SIZE)
SetQuestSlot(log_slot, 0);
- bool rewarded = (m_RewardedQuests.find(quest_id) != m_RewardedQuests.end());
-
- // Not give XP in case already completed once repeatable quest
- uint32 XP = rewarded && !quest->IsDFQuest() ? 0 : uint32(quest->XPValue(this) * sWorld->getRate(RATE_XP_QUEST));
-
- // handle SPELL_AURA_MOD_XP_QUEST_PCT auras
- Unit::AuraEffectList const& ModXPPctAuras = GetAuraEffectsByType(SPELL_AURA_MOD_XP_QUEST_PCT);
- for (Unit::AuraEffectList::const_iterator i = ModXPPctAuras.begin(); i != ModXPPctAuras.end(); ++i)
- AddPct(XP, (*i)->GetAmount());
+ uint32 XP = GetQuestXPReward(quest);
int32 moneyRew = 0;
if (getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
@@ -14786,11 +14795,9 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
moneyRew = int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY));
if (Guild* guild = sGuildMgr->GetGuildById(GetGuildId()))
- guild->GiveXP(uint32(quest->XPValue(this) * sWorld->getRate(RATE_XP_QUEST) * sWorld->getRate(RATE_XP_GUILD_MODIFIER)), this);
+ guild->GiveXP(uint32(quest->XPValue(getLevel()) * sWorld->getRate(RATE_XP_QUEST) * sWorld->getRate(RATE_XP_GUILD_MODIFIER)), this);
- // Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative
- if (quest->GetRewOrReqMoney())
- moneyRew += quest->GetRewOrReqMoney();
+ moneyRew += quest->GetRewMoney();
if (moneyRew)
{
@@ -14805,9 +14812,9 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
RewardHonor(NULL, 0, honor);
// title reward
- if (quest->GetCharTitleId())
+ if (quest->GetRewTitle())
{
- if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(quest->GetCharTitleId()))
+ if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(quest->GetRewTitle()))
SetTitle(titleEntry);
}
@@ -14850,27 +14857,27 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
SendQuestReward(quest, XP);
// cast spells after mark quest complete (some spells have quest completed state requirements in spell_area data)
- if (quest->GetRewSpellCast() > 0)
+ if (quest->GetRewSpell() > 0)
{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetRewSpellCast());
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetRewSpell());
if (questGiver->isType(TYPEMASK_UNIT) && !spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_LEARN_SPELL) && !spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_CREATE_ITEM))
{
if (Creature* creature = GetMap()->GetCreature(questGiver->GetGUID()))
- creature->CastSpell(this, quest->GetRewSpellCast(), true);
+ creature->CastSpell(this, quest->GetRewSpell(), true);
}
else
- CastSpell(this, quest->GetRewSpellCast(), true);
+ CastSpell(this, quest->GetRewSpell(), true);
}
- else if (quest->GetRewSpell() > 0)
+ else if (quest->GetRewDisplaySpell() > 0)
{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetRewSpell());
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetRewDisplaySpell());
if (questGiver->isType(TYPEMASK_UNIT) && !spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_LEARN_SPELL) && !spellInfo->HasEffect(DIFFICULTY_NONE, SPELL_EFFECT_CREATE_ITEM))
{
if (Creature* creature = GetMap()->GetCreature(questGiver->GetGUID()))
- creature->CastSpell(this, quest->GetRewSpell(), true);
+ creature->CastSpell(this, quest->GetRewDisplaySpell(), true);
}
else
- CastSpell(this, quest->GetRewSpell(), true);
+ CastSpell(this, quest->GetRewDisplaySpell(), true);
}
if (quest->GetZoneOrSort() > 0)
@@ -14922,14 +14929,13 @@ void Player::FailQuest(uint32 questId)
SendQuestFailed(questId);
// Destroy quest items on quest failure.
- for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- if (quest->RequiredItemId[i] > 0 && quest->RequiredItemCount[i] > 0)
- // Destroy items received on starting the quest.
- DestroyItemCount(quest->RequiredItemId[i], quest->RequiredItemCount[i], true, true);
- for (uint8 i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
- if (quest->RequiredSourceItemId[i] > 0 && quest->RequiredSourceItemCount[i] > 0)
- // Destroy items received during the quest.
- DestroyItemCount(quest->RequiredSourceItemId[i], quest->RequiredSourceItemCount[i], true, true);
+ for (QuestObjective const& obj : quest->Objectives)
+ if (obj.Type == QUEST_OBJECTIVE_ITEM)
+ DestroyItemCount(obj.ObjectID, obj.Amount, true, true);
+ // Destroy items received during the quest.
+ for (uint8 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i)
+ if (quest->ItemDrop[i] && quest->ItemDropQuantity[i])
+ DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true, true);
}
}
@@ -15090,7 +15096,7 @@ bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg)
bool Player::SatisfyQuestClass(Quest const* qInfo, bool msg) const
{
- uint32 reqClass = qInfo->GetRequiredClasses();
+ uint32 reqClass = qInfo->GetAllowableClasses();
if (reqClass == 0)
return true;
@@ -15111,8 +15117,8 @@ bool Player::SatisfyQuestClass(Quest const* qInfo, bool msg) const
bool Player::SatisfyQuestRace(Quest const* qInfo, bool msg)
{
- uint32 reqraces = qInfo->GetRequiredRaces();
- if (reqraces == 0)
+ int32 reqraces = qInfo->GetAllowableRaces();
+ if (reqraces == -1)
return true;
if ((reqraces & getRaceMask()) == 0)
{
@@ -15151,6 +15157,7 @@ bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg)
return false;
}
+ /** @todo 6.x investigate if it's still needed
// ReputationObjective2 does not seem to be an objective requirement but a requirement
// to be able to accept the quest
uint32 fIdObj = qInfo->GetRepObjectiveFaction2();
@@ -15162,7 +15169,7 @@ bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg)
TC_LOG_DEBUG("misc", "SatisfyQuestReputation: Sent INVALIDREASON_DONT_HAVE_REQ (questId: %u) because player does not have required reputation (ReputationObjective2).", qInfo->GetQuestId());
}
return false;
- }
+ }**/
return true;
}
@@ -15417,9 +15424,10 @@ bool Player::TakeQuestSourceItem(uint32 questId, bool msg)
ASSERT(item);
bool destroyItem = true;
- for (uint8 n = 0; n < QUEST_ITEM_OBJECTIVES_COUNT; ++n)
- if (item->GetStartQuest() == questId && srcItemId == quest->RequiredItemId[n])
- destroyItem = false;
+ if (item->GetStartQuest() == questId)
+ for (QuestObjective const& obj : quest->Objectives)
+ if (obj.Type == QUEST_OBJECTIVE_ITEM && srcItemId == uint32(obj.ObjectID))
+ destroyItem = false;
if (destroyItem)
DestroyItemCount(srcItemId, count, true, true);
@@ -15650,27 +15658,25 @@ uint16 Player::GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry)
if (!qInfo)
return 0;
- for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j)
- if (qInfo->RequiredNpcOrGo[j] == entry)
- return m_QuestStatus[quest_id].CreatureOrGOCount[j];
+ for (uint8 j = 0; j < qInfo->Objectives.size(); ++j)
+ if (qInfo->Objectives[j].ObjectID == entry)
+ return GetQuestObjectiveData(qInfo, j);
return 0;
}
-void Player::AdjustQuestReqItemCount(Quest const* quest, QuestStatusData& questStatusData)
+void Player::AdjustQuestReqItemCount(Quest const* quest)
{
if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER))
{
- for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
+ for (uint8 i = 0; i < quest->Objectives.size(); ++i)
{
- uint32 reqitemcount = quest->RequiredItemCount[i];
- if (reqitemcount != 0)
- {
- uint32 curitemcount = GetItemCount(quest->RequiredItemId[i], true);
+ if (quest->Objectives[i].Type != QUEST_OBJECTIVE_ITEM)
+ continue;
- questStatusData.ItemCount[i] = std::min(curitemcount, reqitemcount);
- m_QuestStatusSave[quest->GetQuestId()] = QUEST_DEFAULT_SAVE_TYPE;
- }
+ uint32 reqItemCount = quest->Objectives[i].Amount;
+ uint32 curItemCount = GetItemCount(quest->Objectives[i].ObjectID, true);
+ SetQuestObjectiveData(quest, i, std::min(curItemCount, reqItemCount));
}
}
}
@@ -15755,13 +15761,18 @@ void Player::AreaExploredOrEventHappens(uint32 questId)
uint16 log_slot = FindQuestSlot(questId);
if (log_slot < MAX_QUEST_LOG_SIZE)
{
+ TC_LOG_ERROR("entities.player.quest", "Deprecated function AreaExploredOrEventHappens called for quest %u", questId);
+ /** @todo
+ This function was previously used for area triggers but now those are a part of quest objective system
+ Currently this function is used to complete quests with no objectives (needs verifying) so probably rename it?
+
QuestStatusData& q_status = m_QuestStatus[questId];
if (!q_status.Explored)
{
q_status.Explored = true;
m_QuestStatusSave[questId] = QUEST_DEFAULT_SAVE_TYPE;
- }
+ }**/
}
if (CanCompleteQuest(questId))
CompleteQuest(questId);
@@ -15803,23 +15814,28 @@ void Player::ItemAddedQuestCheck(uint32 entry, uint32 count)
if (!qInfo || !qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER))
continue;
- for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j)
+ for (uint8 j = 0; j < qInfo->Objectives.size(); ++j)
{
- uint32 reqitem = qInfo->RequiredItemId[j];
- if (reqitem == entry)
+ if (qInfo->Objectives[i].Type != QUEST_OBJECTIVE_ITEM)
+ continue;
+
+ uint32 reqItem = qInfo->Objectives[j].ObjectID;
+ if (reqItem == entry)
{
- uint32 reqitemcount = qInfo->RequiredItemCount[j];
- uint16 curitemcount = q_status.ItemCount[j];
- if (curitemcount < reqitemcount)
+ uint32 reqItemCount = qInfo->Objectives[j].Amount;
+ uint32 curItemCount = GetQuestObjectiveData(qInfo, j);
+ if (curItemCount < reqItemCount)
{
- q_status.ItemCount[j] = std::min<uint16>(q_status.ItemCount[j] + count, reqitemcount);
- m_QuestStatusSave[questid] = QUEST_DEFAULT_SAVE_TYPE;
+ uint32 newItemCount = std::min<uint32>(curItemCount + count, reqItemCount);
+ SetQuestObjectiveData(qInfo, j, newItemCount);
//SendQuestUpdateAddItem(qInfo, j, additemcount);
// FIXME: verify if there's any packet sent updating item
}
+
if (CanCompleteQuest(questid))
CompleteQuest(questid);
+
return;
}
}
@@ -15842,25 +15858,25 @@ void Player::ItemRemovedQuestCheck(uint32 entry, uint32 count)
if (!qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER))
continue;
- for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j)
+ for (uint8 j = 0; j < qInfo->Objectives.size(); ++j)
{
- uint32 reqitem = qInfo->RequiredItemId[j];
- if (reqitem == entry)
+ if (qInfo->Objectives[i].Type != QUEST_OBJECTIVE_ITEM)
+ continue;
+
+ uint32 reqItem = qInfo->Objectives[j].ObjectID;
+ if (reqItem == entry)
{
- QuestStatusData& q_status = m_QuestStatus[questid];
+ uint32 reqItemCount = qInfo->Objectives[j].Amount;
+ uint16 curItemCount = GetQuestObjectiveData(qInfo, j);
- uint32 reqitemcount = qInfo->RequiredItemCount[j];
- uint16 curitemcount = q_status.ItemCount[j];
+ if (curItemCount >= reqItemCount) // we may have more than what the status shows
+ curItemCount = GetItemCount(entry, false);
- if (q_status.ItemCount[j] >= reqitemcount) // we may have more than what the status shows
- curitemcount = GetItemCount(entry, false);
+ uint16 newItemCount = (count > curItemCount) ? 0 : curItemCount - count;
- uint16 newItemCount = (count > curitemcount) ? 0 : curitemcount - count;
- newItemCount = std::min<uint16>(newItemCount, reqitemcount);
- if (newItemCount != q_status.ItemCount[j])
+ if (newItemCount < reqItemCount)
{
- q_status.ItemCount[j] = newItemCount;
- m_QuestStatusSave[questid] = QUEST_DEFAULT_SAVE_TYPE;
+ SetQuestObjectiveData(qInfo, j, newItemCount);
IncompleteQuest(questid);
}
return;
@@ -15884,7 +15900,7 @@ void Player::KilledMonster(CreatureTemplate const* cInfo, ObjectGuid guid)
void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::Empty*/)
{
- uint16 addkillcount = 1;
+ uint16 addKillCount = 1;
uint32 real_entry = entry;
Creature* killed = NULL;
if (!guid.IsEmpty())
@@ -15895,7 +15911,7 @@ void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::E
}
StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_CREATURE, real_entry); // MUST BE CALLED FIRST
- UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, real_entry, addkillcount, 0, killed);
+ UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, real_entry, addKillCount, 0, killed);
for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
{
@@ -15912,26 +15928,23 @@ void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::E
{
if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL) /*&& !qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_CAST)*/)
{
- for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j)
+ for (uint8 j = 0; j < qInfo->Objectives.size(); ++j)
{
- // skip GO activate objective or none
- if (qInfo->RequiredNpcOrGo[j] <= 0)
+ if (qInfo->Objectives[j].Type != QUEST_OBJECTIVE_MONSTER)
continue;
- uint32 reqkill = qInfo->RequiredNpcOrGo[j];
+ uint32 reqkill = qInfo->Objectives[j].ObjectID;
if (reqkill == real_entry)
{
- uint32 reqkillcount = qInfo->RequiredNpcOrGoCount[j];
- uint16 curkillcount = q_status.CreatureOrGOCount[j];
- if (curkillcount < reqkillcount)
+ uint32 reqKillCount = qInfo->Objectives[j].Amount;
+ uint16 curKillCount = GetQuestObjectiveData(qInfo, j);
+ if (curKillCount < reqKillCount)
{
- q_status.CreatureOrGOCount[j] = curkillcount + addkillcount;
-
- m_QuestStatusSave[questid] = QUEST_DEFAULT_SAVE_TYPE;
-
- SendQuestUpdateAddCreatureOrGo(qInfo, guid, j, curkillcount, addkillcount);
+ SetQuestObjectiveData(qInfo, j, curKillCount + addKillCount);
+ SendQuestUpdateAddCredit(qInfo, guid, j, curKillCount + addKillCount);
}
+
if (CanCompleteQuest(questid))
CompleteQuest(questid);
@@ -15946,7 +15959,7 @@ void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::E
void Player::KilledPlayerCredit()
{
- uint16 addkillcount = 1;
+ uint16 addKillCount = 1;
for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
{
@@ -15957,27 +15970,31 @@ void Player::KilledPlayerCredit()
Quest const* qInfo = sObjectMgr->GetQuestTemplate(questid);
if (!qInfo)
continue;
+
+ // This flag is only used for performance optimisation to prevent iterating over all quests
+ if (!qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL))
+ continue;
+
// just if !ingroup || !noraidgroup || raidgroup
QuestStatusData& q_status = m_QuestStatus[questid];
if (q_status.Status == QUEST_STATUS_INCOMPLETE && (!GetGroup() || !GetGroup()->isRaidGroup() || qInfo->IsAllowedInRaid(GetMap()->GetDifficulty())))
{
- if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL))
+ for (uint32 i = 0; i < qInfo->Objectives.size(); ++i)
{
- uint32 reqkill = qInfo->GetPlayersSlain();
- uint16 curkill = q_status.PlayerCount;
+ if (qInfo->Objectives[i].Type != QUEST_OBJECTIVE_PLAYERKILLS)
+ continue;
- if (curkill < reqkill)
+ uint32 curKillCount = GetQuestObjectiveData(qInfo, i);
+ if (curKillCount < uint32(qInfo->Objectives[i].Amount))
{
- q_status.PlayerCount = curkill + addkillcount;
-
- m_QuestStatusSave[questid] = QUEST_DEFAULT_SAVE_TYPE;
-
- SendQuestUpdateAddPlayer(qInfo, curkill, addkillcount);
+ SetQuestObjectiveData(qInfo, i, curKillCount + addKillCount);
+ SendQuestUpdateAddPlayer(qInfo, curKillCount + addKillCount, qInfo->Objectives[i].Amount);
}
if (CanCompleteQuest(questid))
CompleteQuest(questid);
+ // Quest can't have more than one player kill objective (code optimisation)
break;
}
}
@@ -16003,28 +16020,23 @@ void Player::KillCreditGO(uint32 entry, ObjectGuid guid)
{
if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_CAST) /*&& !qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL)*/)
{
- for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j)
+ for (uint8 j = 0; j < qInfo->Objectives.size(); ++j)
{
- uint32 reqTarget = 0;
+ if (qInfo->Objectives[j].Type != QUEST_OBJECTIVE_GAMEOBJECT)
+ continue;
- // GO activate objective
- if (qInfo->RequiredNpcOrGo[j] < 0)
- // checked at quest_template loading
- reqTarget = - qInfo->RequiredNpcOrGo[j];
+ uint32 reqTarget = qInfo->Objectives[j].ObjectID;
// other not this creature/GO related objectives
if (reqTarget != entry)
continue;
- uint32 reqCastCount = qInfo->RequiredNpcOrGoCount[j];
- uint16 curCastCount = q_status.CreatureOrGOCount[j];
+ uint32 reqCastCount = qInfo->Objectives[j].Amount;
+ uint32 curCastCount = GetQuestObjectiveData(qInfo, j);
if (curCastCount < reqCastCount)
{
- q_status.CreatureOrGOCount[j] = curCastCount + addCastCount;
-
- m_QuestStatusSave[questid] = QUEST_DEFAULT_SAVE_TYPE;
-
- SendQuestUpdateAddCreatureOrGo(qInfo, guid, j, curCastCount, addCastCount);
+ SetQuestObjectiveData(qInfo, j, curCastCount + addCastCount);
+ SendQuestUpdateAddCredit(qInfo, guid, j, curCastCount + addCastCount);
}
if (CanCompleteQuest(questid))
@@ -16057,37 +16069,28 @@ void Player::TalkedToCreature(uint32 entry, ObjectGuid guid)
{
if (qInfo->HasSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_SPEAKTO))
{
- for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j)
+ for (uint8 j = 0; j < qInfo->Objectives.size(); ++j)
{
- // skip gameobject objectives
- if (qInfo->RequiredNpcOrGo[j] < 0)
+ if (qInfo->Objectives[j].Type != QUEST_OBJECTIVE_TALKTO)
continue;
- uint32 reqTarget = 0;
-
- if (qInfo->RequiredNpcOrGo[j] > 0) // creature activate objectives
- // checked at quest_template loading
- reqTarget = qInfo->RequiredNpcOrGo[j];
- else
- continue;
+ uint32 reqTarget = qInfo->Objectives[j].ObjectID;
if (reqTarget == entry)
{
- uint32 reqTalkCount = qInfo->RequiredNpcOrGoCount[j];
- uint16 curTalkCount = q_status.CreatureOrGOCount[j];
+ uint32 reqTalkCount = qInfo->Objectives[j].Amount;
+ uint32 curTalkCount = GetQuestObjectiveData(qInfo, j);
if (curTalkCount < reqTalkCount)
{
- q_status.CreatureOrGOCount[j] = curTalkCount + addTalkCount;
-
- m_QuestStatusSave[questid] = QUEST_DEFAULT_SAVE_TYPE;
-
- SendQuestUpdateAddCreatureOrGo(qInfo, guid, j, curTalkCount, addTalkCount);
+ SetQuestObjectiveData(qInfo, j, curTalkCount + addTalkCount);
+ SendQuestUpdateAddCredit(qInfo, guid, j, curTalkCount + addTalkCount);
}
+
if (CanCompleteQuest(questid))
CompleteQuest(questid);
- // same objective target can be in many active quests, but not in 2 objectives for single quest (code optimization).
- continue;
+ // Quest can't have more than one objective for the same creature (code optimisation)
+ break;
}
}
}
@@ -16104,13 +16107,19 @@ void Player::MoneyChanged(uint32 count)
continue;
Quest const* qInfo = sObjectMgr->GetQuestTemplate(questid);
- if (qInfo && qInfo->GetRewOrReqMoney() < 0)
+ if (!qInfo)
+ continue;
+
+ for (QuestObjective const& obj : qInfo->GetObjectives())
{
+ if (obj.Type != QUEST_OBJECTIVE_MONEY)
+ continue;
+
QuestStatusData& q_status = m_QuestStatus[questid];
if (q_status.Status == QUEST_STATUS_INCOMPLETE)
{
- if (int32(count) >= -qInfo->GetRewOrReqMoney())
+ if (int32(count) >= obj.Amount)
{
if (CanCompleteQuest(questid))
CompleteQuest(questid);
@@ -16118,7 +16127,7 @@ void Player::MoneyChanged(uint32 count)
}
else if (q_status.Status == QUEST_STATUS_COMPLETE)
{
- if (int32(count) < -qInfo->GetRewOrReqMoney())
+ if (int32(count) < obj.Amount)
IncompleteQuest(questid);
}
}
@@ -16133,47 +16142,40 @@ void Player::ReputationChanged(FactionEntry const* factionEntry)
{
if (Quest const* qInfo = sObjectMgr->GetQuestTemplate(questid))
{
- if (qInfo->GetRepObjectiveFaction() == factionEntry->ID)
- {
- QuestStatusData& q_status = m_QuestStatus[questid];
- if (q_status.Status == QUEST_STATUS_INCOMPLETE)
- {
- if (GetReputationMgr().GetReputation(factionEntry) >= qInfo->GetRepObjectiveValue())
- if (CanCompleteQuest(questid))
- CompleteQuest(questid);
- }
- else if (q_status.Status == QUEST_STATUS_COMPLETE)
- {
- if (GetReputationMgr().GetReputation(factionEntry) < qInfo->GetRepObjectiveValue())
- IncompleteQuest(questid);
- }
- }
- }
- }
- }
-}
+ QuestStatusData& q_status = m_QuestStatus[questid];
-void Player::ReputationChanged2(FactionEntry const* factionEntry)
-{
- for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
- {
- if (uint32 questid = GetQuestSlotQuestId(i))
- {
- if (Quest const* qInfo = sObjectMgr->GetQuestTemplate(questid))
- {
- if (qInfo->GetRepObjectiveFaction2() == factionEntry->ID)
+ for (QuestObjective const& obj : qInfo->Objectives)
{
- QuestStatusData& q_status = m_QuestStatus[questid];
- if (q_status.Status == QUEST_STATUS_INCOMPLETE)
+ if (uint32(obj.ObjectID) != factionEntry->ID)
+ continue;
+
+ if (obj.Type == QUEST_OBJECTIVE_MIN_REPUTATION)
{
- if (GetReputationMgr().GetReputation(factionEntry) >= qInfo->GetRepObjectiveValue2())
- if (CanCompleteQuest(questid))
- CompleteQuest(questid);
+ if (q_status.Status == QUEST_STATUS_INCOMPLETE)
+ {
+ if (GetReputationMgr().GetReputation(factionEntry) >= obj.Amount)
+ if (CanCompleteQuest(questid))
+ CompleteQuest(questid);
+ }
+ else if (q_status.Status == QUEST_STATUS_COMPLETE)
+ {
+ if (GetReputationMgr().GetReputation(factionEntry) < obj.Amount)
+ IncompleteQuest(questid);
+ }
}
- else if (q_status.Status == QUEST_STATUS_COMPLETE)
+ else if (obj.Type == QUEST_OBJECTIVE_MAX_REPUTATION)
{
- if (GetReputationMgr().GetReputation(factionEntry) < qInfo->GetRepObjectiveValue2())
- IncompleteQuest(questid);
+ if (q_status.Status == QUEST_STATUS_INCOMPLETE)
+ {
+ if (GetReputationMgr().GetReputation(factionEntry) <= obj.Amount)
+ if (CanCompleteQuest(questid))
+ CompleteQuest(questid);
+ }
+ else if (q_status.Status == QUEST_STATUS_COMPLETE)
+ {
+ if (GetReputationMgr().GetReputation(factionEntry) > obj.Amount)
+ IncompleteQuest(questid);
+ }
}
}
}
@@ -16197,38 +16199,38 @@ bool Player::HasQuestForItem(uint32 itemid) const
if (q_status.Status == QUEST_STATUS_INCOMPLETE)
{
- Quest const* qinfo = sObjectMgr->GetQuestTemplate(questid);
- if (!qinfo)
+ Quest const* qInfo = sObjectMgr->GetQuestTemplate(questid);
+ if (!qInfo)
continue;
// hide quest if player is in raid-group and quest is no raid quest
- if (GetGroup() && GetGroup()->isRaidGroup() && !qinfo->IsAllowedInRaid(GetMap()->GetDifficulty()))
+ if (GetGroup() && GetGroup()->isRaidGroup() && !qInfo->IsAllowedInRaid(GetMap()->GetDifficulty()))
if (!InBattleground()) //there are two ways.. we can make every bg-quest a raidquest, or add this code here.. i don't know if this can be exploited by other quests, but i think all other quests depend on a specific area.. but keep this in mind, if something strange happens later
continue;
// There should be no mixed ReqItem/ReqSource drop
// This part for ReqItem drop
- for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j)
+ for (uint8 j = 0; j < qInfo->Objectives.size(); ++j)
{
- if (itemid == qinfo->RequiredItemId[j] && q_status.ItemCount[j] < qinfo->RequiredItemCount[j])
+ if (qInfo->Objectives[i].Type == QUEST_OBJECTIVE_ITEM && itemid == uint32(qInfo->Objectives[i].ObjectID) && q_status.ObjectiveData[j] < qInfo->Objectives[j].Amount)
return true;
}
// This part - for ReqSource
- for (uint8 j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j)
+ for (uint8 j = 0; j < QUEST_ITEM_DROP_COUNT; ++j)
{
// examined item is a source item
- if (qinfo->RequiredSourceItemId[j] == itemid)
+ if (qInfo->ItemDrop[j] == itemid)
{
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
// 'unique' item
- if (pProto->GetMaxCount() && int32(GetItemCount(itemid, true)) < pProto->GetMaxCount())
+ if (pProto->GetMaxCount() && GetItemCount(itemid, true) < pProto->GetMaxCount())
return true;
// allows custom amount drop when not 0
- if (qinfo->RequiredSourceItemCount[j])
+ if (qInfo->ItemDropQuantity[j])
{
- if (GetItemCount(itemid, true) < qinfo->RequiredSourceItemCount[j])
+ if (GetItemCount(itemid, true) < qInfo->ItemDropQuantity[j])
return true;
} else if (GetItemCount(itemid, true) < pProto->GetMaxStackSize())
return true;
@@ -16239,6 +16241,61 @@ bool Player::HasQuestForItem(uint32 itemid) const
return false;
}
+int32 Player::GetQuestObjectiveData(Quest const* quest, uint32 objective) const
+{
+ auto itr = m_QuestStatus.find(quest->GetQuestId());
+
+ if (itr == m_QuestStatus.end())
+ {
+ TC_LOG_ERROR("entities.player.quest", "GetQuestObjectiveData: player %s (%s) doesn't have quest status data for quest %u", GetName().c_str(), GetGUID().ToString().c_str(), quest->GetQuestId());
+ return 0;
+ }
+
+ QuestStatusData const& status = itr->second;
+
+ if (objective >= status.ObjectiveData.size())
+ {
+ TC_LOG_ERROR("entities.player.quest", "GetQuestObjectiveData: player %s (%s) quest %u out of range objective index %u", GetName().c_str(), GetGUID().ToString().c_str(), quest->GetQuestId(), objective);
+ return 0;
+ }
+
+ return status.ObjectiveData[objective];
+}
+
+void Player::SetQuestObjectiveData(Quest const* quest, uint32 objective, int32 data)
+{
+ auto itr = m_QuestStatus.find(quest->GetQuestId());
+
+ if (itr == m_QuestStatus.end())
+ {
+ TC_LOG_ERROR("entities.player.quest", "SetQuestObjectiveData: player %s (%s) doesn't have quest status data for quest %u", GetName().c_str(), GetGUID().ToString().c_str(), quest->GetQuestId());
+ return;
+ }
+
+ QuestStatusData& status = itr->second;
+
+ if (objective >= status.ObjectiveData.size())
+ {
+ TC_LOG_ERROR("entities.player.quest", "SetQuestObjectiveData: player %s (%s) quest %u out of range objective index %u", GetName().c_str(), GetGUID().ToString().c_str(), quest->GetQuestId(), objective);
+ return;
+ }
+
+ // No change
+ if (status.ObjectiveData[objective] == data)
+ return;
+
+ // Set data
+ status.ObjectiveData[objective] = data;
+
+ // Add to save
+ m_QuestStatusSave[quest->GetQuestId()] = QUEST_DEFAULT_SAVE_TYPE;
+
+ // Update quest fields
+ uint16 log_slot = FindQuestSlot(quest->GetQuestId());
+ if (log_slot < MAX_QUEST_LOG_SIZE)
+ SetQuestSlotCounter(log_slot, objective, status.ObjectiveData[objective]);
+}
+
void Player::SendQuestComplete(Quest const* quest)
{
if (quest)
@@ -16262,28 +16319,29 @@ void Player::SendQuestReward(Quest const* quest, uint32 XP)
if (getLevel() < sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
{
xp = XP;
- moneyReward = quest->GetRewOrReqMoney();
+ moneyReward = quest->GetRewMoney();
}
else // At max level, increase gold reward
{
xp = 0;
- moneyReward = uint32(quest->GetRewOrReqMoney() + int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY)));
+ moneyReward = uint32(quest->GetRewMoney() + int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY)));
}
- WorldPacket data(SMSG_QUESTGIVER_QUEST_COMPLETE, (4+4+4+4+4));
-
- data << uint32(quest->GetBonusTalents()); // bonus talents (not verified for 4.x)
- data << uint32(quest->GetRewardSkillPoints()); // 4.x bonus skill points
- data << uint32(moneyReward);
- data << uint32(xp);
- data << uint32(questId);
- data << uint32(quest->GetRewardSkillId()); // 4.x bonus skill id
-
- data.WriteBit(0); // FIXME: unknown bits, common values sent
- data.WriteBit(1);
- data.FlushBits();
+ WorldPackets::Quest::QuestGiverQuestComplete packet;
+
+ packet.QuestID = questId;
+ packet.MoneyReward = moneyReward;
+ packet.XPReward = xp;
+ packet.SkillLineIDReward = quest->GetRewardSkillId();
+ packet.NumSkillUpsReward = quest->GetRewardSkillPoints();
+ packet.TalentReward = quest->GetBonusTalents();
+
+ // @todo fix these 3
+ packet.UseQuestReward = true;
+ packet.LaunchGossip = true;
+ //packet.ItemReward
- GetSession()->SendPacket(&data);
+ GetSession()->SendPacket(packet.Write());
}
void Player::SendQuestFailed(uint32 questId, InventoryResult reason)
@@ -16321,12 +16379,12 @@ void Player::SendQuestConfirmAccept(const Quest* quest, Player* pReceiver)
{
if (pReceiver)
{
- std::string strTitle = quest->GetTitle();
+ std::string strTitle = quest->GetLogTitle();
int loc_idx = pReceiver->GetSession()->GetSessionDbLocaleIndex();
if (loc_idx >= 0)
if (const QuestLocale* pLocale = sObjectMgr->GetQuestLocale(quest->GetQuestId()))
- ObjectMgr::GetLocaleString(pLocale->Title, loc_idx, strTitle);
+ ObjectMgr::GetLocaleString(pLocale->LogTitle, loc_idx, strTitle);
WorldPacket data(SMSG_QUEST_CONFIRM_ACCEPT, (4 + strTitle.size() + 8));
data << uint32(quest->GetQuestId());
@@ -16350,43 +16408,26 @@ void Player::SendPushToPartyResponse(Player* player, uint8 msg)
}
}
-void Player::SendQuestUpdateAddCreatureOrGo(Quest const* quest, ObjectGuid guid, uint32 creatureOrGO_idx, uint16 old_count, uint16 add_count)
+void Player::SendQuestUpdateAddCredit(Quest const* quest, ObjectGuid guid, uint32 objective, uint16 count)
{
- ASSERT(old_count + add_count < 65536 && "mob/GO count store in 16 bits 2^16 = 65536 (0..65536)");
-
- int32 entry = quest->RequiredNpcOrGo[creatureOrGO_idx];
- if (entry < 0)
- // client expected gameobject template id in form (id|0x80000000)
- entry = (-entry) | 0x80000000;
-
- WorldPacket data(SMSG_QUESTUPDATE_ADD_KILL, (4*4+8));
- TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTUPDATE_ADD_KILL");
- data << uint32(quest->GetQuestId());
- data << uint32(entry);
- data << uint32(old_count + add_count);
- data << uint32(quest->RequiredNpcOrGoCount[ creatureOrGO_idx ]);
- data << guid;
- GetSession()->SendPacket(&data);
-
- uint16 log_slot = FindQuestSlot(quest->GetQuestId());
- if (log_slot < MAX_QUEST_LOG_SIZE)
- SetQuestSlotCounter(log_slot, creatureOrGO_idx, GetQuestSlotCounter(log_slot, creatureOrGO_idx) + add_count);
+ WorldPackets::Quest::QuestUpdateAddCredit packet;
+ packet.VictimGUID = guid;
+ packet.QuestID = quest->GetQuestId();
+ packet.ObjectID = quest->Objectives[objective].ObjectID;
+ packet.Count = count;
+ packet.Required = quest->Objectives[objective].Amount;
+ packet.ObjectiveType = quest->Objectives[objective].Type;
+ GetSession()->SendPacket(packet.Write());
}
-void Player::SendQuestUpdateAddPlayer(Quest const* quest, uint16 old_count, uint16 add_count)
+void Player::SendQuestUpdateAddPlayer(Quest const* quest, uint16 newCount, uint32 required)
{
- ASSERT(old_count + add_count < 65536 && "player count store in 16 bits");
-
WorldPacket data(SMSG_QUESTUPDATE_ADD_PVP_KILL, (3*4));
TC_LOG_DEBUG("network", "WORLD: Sent SMSG_QUESTUPDATE_ADD_PVP_KILL");
data << uint32(quest->GetQuestId());
- data << uint32(old_count + add_count);
- data << uint32(quest->GetPlayersSlain());
+ data << uint32(newCount);
+ data << uint32(required);
GetSession()->SendPacket(&data);
-
- uint16 log_slot = FindQuestSlot(quest->GetQuestId());
- if (log_slot < MAX_QUEST_LOG_SIZE)
- SetQuestSlotCounter(log_slot, QUEST_PVP_KILL_SLOT, GetQuestSlotCounter(log_slot, QUEST_PVP_KILL_SLOT) + add_count);
}
bool Player::HasPvPForcingQuest() const
@@ -17147,6 +17188,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
// after spell load, learn rewarded spell if need also
_LoadQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS));
+ _LoadQuestStatusObjectives(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES));
_LoadQuestStatusRewarded(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW));
_LoadDailyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS));
_LoadWeeklyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS));
@@ -17964,10 +18006,8 @@ void Player::_LoadQuestStatus(PreparedQueryResult result)
{
uint16 slot = 0;
- //// 0 1 2 3 4 5 6 7 8 9 10
- //QueryResult* result = CharacterDatabase.PQuery("SELECT quest, status, explored, timer, mobcount1, mobcount2, mobcount3, mobcount4, itemcount1, itemcount2, itemcount3,
- // 11 12
- // itemcount4, playercount FROM character_queststatus WHERE guid = '%u'", GetGUIDLow());
+ //// 0 1 2
+ //QueryResult* result = CharacterDatabase.PQuery("SELECT quest, status, timer WHERE guid = '%u'", GetGUIDLow());
if (result)
{
@@ -17993,9 +18033,7 @@ void Player::_LoadQuestStatus(PreparedQueryResult result)
GetName().c_str(), GetGUID().ToString().c_str(), quest_id, qstatus);
}
- questStatusData.Explored = (fields[2].GetUInt8() > 0);
-
- time_t quest_time = time_t(fields[3].GetUInt32());
+ time_t quest_time = time_t(fields[2].GetUInt32());
if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED) && !GetQuestRewardStatus(quest_id))
{
@@ -18009,16 +18047,6 @@ void Player::_LoadQuestStatus(PreparedQueryResult result)
else
quest_time = 0;
- questStatusData.CreatureOrGOCount[0] = fields[4].GetUInt16();
- questStatusData.CreatureOrGOCount[1] = fields[5].GetUInt16();
- questStatusData.CreatureOrGOCount[2] = fields[6].GetUInt16();
- questStatusData.CreatureOrGOCount[3] = fields[7].GetUInt16();
- questStatusData.ItemCount[0] = fields[8].GetUInt16();
- questStatusData.ItemCount[1] = fields[9].GetUInt16();
- questStatusData.ItemCount[2] = fields[10].GetUInt16();
- questStatusData.ItemCount[3] = fields[11].GetUInt16();
- questStatusData.PlayerCount = fields[12].GetUInt16();
-
// add to quest log
if (slot < MAX_QUEST_LOG_SIZE && questStatusData.Status != QUEST_STATUS_NONE)
{
@@ -18029,16 +18057,12 @@ void Player::_LoadQuestStatus(PreparedQueryResult result)
else if (questStatusData.Status == QUEST_STATUS_FAILED)
SetQuestSlotState(slot, QUEST_STATE_FAIL);
- for (uint8 idx = 0; idx < QUEST_OBJECTIVES_COUNT; ++idx)
- if (questStatusData.CreatureOrGOCount[idx])
- SetQuestSlotCounter(slot, idx, questStatusData.CreatureOrGOCount[idx]);
-
- if (questStatusData.PlayerCount)
- SetQuestSlotCounter(slot, QUEST_PVP_KILL_SLOT, questStatusData.PlayerCount);
-
++slot;
}
+ // Resize quest objective data to proper size
+ questStatusData.ObjectiveData.resize(quest->GetObjectives().size());
+
TC_LOG_DEBUG("entities.player.loading", "Quest status is {%u} for quest {%u} for player (%s)", questStatusData.Status, quest_id, GetGUID().ToString().c_str());
}
}
@@ -18050,6 +18074,43 @@ void Player::_LoadQuestStatus(PreparedQueryResult result)
SetQuestSlot(i, 0);
}
+void Player::_LoadQuestStatusObjectives(PreparedQueryResult result)
+{
+ uint16 slot = 0;
+
+ //// 0 1 2
+ //QueryResult* result = CharacterDatabase.PQuery("SELECT quest, objective, data WHERE guid = '%u'", GetGUIDLow());
+
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 questID = fields[0].GetUInt32();
+
+ auto itr = m_QuestStatus.find(questID);
+ if (itr != m_QuestStatus.end())
+ {
+ QuestStatusData& questStatusData = itr->second;
+ uint8 objectiveIndex = fields[1].GetUInt8();
+
+ if (objectiveIndex < questStatusData.ObjectiveData.size())
+ {
+ int32 data = fields[2].GetInt32();
+ questStatusData.ObjectiveData[objectiveIndex] = data;
+ SetQuestSlotCounter(slot, objectiveIndex, data);
+ }
+ else
+ TC_LOG_ERROR("entities.player", "Player %s (%s) has quest %d out of range objective index %u.", GetName().c_str(), GetGUID().ToString().c_str(), questID, objectiveIndex);
+ }
+ else
+ TC_LOG_ERROR("entities.player", "Player %s (%s) does not have quest %d but has objective data for it.", GetName().c_str(), GetGUID().ToString().c_str(), questID);
+ }
+ while (result->NextRow());
+ }
+}
+
void Player::_LoadQuestStatusRewarded(PreparedQueryResult result)
{
// SELECT quest FROM character_queststatus_rewarded WHERE guid = ?
@@ -18069,9 +18130,9 @@ void Player::_LoadQuestStatusRewarded(PreparedQueryResult result)
LearnQuestRewardedSpells(quest);
// set rewarded title if any
- if (quest->GetCharTitleId())
+ if (quest->GetRewTitle())
{
- if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(quest->GetCharTitleId()))
+ if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(quest->GetRewTitle()))
SetTitle(titleEntry);
}
}
@@ -19442,31 +19503,40 @@ void Player::_SaveQuestStatus(SQLTransaction& trans)
statusItr = m_QuestStatus.find(saveItr->first);
if (statusItr != m_QuestStatus.end() && (keepAbandoned || statusItr->second.Status != QUEST_STATUS_NONE))
{
- uint8 index = 0;
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_QUESTSTATUS);
-
- stmt->setUInt64(index++, GetGUID().GetCounter());
- stmt->setUInt32(index++, statusItr->first);
- stmt->setUInt8(index++, uint8(statusItr->second.Status));
- stmt->setBool(index++, statusItr->second.Explored);
- stmt->setUInt32(index++, uint32(statusItr->second.Timer / IN_MILLISECONDS+ sWorld->GetGameTime()));
-
- for (uint8 i = 0; i < 4; i++)
- stmt->setUInt16(index++, statusItr->second.CreatureOrGOCount[i]);
-
- for (uint8 i = 0; i < 4; i++)
- stmt->setUInt16(index++, statusItr->second.ItemCount[i]);
+ QuestStatusData const& qData = statusItr->second;
- stmt->setUInt16(index, statusItr->second.PlayerCount);
+ // Save main quest status and timer
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_QUESTSTATUS);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ stmt->setUInt32(1, statusItr->first);
+ stmt->setUInt8(2, uint8(qData.Status));
+ stmt->setUInt32(3, uint32(qData.Timer / IN_MILLISECONDS+ sWorld->GetGameTime()));
trans->Append(stmt);
+
+ // Save objectives
+ for (uint32 i = 0; i < qData.ObjectiveData.size(); ++i)
+ {
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_QUESTSTATUS_OBJECTIVES);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ stmt->setUInt32(1, statusItr->first);
+ stmt->setUInt8(2, i);
+ stmt->setInt32(3, qData.ObjectiveData[i]);
+ trans->Append(stmt);
+ }
}
}
else
{
+ // Delete
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST);
stmt->setUInt64(0, GetGUID().GetCounter());
stmt->setUInt32(1, saveItr->first);
trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_BY_QUEST);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ stmt->setUInt32(1, saveItr->first);
+ trans->Append(stmt);
}
}
@@ -23068,7 +23138,7 @@ void Player::LearnDefaultSkill(uint32 skillId, uint16 rank)
void Player::LearnQuestRewardedSpells(Quest const* quest)
{
- int32 spell_id = quest->GetRewSpellCast();
+ int32 spell_id = quest->GetRewSpell();
uint32 src_spell_id = quest->GetSrcSpell();
// skip quests without rewarded spell
@@ -23511,19 +23581,19 @@ bool Player::HasQuestForGO(int32 GOId) const
if (qs.Status == QUEST_STATUS_INCOMPLETE)
{
- Quest const* qinfo = sObjectMgr->GetQuestTemplate(questid);
- if (!qinfo)
+ Quest const* qInfo = sObjectMgr->GetQuestTemplate(questid);
+ if (!qInfo)
continue;
- if (GetGroup() && GetGroup()->isRaidGroup() && !qinfo->IsAllowedInRaid(GetMap()->GetDifficulty()))
+ if (GetGroup() && GetGroup()->isRaidGroup() && !qInfo->IsAllowedInRaid(GetMap()->GetDifficulty()))
continue;
- for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j)
+ for (uint32 j = 0; j < qInfo->Objectives.size(); ++j)
{
- if (qinfo->RequiredNpcOrGo[j] >= 0) //skip non GO case
+ if (qInfo->Objectives[j].Type != QUEST_OBJECTIVE_GAMEOBJECT) //skip non GO case
continue;
- if ((-1)*GOId == qinfo->RequiredNpcOrGo[j] && qs.CreatureOrGOCount[j] < qinfo->RequiredNpcOrGoCount[j])
+ if (GOId == qInfo->Objectives[j].ObjectID && qs.ObjectiveData[j] < qInfo->Objectives[j].Amount)
return true;
}
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 30c1b839125..92556f106bf 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -899,42 +899,43 @@ enum PlayedTimeIndex
// used at player loading query list preparing, and later result selection
enum PlayerLoginQueryIndex
{
- PLAYER_LOGIN_QUERY_LOAD_FROM = 0,
- PLAYER_LOGIN_QUERY_LOAD_GROUP = 1,
- PLAYER_LOGIN_QUERY_LOAD_BOUND_INSTANCES = 2,
- PLAYER_LOGIN_QUERY_LOAD_AURAS = 3,
- PLAYER_LOGIN_QUERY_LOAD_SPELLS = 4,
- PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS = 5,
- PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS = 6,
- PLAYER_LOGIN_QUERY_LOAD_REPUTATION = 7,
- PLAYER_LOGIN_QUERY_LOAD_INVENTORY = 8,
- PLAYER_LOGIN_QUERY_LOAD_ACTIONS = 9,
- PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT = 10,
- PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE = 11,
- PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST = 12,
- PLAYER_LOGIN_QUERY_LOAD_HOME_BIND = 13,
- PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS = 14,
- PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES = 15,
- PLAYER_LOGIN_QUERY_LOAD_GUILD = 16,
- PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO = 17,
- PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS = 18,
- PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS = 19,
- PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS = 20,
- PLAYER_LOGIN_QUERY_LOAD_BG_DATA = 21,
- PLAYER_LOGIN_QUERY_LOAD_GLYPHS = 22,
- PLAYER_LOGIN_QUERY_LOAD_TALENTS = 23,
- PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA = 24,
- PLAYER_LOGIN_QUERY_LOAD_SKILLS = 25,
- PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS = 26,
- PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG = 27,
- PLAYER_LOGIN_QUERY_LOAD_BANNED = 28,
- PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW = 29,
- PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES = 30,
- PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS = 31,
- PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS = 32,
- PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE = 33,
- PLAYER_LOGIN_QUERY_LOAD_CURRENCY = 34,
- PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES = 35,
+ PLAYER_LOGIN_QUERY_LOAD_FROM,
+ PLAYER_LOGIN_QUERY_LOAD_GROUP,
+ PLAYER_LOGIN_QUERY_LOAD_BOUND_INSTANCES,
+ PLAYER_LOGIN_QUERY_LOAD_AURAS,
+ PLAYER_LOGIN_QUERY_LOAD_SPELLS,
+ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS,
+ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES,
+ PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS,
+ PLAYER_LOGIN_QUERY_LOAD_REPUTATION,
+ PLAYER_LOGIN_QUERY_LOAD_INVENTORY,
+ PLAYER_LOGIN_QUERY_LOAD_ACTIONS,
+ PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT,
+ PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE,
+ PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST,
+ PLAYER_LOGIN_QUERY_LOAD_HOME_BIND,
+ PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS,
+ PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES,
+ PLAYER_LOGIN_QUERY_LOAD_GUILD,
+ PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO,
+ PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS,
+ PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS,
+ PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS,
+ PLAYER_LOGIN_QUERY_LOAD_BG_DATA,
+ PLAYER_LOGIN_QUERY_LOAD_GLYPHS,
+ PLAYER_LOGIN_QUERY_LOAD_TALENTS,
+ PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA,
+ PLAYER_LOGIN_QUERY_LOAD_SKILLS,
+ PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS,
+ PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG,
+ PLAYER_LOGIN_QUERY_LOAD_BANNED,
+ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW,
+ PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES,
+ PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS,
+ PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS,
+ PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE,
+ PLAYER_LOGIN_QUERY_LOAD_CURRENCY,
+ PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES,
MAX_PLAYER_LOGIN_QUERY
};
@@ -1591,6 +1592,7 @@ class Player : public Unit, public GridObject<Player>
void AddQuest(Quest const* quest, Object* questGiver);
void CompleteQuest(uint32 quest_id);
void IncompleteQuest(uint32 quest_id);
+ uint32 GetQuestXPReward(Quest const* quest);
void RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool announce = true);
void FailQuest(uint32 quest_id);
bool SatisfyQuestSkill(Quest const* qInfo, bool msg) const;
@@ -1653,12 +1655,13 @@ class Player : public Unit, public GridObject<Player>
void TalkedToCreature(uint32 entry, ObjectGuid guid);
void MoneyChanged(uint32 value);
void ReputationChanged(FactionEntry const* factionEntry);
- void ReputationChanged2(FactionEntry const* factionEntry);
bool HasQuestForItem(uint32 itemId) const;
bool HasQuestForGO(int32 goId) const;
void UpdateForQuestWorldObjects();
bool CanShareQuest(uint32 questId) const;
+ int32 GetQuestObjectiveData(Quest const* quest, uint32 objective) const;
+ void SetQuestObjectiveData(Quest const* quest, uint32 objective, int32 data);
void SendQuestComplete(Quest const* quest);
void SendQuestReward(Quest const* quest, uint32 XP);
void SendQuestFailed(uint32 questId, InventoryResult reason = EQUIP_ERR_OK);
@@ -1666,8 +1669,8 @@ class Player : public Unit, public GridObject<Player>
void SendCanTakeQuestResponse(QuestFailedReason msg) const;
void SendQuestConfirmAccept(Quest const* quest, Player* pReceiver);
void SendPushToPartyResponse(Player* player, uint8 msg);
- void SendQuestUpdateAddCreatureOrGo(Quest const* quest, ObjectGuid guid, uint32 creatureOrGOIdx, uint16 oldCount, uint16 addCount);
- void SendQuestUpdateAddPlayer(Quest const* quest, uint16 oldCount, uint16 addCount);
+ void SendQuestUpdateAddCredit(Quest const* quest, ObjectGuid guid, uint32 objective, uint16 count);
+ void SendQuestUpdateAddPlayer(Quest const* quest, uint16 newCount, uint32 required);
ObjectGuid GetDivider() const { return m_divider; }
void SetDivider(ObjectGuid guid) { m_divider = guid; }
@@ -2657,6 +2660,7 @@ class Player : public Unit, public GridObject<Player>
void _LoadMail();
void _LoadMailedItems(Mail* mail);
void _LoadQuestStatus(PreparedQueryResult result);
+ void _LoadQuestStatusObjectives(PreparedQueryResult result);
void _LoadQuestStatusRewarded(PreparedQueryResult result);
void _LoadDailyQuestStatus(PreparedQueryResult result);
void _LoadWeeklyQuestStatus(PreparedQueryResult result);
@@ -2898,7 +2902,7 @@ class Player : public Unit, public GridObject<Player>
// know currencies are not removed at any point (0 displayed)
void AddKnownCurrency(uint32 itemId);
- void AdjustQuestReqItemCount(Quest const* quest, QuestStatusData& questStatusData);
+ void AdjustQuestReqItemCount(Quest const* quest);
bool IsCanDelayTeleport() const { return m_bCanDelayTeleport; }
void SetCanDelayTeleport(bool setting) { m_bCanDelayTeleport = setting; }
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index dd2a1697e6a..476b340cb2a 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -1049,7 +1049,7 @@ void ObjectMgr::LoadCreatureAddons()
}
if (AdditionalSpellInfo->HasAura(DIFFICULTY_NONE, SPELL_AURA_CONTROL_VEHICLE))
- TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") has SPELL_AURA_CONTROL_VEHICLE aura %lu defined in `auras` field in `creature_addon`.", guid, uint32(atol(*itr)));
+ TC_LOG_ERROR("sql.sql", "Creature (GUID: " UI64FMTD ") has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_addon`.", guid, uint32(atol(*itr)));
creatureAddon.auras[i++] = atoul(*itr);
@@ -3464,40 +3464,34 @@ void ObjectMgr::LoadQuests()
mExclusiveQuestGroups.clear();
QueryResult result = WorldDatabase.Query("SELECT "
- //0 1 2 3 4 5 6 7 8 9 10 11 12
- "Id, Method, Level, MinLevel, MaxLevel, ZoneOrSort, Type, SuggestedPlayers, LimitTime, RequiredClasses, RequiredRaces, RequiredSkillId, RequiredSkillPoints, "
- // 13 14 15 16 17 18 19 20
- "RequiredFactionId1, RequiredFactionId2, RequiredFactionValue1, RequiredFactionValue2, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, "
- // 21 22 23 24 25 26 27 28 29 30 31
- "PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestIdChain, RewardXPId, RewardOrRequiredMoney, RewardMoneyMaxLevel, RewardSpell, RewardSpellCast, RewardHonor, RewardHonorMultiplier, "
- // 32 33 34 35 36 37 38 39 40 41 42 43
- "RewardMailTemplateId, RewardMailDelay, SourceItemId, SourceItemCount, SourceSpellId, Flags, SpecialFlags, MinimapTargetMark, RewardTitleId, RequiredPlayerKills, RewardTalents, RewardArenaPoints, "
- // 44 45 46 47 48 49 50 51 52 53 54 55 56
- "RewardSkillId, RewardSkillPoints, RewardReputationMask, QuestGiverPortrait, QuestTurnInPortrait, RewardItemId1, RewardItemId2, RewardItemId3, RewardItemId4, RewardItemCount1, RewardItemCount2, RewardItemCount3, RewardItemCount4, "
- // 57 58 59 60 61 62 63 64 65 66 67 68
- "RewardChoiceItemId1, RewardChoiceItemId2, RewardChoiceItemId3, RewardChoiceItemId4, RewardChoiceItemId5, RewardChoiceItemId6, RewardChoiceItemCount1, RewardChoiceItemCount2, RewardChoiceItemCount3, RewardChoiceItemCount4, RewardChoiceItemCount5, RewardChoiceItemCount6, "
- // 69 70 71 72 73 74 75 76 77 78
- "RewardFactionId1, RewardFactionId2, RewardFactionId3, RewardFactionId4, RewardFactionId5, RewardFactionValueId1, RewardFactionValueId2, RewardFactionValueId3, RewardFactionValueId4, RewardFactionValueId5, "
- // 79 80 81 82 83
- "RewardFactionValueIdOverride1, RewardFactionValueIdOverride2, RewardFactionValueIdOverride3, RewardFactionValueIdOverride4, RewardFactionValueIdOverride5, "
- // 84 85 86 87 88 89 90 91 92 93 94
- "PointMapId, PointX, PointY, PointOption, Title, Objectives, Details, EndText, CompletedText, OfferRewardText, RequestItemsText, "
- // 95 96 97 98 99 100 101 102
- "RequiredNpcOrGo1, RequiredNpcOrGo2, RequiredNpcOrGo3, RequiredNpcOrGo4, RequiredNpcOrGoCount1, RequiredNpcOrGoCount2, RequiredNpcOrGoCount3, RequiredNpcOrGoCount4, "
- // 103 104 105 106 107 108 109 110
- "RequiredSourceItemId1, RequiredSourceItemId2, RequiredSourceItemId3, RequiredSourceItemId4, RequiredSourceItemCount1, RequiredSourceItemCount2, RequiredSourceItemCount3, RequiredSourceItemCount4, "
- // 111 112 113 114 115 116 117 118 119 120 121 122
- "RequiredItemId1, RequiredItemId2, RequiredItemId3, RequiredItemId4, RequiredItemId5, RequiredItemId6, RequiredItemCount1, RequiredItemCount2, RequiredItemCount3, RequiredItemCount4, RequiredItemCount5, RequiredItemCount6, "
- // 123 124 125 126 127 128 129 130 131 132 133 134 135
- "RequiredSpell, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4, RewardCurrencyId1, RewardCurrencyId2, RewardCurrencyId3, RewardCurrencyId4, RewardCurrencyCount1, RewardCurrencyCount2, RewardCurrencyCount3, RewardCurrencyCount4, "
- // 136 137 138 139 140 141 142 143
- "RequiredCurrencyId1, RequiredCurrencyId2, RequiredCurrencyId3, RequiredCurrencyId4, RequiredCurrencyCount1, RequiredCurrencyCount2, RequiredCurrencyCount3, RequiredCurrencyCount4, "
- // 144 145 146 147 148 149
- "QuestGiverTextWindow, QuestGiverTargetName, QuestTurnTextWindow, QuestTurnTargetName, SoundAccept, SoundTurnIn, "
- // 150 151 152 153 154 155 156 157 158 159
- "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, DetailsEmoteDelay1, DetailsEmoteDelay2, DetailsEmoteDelay3, DetailsEmoteDelay4, EmoteOnIncomplete, EmoteOnComplete, "
- // 160 161 162 163 164 165 166 167
- "OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4, OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4"
+ //0 1 2 3 4 5 6 7 8 9 10 11 12
+ "ID, QuestType, QuestLevel, QuestPackageID, MinLevel, QuestSortID, QuestInfoID, SuggestedGroupNum, RewardNextQuest, RewardXPDifficulty, Float10, RewardMoney, RewardMoneyDifficulty, "
+ //13 14 15 16 17 18 19 20 21
+ "Float13, RewardBonusMoney, RewardDisplaySpell, RewardSpell, RewardHonor, RewardKillHonor, StartItem, Flags, FlagsEx, "
+ //22 23 24 25 26 27 28 29
+ "RewardItem1, RewardAmount1, ItemDrop1, ItemDropQuantity1, RewardItem2, RewardAmount2, ItemDrop2, ItemDropQuantity2, "
+ //30 31 32 33 34 35 36 37
+ "RewardItem3, RewardAmount3, ItemDrop3, ItemDropQuantity3, RewardItem4, RewardAmount4, ItemDrop4, ItemDropQuantity4, "
+ //38 39 40 41 42 43
+ "RewardChoiceItemID1, RewardChoiceItemQuantity1, RewardChoiceItemDisplayID1, RewardChoiceItemID2, RewardChoiceItemQuantity2, RewardChoiceItemDisplayID2, "
+ //44 45 46 47 48 49
+ "RewardChoiceItemID3, RewardChoiceItemQuantity3, RewardChoiceItemDisplayID3, RewardChoiceItemID4, RewardChoiceItemQuantity4, RewardChoiceItemDisplayID4, "
+ //50 51 52 53 54 55
+ "RewardChoiceItemID5, RewardChoiceItemQuantity5, RewardChoiceItemDisplayID5, RewardChoiceItemID6, RewardChoiceItemQuantity6, RewardChoiceItemDisplayID6, "
+ //56 57 58 59 60 61 62 63 64 65 66
+ "POIContinent, POIx, POIy, POIPriority, RewardTitle, RewardTalents, RewardArenaPoints, RewardSkillLineID, RewardNumSkillUps, PortraitGiver, PortraitTurnIn, "
+ //67 68 69 70 71 72
+ "RewardFactionID1, RewardFactionValue1, RewardFactionOverride1, RewardFactionID2, RewardFactionValue2, RewardFactionOverride2, "
+ //73 74 75 76 77 78
+ "RewardFactionID3, RewardFactionValue3, RewardFactionOverride3, RewardFactionID4, RewardFactionValue4, RewardFactionOverride4, "
+ //79 80 81 82
+ "RewardFactionID5, RewardFactionValue5, RewardFactionOverride5, RewardFactionFlags, "
+ //83 84 85 86 87 88 89 90
+ "RewardCurrencyID1, RewardCurrencyQty1, RewardCurrencyID2, RewardCurrencyQty2, RewardCurrencyID3, RewardCurrencyQty3, RewardCurrencyID4, RewardCurrencyQty4, "
+ //91 92 93 94 95
+ "AcceptedSoundKitID, CompleteSoundKitID, AreaGroupID, TimeAllowed, AllowableRaces, "
+ //96 97 98 99 100 101 102 103 104
+ "LogTitle, LogDescription, QuestDescription, AreaDescription, PortraitGiverText, PortraitGiverName, PortraitTurnInText, PortraitTurnInName, QuestCompletionLog"
" FROM quest_template");
if (!result)
{
@@ -3516,6 +3510,161 @@ void ObjectMgr::LoadQuests()
_questTemplates[newQuest->GetQuestId()] = newQuest;
} while (result->NextRow());
+ // Load `quest_details`
+ // 0 1 2 3 4 5 6 7 8
+ result = WorldDatabase.Query("SELECT ID, Emote1, Emote2, Emote3, Emote4, EmoteDelay1, EmoteDelay2, EmoteDelay3, EmoteDelay4 FROM quest_details");
+
+ if (!result)
+ {
+ TC_LOG_ERROR("server.loading", ">> Loaded 0 quest details. DB table `quest_details` is empty.");
+ }
+ else
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 questId = fields[0].GetUInt32();
+
+ auto itr = _questTemplates.find(questId);
+ if (itr != _questTemplates.end())
+ itr->second->LoadQuestDetails(fields);
+ else
+ TC_LOG_ERROR("server.loading", "Table `quest_details` has data for quest %u but such quest does not exist", questId);
+ } while (result->NextRow());
+ }
+
+ // Load `quest_request_items`
+ // 0 1 2 3 4 5
+ result = WorldDatabase.Query("SELECT ID, EmoteOnComplete, EmoteOnIncomplete, EmoteOnCompleteDelay, EmoteOnIncompleteDelay, CompletionText FROM quest_request_items");
+
+ if (!result)
+ {
+ TC_LOG_ERROR("server.loading", ">> Loaded 0 quest request items. DB table `quest_request_items` is empty.");
+ }
+ else
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 questId = fields[0].GetUInt32();
+
+ auto itr = _questTemplates.find(questId);
+ if (itr != _questTemplates.end())
+ itr->second->LoadQuestRequestItems(fields);
+ else
+ TC_LOG_ERROR("server.loading", "Table `quest_request_items` has data for quest %u but such quest does not exist", questId);
+ } while (result->NextRow());
+ }
+
+ // Load `quest_offer_reward`
+ // 0 1 2 3 4 5 6 7 8 9
+ result = WorldDatabase.Query("SELECT ID, Emote1, Emote2, Emote3, Emote4, EmoteDelay1, EmoteDelay2, EmoteDelay3, EmoteDelay4, RewardText FROM quest_offer_reward");
+
+ if (!result)
+ {
+ TC_LOG_ERROR("server.loading", ">> Loaded 0 quest reward emotes. DB table `quest_offer_reward` is empty.");
+ }
+ else
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 questId = fields[0].GetUInt32();
+
+ auto itr = _questTemplates.find(questId);
+ if (itr != _questTemplates.end())
+ itr->second->LoadQuestOfferReward(fields);
+ else
+ TC_LOG_ERROR("server.loading", "Table `quest_offer_reward` has data for quest %u but such quest does not exist", questId);
+ } while (result->NextRow());
+ }
+
+ // Load `quest_template_addon`
+ // 0 1 2 3 4 5 6 7 8
+ result = WorldDatabase.Query("SELECT ID, MaxLevel, AllowableClasses, SourceSpellID, PrevQuestID, NextQuestID, ExclusiveGroup, RewardMailTemplateID, RewardMailDelay, "
+ //9 10 11 12 13 14 15 16
+ "RequiredSkillID, RequiredSkillPoints, RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, ProvidedItemCount, SpecialFlags FROM quest_template_addon");
+
+ if (!result)
+ {
+ TC_LOG_ERROR("server.loading", ">> Loaded 0 quest template addons. DB table `quest_template_addon` is empty.");
+ }
+ else
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 questId = fields[0].GetUInt32();
+
+ auto itr = _questTemplates.find(questId);
+ if (itr != _questTemplates.end())
+ itr->second->LoadQuestTemplateAddon(fields);
+ else
+ TC_LOG_ERROR("server.loading", "Table `quest_template_addon` has data for quest %u but such quest does not exist", questId);
+ } while (result->NextRow());
+ }
+
+ // Load `quest_objectives` order by descending storage index to reduce resizes
+ // 0 1 2 3 4 5 6 7 8
+ result = WorldDatabase.Query("SELECT ID, QuestID, Type, StorageIndex, ObjectID, Amount, Flags, UnkFloat, Description FROM quest_objectives ORDER BY StorageIndex DESC");
+
+ if (!result)
+ {
+ TC_LOG_ERROR("server.loading", ">> Loaded 0 quest objectives. DB table `quest_objectives` is empty.");
+ }
+ else
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 questId = fields[1].GetUInt32();
+
+ auto itr = _questTemplates.find(questId);
+ if (itr != _questTemplates.end())
+ itr->second->LoadQuestObjective(fields);
+ else
+ TC_LOG_ERROR("server.loading", "Table `quest_objectives` has objective for quest %u but such quest does not exist", questId);
+ } while (result->NextRow());
+ }
+
+ // Load `quest_visual_effect` join table with quest_objectives because visual effects are based on objective ID (core stores objectives by their index in quest)
+ // 0 1 2 3 4 5
+ result = WorldDatabase.Query("SELECT v.ID, o.ID, o.QuestID, o.StorageIndex, v.Index, v.VisualEffect FROM quest_visual_effect AS v LEFT JOIN quest_objectives AS o ON v.ID = o.ID ORDER BY v.Index DESC");
+
+ if (!result)
+ {
+ TC_LOG_ERROR("server.loading", ">> Loaded 0 quest visual effects. DB table `quest_visual_effect` is empty.");
+ }
+ else
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 vID = fields[0].GetUInt32();
+ uint32 oID = fields[1].GetUInt32();
+
+ if (!vID)
+ {
+ TC_LOG_ERROR("server.loading", "Table `quest_visual_effect` has visual effect for null objective id");
+ continue;
+ }
+
+ // objID will be null if match for table join is not found
+ if (vID != oID)
+ {
+ TC_LOG_ERROR("server.loading", "Table `quest_visual_effect` has visual effect for objective %u but such objective does not exist.", vID);
+ continue;
+ }
+
+ uint32 questId = fields[2].GetUInt32();
+
+ // Do not throw error here because error for non existing quest is thrown while loading quest objectives. we do not need duplication
+ auto itr = _questTemplates.find(questId);
+ if (itr != _questTemplates.end())
+ itr->second->LoadQuestObjectiveVisualEffect(fields);
+ } while (result->NextRow());
+ }
+
std::map<uint32, uint32> usedMailTemplates;
// Post processing
@@ -3624,23 +3773,23 @@ void ObjectMgr::LoadQuests()
}
}
- // RequiredClasses, can be 0/CLASSMASK_ALL_PLAYABLE to allow any class
- if (qinfo->RequiredClasses)
+ // AllowableClasses, can be 0/CLASSMASK_ALL_PLAYABLE to allow any class
+ if (qinfo->AllowableClasses)
{
- if (!(qinfo->RequiredClasses & CLASSMASK_ALL_PLAYABLE))
+ if (!(qinfo->AllowableClasses & CLASSMASK_ALL_PLAYABLE))
{
- TC_LOG_ERROR("sql.sql", "Quest %u does not contain any playable classes in `RequiredClasses` (%u), value set to 0 (all classes).", qinfo->GetQuestId(), qinfo->RequiredClasses);
- qinfo->RequiredClasses = 0;
+ TC_LOG_ERROR("sql.sql", "Quest %u does not contain any playable classes in `AllowableClasses` (%u), value set to 0 (all classes).", qinfo->GetQuestId(), qinfo->AllowableClasses);
+ qinfo->AllowableClasses = 0;
}
}
- // RequiredRaces, can be 0/RACEMASK_ALL_PLAYABLE to allow any race
- if (qinfo->RequiredRaces)
+ // AllowableRaces, can be -1/RACEMASK_ALL_PLAYABLE to allow any race
+ if (qinfo->AllowableRaces != -1)
{
- if (!(qinfo->RequiredRaces & RACEMASK_ALL_PLAYABLE))
- {
- TC_LOG_ERROR("sql.sql", "Quest %u does not contain any playable races in `RequiredRaces` (%u), value set to 0 (all races).", qinfo->GetQuestId(), qinfo->RequiredRaces);
- qinfo->RequiredRaces = 0;
- }
+ if (qinfo->AllowableRaces > 0 && !(uint32(qinfo->AllowableRaces) & RACEMASK_ALL_PLAYABLE))
+ {
+ TC_LOG_ERROR("sql.sql", "Quest %u does not contain any playable races in `AllowableRaces` (%d), value set to 0 (all races).", qinfo->GetQuestId(), qinfo->AllowableRaces);
+ qinfo->AllowableRaces = -1;
+ }
}
// RequiredSkillId, can be 0
if (qinfo->RequiredSkillId)
@@ -3663,20 +3812,6 @@ void ObjectMgr::LoadQuests()
}
// else Skill quests can have 0 skill level, this is ok
- if (qinfo->RequiredFactionId2 && !sFactionStore.LookupEntry(qinfo->RequiredFactionId2))
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredFactionId2` = %u but faction template %u does not exist, quest can't be done.",
- qinfo->GetQuestId(), qinfo->RequiredFactionId2, qinfo->RequiredFactionId2);
- // no changes, quest can't be done for this requirement
- }
-
- if (qinfo->RequiredFactionId1 && !sFactionStore.LookupEntry(qinfo->RequiredFactionId1))
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredFactionId1` = %u but faction template %u does not exist, quest can't be done.",
- qinfo->GetQuestId(), qinfo->RequiredFactionId1, qinfo->RequiredFactionId1);
- // no changes, quest can't be done for this requirement
- }
-
if (qinfo->RequiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMinRepFaction))
{
TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredMinRepFaction` = %u but faction template %u does not exist, quest can't be done.",
@@ -3705,20 +3840,6 @@ void ObjectMgr::LoadQuests()
// no changes, quest can't be done for this requirement
}
- if (!qinfo->RequiredFactionId1 && qinfo->RequiredFactionValue1 != 0)
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredFactionValue1` = %d but `RequiredFactionId1` is 0, value has no effect",
- qinfo->GetQuestId(), qinfo->RequiredFactionValue1);
- // warning
- }
-
- if (!qinfo->RequiredFactionId2 && qinfo->RequiredFactionValue2 != 0)
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredFactionValue2` = %d but `RequiredFactionId2` is 0, value has no effect",
- qinfo->GetQuestId(), qinfo->RequiredFactionValue2);
- // warning
- }
-
if (!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue != 0)
{
TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect",
@@ -3736,7 +3857,7 @@ void ObjectMgr::LoadQuests()
if (qinfo->RewardTitleId && !sCharTitlesStore.LookupEntry(qinfo->RewardTitleId))
{
TC_LOG_ERROR("sql.sql", "Quest %u has `RewardTitleId` = %u but CharTitle Id %u does not exist, quest can't be rewarded with title.",
- qinfo->GetQuestId(), qinfo->GetCharTitleId(), qinfo->GetCharTitleId());
+ qinfo->GetQuestId(), qinfo->RewardTitleId, qinfo->RewardTitleId);
qinfo->RewardTitleId = 0;
// quest can't reward this title
}
@@ -3763,55 +3884,94 @@ void ObjectMgr::LoadQuests()
qinfo->SourceItemIdCount=0; // no quest work changes in fact
}
- if (qinfo->SourceSpellid)
+ if (qinfo->SourceSpellID)
{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->SourceSpellid);
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->SourceSpellID);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "Quest %u has `SourceSpellid` = %u but spell %u doesn't exist, quest can't be done.",
- qinfo->GetQuestId(), qinfo->SourceSpellid, qinfo->SourceSpellid);
- qinfo->SourceSpellid = 0; // quest can't be done for this requirement
+ qinfo->GetQuestId(), qinfo->SourceSpellID, qinfo->SourceSpellID);
+ qinfo->SourceSpellID = 0; // quest can't be done for this requirement
}
else if (!SpellMgr::IsSpellValid(spellInfo))
{
TC_LOG_ERROR("sql.sql", "Quest %u has `SourceSpellid` = %u but spell %u is broken, quest can't be done.",
- qinfo->GetQuestId(), qinfo->SourceSpellid, qinfo->SourceSpellid);
- qinfo->SourceSpellid = 0; // quest can't be done for this requirement
+ qinfo->GetQuestId(), qinfo->SourceSpellID, qinfo->SourceSpellID);
+ qinfo->SourceSpellID = 0; // quest can't be done for this requirement
}
}
- for (uint8 j = 0; j < QUEST_ITEM_OBJECTIVES_COUNT; ++j)
+ for (uint32 j = 0; j < qinfo->Objectives.size(); ++j)
{
- uint32 id = qinfo->RequiredItemId[j];
- if (id)
- {
- if (qinfo->RequiredItemCount[j] == 0)
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredItemId%d` = %u but `RequiredItemCount%d` = 0, quest can't be done.",
- qinfo->GetQuestId(), j+1, id, j+1);
- // no changes, quest can't be done for this requirement
- }
+ QuestObjective& obj = qinfo->Objectives[j];
- qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER);
+ if (!obj.ObjectID)
+ {
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has `ObjectID` = 0, quest can't be done.", qinfo->GetQuestId(), j);
+ // no changes, quest can't be done for this requirement
+ continue;
+ }
- if (!sObjectMgr->GetItemTemplate(id))
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredItemId%d` = %u but item with entry %u does not exist, quest can't be done.",
- qinfo->GetQuestId(), j+1, id, id);
- qinfo->RequiredItemCount[j] = 0; // prevent incorrect work of quest
- }
+ if (!obj.Amount)
+ {
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has `Amount` = 0, quest can't be done.", qinfo->GetQuestId(), j);
+ // no changes, quest can't be done for this requirement
+ continue;
}
- else if (qinfo->RequiredItemCount[j] > 0)
+
+ switch (obj.Type)
{
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredItemId%d` = 0 but `RequiredItemCount%d` = %u, quest can't be done.",
- qinfo->GetQuestId(), j+1, j+1, qinfo->RequiredItemCount[j]);
- qinfo->RequiredItemCount[j] = 0; // prevent incorrect work of quest
+ case QUEST_OBJECTIVE_ITEM:
+ qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER);
+ if (!sObjectMgr->GetItemTemplate(obj.ObjectID))
+ {
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing item entry %u, quest can't be done.",
+ qinfo->GetQuestId(), j, obj.ObjectID);
+ obj.Amount = 0; // prevent incorrect work of quest
+ }
+ break;
+ case QUEST_OBJECTIVE_MONSTER:
+ qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_SPEAKTO);
+ if (!sObjectMgr->GetCreatureTemplate(obj.ObjectID))
+ {
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing creature entry %u, quest can't be done.",
+ qinfo->GetQuestId(), j, uint32(obj.ObjectID));
+ obj.Amount = 0; // quest can't be done for this requirement
+ }
+ break;
+ case QUEST_OBJECTIVE_GAMEOBJECT:
+ qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_SPEAKTO);
+ if (!sObjectMgr->GetGameObjectTemplate(obj.ObjectID))
+ {
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing gameobject entry %u, quest can't be done.",
+ qinfo->GetQuestId(), j, uint32(obj.ObjectID));
+ obj.Amount = 0; // quest can't be done for this requirement
+ }
+ break;
+ case QUEST_OBJECTIVE_MIN_REPUTATION:
+ case QUEST_OBJECTIVE_MAX_REPUTATION:
+ if (!sFactionStore.LookupEntry(obj.ObjectID))
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing faction id %u", qinfo->GetQuestId(), j, obj.ObjectID);
+ break;
+ case QUEST_OBJECTIVE_PLAYERKILLS:
+ qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL);
+ if (obj.Amount <= 0)
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has invalid player kills count %d", qinfo->GetQuestId(), j, obj.Amount);
+ break;
+ case QUEST_OBJECTIVE_CURRENCY:
+ if (!sCurrencyTypesStore.LookupEntry(obj.ObjectID))
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has non existing currency %u", qinfo->GetQuestId(), j, obj.ObjectID);
+ if (obj.Amount <= 0)
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has invalid currency amount %d", qinfo->GetQuestId(), j, obj.Amount);
+ break;
+ default:
+ TC_LOG_ERROR("sql.sql", "Quest %u objective %u has unknown type %u", qinfo->GetQuestId(), j, obj.Type);
}
}
- for (uint8 j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j)
+ for (uint8 j = 0; j < QUEST_ITEM_DROP_COUNT; ++j)
{
- uint32 id = qinfo->RequiredSourceItemId[j];
+ uint32 id = qinfo->ItemDrop[j];
if (id)
{
if (!sObjectMgr->GetItemTemplate(id))
@@ -3823,53 +3983,15 @@ void ObjectMgr::LoadQuests()
}
else
{
- if (qinfo->RequiredSourceItemCount[j]>0)
+ if (qinfo->ItemDropQuantity[j]>0)
{
TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredSourceItemId%d` = 0 but `RequiredSourceItemCount%d` = %u.",
- qinfo->GetQuestId(), j+1, j+1, qinfo->RequiredSourceItemCount[j]);
+ qinfo->GetQuestId(), j+1, j+1, qinfo->ItemDropQuantity[j]);
// no changes, quest ignore this data
}
}
}
- for (uint8 j = 0; j < QUEST_OBJECTIVES_COUNT; ++j)
- {
- int32 id = qinfo->RequiredNpcOrGo[j];
- if (id < 0 && !sObjectMgr->GetGameObjectTemplate(-id))
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredNpcOrGo%d` = %i but gameobject %u does not exist, quest can't be done.",
- qinfo->GetQuestId(), j+1, id, uint32(-id));
- qinfo->RequiredNpcOrGo[j] = 0; // quest can't be done for this requirement
- }
-
- if (id > 0 && !sObjectMgr->GetCreatureTemplate(id))
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredNpcOrGo%d` = %i but creature with entry %u does not exist, quest can't be done.",
- qinfo->GetQuestId(), j+1, id, uint32(id));
- qinfo->RequiredNpcOrGo[j] = 0; // quest can't be done for this requirement
- }
-
- if (id)
- {
- // In fact SpeakTo and Kill are quite same: either you can speak to mob:SpeakTo or you can't:Kill/Cast
-
- qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_KILL | QUEST_SPECIAL_FLAGS_CAST | QUEST_SPECIAL_FLAGS_SPEAKTO);
-
- if (!qinfo->RequiredNpcOrGoCount[j])
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredNpcOrGo%d` = %u but `RequiredNpcOrGoCount%d` = 0, quest can't be done.",
- qinfo->GetQuestId(), j+1, id, j+1);
- // no changes, quest can be incorrectly done, but we already report this
- }
- }
- else if (qinfo->RequiredNpcOrGoCount[j]>0)
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredNpcOrGo%d` = 0 but `RequiredNpcOrGoCount%d` = %u.",
- qinfo->GetQuestId(), j+1, j+1, qinfo->RequiredNpcOrGoCount[j]);
- // no changes, quest ignore this data
- }
- }
-
for (uint8 j = 0; j < QUEST_REWARD_CHOICES_COUNT; ++j)
{
uint32 id = qinfo->RewardChoiceItemId[j];
@@ -3897,7 +4019,7 @@ void ObjectMgr::LoadQuests()
}
}
- for (uint8 j = 0; j < QUEST_REWARDS_COUNT; ++j)
+ for (uint8 j = 0; j < QUEST_REWARD_ITEM_COUNT; ++j)
{
uint32 id = qinfo->RewardItemId[j];
if (id)
@@ -3909,28 +4031,28 @@ void ObjectMgr::LoadQuests()
qinfo->RewardItemId[j] = 0; // no changes, quest will not reward this item
}
- if (!qinfo->RewardItemIdCount[j])
+ if (!qinfo->RewardItemCount[j])
{
- TC_LOG_ERROR("sql.sql", "Quest %u has `RewardItemId%d` = %u but `RewardItemIdCount%d` = 0, quest will not reward this item.",
+ TC_LOG_ERROR("sql.sql", "Quest %u has `RewardItemId%d` = %u but `RewardItemCount%d` = 0, quest will not reward this item.",
qinfo->GetQuestId(), j+1, id, j+1);
// no changes
}
}
- else if (qinfo->RewardItemIdCount[j]>0)
+ else if (qinfo->RewardItemCount[j]>0)
{
- TC_LOG_ERROR("sql.sql", "Quest %u has `RewardItemId%d` = 0 but `RewardItemIdCount%d` = %u.",
- qinfo->GetQuestId(), j+1, j+1, qinfo->RewardItemIdCount[j]);
+ TC_LOG_ERROR("sql.sql", "Quest %u has `RewardItemId%d` = 0 but `RewardItemCount%d` = %u.",
+ qinfo->GetQuestId(), j+1, j+1, qinfo->RewardItemCount[j]);
// no changes, quest ignore this data
}
}
- for (uint8 j = 0; j < QUEST_REPUTATIONS_COUNT; ++j)
+ for (uint8 j = 0; j < QUEST_REWARD_REPUTATIONS_COUNT; ++j)
{
if (qinfo->RewardFactionId[j])
{
- if (abs(qinfo->RewardFactionValueId[j]) > 9)
+ if (abs(qinfo->RewardFactionValue[j]) > 9)
{
- TC_LOG_ERROR("sql.sql", "Quest %u has RewardFactionValueId%d = %i. That is outside the range of valid values (-9 to 9).", qinfo->GetQuestId(), j+1, qinfo->RewardFactionValueId[j]);
+ TC_LOG_ERROR("sql.sql", "Quest %u has RewardFactionValueId%d = %i. That is outside the range of valid values (-9 to 9).", qinfo->GetQuestId(), j+1, qinfo->RewardFactionValue[j]);
}
if (!sFactionStore.LookupEntry(qinfo->RewardFactionId[j]))
{
@@ -3939,49 +4061,49 @@ void ObjectMgr::LoadQuests()
}
}
- else if (qinfo->RewardFactionValueIdOverride[j] != 0)
+ else if (qinfo->RewardFactionOverride[j] != 0)
{
TC_LOG_ERROR("sql.sql", "Quest %u has `RewardFactionId%d` = 0 but `RewardFactionValueIdOverride%d` = %i.",
- qinfo->GetQuestId(), j+1, j+1, qinfo->RewardFactionValueIdOverride[j]);
+ qinfo->GetQuestId(), j+1, j+1, qinfo->RewardFactionOverride[j]);
// no changes, quest ignore this data
}
}
- if (qinfo->RewardSpell)
+ if (qinfo->RewardDisplaySpell)
{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardSpell);
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardDisplaySpell);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u does not exist, spell removed as display reward.",
- qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell);
- qinfo->RewardSpell = 0; // no spell reward will display for this quest
+ qinfo->GetQuestId(), qinfo->RewardDisplaySpell, qinfo->RewardDisplaySpell);
+ qinfo->RewardDisplaySpell = 0; // no spell reward will display for this quest
}
else if (!SpellMgr::IsSpellValid(spellInfo))
{
TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is broken, quest will not have a spell reward.",
- qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell);
- qinfo->RewardSpell = 0; // no spell reward will display for this quest
+ qinfo->GetQuestId(), qinfo->RewardDisplaySpell, qinfo->RewardDisplaySpell);
+ qinfo->RewardDisplaySpell = 0; // no spell reward will display for this quest
}
}
- if (qinfo->RewardSpellCast > 0)
+ if (qinfo->RewardSpell > 0)
{
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardSpellCast);
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardSpell);
if (!spellInfo)
{
TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.",
- qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast);
- qinfo->RewardSpellCast = 0; // no spell will be cast on player
+ qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell);
+ qinfo->RewardSpell = 0; // no spell will be cast on player
}
else if (!SpellMgr::IsSpellValid(spellInfo))
{
TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpellCast` = %u but spell %u is broken, quest will not have a spell reward.",
- qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast);
- qinfo->RewardSpellCast = 0; // no spell will be cast on player
+ qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell);
+ qinfo->RewardSpell = 0; // no spell will be cast on player
}
}
@@ -4006,14 +4128,14 @@ void ObjectMgr::LoadQuests()
usedMailTemplates[qinfo->RewardMailTemplateId] = qinfo->GetQuestId();
}
- if (qinfo->NextQuestIdChain)
+ if (qinfo->NextQuestInChain)
{
- QuestMap::iterator qNextItr = _questTemplates.find(qinfo->NextQuestIdChain);
+ QuestMap::iterator qNextItr = _questTemplates.find(qinfo->NextQuestInChain);
if (qNextItr == _questTemplates.end())
{
- TC_LOG_ERROR("sql.sql", "Quest %u has `NextQuestIdChain` = %u but quest %u does not exist, quest chain will not work.",
- qinfo->GetQuestId(), qinfo->NextQuestIdChain, qinfo->NextQuestIdChain);
- qinfo->NextQuestIdChain = 0;
+ TC_LOG_ERROR("sql.sql", "Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.",
+ qinfo->GetQuestId(), qinfo->NextQuestInChain, qinfo->NextQuestInChain);
+ qinfo->NextQuestInChain = 0;
}
else
qNextItr->second->prevChainQuests.push_back(qinfo->GetQuestId());
@@ -4045,32 +4167,6 @@ void ObjectMgr::LoadQuests()
}
}
- for (uint8 j = 0; j < QUEST_REQUIRED_CURRENCY_COUNT; ++j)
- {
- if (qinfo->RequiredCurrencyId[j])
- {
- if (qinfo->RequiredCurrencyCount[j] == 0)
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredCurrencyId%d` = %u but `RequiredCurrencyCount%d` = 0, quest can't be done.",
- qinfo->GetQuestId(), j+1, qinfo->RequiredCurrencyId[j], j+1);
- // no changes, quest can't be done for this requirement
- }
-
- if (!sCurrencyTypesStore.LookupEntry(qinfo->RequiredCurrencyId[j]))
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredCurrencyId%d` = %u but currency with entry %u does not exist, quest can't be done.",
- qinfo->GetQuestId(), j+1, qinfo->RequiredCurrencyId[j], qinfo->RequiredCurrencyId[j]);
- qinfo->RequiredCurrencyCount[j] = 0; // prevent incorrect work of quest
- }
- }
- else if (qinfo->RequiredCurrencyCount[j] > 0)
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredCurrencyId%d` = 0 but `RequiredCurrencyCount%d` = %u, quest can't be done.",
- qinfo->GetQuestId(), j+1, j+1, qinfo->RequiredCurrencyCount[j]);
- qinfo->RequiredCurrencyCount[j] = 0; // prevent incorrect work of quest
- }
- }
-
if (qinfo->SoundAccept)
{
if (!sSoundEntriesStore.LookupEntry(qinfo->SoundAccept))
@@ -4091,34 +4187,6 @@ void ObjectMgr::LoadQuests()
}
}
- if (qinfo->RequiredSpell > 0)
- {
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RequiredSpell);
-
- if (!spellInfo)
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredSpell` = %u but spell %u does not exist, quest will not require a spell.",
- qinfo->GetQuestId(), qinfo->RequiredSpell, qinfo->RequiredSpell);
- qinfo->RequiredSpell = 0; // no spell will be required
- }
-
- else if (!SpellMgr::IsSpellValid(spellInfo))
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RequiredSpell` = %u but spell %u is broken, quest will not require a spell.",
- qinfo->GetQuestId(), qinfo->RequiredSpell, qinfo->RequiredSpell);
- qinfo->RequiredSpell = 0; // no spell will be required
- }
-
- /* Can we require talents?
- else if (GetTalentSpellCost(qinfo->RewardSpellCast))
- {
- TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is talent, quest will not have a spell reward.",
- qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast);
- qinfo->RewardSpellCast = 0; // no spell will be casted on player
- }
- }*/
- }
-
if (qinfo->RewardSkillId)
{
if (!sSkillLineStore.LookupEntry(qinfo->RewardSkillId))
@@ -4149,22 +4217,22 @@ void ObjectMgr::LoadQuests()
}
// fill additional data stores
- if (qinfo->PrevQuestId)
+ if (qinfo->PrevQuestID)
{
if (_questTemplates.find(abs(qinfo->GetPrevQuestId())) == _questTemplates.end())
TC_LOG_ERROR("sql.sql", "Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId());
else
- qinfo->prevQuests.push_back(qinfo->PrevQuestId);
+ qinfo->prevQuests.push_back(qinfo->PrevQuestID);
}
- if (qinfo->NextQuestId)
+ if (qinfo->NextQuestID)
{
QuestMap::iterator qNextItr = _questTemplates.find(abs(qinfo->GetNextQuestId()));
if (qNextItr == _questTemplates.end())
TC_LOG_ERROR("sql.sql", "Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId());
else
{
- int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId());
+ int32 signedQuestId = qinfo->NextQuestID < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId());
qNextItr->second->prevQuests.push_back(signedQuestId);
}
}
@@ -4173,8 +4241,6 @@ void ObjectMgr::LoadQuests()
mExclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->ExclusiveGroup, qinfo->GetQuestId()));
if (qinfo->LimitTime)
qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_TIMED);
- if (qinfo->RequiredPlayerKills)
- qinfo->SetSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL);
}
// check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE
@@ -4242,21 +4308,22 @@ void ObjectMgr::LoadQuestLocales()
{
LocaleConstant locale = (LocaleConstant) i;
- AddLocaleString(fields[1 + 15 * (i - 1)].GetString(), locale, data.Title);
- AddLocaleString(fields[1 + 15 * (i - 1) + 1].GetString(), locale, data.Details);
- AddLocaleString(fields[1 + 15 * (i - 1) + 2].GetString(), locale, data.Objectives);
+ AddLocaleString(fields[1 + 15 * (i - 1)].GetString(), locale, data.LogTitle);
+ AddLocaleString(fields[1 + 15 * (i - 1) + 1].GetString(), locale, data.LogDescription);
+ AddLocaleString(fields[1 + 15 * (i - 1) + 2].GetString(), locale, data.QuestDescription);
AddLocaleString(fields[1 + 15 * (i - 1) + 3].GetString(), locale, data.OfferRewardText);
AddLocaleString(fields[1 + 15 * (i - 1) + 4].GetString(), locale, data.RequestItemsText);
- AddLocaleString(fields[1 + 15 * (i - 1) + 5].GetString(), locale, data.EndText);
- AddLocaleString(fields[1 + 15 * (i - 1) + 6].GetString(), locale, data.CompletedText);
+ //AddLocaleString(fields[1 + 15 * (i - 1) + 5].GetString(), locale, data.EndText); Probably deprecated
+ AddLocaleString(fields[1 + 15 * (i - 1) + 6].GetString(), locale, data.QuestCompletionLog);
+ data.ObjectiveDescription.resize(4);
for (uint8 k = 0; k < 4; ++k)
- AddLocaleString(fields[1 + 15 * (i - 1) + 7 + k].GetString(), locale, data.ObjectiveText[k]);
+ AddLocaleString(fields[1 + 15 * (i - 1) + 7 + k].GetString(), locale, data.ObjectiveDescription[k]);
- AddLocaleString(fields[1 + 15 * (i - 1) + 11].GetString(), locale, data.QuestGiverTextWindow);
- AddLocaleString(fields[1 + 15 * (i - 1) + 12].GetString(), locale, data.QuestGiverTargetName);
- AddLocaleString(fields[1 + 15 * (i - 1) + 13].GetString(), locale, data.QuestTurnTextWindow);
- AddLocaleString(fields[1 + 15 * (i - 1) + 14].GetString(), locale, data.QuestTurnTargetName);
+ AddLocaleString(fields[1 + 15 * (i - 1) + 11].GetString(), locale, data.PortraitGiverText);
+ AddLocaleString(fields[1 + 15 * (i - 1) + 12].GetString(), locale, data.PortraitGiverName);
+ AddLocaleString(fields[1 + 15 * (i - 1) + 13].GetString(), locale, data.PortraitTurnInText);
+ AddLocaleString(fields[1 + 15 * (i - 1) + 14].GetString(), locale, data.PortraitTurnInName);
}
} while (result->NextRow());
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 706d45c1bc4..86256eb08e4 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -101,6 +101,10 @@ bool LoginQueryHolder::Initialize()
stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS, stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES);
+ stmt->setUInt64(0, lowGuid);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES, stmt);
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY);
stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS, stmt);
@@ -2083,7 +2087,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res
{
Quest const* quest = iter->second;
uint32 newRaceMask = (newTeamId == TEAM_ALLIANCE) ? RACEMASK_ALLIANCE : RACEMASK_HORDE;
- if (quest->GetRequiredRaces() && !(quest->GetRequiredRaces() & newRaceMask))
+ if (quest->GetAllowableRaces() != -1 && !(quest->GetAllowableRaces() & newRaceMask))
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST);
stmt->setUInt64(0, lowGuid);
diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp
index 78f15b1fda7..2c5bb78867a 100644
--- a/src/server/game/Handlers/LFGHandler.cpp
+++ b/src/server/game/Handlers/LFGHandler.cpp
@@ -52,8 +52,8 @@ void BuildQuestReward(WorldPacket& data, Quest const* quest, Player* player)
{
uint8 rewCount = quest->GetRewItemsCount() + quest->GetRewCurrencyCount();
- data << uint32(quest->GetRewOrReqMoney());
- data << uint32(quest->XPValue(player));
+ data << uint32(quest->GetRewMoney());
+ data << uint32(player->GetQuestXPReward(quest));
data << uint8(rewCount);
if (rewCount)
{
@@ -68,14 +68,14 @@ void BuildQuestReward(WorldPacket& data, Quest const* quest, Player* player)
}
}
- for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
+ for (uint8 i = 0; i < QUEST_REWARD_ITEM_COUNT; ++i)
{
if (uint32 itemId = quest->RewardItemId[i])
{
ItemTemplate const* item = sObjectMgr->GetItemTemplate(itemId);
data << uint32(itemId);
data << uint32(/*item ? item->DisplayInfoID :*/ 0);
- data << uint32(quest->RewardItemIdCount[i]);
+ data << uint32(quest->RewardItemCount[i]);
data << uint8(0); // Is currency
}
}
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index e97b7f1c247..c27def4a82c 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -922,9 +922,26 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recvData)
return;
if (player->IsAlive())
+ {
if (uint32 questId = sObjectMgr->GetQuestForAreaTrigger(triggerId))
- if (player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE)
- player->AreaExploredOrEventHappens(questId);
+ {
+ Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
+ if (qInfo && player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE)
+ {
+ for (uint8 j = 0; j < qInfo->Objectives.size(); ++j)
+ {
+ if (qInfo->Objectives[j].Type == QUEST_OBJECTIVE_AREATRIGGER)
+ {
+ player->SetQuestObjectiveData(qInfo, j, int32(true));
+ break;
+ }
+ }
+
+ if (player->CanCompleteQuest(questId))
+ player->CompleteQuest(questId);
+ }
+ }
+ }
if (sObjectMgr->IsTavernAreaTrigger(triggerId))
{
diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp
index f591a5fa988..851e6e89e97 100644
--- a/src/server/game/Handlers/QuestHandler.cpp
+++ b/src/server/game/Handlers/QuestHandler.cpp
@@ -68,18 +68,15 @@ void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPackets::Quest::QuestG
_player->PlayerTalkClass->SendQuestGiverStatus(questStatus, packet.QuestGiverGUID);
}
-void WorldSession::HandleQuestgiverHelloOpcode(WorldPacket& recvData)
+void WorldSession::HandleQuestgiverHelloOpcode(WorldPackets::Quest::QuestGiverHello& packet)
{
- ObjectGuid guid;
- recvData >> guid;
-
- TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_HELLO %s", guid.ToString().c_str());
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_HELLO %s", packet.QuestGiverGUID.ToString().c_str());
- Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_NONE);
+ Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(packet.QuestGiverGUID, UNIT_NPC_FLAG_NONE);
if (!creature)
{
TC_LOG_DEBUG("network", "WORLD: HandleQuestgiverHelloOpcode - %s not found or you can't interact with him.",
- guid.ToString().c_str());
+ packet.QuestGiverGUID.ToString().c_str());
return;
}
@@ -236,34 +233,28 @@ void WorldSession::HandleQuestgiverQueryQuestOpcode(WorldPacket& recvData)
}
}
-void WorldSession::HandleQuestQueryOpcode(WorldPacket& recvData)
+void WorldSession::HandleQuestQueryOpcode(WorldPackets::Quest::QueryQuestInfo& packet)
{
if (!_player)
return;
- uint32 questId;
- recvData >> questId;
- TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUEST_QUERY quest = %u", questId);
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUEST_QUERY quest = %u", packet.QuestID);
- if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
+ if (Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID))
_player->PlayerTalkClass->SendQuestQueryResponse(quest);
}
-void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
+void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::QuestGiverChooseReward& packet)
{
- uint32 questId, reward;
- ObjectGuid guid;
- recvData >> guid >> questId >> reward;
-
- if (reward >= QUEST_REWARD_CHOICES_COUNT)
+ if (packet.ItemChoiceID >= QUEST_REWARD_CHOICES_COUNT)
{
- TC_LOG_ERROR("network", "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (%s) tried to get invalid reward (%u) (possible packet-hacking detected)", _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), reward);
+ TC_LOG_ERROR("network", "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player %s (%s) tried to get invalid reward (%u) (possible packet-hacking detected)", _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), packet.ItemChoiceID);
return;
}
- TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = %s, quest = %u, reward = %u", guid.ToString().c_str(), questId, reward);
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = %s, quest = %u, reward = %u", packet.QuestGiverGUID.ToString().c_str(), packet.QuestID, packet.ItemChoiceID);
- Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
+ Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID);
if (!quest)
return;
@@ -271,8 +262,8 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
if (!quest->HasFlag(QUEST_FLAGS_AUTOCOMPLETE))
{
- object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
- if (!object || !object->hasInvolvedQuest(questId))
+ object = ObjectAccessor::GetObjectByTypeMask(*_player, packet.QuestGiverGUID, TYPEMASK_UNIT|TYPEMASK_GAMEOBJECT);
+ if (!object || !object->hasInvolvedQuest(packet.QuestID))
return;
// some kind of WPE protection
@@ -280,17 +271,17 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
return;
}
- if ((!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(questId) == QUEST_STATUS_NONE) ||
- (_player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE && !quest->IsAutoComplete()))
+ if ((!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(packet.QuestID) == QUEST_STATUS_NONE) ||
+ (_player->GetQuestStatus(packet.QuestID) != QUEST_STATUS_COMPLETE && !quest->IsAutoComplete()))
{
TC_LOG_ERROR("network", "Error in QUEST_STATUS_COMPLETE: player %s (%s) tried to complete quest %u, but is not allowed to do so (possible packet-hacking or high latency)",
- _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), questId);
+ _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), packet.QuestID);
return;
}
- if (_player->CanRewardQuest(quest, reward, true))
+ if (_player->CanRewardQuest(quest, packet.ItemChoiceID, true))
{
- _player->RewardQuest(quest, reward, object);
+ _player->RewardQuest(quest, packet.ItemChoiceID, object);
switch (object->GetTypeId())
{
@@ -299,10 +290,10 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
{
//For AutoSubmition was added plr case there as it almost same exclute AI script cases.
Creature* creatureQGiver = object->ToCreature();
- if (!creatureQGiver || !sScriptMgr->OnQuestReward(_player, creatureQGiver, quest, reward))
+ if (!creatureQGiver || !sScriptMgr->OnQuestReward(_player, creatureQGiver, quest, packet.ItemChoiceID))
{
// Send next quest
- if (Quest const* nextQuest = _player->GetNextQuest(guid, quest))
+ if (Quest const* nextQuest = _player->GetNextQuest(packet.QuestGiverGUID, quest))
{
// Only send the quest to the player if the conditions are met
if (_player->CanTakeQuest(nextQuest, false))
@@ -310,22 +301,22 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true))
_player->AddQuestAndCheckCompletion(nextQuest, object);
- _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
+ _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, packet.QuestGiverGUID, true);
}
}
if (creatureQGiver)
- creatureQGiver->AI()->sQuestReward(_player, quest, reward);
+ creatureQGiver->AI()->sQuestReward(_player, quest, packet.ItemChoiceID);
}
break;
}
case TYPEID_GAMEOBJECT:
{
GameObject* questGiver = object->ToGameObject();
- if (!sScriptMgr->OnQuestReward(_player, questGiver, quest, reward))
+ if (!sScriptMgr->OnQuestReward(_player, questGiver, quest, packet.ItemChoiceID))
{
// Send next quest
- if (Quest const* nextQuest = _player->GetNextQuest(guid, quest))
+ if (Quest const* nextQuest = _player->GetNextQuest(packet.QuestGiverGUID, quest))
{
// Only send the quest to the player if the conditions are met
if (_player->CanTakeQuest(nextQuest, false))
@@ -333,11 +324,11 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
if (nextQuest->IsAutoAccept() && _player->CanAddQuest(nextQuest, true))
_player->AddQuestAndCheckCompletion(nextQuest, object);
- _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, guid, true);
+ _player->PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, packet.QuestGiverGUID, true);
}
}
- questGiver->AI()->QuestReward(_player, quest, reward);
+ questGiver->AI()->QuestReward(_player, quest, packet.ItemChoiceID);
}
break;
}
@@ -346,7 +337,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPacket& recvData)
}
}
else
- _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, guid, true);
+ _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, packet.QuestGiverGUID, true);
}
void WorldSession::HandleQuestgiverRequestRewardOpcode(WorldPacket& recvData)
@@ -471,16 +462,13 @@ void WorldSession::HandleQuestConfirmAccept(WorldPacket& recvData)
}
}
-void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recvData)
+void WorldSession::HandleQuestgiverCompleteQuest(WorldPackets::Quest::QuestGiverCompleteQuest& packet)
{
- uint32 questId;
- ObjectGuid guid; // NPC / GameObject guid for normal quest completion. Player guid for self-completed quests
- bool autoCompleteMode; // 0 - standart complete quest mode with npc, 1 - auto-complete mode
- recvData >> guid >> questId >> autoCompleteMode;
+ bool autoCompleteMode = packet.FromScript; // 0 - standart complete quest mode with npc, 1 - auto-complete mode
- TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %s, questId = %u self-complete: %u", guid.ToString().c_str(), questId, autoCompleteMode ? 1 : 0);
+ TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = %s, questId = %u self-complete: %u", packet.QuestGiverGUID.ToString().c_str(), packet.QuestID, autoCompleteMode ? 1 : 0);
- Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
+ Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID);
if (!quest)
return;
@@ -491,14 +479,14 @@ void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recvData)
if (autoCompleteMode)
object = _player;
else
- object = ObjectAccessor::GetObjectByTypeMask(*_player, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT);
+ object = ObjectAccessor::GetObjectByTypeMask(*_player, packet.QuestGiverGUID, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT);
if (!object)
return;
if (autoCompleteMode == 0)
{
- if (!object->hasInvolvedQuest(questId))
+ if (!object->hasInvolvedQuest(packet.QuestID))
return;
// some kind of WPE protection
@@ -508,33 +496,33 @@ void WorldSession::HandleQuestgiverCompleteQuest(WorldPacket& recvData)
else
{
// Do not allow completing quests on other players.
- if (guid != _player->GetGUID())
+ if (packet.QuestGiverGUID != _player->GetGUID())
return;
}
- if (!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(questId) == QUEST_STATUS_NONE)
+ if (!_player->CanSeeStartQuest(quest) && _player->GetQuestStatus(packet.QuestID) == QUEST_STATUS_NONE)
{
TC_LOG_ERROR("network", "Possible hacking attempt: Player %s [%s] tried to complete quest [entry: %u] without being in possession of the quest!",
- _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), questId);
+ _player->GetName().c_str(), _player->GetGUID().ToString().c_str(), packet.QuestID);
return;
}
if (Battleground* bg = _player->GetBattleground())
- bg->HandleQuestComplete(questId, _player);
+ bg->HandleQuestComplete(packet.QuestID, _player);
- if (_player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE)
+ if (_player->GetQuestStatus(packet.QuestID) != QUEST_STATUS_COMPLETE)
{
if (quest->IsRepeatable())
- _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, _player->CanCompleteRepeatableQuest(quest), false);
+ _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, _player->CanCompleteRepeatableQuest(quest), false);
else
- _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, _player->CanRewardQuest(quest, false), false);
+ _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, _player->CanRewardQuest(quest, false), false);
}
else
{
- if (quest->GetReqItemsCount()) // some items required
- _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, guid, _player->CanRewardQuest(quest, false), false);
+ if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_DELIVER)) // some items required
+ _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, _player->CanRewardQuest(quest, false), false);
else // no items required
- _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, guid, true);
+ _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, packet.QuestGiverGUID, true);
}
}
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index c81ba4f4bbe..d39da48b3b6 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -3725,8 +3725,8 @@ enum HolidayIds
// QuestInfo.dbc (6.0.2.18988)
enum QuestTypes
{
- QUEST_TYPE_ELITE = 1, // Group
- QUEST_TYPE_LIFE = 21, // Class
+ QUEST_TYPE_GROUP = 1,
+ QUEST_TYPE_CLASS = 21,
QUEST_TYPE_PVP = 41,
QUEST_TYPE_RAID = 62,
QUEST_TYPE_DUNGEON = 81,
diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp
index 3d9ee0367d5..691ac68e5c5 100644
--- a/src/server/game/Quests/QuestDef.cpp
+++ b/src/server/game/Quests/QuestDef.cpp
@@ -20,201 +20,211 @@
#include "Player.h"
#include "World.h"
#include "ObjectMgr.h"
+#include "QuestPackets.h"
Quest::Quest(Field* questRecord)
{
Id = questRecord[0].GetUInt32();
Method = questRecord[1].GetUInt8();
- Level = questRecord[2].GetInt16();
- MinLevel = uint32(questRecord[3].GetInt16());
- MaxLevel = uint32(questRecord[4].GetInt16());
+ Level = questRecord[2].GetInt32();
+ PackageID = questRecord[3].GetUInt32();
+ MinLevel = questRecord[4].GetUInt32();
ZoneOrSort = questRecord[5].GetInt16();
Type = questRecord[6].GetUInt16();
SuggestedPlayers = questRecord[7].GetUInt8();
- LimitTime = questRecord[8].GetUInt32();
- RequiredClasses = questRecord[9].GetUInt16();
- RequiredRaces = questRecord[10].GetUInt32();
- RequiredSkillId = questRecord[11].GetUInt16();
- RequiredSkillPoints = questRecord[12].GetUInt16();
- RequiredFactionId1 = questRecord[13].GetUInt16();
- RequiredFactionId2 = questRecord[14].GetUInt16();
- RequiredFactionValue1 = questRecord[15].GetInt32();
- RequiredFactionValue2 = questRecord[16].GetInt32();
- RequiredMinRepFaction = questRecord[17].GetUInt16();
- RequiredMaxRepFaction = questRecord[18].GetUInt16();
- RequiredMinRepValue = questRecord[19].GetInt32();
- RequiredMaxRepValue = questRecord[20].GetInt32();
- PrevQuestId = questRecord[21].GetInt32();
- NextQuestId = questRecord[22].GetInt32();
- ExclusiveGroup = questRecord[23].GetInt32();
- NextQuestIdChain = questRecord[24].GetUInt32();
- RewardXPId = questRecord[25].GetUInt8();
- RewardOrRequiredMoney = questRecord[26].GetInt32();
- RewardMoneyMaxLevel = questRecord[27].GetUInt32();
- RewardSpell = questRecord[28].GetUInt32();
- RewardSpellCast = questRecord[29].GetInt32();
- RewardHonor = questRecord[30].GetUInt32();
- RewardHonorMultiplier = questRecord[31].GetFloat();
- RewardMailTemplateId = questRecord[32].GetUInt32();
- RewardMailDelay = questRecord[33].GetUInt32();
- SourceItemId = questRecord[34].GetUInt32();
- SourceItemIdCount = questRecord[35].GetUInt8();
- SourceSpellid = questRecord[36].GetUInt32();
- Flags = questRecord[37].GetUInt32();
- SpecialFlags = questRecord[38].GetUInt8();
- MinimapTargetMark = questRecord[39].GetUInt8();
- RewardTitleId = questRecord[40].GetUInt8();
- RequiredPlayerKills = questRecord[41].GetUInt8();
- RewardTalents = questRecord[42].GetUInt8();
- RewardArenaPoints = questRecord[43].GetUInt16();
- RewardSkillId = questRecord[44].GetUInt16();
- RewardSkillPoints = questRecord[45].GetUInt8();
- RewardReputationMask = questRecord[46].GetUInt8();
- QuestGiverPortrait = questRecord[47].GetUInt32();
- QuestTurnInPortrait = questRecord[48].GetUInt32();
- for (int i = 0; i < QUEST_REWARDS_COUNT; ++i)
- RewardItemId[i] = questRecord[49+i].GetUInt32();
-
- for (int i = 0; i < QUEST_REWARDS_COUNT; ++i)
- RewardItemIdCount[i] = questRecord[53+i].GetUInt16();
-
- for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
- RewardChoiceItemId[i] = questRecord[57+i].GetUInt32();
-
- for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
- RewardChoiceItemCount[i] = questRecord[63+i].GetUInt16();
-
- for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
- RewardFactionId[i] = questRecord[69+i].GetUInt16();
-
- for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
- RewardFactionValueId[i] = questRecord[74+i].GetInt32();
+ NextQuestInChain = questRecord[8].GetUInt32();
+ RewardXPDifficulty = questRecord[9].GetUInt32();
+ Float10 = questRecord[10].GetFloat();
+ RewardMoney = questRecord[11].GetUInt32();
+ RewardMoneyDifficulty = questRecord[12].GetUInt32();
+ Float13 = questRecord[13].GetFloat();
+ RewardBonusMoney = questRecord[14].GetUInt32();
+ RewardDisplaySpell = questRecord[15].GetUInt32();
+ RewardSpell = questRecord[16].GetUInt32();
+ RewardHonor = questRecord[17].GetUInt32();
+ RewardKillHonor = questRecord[18].GetUInt32();
+ SourceItemId = questRecord[19].GetUInt32();
+ Flags = questRecord[20].GetUInt32();
+ FlagsEx = questRecord[21].GetUInt32();
+
+ for (uint32 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i)
+ {
+ RewardItemId[i] = questRecord[22+i].GetUInt32();
+ RewardItemCount[i] = questRecord[23+i].GetUInt32();
+ ItemDrop[i] = questRecord[24+i].GetUInt32();
+ ItemDropQuantity[i] = questRecord[25+i].GetUInt32();
+ }
- for (int i = 0; i < QUEST_REPUTATIONS_COUNT; ++i)
- RewardFactionValueIdOverride[i] = questRecord[79+i].GetInt32();
+ for (uint32 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
+ {
+ RewardChoiceItemId[i] = questRecord[38+i].GetUInt32();
+ RewardChoiceItemCount[i] = questRecord[39+i].GetUInt32();
+ RewardChoiceItemDisplayId[i] = questRecord[40+i].GetUInt32();
+ }
- PointMapId = questRecord[84].GetUInt16();
- PointX = questRecord[85].GetFloat();
- PointY = questRecord[86].GetFloat();
- PointOption = questRecord[87].GetUInt32();
- Title = questRecord[88].GetString();
- Objectives = questRecord[89].GetString();
- Details = questRecord[90].GetString();
- EndText = questRecord[91].GetString();
- CompletedText = questRecord[92].GetString();
- OfferRewardText = questRecord[93].GetString();
- RequestItemsText = questRecord[94].GetString();
+ POIContinent = questRecord[56].GetUInt32();
+ POIx = questRecord[57].GetFloat();
+ POIy = questRecord[58].GetFloat();
+ POIPriority = questRecord[59].GetUInt32();
- for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- RequiredNpcOrGo[i] = questRecord[95+i].GetInt32();
+ RewardTitleId = questRecord[60].GetUInt32();
+ RewardTalents = questRecord[61].GetUInt32();
+ RewardArenaPoints = questRecord[62].GetUInt32();
+ RewardSkillId = questRecord[63].GetUInt32();
+ RewardSkillPoints = questRecord[64].GetUInt32();
- for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- RequiredNpcOrGoCount[i] = questRecord[99+i].GetUInt16();
+ QuestGiverPortrait = questRecord[65].GetUInt32();
+ QuestTurnInPortrait = questRecord[66].GetUInt32();
- for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
- RequiredSourceItemId[i] = questRecord[103+i].GetUInt32();
+ for (uint32 i = 0; i < QUEST_REWARD_REPUTATIONS_COUNT; ++i)
+ {
+ RewardFactionId[i] = questRecord[67+i].GetUInt32();
+ RewardFactionValue[i] = questRecord[68+i].GetInt32();
+ RewardFactionOverride[i] = questRecord[69+i].GetInt32();
+ }
- for (int i = 0; i < QUEST_SOURCE_ITEM_IDS_COUNT; ++i)
- RequiredSourceItemCount[i] = questRecord[107+i].GetUInt16();
+ RewardReputationMask = questRecord[82].GetUInt32();
- for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
- RequiredItemId[i] = questRecord[111+i].GetUInt32();
+ for (uint32 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
+ {
+ RewardCurrencyId[i] = questRecord[83+i].GetUInt32();
+ RewardCurrencyCount[i] = questRecord[84+i].GetUInt32();
+ }
- for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
- RequiredItemCount[i] = questRecord[117+i].GetUInt16();
+ SoundAccept = questRecord[91].GetUInt32();
+ SoundTurnIn = questRecord[92].GetUInt32();
+ AreaGroupID = questRecord[93].GetUInt32();
+ LimitTime = questRecord[94].GetUInt32();
+ AllowableRaces = questRecord[95].GetInt32();
+
+ LogTitle = questRecord[96].GetString();
+ LogDescription = questRecord[97].GetString();
+ QuestDescription = questRecord[98].GetString();
+ AreaDescription = questRecord[99].GetString();
+ PortraitGiverText = questRecord[100].GetString();
+ PortraitGiverName = questRecord[101].GetString();
+ PortraitTurnInText = questRecord[102].GetString();
+ PortraitTurnInName = questRecord[103].GetString();
+ QuestCompletionLog = questRecord[104].GetString();
- RequiredSpell = questRecord[123].GetUInt32();
+ _rewItemsCount = 0;
+ _rewChoiceItemsCount = 0;
+ _rewCurrencyCount = 0;
- for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- ObjectiveText[i] = questRecord[124+i].GetString();
+ for (int i = 0; i < QUEST_REWARD_ITEM_COUNT; ++i)
+ if (RewardItemId[i])
+ ++_rewItemsCount;
- for (int i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
- RewardCurrencyId[i] = questRecord[128+i].GetUInt16();
+ for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
+ if (RewardChoiceItemId[i])
+ ++_rewChoiceItemsCount;
for (int i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
- RewardCurrencyCount[i] = questRecord[132+i].GetUInt8();
-
- for (int i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i)
- RequiredCurrencyId[i] = questRecord[136+i].GetUInt16();
-
- for (int i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i)
- RequiredCurrencyCount[i] = questRecord[140+i].GetUInt8();
-
- QuestGiverTextWindow = questRecord[144].GetString();
- QuestGiverTargetName = questRecord[145].GetString();
- QuestTurnTextWindow = questRecord[146].GetString();
- QuestTurnTargetName = questRecord[147].GetString();
- SoundAccept = questRecord[148].GetUInt16();
- SoundTurnIn = questRecord[149].GetUInt16();
+ if (RewardCurrencyId[i])
+ ++_rewCurrencyCount;
+}
+void Quest::LoadQuestDetails(Field* fields)
+{
for (int i = 0; i < QUEST_EMOTE_COUNT; ++i)
- DetailsEmote[i] = questRecord[150+i].GetUInt16();
+ DetailsEmote[i] = fields[1+i].GetUInt16();
for (int i = 0; i < QUEST_EMOTE_COUNT; ++i)
- DetailsEmoteDelay[i] = questRecord[154+i].GetUInt32();
+ DetailsEmoteDelay[i] = fields[5+i].GetUInt32();
+}
+
+void Quest::LoadQuestRequestItems(Field* fields)
+{
+ EmoteOnComplete = fields[1].GetUInt16();
+ EmoteOnIncomplete = fields[2].GetUInt16();
+ EmoteOnCompleteDelay = fields[3].GetUInt32();
+ EmoteOnIncompleteDelay = fields[4].GetUInt32();
+ RequestItemsText = fields[5].GetString();
+}
- EmoteOnIncomplete = questRecord[158].GetUInt16();
- EmoteOnComplete = questRecord[159].GetUInt16();
+void Quest::LoadQuestOfferReward(Field* fields)
+{
for (int i = 0; i < QUEST_EMOTE_COUNT; ++i)
- OfferRewardEmote[i] = questRecord[160+i].GetInt16();
+ OfferRewardEmote[i] = fields[1+i].GetUInt16();
for (int i = 0; i < QUEST_EMOTE_COUNT; ++i)
- OfferRewardEmoteDelay[i] = questRecord[164+i].GetInt32();
+ OfferRewardEmoteDelay[i] = fields[5+i].GetUInt32();
- //int32 VerifiedBuild = questRecord[168].GetInt32();
+ OfferRewardText = fields[9].GetString();
+}
+
+void Quest::LoadQuestTemplateAddon(Field* fields)
+{
+ MaxLevel = fields[1].GetUInt8();
+ AllowableClasses = fields[2].GetUInt32();
+ SourceSpellID = fields[3].GetUInt32();
+ PrevQuestID = fields[4].GetInt32();
+ NextQuestID = fields[5].GetInt32();
+ ExclusiveGroup = fields[6].GetInt32();
+ RewardMailTemplateId = fields[7].GetUInt32();
+ RewardMailDelay = fields[8].GetUInt32();
+ RequiredSkillId = fields[9].GetUInt16();
+ RequiredSkillPoints = fields[10].GetUInt16();
+ RequiredMinRepFaction = fields[11].GetUInt16();
+ RequiredMaxRepFaction = fields[12].GetUInt16();
+ RequiredMinRepValue = fields[13].GetInt32();
+ RequiredMaxRepValue = fields[14].GetInt32();
+ SourceItemIdCount = fields[15].GetUInt8();
+ SpecialFlags = fields[16].GetUInt8();
if (SpecialFlags & QUEST_SPECIAL_FLAGS_AUTO_ACCEPT)
Flags |= QUEST_FLAGS_AUTO_ACCEPT;
+}
- _reqItemsCount = 0;
- _reqNpcOrGoCount = 0;
- _rewItemsCount = 0;
- _rewChoiceItemsCount = 0;
- _rewCurrencyCount = 0;
- _reqCurrencyCount = 0;
-
- for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; ++i)
- if (RequiredItemId[i])
- ++_reqItemsCount;
-
- for (int i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- if (RequiredNpcOrGo[i])
- ++_reqNpcOrGoCount;
+void Quest::LoadQuestObjective(Field* fields)
+{
+ uint8 storageIndex = fields[3].GetUInt8();
+
+ // Allocate space
+ if (storageIndex >= Objectives.size())
+ Objectives.resize(storageIndex+1);
+
+ QuestObjective& obj = Objectives[storageIndex];
+ obj.ID = fields[0].GetUInt32();
+ obj.Type = fields[2].GetUInt8();
+ obj.StorageIndex = storageIndex;
+ obj.ObjectID = fields[4].GetInt32();
+ obj.Amount = fields[5].GetInt32();
+ obj.Flags = fields[6].GetUInt32();
+ obj.UnkFloat = fields[7].GetFloat();
+ obj.Description = fields[8].GetString();
+}
- for (int i = 0; i < QUEST_REWARDS_COUNT; ++i)
- if (RewardItemId[i])
- ++_rewItemsCount;
+void Quest::LoadQuestObjectiveVisualEffect(Field* fields)
+{
+ // No need to check index because checks is objective exists are done in ObjectMgr while loading quest_visual_effect
+ uint8 storageIndex = fields[3].GetUInt8();
+ QuestObjective& obj = Objectives[storageIndex];
- for (int i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
- if (RewardChoiceItemId[i])
- ++_rewChoiceItemsCount;
+ uint8 effectIndex = fields[4].GetUInt8();
+ if (effectIndex >= obj.VisualEffects.size())
+ obj.VisualEffects.resize(effectIndex+1, 0);
- for (int i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
- if (RewardCurrencyId[i])
- ++_rewCurrencyCount;
-
- for (int i = 0; i < QUEST_REQUIRED_CURRENCY_COUNT; ++i)
- if (RequiredCurrencyId[i])
- ++_reqCurrencyCount;
+ obj.VisualEffects[effectIndex] = fields[5].GetInt32();
}
-uint32 Quest::XPValue(Player* player) const
+uint32 Quest::XPValue(uint32 playerLevel) const
{
- if (player)
+ if (playerLevel)
{
- int32 quest_level = (Level == -1 ? player->getLevel() : Level);
+ int32 quest_level = (Level == -1 ? playerLevel : Level);
const QuestXPEntry* xpentry = sQuestXPStore.LookupEntry(quest_level);
if (!xpentry)
return 0;
- int32 diffFactor = 2 * (quest_level - player->getLevel()) + 20;
+ int32 diffFactor = 2 * (quest_level - playerLevel) + 20;
if (diffFactor < 1)
diffFactor = 1;
else if (diffFactor > 10)
diffFactor = 10;
- uint32 xp = diffFactor * xpentry->Exp[RewardXPId] / 10;
+ uint32 xp = diffFactor * xpentry->Exp[RewardXPDifficulty] / 10;
if (xp <= 100)
xp = 5 * ((xp + 2) / 5);
else if (xp <= 500)
@@ -230,14 +240,9 @@ uint32 Quest::XPValue(Player* player) const
return 0;
}
-int32 Quest::GetRewOrReqMoney() const
+int32 Quest::GetRewMoney() const
{
- // RequiredMoney: the amount is the negative copper sum.
- if (RewardOrRequiredMoney <= 0)
- return RewardOrRequiredMoney;
-
- // RewardMoney: the positive amount
- return int32(RewardOrRequiredMoney * sWorld->getRate(RATE_MONEY_QUEST));
+ return int32(RewardMoney * sWorld->getRate(RATE_MONEY_QUEST));
}
void Quest::BuildExtraQuestInfo(WorldPacket& data, Player* player) const
@@ -255,12 +260,12 @@ void Quest::BuildExtraQuestInfo(WorldPacket& data, Player* player) const
data << uint32(0);
}
- data << uint32(GetReqItemsCount());
- for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
+ data << uint32(GetRewItemsCount());
+ for (uint8 i = 0; i < QUEST_REWARD_ITEM_COUNT; ++i)
data << uint32(RewardItemId[i]);
- for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
- data << uint32(RewardItemIdCount[i]);
- for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i)
+ for (uint8 i = 0; i < QUEST_REWARD_ITEM_COUNT; ++i)
+ data << uint32(RewardItemCount[i]);
+ for (uint8 i = 0; i < QUEST_REWARD_ITEM_COUNT; ++i)
{
if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(RewardItemId[i]))
data << uint32(/*itemTemplate->DisplayInfoID*/);
@@ -268,10 +273,10 @@ void Quest::BuildExtraQuestInfo(WorldPacket& data, Player* player) const
data << uint32(0);
}
- data << uint32(GetRewOrReqMoney());
- data << uint32(XPValue(player) * sWorld->getRate(RATE_XP_QUEST));
+ data << uint32(GetRewMoney());
+ data << uint32(player->GetQuestXPReward(this));
- data << uint32(GetCharTitleId());
+ data << uint32(GetRewTitle());
data << uint32(0); // unk
data << float(0.0f); // unk
data << uint32(GetBonusTalents());
@@ -283,25 +288,25 @@ void Quest::BuildExtraQuestInfo(WorldPacket& data, Player* player) const
data << 10 * Trinity::Honor::hk_honor_at_level(_session->GetPlayer()->getLevel(), quest->GetRewHonorMultiplier());
data << float(0); // unk, honor multiplier?
data << uint32(0x08); // unused by client?
- data << uint32(quest->GetRewSpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast == 0)
- data << int32(quest->GetRewSpellCast()); // casted spell
+ data << uint32(quest->GetRewDisplaySpell()); // reward spell, this spell will display (icon) (casted if RewSpellCast == 0)
+ data << int32(quest->GetRewSpell()); // casted spell
data << uint32(0); // unknown
data << uint32(quest->GetBonusTalents()); // bonus talents
data << uint32(quest->GetRewArenaPoints()); // arena points
data << uint32(0);
*/
- for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward factions ids
+ for (uint8 i = 0; i < QUEST_REWARD_REPUTATIONS_COUNT; ++i) // reward factions ids
data << uint32(RewardFactionId[i]);
- for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // columnid in QuestFactionReward.dbc (zero based)?
- data << int32(RewardFactionValueId[i]);
+ for (uint8 i = 0; i < QUEST_REWARD_REPUTATIONS_COUNT; ++i) // columnid in QuestFactionReward.dbc (zero based)?
+ data << int32(RewardFactionValue[i]);
- for (uint8 i = 0; i < QUEST_REPUTATIONS_COUNT; ++i) // reward reputation override?
- data << uint32(RewardFactionValueIdOverride[i]);
+ for (uint8 i = 0; i < QUEST_REWARD_REPUTATIONS_COUNT; ++i) // reward reputation override?
+ data << uint32(RewardFactionOverride[i]);
+ data << uint32(GetRewDisplaySpell());
data << uint32(GetRewSpell());
- data << uint32(GetRewSpellCast());
for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
data << uint32(RewardCurrencyId[i]);
@@ -313,6 +318,46 @@ void Quest::BuildExtraQuestInfo(WorldPacket& data, Player* player) const
data << uint32(GetRewardSkillPoints());
}
+void Quest::BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player) const
+{
+ rewards.ChoiceItemCount = GetRewChoiceItemsCount();
+ rewards.ItemCount = GetRewItemsCount();
+ rewards.Money = GetRewMoney();
+ rewards.XP = player->GetQuestXPReward(this);
+ rewards.Title = GetRewTitle();
+ rewards.Talents = GetBonusTalents();
+ rewards.FactionFlags = GetRewardReputationMask();
+ rewards.SpellCompletionDisplayID = GetRewDisplaySpell();
+ rewards.SpellCompletionID = GetRewSpell();
+ rewards.SkillLineID = GetRewardSkillId();
+ rewards.NumSkillUps = GetRewardSkillPoints();
+
+ for (uint32 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
+ {
+ rewards.ChoiceItems[i].ItemID = RewardChoiceItemId[i];
+ rewards.ChoiceItems[i].Quantity = RewardChoiceItemCount[i];
+ }
+
+ for (uint32 i = 0; i < QUEST_REWARD_ITEM_COUNT; ++i)
+ {
+ rewards.ItemID[i] = RewardItemId[i];
+ rewards.ItemQty[i] = RewardItemCount[i];
+ }
+
+ for (uint32 i = 0; i < QUEST_REWARD_REPUTATIONS_COUNT; ++i)
+ {
+ rewards.FactionID[i] = RewardFactionId[i];
+ rewards.FactionValue[i] = RewardFactionValue[i];
+ rewards.FactionOverride[i] = RewardFactionOverride[i];
+ }
+
+ for (uint32 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
+ {
+ rewards.CurrencyID[i] = RewardCurrencyId[i];
+ rewards.CurrencyQty[i] = RewardCurrencyCount[i];
+ }
+}
+
uint32 Quest::GetRewMoneyMaxLevel() const
{
// If Quest has flag to not give money on max level, it's 0
@@ -320,7 +365,7 @@ uint32 Quest::GetRewMoneyMaxLevel() const
return 0;
// Else, return the rewarded copper sum modified by the rate
- return uint32(RewardMoneyMaxLevel * sWorld->getRate(RATE_MONEY_MAX_LEVEL_QUEST));
+ return uint32(RewardBonusMoney * sWorld->getRate(RATE_MONEY_MAX_LEVEL_QUEST));
}
bool Quest::IsAutoAccept() const
diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h
index 79b7a4b428e..1c3cbef2702 100644
--- a/src/server/game/Quests/QuestDef.h
+++ b/src/server/game/Quests/QuestDef.h
@@ -32,19 +32,23 @@ class Player;
class ObjectMgr;
+namespace WorldPackets
+{
+ namespace Quest
+ {
+ struct QuestRewards;
+ }
+}
+
#define MAX_QUEST_LOG_SIZE 25
-#define QUEST_OBJECTIVES_COUNT 4
-#define QUEST_ITEM_OBJECTIVES_COUNT 6
-#define QUEST_SOURCE_ITEM_IDS_COUNT 4
+#define QUEST_ITEM_DROP_COUNT 4
#define QUEST_REWARD_CHOICES_COUNT 6
-#define QUEST_REWARDS_COUNT 4
+#define QUEST_REWARD_ITEM_COUNT 4
#define QUEST_DEPLINK_COUNT 10
-#define QUEST_REPUTATIONS_COUNT 5
+#define QUEST_REWARD_REPUTATIONS_COUNT 5
#define QUEST_EMOTE_COUNT 4
-#define QUEST_PVP_KILL_SLOT 0
#define QUEST_REWARD_CURRENCY_COUNT 4
-#define QUEST_REQUIRED_CURRENCY_COUNT 4
enum QuestFailedReason
{
@@ -180,34 +184,74 @@ enum QuestSpecialFlags
QUEST_SPECIAL_FLAGS_PLAYER_KILL = 0x800 // Internal flag computed only
};
-struct QuestLocale
+enum QuestObjectiveType
{
- QuestLocale() { ObjectiveText.resize(QUEST_OBJECTIVES_COUNT); }
+ QUEST_OBJECTIVE_MONSTER = 0,
+ QUEST_OBJECTIVE_ITEM = 1,
+ QUEST_OBJECTIVE_GAMEOBJECT = 2,
+ QUEST_OBJECTIVE_TALKTO = 3,
+ QUEST_OBJECTIVE_CURRENCY = 4,
+ QUEST_OBJECTIVE_LEARNSPELL = 5,
+ QUEST_OBJECTIVE_MIN_REPUTATION = 6,
+ QUEST_OBJECTIVE_MAX_REPUTATION = 7,
+ QUEST_OBJECTIVE_MONEY = 8,
+ QUEST_OBJECTIVE_PLAYERKILLS = 9,
+ QUEST_OBJECTIVE_AREATRIGGER = 10,
+ QUEST_OBJECTIVE_WINPETBATTLEAGAINSTNPC = 11,
+ QUEST_OBJECTIVE_DEFEATBATTLEPET = 12,
+ QUEST_OBJECTIVE_WINPVPPETBATTLES = 13
+};
- StringVector Title;
- StringVector Details;
- StringVector Objectives;
+struct QuestLocale
+{
+ StringVector LogTitle;
+ StringVector LogDescription;
+ StringVector QuestDescription;
StringVector OfferRewardText;
StringVector RequestItemsText;
- StringVector EndText;
- StringVector CompletedText;
- std::vector< StringVector > ObjectiveText;
+ StringVector QuestCompletionLog;
+ std::vector< StringVector > ObjectiveDescription;
// new on 4.x
- StringVector QuestGiverTextWindow;
- StringVector QuestGiverTargetName;
- StringVector QuestTurnTextWindow;
- StringVector QuestTurnTargetName;
+ StringVector PortraitGiverText;
+ StringVector PortraitGiverName;
+ StringVector PortraitTurnInText;
+ StringVector PortraitTurnInName;
+};
+
+struct QuestObjective
+{
+ uint32 ID = 0;
+ uint8 Type = 0;
+ uint8 StorageIndex = 0;
+ int32 ObjectID = 0;
+ int32 Amount = 0;
+ uint32 Flags = 0;
+ float UnkFloat = 0.0f;
+ std::string Description;
+ std::vector<int32> VisualEffects;
};
+typedef std::vector<QuestObjective> QuestObjectives;
+
// This Quest class provides a convenient way to access a few pretotaled (cached) quest details,
// all base quest information, and any utility functions such as generating the amount of
// xp to give
class Quest
{
friend class ObjectMgr;
+ friend class Player;
+ friend class PlayerMenu;
public:
+ // Loading data. All queries are in ObjectMgr::LoadQuests()
Quest(Field* questRecord);
- uint32 XPValue(Player* player) const;
+ void LoadQuestDetails(Field* fields);
+ void LoadQuestRequestItems(Field* fields);
+ void LoadQuestOfferReward(Field* fields);
+ void LoadQuestTemplateAddon(Field* fields);
+ void LoadQuestObjective(Field* fields);
+ void LoadQuestObjectiveVisualEffect(Field* fields);
+
+ uint32 XPValue(uint32 playerLevel) const;
bool HasFlag(uint32 flag) const { return (Flags & flag) != 0; }
void SetFlag(uint32 flag) { Flags |= flag; }
@@ -218,61 +262,57 @@ class Quest
// table data accessors:
uint32 GetQuestId() const { return Id; }
uint32 GetQuestMethod() const { return Method; }
+ uint32 GetQuestPackageID() const { return PackageID; }
int32 GetZoneOrSort() const { return ZoneOrSort; }
uint32 GetMinLevel() const { return MinLevel; }
uint32 GetMaxLevel() const { return MaxLevel; }
int32 GetQuestLevel() const { return Level; }
uint32 GetType() const { return Type; }
- uint32 GetRequiredClasses() const { return RequiredClasses; }
- uint32 GetRequiredRaces() const { return RequiredRaces; }
+ uint32 GetAllowableClasses() const { return AllowableClasses; }
+ int32 GetAllowableRaces() const { return AllowableRaces; }
uint32 GetRequiredSkill() const { return RequiredSkillId; }
uint32 GetRequiredSkillValue() const { return RequiredSkillPoints; }
- uint32 GetRepObjectiveFaction() const { return RequiredFactionId1; }
- int32 GetRepObjectiveValue() const { return RequiredFactionValue1; }
- uint32 GetRepObjectiveFaction2() const { return RequiredFactionId2; }
- int32 GetRepObjectiveValue2() const { return RequiredFactionValue2; }
uint32 GetRequiredMinRepFaction() const { return RequiredMinRepFaction; }
int32 GetRequiredMinRepValue() const { return RequiredMinRepValue; }
uint32 GetRequiredMaxRepFaction() const { return RequiredMaxRepFaction; }
int32 GetRequiredMaxRepValue() const { return RequiredMaxRepValue; }
uint32 GetSuggestedPlayers() const { return SuggestedPlayers; }
uint32 GetLimitTime() const { return LimitTime; }
- int32 GetPrevQuestId() const { return PrevQuestId; }
- int32 GetNextQuestId() const { return NextQuestId; }
+ int32 GetPrevQuestId() const { return PrevQuestID; }
+ int32 GetNextQuestId() const { return NextQuestID; }
int32 GetExclusiveGroup() const { return ExclusiveGroup; }
- uint32 GetNextQuestInChain() const { return NextQuestIdChain; }
- uint32 GetCharTitleId() const { return RewardTitleId; }
- uint32 GetPlayersSlain() const { return RequiredPlayerKills; }
+ uint32 GetNextQuestInChain() const { return NextQuestInChain; }
uint32 GetBonusTalents() const { return RewardTalents; }
int32 GetRewArenaPoints() const {return RewardArenaPoints; }
- uint32 GetXPId() const { return RewardXPId; }
+ uint32 GetXPDifficulty() const { return RewardXPDifficulty; }
uint32 GetSrcItemId() const { return SourceItemId; }
uint32 GetSrcItemCount() const { return SourceItemIdCount; }
- uint32 GetSrcSpell() const { return SourceSpellid; }
- std::string const& GetTitle() const { return Title; }
- std::string const& GetDetails() const { return Details; }
- std::string const& GetObjectives() const { return Objectives; }
+ uint32 GetSrcSpell() const { return SourceSpellID; }
+ std::string const& GetLogTitle() const { return LogTitle; }
+ std::string const& GetLogDescription() const { return LogDescription; }
+ std::string const& GetQuestDescription() const { return QuestDescription; }
std::string const& GetOfferRewardText() const { return OfferRewardText; }
std::string const& GetRequestItemsText() const { return RequestItemsText; }
- std::string const& GetEndText() const { return EndText; }
- std::string const& GetCompletedText() const { return CompletedText; }
- std::string const& GetQuestGiverTextWindow() const { return QuestGiverTextWindow; }
- std::string const& GetQuestGiverTargetName() const { return QuestGiverTargetName; }
- std::string const& GetQuestTurnTextWindow() const { return QuestTurnTextWindow; }
- std::string const& GetQuestTurnTargetName() const { return QuestTurnTargetName; }
- int32 GetRewOrReqMoney() const;
- uint32 GetRewHonorAddition() const { return RewardHonor; }
- float GetRewHonorMultiplier() const { return RewardHonorMultiplier; }
+ std::string const& GetQuestCompletionLog() const { return QuestCompletionLog; }
+ std::string const& GetPortraitGiverText() const { return PortraitGiverText; }
+ std::string const& GetPortraitGiverName() const { return PortraitGiverName; }
+ std::string const& GetPortraitTurnInText() const { return PortraitTurnInText; }
+ std::string const& GetPortraitTurnInName() const { return PortraitTurnInName; }
+ QuestObjectives const& GetObjectives() const { return Objectives; };
+ int32 GetRewMoney() const;
+ uint32 GetRewMoneyDifficulty() const { return RewardMoneyDifficulty; }
+ uint32 GetRewHonor() const { return RewardHonor; }
+ uint32 GetRewKillHonor() const { return RewardKillHonor; }
uint32 GetRewMoneyMaxLevel() const; // use in XP calculation at client
uint32 GetRewSpell() const { return RewardSpell; }
- int32 GetRewSpellCast() const { return RewardSpellCast; }
+ int32 GetRewDisplaySpell() const { return RewardDisplaySpell; }
uint32 GetRewMailTemplateId() const { return RewardMailTemplateId; }
uint32 GetRewMailDelaySecs() const { return RewardMailDelay; }
- uint32 GetPointMapId() const { return PointMapId; }
- float GetPointX() const { return PointX; }
- float GetPointY() const { return PointY; }
- uint32 GetPointOpt() const { return PointOption; }
- uint32 GetRequiredSpell() const { return RequiredSpell; }
+ uint32 GetRewTitle() const { return RewardTitleId; }
+ uint32 GetPOIContinent() const { return POIContinent; }
+ float GetPOIx() const { return POIx; }
+ float GetPOIy() const { return POIy; }
+ uint32 GetPOIPriority() const { return POIPriority; }
uint32 GetSoundAccept() const { return SoundAccept; }
uint32 GetSoundTurnIn() const { return SoundTurnIn; }
uint32 GetIncompleteEmote() const { return EmoteOnIncomplete; }
@@ -281,8 +321,9 @@ class Quest
bool IsAutoAccept() const;
bool IsAutoComplete() const;
uint32 GetFlags() const { return Flags; }
+ uint32 GetFlagsEx() const { return FlagsEx; }
uint32 GetSpecialFlags() const { return SpecialFlags; }
- uint32 GetMinimapTargetMark() const { return MinimapTargetMark; }
+ uint32 GetAreaGroupID() const { return AreaGroupID; }
uint32 GetRewardSkillId() const { return RewardSkillId; }
uint32 GetRewardSkillPoints() const { return RewardSkillPoints; }
uint32 GetRewardReputationMask() const { return RewardReputationMask; }
@@ -298,142 +339,132 @@ class Quest
bool IsDFQuest() const { return (SpecialFlags & QUEST_SPECIAL_FLAGS_DF_QUEST) != 0; }
uint32 CalculateHonorGain(uint8 level) const;
- // multiple values
- std::string ObjectiveText[QUEST_OBJECTIVES_COUNT];
- uint32 RequiredItemId[QUEST_ITEM_OBJECTIVES_COUNT];
- uint32 RequiredItemCount[QUEST_ITEM_OBJECTIVES_COUNT];
- uint32 RequiredSourceItemId[QUEST_SOURCE_ITEM_IDS_COUNT];
- uint32 RequiredSourceItemCount[QUEST_SOURCE_ITEM_IDS_COUNT];
- int32 RequiredNpcOrGo[QUEST_OBJECTIVES_COUNT]; // >0 Creature <0 Gameobject
- uint32 RequiredNpcOrGoCount[QUEST_OBJECTIVES_COUNT];
- uint32 RewardChoiceItemId[QUEST_REWARD_CHOICES_COUNT];
- uint32 RewardChoiceItemCount[QUEST_REWARD_CHOICES_COUNT];
- uint32 RewardItemId[QUEST_REWARDS_COUNT];
- uint32 RewardItemIdCount[QUEST_REWARDS_COUNT];
- uint32 RewardFactionId[QUEST_REPUTATIONS_COUNT];
- int32 RewardFactionValueId[QUEST_REPUTATIONS_COUNT];
- int32 RewardFactionValueIdOverride[QUEST_REPUTATIONS_COUNT];
- uint32 DetailsEmote[QUEST_EMOTE_COUNT];
- uint32 DetailsEmoteDelay[QUEST_EMOTE_COUNT];
- uint32 OfferRewardEmote[QUEST_EMOTE_COUNT];
- uint32 OfferRewardEmoteDelay[QUEST_EMOTE_COUNT];
- // 4.x
- uint32 RewardCurrencyId[QUEST_REWARD_CURRENCY_COUNT];
- uint32 RewardCurrencyCount[QUEST_REWARD_CURRENCY_COUNT];
- uint32 RequiredCurrencyId[QUEST_REQUIRED_CURRENCY_COUNT];
- uint32 RequiredCurrencyCount[QUEST_REQUIRED_CURRENCY_COUNT];
-
- uint32 GetReqItemsCount() const { return _reqItemsCount; }
- uint32 GetReqCreatureOrGOcount() const { return _reqNpcOrGoCount; }
uint32 GetRewChoiceItemsCount() const { return _rewChoiceItemsCount; }
uint32 GetRewItemsCount() const { return _rewItemsCount; }
uint32 GetRewCurrencyCount() const { return _rewCurrencyCount; }
- uint32 GetReqCurrencyCount() const { return _reqCurrencyCount; }
void BuildExtraQuestInfo(WorldPacket& data, Player* player) const;
+ void BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player) const;
typedef std::vector<int32> PrevQuests;
PrevQuests prevQuests;
typedef std::vector<uint32> PrevChainQuests;
PrevChainQuests prevChainQuests;
- // cached data
private:
- uint32 _reqItemsCount;
- uint32 _reqNpcOrGoCount;
uint32 _rewChoiceItemsCount;
uint32 _rewItemsCount;
uint32 _rewCurrencyCount;
- uint32 _reqCurrencyCount;
- // table data
- protected:
+ public:
+ // wdb data (quest query response)
uint32 Id;
uint32 Method;
+ uint32 PackageID;
int32 ZoneOrSort;
uint32 MinLevel;
- uint32 MaxLevel;
int32 Level;
uint32 Type;
- uint32 RequiredClasses;
- uint32 RequiredRaces;
- uint32 RequiredSkillId;
- uint32 RequiredSkillPoints;
- uint32 RequiredFactionId1;
- int32 RequiredFactionValue1;
- uint32 RequiredFactionId2;
- int32 RequiredFactionValue2;
- uint32 RequiredMinRepFaction;
- int32 RequiredMinRepValue;
- uint32 RequiredMaxRepFaction;
- int32 RequiredMaxRepValue;
uint32 SuggestedPlayers;
- uint32 LimitTime;
+ uint32 NextQuestInChain;
+ uint32 RewardXPDifficulty;
+ float Float10;
+ uint32 RewardMoney;
+ uint32 RewardMoneyDifficulty;
+ float Float13;
+ uint32 RewardBonusMoney;
+ uint32 RewardDisplaySpell;
+ uint32 RewardSpell;
+ uint32 RewardHonor;
+ uint32 RewardKillHonor;
+ uint32 SourceItemId;
uint32 Flags;
+ uint32 FlagsEx;
+ uint32 RewardItemId[QUEST_REWARD_ITEM_COUNT];
+ uint32 RewardItemCount[QUEST_REWARD_ITEM_COUNT];
+ uint32 ItemDrop[QUEST_ITEM_DROP_COUNT];
+ uint32 ItemDropQuantity[QUEST_ITEM_DROP_COUNT];
+ uint32 RewardChoiceItemId[QUEST_REWARD_CHOICES_COUNT];
+ uint32 RewardChoiceItemCount[QUEST_REWARD_CHOICES_COUNT];
+ uint32 RewardChoiceItemDisplayId[QUEST_REWARD_CHOICES_COUNT];
+ uint32 POIContinent;
+ float POIx;
+ float POIy;
+ uint32 POIPriority;
uint32 RewardTitleId;
- uint32 RequiredPlayerKills;
uint32 RewardTalents;
int32 RewardArenaPoints;
- int32 PrevQuestId;
- int32 NextQuestId;
- int32 ExclusiveGroup;
- uint32 NextQuestIdChain;
- uint32 RewardXPId;
- uint32 SourceItemId;
- uint32 SourceItemIdCount;
- uint32 SourceSpellid;
- std::string Title;
- std::string Details;
- std::string Objectives;
- std::string OfferRewardText;
- std::string RequestItemsText;
- std::string EndText;
- std::string CompletedText;
- uint32 RewardHonor;
- float RewardHonorMultiplier;
- int32 RewardOrRequiredMoney;
- uint32 RewardMoneyMaxLevel;
- uint32 RewardSpell;
- int32 RewardSpellCast;
- uint32 RewardMailTemplateId;
- uint32 RewardMailDelay;
- uint32 PointMapId;
- float PointX;
- float PointY;
- uint32 PointOption;
- uint32 EmoteOnIncomplete;
- uint32 EmoteOnComplete;
- // new in 4.x
- uint32 MinimapTargetMark;
uint32 RewardSkillId;
uint32 RewardSkillPoints;
- uint32 RewardReputationMask;
uint32 QuestGiverPortrait;
uint32 QuestTurnInPortrait;
- uint32 RequiredSpell;
- std::string QuestGiverTextWindow;
- std::string QuestGiverTargetName;
- std::string QuestTurnTextWindow;
- std::string QuestTurnTargetName;
+ uint32 RewardFactionId[QUEST_REWARD_REPUTATIONS_COUNT];
+ int32 RewardFactionValue[QUEST_REWARD_REPUTATIONS_COUNT];
+ int32 RewardFactionOverride[QUEST_REWARD_REPUTATIONS_COUNT];
+ uint32 RewardReputationMask;
+ uint32 RewardCurrencyId[QUEST_REWARD_CURRENCY_COUNT];
+ uint32 RewardCurrencyCount[QUEST_REWARD_CURRENCY_COUNT];
uint32 SoundAccept;
uint32 SoundTurnIn;
+ uint32 AreaGroupID;
+ uint32 LimitTime;
+ int32 AllowableRaces;
+ QuestObjectives Objectives;
+ std::string LogTitle;
+ std::string LogDescription;
+ std::string QuestDescription;
+ std::string AreaDescription;
+ std::string PortraitGiverText;
+ std::string PortraitGiverName;
+ std::string PortraitTurnInText;
+ std::string PortraitTurnInName;
+ std::string QuestCompletionLog;
+
+ protected:
+
+ // quest_detais table
+ uint32 DetailsEmote[QUEST_EMOTE_COUNT] = {};
+ uint32 DetailsEmoteDelay[QUEST_EMOTE_COUNT] = {};
+
+ // quest_request_items table
+ uint32 EmoteOnComplete = 0;
+ uint32 EmoteOnIncomplete = 0;
+ uint32 EmoteOnCompleteDelay = 0;
+ uint32 EmoteOnIncompleteDelay = 0;
+ std::string RequestItemsText;
+
+ // quest_offer_reward table
+ uint32 OfferRewardEmote[QUEST_EMOTE_COUNT] = {};
+ uint32 OfferRewardEmoteDelay[QUEST_EMOTE_COUNT] = {};
+ std::string OfferRewardText;
- uint32 SpecialFlags; // custom flags, not sniffed/WDB
+ // quest_template_addon table (custom data)
+ uint32 MaxLevel = 0;
+ uint32 AllowableClasses = 0;
+ uint32 SourceSpellID = 0;
+ int32 PrevQuestID = 0;
+ int32 NextQuestID = 0;
+ int32 ExclusiveGroup = 0;
+ uint32 RewardMailTemplateId = 0;
+ uint32 RewardMailDelay = 0;
+ uint32 RequiredSkillId = 0;
+ uint32 RequiredSkillPoints = 0;
+ uint32 RequiredMinRepFaction = 0;
+ int32 RequiredMinRepValue = 0;
+ uint32 RequiredMaxRepFaction = 0;
+ int32 RequiredMaxRepValue = 0;
+ uint32 SourceItemIdCount = 0;
+ uint32 SpecialFlags = 0; // custom flags, not sniffed/WDB
};
struct QuestStatusData
{
- QuestStatusData(): Status(QUEST_STATUS_NONE), Timer(0), PlayerCount(0), Explored(false)
+ QuestStatusData(): Status(QUEST_STATUS_NONE), Timer(0)
{
- memset(ItemCount, 0, QUEST_ITEM_OBJECTIVES_COUNT * sizeof(uint16));
- memset(CreatureOrGOCount, 0, QUEST_OBJECTIVES_COUNT * sizeof(uint16));
}
QuestStatus Status;
uint32 Timer;
- uint16 ItemCount[QUEST_ITEM_OBJECTIVES_COUNT];
- uint16 CreatureOrGOCount[QUEST_OBJECTIVES_COUNT];
- uint16 PlayerCount;
- bool Explored;
+ std::vector<int32> ObjectiveData;
};
#endif
diff --git a/src/server/game/Server/Packets/QuestPackets.cpp b/src/server/game/Server/Packets/QuestPackets.cpp
index e20023d3dd2..3b95a19c7c6 100644
--- a/src/server/game/Server/Packets/QuestPackets.cpp
+++ b/src/server/game/Server/Packets/QuestPackets.cpp
@@ -41,3 +41,281 @@ WorldPacket const* WorldPackets::Quest::QuestGiverStatusMultiple::Write()
return &_worldPacket;
}
+
+void WorldPackets::Quest::QuestGiverHello::Read()
+{
+ _worldPacket >> QuestGiverGUID;
+}
+
+void WorldPackets::Quest::QueryQuestInfo::Read()
+{
+ _worldPacket >> QuestID;
+ _worldPacket >> QuestGiver;
+}
+
+WorldPacket const* WorldPackets::Quest::QueryQuestInfoResponse::Write()
+{
+ _worldPacket << QuestID;
+
+ _worldPacket.WriteBit(Allow);
+ _worldPacket.FlushBits();
+
+ if (Allow)
+ {
+ _worldPacket << Info.QuestID;
+ _worldPacket << Info.QuestType;
+ _worldPacket << Info.QuestLevel;
+ _worldPacket << Info.QuestPackageID;
+ _worldPacket << Info.QuestMinLevel;
+ _worldPacket << Info.QuestSortID;
+ _worldPacket << Info.QuestInfoID;
+ _worldPacket << Info.SuggestedGroupNum;
+ _worldPacket << Info.RewardNextQuest;
+ _worldPacket << Info.RewardXPDifficulty;
+ _worldPacket << float(1.0f); // Unk Float10
+ _worldPacket << Info.RewardMoney;
+ _worldPacket << Info.RewardMoneyDifficulty;
+ _worldPacket << float(1.0f); // Unk Float13
+ _worldPacket << Info.RewardBonusMoney;
+ _worldPacket << Info.RewardDisplaySpell;
+ _worldPacket << Info.RewardSpell;
+ _worldPacket << Info.RewardHonor;
+ _worldPacket << Info.RewardKillHonor;
+ _worldPacket << Info.StartItem;
+ _worldPacket << Info.Flags;
+ _worldPacket << Info.FlagsEx;
+
+ for (uint32 i = 0; i < QUEST_REWARD_ITEM_COUNT; ++i)
+ {
+ _worldPacket << Info.RewardItems[i];
+ _worldPacket << Info.RewardAmount[i];
+ _worldPacket << Info.ItemDrop[i];
+ _worldPacket << Info.ItemDropQuantity[i];
+ }
+
+ for (uint32 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
+ {
+ _worldPacket << Info.UnfilteredChoiceItems[i].ItemID;
+ _worldPacket << Info.UnfilteredChoiceItems[i].Quantity;
+ _worldPacket << Info.UnfilteredChoiceItems[i].DisplayID;
+ }
+
+ _worldPacket << Info.POIContinent;
+ _worldPacket << Info.POIx;
+ _worldPacket << Info.POIy;
+ _worldPacket << Info.POIPriority;
+
+ _worldPacket << Info.RewardTitle;
+ _worldPacket << Info.RewardTalents;
+ _worldPacket << Info.RewardArenaPoints;
+ _worldPacket << Info.RewardSkillLineID;
+ _worldPacket << Info.RewardNumSkillUps;
+
+ _worldPacket << Info.PortraitGiver;
+ _worldPacket << Info.PortraitTurnIn;
+
+ for (uint32 i = 0; i < QUEST_REWARD_REPUTATIONS_COUNT; ++i)
+ {
+ _worldPacket << Info.RewardFactionID[i];
+ _worldPacket << Info.RewardFactionValue[i];
+ _worldPacket << Info.RewardFactionOverride[i];
+ }
+
+ _worldPacket << Info.RewardFactionFlags;
+
+ for (uint32 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
+ {
+ _worldPacket << Info.RewardCurrencyID[i];
+ _worldPacket << Info.RewardCurrencyQty[i];
+ }
+
+ _worldPacket << Info.AcceptedSoundKitID;
+ _worldPacket << Info.CompleteSoundKitID;
+
+ _worldPacket << Info.AreaGroupID;
+ _worldPacket << Info.TimeAllowed;
+
+ _worldPacket << int32(Info.Objectives.size());
+ _worldPacket << int32(-1); // Unk Int2950
+
+ for (uint32 i = 0; i < Info.Objectives.size(); ++i)
+ {
+ _worldPacket << Info.Objectives[i].ID;
+ _worldPacket << Info.Objectives[i].Type;
+ _worldPacket << Info.Objectives[i].StorageIndex;
+ _worldPacket << Info.Objectives[i].ObjectID;
+ _worldPacket << Info.Objectives[i].Amount;
+ _worldPacket << Info.Objectives[i].Flags;
+ _worldPacket << Info.Objectives[i].UnkFloat;
+
+ _worldPacket << int32(Info.Objectives[i].VisualEffects.size());
+ for (uint32 j = 0; j < Info.Objectives[i].VisualEffects.size(); ++j)
+ _worldPacket << Info.Objectives[i].VisualEffects[i];
+
+ _worldPacket.WriteBits(Info.Objectives[i].Description.size(), 8);
+ _worldPacket.WriteString(Info.Objectives[i].Description);
+ }
+
+ _worldPacket.WriteBits(Info.LogTitle.size(), 9);
+ _worldPacket.WriteBits(Info.LogDescription.size(), 12);
+ _worldPacket.WriteBits(Info.QuestDescription.size(), 12);
+ _worldPacket.WriteBits(Info.AreaDescription.size(), 9);
+ _worldPacket.WriteBits(Info.PortraitGiverText.size(), 10);
+ _worldPacket.WriteBits(Info.PortraitGiverName.size(), 8);
+ _worldPacket.WriteBits(Info.PortraitTurnInText.size(), 10);
+ _worldPacket.WriteBits(Info.PortraitTurnInName.size(), 8);
+ _worldPacket.WriteBits(Info.QuestCompletionLog.size(), 11);
+ _worldPacket.FlushBits();
+
+ _worldPacket.WriteString(Info.LogTitle);
+ _worldPacket.WriteString(Info.LogDescription);
+ _worldPacket.WriteString(Info.QuestDescription);
+ _worldPacket.WriteString(Info.AreaDescription);
+ _worldPacket.WriteString(Info.PortraitGiverText);
+ _worldPacket.WriteString(Info.PortraitGiverName);
+ _worldPacket.WriteString(Info.PortraitTurnInText);
+ _worldPacket.WriteString(Info.PortraitTurnInName);
+ _worldPacket.WriteString(Info.QuestCompletionLog);
+ }
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Quest::QuestUpdateAddCredit::Write()
+{
+ _worldPacket << VictimGUID;
+ _worldPacket << QuestID;
+ _worldPacket << ObjectID;
+ _worldPacket << Count;
+ _worldPacket << Required;
+ _worldPacket << ObjectiveType;
+
+ return &_worldPacket;
+};
+
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Quest::QuestRewards const& questRewards)
+{
+ data << questRewards.ChoiceItemCount;
+
+ for (uint32 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
+ {
+ data << questRewards.ChoiceItems[i].ItemID;
+ data << questRewards.ChoiceItems[i].Quantity;
+ }
+
+ data << questRewards.ItemCount;
+
+ for (uint32 i = 0; i < QUEST_REWARD_ITEM_COUNT; ++i)
+ {
+ data << questRewards.ItemID[i];
+ data << questRewards.ItemQty[i];
+ }
+
+ data << questRewards.Money;
+ data << questRewards.XP;
+ data << questRewards.Title;
+ data << questRewards.Talents;
+ data << questRewards.FactionFlags;
+
+ for (uint32 i = 0; i < QUEST_REWARD_REPUTATIONS_COUNT; ++i)
+ {
+ data << questRewards.FactionID[i];
+ data << questRewards.FactionValue[i];
+ data << questRewards.FactionOverride[i];
+ }
+
+ data << questRewards.SpellCompletionDisplayID;
+ data << questRewards.SpellCompletionID;
+
+ for (uint32 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
+ {
+ data << questRewards.CurrencyID[i];
+ data << questRewards.CurrencyQty[i];
+ }
+
+ data << questRewards.SkillLineID;
+ data << questRewards.NumSkillUps;
+
+ data.WriteBit(false); // Unk
+ data.FlushBits();
+
+ return data;
+}
+
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Quest::QuestGiverOfferReward const& offer)
+{
+ data << offer.QuestGiverGUID;
+ data << offer.QuestGiverCreatureID;
+ data << offer.QuestID;
+ data << offer.QuestFlags[0]; // Flags
+ data << offer.QuestFlags[1]; // FlagsEx
+ data << offer.SuggestedPartyMembers;
+ data << offer.Rewards; // WorldPackets::Quest::QuestRewards
+
+ data << int32(offer.Emotes.size());
+ for (WorldPackets::Quest::QuestDescEmote const& emote : offer.Emotes)
+ {
+ data << emote.Type;
+ data << emote.Delay;
+ }
+
+ data.WriteBit(offer.AutoLaunched);
+ data.FlushBits();
+
+ return data;
+}
+
+WorldPacket const* WorldPackets::Quest::QuestGiverOfferRewardMessage::Write()
+{
+ _worldPacket << QuestData; // WorldPackets::Quest::QuestGiverOfferReward
+ _worldPacket << PortraitTurnIn;
+ _worldPacket << PortraitGiver;
+ _worldPacket << QuestPackageID;
+
+ _worldPacket.WriteBits(QuestTitle.size(), 9);
+ _worldPacket.WriteBits(RewardText.size(), 12);
+ _worldPacket.WriteBits(PortraitTurnInText.size(), 10);
+ _worldPacket.WriteBits(PortraitGiverName.size(), 8);
+ _worldPacket.WriteBits(PortraitGiverText.size(), 10);
+ _worldPacket.WriteBits(PortraitTurnInName.size(), 8);
+
+ _worldPacket.WriteString(QuestTitle);
+ _worldPacket.WriteString(RewardText);
+ _worldPacket.WriteString(PortraitTurnInText);
+ _worldPacket.WriteString(PortraitGiverName);
+ _worldPacket.WriteString(PortraitGiverText);
+ _worldPacket.WriteString(PortraitTurnInName);
+
+ return &_worldPacket;
+};
+
+void WorldPackets::Quest::QuestGiverChooseReward::Read()
+{
+ _worldPacket >> QuestGiverGUID;
+ _worldPacket >> QuestID;
+ _worldPacket >> ItemChoiceID;
+}
+
+WorldPacket const* WorldPackets::Quest::QuestGiverQuestComplete::Write()
+{
+ _worldPacket << QuestID;
+ _worldPacket << SkillLineIDReward;
+ _worldPacket << MoneyReward;
+ _worldPacket << NumSkillUpsReward;
+ _worldPacket << XPReward;
+ _worldPacket << TalentReward;
+ _worldPacket << ItemReward; // WorldPackets::Item::ItemInstance
+
+ _worldPacket.WriteBit(UseQuestReward);
+ _worldPacket.WriteBit(LaunchGossip);
+ _worldPacket.FlushBits();
+
+ return &_worldPacket;
+}
+
+void WorldPackets::Quest::QuestGiverCompleteQuest::Read()
+{
+ _worldPacket >> QuestGiverGUID;
+ _worldPacket >> QuestID;
+ FromScript = _worldPacket.ReadBit();
+}
diff --git a/src/server/game/Server/Packets/QuestPackets.h b/src/server/game/Server/Packets/QuestPackets.h
index 12410380c3a..75e122ff904 100644
--- a/src/server/game/Server/Packets/QuestPackets.h
+++ b/src/server/game/Server/Packets/QuestPackets.h
@@ -21,6 +21,7 @@
#include "Packet.h"
#include "QuestDef.h"
#include "ObjectGuid.h"
+#include "ItemPackets.h"
namespace WorldPackets
{
@@ -74,7 +75,236 @@ namespace WorldPackets
std::vector<QuestGiverInfo> QuestGiver;
};
+
+ class QuestGiverHello final : public ClientPacket
+ {
+ public:
+ QuestGiverHello(WorldPacket&& packet) : ClientPacket(CMSG_QUESTGIVER_HELLO, std::move(packet)) { }
+
+ void Read() override;
+
+ ObjectGuid QuestGiverGUID;
+ };
+
+ class QueryQuestInfo final : public ClientPacket
+ {
+ public:
+ QueryQuestInfo(WorldPacket&& packet) : ClientPacket(CMSG_QUEST_QUERY, std::move(packet)) { }
+
+ void Read() override;
+
+ ObjectGuid QuestGiver;
+ int32 QuestID;
+ };
+
+ struct QuestInfoChoiceItem
+ {
+ int32 ItemID;
+ int32 Quantity;
+ int32 DisplayID;
+ };
+
+ struct QuestInfo
+ {
+ int32 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 QuestPackageID = 0;
+ int32 QuestMinLevel = 0;
+ int32 QuestSortID = 0; // zone or sort to display in quest log
+ int32 QuestInfoID = 0;
+ int32 SuggestedGroupNum = 0;
+ int32 RewardNextQuest = 0; // client will request this quest from NPC, if not 0
+ int32 RewardXPDifficulty = 0; // used for calculating rewarded experience
+ int32 RewardMoney = 0; // reward money (below max lvl)
+ int32 RewardMoneyDifficulty = 0; // used in XP calculation at client
+ int32 RewardBonusMoney = 0;
+ int32 RewardDisplaySpell = 0; // reward spell, this spell will be displayed (icon)
+ int32 RewardSpell = 0;
+ int32 RewardHonor = 0;
+ float RewardKillHonor = 0.0f;
+ int32 StartItem = 0;
+ int32 Flags = 0;
+ int32 FlagsEx = 0;
+ int32 POIContinent = 0;
+ float POIx = 0.0f;
+ float POIy = 0.0f;
+ int32 POIPriority = 0;
+ std::string LogTitle;
+ std::string LogDescription;
+ std::string QuestDescription;
+ std::string AreaDescription;
+ int32 RewardTitle = 0; // new 2.4.0, player gets this title (id from CharTitles)
+ int32 RewardTalents = 0;
+ int32 RewardArenaPoints = 0;
+ int32 RewardSkillLineID = 0; // reward skill id
+ int32 RewardNumSkillUps = 0; // reward skill points
+ int32 PortraitGiver = 0; // quest giver entry ?
+ int32 PortraitTurnIn = 0; // quest turn in entry ?
+ std::string PortraitGiverText;
+ std::string PortraitGiverName;
+ std::string PortraitTurnInText;
+ std::string PortraitTurnInName;
+ std::string QuestCompletionLog;
+ int32 RewardFactionFlags = 0; // rep mask (unsure on what it does)
+ int32 AcceptedSoundKitID = 0;
+ int32 CompleteSoundKitID = 0;
+ int32 AreaGroupID = 0;
+ int32 TimeAllowed = 0;
+ std::vector<QuestObjective> Objectives;
+ int32 RewardItems[QUEST_REWARD_ITEM_COUNT] = {};
+ int32 RewardAmount[QUEST_REWARD_ITEM_COUNT] = {};
+ int32 ItemDrop[QUEST_ITEM_DROP_COUNT] = {};
+ int32 ItemDropQuantity[QUEST_ITEM_DROP_COUNT] = {};
+ QuestInfoChoiceItem UnfilteredChoiceItems[QUEST_REWARD_CHOICES_COUNT];
+ int32 RewardFactionID[QUEST_REWARD_REPUTATIONS_COUNT] = {};
+ int32 RewardFactionValue[QUEST_REWARD_REPUTATIONS_COUNT] = {};
+ int32 RewardFactionOverride[QUEST_REWARD_REPUTATIONS_COUNT] = {};
+ int32 RewardCurrencyID[QUEST_REWARD_CURRENCY_COUNT] = {};
+ int32 RewardCurrencyQty[QUEST_REWARD_CURRENCY_COUNT] = {};
+ };
+
+ class QueryQuestInfoResponse final : public ServerPacket
+ {
+ public:
+ QueryQuestInfoResponse() : ServerPacket(SMSG_QUEST_QUERY_RESPONSE, 1200) { }
+
+ WorldPacket const* Write() override;
+
+ bool Allow = false;
+ QuestInfo Info;
+ uint32 QuestID = 0;
+ };
+
+ class QuestUpdateAddCredit final : public ServerPacket
+ {
+ public:
+ QuestUpdateAddCredit() : ServerPacket(SMSG_QUESTUPDATE_ADD_KILL, 16+4+4+2+2+1) { }
+
+ WorldPacket const* Write() override;
+
+ ObjectGuid VictimGUID;
+ int32 ObjectID = 0;
+ int32 QuestID = 0;
+ uint16 Count = 0;
+ uint16 Required = 0;
+ uint8 ObjectiveType = 0;
+ };
+
+ struct QuestChoiceItem
+ {
+ int32 ItemID = 0;
+ int32 Quantity = 0;
+ };
+
+ struct QuestRewards
+ {
+ int32 ChoiceItemCount = 0;
+ int32 ItemCount = 0;
+ int32 Money = 0;
+ int32 XP = 0;
+ int32 Title = 0;
+ int32 Talents = 0;
+ int32 FactionFlags = 0;
+ int32 SpellCompletionDisplayID = 0;
+ int32 SpellCompletionID = 0;
+ int32 SkillLineID = 0;
+ int32 NumSkillUps = 0;
+ QuestChoiceItem ChoiceItems[QUEST_REWARD_CHOICES_COUNT];
+ int32 ItemID[QUEST_REWARD_ITEM_COUNT] = {};
+ int32 ItemQty[QUEST_REWARD_ITEM_COUNT] = {};
+ int32 FactionID[QUEST_REWARD_REPUTATIONS_COUNT] = {};
+ int32 FactionValue[QUEST_REWARD_REPUTATIONS_COUNT] = {};
+ int32 FactionOverride[QUEST_REWARD_REPUTATIONS_COUNT] = {};
+ int32 CurrencyID[QUEST_REWARD_CURRENCY_COUNT] = {};
+ int32 CurrencyQty[QUEST_REWARD_CURRENCY_COUNT] = {};
+ };
+
+ struct QuestDescEmote
+ {
+ QuestDescEmote(int32 type = 0, uint32 delay = 0) : Type(type), Delay(delay) {}
+ int32 Type;
+ uint32 Delay;
+ };
+
+ struct QuestGiverOfferReward
+ {
+ ObjectGuid QuestGiverGUID;
+ int32 QuestGiverCreatureID = 0;
+ int32 QuestID = 0;
+ bool AutoLaunched = false;
+ int32 SuggestedPartyMembers = 0;
+ QuestRewards Rewards;
+ std::vector<QuestDescEmote> Emotes;
+ int32 QuestFlags[2] = {}; // Flags and FlagsEx
+ };
+
+ class QuestGiverOfferRewardMessage final : public ServerPacket
+ {
+ public:
+ QuestGiverOfferRewardMessage() : ServerPacket(SMSG_QUESTGIVER_OFFER_REWARD, 600) { }
+
+ WorldPacket const* Write() override;
+
+ int32 PortraitTurnIn = 0;
+ int32 PortraitGiver = 0;
+ std::string PortraitGiverText;
+ std::string QuestTitle;
+ std::string PortraitTurnInText;
+ std::string PortraitGiverName;
+ std::string RewardText;
+ std::string PortraitTurnInName;
+ QuestGiverOfferReward QuestData;
+ int32 QuestPackageID = 0;
+ };
+
+ class QuestGiverChooseReward final : public ClientPacket
+ {
+ public:
+ QuestGiverChooseReward(WorldPacket&& packet) : ClientPacket(CMSG_QUESTGIVER_CHOOSE_REWARD, std::move(packet)) { }
+
+ void Read() override;
+
+ ObjectGuid QuestGiverGUID;
+ int32 QuestID = 0;
+ int32 ItemChoiceID = 0;
+ };
+
+ class QuestGiverQuestComplete final : public ServerPacket
+ {
+ public:
+ QuestGiverQuestComplete() : ServerPacket(SMSG_QUESTGIVER_QUEST_COMPLETE, 40) { }
+
+ WorldPacket const* Write() override;
+
+ bool UseQuestReward = false;
+ int32 SkillLineIDReward = 0;
+ int32 MoneyReward = 0;
+ int32 NumSkillUpsReward = 0;
+ int32 XPReward = 0;
+ int32 QuestID = 0;
+ int32 TalentReward = 0;
+ bool LaunchGossip = 0;
+
+ // Not in JAM struct
+ WorldPackets::Item::ItemInstance ItemReward;
+ };
+
+ class QuestGiverCompleteQuest final : public ClientPacket
+ {
+ public:
+ QuestGiverCompleteQuest(WorldPacket&& packet) : ClientPacket(CMSG_QUESTGIVER_COMPLETE_QUEST, std::move(packet)) { }
+
+ void Read() override;
+
+ ObjectGuid QuestGiverGUID; // NPC / GameObject guid for normal quest completion. Player guid for self-completed quests
+ int32 QuestID = 0;
+ bool FromScript = false; // 0 - standart complete quest mode with npc, 1 - auto-complete mode
+ };
}
}
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Quest::QuestRewards const& questRewards);
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Quest::QuestGiverOfferReward const& offer);
+
#endif // QuestPackets_h__
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 1cca6672086..3b5e7afa996 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -537,9 +537,9 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_QUERY_QUESTS_COMPLETED, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryQuestsCompleted );
DEFINE_OPCODE_HANDLER_OLD(CMSG_QUERY_TIME, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryTimeOpcode );
DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_ACCEPT_QUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverAcceptQuestOpcode);
- DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_CHOOSE_REWARD, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverChooseRewardOpcode);
- DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_COMPLETE_QUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverCompleteQuest );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_HELLO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverHelloOpcode );
+ DEFINE_HANDLER(CMSG_QUESTGIVER_CHOOSE_REWARD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::QuestGiverChooseReward, &WorldSession::HandleQuestgiverChooseRewardOpcode);
+ DEFINE_HANDLER(CMSG_QUESTGIVER_COMPLETE_QUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::QuestGiverCompleteQuest, &WorldSession::HandleQuestgiverCompleteQuest);
+ DEFINE_HANDLER(CMSG_QUESTGIVER_HELLO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::QuestGiverHello, &WorldSession::HandleQuestgiverHelloOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_QUERY_QUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverQueryQuestOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_QUESTGIVER_REQUEST_REWARD, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestgiverRequestRewardOpcode);
DEFINE_HANDLER(CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::QuestGiverStatusMultipleQuery, &WorldSession::HandleQuestgiverStatusMultipleQuery);
@@ -548,7 +548,7 @@ void OpcodeTable::Initialize()
DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEST_CONFIRM_ACCEPT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestConfirmAccept );
DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEST_NPC_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestNPCQuery );
DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEST_POI_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestPOIQuery );
- DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEST_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestQueryOpcode );
+ DEFINE_HANDLER(CMSG_QUEST_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Quest::QueryQuestInfo, &WorldSession::HandleQuestQueryOpcode);
DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEUED_MESSAGES_END, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
DEFINE_OPCODE_HANDLER_OLD(CMSG_RANDOM_ROLL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRandomRollOpcode );
DEFINE_HANDLER(CMSG_RANDOMIZE_CHAR_NAME, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::GenerateRandomCharacterName, &WorldSession::HandleRandomizeCharNameOpcode);
@@ -1224,8 +1224,8 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_SEASON, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_QUESTS_COMPLETED_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_TIME_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_OFFER_REWARD, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_OFFER_REWARD, STATUS_NEVER, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_COMPLETE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_DETAILS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_QUEST_INVALID, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
@@ -1234,7 +1234,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_STATUS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_STATUS_MULTIPLE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTLOG_FULL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_ADD_KILL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_ADD_KILL, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_ADD_PVP_KILL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTUPDATE_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
@@ -1243,7 +1243,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_FORCE_REMOVE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_NPC_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_POI_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_QUERY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUEST_QUERY_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_GROUP_ONLY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_INSTANCE_INFO, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_RAID_INSTANCE_MESSAGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index ddad78a527b..0c8f0569da8 100644
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -482,9 +482,9 @@ enum OpcodeClient : uint32
CMSG_QUERY_TIME = 0xBADD,
CMSG_QUESTGIVER_ACCEPT_QUEST = 0xBADD,
CMSG_QUESTGIVER_CANCEL = 0xBADD,
- CMSG_QUESTGIVER_CHOOSE_REWARD = 0xBADD,
- CMSG_QUESTGIVER_COMPLETE_QUEST = 0xBADD,
- CMSG_QUESTGIVER_HELLO = 0xBADD,
+ CMSG_QUESTGIVER_CHOOSE_REWARD = 0x0DAD,
+ CMSG_QUESTGIVER_COMPLETE_QUEST = 0x1E8A,
+ CMSG_QUESTGIVER_HELLO = 0x058E,
CMSG_QUESTGIVER_QUERY_QUEST = 0x1924,
CMSG_QUESTGIVER_QUEST_AUTOLAUNCH = 0xBADD,
CMSG_QUESTGIVER_REQUEST_REWARD = 0xBADD,
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 5a4a3465474..b8d9020e440 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -189,6 +189,10 @@ namespace WorldPackets
{
class QuestGiverStatusQuery;
class QuestGiverStatusMultipleQuery;
+ class QuestGiverHello;
+ class QueryQuestInfo;
+ class QuestGiverChooseReward;
+ class QuestGiverCompleteQuest;
}
namespace Item
@@ -901,17 +905,17 @@ class WorldSession
void HandleQuestgiverStatusQueryOpcode(WorldPackets::Quest::QuestGiverStatusQuery& packet);
void HandleQuestgiverStatusMultipleQuery(WorldPackets::Quest::QuestGiverStatusMultipleQuery& packet);
- void HandleQuestgiverHelloOpcode(WorldPacket& recvPacket);
+ void HandleQuestgiverHelloOpcode(WorldPackets::Quest::QuestGiverHello& packet);
void HandleQuestgiverAcceptQuestOpcode(WorldPacket& recvPacket);
void HandleQuestgiverQueryQuestOpcode(WorldPacket& recvPacket);
- void HandleQuestgiverChooseRewardOpcode(WorldPacket& recvPacket);
+ void HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::QuestGiverChooseReward& packet);
void HandleQuestgiverRequestRewardOpcode(WorldPacket& recvPacket);
- void HandleQuestQueryOpcode(WorldPacket& recvPacket);
+ void HandleQuestQueryOpcode(WorldPackets::Quest::QueryQuestInfo& packet);
void HandleQuestgiverCancel(WorldPacket& recvData);
void HandleQuestLogSwapQuest(WorldPacket& recvData);
void HandleQuestLogRemoveQuest(WorldPacket& recvData);
void HandleQuestConfirmAccept(WorldPacket& recvData);
- void HandleQuestgiverCompleteQuest(WorldPacket& recvData);
+ void HandleQuestgiverCompleteQuest(WorldPackets::Quest::QuestGiverCompleteQuest& packet);
void HandleQuestgiverQuestAutoLaunch(WorldPacket& recvPacket);
void HandlePushQuestToParty(WorldPacket& recvPacket);
void HandleQuestPushResult(WorldPacket& recvPacket);
diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp
index d746b07af75..f92e62f2aa9 100644
--- a/src/server/scripts/Commands/cs_lookup.cpp
+++ b/src/server/scripts/Commands/cs_lookup.cpp
@@ -599,9 +599,9 @@ public:
uint8 ulocaleIndex = uint8(localeIndex);
if (QuestLocale const* questLocale = sObjectMgr->GetQuestLocale(qInfo->GetQuestId()))
{
- if (questLocale->Title.size() > ulocaleIndex && !questLocale->Title[ulocaleIndex].empty())
+ if (questLocale->LogTitle.size() > ulocaleIndex && !questLocale->LogTitle[ulocaleIndex].empty())
{
- std::string title = questLocale->Title[ulocaleIndex];
+ std::string title = questLocale->LogTitle[ulocaleIndex];
if (Utf8FitTo(title, wNamePart))
{
@@ -647,7 +647,7 @@ public:
}
}
- std::string title = qInfo->GetTitle();
+ std::string title = qInfo->GetLogTitle();
if (title.empty())
continue;
diff --git a/src/server/scripts/Commands/cs_quest.cpp b/src/server/scripts/Commands/cs_quest.cpp
index 91ccd358f93..26806ce6785 100644
--- a/src/server/scripts/Commands/cs_quest.cpp
+++ b/src/server/scripts/Commands/cs_quest.cpp
@@ -180,67 +180,61 @@ public:
return false;
}
- // Add quest items for quests that require items
- for (uint8 x = 0; x < QUEST_ITEM_OBJECTIVES_COUNT; ++x)
+ for (uint32 i = 0; i < quest->Objectives.size(); ++i)
{
- uint32 id = quest->RequiredItemId[x];
- uint32 count = quest->RequiredItemCount[x];
- if (!id || !count)
- continue;
+ QuestObjective const& obj = quest->Objectives[i];
- uint32 curItemCount = player->GetItemCount(id, true);
-
- ItemPosCountVec dest;
- uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, id, count-curItemCount);
- if (msg == EQUIP_ERR_OK)
- {
- Item* item = player->StoreNewItem(dest, id, true);
- player->SendNewItem(item, count-curItemCount, true, false);
- }
- }
-
- // All creature/GO slain/cast (not required, but otherwise it will display "Creature slain 0/10")
- for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
- {
- int32 creature = quest->RequiredNpcOrGo[i];
- uint32 creatureCount = quest->RequiredNpcOrGoCount[i];
-
- if (creature > 0)
+ switch (obj.Type)
{
- if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creature))
- for (uint16 z = 0; z < creatureCount; ++z)
- player->KilledMonster(creatureInfo, ObjectGuid::Empty);
+ case QUEST_OBJECTIVE_ITEM:
+ {
+ uint32 curItemCount = player->GetItemCount(obj.ObjectID, true);
+ ItemPosCountVec dest;
+ uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, obj.ObjectID, obj.Amount - curItemCount);
+ if (msg == EQUIP_ERR_OK)
+ {
+ Item* item = player->StoreNewItem(dest, obj.ObjectID, true);
+ player->SendNewItem(item, obj.Amount - curItemCount, true, false);
+ }
+ break;
+ }
+ case QUEST_OBJECTIVE_MONSTER:
+ {
+ if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(obj.ObjectID))
+ for (uint16 z = 0; z < obj.Amount; ++z)
+ player->KilledMonster(creatureInfo, ObjectGuid::Empty);
+ break;
+ }
+ case QUEST_OBJECTIVE_GAMEOBJECT:
+ {
+ for (uint16 z = 0; z < obj.Amount; ++z)
+ player->KillCreditGO(obj.ObjectID);
+ break;
+ }
+ case QUEST_OBJECTIVE_MIN_REPUTATION:
+ {
+ uint32 curRep = player->GetReputationMgr().GetReputation(obj.ObjectID);
+ if (curRep < uint32(obj.Amount))
+ if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(obj.ObjectID))
+ player->GetReputationMgr().SetReputation(factionEntry, obj.Amount);
+ break;
+ }
+ case QUEST_OBJECTIVE_MAX_REPUTATION:
+ {
+ uint32 curRep = player->GetReputationMgr().GetReputation(obj.ObjectID);
+ if (curRep > uint32(obj.Amount))
+ if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(obj.ObjectID))
+ player->GetReputationMgr().SetReputation(factionEntry, obj.Amount);
+ break;
+ }
+ case QUEST_OBJECTIVE_MONEY:
+ {
+ player->ModifyMoney(obj.Amount);
+ break;
+ }
}
- else if (creature < 0)
- for (uint16 z = 0; z < creatureCount; ++z)
- player->KillCreditGO(creature);
}
- // If the quest requires reputation to complete
- if (uint32 repFaction = quest->GetRepObjectiveFaction())
- {
- uint32 repValue = quest->GetRepObjectiveValue();
- uint32 curRep = player->GetReputationMgr().GetReputation(repFaction);
- if (curRep < repValue)
- if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(repFaction))
- player->GetReputationMgr().SetReputation(factionEntry, repValue);
- }
-
- // If the quest requires a SECOND reputation to complete
- if (uint32 repFaction = quest->GetRepObjectiveFaction2())
- {
- uint32 repValue2 = quest->GetRepObjectiveValue2();
- uint32 curRep = player->GetReputationMgr().GetReputation(repFaction);
- if (curRep < repValue2)
- if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(repFaction))
- player->GetReputationMgr().SetReputation(factionEntry, repValue2);
- }
-
- // If the quest requires money
- int32 ReqOrRewMoney = quest->GetRewOrReqMoney();
- if (ReqOrRewMoney < 0)
- player->ModifyMoney(-ReqOrRewMoney);
-
if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled
{
// prepare Quest Tracker datas
diff --git a/src/server/scripts/Northrend/zone_borean_tundra.cpp b/src/server/scripts/Northrend/zone_borean_tundra.cpp
index 5585d09b0d6..f1d413c181c 100644
--- a/src/server/scripts/Northrend/zone_borean_tundra.cpp
+++ b/src/server/scripts/Northrend/zone_borean_tundra.cpp
@@ -2052,7 +2052,7 @@ public:
{
Quest const* qInfo = sObjectMgr->GetQuestTemplate(QUEST_YOU_RE_NOT_SO_BIG_NOW);
if (qInfo)
- player->KilledMonsterCredit(qInfo->RequiredNpcOrGo[0]);
+ player->KilledMonsterCredit(qInfo->Objectives[0].ObjectID);
}
}
};
diff --git a/src/server/scripts/Northrend/zone_sholazar_basin.cpp b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
index f4275121101..21468ccce90 100644
--- a/src/server/scripts/Northrend/zone_sholazar_basin.cpp
+++ b/src/server/scripts/Northrend/zone_sholazar_basin.cpp
@@ -493,16 +493,15 @@ public:
if (!quest)
return;
- QuestStatusMap::const_iterator itr = player->getQuestStatusMap().find(QUEST_TASTE_TEST);
- if (itr->second.Status != QUEST_STATUS_INCOMPLETE)
+ if (player->GetQuestStatus(QUEST_TASTE_TEST) != QUEST_STATUS_INCOMPLETE)
return;
- for (uint8 i = 0; i < 3; ++i)
+ for (uint32 i = 0; i < quest->Objectives.size(); ++i)
{
- if (uint32(quest->RequiredNpcOrGo[i]) != me->GetEntry())
+ if (uint32(quest->Objectives[i].ObjectID) != me->GetEntry())
continue;
- if (itr->second.CreatureOrGOCount[i] != 0)
+ if (player->GetQuestObjectiveData(quest, i) != 0)
continue;
player->KilledMonsterCredit(me->GetEntry());
diff --git a/src/server/scripts/World/go_scripts.cpp b/src/server/scripts/World/go_scripts.cpp
index 800b533d216..625a8fb05bf 100644
--- a/src/server/scripts/World/go_scripts.cpp
+++ b/src/server/scripts/World/go_scripts.cpp
@@ -898,7 +898,7 @@ public:
if (qInfo)
{
/// @todo prisoner should help player for a short period of time
- player->KilledMonsterCredit(qInfo->RequiredNpcOrGo[0]);
+ player->KilledMonsterCredit(qInfo->Objectives[0].ObjectID);
pPrisoner->DisappearAndDie();
}
return true;
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index 560a48be0c5..899ba4efe4b 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -82,8 +82,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_CHARACTER_AURAS, "SELECT caster_guid, spell, effect_mask, recalculate_mask, stackcount, amount0, amount1, amount2, "
"base_amount0, base_amount1, base_amount2, maxduration, remaintime, remaincharges FROM character_aura WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_SPELL, "SELECT spell, active, disabled FROM character_spell WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, explored, timer, mobcount1, mobcount2, mobcount3, mobcount4, "
- "itemcount1, itemcount2, itemcount3, itemcount4, playercount FROM character_queststatus WHERE guid = ? AND status <> 0", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, timer FROM character_queststatus WHERE guid = ? AND status <> 0", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES, "SELECT quest, objective, data FROM character_queststatus_objectives WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC);
@@ -499,6 +499,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_CHAR_TAXI_PATH, "UPDATE characters SET taxi_path = '' WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_TAXIMASK, "UPDATE characters SET taximask = ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS, "DELETE FROM character_queststatus WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES, "DELETE FROM character_queststatus_objectives WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID, "DELETE FROM character_social WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_SOCIAL_BY_FRIEND, "DELETE FROM character_social WHERE friend = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT, "DELETE FROM character_achievement WHERE achievement = ? AND guid = ?", CONNECTION_ASYNC);
@@ -537,8 +538,10 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM, "DELETE FROM character_inventory WHERE item = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_INVENTORY_BY_BAG_SLOT, "DELETE FROM character_inventory WHERE bag = ? AND slot = ? AND guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_MAIL, "UPDATE mail SET has_items = ?, expire_time = ?, deliver_time = ?, money = ?, cod = ?, checked = ? WHERE id = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_REP_CHAR_QUESTSTATUS, "REPLACE INTO character_queststatus (guid, quest, status, explored, timer, mobcount1, mobcount2, mobcount3, mobcount4, itemcount1, itemcount2, itemcount3, itemcount4, playercount) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_REP_CHAR_QUESTSTATUS, "REPLACE INTO character_queststatus (guid, quest, status, timer) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST, "DELETE FROM character_queststatus WHERE guid = ? AND quest = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_REP_CHAR_QUESTSTATUS_OBJECTIVES, "REPLACE INTO character_queststatus_objectives (guid, quest, objective, data) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_BY_QUEST, "DELETE FROM character_queststatus_objectives WHERE guid = ? AND quest = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_CHAR_QUESTSTATUS_REWARDED, "INSERT IGNORE INTO character_queststatus_rewarded (guid, quest, active) VALUES (?, ?, 1)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST, "DELETE FROM character_queststatus_rewarded WHERE guid = ? AND quest = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE, "UPDATE character_queststatus_rewarded SET quest = ? WHERE quest = ? AND guid = ?", CONNECTION_ASYNC);
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h
index 3c9f5a53411..a2808163ab4 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.h
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.h
@@ -80,8 +80,9 @@ enum CharacterDatabaseStatements
CHAR_SEL_CHARACTER_INSTANCE,
CHAR_SEL_CHARACTER_AURAS,
CHAR_SEL_CHARACTER_SPELL,
- CHAR_SEL_CHARACTER_QUESTSTATUS,
+ CHAR_SEL_CHARACTER_QUESTSTATUS,
+ CHAR_SEL_CHARACTER_QUESTSTATUS_OBJECTIVES,
CHAR_SEL_CHARACTER_QUESTSTATUS_DAILY,
CHAR_SEL_CHARACTER_QUESTSTATUS_WEEKLY,
CHAR_SEL_CHARACTER_QUESTSTATUS_MONTHLY,
@@ -429,6 +430,7 @@ enum CharacterDatabaseStatements
CHAR_UPD_CHAR_TAXI_PATH,
CHAR_UPD_CHAR_TAXIMASK,
CHAR_DEL_CHAR_QUESTSTATUS,
+ CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES,
CHAR_DEL_CHAR_SOCIAL_BY_GUID,
CHAR_DEL_CHAR_SOCIAL_BY_FRIEND,
CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT,
@@ -469,6 +471,8 @@ enum CharacterDatabaseStatements
CHAR_UPD_MAIL,
CHAR_REP_CHAR_QUESTSTATUS,
CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST,
+ CHAR_REP_CHAR_QUESTSTATUS_OBJECTIVES,
+ CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_BY_QUEST,
CHAR_INS_CHAR_QUESTSTATUS_REWARDED,
CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST,
CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_FACTION_CHANGE,