diff --git a/src/game/Cell.h b/src/game/Cell.h
index 32dec55..e8b1da1 100644
--- a/src/game/Cell.h
+++ b/src/game/Cell.h
@@ -25,6 +25,7 @@
 #include <cmath>
 
 class Map;
+class WorldObject;
 
 enum District
 {
@@ -140,6 +141,7 @@ struct MANGOS_DLL_DECL Cell
     } data;
 
     template<class LOCK_TYPE, class T, class CONTAINER> void Visit(const CellLock<LOCK_TYPE> &, TypeContainerVisitor<T, CONTAINER> &visitor, Map &) const;
+    template<class LOCK_TYPE, class T, class CONTAINER> void Visit(const CellLock<LOCK_TYPE> &, TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, const WorldObject &obj, float radius) const;
 };
 
 template<class T>
diff --git a/src/game/CellImpl.h b/src/game/CellImpl.h
index 7302820..a72aefc 100644
--- a/src/game/CellImpl.h
+++ b/src/game/CellImpl.h
@@ -127,4 +127,70 @@ Cell::Visit(const CellLock<LOCK_TYPE> &l, TypeContainerVisitor<T, CONTAINER> &vi
         }
     }
 }
+
+template<class LOCK_TYPE, class T, class CONTAINER>
+inline void
+Cell::Visit(const CellLock<LOCK_TYPE> &l, TypeContainerVisitor<T, CONTAINER> &visitor, Map &m, const WorldObject &obj, float radius) const
+{
+    const CellPair &standing_cell = l.i_cellPair;
+    if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
+        return;
+
+    //no jokes here...
+    //ASSERT(radius);
+    if(radius <= 0.0f)
+    {
+        Visit(l, visitor, m);
+        return;
+    }
+
+    //lets calculate object coord offsets from cell borders
+    double x_offset = (double(obj.GetPositionX()) - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL;
+    double y_offset = (double(obj.GetPositionY()) - CENTER_GRID_CELL_OFFSET)/SIZE_OF_GRID_CELL;
+
+    int x_val = int(x_offset + CENTER_GRID_CELL_ID + 0.5);
+    int y_val = int(y_offset + CENTER_GRID_CELL_ID + 0.5);
+
+    const float x_off = (float(x_offset) - x_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL;
+    const float y_off = (float(y_offset) - y_val + CENTER_GRID_CELL_ID) * SIZE_OF_GRID_CELL;
+
+    int left = 0, right = 0, upper = 0, lower = 0;
+
+    if(CENTER_GRID_CELL_OFFSET - x_off < radius)
+        ++right;
+    if(CENTER_GRID_CELL_OFFSET + x_off < radius)
+        ++left;
+    if(CENTER_GRID_CELL_OFFSET - y_off < radius)
+        ++upper;
+    if(CENTER_GRID_CELL_OFFSET + y_off < radius)
+        ++lower;
+
+    if(!left && !right && !upper && !lower)
+    {
+        m.Visit(l, visitor);
+        return;
+    }
+
+    CellPair begin_cell = standing_cell;
+    CellPair end_cell = standing_cell;
+
+    begin_cell << left;
+    begin_cell -= lower;
+    end_cell >> right;
+    end_cell += upper;
+
+    // loop the cell range
+    for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; x++)
+    {
+        for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; y++)
+        {
+            CellPair cell_pair(x,y);
+            Cell r_zone(cell_pair);
+            r_zone.data.Part.nocreate = l->data.Part.nocreate;
+            CellLock<LOCK_TYPE> lock(r_zone, cell_pair);
+            m.Visit(lock, visitor);
+        }
+    }
+}
+
 #endif
diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp
index 89c6a75..8245361 100644
--- a/src/game/DynamicObject.cpp
+++ b/src/game/DynamicObject.cpp
@@ -120,8 +120,8 @@ void DynamicObject::Update(uint32 p_time)
     TypeContainerVisitor<MaNGOS::DynamicObjectUpdater, GridTypeMapContainer > grid_object_notifier(notifier);
 
     CellLock<GridReadGuard> cell_lock(cell, p);
-    cell_lock->Visit(cell_lock, world_object_notifier, *GetMap());
-    cell_lock->Visit(cell_lock, grid_object_notifier,  *GetMap());
+    cell_lock->Visit(cell_lock, world_object_notifier, *GetMap(), *this, GetRadius());
+    cell_lock->Visit(cell_lock, grid_object_notifier,  *GetMap(), *this, GetRadius());
 
     if(deleteThis)
     {
diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp
index 1aefbcb..77e3bd5 100644
--- a/src/game/GridNotifiers.cpp
+++ b/src/game/GridNotifiers.cpp
@@ -28,41 +28,44 @@
 using namespace MaNGOS;
 
 void
-MaNGOS::PlayerNotifier::Visit(PlayerMapType &m)
-{
-    for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
-    {
-        if( iter->getSource() == &i_player )
-            continue;
-
-        iter->getSource()->UpdateVisibilityOf(&i_player);
-        i_player.UpdateVisibilityOf(iter->getSource());
-    }
-}
-
-void
 VisibleChangesNotifier::Visit(PlayerMapType &m)
 {
+    if(i_object.isNotified(NOTIFIED_VISIBILITY))
+        return;
+
     for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
     {
-        if(iter->getSource() == &i_object)
+        Player * pl = iter->getSource();
+        if( pl == &i_object || pl->isNotified(NOTIFIED_VISIBILITY))
             continue;
 
-        iter->getSource()->UpdateVisibilityOf(&i_object);
+        pl->UpdateVisibilityOf(&i_object);
     }
 }
 
 void
 VisibleNotifier::Visit(PlayerMapType &m)
 {
+    if(i_player.isNotified(NOTIFIED_VISIBILITY))
+        return;
+
     for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
     {
-        if( iter->getSource() == &i_player )
+        Player * pl = iter->getSource();
+        if( pl == &i_player )
             continue;
 
-        iter->getSource()->UpdateVisibilityOf(&i_player);
-        i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_data_updates,i_visibleNow);
-        i_clientGUIDs.erase(iter->getSource()->GetGUID());
+        //since we removed PlayerNotifier we need
+        //player-player visibility code from there
+        if(!pl->isNotified(NOTIFIED_VISIBILITY))
+        {
+            pl->UpdateVisibilityOf(&i_player);
+            i_player.UpdateVisibilityOf(pl);
+        }
+
+        //pl->UpdateVisibilityOf(&i_player);
+        i_player.UpdateVisibilityOf(pl,i_data,i_data_updates,i_visibleNow);
+        i_clientGUIDs.erase(pl->GetGUID());
     }
 }
 
diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h
index ae34ed7..254a738 100644
--- a/src/game/GridNotifiers.h
+++ b/src/game/GridNotifiers.h
@@ -37,15 +37,6 @@ class Player;
 
 namespace MaNGOS
 {
-
-    struct MANGOS_DLL_DECL PlayerNotifier
-    {
-        explicit PlayerNotifier(Player &pl) : i_player(pl) {}
-        void Visit(PlayerMapType &);
-        template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
-        Player &i_player;
-    };
-
     struct MANGOS_DLL_DECL VisibleNotifier
     {
         Player &i_player;
@@ -188,6 +179,36 @@ namespace MaNGOS
         #endif
     };
 
+    struct MANGOS_DLL_DECL DelayedCreatureRelocation
+    {
+        typedef GridReadGuard ReadGuard;
+        Map &i_map;
+        CellLock<ReadGuard>& i_lock;
+        const float i_radius;
+        DelayedCreatureRelocation(CellLock<ReadGuard>& lock, Map &map, float radius) : i_lock(lock), i_map(map), i_radius(radius) {}
+        template<class T> void Visit(GridRefManager<T> &) {}
+        void Visit(CreatureMapType &);
+    };
+
+    struct MANGOS_DLL_DECL DelayedObjectVisibilityNotifier
+    {
+        typedef GridReadGuard ReadGuard;
+        Map &i_map;
+        CellLock<ReadGuard>& i_lock;
+        const float i_radius;
+        DelayedObjectVisibilityNotifier(CellLock<ReadGuard>& lock, Map &map, float radius) : i_lock(lock), i_map(map), i_radius(radius) {}
+        template<class T> void Visit(GridRefManager<T> &);
+        void Visit(PlayerMapType &) {}
+    };
+
+    struct MANGOS_DLL_DECL ResetNotifier
+    {
+        ResetNotifier() {}
+        template<class T> void Visit(GridRefManager<T> &) {}
+        void Visit(CreatureMapType &);
+        void Visit(PlayerMapType &);
+    };
+
     struct MANGOS_DLL_DECL DynamicObjectUpdater
     {
         DynamicObject &i_dynobject;
diff --git a/src/game/GridNotifiersImpl.h b/src/game/GridNotifiersImpl.h
index 583732a..b5007ba 100644
--- a/src/game/GridNotifiersImpl.h
+++ b/src/game/GridNotifiersImpl.h
@@ -31,10 +31,17 @@ template<class T>
 inline void
 MaNGOS::VisibleNotifier::Visit(GridRefManager<T> &m)
 {
+    if(i_player.isNotified(NOTIFIED_VISIBILITY))
+        return;
+
     for(typename GridRefManager<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
     {
-        i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_data_updates,i_visibleNow);
-        i_clientGUIDs.erase(iter->getSource()->GetGUID());
+        T * obj = iter->getSource();
+        if(!obj->isNotified(NOTIFIED_VISIBILITY))
+            i_player.UpdateVisibilityOf(obj);
+
+        i_player.UpdateVisibilityOf(obj,i_data,i_data_updates,i_visibleNow);
+        i_clientGUIDs.erase(obj->GetGUID());
     }
 }
 
@@ -49,6 +56,9 @@ MaNGOS::ObjectUpdater::Visit(CreatureMapType &m)
 inline void
 MaNGOS::PlayerRelocationNotifier::Visit(PlayerMapType &m)
 {
+    if(i_player.isNotified(NOTIFIED_RELOCATION))
+        return;
+
     for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
     {
         if(&i_player==iter->getSource())
@@ -66,9 +76,6 @@ MaNGOS::PlayerRelocationNotifier::Visit(PlayerMapType &m)
 
 inline void PlayerCreatureRelocationWorker(Player* pl, Creature* c)
 {
-    // update creature visibility at player/creature move
-    pl->UpdateVisibilityOf(c);
-
     // Creature AI reaction
     if(!c->hasUnitState(UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING))
     {
@@ -95,41 +102,100 @@ inline void CreatureCreatureRelocationWorker(Creature* c1, Creature* c2)
 inline void
 MaNGOS::PlayerRelocationNotifier::Visit(CreatureMapType &m)
 {
-    if(!i_player.isAlive() || i_player.isInFlight())
+    if(!i_player.isAlive() || i_player.isInFlight() || i_player.isNotified(NOTIFIED_RELOCATION))
         return;
 
     for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
-        if( iter->getSource()->isAlive())
-            PlayerCreatureRelocationWorker(&i_player,iter->getSource());
+    {
+        Creature * c = iter->getSource();
+        if(c->isAlive() && !c->isNotified(NOTIFIED_RELOCATION))
+            PlayerCreatureRelocationWorker(&i_player, c);
+    }
 }
 
 template<>
 inline void
 MaNGOS::CreatureRelocationNotifier::Visit(PlayerMapType &m)
 {
-    if(!i_creature.isAlive())
+    if(!i_creature.isAlive() || i_creature.isNotified(NOTIFIED_RELOCATION))
         return;
 
     for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
-        if( iter->getSource()->isAlive() && !iter->getSource()->isInFlight())
-            PlayerCreatureRelocationWorker(iter->getSource(), &i_creature);
+    {
+        Player * pl = iter->getSource();
+        if( pl->isAlive() && !pl->isInFlight() && !pl->isNotified(NOTIFIED_RELOCATION))
+            PlayerCreatureRelocationWorker(pl, &i_creature);
+    }
 }
 
 template<>
 inline void
 MaNGOS::CreatureRelocationNotifier::Visit(CreatureMapType &m)
 {
-    if(!i_creature.isAlive())
+    if(!i_creature.isAlive() || i_creature.isNotified(NOTIFIED_RELOCATION))
         return;
 
     for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
     {
         Creature* c = iter->getSource();
-        if( c != &i_creature && c->isAlive())
+        if( c != &i_creature && c->isAlive() && !c->isNotified(NOTIFIED_RELOCATION))
             CreatureCreatureRelocationWorker(c, &i_creature);
     }
 }
 
+inline void
+MaNGOS::DelayedCreatureRelocation::Visit(CreatureMapType &m)
+{
+    for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
+    {
+        Creature * _creature = iter->getSource();
+        if(!_creature->isAlive() || !_creature->isNeedNotify(NOTIFY_RELOCATION) || _creature->isNotified(NOTIFIED_RELOCATION))
+            continue;
+
+        CreatureRelocationNotifier relocate(*_creature);
+        TypeContainerVisitor<MaNGOS::CreatureRelocationNotifier, WorldTypeMapContainer > c2world_relocation(relocate);
+        TypeContainerVisitor<MaNGOS::CreatureRelocationNotifier, GridTypeMapContainer >  c2grid_relocation(relocate);
+
+        i_lock->Visit(i_lock, c2world_relocation, i_map, *_creature, i_radius);
+        i_lock->Visit(i_lock, c2grid_relocation, i_map, *_creature, i_radius);
+
+        _creature->SetNotified(NOTIFIED_RELOCATION);
+    }
+}
+
+template<class T>
+inline void		// i_object data to all nearby players
+MaNGOS::DelayedObjectVisibilityNotifier::Visit(GridRefManager<T> &m)
+{
+    for(typename GridRefManager<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
+    {
+        T * obj = iter->getSource();
+        if(!obj->isNeedNotify(NOTIFY_VISIBILITY) || obj->isNotified(NOTIFIED_VISIBILITY))
+            continue;
+
+        VisibleChangesNotifier notify(*obj);
+
+        TypeContainerVisitor<VisibleChangesNotifier, WorldTypeMapContainer > world_notifier(notify);
+        i_lock->Visit(i_lock, world_notifier, i_map, *obj, i_radius);
+
+        obj->SetNotified(NOTIFIED_VISIBILITY);
+    }
+}
+
+inline void
+MaNGOS::ResetNotifier::Visit(CreatureMapType &m)
+{
+    for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
+        iter->getSource()->ResetNotifies();
+}
+
+inline void
+MaNGOS::ResetNotifier::Visit(PlayerMapType &m)
+{
+    for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
+        iter->getSource()->ResetNotifies();
+}
+
 inline void MaNGOS::DynamicObjectUpdater::VisitHelper(Unit* target)
 {
     if(!target->isAlive() || target->isInFlight() )
diff --git a/src/game/Map.cpp b/src/game/Map.cpp
index 35b6c53..ce6a753 100644
--- a/src/game/Map.cpp
+++ b/src/game/Map.cpp
@@ -187,6 +187,7 @@ void Map::DeleteStateMachine()
 Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
   : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode),
   i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0),
+  m_VisibilityNotifyTimer(MAP_NOTIFY_DELAY), m_RelocationNotifyTimer(MAP_NOTIFY_DELAY * 1.5),
   m_activeNonPlayersIter(m_activeNonPlayers.end()),
   i_gridExpiry(expiry)
 {
@@ -303,7 +304,8 @@ void Map::AddNotifier(T* , Cell const& , CellPair const& )
 template<>
 void Map::AddNotifier(Player* obj, Cell const& cell, CellPair const& cellpair)
 {
-    PlayerRelocationNotify(obj,cell,cellpair);
+    //PlayerRelocationNotify(obj,cell,cellpair);
+    obj->ScheduleNotify(NOTIFY_RELOCATION);
 }
 
 template<>
@@ -411,8 +413,9 @@ bool Map::Add(Player *player)
     SendInitSelf(player);
     SendInitTransports(player);
 
-    UpdatePlayerVisibility(player,cell,p);
-    UpdateObjectsVisibilityFor(player,cell,p);
+    //UpdatePlayerVisibility(player,cell,p);
+    //UpdateObjectsVisibilityFor(player,cell,p);
+    player->ScheduleNotify(NOTIFY_VISIBILITY);
 
     AddNotifier(player,cell,p);
     return true;
@@ -517,7 +520,7 @@ void Map::MessageDistBroadcast(Player *player, WorldPacket *msg, float dist, boo
     MaNGOS::MessageDistDeliverer post_man(*player, msg, dist, to_self, own_team_only);
     TypeContainerVisitor<MaNGOS::MessageDistDeliverer , WorldTypeMapContainer > message(post_man);
     CellLock<ReadGuard> cell_lock(cell, p);
-    cell_lock->Visit(cell_lock, message, *this);
+    cell_lock->Visit(cell_lock, message, *this, *player, dist);
 }
 
 void Map::MessageDistBroadcast(WorldObject *obj, WorldPacket *msg, float dist)
@@ -537,10 +540,10 @@ void Map::MessageDistBroadcast(WorldObject *obj, WorldPacket *msg, float dist)
     if( !loaded(GridPair(cell.data.Part.grid_x, cell.data.Part.grid_y)) )
         return;
 
-    MaNGOS::ObjectMessageDistDeliverer post_man(*obj, msg,dist);
+    MaNGOS::ObjectMessageDistDeliverer post_man(*obj, msg, dist);
     TypeContainerVisitor<MaNGOS::ObjectMessageDistDeliverer, WorldTypeMapContainer > message(post_man);
     CellLock<ReadGuard> cell_lock(cell, p);
-    cell_lock->Visit(cell_lock, message, *this);
+    cell_lock->Visit(cell_lock, message, *this, *obj, dist);
 }
 
 bool Map::loaded(const GridPair &p) const
@@ -662,16 +665,367 @@ void Map::Update(const uint32 &t_diff)
 
     // Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load !
     // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
-    if (IsBattleGroundOrArena())
-        return;
+    if (IsBattleGroundOrArena() == false)
+    {
+        for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); )
+        {
+            NGridType *grid = i->getSource();
+            GridInfo *info = i->getSource()->getGridInfoRef();
+            ++i;                                                // The update might delete the map and we need the next map before the iterator gets invalid
+            assert(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE);
+            si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, grid->getX(), grid->getY(), t_diff);
+        }
+    }
 
-    for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); )
+    //lets update visibility and object reactions with some delay
+    if(CanNotifyVisibility(t_diff))
+        ProcessVisibilityNotifies();
+
+    //visibility and relocation notifiers delayed by
+    //(MAP_NOTIFY_DELAY / 2) msec between each other
+    if(CanNotifyRelocation(t_diff))
+    {
+        ProcessRelocationNotifies();
+        ResetNotifies();
+    }
+}
+
+//process timer for delayed aggro/visibility calculations
+bool Map::CanNotifyRelocation(const uint32& diff)
+{
+    if(m_RelocationNotifyTimer <= diff)
+    {
+        m_RelocationNotifyTimer = MAP_NOTIFY_DELAY;
+        return true;
+    }
+
+    m_RelocationNotifyTimer -= diff;
+    return false;
+}
+
+bool Map::CanNotifyVisibility(const uint32& diff)
+{
+    if(m_VisibilityNotifyTimer <= diff)
+    {
+        m_VisibilityNotifyTimer = MAP_NOTIFY_DELAY;
+        return true;
+    }
+
+    m_VisibilityNotifyTimer -= diff;
+    return false;
+}
+
+void Map::ProcessVisibilityNotifies()
+{
+    resetMarkedCells();
+
+    for(m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter)
+    {
+        Player* player = m_mapRefIter->getSource();
+        if(!player->IsInWorld())
+            continue;
+
+        CellPair standing_cell = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
+        // Check for correctness of standing_cell, it also avoids problems with update_cell
+        if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
+            continue;
+
+        if (player->isNeedNotify(NOTIFY_VISIBILITY))
+        {
+            UpdateObjectsVisibilityFor(player, Cell(standing_cell), standing_cell);
+            player->SetNotified(NOTIFY_VISIBILITY);
+        }
+
+        // the overloaded operators handle range checking
+        // so ther's no need for range checking inside the loop
+        CellPair begin_cell(standing_cell), end_cell(standing_cell);
+        begin_cell << 1; begin_cell -= 1;               // upper left
+        end_cell >> 1; end_cell += 1;                   // lower right
+
+        for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
+        {
+            for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
+            {
+                // marked cells are those that have been visited
+                // don't visit the same cell twice
+                uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+                if(!isCellMarked(cell_id))
+                {
+                    markCell(cell_id);
+                    CellPair pair(x,y);
+                    Cell cell(pair);
+                    cell.data.Part.reserved = CENTER_DISTRICT;
+                    cell.SetNoCreate();
+                    CellLock<ReadGuard> cell_lock(cell, pair);
+                    MaNGOS::DelayedObjectVisibilityNotifier cell_relocation(cell_lock, *this, sWorld.GetMaxVisibleDistanceForPlayer());
+                    TypeContainerVisitor<MaNGOS::DelayedObjectVisibilityNotifier, GridTypeMapContainer  > grid_object_relocation(cell_relocation);
+                    TypeContainerVisitor<MaNGOS::DelayedObjectVisibilityNotifier, WorldTypeMapContainer > world_object_relocation(cell_relocation);
+                    cell_lock->Visit(cell_lock, grid_object_relocation,  *this);
+                    cell_lock->Visit(cell_lock, world_object_relocation,  *this);
+                }
+            }
+        }
+    }
+
+    // non-player active objects
+    if(!m_activeNonPlayers.empty())
     {
-        NGridType *grid = i->getSource();
-        GridInfo *info = i->getSource()->getGridInfoRef();
-        ++i;                                                // The update might delete the map and we need the next map before the iterator gets invalid
-        assert(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE);
-        si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, grid->getX(), grid->getY(), t_diff);
+        for(m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end(); )
+        {
+            // skip not in world
+            WorldObject* obj = *m_activeNonPlayersIter;
+
+            // step before processing, in this case if Map::Remove remove next object we correctly
+            // step to next-next, and if we step to end() then newly added objects can wait next update.
+            ++m_activeNonPlayersIter;
+
+            if(!obj->IsInWorld())
+                continue;
+
+            CellPair standing_cell(MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()));
+
+            // Check for correctness of standing_cell, it also avoids problems with update_cell
+            if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
+                continue;
+
+            // the overloaded operators handle range checking
+            // so ther's no need for range checking inside the loop
+            CellPair begin_cell(standing_cell), end_cell(standing_cell);
+            begin_cell << 1; begin_cell -= 1;               // upper left
+            end_cell >> 1; end_cell += 1;                   // lower right
+
+            for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
+            {
+                for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
+                {
+                    // marked cells are those that have been visited
+                    // don't visit the same cell twice
+                    uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+                    if(!isCellMarked(cell_id))
+                    {
+                        markCell(cell_id);
+                        CellPair pair(x,y);
+                        Cell cell(pair);
+                        cell.data.Part.reserved = CENTER_DISTRICT;
+                        cell.SetNoCreate();
+                        CellLock<ReadGuard> cell_lock(cell, pair);
+                        MaNGOS::DelayedObjectVisibilityNotifier cell_relocation(cell_lock, *this, sWorld.GetMaxVisibleDistanceForPlayer());
+                        TypeContainerVisitor<MaNGOS::DelayedObjectVisibilityNotifier, GridTypeMapContainer  > grid_object_relocation(cell_relocation);
+                        TypeContainerVisitor<MaNGOS::DelayedObjectVisibilityNotifier, WorldTypeMapContainer > world_object_relocation(cell_relocation);
+                        cell_lock->Visit(cell_lock, grid_object_relocation,  *this);
+                        cell_lock->Visit(cell_lock, world_object_relocation,  *this);
+                    }
+                }
+            }
+        }
+    }
+}
+
+void Map::ProcessRelocationNotifies()
+{
+    resetMarkedCells();
+
+    for(m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter)
+    {
+        Player* player = m_mapRefIter->getSource();
+        if(!player->IsInWorld())
+            continue;
+
+        CellPair standing_cell = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
+        // Check for correctness of standing_cell, it also avoids problems with update_cell
+        if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
+            continue;
+
+        if (player->isNeedNotify(NOTIFY_RELOCATION))
+        {
+            PlayerRelocationNotify(player, Cell(standing_cell), standing_cell);
+            player->SetNotified(NOTIFY_RELOCATION);
+        }
+
+        // the overloaded operators handle range checking
+        // so ther's no need for range checking inside the loop
+        CellPair begin_cell(standing_cell), end_cell(standing_cell);
+        begin_cell << 1; begin_cell -= 1;               // upper left
+        end_cell >> 1; end_cell += 1;                   // lower right
+
+        for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
+        {
+            for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
+            {
+                // marked cells are those that have been visited
+                // don't visit the same cell twice
+                uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+                if(!isCellMarked(cell_id))
+                {
+                    markCell(cell_id);
+                    CellPair pair(x,y);
+                    Cell cell(pair);
+                    cell.data.Part.reserved = CENTER_DISTRICT;
+                    cell.SetNoCreate();
+                    CellLock<ReadGuard> cell_lock(cell, pair);
+                    MaNGOS::DelayedCreatureRelocation cell_relocation(cell_lock, *this, sWorld.GetMaxVisibleDistanceForCreature());
+                    TypeContainerVisitor<MaNGOS::DelayedCreatureRelocation, GridTypeMapContainer  > grid_object_relocation(cell_relocation);
+                    TypeContainerVisitor<MaNGOS::DelayedCreatureRelocation, WorldTypeMapContainer > world_object_relocation(cell_relocation);
+                    cell_lock->Visit(cell_lock, grid_object_relocation,  *this);
+                    cell_lock->Visit(cell_lock, world_object_relocation,  *this);
+                }
+            }
+        }
+    }
+
+    // non-player active objects
+    if(!m_activeNonPlayers.empty())
+    {
+        for(m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end(); )
+        {
+            // skip not in world
+            WorldObject* obj = *m_activeNonPlayersIter;
+
+            // step before processing, in this case if Map::Remove remove next object we correctly
+            // step to next-next, and if we step to end() then newly added objects can wait next update.
+            ++m_activeNonPlayersIter;
+
+            if(!obj->IsInWorld())
+                continue;
+
+            CellPair standing_cell(MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()));
+
+            // Check for correctness of standing_cell, it also avoids problems with update_cell
+            if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
+                continue;
+
+            // the overloaded operators handle range checking
+            // so ther's no need for range checking inside the loop
+            CellPair begin_cell(standing_cell), end_cell(standing_cell);
+            begin_cell << 1; begin_cell -= 1;               // upper left
+            end_cell >> 1; end_cell += 1;                   // lower right
+
+            for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
+            {
+                for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
+                {
+                    // marked cells are those that have been visited
+                    // don't visit the same cell twice
+                    uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+                    if(!isCellMarked(cell_id))
+                    {
+                        markCell(cell_id);
+                        CellPair pair(x,y);
+                        Cell cell(pair);
+                        cell.data.Part.reserved = CENTER_DISTRICT;
+                        cell.SetNoCreate();
+                        CellLock<ReadGuard> cell_lock(cell, pair);
+                        MaNGOS::DelayedCreatureRelocation cell_relocation(cell_lock, *this, sWorld.GetMaxVisibleDistanceForCreature());
+                        TypeContainerVisitor<MaNGOS::DelayedCreatureRelocation, GridTypeMapContainer  > grid_object_relocation(cell_relocation);
+                        TypeContainerVisitor<MaNGOS::DelayedCreatureRelocation, WorldTypeMapContainer > world_object_relocation(cell_relocation);
+                        cell_lock->Visit(cell_lock, grid_object_relocation,  *this);
+                        cell_lock->Visit(cell_lock, world_object_relocation,  *this);
+                    }
+                }
+            }
+        }
+    }
+}
+
+void Map::ResetNotifies()
+{
+    resetMarkedCells();
+
+    MaNGOS::ResetNotifier reset;
+
+    TypeContainerVisitor<MaNGOS::ResetNotifier, GridTypeMapContainer >  grid_notifier(reset);
+    TypeContainerVisitor<MaNGOS::ResetNotifier, WorldTypeMapContainer > world_notifier(reset);
+
+    for(m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter)
+    {
+        Player* player = m_mapRefIter->getSource();
+        if(!player->IsInWorld())
+            continue;
+
+        player->ResetNotifies();
+
+        CellPair standing_cell = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
+
+        // Check for correctness of standing_cell, it also avoids problems with update_cell
+        if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
+            continue;
+
+        // the overloaded operators handle range checking
+        // so ther's no need for range checking inside the loop
+        CellPair begin_cell(standing_cell), end_cell(standing_cell);
+        begin_cell << 1; begin_cell -= 1;               // upper left
+        end_cell >> 1; end_cell += 1;                   // lower right
+
+        for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
+        {
+            for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
+            {
+                // marked cells are those that have been visited
+                // don't visit the same cell twice
+                uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+                if(!isCellMarked(cell_id))
+                {
+                    markCell(cell_id);
+                    CellPair pair(x,y);
+                    Cell cell(pair);
+                    cell.data.Part.reserved = CENTER_DISTRICT;
+                    cell.SetNoCreate();
+                    CellLock<ReadGuard> cell_lock(cell, pair);
+                    cell_lock->Visit(cell_lock, grid_notifier,  *this);
+                    cell_lock->Visit(cell_lock, world_notifier,  *this);
+                }
+            }
+        }
+    }
+
+    // non-player active objects
+    if(!m_activeNonPlayers.empty())
+    {
+        for(m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end(); )
+        {
+            // skip not in world
+            WorldObject* obj = *m_activeNonPlayersIter;
+
+            // step before processing, in this case if Map::Remove remove next object we correctly
+            // step to next-next, and if we step to end() then newly added objects can wait next update.
+            ++m_activeNonPlayersIter;
+
+            if(!obj->IsInWorld())
+                continue;
+
+            CellPair standing_cell(MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()));
+
+            // Check for correctness of standing_cell, it also avoids problems with update_cell
+            if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
+                continue;
+
+            // the overloaded operators handle range checking
+            // so ther's no need for range checking inside the loop
+            CellPair begin_cell(standing_cell), end_cell(standing_cell);
+            begin_cell << 1; begin_cell -= 1;               // upper left
+            end_cell >> 1; end_cell += 1;                   // lower right
+
+            for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
+            {
+                for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
+                {
+                    // marked cells are those that have been visited
+                    // don't visit the same cell twice
+                    uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+                    if(!isCellMarked(cell_id))
+                    {
+                        markCell(cell_id);
+                        CellPair pair(x,y);
+                        Cell cell(pair);
+                        cell.data.Part.reserved = CENTER_DISTRICT;
+                        cell.SetNoCreate();
+                        CellLock<ReadGuard> cell_lock(cell, pair);
+                        cell_lock->Visit(cell_lock, grid_notifier,  *this);
+                        cell_lock->Visit(cell_lock, world_notifier,  *this);
+                    }
+                }
+            }
+        }
     }
 }
 
