AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
quest_commandscript Class Reference
Inheritance diagram for quest_commandscript:
CommandScript ScriptObject

Public Member Functions

 quest_commandscript ()
 
ChatCommandTable GetCommands () const override
 
virtual std::vector< Acore::ChatCommands::ChatCommandBuilderGetCommands () const =0
 
- Public Member Functions inherited from ScriptObject
virtual bool IsDatabaseBound () const
 
virtual bool isAfterLoadScript () const
 
virtual void checkValidity ()
 
const std::string & GetName () const
 

Static Public Member Functions

static bool HandleQuestAdd (ChatHandler *handler, Quest const *quest, Optional< PlayerIdentifier > playerTarget)
 
static bool HandleQuestRemove (ChatHandler *handler, Quest const *quest, Optional< PlayerIdentifier > playerTarget)
 
static bool HandleQuestComplete (ChatHandler *handler, Quest const *quest, Optional< PlayerIdentifier > playerTarget)
 
static bool HandleQuestReward (ChatHandler *handler, Quest const *quest, Optional< PlayerIdentifier > playerTarget)
 

Additional Inherited Members

- Protected Member Functions inherited from CommandScript
 CommandScript (const char *name)
 
- Protected Member Functions inherited from ScriptObject
 ScriptObject (const char *name)
 
virtual ~ScriptObject ()=default
 

Detailed Description

Constructor & Destructor Documentation

◆ quest_commandscript()

quest_commandscript::quest_commandscript ( )
inline
37: CommandScript("quest_commandscript") { }
Definition: ScriptMgr.h:850

Member Function Documentation

◆ GetCommands()

ChatCommandTable quest_commandscript::GetCommands ( ) const
inlineoverridevirtual

Implements CommandScript.

40 {
41 static ChatCommandTable questCommandTable =
42 {
43 { "add", HandleQuestAdd, SEC_GAMEMASTER, Console::Yes },
44 { "complete", HandleQuestComplete, SEC_GAMEMASTER, Console::Yes },
45 { "remove", HandleQuestRemove, SEC_GAMEMASTER, Console::Yes },
46 { "reward", HandleQuestReward, SEC_GAMEMASTER, Console::Yes },
47 };
48 static ChatCommandTable commandTable =
49 {
50 { "quest", questCommandTable },
51 };
52 return commandTable;
53 }
@ SEC_GAMEMASTER
Definition: Common.h:68
std::vector< ChatCommandBuilder > ChatCommandTable
Definition: ChatCommand.h:50
static bool HandleQuestComplete(ChatHandler *handler, Quest const *quest, Optional< PlayerIdentifier > playerTarget)
Definition: cs_quest.cpp:230
static bool HandleQuestReward(ChatHandler *handler, Quest const *quest, Optional< PlayerIdentifier > playerTarget)
Definition: cs_quest.cpp:499
static bool HandleQuestRemove(ChatHandler *handler, Quest const *quest, Optional< PlayerIdentifier > playerTarget)
Definition: cs_quest.cpp:138
static bool HandleQuestAdd(ChatHandler *handler, Quest const *quest, Optional< PlayerIdentifier > playerTarget)
Definition: cs_quest.cpp:55

References HandleQuestAdd(), HandleQuestComplete(), HandleQuestRemove(), HandleQuestReward(), and SEC_GAMEMASTER.

◆ HandleQuestAdd()

