TrinityCore
Loading...
Searching...
No Matches
GameEventMgr.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "GameEventMgr.h"
19#include "BattlegroundMgr.h"
20#include "CreatureAI.h"
21#include "DBCStores.h"
22#include "DatabaseEnv.h"
23#include "GameObjectAI.h"
24#include "GameTime.h"
25#include "Language.h"
26#include "Log.h"
27#include "MapManager.h"
28#include "ObjectMgr.h"
29#include "PoolMgr.h"
30#include "Player.h"
31#include "World.h"
32#include "WorldStatePackets.h"
33
39
41{
42 switch (mGameEvent[entry].state)
43 {
44 default:
46 {
47 time_t currenttime = GameTime::GetGameTime();
48 // Get the event information
49 return mGameEvent[entry].start < currenttime
50 && currenttime < mGameEvent[entry].end
51 && (currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE) < mGameEvent[entry].length * MINUTE;
52 }
53 // if the state is conditions or nextphase, then the event should be active
56 return true;
57 // finished world events are inactive
60 return false;
61 // if inactive world event, check the prerequisite events
63 {
64 time_t currenttime = GameTime::GetGameTime();
65 for (std::set<uint16>::const_iterator itr = mGameEvent[entry].prerequisite_events.begin(); itr != mGameEvent[entry].prerequisite_events.end(); ++itr)
66 {
67 if ((mGameEvent[*itr].state != GAMEEVENT_WORLD_NEXTPHASE && mGameEvent[*itr].state != GAMEEVENT_WORLD_FINISHED) || // if prereq not in nextphase or finished state, then can't start this one
68 mGameEvent[*itr].nextstart > currenttime) // if not in nextphase state for long enough, can't start this one
69 return false;
70 }
71 // all prerequisite events are met
72 // but if there are no prerequisites, this can be only activated through gm command
73 return !(mGameEvent[entry].prerequisite_events.empty());
74 }
75 }
76}
77
79{
80 time_t currenttime = GameTime::GetGameTime();
81
82 // for NEXTPHASE state world events, return the delay to start the next event, so the followup event will be checked correctly
83 if ((mGameEvent[entry].state == GAMEEVENT_WORLD_NEXTPHASE || mGameEvent[entry].state == GAMEEVENT_WORLD_FINISHED) && mGameEvent[entry].nextstart >= currenttime)
84 return uint32(mGameEvent[entry].nextstart - currenttime);
85
86 // for CONDITIONS state world events, return the length of the wait period, so if the conditions are met, this check will be called again to set the timer as NEXTPHASE event
87 if (mGameEvent[entry].state == GAMEEVENT_WORLD_CONDITIONS)
88 {
89 if (mGameEvent[entry].length)
90 return mGameEvent[entry].length * 60;
91 else
92 return max_ge_check_delay;
93 }
94
95 // outdated event: we return max
96 if (currenttime > mGameEvent[entry].end)
97 return max_ge_check_delay;
98
99 // never started event, we return delay before start
100 if (mGameEvent[entry].start > currenttime)
101 return uint32(mGameEvent[entry].start - currenttime);
102
103 uint32 delay;
104 // in event, we return the end of it
105 if ((((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * 60)) < (mGameEvent[entry].length * 60)))
106 // we return the delay before it ends
107 delay = (mGameEvent[entry].length * MINUTE) - ((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE));
108 else // not in window, we return the delay before next start
109 delay = (mGameEvent[entry].occurence * MINUTE) - ((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE));
110 // In case the end is before next check
111 if (mGameEvent[entry].end < time_t(currenttime + delay))
112 return uint32(mGameEvent[entry].end - currenttime);
113 else
114 return delay;
115}
116
118{
119 if (event_id < 1 || event_id >= mGameEvent.size())
120 return;
121
122 if (!mGameEvent[event_id].isValid())
123 return;
124
125 if (m_ActiveEvents.find(event_id) != m_ActiveEvents.end())
126 return;
127
128 StartEvent(event_id);
129}
130
131bool GameEventMgr::StartEvent(uint16 event_id, bool overwrite)
132{
133 GameEventData &data = mGameEvent[event_id];
134 if (data.state == GAMEEVENT_NORMAL || data.state == GAMEEVENT_INTERNAL)
135 {
136 AddActiveEvent(event_id);
137 ApplyNewEvent(event_id);
138 if (overwrite)
139 {
140 mGameEvent[event_id].start = GameTime::GetGameTime();
141 if (data.end <= data.start)
142 data.end = data.start + data.length * MINUTE;
143 }
144 return false;
145 }
146 else
147 {
149 // set to conditions phase
151
152 // add to active events
153 AddActiveEvent(event_id);
154 // add spawns
155 ApplyNewEvent(event_id);
156
157 // check if can go to next state
158 bool conditions_met = CheckOneGameEventConditions(event_id);
159 // save to db
160 SaveWorldEventStateToDB(event_id);
161 // force game event update to set the update timer if conditions were met from a command
162 // this update is needed to possibly start events dependent on the started one
163 // or to scedule another update where the next event will be started
164 if (overwrite && conditions_met)
165 sWorld->ForceGameEventUpdate();
166
167 return conditions_met;
168 }
169}
170
171void GameEventMgr::StopEvent(uint16 event_id, bool overwrite)
172{
173 GameEventData &data = mGameEvent[event_id];
174 bool serverwide_evt = data.state != GAMEEVENT_NORMAL && data.state != GAMEEVENT_INTERNAL;
175
176 RemoveActiveEvent(event_id);
177 UnApplyEvent(event_id);
178
179 if (overwrite && !serverwide_evt)
180 {
181 data.start = GameTime::GetGameTime() - data.length * MINUTE;
182 if (data.end <= data.start)
183 data.end = data.start + data.length * MINUTE;
184 }
185 else if (serverwide_evt)
186 {
187 // if finished world event, then only gm command can stop it
188 if (overwrite || data.state != GAMEEVENT_WORLD_FINISHED)
189 {
190 // reset conditions
191 data.nextstart = 0;
193 GameEventConditionMap::iterator itr;
194 for (itr = data.conditions.begin(); itr != data.conditions.end(); ++itr)
195 itr->second.done = 0;
196
197 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
199 stmt->setUInt8(0, uint8(event_id));
200 trans->Append(stmt);
201
202 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GAME_EVENT_SAVE);
203 stmt->setUInt8(0, uint8(event_id));
204 trans->Append(stmt);
205
206 CharacterDatabase.CommitTransaction(trans);
207 }
208 }
209}
210
212{
213 {
214 uint32 oldMSTime = getMSTime();
215 // 0 1 2 3 4 5 6 7 8 9
216 QueryResult result = WorldDatabase.Query("SELECT eventEntry, UNIX_TIMESTAMP(start_time), UNIX_TIMESTAMP(end_time), occurence, length, holiday, holidayStage, description, world_event, announce FROM game_event");
217 if (!result)
218 {
219 mGameEvent.clear();
220 TC_LOG_INFO("server.loading", ">> Loaded 0 game events. DB table `game_event` is empty.");
221 return;
222 }
223
224 uint32 count = 0;
225 do
226 {
227 Field* fields = result->Fetch();
228
229 uint8 event_id = fields[0].GetUInt8();
230 if (event_id == 0)
231 {
232 TC_LOG_ERROR("sql.sql", "`game_event`: game event entry 0 is reserved and can't be used.");
233 continue;
234 }
235
236 GameEventData& pGameEvent = mGameEvent[event_id];
237 uint64 starttime = fields[1].GetUInt64();
238 pGameEvent.start = time_t(starttime);
239 uint64 endtime = fields[2].GetUInt64();
240 pGameEvent.end = time_t(endtime);
241 pGameEvent.occurence = fields[3].GetUInt64();
242 pGameEvent.length = fields[4].GetUInt64();
243 pGameEvent.holiday_id = HolidayIds(fields[5].GetUInt32());
244 pGameEvent.holidayStage = fields[6].GetUInt8();
245 pGameEvent.description = fields[7].GetString();
246 pGameEvent.state = (GameEventState)(fields[8].GetUInt8());
247 pGameEvent.announce = fields[9].GetUInt8();
248 pGameEvent.nextstart = 0;
249
250 ++count;
251
252 if (pGameEvent.length == 0 && pGameEvent.state == GAMEEVENT_NORMAL) // length>0 is validity check
253 {
254 TC_LOG_ERROR("sql.sql", "`game_event`: game event id ({}) is not a world event and has length = 0, thus cannot be used.", event_id);
255 continue;
256 }
257
258 if (pGameEvent.holiday_id != HOLIDAY_NONE)
259 {
260 if (!sHolidaysStore.LookupEntry(pGameEvent.holiday_id))
261 {
262 TC_LOG_ERROR("sql.sql", "`game_event`: game event id ({}) contains nonexisting holiday id {}.", event_id, pGameEvent.holiday_id);
263 pGameEvent.holiday_id = HOLIDAY_NONE;
264 continue;
265 }
266 if (pGameEvent.holidayStage > MAX_HOLIDAY_DURATIONS)
267 {
268 TC_LOG_ERROR("sql.sql", "`game_event` game event id ({}) has out of range holidayStage {}.", event_id, pGameEvent.holidayStage);
269 pGameEvent.holidayStage = 0;
270 continue;
271 }
272
273 SetHolidayEventTime(pGameEvent);
274 }
275
276 }
277 while (result->NextRow());
278
279 TC_LOG_INFO("server.loading", ">> Loaded {} game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
280
281 }
282
283 TC_LOG_INFO("server.loading", "Loading Game Event Saves Data...");
284 {
285 uint32 oldMSTime = getMSTime();
286
287 // 0 1 2
288 QueryResult result = CharacterDatabase.Query("SELECT eventEntry, state, next_start FROM game_event_save");
289
290 if (!result)
291 TC_LOG_INFO("server.loading", ">> Loaded 0 game event saves in game events. DB table `game_event_save` is empty.");
292 else
293 {
294 uint32 count = 0;
295 do
296 {
297 Field* fields = result->Fetch();
298
299 uint8 event_id = fields[0].GetUInt8();
300
301 if (event_id >= mGameEvent.size())
302 {
303 TC_LOG_ERROR("sql.sql", "`game_event_save`: game event entry ({}) is out of range compared to max event entry in `game_event`.", event_id);
304 continue;
305 }
306
307 if (mGameEvent[event_id].state != GAMEEVENT_NORMAL && mGameEvent[event_id].state != GAMEEVENT_INTERNAL)
308 {
309 mGameEvent[event_id].state = (GameEventState)(fields[1].GetUInt8());
310 mGameEvent[event_id].nextstart = time_t(fields[2].GetUInt32());
311 }
312 else
313 {
314 TC_LOG_ERROR("sql.sql", "game_event_save includes event save for non-worldevent id {}.", event_id);
315 continue;
316 }
317
318 ++count;
319 }
320 while (result->NextRow());
321
322 TC_LOG_INFO("server.loading", ">> Loaded {} game event saves in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
323
324 }
325 }
326
327 TC_LOG_INFO("server.loading", "Loading Game Event Prerequisite Data...");
328 {
329 uint32 oldMSTime = getMSTime();
330
331 // 0 1
332 QueryResult result = WorldDatabase.Query("SELECT eventEntry, prerequisite_event FROM game_event_prerequisite");
333 if (!result)
334 TC_LOG_INFO("server.loading", ">> Loaded 0 game event prerequisites in game events. DB table `game_event_prerequisite` is empty.");
335 else
336 {
337 uint32 count = 0;
338 do
339 {
340 Field* fields = result->Fetch();
341
342 uint16 event_id = fields[0].GetUInt8();
343
344 if (event_id >= mGameEvent.size())
345 {
346 TC_LOG_ERROR("sql.sql", "`game_event_prerequisite`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
347 continue;
348 }
349
350 if (mGameEvent[event_id].state != GAMEEVENT_NORMAL && mGameEvent[event_id].state != GAMEEVENT_INTERNAL)
351 {
352 uint16 prerequisite_event = fields[1].GetUInt32();
353 if (prerequisite_event >= mGameEvent.size())
354 {
355 TC_LOG_ERROR("sql.sql", "`game_event_prerequisite`: game event prerequisite id ({}) is out of range compared to max event id in `game_event`.", prerequisite_event);
356 continue;
357 }
358 mGameEvent[event_id].prerequisite_events.insert(prerequisite_event);
359 }
360 else
361 {
362 TC_LOG_ERROR("sql.sql", "game_event_prerequisiste includes event entry for non-worldevent id {}.", event_id);
363 continue;
364 }
365
366 ++count;
367 }
368 while (result->NextRow());
369
370 TC_LOG_INFO("server.loading", ">> Loaded {} game event prerequisites in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
371
372 }
373 }
374
375 TC_LOG_INFO("server.loading", "Loading Game Event Creature Data...");
376 {
377 uint32 oldMSTime = getMSTime();
378
379 // 0 1
380 QueryResult result = WorldDatabase.Query("SELECT guid, eventEntry FROM game_event_creature");
381
382 if (!result)
383 TC_LOG_INFO("server.loading", ">> Loaded 0 creatures in game events. DB table `game_event_creature` is empty.");
384 else
385 {
386 uint32 count = 0;
387 do
388 {
389 Field* fields = result->Fetch();
390
391 ObjectGuid::LowType guid = fields[0].GetUInt32();
392 int16 event_id = fields[1].GetInt8();
393
394 int32 internal_event_id = mGameEvent.size() + event_id - 1;
395
396 CreatureData const* data = sObjectMgr->GetCreatureData(guid);
397 if (!data)
398 {
399 TC_LOG_ERROR("sql.sql", "`game_event_creature` contains creature (GUID: {}) not found in `creature` table.", guid);
400 continue;
401 }
402
403 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventCreatureGuids.size()))
404 {
405 TC_LOG_ERROR("sql.sql", "`game_event_creature`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
406 continue;
407 }
408
409 // Log error for pooled object, but still spawn it
410 if (uint32 poolId = sPoolMgr->IsPartOfAPool(SPAWN_TYPE_CREATURE, guid))
411 TC_LOG_ERROR("sql.sql", "`game_event_creature`: game event id ({}) contains creature ({}) which is part of a pool ({}). This should be spawned in game_event_pool", event_id, guid, poolId);
412
413 GuidList& crelist = mGameEventCreatureGuids[internal_event_id];
414 crelist.push_back(guid);
415
416 ++count;
417 }
418 while (result->NextRow());
419
420 TC_LOG_INFO("server.loading", ">> Loaded {} creatures in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
421
422 }
423 }
424
425 TC_LOG_INFO("server.loading", "Loading Game Event GO Data...");
426 {
427 uint32 oldMSTime = getMSTime();
428
429 // 0 1
430 QueryResult result = WorldDatabase.Query("SELECT guid, eventEntry FROM game_event_gameobject");
431
432 if (!result)
433 TC_LOG_INFO("server.loading", ">> Loaded 0 gameobjects in game events. DB table `game_event_gameobject` is empty.");
434 else
435 {
436 uint32 count = 0;
437 do
438 {
439 Field* fields = result->Fetch();
440
441 ObjectGuid::LowType guid = fields[0].GetUInt32();
442 int16 event_id = fields[1].GetInt8();
443
444 int32 internal_event_id = mGameEvent.size() + event_id - 1;
445
446 GameObjectData const* data = sObjectMgr->GetGameObjectData(guid);
447 if (!data)
448 {
449 TC_LOG_ERROR("sql.sql", "`game_event_gameobject` contains gameobject (GUID: {}) not found in `gameobject` table.", guid);
450 continue;
451 }
452
453 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventGameobjectGuids.size()))
454 {
455 TC_LOG_ERROR("sql.sql", "`game_event_gameobject`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
456 continue;
457 }
458
459 // Log error for pooled object, but still spawn it
460 if (uint32 poolId = sPoolMgr->IsPartOfAPool(SPAWN_TYPE_GAMEOBJECT, guid))
461 TC_LOG_ERROR("sql.sql", "`game_event_gameobject`: game event id ({}) contains game object ({}) which is part of a pool ({}). This should be spawned in game_event_pool", event_id, guid, poolId);
462
463 GuidList& golist = mGameEventGameobjectGuids[internal_event_id];
464 golist.push_back(guid);
465
466 ++count;
467 }
468 while (result->NextRow());
469
470 TC_LOG_INFO("server.loading", ">> Loaded {} gameobjects in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
471 }
472 }
473
474 TC_LOG_INFO("server.loading", "Loading Game Event Model/Equipment Change Data...");
475 {
476 uint32 oldMSTime = getMSTime();
477
478 // 0 1 2 3 4
479 QueryResult result = WorldDatabase.Query("SELECT creature.guid, creature.id, game_event_model_equip.eventEntry, game_event_model_equip.modelid, game_event_model_equip.equipment_id "
480 "FROM creature JOIN game_event_model_equip ON creature.guid = game_event_model_equip.guid");
481
482 if (!result)
483 TC_LOG_INFO("server.loading", ">> Loaded 0 model/equipment changes in game events. DB table `game_event_model_equip` is empty.");
484 else
485 {
486 uint32 count = 0;
487 do
488 {
489 Field* fields = result->Fetch();
490
491 ObjectGuid::LowType guid = fields[0].GetUInt32();
492 uint32 entry = fields[1].GetUInt32();
493 uint16 event_id = fields[2].GetUInt8();
494
495 if (event_id >= mGameEventModelEquip.size())
496 {
497 TC_LOG_ERROR("sql.sql", "`game_event_model_equip`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
498 continue;
499 }
500
501 ModelEquipList& equiplist = mGameEventModelEquip[event_id];
502 ModelEquip newModelEquipSet;
503 newModelEquipSet.modelid = fields[3].GetUInt32();
504 newModelEquipSet.equipment_id = fields[4].GetUInt8();
505 newModelEquipSet.equipement_id_prev = 0;
506 newModelEquipSet.modelid_prev = 0;
507
508 if (newModelEquipSet.equipment_id > 0)
509 {
510 int8 equipId = static_cast<int8>(newModelEquipSet.equipment_id);
511 if (!sObjectMgr->GetEquipmentInfo(entry, equipId))
512 {
513 TC_LOG_ERROR("sql.sql", "Table `game_event_model_equip` contains creature (Guid: {}, entry: {}) with equipment_id {} not found in table `creature_equip_template`. Setting entry to no equipment.",
514 guid, entry, newModelEquipSet.equipment_id);
515 continue;
516 }
517 }
518
519 equiplist.push_back(std::pair<ObjectGuid::LowType, ModelEquip>(guid, newModelEquipSet));
520
521 ++count;
522 }
523 while (result->NextRow());
524
525 TC_LOG_INFO("server.loading", ">> Loaded {} model/equipment changes in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
526 }
527 }
528
529 TC_LOG_INFO("server.loading", "Loading Game Event Quest Data...");
530 {
531 uint32 oldMSTime = getMSTime();
532
533 // 0 1 2
534 QueryResult result = WorldDatabase.Query("SELECT id, quest, eventEntry FROM game_event_creature_quest");
535
536 if (!result)
537 TC_LOG_INFO("server.loading", ">> Loaded 0 quests additions in game events. DB table `game_event_creature_quest` is empty.");
538 else
539 {
540 uint32 count = 0;
541 do
542 {
543 Field* fields = result->Fetch();
544
545 uint32 id = fields[0].GetUInt32();
546 uint32 quest = fields[1].GetUInt32();
547 uint16 event_id = fields[2].GetUInt8();
548
549 if (event_id >= mGameEventCreatureQuests.size())
550 {
551 TC_LOG_ERROR("sql.sql", "`game_event_creature_quest`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
552 continue;
553 }
554
555 QuestRelList& questlist = mGameEventCreatureQuests[event_id];
556 questlist.push_back(QuestRelation(id, quest));
557
558 ++count;
559 }
560 while (result->NextRow());
561
562 TC_LOG_INFO("server.loading", ">> Loaded {} quests additions in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
563 }
564 }
565
566 TC_LOG_INFO("server.loading", "Loading Game Event GO Quest Data...");
567 {
568 uint32 oldMSTime = getMSTime();
569
570 // 0 1 2
571 QueryResult result = WorldDatabase.Query("SELECT id, quest, eventEntry FROM game_event_gameobject_quest");
572
573 if (!result)
574 TC_LOG_INFO("server.loading", ">> Loaded 0 go quests additions in game events. DB table `game_event_gameobject_quest` is empty.");
575 else
576 {
577 uint32 count = 0;
578 do
579 {
580 Field* fields = result->Fetch();
581
582 uint32 id = fields[0].GetUInt32();
583 uint32 quest = fields[1].GetUInt32();
584 uint16 event_id = fields[2].GetUInt8();
585
586 if (event_id >= mGameEventGameObjectQuests.size())
587 {
588 TC_LOG_ERROR("sql.sql", "`game_event_gameobject_quest`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
589 continue;
590 }
591
592 QuestRelList& questlist = mGameEventGameObjectQuests[event_id];
593 questlist.push_back(QuestRelation(id, quest));
594
595 ++count;
596 }
597 while (result->NextRow());
598
599 TC_LOG_INFO("server.loading", ">> Loaded {} quests additions in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
600 }
601 }
602
603 TC_LOG_INFO("server.loading", "Loading Game Event Quest Condition Data...");
604 {
605 uint32 oldMSTime = getMSTime();
606
607 // 0 1 2 3
608 QueryResult result = WorldDatabase.Query("SELECT quest, eventEntry, condition_id, num FROM game_event_quest_condition");
609
610 if (!result)
611 TC_LOG_INFO("server.loading", ">> Loaded 0 quest event conditions in game events. DB table `game_event_quest_condition` is empty.");
612 else
613 {
614 uint32 count = 0;
615 do
616 {
617 Field* fields = result->Fetch();
618
619 uint32 quest = fields[0].GetUInt32();
620 uint16 event_id = fields[1].GetUInt8();
621 uint32 condition = fields[2].GetUInt32();
622 float num = fields[3].GetFloat();
623
624 if (event_id >= mGameEvent.size())
625 {
626 TC_LOG_ERROR("sql.sql", "`game_event_quest_condition`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
627 continue;
628 }
629
630 mQuestToEventConditions[quest].event_id = event_id;
631 mQuestToEventConditions[quest].condition = condition;
632 mQuestToEventConditions[quest].num = num;
633
634 ++count;
635 }
636 while (result->NextRow());
637
638 TC_LOG_INFO("server.loading", ">> Loaded {} quest event conditions in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
639 }
640 }
641
642 TC_LOG_INFO("server.loading", "Loading Game Event Condition Data...");
643 {
644 uint32 oldMSTime = getMSTime();
645
646 // 0 1 2 3 4
647 QueryResult result = WorldDatabase.Query("SELECT eventEntry, condition_id, req_num, max_world_state_field, done_world_state_field FROM game_event_condition");
648
649 if (!result)
650 TC_LOG_INFO("server.loading", ">> Loaded 0 conditions in game events. DB table `game_event_condition` is empty.");
651 else
652 {
653 uint32 count = 0;
654 do
655 {
656 Field* fields = result->Fetch();
657
658 uint16 event_id = fields[0].GetUInt8();
659 uint32 condition = fields[1].GetUInt32();
660
661 if (event_id >= mGameEvent.size())
662 {
663 TC_LOG_ERROR("sql.sql", "`game_event_condition`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
664 continue;
665 }
666
667 mGameEvent[event_id].conditions[condition].reqNum = fields[2].GetFloat();
668 mGameEvent[event_id].conditions[condition].done = 0;
669 mGameEvent[event_id].conditions[condition].max_world_state = fields[3].GetUInt16();
670 mGameEvent[event_id].conditions[condition].done_world_state = fields[4].GetUInt16();
671
672 ++count;
673 }
674 while (result->NextRow());
675
676 TC_LOG_INFO("server.loading", ">> Loaded {} conditions in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
677 }
678 }
679
680 TC_LOG_INFO("server.loading", "Loading Game Event Condition Save Data...");
681 {
682 uint32 oldMSTime = getMSTime();
683
684 // 0 1 2
685 QueryResult result = CharacterDatabase.Query("SELECT eventEntry, condition_id, done FROM game_event_condition_save");
686
687 if (!result)
688 TC_LOG_INFO("server.loading", ">> Loaded 0 condition saves in game events. DB table `game_event_condition_save` is empty.");
689 else
690 {
691 uint32 count = 0;
692 do
693 {
694 Field* fields = result->Fetch();
695
696 uint16 event_id = fields[0].GetUInt8();
697 uint32 condition = fields[1].GetUInt32();
698
699 if (event_id >= mGameEvent.size())
700 {
701 TC_LOG_ERROR("sql.sql", "`game_event_condition_save`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
702 continue;
703 }
704
705 GameEventConditionMap::iterator itr = mGameEvent[event_id].conditions.find(condition);
706 if (itr != mGameEvent[event_id].conditions.end())
707 {
708 itr->second.done = fields[2].GetFloat();
709 }
710 else
711 {
712 TC_LOG_ERROR("sql.sql", "game_event_condition_save contains not present condition event id {} condition id {}.", event_id, condition);
713 continue;
714 }
715
716 ++count;
717 }
718 while (result->NextRow());
719
720 TC_LOG_INFO("server.loading", ">> Loaded {} condition saves in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
721 }
722 }
723
724 TC_LOG_INFO("server.loading", "Loading Game Event NPCflag Data...");
725 {
726 uint32 oldMSTime = getMSTime();
727
728 // 0 1 2
729 QueryResult result = WorldDatabase.Query("SELECT guid, eventEntry, npcflag FROM game_event_npcflag");
730
731 if (!result)
732 TC_LOG_INFO("server.loading", ">> Loaded 0 npcflags in game events. DB table `game_event_npcflag` is empty.");
733 else
734 {
735 uint32 count = 0;
736 do
737 {
738 Field* fields = result->Fetch();
739
740 ObjectGuid::LowType guid = fields[0].GetUInt32();
741 uint16 event_id = fields[1].GetUInt8();
742 uint32 npcflag = fields[2].GetUInt32();
743
744 if (event_id >= mGameEvent.size())
745 {
746 TC_LOG_ERROR("sql.sql", "`game_event_npcflag`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
747 continue;
748 }
749
750 mGameEventNPCFlags[event_id].push_back(GuidNPCFlagPair(guid, npcflag));
751
752 ++count;
753 }
754 while (result->NextRow());
755
756 TC_LOG_INFO("server.loading", ">> Loaded {} npcflags in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
757 }
758 }
759
760 TC_LOG_INFO("server.loading", "Loading Game Event Seasonal Quest Relations...");
761 {
762 uint32 oldMSTime = getMSTime();
763
764 // 0 1
765 QueryResult result = WorldDatabase.Query("SELECT questId, eventEntry FROM game_event_seasonal_questrelation");
766
767 if (!result)
768 TC_LOG_INFO("server.loading", ">> Loaded 0 seasonal quests additions in game events. DB table `game_event_seasonal_questrelation` is empty.");
769 else
770 {
771 uint32 count = 0;
772 do
773 {
774 Field* fields = result->Fetch();
775
776 uint32 questId = fields[0].GetUInt32();
777 uint32 eventEntry = fields[1].GetUInt32();
778
779 Quest* questTemplate = const_cast<Quest*>(sObjectMgr->GetQuestTemplate(questId));
780 if (!questTemplate)
781 {
782 TC_LOG_ERROR("sql.sql", "`game_event_seasonal_questrelation`: quest id ({}) does not exist in `quest_template`.", questId);
783 continue;
784 }
785
786 if (eventEntry >= mGameEvent.size())
787 {
788 TC_LOG_ERROR("sql.sql", "`game_event_seasonal_questrelation`: event id ({}) is out of range compared to max event in `game_event`.", eventEntry);
789 continue;
790 }
791
792 questTemplate->SetEventIdForQuest(static_cast<uint16>(eventEntry));
793 ++count;
794 }
795 while (result->NextRow());
796
797 TC_LOG_INFO("server.loading", ">> Loaded {} quests additions in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
798 }
799 }
800
801 TC_LOG_INFO("server.loading", "Loading Game Event Vendor Additions Data...");
802 {
803 uint32 oldMSTime = getMSTime();
804
805 // 0 1 2 3 4 5
806 QueryResult result = WorldDatabase.Query("SELECT eventEntry, guid, item, maxcount, incrtime, ExtendedCost FROM game_event_npc_vendor ORDER BY guid, slot ASC");
807
808 if (!result)
809 TC_LOG_INFO("server.loading", ">> Loaded 0 vendor additions in game events. DB table `game_event_npc_vendor` is empty.");
810 else
811 {
812 uint32 count = 0;
813 do
814 {
815 Field* fields = result->Fetch();
816
817 uint8 event_id = fields[0].GetUInt8();
818
819 if (event_id >= mGameEventVendors.size())
820 {
821 TC_LOG_ERROR("sql.sql", "`game_event_npc_vendor`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
822 continue;
823 }
824
825 NPCVendorList& vendors = mGameEventVendors[event_id];
826 NPCVendorEntry newEntry;
827 ObjectGuid::LowType guid = fields[1].GetUInt32();
828 newEntry.item = fields[2].GetUInt32();
829 newEntry.maxcount = fields[3].GetUInt32();
830 newEntry.incrtime = fields[4].GetUInt32();
831 newEntry.ExtendedCost = fields[5].GetUInt32();
832 // get the event npc flag for checking if the npc will be vendor during the event or not
833 uint32 event_npc_flag = 0;
834 NPCFlagList& flist = mGameEventNPCFlags[event_id];
835 for (NPCFlagList::const_iterator itr = flist.begin(); itr != flist.end(); ++itr)
836 {
837 if (itr->first == guid)
838 {
839 event_npc_flag = itr->second;
840 break;
841 }
842 }
843 // get creature entry
844 newEntry.entry = 0;
845
846 if (CreatureData const* data = sObjectMgr->GetCreatureData(guid))
847 newEntry.entry = data->id;
848
849 // check validity with event's npcflag
850 if (!sObjectMgr->IsVendorItemValid(newEntry.entry, newEntry.item, newEntry.maxcount, newEntry.incrtime, newEntry.ExtendedCost, nullptr, nullptr, event_npc_flag))
851 continue;
852
853 vendors.push_back(newEntry);
854
855 ++count;
856 }
857 while (result->NextRow());
858
859 TC_LOG_INFO("server.loading", ">> Loaded {} vendor additions in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
860 }
861 }
862
863 TC_LOG_INFO("server.loading", "Loading Game Event Battleground Holiday Data...");
864 {
865 uint32 oldMSTime = getMSTime();
866
867 // 0 1
868 QueryResult result = WorldDatabase.Query("SELECT EventEntry, BattlegroundID FROM game_event_battleground_holiday");
869
870 if (!result)
871 TC_LOG_INFO("server.loading", ">> Loaded 0 battleground holidays in game events. DB table `game_event_battleground_holiday` is empty.");
872 else
873 {
874 uint32 count = 0;
875 do
876 {
877 Field* fields = result->Fetch();
878
879 uint16 event_id = fields[0].GetUInt8();
880
881 if (event_id >= mGameEvent.size())
882 {
883 TC_LOG_ERROR("sql.sql", "`game_event_battleground_holiday`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
884 continue;
885 }
886
887 mGameEventBattlegroundHolidays[event_id] = fields[1].GetUInt32();
888
889 ++count;
890 }
891 while (result->NextRow());
892
893 TC_LOG_INFO("server.loading", ">> Loaded {} battleground holidays in game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
894 }
895 }
896
897 TC_LOG_INFO("server.loading", "Loading Game Event Pool Data...");
898 {
899 uint32 oldMSTime = getMSTime();
900
901 // 0 1
902 QueryResult result = WorldDatabase.Query("SELECT pool_template.entry, game_event_pool.eventEntry FROM pool_template"
903 " JOIN game_event_pool ON pool_template.entry = game_event_pool.pool_entry");
904
905 if (!result)
906 TC_LOG_INFO("server.loading", ">> Loaded 0 pools for game events. DB table `game_event_pool` is empty.");
907 else
908 {
909 uint32 count = 0;
910 do
911 {
912 Field* fields = result->Fetch();
913
914 uint32 entry = fields[0].GetUInt32();
915 int16 event_id = fields[1].GetInt8();
916
917 int32 internal_event_id = mGameEvent.size() + event_id - 1;
918
919 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventPoolIds.size()))
920 {
921 TC_LOG_ERROR("sql.sql", "`game_event_pool`: game event id ({}) is out of range compared to max event id in `game_event`.", event_id);
922 continue;
923 }
924
925 if (!sPoolMgr->CheckPool(entry))
926 {
927 TC_LOG_ERROR("sql.sql", "Pool Id ({}) has all creatures or gameobjects with explicit chance sum <> 100 and no equal chance defined. The pool system cannot pick one to spawn.", entry);
928 continue;
929 }
930
931 IdList& poollist = mGameEventPoolIds[internal_event_id];
932 poollist.push_back(entry);
933
934 ++count;
935 }
936 while (result->NextRow());
937
938 TC_LOG_INFO("server.loading", ">> Loaded {} pools for game events in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
939 }
940 }
941}
942
944{
945 uint32 oldMSTime = getMSTime();
946
947 // 0 1 2 3
948 QueryResult result = WorldDatabase.Query("SELECT id, date_id, date_value, holiday_duration FROM holiday_dates");
949 if (!result)
950 {
951 TC_LOG_INFO("server.loading", ">> Loaded 0 holiday dates. DB table `holiday_dates` is empty.");
952 return;
953 }
954
955 uint32 count = 0;
956 do
957 {
958 Field* fields = result->Fetch();
959
960 uint32 holidayId = fields[0].GetUInt32();
961 HolidaysEntry* entry = const_cast<HolidaysEntry*>(sHolidaysStore.LookupEntry(holidayId));
962 if (!entry)
963 {
964 TC_LOG_ERROR("sql.sql", "holiday_dates entry has invalid holiday id {}.", holidayId);
965 continue;
966 }
967
968 uint8 dateId = fields[1].GetUInt8();
969 if (dateId >= MAX_HOLIDAY_DATES)
970 {
971 TC_LOG_ERROR("sql.sql", "holiday_dates entry has out of range date_id {}.", dateId);
972 continue;
973 }
974
975 entry->Date[dateId] = fields[2].GetUInt32();
976
977 if (uint32 duration = fields[3].GetUInt32())
978 entry->Duration[0] = duration;
979
980 auto itr = std::lower_bound(modifiedHolidays.begin(), modifiedHolidays.end(), entry->ID);
981 if (itr == modifiedHolidays.end() || *itr != entry->ID)
982 modifiedHolidays.insert(itr, entry->ID);
983 ++count;
984
985 } while (result->NextRow());
986
987 TC_LOG_INFO("server.loading", ">> Loaded {} holiday dates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
988}
989
991{
992 uint32 mask = 0;
993 ObjectGuid::LowType guid = cr->GetSpawnId();
994
995 for (ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
996 {
997 for (NPCFlagList::iterator itr = mGameEventNPCFlags[*e_itr].begin();
998 itr != mGameEventNPCFlags[*e_itr].end();
999 ++ itr)
1000 if (itr->first == guid)
1001 mask |= itr->second;
1002 }
1003
1004 return mask;
1005}
1006
1008{
1009 QueryResult result = WorldDatabase.Query("SELECT MAX(eventEntry) FROM game_event");
1010 if (result)
1011 {
1012 Field* fields = result->Fetch();
1013
1014 uint32 maxEventId = fields[0].GetUInt8();
1015
1016 // Id starts with 1 and vector with 0, thus increment
1017 maxEventId++;
1018
1019 mGameEvent.resize(maxEventId);
1020 mGameEventCreatureGuids.resize(maxEventId * 2 - 1);
1021 mGameEventGameobjectGuids.resize(maxEventId * 2 - 1);
1022 mGameEventCreatureQuests.resize(maxEventId);
1023 mGameEventGameObjectQuests.resize(maxEventId);
1024 mGameEventVendors.resize(maxEventId);
1025 mGameEventBattlegroundHolidays.resize(maxEventId, 0);
1026 mGameEventPoolIds.resize(maxEventId * 2 - 1);
1027 mGameEventNPCFlags.resize(maxEventId);
1028 mGameEventModelEquip.resize(maxEventId);
1029 }
1030}
1031
1032uint32 GameEventMgr::StartSystem() // return the next event delay in ms
1033{
1034 m_ActiveEvents.clear();
1035 uint32 delay = Update();
1036 isSystemInit = true;
1037 return delay;
1038}
1039
1041{
1042 uint8 season = sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID);
1043 QueryResult result = WorldDatabase.PQuery("SELECT eventEntry FROM game_event_arena_seasons WHERE season = '{}'", season);
1044
1045 if (!result)
1046 {
1047 TC_LOG_ERROR("gameevent", "ArenaSeason ({}) must be an existing Arena Season.", season);
1048 return;
1049 }
1050
1051 Field* fields = result->Fetch();
1052 uint16 eventId = fields[0].GetUInt8();
1053
1054 if (eventId >= mGameEvent.size())
1055 {
1056 TC_LOG_ERROR("gameevent", "EventEntry {} for ArenaSeason ({}) does not exist.", eventId, season);
1057 return;
1058 }
1059
1060 StartEvent(eventId, true);
1061 TC_LOG_INFO("gameevent", "Arena Season {} started...", season);
1062
1063}
1064
1065uint32 GameEventMgr::Update() // return the next event delay in ms
1066{
1067 time_t currenttime = GameTime::GetGameTime();
1068 uint32 nextEventDelay = max_ge_check_delay; // 1 day
1069 uint32 calcDelay;
1070 std::set<uint16> activate, deactivate;
1071 for (uint16 itr = 1; itr < mGameEvent.size(); ++itr)
1072 {
1073 // must do the activating first, and after that the deactivating
1074 // so first queue it
1075 //TC_LOG_ERROR("sql.sql", "Checking event {}", itr);
1076 if (CheckOneGameEvent(itr))
1077 {
1078 // if the world event is in NEXTPHASE state, and the time has passed to finish this event, then do so
1079 if (mGameEvent[itr].state == GAMEEVENT_WORLD_NEXTPHASE && mGameEvent[itr].nextstart <= currenttime)
1080 {
1081 // set this event to finished, null the nextstart time
1083 mGameEvent[itr].nextstart = 0;
1084 // save the state of this gameevent
1086 // queue for deactivation
1087 if (IsActiveEvent(itr))
1088 deactivate.insert(itr);
1089 // go to next event, this no longer needs an event update timer
1090 continue;
1091 }
1093 // changed, save to DB the gameevent state, will be updated in next update cycle
1095
1096 //TC_LOG_DEBUG("misc", "GameEvent {} is active", itr->first);
1097 // queue for activation
1098 if (!IsActiveEvent(itr))
1099 activate.insert(itr);
1100 }
1101 else
1102 {
1103 //TC_LOG_DEBUG("misc", "GameEvent {} is not active", itr->first);
1104 if (IsActiveEvent(itr))
1105 deactivate.insert(itr);
1106 else
1107 {
1108 if (!isSystemInit)
1109 {
1110 int16 event_nid = (-1) * (itr);
1111 // spawn all negative ones for this event
1112 GameEventSpawn(event_nid);
1113 }
1114 }
1115 }
1116 calcDelay = NextCheck(itr);
1117 if (calcDelay < nextEventDelay)
1118 nextEventDelay = calcDelay;
1119 }
1120 // now activate the queue
1121 // a now activated event can contain a spawn of a to-be-deactivated one
1122 // following the activate - deactivate order, deactivating the first event later will leave the spawn in (wont disappear then reappear clientside)
1123 for (std::set<uint16>::iterator itr = activate.begin(); itr != activate.end(); ++itr)
1124 // start the event
1125 // returns true the started event completed
1126 // in that case, initiate next update in 1 second
1127 if (StartEvent(*itr))
1128 nextEventDelay = 0;
1129 for (std::set<uint16>::iterator itr = deactivate.begin(); itr != deactivate.end(); ++itr)
1130 StopEvent(*itr);
1131 TC_LOG_INFO("gameevent", "Next game event check in {} seconds.", nextEventDelay + 1);
1132 return (nextEventDelay + 1) * IN_MILLISECONDS; // Add 1 second to be sure event has started/stopped at next call
1133}
1134
1136{
1137 TC_LOG_INFO("gameevent", "GameEvent {} \"{}\" removed.", event_id, mGameEvent[event_id].description);
1139 RunSmartAIScripts(event_id, false);
1140 // un-spawn positive event tagged objects
1141 GameEventUnspawn(event_id);
1142 // spawn negative event tagget objects
1143 int16 event_nid = (-1) * event_id;
1144 GameEventSpawn(event_nid);
1145 // restore equipment or model
1146 ChangeEquipOrModel(event_id, false);
1147 // Remove quests that are events only to non event npc
1148 UpdateEventQuests(event_id, false);
1149 UpdateWorldStates(event_id, false);
1150 // update npcflags in this event
1151 UpdateEventNPCFlags(event_id);
1152 // remove vendor items
1153 UpdateEventNPCVendor(event_id, false);
1154 // update bg holiday
1156}
1157
1159{
1160 uint8 announce = mGameEvent[event_id].announce;
1161 if (announce == 1 || (announce == 2 && sWorld->getBoolConfig(CONFIG_EVENT_ANNOUNCE)))
1162 sWorld->SendWorldText(LANG_EVENTMESSAGE, mGameEvent[event_id].description.c_str());
1163
1164 TC_LOG_INFO("gameevent", "GameEvent {} \"{}\" started.", event_id, mGameEvent[event_id].description);
1165
1166 // spawn positive event tagget objects
1167 GameEventSpawn(event_id);
1168 // un-spawn negative event tagged objects
1169 int16 event_nid = (-1) * event_id;
1170 GameEventUnspawn(event_nid);
1171 // Change equipement or model
1172 ChangeEquipOrModel(event_id, true);
1173 // Add quests that are events only to non event npc
1174 UpdateEventQuests(event_id, true);
1175 UpdateWorldStates(event_id, true);
1176 // update npcflags in this event
1177 UpdateEventNPCFlags(event_id);
1178 // add vendor items
1179 UpdateEventNPCVendor(event_id, true);
1180 // update bg holiday
1182
1184 RunSmartAIScripts(event_id, true);
1185
1186 // check for seasonal quest reset.
1187 sWorld->ResetEventSeasonalQuests(event_id, GetLastStartTime(event_id));
1188}
1189
1191{
1192 std::unordered_map<uint32, std::unordered_set<ObjectGuid::LowType>> creaturesByMap;
1193
1194 // go through the creatures whose npcflags are changed in the event
1195 for (NPCFlagList::iterator itr = mGameEventNPCFlags[event_id].begin(); itr != mGameEventNPCFlags[event_id].end(); ++itr)
1196 // get the creature data from the low guid to get the entry, to be able to find out the whole guid
1197 if (CreatureData const* data = sObjectMgr->GetCreatureData(itr->first))
1198 creaturesByMap[data->mapId].insert(itr->first);
1199
1200 for (auto const& p : creaturesByMap)
1201 {
1202 sMapMgr->DoForAllMapsWithMapId(p.first, [this, &p](Map* map)
1203 {
1204 for (auto& spawnId : p.second)
1205 {
1206 auto creatureBounds = map->GetCreatureBySpawnIdStore().equal_range(spawnId);
1207 for (auto itr = creatureBounds.first; itr != creatureBounds.second; ++itr)
1208 {
1209 Creature* creature = itr->second;
1210 uint32 npcflag = GetNPCFlag(creature);
1211 if (CreatureTemplate const* creatureTemplate = creature->GetCreatureTemplate())
1212 npcflag |= creatureTemplate->npcflag;
1213
1214 creature->ReplaceAllNpcFlags(NPCFlags(npcflag));
1215 // reset gossip options, since the flag change might have added / removed some
1216 //cr->ResetGossipOptions();
1217 }
1218 }
1219 });
1220 }
1221}
1222
1224{
1225 sBattlegroundMgr->ResetHolidays();
1226
1227 for (uint16 activeEventId : m_ActiveEvents)
1228 sBattlegroundMgr->SetHolidayActive(mGameEventBattlegroundHolidays[activeEventId]);
1229}
1230
1231void GameEventMgr::UpdateEventNPCVendor(uint16 event_id, bool activate)
1232{
1233 for (NPCVendorList::iterator itr = mGameEventVendors[event_id].begin(); itr != mGameEventVendors[event_id].end(); ++itr)
1234 {
1235 if (activate)
1236 sObjectMgr->AddVendorItem(itr->entry, itr->item, itr->maxcount, itr->incrtime, itr->ExtendedCost, false);
1237 else
1238 sObjectMgr->RemoveVendorItem(itr->entry, itr->item, false);
1239 }
1240}
1241
1243{
1244 int32 internal_event_id = mGameEvent.size() + event_id - 1;
1245
1246 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventCreatureGuids.size()))
1247 {
1248 TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempted access to out of range mGameEventCreatureGuids element {} (size: {}).",
1249 internal_event_id, mGameEventCreatureGuids.size());
1250 return;
1251 }
1252
1253 for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin(); itr != mGameEventCreatureGuids[internal_event_id].end(); ++itr)
1254 {
1255 // Add to correct cell
1256 if (CreatureData const* data = sObjectMgr->GetCreatureData(*itr))
1257 {
1258 sObjectMgr->AddCreatureToGrid(*itr, data);
1259
1260 // Spawn if necessary (loaded grids only)
1261 Map* map = sMapMgr->CreateBaseMap(data->mapId);
1263 // We use spawn coords to spawn
1264 if (!map->Instanceable() && map->IsGridLoaded(data->spawnPoint))
1265 {
1266 Creature* creature = new Creature();
1267 //TC_LOG_DEBUG("misc", "Spawning creature {}", *itr);
1268 if (!creature->LoadFromDB(*itr, map, true, false))
1269 delete creature;
1270 }
1271 }
1272 }
1273
1274 if (internal_event_id >= int32(mGameEventGameobjectGuids.size()))
1275 {
1276 TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempted access to out of range mGameEventGameobjectGuids element {} (size: {}).",
1277 internal_event_id, mGameEventGameobjectGuids.size());
1278 return;
1279 }
1280
1281 for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin(); itr != mGameEventGameobjectGuids[internal_event_id].end(); ++itr)
1282 {
1283 // Add to correct cell
1284 if (GameObjectData const* data = sObjectMgr->GetGameObjectData(*itr))
1285 {
1286 sObjectMgr->AddGameobjectToGrid(*itr, data);
1287 // Spawn if necessary (loaded grids only)
1288 // this base map checked as non-instanced and then only existed
1289 Map* map = sMapMgr->CreateBaseMap(data->mapId);
1291 // We use current coords to unspawn, not spawn coords since creature can have changed grid
1292 if (!map->Instanceable() && map->IsGridLoaded(data->spawnPoint))
1293 {
1294 GameObject* pGameobject = new GameObject;
1295 //TC_LOG_DEBUG("misc", "Spawning gameobject {}", *itr);
1297 if (!pGameobject->LoadFromDB(*itr, map, false))
1298 delete pGameobject;
1299 else
1300 {
1301 if (pGameobject->isSpawnedByDefault())
1302 map->AddToMap(pGameobject);
1303 }
1304 }
1305 }
1306 }
1307
1308 if (internal_event_id >= int32(mGameEventPoolIds.size()))
1309 {
1310 TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempted access to out of range mGameEventPoolIds element {} (size: {}).",
1311 internal_event_id, mGameEventPoolIds.size());
1312 return;
1313 }
1314
1315 for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin(); itr != mGameEventPoolIds[internal_event_id].end(); ++itr)
1316 sPoolMgr->SpawnPool(*itr);
1317}
1318
1320{
1321 int32 internal_event_id = mGameEvent.size() + event_id - 1;
1322
1323 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventCreatureGuids.size()))
1324 {
1325 TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempted access to out of range mGameEventCreatureGuids element {} (size: {}).",
1326 internal_event_id, mGameEventCreatureGuids.size());
1327 return;
1328 }
1329
1330 for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin(); itr != mGameEventCreatureGuids[internal_event_id].end(); ++itr)
1331 {
1332 // check if it's needed by another event, if so, don't remove
1333 if (event_id > 0 && hasCreatureActiveEventExcept(*itr, event_id))
1334 continue;
1335 // Remove the creature from grid
1336 if (CreatureData const* data = sObjectMgr->GetCreatureData(*itr))
1337 {
1338 sObjectMgr->RemoveCreatureFromGrid(*itr, data);
1339
1340 sMapMgr->DoForAllMapsWithMapId(data->mapId, [&itr](Map* map)
1341 {
1342 map->RemoveRespawnTime(SPAWN_TYPE_CREATURE, *itr);
1343 auto creatureBounds = map->GetCreatureBySpawnIdStore().equal_range(*itr);
1344 for (auto itr2 = creatureBounds.first; itr2 != creatureBounds.second;)
1345 {
1346 Creature* creature = itr2->second;
1347 ++itr2;
1348 creature->AddObjectToRemoveList();
1349 }
1350 });
1351 }
1352 }
1353
1354 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventGameobjectGuids.size()))
1355 {
1356 TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempted access to out of range mGameEventGameobjectGuids element {} (size: {}).",
1357 internal_event_id, mGameEventGameobjectGuids.size());
1358 return;
1359 }
1360
1361 for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin(); itr != mGameEventGameobjectGuids[internal_event_id].end(); ++itr)
1362 {
1363 // check if it's needed by another event, if so, don't remove
1364 if (event_id >0 && hasGameObjectActiveEventExcept(*itr, event_id))
1365 continue;
1366 // Remove the gameobject from grid
1367 if (GameObjectData const* data = sObjectMgr->GetGameObjectData(*itr))
1368 {
1369 sObjectMgr->RemoveGameobjectFromGrid(*itr, data);
1370
1371 sMapMgr->DoForAllMapsWithMapId(data->mapId, [&itr](Map* map)
1372 {
1373 map->RemoveRespawnTime(SPAWN_TYPE_GAMEOBJECT, *itr);
1374 auto gameobjectBounds = map->GetGameObjectBySpawnIdStore().equal_range(*itr);
1375 for (auto itr2 = gameobjectBounds.first; itr2 != gameobjectBounds.second;)
1376 {
1377 GameObject* go = itr2->second;
1378 ++itr2;
1379 go->AddObjectToRemoveList();
1380 }
1381 });
1382 }
1383 }
1384 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventPoolIds.size()))
1385 {
1386 TC_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempted access to out of range mGameEventPoolIds element {} (size: {}).", internal_event_id, mGameEventPoolIds.size());
1387 return;
1388 }
1389
1390 for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin(); itr != mGameEventPoolIds[internal_event_id].end(); ++itr)
1391 {
1392 sPoolMgr->DespawnPool(*itr, true);
1393 }
1394}
1395
1396void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate)
1397{
1398 for (ModelEquipList::iterator itr = mGameEventModelEquip[event_id].begin(); itr != mGameEventModelEquip[event_id].end(); ++itr)
1399 {
1400 // Remove the creature from grid
1401 CreatureData const* data = sObjectMgr->GetCreatureData(itr->first);
1402 if (!data)
1403 continue;
1404
1405 // Update if spawned
1406 sMapMgr->DoForAllMapsWithMapId(data->mapId, [&itr, activate](Map* map)
1407
1408 {
1409 auto creatureBounds = map->GetCreatureBySpawnIdStore().equal_range(itr->first);
1410 for (auto itr2 = creatureBounds.first; itr2 != creatureBounds.second; ++itr2)
1411 {
1412 Creature* creature = itr2->second;
1413 if (activate)
1414 {
1415 itr->second.equipement_id_prev = creature->GetCurrentEquipmentId();
1416 itr->second.modelid_prev = creature->GetDisplayId();
1417 creature->LoadEquipment(itr->second.equipment_id, true);
1418 if (itr->second.modelid > 0 && itr->second.modelid_prev != itr->second.modelid &&
1419 sObjectMgr->GetCreatureModelInfo(itr->second.modelid))
1420 {
1421 creature->SetDisplayId(itr->second.modelid);
1422 creature->SetNativeDisplayId(itr->second.modelid);
1423 }
1424 }
1425 else
1426 {
1427 creature->LoadEquipment(itr->second.equipement_id_prev, true);
1428 if (itr->second.modelid_prev > 0 && itr->second.modelid_prev != itr->second.modelid &&
1429 sObjectMgr->GetCreatureModelInfo(itr->second.modelid_prev))
1430 {
1431 creature->SetDisplayId(itr->second.modelid_prev);
1432 creature->SetNativeDisplayId(itr->second.modelid_prev);
1433 }
1434 }
1435 }
1436 });
1437 // now last step: put in data
1438 CreatureData& data2 = sObjectMgr->NewOrExistCreatureData(itr->first);
1439 if (activate)
1440 {
1441 itr->second.modelid_prev = data2.displayid;
1442 itr->second.equipement_id_prev = data2.equipmentId;
1443 data2.displayid = itr->second.modelid;
1444 data2.equipmentId = itr->second.equipment_id;
1445 }
1446 else
1447 {
1448 data2.displayid = itr->second.modelid_prev;
1449 data2.equipmentId = itr->second.equipement_id_prev;
1450 }
1451 }
1452}
1453
1455{
1456 for (ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
1457 {
1458 if ((*e_itr) != event_id)
1459 for (QuestRelList::iterator itr = mGameEventCreatureQuests[*e_itr].begin();
1460 itr != mGameEventCreatureQuests[*e_itr].end();
1461 ++ itr)
1462 if (itr->second == quest_id)
1463 return true;
1464 }
1465 return false;
1466}
1467
1469{
1470 for (ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
1471 {
1472 if ((*e_itr) != event_id)
1473 for (QuestRelList::iterator itr = mGameEventGameObjectQuests[*e_itr].begin();
1474 itr != mGameEventGameObjectQuests[*e_itr].end();
1475 ++ itr)
1476 if (itr->second == quest_id)
1477 return true;
1478 }
1479 return false;
1480}
1482{
1483 for (ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
1484 {
1485 if ((*e_itr) != event_id)
1486 {
1487 int32 internal_event_id = mGameEvent.size() + (*e_itr) - 1;
1488 for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin();
1489 itr != mGameEventCreatureGuids[internal_event_id].end();
1490 ++ itr)
1491 if (*itr == creature_id)
1492 return true;
1493 }
1494 }
1495 return false;
1496}
1498{
1499 for (ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
1500 {
1501 if ((*e_itr) != event_id)
1502 {
1503 int32 internal_event_id = mGameEvent.size() + (*e_itr) - 1;
1504 for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin();
1505 itr != mGameEventGameobjectGuids[internal_event_id].end();
1506 ++ itr)
1507 if (*itr == go_id)
1508 return true;
1509 }
1510 }
1511 return false;
1512}
1513
1514void GameEventMgr::UpdateEventQuests(uint16 event_id, bool activate)
1515{
1516 QuestRelList::iterator itr;
1517 for (itr = mGameEventCreatureQuests[event_id].begin(); itr != mGameEventCreatureQuests[event_id].end(); ++itr)
1518 {
1519 QuestRelations* CreatureQuestMap = sObjectMgr->GetCreatureQuestRelationMapHACK();
1520 if (activate) // Add the pair(id, quest) to the multimap
1521 CreatureQuestMap->insert(QuestRelations::value_type(itr->first, itr->second));
1522 else
1523 {
1524 if (!hasCreatureQuestActiveEventExcept(itr->second, event_id))
1525 {
1526 // Remove the pair(id, quest) from the multimap
1527 QuestRelations::iterator qitr = CreatureQuestMap->find(itr->first);
1528 if (qitr == CreatureQuestMap->end())
1529 continue;
1530 QuestRelations::iterator lastElement = CreatureQuestMap->upper_bound(itr->first);
1531 for (; qitr != lastElement; ++qitr)
1532 {
1533 if (qitr->second == itr->second)
1534 {
1535 CreatureQuestMap->erase(qitr); // iterator is now no more valid
1536 break; // but we can exit loop since the element is found
1537 }
1538 }
1539 }
1540 }
1541 }
1542 for (itr = mGameEventGameObjectQuests[event_id].begin(); itr != mGameEventGameObjectQuests[event_id].end(); ++itr)
1543 {
1544 QuestRelations* GameObjectQuestMap = sObjectMgr->GetGOQuestRelationMapHACK();
1545 if (activate) // Add the pair(id, quest) to the multimap
1546 GameObjectQuestMap->insert(QuestRelations::value_type(itr->first, itr->second));
1547 else
1548 {
1549 if (!hasGameObjectQuestActiveEventExcept(itr->second, event_id))
1550 {
1551 // Remove the pair(id, quest) from the multimap
1552 QuestRelations::iterator qitr = GameObjectQuestMap->find(itr->first);
1553 if (qitr == GameObjectQuestMap->end())
1554 continue;
1555 QuestRelations::iterator lastElement = GameObjectQuestMap->upper_bound(itr->first);
1556 for (; qitr != lastElement; ++qitr)
1557 {
1558 if (qitr->second == itr->second)
1559 {
1560 GameObjectQuestMap->erase(qitr); // iterator is now no more valid
1561 break; // but we can exit loop since the element is found
1562 }
1563 }
1564 }
1565 }
1566 }
1567}
1568
1569void GameEventMgr::UpdateWorldStates(uint16 event_id, bool Activate)
1570{
1571 GameEventData const& event = mGameEvent[event_id];
1572 if (event.holiday_id != HOLIDAY_NONE)
1573 {
1575 if (bgTypeId != BATTLEGROUND_TYPE_NONE)
1576 {
1577 BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
1578 if (bl && bl->HolidayWorldState)
1579 {
1581 worldstate.VariableID = bl->HolidayWorldState;
1582 worldstate.Value = Activate ? 1 : 0;
1583 sWorld->SendGlobalMessage(worldstate.Write());
1584 }
1585 }
1586 }
1587}
1588
1589GameEventMgr::GameEventMgr() : isSystemInit(false) { }
1590
1592{
1593 // translate the quest to event and condition
1594 QuestIdToEventConditionMap::iterator itr = mQuestToEventConditions.find(quest_id);
1595 // quest is registered
1596 if (itr != mQuestToEventConditions.end())
1597 {
1598 uint16 event_id = itr->second.event_id;
1599 uint32 condition = itr->second.condition;
1600 float num = itr->second.num;
1601
1602 // the event is not active, so return, don't increase condition finishes
1603 if (!IsActiveEvent(event_id))
1604 return;
1605 // not in correct phase, return
1606 if (mGameEvent[event_id].state != GAMEEVENT_WORLD_CONDITIONS)
1607 return;
1608 GameEventConditionMap::iterator citr = mGameEvent[event_id].conditions.find(condition);
1609 // condition is registered
1610 if (citr != mGameEvent[event_id].conditions.end())
1611 {
1612 // increase the done count, only if less then the req
1613 if (citr->second.done < citr->second.reqNum)
1614 {
1615 citr->second.done += num;
1616 // check max limit
1617 if (citr->second.done > citr->second.reqNum)
1618 citr->second.done = citr->second.reqNum;
1619 // save the change to db
1620 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1621
1623 stmt->setUInt8(0, uint8(event_id));
1624 stmt->setUInt32(1, condition);
1625 trans->Append(stmt);
1626
1627 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GAME_EVENT_CONDITION_SAVE);
1628 stmt->setUInt8(0, uint8(event_id));
1629 stmt->setUInt32(1, condition);
1630 stmt->setFloat(2, citr->second.done);
1631 trans->Append(stmt);
1632 CharacterDatabase.CommitTransaction(trans);
1633 // check if all conditions are met, if so, update the event state
1634 if (CheckOneGameEventConditions(event_id))
1635 {
1636 // changed, save to DB the gameevent state
1637 SaveWorldEventStateToDB(event_id);
1638 // force update events to set timer
1639 sWorld->ForceGameEventUpdate();
1640 }
1641 }
1642 }
1643 }
1644}
1645
1647{
1648 for (GameEventConditionMap::const_iterator itr = mGameEvent[event_id].conditions.begin(); itr != mGameEvent[event_id].conditions.end(); ++itr)
1649 if (itr->second.done < itr->second.reqNum)
1650 // return false if a condition doesn't match
1651 return false;
1652 // set the phase
1653 mGameEvent[event_id].state = GAMEEVENT_WORLD_NEXTPHASE;
1654 // set the followup events' start time
1655 if (!mGameEvent[event_id].nextstart)
1656 {
1657 time_t currenttime = GameTime::GetGameTime();
1658 mGameEvent[event_id].nextstart = currenttime + mGameEvent[event_id].length * 60;
1659 }
1660 return true;
1661}
1662
1664{
1665 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1666
1668 stmt->setUInt8(0, uint8(event_id));
1669 trans->Append(stmt);
1670
1671 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GAME_EVENT_SAVE);
1672 stmt->setUInt8(0, uint8(event_id));
1673 stmt->setUInt8(1, mGameEvent[event_id].state);
1674 stmt->setUInt32(2, mGameEvent[event_id].nextstart ? uint32(mGameEvent[event_id].nextstart) : 0);
1675 trans->Append(stmt);
1676 CharacterDatabase.CommitTransaction(trans);
1677}
1678
1680{
1681 GameEventConditionMap::const_iterator itr;
1682 for (itr = mGameEvent[event_id].conditions.begin(); itr !=mGameEvent[event_id].conditions.end(); ++itr)
1683 {
1684 if (itr->second.done_world_state)
1685 player->SendUpdateWorldState(itr->second.done_world_state, (uint32)(itr->second.done));
1686 if (itr->second.max_world_state)
1687 player->SendUpdateWorldState(itr->second.max_world_state, (uint32)(itr->second.reqNum));
1688 }
1689}
1690
1692{
1693public:
1694 GameEventAIHookWorker(uint16 eventId, bool activate) : _eventId(eventId), _activate(activate) { }
1695
1696 void Visit(std::unordered_map<ObjectGuid, Creature*>& creatureMap)
1697 {
1698 for (auto const& p : creatureMap)
1699 if (p.second->IsInWorld() && p.second->IsAIEnabled())
1700 p.second->AI()->OnGameEvent(_activate, _eventId);
1701 }
1702
1703 void Visit(std::unordered_map<ObjectGuid, GameObject*>& gameObjectMap)
1704 {
1705 for (auto const& p : gameObjectMap)
1706 if (p.second->IsInWorld())
1707 p.second->AI()->OnGameEvent(_activate, _eventId);
1708 }
1709
1710 template<class T>
1711 void Visit(std::unordered_map<ObjectGuid, T*>&) { }
1712
1713private:
1716};
1717
1718void GameEventMgr::RunSmartAIScripts(uint16 event_id, bool activate)
1719{
1722 sMapMgr->DoForAllMaps([event_id, activate](Map* map)
1723 {
1724 GameEventAIHookWorker worker(event_id, activate);
1726 visitor.Visit(map->GetObjectsStore());
1727 });
1728}
1729
1731{
1732 if (!event.holidayStage) // Ignore holiday
1733 return;
1734
1735 HolidaysEntry const* holiday = sHolidaysStore.LookupEntry(event.holiday_id);
1736 if (!holiday->Date[0] || !holiday->Duration[0]) // Invalid definitions
1737 {
1738 TC_LOG_ERROR("sql.sql", "Missing date or duration for holiday {}.", event.holiday_id);
1739 return;
1740 }
1741
1742 uint8 stageIndex = event.holidayStage - 1;
1743 event.length = holiday->Duration[stageIndex] * HOUR / MINUTE;
1744
1745 time_t stageOffset = 0;
1746 for (uint8 i = 0; i < stageIndex; ++i)
1747 stageOffset += holiday->Duration[i] * HOUR;
1748
1749 switch (holiday->CalendarFilterType)
1750 {
1751 case -1: // Yearly
1752 event.occurence = YEAR / MINUTE; // Not all too useful
1753 break;
1754 case 0: // Weekly
1755 event.occurence = WEEK / MINUTE;
1756 break;
1757 case 1: // Defined dates only (Darkmoon Faire)
1758 break;
1759 case 2: // Only used for looping events (Call to Arms)
1760 break;
1761 }
1762
1763 if (holiday->Looping)
1764 {
1765 event.occurence = 0;
1766 for (uint8 i = 0; i < MAX_HOLIDAY_DURATIONS && holiday->Duration[i]; ++i)
1767 event.occurence += holiday->Duration[i] * HOUR / MINUTE;
1768 }
1769
1770 bool singleDate = ((holiday->Date[0] >> 24) & 0x1F) == 31; // Events with fixed date within year have - 1
1771
1772 time_t curTime = GameTime::GetGameTime();
1773 for (uint8 i = 0; i < MAX_HOLIDAY_DATES && holiday->Date[i]; ++i)
1774 {
1775 uint32 date = holiday->Date[i];
1776
1777 tm timeInfo;
1778 if (singleDate)
1779 {
1780 localtime_r(&curTime, &timeInfo);
1781 timeInfo.tm_year -= 1; // First try last year (event active through New Year)
1782 }
1783 else
1784 timeInfo.tm_year = ((date >> 24) & 0x1F) + 100;
1785
1786 timeInfo.tm_mon = (date >> 20) & 0xF;
1787 timeInfo.tm_mday = ((date >> 14) & 0x3F) + 1;
1788 timeInfo.tm_hour = (date >> 6) & 0x1F;
1789 timeInfo.tm_min = date & 0x3F;
1790 timeInfo.tm_sec = 0;
1791 timeInfo.tm_wday = 0;
1792 timeInfo.tm_yday = 0;
1793 timeInfo.tm_isdst = -1;
1794
1795 // try to get next start time (skip past dates)
1796 time_t startTime = mktime(&timeInfo);
1797 if (curTime < startTime + event.length * MINUTE)
1798 {
1799 event.start = startTime + stageOffset;
1800 break;
1801 }
1802 else if (singleDate)
1803 {
1804 tm tmCopy;
1805 localtime_r(&curTime, &tmCopy);
1806 int year = tmCopy.tm_year; // This year
1807 tmCopy = timeInfo;
1808 tmCopy.tm_year = year;
1809
1810 event.start = mktime(&tmCopy) + stageOffset;
1811 break;
1812 }
1813 else
1814 {
1815 // date is due and not a singleDate event, try with next DBC date (modified by holiday_dates)
1816 // if none is found we don't modify start date and use the one in game_event
1817 }
1818 }
1819}
1820
1822{
1823 if (event_id >= mGameEvent.size())
1824 return 0;
1825
1826 if (mGameEvent[event_id].state != GAMEEVENT_NORMAL)
1827 return 0;
1828
1830 SystemTimePoint eventInitialStart = std::chrono::system_clock::from_time_t(mGameEvent[event_id].start);
1831 Minutes occurence(mGameEvent[event_id].occurence);
1832 SystemTimePoint::duration durationSinceLastStart = (now - eventInitialStart) % occurence;
1833 return std::chrono::system_clock::to_time_t(now - durationSinceLastStart);
1834}
1835
1837{
1838 if (id == HOLIDAY_NONE)
1839 return false;
1840
1841 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
1842 GameEventMgr::ActiveEvents const& ae = sGameEventMgr->GetActiveEventList();
1843
1844 for (GameEventMgr::ActiveEvents::const_iterator itr = ae.begin(); itr != ae.end(); ++itr)
1845 if (events[*itr].holiday_id == id)
1846 return true;
1847
1848 return false;
1849}
1850
1852{
1853 GameEventMgr::ActiveEvents const& ae = sGameEventMgr->GetActiveEventList();
1854 return ae.find(eventId) != ae.end();
1855}
#define sBattlegroundMgr
@ CHAR_DEL_GAME_EVENT_SAVE
@ CHAR_DEL_ALL_GAME_EVENT_CONDITION_SAVE
@ CHAR_INS_GAME_EVENT_SAVE
@ CHAR_DEL_GAME_EVENT_CONDITION_SAVE
@ CHAR_INS_GAME_EVENT_CONDITION_SAVE
@ IN_MILLISECONDS
Definition Common.h:35
@ MINUTE
Definition Common.h:29
@ HOUR
Definition Common.h:30
@ WEEK
Definition Common.h:32
@ YEAR
Definition Common.h:34
DBCStorage< BattlemasterListEntry > sBattlemasterListStore(BattlemasterListEntryfmt)
DBCStorage< HolidaysEntry > sHolidaysStore(Holidaysfmt)
#define MAX_HOLIDAY_DURATIONS
#define MAX_HOLIDAY_DATES
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint8_t uint8
Definition Define.h:135
int16_t int16
Definition Define.h:130
int8_t int8
Definition Define.h:131
int32_t int32
Definition Define.h:129
uint64_t uint64
Definition Define.h:132
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
std::chrono::system_clock::time_point SystemTimePoint
Definition Duration.h:37
std::chrono::minutes Minutes
Minutes shorthand typedef.
Definition Duration.h:30
bool IsHolidayActive(HolidayIds id)
bool IsEventActive(uint16 eventId)
#define sGameEventMgr
#define max_ge_check_delay
GameEventState
@ GAMEEVENT_NORMAL
@ GAMEEVENT_INTERNAL
@ GAMEEVENT_WORLD_FINISHED
@ GAMEEVENT_WORLD_CONDITIONS
@ GAMEEVENT_WORLD_NEXTPHASE
@ GAMEEVENT_WORLD_INACTIVE
@ LANG_EVENTMESSAGE
Definition Language.h:36
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
#define sMapMgr
Definition MapManager.h:211
#define sObjectMgr
Definition ObjectMgr.h:1721
std::multimap< uint32, uint32 > QuestRelations
Definition ObjectMgr.h:584
#define sPoolMgr
Definition PoolMgr.h:148
BattlegroundTypeId
@ BATTLEGROUND_TYPE_NONE
HolidayIds
@ HOLIDAY_NONE
@ SPAWN_TYPE_GAMEOBJECT
Definition SpawnData.h:32
@ SPAWN_TYPE_CREATURE
Definition SpawnData.h:31
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
NPCFlags
Non Player Character flags.
static BattlegroundTypeId WeekendHolidayIdToBGType(HolidayIds holiday)
bool LoadFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap, bool allowDuplicate)
ObjectGuid::LowType GetSpawnId() const
Definition Creature.h:83
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:186
Class used to access individual fields of database query result.
Definition Field.h:92
uint8 GetUInt8() const
Definition Field.cpp:29
std::string GetString() const
Definition Field.cpp:125
int8 GetInt8() const
Definition Field.cpp:37
uint64 GetUInt64() const
Definition Field.cpp:77
uint16 GetUInt16() const
Definition Field.cpp:45
float GetFloat() const
Definition Field.cpp:93
uint32 GetUInt32() const
Definition Field.cpp:61
void Visit(std::unordered_map< ObjectGuid, T * > &)
void Visit(std::unordered_map< ObjectGuid, Creature * > &creatureMap)
void Visit(std::unordered_map< ObjectGuid, GameObject * > &gameObjectMap)
GameEventAIHookWorker(uint16 eventId, bool activate)
static GameEventMgr * instance()
uint32 NextCheck(uint16 entry) const
void HandleQuestComplete(uint32 quest_id)
void LoadHolidayDates()
ActiveEvents m_ActiveEvents
bool StartEvent(uint16 event_id, bool overwrite=false)
GameEventDataMap mGameEvent
GameEventNPCFlagMap mGameEventNPCFlags
bool IsActiveEvent(uint16 event_id)
GameEventIdMap mGameEventPoolIds
std::vector< GameEventData > GameEventDataMap
void GameEventSpawn(int16 event_id)
void GameEventUnspawn(int16 event_id)
GameEventGuidMap mGameEventCreatureGuids
void RemoveActiveEvent(uint16 event_id)
void UnApplyEvent(uint16 event_id)
void UpdateEventQuests(uint16 event_id, bool activate)
void UpdateEventNPCVendor(uint16 event_id, bool activate)
void UpdateWorldStates(uint16 event_id, bool Activate)
bool hasCreatureActiveEventExcept(ObjectGuid::LowType creature_guid, uint16 event_id)
time_t GetLastStartTime(uint16 event_id) const
void AddActiveEvent(uint16 event_id)
void StartInternalEvent(uint16 event_id)
std::list< ObjectGuid::LowType > GuidList
void ApplyNewEvent(uint16 event_id)
GameEventModelEquipMap mGameEventModelEquip
std::list< ModelEquipPair > ModelEquipList
void UpdateBattlegroundSettings()
GameEventBattlegroundMap mGameEventBattlegroundHolidays
GameEventNPCVendorMap mGameEventVendors
GameEventQuestMap mGameEventCreatureQuests
GameEventGuidMap mGameEventGameobjectGuids
void SaveWorldEventStateToDB(uint16 event_id)
void UpdateEventNPCFlags(uint16 event_id)
bool CheckOneGameEventConditions(uint16 event_id)
Runs SMART_EVENT_GAME_EVENT_START/_END SAI.
void ChangeEquipOrModel(int16 event_id, bool activate)
uint32 StartSystem()
void RunSmartAIScripts(uint16 event_id, bool activate)
std::set< uint16 > ActiveEvents
QuestIdToEventConditionMap mQuestToEventConditions
bool hasCreatureQuestActiveEventExcept(uint32 quest_id, uint16 event_id)
std::list< GuidNPCFlagPair > NPCFlagList
std::list< uint32 > IdList
GameEventQuestMap mGameEventGameObjectQuests
void SetHolidayEventTime(GameEventData &event)
std::list< QuestRelation > QuestRelList
void SendWorldStateUpdate(Player *player, uint16 event_id)
bool hasGameObjectActiveEventExcept(ObjectGuid::LowType go_guid, uint16 event_id)
uint32 GetNPCFlag(Creature *cr)
bool CheckOneGameEvent(uint16 entry) const
void StopEvent(uint16 event_id, bool overwrite=false)
void StartArenaSeason()
std::list< NPCVendorEntry > NPCVendorList
bool hasGameObjectQuestActiveEventExcept(uint32 quest_id, uint16 event_id)
std::pair< uint32, uint32 > QuestRelation
std::pair< ObjectGuid::LowType, uint32 > GuidNPCFlagPair
std::vector< uint32 > modifiedHolidays
bool LoadFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap, bool=true)
bool isSpawnedByDefault() const
Definition GameObject.h:161
Definition Map.h:281
MapStoredObjectTypesContainer & GetObjectsStore()
Definition Map.h:489
bool AddToMap(T *)
Definition Map.cpp:630
void RemoveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, CharacterDatabaseTransaction dbTrans=nullptr, bool alwaysDeleteFromDB=false)
Definition Map.h:753
bool Instanceable() const
Definition Map.cpp:4226
bool IsGridLoaded(uint32 gridId) const
Definition Map.h:330
CreatureBySpawnIdContainer & GetCreatureBySpawnIdStore()
Definition Map.h:492
uint32 LowType
Definition ObjectGuid.h:142
void SendUpdateWorldState(uint32 variable, uint32 value) const
Definition Player.cpp:8493
void setUInt32(uint8 index, uint32 value)
void setFloat(uint8 index, float value)
void setUInt8(uint8 index, uint8 value)
void SetEventIdForQuest(uint16 eventId)
Definition QuestDef.h:327
void Visit(TYPE_CONTAINER &c)
void ReplaceAllNpcFlags(NPCFlags flags)
Definition Unit.h:1099
#define sWorld
Definition World.h:900
@ CONFIG_ARENA_SEASON_ID
Definition World.h:322
@ CONFIG_EVENT_ANNOUNCE
Definition World.h:158
SystemTimePoint GetSystemTime()
Current chrono system_clock time point.
Definition GameTime.cpp:52
time_t GetGameTime()
Definition GameTime.cpp:42
GameEventState state
HolidayIds holiday_id
GameEventConditionMap conditions
std::string description
int32 CalendarFilterType
uint32 Duration[MAX_HOLIDAY_DURATIONS]
uint32 Date[MAX_HOLIDAY_DATES]
uint32 modelid
uint8 equipement_id_prev
uint32 modelid_prev
uint8 equipment_id
uint32 ExtendedCost
uint32 mapId
Definition SpawnData.h:86