[8252] Move DB scripting code from global World to Map. Author: Ambal

This one more step to pre-map events proccesing and parallel in future.

    [8256] Restore DB script loading broken after [8252]. Author: VladimirMangos

    Also propetly decrease scheduled DB script actions at map unloading.
    Some code style restore.

--HG--
branch : trunk
This commit is contained in:
megamage
2009-07-31 10:48:34 +08:00
parent b1bd5e7905
commit 0a2af88cb4
10 changed files with 921 additions and 892 deletions
+33 -21
View File
@@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
`required_8251_03_mangos_spell_proc_event` bit(1) default NULL
`required_8254_01_mangos_spell_proc_event` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--
@@ -15654,7 +15654,7 @@ INSERT INTO spell_chain VALUES
(27219,11700,689,7,0),
(27220,27219,689,8,0),
(47857,27220,689,9,0),
/*DrainSoul*/
/*Drain Soul*/
(1120,0,1120,1,0),
(8288,1120,1120,2,0),
(8289,8288,1120,3,0),
@@ -15670,14 +15670,20 @@ INSERT INTO spell_chain VALUES
(59161,48181,48181,2,0),
(59163,59161,48181,3,0),
(59164,59163,48181,4,0),
/*HowlofTerror*/
/*Howl of Terror*/
(5484,0,5484,1,0),
(17928,5484,5484,2,0),
/*SeedofCorruption*/
/*Seed of Corruption*/
(27243,0,27243,1,0),
(47835,27243,27243,2,0),
(47836,47835,27243,3,0),
/*UnstableAffliction*/
/* Shadow embrace */
(32385,0,32385,1,0),
(32387,32385,32385,2,0),
(32392,32387,32385,3,0),
(32393,32392,32385,4,0),
(32394,32393,32385,5,0),
/*Unstable Affliction*/
(30108,0,30108,1,0),
(30404,30108,30108,2,0),
(30405,30404,30108,3,0),
@@ -15776,6 +15782,12 @@ INSERT INTO spell_chain VALUES
(26372,26371,26364,9,0),
(49278,26372,26364,10,0),
(49279,49278,26364,11,0),
/*Maelstrom Weapon*/
(51528,0,51528,1,0),
(51529,51528,51528,2,0),
(51530,51529,51528,3,0),
(51531,51530,51528,4,0),
(51532,51531,51528,5,0),
/*Nature Resistance Totem*/
(10595,0,10595,1,0),
(10600,10595,10595,2,0),
@@ -17233,7 +17245,7 @@ INSERT INTO `spell_proc_event` VALUES
(12999, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 4.000000, 0.000000, 0),
(13000, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 6.000000, 0.000000, 0),
(13001, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 8.000000, 0.000000, 0),
(13002, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 10.000000, 0.000000, 0),
(13002, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,10.000000, 0.000000, 0),
(13045, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(13046, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(13047, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
@@ -17327,8 +17339,8 @@ INSERT INTO `spell_proc_event` VALUES
(20131, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0.000000, 0.000000, 0),
(20132, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0.000000, 0.000000, 0),
(20164, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 5.000000, 0.000000, 0),
(20165, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 20.000000, 0.000000, 0),
(20166, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 20.000000, 0.000000, 0),
(20165, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,20.000000, 0.000000, 0),
(20166, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,15.000000, 0.000000, 0),
(20182, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0.000000, 0.000000, 0),
(20210, 0x00000000, 10, 0xC0000000, 0x00010000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(20212, 0x00000000, 10, 0xC0000000, 0x00010000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
@@ -17366,7 +17378,7 @@ INSERT INTO `spell_proc_event` VALUES
(24353, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(24389, 0x00000000, 3, 0x00C00017, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(24658, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00014110, 0x00000000, 0.000000, 0.000000, 0),
(24905, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 15.000000, 0.000000, 0),
(24905, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002,15.000000, 0.000000, 0),
(24932, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 6),
(25050, 0x00000004, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(25669, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 1.000000, 0.000000, 0),
@@ -17462,7 +17474,7 @@ INSERT INTO `spell_proc_event` VALUES
(31570, 0x00000000, 3, 0x00010000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(31785, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00008800, 0x00000000, 0.000000, 0.000000, 0),
(31794, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0.000000, 0.000000, 0),
(31801, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 20.000000, 0.000000, 0),
(31801, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,20.000000, 0.000000, 0),
(31833, 0x00000000, 10, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(31835, 0x00000000, 10, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(31836, 0x00000000, 10, 0x80000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
@@ -17472,11 +17484,7 @@ INSERT INTO `spell_proc_event` VALUES
(31877, 0x00000000, 10, 0x00800000, 0x00000000, 0x00000008, 0x00004110, 0x00000000, 0.000000, 0.000000, 0),
(31878, 0x00000000, 10, 0x00800000, 0x00000000, 0x00000008, 0x00004110, 0x00000000, 0.000000, 0.000000, 0),
(31904, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0.000000, 0.000000, 0),
(32385, 0x00000000, 5, 0x00000402, 0x00000011, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(32387, 0x00000000, 5, 0x00000402, 0x00000011, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(32392, 0x00000000, 5, 0x00000402, 0x00000011, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(32393, 0x00000000, 5, 0x00000402, 0x00000011, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(32394, 0x00000000, 5, 0x00000402, 0x00000011, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(32385, 0x00000000, 5, 0x00000001, 0x00040000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(32409, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(32587, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0.000000, 0.000000, 0),
(32642, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000040, 0.000000, 0.000000, 0),
@@ -17752,6 +17760,7 @@ INSERT INTO `spell_proc_event` VALUES
(51483, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0),
(51485, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0),
(51486, 0x00000001, 11, 0x20000000, 0x00000000, 0x00000000, 0x00004000, 0x00000000, 0.000000, 0.000000, 0),
(51528, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,12.500000, 0.000000, 0),
(51556, 0x00000000, 11, 0x000000C0, 0x00000000, 0x00000010, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(51557, 0x00000000, 11, 0x000000C0, 0x00000000, 0x00000010, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(51558, 0x00000000, 11, 0x000000C0, 0x00000000, 0x00000010, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
@@ -17781,12 +17790,12 @@ INSERT INTO `spell_proc_event` VALUES
(51698, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 1),
(51700, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 1),
(51701, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 1),
(51940, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 20.000000, 0),
(51989, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 20.000000, 0),
(52004, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 20.000000, 0),
(52005, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 20.000000, 0),
(52007, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 20.000000, 0),
(52008, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 20.000000, 0),
(51940, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000,20.000000, 0),
(51989, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000,20.000000, 0),
(52004, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000,20.000000, 0),
(52005, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000,20.000000, 0),
(52007, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000,20.000000, 0),
(52008, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000,20.000000, 0),
(52020, 0x00000000, 7, 0x00008000, 0x00100000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(52127, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 3),
(52420, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 30),
@@ -17857,6 +17866,7 @@ INSERT INTO `spell_proc_event` VALUES
(55677, 0x00000000, 6, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(55680, 0x00000000, 6, 0x00000200, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(55689, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
(55747, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 45),
(55768, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 45),
(55776, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 45),
(56218, 0x00000000, 5, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
@@ -17904,6 +17914,8 @@ INSERT INTO `spell_proc_event` VALUES
(60132, 0x00000000, 15, 0x00000000, 0x08020000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(60170, 0x00000000, 5, 0x00000006, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(60172, 0x00000000, 5, 0x00040000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0.000000, 0.000000, 0),
(60436, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 45),
(60442, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 45),
(60493, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 45),
(60503, 0x00000000, 4, 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0.000000, 0.000000, 0),
(60537, 0x00000000, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 0),
+3 -3
View File
@@ -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;
}
+856 -9
View File
@@ -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)
{
+9
View File
@@ -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>
+2 -2
View File
@@ -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 )
+7 -7
View File
@@ -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)
+1 -1
View File
@@ -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*/)
+1 -1
View File
@@ -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);
+1 -842
View File
@@ -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)
{
+8 -6
View File
@@ -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];