static bool quest_commandscript::HandleQuestAdd ( ChatHandler handler,
Quest const *  quest,
Optional< PlayerIdentifier playerTarget 
)
inlinestatic
56 {
57 if (!playerTarget)
58 {
59 playerTarget = PlayerIdentifier::FromTargetOrSelf(handler);
60 }
61
62 if (!playerTarget)
63 {
65 handler->SetSentErrorMessage(true);
66 return false;
67 }
68
69 uint32 entry = quest->GetQuestId();
70
71 // check item starting quest (it can work incorrectly if added without item in inventory)
72 ItemTemplateContainer const* itc = sObjectMgr->GetItemTemplateStore();
73 ItemTemplateContainer::const_iterator result = find_if(itc->begin(), itc->end(), Finder<uint32, ItemTemplate>(entry, &ItemTemplate::StartQuest));
74
75 if (result != itc->end())
76 {
77 handler->PSendSysMessage(LANG_COMMAND_QUEST_STARTFROMITEM, entry, result->second.ItemId);
78 handler->SetSentErrorMessage(true);
79 return false;
80 }
81
82 if (Player* player = playerTarget->GetConnectedPlayer())
83 {
84 if (player->IsActiveQuest(entry))
85 {
86 handler->PSendSysMessage(LANG_COMMAND_QUEST_ACTIVE, quest->GetTitle().c_str(), entry);
87 handler->SetSentErrorMessage(true);
88 return false;
89 }
90
91 // ok, normal (creature/GO starting) quest
92 if (player->CanAddQuest(quest, true))
93 {
94 player->AddQuestAndCheckCompletion(quest, nullptr);
95 }
96 }
97 else
98 {
99 ObjectGuid::LowType guid = playerTarget->GetGUID().GetCounter();
100 QueryResult result = CharacterDatabase.Query("SELECT 1 FROM character_queststatus WHERE guid = {} AND quest = {}", guid, entry);
101
102 if (result)
103 {
104 handler->PSendSysMessage(LANG_COMMAND_QUEST_ACTIVE, quest->GetTitle().c_str(), entry);
105 handler->SetSentErrorMessage(true);
106 return false;
107 }
108
109 uint8 index = 0;
110
112 stmt->SetData(index++, guid);
113 stmt->SetData(index++, entry);
114 stmt->SetData(index++, 1);
115 stmt->SetData(index++, false);
116 stmt->SetData(index++, 0);
117
118 for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
119 {
120 stmt->SetData(index++, 0);
121 }
122
123 for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++)
124 {
125 stmt->SetData(index++, 0);
126 }
127
128 stmt->SetData(index, 0);
129
130 CharacterDatabase.Execute(stmt);
131 }
132
133 handler->PSendSysMessage(LANG_COMMAND_QUEST_ADD, quest->GetTitle().c_str(), entry);
134 handler->SetSentErrorMessage(false);
135 return true;
136 }
std::uint8_t uint8
Definition: Define.h:110
std::uint32_t uint32
Definition: Define.h:108
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
std::shared_ptr< ResultSet > QueryResult
Definition: DatabaseEnvFwd.h:28
@ CHAR_REP_CHAR_QUESTSTATUS
Definition: CharacterDatabase.h:433
std::unordered_map< uint32, ItemTemplate > ItemTemplateContainer
Definition: ItemTemplate.h:838
#define sObjectMgr
Definition: ObjectMgr.h:1640
@ LANG_COMMAND_QUEST_STARTFROMITEM
Definition: Language.h:488
@ LANG_COMMAND_QUEST_ACTIVE
Definition: Language.h:492
@ LANG_PLAYER_NOT_FOUND
Definition: Language.h:522
@ LANG_COMMAND_QUEST_ADD
Definition: Language.h:1128
#define QUEST_ITEM_OBJECTIVES_COUNT
Definition: QuestDef.h:36
#define QUEST_OBJECTIVES_COUNT
Definition: QuestDef.h:35
Definition: Util.h:35
Definition: PreparedStatement.h:158
Acore::Types::is_default< T > SetData(const uint8 index, T value)
Definition: PreparedStatement.h:78
void SetSentErrorMessage(bool val)
Definition: Chat.h:118
void PSendSysMessage(char const *fmt, Args &&... args)
Definition: Chat.h:60
virtual void SendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition: Chat.cpp:103
static Optional< PlayerIdentifier > FromTargetOrSelf(ChatHandler *handler)
Definition: ChatCommandTags.h:189
uint32 StartQuest
Definition: ItemTemplate.h:677
uint32 LowType
Definition: ObjectGuid.h:124
Definition: Player.h:1046

References CHAR_REP_CHAR_QUESTSTATUS, CharacterDatabase, Acore::ChatCommands::PlayerIdentifier::FromTargetOrSelf(), Quest::GetQuestId(), Quest::GetTitle(), LANG_COMMAND_QUEST_ACTIVE, LANG_COMMAND_QUEST_ADD, LANG_COMMAND_QUEST_STARTFROMITEM, LANG_PLAYER_NOT_FOUND, ChatHandler::PSendSysMessage(), QUEST_ITEM_OBJECTIVES_COUNT, QUEST_OBJECTIVES_COUNT, ChatHandler::SendSysMessage(), PreparedStatementBase::SetData(), ChatHandler::SetSentErrorMessage(), sObjectMgr, and ItemTemplate::StartQuest.

Referenced by GetCommands().

◆ HandleQuestComplete()