@@ -709,6 +1063,7 @@ void Map::Remove(Player *player, bool remove)
     NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
     assert(grid != NULL);
 
+    player->ResetNotifies();
     player->RemoveFromWorld();
     RemoveFromGrid(player,grid,cell);
 
@@ -755,6 +1110,7 @@ Map::Remove(T *obj, bool remove)
     if(obj->isActiveObject())
         RemoveFromActive(obj);
 
+    //obj->RemoveAllNotifies();
     obj->RemoveFromWorld();
     RemoveFromGrid(obj,grid,cell);
 
@@ -801,9 +1157,12 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati
     }
 
     // if move then update what player see and who seen
-    UpdatePlayerVisibility(player,new_cell,new_val);
-    UpdateObjectsVisibilityFor(player,new_cell,new_val);
-    PlayerRelocationNotify(player,new_cell,new_val);
+    //UpdatePlayerVisibility(player,new_cell,new_val);
+    //UpdateObjectsVisibilityFor(player,new_cell,new_val);
+
+    //PlayerRelocationNotify(player,new_cell,new_val);
+    player->ScheduleNotify(NOTIFY_RELOCATION | NOTIFY_VISIBILITY);
+
     NGridType* newGrid = getNGrid(new_cell.GridX(), new_cell.GridY());
     if( !same_cell && newGrid->GetGridState()!= GRID_STATE_ACTIVE )
     {
@@ -835,7 +1194,8 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang
     else
     {
         creature->Relocate(x, y, z, ang);
-        CreatureRelocationNotify(creature,new_cell,new_val);
+        creature->ScheduleNotify(NOTIFY_RELOCATION | NOTIFY_VISIBILITY);
+        //CreatureRelocationNotify(creature,new_cell,new_val);
     }
     assert(CheckGridIntegrity(creature,true));
 }
