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