static bool quest_commandscript::HandleQuestComplete ( ChatHandler handler,
Quest const *  quest,
Optional< PlayerIdentifier playerTarget 
)
inlinestatic
231 {
232 if (!playerTarget)
233 {
234 playerTarget = PlayerIdentifier::FromTargetOrSelf(handler);
235 }
236
237 if (!playerTarget)
238 {
240 handler->SetSentErrorMessage(true);
241 return false;
242 }
243
244 uint32 entry = quest->GetQuestId();
245
246 if (Player* player = playerTarget->GetConnectedPlayer())
247 {
248 // If player doesn't have the quest
249 if (player->GetQuestStatus(entry) == QUEST_STATUS_NONE)
250 {
252 handler->SetSentErrorMessage(true);
253 return false;
254 }
255
256 // Add quest items for quests that require items
257 for (uint8 x = 0; x < QUEST_ITEM_OBJECTIVES_COUNT; ++x)
258 {
259 uint32 id = quest->RequiredItemId[x];
260 uint32 count = quest->RequiredItemCount[x];
261 if (!id || !count)
262 {
263 continue;
264 }
265
266 uint32 curItemCount = player->GetItemCount(id, true);
267
268 ItemPosCountVec dest;
269 uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, id, count - curItemCount);
270 if (msg == EQUIP_ERR_OK)
271 {
272 Item* item = player->StoreNewItem(dest, id, true);
273 player->SendNewItem(item, count - curItemCount, true, false);
274 }
275 }
276
277 // All creature/GO slain/casted (not required, but otherwise it will display "Creature slain 0/10")
278 for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
279 {
280 int32 creature = quest->RequiredNpcOrGo[i];
281 uint32 creatureCount = quest->RequiredNpcOrGoCount[i];
282
283 if (creature > 0)
284 {
285 if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creature))
286 {
287 for (uint16 z = 0; z < creatureCount; ++z)
288 {
289 player->KilledMonster(creatureInfo, ObjectGuid::Empty);
290 }
291 }
292 }
293 else if (creature < 0)
294 {
295 for (uint16 z = 0; z < creatureCount; ++z)
296 {
297 player->KillCreditGO(creature);
298 }
299 }
300 }
301
302 // player kills
303 if (quest->HasSpecialFlag(QUEST_SPECIAL_FLAGS_PLAYER_KILL))
304 {
305 if (uint32 reqPlayers = quest->GetPlayersSlain())
306 {
307 player->KilledPlayerCreditForQuest(reqPlayers, quest);
308 }
309 }
310
311 // If the quest requires reputation to complete
312 if (uint32 repFaction = quest->GetRepObjectiveFaction())
313 {
314 uint32 repValue = quest->GetRepObjectiveValue();
315 uint32 curRep = player->GetReputationMgr().GetReputation(repFaction);
316 if (curRep < repValue)
317 {
318 if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(repFaction))
319 {
320 player->GetReputationMgr().SetReputation(factionEntry, static_cast<float>(repValue));
321 }
322 }
323 }
324
325 // If the quest requires a SECOND reputation to complete
326 if (uint32 repFaction = quest->GetRepObjectiveFaction2())
327 {
328 uint32 repValue2 = quest->GetRepObjectiveValue2();
329 uint32 curRep = player->GetReputationMgr().GetReputation(repFaction);
330 if (curRep < repValue2)
331 {
332 if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(repFaction))
333 {
334 player->GetReputationMgr().SetReputation(factionEntry, static_cast<float>(repValue2));
335 }
336 }
337 }
338
339 // If the quest requires money
340 int32 ReqOrRewMoney = quest->GetRewOrReqMoney(player->GetLevel());
341 if (ReqOrRewMoney < 0)
342 {
343 player->ModifyMoney(-ReqOrRewMoney);
344 }
345
346 player->CompleteQuest(entry);
347 }
348 else
349 {
350 ObjectGuid::LowType guid = playerTarget->GetGUID().GetCounter();
351 QueryResult result = CharacterDatabase.Query("SELECT 1 FROM character_queststatus WHERE guid = {} AND quest = {}", guid, entry);
352
353 if (!result)
354 {
355 handler->PSendSysMessage(LANG_COMMAND_QUEST_NOT_FOUND_IN_LOG, quest->GetTitle(), entry);
356 handler->SetSentErrorMessage(true);
357 return false;
358 }
359
360 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
361
362 typedef std::pair<uint32, uint32> items;
363 std::vector<items> questItems;
364
365 for (uint8 x = 0; x < QUEST_ITEM_OBJECTIVES_COUNT; ++x)
366 {
367 uint32 id = quest->RequiredItemId[x];
368 uint32 count = quest->RequiredItemCount[x];
369 if (!id || !count)
370 {
371 continue;
372 }
373
374 questItems.push_back(std::pair(id, count));
375 }
376
377 if (!questItems.empty())
378 {
380 // fill mail
381 MailDraft draft(quest->GetTitle(), std::string());
382
383 for (auto const& itr : questItems)
384 {
385 if (Item* item = Item::CreateItem(itr.first, itr.second))
386 {
387 item->SaveToDB(trans);
388 draft.AddItem(item);
389 }
390 }
391
392 draft.SendMailTo(trans, MailReceiver(nullptr, guid), sender);
393 }
394
395 uint8 index = 0;
396
398 stmt->SetData(index++, guid);
399 stmt->SetData(index++, entry);
400 stmt->SetData(index++, 1);
401 stmt->SetData(index++, quest->HasFlag(QUEST_FLAGS_EXPLORATION));
402 stmt->SetData(index++, 0);
403
404 for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
405 {
406 stmt->SetData(index++, quest->RequiredNpcOrGoCount[i]);
407 }
408
409 for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++)
410 {
411 // Will be updated once they loot the items from the mailbox.
412 stmt->SetData(index++, 0);
413 }
414
415 stmt->SetData(index, 0);
416
417 trans->Append(stmt);
418
419 // If the quest requires reputation to complete, set the player rep to the required amount.
420 if (uint32 repFaction = quest->GetRepObjectiveFaction())
421 {
422 uint32 repValue = quest->GetRepObjectiveValue();
423
424 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_REP_BY_FACTION);
425 stmt->SetData(0, repFaction);
426 stmt->SetData(1, guid);
427 PreparedQueryResult result = CharacterDatabase.Query(stmt);
428
429 if (result)
430 {
431 Field* fields = result->Fetch();
432 uint32 curRep = fields[0].Get<uint32>();
433
434 if (curRep < repValue)
435 {
436 if (sFactionStore.LookupEntry(repFaction))
437 {
438 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_REP_FACTION_CHANGE);
439 stmt->SetData(0, repFaction);
440 stmt->SetData(1, repValue);
441 stmt->SetData(2, repFaction);
442 stmt->SetData(3, guid);
443 trans->Append(stmt);
444 }
445 }
446 }
447 }
448
449 // If the quest requires reputation to complete, set the player rep to the required amount.
450 if (uint32 repFaction = quest->GetRepObjectiveFaction2())
451 {
452 uint32 repValue = quest->GetRepObjectiveValue();
453
454 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_REP_BY_FACTION);
455 stmt->SetData(0, repFaction);
456 stmt->SetData(1, guid);
457 PreparedQueryResult result = CharacterDatabase.Query(stmt);
458
459 if (result)
460 {
461 Field* fields = result->Fetch();
462 uint32 curRep = fields[0].Get<uint32>();
463
464 if (curRep < repValue)
465 {
466 if (sFactionStore.LookupEntry(repFaction))
467 {
468 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_REP_FACTION_CHANGE);
469 stmt->SetData(0, repFaction);
470 stmt->SetData(1, repValue);
471 stmt->SetData(2, repFaction);
472 stmt->SetData(3, guid);
473 trans->Append(stmt);
474 }
475 }
476 }
477 }
478
479 CharacterDatabase.CommitTransaction(trans);
480 }
481
482 // check if Quest Tracker is enabled
483 if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER))
484 {
485 // prepare Quest Tracker datas
486 auto stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_QUEST_TRACK_GM_COMPLETE);
487 stmt->SetData(0, entry);
488 stmt->SetData(1, playerTarget->GetGUID().GetCounter());
489
490 // add to Quest Tracker
491 CharacterDatabase.Execute(stmt);
492 }
493
494 handler->PSendSysMessage(LANG_COMMAND_QUEST_COMPLETE, quest->GetTitle().c_str(), entry);
495 handler->SetSentErrorMessage(false);
496 return true;
497 }
std::int32_t int32
Definition: Define.h:104
std::uint16_t uint16
Definition: Define.h:109
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
Definition: DatabaseEnvFwd.h:70
std::shared_ptr< PreparedResultSet > PreparedQueryResult
Definition: DatabaseEnvFwd.h:46
@ CHAR_SEL_CHAR_REP_BY_FACTION
Definition: CharacterDatabase.h:396
@ CHAR_UPD_QUEST_TRACK_GM_COMPLETE
Definition: CharacterDatabase.h:499
@ CHAR_UPD_CHAR_REP_FACTION_CHANGE
Definition: CharacterDatabase.h:398
DBCStorage< FactionEntry > sFactionStore(FactionEntryfmt)
@ EQUIP_ERR_OK
Definition: Item.h:41
std::vector< ItemPosCount > ItemPosCountVec
Definition: Player.h:772
@ NULL_BAG
Definition: Unit.h:210
@ NULL_SLOT
Definition: Unit.h:211
@ MAIL_STATIONERY_GM
Definition: Mail.h:60
@ MAIL_NORMAL
Definition: Mail.h:38
@ LANG_COMMAND_QUEST_COMPLETE
Definition: Language.h:491
@ LANG_COMMAND_QUEST_NOTFOUND
Definition: Language.h:487
@ LANG_COMMAND_QUEST_NOT_FOUND_IN_LOG
Definition: Language.h:1129
@ QUEST_FLAGS_EXPLORATION
Definition: QuestDef.h:134
@ QUEST_STATUS_NONE
Definition: QuestDef.h:100
@ QUEST_SPECIAL_FLAGS_PLAYER_KILL
Definition: QuestDef.h:176
@ CONFIG_QUEST_ENABLE_QUEST_TRACKER
Definition: IWorld.h:149
#define sWorld
Definition: World.h:451
Class used to access individual fields of database query result.
Definition: Field.h:99
std::enable_if_t< std::is_arithmetic_v< T >, T > Get() const
Definition: Field.h:113
Definition: CreatureData.h:176
Definition: Item.h:214
static Item * CreateItem(uint32 item, uint32 count, Player const *player=nullptr, bool clone=false, uint32 randomPropertyId=0)
Definition: Item.cpp:1089
virtual void SaveToDB(CharacterDatabaseTransaction trans)
Definition: Item.cpp:338
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:106
LowType GetCounter() const
Definition: ObjectGuid.h:147
static ObjectGuid const Empty
Definition: ObjectGuid.h:122
Definition: Mail.h:84
Definition: Mail.h:106
Definition: Mail.h:120
Definition: DBCStructure.h:898