@@ -867,7 +1227,8 @@ void Map::MoveAllCreaturesInMoveList()
         {
             // update pos
             c->Relocate(cm.x, cm.y, cm.z, cm.ang);
-            CreatureRelocationNotify(c,new_cell,new_cell.cellPair());
+            c->ScheduleNotify(NOTIFY_RELOCATION | NOTIFY_VISIBILITY);
+            //CreatureRelocationNotify(c,new_cell,new_cell.cellPair());
         }
         else
         {
@@ -979,7 +1340,8 @@ bool Map::CreatureRespawnRelocation(Creature *c)
     {
         c->Relocate(resp_x, resp_y, resp_z, resp_o);
         c->GetMotionMaster()->Initialize();                 // prevent possible problems with default move generators
-        CreatureRelocationNotify(c,resp_cell,resp_cell.cellPair());
+        c->ScheduleNotify(NOTIFY_RELOCATION | NOTIFY_VISIBILITY);
+        //CreatureRelocationNotify(c,resp_cell,resp_cell.cellPair());
         return true;
     }
     else
@@ -1888,18 +2250,20 @@ void Map::UpdateObjectVisibility( WorldObject* obj, Cell cell, CellPair cellpair
     MaNGOS::VisibleChangesNotifier notifier(*obj);
     TypeContainerVisitor<MaNGOS::VisibleChangesNotifier, WorldTypeMapContainer > player_notifier(notifier);
     CellLock<GridReadGuard> cell_lock(cell, cellpair);
-    cell_lock->Visit(cell_lock, player_notifier, *this);
+    cell_lock->Visit(cell_lock, player_notifier, *this, *obj, sWorld.GetMaxVisibleDistanceForPlayer());
+
+    obj->SetNotified(NOTIFIED_VISIBILITY);
 }
 
 void Map::UpdatePlayerVisibility( Player* player, Cell cell, CellPair cellpair )
 {
-    cell.data.Part.reserved = ALL_DISTRICT;
+    //cell.data.Part.reserved = ALL_DISTRICT;
 
-    MaNGOS::PlayerNotifier pl_notifier(*player);
-    TypeContainerVisitor<MaNGOS::PlayerNotifier, WorldTypeMapContainer > player_notifier(pl_notifier);
+    //MaNGOS::PlayerNotifier pl_notifier(*player);
+    //TypeContainerVisitor<MaNGOS::PlayerNotifier, WorldTypeMapContainer > player_notifier(pl_notifier);
 
-    CellLock<ReadGuard> cell_lock(cell, cellpair);
-    cell_lock->Visit(cell_lock, player_notifier, *this);
+    //CellLock<ReadGuard> cell_lock(cell, cellpair);
+    //cell_lock->Visit(cell_lock, player_notifier, *this, *player, sWorld.GetMaxVisibleDistanceForPlayer());
 }
 
 void Map::UpdateObjectsVisibilityFor( Player* player, Cell cell, CellPair cellpair )
@@ -1911,9 +2275,10 @@ void Map::UpdateObjectsVisibilityFor( Player* player, Cell cell, CellPair cellpa
     TypeContainerVisitor<MaNGOS::VisibleNotifier, WorldTypeMapContainer > world_notifier(notifier);
     TypeContainerVisitor<MaNGOS::VisibleNotifier, GridTypeMapContainer  > grid_notifier(notifier);
     CellLock<GridReadGuard> cell_lock(cell, cellpair);
-    cell_lock->Visit(cell_lock, world_notifier, *this);
-    cell_lock->Visit(cell_lock, grid_notifier,  *this);
+    cell_lock->Visit(cell_lock, world_notifier, *this, *player, sWorld.GetMaxVisibleDistanceForPlayer());
+    cell_lock->Visit(cell_lock, grid_notifier,  *this, *player, sWorld.GetMaxVisibleDistanceForPlayer());
 
+    player->SetNotified(NOTIFIED_VISIBILITY);
     // send data
     notifier.Notify();
 }
@@ -1923,12 +2288,15 @@ void Map::PlayerRelocationNotify( Player* player, Cell cell, CellPair cellpair )
     CellLock<ReadGuard> cell_lock(cell, cellpair);
     MaNGOS::PlayerRelocationNotifier relocationNotifier(*player);
     cell.data.Part.reserved = ALL_DISTRICT;
+    //cell.SetNoCreate();
 
     TypeContainerVisitor<MaNGOS::PlayerRelocationNotifier, GridTypeMapContainer >  p2grid_relocation(relocationNotifier);
     TypeContainerVisitor<MaNGOS::PlayerRelocationNotifier, WorldTypeMapContainer > p2world_relocation(relocationNotifier);
 
-    cell_lock->Visit(cell_lock, p2grid_relocation, *this);
-    cell_lock->Visit(cell_lock, p2world_relocation, *this);
+    cell_lock->Visit(cell_lock, p2grid_relocation, *this, *player, sWorld.GetMaxVisibleDistanceForCreature());
+    cell_lock->Visit(cell_lock, p2world_relocation, *this, *player, sWorld.GetMaxVisibleDistanceForCreature());
+
+    player->SetNotified(NOTIFIED_RELOCATION);
 }
 
 void Map::CreatureRelocationNotify(Creature *creature, Cell cell, CellPair cellpair)
