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