References MailDraft::AddItem(), CHAR_REP_CHAR_QUESTSTATUS, CHAR_SEL_CHAR_REP_BY_FACTION, CHAR_UPD_CHAR_REP_FACTION_CHANGE, CHAR_UPD_QUEST_TRACK_GM_COMPLETE, CharacterDatabase, CONFIG_QUEST_ENABLE_QUEST_TRACKER, Item::CreateItem(), ObjectGuid::Empty, EQUIP_ERR_OK, Acore::ChatCommands::PlayerIdentifier::FromTargetOrSelf(), Field::Get(), Quest::GetPlayersSlain(), Quest::GetQuestId(), Quest::GetRepObjectiveFaction(), Quest::GetRepObjectiveFaction2(), Quest::GetRepObjectiveValue(), Quest::GetRepObjectiveValue2(), Quest::GetRewOrReqMoney(), Quest::GetTitle(), Quest::HasFlag(), Quest::HasSpecialFlag(), LANG_COMMAND_QUEST_COMPLETE, LANG_COMMAND_QUEST_NOT_FOUND_IN_LOG, LANG_COMMAND_QUEST_NOTFOUND, LANG_PLAYER_NOT_FOUND, MAIL_NORMAL, MAIL_STATIONERY_GM, NULL_BAG, NULL_SLOT, ChatHandler::PSendSysMessage(), QUEST_FLAGS_EXPLORATION, QUEST_ITEM_OBJECTIVES_COUNT, QUEST_OBJECTIVES_COUNT, QUEST_SPECIAL_FLAGS_PLAYER_KILL, QUEST_STATUS_NONE, Quest::RequiredItemCount, Quest::RequiredItemId, Quest::RequiredNpcOrGo, Quest::RequiredNpcOrGoCount, MailDraft::SendMailTo(), ChatHandler::SendSysMessage(), PreparedStatementBase::SetData(), ChatHandler::SetSentErrorMessage(), sFactionStore, sObjectMgr, and sWorld.