@@ -1941,8 +2309,10 @@ void Map::CreatureRelocationNotify(Creature *creature, Cell cell, CellPair cellp
     TypeContainerVisitor<MaNGOS::CreatureRelocationNotifier, WorldTypeMapContainer > c2world_relocation(relocationNotifier);
     TypeContainerVisitor<MaNGOS::CreatureRelocationNotifier, GridTypeMapContainer >  c2grid_relocation(relocationNotifier);
 
-    cell_lock->Visit(cell_lock, c2world_relocation, *this);
-    cell_lock->Visit(cell_lock, c2grid_relocation, *this);
+    cell_lock->Visit(cell_lock, c2world_relocation, *this, *creature, sWorld.GetMaxVisibleDistanceForCreature());
+    cell_lock->Visit(cell_lock, c2grid_relocation, *this, *creature, sWorld.GetMaxVisibleDistanceForCreature());
+
+    creature->SetNotified(NOTIFIED_RELOCATION);
 }
 
 void Map::SendInitSelf( Player * player )
diff --git a/src/game/Map.h b/src/game/Map.h
index a075531..e96ed3a 100644
--- a/src/game/Map.h
+++ b/src/game/Map.h
@@ -240,6 +240,7 @@ typedef UNORDERED_MAP<Creature*, CreatureMover> CreatureMoveList;
 #define MAX_HEIGHT            100000.0f                     // can be use for find ground height at surface
 #define INVALID_HEIGHT       -100000.0f                     // for check, must be equal to VMAP_INVALID_HEIGHT, real value for unknown height is VMAP_INVALID_HEIGHT_VALUE
 #define MIN_UNLOAD_DELAY      1                             // immediate unload
