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
 
uint16 GetTotalAvailableHooks ()
 

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, uint16 totalAvailableHooks=0)
 
virtual ~ScriptObject ()=default
 

Detailed Description

Constructor & Destructor Documentation

◆ quest_commandscript()

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

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:59
std::vector< ChatCommandBuilder > ChatCommandTable
Definition: ChatCommand.h:46
static bool HandleQuestComplete(ChatHandler *handler, Quest const *quest, Optional< PlayerIdentifier > playerTarget)
Definition: cs_quest.cpp:224
static bool HandleQuestReward(ChatHandler *handler, Quest const *quest, Optional< PlayerIdentifier > playerTarget)
Definition: cs_quest.cpp:490
static bool HandleQuestRemove(ChatHandler *handler, Quest const *quest, Optional< PlayerIdentifier > playerTarget)
Definition: cs_quest.cpp:134
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 return false;
66 }
67
68 uint32 entry = quest->GetQuestId();
69
70 // check item starting quest (it can work incorrectly if added without item in inventory)
71 ItemTemplateContainer const* itc = sObjectMgr->GetItemTemplateStore();
72 ItemTemplateContainer::const_iterator result = find_if(itc->begin(), itc->end(), Finder<uint32, ItemTemplate>(entry, &ItemTemplate::StartQuest));
73
74 if (result != itc->end())
75 {
76 handler->SendErrorMessage(LANG_COMMAND_QUEST_STARTFROMITEM, entry, result->second.ItemId);
77 return false;
78 }
79
80 if (Player* player = playerTarget->GetConnectedPlayer())
81 {
82 if (player->IsActiveQuest(entry))
83 {
84 handler->SendErrorMessage(LANG_COMMAND_QUEST_ACTIVE, quest->GetTitle().c_str(), entry);
85 return false;
86 }
87
88 // ok, normal (creature/GO starting) quest
89 if (player->CanAddQuest(quest, true))
90 {
91 player->AddQuestAndCheckCompletion(quest, nullptr);
92 }
93 }
94 else
95 {
96 ObjectGuid::LowType guid = playerTarget->GetGUID().GetCounter();
97 QueryResult result = CharacterDatabase.Query("SELECT 1 FROM character_queststatus WHERE guid = {} AND quest = {}", guid, entry);
98
99 if (result)
100 {
101 handler->SendErrorMessage(LANG_COMMAND_QUEST_ACTIVE, quest->GetTitle().c_str(), entry);
102 return false;
103 }
104
105 uint8 index = 0;
106
108 stmt->SetData(index++, guid);
109 stmt->SetData(index++, entry);
110 stmt->SetData(index++, 1);
111 stmt->SetData(index++, false);
112 stmt->SetData(index++, 0);
113
114 for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; i++)
115 {
116 stmt->SetData(index++, 0);
117 }
118
119 for (uint8 i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++)
120 {
121 stmt->SetData(index++, 0);
122 }
123
124 stmt->SetData(index, 0);
125
126 CharacterDatabase.Execute(stmt);
127 }
128
129 handler->PSendSysMessage(LANG_COMMAND_QUEST_ADD, quest->GetTitle(), entry);
130 handler->SetSentErrorMessage(false);
131 return true;
132 }
std::uint8_t uint8
Definition: Define.h:109
std::uint32_t uint32
Definition: Define.h:107
#define sObjectMgr
Definition: ObjectMgr.h:1635
#define QUEST_ITEM_OBJECTIVES_COUNT
Definition: QuestDef.h:36
#define QUEST_OBJECTIVES_COUNT
Definition: QuestDef.h:35
@ LANG_COMMAND_QUEST_STARTFROMITEM
Definition: Language.h:505
@ LANG_COMMAND_QUEST_ACTIVE
Definition: Language.h:509
@ LANG_PLAYER_NOT_FOUND
Definition: Language.h:539
@ LANG_COMMAND_QUEST_ADD
Definition: Language.h:1121
std::unordered_map< uint32, ItemTemplate > ItemTemplateContainer
Definition: ItemTemplate.h:835
@ CHAR_REP_CHAR_QUESTSTATUS
Definition: CharacterDatabase.h:436
std::shared_ptr< ResultSet > QueryResult
Definition: DatabaseEnvFwd.h:27
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
Definition: Util.h:35
Definition: PreparedStatement.h:157
Acore::Types::is_default< T > SetData(const uint8 index, T value)
Definition: PreparedStatement.h:77
void PSendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition: Chat.cpp:210
void SendErrorMessage(uint32 entry)
Definition: Chat.cpp:215
void SetSentErrorMessage(bool val)
Definition: Chat.h:238
static Optional< PlayerIdentifier > FromTargetOrSelf(ChatHandler *handler)
Definition: ChatCommandTags.h:184
uint32 StartQuest
Definition: ItemTemplate.h:668
uint32 LowType
Definition: ObjectGuid.h:122
Definition: Player.h:1064

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

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

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::SendErrorMessage(), PreparedStatementBase::SetData(), and ChatHandler::SetSentErrorMessage().

Referenced by GetCommands().

◆ HandleQuestReward()

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

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, ChatHandler::SendErrorMessage(), MailDraft::SendMailTo(), PreparedStatementBase::SetData(), ChatHandler::SetSentErrorMessage(), sObjectMgr, sWorld, and Quest::XPValue().

Referenced by GetCommands().