Referenced by GetCommands().

◆ HandleQuestRemove()

static bool quest_commandscript::HandleQuestRemove ( ChatHandler handler,
Quest const *  quest,
Optional< PlayerIdentifier playerTarget 
)
inlinestatic
139 {
140 if (!playerTarget)
141 {
142 playerTarget = PlayerIdentifier::FromTargetOrSelf(handler);
143 }
144
145 if (!playerTarget)
146 {
148 handler->SetSentErrorMessage(true);
149 return false;
150 }
151
152 uint32 entry = quest->GetQuestId();
153
154 if (!quest)
155 {
157 handler->SetSentErrorMessage(true);
158 return false;
159 }
160
161 if (Player* player = playerTarget->GetConnectedPlayer())
162 {
163 // remove all quest entries for 'entry' from quest log
164 for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
165 {
166 uint32 logQuest = player->GetQuestSlotQuestId(slot);
167 if (logQuest == entry)
168 {
169 player->SetQuestSlot(slot, 0);
170
171 // we ignore unequippable quest items in this case, its' still be equipped
172 player->TakeQuestSourceItem(logQuest, false);
173
174 if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
175 {
176 player->pvpInfo.IsHostile = player->pvpInfo.IsInHostileArea || player->HasPvPForcingQuest();
177 player->UpdatePvPState();
178 }
179 }
180 }
181
182 player->RemoveRewardedQuest(entry);
183 player->RemoveActiveQuest(entry, false);
184 }
185 else
186 {
187 ObjectGuid::LowType guid = playerTarget->GetGUID().GetCounter();
188 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
189
191 stmt->SetData(0, guid);
192 stmt->SetData(1, entry);
193 trans->Append(stmt);
194
195 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST);
196 stmt->SetData(0, guid);
197 stmt->SetData(1, entry);
198 trans->Append(stmt);
199
200 for (uint32 const& requiredItem : quest->RequiredItemId)
201 {
203 stmt->SetData(0, requiredItem);
204 stmt->SetData(1, guid);
205
206 PreparedQueryResult result = CharacterDatabase.Query(stmt);
207
208 if (result)
209 {
210 Field* fields = result->Fetch();
211
212 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM);
213 stmt->SetData(0, fields[0].Get<uint32>());
214 trans->Append(stmt);
215
216 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
217 stmt->SetData(0, fields[0].Get<uint32>());
218 trans->Append(stmt);
219 }
220 }
221
222 CharacterDatabase.CommitTransaction(trans);
223 }
224
225 handler->PSendSysMessage(LANG_COMMAND_QUEST_REMOVED, quest->GetTitle().c_str(), entry);
226 handler->SetSentErrorMessage(false);
227 return true;
228 }
@ CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST
Definition: CharacterDatabase.h:436
@ CHAR_DEL_ITEM_INSTANCE
Definition: CharacterDatabase.h:127
@ CHAR_DEL_CHAR_INVENTORY_BY_ITEM
Definition: CharacterDatabase.h:430
@ CHAR_SEL_CHAR_INVENTORY_ITEM_BY_ENTRY_AND_OWNER
Definition: CharacterDatabase.h:359
@ CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST
Definition: CharacterDatabase.h:434
@ LANG_COMMAND_QUEST_REMOVED
Definition: Language.h:489
@ QUEST_FLAGS_FLAGS_PVP
Definition: QuestDef.h:145
#define MAX_QUEST_LOG_SIZE
Definition: QuestDef.h:33