+#define MAP_NOTIFY_DELAY      1000                          // lets update player/mob relocation and visibility every 1000 msec
 
 class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::ObjectLevelLockable<Map, ACE_Thread_Mutex>
 {
@@ -407,6 +408,16 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
         void LoadMap(int gx,int gy, bool reload = false);
         GridMap *GetGrid(float x, float y);
 
+        //process timer for delayed aggro/visibility calculations
+        bool CanNotifyRelocation(const uint32& diff);
+        bool CanNotifyVisibility(const uint32& diff);
+
+        //these functions used to process player/mob aggro reactions and
+        //visibility calculations. Highly optimized for massive calculations
+        void ProcessRelocationNotifies();
+        void ProcessVisibilityNotifies();
+        void ResetNotifies();
+
         void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; }
         //uint64 CalculateGridMask(const uint32 &y) const;
 
@@ -453,6 +464,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
         uint32 i_id;
         uint32 i_InstanceId;
         uint32 m_unloadTimer;
+        uint32 m_RelocationNotifyTimer;
+        uint32 m_VisibilityNotifyTimer;
 
         MapRefManager m_mapRefManager;
         MapRefManager::iterator m_mapRefIter;
diff --git a/src/game/Object.cpp b/src/game/Object.cpp
index fc7826a..943675a 100644
--- a/src/game/Object.cpp
+++ b/src/game/Object.cpp
@@ -1051,6 +1051,8 @@ WorldObject::WorldObject()
     : m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL),
     m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f)
 {
+    m_notifyflags = 0;
+    m_executed_notifies = 0;
 }
 
 void WorldObject::CleanupsBeforeDelete()
