aboutsummaryrefslogtreecommitdiff
path: root/src/game/GameEvent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/GameEvent.cpp')
-rw-r--r--src/game/GameEvent.cpp659
1 files changed, 659 insertions, 0 deletions
diff --git a/src/game/GameEvent.cpp b/src/game/GameEvent.cpp
new file mode 100644
index 00000000000..e36cb6caae8
--- /dev/null
+++ b/src/game/GameEvent.cpp
@@ -0,0 +1,659 @@
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "GameEvent.h"
+#include "World.h"
+#include "ObjectMgr.h"
+#include "ProgressBar.h"
+#include "Language.h"
+#include "Log.h"
+#include "MapManager.h"
+#include "Policies/SingletonImp.h"
+
+INSTANTIATE_SINGLETON_1(GameEvent);
+
+bool GameEvent::CheckOneGameEvent(uint16 entry) const
+{
+ // Get the event information
+ time_t currenttime = time(NULL);
+ if( mGameEvent[entry].start < currenttime && currenttime < mGameEvent[entry].end &&
+ ((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE)) < (mGameEvent[entry].length * MINUTE) )
+ return true;
+ else
+ return false;
+}
+
+uint32 GameEvent::NextCheck(uint16 entry) const
+{
+ time_t currenttime = time(NULL);
+
+ // outdated event: we return max
+ if (currenttime > mGameEvent[entry].end)
+ return max_ge_check_delay;
+
+ // never started event, we return delay before start
+ if (mGameEvent[entry].start > currenttime)
+ return (mGameEvent[entry].start - currenttime);
+
+ uint32 delay;
+ // in event, we return the end of it
+ if ((((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * 60)) < (mGameEvent[entry].length * 60)))
+ // we return the delay before it ends
+ delay = (mGameEvent[entry].length * MINUTE) - ((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE));
+ else // not in window, we return the delay before next start
+ delay = (mGameEvent[entry].occurence * MINUTE) - ((currenttime - mGameEvent[entry].start) % (mGameEvent[entry].occurence * MINUTE));
+ // In case the end is before next check
+ if (mGameEvent[entry].end < time_t(currenttime + delay))
+ return (mGameEvent[entry].end - currenttime);
+ else
+ return delay;
+}
+
+void GameEvent::StartEvent( uint16 event_id, bool overwrite )
+{
+ AddActiveEvent(event_id);
+ ApplyNewEvent(event_id);
+ if(overwrite)
+ {
+ mGameEvent[event_id].start = time(NULL);
+ if(mGameEvent[event_id].end <= mGameEvent[event_id].start)
+ mGameEvent[event_id].end = mGameEvent[event_id].start+mGameEvent[event_id].length;
+ }
+}
+
+void GameEvent::StopEvent( uint16 event_id, bool overwrite )
+{
+ RemoveActiveEvent(event_id);
+ UnApplyEvent(event_id);
+ if(overwrite)
+ {
+ mGameEvent[event_id].start = time(NULL) - mGameEvent[event_id].length * MINUTE;
+ if(mGameEvent[event_id].end <= mGameEvent[event_id].start)
+ mGameEvent[event_id].end = mGameEvent[event_id].start+mGameEvent[event_id].length;
+ }
+}
+
+void GameEvent::LoadFromDB()
+{
+ {
+ QueryResult *result = WorldDatabase.Query("SELECT MAX(entry) FROM game_event");
+ if( !result )
+ {
+ sLog.outString(">> Table game_event is empty.");
+ sLog.outString();
+ return;
+ }
+
+ Field *fields = result->Fetch();
+
+ uint32 max_event_id = fields[0].GetUInt16();
+ delete result;
+
+ mGameEvent.resize(max_event_id+1);
+ }
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,UNIX_TIMESTAMP(start_time),UNIX_TIMESTAMP(end_time),occurence,length,description FROM game_event");
+ if( !result )
+ {
+ mGameEvent.clear();
+ sLog.outString(">> Table game_event is empty:");
+ sLog.outString();
+ return;
+ }
+
+ uint32 count = 0;
+
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ ++count;
+ Field *fields = result->Fetch();
+
+ bar.step();
+
+ uint16 event_id = fields[0].GetUInt16();
+ if(event_id==0)
+ {
+ sLog.outErrorDb("`game_event` game event id (%i) is reserved and can't be used.",event_id);
+ continue;
+ }
+
+ GameEventData& pGameEvent = mGameEvent[event_id];
+ uint64 starttime = fields[1].GetUInt64();
+ pGameEvent.start = time_t(starttime);
+ uint64 endtime = fields[2].GetUInt64();
+ pGameEvent.end = time_t(endtime);
+ pGameEvent.occurence = fields[3].GetUInt32();
+ pGameEvent.length = fields[4].GetUInt32();
+
+ if(pGameEvent.length==0) // length>0 is validity check
+ {
+ sLog.outErrorDb("`game_event` game event id (%i) have length 0 and can't be used.",event_id);
+ continue;
+ }
+
+ pGameEvent.description = fields[5].GetCppString();
+
+ } while( result->NextRow() );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u game events", count );
+ delete result;
+
+ mGameEventCreatureGuids.resize(mGameEvent.size()*2-1);
+ // 1 2
+ result = WorldDatabase.Query("SELECT creature.guid, game_event_creature.event "
+ "FROM creature JOIN game_event_creature ON creature.guid = game_event_creature.guid");
+
+ count = 0;
+ if( !result )
+ {
+ barGoLink bar2(1);
+ bar2.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u creatures in game events", count );
+ }
+ else
+ {
+
+ barGoLink bar2( result->GetRowCount() );
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar2.step();
+
+ uint32 guid = fields[0].GetUInt32();
+ int16 event_id = fields[1].GetInt16();
+
+ int32 internal_event_id = mGameEvent.size() + event_id - 1;
+
+ if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size())
+ {
+ sLog.outErrorDb("`game_event_creature` game event id (%i) is out of range compared to max event id in `game_event`",event_id);
+ continue;
+ }
+
+ ++count;
+ GuidList& crelist = mGameEventCreatureGuids[internal_event_id];
+ crelist.push_back(guid);
+
+ } while( result->NextRow() );
+ sLog.outString();
+ sLog.outString( ">> Loaded %u creatures in game events", count );
+ delete result;
+ }
+
+ mGameEventGameobjectGuids.resize(mGameEvent.size()*2-1);
+ // 1 2
+ result = WorldDatabase.Query("SELECT gameobject.guid, game_event_gameobject.event "
+ "FROM gameobject JOIN game_event_gameobject ON gameobject.guid=game_event_gameobject.guid");
+
+ count = 0;
+ if( !result )
+ {
+ barGoLink bar3(1);
+ bar3.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u gameobjects in game events", count );
+ }
+ else
+ {
+
+ barGoLink bar3( result->GetRowCount() );
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar3.step();
+
+ uint32 guid = fields[0].GetUInt32();
+ int16 event_id = fields[1].GetInt16();
+
+ int32 internal_event_id = mGameEvent.size() + event_id - 1;
+
+ if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size())
+ {
+ sLog.outErrorDb("`game_event_gameobject` game event id (%i) is out of range compared to max event id in `game_event`",event_id);
+ continue;
+ }
+
+ ++count;
+ GuidList& golist = mGameEventGameobjectGuids[internal_event_id];
+ golist.push_back(guid);
+
+ } while( result->NextRow() );
+ sLog.outString();
+ sLog.outString( ">> Loaded %u gameobjects in game events", count );
+
+ delete result;
+ }
+
+ mGameEventModelEquip.resize(mGameEvent.size());
+ // 0 1 2
+ result = WorldDatabase.Query("SELECT creature.guid, game_event_model_equip.event, game_event_model_equip.modelid,"
+ // 3
+ "game_event_model_equip.equipment_id "
+ "FROM creature JOIN game_event_model_equip ON creature.guid=game_event_model_equip.guid");
+
+ count = 0;
+ if( !result )
+ {
+ barGoLink bar3(1);
+ bar3.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u model/equipment changes in game events", count );
+ }
+ else
+ {
+
+ barGoLink bar3( result->GetRowCount() );
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar3.step();
+ uint32 guid = fields[0].GetUInt32();
+ uint16 event_id = fields[1].GetUInt16();
+
+ if(event_id >= mGameEventModelEquip.size())
+ {
+ sLog.outErrorDb("`game_event_model_equip` game event id (%u) is out of range compared to max event id in `game_event`",event_id);
+ continue;
+ }
+
+ ++count;
+ ModelEquipList& equiplist = mGameEventModelEquip[event_id];
+ ModelEquip newModelEquipSet;
+ newModelEquipSet.modelid = fields[2].GetUInt32();
+ newModelEquipSet.equipment_id = fields[3].GetUInt32();
+ newModelEquipSet.equipement_id_prev = 0;
+ newModelEquipSet.modelid_prev = 0;
+
+ if(newModelEquipSet.equipment_id > 0)
+ {
+ if(!objmgr.GetEquipmentInfo(newModelEquipSet.equipment_id))
+ {
+ sLog.outErrorDb("Table `game_event_model_equip` have creature (Guid: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", guid, newModelEquipSet.equipment_id);
+ continue;
+ }
+ }
+
+ equiplist.push_back(std::pair<uint32, ModelEquip>(guid, newModelEquipSet));
+
+ } while( result->NextRow() );
+ sLog.outString();
+ sLog.outString( ">> Loaded %u model/equipment changes in game events", count );
+
+ delete result;
+ }
+
+ mGameEventQuests.resize(mGameEvent.size());
+ // 0 1 2
+ result = WorldDatabase.Query("SELECT id, quest, event FROM game_event_creature_quest");
+
+ count = 0;
+ if( !result )
+ {
+ barGoLink bar3(1);
+ bar3.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u quests additions in game events", count );
+ }
+ else
+ {
+
+ barGoLink bar3( result->GetRowCount() );
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar3.step();
+ uint32 id = fields[0].GetUInt32();
+ uint32 quest = fields[1].GetUInt32();
+ uint16 event_id = fields[2].GetUInt16();
+
+ if(event_id >= mGameEventQuests.size())
+ {
+ sLog.outErrorDb("`game_event_creature_quest` game event id (%u) is out of range compared to max event id in `game_event`",event_id);
+ continue;
+ }
+
+ ++count;
+ QuestRelList& questlist = mGameEventQuests[event_id];
+ questlist.push_back(QuestRelation(id, quest));
+
+ } while( result->NextRow() );
+ sLog.outString();
+ sLog.outString( ">> Loaded %u quests additions in game events", count );
+
+ delete result;
+ }
+}
+
+uint32 GameEvent::Initialize() // return the next event delay in ms
+{
+ m_ActiveEvents.clear();
+ uint32 delay = Update();
+ sLog.outBasic("Game Event system initialized." );
+ isSystemInit = true;
+ return delay;
+}
+
+uint32 GameEvent::Update() // return the next event delay in ms
+{
+ uint32 nextEventDelay = max_ge_check_delay; // 1 day
+ uint32 calcDelay;
+ for (uint16 itr = 1; itr < mGameEvent.size(); itr++)
+ {
+ //sLog.outErrorDb("Checking event %u",itr);
+ if (CheckOneGameEvent(itr))
+ {
+ //sLog.outDebug("GameEvent %u is active",itr->first);
+ if (!IsActiveEvent(itr))
+ StartEvent(itr);
+ }
+ else
+ {
+ //sLog.outDebug("GameEvent %u is not active",itr->first);
+ if (IsActiveEvent(itr))
+ StopEvent(itr);
+ else
+ {
+ if (!isSystemInit)
+ {
+ int16 event_nid = (-1) * (itr);
+ // spawn all negative ones for this event
+ GameEventSpawn(event_nid);
+ }
+ }
+ }
+ calcDelay = NextCheck(itr);
+ if (calcDelay < nextEventDelay)
+ nextEventDelay = calcDelay;
+ }
+ sLog.outBasic("Next game event check in %u seconds.", nextEventDelay + 1);
+ return (nextEventDelay + 1) * 1000; // Add 1 second to be sure event has started/stopped at next call
+}
+
+void GameEvent::UnApplyEvent(uint16 event_id)
+{
+ sLog.outString("GameEvent %u \"%s\" removed.", event_id, mGameEvent[event_id].description.c_str());
+ // un-spawn positive event tagged objects
+ GameEventUnspawn(event_id);
+ // spawn negative event tagget objects
+ int16 event_nid = (-1) * event_id;
+ GameEventSpawn(event_nid);
+ // restore equipment or model
+ ChangeEquipOrModel(event_id, false);
+ // Remove quests that are events only to non event npc
+ UpdateEventQuests(event_id, false);
+}
+
+void GameEvent::ApplyNewEvent(uint16 event_id)
+{
+ switch(sWorld.getConfig(CONFIG_EVENT_ANNOUNCE))
+ {
+ case 0: // disable
+ break;
+ case 1: // announce events
+ sWorld.SendWorldText(LANG_EVENTMESSAGE, mGameEvent[event_id].description.c_str());
+ break;
+ }
+
+ sLog.outString("GameEvent %u \"%s\" started.", event_id, mGameEvent[event_id].description.c_str());
+ // spawn positive event tagget objects
+ GameEventSpawn(event_id);
+ // un-spawn negative event tagged objects
+ int16 event_nid = (-1) * event_id;
+ GameEventUnspawn(event_nid);
+ // Change equipement or model
+ ChangeEquipOrModel(event_id, true);
+ // Add quests that are events only to non event npc
+ UpdateEventQuests(event_id, true);
+}
+
+void GameEvent::GameEventSpawn(int16 event_id)
+{
+ int32 internal_event_id = mGameEvent.size() + event_id - 1;
+
+ if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size())
+ {
+ sLog.outError("GameEvent::GameEventSpawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size());
+ return;
+ }
+
+ for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin();itr != mGameEventCreatureGuids[internal_event_id].end();++itr)
+ {
+ // Add to correct cell
+ CreatureData const* data = objmgr.GetCreatureData(*itr);
+ if (data)
+ {
+ objmgr.AddCreatureToGrid(*itr, data);
+
+ // Spawn if necessary (loaded grids only)
+ Map* map = const_cast<Map*>(MapManager::Instance().GetBaseMap(data->mapid));
+ // We use spawn coords to spawn
+ if(!map->Instanceable() && !map->IsRemovalGrid(data->posX,data->posY))
+ {
+ Creature* pCreature = new Creature;
+ //sLog.outDebug("Spawning creature %u",*itr);
+ if (!pCreature->LoadFromDB(*itr, map))
+ {
+ delete pCreature;
+ }
+ else
+ {
+ map->Add(pCreature);
+ }
+ }
+ }
+ }
+
+ if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size())
+ {
+ sLog.outError("GameEvent::GameEventSpawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size());
+ return;
+ }
+
+ for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin();itr != mGameEventGameobjectGuids[internal_event_id].end();++itr)
+ {
+ // Add to correct cell
+ GameObjectData const* data = objmgr.GetGOData(*itr);
+ if (data)
+ {
+ objmgr.AddGameobjectToGrid(*itr, data);
+ // Spawn if necessary (loaded grids only)
+ // this base map checked as non-instanced and then only existed
+ Map* map = const_cast<Map*>(MapManager::Instance().GetBaseMap(data->mapid));
+ // We use current coords to unspawn, not spawn coords since creature can have changed grid
+ if(!map->Instanceable() && !map->IsRemovalGrid(data->posX, data->posY))
+ {
+ GameObject* pGameobject = new GameObject;
+ //sLog.outDebug("Spawning gameobject %u", *itr);
+ if (!pGameobject->LoadFromDB(*itr, map))
+ {
+ delete pGameobject;
+ }
+ else
+ {
+ if(pGameobject->isSpawnedByDefault())
+ map->Add(pGameobject);
+ }
+ }
+ }
+ }
+}
+
+void GameEvent::GameEventUnspawn(int16 event_id)
+{
+ int32 internal_event_id = mGameEvent.size() + event_id - 1;
+
+ if(internal_event_id < 0 || internal_event_id >= mGameEventCreatureGuids.size())
+ {
+ sLog.outError("GameEvent::GameEventUnspawn attempt access to out of range mGameEventCreatureGuids element %i (size: %u)",internal_event_id,mGameEventCreatureGuids.size());
+ return;
+ }
+
+ for (GuidList::iterator itr = mGameEventCreatureGuids[internal_event_id].begin();itr != mGameEventCreatureGuids[internal_event_id].end();++itr)
+ {
+ // Remove the creature from grid
+ if( CreatureData const* data = objmgr.GetCreatureData(*itr) )
+ {
+ objmgr.RemoveCreatureFromGrid(*itr, data);
+
+ if( Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(*itr, data->id, HIGHGUID_UNIT), (Creature*)NULL) )
+ {
+ pCreature->CleanupsBeforeDelete();
+ pCreature->AddObjectToRemoveList();
+ }
+ }
+ }
+
+ if(internal_event_id < 0 || internal_event_id >= mGameEventGameobjectGuids.size())
+ {
+ sLog.outError("GameEvent::GameEventUnspawn attempt access to out of range mGameEventGameobjectGuids element %i (size: %u)",internal_event_id,mGameEventGameobjectGuids.size());
+ return;
+ }
+
+ for (GuidList::iterator itr = mGameEventGameobjectGuids[internal_event_id].begin();itr != mGameEventGameobjectGuids[internal_event_id].end();++itr)
+ {
+ // Remove the gameobject from grid
+ if(GameObjectData const* data = objmgr.GetGOData(*itr))
+ {
+ objmgr.RemoveGameobjectFromGrid(*itr, data);
+
+ if( GameObject* pGameobject = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(*itr, data->id, HIGHGUID_GAMEOBJECT), (GameObject*)NULL) )
+ pGameobject->AddObjectToRemoveList();
+ }
+ }
+}
+
+void GameEvent::ChangeEquipOrModel(int16 event_id, bool activate)
+{
+ for(ModelEquipList::iterator itr = mGameEventModelEquip[event_id].begin();itr != mGameEventModelEquip[event_id].end();++itr)
+ {
+ // Remove the creature from grid
+ CreatureData const* data = objmgr.GetCreatureData(itr->first);
+ if(!data)
+ continue;
+
+ // Update if spawned
+ Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(itr->first, data->id,HIGHGUID_UNIT), (Creature*)NULL);
+ if (pCreature)
+ {
+ if (activate)
+ {
+ itr->second.equipement_id_prev = pCreature->GetCurrentEquipmentId();
+ itr->second.modelid_prev = pCreature->GetDisplayId();
+ pCreature->LoadEquipment(itr->second.equipment_id, true);
+ if (itr->second.modelid >0 && itr->second.modelid_prev != itr->second.modelid)
+ {
+ CreatureModelInfo const *minfo = objmgr.GetCreatureModelInfo(itr->second.modelid);
+ if (minfo)
+ {
+ pCreature->SetDisplayId(itr->second.modelid);
+ pCreature->SetNativeDisplayId(itr->second.modelid);
+ pCreature->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS,minfo->bounding_radius);
+ pCreature->SetFloatValue(UNIT_FIELD_COMBATREACH,minfo->combat_reach );
+ }
+ }
+ }
+ else
+ {
+ pCreature->LoadEquipment(itr->second.equipement_id_prev, true);
+ if (itr->second.modelid_prev >0 && itr->second.modelid_prev != itr->second.modelid)
+ {
+ CreatureModelInfo const *minfo = objmgr.GetCreatureModelInfo(itr->second.modelid_prev);
+ if (minfo)
+ {
+ pCreature->SetDisplayId(itr->second.modelid_prev);
+ pCreature->SetNativeDisplayId(itr->second.modelid_prev);
+ pCreature->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS,minfo->bounding_radius);
+ pCreature->SetFloatValue(UNIT_FIELD_COMBATREACH,minfo->combat_reach );
+ }
+ }
+ }
+ }
+ else // If not spawned
+ {
+ CreatureData const* data = objmgr.GetCreatureData(itr->first);
+ if (data && activate)
+ {
+ CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(data->id);
+ uint32 display_id = objmgr.ChooseDisplayId(0,cinfo,data);
+ CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id);
+ if (minfo)
+ display_id = minfo->modelid;
+ if (data->equipmentId == 0)
+ itr->second.equipement_id_prev = cinfo->equipmentId;
+ else if (data->equipmentId != -1)
+ itr->second.equipement_id_prev = data->equipmentId;
+ itr->second.modelid_prev = display_id;
+ }
+ }
+ // now last step: put in data
+ // just to have write access to it
+ CreatureData& data2 = objmgr.NewOrExistCreatureData(itr->first);
+ if (activate)
+ {
+ data2.displayid = itr->second.modelid;
+ data2.equipmentId = itr->second.equipment_id;
+ }
+ else
+ {
+ data2.displayid = itr->second.modelid_prev;
+ data2.equipmentId = itr->second.equipement_id_prev;
+ }
+ }
+}
+
+void GameEvent::UpdateEventQuests(uint16 event_id, bool Activate)
+{
+ QuestRelList::iterator itr;
+ for (itr = mGameEventQuests[event_id].begin();itr != mGameEventQuests[event_id].end();++itr)
+ {
+ QuestRelations &CreatureQuestMap = objmgr.mCreatureQuestRelations;
+ if (Activate) // Add the pair(id,quest) to the multimap
+ CreatureQuestMap.insert(QuestRelations::value_type(itr->first, itr->second));
+ else
+ { // Remove the pair(id,quest) from the multimap
+ QuestRelations::iterator qitr = CreatureQuestMap.find(itr->first);
+ if (qitr == CreatureQuestMap.end())
+ continue;
+ QuestRelations::iterator lastElement = CreatureQuestMap.upper_bound(itr->first);
+ for ( ;qitr != lastElement;++qitr)
+ {
+ if (qitr->second == itr->second)
+ {
+ CreatureQuestMap.erase(qitr); // iterator is now no more valid
+ break; // but we can exit loop since the element is found
+ }
+ }
+ }
+ }
+}
+
+GameEvent::GameEvent()
+{
+ isSystemInit = false;
+}