Scripts/DB_Scripts: massive cleanup of SCRIPT_COMMAND_* related staff

* add union into ScriptInfo structure (thanks NoFantasy for the idea);
* move scripts methods from Map.cpp to new file MapScripts.cpp;
* remove magic numbers and introduce eScriptFlags enumeration.

It's just a beginning and more changes to come. Stay tuned!

--HG--
branch : trunk
This commit is contained in:
azazel
2010-09-22 18:13:57 +06:00
parent 562a8c272d
commit eae0e5c822
6 changed files with 1295 additions and 1071 deletions

View File

@@ -4726,41 +4726,41 @@ void ObjectMgr::LoadScripts(ScriptsType type)
Field *fields = result->Fetch();
ScriptInfo tmp;
tmp.id = fields[0].GetUInt32();
if (isSpellScriptTable)
tmp.id |= fields[10].GetUInt8() << 24;
tmp.delay = fields[1].GetUInt32();
tmp.command = ScriptCommands(fields[2].GetUInt32());
tmp.datalong = fields[3].GetUInt32();
tmp.datalong2 = fields[4].GetUInt32();
tmp.dataint = fields[5].GetInt32();
tmp.x = fields[6].GetFloat();
tmp.y = fields[7].GetFloat();
tmp.z = fields[8].GetFloat();
tmp.o = fields[9].GetFloat();
tmp.type = type;
tmp.id = fields[0].GetUInt32();
if (isSpellScriptTable)
tmp.id |= fields[10].GetUInt8() << 24;
tmp.delay = fields[1].GetUInt32();
tmp.command = ScriptCommands(fields[2].GetUInt32());
tmp.Raw.nData[0] = fields[3].GetUInt32();
tmp.Raw.nData[1] = fields[4].GetUInt32();
tmp.Raw.nData[2] = fields[5].GetInt32();
tmp.Raw.fData[0] = fields[6].GetFloat();
tmp.Raw.fData[1] = fields[7].GetFloat();
tmp.Raw.fData[2] = fields[8].GetFloat();
tmp.Raw.fData[3] = fields[9].GetFloat();
// generic command args check
switch (tmp.command)
{
case SCRIPT_COMMAND_TALK:
{
if (tmp.datalong > CHAT_TYPE_WHISPER && tmp.datalong != CHAT_MSG_RAID_BOSS_WHISPER)
if (tmp.Talk.ChatType > CHAT_TYPE_WHISPER && tmp.Talk.ChatType != CHAT_MSG_RAID_BOSS_WHISPER)
{
sLog.outErrorDb("Table `%s` has invalid talk type (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u",
tableName.c_str(),tmp.datalong,tmp.id);
tableName.c_str(), tmp.Talk.ChatType, tmp.id);
continue;
}
if (tmp.dataint == 0)
if (!tmp.Talk.TextID)
{
sLog.outErrorDb("Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u",
tableName.c_str(),tmp.dataint,tmp.id);
tableName.c_str(), tmp.Talk.TextID, tmp.id);
continue;
}
if (tmp.dataint < MIN_DB_SCRIPT_STRING_ID || tmp.dataint >= MAX_DB_SCRIPT_STRING_ID)
if (tmp.Talk.TextID < MIN_DB_SCRIPT_STRING_ID || tmp.Talk.TextID >= MAX_DB_SCRIPT_STRING_ID)
{
sLog.outErrorDb("Table `%s` has out of range text id (dataint = %i expected %u-%u) in SCRIPT_COMMAND_TALK for script id %u",
tableName.c_str(),tmp.dataint,MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID,tmp.id);
tableName.c_str(), tmp.Talk.TextID, MIN_DB_SCRIPT_STRING_ID, MAX_DB_SCRIPT_STRING_ID, tmp.id);
continue;
}
@@ -4769,10 +4769,10 @@ void ObjectMgr::LoadScripts(ScriptsType type)
case SCRIPT_COMMAND_EMOTE:
{
if (!sEmotesStore.LookupEntry(tmp.datalong))
if (!sEmotesStore.LookupEntry(tmp.Emote.EmoteID))
{
sLog.outErrorDb("Table `%s` has invalid emote id (datalong = %u) in SCRIPT_COMMAND_EMOTE for script id %u",
tableName.c_str(),tmp.datalong,tmp.id);
tableName.c_str(), tmp.Emote.EmoteID, tmp.id);
continue;
}
break;
@@ -4780,46 +4780,73 @@ void ObjectMgr::LoadScripts(ScriptsType type)
case SCRIPT_COMMAND_TELEPORT_TO:
{
if (!sMapStore.LookupEntry(tmp.datalong))
if (!sMapStore.LookupEntry(tmp.TeleportTo.MapID))
{
sLog.outErrorDb("Table `%s` has invalid map (Id: %u) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",
tableName.c_str(),tmp.datalong,tmp.id);
tableName.c_str(), tmp.TeleportTo.MapID, tmp.id);
continue;
}
if (!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o))
if (!Trinity::IsValidMapCoord(tmp.TeleportTo.DestX, tmp.TeleportTo.DestY, tmp.TeleportTo.DestZ, tmp.TeleportTo.Orientation))
{
sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",
tableName.c_str(),tmp.x,tmp.y,tmp.id);
sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f Z: %f O: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",
tableName.c_str(), tmp.TeleportTo.DestX, tmp.TeleportTo.DestY, tmp.TeleportTo.DestZ, tmp.TeleportTo.Orientation, tmp.id);
continue;
}
break;
}
case SCRIPT_COMMAND_QUEST_EXPLORED:
{
Quest const* quest = GetQuestTemplate(tmp.QuestExplored.QuestID);
if (!quest)
{
sLog.outErrorDb("Table `%s` has invalid quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",
tableName.c_str(), tmp.QuestExplored.QuestID, tmp.id);
continue;
}
if (!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
{
sLog.outErrorDb("Table `%s` has quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.",
tableName.c_str(), tmp.QuestExplored.QuestID, tmp.id);
// this will prevent quest completing without objective
const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
// continue; - quest objective requirement set and command can be allowed
}
if (float(tmp.QuestExplored.Distance) > DEFAULT_VISIBILITY_DISTANCE)
{
sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",
tableName.c_str(), tmp.QuestExplored.Distance, tmp.id);
continue;
}
if (tmp.QuestExplored.Distance && float(tmp.QuestExplored.Distance) > DEFAULT_VISIBILITY_DISTANCE)
{
sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, max distance is %f or 0 for disable distance check",
tableName.c_str(), tmp.QuestExplored.Distance, tmp.id, DEFAULT_VISIBILITY_DISTANCE);
continue;
}
if (tmp.QuestExplored.Distance && float(tmp.QuestExplored.Distance) < INTERACTION_DISTANCE)
{
sLog.outErrorDb("Table `%s` has too small distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, min distance is %f or 0 for disable distance check",
tableName.c_str(), tmp.QuestExplored.Distance, tmp.id, INTERACTION_DISTANCE);
continue;
}
break;
}
case SCRIPT_COMMAND_KILL_CREDIT:
{
if (!GetCreatureTemplate(tmp.datalong))
if (!GetCreatureTemplate(tmp.KillCredit.CreatureEntry))
{
sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_KILL_CREDIT for script id %u",
tableName.c_str(),tmp.datalong,tmp.id);
continue;
}
break;
}
case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
{
if (!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o))
{
sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",
tableName.c_str(),tmp.x,tmp.y,tmp.id);
continue;
}
if (!GetCreatureTemplate(tmp.datalong))
{
sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",
tableName.c_str(),tmp.datalong,tmp.id);
tableName.c_str(), tmp.KillCredit.CreatureEntry, tmp.id);
continue;
}
break;
@@ -4827,11 +4854,11 @@ void ObjectMgr::LoadScripts(ScriptsType type)
case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
{
GameObjectData const* data = GetGOData(tmp.datalong);
GameObjectData const* data = GetGOData(tmp.RespawnGameobject.GOGuid);
if (!data)
{
sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",
tableName.c_str(),tmp.datalong,tmp.id);
tableName.c_str(), tmp.RespawnGameobject.GOGuid, tmp.id);
continue;
}
@@ -4839,7 +4866,7 @@ void ObjectMgr::LoadScripts(ScriptsType type)
if (!info)
{
sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",
tableName.c_str(),tmp.datalong,data->id,tmp.id);
tableName.c_str(), tmp.RespawnGameobject.GOGuid, data->id, tmp.id);
continue;
}
@@ -4850,19 +4877,38 @@ void ObjectMgr::LoadScripts(ScriptsType type)
info->type == GAMEOBJECT_TYPE_TRAP)
{
sLog.outErrorDb("Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",
tableName.c_str(),info->id,tmp.id);
tableName.c_str(), info->id, tmp.id);
continue;
}
break;
}
case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
{
if (!Trinity::IsValidMapCoord(tmp.TempSummonCreature.PosX, tmp.TempSummonCreature.PosY, tmp.TempSummonCreature.PosZ, tmp.TempSummonCreature.Orientation))
{
sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f Z: %f O: %f) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",
tableName.c_str(), tmp.TempSummonCreature.PosX, tmp.TempSummonCreature.PosY, tmp.TempSummonCreature.PosZ, tmp.TempSummonCreature.Orientation, tmp.id);
continue;
}
if (!GetCreatureTemplate(tmp.TempSummonCreature.CreatureEntry))
{
sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",
tableName.c_str(), tmp.TempSummonCreature.CreatureEntry, tmp.id);
continue;
}
break;
}
case SCRIPT_COMMAND_OPEN_DOOR:
case SCRIPT_COMMAND_CLOSE_DOOR:
{
GameObjectData const* data = GetGOData(tmp.datalong);
GameObjectData const* data = GetGOData(tmp.ToggleDoor.GOGuid);
if (!data)
{
sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u",
tableName.c_str(),tmp.datalong,(tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
tableName.c_str(), tmp.ToggleDoor.GOGuid, GetScriptCommandName(tmp.command).c_str(), tmp.id);
continue;
}
@@ -4870,57 +4916,14 @@ void ObjectMgr::LoadScripts(ScriptsType type)
if (!info)
{
sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u",
tableName.c_str(),tmp.datalong,data->id,(tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
tableName.c_str(), tmp.ToggleDoor.GOGuid, data->id, GetScriptCommandName(tmp.command).c_str(), tmp.id);
continue;
}
if (info->type != GAMEOBJECT_TYPE_DOOR)
{
sLog.outErrorDb("Table `%s` has gameobject type (%u) non supported by command %s for script id %u",tableName.c_str(),info->id,(tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
continue;
}
break;
}
case SCRIPT_COMMAND_QUEST_EXPLORED:
{
Quest const* quest = GetQuestTemplate(tmp.datalong);
if (!quest)
{
sLog.outErrorDb("Table `%s` has invalid quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",
tableName.c_str(),tmp.datalong,tmp.id);
continue;
}
if (!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
{
sLog.outErrorDb("Table `%s` has quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.",
tableName.c_str(),tmp.datalong,tmp.id);
// this will prevent quest completing without objective
const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
// continue; - quest objective requirement set and command can be allowed
}
if (float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE)
{
sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",
tableName.c_str(),tmp.datalong2,tmp.id);
continue;
}
if (tmp.datalong2 && float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE)
{
sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, max distance is %f or 0 for disable distance check",
tableName.c_str(),tmp.datalong2,tmp.id,DEFAULT_VISIBILITY_DISTANCE);
continue;
}
if (tmp.datalong2 && float(tmp.datalong2) < INTERACTION_DISTANCE)
{
sLog.outErrorDb("Table `%s` has too small distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, min distance is %f or 0 for disable distance check",
tableName.c_str(),tmp.datalong2,tmp.id,INTERACTION_DISTANCE);
sLog.outErrorDb("Table `%s` has gameobject type (%u) non supported by command %s for script id %u",
tableName.c_str(), info->id, GetScriptCommandName(tmp.command).c_str(), tmp.id);
continue;
}
@@ -4929,44 +4932,45 @@ void ObjectMgr::LoadScripts(ScriptsType type)
case SCRIPT_COMMAND_REMOVE_AURA:
{
if (!sSpellStore.LookupEntry(tmp.datalong))
if (!sSpellStore.LookupEntry(tmp.RemoveAura.SpellID))
{
sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA for script id %u",
tableName.c_str(),tmp.datalong,tmp.id);
tableName.c_str(), tmp.RemoveAura.SpellID, tmp.id);
continue;
}
if (tmp.datalong2 & ~0x1) // 1 bits (0,1)
if (tmp.RemoveAura.Flags & ~0x1) // 1 bits (0,1)
{
sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u) in SCRIPT_COMMAND_REMOVE_AURA for script id %u",
tableName.c_str(),tmp.datalong2,tmp.id);
tableName.c_str(), tmp.RemoveAura.Flags, tmp.id);
continue;
}
break;
}
case SCRIPT_COMMAND_CAST_SPELL:
{
if (!sSpellStore.LookupEntry(tmp.datalong))
if (!sSpellStore.LookupEntry(tmp.CastSpell.SpellID))
{
sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_CAST_SPELL for script id %u",
tableName.c_str(),tmp.datalong,tmp.id);
tableName.c_str(), tmp.CastSpell.SpellID, tmp.id);
continue;
}
if (tmp.datalong2 > 4) // targeting type
if (tmp.CastSpell.Flags > 4) // targeting type
{
sLog.outErrorDb("Table `%s` using unknown target in datalong2 (%u) in SCRIPT_COMMAND_CAST_SPELL for script id %u",
tableName.c_str(),tmp.datalong2,tmp.id);
tableName.c_str(), tmp.CastSpell.Flags, tmp.id);
continue;
}
if (tmp.datalong2 != 4 && tmp.dataint & ~0x1) // 1 bit (0,1)
if (tmp.CastSpell.Flags != 4 && tmp.CastSpell.CreatureEntry & ~0x1) // 1 bit (0,1)
{
sLog.outErrorDb("Table `%s` using unknown flags in dataint (%u) in SCRIPT_COMMAND_CAST_SPELL for script id %u",
tableName.c_str(),tmp.dataint,tmp.id);
tableName.c_str(), tmp.CastSpell.CreatureEntry, tmp.id);
continue;
}
else if (tmp.datalong2 == 4 && !GetCreatureTemplate(tmp.dataint))
else if (tmp.CastSpell.Flags == 4 && !GetCreatureTemplate(tmp.CastSpell.CreatureEntry))
{
sLog.outErrorDb("Table `%s` using invalid creature entry in dataint (%u) in SCRIPT_COMMAND_CAST_SPELL for script id %u",
tableName.c_str(),tmp.dataint,tmp.id);
tableName.c_str(), tmp.CastSpell.CreatureEntry, tmp.id);
continue;
}
break;
@@ -4974,16 +4978,16 @@ void ObjectMgr::LoadScripts(ScriptsType type)
case SCRIPT_COMMAND_CREATE_ITEM:
{
if (!GetItemPrototype(tmp.datalong))
if (!GetItemPrototype(tmp.CreateItem.ItemEntry))
{
sLog.outErrorDb("Table `%s` has nonexistent item (entry: %u) in SCRIPT_COMMAND_CREATE_ITEM for script id %u",
tableName.c_str(), tmp.datalong, tmp.id);
tableName.c_str(), tmp.CreateItem.ItemEntry, tmp.id);
continue;
}
if (!tmp.datalong2)
if (!tmp.CreateItem.Amount)
{
sLog.outErrorDb("Table `%s` SCRIPT_COMMAND_CREATE_ITEM but amount is %u for script id %u",
tableName.c_str(), tmp.datalong2, tmp.id);
tableName.c_str(), tmp.CreateItem.Amount, tmp.id);
continue;
}
break;
@@ -8939,11 +8943,11 @@ void ObjectMgr::CheckScripts(ScriptsType type, std::set<int32>& ids)
{
case SCRIPT_COMMAND_TALK:
{
if (!GetTrinityStringLocale (itrM->second.dataint))
sLog.outErrorDb("Table `db_script_string` not has string id %u used db script (ID: %u)", itrM->second.dataint, itrMM->first);
if (!GetTrinityStringLocale (itrM->second.Talk.TextID))
sLog.outErrorDb("Table `db_script_string` not has string id %u used db script (ID: %u)", itrM->second.Talk.TextID, itrMM->first);
if (ids.find(itrM->second.dataint) != ids.end())
ids.erase(itrM->second.dataint);
if (ids.find(itrM->second.Talk.TextID) != ids.end())
ids.erase(itrM->second.Talk.TextID);
}
default:
break;

View File

@@ -88,19 +88,223 @@ enum ScriptsType
SCRIPTS_LAST
};
enum eScriptFlags
{
// Talk Flags
SF_TALK_USE_PLAYER = 0x1,
// Emote flags
SF_EMOTE_USE_STATE = 0x1,
// TeleportTo flags
SF_TELEPORT_USE_CREATURE = 0x1,
// KillCredit flags
SF_KILLCREDIT_REWARD_GROUP = 0x1,
// RemoveAura flags
SF_REMOVEAURA_REVERSE = 0x1,
// CastSpell flags
SF_CASTSPELL_SOURCE_TO_TARGET = 0,
SF_CASTSPELL_SOURCE_TO_SOURCE = 1,
SF_CASTSPELL_TARGET_TO_TARGET = 2,
SF_CASTSPELL_TARGET_TO_SOURCE = 3,
SF_CASTSPELL_SEARCH_CREATURE = 4,
SF_CASTSPELL_TRIGGERED = 0x1,
// PlaySound flags
SF_PLAYSOUND_TARGET_PLAYER = 0x1,
SF_PLAYSOUND_DISTANCE_SOUND = 0x2,
// Orientation flags
SF_ORIENTATION_FACE_TARGET = 0x1,
};
struct ScriptInfo
{
ScriptsType type;
uint32 id;
uint32 delay;
ScriptCommands command;
uint32 datalong;
uint32 datalong2;
int32 dataint;
float x;
float y;
float z;
float o;
ScriptsType type;
union
{
struct
{
uint32 nData[3];
float fData[4];
} Raw;
struct // SCRIPT_COMMAND_TALK (0)
{
uint32 ChatType; // datalong
uint32 Flags; // datalong2
int32 TextID; // dataint
} Talk;
struct // SCRIPT_COMMAND_EMOTE (1)
{
uint32 EmoteID; // datalong
uint32 Flags; // datalong2
} Emote;
struct // SCRIPT_COMMAND_FIELD_SET (2)
{
uint32 FieldID; // datalong
uint32 FieldValue; // datalong2
} FieldSet;
struct // SCRIPT_COMMAND_MOVE_TO (3)
{
uint32 Unused1; // datalong
uint32 TravelTime; // datalong2
int32 Unused2; // dataint
float DestX;
float DestY;
float DestZ;
} MoveTo;
struct // SCRIPT_COMMAND_FLAG_SET (4)
// SCRIPT_COMMAND_FLAG_REMOVE (5)
{
uint32 FieldID; // datalong
uint32 FieldValue; // datalong2
} FlagToggle;
struct // SCRIPT_COMMAND_TELEPORT_TO (6)
{
uint32 MapID; // datalong
uint32 Flags; // datalong2
int32 Unused1; // dataint
float DestX;
float DestY;
float DestZ;
float Orientation;
} TeleportTo;
struct // SCRIPT_COMMAND_QUEST_EXPLORED (7)
{
uint32 QuestID; // datalong
uint32 Distance; // datalong2
} QuestExplored;
struct // SCRIPT_COMMAND_KILL_CREDIT (8)
{
uint32 CreatureEntry; // datalong
uint32 Flags; // datalong2
} KillCredit;
struct // SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (9)
{
uint32 GOGuid; // datalong
uint32 DespawnDelay; // datalong2
} RespawnGameobject;
struct // SCRIPT_COMMAND_TEMP_SUMMON_CREATURE (10)
{
uint32 CreatureEntry; // datalong
uint32 DespawnDelay; // datalong2
int32 Unused1; // dataint
float PosX;
float PosY;
float PosZ;
float Orientation;
} TempSummonCreature;
struct // SCRIPT_COMMAND_CLOSE_DOOR (12)
// SCRIPT_COMMAND_OPEN_DOOR (11)
{
uint32 GOGuid; // datalong
uint32 ResetDelay; // datalong2
} ToggleDoor;
// SCRIPT_COMMAND_ACTIVATE_OBJECT (13)
struct // SCRIPT_COMMAND_REMOVE_AURA (14)
{
uint32 SpellID; // datalong
uint32 Flags; // datalong2
} RemoveAura;
struct // SCRIPT_COMMAND_CAST_SPELL (15)
{
uint32 SpellID; // datalong
uint32 Flags; // datalong2
int32 CreatureEntry; // dataint
float SearchRadius;
} CastSpell;
struct // SCRIPT_COMMAND_PLAY_SOUND (16)
{
uint32 SoundID; // datalong
uint32 Flags; // datalong2
} PlaySound;
struct // SCRIPT_COMMAND_CREATE_ITEM (17)
{
uint32 ItemEntry; // datalong
uint32 Amount; // datalong2
} CreateItem;
struct // SCRIPT_COMMAND_DESPAWN_SELF (18)
{
uint32 DespawnDelay; // datalong
} DespawnSelf;
struct // SCRIPT_COMMAND_LOAD_PATH (20)
{
uint32 PathID; // datalong
uint32 IsRepeatable; // datalong2
} LoadPath;
struct // SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT (21)
{
uint32 CreatureEntry; // datalong
uint32 ScriptID; // datalong2
uint32 ScriptType; // dataint
} CallScript;
struct // SCRIPT_COMMAND_KILL (22)
{
uint32 Unused1; // datalong
uint32 Unused2; // datalong2
int32 RemoveCorpse; // dataint
} Kill;
struct // SCRIPT_COMMAND_ORIENTATION (30)
{
uint32 Flags; // datalong
uint32 Unused1; // datalong2
int32 Unused2; // dataint
float Unused3;
float Unused4;
float Unused5;
float Orientation;
} Orientation;
struct // SCRIPT_COMMAND_EQUIP (31)
{
uint32 EquipmentID; // datalong
} Equip;
struct // SCRIPT_COMMAND_MODEL (32)
{
uint32 ModelID; // datalong
} Model;
// SCRIPT_COMMAND_CLOSE_GOSSIP (33)
struct // SCRIPT_COMMAND_PLAYMOVIE (34)
{
uint32 MovieID; // datalong
} PlayMovie;
};
std::string GetDebugInfo() const;
};

