Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
GameEventMgr.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "BattlegroundMgr.h"
7#include "GameEventMgr.h"
8#include "GameObjectAI.h"
9#include "GossipDef.h"
10#include "Language.h"
11#include "Log.h"
12#include "MapManager.h"
13#include "ObjectMgr.h"
14#include "Player.h"
15#include "PoolMgr.h"
16#include "UnitAI.h"
17#include "World.h"
18#include "WorldPacket.h"
19
21{
22 switch (mGameEvent[entry].state)
23 {
24 default:
26 {
27 time_t currenttime = time(NULL);
28 // Get the event information
29 return mGameEvent[entry].start < currenttime
30 && currenttime < mGameEvent[entry].end
31 && (currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE) < mGameEvent[entry].length * MINUTE;
32 }
33 // if the state is conditions or nextphase, then the event should be active
36 return true;
37 // finished world events are inactive
40 return false;
41 // if inactive world event, check the prerequisite events
43 {
44 time_t currenttime = time(NULL);
45 for (std::set<uint16>::const_iterator itr = mGameEvent[entry].prerequisite_events.begin(); itr != mGameEvent[entry].prerequisite_events.end(); ++itr)
46 {
47 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
48 mGameEvent[*itr].nextstart > currenttime) // if not in nextphase state for long enough, can't start this one
49 return false;
50 }
51 // all prerequisite events are met
52 // but if there are no prerequisites, this can be only activated through gm command
53 return !(mGameEvent[entry].prerequisite_events.empty());
54 }
55 }
56}
57
59{
60 time_t currenttime = time(NULL);
61
62 // for NEXTPHASE state world events, return the delay to start the next event, so the followup event will be checked correctly
63 if ((mGameEvent[entry].state == GAMEEVENT_WORLD_NEXTPHASE || mGameEvent[entry].state == GAMEEVENT_WORLD_FINISHED) && mGameEvent[entry].nextstart >= currenttime)
64 return uint32(mGameEvent[entry].nextstart - currenttime);
65
66 // 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
67 if (mGameEvent[entry].state == GAMEEVENT_WORLD_CONDITIONS)
68 {
69 if (mGameEvent[entry].length)
70 return mGameEvent[entry].length * 60;
71 else
72 return max_ge_check_delay;
73 }
74
75 // outdated event: we return max
76 if (currenttime > mGameEvent[entry].end)
77 return max_ge_check_delay;
78
79 // never started event, we return delay before start
80 if (mGameEvent[entry].start > currenttime)
81 return uint32(mGameEvent[entry].start - currenttime);
82
83 uint32 delay;
84 // in event, we return the end of it
85 if ((((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * 60)) < (mGameEvent[entry].length * 60)))
86 // we return the delay before it ends
87 delay = (mGameEvent[entry].length * MINUTE) - ((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE));
88 else // not in window, we return the delay before next start
89 delay = (mGameEvent[entry].occurence * MINUTE) - ((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE));
90 // In case the end is before next check
91 if (mGameEvent[entry].end < time_t(currenttime + delay))
92 return uint32(mGameEvent[entry].end - currenttime);
93 else
94 return delay;
95}
96
98{
99 if (event_id < 1 || event_id >= mGameEvent.size())
100 return;
101
102 if (!mGameEvent[event_id].isValid())
103 return;
104
105 if (m_ActiveEvents.find(event_id) != m_ActiveEvents.end())
106 return;
107
108 StartEvent(event_id);
109}
110
111bool GameEventMgr::StartEvent(uint16 event_id, bool overwrite)
112{
113 GameEventData& data = mGameEvent[event_id];
114 if (data.state == GAMEEVENT_NORMAL || data.state == GAMEEVENT_INTERNAL)
115 {
116 AddActiveEvent(event_id);
117 ApplyNewEvent(event_id);
118 if (overwrite)
119 {
120 mGameEvent[event_id].start = time(NULL);
121 if (data.end <= data.start)
122 data.end = data.start + data.length;
123 }
124 return false;
125 }
126 else
127 {
129 // set to conditions phase
131
132 // add to active events
133 AddActiveEvent(event_id);
134 // add spawns
135 ApplyNewEvent(event_id);
136
137 // check if can go to next state
138 bool conditions_met = CheckOneGameEventConditions(event_id);
139 // save to db
140 SaveWorldEventStateToDB(event_id);
141 // force game event update to set the update timer if conditions were met from a command
142 // this update is needed to possibly start events dependent on the started one
143 // or to scedule another update where the next event will be started
144 if (overwrite && conditions_met)
145 sWorld->ForceGameEventUpdate();
146
147 return conditions_met;
148 }
149}
150
151void GameEventMgr::StopEvent(uint16 event_id, bool overwrite)
152{
153 GameEventData& data = mGameEvent[event_id];
154 bool serverwide_evt = data.state != GAMEEVENT_NORMAL && data.state != GAMEEVENT_INTERNAL;
155
156 RemoveActiveEvent(event_id);
157 UnApplyEvent(event_id);
158
159 if (overwrite && !serverwide_evt)
160 {
161 data.start = time(NULL) - data.length * MINUTE;
162 if (data.end <= data.start)
163 data.end = data.start + data.length;
164 }
165 else if (serverwide_evt)
166 {
167 // if finished world event, then only gm command can stop it
168 if (overwrite || data.state != GAMEEVENT_WORLD_FINISHED)
169 {
170 // reset conditions
171 data.nextstart = 0;
173 GameEventConditionMap::iterator itr;
174 for (itr = data.conditions.begin(); itr != data.conditions.end(); ++itr)
175 itr->second.done = 0;
176
177 SQLTransaction trans = CharacterDatabase.BeginTransaction();
179 stmt->setUInt8(0, uint8(event_id));
180 trans->Append(stmt);
181
182 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GAME_EVENT_SAVE);
183 stmt->setUInt8(0, uint8(event_id));
184 trans->Append(stmt);
185
186 CharacterDatabase.CommitTransaction(trans);
187 }
188 }
189}
190
192{
193 {
194 uint32 oldMSTime = getMSTime();
195 // 0 1 2 3 4 5 6 7 8
196 QueryResult result = WorldDatabase.Query("SELECT eventEntry, UNIX_TIMESTAMP(start_time), UNIX_TIMESTAMP(end_time), occurence, length, holiday, description, world_event, announce FROM game_event");
197 if (!result)
198 {
199 mGameEvent.clear();
200 SF_LOG_ERROR("server.loading", ">> Loaded 0 game events. DB table `game_event` is empty.");
201 return;
202 }
203
204 uint32 count = 0;
205 do
206 {
207 Field* fields = result->Fetch();
208
209 uint8 event_id = fields[0].GetUInt8();
210 if (event_id == 0)
211 {
212 SF_LOG_ERROR("sql.sql", "`game_event` game event entry 0 is reserved and can't be used.");
213 continue;
214 }
215
216 GameEventData& pGameEvent = mGameEvent[event_id];
217 uint64 starttime = fields[1].GetUInt64();
218 pGameEvent.start = time_t(starttime);
219 uint64 endtime = fields[2].GetUInt64();
220 pGameEvent.end = time_t(endtime);
221 pGameEvent.occurence = fields[3].GetUInt64();
222 pGameEvent.length = fields[4].GetUInt64();
223 pGameEvent.holiday_id = HolidayIds(fields[5].GetUInt32());
224
225 pGameEvent.state = (GameEventState)(fields[7].GetUInt8());
226 pGameEvent.nextstart = 0;
227 pGameEvent.announce = fields[8].GetUInt8();
228
229 if (pGameEvent.length == 0 && pGameEvent.state == GAMEEVENT_NORMAL) // length>0 is validity check
230 {
231 SF_LOG_ERROR("sql.sql", "`game_event` game event id (%i) isn't a world event and has length = 0, thus it can't be used.", event_id);
232 continue;
233 }
234
235 if (pGameEvent.holiday_id != HolidayIds::HOLIDAY_NONE)
236 {
237 if (!sHolidaysStore.LookupEntry(uint32(pGameEvent.holiday_id)))
238 {
239 SF_LOG_ERROR("sql.sql", "`game_event` game event id (%i) have not existed holiday id %u.", event_id, uint32(pGameEvent.holiday_id));
241 }
242 }
243
244 pGameEvent.description = fields[6].GetString();
245
246 ++count;
247 } while (result->NextRow());
248
249 SF_LOG_INFO("server.loading", ">> Loaded %u game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
250 }
251
252 SF_LOG_INFO("server.loading", "Loading Game Event Saves Data...");
253 {
254 uint32 oldMSTime = getMSTime();
255
256 // 0 1 2
257 QueryResult result = CharacterDatabase.Query("SELECT eventEntry, state, next_start FROM game_event_save");
258
259 if (!result)
260 SF_LOG_INFO("server.loading", ">> Loaded 0 game event saves in game events. DB table `game_event_save` is empty.");
261 else
262 {
263 uint32 count = 0;
264 do
265 {
266 Field* fields = result->Fetch();
267
268 uint8 event_id = fields[0].GetUInt8();
269
270 if (event_id >= mGameEvent.size())
271 {
272 SF_LOG_ERROR("sql.sql", "`game_event_save` game event entry (%i) is out of range compared to max event entry in `game_event`", event_id);
273 continue;
274 }
275
276 if (mGameEvent[event_id].state != GAMEEVENT_NORMAL && mGameEvent[event_id].state != GAMEEVENT_INTERNAL)
277 {
278 mGameEvent[event_id].state = (GameEventState)(fields[1].GetUInt8());
279 mGameEvent[event_id].nextstart = time_t(fields[2].GetUInt32());
280 }
281 else
282 {
283 SF_LOG_ERROR("sql.sql", "game_event_save includes event save for non-worldevent id %u", event_id);
284 continue;
285 }
286
287 ++count;
288 } while (result->NextRow());
289
290 SF_LOG_INFO("server.loading", ">> Loaded %u game event saves in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
291 }
292 }
293
294 SF_LOG_INFO("server.loading", "Loading Game Event Prerequisite Data...");
295 {
296 uint32 oldMSTime = getMSTime();
297
298 // 0 1
299 QueryResult result = WorldDatabase.Query("SELECT eventEntry, prerequisite_event FROM game_event_prerequisite");
300 if (!result)
301 SF_LOG_INFO("server.loading", ">> Loaded 0 game event prerequisites in game events. DB table `game_event_prerequisite` is empty.");
302 else
303 {
304 uint32 count = 0;
305 do
306 {
307 Field* fields = result->Fetch();
308
309 uint16 event_id = fields[0].GetUInt8();
310
311 if (event_id >= mGameEvent.size())
312 {
313 SF_LOG_ERROR("sql.sql", "`game_event_prerequisite` game event id (%i) is out of range compared to max event id in `game_event`", event_id);
314 continue;
315 }
316
317 if (mGameEvent[event_id].state != GAMEEVENT_NORMAL && mGameEvent[event_id].state != GAMEEVENT_INTERNAL)
318 {
319 uint16 prerequisite_event = fields[1].GetUInt32();
320 if (prerequisite_event >= mGameEvent.size())
321 {
322 SF_LOG_ERROR("sql.sql", "`game_event_prerequisite` game event prerequisite id (%i) is out of range compared to max event id in `game_event`", prerequisite_event);
323 continue;
324 }
325 mGameEvent[event_id].prerequisite_events.insert(prerequisite_event);
326 }
327 else
328 {
329 SF_LOG_ERROR("sql.sql", "game_event_prerequisiste includes event entry for non-worldevent id %u", event_id);
330 continue;
331 }
332
333 ++count;
334 } while (result->NextRow());
335
336 SF_LOG_INFO("server.loading", ">> Loaded %u game event prerequisites in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
337 }
338 }
339
340 SF_LOG_INFO("server.loading", "Loading Game Event Creature Data...");
341 {
342 uint32 oldMSTime = getMSTime();
343
344 // 0 1
345 QueryResult result = WorldDatabase.Query("SELECT guid, eventEntry FROM game_event_creature");
346
347 if (!result)
348 SF_LOG_INFO("server.loading", ">> Loaded 0 creatures in game events. DB table `game_event_creature` is empty");
349 else
350 {
351 uint32 count = 0;
352 do
353 {
354 Field* fields = result->Fetch();
355
356 uint32 guid = fields[0].GetUInt32();
357 int16 event_id = fields[1].GetInt8();
358
359 int32 internal_event_id = mGameEvent.size() + event_id - 1;
360
361 CreatureData const* data = sObjectMgr->GetCreatureData(guid);
362 if (!data)
363 {
364 SF_LOG_ERROR("sql.sql", "`game_event_creature` contains creature (GUID: %u) not found in `creature` table.", guid);
365 continue;
366 }
367
368 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventCreatureGuids.size()))
369 {
370 SF_LOG_ERROR("sql.sql", "`game_event_creature` game event id (%i) is out of range compared to max event id in `game_event`", event_id);
371 continue;
372 }
373
374 GuidList& crelist = mGameEventCreatureGuids[internal_event_id];
375 crelist.push_back(guid);
376
377 ++count;
378 } while (result->NextRow());
379
380 SF_LOG_INFO("server.loading", ">> Loaded %u creatures in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
381 }
382 }
383
384 SF_LOG_INFO("server.loading", "Loading Game Event GO Data...");
385 {
386 uint32 oldMSTime = getMSTime();
387
388 // 0 1
389 QueryResult result = WorldDatabase.Query("SELECT guid, eventEntry FROM game_event_gameobject");
390
391 if (!result)
392 SF_LOG_INFO("server.loading", ">> Loaded 0 gameobjects in game events. DB table `game_event_gameobject` is empty.");
393 else
394 {
395 uint32 count = 0;
396 do
397 {
398 Field* fields = result->Fetch();
399
400 uint32 guid = fields[0].GetUInt32();
401 int16 event_id = fields[1].GetInt8();
402
403 int32 internal_event_id = mGameEvent.size() + event_id - 1;
404
405 GameObjectData const* data = sObjectMgr->GetGOData(guid);
406 if (!data)
407 {
408 SF_LOG_ERROR("sql.sql", "`game_event_gameobject` contains gameobject (GUID: %u) not found in `gameobject` table.", guid);
409 continue;
410 }
411
412 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventGameobjectGuids.size()))
413 {
414 SF_LOG_ERROR("sql.sql", "`game_event_gameobject` game event id (%i) is out of range compared to max event id in `game_event`", event_id);
415 continue;
416 }
417
418 GuidList& golist = mGameEventGameobjectGuids[internal_event_id];
419 golist.push_back(guid);
420
421 ++count;
422 } while (result->NextRow());
423
424 SF_LOG_INFO("server.loading", ">> Loaded %u gameobjects in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
425 }
426 }
427
428 SF_LOG_INFO("server.loading", "Loading Game Event Model/Equipment Change Data...");
429 {
430 uint32 oldMSTime = getMSTime();
431
432 // 0 1 2 3 4
433 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 "
434 "FROM creature JOIN game_event_model_equip ON creature.guid=game_event_model_equip.guid");
435
436 if (!result)
437 SF_LOG_INFO("server.loading", ">> Loaded 0 model/equipment changes in game events. DB table `game_event_model_equip` is empty.");
438 else
439 {
440 uint32 count = 0;
441 do
442 {
443 Field* fields = result->Fetch();
444
445 uint32 guid = fields[0].GetUInt32();
446 uint32 entry = fields[1].GetUInt32();
447 uint16 event_id = fields[2].GetUInt8();
448
449 if (event_id >= mGameEventModelEquip.size())
450 {
451 SF_LOG_ERROR("sql.sql", "`game_event_model_equip` game event id (%u) is out of range compared to max event id in `game_event`", event_id);
452 continue;
453 }
454
455 ModelEquipList& equiplist = mGameEventModelEquip[event_id];
456 ModelEquip newModelEquipSet;
457 newModelEquipSet.modelid = fields[3].GetUInt32();
458 newModelEquipSet.equipment_id = fields[4].GetUInt8();
459 newModelEquipSet.equipement_id_prev = 0;
460 newModelEquipSet.modelid_prev = 0;
461
462 if (newModelEquipSet.equipment_id > 0)
463 {
464 int8 equipId = static_cast<int8>(newModelEquipSet.equipment_id);
465 if (!sObjectMgr->GetEquipmentInfo(entry, equipId))
466 {
467 SF_LOG_ERROR("sql.sql", "Table `game_event_model_equip` have creature (Guid: %u, entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.",
468 guid, entry, newModelEquipSet.equipment_id);
469 continue;
470 }
471 }
472
473 equiplist.push_back(std::pair<uint32, ModelEquip>(guid, newModelEquipSet));
474
475 ++count;
476 } while (result->NextRow());
477
478 SF_LOG_INFO("server.loading", ">> Loaded %u model/equipment changes in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
479 }
480 }
481
482 SF_LOG_INFO("server.loading", "Loading Game Event Quest Data...");
483 {
484 uint32 oldMSTime = getMSTime();
485
486 // 0 1 2
487 QueryResult result = WorldDatabase.Query("SELECT id, quest, eventEntry FROM game_event_creature_quest");
488
489 if (!result)
490 SF_LOG_INFO("server.loading", ">> Loaded 0 quests additions in game events. DB table `game_event_creature_quest` is empty.");
491 else
492 {
493 uint32 count = 0;
494 do
495 {
496 Field* fields = result->Fetch();
497
498 uint32 id = fields[0].GetUInt32();
499 uint32 quest = fields[1].GetUInt32();
500 uint16 event_id = fields[2].GetUInt8();
501
502 if (event_id >= mGameEventCreatureQuests.size())
503 {
504 SF_LOG_ERROR("sql.sql", "`game_event_creature_quest` game event id (%u) is out of range compared to max event id in `game_event`", event_id);
505 continue;
506 }
507
508 QuestRelList& questlist = mGameEventCreatureQuests[event_id];
509 questlist.push_back(QuestRelation(id, quest));
510
511 ++count;
512 } while (result->NextRow());
513
514 SF_LOG_INFO("server.loading", ">> Loaded %u quests additions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
515 }
516 }
517
518 SF_LOG_INFO("server.loading", "Loading Game Event GO Quest Data...");
519 {
520 uint32 oldMSTime = getMSTime();
521
522 // 0 1 2
523 QueryResult result = WorldDatabase.Query("SELECT id, quest, eventEntry FROM game_event_gameobject_quest");
524
525 if (!result)
526 SF_LOG_INFO("server.loading", ">> Loaded 0 go quests additions in game events. DB table `game_event_gameobject_quest` is empty.");
527 else
528 {
529 uint32 count = 0;
530 do
531 {
532 Field* fields = result->Fetch();
533
534 uint32 id = fields[0].GetUInt32();
535 uint32 quest = fields[1].GetUInt32();
536 uint16 event_id = fields[2].GetUInt8();
537
538 if (event_id >= mGameEventGameObjectQuests.size())
539 {
540 SF_LOG_ERROR("sql.sql", "`game_event_gameobject_quest` game event id (%u) is out of range compared to max event id in `game_event`", event_id);
541 continue;
542 }
543
544 QuestRelList& questlist = mGameEventGameObjectQuests[event_id];
545 questlist.push_back(QuestRelation(id, quest));
546
547 ++count;
548 } while (result->NextRow());
549
550 SF_LOG_INFO("server.loading", ">> Loaded %u quests additions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
551 }
552 }
553
554 SF_LOG_INFO("server.loading", "Loading Game Event Quest Condition Data...");
555 {
556 uint32 oldMSTime = getMSTime();
557
558 // 0 1 2 3
559 QueryResult result = WorldDatabase.Query("SELECT quest, eventEntry, condition_id, num FROM game_event_quest_condition");
560
561 if (!result)
562 SF_LOG_INFO("server.loading", ">> Loaded 0 quest event conditions in game events. DB table `game_event_quest_condition` is empty.");
563 else
564 {
565 uint32 count = 0;
566 do
567 {
568 Field* fields = result->Fetch();
569
570 uint32 quest = fields[0].GetUInt32();
571 uint16 event_id = fields[1].GetUInt8();
572 uint32 condition = fields[2].GetUInt32();
573 float num = fields[3].GetFloat();
574
575 if (event_id >= mGameEvent.size())
576 {
577 SF_LOG_ERROR("sql.sql", "`game_event_quest_condition` game event id (%u) is out of range compared to max event id in `game_event`", event_id);
578 continue;
579 }
580
581 mQuestToEventConditions[quest].event_id = event_id;
582 mQuestToEventConditions[quest].condition = condition;
583 mQuestToEventConditions[quest].num = num;
584
585 ++count;
586 } while (result->NextRow());
587
588 SF_LOG_INFO("server.loading", ">> Loaded %u quest event conditions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
589 }
590 }
591
592 SF_LOG_INFO("server.loading", "Loading Game Event Condition Data...");
593 {
594 uint32 oldMSTime = getMSTime();
595
596 // 0 1 2 3 4
597 QueryResult result = WorldDatabase.Query("SELECT eventEntry, condition_id, req_num, max_world_state_field, done_world_state_field FROM game_event_condition");
598
599 if (!result)
600 SF_LOG_INFO("server.loading", ">> Loaded 0 conditions in game events. DB table `game_event_condition` is empty.");
601 else
602 {
603 uint32 count = 0;
604 do
605 {
606 Field* fields = result->Fetch();
607
608 uint16 event_id = fields[0].GetUInt8();
609 uint32 condition = fields[1].GetUInt32();
610
611 if (event_id >= mGameEvent.size())
612 {
613 SF_LOG_ERROR("sql.sql", "`game_event_condition` game event id (%u) is out of range compared to max event id in `game_event`", event_id);
614 continue;
615 }
616
617 mGameEvent[event_id].conditions[condition].reqNum = fields[2].GetFloat();
618 mGameEvent[event_id].conditions[condition].done = 0;
619 mGameEvent[event_id].conditions[condition].max_world_state = fields[3].GetUInt16();
620 mGameEvent[event_id].conditions[condition].done_world_state = fields[4].GetUInt16();
621
622 ++count;
623 } while (result->NextRow());
624
625 SF_LOG_INFO("server.loading", ">> Loaded %u conditions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
626 }
627 }
628
629 SF_LOG_INFO("server.loading", "Loading Game Event Condition Save Data...");
630 {
631 uint32 oldMSTime = getMSTime();
632
633 // 0 1 2
634 QueryResult result = CharacterDatabase.Query("SELECT eventEntry, condition_id, done FROM game_event_condition_save");
635
636 if (!result)
637 SF_LOG_INFO("server.loading", ">> Loaded 0 condition saves in game events. DB table `game_event_condition_save` is empty.");
638 else
639 {
640 uint32 count = 0;
641 do
642 {
643 Field* fields = result->Fetch();
644
645 uint16 event_id = fields[0].GetUInt8();
646 uint32 condition = fields[1].GetUInt32();
647
648 if (event_id >= mGameEvent.size())
649 {
650 SF_LOG_ERROR("sql.sql", "`game_event_condition_save` game event id (%u) is out of range compared to max event id in `game_event`", event_id);
651 continue;
652 }
653
654 GameEventConditionMap::iterator itr = mGameEvent[event_id].conditions.find(condition);
655 if (itr != mGameEvent[event_id].conditions.end())
656 {
657 itr->second.done = fields[2].GetFloat();
658 }
659 else
660 {
661 SF_LOG_ERROR("sql.sql", "game_event_condition_save contains not present condition evt id %u cond id %u", event_id, condition);
662 continue;
663 }
664
665 ++count;
666 } while (result->NextRow());
667
668 SF_LOG_INFO("server.loading", ">> Loaded %u condition saves in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
669 }
670 }
671
672 SF_LOG_INFO("server.loading", "Loading Game Event NPCflag Data...");
673 {
674 uint32 oldMSTime = getMSTime();
675
676 // 0 1 2
677 QueryResult result = WorldDatabase.Query("SELECT guid, eventEntry, npcflag FROM game_event_npcflag");
678
679 if (!result)
680 SF_LOG_INFO("server.loading", ">> Loaded 0 npcflags in game events. DB table `game_event_npcflag` is empty.");
681 else
682 {
683 uint32 count = 0;
684 do
685 {
686 Field* fields = result->Fetch();
687
688 uint32 guid = fields[0].GetUInt32();
689 uint16 event_id = fields[1].GetUInt8();
690 uint32 npcflag = fields[2].GetUInt32();
691
692 if (event_id >= mGameEvent.size())
693 {
694 SF_LOG_ERROR("sql.sql", "`game_event_npcflag` game event id (%u) is out of range compared to max event id in `game_event`", event_id);
695 continue;
696 }
697
698 mGameEventNPCFlags[event_id].push_back(GuidNPCFlagPair(guid, npcflag));
699
700 ++count;
701 } while (result->NextRow());
702
703 SF_LOG_INFO("server.loading", ">> Loaded %u npcflags in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
704 }
705 }
706
707 SF_LOG_INFO("server.loading", "Loading Game Event Seasonal Quest Relations...");
708 {
709 uint32 oldMSTime = getMSTime();
710
711 // 0 1
712 QueryResult result = WorldDatabase.Query("SELECT questId, eventEntry FROM game_event_seasonal_questrelation");
713
714 if (!result)
715 SF_LOG_INFO("server.loading", ">> Loaded 0 seasonal quests additions in game events. DB table `game_event_seasonal_questrelation` is empty.");
716 else
717 {
718 uint32 count = 0;
719 do
720 {
721 Field* fields = result->Fetch();
722
723 uint32 questId = fields[0].GetUInt32();
724 uint32 eventEntry = fields[1].GetUInt32();
725
726 if (!sObjectMgr->GetQuestTemplate(questId))
727 {
728 SF_LOG_ERROR("sql.sql", "`game_event_seasonal_questrelation` quest id (%u) does not exist in `quest_template`", questId);
729 continue;
730 }
731
732 if (eventEntry >= mGameEvent.size())
733 {
734 SF_LOG_ERROR("sql.sql", "`game_event_seasonal_questrelation` event id (%u) is out of range compared to max event in `game_event`", eventEntry);
735 continue;
736 }
737
738 _questToEventLinks[questId] = eventEntry;
739 ++count;
740 } while (result->NextRow());
741
742 SF_LOG_INFO("server.loading", ">> Loaded %u quests additions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
743 }
744 }
745
746 SF_LOG_INFO("server.loading", "Loading Game Event Vendor Additions Data...");
747 {
748 uint32 oldMSTime = getMSTime();
749
750 // 0 1 2 3 4 5 6
751 QueryResult result = WorldDatabase.Query("SELECT eventEntry, guid, item, maxcount, incrtime, ExtendedCost, type FROM game_event_npc_vendor ORDER BY guid, slot ASC");
752
753 if (!result)
754 SF_LOG_INFO("server.loading", ">> Loaded 0 vendor additions in game events. DB table `game_event_npc_vendor` is empty.");
755 else
756 {
757 uint32 count = 0;
758 do
759 {
760 Field* fields = result->Fetch();
761
762 uint8 event_id = fields[0].GetUInt8();
763
764 if (event_id >= mGameEventVendors.size())
765 {
766 SF_LOG_ERROR("sql.sql", "`game_event_npc_vendor` game event id (%u) is out of range compared to max event id in `game_event`", event_id);
767 continue;
768 }
769
770 NPCVendorList& vendors = mGameEventVendors[event_id];
771 NPCVendorEntry newEntry;
772 uint32 guid = fields[1].GetUInt32();
773 newEntry.item = fields[2].GetUInt32();
774 newEntry.maxcount = fields[3].GetUInt32();
775 newEntry.incrtime = fields[4].GetUInt32();
776 newEntry.ExtendedCost = fields[5].GetUInt32();
777 newEntry.Type = fields[6].GetUInt8();
778 // get the event npc flag for checking if the npc will be vendor during the event or not
779 uint32 event_npc_flag = 0;
780 NPCFlagList& flist = mGameEventNPCFlags[event_id];
781 for (NPCFlagList::const_iterator itr = flist.begin(); itr != flist.end(); ++itr)
782 {
783 if (itr->first == guid)
784 {
785 event_npc_flag = itr->second;
786 break;
787 }
788 }
789 // get creature entry
790 newEntry.entry = 0;
791
792 if (CreatureData const* data = sObjectMgr->GetCreatureData(guid))
793 newEntry.entry = data->id;
794
795 // check validity with event's npcflag
796 if (!sObjectMgr->IsVendorItemValid(newEntry.entry, newEntry.item, newEntry.maxcount, newEntry.incrtime, newEntry.ExtendedCost, newEntry.Type, NULL, NULL, event_npc_flag))
797 continue;
798
799 vendors.push_back(newEntry);
800
801 ++count;
802 } while (result->NextRow());
803
804 SF_LOG_INFO("server.loading", ">> Loaded %u vendor additions in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
805 }
806 }
807
808 SF_LOG_INFO("server.loading", "Loading Game Event Battleground Data...");
809 {
810 uint32 oldMSTime = getMSTime();
811
812 // 0 1
813 QueryResult result = WorldDatabase.Query("SELECT eventEntry, bgflag FROM game_event_battleground_holiday");
814
815 if (!result)
816 SF_LOG_INFO("server.loading", ">> Loaded 0 battleground holidays in game events. DB table `game_event_battleground_holiday` is empty.");
817 else
818 {
819 uint32 count = 0;
820 do
821 {
822 Field* fields = result->Fetch();
823
824 uint16 event_id = fields[0].GetUInt8();
825
826 if (event_id >= mGameEvent.size())
827 {
828 SF_LOG_ERROR("sql.sql", "`game_event_battleground_holiday` game event id (%u) is out of range compared to max event id in `game_event`", event_id);
829 continue;
830 }
831
832 mGameEventBattlegroundHolidays[event_id] = fields[1].GetUInt32();
833
834 ++count;
835 } while (result->NextRow());
836
837 SF_LOG_INFO("server.loading", ">> Loaded %u battleground holidays in game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
838 }
839 }
840
841 SF_LOG_INFO("server.loading", "Loading Game Event Pool Data...");
842 {
843 uint32 oldMSTime = getMSTime();
844
845 // 0 1
846 QueryResult result = WorldDatabase.Query("SELECT pool_template.entry, game_event_pool.eventEntry FROM pool_template"
847 " JOIN game_event_pool ON pool_template.entry = game_event_pool.pool_entry");
848
849 if (!result)
850 SF_LOG_INFO("server.loading", ">> Loaded 0 pools for game events. DB table `game_event_pool` is empty.");
851 else
852 {
853 uint32 count = 0;
854 do
855 {
856 Field* fields = result->Fetch();
857
858 uint32 entry = fields[0].GetUInt32();
859 int16 event_id = fields[1].GetInt8();
860
861 int32 internal_event_id = mGameEvent.size() + event_id - 1;
862
863 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventPoolIds.size()))
864 {
865 SF_LOG_ERROR("sql.sql", "`game_event_pool` game event id (%i) is out of range compared to max event id in `game_event`", event_id);
866 continue;
867 }
868
869 if (!sPoolMgr->CheckPool(entry))
870 {
871 SF_LOG_ERROR("sql.sql", "Pool Id (%u) has all creatures or gameobjects with explicit chance sum <>100 and no equal chance defined. The pool system cannot pick one to spawn.", entry);
872 continue;
873 }
874
875 IdList& poollist = mGameEventPoolIds[internal_event_id];
876 poollist.push_back(entry);
877
878 ++count;
879 } while (result->NextRow());
880
881 SF_LOG_INFO("server.loading", ">> Loaded %u pools for game events in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
882 }
883 }
884}
885
887{
888 uint32 mask = 0;
889 uint32 guid = cr->GetDBTableGUIDLow();
890
891 for (ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
892 {
893 for (NPCFlagList::iterator itr = mGameEventNPCFlags[*e_itr].begin();
894 itr != mGameEventNPCFlags[*e_itr].end();
895 ++itr)
896 if (itr->first == guid)
897 mask |= itr->second;
898 }
899
900 return mask;
901}
902
904{
905 QueryResult result = WorldDatabase.Query("SELECT MAX(eventEntry) FROM game_event");
906 if (result)
907 {
908 Field* fields = result->Fetch();
909
910 uint32 maxEventId = fields[0].GetUInt8();
911
912 // Id starts with 1 and vector with 0, thus increment
913 maxEventId++;
914
915 mGameEvent.resize(maxEventId);
916 mGameEventCreatureGuids.resize(maxEventId * 2 - 1);
917 mGameEventGameobjectGuids.resize(maxEventId * 2 - 1);
918 mGameEventCreatureQuests.resize(maxEventId);
919 mGameEventGameObjectQuests.resize(maxEventId);
920 mGameEventVendors.resize(maxEventId);
921 mGameEventBattlegroundHolidays.resize(maxEventId, 0);
922 mGameEventPoolIds.resize(maxEventId * 2 - 1);
923 mGameEventNPCFlags.resize(maxEventId);
924 mGameEventModelEquip.resize(maxEventId);
925 }
926}
927
928uint32 GameEventMgr::StartSystem() // return the next event delay in ms
929{
930 m_ActiveEvents.clear();
931 uint32 delay = Update();
932 isSystemInit = true;
933 return delay;
934}
935
937{
939 QueryResult result = WorldDatabase.PQuery("SELECT eventEntry FROM game_event_arena_seasons WHERE season = '%i'", season);
940
941 if (!result)
942 {
943 SF_LOG_ERROR("gameevent", "ArenaSeason (%u) must be an existant Arena Season", season);
944 return;
945 }
946
947 Field* fields = result->Fetch();
948 uint16 eventId = fields[0].GetUInt8();
949
950 if (eventId >= mGameEvent.size())
951 {
952 SF_LOG_ERROR("gameevent", "EventEntry %u for ArenaSeason (%u) does not exists", eventId, season);
953 return;
954 }
955
956 StartEvent(eventId, true);
957 SF_LOG_INFO("gameevent", "Arena Season %u started...", season);
958}
959
960uint32 GameEventMgr::Update() // return the next event delay in ms
961{
962 time_t currenttime = time(NULL);
963 uint32 nextEventDelay = max_ge_check_delay; // 1 day
964 uint32 calcDelay;
965 std::set<uint16> activate, deactivate;
966 for (uint16 itr = 1; itr < mGameEvent.size(); ++itr)
967 {
968 // must do the activating first, and after that the deactivating
969 // so first queue it
970 //SF_LOG_ERROR("sql.sql", "Checking event %u", itr);
971 if (CheckOneGameEvent(itr))
972 {
973 // if the world event is in NEXTPHASE state, and the time has passed to finish this event, then do so
974 if (mGameEvent[itr].state == GAMEEVENT_WORLD_NEXTPHASE && mGameEvent[itr].nextstart <= currenttime)
975 {
976 // set this event to finished, null the nextstart time
978 mGameEvent[itr].nextstart = 0;
979 // save the state of this gameevent
981 // queue for deactivation
982 if (IsActiveEvent(itr))
983 deactivate.insert(itr);
984 // go to next event, this no longer needs an event update timer
985 continue;
986 }
988 // changed, save to DB the gameevent state, will be updated in next update cycle
990
991 //SF_LOG_DEBUG("misc", "GameEvent %u is active", itr->first);
992 // queue for activation
993 if (!IsActiveEvent(itr))
994 activate.insert(itr);
995 }
996 else
997 {
998 //SF_LOG_DEBUG("misc", "GameEvent %u is not active", itr->first);
999 if (IsActiveEvent(itr))
1000 deactivate.insert(itr);
1001 else
1002 {
1003 if (!isSystemInit)
1004 {
1005 int16 event_nid = (-1) * (itr);
1006 // spawn all negative ones for this event
1007 GameEventSpawn(event_nid);
1008 }
1009 }
1010 }
1011 calcDelay = NextCheck(itr);
1012 if (calcDelay < nextEventDelay)
1013 nextEventDelay = calcDelay;
1014 }
1015 // now activate the queue
1016 // a now activated event can contain a spawn of a to-be-deactivated one
1017 // following the activate - deactivate order, deactivating the first event later will leave the spawn in (wont disappear then reappear clientside)
1018 for (std::set<uint16>::iterator itr = activate.begin(); itr != activate.end(); ++itr)
1019 // start the event
1020 // returns true the started event completed
1021 // in that case, initiate next update in 1 second
1022 if (StartEvent(*itr))
1023 nextEventDelay = 0;
1024 for (std::set<uint16>::iterator itr = deactivate.begin(); itr != deactivate.end(); ++itr)
1025 StopEvent(*itr);
1026 SF_LOG_INFO("gameevent", "Next game event check in %u seconds.", nextEventDelay + 1);
1027 return (nextEventDelay + 1) * IN_MILLISECONDS; // Add 1 second to be sure event has started/stopped at next call
1028}
1029
1031{
1032 SF_LOG_INFO("gameevent", "GameEvent %u \"%s\" removed.", event_id, mGameEvent[event_id].description.c_str());
1034 RunSmartAIScripts(event_id, false);
1035 // un-spawn positive event tagged objects
1036 GameEventUnspawn(event_id);
1037 // spawn negative event tagget objects
1038 int16 event_nid = (-1) * event_id;
1039 GameEventSpawn(event_nid);
1040 // restore equipment or model
1041 ChangeEquipOrModel(event_id, false);
1042 // Remove quests that are events only to non event npc
1043 UpdateEventQuests(event_id, false);
1044 UpdateWorldStates(event_id, false);
1045 // update npcflags in this event
1046 UpdateEventNPCFlags(event_id);
1047 // remove vendor items
1048 UpdateEventNPCVendor(event_id, false);
1049 // update bg holiday
1051}
1052
1054{
1055 uint8 announce = mGameEvent[event_id].announce;
1056 if (announce == 1 || (announce == 2 && sWorld->GetBoolConfig(WorldBoolConfigs::CONFIG_EVENT_ANNOUNCE)))
1057 sWorld->SendWorldText(LANG_EVENTMESSAGE, mGameEvent[event_id].description.c_str());
1058
1059 SF_LOG_INFO("gameevent", "GameEvent %u \"%s\" started.", event_id, mGameEvent[event_id].description.c_str());
1060
1062 RunSmartAIScripts(event_id, true);
1063
1064 // spawn positive event tagget objects
1065 GameEventSpawn(event_id);
1066 // un-spawn negative event tagged objects
1067 int16 event_nid = (-1) * event_id;
1068 GameEventUnspawn(event_nid);
1069 // Change equipement or model
1070 ChangeEquipOrModel(event_id, true);
1071 // Add quests that are events only to non event npc
1072 UpdateEventQuests(event_id, true);
1073 UpdateWorldStates(event_id, true);
1074 // update npcflags in this event
1075 UpdateEventNPCFlags(event_id);
1076 // add vendor items
1077 UpdateEventNPCVendor(event_id, true);
1078 // update bg holiday
1080 // check for seasonal quest reset.
1081 sWorld->ResetEventSeasonalQuests(event_id);
1082}
1083
1085{
1086 // go through the creatures whose npcflags are changed in the event
1087 for (NPCFlagList::iterator itr = mGameEventNPCFlags[event_id].begin(); itr != mGameEventNPCFlags[event_id].end(); ++itr)
1088 {
1089 // get the creature data from the low guid to get the entry, to be able to find out the whole guid
1090 if (CreatureData const* data = sObjectMgr->GetCreatureData(itr->first))
1091 {
1093 // if we found the creature, modify its npcflag
1094 if (cr)
1095 {
1096 uint32 npcflag = GetNPCFlag(cr);
1097 if (const CreatureTemplate* ci = cr->GetCreatureTemplate())
1098 npcflag |= ci->npcflag;
1100 // reset gossip options, since the flag change might have added / removed some
1101 //cr->ResetGossipOptions();
1102 }
1103 // if we didn't find it, then the npcflag will be updated when the creature is loaded
1104 }
1105 }
1106}
1107
1109{
1110 uint32 mask = 0;
1111 for (ActiveEvents::const_iterator itr = m_ActiveEvents.begin(); itr != m_ActiveEvents.end(); ++itr)
1112 mask |= mGameEventBattlegroundHolidays[*itr];
1113 sBattlegroundMgr->SetHolidayWeekends(mask);
1114}
1115
1116void GameEventMgr::UpdateEventNPCVendor(uint16 event_id, bool activate)
1117{
1118 for (NPCVendorList::iterator itr = mGameEventVendors[event_id].begin(); itr != mGameEventVendors[event_id].end(); ++itr)
1119 {
1120 if (activate)
1121 sObjectMgr->AddVendorItem(itr->entry, itr->item, itr->maxcount, itr->incrtime, itr->ExtendedCost, itr->Type, false);
1122 else
1123 sObjectMgr->RemoveVendorItem(itr->entry, itr->item, itr->Type, false);
1124 }
1125}
1126
1128{
1129 int32 internal_event_id = mGameEvent.size() + event_id - 1;
1130
1131 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventCreatureGuids.size()))
1132 {
1133 SF_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: " SIZEFMTD ")",
1134 internal_event_id, mGameEventCreatureGuids.size());
1135 return;
1136 }
1137
1138 for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin(); itr != mGameEventCreatureGuids[internal_event_id].end(); ++itr)
1139 {
1140 // Add to correct cell
1141 if (CreatureData const* data = sObjectMgr->GetCreatureData(*itr))
1142 {
1143 sObjectMgr->AddCreatureToGrid(*itr, data);
1144
1145 // Spawn if necessary (loaded grids only)
1146 Map* map = sMapMgr->CreateBaseMap(data->mapid);
1147 // We use spawn coords to spawn
1148 if (!map->Instanceable() && map->IsGridLoaded(data->posX, data->posY))
1149 {
1150 Creature* creature = new Creature;
1151 //SF_LOG_DEBUG("misc", "Spawning creature %u", *itr);
1152 if (!creature->LoadCreatureFromDB(*itr, map))
1153 delete creature;
1154 }
1155 }
1156 }
1157
1158 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventGameobjectGuids.size()))
1159 {
1160 SF_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: " SIZEFMTD ")",
1161 internal_event_id, mGameEventGameobjectGuids.size());
1162 return;
1163 }
1164
1165 for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin(); itr != mGameEventGameobjectGuids[internal_event_id].end(); ++itr)
1166 {
1167 // Add to correct cell
1168 if (GameObjectData const* data = sObjectMgr->GetGOData(*itr))
1169 {
1170 sObjectMgr->AddGameobjectToGrid(*itr, data);
1171 // Spawn if necessary (loaded grids only)
1172 // this base map checked as non-instanced and then only existed
1173 Map* map = sMapMgr->CreateBaseMap(data->mapid);
1174 // We use current coords to unspawn, not spawn coords since creature can have changed grid
1175 if (!map->Instanceable() && map->IsGridLoaded(data->posX, data->posY))
1176 {
1177 GameObject* pGameobject = new GameObject;
1178 //SF_LOG_DEBUG("misc", "Spawning gameobject %u", *itr);
1180 if (!pGameobject->LoadGameObjectFromDB(*itr, map, false))
1181 delete pGameobject;
1182 else
1183 {
1184 if (pGameobject->isSpawnedByDefault())
1185 map->AddToMap(pGameobject);
1186 }
1187 }
1188 }
1189 }
1190
1191 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventPoolIds.size()))
1192 {
1193 SF_LOG_ERROR("gameevent", "GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %u (size: " SIZEFMTD ")",
1194 internal_event_id, mGameEventPoolIds.size());
1195 return;
1196 }
1197
1198 for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin(); itr != mGameEventPoolIds[internal_event_id].end(); ++itr)
1199 sPoolMgr->SpawnPool(*itr);
1200}
1201
1203{
1204 int32 internal_event_id = mGameEvent.size() + event_id - 1;
1205
1206 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventCreatureGuids.size()))
1207 {
1208 SF_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: " SIZEFMTD ")",
1209 internal_event_id, mGameEventCreatureGuids.size());
1210 return;
1211 }
1212
1213 for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin(); itr != mGameEventCreatureGuids[internal_event_id].end(); ++itr)
1214 {
1215 // check if it's needed by another event, if so, don't remove
1216 if (event_id > 0 && hasCreatureActiveEventExcept(*itr, event_id))
1217 continue;
1218 // Remove the creature from grid
1219 if (CreatureData const* data = sObjectMgr->GetCreatureData(*itr))
1220 {
1221 sObjectMgr->RemoveCreatureFromGrid(*itr, data);
1222
1223 if (Creature* creature = ObjectAccessor::GetObjectInWorld(MAKE_NEW_GUID(*itr, data->id, HIGHGUID_UNIT), (Creature*)NULL))
1224 creature->AddObjectToRemoveList();
1225 }
1226 }
1227
1228 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventGameobjectGuids.size()))
1229 {
1230 SF_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: " SIZEFMTD ")",
1231 internal_event_id, mGameEventGameobjectGuids.size());
1232 return;
1233 }
1234
1235 for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin(); itr != mGameEventGameobjectGuids[internal_event_id].end(); ++itr)
1236 {
1237 // check if it's needed by another event, if so, don't remove
1238 if (event_id > 0 && hasGameObjectActiveEventExcept(*itr, event_id))
1239 continue;
1240 // Remove the gameobject from grid
1241 if (GameObjectData const* data = sObjectMgr->GetGOData(*itr))
1242 {
1243 sObjectMgr->RemoveGameobjectFromGrid(*itr, data);
1244
1245 if (GameObject* pGameobject = ObjectAccessor::GetObjectInWorld(MAKE_NEW_GUID(*itr, data->id, HIGHGUID_GAMEOBJECT), (GameObject*)NULL))
1246 pGameobject->AddObjectToRemoveList();
1247 }
1248 }
1249 if (internal_event_id < 0 || internal_event_id >= int32(mGameEventPoolIds.size()))
1250 {
1251 SF_LOG_ERROR("gameevent", "GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %u (size: " SIZEFMTD ")", internal_event_id, mGameEventPoolIds.size());
1252 return;
1253 }
1254
1255 for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin(); itr != mGameEventPoolIds[internal_event_id].end(); ++itr)
1256 {
1257 sPoolMgr->DespawnPool(*itr);
1258 }
1259}
1260
1261void GameEventMgr::ChangeEquipOrModel(int16 event_id, bool activate)
1262{
1263 for (ModelEquipList::iterator itr = mGameEventModelEquip[event_id].begin(); itr != mGameEventModelEquip[event_id].end(); ++itr)
1264 {
1265 // Remove the creature from grid
1266 CreatureData const* data = sObjectMgr->GetCreatureData(itr->first);
1267 if (!data)
1268 continue;
1269
1270 // Update if spawned
1271 Creature* creature = ObjectAccessor::GetObjectInWorld(MAKE_NEW_GUID(itr->first, data->id, HIGHGUID_UNIT), (Creature*)NULL);
1272 if (creature)
1273 {
1274 if (activate)
1275 {
1276 itr->second.equipement_id_prev = creature->GetCurrentEquipmentId();
1277 itr->second.modelid_prev = creature->GetDisplayId();
1278 creature->LoadEquipment(itr->second.equipment_id, true);
1279 if (itr->second.modelid > 0 && itr->second.modelid_prev != itr->second.modelid &&
1280 sObjectMgr->GetCreatureModelInfo(itr->second.modelid))
1281 {
1282 creature->SetDisplayId(itr->second.modelid);
1283 creature->SetNativeDisplayId(itr->second.modelid);
1284 }
1285 }
1286 else
1287 {
1288 creature->LoadEquipment(itr->second.equipement_id_prev, true);
1289 if (itr->second.modelid_prev > 0 && itr->second.modelid_prev != itr->second.modelid &&
1290 sObjectMgr->GetCreatureModelInfo(itr->second.modelid_prev))
1291 {
1292 creature->SetDisplayId(itr->second.modelid_prev);
1293 creature->SetNativeDisplayId(itr->second.modelid_prev);
1294 }
1295 }
1296 }
1297 else // If not spawned
1298 {
1299 CreatureData const* data2 = sObjectMgr->GetCreatureData(itr->first);
1300 if (data2 && activate)
1301 {
1302 CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(data2->id);
1303 uint32 displayID = ObjectMgr::ChooseDisplayId(cinfo, data2);
1304 sObjectMgr->GetCreatureModelRandomGender(&displayID);
1305
1306 if (data2->equipmentId == 0)
1307 itr->second.equipement_id_prev = 0;
1308 else if (data2->equipmentId != -1)
1309 itr->second.equipement_id_prev = data->equipmentId;
1310 itr->second.modelid_prev = displayID;
1311 }
1312 }
1313 // now last step: put in data
1314 // just to have write access to it
1315 CreatureData& data2 = sObjectMgr->NewOrExistCreatureData(itr->first);
1316 if (activate)
1317 {
1318 data2.displayid = itr->second.modelid;
1319 data2.equipmentId = itr->second.equipment_id;
1320 }
1321 else
1322 {
1323 data2.displayid = itr->second.modelid_prev;
1324 data2.equipmentId = itr->second.equipement_id_prev;
1325 }
1326 }
1327}
1328
1330{
1331 for (ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
1332 {
1333 if ((*e_itr) != event_id)
1334 for (QuestRelList::iterator itr = mGameEventCreatureQuests[*e_itr].begin();
1335 itr != mGameEventCreatureQuests[*e_itr].end();
1336 ++itr)
1337 if (itr->second == quest_id)
1338 return true;
1339 }
1340 return false;
1341}
1342
1344{
1345 for (ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
1346 {
1347 if ((*e_itr) != event_id)
1348 for (QuestRelList::iterator itr = mGameEventGameObjectQuests[*e_itr].begin();
1349 itr != mGameEventGameObjectQuests[*e_itr].end();
1350 ++itr)
1351 if (itr->second == quest_id)
1352 return true;
1353 }
1354 return false;
1355}
1357{
1358 for (ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
1359 {
1360 if ((*e_itr) != event_id)
1361 {
1362 int32 internal_event_id = mGameEvent.size() + (*e_itr) - 1;
1363 for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin();
1364 itr != mGameEventCreatureGuids[internal_event_id].end();
1365 ++itr)
1366 if (*itr == creature_id)
1367 return true;
1368 }
1369 }
1370 return false;
1371}
1373{
1374 for (ActiveEvents::iterator e_itr = m_ActiveEvents.begin(); e_itr != m_ActiveEvents.end(); ++e_itr)
1375 {
1376 if ((*e_itr) != event_id)
1377 {
1378 int32 internal_event_id = mGameEvent.size() + (*e_itr) - 1;
1379 for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin();
1380 itr != mGameEventGameobjectGuids[internal_event_id].end();
1381 ++itr)
1382 if (*itr == go_id)
1383 return true;
1384 }
1385 }
1386 return false;
1387}
1388
1389void GameEventMgr::UpdateEventQuests(uint16 event_id, bool activate)
1390{
1391 QuestRelList::iterator itr;
1392 for (itr = mGameEventCreatureQuests[event_id].begin(); itr != mGameEventCreatureQuests[event_id].end(); ++itr)
1393 {
1394 QuestRelations* CreatureQuestMap = sObjectMgr->GetCreatureQuestRelationMap();
1395 if (activate) // Add the pair(id, quest) to the multimap
1396 CreatureQuestMap->insert(QuestRelations::value_type(itr->first, itr->second));
1397 else
1398 {
1399 if (!hasCreatureQuestActiveEventExcept(itr->second, event_id))
1400 {
1401 // Remove the pair(id, quest) from the multimap
1402 QuestRelations::iterator qitr = CreatureQuestMap->find(itr->first);
1403 if (qitr == CreatureQuestMap->end())
1404 continue;
1405 QuestRelations::iterator lastElement = CreatureQuestMap->upper_bound(itr->first);
1406 for (; qitr != lastElement; ++qitr)
1407 {
1408 if (qitr->second == itr->second)
1409 {
1410 CreatureQuestMap->erase(qitr); // iterator is now no more valid
1411 break; // but we can exit loop since the element is found
1412 }
1413 }
1414 }
1415 }
1416 }
1417 for (itr = mGameEventGameObjectQuests[event_id].begin(); itr != mGameEventGameObjectQuests[event_id].end(); ++itr)
1418 {
1419 QuestRelations* GameObjectQuestMap = sObjectMgr->GetGOQuestRelationMap();
1420 if (activate) // Add the pair(id, quest) to the multimap
1421 GameObjectQuestMap->insert(QuestRelations::value_type(itr->first, itr->second));
1422 else
1423 {
1424 if (!hasGameObjectQuestActiveEventExcept(itr->second, event_id))
1425 {
1426 // Remove the pair(id, quest) from the multimap
1427 QuestRelations::iterator qitr = GameObjectQuestMap->find(itr->first);
1428 if (qitr == GameObjectQuestMap->end())
1429 continue;
1430 QuestRelations::iterator lastElement = GameObjectQuestMap->upper_bound(itr->first);
1431 for (; qitr != lastElement; ++qitr)
1432 {
1433 if (qitr->second == itr->second)
1434 {
1435 GameObjectQuestMap->erase(qitr); // iterator is now no more valid
1436 break; // but we can exit loop since the element is found
1437 }
1438 }
1439 }
1440 }
1441 }
1442}
1443
1444void GameEventMgr::UpdateWorldStates(uint16 event_id, bool Activate)
1445{
1446 GameEventData const& event = mGameEvent[event_id];
1447 if (event.holiday_id != HolidayIds::HOLIDAY_NONE)
1448 {
1451 {
1452 BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(uint32(bgTypeId));
1453 if (bl && bl->HolidayWorldStateId)
1454 {
1455 WorldPacket data;
1456 sBattlegroundMgr->BuildUpdateWorldStatePacket(&data, bl->HolidayWorldStateId, Activate ? 1 : 0);
1457 sWorld->SendGlobalMessage(&data);
1458 }
1459 }
1460 }
1461}
1462
1464
1466{
1467 // translate the quest to event and condition
1468 QuestIdToEventConditionMap::iterator itr = mQuestToEventConditions.find(quest_id);
1469 // quest is registered
1470 if (itr != mQuestToEventConditions.end())
1471 {
1472 uint16 event_id = itr->second.event_id;
1473 uint32 condition = itr->second.condition;
1474 float num = itr->second.num;
1475
1476 // the event is not active, so return, don't increase condition finishes
1477 if (!IsActiveEvent(event_id))
1478 return;
1479 // not in correct phase, return
1480 if (mGameEvent[event_id].state != GAMEEVENT_WORLD_CONDITIONS)
1481 return;
1482 GameEventConditionMap::iterator citr = mGameEvent[event_id].conditions.find(condition);
1483 // condition is registered
1484 if (citr != mGameEvent[event_id].conditions.end())
1485 {
1486 // increase the done count, only if less then the req
1487 if (citr->second.done < citr->second.reqNum)
1488 {
1489 citr->second.done += num;
1490 // check max limit
1491 if (citr->second.done > citr->second.reqNum)
1492 citr->second.done = citr->second.reqNum;
1493 // save the change to db
1494 SQLTransaction trans = CharacterDatabase.BeginTransaction();
1495
1497 stmt->setUInt8(0, uint8(event_id));
1498 stmt->setUInt32(1, condition);
1499 trans->Append(stmt);
1500
1501 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GAME_EVENT_CONDITION_SAVE);
1502 stmt->setUInt8(0, uint8(event_id));
1503 stmt->setUInt32(1, condition);
1504 stmt->setFloat(2, citr->second.done);
1505 trans->Append(stmt);
1506 CharacterDatabase.CommitTransaction(trans);
1507 // check if all conditions are met, if so, update the event state
1508 if (CheckOneGameEventConditions(event_id))
1509 {
1510 // changed, save to DB the gameevent state
1511 SaveWorldEventStateToDB(event_id);
1512 // force update events to set timer
1513 sWorld->ForceGameEventUpdate();
1514 }
1515 }
1516 }
1517 }
1518}
1519
1521{
1522 for (GameEventConditionMap::const_iterator itr = mGameEvent[event_id].conditions.begin(); itr != mGameEvent[event_id].conditions.end(); ++itr)
1523 if (itr->second.done < itr->second.reqNum)
1524 // return false if a condition doesn't match
1525 return false;
1526 // set the phase
1527 mGameEvent[event_id].state = GAMEEVENT_WORLD_NEXTPHASE;
1528 // set the followup events' start time
1529 if (!mGameEvent[event_id].nextstart)
1530 {
1531 time_t currenttime = time(NULL);
1532 mGameEvent[event_id].nextstart = currenttime + mGameEvent[event_id].length * 60;
1533 }
1534 return true;
1535}
1536
1538{
1539 SQLTransaction trans = CharacterDatabase.BeginTransaction();
1540
1541 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GAME_EVENT_SAVE);
1542 stmt->setUInt8(0, uint8(event_id));
1543 trans->Append(stmt);
1544
1545 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GAME_EVENT_SAVE);
1546 stmt->setUInt8(0, uint8(event_id));
1547 stmt->setUInt8(1, mGameEvent[event_id].state);
1548 stmt->setUInt32(2, mGameEvent[event_id].nextstart ? uint32(mGameEvent[event_id].nextstart) : 0);
1549 trans->Append(stmt);
1550 CharacterDatabase.CommitTransaction(trans);
1551}
1552
1554{
1555 GameEventConditionMap::const_iterator itr;
1556 for (itr = mGameEvent[event_id].conditions.begin(); itr != mGameEvent[event_id].conditions.end(); ++itr)
1557 {
1558 if (itr->second.done_world_state)
1559 player->SendUpdateWorldState(itr->second.done_world_state, (uint32)(itr->second.done));
1560 if (itr->second.max_world_state)
1561 player->SendUpdateWorldState(itr->second.max_world_state, (uint32)(itr->second.reqNum));
1562 }
1563}
1564
1565void GameEventMgr::RunSmartAIScripts(uint16 event_id, bool activate)
1566{
1569 {
1572 for (HashMapHolder<Creature>::MapType::const_iterator iter = m.begin(); iter != m.end(); ++iter)
1573 if (iter->second->IsInWorld())
1574 iter->second->AI()->sOnGameEvent(activate, event_id);
1575 }
1576 {
1579 for (HashMapHolder<GameObject>::MapType::const_iterator iter = m.begin(); iter != m.end(); ++iter)
1580 if (iter->second->IsInWorld())
1581 iter->second->AI()->OnGameEvent(activate, event_id);
1582 }
1583}
1584
1586{
1587 if (!quest)
1588 return 0;
1589
1591 if (itr == _questToEventLinks.end())
1592 return 0;
1593
1594 return itr->second;
1595}
1596
1598{
1599 if (id == HolidayIds::HOLIDAY_NONE)
1600 return false;
1601
1602 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
1603 GameEventMgr::ActiveEvents const& ae = sGameEventMgr->GetActiveEventList();
1604
1605 for (GameEventMgr::ActiveEvents::const_iterator itr = ae.begin(); itr != ae.end(); ++itr)
1606 if (events[*itr].holiday_id == id)
1607 return true;
1608
1609 return false;
1610}
1611
1612bool IsEventActive(uint16 event_id)
1613{
1614 GameEventMgr::ActiveEvents const& ae = sGameEventMgr->GetActiveEventList();
1615 return ae.find(event_id) != ae.end();
1616}
#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:125
@ MINUTE
Definition Common.h:119
DBCStorage< BattlemasterListEntry > sBattlemasterListStore(BattlemasterListEntryfmt)
DBCStorage< HolidaysEntry > sHolidaysStore(Holidaysfmt)
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
#define SIZEFMTD
Definition Define.h:70
std::int8_t int8
Definition Define.h:75
std::uint64_t uint64
Definition Define.h:76
std::uint16_t uint16
Definition Define.h:78
std::int16_t int16
Definition Define.h:74
bool IsHolidayActive(HolidayIds id)
bool IsEventActive(uint16 event_id)
#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:17
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
#define SF_LOG_INFO(filterType__,...)
Definition Log.h:137
#define sMapMgr
Definition MapManager.h:145
@ HIGHGUID_GAMEOBJECT
@ HIGHGUID_UNIT
uint64 MAKE_NEW_GUID(uint32 l, uint32 e, uint32 h)
#define sObjectMgr
Definition ObjectMgr.h:1617
std::multimap< uint32, uint32 > QuestRelations
Definition ObjectMgr.h:455
#define sPoolMgr
Definition PoolMgr.h:154
Skyfire::AutoPtr< ResultSet, Skyfire::Mutex > QueryResult
Definition QueryResult.h:48
BattlegroundTypeId
HolidayIds
#define SF_SHARED_GUARD
Definition SharedMutex.h:17
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:22
uint32 getMSTime()
Definition Timer.h:12
Skyfire::AutoPtr< Transaction, Skyfire::Mutex > SQLTransaction
Definition Transaction.h:42
#define UNORDERED_MAP
@ UNIT_FIELD_NPC_FLAGS
static BattlegroundTypeId WeekendHolidayIdToBGType(HolidayIds holiday)
uint32 GetDBTableGUIDLow() const
Definition Creature.h:445
void LoadEquipment(int8 id=1, bool force=false)
void SetDisplayId(uint32 modelId) OVERRIDE
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:524
uint8 GetCurrentEquipmentId() const
Definition Creature.h:513
bool LoadCreatureFromDB(uint32 guid, Map *map, bool addToMap=true)
Definition Field.h:16
uint8 GetUInt8() const
Definition Field.h:26
std::string GetString() const
Definition Field.h:228
int8 GetInt8() const
Definition Field.h:44
uint64 GetUInt64() const
Definition Field.h:141
uint16 GetUInt16() const
Definition Field.h:69
float GetFloat() const
Definition Field.h:177
uint32 GetUInt32() const
Definition Field.h:105
uint32 NextCheck(uint16 entry) const
void HandleQuestComplete(uint32 quest_id)
ActiveEvents m_ActiveEvents
bool StartEvent(uint16 event_id, bool overwrite=false)
GameEventDataMap mGameEvent
uint16 GetEventIdForQuest(Quest const *quest) const
GameEventNPCFlagMap mGameEventNPCFlags
std::list< uint32 > GuidList
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)
void AddActiveEvent(uint16 event_id)
void StartInternalEvent(uint16 event_id)
void ApplyNewEvent(uint16 event_id)
GameEventModelEquipMap mGameEventModelEquip
std::list< ModelEquipPair > ModelEquipList
void UpdateBattlegroundSettings()
GameEventBitmask mGameEventBattlegroundHolidays
GameEventNPCVendorMap mGameEventVendors
GameEventQuestMap mGameEventCreatureQuests
std::pair< uint32, uint32 > GuidNPCFlagPair
GameEventGuidMap mGameEventGameobjectGuids
void SaveWorldEventStateToDB(uint16 event_id)
UNORDERED_MAP< uint32, uint16 > _questToEventLinks
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
std::list< QuestRelation > QuestRelList
void SendWorldStateUpdate(Player *player, 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
bool hasGameObjectActiveEventExcept(uint32 go_guid, uint16 event_id)
bool hasCreatureActiveEventExcept(uint32 creature_guid, uint16 event_id)
bool isSpawnedByDefault() const
Definition GameObject.h:711
bool LoadGameObjectFromDB(uint32 guid, Map *map, bool addToMap=true)
static SF_SHARED_MUTEX * GetLock()
static T * Find(uint64 guid)
UNORDERED_MAP< uint64, T * > MapType
Definition Map.h:238
bool AddToMap(T *)
Definition Map.cpp:504
bool Instanceable() const
Definition Map.h:367
bool IsGridLoaded(float x, float y) const
Definition Map.h:283
static HashMapHolder< GameObject >::MapType const & GetGameObjects()
static T * GetObjectInWorld(uint64 guid, T *)
static HashMapHolder< Creature >::MapType const & GetCreatures()
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:1038
static uint32 ChooseDisplayId(CreatureTemplate const *cinfo, CreatureData const *data=NULL)
void SendUpdateWorldState(uint32 Field, uint32 Value)
Definition Player.cpp:9734
void setFloat(const uint8 index, const float value)
void setUInt32(const uint8 index, const uint32 value)
void setUInt8(const uint8 index, const uint8 value)
uint32 GetQuestId() const
Definition QuestDef.h:270
uint32 GetDisplayId() const
Definition Unit.h:2490
void SetNativeDisplayId(uint32 modelId)
Definition Unit.h:2500
CharacterDatabaseWorkerPool CharacterDatabase
Accessor to the character database.
Definition Main.cpp:41
WorldDatabaseWorkerPool WorldDatabase
Accessor to the world database.
Definition Main.cpp:40
#define sWorld
Definition World.h:910
@ CONFIG_ARENA_SEASON_ID
Definition World.h:298
@ CONFIG_EVENT_ANNOUNCE
Definition World.h:163
uint32 HolidayWorldStateId
uint32 id
Definition Creature.h:260
uint32 displayid
Definition Creature.h:264
int8 equipmentId
Definition Creature.h:265
GameEventState state
HolidayIds holiday_id
GameEventConditionMap conditions
std::string description
uint32 modelid
uint8 equipement_id_prev
uint32 modelid_prev
uint8 equipment_id
uint8 Type
int32 maxcount
uint32 item
uint32 entry
uint32 incrtime
uint32 ExtendedCost