aboutsummaryrefslogtreecommitdiff
path: root/src/game/Map.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/Map.cpp')
-rw-r--r--src/game/Map.cpp1028
1 files changed, 948 insertions, 80 deletions
diff --git a/src/game/Map.cpp b/src/game/Map.cpp
index 6dbb0e37c86..47925102892 100644
--- a/src/game/Map.cpp
+++ b/src/game/Map.cpp
@@ -20,6 +20,7 @@
#include "MapManager.h"
#include "Player.h"
+#include "Vehicle.h"
#include "GridNotifiers.h"
#include "Log.h"
#include "GridStates.h"
@@ -36,6 +37,7 @@
#include "Group.h"
#include "MapRefManager.h"
#include "Vehicle.h"
+#include "WaypointManager.h"
#include "MapInstanced.h"
#include "InstanceSaveMgr.h"
@@ -46,9 +48,20 @@
GridState* si_GridStates[MAX_GRID_STATE];
+struct ScriptAction
+{
+ uint64 sourceGUID;
+ uint64 targetGUID;
+ uint64 ownerGUID; // owner of source if source is item
+ ScriptInfo const* script; // pointer to static script data
+};
+
Map::~Map()
{
UnloadAll();
+
+ if(!m_scriptSchedule.empty())
+ sWorld.DecreaseScheduledScriptCount(m_scriptSchedule.size());
}
bool Map::ExistMap(uint32 mapid,int gx,int gy)
@@ -127,14 +140,12 @@ void Map::LoadMap(int gx,int gy, bool reload)
if(GridMaps[gx][gy])
return;
- Map* baseMap = const_cast<Map*>(MapManager::Instance().CreateBaseMap(i_id));
-
// load grid map for base map
- if (!baseMap->GridMaps[gx][gy])
- baseMap->EnsureGridCreated(GridPair(63-gx,63-gy));
+ if (!m_parentMap->GridMaps[gx][gy])
+ m_parentMap->EnsureGridCreated(GridPair(63-gx,63-gy));
- ((MapInstanced*)(baseMap))->AddGridMapReference(GridPair(gx,gy));
- GridMaps[gx][gy] = baseMap->GridMaps[gx][gy];
+ ((MapInstanced*)(m_parentMap))->AddGridMapReference(GridPair(gx,gy));
+ GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy];
return;
}
@@ -144,7 +155,7 @@ void Map::LoadMap(int gx,int gy, bool reload)
//map already load, delete it before reloading (Is it necessary? Do we really need the ability the reload maps during runtime?)
if(GridMaps[gx][gy])
{
- sLog.outDetail("Unloading already loaded map %u before reloading.",i_id);
+ sLog.outDetail("Unloading already loaded map %u before reloading.",GetId());
delete (GridMaps[gx][gy]);
GridMaps[gx][gy]=NULL;
}
@@ -153,7 +164,7 @@ void Map::LoadMap(int gx,int gy, bool reload)
char *tmp=NULL;
int len = sWorld.GetDataPath().length()+strlen("maps/%03u%02u%02u.map")+1;
tmp = new char[len];
- snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),i_id,gx,gy);
+ snprintf(tmp, len, (char *)(sWorld.GetDataPath()+"maps/%03u%02u%02u.map").c_str(),GetId(),gx,gy);
sLog.outDetail("Loading map %s",tmp);
// loading data
GridMaps[gx][gy] = new GridMap();
@@ -187,11 +198,10 @@ void Map::DeleteStateMachine()
delete si_GridStates[GRID_STATE_REMOVAL];
}
-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),
+Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent)
+ : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId), m_unloadTimer(0),
m_activeNonPlayersIter(m_activeNonPlayers.end()),
- i_gridExpiry(expiry)
+ i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this)
, i_lock(true)
{
m_notifyTimer.SetInterval(IN_MILISECONDS/2);
@@ -364,6 +374,13 @@ void Map::DeleteFromWorld(T* obj)
delete obj;
}
+template<>
+void Map::DeleteFromWorld(Player* pl)
+{
+ ObjectAccessor::Instance().RemoveObject(pl);
+ delete pl;
+}
+
template<class T>
void Map::AddNotifier(T*)
{
@@ -393,7 +410,7 @@ Map::EnsureGridCreated(const GridPair &p)
Guard guard(*this);
if(!getNGrid(p.x_coord, p.y_coord))
{
- sLog.outDebug("Creating grid[%u,%u] for map %u instance %u", p.x_coord, p.y_coord, i_id, i_InstanceId);
+ sLog.outDebug("Creating grid[%u,%u] for map %u instance %u", p.x_coord, p.y_coord, GetId(), i_InstanceId);
setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld.getConfig(CONFIG_GRID_UNLOAD)),
p.x_coord, p.y_coord);
@@ -425,11 +442,11 @@ Map::EnsureGridLoadedAtEnter(const Cell &cell, Player *player)
if (player)
{
player->SendDelayResponse(MAX_GRID_LOAD_TIME);
- DEBUG_LOG("Player %s enter cell[%u,%u] triggers of loading grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), i_id);
+ DEBUG_LOG("Player %s enter cell[%u,%u] triggers of loading grid[%u,%u] on map %u", player->GetName(), cell.CellX(), cell.CellY(), cell.GridX(), cell.GridY(), GetId());
}
else
{
- DEBUG_LOG("Active object nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), i_id);
+ DEBUG_LOG("Active object nearby triggers of loading grid [%u,%u] on map %u", cell.GridX(), cell.GridY(), GetId());
}
ResetGridExpiry(*getNGrid(cell.GridX(), cell.GridY()), 0.1f);
@@ -450,7 +467,7 @@ bool Map::EnsureGridLoaded(const Cell &cell)
assert(grid != NULL);
if( !isGridObjectDataLoaded(cell.GridX(), cell.GridY()) )
{
- sLog.outDebug("Loading grid[%u,%u] for map %u instance %u", cell.GridX(), cell.GridY(), i_id, i_InstanceId);
+ sLog.outDebug("Loading grid[%u,%u] for map %u instance %u", cell.GridX(), cell.GridY(), GetId(), i_InstanceId);
ObjectGridLoader loader(*grid, this, cell);
loader.LoadN();
@@ -474,10 +491,8 @@ void Map::LoadGrid(float x, float y)
bool Map::Add(Player *player)
{
- player->GetMapRef().link(this, player);
-
- player->SetInstanceId(GetInstanceId());
-
+ // Check if we are adding to correct map
+ assert (player->GetMap() == this);
// update player state for other player and visa-versa
CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
Cell cell(p);
@@ -504,6 +519,8 @@ Map::Add(T *obj)
return;
}
+ obj->SetMap(this);
+
Cell cell(p);
if(obj->isActiveObject())
EnsureGridLoadedAtEnter(cell);
@@ -525,7 +542,6 @@ Map::Add(T *obj)
//also, trigger needs to cast spell, if not update, cannot see visual
//if(obj->GetTypeId() != TYPEID_UNIT)
UpdateObjectVisibility(obj,cell,p);
-
AddNotifier(obj);
}
@@ -633,12 +649,14 @@ void Map::AddUnitToNotify(Unit* u)
}
}
-void Map::RemoveUnitFromNotify(int32 slot)
+void Map::RemoveUnitFromNotify(Unit *unit, int32 slot)
{
if(i_lock)
{
- assert(slot < i_unitsToNotifyBacklog.size());
- i_unitsToNotifyBacklog[slot] = NULL;
+ if(slot < i_unitsToNotifyBacklog.size() && i_unitsToNotifyBacklog[slot] == unit)
+ i_unitsToNotifyBacklog[slot] = NULL;
+ else if(slot < i_unitsToNotify.size() && i_unitsToNotify[slot] == unit)
+ i_unitsToNotify[slot] = NULL;
}
else
{
@@ -774,37 +792,39 @@ 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;
-
- for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); )
+ if (!IsBattleGroundOrArena())
{
- 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(); )
+ {
+ 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);
+ }
}
+
+ ///- Process necessary scripts
+ if (!m_scriptSchedule.empty())
+ ScriptsProcess();
}
void Map::Remove(Player *player, bool remove)
{
- // this may be called during Map::Update
- // after decrement+unlink, ++m_mapRefIter will continue correctly
- // when the first element of the list is being removed
- // nocheck_prev will return the padding element of the RefManager
- // instead of NULL in the case of prev
- if(m_mapRefIter == player->GetMapRef())
- m_mapRefIter = m_mapRefIter->nocheck_prev();
- player->GetMapRef().unlink();
CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
{
+ if(remove)
+ player->CleanupsBeforeDelete();
+
// invalid coordinates
player->RemoveFromWorld();
if( remove )
+ {
+ player->ResetMap();
DeleteFromWorld(player);
+ }
return;
}
@@ -821,6 +841,9 @@ void Map::Remove(Player *player, bool remove)
NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
assert(grid != NULL);
+ if(remove)
+ player->CleanupsBeforeDelete();
+
player->RemoveFromWorld();
RemoveFromGrid(player,grid,cell);
@@ -870,6 +893,7 @@ Map::Remove(T *obj, bool remove)
UpdateObjectVisibility(obj,cell,p);
+ obj->ResetMap();
if( remove )
{
// if option set then object already saved at this moment
@@ -1010,7 +1034,6 @@ void Map::MoveAllCreaturesInMoveList()
if((sLog.getLogFilter() & LOG_FILTER_CREATURE_MOVES)==0)
sLog.outDebug("Creature (GUID: %u Entry: %u ) can't be move to unloaded respawn grid.",c->GetGUIDLow(),c->GetEntry());
#endif
- c->CleanupsBeforeDelete();
AddObjectToRemoveList(c);
}
}
@@ -1121,7 +1144,7 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool unloadAll)
if(!unloadAll && ActiveObjectsNearGrid(x, y) )
return false;
- sLog.outDebug("Unloading grid[%u,%u] for map %u", x,y, i_id);
+ sLog.outDebug("Unloading grid[%u,%u] for map %u", x,y, GetId());
ObjectGridUnloader unloader(*grid);
@@ -1167,13 +1190,29 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool unloadAll)
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gy, gx);
}
else
- ((MapInstanced*)(MapManager::Instance().CreateBaseMap(i_id)))->RemoveGridMapReference(GridPair(gx, gy));
+ ((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridPair(gx, gy));
+
GridMaps[gx][gy] = NULL;
}
- DEBUG_LOG("Unloading grid[%u,%u] for map %u finished", x,y, i_id);
+ DEBUG_LOG("Unloading grid[%u,%u] for map %u finished", x,y, GetId());
return true;
}
+void Map::RemoveAllPlayers()
+{
+ if(HavePlayers())
+ {
+ sLog.outError("Map::UnloadAll: there are still players in the instance at unload, should not happen!");
+
+ for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
+ {
+ Player* plr = itr->getSource();
+ if(!plr->IsBeingTeleportedFar())
+ plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation());
+ }
+ }
+}
+
void Map::UnloadAll()
{
// clear all delayed moves, useless anyway do this moves before map unload.
@@ -1297,11 +1336,11 @@ bool GridMap::loadHeihgtData(FILE *in, uint32 offset, uint32 size)
map_heightHeader header;
fseek(in, offset, SEEK_SET);
fread(&header, sizeof(header), 1, in);
- if (header.fourcc != uint32(MAP_HEIGTH_MAGIC))
+ if (header.fourcc != uint32(MAP_HEIGHT_MAGIC))
return false;
m_gridHeight = header.gridHeight;
- if (!(header.flags & MAP_HEIGHT_NO_HIGHT))
+ if (!(header.flags & MAP_HEIGHT_NO_HEIGHT))
{
if ((header.flags & MAP_HEIGHT_AS_INT16))
{
@@ -1350,12 +1389,12 @@ bool GridMap::loadLiquidData(FILE *in, uint32 offset, uint32 size)
m_liquid_height= header.height;
m_liquidLevel = header.liquidLevel;
- if (!(header.flags&MAP_LIQUID_NO_TYPE))
+ if (!(header.flags & MAP_LIQUID_NO_TYPE))
{
m_liquid_type = new uint8 [16*16];
fread(m_liquid_type, sizeof(uint8), 16*16, in);
}
- if (!(header.flags&MAP_LIQUID_NO_HIGHT))
+ if (!(header.flags & MAP_LIQUID_NO_HEIGHT))
{
m_liquid_map = new float [m_liquid_width*m_liquid_height];
fread(m_liquid_map, sizeof(float), m_liquid_width*m_liquid_height, in);
@@ -1792,7 +1831,7 @@ uint16 Map::GetAreaFlag(float x, float y, float z) const
areaflag = gmap->getArea(x, y);
// this used while not all *.map files generated (instances)
else
- areaflag = GetAreaFlagByMapId(i_id);
+ areaflag = GetAreaFlagByMapId(GetId());
//FIXME: some hacks for areas above or underground for ground area
// required for area specific spells/etc, until map/vmap data
@@ -1990,7 +2029,7 @@ void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 area
zoneid = entry ? (( entry->zone != 0 ) ? entry->zone : entry->ID) : 0;
}
-bool Map::IsInWater(float x, float y, float pZ) const
+bool Map::IsInWater(float x, float y, float pZ, float min_depth) const
{
// Check surface in x, y point for liquid
if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y))
@@ -1998,7 +2037,7 @@ bool Map::IsInWater(float x, float y, float pZ) const
LiquidData liquid_status;
if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, &liquid_status))
{
- if (liquid_status.level - liquid_status.depth_level > 2)
+ if (liquid_status.level - liquid_status.depth_level > min_depth)
return true;
}
}
@@ -2097,7 +2136,7 @@ void Map::SendInitTransports( Player * player )
for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i)
{
// send data for current transport in other place
- if((*i) != player->GetTransport() && (*i)->GetMapId()==i_id)
+ if((*i) != player->GetTransport() && (*i)->GetMapId()==GetId())
{
(*i)->BuildCreateUpdateBlockForPlayer(&transData, player);
}
@@ -2123,7 +2162,7 @@ void Map::SendRemoveTransports( Player * player )
// except used transport
for (MapManager::TransportSet::const_iterator i = tset.begin(); i != tset.end(); ++i)
- if((*i) != player->GetTransport() && (*i)->GetMapId()!=i_id)
+ if((*i) != player->GetTransport() && (*i)->GetMapId()!=GetId())
(*i)->BuildOutOfRangeUpdateBlock(&transData);
WorldPacket packet;
@@ -2151,6 +2190,8 @@ void Map::AddObjectToRemoveList(WorldObject *obj)
{
assert(obj->GetMapId()==GetId() && obj->GetInstanceId()==GetInstanceId());
+ obj->CleanupsBeforeDelete(); // remove or simplify at least cross referenced links
+
i_objectsToRemove.insert(obj);
//sLog.outDebug("Object (GUID: %u TypeId: %u ) added to removing list.",obj->GetGUIDLow(),obj->GetTypeId());
}
@@ -2326,8 +2367,8 @@ template void Map::Remove(DynamicObject *, bool);
/* ******* Dungeon Instance Maps ******* */
-InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
- : Map(id, expiry, InstanceId, SpawnMode),
+InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent)
+ : Map(id, expiry, InstanceId, SpawnMode, _parent),
m_resetAfterUnload(false), m_unloadWhenEmpty(false),
i_data(NULL), i_script_id(0)
{
@@ -2388,8 +2429,9 @@ bool InstanceMap::Add(Player *player)
{
Guard guard(*this);
- if(!CanEnter(player))
- return false;
+ // Check moved to void WorldSession::HandleMoveWorldportAckOpcode()
+ //if(!CanEnter(player))
+ //return false;
// Dungeon only code
if(IsDungeon())
@@ -2617,15 +2659,7 @@ void InstanceMap::PermBindAllPlayers(Player *player)
void InstanceMap::UnloadAll()
{
- if(HavePlayers())
- {
- sLog.outError("InstanceMap::UnloadAll: there are still players in the instance at unload, should not happen!");
- for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
- {
- Player* plr = itr->getSource();
- plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation());
- }
- }
+ assert(!HavePlayers());
if(m_resetAfterUnload == true)
objmgr.DeleteRespawnTimeForInstance(GetInstanceId());
@@ -2662,8 +2696,8 @@ uint32 InstanceMap::GetMaxPlayers() const
/* ******* Battleground Instance Maps ******* */
-BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId)
- : Map(id, expiry, InstanceId, DIFFICULTY_NORMAL)
+BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent)
+ : Map(id, expiry, InstanceId, DIFFICULTY_NORMAL, _parent)
{
}
@@ -2692,8 +2726,9 @@ bool BattleGroundMap::Add(Player * player)
{
{
Guard guard(*this);
- if(!CanEnter(player))
- return false;
+ //Check moved to void WorldSession::HandleMoveWorldportAckOpcode()
+ //if(!CanEnter(player))
+ //return false;
// reset instance validity, battleground maps do not homebind
player->m_InstanceValid = true;
}
@@ -2711,21 +2746,847 @@ void BattleGroundMap::SetUnload()
m_unloadTimer = MIN_UNLOAD_DELAY;
}
-void BattleGroundMap::UnloadAll()
+void BattleGroundMap::RemoveAllPlayers()
{
- while(HavePlayers())
+ if(HavePlayers())
{
- if(Player * plr = m_mapRefManager.getFirst()->getSource())
+ for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr)
{
- plr->TeleportTo(plr->GetBattleGroundEntryPoint());
- // TeleportTo removes the player from this map (if the map exists) -> calls BattleGroundMap::Remove -> invalidates the iterator.
- // just in case, remove the player from the list explicitly here as well to prevent a possible infinite loop
- // note that this remove is not needed if the code works well in other places
- plr->GetMapRef().unlink();
+ Player* plr = itr->getSource();
+ if(!plr->IsBeingTeleportedFar())
+ plr->TeleportTo(plr->GetBattleGroundEntryPoint());
}
}
+}
- Map::UnloadAll();
+/// Put scripts in the execution queue
+void Map::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target)
+{
+ ///- Find the script map
+ ScriptMapMap::const_iterator s = scripts.find(id);
+ if (s == scripts.end())
+ return;
+
+ // prepare static data
+ uint64 sourceGUID = source ? source->GetGUID() : (uint64)0; //some script commands doesn't have source
+ uint64 targetGUID = target ? target->GetGUID() : (uint64)0;
+ uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0;
+
+ ///- Schedule script execution for all scripts in the script map
+ ScriptMap const *s2 = &(s->second);
+ bool immedScript = false;
+ for (ScriptMap::const_iterator iter = s2->begin(); iter != s2->end(); ++iter)
+ {
+ ScriptAction sa;
+ sa.sourceGUID = sourceGUID;
+ sa.targetGUID = targetGUID;
+ sa.ownerGUID = ownerGUID;
+
+ sa.script = &iter->second;
+ m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(time_t(sWorld.GetGameTime() + iter->first), sa));
+ if (iter->first == 0)
+ immedScript = true;
+
+ sWorld.IncreaseScheduledScriptsCount();
+ }
+ ///- If one of the effects should be immediate, launch the script execution
+ if (/*start &&*/ immedScript)
+ ScriptsProcess();
+}
+
+void Map::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target)
+{
+ // NOTE: script record _must_ exist until command executed
+
+ // prepare static data
+ uint64 sourceGUID = source ? source->GetGUID() : (uint64)0;
+ uint64 targetGUID = target ? target->GetGUID() : (uint64)0;
+ uint64 ownerGUID = (source->GetTypeId()==TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : (uint64)0;
+
+ ScriptAction sa;
+ sa.sourceGUID = sourceGUID;
+ sa.targetGUID = targetGUID;
+ sa.ownerGUID = ownerGUID;
+
+ sa.script = &script;
+ m_scriptSchedule.insert(std::pair<time_t, ScriptAction>(time_t(sWorld.GetGameTime() + delay), sa));
+
+ sWorld.IncreaseScheduledScriptsCount();
+
+ ///- If effects should be immediate, launch the script execution
+ if(delay == 0)
+ ScriptsProcess();
+}
+
+/// Process queued scripts
+void Map::ScriptsProcess()
+{
+ if (m_scriptSchedule.empty())
+ return;
+
+ ///- Process overdue queued scripts
+ std::multimap<time_t, ScriptAction>::iterator iter = m_scriptSchedule.begin();
+ // ok as multimap is a *sorted* associative container
+ while (!m_scriptSchedule.empty() && (iter->first <= sWorld.GetGameTime()))
+ {
+ ScriptAction const& step = iter->second;
+
+ Object* source = NULL;
+
+ if(step.sourceGUID)
+ {
+ switch(GUID_HIPART(step.sourceGUID))
+ {
+ case HIGHGUID_ITEM:
+ // case HIGHGUID_CONTAINER: ==HIGHGUID_ITEM
+ {
+ Player* player = HashMapHolder<Player>::Find(step.ownerGUID);
+ if(player)
+ source = player->GetItemByGuid(step.sourceGUID);
+ break;
+ }
+ case HIGHGUID_UNIT:
+ source = HashMapHolder<Creature>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_PET:
+ source = HashMapHolder<Pet>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_VEHICLE:
+ source = HashMapHolder<Vehicle>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_PLAYER:
+ source = HashMapHolder<Player>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_GAMEOBJECT:
+ source = HashMapHolder<GameObject>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_CORPSE:
+ source = HashMapHolder<Corpse>::Find(step.sourceGUID);
+ break;
+ case HIGHGUID_MO_TRANSPORT:
+ for (MapManager::TransportSet::iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter)
+ {
+ if((*iter)->GetGUID() == step.sourceGUID)
+ {
+ source = reinterpret_cast<Object*>(*iter);
+ break;
+ }
+ }
+ break;
+ default:
+ sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.sourceGUID));
+ break;
+ }
+ }
+
+ //if(source && !source->IsInWorld()) source = NULL;
+
+ Object* target = NULL;
+
+ if(step.targetGUID)
+ {
+ switch(GUID_HIPART(step.targetGUID))
+ {
+ case HIGHGUID_UNIT:
+ target = HashMapHolder<Creature>::Find(step.targetGUID);
+ break;
+ case HIGHGUID_PET:
+ target = HashMapHolder<Pet>::Find(step.targetGUID);
+ break;
+ case HIGHGUID_VEHICLE:
+ target = HashMapHolder<Vehicle>::Find(step.targetGUID);
+ break;
+ case HIGHGUID_PLAYER: // empty GUID case also
+ target = HashMapHolder<Player>::Find(step.targetGUID);
+ break;
+ case HIGHGUID_GAMEOBJECT:
+ target = HashMapHolder<GameObject>::Find(step.targetGUID);
+ break;
+ case HIGHGUID_CORPSE:
+ target = HashMapHolder<Corpse>::Find(step.targetGUID);
+ break;
+ default:
+ sLog.outError("*_script source with unsupported high guid value %u",GUID_HIPART(step.targetGUID));
+ break;
+ }
+ }
+
+ //if(target && !target->IsInWorld()) target = NULL;
+
+ switch (step.script->command)
+ {
+ case SCRIPT_COMMAND_TALK:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_TALK call for NULL creature.");
+ break;
+ }
+
+ if(source->GetTypeId()!=TYPEID_UNIT)
+ {
+ sLog.outError("SCRIPT_COMMAND_TALK call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+ if(step.script->datalong > 3)
+ {
+ sLog.outError("SCRIPT_COMMAND_TALK invalid chat type (%u), skipping.",step.script->datalong);
+ break;
+ }
+
+ uint64 unit_target = target ? target->GetGUID() : 0;
+
+ //datalong 0=normal say, 1=whisper, 2=yell, 3=emote text
+ switch(step.script->datalong)
+ {
+ case 0: // Say
+ ((Creature *)source)->Say(step.script->dataint, LANG_UNIVERSAL, unit_target);
+ break;
+ case 1: // Whisper
+ if(!unit_target)
+ {
+ sLog.outError("SCRIPT_COMMAND_TALK attempt to whisper (%u) NULL, skipping.",step.script->datalong);
+ break;
+ }
+ ((Creature *)source)->Whisper(step.script->dataint,unit_target);
+ break;
+ case 2: // Yell
+ ((Creature *)source)->Yell(step.script->dataint, LANG_UNIVERSAL, unit_target);
+ break;
+ case 3: // Emote text
+ ((Creature *)source)->TextEmote(step.script->dataint, unit_target);
+ break;
+ default:
+ break; // must be already checked at load
+ }
+ break;
+ }
+
+ case SCRIPT_COMMAND_EMOTE:
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_EMOTE call for NULL creature.");
+ break;
+ }
+
+ if(source->GetTypeId()!=TYPEID_UNIT)
+ {
+ sLog.outError("SCRIPT_COMMAND_EMOTE call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ ((Creature *)source)->HandleEmoteCommand(step.script->datalong);
+ break;
+ case SCRIPT_COMMAND_FIELD_SET:
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_FIELD_SET call for NULL object.");
+ break;
+ }
+ if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
+ {
+ sLog.outError("SCRIPT_COMMAND_FIELD_SET call for wrong field %u (max count: %u) in object (TypeId: %u).",
+ step.script->datalong,source->GetValuesCount(),source->GetTypeId());
+ break;
+ }
+
+ source->SetUInt32Value(step.script->datalong, step.script->datalong2);
+ break;
+ case SCRIPT_COMMAND_MOVE_TO:
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_MOVE_TO call for NULL creature.");
+ break;
+ }
+
+ if(source->GetTypeId()!=TYPEID_UNIT)
+ {
+ sLog.outError("SCRIPT_COMMAND_MOVE_TO call for non-creature (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+ ((Creature*)source)->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->datalong2 );
+ ((Creature*)source)->GetMap()->CreatureRelocation(((Creature*)source), step.script->x, step.script->y, step.script->z, 0);
+ break;
+ case SCRIPT_COMMAND_FLAG_SET:
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_FLAG_SET call for NULL object.");
+ break;
+ }
+ if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
+ {
+ sLog.outError("SCRIPT_COMMAND_FLAG_SET call for wrong field %u (max count: %u) in object (TypeId: %u).",
+ step.script->datalong,source->GetValuesCount(),source->GetTypeId());
+ break;
+ }
+
+ source->SetFlag(step.script->datalong, step.script->datalong2);
+ break;
+ case SCRIPT_COMMAND_FLAG_REMOVE:
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for NULL object.");
+ break;
+ }
+ if(step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= source->GetValuesCount())
+ {
+ sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE call for wrong field %u (max count: %u) in object (TypeId: %u).",
+ step.script->datalong,source->GetValuesCount(),source->GetTypeId());
+ break;
+ }
+
+ source->RemoveFlag(step.script->datalong, step.script->datalong2);
+ break;
+
+ case SCRIPT_COMMAND_TELEPORT_TO:
+ {
+ // accept player in any one from target/source arg
+ if (!target && !source)
+ {
+ sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for NULL object.");
+ break;
+ }
+
+ // must be only Player
+ if((!target || target->GetTypeId() != TYPEID_PLAYER) && (!source || source->GetTypeId() != TYPEID_PLAYER))
+ {
+ sLog.outError("SCRIPT_COMMAND_TELEPORT_TO call for non-player (TypeIdSource: %u)(TypeIdTarget: %u), skipping.", source ? source->GetTypeId() : 0, target ? target->GetTypeId() : 0);
+ break;
+ }
+
+ Player* pSource = target && target->GetTypeId() == TYPEID_PLAYER ? (Player*)target : (Player*)source;
+
+ pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o);
+ break;
+ }
+
+ case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
+ {
+ if(!step.script->datalong) // creature not specified
+ {
+ sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL creature.");
+ break;
+ }
+
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for NULL world object.");
+ break;
+ }
+
+ WorldObject* summoner = dynamic_cast<WorldObject*>(source);
+
+ if(!summoner)
+ {
+ sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON_CREATURE call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ float x = step.script->x;
+ float y = step.script->y;
+ float z = step.script->z;
+ float o = step.script->o;
+
+ Creature* pCreature = summoner->SummonCreature(step.script->datalong, x, y, z, o,TEMPSUMMON_TIMED_OR_DEAD_DESPAWN,step.script->datalong2);
+ if (!pCreature)
+ {
+ sLog.outError("SCRIPT_COMMAND_TEMP_SUMMON failed for creature (entry: %u).",step.script->datalong);
+ break;
+ }
+
+ break;
+ }
+
+ case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
+ {
+ if(!step.script->datalong) // gameobject not specified
+ {
+ sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL gameobject.");
+ break;
+ }
+
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for NULL world object.");
+ break;
+ }
+
+ WorldObject* summoner = dynamic_cast<WorldObject*>(source);
+
+ if(!summoner)
+ {
+ sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT call for non-WorldObject (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ GameObject *go = NULL;
+ int32 time_to_despawn = step.script->datalong2<5 ? 5 : (int32)step.script->datalong2;
+
+ CellPair p(MaNGOS::ComputeCellPair(summoner->GetPositionX(), summoner->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+
+ MaNGOS::GameObjectWithDbGUIDCheck go_check(*summoner,step.script->datalong);
+ MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(summoner, go,go_check);
+
+ TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, object_checker, *summoner->GetMap());
+
+ if ( !go )
+ {
+ sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT failed for gameobject(guid: %u).", step.script->datalong);
+ break;
+ }
+
+ if( go->GetGoType()==GAMEOBJECT_TYPE_FISHINGNODE ||
+ go->GetGoType()==GAMEOBJECT_TYPE_DOOR ||
+ go->GetGoType()==GAMEOBJECT_TYPE_BUTTON ||
+ go->GetGoType()==GAMEOBJECT_TYPE_TRAP )
+ {
+ sLog.outError("SCRIPT_COMMAND_RESPAWN_GAMEOBJECT can not be used with gameobject of type %u (guid: %u).", uint32(go->GetGoType()), step.script->datalong);
+ break;
+ }
+
+ if( go->isSpawned() )
+ break; //gameobject already spawned
+
+ go->SetLootState(GO_READY);
+ go->SetRespawnTime(time_to_despawn); //despawn object in ? seconds
+
+ go->GetMap()->Add(go);
+ break;
+ }
+ case SCRIPT_COMMAND_OPEN_DOOR:
+ {
+ if(!step.script->datalong) // door not specified
+ {
+ sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL door.");
+ break;
+ }
+
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for NULL unit.");
+ break;
+ }
+
+ if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player)
+ {
+ sLog.outError("SCRIPT_COMMAND_OPEN_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ Unit* caster = (Unit*)source;
+
+ GameObject *door = NULL;
+ int32 time_to_close = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2;
+
+ CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+
+ MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
+ MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check);
+
+ TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, object_checker, *caster->GetMap());
+
+ if (!door)
+ {
+ sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for gameobject(guid: %u).", step.script->datalong);
+ break;
+ }
+ if (door->GetGoType() != GAMEOBJECT_TYPE_DOOR)
+ {
+ sLog.outError("SCRIPT_COMMAND_OPEN_DOOR failed for non-door(GoType: %u).", door->GetGoType());
+ break;
+ }
+
+ if (door->GetGoState() != GO_STATE_READY)
+ break; //door already open
+
+ door->UseDoorOrButton(time_to_close);
+
+ if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON)
+ ((GameObject*)target)->UseDoorOrButton(time_to_close);
+ break;
+ }
+ case SCRIPT_COMMAND_CLOSE_DOOR:
+ {
+ if(!step.script->datalong) // guid for door not specified
+ {
+ sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL door.");
+ break;
+ }
+
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for NULL unit.");
+ break;
+ }
+
+ if(!source->isType(TYPEMASK_UNIT)) // must be any Unit (creature or player)
+ {
+ sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR call for non-unit (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ Unit* caster = (Unit*)source;
+
+ GameObject *door = NULL;
+ int32 time_to_open = step.script->datalong2 < 15 ? 15 : (int32)step.script->datalong2;
+
+ CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+
+ MaNGOS::GameObjectWithDbGUIDCheck go_check(*caster,step.script->datalong);
+ MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck> checker(caster,door,go_check);
+
+ TypeContainerVisitor<MaNGOS::GameObjectSearcher<MaNGOS::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > object_checker(checker);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, object_checker, *caster->GetMap());
+
+ if ( !door )
+ {
+ sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for gameobject(guid: %u).", step.script->datalong);
+ break;
+ }
+ if ( door->GetGoType() != GAMEOBJECT_TYPE_DOOR )
+ {
+ sLog.outError("SCRIPT_COMMAND_CLOSE_DOOR failed for non-door(GoType: %u).", door->GetGoType());
+ break;
+ }
+
+ if( door->GetGoState() == GO_STATE_READY )
+ break; //door already closed
+
+ door->UseDoorOrButton(time_to_open);
+
+ if(target && target->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)target)->GetGoType()==GAMEOBJECT_TYPE_BUTTON)
+ ((GameObject*)target)->UseDoorOrButton(time_to_open);
+
+ break;
+ }
+ case SCRIPT_COMMAND_QUEST_EXPLORED:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL source.");
+ break;
+ }
+
+ if(!target)
+ {
+ sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for NULL target.");
+ break;
+ }
+
+ // when script called for item spell casting then target == (unit or GO) and source is player
+ WorldObject* worldObject;
+ Player* player;
+
+ if(target->GetTypeId()==TYPEID_PLAYER)
+ {
+ if(source->GetTypeId()!=TYPEID_UNIT && source->GetTypeId()!=TYPEID_GAMEOBJECT)
+ {
+ sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ worldObject = (WorldObject*)source;
+ player = (Player*)target;
+ }
+ else
+ {
+ if(target->GetTypeId()!=TYPEID_UNIT && target->GetTypeId()!=TYPEID_GAMEOBJECT)
+ {
+ sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-creature and non-gameobject (TypeId: %u), skipping.",target->GetTypeId());
+ break;
+ }
+
+ if(source->GetTypeId()!=TYPEID_PLAYER)
+ {
+ sLog.outError("SCRIPT_COMMAND_QUEST_EXPLORED call for non-player(TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ worldObject = (WorldObject*)target;
+ player = (Player*)source;
+ }
+
+ // quest id and flags checked at script loading
+ if( (worldObject->GetTypeId()!=TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) &&
+ (step.script->datalong2==0 || worldObject->IsWithinDistInMap(player,float(step.script->datalong2))) )
+ player->AreaExploredOrEventHappens(step.script->datalong);
+ else
+ player->FailQuest(step.script->datalong);
+
+ break;
+ }
+
+ case SCRIPT_COMMAND_ACTIVATE_OBJECT:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT must have source caster.");
+ break;
+ }
+
+ if(!source->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT source caster isn't unit (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ if(!target)
+ {
+ sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for NULL gameobject.");
+ break;
+ }
+
+ if(target->GetTypeId()!=TYPEID_GAMEOBJECT)
+ {
+ sLog.outError("SCRIPT_COMMAND_ACTIVATE_OBJECT call for non-gameobject (TypeId: %u), skipping.",target->GetTypeId());
+ break;
+ }
+
+ Unit* caster = (Unit*)source;
+
+ GameObject *go = (GameObject*)target;
+
+ go->Use(caster);
+ break;
+ }
+
+ case SCRIPT_COMMAND_REMOVE_AURA:
+ {
+ Object* cmdTarget = step.script->datalong2 ? source : target;
+
+ if(!cmdTarget)
+ {
+ sLog.outError("SCRIPT_COMMAND_REMOVE_AURA call for NULL %s.",step.script->datalong2 ? "source" : "target");
+ break;
+ }
+
+ if(!cmdTarget->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_REMOVE_AURA %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 ? "source" : "target",cmdTarget->GetTypeId());
+ break;
+ }
+
+ ((Unit*)cmdTarget)->RemoveAurasDueToSpell(step.script->datalong);
+ break;
+ }
+
+ case SCRIPT_COMMAND_CAST_SPELL:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL must have source caster.");
+ break;
+ }
+
+ Object* cmdTarget = step.script->datalong2 & 0x01 ? source : target;
+
+ if(!cmdTarget)
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x01 ? "source" : "target");
+ break;
+ }
+
+ if(!cmdTarget->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x01 ? "source" : "target",cmdTarget->GetTypeId());
+ break;
+ }
+
+ Unit* spellTarget = (Unit*)cmdTarget;
+
+ Object* cmdSource = step.script->datalong2 & 0x02 ? target : source;
+
+ if(!cmdSource)
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL call for NULL %s.",step.script->datalong2 & 0x02 ? "target" : "source");
+ break;
+ }
+
+ if(!cmdSource->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_CAST_SPELL %s isn't unit (TypeId: %u), skipping.",step.script->datalong2 & 0x02 ? "target" : "source", cmdSource->GetTypeId());
+ break;
+ }
+
+ Unit* spellSource = (Unit*)cmdSource;
+
+ //TODO: when GO cast implemented, code below must be updated accordingly to also allow GO spell cast
+ spellSource->CastSpell(spellTarget,step.script->datalong,false);
+
+ break;
+ }
+
+ case SCRIPT_COMMAND_LOAD_PATH:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_START_MOVE is tried to apply to NON-existing unit.");
+ break;
+ }
+
+ if(!source->isType(TYPEMASK_UNIT))
+ {
+ sLog.outError("SCRIPT_COMMAND_START_MOVE source mover isn't unit (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ if(!WaypointMgr.GetPath(step.script->datalong))
+ {
+ sLog.outError("SCRIPT_COMMAND_START_MOVE source mover has an invallid path, skipping.", step.script->datalong2);
+ break;
+ }
+
+ dynamic_cast<Unit*>(source)->GetMotionMaster()->MovePath(step.script->datalong, step.script->datalong2);
+ break;
+ }
+
+ case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT:
+ {
+ if(!step.script->datalong || !step.script->datalong2)
+ {
+ sLog.outError("SCRIPT_COMMAND_CALLSCRIPT calls invallid db_script_id or lowguid not present: skipping.");
+ break;
+ }
+ //our target
+ Creature* target = NULL;
+
+ if(source) //using grid searcher
+ {
+ CellPair p(Trinity::ComputeCellPair(((Unit*)source)->GetPositionX(), ((Unit*)source)->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+
+ //sLog.outDebug("Attempting to find Creature: Db GUID: %i", step.script->datalong);
+ Trinity::CreatureWithDbGUIDCheck target_check(((Unit*)source), step.script->datalong);
+ Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(((Unit*)source), target, target_check);
+
+ TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, unit_checker, *(((Unit*)source)->GetMap()));
+ }
+ else //check hashmap holders
+ {
+ if(CreatureData const* data = objmgr.GetCreatureData(step.script->datalong))
+ target = ObjectAccessor::GetObjectInWorld<Creature>(data->mapid, data->posX, data->posY, MAKE_NEW_GUID(step.script->datalong, data->id, HIGHGUID_UNIT), target);
+ }
+ //sLog.outDebug("attempting to pass target...");
+ if(!target)
+ break;
+ //sLog.outDebug("target passed");
+ //Lets choose our ScriptMap map
+ ScriptMapMap *datamap = NULL;
+ switch(step.script->dataint)
+ {
+ case 1://QUEST END SCRIPTMAP
+ datamap = &sQuestEndScripts;
+ break;
+ case 2://QUEST START SCRIPTMAP
+ datamap = &sQuestStartScripts;
+ break;
+ case 3://SPELLS SCRIPTMAP
+ datamap = &sSpellScripts;
+ break;
+ case 4://GAMEOBJECTS SCRIPTMAP
+ datamap = &sGameObjectScripts;
+ break;
+ case 5://EVENTS SCRIPTMAP
+ datamap = &sEventScripts;
+ break;
+ case 6://WAYPOINTS SCRIPTMAP
+ datamap = &sWaypointScripts;
+ break;
+ default:
+ sLog.outError("SCRIPT_COMMAND_CALLSCRIPT ERROR: no scriptmap present... ignoring");
+ break;
+ }
+ //if no scriptmap present...
+ if(!datamap)
+ break;
+
+ uint32 script_id = step.script->datalong2;
+ //insert script into schedule but do not start it
+ ScriptsStart(*datamap, script_id, target, NULL/*, false*/);
+ break;
+ }
+
+ case SCRIPT_COMMAND_KILL:
+ {
+ if(!source || ((Creature*)source)->isDead())
+ break;
+
+ ((Creature*)source)->DealDamage(((Creature*)source), ((Creature*)source)->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+
+ switch(step.script->dataint)
+ {
+ case 0: break; //return false not remove corpse
+ case 1: ((Creature*)source)->RemoveCorpse(); break;
+ }
+ break;
+ }
+
+ case SCRIPT_COMMAND_PLAY_SOUND:
+ {
+ if(!source)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for NULL creature.");
+ break;
+ }
+
+ WorldObject* pSource = dynamic_cast<WorldObject*>(source);
+ if(!pSource)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND call for non-world object (TypeId: %u), skipping.",source->GetTypeId());
+ break;
+ }
+
+ // bitmask: 0/1=anyone/target, 0/2=with distance dependent
+ Player* pTarget = NULL;
+ if(step.script->datalong2 & 1)
+ {
+ if(!target)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for NULL target.");
+ break;
+ }
+
+ if(target->GetTypeId()!=TYPEID_PLAYER)
+ {
+ sLog.outError("SCRIPT_COMMAND_PLAY_SOUND in targeted mode call for non-player (TypeId: %u), skipping.",target->GetTypeId());
+ break;
+ }
+
+ pTarget = (Player*)target;
+ }
+
+ // bitmask: 0/1=anyone/target, 0/2=with distance dependent
+ if(step.script->datalong2 & 2)
+ pSource->PlayDistanceSound(step.script->datalong,pTarget);
+ else
+ pSource->PlayDirectSound(step.script->datalong,pTarget);
+ break;
+ }
+ default:
+ sLog.outError("Unknown script command %u called.",step.script->command);
+ break;
+ }
+
+ m_scriptSchedule.erase(iter);
+ sWorld.DecreaseScheduledScriptCount();
+
+ iter = m_scriptSchedule.begin();
+ }
+ return;
}
Creature*
@@ -2774,3 +3635,10 @@ Map::GetDynamicObject(uint64 guid)
return NULL;
return ret;
}
+
+void Map::UpdateIteratorBack(Player *player)
+{
+ if(m_mapRefIter == player->GetMapRef())
+ m_mapRefIter = m_mapRefIter->nocheck_prev();
+}
+