aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/game/GameObject.cpp6
-rw-r--r--src/game/Map.cpp865
-rw-r--r--src/game/Map.h9
-rw-r--r--src/game/Player.cpp4
-rw-r--r--src/game/SpellEffects.cpp14
-rw-r--r--src/game/Transports.cpp2
-rw-r--r--src/game/WaypointMovementGenerator.cpp2
-rw-r--r--src/game/World.cpp843
-rw-r--r--src/game/World.h14
9 files changed, 888 insertions, 871 deletions
diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp
index 59ec04fc649..b6ac3442c0d 100644
--- a/src/game/GameObject.cpp
+++ b/src/game/GameObject.cpp
@@ -949,7 +949,7 @@ void GameObject::Use(Unit* user)
UseDoorOrButton();
// activate script
- sWorld.ScriptsStart(sGameObjectScripts, GetDBTableGUIDLow(), spellCaster, this);
+ GetMap()->ScriptsStart(sGameObjectScripts, GetDBTableGUIDLow(), spellCaster, this);
return;
case GAMEOBJECT_TYPE_QUESTGIVER: //2
@@ -1045,7 +1045,7 @@ void GameObject::Use(Unit* user)
player->CastedCreatureOrGO(info->id, GetGUID(), 0);
if (info->goober.eventId)
- sWorld.ScriptsStart(sEventScripts, info->goober.eventId, player, this);
+ GetMap()->ScriptsStart(sEventScripts, info->goober.eventId, player, this);
}
// cast this spell later if provided
@@ -1068,7 +1068,7 @@ void GameObject::Use(Unit* user)
player->SendCinematicStart(info->camera.cinematicId);
if (info->camera.eventID)
- sWorld.ScriptsStart(sEventScripts, info->camera.eventID, player, this);
+ GetMap()->ScriptsStart(sEventScripts, info->camera.eventID, player, this);
return;
}
diff --git a/src/game/Map.cpp b/src/game/Map.cpp
index 93fd3e21e1b..a0485e72a85 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)
@@ -780,17 +793,21 @@ 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)
@@ -2745,6 +2762,836 @@ void BattleGroundMap::UnloadAll()
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*
Map::GetCreature(uint64 guid)
{
diff --git a/src/game/Map.h b/src/game/Map.h
index ed918125328..e9c303eaa8a 100644
--- a/src/game/Map.h
+++ b/src/game/Map.h
@@ -43,9 +43,12 @@ class WorldPacket;
class InstanceData;
class Group;
class InstanceSave;
+class Object;
class WorldObject;
class TempSummon;
class CreatureGroup;
+struct ScriptInfo;
+struct ScriptAction;
typedef ACE_RW_Thread_Mutex GridRWLock;
@@ -398,6 +401,10 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
typedef MapRefManager PlayerList;
PlayerList const& GetPlayers() const { return m_mapRefManager; }
+ //per-map script storage
+ void ScriptsStart(std::map<uint32, std::multimap<uint32, ScriptInfo> > const& scripts, uint32 id, Object* source, Object* target);
+ void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target);
+
// must called with AddToWorld
template<class T>
void AddToActive(T* obj) { AddToActiveHelper(obj); }
@@ -467,6 +474,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
void setGridObjectDataLoaded(bool pLoaded, uint32 x, uint32 y) { getNGrid(x,y)->setGridObjectDataLoaded(pLoaded); }
void setNGrid(NGridType* grid, uint32 x, uint32 y);
+ void ScriptsProcess();
void UpdateActiveCells(const float &x, const float &y, const uint32 &t_diff);
protected:
@@ -508,6 +516,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
std::vector<Unit*> i_unitsToNotify;
std::set<WorldObject *> i_objectsToRemove;
std::map<WorldObject*, bool> i_objectsToSwitch;
+ std::multimap<time_t, ScriptAction> m_scriptSchedule;
// Type specific code for add/remove to/from grid
template<class T>
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 6c7fb40c3fa..76e109683a9 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -12882,7 +12882,7 @@ void Player::AddQuest( Quest const *pQuest, Object *questGiver )
//starting initial quest script
if(questGiver && pQuest->GetQuestStartScript()!=0)
- sWorld.ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this);
+ GetMap()->ScriptsStart(sQuestStartScripts, pQuest->GetQuestStartScript(), questGiver, this);
// Some spells applied at quest activation
SpellAreaForQuestMapBounds saBounds = spellmgr.GetSpellAreaForQuestMapBounds(quest_id,true);
@@ -14142,7 +14142,7 @@ void Player::SendQuestReward( Quest const *pQuest, uint32 XP, Object * questGive
GetSession()->SendPacket( &data );
if (pQuest->GetQuestCompleteScript() != 0)
- sWorld.ScriptsStart(sQuestEndScripts, pQuest->GetQuestCompleteScript(), questGiver, this);
+ GetMap()->ScriptsStart(sQuestEndScripts, pQuest->GetQuestCompleteScript(), questGiver, this);
}
void Player::SendQuestFailed( uint32 quest_id )
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index 2e683e05122..cf32a96f9f2 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -2483,7 +2483,7 @@ void Spell::EffectSendEvent(uint32 EffectIndex)
we do not handle a flag dropping or clicking on flag in battleground by sendevent system
*/
sLog.outDebug("Spell ScriptStart %u for spellid %u in EffectSendEvent ", m_spellInfo->EffectMiscValue[EffectIndex], m_spellInfo->Id);
- sWorld.ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
+ m_caster->GetMap()->ScriptsStart(sEventScripts, m_spellInfo->EffectMiscValue[EffectIndex], m_caster, focusObject);
}
void Spell::EffectPowerBurn(uint32 i)
@@ -2999,7 +2999,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
case GAMEOBJECT_TYPE_DOOR:
case GAMEOBJECT_TYPE_BUTTON:
gameObjTarget->UseDoorOrButton();
- sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
+ player->GetMap()->ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
return;
case GAMEOBJECT_TYPE_QUESTGIVER:
@@ -3019,7 +3019,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
if (gameObjTarget->GetGOInfo()->goober.eventId)
{
sLog.outDebug("Goober ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->goober.eventId,gameObjTarget->GetDBTableGUIDLow());
- sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
+ player->GetMap()->ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->goober.eventId, player, gameObjTarget);
gameObjTarget->EventInform(gameObjTarget->GetGOInfo()->goober.eventId);
}
@@ -3030,7 +3030,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
return;
Script->GOHello(player, gameObjTarget);
- sWorld.ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
+ gameObjTarget->GetMap()->ScriptsStart(sGameObjectScripts, gameObjTarget->GetDBTableGUIDLow(), player, gameObjTarget);
gameObjTarget->AddUniqueUse(player);
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
@@ -3052,7 +3052,7 @@ void Spell::SendLoot(uint64 guid, LootType loottype)
if (gameObjTarget->GetGOInfo()->chest.eventId)
{
sLog.outDebug("Chest ScriptStart id %u for GO %u", gameObjTarget->GetGOInfo()->chest.eventId,gameObjTarget->GetDBTableGUIDLow());
- sWorld.ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
+ player->GetMap()->ScriptsStart(sEventScripts, gameObjTarget->GetGOInfo()->chest.eventId, player, gameObjTarget);
}
// triggering linked GO
@@ -5501,7 +5501,7 @@ void Spell::EffectScriptEffect(uint32 effIndex)
// normal DB scripted effect
sLog.outDebug("Spell ScriptStart spellid %u in EffectScriptEffect ", m_spellInfo->Id);
- sWorld.ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
+ m_caster->GetMap()->ScriptsStart(sSpellScripts, m_spellInfo->Id, m_caster, unitTarget);
}
void Spell::EffectSanctuary(uint32 /*i*/)
@@ -5703,7 +5703,7 @@ void Spell::EffectActivateObject(uint32 effect_idx)
int32 delay_secs = m_spellInfo->EffectMiscValue[effect_idx];
- sWorld.ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
+ gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
}
void Spell::EffectApplyGlyph(uint32 i)
diff --git a/src/game/Transports.cpp b/src/game/Transports.cpp
index b0a588509f4..b2a89805ea9 100644
--- a/src/game/Transports.cpp
+++ b/src/game/Transports.cpp
@@ -487,7 +487,7 @@ void Transport::CheckForEvent(uint32 entry, uint32 wp_id)
{
uint32 key = entry*100+wp_id;
if(objmgr.TransportEventMap.find(key) != objmgr.TransportEventMap.end())
- sWorld.ScriptsStart(sEventScripts, objmgr.TransportEventMap[key], this, NULL);
+ GetMap()->ScriptsStart(sEventScripts, objmgr.TransportEventMap[key], this, NULL);
}
void Transport::Update(uint32 /*p_time*/)
diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp
index 34be9d3179b..92fd9bca2d7 100644
--- a/src/game/WaypointMovementGenerator.cpp
+++ b/src/game/WaypointMovementGenerator.cpp
@@ -198,7 +198,7 @@ WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff)
//note: disable "start" for mtmap
if(node->event_id && rand()%100 < node->event_chance)
- sWorld.ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL, false);
+ unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/);
MovementInform(unit);
unit.UpdateWaypointID(i_currentNode);
diff --git a/src/game/World.cpp b/src/game/World.cpp
index db59f101389..932eb555f20 100644
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -63,7 +63,6 @@
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "InstanceSaveMgr.h"
-#include "WaypointManager.h"
#include "Util.h"
#include "Language.h"
#include "CreatureGroups.h"
@@ -83,14 +82,6 @@ float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE;
float World::m_VisibleUnitGreyDistance = 0;
float World::m_VisibleObjectGreyDistance = 0;
-struct ScriptAction
-{
- uint64 sourceGUID;
- uint64 targetGUID;
- uint64 ownerGUID; // owner of source if source is item
- ScriptInfo const* script; // pointer to static script data
-};
-
/// World constructor
World::World()
{
@@ -106,6 +97,7 @@ World::World()
m_MaxPlayerCount = 0;
m_resultQueue = NULL;
m_NextDailyQuestReset = 0;
+ m_scheduledScripts = 0;
m_defaultDbcLocale = LOCALE_enUS;
m_availableDbcLocaleMask = 0;
@@ -1796,14 +1788,6 @@ void World::Update(uint32 diff)
MapManager::Instance().DoDelayedMovesAndRemoves();
}*/
- ///- Process necessary scripts
- if (!m_scriptSchedule.empty())
- {
- RecordTimeDiff(NULL);
- ScriptsProcess();
- RecordTimeDiff("UpdateScriptsProcess");
- }
-
sBattleGroundMgr.Update(diff);
RecordTimeDiff("UpdateBattleGroundMgr");
@@ -1848,831 +1832,6 @@ void World::ForceGameEventUpdate()
m_timers[WUPDATE_EVENTS].Reset();
}
-/// Put scripts in the execution queue
-void World::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, Object* target, bool start)
-{
- ///- 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>(m_gameTime + iter->first, sa));
- if (iter->first == 0)
- immedScript = true;
- }
- ///- If one of the effects should be immediate, launch the script execution
- if (start && immedScript)
- ScriptsProcess();
-}
-
-void World::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>(m_gameTime + delay, sa));
-
- ///- If effects should be immediate, launch the script execution
- if(delay == 0)
- ScriptsProcess();
-}
-
-/// Process queued scripts
-void World::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 <= m_gameTime))
- {
- 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(Trinity::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<Trinity::GameObjectSearcher<Trinity::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(Trinity::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<Trinity::GameObjectSearcher<Trinity::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(Trinity::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<Trinity::GameObjectSearcher<Trinity::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);
-
- iter = m_scriptSchedule.begin();
- }
- return;
-}
-
/// Send a packet to all players (except self if mentioned)
void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team)
{
diff --git a/src/game/World.h b/src/game/World.h
index 4864977b029..78d4c181b4a 100644
--- a/src/game/World.h
+++ b/src/game/World.h
@@ -29,6 +29,7 @@
#include "Timer.h"
#include "Policies/Singleton.h"
#include "SharedDefines.h"
+#include "ace/Atomic_Op.h"
#include <map>
#include <set>
@@ -553,9 +554,10 @@ class World
BanReturn BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author);
bool RemoveBanAccount(BanMode mode, std::string nameOrIP);
- void ScriptsStart(std::map<uint32, std::multimap<uint32, ScriptInfo> > const& scripts, uint32 id, Object* source, Object* target, bool start = true);
- void ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* source, Object* target);
- bool IsScriptScheduled() const { return !m_scriptSchedule.empty(); }
+ uint32 IncreaseScheduledScriptsCount() { return (uint32)++m_scheduledScripts; }
+ uint32 DecreaseScheduledScriptCount() { return (uint32)--m_scheduledScripts; }
+ uint32 DecreaseScheduledScriptCount(size_t count) { return (uint32)(m_scheduledScripts -= count); }
+ bool IsScriptScheduled() const { return m_scheduledScripts > 0; }
bool IsAllowedMap(uint32 mapid) { return m_forbiddenMapIds.count(mapid) == 0 ;}
@@ -592,7 +594,6 @@ class World
void RecordTimeDiff(const char * text, ...);
protected:
void _UpdateGameTime();
- void ScriptsProcess();
// callback for UpdateRealmCharacters
void _UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId);
@@ -606,6 +607,9 @@ class World
bool m_isClosed;
+ //atomic op counter for active scripts amount
+ ACE_Atomic_Op<ACE_Thread_Mutex, long> m_scheduledScripts;
+
time_t m_startTime;
time_t m_gameTime;
IntervalTimer m_timers[WUPDATE_COUNT];
@@ -626,8 +630,6 @@ class World
uint32 m_PlayerCount;
uint32 m_MaxPlayerCount;
- std::multimap<time_t, ScriptAction> m_scriptSchedule;
-
std::string m_newCharString;
float rate_values[MAX_RATES];