TrinityCore
QuestHandler.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "WorldSession.h"
19#include "Battleground.h"
20#include "Common.h"
21#include "Creature.h"
22#include "CreatureAI.h"
23#include "DatabaseEnv.h"
24#include "DB2Stores.h"
25#include "GameObject.h"
26#include "GameObjectAI.h"
27#include "GossipDef.h"
28#include "Group.h"
29#include "Log.h"
30#include "ObjectAccessor.h"
31#include "ObjectMgr.h"
32#include "Player.h"
33#include "PoolMgr.h"
34#include "QuestDef.h"
35#include "QuestPackets.h"
36#include "QuestPools.h"
37#include "ReputationMgr.h"
38#include "ScriptMgr.h"
39#include "World.h"
40
42{
43
45 if (!questGiver)
46 {
47 TC_LOG_INFO("network", "Error in CMSG_QUESTGIVER_STATUS_QUERY, called for non-existing questgiver ({})", packet.QuestGiverGUID.ToString());
48 return;
49 }
50
51 QuestGiverStatus questStatus = _player->GetQuestDialogStatus(questGiver);
52
53 //inform client about status of quest
54 _player->PlayerTalkClass->SendQuestGiverStatus(questStatus, packet.QuestGiverGUID);
55}
56
58{
59 TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_HELLO {}", packet.QuestGiverGUID.ToString());
60
62 if (!creature)
63 {
64 TC_LOG_DEBUG("network", "WORLD: HandleQuestgiverHelloOpcode - {} not found or you can't interact with him.",
65 packet.QuestGiverGUID.ToString());
66 return;
67 }
68
69 // remove fake death
70 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
72
73 // Stop the npc if moving
74 if (uint32 pause = creature->GetMovementTemplate().GetInteractionPauseTimer())
75 creature->PauseMovement(pause);
76 creature->SetHomePosition(creature->GetPosition());
77
78 _player->PlayerTalkClass->ClearMenus();
79 if (creature->AI()->OnGossipHello(_player))
80 return;
81
82 _player->PrepareGossipMenu(creature, _player->GetGossipMenuForSource(creature), true);
83 _player->SendPreparedGossip(creature);
84}
85
87{
88 TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_ACCEPT_QUEST {}, quest = {}, startcheat = {}", packet.QuestGiverGUID.ToString(), packet.QuestID, packet.StartCheat);
89
90 Object* object;
91 if (!packet.QuestGiverGUID.IsPlayer())
93 else
95
96 auto CLOSE_GOSSIP_CLEAR_SHARING_INFO = ([this]()
97 {
98 _player->PlayerTalkClass->SendCloseGossip();
100 });
101
102 // no or incorrect quest giver
103 if (!object)
104 {
105 CLOSE_GOSSIP_CLEAR_SHARING_INFO();
106 return;
107 }
108
109 if (Player* playerQuestObject = object->ToPlayer())
110 {
111 if ((_player->GetPlayerSharingQuest().IsEmpty() && _player->GetPlayerSharingQuest() != packet.QuestGiverGUID) || !playerQuestObject->CanShareQuest(packet.QuestID))
112 {
113 CLOSE_GOSSIP_CLEAR_SHARING_INFO();
114 return;
115 }
116 if (!_player->IsInSameRaidWith(playerQuestObject))
117 {
118 CLOSE_GOSSIP_CLEAR_SHARING_INFO();
119 return;
120 }
121 }
122 else
123 {
124 if (!object->hasQuest(packet.QuestID))
125 {
126 CLOSE_GOSSIP_CLEAR_SHARING_INFO();
127 return;
128 }
129 }
130
131 // some kind of WPE protection
133 {
134 CLOSE_GOSSIP_CLEAR_SHARING_INFO();
135 return;
136 }
137
138 if (Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID))
139 {
140 // prevent cheating
141 if (!GetPlayer()->CanTakeQuest(quest, true))
142 {
143 CLOSE_GOSSIP_CLEAR_SHARING_INFO();
144 return;
145 }
146
148 {
150 if (player)
151 {
154 }
155 }
156
157 if (_player->CanAddQuest(quest, true))
158 {
159 _player->AddQuestAndCheckCompletion(quest, object);
160
161 if (quest->IsPushedToPartyOnAccept())
162 {
163 if (Group* group = _player->GetGroup())
164 {
165 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
166 {
167 Player* player = itr->GetSource();
168
169 if (!player || player == _player || !player->IsInMap(_player)) // not self and in same map
170 continue;
171
172 if (player->CanTakeQuest(quest, true))
173 {
174 player->SetQuestSharingInfo(_player->GetGUID(), quest->GetQuestId());
175
176 // need confirmation that any gossip window will close
177 player->PlayerTalkClass->SendCloseGossip();
178
179 _player->SendQuestConfirmAccept(quest, player);
180 }
181 }
182 }
183 }
184
185 _player->PlayerTalkClass->SendCloseGossip();
186
187 if (quest->HasFlag(QUEST_FLAGS_LAUNCH_GOSSIP_ACCEPT))
188 {
189 auto launchGossip = [&](WorldObject* worldObject)
190 {
191 _player->PlayerTalkClass->ClearMenus();
192 _player->PrepareGossipMenu(worldObject, _player->GetGossipMenuForSource(worldObject), true);
193 _player->SendPreparedGossip(worldObject);
194 };
195
196 if (Creature* creature = object->ToCreature())
197 launchGossip(creature);
198 else if (GameObject* go = object->ToGameObject())
199 launchGossip(go);
200 }
201
202 return;
203 }
204 }
205
206 CLOSE_GOSSIP_CLEAR_SHARING_INFO();
207}
208
210{
211 TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_QUERY_QUEST QuestGiverGUID = {}, QuestID = {}, RespondToGiver = {}", packet.QuestGiverGUID.ToString(), packet.QuestID, packet.RespondToGiver);
212
213 // Verify that the guid is valid and is a questgiver or involved in the requested quest
215 if (!object || (!object->hasQuest(packet.QuestID) && !object->hasInvolvedQuest(packet.QuestID)))
216 {
217 _player->PlayerTalkClass->SendCloseGossip();
218 return;
219 }
220
221 if (Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID))
222 {
223 if (!_player->CanTakeQuest(quest, true))
224 return;
225
226 if (quest->IsAutoAccept() && _player->CanAddQuest(quest, true))
227 _player->AddQuestAndCheckCompletion(quest, object);
228
229 if (quest->IsTurnIn())
230 _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, object->GetGUID(), _player->CanCompleteQuest(quest->GetQuestId()), true);
231 else
232 _player->PlayerTalkClass->SendQuestGiverQuestDetails(quest, object->GetGUID(), true, false);
233 }
234}
235
237{
238 TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUEST_QUERY quest = {}", packet.QuestID);
239
240 if (Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID))
241 _player->PlayerTalkClass->SendQuestQueryResponse(quest);
242 else
243 {
245 response.QuestID = packet.QuestID;
246 SendPacket(response.Write());
247 }
248}
249
251{
252 TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_CHOOSE_REWARD npc = {}, quest = {}, reward = {}",
253 packet.QuestGiverGUID.ToString(), packet.QuestID, packet.Choice.Item.ItemID);
254
255 Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID);
256 if (!quest)
257 return;
258
259 if (packet.Choice.Item.ItemID)
260 {
261 switch (packet.Choice.LootItemType)
262 {
264 {
265 ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(packet.Choice.Item.ItemID);
266 if (!rewardProto)
267 {
268 TC_LOG_ERROR("entities.player.cheat", "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player {} {} tried to get invalid reward item (Item Entry: {}) for quest {} (possible packet-hacking detected)",
269 _player->GetName(), _player->GetGUID().ToString(), packet.Choice.Item.ItemID, packet.QuestID);
270 return;
271 }
272
273 bool itemValid = false;
274 for (uint32 i = 0; i < quest->GetRewChoiceItemsCount(); ++i)
275 {
276 if (quest->RewardChoiceItemId[i] && quest->RewardChoiceItemType[i] == LootItemType::Item && quest->RewardChoiceItemId[i] == packet.Choice.Item.ItemID)
277 {
278 itemValid = true;
279 break;
280 }
281 }
282
283 if (!itemValid && quest->GetQuestPackageID())
284 {
285 if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItems(quest->GetQuestPackageID()))
286 {
287 for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
288 {
289 if (uint32(questPackageItem->ItemID) != packet.Choice.Item.ItemID)
290 continue;
291
292 if (_player->CanSelectQuestPackageItem(questPackageItem))
293 {
294 itemValid = true;
295 break;
296 }
297 }
298 }
299
300 if (!itemValid)
301 {
302 if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItemsFallback(quest->GetQuestPackageID()))
303 {
304 for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
305 {
306 if (uint32(questPackageItem->ItemID) != packet.Choice.Item.ItemID)
307 continue;
308
309 itemValid = true;
310 break;
311 }
312 }
313 }
314 }
315
316 if (!itemValid)
317 {
318 TC_LOG_ERROR("entities.player.cheat", "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player {} {} tried to get reward item (Item Entry: {}) wich is not a reward for quest {} (possible packet-hacking detected)",
319 _player->GetName(), _player->GetGUID().ToString(), packet.Choice.Item.ItemID, packet.QuestID);
320 return;
321 }
322 break;
323 }
325 {
326 if (!sCurrencyTypesStore.HasRecord(packet.Choice.Item.ItemID))
327 {
328 TC_LOG_ERROR("entities.player.cheat", "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player {} {} tried to get invalid reward currency (Currency ID: {}) for quest {} (possible packet-hacking detected)",
329 _player->GetName(), _player->GetGUID().ToString(), packet.Choice.Item.ItemID, packet.QuestID);
330 return;
331 }
332
333 bool currencyValid = false;
334 for (uint32 i = 0; i < quest->GetRewChoiceItemsCount(); ++i)
335 {
336 if (quest->RewardChoiceItemId[i] && quest->RewardChoiceItemType[i] == LootItemType::Currency && quest->RewardChoiceItemId[i] == packet.Choice.Item.ItemID)
337 {
338 currencyValid = true;
339 break;
340 }
341 }
342
343 if (!currencyValid)
344 {
345 TC_LOG_ERROR("entities.player.cheat", "Error in CMSG_QUESTGIVER_CHOOSE_REWARD: player {} {} tried to get reward currency (Currency ID: {}) wich is not a reward for quest {} (possible packet-hacking detected)",
346 _player->GetName(), _player->GetGUID().ToString(), packet.Choice.Item.ItemID, packet.QuestID);
347 return;
348 }
349 break;
350 }
351 default:
352 break;
353 }
354 }
355
356 Object* object = _player;
357
359 {
361 if (!object || !object->hasInvolvedQuest(packet.QuestID))
362 return;
363
364 // some kind of WPE protection
366 return;
367 }
368
371 {
372 TC_LOG_ERROR("network", "Error in QUEST_STATUS_COMPLETE: player {} {} tried to complete quest {}, but is not allowed to do so (possible packet-hacking or high latency)",
373 _player->GetName(), _player->GetGUID().ToString(), packet.QuestID);
374 return;
375 }
376
377 if (_player->CanRewardQuest(quest, true)) // First, check if player is allowed to turn the quest in (all objectives completed). If not, we send players to the offer reward screen
378 {
379 if (_player->CanRewardQuest(quest, packet.Choice.LootItemType, packet.Choice.Item.ItemID, true)) // Then check if player can receive the reward item (if inventory is not full, if player doesn't have too many unique items, and so on). If not, the client will close the gossip window
380 {
382 bg->HandleQuestComplete(packet.QuestID, _player);
383
384 _player->RewardQuest(quest, packet.Choice.LootItemType, packet.Choice.Item.ItemID, object);
385 }
386 }
387 else
388 _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, packet.QuestGiverGUID, true);
389}
390
392{
393 TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_REQUEST_REWARD npc = {}, quest = {}", packet.QuestGiverGUID.ToString(), packet.QuestID);
394
395 Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID);
396 if (!quest)
397 return;
398
400 {
402 if (!object || !object->hasInvolvedQuest(packet.QuestID))
403 return;
404
405 // some kind of WPE protection
407 return;
408 }
409
410 if (_player->CanCompleteQuest(packet.QuestID))
412
414 return;
415
416 if (quest)
417 _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, packet.QuestGiverGUID, true);
418}
419
421{
422 TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTLOG_REMOVE_QUEST slot = {}", packet.Entry);
423
424 if (packet.Entry < MAX_QUEST_LOG_SIZE)
425 {
426 if (uint32 questId = _player->GetQuestSlotQuestId(packet.Entry))
427 {
428 if (!_player->TakeQuestSourceItem(questId, true))
429 return; // can't un-equip some items, reject quest cancel
430
431 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
432 QuestStatus oldStatus = _player->GetQuestStatus(questId);
433
434 if (quest)
435 {
437 for (QuestObjective const& objective : quest->Objectives)
438 if (_player->IsQuestObjectiveComplete(packet.Entry, quest, objective))
439 return;
440
441 if (quest->GetLimitTime())
442 _player->RemoveTimedQuest(questId);
443
444 if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
445 {
448 }
449 }
450
451 _player->SetQuestSlot(packet.Entry, 0);
452 _player->TakeQuestSourceItem(questId, true); // remove quest src item from player
453 _player->AbandonQuest(questId); // remove all quest items player received before abandoning quest. Note, this does not remove normal drop items that happen to be quest requirements.
454 _player->RemoveActiveQuest(questId);
456
457 TC_LOG_INFO("network", "Player {} abandoned quest {}", _player->GetGUID().ToString(), questId);
458
459 if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled
460 {
461 // prepare Quest Tracker datas
463 stmt->setUInt32(0, questId);
464 stmt->setUInt64(1, _player->GetGUID().GetCounter());
465
466 // add to Quest Tracker
467 CharacterDatabase.Execute(stmt);
468 }
469
470 sScriptMgr->OnQuestStatusChange(_player, questId);
471
472 if (quest)
473 sScriptMgr->OnQuestStatusChange(_player, quest, oldStatus, QUEST_STATUS_NONE);
474 }
475
477 }
478}
479
481{
482 TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUEST_CONFIRM_ACCEPT questId = {}", packet.QuestID);
483
484 if (_player->GetSharedQuestID() != uint32(packet.QuestID))
485 return;
486
488 Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID);
489 if (!quest)
490 return;
491
493 if (!originalPlayer)
494 return;
495
496 if (!_player->IsInSameRaidWith(originalPlayer))
497 return;
498
499 if (!originalPlayer->IsActiveQuest(packet.QuestID))
500 return;
501
502 if (!_player->CanTakeQuest(quest, true))
503 return;
504
505 if (!_player->CanAddQuest(quest, true))
506 return;
507
508 _player->AddQuestAndCheckCompletion(quest, nullptr); // NULL, this prevent DB script from duplicate running
509
510 if (quest->GetSrcSpell() > 0)
511 _player->CastSpell(_player, quest->GetSrcSpell(), true);
512}
513
515{
516 bool autoCompleteMode = packet.FromScript; // 0 - standart complete quest mode with npc, 1 - auto-complete mode
517
518 TC_LOG_DEBUG("network", "WORLD: Received CMSG_QUESTGIVER_COMPLETE_QUEST npc = {}, questId = {} self-complete: {}", packet.QuestGiverGUID.ToString(), packet.QuestID, autoCompleteMode ? 1 : 0);
519
520 Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID);
521 if (!quest)
522 return;
523
524 Object* object = nullptr;
525 if (autoCompleteMode)
526 object = _player;
527 else
529
530 if (!object)
531 return;
532
534 {
535 if (!object->hasInvolvedQuest(packet.QuestID))
536 return;
537
538 // some kind of WPE protection
540 return;
541 }
542 else
543 {
544 // Do not allow completing quests on other players.
545 if (packet.QuestGiverGUID != _player->GetGUID())
546 return;
547 }
548
550 {
551 TC_LOG_ERROR("entities.player.cheat", "Possible hacking attempt: Player {} [{}] tried to complete quest [entry: {}] without being in possession of the quest!",
552 _player->GetName(), _player->GetGUID().ToString(), packet.QuestID);
553 return;
554 }
555
557 {
558 if (quest->IsRepeatable())
559 _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, _player->CanCompleteRepeatableQuest(quest), false);
560 else
561 _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, _player->CanRewardQuest(quest, false), false);
562 }
563 else
564 {
565 if (quest->HasQuestObjectiveType(QUEST_OBJECTIVE_ITEM)) // some items required
566 _player->PlayerTalkClass->SendQuestGiverRequestItems(quest, packet.QuestGiverGUID, _player->CanRewardQuest(quest, false), false);
567 else // no items required
568 _player->PlayerTalkClass->SendQuestGiverOfferReward(quest, packet.QuestGiverGUID, true);
569 }
570}
571
573{
574 if (_player->FindQuestSlot(questGiverCloseQuest.QuestID) >= MAX_QUEST_LOG_SIZE)
575 return;
576
577 Quest const* quest = sObjectMgr->GetQuestTemplate(questGiverCloseQuest.QuestID);
578 if (!quest)
579 return;
580
581 sScriptMgr->OnQuestAcknowledgeAutoAccept(_player, quest);
582}
583
585{
586 Quest const* quest = sObjectMgr->GetQuestTemplate(packet.QuestID);
587 if (!quest)
588 return;
589
590 Player* const sender = GetPlayer();
591
592 if (!_player->CanShareQuest(packet.QuestID))
593 {
595 return;
596 }
597
598 // in pool and not currently available (wintergrasp weekly, dalaran weekly) - can't share
599 if (!sQuestPoolMgr->IsQuestActive(packet.QuestID))
600 {
602 return;
603 }
604
605 Group* group = sender->GetGroup();
606 if (!group)
607 {
609 return;
610 }
611
612 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
613 {
614 Player* receiver = itr->GetSource();
615
616 if (!receiver || receiver == sender)
617 continue;
618
619 if (!receiver->GetPlayerSharingQuest().IsEmpty())
620 {
622 continue;
623 }
624
625 if (!receiver->IsAlive())
626 {
629 continue;
630 }
631
632 switch (receiver->GetQuestStatus(packet.QuestID))
633 {
635 {
638 continue;
639 }
642 {
645 continue;
646 }
647 default:
648 break;
649 }
650
651 if (!receiver->SatisfyQuestLog(false))
652 {
655 continue;
656 }
657
658 if (!receiver->SatisfyQuestDay(quest, false))
659 {
662 continue;
663 }
664
665 if (!receiver->SatisfyQuestMinLevel(quest, false))
666 {
669 continue;
670 }
671
672 if (!receiver->SatisfyQuestMaxLevel(quest, false))
673 {
676 continue;
677 }
678
679 if (!receiver->SatisfyQuestClass(quest, false))
680 {
683 continue;
684 }
685
686 if (!receiver->SatisfyQuestRace(quest, false))
687 {
690 continue;
691 }
692
693 if (!receiver->SatisfyQuestReputation(quest, false))
694 {
697 continue;
698 }
699
700 if (!receiver->SatisfyQuestDependentQuests(quest, false))
701 {
704 continue;
705 }
706
707 if (!receiver->SatisfyQuestExpansion(quest, false))
708 {
711 continue;
712 }
713
714 if (!receiver->CanTakeQuest(quest, false))
715 {
718 continue;
719 }
720
722
723 if (quest->IsTurnIn() && quest->IsRepeatable() && !quest->IsDailyOrWeekly())
724 receiver->PlayerTalkClass->SendQuestGiverRequestItems(quest, sender->GetGUID(), receiver->CanCompleteRepeatableQuest(quest), true);
725 else
726 {
727 receiver->SetQuestSharingInfo(sender->GetGUID(), quest->GetQuestId());
728 receiver->PlayerTalkClass->SendQuestGiverQuestDetails(quest, receiver->GetGUID(), true, false);
729 if (quest->IsAutoAccept() && receiver->CanAddQuest(quest, true) && receiver->CanTakeQuest(quest, true))
730 {
731 receiver->AddQuestAndCheckCompletion(quest, sender);
733 receiver->ClearQuestSharingInfo();
734 }
735 }
736 }
737}
738
740{
742 {
745 player->SendPushToPartyResponse(_player, static_cast<QuestPushReason>(packet.Result));
746
748 }
749}
750
752{
754}
755
757{
758 _player->SendQuestGiverStatusMultiple(questGiverStatusTrackedQuery.QuestGiverGUIDs);
759}
760
762{
764
766 //response.WorldQuestUpdates.push_back(WorldPackets::Quest::WorldQuestUpdateInfo(lastUpdate, questID, timer, variableID, value));
767
768 SendPacket(response.Write());
769}
770
772{
773 if (_player->PlayerTalkClass->GetInteractionData().PlayerChoiceId != uint32(choiceResponse.ChoiceID))
774 {
775 TC_LOG_ERROR("entities.player.cheat", "Error in CMSG_CHOICE_RESPONSE: {} tried to respond to invalid player choice {} (allowed {}) (possible packet-hacking detected)",
776 GetPlayerInfo(), choiceResponse.ChoiceID, _player->PlayerTalkClass->GetInteractionData().PlayerChoiceId);
777 return;
778 }
779
780 PlayerChoice const* playerChoice = sObjectMgr->GetPlayerChoice(choiceResponse.ChoiceID);
781 if (!playerChoice)
782 return;
783
784 PlayerChoiceResponse const* playerChoiceResponse = playerChoice->GetResponseByIdentifier(choiceResponse.ResponseIdentifier);
785 if (!playerChoiceResponse)
786 {
787 TC_LOG_ERROR("entities.player.cheat", "Error in CMSG_CHOICE_RESPONSE: {} tried to select invalid player choice response {} (possible packet-hacking detected)",
788 GetPlayerInfo(), choiceResponse.ResponseIdentifier);
789 return;
790 }
791
792 sScriptMgr->OnPlayerChoiceResponse(GetPlayer(), choiceResponse.ChoiceID, choiceResponse.ResponseIdentifier);
793
794 if (playerChoiceResponse->Reward)
795 {
796 if (playerChoiceResponse->Reward->TitleId)
797 _player->SetTitle(sCharTitlesStore.AssertEntry(playerChoiceResponse->Reward->TitleId), false);
798
799 if (playerChoiceResponse->Reward->PackageId)
800 _player->RewardQuestPackage(playerChoiceResponse->Reward->PackageId, ItemContext::NONE);
801
802 if (playerChoiceResponse->Reward->SkillLineId && _player->HasSkill(playerChoiceResponse->Reward->SkillLineId))
803 _player->UpdateSkillPro(playerChoiceResponse->Reward->SkillLineId, 1000, playerChoiceResponse->Reward->SkillPointCount);
804
805 if (playerChoiceResponse->Reward->HonorPointCount)
806 _player->AddHonorXP(playerChoiceResponse->Reward->HonorPointCount);
807
808 if (playerChoiceResponse->Reward->Money)
809 _player->ModifyMoney(playerChoiceResponse->Reward->Money, false);
810
811 if (playerChoiceResponse->Reward->Xp)
812 _player->GiveXP(playerChoiceResponse->Reward->Xp, nullptr, 0.0f);
813
814 for (PlayerChoiceResponseRewardItem const& item : playerChoiceResponse->Reward->Items)
815 {
816 ItemPosCountVec dest;
818 {
819 Item* newItem = _player->StoreNewItem(dest, item.Id, true, GenerateItemRandomBonusListId(item.Id), {}, ItemContext::Quest_Reward, &item.BonusListIDs);
820 _player->SendNewItem(newItem, item.Quantity, true, false);
821 }
822 }
823
824 for (PlayerChoiceResponseRewardEntry const& currency : playerChoiceResponse->Reward->Currency)
825 _player->ModifyCurrency(currency.Id, currency.Quantity);
826
827 for (PlayerChoiceResponseRewardEntry const& faction : playerChoiceResponse->Reward->Faction)
828 _player->GetReputationMgr().ModifyReputation(sFactionStore.AssertEntry(faction.Id), faction.Quantity);
829 }
830}
@ CHAR_UPD_QUEST_TRACK_ABANDON_TIME
DB2Storage< CharTitlesEntry > sCharTitlesStore("CharTitles.db2", &CharTitlesLoadInfo::Instance)
DB2Storage< CurrencyTypesEntry > sCurrencyTypesStore("CurrencyTypes.db2", &CurrencyTypesLoadInfo::Instance)
DB2Storage< FactionEntry > sFactionStore("Faction.db2", &FactionLoadInfo::Instance)
#define sDB2Manager
Definition: DB2Stores.h:538
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
uint32_t uint32
Definition: Define.h:142
@ EQUIP_ERR_OK
Definition: ItemDefines.h:26
ItemRandomBonusListId GenerateItemRandomBonusListId(uint32 item_id)
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
@ TYPEMASK_ITEM
Definition: ObjectGuid.h:56
@ TYPEMASK_UNIT
Definition: ObjectGuid.h:60
@ TYPEMASK_GAMEOBJECT
Definition: ObjectGuid.h:63
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::vector< ItemPosCount > ItemPosCountVec
Definition: Player.h:750
QuestPushReason
Definition: QuestDef.h:76
@ QUEST_OBJECTIVE_ITEM
Definition: QuestDef.h:333
QuestGiverStatus
Definition: QuestDef.h:153
#define MAX_QUEST_LOG_SIZE
Definition: QuestDef.h:44
@ QUEST_FLAGS_EX_NO_ABANDON_ONCE_BEGUN
Definition: QuestDef.h:243
QuestStatus
Definition: QuestDef.h:141
@ QUEST_STATUS_REWARDED
Definition: QuestDef.h:148
@ QUEST_STATUS_INCOMPLETE
Definition: QuestDef.h:145
@ QUEST_STATUS_NONE
Definition: QuestDef.h:142
@ QUEST_STATUS_COMPLETE
Definition: QuestDef.h:143
@ QUEST_FLAGS_FLAGS_PVP
Definition: QuestDef.h:207
@ QUEST_FLAGS_AUTO_COMPLETE
Definition: QuestDef.h:210
@ QUEST_FLAGS_LAUNCH_GOSSIP_ACCEPT
Definition: QuestDef.h:223
#define sQuestPoolMgr
Definition: QuestPools.h:63
#define sScriptMgr
Definition: ScriptMgr.h:1418
@ SPELL_AURA_FEIGN_DEATH
@ UNIT_NPC_FLAG_QUESTGIVER
Definition: UnitDefines.h:298
@ UNIT_NPC_FLAG_2_NONE
Definition: UnitDefines.h:336
@ UNIT_STATE_DIED
Definition: Unit.h:255
@ NULL_BAG
Definition: Unit.h:62
@ NULL_SLOT
Definition: Unit.h:63
virtual bool OnGossipHello(Player *)
Definition: CreatureAI.h:198
void SetHomePosition(float x, float y, float z, float o)
Definition: Creature.h:371
CreatureMovementData const & GetMovementTemplate() const
Definition: Creature.cpp:2939
CreatureAI * AI() const
Definition: Creature.h:214
GroupReference * next()
Definition: Group.h:197
GroupReference * GetFirstMember()
Definition: Group.h:325
Definition: Item.h:170
LowType GetCounter() const
Definition: ObjectGuid.h:293
bool IsEmpty() const
Definition: ObjectGuid.h:319
bool IsPlayer() const
Definition: ObjectGuid.h:326
std::string ToString() const
Definition: ObjectGuid.cpp:554
Definition: Object.h:150
static Creature * ToCreature(Object *o)
Definition: Object.h:219
static GameObject * ToGameObject(Object *o)
Definition: Object.h:231
virtual bool hasQuest(uint32) const
Definition: Object.h:192
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
virtual bool hasInvolvedQuest(uint32) const
Definition: Object.h:193
static Player * ToPlayer(Object *o)
Definition: Object.h:213
void SendQuestConfirmAccept(Quest const *quest, Player *receiver) const
Definition: Player.cpp:17265
bool CanInteractWithQuestGiver(Object *questGiver) const
Definition: Player.cpp:1929
Item * StoreNewItem(ItemPosCountVec const &pos, uint32 itemId, bool update, ItemRandomBonusListId randomBonusListId=0, GuidSet const &allowedLooters=GuidSet(), ItemContext context=ItemContext::NONE, std::vector< int32 > const *bonusListIDs=nullptr, bool addToCollection=true)
Definition: Player.cpp:11537
bool HasPvPForcingQuest() const
Definition: Player.cpp:17391
bool IsInSameRaidWith(Player const *p) const
Definition: Player.cpp:2160
bool ModifyMoney(int64 amount, bool sendError=true)
Definition: Player.cpp:24098
bool CanCompleteQuest(uint32 quest_id, uint32 ignoredQuestObjectiveId=0)
Definition: Player.cpp:14656
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition: Player.cpp:1947
void DespawnPersonalSummonsForQuest(uint32 questId)
Definition: Player.cpp:16363
uint16 FindQuestSlot(uint32 quest_id) const
Definition: Player.cpp:16432
void UpdatePvPState(bool onlyFFA=false)
Definition: Player.cpp:23317
void AddHonorXP(uint32 xp)
Definition: Player.cpp:6921
bool SatisfyQuestMinLevel(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15556
void GiveXP(uint32 xp, Unit *victim, float group_rate=1.0f)
Definition: Player.cpp:2210
void SendPreparedGossip(WorldObject *source)
Definition: Player.cpp:14137
bool CanSeeStartQuest(Quest const *quest) const
Definition: Player.cpp:14606
bool SatisfyQuestDay(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15905
QuestGiverStatus GetQuestDialogStatus(Object const *questGiver) const
Definition: Player.cpp:16194
bool CanAddQuest(Quest const *quest, bool msg) const
Definition: Player.cpp:14632
bool CanRewardQuest(Quest const *quest, bool msg) const
Definition: Player.cpp:14717
void CompleteQuest(uint32 quest_id)
Definition: Player.cpp:15023
void RewardQuestPackage(uint32 questPackageId, ItemContext context, uint32 onlyItemId=0)
Definition: Player.cpp:15109
bool HasSkill(uint32 skill) const
Definition: Player.cpp:6031
uint32 GetSharedQuestID() const
Definition: Player.h:1672
bool SatisfyQuestLog(bool msg) const
Definition: Player.cpp:15586
uint32 GetQuestSlotQuestId(uint16 slot) const
Definition: Player.cpp:16441
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
bool CanShareQuest(uint32 questId) const
Definition: Player.cpp:16064
bool SatisfyQuestRace(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15758
bool SatisfyQuestClass(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15736
bool SatisfyQuestReputation(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15774
Battleground * GetBattleground() const
Definition: Player.cpp:24976
bool SatisfyQuestMaxLevel(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15571
bool IsActiveQuest(uint32 quest_id) const
Definition: Player.cpp:14575
PvPInfo pvpInfo
Definition: Player.h:1953
bool SatisfyQuestExpansion(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15943
void SetQuestSlot(uint16 slot, uint32 quest_id)
Definition: Player.cpp:16505
void AddQuestAndCheckCompletion(Quest const *quest, Object *questGiver)
Definition: Player.cpp:14774
void SetTitle(CharTitlesEntry const *title, bool lost=false)
Definition: Player.cpp:26283
void SetQuestSharingInfo(ObjectGuid guid, uint32 id)
Definition: Player.h:1674
void ClearQuestSharingInfo()
Definition: Player.h:1675
bool CanTakeQuest(Quest const *quest, bool msg) const
Definition: Player.cpp:14620
bool TakeQuestSourceItem(uint32 questId, bool msg)
Definition: Player.cpp:15999
bool IsQuestObjectiveComplete(uint16 slot, Quest const *quest, QuestObjective const &objective) const
Definition: Player.cpp:17090
void RemoveActiveQuest(uint32 questId, bool update=true)
Definition: Player.cpp:16093
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition: Player.cpp:16050
bool CanCompleteRepeatableQuest(Quest const *quest)
Definition: Player.cpp:14703
bool SatisfyQuestDependentQuests(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15600
bool CanSelectQuestPackageItem(QuestPackageItemEntry const *questPackageItem) const
Definition: Player.cpp:15084
void SendPushToPartyResponse(Player const *player, QuestPushReason reason, Quest const *quest=nullptr) const
Definition: Player.cpp:17286
bool UpdateSkillPro(uint16 skillId, int32 chance, uint32 step)
Definition: Player.cpp:5661
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
void PrepareGossipMenu(WorldObject *source, uint32 menuId, bool showQuests=false)
Definition: Player.cpp:14036
void AbandonQuest(uint32 quest_id)
Definition: Player.cpp:15508
ObjectGuid GetPlayerSharingQuest() const
Definition: Player.h:1673
void RemoveTimedQuest(uint32 questId)
Definition: Player.h:1681
void SendQuestGiverStatusMultiple()
Definition: Player.cpp:17356
void ModifyCurrency(uint32 id, int32 amount, CurrencyGainSource gainSource=CurrencyGainSource::Cheat, CurrencyDestroyReason destroyReason=CurrencyDestroyReason::Cheat)
Modify currency amount.
Definition: Player.cpp:7110
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
Definition: Player.cpp:10032
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition: Player.h:2380
ReputationMgr & GetReputationMgr()
Definition: Player.h:2251
void RewardQuest(Quest const *quest, LootItemType rewardType, uint32 rewardId, Object *questGiver, bool announce=true)
Definition: Player.cpp:15152
void SendNewItem(Item *item, uint32 quantity, bool received, bool created, bool broadcast=false, uint32 dungeonEncounterId=0)
Definition: Player.cpp:13990
uint32 GetGossipMenuForSource(WorldObject const *source) const
Definition: Player.cpp:14389
void setUInt32(const uint8 index, const uint32 value)
void setUInt64(const uint8 index, const uint64 value)
bool IsTurnIn() const
Definition: QuestDef.cpp:544
std::array< LootItemType, QUEST_REWARD_CHOICES_COUNT > RewardChoiceItemType
Definition: QuestDef.h:692
bool HasQuestObjectiveType(QuestObjectiveType type) const
Definition: QuestDef.h:575
std::array< uint32, QUEST_REWARD_CHOICES_COUNT > RewardChoiceItemId
Definition: QuestDef.h:693
uint32 GetQuestPackageID() const
Definition: QuestDef.h:589
QuestObjectives Objectives
Definition: QuestDef.h:702
uint32 GetSrcSpell() const
Definition: QuestDef.h:615
bool IsRepeatable() const
Definition: QuestDef.h:654
int64 GetLimitTime() const
Definition: QuestDef.h:603
uint32 GetQuestId() const
Definition: QuestDef.h:587
bool IsAutoAccept() const
Definition: QuestDef.cpp:539
uint32 GetRewChoiceItemsCount() const
Definition: QuestDef.h:708
bool IsDailyOrWeekly() const
Definition: QuestDef.h:678
bool HasFlagEx(QuestFlagsEx flag) const
Definition: QuestDef.h:570
bool HasFlag(QuestFlags flag) const
Definition: QuestDef.h:569
bool ModifyReputation(FactionEntry const *factionEntry, int32 standing, bool spillOverOnly=false, bool noSpillover=false)
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3812
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition: Unit.cpp:10064
bool IsAlive() const
Definition: Unit.h:1164
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
std::string const & GetName() const
Definition: Object.h:555
bool IsInMap(WorldObject const *obj) const
Definition: Object.cpp:1115
WorldPacket const * Write() override
WorldPacket const * Write() override
void HandleQuestLogRemoveQuest(WorldPackets::Quest::QuestLogRemoveQuest &packet)
void HandleRequestWorldQuestUpdate(WorldPackets::Quest::RequestWorldQuestUpdate &packet)
void HandleQuestgiverRequestRewardOpcode(WorldPackets::Quest::QuestGiverRequestReward &packet)
void HandlePushQuestToParty(WorldPackets::Quest::PushQuestToParty &packet)
void HandleQuestgiverStatusMultipleQuery(WorldPackets::Quest::QuestGiverStatusMultipleQuery &packet)
void HandleQuestgiverAcceptQuestOpcode(WorldPackets::Quest::QuestGiverAcceptQuest &packet)
void HandlePlayerChoiceResponse(WorldPackets::Quest::ChoiceResponse &choiceResponse)
void HandleQuestgiverHelloOpcode(WorldPackets::Quest::QuestGiverHello &packet)
std::string GetPlayerInfo() const
void HandleQuestQueryOpcode(WorldPackets::Quest::QueryQuestInfo &packet)
void HandleQuestPushResult(WorldPackets::Quest::QuestPushResult &packet)
Player * GetPlayer() const
void HandleQuestgiverStatusQueryOpcode(WorldPackets::Quest::QuestGiverStatusQuery &packet)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
Player * _player
void HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::QuestGiverChooseReward &packet)
void HandleQuestgiverCompleteQuest(WorldPackets::Quest::QuestGiverCompleteQuest &packet)
void HandleQuestConfirmAccept(WorldPackets::Quest::QuestConfirmAccept &packet)
void HandleQuestgiverStatusTrackedQueryOpcode(WorldPackets::Quest::QuestGiverStatusTrackedQuery &questGiverStatusTrackedQuery)
void HandleQuestgiverQueryQuestOpcode(WorldPackets::Quest::QuestGiverQueryQuest &packet)
void HandleQuestgiverCloseQuest(WorldPackets::Quest::QuestGiverCloseQuest &questGiverCloseQuest)
#define sWorld
Definition: World.h:931
@ CONFIG_QUEST_ENABLE_QUEST_TRACKER
Definition: World.h:166
TC_GAME_API Object * GetObjectByTypeMask(WorldObject const &, ObjectGuid const &, uint32 typemask)
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
uint32 GetInteractionPauseTimer() const
Definition: CreatureData.h:407
std::vector< int32 > BonusListIDs
Definition: ObjectMgr.h:871
Optional< PlayerChoiceResponseReward > Reward
Definition: ObjectMgr.h:926
PlayerChoiceResponse const * GetResponseByIdentifier(int32 responseIdentifier) const
Definition: ObjectMgr.h:951
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81
bool IsHostile
Definition: Player.h:348
bool IsInHostileArea
Definition: Player.h:349