References CHAR_DEL_CHAR_INVENTORY_BY_ITEM, CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST, CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST, CHAR_DEL_ITEM_INSTANCE, CHAR_SEL_CHAR_INVENTORY_ITEM_BY_ENTRY_AND_OWNER, CharacterDatabase, Acore::ChatCommands::PlayerIdentifier::FromTargetOrSelf(), Quest::GetQuestId(), Quest::GetTitle(), Quest::HasFlag(), LANG_COMMAND_QUEST_NOTFOUND, LANG_COMMAND_QUEST_REMOVED, LANG_PLAYER_NOT_FOUND, MAX_QUEST_LOG_SIZE, ChatHandler::PSendSysMessage(), QUEST_FLAGS_FLAGS_PVP, Quest::RequiredItemId, ChatHandler::SendSysMessage(), PreparedStatementBase::SetData(), and ChatHandler::SetSentErrorMessage().

Referenced by GetCommands().

◆ HandleQuestReward()

static bool quest_commandscript::HandleQuestReward ( ChatHandler handler,
Quest const *  quest,
Optional< PlayerIdentifier playerTarget 
)
inlinestatic
500 {
501 if (!playerTarget)
502 {
503 playerTarget = PlayerIdentifier::FromTargetOrSelf(handler);
504 }
505
506 if (!playerTarget)
507 {
509 handler->SetSentErrorMessage(true);
510 return false;
511 }
512
513 uint32 entry = quest->GetQuestId();
514
515 if (Player* player = playerTarget->GetConnectedPlayer())
516 {
517 // If player doesn't have the quest
518 if (player->GetQuestStatus(entry) != QUEST_STATUS_COMPLETE)
519 {
521 handler->SetSentErrorMessage(true);
522 return false;
523 }
524
525 player->RewardQuest(quest, 0, player);
526 }
527 else
528 {
529 // Achievement criteria updates correctly the next time a quest is rewarded.
530 // Titles are already awarded correctly the next time they login (only one quest awards title - 11549).
531 // Rewarded talent points (Death Knights) and spells (e.g Druid forms) are also granted on login.
532 // No reputation gains - too troublesome to calculate them when the player is offline.
533
534 ObjectGuid::LowType guid = playerTarget->GetGUID().GetCounter();
535 uint8 charLevel = sCharacterCache->GetCharacterLevelByGuid(ObjectGuid(HighGuid::Player, guid));
536 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
538
539 QueryResult result = CharacterDatabase.Query("SELECT 1 FROM character_queststatus WHERE guid = {} AND quest = {} AND status = 1", guid, entry);
540
541 if (!result)
542 {
544 handler->SetSentErrorMessage(true);
545 return false;
546 }
547
548 for (uint32 const& requiredItem : quest->RequiredItemId)
549 {
551 stmt->SetData(0, requiredItem);
552 stmt->SetData(1, guid);
553
554 PreparedQueryResult result = CharacterDatabase.Query(stmt);
555
556 if (result)
557 {
558 Field* fields = result->Fetch();
559
560 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM);
561 stmt->SetData(0, fields[0].Get<uint32>());
562 trans->Append(stmt);
563
564 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
565 stmt->SetData(0, fields[0].Get<uint32>());
566 trans->Append(stmt);
567 }
568 }
569
570 for (uint32 const& sourceItem : quest->ItemDrop)
571 {
573 stmt->SetData(0, sourceItem);
574 stmt->SetData(1, guid);
575
576 PreparedQueryResult result = CharacterDatabase.Query(stmt);
577
578 if (result)
579 {
580 Field* fields = result->Fetch();
581
582 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM);
583 stmt->SetData(0, fields[0].Get<uint32>());
584 trans->Append(stmt);
585
586 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
587 stmt->SetData(0, fields[0].Get<uint32>());
588 trans->Append(stmt);
589 }
590 }
591
592 typedef std::pair<uint32, uint32> items;
593 std::vector<items> questRewardItems;
594
595 if (quest->GetRewChoiceItemsCount())
596 {
597 for (uint32 const& itemId : quest->RewardChoiceItemId)
598 {
599 uint8 index = 0;
600 questRewardItems.push_back(std::pair(itemId, quest->RewardChoiceItemCount[index++]));
601 }
602 }
603
604 if (quest->GetRewItemsCount())
605 {
606 for (uint32 const& itemId : quest->RewardItemId)
607 {
608 uint8 index = 0;
609 questRewardItems.push_back(std::pair(itemId, quest->RewardItemIdCount[index++]));
610 }
611 }
612
613 if (!questRewardItems.empty())
614 {
616 // fill mail
617 MailDraft draft(quest->GetTitle(), "This quest has been manually rewarded to you. This mail contains your quest rewards.");
618
619 for (auto const& itr : questRewardItems)
620 {
621 if (!itr.first || !itr.second)
622 {
623 continue;
624 }
625
626 // Skip invalid items.
627 if (!sObjectMgr->GetItemTemplate(itr.first))
628 {
629 continue;
630 }
631
632 if (Item* item = Item::CreateItem(itr.first, itr.second))
633 {
634 item->SaveToDB(trans);
635 draft.AddItem(item);
636 }
637 }
638
639 draft.SendMailTo(trans, MailReceiver(nullptr, guid), sender);
640 }
641
642 // Send quest giver mail, if any.
643 if (uint32 mail_template_id = quest->GetRewMailTemplateId())
644 {
645 if (quest->GetRewMailSenderEntry() != 0)
646 {
647 MailDraft(mail_template_id).SendMailTo(trans, MailReceiver(nullptr, guid), quest->GetRewMailSenderEntry(), MAIL_CHECK_MASK_HAS_BODY, quest->GetRewMailDelaySecs());
648 }
649 }
650
651 if (quest->IsDaily() || quest->IsDFQuest())
652 {
653 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_DAILYQUESTSTATUS);
654 stmt->SetData(0, guid);
655 stmt->SetData(1, entry);
656 stmt->SetData(2, GameTime::GetGameTime().count());
657 trans->Append(stmt);
658 }
659 else if (quest->IsWeekly())
660 {
661 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS);
662 stmt->SetData(0, guid);
663 stmt->SetData(1, entry);
664 trans->Append(stmt);
665 }
666 else if (quest->IsMonthly())
667 {
668 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_MONTHLYQUESTSTATUS);
669 stmt->SetData(0, guid);
670 stmt->SetData(1, entry);
671 trans->Append(stmt);
672 }
673 else if (quest->IsSeasonal())
674 {
675 // We can't know which event is the quest linked to, so we can't do anything about this.
676 /* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_SEASONALQUESTSTATUS);
677 stmt->SetData(0, guid);
678 stmt->SetData(1, entry);
679 stmt->SetData(2, event_id);
680 trans->Append(stmt);*/
681 }
682
683 if (uint32 honor = quest->CalculateHonorGain(charLevel))
684 {
686 stmt->SetData(0, honor);
687 stmt->SetData(1, guid);
688 trans->Append(stmt);
689 }
690
691 if (quest->GetRewArenaPoints())
692 {
694 stmt->SetData(0, quest->GetRewArenaPoints());
695 stmt->SetData(1, guid);
696 trans->Append(stmt);
697 }
698
699 int32 rewMoney = 0;
700
701 if (charLevel >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
702 {
703 rewMoney = quest->GetRewMoneyMaxLevel();
704 }
705 else
706 {
707 // Some experience might get lost on level up.
708 uint32 xp = uint32(quest->XPValue(charLevel) * sWorld->getRate(RATE_XP_QUEST));
709 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_XP_ACCUMULATIVE);
710 stmt->SetData(0, xp);
711 stmt->SetData(1, guid);
712 trans->Append(stmt);
713 }
714
715 if (int32 rewOrReqMoney = quest->GetRewOrReqMoney(charLevel))
716 {
717 rewMoney += rewOrReqMoney;
718 }
719
720 // Only reward money, don't subtract, let's not cause an overflow...
721 if (rewMoney > 0)
722 {
724 stmt->SetData(0, rewMoney);
725 stmt->SetData(1, guid);
726 trans->Append(stmt);
727 }
728
729 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_QUESTSTATUS_REWARDED);
730 stmt->SetData(0, guid);
731 stmt->SetData(1, entry);
732 trans->Append(stmt);
733
734 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST);
735 stmt->SetData(0, guid);
736 stmt->SetData(1, entry);
737 trans->Append(stmt);
738
739 CharacterDatabase.CommitTransaction(trans);
740 }
741
742 handler->PSendSysMessage(LANG_COMMAND_QUEST_REWARDED, quest->GetTitle().c_str(), entry);
743 handler->SetSentErrorMessage(false);
744 return true;
745 }
@ CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS
Definition: CharacterDatabase.h:75
@ CHAR_INS_CHARACTER_MONTHLYQUESTSTATUS
Definition: CharacterDatabase.h:76
@ CHAR_UDP_CHAR_MONEY_ACCUMULATIVE
Definition: CharacterDatabase.h:425
@ CHAR_UDP_CHAR_HONOR_POINTS_ACCUMULATIVE
Definition: CharacterDatabase.h:421
@ CHAR_UPD_XP_ACCUMULATIVE
Definition: CharacterDatabase.h:296
@ CHAR_INS_CHARACTER_DAILYQUESTSTATUS
Definition: CharacterDatabase.h:74
@ CHAR_UDP_CHAR_ARENA_POINTS_ACCUMULATIVE
Definition: CharacterDatabase.h:423
@ CHAR_INS_CHAR_QUESTSTATUS_REWARDED
Definition: CharacterDatabase.h:435
#define sCharacterCache
Definition: CharacterCache.h:83
@ MAIL_CHECK_MASK_HAS_BODY
Definition: Mail.h:52
@ LANG_COMMAND_QUEST_REWARDED
Definition: Language.h:490
@ LANG_COMMAND_QUEST_NOT_COMPLETE
Definition: Language.h:1130
@ QUEST_STATUS_COMPLETE
Definition: QuestDef.h:101
@ CONFIG_MAX_PLAYER_LEVEL
Definition: IWorld.h:234
@ RATE_XP_QUEST
Definition: IWorld.h:465
Seconds GetGameTime()
Definition: GameTime.cpp:38
Definition: ObjectGuid.h:120
void SendMailTo(CharacterDatabaseTransaction trans, MailReceiver const &receiver, MailSender const &sender, MailCheckMask checked=MAIL_CHECK_MASK_NONE, uint32 deliver_delay=0, uint32 custom_expiration=0, bool deleteMailItemsFromDB=false, bool sendMail=true)
Definition: Mail.cpp:186