diff --git a/src/game/Object.h b/src/game/Object.h
index aa53d62..df7290e 100644
--- a/src/game/Object.h
+++ b/src/game/Object.h
@@ -83,6 +83,20 @@ enum PhaseMasks
     PHASEMASK_ANYWHERE = 0xFFFFFFFF
 };
 
+enum NotifyFlags
+{
+    NOTIFY_NONE						= 0x00,
+    NOTIFY_RELOCATION				= 0x01,
+    NOTIFY_VISIBILITY		        = 0x02,
+    NOTIFY_ALL						= 0xFF
+};
+
+enum ExecutedNotifiers
+{
+    NOTIFIED_RELOCATION = 1,
+    NOTIFIED_VISIBILITY = 2
+};
+
 class WorldPacket;
 class UpdateData;
 class ByteBuffer;
@@ -481,6 +495,15 @@ class MANGOS_DLL_SPEC WorldObject : public Object
         // low level function for visibility change code, must be define in all main world object subclasses
         virtual bool isVisibleForInState(Player const* u, bool inVisibleList) const = 0;
 
+        //new relocation and visibility system functions
+        void ScheduleNotify(uint16 f) { m_notifyflags |= f;}
+        void RemoveFromNotify(uint16 f) { m_notifyflags &= ~f;}
+        bool isNeedNotify(uint16 f) const { return m_notifyflags & f;}
+
+        bool isNotified(uint16 f) const { return m_executed_notifies & f;}
+        void SetNotified(uint16 f) { m_executed_notifies |= f;}
+        void ResetNotifies() { m_executed_notifies = 0; m_executed_notifies = 0; }
+
         Map      * GetMap() const;
         Map const* GetBaseMap() const;
         Creature* SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime);
@@ -498,5 +521,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object
         float m_positionY;
         float m_positionZ;
         float m_orientation;
+
+        uint16 m_notifyflags;
+        uint16 m_executed_notifies;
 };
 #endif
