diff --git a/src/common/Utilities/EventMap.cpp b/src/common/Utilities/EventMap.cpp
new file mode 100644
index 000000000..15a95829e
--- /dev/null
+++ b/src/common/Utilities/EventMap.cpp
@@ -0,0 +1,260 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 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 Affero General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+
+#include "EventMap.h"
+#include "Random.h"
+
+void EventMap::Reset()
+{
+ _eventMap.clear();
+ _time = 0;
+ _phase = 0;
+}
+
+void EventMap::SetPhase(uint8 phase)
+{
+ if (!phase)
+ {
+ _phase = 0;
+ }
+ else if (phase <= 8)
+ {
+ _phase = (1 << (phase - 1));
+ }
+}
+
+void EventMap::AddPhase(uint8 phase)
+{
+ if (phase && phase <= 8)
+ {
+ _phase |= (1 << (phase - 1));
+ }
+}
+
+void EventMap::RemovePhase(uint8 phase)
+{
+ if (phase && phase <= 8)
+ {
+ _phase &= ~(1 << (phase - 1));
+ }
+}
+
+void EventMap::ScheduleEvent(uint32 eventId, uint32 time, uint32 group /*= 0*/, uint32 phase /*= 0*/)
+{
+ if (group && group <= 8)
+ {
+ eventId |= (1 << (group + 15));
+ }
+
+ if (phase && phase <= 8)
+ {
+ eventId |= (1 << (phase + 23));
+ }
+
+ _eventMap.emplace(_time + time, eventId);
+}
+
+void EventMap::ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group /*= 0*/, uint8 phase /* = 0*/)
+{
+ ScheduleEvent(eventId, time.count(), group, phase);
+}
+
+void EventMap::ScheduleEvent(uint32 eventId, Milliseconds minTime, Milliseconds maxTime, uint32 group /*= 0*/, uint32 phase /*= 0*/)
+{
+ ScheduleEvent(eventId, randtime(minTime, maxTime).count(), group, phase);
+}
+
+void EventMap::RescheduleEvent(uint32 eventId, uint32 time, uint32 groupId /*= 0*/, uint32 phase/* = 0*/)
+{
+ CancelEvent(eventId);
+ ScheduleEvent(eventId, time, groupId, phase);
+}
+
+void EventMap::RescheduleEvent(uint32 eventId, Milliseconds time, uint32 group /*= 0*/, uint8 phase /* = 0*/)
+{
+ CancelEvent(eventId);
+ ScheduleEvent(eventId, time.count(), group, phase);
+}
+
+void EventMap::RescheduleEvent(uint32 eventId, Milliseconds minTime, Milliseconds maxTime, uint32 group /*= 0*/, uint32 phase /*= 0*/)
+{
+ CancelEvent(eventId);
+ ScheduleEvent(eventId, randtime(minTime, maxTime).count(), group, phase);
+}
+
+void EventMap::RepeatEvent(uint32 time)
+{
+ _eventMap.emplace(_time + time, _lastEvent);
+}
+
+void EventMap::Repeat(Milliseconds time)
+{
+ RepeatEvent(time.count());
+}
+
+uint32 EventMap::ExecuteEvent()
+{
+ while (!Empty())
+ {
+ auto const& itr = _eventMap.begin();
+
+ if (itr->first > _time)
+ {
+ return 0;
+ }
+ else if (_phase && (itr->second & 0xFF000000) && !((itr->second >> 24) & _phase))
+ {
+ _eventMap.erase(itr);
+ }
+ else
+ {
+ uint32 eventId = (itr->second & 0x0000FFFF);
+ _lastEvent = itr->second;
+ _eventMap.erase(itr);
+ return eventId;
+ }
+ }
+
+ return 0;
+}
+
+void EventMap::DelayEvents(uint32 delay)
+{
+ _time = delay < _time ? _time - delay : 0;
+}
+
+void EventMap::DelayEvents(Milliseconds delay)
+{
+ DelayEvents(delay.count());
+}
+
+void EventMap::DelayEvents(uint32 delay, uint32 group)
+{
+ if (group > 8 || Empty())
+ {
+ return;
+ }
+
+ EventStore delayed;
+
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (!group || (itr->second & (1 << (group + 15))))
+ {
+ delayed.insert(EventStore::value_type(itr->first + delay, itr->second));
+ itr = _eventMap.erase(itr);
+ continue;
+ }
+
+ ++itr;
+ }
+
+ _eventMap.insert(delayed.begin(), delayed.end());
+}
+
+void EventMap::DelayEventsToMax(uint32 delay, uint32 group)
+{
+ for (auto itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (itr->first < _time + delay && (group == 0 || ((1 << (group + 15)) & itr->second)))
+ {
+ ScheduleEvent(itr->second, delay);
+ _eventMap.erase(itr);
+ itr = _eventMap.begin();
+ continue;
+ }
+
+ ++itr;
+ }
+}
+
+void EventMap::CancelEvent(uint32 eventId)
+{
+ if (Empty())
+ {
+ return;
+ }
+
+ for (auto itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (eventId == (itr->second & 0x0000FFFF))
+ {
+ itr = _eventMap.erase(itr);
+ continue;
+ }
+
+ ++itr;
+ }
+}
+
+void EventMap::CancelEventGroup(uint32 group)
+{
+ if (!group || group > 8 || Empty())
+ {
+ return;
+ }
+
+ uint32 groupMask = (1 << (group + 15));
+ for (EventStore::iterator itr = _eventMap.begin(); itr != _eventMap.end();)
+ {
+ if (itr->second & groupMask)
+ {
+ _eventMap.erase(itr);
+ itr = _eventMap.begin();
+ continue;
+ }
+
+ ++itr;
+ }
+}
+
+uint32 EventMap::GetNextEventTime(uint32 eventId) const
+{
+ if (Empty())
+ {
+ return 0;
+ }
+
+ for (auto const& itr : _eventMap)
+ {
+ if (eventId == (itr.second & 0x0000FFFF))
+ {
+ return itr.first;
+ }
+ }
+
+ return 0;
+}
+
+uint32 EventMap::GetNextEventTime() const
+{
+ return Empty() ? 0 : _eventMap.begin()->first;
+}
+
+bool EventMap::IsInPhase(uint8 phase)
+{
+ return phase <= 8 && (!phase || _phase & (1 << (phase - 1)));
+}
+
+Milliseconds EventMap::GetTimeUntilEvent(uint32 eventId) const
+{
+ for (std::pair const& itr : _eventMap)
+ if (eventId == (itr.second & 0x0000FFFF))
+ return std::chrono::duration_cast(Milliseconds(itr.first) - Milliseconds(_time));
+
+ return Milliseconds::max();
+}
diff --git a/src/common/Utilities/EventMap.h b/src/common/Utilities/EventMap.h
new file mode 100644
index 000000000..45f97b15a
--- /dev/null
+++ b/src/common/Utilities/EventMap.h
@@ -0,0 +1,321 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 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 Affero General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+
+#ifndef _EVENT_MAP_H_
+#define _EVENT_MAP_H_
+
+#include "Define.h"
+#include "Duration.h"
+#include