References MailDraft::AddItem(), Quest::CalculateHonorGain(), CHAR_DEL_CHAR_INVENTORY_BY_ITEM, CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST, CHAR_DEL_ITEM_INSTANCE, CHAR_INS_CHAR_QUESTSTATUS_REWARDED, CHAR_INS_CHARACTER_DAILYQUESTSTATUS, CHAR_INS_CHARACTER_MONTHLYQUESTSTATUS, CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS, CHAR_SEL_CHAR_INVENTORY_ITEM_BY_ENTRY_AND_OWNER, CHAR_UDP_CHAR_ARENA_POINTS_ACCUMULATIVE, CHAR_UDP_CHAR_HONOR_POINTS_ACCUMULATIVE, CHAR_UDP_CHAR_MONEY_ACCUMULATIVE, CHAR_UPD_XP_ACCUMULATIVE, CharacterDatabase, CONFIG_MAX_PLAYER_LEVEL, Item::CreateItem(), Acore::ChatCommands::PlayerIdentifier::FromTargetOrSelf(), GameTime::GetGameTime(), Quest::GetQuestId(), Quest::GetRewArenaPoints(), Quest::GetRewChoiceItemsCount(), Quest::GetRewItemsCount(), Quest::GetRewMailDelaySecs(), Quest::GetRewMailSenderEntry(), Quest::GetRewMailTemplateId(), Quest::GetRewMoneyMaxLevel(), Quest::GetRewOrReqMoney(), Quest::GetTitle(), Quest::IsDaily(), Quest::IsDFQuest(), Quest::IsMonthly(), Quest::IsSeasonal(), Quest::IsWeekly(), Quest::ItemDrop, LANG_COMMAND_QUEST_NOT_COMPLETE, LANG_COMMAND_QUEST_NOTFOUND, LANG_COMMAND_QUEST_REWARDED, LANG_PLAYER_NOT_FOUND, MAIL_CHECK_MASK_HAS_BODY, MAIL_NORMAL, MAIL_STATIONERY_GM, ChatHandler::PSendSysMessage(), QUEST_STATUS_COMPLETE, RATE_XP_QUEST, Quest::RequiredItemId, Quest::RewardChoiceItemCount, Quest::RewardChoiceItemId, Quest::RewardItemId, Quest::RewardItemIdCount, sCharacterCache, MailDraft::SendMailTo(), ChatHandler::SendSysMessage(), PreparedStatementBase::SetData(), ChatHandler::SetSentErrorMessage(), sObjectMgr, sWorld, and Quest::XPValue().

Referenced by GetCommands().