· 8 years ago · May 15, 2018, 09:18 AM
1From cef006aa8228e902d9892c6dec3aadc7a348bdf8 Mon Sep 17 00:00:00 2001
2From: kandera <kanderacutie@hotmail.com>
3Date: Tue, 3 Jan 2012 08:37:21 -0500
4Subject: [PATCH] Core/Quests: Add implementation of seasonal quest reset.
5 uses a new table much like character_queststatus_weekly.
6 fixed typo where WEEKLY was WEKLY. Attempt 2
7
8---
9 ..._00_world_game_event_seasonal_questrelation.sql | 387 ++++++++++++++++++++
10 ...1_characters_character_queststatus_seasonal.sql | 8 +
11 src/server/game/Entities/Player/Player.cpp | 89 +++++-
12 src/server/game/Entities/Player/Player.h | 12 +-
13 src/server/game/Events/GameEventMgr.cpp | 45 +++
14 src/server/game/Events/GameEventMgr.h | 3 +
15 src/server/game/Quests/QuestDef.cpp | 1 +
16 src/server/game/Quests/QuestDef.h | 5 +
17 .../Server/Protocol/Handlers/CharacterHandler.cpp | 8 +-
18 src/server/game/World/World.cpp | 11 +
19 src/server/game/World/World.h | 1 +
20 .../Database/Implementation/CharacterDatabase.cpp | 4 +-
21 .../Database/Implementation/CharacterDatabase.h | 4 +-
22 13 files changed, 567 insertions(+), 11 deletions(-)
23 create mode 100644 sql/updates/world/2012_01_03_00_world_game_event_seasonal_questrelation.sql
24 create mode 100644 sql/updates/world/2012_01_03_01_characters_character_queststatus_seasonal.sql
25 mode change 100755 => 100644 src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp
26 mode change 100755 => 100644 src/server/shared/Database/Implementation/CharacterDatabase.cpp
27 mode change 100755 => 100644 src/server/shared/Database/Implementation/CharacterDatabase.h
28
29diff --git a/sql/updates/world/2012_01_03_00_world_game_event_seasonal_questrelation.sql b/sql/updates/world/2012_01_03_00_world_game_event_seasonal_questrelation.sql
30new file mode 100644
31index 0000000..b4ff9c1
32--- /dev/null
33+++ b/sql/updates/world/2012_01_03_00_world_game_event_seasonal_questrelation.sql
34@@ -0,0 +1,387 @@
35+DROP TABLE IF EXISTS `game_event_seasonal_questrelation`;
36+CREATE TABLE `game_event_seasonal_questrelation` (
37+ `quest` mediumint(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
38+ `event` mediumint(10) NOT NULL DEFAULT '0' COMMENT 'Quest Identifier',
39+ PRIMARY KEY (`quest`,`event`),
40+ KEY `idx_quest` (`quest`)
41+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System';
42+
43+INSERT INTO `game_event_seasonal_questrelation` (`quest`,`event`) VALUES
44+ (1657, 12),
45+ (1658, 12),
46+ (6961, 2),
47+ (6962, 2),
48+ (6963, 2),
49+ (6964, 2),
50+ (6983, 3),
51+ (6984, 3),
52+ (7021, 2),
53+ (7022, 2),
54+ (7023, 2),
55+ (7024, 2),
56+ (7025, 2),
57+ (7042, 2),
58+ (7043, 2),
59+ (7045, 2),
60+ (7061, 2),
61+ (7062, 2),
62+ (7063, 2),
63+ (8149, 11),
64+ (8150, 11),
65+ (8311, 12),
66+ (8312, 12),
67+ (8322, 12),
68+ (8353, 12),
69+ (8354, 12),
70+ (8355, 12),
71+ (8356, 12),
72+ (8357, 12),
73+ (8358, 12),
74+ (8359, 12),
75+ (8360, 12),
76+ (8373, 12),
77+ (8409, 12),
78+ (8744, 52),
79+ (8746, 2),
80+ (8762, 2),
81+ (8763, 2),
82+ (8767, 52),
83+ (8768, 52),
84+ (8769, 52),
85+ (8788, 52),
86+ (8799, 2),
87+ (8803, 52),
88+ (8827, 2),
89+ (8828, 2),
90+ (8860, 6),
91+ (8861, 6),
92+ (8868, 7),
93+ (8897, 8),
94+ (8898, 8),
95+ (8899, 8),
96+ (8900, 8),
97+ (8901, 8),
98+ (8902, 8),
99+ (8903, 8),
100+ (8904, 8),
101+ (8971, -1),
102+ (8972, -1),
103+ (8973, -1),
104+ (8974, -1),
105+ (8975, -1),
106+ (8976, -1),
107+ (8979, 8),
108+ (8980, 8),
109+ (8981, 8),
110+ (8982, 8),
111+ (8983, 8),
112+ (8984, 8),
113+ (8993, 8),
114+ (9024, 8),
115+ (9025, 8),
116+ (9026, 8),
117+ (9027, 8),
118+ (9028, 8),
119+ (11131, 12),
120+ (11135, 12),
121+ (11219, 12),
122+ (11220, 12),
123+ (11242, 12),
124+ (11356, 12),
125+ (11357, 12),
126+ (11360, 12),
127+ (11361, 12),
128+ (11392, 12),
129+ (11401, 12),
130+ (11403, 12),
131+ (11404, 12),
132+ (11405, 12),
133+ (11435, 12),
134+ (11439, 12),
135+ (11440, 12),
136+ (11449, 12),
137+ (11450, 12),
138+ (11528, 52),
139+ (11558, 8),
140+ (11580, 1),
141+ (11581, 1),
142+ (11583, 1),
143+ (11584, 1),
144+ (11696, 1),
145+ (11732, 1),
146+ (11734, 1),
147+ (11735, 1),
148+ (11736, 1),
149+ (11737, 1),
150+ (11738, 1),
151+ (11739, 1),
152+ (11740, 1),
153+ (11741, 1),
154+ (11742, 1),
155+ (11743, 1),
156+ (11744, 1),
157+ (11745, 1),
158+ (11746, 1),
159+ (11747, 1),
160+ (11748, 1),
161+ (11749, 1),
162+ (11750, 1),
163+ (11751, 1),
164+ (11752, 1),
165+ (11753, 1),
166+ (11754, 1),
167+ (11755, 1),
168+ (11756, 1),
169+ (11757, 1),
170+ (11758, 1),
171+ (11759, 1),
172+ (11760, 1),
173+ (11761, 1),
174+ (11762, 1),
175+ (11763, 1),
176+ (11764, 1),
177+ (11765, 1),
178+ (11766, 1),
179+ (11767, 1),
180+ (11768, 1),
181+ (11769, 1),
182+ (11770, 1),
183+ (11771, 1),
184+ (11772, 1),
185+ (11773, 1),
186+ (11774, 1),
187+ (11775, 1),
188+ (11776, 1),
189+ (11777, 1),
190+ (11778, 1),
191+ (11779, 1),
192+ (11780, 1),
193+ (11781, 1),
194+ (11782, 1),
195+ (11783, 1),
196+ (11784, 1),
197+ (11785, 1),
198+ (11786, 1),
199+ (11787, 1),
200+ (11799, 1),
201+ (11800, 1),
202+ (11801, 1),
203+ (11802, 1),
204+ (11803, 1),
205+ (11804, 1),
206+ (11805, 1),
207+ (11806, 1),
208+ (11807, 1),
209+ (11808, 1),
210+ (11809, 1),
211+ (11810, 1),
212+ (11811, 1),
213+ (11812, 1),
214+ (11813, 1),
215+ (11814, 1),
216+ (11815, 1),
217+ (11816, 1),
218+ (11817, 1),
219+ (11818, 1),
220+ (11819, 1),
221+ (11820, 1),
222+ (11821, 1),
223+ (11822, 1),
224+ (11823, 1),
225+ (11824, 1),
226+ (11825, 1),
227+ (11826, 1),
228+ (11827, 1),
229+ (11828, 1),
230+ (11829, 1),
231+ (11830, 1),
232+ (11831, 1),
233+ (11832, 1),
234+ (11833, 1),
235+ (11834, 1),
236+ (11835, 1),
237+ (11836, 1),
238+ (11837, 1),
239+ (11838, 1),
240+ (11839, 1),
241+ (11840, 1),
242+ (11841, 1),
243+ (11842, 1),
244+ (11843, 1),
245+ (11844, 1),
246+ (11845, 1),
247+ (11846, 1),
248+ (11847, 1),
249+ (11848, 1),
250+ (11849, 1),
251+ (11850, 1),
252+ (11851, 1),
253+ (11852, 1),
254+ (11853, 1),
255+ (11854, 1),
256+ (11855, 1),
257+ (11856, 1),
258+ (11857, 1),
259+ (11858, 1),
260+ (11859, 1),
261+ (11860, 1),
262+ (11861, 1),
263+ (11862, 1),
264+ (11863, 1),
265+ (11937, 1),
266+ (11976, 1),
267+ (12133, 12),
268+ (12135, 12),
269+ (12139, 12),
270+ (12155, 12),
271+ (12286, -1),
272+ (12313, 24),
273+ (12331, 12),
274+ (12332, 12),
275+ (12333, 12),
276+ (12334, 12),
277+ (12335, 12),
278+ (12336, 12),
279+ (12337, 12),
280+ (12338, 12),
281+ (12339, 12),
282+ (12340, 12),
283+ (12341, 12),
284+ (12342, 12),
285+ (12343, 12),
286+ (12344, 12),
287+ (12345, 12),
288+ (12346, 12),
289+ (12347, 12),
290+ (12348, 12),
291+ (12349, 12),
292+ (12350, 12),
293+ (12351, 12),
294+ (12352, 12),
295+ (12353, 12),
296+ (12354, 12),
297+ (12355, 12),
298+ (12356, 12),
299+ (12357, 12),
300+ (12358, 12),
301+ (12359, 12),
302+ (12360, 12),
303+ (12361, 12),
304+ (12362, 12),
305+ (12363, 12),
306+ (12364, 12),
307+ (12365, 12),
308+ (12366, 12),
309+ (12367, 12),
310+ (12368, 12),
311+ (12369, 12),
312+ (12370, 12),
313+ (12371, 12),
314+ (12373, 12),
315+ (12374, 12),
316+ (12375, 12),
317+ (12376, 12),
318+ (12377, 12),
319+ (12378, 12),
320+ (12379, 12),
321+ (12380, 12),
322+ (12381, 12),
323+ (12382, 12),
324+ (12383, 12),
325+ (12384, 12),
326+ (12385, 12),
327+ (12386, 12),
328+ (12387, 12),
329+ (12388, 12),
330+ (12389, 12),
331+ (12390, 12),
332+ (12391, 12),
333+ (12392, 12),
334+ (12393, 12),
335+ (12394, 12),
336+ (12395, 12),
337+ (12396, 12),
338+ (12397, 12),
339+ (12398, 12),
340+ (12399, 12),
341+ (12400, 12),
342+ (12401, 12),
343+ (12402, 12),
344+ (12403, 12),
345+ (12404, 12),
346+ (12405, 12),
347+ (12406, 12),
348+ (12407, 12),
349+ (12408, 12),
350+ (12409, 12),
351+ (12410, 12),
352+ (12940, 12),
353+ (12941, 12),
354+ (12944, 12),
355+ (12945, 12),
356+ (12946, 12),
357+ (12947, 12),
358+ (12950, 12),
359+ (13203, 52),
360+ (13433, 12),
361+ (13434, 12),
362+ (13435, 12),
363+ (13436, 12),
364+ (13437, 12),
365+ (13438, 12),
366+ (13439, 12),
367+ (13440, 12),
368+ (13441, 12),
369+ (13442, 12),
370+ (13443, 12),
371+ (13444, 12),
372+ (13445, 12),
373+ (13446, 12),
374+ (13447, 12),
375+ (13448, 12),
376+ (13449, 12),
377+ (13450, 12),
378+ (13451, 12),
379+ (13452, 12),
380+ (13453, 12),
381+ (13454, 12),
382+ (13455, 12),
383+ (13456, 12),
384+ (13457, 12),
385+ (13458, 12),
386+ (13459, 12),
387+ (13460, 12),
388+ (13461, 12),
389+ (13462, 12),
390+ (13463, 12),
391+ (13464, 12),
392+ (13465, 12),
393+ (13466, 12),
394+ (13467, 12),
395+ (13468, 12),
396+ (13469, 12),
397+ (13470, 12),
398+ (13471, 12),
399+ (13472, 12),
400+ (13473, 12),
401+ (13474, 12),
402+ (13485, 1),
403+ (13486, 1),
404+ (13487, 1),
405+ (13488, 1),
406+ (13489, 1),
407+ (13490, 1),
408+ (13491, 1),
409+ (13492, 1),
410+ (13493, 1),
411+ (13494, 1),
412+ (13495, 1),
413+ (13496, 1),
414+ (13497, 1),
415+ (13498, 1),
416+ (13499, 1),
417+ (13500, 1),
418+ (13501, 12),
419+ (13548, 12),
420+ (13966, 52);
421+
422diff --git a/sql/updates/world/2012_01_03_01_characters_character_queststatus_seasonal.sql b/sql/updates/world/2012_01_03_01_characters_character_queststatus_seasonal.sql
423new file mode 100644
424index 0000000..88264c4
425--- /dev/null
426+++ b/sql/updates/world/2012_01_03_01_characters_character_queststatus_seasonal.sql
427@@ -0,0 +1,8 @@
428+DROP TABLE IF EXISTS `character_queststatus_seasonal`;
429+CREATE TABLE `character_queststatus_seasonal` (
430+ `guid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
431+ `quest` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Quest Identifier',
432+ `event` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Event Identifier',
433+ PRIMARY KEY (`guid`,`quest`),
434+ KEY `idx_guid` (`guid`)
435+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Player System';
436\ No newline at end of file
437diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
438index 74f475a..45ebf48 100755
439--- a/src/server/game/Entities/Player/Player.cpp
440+++ b/src/server/game/Entities/Player/Player.cpp
441@@ -14529,7 +14529,7 @@ bool Player::CanSeeStartQuest(Quest const* quest)
442 SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) &&
443 SatisfyQuestPreviousQuest(quest, false) && SatisfyQuestNextChain(quest, false) &&
444 SatisfyQuestPrevChain(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) &&
445- !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this))
446+ SatisfyQuestSeasonal(quest, false) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this))
447 {
448 return getLevel() + sWorld->getIntConfig(CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF) >= quest->GetMinLevel();
449 }
450@@ -14545,7 +14545,7 @@ bool Player::CanTakeQuest(Quest const* quest, bool msg)
451 && SatisfyQuestPreviousQuest(quest, msg) && SatisfyQuestTimed(quest, msg)
452 && SatisfyQuestNextChain(quest, msg) && SatisfyQuestPrevChain(quest, msg)
453 && SatisfyQuestDay(quest, msg) && SatisfyQuestWeek(quest, msg)
454- && !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this)
455+ && SatisfyQuestSeasonal(quest,msg) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this)
456 && SatisfyQuestConditions(quest, msg);
457 }
458
459@@ -14669,7 +14669,7 @@ bool Player::CanRewardQuest(Quest const* quest, bool msg)
460 return false;
461
462 // daily quest can't be rewarded (25 daily quest already completed)
463- if (!SatisfyQuestDay(quest, true) || !SatisfyQuestWeek(quest, true))
464+ if (!SatisfyQuestDay(quest, true) || !SatisfyQuestWeek(quest, true) || !SatisfyQuestSeasonal(quest,true))
465 return false;
466
467 // rewarded and not repeatable quest (only cheating case, then ignore without message)
468@@ -14978,6 +14978,8 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
469 }
470 else if (quest->IsWeekly())
471 SetWeeklyQuestStatus(quest_id);
472+ else if (quest->IsSeasonal())
473+ SetSeasonalQuestStatus(quest_id);
474
475 RemoveActiveQuest(quest_id);
476 m_RewardedQuests.insert(quest_id);
477@@ -15333,7 +15335,7 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg)
478
479 // not allow have daily quest if daily quest from exclusive group already recently completed
480 Quest const* Nquest = sObjectMgr->GetQuestTemplate(exclude_Id);
481- if (!SatisfyQuestDay(Nquest, false) || !SatisfyQuestWeek(Nquest, false))
482+ if (!SatisfyQuestDay(Nquest, false) || !SatisfyQuestWeek(Nquest, false) || !SatisfyQuestSeasonal(Nquest,false))
483 {
484 if (msg)
485 SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ);
486@@ -15342,7 +15344,7 @@ bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg)
487 }
488
489 // alternative quest already started or completed - but don't check rewarded states if both are repeatable
490- if (GetQuestStatus(exclude_Id) != QUEST_STATUS_NONE || (!(qInfo->IsRepeatable() && Nquest->IsRepeatable()) && m_RewardedQuests.find(exclude_Id) != m_RewardedQuests.end()))
491+ if (GetQuestStatus(exclude_Id) != QUEST_STATUS_NONE || (!(qInfo->IsRepeatable() && Nquest->IsRepeatable()) && (m_RewardedQuests.find(exclude_Id) != m_RewardedQuests.end())))
492 {
493 if (msg)
494 SendCanTakeQuestResponse(INVALIDREASON_DONT_HAVE_REQ);
495@@ -15443,6 +15445,15 @@ bool Player::SatisfyQuestWeek(Quest const* qInfo, bool /*msg*/)
496 return m_weeklyquests.find(qInfo->GetQuestId()) == m_weeklyquests.end();
497 }
498
499+bool Player::SatisfyQuestSeasonal(Quest const* qInfo, bool /*msg*/)
500+{
501+ if (!qInfo->IsSeasonal() || m_seasonalquests.empty())
502+ return true;
503+
504+ // if not found in cooldown list
505+ return m_seasonalquests[qInfo->GetSeasonalQuestEvent()].find(qInfo->GetQuestId()) == m_seasonalquests[qInfo->GetSeasonalQuestEvent()].end();
506+}
507+
508 bool Player::GiveQuestSourceItem(Quest const* quest)
509 {
510 uint32 srcitem = quest->GetSrcItemId();
511@@ -16980,7 +16991,8 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
512 _LoadQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS));
513 _LoadQuestStatusRewarded(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUSREW));
514 _LoadDailyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS));
515- _LoadWeeklyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADWEKLYQUESTSTATUS));
516+ _LoadWeeklyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS));
517+ _LoadSeasonalQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS));
518 _LoadRandomBGStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADRANDOMBG));
519
520 // after spell and quest load
521@@ -17846,6 +17858,29 @@ void Player::_LoadWeeklyQuestStatus(PreparedQueryResult result)
522 m_WeeklyQuestChanged = false;
523 }
524
525+void Player::_LoadSeasonalQuestStatus(PreparedQueryResult result)
526+{
527+ m_seasonalquests.clear();
528+
529+ if (result)
530+ {
531+ do
532+ {
533+ uint32 quest_id = (*result)[0].GetUInt32();
534+ uint16 event_id = (*result)[1].GetUInt16();
535+ Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
536+ if (!quest)
537+ continue;
538+
539+ m_seasonalquests[event_id].insert(quest_id);
540+ sLog->outDebug(LOG_FILTER_PLAYER_LOADING, "Seasonal quest {%u} cooldown for player (GUID: %u)", quest_id, GetGUIDLow());
541+ }
542+ while (result->NextRow());
543+ }
544+
545+ m_SeasonalQuestChanged = false;
546+}
547+
548 void Player::_LoadSpells(PreparedQueryResult result)
549 {
550 //QueryResult* result = CharacterDatabase.PQuery("SELECT spell, active, disabled FROM character_spell WHERE guid = '%u'", GetGUIDLow());
551@@ -18572,6 +18607,7 @@ void Player::SaveToDB(bool create /*=false*/)
552 _SaveQuestStatus(trans);
553 _SaveDailyQuestStatus(trans);
554 _SaveWeeklyQuestStatus(trans);
555+ _SaveSeasonalQuestStatus(trans);
556 _SaveTalents(trans);
557 _SaveSpells(trans);
558 _SaveSpellCooldowns(trans);
559@@ -18944,6 +18980,27 @@ void Player::_SaveWeeklyQuestStatus(SQLTransaction& trans)
560 m_WeeklyQuestChanged = false;
561 }
562
563+void Player::_SaveSeasonalQuestStatus(SQLTransaction& trans)
564+{
565+ if (!m_SeasonalQuestChanged || m_seasonalquests.empty())
566+ return;
567+
568+ // we don't need transactions here.
569+ trans->PAppend("DELETE FROM character_queststatus_seasonal WHERE guid = '%u'", GetGUIDLow());
570+
571+ for (SeasonalEventQuestMap::const_iterator iter = m_seasonalquests.begin(); iter != m_seasonalquests.end(); ++iter)
572+ {
573+ uint16 event_id = iter->first;
574+ for (SeasonalQuestSet::const_iterator itr = (iter->second).begin(); itr != (iter->second).end(); ++itr)
575+ {
576+ uint32 quest_id = (*itr);
577+ trans->PAppend("INSERT INTO character_queststatus_seasonal (guid, quest, event) VALUES ('%u', '%u', '%u')", GetGUIDLow(), quest_id, event_id);
578+ }
579+ }
580+
581+ m_SeasonalQuestChanged = false;
582+}
583+
584 void Player::_SaveSkills(SQLTransaction& trans)
585 {
586 // we don't need transactions here.
587@@ -22036,6 +22093,16 @@ void Player::SetWeeklyQuestStatus(uint32 quest_id)
588 m_WeeklyQuestChanged = true;
589 }
590
591+void Player::SetSeasonalQuestStatus(uint32 quest_id)
592+{
593+ Quest const* q = sObjectMgr->GetQuestTemplate(quest_id);
594+ if (q)
595+ m_seasonalquests[q->GetSeasonalQuestEvent()].insert(quest_id);
596+ else
597+ m_seasonalquests[0].insert(quest_id);
598+ m_SeasonalQuestChanged = true;
599+}
600+
601 void Player::ResetDailyQuestStatus()
602 {
603 for (uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx)
604@@ -22058,6 +22125,16 @@ void Player::ResetWeeklyQuestStatus()
605 m_WeeklyQuestChanged = false;
606 }
607
608+void Player::ResetSeasonalQuestStatus(uint16 event_id)
609+{
610+ if (m_seasonalquests.empty() || m_seasonalquests[event_id].empty())
611+ return;
612+
613+ m_seasonalquests[event_id].clear();
614+ // DB data deleted in caller
615+ m_SeasonalQuestChanged = false;
616+}
617+
618 Battleground* Player::GetBattleground() const
619 {
620 if (GetBattlegroundId() == 0)
621diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
622index 7da008d..dd03ba1 100755
623--- a/src/server/game/Entities/Player/Player.h
624+++ b/src/server/game/Entities/Player/Player.h
625@@ -815,11 +815,12 @@ enum PlayerLoginQueryIndex
626 PLAYER_LOGIN_QUERY_LOADTALENTS = 23,
627 PLAYER_LOGIN_QUERY_LOADACCOUNTDATA = 24,
628 PLAYER_LOGIN_QUERY_LOADSKILLS = 25,
629- PLAYER_LOGIN_QUERY_LOADWEKLYQUESTSTATUS = 26,
630+ PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS = 26,
631 PLAYER_LOGIN_QUERY_LOADRANDOMBG = 27,
632 PLAYER_LOGIN_QUERY_LOADBANNED = 28,
633 PLAYER_LOGIN_QUERY_LOADQUESTSTATUSREW = 29,
634 PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES = 30,
635+ PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS = 31,
636 MAX_PLAYER_LOGIN_QUERY,
637 };
638
639@@ -1422,6 +1423,7 @@ class Player : public Unit, public GridObject<Player>
640 bool SatisfyQuestPrevChain(Quest const* qInfo, bool msg);
641 bool SatisfyQuestDay(Quest const* qInfo, bool msg);
642 bool SatisfyQuestWeek(Quest const* qInfo, bool msg);
643+ bool SatisfyQuestSeasonal(Quest const* qInfo, bool msg);
644 bool GiveQuestSourceItem(Quest const* quest);
645 bool TakeQuestSourceItem(uint32 questId, bool msg);
646 bool GetQuestRewardStatus(uint32 quest_id) const;
647@@ -1432,8 +1434,10 @@ class Player : public Unit, public GridObject<Player>
648
649 void SetDailyQuestStatus(uint32 quest_id);
650 void SetWeeklyQuestStatus(uint32 quest_id);
651+ void SetSeasonalQuestStatus(uint32 quest_id);
652 void ResetDailyQuestStatus();
653 void ResetWeeklyQuestStatus();
654+ void ResetSeasonalQuestStatus(uint16 event_id);
655
656 uint16 FindQuestSlot(uint32 quest_id) const;
657 uint32 GetQuestSlotQuestId(uint16 slot) const { return GetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_ID_OFFSET); }
658@@ -2558,8 +2562,11 @@ class Player : public Unit, public GridObject<Player>
659
660 //We allow only one timed quest active at the same time. Below can then be simple value instead of set.
661 typedef std::set<uint32> QuestSet;
662+ typedef std::set<uint32> SeasonalQuestSet;
663+ typedef UNORDERED_MAP<uint32,SeasonalQuestSet> SeasonalEventQuestMap;
664 QuestSet m_timedquests;
665 QuestSet m_weeklyquests;
666+ SeasonalEventQuestMap m_seasonalquests;
667
668 uint64 m_divider;
669 uint32 m_ingametime;
670@@ -2580,6 +2587,7 @@ class Player : public Unit, public GridObject<Player>
671 void _LoadQuestStatusRewarded(PreparedQueryResult result);
672 void _LoadDailyQuestStatus(PreparedQueryResult result);
673 void _LoadWeeklyQuestStatus(PreparedQueryResult result);
674+ void _LoadSeasonalQuestStatus(PreparedQueryResult result);
675 void _LoadRandomBGStatus(PreparedQueryResult result);
676 void _LoadGroup(PreparedQueryResult result);
677 void _LoadSkills(PreparedQueryResult result);
678@@ -2605,6 +2613,7 @@ class Player : public Unit, public GridObject<Player>
679 void _SaveQuestStatus(SQLTransaction& trans);
680 void _SaveDailyQuestStatus(SQLTransaction& trans);
681 void _SaveWeeklyQuestStatus(SQLTransaction& trans);
682+ void _SaveSeasonalQuestStatus(SQLTransaction& trans);
683 void _SaveSkills(SQLTransaction& trans);
684 void _SaveSpells(SQLTransaction& trans);
685 void _SaveEquipmentSets(SQLTransaction& trans);
686@@ -2716,6 +2725,7 @@ class Player : public Unit, public GridObject<Player>
687
688 bool m_DailyQuestChanged;
689 bool m_WeeklyQuestChanged;
690+ bool m_SeasonalQuestChanged;
691 time_t m_lastDailyQuestTime;
692
693 uint32 m_drunkTimer;
694diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp
695index 8b9e2fe..54d3cdc 100755
696--- a/src/server/game/Events/GameEventMgr.cpp
697+++ b/src/server/game/Events/GameEventMgr.cpp
698@@ -759,6 +759,49 @@ void GameEventMgr::LoadFromDB()
699 }
700 }
701
702+ sLog->outString("Loading Game Event Seasonal Quest Relations...");
703+ {
704+ uint32 oldMSTime = getMSTime();
705+
706+ // 0 1 2
707+ QueryResult result = WorldDatabase.Query("SELECT quest, event FROM game_event_seasonal_questrelation");
708+
709+ if (!result)
710+ {
711+ sLog->outString(">> Loaded 0 seasonal quests additions in game events. DB table `game_event_seasonal_questrelation` is empty.");
712+ sLog->outString();
713+ }
714+ else
715+ {
716+ uint32 count = 0;
717+ do
718+ {
719+ Field* fields = result->Fetch();
720+
721+ uint32 quest = fields[0].GetUInt32();
722+ uint16 event_id = fields[1].GetUInt16();
723+
724+ if (event_id >= mGameEventSeasonalQuests.size())
725+ {
726+ sLog->outErrorDb("`game_event_seasonal_questrelation` event id (%u) is out of range compared to max event in `game_event`", event_id);
727+ continue;
728+ }
729+
730+ SeasonalQuestRelList& questlist = mGameEventSeasonalQuests[event_id];
731+ questlist.insert(quest);
732+ Quest const* q = sObjectMgr->GetQuestTemplate(quest);
733+ if (q)
734+ const_cast<Quest*>(q)->SetSeasonalQuestEvent(event_id);
735+
736+ ++count;
737+ }
738+ while (result->NextRow());
739+
740+ sLog->outString(">> Loaded %u quests additions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
741+ sLog->outString();
742+ }
743+ }
744+
745 sLog->outString("Loading Game Event Vendor Additions Data...");
746 {
747 uint32 oldMSTime = getMSTime();
748@@ -1079,6 +1122,8 @@ void GameEventMgr::UnApplyEvent(uint16 event_id)
749 UpdateEventNPCVendor(event_id, false);
750 // update bg holiday
751 UpdateBattlegroundSettings();
752+ // check for seasonal quest reset.
753+ sWorld->ResetEventSeasonalQuests(event_id);
754 }
755
756 void GameEventMgr::ApplyNewEvent(uint16 event_id)
757diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h
758index 34258ba..059b2a0 100755
759--- a/src/server/game/Events/GameEventMgr.h
760+++ b/src/server/game/Events/GameEventMgr.h
761@@ -150,6 +150,8 @@ class GameEventMgr
762 typedef std::pair<uint32, uint32> QuestRelation;
763 typedef std::list<QuestRelation> QuestRelList;
764 typedef std::vector<QuestRelList> GameEventQuestMap;
765+ typedef std::set<uint32> SeasonalQuestRelList;
766+ typedef std::vector<SeasonalQuestRelList> GameEventSeasonalQuestMap;
767 typedef std::list<NPCVendorEntry> NPCVendorList;
768 typedef std::vector<NPCVendorList> GameEventNPCVendorMap;
769 typedef std::map<uint32 /*quest id*/, GameEventQuestToEventConditionNum> QuestIdToEventConditionMap;
770@@ -159,6 +161,7 @@ class GameEventMgr
771 typedef std::vector<uint32> GameEventBitmask;
772 GameEventQuestMap mGameEventCreatureQuests;
773 GameEventQuestMap mGameEventGameObjectQuests;
774+ GameEventSeasonalQuestMap mGameEventSeasonalQuests;
775 GameEventNPCVendorMap mGameEventVendors;
776 GameEventModelEquipMap mGameEventModelEquip;
777 //GameEventGuidMap mGameEventCreatureGuids;
778diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp
779index 14a6577..674f54d 100755
780--- a/src/server/game/Quests/QuestDef.cpp
781+++ b/src/server/game/Quests/QuestDef.cpp
782@@ -65,6 +65,7 @@
783 RequiredPlayerKills = questRecord[40].GetUInt32();
784 RewardTalents = questRecord[41].GetUInt32();
785 RewardArenaPoints = questRecord[42].GetInt32();
786+ SeasonalQuestEvent = 0;
787
788 for (int i = 0; i < QUEST_REWARDS_COUNT; ++i)
789 RewardItemId[i] = questRecord[43+i].GetUInt32();
790diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h
791index 90905f2..4fbfcd1 100755
792--- a/src/server/game/Quests/QuestDef.h
793+++ b/src/server/game/Quests/QuestDef.h
794@@ -187,6 +187,7 @@ class Quest
795
796 bool HasFlag(uint32 flag) const { return (Flags & flag) != 0; }
797 void SetFlag(uint32 flag) { Flags |= flag; }
798+ void SetSeasonalQuestEvent(uint16 event_id) { SeasonalQuestEvent = event_id; }
799
800 // table data accessors:
801 uint32 GetQuestId() const { return Id; }
802@@ -246,11 +247,13 @@ class Quest
803 uint32 GetCompleteEmote() const { return EmoteOnComplete; }
804 uint32 GetQuestStartScript() const { return StartScript; }
805 uint32 GetQuestCompleteScript() const { return CompleteScript; }
806+ uint16 GetSeasonalQuestEvent() const {return SeasonalQuestEvent; }
807 bool IsRepeatable() const { return Flags & QUEST_TRINITY_FLAGS_REPEATABLE; }
808 bool IsAutoComplete() const;
809 uint32 GetFlags() const { return Flags; }
810 bool IsDaily() const { return Flags & QUEST_FLAGS_DAILY; }
811 bool IsWeekly() const { return Flags & QUEST_FLAGS_WEEKLY; }
812+ bool IsSeasonal() const { return ZoneOrSort == -22; }
813 bool IsDailyOrWeekly() const { return Flags & (QUEST_FLAGS_DAILY | QUEST_FLAGS_WEEKLY); }
814 bool IsAutoAccept() const { return Flags & QUEST_FLAGS_AUTO_ACCEPT; }
815 bool IsRaidQuest() const { return Type == QUEST_TYPE_RAID || Type == QUEST_TYPE_RAID_10 || Type == QUEST_TYPE_RAID_25; }
816@@ -295,6 +298,8 @@ class Quest
817 uint32 m_reqCreatureOrGOcount;
818 uint32 m_rewchoiceitemscount;
819 uint32 m_rewitemscount;
820+ //additional data needed for seasonal quest events
821+ uint16 SeasonalQuestEvent;
822
823 // table data
824 protected:
825diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp
826old mode 100755
827new mode 100644
828index 11de2c6..17fa6d8
829--- a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp
830+++ b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp
831@@ -93,9 +93,13 @@ bool LoginQueryHolder::Initialize()
832 stmt->setUInt32(0, lowGuid);
833 res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS, stmt);
834
835- stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_WEKLYQUESTSTATUS);
836+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS);
837 stmt->setUInt32(0, lowGuid);
838- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADWEKLYQUESTSTATUS, stmt);
839+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS, stmt);
840+
841+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_SEASONALQUESTSTATUS);
842+ stmt->setUInt32(0, lowGuid);
843+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS, stmt);
844
845 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_REPUTATION);
846 stmt->setUInt32(0, lowGuid);
847diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
848index b9ac3d1..f05a272 100755
849--- a/src/server/game/World/World.cpp
850+++ b/src/server/game/World/World.cpp
851@@ -2746,6 +2746,17 @@ void World::ResetWeeklyQuests()
852 sPoolMgr->ChangeWeeklyQuests();
853 }
854
855+void World::ResetEventSeasonalQuests(uint16 event_id)
856+{
857+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_SEASONAL);
858+ stmt->setUInt16(0,event_id);
859+ CharacterDatabase.Execute(stmt);
860+
861+ for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
862+ if (itr->second->GetPlayer())
863+ itr->second->GetPlayer()->ResetSeasonalQuestStatus(event_id);
864+}
865+
866 void World::ResetRandomBG()
867 {
868 sLog->outDetail("Random BG status reset for all characters.");
869diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
870index 0243837..bedd8a8 100755
871--- a/src/server/game/World/World.h
872+++ b/src/server/game/World/World.h
873@@ -746,6 +746,7 @@ class World
874
875 uint32 GetCleaningFlags() const { return m_CleaningFlags; }
876 void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; }
877+ void ResetEventSeasonalQuests(uint16 event_id);
878 protected:
879 void _UpdateGameTime();
880 // callback for UpdateRealmCharacters
881diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
882old mode 100755
883new mode 100644
884index b5b174a..12ce388
885--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
886+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
887@@ -46,6 +46,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
888 PREPARE_STATEMENT(CHAR_SEL_GUID_RACE_ACC_BY_NAME, "SELECT guid, race, account FROM characters WHERE name = ?", CONNECTION_ASYNC);
889 PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_DAILY, "DELETE FROM character_queststatus_daily", CONNECTION_ASYNC);
890 PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_WEEKLY, "DELETE FROM character_queststatus_weekly", CONNECTION_ASYNC);
891+ PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_SEASONAL, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC);
892 PREPARE_STATEMENT(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random", CONNECTION_ASYNC);
893 PREPARE_STATEMENT(CHAR_INS_BATTLEGROUND_RANDOM, "INSERT INTO character_battleground_random (guid) VALUES (?)", CONNECTION_ASYNC);
894
895@@ -63,7 +64,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
896 PREPARE_STATEMENT(CHAR_SEL_CHARACTER_QUESTSTATUS, "SELECT quest, status, explored, timer, mobcount1, mobcount2, mobcount3, mobcount4, "
897 "itemcount1, itemcount2, itemcount3, itemcount4, playercount FROM character_queststatus WHERE guid = ?", CONNECTION_ASYNC)
898 PREPARE_STATEMENT(CHAR_SEL_CHARACTER_DAILYQUESTSTATUS, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC)
899- PREPARE_STATEMENT(CHAR_SEL_CHARACTER_WEKLYQUESTSTATUS, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC)
900+ PREPARE_STATEMENT(CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC)
901+ PREPARE_STATEMENT(CHAR_SEL_PLAYER_SEASONALQUESTSTATUS, "SELECT quest FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC)
902 PREPARE_STATEMENT(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC)
903 PREPARE_STATEMENT(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, bag, slot, "
904 "item, itemEntry FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot", CONNECTION_ASYNC)
905diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h
906old mode 100755
907new mode 100644
908index a0f5b9a..3ce288f
909--- a/src/server/shared/Database/Implementation/CharacterDatabase.h
910+++ b/src/server/shared/Database/Implementation/CharacterDatabase.h
911@@ -66,6 +66,7 @@ enum CharacterDatabaseStatements
912 CHAR_SEL_GUID_RACE_ACC_BY_NAME,
913 CHAR_DEL_QUEST_STATUS_DAILY,
914 CHAR_DEL_QUEST_STATUS_WEEKLY,
915+ CHAR_DEL_QUEST_STATUS_SEASONAL,
916 CHAR_DEL_BATTLEGROUND_RANDOM,
917 CHAR_INS_BATTLEGROUND_RANDOM,
918
919@@ -76,7 +77,8 @@ enum CharacterDatabaseStatements
920 CHAR_SEL_CHARACTER_SPELL,
921 CHAR_SEL_CHARACTER_QUESTSTATUS,
922 CHAR_SEL_CHARACTER_DAILYQUESTSTATUS,
923- CHAR_SEL_CHARACTER_WEKLYQUESTSTATUS,
924+ CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS,
925+ CHAR_SEL_PLAYER_SEASONALQUESTSTATUS,
926 CHAR_SEL_CHARACTER_REPUTATION,
927 CHAR_SEL_CHARACTER_INVENTORY,
928 CHAR_SEL_CHARACTER_ACTIONS,
929--
9301.7.5.4