diff options
| author | azazel <none@none> | 2010-09-22 18:13:57 +0600 |
|---|---|---|
| committer | azazel <none@none> | 2010-09-22 18:13:57 +0600 |
| commit | eae0e5c822d979694f5d686269391c4643bc9fcf (patch) | |
| tree | 45fa2324df331c0a43bd2a16efe74591dfeef196 /src | |
| parent | 562a8c272d2402a870a0f7a51b0742cc1e4d9192 (diff) | |
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
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 222 | ||||
| -rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 220 | ||||
| -rw-r--r-- | src/server/game/Maps/Map.cpp | 949 | ||||
| -rw-r--r-- | src/server/game/Maps/Map.h | 8 | ||||
| -rw-r--r-- | src/server/game/Scripting/MapScripts.cpp | 944 | ||||
| -rw-r--r-- | src/server/game/World/World.h | 1 |
6 files changed, 1284 insertions, 1060 deletions
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index c67c3e214e4..4d2eac5b898 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -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_KILL_CREDIT: + case SCRIPT_COMMAND_QUEST_EXPLORED: { - if (!GetCreatureTemplate(tmp.datalong)) + Quest const* quest = GetQuestTemplate(tmp.QuestExplored.QuestID); + if (!quest) { - 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); + 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; } - break; - } - case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: - { - if (!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o)) + if (!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT)) { - 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); + 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 (!GetCreatureTemplate(tmp.datalong)) + if (tmp.QuestExplored.Distance && float(tmp.QuestExplored.Distance) > DEFAULT_VISIBILITY_DISTANCE) { - 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); + 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.KillCredit.CreatureEntry)) + { + sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_KILL_CREDIT for script id %u", + 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,77 +4877,53 @@ 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_OPEN_DOOR: - case SCRIPT_COMMAND_CLOSE_DOOR: - { - GameObjectData const* data = GetGOData(tmp.datalong); - 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); - continue; - } - GameObjectInfo const* info = GetGameObjectInfo(data->id); - if (!info) + 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 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); + 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 (info->type != GAMEOBJECT_TYPE_DOOR) + if (!GetCreatureTemplate(tmp.TempSummonCreature.CreatureEntry)) { - 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); + 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_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) + case SCRIPT_COMMAND_OPEN_DOOR: + case SCRIPT_COMMAND_CLOSE_DOOR: + { + GameObjectData const* data = GetGOData(tmp.ToggleDoor.GOGuid); + if (!data) { - 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); + sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u", + tableName.c_str(), tmp.ToggleDoor.GOGuid, GetScriptCommandName(tmp.command).c_str(), tmp.id); continue; } - if (tmp.datalong2 && float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE) + GameObjectInfo const* info = GetGameObjectInfo(data->id); + if (!info) { - 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); + sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u", + tableName.c_str(), tmp.ToggleDoor.GOGuid, data->id, GetScriptCommandName(tmp.command).c_str(), tmp.id); continue; } - if (tmp.datalong2 && float(tmp.datalong2) < INTERACTION_DISTANCE) + if (info->type != GAMEOBJECT_TYPE_DOOR) { - 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; diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 2520b2399d2..7c02a3e6b36 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -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; }; diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 085c9957c66..c5698b41584 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -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 "Map.h" #include "GridStates.h" +#include "ScriptMgr.h" +#include "VMapFactory.h" +#include "MapInstanced.h" #include "CellImpl.h" -#include "InstanceScript.h" -#include "Map.h" +#include "GridNotifiers.h" #include "GridNotifiersImpl.h" -#include "Config.h" #include "Transport.h" +#include "InstanceScript.h" #include "ObjectAccessor.h" +#include "MapManager.h" #include "ObjectMgr.h" -#include "World.h" -#include "Group.h" -#include "MapRefManager.h" -#include "Vehicle.h" -#include "WaypointManager.h" -#include "DBCEnums.h" -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "GossipDef.h" -#include "ScriptMgr.h" -#include "MapInstanced.h" -#include "InstanceSaveMgr.h" -#include "VMapFactory.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) { diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 568a6ea57a3..cad72c8b98e 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -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 //****************************************** diff --git a/src/server/game/Scripting/MapScripts.cpp b/src/server/game/Scripting/MapScripts.cpp new file mode 100644 index 00000000000..727f764ff3f --- /dev/null +++ b/src/server/game/Scripting/MapScripts.cpp @@ -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(); + } +} diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 34ccd57bb1c..498ddf0b7de 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -41,7 +41,6 @@ class Object; class WorldPacket; class WorldSession; class Player; -struct ScriptAction; struct ScriptInfo; class WorldSocket; class SystemMgr; |