View File

@@ -18,33 +18,19 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "MapManager.h"
#include "Player.h"
#include "Vehicle.h"
#include "GridNotifiers.h"
#include "Log.h"
#include "GridStates.h"
#include "CellImpl.h"
#include "InstanceScript.h"
#include "Map.h"
#include "GridNotifiersImpl.h"
#include "Config.h"
#include "Transport.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "World.h"
#include "Group.h"
#include "MapRefManager.h"
#include "Vehicle.h"
#include "WaypointManager.h"
#include "DBCEnums.h"
#include "GridStates.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "GossipDef.h"
#include "ScriptMgr.h"
#include "MapInstanced.h"
#include "InstanceSaveMgr.h"
#include "VMapFactory.h"
#include "MapInstanced.h"
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "Transport.h"
#include "InstanceScript.h"
#include "ObjectAccessor.h"
#include "MapManager.h"
#include "ObjectMgr.h"
#define DEFAULT_GRID_EXPIRY 300
#define MAX_GRID_LOAD_TIME 50
@@ -52,14 +38,6 @@
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()
{
sScriptMgr.OnDestroyMap(this);
@@ -2677,919 +2655,6 @@ void BattlegroundMap::RemoveAllPlayers()
}
/// 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 && !i_scriptLock)
{
i_scriptLock = true;
ScriptsProcess();
i_scriptLock = false;
}
}
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 && !i_scriptLock)
{
i_scriptLock = true;
ScriptsProcess();
i_scriptLock = false;
}
}
// Helpers for ScriptProcess method.
inline Player* Map::_GetScriptPlayerSourceOrTarget(Object* source, Object* target, const ScriptInfo* scriptInfo) const
{
Player *pPlayer = NULL;
if (!source && !target)
sLog.outError("%s source and target objects are NULL.", scriptInfo->GetDebugInfo().c_str());
else
{
// Check target first, then source.
if (target)
pPlayer = target->ToPlayer();
if (!pPlayer && source)
pPlayer = source->ToPlayer();
if (!pPlayer)
sLog.outError("%s neither source nor target object is player (source: TypeId: %u, Entry: %u, GUID: %u; target: TypeId: %u, Entry: %u, GUID: %u), skipping.",
scriptInfo->GetDebugInfo().c_str(),
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUIDLow() : 0,
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUIDLow() : 0);
}
return pPlayer;
}
inline Creature* Map::_GetScriptCreatureSourceOrTarget(Object* source, Object* target, const ScriptInfo* scriptInfo, bool bReverse) const
{
Creature *pCreature = NULL;
if (!source && !target)
sLog.outError("%s source and target objects are NULL.", scriptInfo->GetDebugInfo().c_str());
else
{
if (bReverse)
{
// Check target first, then source.
if (target)
pCreature = target->ToCreature();
if (!pCreature && source)
pCreature = source->ToCreature();
}
else
{
// Check source first, then target.
if (source)
pCreature = source->ToCreature();
if (!pCreature && target)
pCreature = target->ToCreature();
}
if (!pCreature)
sLog.outError("%s neither source nor target are creatures (source: TypeId: %u, Entry: %u, GUID: %u; target: TypeId: %u, Entry: %u, GUID: %u), skipping.",
scriptInfo->GetDebugInfo().c_str(),
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUIDLow() : 0,
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUIDLow() : 0);
}
return pCreature;
}
inline Unit* Map::_GetScriptUnit(Object* obj, bool isSource, const ScriptInfo* scriptInfo) const
{
Unit* pUnit = NULL;
if (!obj)
sLog.outError("%s %s object is NULL.", scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target");
else if (!obj->isType(TYPEMASK_UNIT))
sLog.outError("%s %s object is not unit (TypeId: %u, Entry: %u, GUID: %u), skipping.",
scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target", obj->GetTypeId(), obj->GetEntry(), obj->GetGUIDLow());
else
{
pUnit = dynamic_cast<Unit*>(obj);
if (!pUnit)
sLog.outError("%s %s object could not be casted to unit.",
scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target");
}
return pUnit;
}
inline Player* Map::_GetScriptPlayer(Object* obj, bool isSource, const ScriptInfo* scriptInfo) const
{
Player* pPlayer = NULL;
if (!obj)
sLog.outError("%s %s object is NULL.", scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target");
else
{
pPlayer = obj->ToPlayer();
if (!pPlayer)
sLog.outError("%s %s object is not a player (TypeId: %u, Entry: %u, GUID: %u).",
scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target", obj->GetTypeId(), obj->GetEntry(), obj->GetGUIDLow());
}
return pPlayer;
}
inline Creature* Map::_GetScriptCreature(Object* obj, bool isSource, const ScriptInfo* scriptInfo) const
{
Creature* pCreature = NULL;
if (!obj)
sLog.outError("%s %s object is NULL.", scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target");
else
{
pCreature = obj->ToCreature();
if (!pCreature)
sLog.outError("%s %s object is not a creature (TypeId: %u, Entry: %u, GUID: %u).", scriptInfo->GetDebugInfo().c_str(),
isSource ? "source" : "target", obj->GetTypeId(), obj->GetEntry(), obj->GetGUIDLow());
}
return pCreature;
}
inline WorldObject* Map::_GetScriptWorldObject(Object* obj, bool isSource, const ScriptInfo* scriptInfo) const
{
WorldObject* pWorldObject = NULL;
if (!obj)
sLog.outError("%s %s object is NULL.",
scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target");
else
{
pWorldObject = dynamic_cast<WorldObject*>(obj);
if (!pWorldObject)
sLog.outError("%s %s object is not a world object (TypeId: %u, Entry: %u, GUID: %u).",
scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target", obj->GetTypeId(), obj->GetEntry(), obj->GetGUIDLow());
}
return pWorldObject;
}
inline void Map::_ScriptProcessDoor(Object* source, Object* target, const ScriptInfo* scriptInfo) const
{
bool bOpen = false;
uint32 guid = scriptInfo->datalong;
int32 nTimeToToggle = (int32) scriptInfo->datalong2;
switch (scriptInfo->command)
{
case SCRIPT_COMMAND_OPEN_DOOR: bOpen = true; break;
case SCRIPT_COMMAND_CLOSE_DOOR: break;
default:
sLog.outError("%s unknown command for _ScriptProcessDoor.", scriptInfo->GetDebugInfo().c_str());
return;
}
if (!guid)
sLog.outError("%s door guid is not specified.", scriptInfo->GetDebugInfo().c_str());
else if (!source)
sLog.outError("%s source object is NULL.", scriptInfo->GetDebugInfo().c_str());
else if (!source->isType(TYPEMASK_UNIT))
sLog.outError("%s source object is not unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", scriptInfo->GetDebugInfo().c_str(),
source->GetTypeId(), source->GetEntry(), source->GetGUIDLow());
else
{
WorldObject* wSource = dynamic_cast <WorldObject*> (source);
if (!wSource)
sLog.outError("%s source object could not be casted to world object (TypeId: %u, Entry: %u, GUID: %u), skipping.",
scriptInfo->GetDebugInfo().c_str(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow());
else
{
GameObject *pDoor = _FindGameObject(wSource, guid);
if (!pDoor)
sLog.outError("%s gameobject was not found (guid: %u).", scriptInfo->GetDebugInfo().c_str(), guid);
else if (pDoor->GetGoType() != GAMEOBJECT_TYPE_DOOR)
sLog.outError("%s gameobject is not a door (GoType: %u, Entry: %u, GUID: %u).",
scriptInfo->GetDebugInfo().c_str(), pDoor->GetGoType(), pDoor->GetEntry(), pDoor->GetGUIDLow());
else if (bOpen == (pDoor->GetGoState() == GO_STATE_READY))
{
if (nTimeToToggle < 15)
nTimeToToggle = 15;
pDoor->UseDoorOrButton(nTimeToToggle);
if (target && target->isType(TYPEMASK_GAMEOBJECT))
{
GameObject* goTarget = dynamic_cast<GameObject*>(target);
if (goTarget && goTarget->GetGoType() == GAMEOBJECT_TYPE_BUTTON)
goTarget->UseDoorOrButton(nTimeToToggle);
}
}
}
}
}
inline GameObject* Map::_FindGameObject(WorldObject* pSearchObject, uint32 guid) const
{
GameObject *pGameObject = NULL;
CellPair p(Trinity::ComputeCellPair(pSearchObject->GetPositionX(), pSearchObject->GetPositionY()));
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
Trinity::GameObjectWithDbGUIDCheck goCheck(*pSearchObject, guid);
Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(pSearchObject, pGameObject, goCheck);
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > objectChecker(checker);
cell.Visit(p, objectChecker, *pSearchObject->GetMap());
return pGameObject;
}
/// 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_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 = sMapMgr.m_Transports.begin(); iter != sMapMgr.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;
std::string tableName = GetScriptsTableNameByType(step.script->type);
std::string commandName = GetScriptCommandName(step.script->command);
switch (step.script->command)
{
case SCRIPT_COMMAND_TALK:
if (step.script->datalong > CHAT_TYPE_WHISPER && step.script->datalong != CHAT_MSG_RAID_BOSS_WHISPER)
{
sLog.outError("%s invalid chat type (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->datalong);
break;
}
if (step.script->datalong2 & 0x1)
{
if (Player *pSource = _GetScriptPlayerSourceOrTarget(source, target, step.script))
{
uint64 targetGUID = target ? target->GetGUID() : 0;
LocaleConstant loc_idx = pSource->GetSession()->GetSessionDbLocaleIndex();
const std::string text(sObjectMgr.GetTrinityString(step.script->dataint, loc_idx));
switch (step.script->datalong)
{
case CHAT_TYPE_SAY:
pSource->Say(text, LANG_UNIVERSAL);
break;
case CHAT_TYPE_YELL:
pSource->Yell(text, LANG_UNIVERSAL);
break;
case CHAT_TYPE_TEXT_EMOTE:
case CHAT_TYPE_BOSS_EMOTE:
pSource->TextEmote(text);
break;
case CHAT_TYPE_WHISPER:
if (!targetGUID || !IS_PLAYER_GUID(targetGUID))
{
sLog.outError("%s attempt to whisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str());
break;
}
pSource->Whisper(text, LANG_UNIVERSAL, targetGUID);
break;
default:
break; // must be already checked at load
}
}
}
else
{
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
uint64 targetGUID = target ? target->GetGUID() : 0;
switch (step.script->datalong)
{
case CHAT_TYPE_SAY:
cSource->Say(step.script->dataint, LANG_UNIVERSAL, targetGUID);
break;
case CHAT_TYPE_YELL:
cSource->Yell(step.script->dataint, LANG_UNIVERSAL, targetGUID);
break;
case CHAT_TYPE_TEXT_EMOTE:
cSource->TextEmote(step.script->dataint, targetGUID);
break;
case CHAT_TYPE_BOSS_EMOTE:
cSource->MonsterTextEmote(step.script->dataint, targetGUID, true);
break;
case CHAT_TYPE_WHISPER:
if (!targetGUID || !IS_PLAYER_GUID(targetGUID))
{
sLog.outError("%s attempt to whisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str());
break;
}
cSource->Whisper(step.script->dataint, targetGUID);
break;
case CHAT_MSG_RAID_BOSS_WHISPER: //42
if (!targetGUID || !IS_PLAYER_GUID(targetGUID))
{
sLog.outError("%s attempt to raidbosswhisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str());
break;
}
cSource->MonsterWhisper(step.script->dataint, targetGUID, true);
break;
default:
break; // must be already checked at load
}
}
}
break;
case SCRIPT_COMMAND_EMOTE:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
if (step.script->datalong2)
cSource->SetUInt32Value(UNIT_NPC_EMOTESTATE, step.script->datalong);
else
cSource->HandleEmoteCommand(step.script->datalong);
}
break;
case SCRIPT_COMMAND_FIELD_SET:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
// Validate field number.
if (step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= cSource->GetValuesCount())
sLog.outError("%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.",
step.script->GetDebugInfo().c_str(), step.script->datalong,
cSource->GetValuesCount(), cSource->GetTypeId(), cSource->GetEntry(), cSource->GetGUIDLow());
else
cSource->SetUInt32Value(step.script->datalong, step.script->datalong2);
}
break;
case SCRIPT_COMMAND_MOVE_TO:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
cSource->SendMonsterMoveWithSpeed(step.script->x, step.script->y, step.script->z, step.script->datalong2);
cSource->GetMap()->CreatureRelocation(cSource, step.script->x, step.script->y, step.script->z, 0);
}
break;
case SCRIPT_COMMAND_FLAG_SET:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
// Validate field number.
if (step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= cSource->GetValuesCount())
sLog.outError("%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.",
step.script->GetDebugInfo().c_str(), step.script->datalong,
source->GetValuesCount(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow());
else
cSource->SetFlag(step.script->datalong, step.script->datalong2);
}
break;
case SCRIPT_COMMAND_FLAG_REMOVE:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
// Validate field number.
if (step.script->datalong <= OBJECT_FIELD_ENTRY || step.script->datalong >= cSource->GetValuesCount())
sLog.outError("%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.",
step.script->GetDebugInfo().c_str(), step.script->datalong,
source->GetValuesCount(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow());
else
cSource->RemoveFlag(step.script->datalong, step.script->datalong2);
}
break;
case SCRIPT_COMMAND_TELEPORT_TO:
switch (step.script->datalong2)
{
case 0:
// Source or target must be Player.
if (Player *pSource = _GetScriptPlayerSourceOrTarget(source, target, step.script))
pSource->TeleportTo(step.script->datalong, step.script->x, step.script->y, step.script->z, step.script->o);
break;
case 1:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true))
cSource->NearTeleportTo(step.script->x, step.script->y, step.script->z, step.script->o);
break;
default:
sLog.outError("%s unknown datalong2 flag (%u), skipping.",
step.script->GetDebugInfo().c_str(), step.script->datalong2);
}
break;
case SCRIPT_COMMAND_KILL_CREDIT:
// Source or target must be Player.
if (Player *pSource = _GetScriptPlayerSourceOrTarget(source, target, step.script))
{
if (step.script->datalong2)
pSource->RewardPlayerAndGroupAtEvent(step.script->datalong, pSource);
else
pSource->KilledMonsterCredit(step.script->datalong, 0);
}
break;
case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
{
// Source must be WorldObject.
if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script))
{
if (!step.script->datalong)
sLog.outError("%s creature entry (datalong) is not specified.", step.script->GetDebugInfo().c_str());
else
{
float x = step.script->x;
float y = step.script->y;
float z = step.script->z;
float o = step.script->o;
if (!pSummoner->SummonCreature(step.script->datalong, x, y, z, o, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, step.script->datalong2))
sLog.outError("%s creature was not spawned (entry: %u).", step.script->GetDebugInfo().c_str(), step.script->datalong);
}
}
break;
}
case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
if (!step.script->datalong)
{
sLog.outError("%s gameobject entry (datalong) is not specified.", step.script->GetDebugInfo().c_str());
break;
}
// Source or target must be WorldObject.
if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script))
{
GameObject *pGO = _FindGameObject(pSummoner, step.script->datalong);
if (!pGO)
{
sLog.outError("%s gameobject was not found (guid: %u).", step.script->GetDebugInfo().c_str(), step.script->datalong);
break;
}
if (pGO->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE ||
pGO->GetGoType() == GAMEOBJECT_TYPE_DOOR ||
pGO->GetGoType() == GAMEOBJECT_TYPE_BUTTON ||
pGO->GetGoType() == GAMEOBJECT_TYPE_TRAP)
{
sLog.outError("%s can not be used with gameobject of type %u (guid: %u).",
step.script->GetDebugInfo().c_str(), uint32(pGO->GetGoType()), step.script->datalong);
break;
}
// Check that GO is not spawned
if (!pGO->isSpawned())
{
int32 nTimeToDespawn = step.script->datalong2 < 5 ? 5 : (int32) step.script->datalong2;
pGO->SetLootState(GO_READY);
pGO->SetRespawnTime(nTimeToDespawn);
pGO->GetMap()->Add(pGO);
}
}
break;
case SCRIPT_COMMAND_OPEN_DOOR:
case SCRIPT_COMMAND_CLOSE_DOOR:
_ScriptProcessDoor(source, target, step.script);
break;
case SCRIPT_COMMAND_QUEST_EXPLORED:
{
if (!source)
{
sLog.outError("%s source object is NULL.", step.script->GetDebugInfo().c_str());
break;
}
if (!target)
{
sLog.outError("%s target object is NULL.", step.script->GetDebugInfo().c_str());
break;
}
// when script called for item spell casting then target == (unit or GO) and source is player
WorldObject* worldObject;
Player* pTarget = target->ToPlayer();
if (pTarget)
{
if (source->GetTypeId() != TYPEID_UNIT && source->GetTypeId() != TYPEID_GAMEOBJECT && source->GetTypeId() != TYPEID_PLAYER)
{
sLog.outError("%s source is not unit, gameobject or player (TypeId: %u, Entry: %u, GUID: %u), skipping.",
step.script->GetDebugInfo().c_str(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow());
break;
}
worldObject = dynamic_cast<WorldObject*>(source);
}
else
{
pTarget = source->ToPlayer();
if (pTarget)
{
if (target->GetTypeId() != TYPEID_UNIT && target->GetTypeId() != TYPEID_GAMEOBJECT && target->GetTypeId() != TYPEID_PLAYER)
{
sLog.outError("%s target is not unit, gameobject or player (TypeId: %u, Entry: %u, GUID: %u), skipping.",
step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUIDLow());
break;
}
worldObject = dynamic_cast<WorldObject*>(target);
}
else
{
sLog.outError("%s neither source nor target is player (source: TypeId: %u, Entry: %u, GUID: %u; target: TypeId: %u, Entry: %u, GUID: %u), skipping.",
step.script->GetDebugInfo().c_str(),
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUIDLow() : 0,
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUIDLow() : 0);
break;
}
}
// quest id and flags checked at script loading
if ((worldObject->GetTypeId() != TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) &&
(step.script->datalong2 == 0 || worldObject->IsWithinDistInMap(pTarget, float(step.script->datalong2))))
pTarget->AreaExploredOrEventHappens(step.script->datalong);
else
pTarget->FailQuest(step.script->datalong);
break;
}
case SCRIPT_COMMAND_ACTIVATE_OBJECT:
// Source must be Unit.
if (Unit *pSource = _GetScriptUnit(source, true, step.script))
{
// Target must be GameObject.
if (!target)
{
sLog.outError("%s target object is NULL.", step.script->GetDebugInfo().c_str());
break;
}
if (target->GetTypeId() != TYPEID_GAMEOBJECT)
{
sLog.outError("%s target object is not gameobject (TypeId: %u, Entry: %u, GUID: %u), skipping.",
step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUIDLow());
break;
}
if (GameObject *pGO = dynamic_cast<GameObject*>(target))
pGO->Use(pSource);
}
break;
case SCRIPT_COMMAND_REMOVE_AURA:
// Source (datalong2 != 0) or target (datalong2 == 0) must be Unit.
if (Unit *pTarget = _GetScriptUnit(step.script->datalong2 ? source : target, step.script->datalong2, step.script))
pTarget->RemoveAurasDueToSpell(step.script->datalong);
break;
case SCRIPT_COMMAND_CAST_SPELL:
{
// TODO: Allow gameobjects to be targets and casters
if (!source && !target)
{
sLog.outError("%s source and target objects are NULL.", step.script->GetDebugInfo().c_str());
break;
}
Unit* uSource = NULL;
Unit* uTarget = NULL;
// source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s
switch (step.script->datalong2)
{
case 0: // source -> target
uSource = dynamic_cast<Unit*>(source);
uTarget = dynamic_cast<Unit*>(target);
break;
case 1: // source -> source
uSource = dynamic_cast<Unit*>(source);
uTarget = uSource;
break;
case 2: // target -> target
uSource = dynamic_cast<Unit*>(target);
uTarget = uSource;
break;
case 3: // target -> source
uSource = dynamic_cast<Unit*>(target);
uTarget = dynamic_cast<Unit*>(source);
break;
case 4: // source -> creature with entry
uSource = dynamic_cast<Unit*>(source);
uTarget = GetClosestCreatureWithEntry(uSource, abs(step.script->dataint), step.script->x);
break;
}
if (!uSource || !uSource->isType(TYPEMASK_UNIT))
{
sLog.outError("%s no source unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->datalong);
break;
}
if (!uTarget || !uTarget->isType(TYPEMASK_UNIT))
{
sLog.outError("%s no target unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->datalong);
break;
}
bool triggered = (step.script->datalong2 != 4) ? step.script->dataint & 0x1 : step.script->dataint < 0;
uSource->CastSpell(uTarget, step.script->datalong, triggered);
break;
}
case SCRIPT_COMMAND_PLAY_SOUND:
// Source must be WorldObject.
if (WorldObject* pSource = _GetScriptWorldObject(source, true, step.script))
{
// datalong2 bitmask: 0/1=anyone/target
Player* pTarget = NULL;
if (step.script->datalong2 & 1)
{
// Target must be Player.
pTarget = _GetScriptPlayer(target, false, step.script);
if (!pTarget)
break;
}
// datalong2 bitmask: 0/2=without/with distance dependent
if (step.script->datalong2 & 2)
pSource->PlayDistanceSound(step.script->datalong, pTarget);
else
pSource->PlayDirectSound(step.script->datalong, pTarget);
}
break;
case SCRIPT_COMMAND_CREATE_ITEM:
// Target or source must be Player.
if (Player* pReceiver = _GetScriptPlayerSourceOrTarget(source, target, step.script))
{
ItemPosCountVec dest;
uint8 msg = pReceiver->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, step.script->datalong, step.script->datalong2);
if (msg == EQUIP_ERR_OK)
{
if (Item* item = pReceiver->StoreNewItem(dest, step.script->datalong, true))
pReceiver->SendNewItem(item, step.script->datalong2, false, true);
}
else
pReceiver->SendEquipError(msg, NULL, NULL, step.script->datalong);
}
break;
case SCRIPT_COMMAND_DESPAWN_SELF:
// Target or source must be Creature.
if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true))
cSource->ForcedDespawn(step.script->datalong);
break;
case SCRIPT_COMMAND_LOAD_PATH:
// Source must be Unit.
if (Unit* pSource = _GetScriptUnit(source, true, step.script))
{
if (!sWaypointMgr->GetPath(step.script->datalong))
sLog.outError("%s source object has an invalid path (%u), skipping.", step.script->GetDebugInfo().c_str(), step.script->datalong);
else
pSource->GetMotionMaster()->MovePath(step.script->datalong, step.script->datalong2);
}
break;
case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT:
{
if (!step.script->datalong)
{
sLog.outError("%s creature entry is not specified, skipping.", step.script->GetDebugInfo().c_str());
break;
}
if (!step.script->datalong2)
{
sLog.outError("%s script id is not specified, skipping.", step.script->GetDebugInfo().c_str());
break;
}
Creature* cTarget;
if (source) //using grid searcher
{
WorldObject* wSource = dynamic_cast <WorldObject*> (source);
CellPair p(Trinity::ComputeCellPair(wSource->GetPositionX(), wSource->GetPositionY()));
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
Trinity::CreatureWithDbGUIDCheck target_check(wSource, step.script->datalong);
Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(wSource, cTarget, target_check);
TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker);
cell.Visit(p, unit_checker, *wSource->GetMap());
}
else //check hashmap holders
{
if (CreatureData const* data = sObjectMgr.GetCreatureData(step.script->datalong))
cTarget = ObjectAccessor::GetObjectInWorld<Creature>(data->mapid, data->posX, data->posY, MAKE_NEW_GUID(step.script->datalong, data->id, HIGHGUID_UNIT), cTarget);
}
if (!cTarget)
{
sLog.outError("%s target was not found (entry: %u)", step.script->GetDebugInfo().c_str(), step.script->datalong);
break;
}
//Lets choose our ScriptMap map
ScriptMapMap *datamap = GetScriptsMapByType(ScriptsType(step.script->dataint));
//if no scriptmap present...
if (!datamap)
{
sLog.outError("%s unknown scriptmap (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->dataint);
break;
}
// Insert script into schedule but do not start it
ScriptsStart(*datamap, step.script->datalong2, cTarget, NULL);
break;
}
case SCRIPT_COMMAND_KILL:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
if (cSource->isDead())
sLog.outError("%s creature is already dead (Entry: %u, GUID: %u)",
step.script->GetDebugInfo().c_str(), cSource->GetEntry(), cSource->GetGUIDLow());
else
{
cSource->setDeathState(JUST_DIED);
if (step.script->dataint == 1)
cSource->RemoveCorpse();
}
}
break;
case SCRIPT_COMMAND_ORIENTATION:
// Source must be Unit.
if (Unit *pSource = _GetScriptUnit(source, true, step.script))
{
if (!step.script->datalong)
pSource->SetOrientation(step.script->o);
else
{
// Target must be Unit.
Unit* pTarget = _GetScriptUnit(target, false, step.script);
if (!pTarget)
break;
pSource->SetInFront(pTarget);
}
pSource->SendMovementFlagUpdate();
}
break;
case SCRIPT_COMMAND_EQUIP:
// Source must be Creature.
if (Creature *cSource = _GetScriptCreature(source, true, step.script))
cSource->LoadEquipment(step.script->datalong);
break;
case SCRIPT_COMMAND_MODEL:
// Source must be Creature.
if (Creature *cSource = _GetScriptCreature(source, true, step.script))
cSource->SetDisplayId(step.script->datalong);
break;
case SCRIPT_COMMAND_CLOSE_GOSSIP:
// Source must be Player.
if (Player *pSource = _GetScriptPlayer(source, true, step.script))
pSource->PlayerTalkClass->CloseGossip();
break;
case SCRIPT_COMMAND_PLAYMOVIE:
// Source must be Player.
if (Player *pSource = _GetScriptPlayer(source, true, step.script))
pSource->SendMovieStart(step.script->datalong);
break;
default:
sLog.outError("Unknown script command %s.", step.script->GetDebugInfo().c_str());
break;
}
m_scriptSchedule.erase(iter);
sWorld.DecreaseScheduledScriptCount();
iter = m_scriptSchedule.begin();
}
}
Creature*
Map::GetCreature(uint64 guid)
{

View File

@@ -53,6 +53,14 @@ class Battleground;
class MapInstanced;
class InstanceMap;
struct ScriptAction
{
uint64 sourceGUID;
uint64 targetGUID;
uint64 ownerGUID; // owner of source if source is item
ScriptInfo const* script; // pointer to static script data
};
//******************************************
// Map file format defines
//******************************************

View File

@@ -0,0 +1,944 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Map.h"
#include "World.h"
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "Transport.h"
#include "ScriptedCreature.h"
#include "WaypointManager.h"
#include "GossipDef.h"
#include "MapManager.h"
#include "ObjectMgr.h"
#include "MapRefManager.h"
/// 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 && !i_scriptLock)
{
i_scriptLock = true;
ScriptsProcess();
i_scriptLock = false;
}
}
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 && !i_scriptLock)
{
i_scriptLock = true;
ScriptsProcess();
i_scriptLock = false;
}
}
// Helpers for ScriptProcess method.
inline Player* Map::_GetScriptPlayerSourceOrTarget(Object* source, Object* target, const ScriptInfo* scriptInfo) const
{
Player *pPlayer = NULL;
if (!source && !target)
sLog.outError("%s source and target objects are NULL.", scriptInfo->GetDebugInfo().c_str());
else
{
// Check target first, then source.
if (target)
pPlayer = target->ToPlayer();
if (!pPlayer && source)
pPlayer = source->ToPlayer();
if (!pPlayer)
sLog.outError("%s neither source nor target object is player (source: TypeId: %u, Entry: %u, GUID: %u; target: TypeId: %u, Entry: %u, GUID: %u), skipping.",
scriptInfo->GetDebugInfo().c_str(),
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUIDLow() : 0,
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUIDLow() : 0);
}
return pPlayer;
}
inline Creature* Map::_GetScriptCreatureSourceOrTarget(Object* source, Object* target, const ScriptInfo* scriptInfo, bool bReverse) const
{
Creature *pCreature = NULL;
if (!source && !target)
sLog.outError("%s source and target objects are NULL.", scriptInfo->GetDebugInfo().c_str());
else
{
if (bReverse)
{
// Check target first, then source.
if (target)
pCreature = target->ToCreature();
if (!pCreature && source)
pCreature = source->ToCreature();
}
else
{
// Check source first, then target.
if (source)
pCreature = source->ToCreature();
if (!pCreature && target)
pCreature = target->ToCreature();
}
if (!pCreature)
sLog.outError("%s neither source nor target are creatures (source: TypeId: %u, Entry: %u, GUID: %u; target: TypeId: %u, Entry: %u, GUID: %u), skipping.",
scriptInfo->GetDebugInfo().c_str(),
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUIDLow() : 0,
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUIDLow() : 0);
}
return pCreature;
}
inline Unit* Map::_GetScriptUnit(Object* obj, bool isSource, const ScriptInfo* scriptInfo) const
{
Unit* pUnit = NULL;
if (!obj)
sLog.outError("%s %s object is NULL.", scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target");
else if (!obj->isType(TYPEMASK_UNIT))
sLog.outError("%s %s object is not unit (TypeId: %u, Entry: %u, GUID: %u), skipping.",
scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target", obj->GetTypeId(), obj->GetEntry(), obj->GetGUIDLow());
else
{
pUnit = dynamic_cast<Unit*>(obj);
if (!pUnit)
sLog.outError("%s %s object could not be casted to unit.",
scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target");
}
return pUnit;
}
inline Player* Map::_GetScriptPlayer(Object* obj, bool isSource, const ScriptInfo* scriptInfo) const
{
Player* pPlayer = NULL;
if (!obj)
sLog.outError("%s %s object is NULL.", scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target");
else
{
pPlayer = obj->ToPlayer();
if (!pPlayer)
sLog.outError("%s %s object is not a player (TypeId: %u, Entry: %u, GUID: %u).",
scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target", obj->GetTypeId(), obj->GetEntry(), obj->GetGUIDLow());
}
return pPlayer;
}
inline Creature* Map::_GetScriptCreature(Object* obj, bool isSource, const ScriptInfo* scriptInfo) const
{
Creature* pCreature = NULL;
if (!obj)
sLog.outError("%s %s object is NULL.", scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target");
else
{
pCreature = obj->ToCreature();
if (!pCreature)
sLog.outError("%s %s object is not a creature (TypeId: %u, Entry: %u, GUID: %u).", scriptInfo->GetDebugInfo().c_str(),
isSource ? "source" : "target", obj->GetTypeId(), obj->GetEntry(), obj->GetGUIDLow());
}
return pCreature;
}
inline WorldObject* Map::_GetScriptWorldObject(Object* obj, bool isSource, const ScriptInfo* scriptInfo) const
{
WorldObject* pWorldObject = NULL;
if (!obj)
sLog.outError("%s %s object is NULL.",
scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target");
else
{
pWorldObject = dynamic_cast<WorldObject*>(obj);
if (!pWorldObject)
sLog.outError("%s %s object is not a world object (TypeId: %u, Entry: %u, GUID: %u).",
scriptInfo->GetDebugInfo().c_str(), isSource ? "source" : "target", obj->GetTypeId(), obj->GetEntry(), obj->GetGUIDLow());
}
return pWorldObject;
}
inline void Map::_ScriptProcessDoor(Object* source, Object* target, const ScriptInfo* scriptInfo) const
{
bool bOpen = false;
uint32 guid = scriptInfo->ToggleDoor.GOGuid;
int32 nTimeToToggle = std::max(15, int32(scriptInfo->ToggleDoor.ResetDelay));
switch (scriptInfo->command)
{
case SCRIPT_COMMAND_OPEN_DOOR: bOpen = true; break;
case SCRIPT_COMMAND_CLOSE_DOOR: break;
default:
sLog.outError("%s unknown command for _ScriptProcessDoor.", scriptInfo->GetDebugInfo().c_str());
return;
}
if (!guid)
sLog.outError("%s door guid is not specified.", scriptInfo->GetDebugInfo().c_str());
else if (!source)
sLog.outError("%s source object is NULL.", scriptInfo->GetDebugInfo().c_str());
else if (!source->isType(TYPEMASK_UNIT))
sLog.outError("%s source object is not unit (TypeId: %u, Entry: %u, GUID: %u), skipping.", scriptInfo->GetDebugInfo().c_str(),
source->GetTypeId(), source->GetEntry(), source->GetGUIDLow());
else
{
WorldObject* wSource = dynamic_cast <WorldObject*> (source);
if (!wSource)
sLog.outError("%s source object could not be casted to world object (TypeId: %u, Entry: %u, GUID: %u), skipping.",
scriptInfo->GetDebugInfo().c_str(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow());
else
{
GameObject *pDoor = _FindGameObject(wSource, guid);
if (!pDoor)
sLog.outError("%s gameobject was not found (guid: %u).", scriptInfo->GetDebugInfo().c_str(), guid);
else if (pDoor->GetGoType() != GAMEOBJECT_TYPE_DOOR)
sLog.outError("%s gameobject is not a door (GoType: %u, Entry: %u, GUID: %u).",
scriptInfo->GetDebugInfo().c_str(), pDoor->GetGoType(), pDoor->GetEntry(), pDoor->GetGUIDLow());
else if (bOpen == (pDoor->GetGoState() == GO_STATE_READY))
{
pDoor->UseDoorOrButton(nTimeToToggle);
if (target && target->isType(TYPEMASK_GAMEOBJECT))
{
GameObject* goTarget = dynamic_cast<GameObject*>(target);
if (goTarget && goTarget->GetGoType() == GAMEOBJECT_TYPE_BUTTON)
goTarget->UseDoorOrButton(nTimeToToggle);
}
}
}
}
}
inline GameObject* Map::_FindGameObject(WorldObject* pSearchObject, uint32 guid) const
{
GameObject *pGameObject = NULL;
CellPair p(Trinity::ComputeCellPair(pSearchObject->GetPositionX(), pSearchObject->GetPositionY()));
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
Trinity::GameObjectWithDbGUIDCheck goCheck(*pSearchObject, guid);
Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck> checker(pSearchObject, pGameObject, goCheck);
TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectWithDbGUIDCheck>, GridTypeMapContainer > objectChecker(checker);
cell.Visit(p, objectChecker, *pSearchObject->GetMap());
return pGameObject;
}
/// 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_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 = sMapMgr.m_Transports.begin(); iter != sMapMgr.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;
std::string tableName = GetScriptsTableNameByType(step.script->type);
std::string commandName = GetScriptCommandName(step.script->command);
switch (step.script->command)
{
case SCRIPT_COMMAND_TALK:
if (step.script->Talk.ChatType > CHAT_TYPE_WHISPER && step.script->Talk.ChatType != CHAT_MSG_RAID_BOSS_WHISPER)
{
sLog.outError("%s invalid chat type (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->Talk.ChatType);
break;
}
if (step.script->Talk.Flags & SF_TALK_USE_PLAYER)
{
if (Player *pSource = _GetScriptPlayerSourceOrTarget(source, target, step.script))
{
uint64 targetGUID = target ? target->GetGUID() : 0;
LocaleConstant loc_idx = pSource->GetSession()->GetSessionDbLocaleIndex();
const std::string text(sObjectMgr.GetTrinityString(step.script->Talk.TextID, loc_idx));
switch (step.script->Talk.ChatType)
{
case CHAT_TYPE_SAY:
pSource->Say(text, LANG_UNIVERSAL);
break;
case CHAT_TYPE_YELL:
pSource->Yell(text, LANG_UNIVERSAL);
break;
case CHAT_TYPE_TEXT_EMOTE:
case CHAT_TYPE_BOSS_EMOTE:
pSource->TextEmote(text);
break;
case CHAT_TYPE_WHISPER:
case CHAT_MSG_RAID_BOSS_WHISPER:
if (!targetGUID || !IS_PLAYER_GUID(targetGUID))
{
sLog.outError("%s attempt to whisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str());
break;
}
pSource->Whisper(text, LANG_UNIVERSAL, targetGUID);
break;
default:
break; // must be already checked at load
}
}
}
else
{
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
uint64 targetGUID = target ? target->GetGUID() : 0;
switch (step.script->Talk.ChatType)
{
case CHAT_TYPE_SAY:
cSource->Say(step.script->Talk.TextID, LANG_UNIVERSAL, targetGUID);
break;
case CHAT_TYPE_YELL:
cSource->Yell(step.script->Talk.TextID, LANG_UNIVERSAL, targetGUID);
break;
case CHAT_TYPE_TEXT_EMOTE:
cSource->TextEmote(step.script->Talk.TextID, targetGUID);
break;
case CHAT_TYPE_BOSS_EMOTE:
cSource->MonsterTextEmote(step.script->Talk.TextID, targetGUID, true);
break;
case CHAT_TYPE_WHISPER:
if (!targetGUID || !IS_PLAYER_GUID(targetGUID))
{
sLog.outError("%s attempt to whisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str());
break;
}
cSource->Whisper(step.script->Talk.TextID, targetGUID);
break;
case CHAT_MSG_RAID_BOSS_WHISPER: //42
if (!targetGUID || !IS_PLAYER_GUID(targetGUID))
{
sLog.outError("%s attempt to raidbosswhisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str());
break;
}
cSource->MonsterWhisper(step.script->Talk.TextID, targetGUID, true);
break;
default:
break; // must be already checked at load
}
}
}
break;
case SCRIPT_COMMAND_EMOTE:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
if (step.script->Emote.Flags & SF_EMOTE_USE_STATE)
cSource->SetUInt32Value(UNIT_NPC_EMOTESTATE, step.script->Emote.EmoteID);
else
cSource->HandleEmoteCommand(step.script->Emote.EmoteID);
}
break;
case SCRIPT_COMMAND_FIELD_SET:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
// Validate field number.
if (step.script->FieldSet.FieldID <= OBJECT_FIELD_ENTRY || step.script->FieldSet.FieldID >= cSource->GetValuesCount())
sLog.outError("%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.",
step.script->GetDebugInfo().c_str(), step.script->FieldSet.FieldID,
cSource->GetValuesCount(), cSource->GetTypeId(), cSource->GetEntry(), cSource->GetGUIDLow());
else
cSource->SetUInt32Value(step.script->FieldSet.FieldID, step.script->FieldSet.FieldValue);
}
break;
case SCRIPT_COMMAND_MOVE_TO:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
cSource->SendMonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, step.script->MoveTo.TravelTime);
cSource->GetMap()->CreatureRelocation(cSource, step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, 0);
}
break;
case SCRIPT_COMMAND_FLAG_SET:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
// Validate field number.
if (step.script->FlagToggle.FieldID <= OBJECT_FIELD_ENTRY || step.script->FlagToggle.FieldID >= cSource->GetValuesCount())
sLog.outError("%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.",
step.script->GetDebugInfo().c_str(), step.script->FlagToggle.FieldID,
source->GetValuesCount(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow());
else
cSource->SetFlag(step.script->FlagToggle.FieldID, step.script->FlagToggle.FieldValue);
}
break;
case SCRIPT_COMMAND_FLAG_REMOVE:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
// Validate field number.
if (step.script->FlagToggle.FieldID <= OBJECT_FIELD_ENTRY || step.script->FlagToggle.FieldID >= cSource->GetValuesCount())
sLog.outError("%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.",
step.script->GetDebugInfo().c_str(), step.script->FlagToggle.FieldID,
source->GetValuesCount(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow());
else
cSource->RemoveFlag(step.script->FlagToggle.FieldID, step.script->FlagToggle.FieldValue);
}
break;
case SCRIPT_COMMAND_TELEPORT_TO:
if (step.script->TeleportTo.Flags & SF_TELEPORT_USE_CREATURE)
{
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true))
cSource->NearTeleportTo(step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation);
}
else
{
// Source or target must be Player.
if (Player *pSource = _GetScriptPlayerSourceOrTarget(source, target, step.script))
pSource->TeleportTo(step.script->TeleportTo.MapID, step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation);
}
break;
case SCRIPT_COMMAND_QUEST_EXPLORED:
{
if (!source)
{
sLog.outError("%s source object is NULL.", step.script->GetDebugInfo().c_str());
break;
}
if (!target)
{
sLog.outError("%s target object is NULL.", step.script->GetDebugInfo().c_str());
break;
}
// when script called for item spell casting then target == (unit or GO) and source is player
WorldObject* worldObject;
Player* pTarget = target->ToPlayer();
if (pTarget)
{
if (source->GetTypeId() != TYPEID_UNIT && source->GetTypeId() != TYPEID_GAMEOBJECT && source->GetTypeId() != TYPEID_PLAYER)
{
sLog.outError("%s source is not unit, gameobject or player (TypeId: %u, Entry: %u, GUID: %u), skipping.",
step.script->GetDebugInfo().c_str(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow());
break;
}
worldObject = dynamic_cast<WorldObject*>(source);
}
else
{
pTarget = source->ToPlayer();
if (pTarget)
{
if (target->GetTypeId() != TYPEID_UNIT && target->GetTypeId() != TYPEID_GAMEOBJECT && target->GetTypeId() != TYPEID_PLAYER)
{
sLog.outError("%s target is not unit, gameobject or player (TypeId: %u, Entry: %u, GUID: %u), skipping.",
step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUIDLow());
break;
}
worldObject = dynamic_cast<WorldObject*>(target);
}
else
{
sLog.outError("%s neither source nor target is player (source: TypeId: %u, Entry: %u, GUID: %u; target: TypeId: %u, Entry: %u, GUID: %u), skipping.",
step.script->GetDebugInfo().c_str(),
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUIDLow() : 0,
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUIDLow() : 0);
break;
}
}
// quest id and flags checked at script loading
if ((worldObject->GetTypeId() != TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) &&
(step.script->QuestExplored.Distance == 0 || worldObject->IsWithinDistInMap(pTarget, float(step.script->QuestExplored.Distance))))
pTarget->AreaExploredOrEventHappens(step.script->QuestExplored.QuestID);
else
pTarget->FailQuest(step.script->QuestExplored.QuestID);
break;
}
case SCRIPT_COMMAND_KILL_CREDIT:
// Source or target must be Player.
if (Player *pSource = _GetScriptPlayerSourceOrTarget(source, target, step.script))
{
if (step.script->KillCredit.Flags & SF_KILLCREDIT_REWARD_GROUP)
pSource->RewardPlayerAndGroupAtEvent(step.script->KillCredit.CreatureEntry, pSource);
else
pSource->KilledMonsterCredit(step.script->KillCredit.CreatureEntry, 0);
}
break;
case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
if (!step.script->RespawnGameobject.GOGuid)
{
sLog.outError("%s gameobject guid (datalong) is not specified.", step.script->GetDebugInfo().c_str());
break;
}
// Source or target must be WorldObject.
if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script))
{
GameObject *pGO = _FindGameObject(pSummoner, step.script->RespawnGameobject.GOGuid);
if (!pGO)
{
sLog.outError("%s gameobject was not found (guid: %u).", step.script->GetDebugInfo().c_str(), step.script->RespawnGameobject.GOGuid);
break;
}
if (pGO->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE ||
pGO->GetGoType() == GAMEOBJECT_TYPE_DOOR ||
pGO->GetGoType() == GAMEOBJECT_TYPE_BUTTON ||
pGO->GetGoType() == GAMEOBJECT_TYPE_TRAP)
{
sLog.outError("%s can not be used with gameobject of type %u (guid: %u).",
step.script->GetDebugInfo().c_str(), uint32(pGO->GetGoType()), step.script->RespawnGameobject.GOGuid);
break;
}
// Check that GO is not spawned
if (!pGO->isSpawned())
{
int32 nTimeToDespawn = std::max(5, int32(step.script->RespawnGameobject.DespawnDelay));
pGO->SetLootState(GO_READY);
pGO->SetRespawnTime(nTimeToDespawn);
pGO->GetMap()->Add(pGO);
}
}
break;
case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
{
// Source must be WorldObject.
if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script))
{
if (!step.script->TempSummonCreature.CreatureEntry)
sLog.outError("%s creature entry (datalong) is not specified.", step.script->GetDebugInfo().c_str());
else
{
float x = step.script->TempSummonCreature.PosX;
float y = step.script->TempSummonCreature.PosY;
float z = step.script->TempSummonCreature.PosZ;
float o = step.script->TempSummonCreature.Orientation;
if (!pSummoner->SummonCreature(step.script->TempSummonCreature.CreatureEntry, x, y, z, o, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, step.script->TempSummonCreature.DespawnDelay))
sLog.outError("%s creature was not spawned (entry: %u).", step.script->GetDebugInfo().c_str(), step.script->TempSummonCreature.CreatureEntry);
}
}
break;
}
case SCRIPT_COMMAND_OPEN_DOOR:
case SCRIPT_COMMAND_CLOSE_DOOR:
_ScriptProcessDoor(source, target, step.script);
break;
case SCRIPT_COMMAND_ACTIVATE_OBJECT:
// Source must be Unit.
if (Unit *pSource = _GetScriptUnit(source, true, step.script))
{
// Target must be GameObject.
if (!target)
{
sLog.outError("%s target object is NULL.", step.script->GetDebugInfo().c_str());
break;
}
if (target->GetTypeId() != TYPEID_GAMEOBJECT)
{
sLog.outError("%s target object is not gameobject (TypeId: %u, Entry: %u, GUID: %u), skipping.",
step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUIDLow());
break;
}
if (GameObject *pGO = dynamic_cast<GameObject*>(target))
pGO->Use(pSource);
}
break;
case SCRIPT_COMMAND_REMOVE_AURA:
{
// Source (datalong2 != 0) or target (datalong2 == 0) must be Unit.
bool bReverse = step.script->RemoveAura.Flags & SF_REMOVEAURA_REVERSE;
if (Unit *pTarget = _GetScriptUnit(bReverse ? source : target, bReverse, step.script))
pTarget->RemoveAurasDueToSpell(step.script->RemoveAura.SpellID);
break;
}
case SCRIPT_COMMAND_CAST_SPELL:
{
// TODO: Allow gameobjects to be targets and casters
if (!source && !target)
{
sLog.outError("%s source and target objects are NULL.", step.script->GetDebugInfo().c_str());
break;
}
Unit* uSource = NULL;
Unit* uTarget = NULL;
// source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s
switch (step.script->CastSpell.Flags)
{
case SF_CASTSPELL_SOURCE_TO_TARGET: // source -> target
uSource = dynamic_cast<Unit*>(source);
uTarget = dynamic_cast<Unit*>(target);
break;
case SF_CASTSPELL_SOURCE_TO_SOURCE: // source -> source
uSource = dynamic_cast<Unit*>(source);
uTarget = uSource;
break;
case SF_CASTSPELL_TARGET_TO_TARGET: // target -> target
uSource = dynamic_cast<Unit*>(target);
uTarget = uSource;
break;
case SF_CASTSPELL_TARGET_TO_SOURCE: // target -> source
uSource = dynamic_cast<Unit*>(target);
uTarget = dynamic_cast<Unit*>(source);
break;
case SF_CASTSPELL_SEARCH_CREATURE: // source -> creature with entry
uSource = dynamic_cast<Unit*>(source);
uTarget = GetClosestCreatureWithEntry(uSource, abs(step.script->CastSpell.CreatureEntry), step.script->CastSpell.SearchRadius);
break;
}
if (!uSource || !uSource->isType(TYPEMASK_UNIT))
{
sLog.outError("%s no source unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->CastSpell.SpellID);
break;
}
if (!uTarget || !uTarget->isType(TYPEMASK_UNIT))
{
sLog.outError("%s no target unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->CastSpell.SpellID);
break;
}
bool triggered = (step.script->CastSpell.Flags != 4) ?
step.script->CastSpell.CreatureEntry & SF_CASTSPELL_TRIGGERED :
step.script->CastSpell.CreatureEntry < 0;
uSource->CastSpell(uTarget, step.script->CastSpell.SpellID, triggered);
break;
}
case SCRIPT_COMMAND_PLAY_SOUND:
// Source must be WorldObject.
if (WorldObject* pSource = _GetScriptWorldObject(source, true, step.script))
{
// PlaySound.Flags bitmask: 0/1=anyone/target
Player* pTarget = NULL;
if (step.script->PlaySound.Flags & SF_PLAYSOUND_TARGET_PLAYER)
{
// Target must be Player.
pTarget = _GetScriptPlayer(target, false, step.script);
if (!pTarget)
break;
}
// PlaySound.Flags bitmask: 0/2=without/with distance dependent
if (step.script->PlaySound.Flags & SF_PLAYSOUND_DISTANCE_SOUND)
pSource->PlayDistanceSound(step.script->PlaySound.SoundID, pTarget);
else
pSource->PlayDirectSound(step.script->PlaySound.SoundID, pTarget);
}
break;
case SCRIPT_COMMAND_CREATE_ITEM:
// Target or source must be Player.
if (Player* pReceiver = _GetScriptPlayerSourceOrTarget(source, target, step.script))
{
ItemPosCountVec dest;
uint8 msg = pReceiver->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, step.script->CreateItem.ItemEntry, step.script->CreateItem.Amount);
if (msg == EQUIP_ERR_OK)
{
if (Item* item = pReceiver->StoreNewItem(dest, step.script->CreateItem.ItemEntry, true))
pReceiver->SendNewItem(item, step.script->CreateItem.Amount, false, true);
}
else
pReceiver->SendEquipError(msg, NULL, NULL, step.script->CreateItem.ItemEntry);
}
break;
case SCRIPT_COMMAND_DESPAWN_SELF:
// Target or source must be Creature.
if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true))
cSource->ForcedDespawn(step.script->DespawnSelf.DespawnDelay);
break;
case SCRIPT_COMMAND_LOAD_PATH:
// Source must be Unit.
if (Unit* pSource = _GetScriptUnit(source, true, step.script))
{
if (!sWaypointMgr->GetPath(step.script->LoadPath.PathID))
sLog.outError("%s source object has an invalid path (%u), skipping.", step.script->GetDebugInfo().c_str(), step.script->LoadPath.PathID);
else
pSource->GetMotionMaster()->MovePath(step.script->LoadPath.PathID, step.script->LoadPath.IsRepeatable);
}
break;
case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT:
{
if (!step.script->CallScript.CreatureEntry)
{
sLog.outError("%s creature entry is not specified, skipping.", step.script->GetDebugInfo().c_str());
break;
}
if (!step.script->CallScript.ScriptID)
{
sLog.outError("%s script id is not specified, skipping.", step.script->GetDebugInfo().c_str());
break;
}
Creature* cTarget;
if (source) //using grid searcher
{
WorldObject* wSource = dynamic_cast <WorldObject*> (source);
CellPair p(Trinity::ComputeCellPair(wSource->GetPositionX(), wSource->GetPositionY()));
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
Trinity::CreatureWithDbGUIDCheck target_check(wSource, step.script->CallScript.CreatureEntry);
Trinity::CreatureSearcher<Trinity::CreatureWithDbGUIDCheck> checker(wSource, cTarget, target_check);
TypeContainerVisitor<Trinity::CreatureSearcher <Trinity::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker);
cell.Visit(p, unit_checker, *wSource->GetMap());
}
else //check hashmap holders
{
if (CreatureData const* data = sObjectMgr.GetCreatureData(step.script->CallScript.CreatureEntry))
cTarget = ObjectAccessor::GetObjectInWorld<Creature>(data->mapid, data->posX, data->posY, MAKE_NEW_GUID(step.script->CallScript.CreatureEntry, data->id, HIGHGUID_UNIT), cTarget);
}
if (!cTarget)
{
sLog.outError("%s target was not found (entry: %u)", step.script->GetDebugInfo().c_str(), step.script->CallScript.CreatureEntry);
break;
}
//Lets choose our ScriptMap map
ScriptMapMap *datamap = GetScriptsMapByType(ScriptsType(step.script->CallScript.ScriptType));
//if no scriptmap present...
if (!datamap)
{
sLog.outError("%s unknown scriptmap (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->CallScript.ScriptType);
break;
}
// Insert script into schedule but do not start it
ScriptsStart(*datamap, step.script->CallScript.ScriptID, cTarget, NULL);
break;
}
case SCRIPT_COMMAND_KILL:
// Source or target must be Creature.
if (Creature *cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script))
{
if (cSource->isDead())
sLog.outError("%s creature is already dead (Entry: %u, GUID: %u)",
step.script->GetDebugInfo().c_str(), cSource->GetEntry(), cSource->GetGUIDLow());
else
{
cSource->setDeathState(JUST_DIED);
if (step.script->Kill.RemoveCorpse == 1)
cSource->RemoveCorpse();
}
}
break;
case SCRIPT_COMMAND_ORIENTATION:
// Source must be Unit.
if (Unit *pSource = _GetScriptUnit(source, true, step.script))
{
if (step.script->Orientation.Flags& SF_ORIENTATION_FACE_TARGET)
{
// Target must be Unit.
Unit* pTarget = _GetScriptUnit(target, false, step.script);
if (!pTarget)
break;
pSource->SetInFront(pTarget);
}
else
pSource->SetOrientation(step.script->Orientation.Orientation);
pSource->SendMovementFlagUpdate();
}
break;
case SCRIPT_COMMAND_EQUIP:
// Source must be Creature.
if (Creature *cSource = _GetScriptCreature(source, true, step.script))
cSource->LoadEquipment(step.script->Equip.EquipmentID);
break;
case SCRIPT_COMMAND_MODEL:
// Source must be Creature.
if (Creature *cSource = _GetScriptCreature(source, true, step.script))
cSource->SetDisplayId(step.script->Model.ModelID);
break;
case SCRIPT_COMMAND_CLOSE_GOSSIP:
// Source must be Player.
if (Player *pSource = _GetScriptPlayer(source, true, step.script))
pSource->PlayerTalkClass->CloseGossip();
break;
case SCRIPT_COMMAND_PLAYMOVIE:
// Source must be Player.
if (Player *pSource = _GetScriptPlayer(source, true, step.script))
pSource->SendMovieStart(step.script->PlayMovie.MovieID);
break;
default:
sLog.outError("Unknown script command %s.", step.script->GetDebugInfo().c_str());
break;
}
m_scriptSchedule.erase(iter);
sWorld.DecreaseScheduledScriptCount();
iter = m_scriptSchedule.begin();
}
}

View File

@@ -41,7 +41,6 @@ class Object;
class WorldPacket;
class WorldSession;
class Player;
struct ScriptAction;
struct ScriptInfo;
class WorldSocket;
class SystemMgr;