From 0d6f990e4efdf5bea03411d505e97a442e475171 Mon Sep 17 00:00:00 2001 From: zergtmn Date: Fri, 24 Dec 2010 00:23:31 +0500 Subject: [PATCH] [10912] Move scripting related functions from ObjectMgr to ScriptMgr --- src/bindings/universal/ScriptMgr.cpp | 1 + src/game/Creature.cpp | 3 +- src/game/GameObject.cpp | 1 + src/game/Level3.cpp | 14 +- src/game/Makefile.am | 2 + src/game/Map.cpp | 5 +- src/game/ObjectMgr.cpp | 873 +------------------------- src/game/ObjectMgr.h | 292 --------- src/game/Player.cpp | 1 + src/game/ScriptCalls.cpp | 2 +- src/game/ScriptCalls.h | 6 +- src/game/ScriptMgr.cpp | 899 +++++++++++++++++++++++++++ src/game/ScriptMgr.h | 330 ++++++++++ src/game/SpellEffects.cpp | 1 + src/game/Transports.cpp | 1 + src/game/WaypointManager.cpp | 1 + src/game/World.cpp | 23 +- src/game/pchdef.h | 1 + src/shared/revision_nr.h | 2 +- win/VC100/game.vcxproj | 2 + win/VC100/game.vcxproj.filters | 6 + win/VC80/game.vcproj | 8 + win/VC90/game.vcproj | 8 + 23 files changed, 1297 insertions(+), 1185 deletions(-) create mode 100644 src/game/ScriptMgr.cpp create mode 100644 src/game/ScriptMgr.h diff --git a/src/bindings/universal/ScriptMgr.cpp b/src/bindings/universal/ScriptMgr.cpp index a79a17636..e89dae536 100644 --- a/src/bindings/universal/ScriptMgr.cpp +++ b/src/bindings/universal/ScriptMgr.cpp @@ -23,6 +23,7 @@ #include "../../game/Player.h" #include "../../game/Map.h" #include "../../game/ObjectMgr.h" +#include "../../game/ScriptMgr.h" #include "../../game/SpellAuras.h" //uint8 loglevel = 0; diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 334f2af2a..242c0a11f 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -21,6 +21,7 @@ #include "WorldPacket.h" #include "World.h" #include "ObjectMgr.h" +#include "ScriptMgr.h" #include "ObjectGuid.h" #include "SpellMgr.h" #include "QuestDef.h" @@ -2167,7 +2168,7 @@ std::string Creature::GetAIName() const std::string Creature::GetScriptName() const { - return sObjectMgr.GetScriptName(GetScriptId()); + return sScriptMgr.GetScriptName(GetScriptId()); } uint32 Creature::GetScriptId() const diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp index a7daf67cc..694f09fed 100644 --- a/src/game/GameObject.cpp +++ b/src/game/GameObject.cpp @@ -36,6 +36,7 @@ #include "BattleGroundAV.h" #include "Util.h" #include "ScriptCalls.h" +#include "ScriptMgr.h" GameObject::GameObject() : WorldObject() { diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 3110f2cc0..8963e34b9 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -297,7 +297,7 @@ bool ChatHandler::HandleReloadGossipScriptsCommand(char* args) if (*args!='a') sLog.outString( "Re-Loading Scripts from `gossip_scripts`..."); - sObjectMgr.LoadGossipScripts(); + sScriptMgr.LoadGossipScripts(); if (*args!='a') SendGlobalSysMessage("DB table `gossip_scripts` reloaded."); @@ -702,7 +702,7 @@ bool ChatHandler::HandleReloadGameObjectScriptsCommand(char* args) if (*args!='a') sLog.outString( "Re-Loading Scripts from `gameobject_scripts`..."); - sObjectMgr.LoadGameObjectScripts(); + sScriptMgr.LoadGameObjectScripts(); if (*args!='a') SendGlobalSysMessage("DB table `gameobject_scripts` reloaded."); @@ -722,7 +722,7 @@ bool ChatHandler::HandleReloadEventScriptsCommand(char* args) if (*args!='a') sLog.outString( "Re-Loading Scripts from `event_scripts`..."); - sObjectMgr.LoadEventScripts(); + sScriptMgr.LoadEventScripts(); if (*args!='a') SendGlobalSysMessage("DB table `event_scripts` reloaded."); @@ -767,7 +767,7 @@ bool ChatHandler::HandleReloadQuestEndScriptsCommand(char* args) if (*args != 'a') sLog.outString( "Re-Loading Scripts from `quest_end_scripts`..."); - sObjectMgr.LoadQuestEndScripts(); + sScriptMgr.LoadQuestEndScripts(); if (*args != 'a') SendGlobalSysMessage("DB table `quest_end_scripts` reloaded."); @@ -787,7 +787,7 @@ bool ChatHandler::HandleReloadQuestStartScriptsCommand(char* args) if (*args != 'a') sLog.outString( "Re-Loading Scripts from `quest_start_scripts`..."); - sObjectMgr.LoadQuestStartScripts(); + sScriptMgr.LoadQuestStartScripts(); if (*args != 'a') SendGlobalSysMessage("DB table `quest_start_scripts` reloaded."); @@ -807,7 +807,7 @@ bool ChatHandler::HandleReloadSpellScriptsCommand(char* args) if (*args != 'a') sLog.outString( "Re-Loading Scripts from `spell_scripts`..."); - sObjectMgr.LoadSpellScripts(); + sScriptMgr.LoadSpellScripts(); if (*args != 'a') SendGlobalSysMessage("DB table `spell_scripts` reloaded."); @@ -818,7 +818,7 @@ bool ChatHandler::HandleReloadSpellScriptsCommand(char* args) bool ChatHandler::HandleReloadDbScriptStringCommand(char* /*args*/) { sLog.outString( "Re-Loading Script strings from `db_script_string`..."); - sObjectMgr.LoadDbScriptStrings(); + sScriptMgr.LoadDbScriptStrings(); SendGlobalSysMessage("DB table `db_script_string` reloaded."); return true; } diff --git a/src/game/Makefile.am b/src/game/Makefile.am index a1c6b7187..c88cd2a75 100644 --- a/src/game/Makefile.am +++ b/src/game/Makefile.am @@ -235,6 +235,8 @@ libmangosgame_a_SOURCES = \ ReputationMgr.h \ ScriptCalls.cpp \ ScriptCalls.h \ + ScriptMgr.cpp \ + ScriptMgr.h \ SharedDefines.h \ SkillHandler.cpp \ SpellAuraDefines.h \ diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 94b629158..9ec26167a 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -31,6 +31,7 @@ #include "ObjectMgr.h" #include "World.h" #include "ScriptCalls.h" +#include "ScriptMgr.h" #include "Group.h" #include "MapRefManager.h" #include "DBCEnums.h" @@ -1496,7 +1497,7 @@ void InstanceMap::CreateInstanceData(bool load) const char* data = fields[0].GetString(); if(data) { - DEBUG_LOG("Loading instance data for `%s` with id %u", sObjectMgr.GetScriptName(i_script_id), i_InstanceId); + DEBUG_LOG("Loading instance data for `%s` with id %u", sScriptMgr.GetScriptName(i_script_id), i_InstanceId); i_data->Load(data); } delete result; @@ -1504,7 +1505,7 @@ void InstanceMap::CreateInstanceData(bool load) } else { - DEBUG_LOG("New instance data, \"%s\" ,initialized!", sObjectMgr.GetScriptName(i_script_id)); + DEBUG_LOG("New instance data, \"%s\" ,initialized!", sScriptMgr.GetScriptName(i_script_id)); i_data->Initialize(); } } diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index ade2d4ddc..8b18ae4e6 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -25,6 +25,7 @@ #include "Log.h" #include "MapManager.h" #include "ObjectGuid.h" +#include "ScriptMgr.h" #include "SpellMgr.h" #include "UpdateMask.h" #include "World.h" @@ -51,14 +52,6 @@ INSTANTIATE_SINGLETON_1(ObjectMgr); -ScriptMapMap sQuestEndScripts; -ScriptMapMap sQuestStartScripts; -ScriptMapMap sSpellScripts; -ScriptMapMap sGameObjectScripts; -ScriptMapMap sEventScripts; -ScriptMapMap sGossipScripts; -ScriptMapMap sCreatureMovementScripts; - bool normalizePlayerName(std::string& name) { if(name.empty()) @@ -494,7 +487,7 @@ struct SQLCreatureLoader : public SQLStorageLoaderBase template void convert_from_str(uint32 /*field_pos*/, char const *src, D &dst) { - dst = D(sObjectMgr.GetScriptId(src)); + dst = D(sScriptMgr.GetScriptId(src)); } }; @@ -1870,7 +1863,7 @@ struct SQLItemLoader : public SQLStorageLoaderBase template void convert_from_str(uint32 /*field_pos*/, char const *src, D &dst) { - dst = D(sObjectMgr.GetScriptId(src)); + dst = D(sScriptMgr.GetScriptId(src)); } }; @@ -4553,594 +4546,6 @@ void ObjectMgr::LoadQuestLocales() sLog.outString( ">> Loaded %lu Quest locale strings", (unsigned long)mQuestLocaleMap.size() ); } -void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename) -{ - if (sWorld.IsScriptScheduled()) // function don't must be called in time scripts use. - return; - - sLog.outString("%s :", tablename); - - scripts.clear(); // need for reload support - - QueryResult *result = WorldDatabase.PQuery("SELECT id, delay, command, datalong, datalong2, datalong3, datalong4, data_flags, dataint, dataint2, dataint3, dataint4, x, y, z, o FROM %s", tablename); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u script definitions", count); - return; - } - - barGoLink bar((int)result->GetRowCount()); - - do - { - bar.step(); - - Field *fields = result->Fetch(); - ScriptInfo tmp; - tmp.id = fields[0].GetUInt32(); - tmp.delay = fields[1].GetUInt32(); - tmp.command = fields[2].GetUInt32(); - tmp.raw.data[0] = fields[3].GetUInt32(); - tmp.raw.data[1] = fields[4].GetUInt32(); - tmp.raw.data[2] = fields[5].GetUInt32(); - tmp.raw.data[3] = fields[6].GetUInt32(); - tmp.raw.data[4] = fields[7].GetUInt32(); - tmp.raw.data[5] = fields[8].GetInt32(); - tmp.raw.data[6] = fields[9].GetInt32(); - tmp.raw.data[7] = fields[10].GetInt32(); - tmp.raw.data[8] = fields[11].GetInt32(); - tmp.x = fields[12].GetFloat(); - tmp.y = fields[13].GetFloat(); - tmp.z = fields[14].GetFloat(); - tmp.o = fields[15].GetFloat(); - - // generic command args check - switch(tmp.command) - { - case SCRIPT_COMMAND_TALK: - { - if (tmp.talk.chatType > CHAT_TYPE_ZONE_YELL) - { - sLog.outErrorDb("Table `%s` has invalid CHAT_TYPE_ (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u", tablename, tmp.talk.chatType, tmp.id); - continue; - } - if (tmp.talk.creatureEntry && !GetCreatureTemplate(tmp.talk.creatureEntry)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_TALK for script id %u, but this creature_template does not exist.", tablename, tmp.talk.creatureEntry, tmp.id); - continue; - } - if (tmp.talk.creatureEntry && !tmp.talk.searchRadius) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_TALK for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.talk.creatureEntry, tmp.id, tmp.talk.searchRadius); - continue; - } - if (!GetLanguageDescByID(tmp.talk.language)) - { - sLog.outErrorDb("Table `%s` has datalong4 = %u in SCRIPT_COMMAND_TALK for script id %u, but this language does not exist.", tablename, tmp.talk.language, tmp.id); - continue; - } - if (tmp.talk.textId[0] == 0) - { - sLog.outErrorDb("Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u", tablename, tmp.talk.textId[0], tmp.id); - continue; - } - - for(int i = 0; i < MAX_TEXT_ID; ++i) - { - if (tmp.talk.textId[i] && (tmp.talk.textId[i] < MIN_DB_SCRIPT_STRING_ID || tmp.talk.textId[i] >= 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, tmp.talk.textId[i], MIN_DB_SCRIPT_STRING_ID, MAX_DB_SCRIPT_STRING_ID, tmp.id); - continue; - } - } - - // if (!GetMangosStringLocale(tmp.dataint)) will be checked after db_script_string loading - break; - } - case SCRIPT_COMMAND_EMOTE: - { - 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, tmp.emote.emoteId, tmp.id); - continue; - } - break; - } - case SCRIPT_COMMAND_TELEPORT_TO: - { - 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, tmp.teleportTo.mapId, tmp.id); - continue; - } - - if (!MaNGOS::IsValidMapCoord(tmp.x, tmp.y, tmp.z, tmp.o)) - { - sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u", tablename, tmp.x, tmp.y, 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, tmp.questExplored.questId, tmp.id); - continue; - } - - if (!quest->HasSpecialFlag(QUEST_SPECIAL_FLAG_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_SPECIAL_FLAG_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.", tablename, tmp.questExplored.questId, tmp.id); - - // this will prevent quest completing without objective - const_cast(quest)->SetSpecialFlag(QUEST_SPECIAL_FLAG_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, 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, 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, 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, tmp.killCredit.creatureEntry, tmp.id); - continue; - } - break; - } - case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: - { - GameObjectData const* data = GetGOData(tmp.GetGOGuid()); - if (!data) - { - sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u", tablename, tmp.GetGOGuid(), tmp.id); - continue; - } - - GameObjectInfo const* info = GetGameObjectInfo(data->id); - 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, tmp.GetGOGuid(), data->id, tmp.id); - continue; - } - - if (info->type == GAMEOBJECT_TYPE_FISHINGNODE || - info->type == GAMEOBJECT_TYPE_FISHINGHOLE || - info->type == GAMEOBJECT_TYPE_DOOR || - info->type == GAMEOBJECT_TYPE_BUTTON || - 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, info->id, tmp.id); - continue; - } - break; - } - case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: - { - if (!MaNGOS::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, tmp.x, tmp.y, tmp.id); - continue; - } - - if (!GetCreatureTemplate(tmp.summonCreature.creatureEntry)) - { - sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u", tablename, tmp.summonCreature.creatureEntry, tmp.id); - continue; - } - break; - } - case SCRIPT_COMMAND_OPEN_DOOR: - case SCRIPT_COMMAND_CLOSE_DOOR: - { - GameObjectData const* data = GetGOData(tmp.GetGOGuid()); - if (!data) - { - sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u", tablename, tmp.GetGOGuid(), (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) - { - sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u", tablename, tmp.GetGOGuid(), data->id, (tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"), 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, info->id, (tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"), tmp.id); - continue; - } - - break; - } - case SCRIPT_COMMAND_REMOVE_AURA: - { - if (!sSpellStore.LookupEntry(tmp.removeAura.spellId)) - { - sLog.outErrorDb("Table `%s` using nonexistent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u", - tablename, tmp.removeAura.spellId, tmp.id); - continue; - } - if (tmp.removeAura.isSourceTarget & ~0x1) // 1 bits (0,1) - { - sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u", - tablename, tmp.removeAura.isSourceTarget, tmp.id); - continue; - } - break; - } - case SCRIPT_COMMAND_CAST_SPELL: - { - if (!sSpellStore.LookupEntry(tmp.castSpell.spellId)) - { - sLog.outErrorDb("Table `%s` using nonexistent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u", - tablename, tmp.castSpell.spellId, tmp.id); - continue; - } - if (tmp.castSpell.flags & ~0x3) // 2 bits - { - sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u", - tablename, tmp.castSpell.flags, tmp.id); - continue; - } - break; - } - case SCRIPT_COMMAND_CREATE_ITEM: - { - if (!GetItemPrototype(tmp.createItem.itemEntry)) - { - sLog.outErrorDb("Table `%s` has nonexistent item (entry: %u) in SCRIPT_COMMAND_CREATE_ITEM for script id %u", - tablename, tmp.createItem.itemEntry, tmp.id); - continue; - } - if (!tmp.createItem.amount) - { - sLog.outErrorDb("Table `%s` SCRIPT_COMMAND_CREATE_ITEM but amount is %u for script id %u", - tablename, tmp.createItem.amount, tmp.id); - continue; - } - break; - } - case SCRIPT_COMMAND_DESPAWN_SELF: - { - // for later, we might consider despawn by database guid, and define in datalong2 as option to despawn self. - break; - } - case SCRIPT_COMMAND_PLAY_MOVIE: - { - if (!sMovieStore.LookupEntry(tmp.playMovie.movieId)) - { - sLog.outErrorDb("Table `%s` use non-existing movie_id (id: %u) in SCRIPT_COMMAND_PLAY_MOVIE for script id %u", - tablename, tmp.playMovie.movieId, tmp.id); - continue; - } - break; - } - case SCRIPT_COMMAND_MOVEMENT: - { - if (tmp.movement.movementType >= MAX_DB_MOTION_TYPE) - { - sLog.outErrorDb("Table `%s` SCRIPT_COMMAND_MOVEMENT has invalid MovementType %u for script id %u", - tablename, tmp.movement.movementType, tmp.id); - continue; - } - if (tmp.movement.creatureEntry && !GetCreatureTemplate(tmp.movement.creatureEntry)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOVEMENT for script id %u, but this creature_template does not exist.", tablename, tmp.movement.creatureEntry, tmp.id); - continue; - } - if (tmp.movement.creatureEntry && !tmp.movement.searchRadius) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOVEMENT for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.movement.creatureEntry, tmp.id, tmp.movement.searchRadius); - continue; - } - - break; - } - case SCRIPT_COMMAND_SET_ACTIVEOBJECT: - { - if (tmp.activeObject.creatureEntry && !GetCreatureTemplate(tmp.activeObject.creatureEntry)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_ACTIVEOBJECT for script id %u, but this creature_template does not exist.", tablename, tmp.activeObject.creatureEntry, tmp.id); - continue; - } - if (tmp.activeObject.creatureEntry && !tmp.activeObject.searchRadius) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_ACTIVEOBJECT for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.activeObject.creatureEntry, tmp.id, tmp.activeObject.searchRadius); - continue; - } - - break; - } - case SCRIPT_COMMAND_SET_FACTION: - { - if (tmp.faction.factionId && !sFactionStore.LookupEntry(tmp.faction.factionId)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_FACTION for script id %u, but this faction does not exist.", tablename, tmp.faction.factionId, tmp.id); - continue; - } - - if (tmp.faction.creatureEntry && !GetCreatureTemplate(tmp.faction.creatureEntry)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_FACTION for script id %u, but this creature_template does not exist.", tablename, tmp.faction.creatureEntry, tmp.id); - continue; - } - if (tmp.faction.creatureEntry && !tmp.faction.searchRadius) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_FACTION for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.faction.creatureEntry, tmp.id, tmp.faction.searchRadius); - continue; - } - - break; - } - case SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL: - { - if (tmp.morph.flags & 0x01) - { - if (tmp.morph.creatureOrModelEntry && !sCreatureDisplayInfoStore.LookupEntry(tmp.morph.creatureOrModelEntry)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL for script id %u, but this model does not exist.", tablename, tmp.morph.creatureOrModelEntry, tmp.id); - continue; - } - } - else - { - if (tmp.morph.creatureOrModelEntry && !GetCreatureTemplate(tmp.morph.creatureOrModelEntry)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL for script id %u, but this creature_template does not exist.", tablename, tmp.morph.creatureOrModelEntry, tmp.id); - continue; - } - } - - if (tmp.morph.creatureEntry && !GetCreatureTemplate(tmp.morph.creatureEntry)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL for script id %u, but this creature_template does not exist.", tablename, tmp.morph.creatureEntry, tmp.id); - continue; - } - if (tmp.morph.creatureEntry && !tmp.morph.searchRadius) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.morph.creatureEntry, tmp.id, tmp.morph.searchRadius); - continue; - } - - break; - } - case SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL: - { - if (tmp.mount.flags & 0x01) - { - if (tmp.mount.creatureOrModelEntry && !sCreatureDisplayInfoStore.LookupEntry(tmp.mount.creatureOrModelEntry)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL for script id %u, but this model does not exist.", tablename, tmp.mount.creatureOrModelEntry, tmp.id); - continue; - } - } - else - { - if (tmp.mount.creatureOrModelEntry && !GetCreatureTemplate(tmp.mount.creatureOrModelEntry)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL for script id %u, but this creature_template does not exist.", tablename, tmp.mount.creatureOrModelEntry, tmp.id); - continue; - } - } - - if (tmp.mount.creatureEntry && !GetCreatureTemplate(tmp.mount.creatureEntry)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL for script id %u, but this creature_template does not exist.", tablename, tmp.mount.creatureEntry, tmp.id); - continue; - } - if (tmp.mount.creatureEntry && !tmp.mount.searchRadius) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.mount.creatureEntry, tmp.id, tmp.mount.searchRadius); - continue; - } - - break; - } - case SCRIPT_COMMAND_SET_RUN: - { - if (tmp.run.creatureEntry && !GetCreatureTemplate(tmp.run.creatureEntry)) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_RUN for script id %u, but this creature_template does not exist.", tablename, tmp.run.creatureEntry, tmp.id); - continue; - } - if (tmp.run.creatureEntry && !tmp.run.searchRadius) - { - sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_RUN for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.run.creatureEntry, tmp.id, tmp.run.searchRadius); - continue; - } - - break; - } - } - - if (scripts.find(tmp.id) == scripts.end()) - { - ScriptMap emptyMap; - scripts[tmp.id] = emptyMap; - } - scripts[tmp.id].insert(ScriptMap::value_type(tmp.delay, tmp)); - - ++count; - } while(result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString(">> Loaded %u script definitions", count); -} - -void ObjectMgr::LoadGameObjectScripts() -{ - LoadScripts(sGameObjectScripts, "gameobject_scripts"); - - // check ids - for(ScriptMapMap::const_iterator itr = sGameObjectScripts.begin(); itr != sGameObjectScripts.end(); ++itr) - { - if (!GetGOData(itr->first)) - sLog.outErrorDb("Table `gameobject_scripts` has not existing gameobject (GUID: %u) as script id", itr->first); - } -} - -void ObjectMgr::LoadQuestEndScripts() -{ - LoadScripts(sQuestEndScripts, "quest_end_scripts"); - - // check ids - for(ScriptMapMap::const_iterator itr = sQuestEndScripts.begin(); itr != sQuestEndScripts.end(); ++itr) - { - if (!GetQuestTemplate(itr->first)) - sLog.outErrorDb("Table `quest_end_scripts` has not existing quest (Id: %u) as script id", itr->first); - } -} - -void ObjectMgr::LoadQuestStartScripts() -{ - LoadScripts(sQuestStartScripts, "quest_start_scripts"); - - // check ids - for(ScriptMapMap::const_iterator itr = sQuestStartScripts.begin(); itr != sQuestStartScripts.end(); ++itr) - { - if (!GetQuestTemplate(itr->first)) - sLog.outErrorDb("Table `quest_start_scripts` has not existing quest (Id: %u) as script id", itr->first); - } -} - -void ObjectMgr::LoadSpellScripts() -{ - LoadScripts(sSpellScripts, "spell_scripts"); - - // check ids - for(ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr) - { - SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first); - - if (!spellInfo) - { - sLog.outErrorDb("Table `spell_scripts` has not existing spell (Id: %u) as script id", itr->first); - continue; - } - - //check for correct spellEffect - bool found = false; - for(int i = 0; i < MAX_EFFECT_INDEX; ++i) - { - // skip empty effects - if (!spellInfo->Effect[i]) - continue; - - if (spellInfo->Effect[i] == SPELL_EFFECT_SCRIPT_EFFECT) - { - found = true; - break; - } - } - - if (!found) - sLog.outErrorDb("Table `spell_scripts` has unsupported spell (Id: %u) without SPELL_EFFECT_SCRIPT_EFFECT (%u) spell effect", itr->first, SPELL_EFFECT_SCRIPT_EFFECT); - } -} - -void ObjectMgr::LoadEventScripts() -{ - LoadScripts(sEventScripts, "event_scripts"); - - std::set evt_scripts; - - // Load all possible script entries from gameobjects - for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i) - if (GameObjectInfo const* goInfo = sGOStorage.LookupEntry(i)) - if (uint32 eventId = goInfo->GetEventScriptId()) - evt_scripts.insert(eventId); - - // Load all possible script entries from spells - for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) - { - SpellEntry const* spell = sSpellStore.LookupEntry(i); - if (spell) - { - for(int j = 0; j < MAX_EFFECT_INDEX; ++j) - { - if (spell->Effect[j] == SPELL_EFFECT_SEND_EVENT) - { - if (spell->EffectMiscValue[j]) - evt_scripts.insert(spell->EffectMiscValue[j]); - } - } - } - } - - for(size_t path_idx = 0; path_idx < sTaxiPathNodesByPath.size(); ++path_idx) - { - for(size_t node_idx = 0; node_idx < sTaxiPathNodesByPath[path_idx].size(); ++node_idx) - { - TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx]; - - if (node.arrivalEventID) - evt_scripts.insert(node.arrivalEventID); - - if (node.departureEventID) - evt_scripts.insert(node.departureEventID); - } - } - - // Then check if all scripts are in above list of possible script entries - for(ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr) - { - std::set::const_iterator itr2 = evt_scripts.find(itr->first); - if (itr2 == evt_scripts.end()) - sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field or any spell effect %u or path taxi node data", - itr->first, SPELL_EFFECT_SEND_EVENT); - } -} - -void ObjectMgr::LoadGossipScripts() -{ - LoadScripts(sGossipScripts, "gossip_scripts"); - - // checks are done in LoadGossipMenuItems -} - -void ObjectMgr::LoadCreatureMovementScripts() -{ - LoadScripts(sCreatureMovementScripts, "creature_movement_scripts"); - - // checks are done in WaypointManager::Load -} - void ObjectMgr::LoadPageTexts() { sPageTextStore.Free(); // for reload case @@ -5248,7 +4653,7 @@ struct SQLInstanceLoader : public SQLStorageLoaderBase template void convert_from_str(uint32 /*field_pos*/, char const *src, D &dst) { - dst = D(sObjectMgr.GetScriptId(src)); + dst = D(sScriptMgr.GetScriptId(src)); } }; @@ -5668,134 +5073,6 @@ void ObjectMgr::LoadTavernAreaTriggers() sLog.outString( ">> Loaded %u tavern triggers", count ); } -void ObjectMgr::LoadAreaTriggerScripts() -{ - m_AreaTriggerScripts.clear(); // need for reload case - QueryResult *result = WorldDatabase.Query("SELECT entry, ScriptName FROM scripted_areatrigger"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u scripted areatrigger", count); - return; - } - - barGoLink bar((int)result->GetRowCount()); - - do - { - ++count; - bar.step(); - - Field *fields = result->Fetch(); - - uint32 triggerId = fields[0].GetUInt32(); - const char *scriptName = fields[1].GetString(); - - if (!sAreaTriggerStore.LookupEntry(triggerId)) - { - sLog.outErrorDb("Table `scripted_areatrigger` has area trigger (ID: %u) not listed in `AreaTrigger.dbc`.", triggerId); - continue; - } - - m_AreaTriggerScripts[triggerId] = GetScriptId(scriptName); - } while(result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString(">> Loaded %u areatrigger scripts", count); -} - -void ObjectMgr::LoadEventIdScripts() -{ - m_EventIdScripts.clear(); // need for reload case - QueryResult *result = WorldDatabase.Query("SELECT id, ScriptName FROM scripted_event_id"); - - uint32 count = 0; - - if (!result) - { - barGoLink bar(1); - bar.step(); - - sLog.outString(); - sLog.outString(">> Loaded %u scripted event id", count); - return; - } - - barGoLink bar((int)result->GetRowCount()); - - // TODO: remove duplicate code below, same way to collect event id's used in LoadEventScripts() - std::set evt_scripts; - - // Load all possible event entries from gameobjects - for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i) - if (GameObjectInfo const* goInfo = sGOStorage.LookupEntry(i)) - if (uint32 eventId = goInfo->GetEventScriptId()) - evt_scripts.insert(eventId); - - // Load all possible event entries from spells - for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) - { - SpellEntry const* spell = sSpellStore.LookupEntry(i); - if (spell) - { - for(int j = 0; j < MAX_EFFECT_INDEX; ++j) - { - if (spell->Effect[j] == SPELL_EFFECT_SEND_EVENT) - { - if (spell->EffectMiscValue[j]) - evt_scripts.insert(spell->EffectMiscValue[j]); - } - } - } - } - - // Load all possible event entries from taxi path nodes - for(size_t path_idx = 0; path_idx < sTaxiPathNodesByPath.size(); ++path_idx) - { - for(size_t node_idx = 0; node_idx < sTaxiPathNodesByPath[path_idx].size(); ++node_idx) - { - TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx]; - - if (node.arrivalEventID) - evt_scripts.insert(node.arrivalEventID); - - if (node.departureEventID) - evt_scripts.insert(node.departureEventID); - } - } - - do - { - ++count; - bar.step(); - - Field *fields = result->Fetch(); - - uint32 eventId = fields[0].GetUInt32(); - const char *scriptName = fields[1].GetString(); - - std::set::const_iterator itr = evt_scripts.find(eventId); - if (itr == evt_scripts.end()) - sLog.outErrorDb("Table `scripted_event_id` has id %u not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field or any spell effect %u or path taxi node data", - eventId, SPELL_EFFECT_SEND_EVENT); - - m_EventIdScripts[eventId] = GetScriptId(scriptName); - } while(result->NextRow()); - - delete result; - - sLog.outString(); - sLog.outString(">> Loaded %u scripted event id", count); -} - uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid, Team team ) { bool found = false; @@ -6543,7 +5820,7 @@ struct SQLGameObjectLoader : public SQLStorageLoaderBase template void convert_from_str(uint32 /*field_pos*/, char const *src, D &dst) { - dst = D(sObjectMgr.GetScriptId(src)); + dst = D(sScriptMgr.GetScriptId(src)); } }; @@ -8215,24 +7492,6 @@ bool ObjectMgr::CheckDeclinedNames( std::wstring mainpart, DeclinedName const& n return true; } -uint32 ObjectMgr::GetAreaTriggerScriptId(uint32 triggerId) const -{ - AreaTriggerScriptMap::const_iterator itr = m_AreaTriggerScripts.find(triggerId); - if (itr != m_AreaTriggerScripts.end()) - return itr->second; - - return 0; -} - -uint32 ObjectMgr::GetEventIdScriptId(uint32 eventId) const -{ - EventIdScriptMap::const_iterator itr = m_EventIdScripts.find(eventId); - if (itr != m_EventIdScripts.end()) - return itr->second; - - return 0; -} - // Checks if player meets the condition bool PlayerCondition::Meets(Player const * player) const { @@ -9564,108 +8823,6 @@ bool ObjectMgr::IsVendorItemValid(bool isTemplate, char const* tableName, uint32 return true; } -void ObjectMgr::LoadScriptNames() -{ - m_scriptNames.push_back(""); - QueryResult *result = WorldDatabase.Query( - "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM item_template WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM scripted_areatrigger WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM scripted_event_id WHERE ScriptName <> '' " - "UNION " - "SELECT DISTINCT(ScriptName) FROM instance_template WHERE ScriptName <> ''"); - - if (!result) - { - barGoLink bar(1); - bar.step(); - sLog.outString(); - sLog.outErrorDb(">> Loaded empty set of Script Names!"); - return; - } - - barGoLink bar((int)result->GetRowCount()); - uint32 count = 0; - - do - { - bar.step(); - m_scriptNames.push_back((*result)[0].GetString()); - ++count; - } while (result->NextRow()); - delete result; - - std::sort(m_scriptNames.begin(), m_scriptNames.end()); - sLog.outString(); - sLog.outString( ">> Loaded %d Script Names", count ); -} - -uint32 ObjectMgr::GetScriptId(const char *name) const -{ - // use binary search to find the script name in the sorted vector - // assume "" is the first element - if (!name) - return 0; - - ScriptNameMap::const_iterator itr = - std::lower_bound(m_scriptNames.begin(), m_scriptNames.end(), name); - - if (itr == m_scriptNames.end() || *itr != name) - return 0; - - return uint32(itr - m_scriptNames.begin()); -} - -void ObjectMgr::CheckScriptTexts(ScriptMapMap const& scripts,std::set& ids) -{ - for(ScriptMapMap::const_iterator itrMM = scripts.begin(); itrMM != scripts.end(); ++itrMM) - { - for(ScriptMap::const_iterator itrM = itrMM->second.begin(); itrM != itrMM->second.end(); ++itrM) - { - if (itrM->second.command == SCRIPT_COMMAND_TALK) - { - for(int i = 0; i < MAX_TEXT_ID; ++i) - { - if (itrM->second.talk.textId[i] && !GetMangosStringLocale (itrM->second.talk.textId[i])) - sLog.outErrorDb( "Table `db_script_string` is missing string id %u, used in database script id %u.", itrM->second.talk.textId[i], itrMM->first); - - if (ids.find(itrM->second.talk.textId[i]) != ids.end()) - ids.erase(itrM->second.talk.textId[i]); - } - } - } - } -} - -void ObjectMgr::LoadDbScriptStrings() -{ - LoadMangosStrings(WorldDatabase,"db_script_string",MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID); - - std::set ids; - - for(int32 i = MIN_DB_SCRIPT_STRING_ID; i < MAX_DB_SCRIPT_STRING_ID; ++i) - if(GetMangosStringLocale(i)) - ids.insert(i); - - CheckScriptTexts(sQuestEndScripts,ids); - CheckScriptTexts(sQuestStartScripts,ids); - CheckScriptTexts(sSpellScripts,ids); - CheckScriptTexts(sGameObjectScripts,ids); - CheckScriptTexts(sEventScripts,ids); - CheckScriptTexts(sGossipScripts,ids); - CheckScriptTexts(sCreatureMovementScripts,ids); - - sWaypointMgr.CheckTextsExistance(ids); - - for(std::set::const_iterator itr = ids.begin(); itr != ids.end(); ++itr) - sLog.outErrorDb( "Table `db_script_string` has unused string id %u", *itr); -} - void ObjectMgr::AddGuild( Guild* guild ) { mGuildMap[guild->GetId()] = guild ; @@ -9697,16 +8854,6 @@ void ObjectMgr::RemoveArenaTeam( uint32 Id ) } // Functions for scripting access -uint32 GetAreaTriggerScriptId(uint32 triggerId) -{ - return sObjectMgr.GetAreaTriggerScriptId(triggerId); -} - -uint32 GetEventIdScriptId(uint32 eventId) -{ - return sObjectMgr.GetEventIdScriptId(eventId); -} - bool LoadMangosStrings(DatabaseType& db, char const* table,int32 start_value, int32 end_value) { // MAX_DB_SCRIPT_STRING_ID is max allowed negative value for scripts (scrpts can use only more deep negative values @@ -9720,16 +8867,6 @@ bool LoadMangosStrings(DatabaseType& db, char const* table,int32 start_value, in return sObjectMgr.LoadMangosStrings(db,table,start_value,end_value); } -uint32 MANGOS_DLL_SPEC GetScriptId(const char *name) -{ - return sObjectMgr.GetScriptId(name); -} - -ObjectMgr::ScriptNameMap const& GetScriptNames() -{ - return sObjectMgr.GetScriptNames(); -} - CreatureInfo const* GetCreatureTemplateStore(uint32 entry) { return sCreatureStorage.LookupEntry(entry); diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index 2697a5de2..331237a28 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -59,263 +59,6 @@ struct GameTele typedef UNORDERED_MAP GameTeleMap; -enum eScriptCommand -{ - SCRIPT_COMMAND_TALK = 0, // source = WorldObject, target = any/none, datalong (see enum ChatType for supported CHAT_TYPE_'s) - // datalong2 = creature entry (searching for a buddy, closest to source), datalong3 = creature search radius, datalong4 = language - // data_flags = flag_target_player_as_source = 0x01 - // flag_original_source_as_target = 0x02 - // flag_buddy_as_target = 0x04 - // dataint = text entry from db_script_string -table. dataint2-4 optional for random selected text. - SCRIPT_COMMAND_EMOTE = 1, // source = unit, datalong = emote_id - SCRIPT_COMMAND_FIELD_SET = 2, // source = any, datalong = field_id, datalong2 = value - SCRIPT_COMMAND_MOVE_TO = 3, // source = Creature, datalong2 = time, x/y/z - SCRIPT_COMMAND_FLAG_SET = 4, // source = any, datalong = field_id, datalong2 = bitmask - SCRIPT_COMMAND_FLAG_REMOVE = 5, // source = any, datalong = field_id, datalong2 = bitmask - SCRIPT_COMMAND_TELEPORT_TO = 6, // source or target with Player, datalong = map_id, x/y/z - SCRIPT_COMMAND_QUEST_EXPLORED = 7, // one from source or target must be Player, another GO/Creature, datalong=quest_id, datalong2=distance or 0 - SCRIPT_COMMAND_KILL_CREDIT = 8, // source or target with Player, datalong = creature entry, datalong2 = bool (0=personal credit, 1=group credit) - SCRIPT_COMMAND_RESPAWN_GAMEOBJECT = 9, // source = any (summoner), datalong=db_guid, datalong2=despawn_delay - SCRIPT_COMMAND_TEMP_SUMMON_CREATURE = 10, // source = any (summoner), datalong=creature entry, datalong2=despawn_delay - SCRIPT_COMMAND_OPEN_DOOR = 11, // source = unit, datalong=db_guid, datalong2=reset_delay - SCRIPT_COMMAND_CLOSE_DOOR = 12, // source = unit, datalong=db_guid, datalong2=reset_delay - SCRIPT_COMMAND_ACTIVATE_OBJECT = 13, // source = unit, target=GO - SCRIPT_COMMAND_REMOVE_AURA = 14, // source (datalong2!=0) or target (datalong==0) unit, datalong = spell_id - SCRIPT_COMMAND_CAST_SPELL = 15, // source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s - SCRIPT_COMMAND_PLAY_SOUND = 16, // source = any object, target=any/player, datalong (sound_id), datalong2 (bitmask: 0/1=anyone/target, 0/2=with distance dependent, so 1|2 = 3 is target with distance dependent) - SCRIPT_COMMAND_CREATE_ITEM = 17, // source or target must be player, datalong = item entry, datalong2 = amount - SCRIPT_COMMAND_DESPAWN_SELF = 18, // source or target must be creature, datalong = despawn delay - SCRIPT_COMMAND_PLAY_MOVIE = 19, // target can only be a player, datalog = movie id - SCRIPT_COMMAND_MOVEMENT = 20, // source or target must be creature. datalong = MovementType (0:idle, 1:random or 2:waypoint) - // datalong2 = creature entry (searching for a buddy, closest to source), datalong3 = creature search radius - SCRIPT_COMMAND_SET_ACTIVEOBJECT = 21, // source=any, target=creature - // datalong=bool 0=off, 1=on - // datalong2=creature entry, datalong3=search radius - SCRIPT_COMMAND_SET_FACTION = 22, // source=any, target=creature - // datalong=factionId, - // datalong2=creature entry, datalong3=search radius - SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL = 23, // source=any, target=creature - // datalong=creature entry/modelid (depend on data_flags) - // datalong2=creature entry, datalong3=search radius - // dataflags= 0x01 to use datalong value as modelid explicit - SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL = 24, // source=any, target=creature - // datalong=creature entry/modelid (depend on data_flags) - // datalong2=creature entry, datalong3=search radius - // dataflags= 0x01 to use datalong value as modelid explicit - SCRIPT_COMMAND_SET_RUN = 25, // source=any, target=creature - // datalong= bool 0=off, 1=on - // datalong2=creature entry, datalong3=search radius -}; - -#define MAX_TEXT_ID 4 // used for SCRIPT_COMMAND_TALK - -struct ScriptInfo -{ - uint32 id; - uint32 delay; - uint32 command; - - union - { - struct // SCRIPT_COMMAND_TALK (0) - { - uint32 chatType; // datalong - uint32 creatureEntry; // datalong2 - uint32 searchRadius; // datalong3 - uint32 language; // datalong4 - uint32 flags; // data_flags - int32 textId[MAX_TEXT_ID]; // dataint to dataint4 - } talk; - - struct // SCRIPT_COMMAND_EMOTE (1) - { - uint32 emoteId; // datalong - } emote; - - struct // SCRIPT_COMMAND_FIELD_SET (2) - { - uint32 fieldId; // datalong - uint32 fieldValue; // datalong2 - } setField; - - struct // SCRIPT_COMMAND_MOVE_TO (3) - { - uint32 unused1; // datalong - uint32 travelTime; // datalong2 - } moveTo; - - struct // SCRIPT_COMMAND_FLAG_SET (4) - { - uint32 fieldId; // datalong - uint32 fieldValue; // datalong2 - } setFlag; - - struct // SCRIPT_COMMAND_FLAG_REMOVE (5) - { - uint32 fieldId; // datalong - uint32 fieldValue; // datalong2 - } removeFlag; - - struct // SCRIPT_COMMAND_TELEPORT_TO (6) - { - uint32 mapId; // datalong - } teleportTo; - - struct // SCRIPT_COMMAND_QUEST_EXPLORED (7) - { - uint32 questId; // datalong - uint32 distance; // datalong2 - } questExplored; - - struct // SCRIPT_COMMAND_KILL_CREDIT (8) - { - uint32 creatureEntry; // datalong - uint32 isGroupCredit; // datalong2 - } killCredit; - - struct // SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (9) - { - uint32 goGuid; // datalong - int32 despawnDelay; // datalong2 - } respawnGo; - - struct // SCRIPT_COMMAND_TEMP_SUMMON_CREATURE (10) - { - uint32 creatureEntry; // datalong - uint32 despawnDelay; // datalong2 - uint32 unused1; // datalong3 - uint32 unused2; // datalong4 - uint32 flags; // data_flags - } summonCreature; - - struct // SCRIPT_COMMAND_OPEN_DOOR (11) - { - uint32 goGuid; // datalong - int32 resetDelay; // datalong2 - } openDoor; - - struct // SCRIPT_COMMAND_CLOSE_DOOR (12) - { - uint32 goGuid; // datalong - int32 resetDelay; // datalong2 - } closeDoor; - - // SCRIPT_COMMAND_ACTIVATE_OBJECT (13) - - struct // SCRIPT_COMMAND_REMOVE_AURA (14) - { - uint32 spellId; // datalong - uint32 isSourceTarget; // datalong2 - } removeAura; - - struct // SCRIPT_COMMAND_CAST_SPELL (15) - { - uint32 spellId; // datalong - uint32 flags; // datalong2 - } 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 - } despawn; - - struct // SCRIPT_COMMAND_PLAY_MOVIE (19) - { - uint32 movieId; // datalong - } playMovie; - - struct // SCRIPT_COMMAND_MOVEMENT (20) - { - uint32 movementType; // datalong - uint32 creatureEntry; // datalong2 - uint32 searchRadius; // datalong3 - } movement; - - struct // SCRIPT_COMMAND_SET_ACTIVEOBJECT (21) - { - uint32 activate; // datalong - uint32 creatureEntry; // datalong2 - uint32 searchRadius; // datalong3 - } activeObject; - - struct // SCRIPT_COMMAND_SET_FACTION (22) - { - uint32 factionId; // datalong - uint32 creatureEntry; // datalong2 - uint32 searchRadius; // datalong3 - } faction; - - struct // SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL (23) - { - uint32 creatureOrModelEntry; // datalong - uint32 creatureEntry; // datalong2 - uint32 searchRadius; // datalong3 - uint32 empty1; // datalong4 - uint32 flags; // data_flags - } morph; - - struct // SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL (24) - { - uint32 creatureOrModelEntry; // datalong - uint32 creatureEntry; // datalong2 - uint32 searchRadius; // datalong3 - uint32 empty1; // datalong4 - uint32 flags; // data_flags - } mount; - - struct // SCRIPT_COMMAND_SET_RUN (25) - { - uint32 run; // datalong - uint32 creatureEntry; // datalong2 - uint32 searchRadius; // datalong3 - } run; - - struct - { - uint32 data[9]; - } raw; - }; - - float x; - float y; - float z; - float o; - - // helpers - uint32 GetGOGuid() const - { - switch(command) - { - case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: return respawnGo.goGuid; - case SCRIPT_COMMAND_OPEN_DOOR: return openDoor.goGuid; - case SCRIPT_COMMAND_CLOSE_DOOR: return closeDoor.goGuid; - default: return 0; - } - } -}; - -typedef std::multimap ScriptMap; -typedef std::map ScriptMapMap; -extern ScriptMapMap sQuestEndScripts; -extern ScriptMapMap sQuestStartScripts; -extern ScriptMapMap sSpellScripts; -extern ScriptMapMap sGameObjectScripts; -extern ScriptMapMap sEventScripts; -extern ScriptMapMap sGossipScripts; -extern ScriptMapMap sCreatureMovementScripts; - struct SpellClickInfo { uint32 spellId; @@ -704,9 +447,6 @@ class ObjectMgr typedef UNORDERED_MAP AreaTriggerMap; - typedef UNORDERED_MAP AreaTriggerScriptMap; - typedef UNORDERED_MAP EventIdScriptMap; - typedef UNORDERED_MAP RepRewardRateMap; typedef UNORDERED_MAP RepOnKillMap; typedef UNORDERED_MAP RepSpilloverTemplateMap; @@ -715,8 +455,6 @@ class ObjectMgr typedef UNORDERED_MAP WeatherZoneMap; - typedef std::vector ScriptNameMap; - Player* GetPlayer(const char* name) const { return ObjectAccessor::FindPlayerByName(name);} Player* GetPlayer(ObjectGuid guid) const { return ObjectAccessor::FindPlayer(guid); } @@ -839,9 +577,6 @@ class ObjectMgr AreaTrigger const* GetGoBackTrigger(uint32 Map) const; AreaTrigger const* GetMapEntranceTrigger(uint32 Map) const; - uint32 GetAreaTriggerScriptId(uint32 triggerId) const; - uint32 GetEventIdScriptId(uint32 eventId) const; - RepRewardRate const* GetRepRewardRate(uint32 factionId) const { RepRewardRateMap::const_iterator itr = m_RepRewardRateMap.find(factionId); @@ -900,17 +635,8 @@ class ObjectMgr void LoadCreatureQuestRelations(); void LoadCreatureInvolvedRelations(); - void LoadGameObjectScripts(); - void LoadQuestEndScripts(); - void LoadQuestStartScripts(); - void LoadEventScripts(); - void LoadSpellScripts(); - void LoadGossipScripts(); - void LoadCreatureMovementScripts(); - bool LoadMangosStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value); bool LoadMangosStrings() { return LoadMangosStrings(WorldDatabase,"mangos_string",MIN_MANGOS_STRING_ID,MAX_MANGOS_STRING_ID); } - void LoadDbScriptStrings(); void LoadCreatureLocales(); void LoadCreatureTemplates(); void LoadCreatures(); @@ -938,8 +664,6 @@ class ObjectMgr void LoadAreaTriggerTeleports(); void LoadQuestAreaTriggers(); - void LoadAreaTriggerScripts(); - void LoadEventIdScripts(); void LoadTavernAreaTriggers(); void LoadGameObjectForQuests(); @@ -1241,11 +965,6 @@ class ObjectMgr bool RemoveVendorItem(uint32 entry,uint32 item); bool IsVendorItemValid(bool isTemplate, char const* tableName, uint32 vendor_entry, uint32 item, uint32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* pl = NULL, std::set* skip_vendors = NULL) const; - void LoadScriptNames(); - ScriptNameMap const& GetScriptNames() const { return m_scriptNames; } - const char* GetScriptName(uint32 id) const { return id < m_scriptNames.size() ? m_scriptNames[id].c_str() : ""; } - uint32 GetScriptId(const char *name) const; - int GetOrNewIndexForLocale(LocaleConstant loc); SpellClickInfoMapBounds GetSpellClickInfoMapBounds(uint32 creature_id) const @@ -1345,9 +1064,6 @@ class ObjectMgr GossipTextMap mGossipText; AreaTriggerMap mAreaTriggers; - AreaTriggerScriptMap m_AreaTriggerScripts; - EventIdScriptMap m_EventIdScripts; - RepRewardRateMap m_RepRewardRateMap; RepOnKillMap mRepOnKill; RepSpilloverTemplateMap m_RepSpilloverTemplateMap; @@ -1368,8 +1084,6 @@ class ObjectMgr GameTeleMap m_GameTeleMap; - ScriptNameMap m_scriptNames; - SpellClickInfoMap mSpellClickInfoMap; ItemConvertMap m_ItemConvert; @@ -1388,8 +1102,6 @@ class ObjectMgr int DBCLocaleIndex; private: - void LoadScripts(ScriptMapMap& scripts, char const* tablename); - void CheckScriptTexts(ScriptMapMap const& scripts,std::set& ids); void LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment); void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr); void LoadQuestRelationsHelper(QuestRelationsMap& map, char const* table); @@ -1452,10 +1164,6 @@ class ObjectMgr // scripting access functions MANGOS_DLL_SPEC bool LoadMangosStrings(DatabaseType& db, char const* table,int32 start_value = MAX_CREATURE_AI_TEXT_STRING_ID, int32 end_value = std::numeric_limits::min()); -MANGOS_DLL_SPEC uint32 GetAreaTriggerScriptId(uint32 triggerId); -MANGOS_DLL_SPEC uint32 GetEventIdScriptId(uint32 eventId); -MANGOS_DLL_SPEC uint32 GetScriptId(const char *name); -MANGOS_DLL_SPEC ObjectMgr::ScriptNameMap const& GetScriptNames(); MANGOS_DLL_SPEC CreatureInfo const* GetCreatureTemplateStore(uint32 entry); MANGOS_DLL_SPEC Quest const* GetQuestTemplateStore(uint32 entry); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 8cf5741cf..0af7375a9 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -56,6 +56,7 @@ #include "Chat.h" #include "Database/DatabaseImpl.h" #include "Spell.h" +#include "ScriptMgr.h" #include "SocialMgr.h" #include "AchievementMgr.h" #include "Mail.h" diff --git a/src/game/ScriptCalls.cpp b/src/game/ScriptCalls.cpp index 35f9b664b..10d121582 100644 --- a/src/game/ScriptCalls.cpp +++ b/src/game/ScriptCalls.cpp @@ -99,7 +99,7 @@ bool LoadScriptingModule(char const* libName) UnloadScriptingModule(); Script=testScript; - Script->ScriptsInit(sObjectMgr.GetScriptNames()); + Script->ScriptsInit(sScriptMgr.GetScriptNames()); sWorld.SetScriptsVersion(Script->ScriptsVersion()); diff --git a/src/game/ScriptCalls.h b/src/game/ScriptCalls.h index 54c5536a0..e82a07acb 100644 --- a/src/game/ScriptCalls.h +++ b/src/game/ScriptCalls.h @@ -21,13 +21,15 @@ #include "Common.h" #include "ObjectMgr.h" -#include "DBCEnums.h" +#include "ScriptMgr.h" +#include "DBCStructure.h" class Aura; class Creature; class CreatureAI; class GameObject; class Item; +class Object; class Player; class Quest; class Unit; @@ -38,7 +40,7 @@ class InstanceData; bool LoadScriptingModule(char const* libName = ""); void UnloadScriptingModule(); -typedef void(MANGOS_IMPORT * scriptCallScriptsInit) (const ObjectMgr::ScriptNameMap &scriptNames); +typedef void(MANGOS_IMPORT * scriptCallScriptsInit) (ScriptMgr::ScriptNameMap const& scriptNames); typedef void(MANGOS_IMPORT * scriptCallScriptsFree) (); typedef char const* (MANGOS_IMPORT * scriptCallScriptsVersion) (); diff --git a/src/game/ScriptMgr.cpp b/src/game/ScriptMgr.cpp new file mode 100644 index 000000000..7790a571e --- /dev/null +++ b/src/game/ScriptMgr.cpp @@ -0,0 +1,899 @@ +/* + * Copyright (C) 2005-2010 MaNGOS + * + * 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 "ScriptMgr.h" +#include "Policies/SingletonImp.h" +#include "Log.h" +#include "ProgressBar.h" +#include "ObjectMgr.h" +#include "WaypointManager.h" +#include "World.h" + +ScriptMapMap sQuestEndScripts; +ScriptMapMap sQuestStartScripts; +ScriptMapMap sSpellScripts; +ScriptMapMap sGameObjectScripts; +ScriptMapMap sEventScripts; +ScriptMapMap sGossipScripts; +ScriptMapMap sCreatureMovementScripts; + +INSTANTIATE_SINGLETON_1(ScriptMgr); + +ScriptMgr::ScriptMgr() +{ +} + +ScriptMgr::~ScriptMgr() +{ +} + +void ScriptMgr::LoadScripts(ScriptMapMap& scripts, const char* tablename) +{ + if (sWorld.IsScriptScheduled()) // function don't must be called in time scripts use. + return; + + sLog.outString("%s :", tablename); + + scripts.clear(); // need for reload support + + QueryResult *result = WorldDatabase.PQuery("SELECT id, delay, command, datalong, datalong2, datalong3, datalong4, data_flags, dataint, dataint2, dataint3, dataint4, x, y, z, o FROM %s", tablename); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u script definitions", count); + return; + } + + barGoLink bar((int)result->GetRowCount()); + + do + { + bar.step(); + + Field *fields = result->Fetch(); + ScriptInfo tmp; + tmp.id = fields[0].GetUInt32(); + tmp.delay = fields[1].GetUInt32(); + tmp.command = fields[2].GetUInt32(); + tmp.raw.data[0] = fields[3].GetUInt32(); + tmp.raw.data[1] = fields[4].GetUInt32(); + tmp.raw.data[2] = fields[5].GetUInt32(); + tmp.raw.data[3] = fields[6].GetUInt32(); + tmp.raw.data[4] = fields[7].GetUInt32(); + tmp.raw.data[5] = fields[8].GetInt32(); + tmp.raw.data[6] = fields[9].GetInt32(); + tmp.raw.data[7] = fields[10].GetInt32(); + tmp.raw.data[8] = fields[11].GetInt32(); + tmp.x = fields[12].GetFloat(); + tmp.y = fields[13].GetFloat(); + tmp.z = fields[14].GetFloat(); + tmp.o = fields[15].GetFloat(); + + // generic command args check + switch(tmp.command) + { + case SCRIPT_COMMAND_TALK: + { + if (tmp.talk.chatType > CHAT_TYPE_ZONE_YELL) + { + sLog.outErrorDb("Table `%s` has invalid CHAT_TYPE_ (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u", tablename, tmp.talk.chatType, tmp.id); + continue; + } + if (tmp.talk.creatureEntry && !ObjectMgr::GetCreatureTemplate(tmp.talk.creatureEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_TALK for script id %u, but this creature_template does not exist.", tablename, tmp.talk.creatureEntry, tmp.id); + continue; + } + if (tmp.talk.creatureEntry && !tmp.talk.searchRadius) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_TALK for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.talk.creatureEntry, tmp.id, tmp.talk.searchRadius); + continue; + } + if (!GetLanguageDescByID(tmp.talk.language)) + { + sLog.outErrorDb("Table `%s` has datalong4 = %u in SCRIPT_COMMAND_TALK for script id %u, but this language does not exist.", tablename, tmp.talk.language, tmp.id); + continue; + } + if (tmp.talk.textId[0] == 0) + { + sLog.outErrorDb("Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u", tablename, tmp.talk.textId[0], tmp.id); + continue; + } + + for(int i = 0; i < MAX_TEXT_ID; ++i) + { + if (tmp.talk.textId[i] && (tmp.talk.textId[i] < MIN_DB_SCRIPT_STRING_ID || tmp.talk.textId[i] >= 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, tmp.talk.textId[i], MIN_DB_SCRIPT_STRING_ID, MAX_DB_SCRIPT_STRING_ID, tmp.id); + continue; + } + } + + // if (!GetMangosStringLocale(tmp.dataint)) will be checked after db_script_string loading + break; + } + case SCRIPT_COMMAND_EMOTE: + { + 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, tmp.emote.emoteId, tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_TELEPORT_TO: + { + 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, tmp.teleportTo.mapId, tmp.id); + continue; + } + + if (!MaNGOS::IsValidMapCoord(tmp.x, tmp.y, tmp.z, tmp.o)) + { + sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u", tablename, tmp.x, tmp.y, tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_QUEST_EXPLORED: + { + Quest const* quest = sObjectMgr.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, tmp.questExplored.questId, tmp.id); + continue; + } + + if (!quest->HasSpecialFlag(QUEST_SPECIAL_FLAG_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_SPECIAL_FLAG_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.", tablename, tmp.questExplored.questId, tmp.id); + + // this will prevent quest completing without objective + const_cast(quest)->SetSpecialFlag(QUEST_SPECIAL_FLAG_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, 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, 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, tmp.questExplored.distance, tmp.id, INTERACTION_DISTANCE); + continue; + } + + break; + } + case SCRIPT_COMMAND_KILL_CREDIT: + { + if (!ObjectMgr::GetCreatureTemplate(tmp.killCredit.creatureEntry)) + { + sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_KILL_CREDIT for script id %u", tablename, tmp.killCredit.creatureEntry, tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: + { + GameObjectData const* data = sObjectMgr.GetGOData(tmp.GetGOGuid()); + if (!data) + { + sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u", tablename, tmp.GetGOGuid(), tmp.id); + continue; + } + + GameObjectInfo const* info = ObjectMgr::GetGameObjectInfo(data->id); + 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, tmp.GetGOGuid(), data->id, tmp.id); + continue; + } + + if (info->type == GAMEOBJECT_TYPE_FISHINGNODE || + info->type == GAMEOBJECT_TYPE_FISHINGHOLE || + info->type == GAMEOBJECT_TYPE_DOOR || + info->type == GAMEOBJECT_TYPE_BUTTON || + 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, info->id, tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: + { + if (!MaNGOS::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, tmp.x, tmp.y, tmp.id); + continue; + } + + if (!ObjectMgr::GetCreatureTemplate(tmp.summonCreature.creatureEntry)) + { + sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u", tablename, tmp.summonCreature.creatureEntry, tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_OPEN_DOOR: + case SCRIPT_COMMAND_CLOSE_DOOR: + { + GameObjectData const* data = sObjectMgr.GetGOData(tmp.GetGOGuid()); + if (!data) + { + sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u", tablename, tmp.GetGOGuid(), (tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"), tmp.id); + continue; + } + + GameObjectInfo const* info = ObjectMgr::GetGameObjectInfo(data->id); + if (!info) + { + sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u", tablename, tmp.GetGOGuid(), data->id, (tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"), 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, info->id, (tmp.command == SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"), tmp.id); + continue; + } + + break; + } + case SCRIPT_COMMAND_REMOVE_AURA: + { + if (!sSpellStore.LookupEntry(tmp.removeAura.spellId)) + { + sLog.outErrorDb("Table `%s` using nonexistent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u", + tablename, tmp.removeAura.spellId, tmp.id); + continue; + } + if (tmp.removeAura.isSourceTarget & ~0x1) // 1 bits (0,1) + { + sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u", + tablename, tmp.removeAura.isSourceTarget, tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_CAST_SPELL: + { + if (!sSpellStore.LookupEntry(tmp.castSpell.spellId)) + { + sLog.outErrorDb("Table `%s` using nonexistent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u", + tablename, tmp.castSpell.spellId, tmp.id); + continue; + } + if (tmp.castSpell.flags & ~0x3) // 2 bits + { + sLog.outErrorDb("Table `%s` using unknown flags in datalong2 (%u)i n SCRIPT_COMMAND_CAST_SPELL for script id %u", + tablename, tmp.castSpell.flags, tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_CREATE_ITEM: + { + if (!ObjectMgr::GetItemPrototype(tmp.createItem.itemEntry)) + { + sLog.outErrorDb("Table `%s` has nonexistent item (entry: %u) in SCRIPT_COMMAND_CREATE_ITEM for script id %u", + tablename, tmp.createItem.itemEntry, tmp.id); + continue; + } + if (!tmp.createItem.amount) + { + sLog.outErrorDb("Table `%s` SCRIPT_COMMAND_CREATE_ITEM but amount is %u for script id %u", + tablename, tmp.createItem.amount, tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_DESPAWN_SELF: + { + // for later, we might consider despawn by database guid, and define in datalong2 as option to despawn self. + break; + } + case SCRIPT_COMMAND_PLAY_MOVIE: + { + if (!sMovieStore.LookupEntry(tmp.playMovie.movieId)) + { + sLog.outErrorDb("Table `%s` use non-existing movie_id (id: %u) in SCRIPT_COMMAND_PLAY_MOVIE for script id %u", + tablename, tmp.playMovie.movieId, tmp.id); + continue; + } + break; + } + case SCRIPT_COMMAND_MOVEMENT: + { + if (tmp.movement.movementType >= MAX_DB_MOTION_TYPE) + { + sLog.outErrorDb("Table `%s` SCRIPT_COMMAND_MOVEMENT has invalid MovementType %u for script id %u", + tablename, tmp.movement.movementType, tmp.id); + continue; + } + if (tmp.movement.creatureEntry && !ObjectMgr::GetCreatureTemplate(tmp.movement.creatureEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOVEMENT for script id %u, but this creature_template does not exist.", tablename, tmp.movement.creatureEntry, tmp.id); + continue; + } + if (tmp.movement.creatureEntry && !tmp.movement.searchRadius) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOVEMENT for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.movement.creatureEntry, tmp.id, tmp.movement.searchRadius); + continue; + } + + break; + } + case SCRIPT_COMMAND_SET_ACTIVEOBJECT: + { + if (tmp.activeObject.creatureEntry && !ObjectMgr::GetCreatureTemplate(tmp.activeObject.creatureEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_ACTIVEOBJECT for script id %u, but this creature_template does not exist.", tablename, tmp.activeObject.creatureEntry, tmp.id); + continue; + } + if (tmp.activeObject.creatureEntry && !tmp.activeObject.searchRadius) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_ACTIVEOBJECT for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.activeObject.creatureEntry, tmp.id, tmp.activeObject.searchRadius); + continue; + } + + break; + } + case SCRIPT_COMMAND_SET_FACTION: + { + if (tmp.faction.factionId && !sFactionStore.LookupEntry(tmp.faction.factionId)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_FACTION for script id %u, but this faction does not exist.", tablename, tmp.faction.factionId, tmp.id); + continue; + } + + if (tmp.faction.creatureEntry && !ObjectMgr::GetCreatureTemplate(tmp.faction.creatureEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_FACTION for script id %u, but this creature_template does not exist.", tablename, tmp.faction.creatureEntry, tmp.id); + continue; + } + if (tmp.faction.creatureEntry && !tmp.faction.searchRadius) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_FACTION for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.faction.creatureEntry, tmp.id, tmp.faction.searchRadius); + continue; + } + + break; + } + case SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL: + { + if (tmp.morph.flags & 0x01) + { + if (tmp.morph.creatureOrModelEntry && !sCreatureDisplayInfoStore.LookupEntry(tmp.morph.creatureOrModelEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL for script id %u, but this model does not exist.", tablename, tmp.morph.creatureOrModelEntry, tmp.id); + continue; + } + } + else + { + if (tmp.morph.creatureOrModelEntry && !ObjectMgr::GetCreatureTemplate(tmp.morph.creatureOrModelEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL for script id %u, but this creature_template does not exist.", tablename, tmp.morph.creatureOrModelEntry, tmp.id); + continue; + } + } + + if (tmp.morph.creatureEntry && !ObjectMgr::GetCreatureTemplate(tmp.morph.creatureEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL for script id %u, but this creature_template does not exist.", tablename, tmp.morph.creatureEntry, tmp.id); + continue; + } + if (tmp.morph.creatureEntry && !tmp.morph.searchRadius) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.morph.creatureEntry, tmp.id, tmp.morph.searchRadius); + continue; + } + + break; + } + case SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL: + { + if (tmp.mount.flags & 0x01) + { + if (tmp.mount.creatureOrModelEntry && !sCreatureDisplayInfoStore.LookupEntry(tmp.mount.creatureOrModelEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL for script id %u, but this model does not exist.", tablename, tmp.mount.creatureOrModelEntry, tmp.id); + continue; + } + } + else + { + if (tmp.mount.creatureOrModelEntry && !ObjectMgr::GetCreatureTemplate(tmp.mount.creatureOrModelEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL for script id %u, but this creature_template does not exist.", tablename, tmp.mount.creatureOrModelEntry, tmp.id); + continue; + } + } + + if (tmp.mount.creatureEntry && !ObjectMgr::GetCreatureTemplate(tmp.mount.creatureEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL for script id %u, but this creature_template does not exist.", tablename, tmp.mount.creatureEntry, tmp.id); + continue; + } + if (tmp.mount.creatureEntry && !tmp.mount.searchRadius) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.mount.creatureEntry, tmp.id, tmp.mount.searchRadius); + continue; + } + + break; + } + case SCRIPT_COMMAND_SET_RUN: + { + if (tmp.run.creatureEntry && !ObjectMgr::GetCreatureTemplate(tmp.run.creatureEntry)) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_RUN for script id %u, but this creature_template does not exist.", tablename, tmp.run.creatureEntry, tmp.id); + continue; + } + if (tmp.run.creatureEntry && !tmp.run.searchRadius) + { + sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_SET_RUN for script id %u, but search radius is too small (datalong3 = %u).", tablename, tmp.run.creatureEntry, tmp.id, tmp.run.searchRadius); + continue; + } + + break; + } + } + + if (scripts.find(tmp.id) == scripts.end()) + { + ScriptMap emptyMap; + scripts[tmp.id] = emptyMap; + } + scripts[tmp.id].insert(ScriptMap::value_type(tmp.delay, tmp)); + + ++count; + } while(result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u script definitions", count); +} + +void ScriptMgr::LoadGameObjectScripts() +{ + LoadScripts(sGameObjectScripts, "gameobject_scripts"); + + // check ids + for(ScriptMapMap::const_iterator itr = sGameObjectScripts.begin(); itr != sGameObjectScripts.end(); ++itr) + { + if (!sObjectMgr.GetGOData(itr->first)) + sLog.outErrorDb("Table `gameobject_scripts` has not existing gameobject (GUID: %u) as script id", itr->first); + } +} + +void ScriptMgr::LoadQuestEndScripts() +{ + LoadScripts(sQuestEndScripts, "quest_end_scripts"); + + // check ids + for(ScriptMapMap::const_iterator itr = sQuestEndScripts.begin(); itr != sQuestEndScripts.end(); ++itr) + { + if (!sObjectMgr.GetQuestTemplate(itr->first)) + sLog.outErrorDb("Table `quest_end_scripts` has not existing quest (Id: %u) as script id", itr->first); + } +} + +void ScriptMgr::LoadQuestStartScripts() +{ + LoadScripts(sQuestStartScripts, "quest_start_scripts"); + + // check ids + for(ScriptMapMap::const_iterator itr = sQuestStartScripts.begin(); itr != sQuestStartScripts.end(); ++itr) + { + if (!sObjectMgr.GetQuestTemplate(itr->first)) + sLog.outErrorDb("Table `quest_start_scripts` has not existing quest (Id: %u) as script id", itr->first); + } +} + +void ScriptMgr::LoadSpellScripts() +{ + LoadScripts(sSpellScripts, "spell_scripts"); + + // check ids + for(ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr) + { + SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first); + + if (!spellInfo) + { + sLog.outErrorDb("Table `spell_scripts` has not existing spell (Id: %u) as script id", itr->first); + continue; + } + + //check for correct spellEffect + bool found = false; + for(int i = 0; i < MAX_EFFECT_INDEX; ++i) + { + // skip empty effects + if (!spellInfo->Effect[i]) + continue; + + if (spellInfo->Effect[i] == SPELL_EFFECT_SCRIPT_EFFECT) + { + found = true; + break; + } + } + + if (!found) + sLog.outErrorDb("Table `spell_scripts` has unsupported spell (Id: %u) without SPELL_EFFECT_SCRIPT_EFFECT (%u) spell effect", itr->first, SPELL_EFFECT_SCRIPT_EFFECT); + } +} + +void ScriptMgr::LoadEventScripts() +{ + LoadScripts(sEventScripts, "event_scripts"); + + std::set evt_scripts; + + // Load all possible script entries from gameobjects + for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i) + if (GameObjectInfo const* goInfo = sGOStorage.LookupEntry(i)) + if (uint32 eventId = goInfo->GetEventScriptId()) + evt_scripts.insert(eventId); + + // Load all possible script entries from spells + for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) + { + SpellEntry const* spell = sSpellStore.LookupEntry(i); + if (spell) + { + for(int j = 0; j < MAX_EFFECT_INDEX; ++j) + { + if (spell->Effect[j] == SPELL_EFFECT_SEND_EVENT) + { + if (spell->EffectMiscValue[j]) + evt_scripts.insert(spell->EffectMiscValue[j]); + } + } + } + } + + for(size_t path_idx = 0; path_idx < sTaxiPathNodesByPath.size(); ++path_idx) + { + for(size_t node_idx = 0; node_idx < sTaxiPathNodesByPath[path_idx].size(); ++node_idx) + { + TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx]; + + if (node.arrivalEventID) + evt_scripts.insert(node.arrivalEventID); + + if (node.departureEventID) + evt_scripts.insert(node.departureEventID); + } + } + + // Then check if all scripts are in above list of possible script entries + for(ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr) + { + std::set::const_iterator itr2 = evt_scripts.find(itr->first); + if (itr2 == evt_scripts.end()) + sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field or any spell effect %u or path taxi node data", + itr->first, SPELL_EFFECT_SEND_EVENT); + } +} + +void ScriptMgr::LoadGossipScripts() +{ + LoadScripts(sGossipScripts, "gossip_scripts"); + + // checks are done in LoadGossipMenuItems +} + +void ScriptMgr::LoadCreatureMovementScripts() +{ + LoadScripts(sCreatureMovementScripts, "creature_movement_scripts"); + + // checks are done in WaypointManager::Load +} + +void ScriptMgr::LoadDbScriptStrings() +{ + LoadMangosStrings(WorldDatabase,"db_script_string",MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID); + + std::set ids; + + for(int32 i = MIN_DB_SCRIPT_STRING_ID; i < MAX_DB_SCRIPT_STRING_ID; ++i) + if (sObjectMgr.GetMangosStringLocale(i)) + ids.insert(i); + + CheckScriptTexts(sQuestEndScripts,ids); + CheckScriptTexts(sQuestStartScripts,ids); + CheckScriptTexts(sSpellScripts,ids); + CheckScriptTexts(sGameObjectScripts,ids); + CheckScriptTexts(sEventScripts,ids); + CheckScriptTexts(sGossipScripts,ids); + CheckScriptTexts(sCreatureMovementScripts,ids); + + sWaypointMgr.CheckTextsExistance(ids); + + for(std::set::const_iterator itr = ids.begin(); itr != ids.end(); ++itr) + sLog.outErrorDb( "Table `db_script_string` has unused string id %u", *itr); +} + +void ScriptMgr::CheckScriptTexts(ScriptMapMap const& scripts, std::set& ids) +{ + for(ScriptMapMap::const_iterator itrMM = scripts.begin(); itrMM != scripts.end(); ++itrMM) + { + for(ScriptMap::const_iterator itrM = itrMM->second.begin(); itrM != itrMM->second.end(); ++itrM) + { + if (itrM->second.command == SCRIPT_COMMAND_TALK) + { + for(int i = 0; i < MAX_TEXT_ID; ++i) + { + if (itrM->second.talk.textId[i] && !sObjectMgr.GetMangosStringLocale(itrM->second.talk.textId[i])) + sLog.outErrorDb( "Table `db_script_string` is missing string id %u, used in database script id %u.", itrM->second.talk.textId[i], itrMM->first); + + if (ids.find(itrM->second.talk.textId[i]) != ids.end()) + ids.erase(itrM->second.talk.textId[i]); + } + } + } + } +} + +void ScriptMgr::LoadAreaTriggerScripts() +{ + m_AreaTriggerScripts.clear(); // need for reload case + QueryResult *result = WorldDatabase.Query("SELECT entry, ScriptName FROM scripted_areatrigger"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u scripted areatrigger", count); + return; + } + + barGoLink bar((int)result->GetRowCount()); + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + uint32 triggerId = fields[0].GetUInt32(); + const char *scriptName = fields[1].GetString(); + + if (!sAreaTriggerStore.LookupEntry(triggerId)) + { + sLog.outErrorDb("Table `scripted_areatrigger` has area trigger (ID: %u) not listed in `AreaTrigger.dbc`.", triggerId); + continue; + } + + m_AreaTriggerScripts[triggerId] = GetScriptId(scriptName); + } while(result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u areatrigger scripts", count); +} + +void ScriptMgr::LoadEventIdScripts() +{ + m_EventIdScripts.clear(); // need for reload case + QueryResult *result = WorldDatabase.Query("SELECT id, ScriptName FROM scripted_event_id"); + + uint32 count = 0; + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded %u scripted event id", count); + return; + } + + barGoLink bar((int)result->GetRowCount()); + + // TODO: remove duplicate code below, same way to collect event id's used in LoadEventScripts() + std::set evt_scripts; + + // Load all possible event entries from gameobjects + for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i) + if (GameObjectInfo const* goInfo = sGOStorage.LookupEntry(i)) + if (uint32 eventId = goInfo->GetEventScriptId()) + evt_scripts.insert(eventId); + + // Load all possible event entries from spells + for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i) + { + SpellEntry const* spell = sSpellStore.LookupEntry(i); + if (spell) + { + for(int j = 0; j < MAX_EFFECT_INDEX; ++j) + { + if (spell->Effect[j] == SPELL_EFFECT_SEND_EVENT) + { + if (spell->EffectMiscValue[j]) + evt_scripts.insert(spell->EffectMiscValue[j]); + } + } + } + } + + // Load all possible event entries from taxi path nodes + for(size_t path_idx = 0; path_idx < sTaxiPathNodesByPath.size(); ++path_idx) + { + for(size_t node_idx = 0; node_idx < sTaxiPathNodesByPath[path_idx].size(); ++node_idx) + { + TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx]; + + if (node.arrivalEventID) + evt_scripts.insert(node.arrivalEventID); + + if (node.departureEventID) + evt_scripts.insert(node.departureEventID); + } + } + + do + { + ++count; + bar.step(); + + Field *fields = result->Fetch(); + + uint32 eventId = fields[0].GetUInt32(); + const char *scriptName = fields[1].GetString(); + + std::set::const_iterator itr = evt_scripts.find(eventId); + if (itr == evt_scripts.end()) + sLog.outErrorDb("Table `scripted_event_id` has id %u not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field or any spell effect %u or path taxi node data", + eventId, SPELL_EFFECT_SEND_EVENT); + + m_EventIdScripts[eventId] = GetScriptId(scriptName); + } while(result->NextRow()); + + delete result; + + sLog.outString(); + sLog.outString(">> Loaded %u scripted event id", count); +} + +void ScriptMgr::LoadScriptNames() +{ + m_scriptNames.push_back(""); + QueryResult *result = WorldDatabase.Query( + "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM item_template WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM scripted_areatrigger WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM scripted_event_id WHERE ScriptName <> '' " + "UNION " + "SELECT DISTINCT(ScriptName) FROM instance_template WHERE ScriptName <> ''"); + + if (!result) + { + barGoLink bar(1); + bar.step(); + sLog.outString(); + sLog.outErrorDb(">> Loaded empty set of Script Names!"); + return; + } + + barGoLink bar((int)result->GetRowCount()); + uint32 count = 0; + + do + { + bar.step(); + m_scriptNames.push_back((*result)[0].GetString()); + ++count; + } while (result->NextRow()); + delete result; + + std::sort(m_scriptNames.begin(), m_scriptNames.end()); + sLog.outString(); + sLog.outString( ">> Loaded %d Script Names", count ); +} + +uint32 ScriptMgr::GetScriptId(const char *name) const +{ + // use binary search to find the script name in the sorted vector + // assume "" is the first element + if (!name) + return 0; + + ScriptNameMap::const_iterator itr = + std::lower_bound(m_scriptNames.begin(), m_scriptNames.end(), name); + + if (itr == m_scriptNames.end() || *itr != name) + return 0; + + return uint32(itr - m_scriptNames.begin()); +} + +uint32 ScriptMgr::GetAreaTriggerScriptId(uint32 triggerId) const +{ + AreaTriggerScriptMap::const_iterator itr = m_AreaTriggerScripts.find(triggerId); + if (itr != m_AreaTriggerScripts.end()) + return itr->second; + + return 0; +} + +uint32 ScriptMgr::GetEventIdScriptId(uint32 eventId) const +{ + EventIdScriptMap::const_iterator itr = m_EventIdScripts.find(eventId); + if (itr != m_EventIdScripts.end()) + return itr->second; + + return 0; +} + +uint32 GetAreaTriggerScriptId(uint32 triggerId) +{ + return sScriptMgr.GetAreaTriggerScriptId(triggerId); +} + +uint32 GetEventIdScriptId(uint32 eventId) +{ + return sScriptMgr.GetEventIdScriptId(eventId); +} + +uint32 GetScriptId(const char *name) +{ + return sScriptMgr.GetScriptId(name); +} + +ScriptMgr::ScriptNameMap const& GetScriptNames() +{ + return sScriptMgr.GetScriptNames(); +} diff --git a/src/game/ScriptMgr.h b/src/game/ScriptMgr.h new file mode 100644 index 000000000..28ed34467 --- /dev/null +++ b/src/game/ScriptMgr.h @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2005-2010 MaNGOS + * + * 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 + */ + +#ifndef _SCRIPTMGR_H +#define _SCRIPTMGR_H + +#include "Common.h" +#include "Policies/Singleton.h" + +enum eScriptCommand +{ + SCRIPT_COMMAND_TALK = 0, // source = WorldObject, target = any/none, datalong (see enum ChatType for supported CHAT_TYPE_'s) + // datalong2 = creature entry (searching for a buddy, closest to source), datalong3 = creature search radius, datalong4 = language + // data_flags = flag_target_player_as_source = 0x01 + // flag_original_source_as_target = 0x02 + // flag_buddy_as_target = 0x04 + // dataint = text entry from db_script_string -table. dataint2-4 optional for random selected text. + SCRIPT_COMMAND_EMOTE = 1, // source = unit, datalong = emote_id + SCRIPT_COMMAND_FIELD_SET = 2, // source = any, datalong = field_id, datalong2 = value + SCRIPT_COMMAND_MOVE_TO = 3, // source = Creature, datalong2 = time, x/y/z + SCRIPT_COMMAND_FLAG_SET = 4, // source = any, datalong = field_id, datalong2 = bitmask + SCRIPT_COMMAND_FLAG_REMOVE = 5, // source = any, datalong = field_id, datalong2 = bitmask + SCRIPT_COMMAND_TELEPORT_TO = 6, // source or target with Player, datalong = map_id, x/y/z + SCRIPT_COMMAND_QUEST_EXPLORED = 7, // one from source or target must be Player, another GO/Creature, datalong=quest_id, datalong2=distance or 0 + SCRIPT_COMMAND_KILL_CREDIT = 8, // source or target with Player, datalong = creature entry, datalong2 = bool (0=personal credit, 1=group credit) + SCRIPT_COMMAND_RESPAWN_GAMEOBJECT = 9, // source = any (summoner), datalong=db_guid, datalong2=despawn_delay + SCRIPT_COMMAND_TEMP_SUMMON_CREATURE = 10, // source = any (summoner), datalong=creature entry, datalong2=despawn_delay + SCRIPT_COMMAND_OPEN_DOOR = 11, // source = unit, datalong=db_guid, datalong2=reset_delay + SCRIPT_COMMAND_CLOSE_DOOR = 12, // source = unit, datalong=db_guid, datalong2=reset_delay + SCRIPT_COMMAND_ACTIVATE_OBJECT = 13, // source = unit, target=GO + SCRIPT_COMMAND_REMOVE_AURA = 14, // source (datalong2!=0) or target (datalong==0) unit, datalong = spell_id + SCRIPT_COMMAND_CAST_SPELL = 15, // source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s + SCRIPT_COMMAND_PLAY_SOUND = 16, // source = any object, target=any/player, datalong (sound_id), datalong2 (bitmask: 0/1=anyone/target, 0/2=with distance dependent, so 1|2 = 3 is target with distance dependent) + SCRIPT_COMMAND_CREATE_ITEM = 17, // source or target must be player, datalong = item entry, datalong2 = amount + SCRIPT_COMMAND_DESPAWN_SELF = 18, // source or target must be creature, datalong = despawn delay + SCRIPT_COMMAND_PLAY_MOVIE = 19, // target can only be a player, datalog = movie id + SCRIPT_COMMAND_MOVEMENT = 20, // source or target must be creature. datalong = MovementType (0:idle, 1:random or 2:waypoint) + // datalong2 = creature entry (searching for a buddy, closest to source), datalong3 = creature search radius + SCRIPT_COMMAND_SET_ACTIVEOBJECT = 21, // source=any, target=creature + // datalong=bool 0=off, 1=on + // datalong2=creature entry, datalong3=search radius + SCRIPT_COMMAND_SET_FACTION = 22, // source=any, target=creature + // datalong=factionId, + // datalong2=creature entry, datalong3=search radius + SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL = 23, // source=any, target=creature + // datalong=creature entry/modelid (depend on data_flags) + // datalong2=creature entry, datalong3=search radius + // dataflags= 0x01 to use datalong value as modelid explicit + SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL = 24, // source=any, target=creature + // datalong=creature entry/modelid (depend on data_flags) + // datalong2=creature entry, datalong3=search radius + // dataflags= 0x01 to use datalong value as modelid explicit + SCRIPT_COMMAND_SET_RUN = 25, // source=any, target=creature + // datalong= bool 0=off, 1=on + // datalong2=creature entry, datalong3=search radius +}; + +#define MAX_TEXT_ID 4 // used for SCRIPT_COMMAND_TALK + +struct ScriptInfo +{ + uint32 id; + uint32 delay; + uint32 command; + + union + { + struct // SCRIPT_COMMAND_TALK (0) + { + uint32 chatType; // datalong + uint32 creatureEntry; // datalong2 + uint32 searchRadius; // datalong3 + uint32 language; // datalong4 + uint32 flags; // data_flags + int32 textId[MAX_TEXT_ID]; // dataint to dataint4 + } talk; + + struct // SCRIPT_COMMAND_EMOTE (1) + { + uint32 emoteId; // datalong + } emote; + + struct // SCRIPT_COMMAND_FIELD_SET (2) + { + uint32 fieldId; // datalong + uint32 fieldValue; // datalong2 + } setField; + + struct // SCRIPT_COMMAND_MOVE_TO (3) + { + uint32 unused1; // datalong + uint32 travelTime; // datalong2 + } moveTo; + + struct // SCRIPT_COMMAND_FLAG_SET (4) + { + uint32 fieldId; // datalong + uint32 fieldValue; // datalong2 + } setFlag; + + struct // SCRIPT_COMMAND_FLAG_REMOVE (5) + { + uint32 fieldId; // datalong + uint32 fieldValue; // datalong2 + } removeFlag; + + struct // SCRIPT_COMMAND_TELEPORT_TO (6) + { + uint32 mapId; // datalong + } teleportTo; + + struct // SCRIPT_COMMAND_QUEST_EXPLORED (7) + { + uint32 questId; // datalong + uint32 distance; // datalong2 + } questExplored; + + struct // SCRIPT_COMMAND_KILL_CREDIT (8) + { + uint32 creatureEntry; // datalong + uint32 isGroupCredit; // datalong2 + } killCredit; + + struct // SCRIPT_COMMAND_RESPAWN_GAMEOBJECT (9) + { + uint32 goGuid; // datalong + int32 despawnDelay; // datalong2 + } respawnGo; + + struct // SCRIPT_COMMAND_TEMP_SUMMON_CREATURE (10) + { + uint32 creatureEntry; // datalong + uint32 despawnDelay; // datalong2 + uint32 unused1; // datalong3 + uint32 unused2; // datalong4 + uint32 flags; // data_flags + } summonCreature; + + struct // SCRIPT_COMMAND_OPEN_DOOR (11) + { + uint32 goGuid; // datalong + int32 resetDelay; // datalong2 + } openDoor; + + struct // SCRIPT_COMMAND_CLOSE_DOOR (12) + { + uint32 goGuid; // datalong + int32 resetDelay; // datalong2 + } closeDoor; + + // SCRIPT_COMMAND_ACTIVATE_OBJECT (13) + + struct // SCRIPT_COMMAND_REMOVE_AURA (14) + { + uint32 spellId; // datalong + uint32 isSourceTarget; // datalong2 + } removeAura; + + struct // SCRIPT_COMMAND_CAST_SPELL (15) + { + uint32 spellId; // datalong + uint32 flags; // datalong2 + } 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 + } despawn; + + struct // SCRIPT_COMMAND_PLAY_MOVIE (19) + { + uint32 movieId; // datalong + } playMovie; + + struct // SCRIPT_COMMAND_MOVEMENT (20) + { + uint32 movementType; // datalong + uint32 creatureEntry; // datalong2 + uint32 searchRadius; // datalong3 + } movement; + + struct // SCRIPT_COMMAND_SET_ACTIVEOBJECT (21) + { + uint32 activate; // datalong + uint32 creatureEntry; // datalong2 + uint32 searchRadius; // datalong3 + } activeObject; + + struct // SCRIPT_COMMAND_SET_FACTION (22) + { + uint32 factionId; // datalong + uint32 creatureEntry; // datalong2 + uint32 searchRadius; // datalong3 + } faction; + + struct // SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL (23) + { + uint32 creatureOrModelEntry; // datalong + uint32 creatureEntry; // datalong2 + uint32 searchRadius; // datalong3 + uint32 empty1; // datalong4 + uint32 flags; // data_flags + } morph; + + struct // SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL (24) + { + uint32 creatureOrModelEntry; // datalong + uint32 creatureEntry; // datalong2 + uint32 searchRadius; // datalong3 + uint32 empty1; // datalong4 + uint32 flags; // data_flags + } mount; + + struct // SCRIPT_COMMAND_SET_RUN (25) + { + uint32 run; // datalong + uint32 creatureEntry; // datalong2 + uint32 searchRadius; // datalong3 + } run; + + struct + { + uint32 data[9]; + } raw; + }; + + float x; + float y; + float z; + float o; + + // helpers + uint32 GetGOGuid() const + { + switch(command) + { + case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: return respawnGo.goGuid; + case SCRIPT_COMMAND_OPEN_DOOR: return openDoor.goGuid; + case SCRIPT_COMMAND_CLOSE_DOOR: return closeDoor.goGuid; + default: return 0; + } + } +}; + +typedef std::multimap ScriptMap; +typedef std::map ScriptMapMap; +extern ScriptMapMap sQuestEndScripts; +extern ScriptMapMap sQuestStartScripts; +extern ScriptMapMap sSpellScripts; +extern ScriptMapMap sGameObjectScripts; +extern ScriptMapMap sEventScripts; +extern ScriptMapMap sGossipScripts; +extern ScriptMapMap sCreatureMovementScripts; + +class ScriptMgr +{ +public: + ScriptMgr(); + ~ScriptMgr(); + + typedef std::vector ScriptNameMap; + + void LoadGameObjectScripts(); + void LoadQuestEndScripts(); + void LoadQuestStartScripts(); + void LoadEventScripts(); + void LoadSpellScripts(); + void LoadGossipScripts(); + void LoadCreatureMovementScripts(); + + void LoadDbScriptStrings(); + + void LoadScriptNames(); + void LoadAreaTriggerScripts(); + void LoadEventIdScripts(); + + uint32 GetAreaTriggerScriptId(uint32 triggerId) const; + uint32 GetEventIdScriptId(uint32 eventId) const; + + ScriptNameMap const& GetScriptNames() { return m_scriptNames; } + const char* GetScriptName(uint32 id) const { return id < m_scriptNames.size() ? m_scriptNames[id].c_str() : ""; } + uint32 GetScriptId(const char *name) const; +private: + void LoadScripts(ScriptMapMap& scripts, const char* tablename); + void CheckScriptTexts(ScriptMapMap const& scripts, std::set& ids); + + typedef UNORDERED_MAP AreaTriggerScriptMap; + typedef UNORDERED_MAP EventIdScriptMap; + + AreaTriggerScriptMap m_AreaTriggerScripts; + EventIdScriptMap m_EventIdScripts; + + ScriptNameMap m_scriptNames; +}; + +#define sScriptMgr MaNGOS::Singleton::Instance() + +MANGOS_DLL_SPEC uint32 GetAreaTriggerScriptId(uint32 triggerId); +MANGOS_DLL_SPEC uint32 GetEventIdScriptId(uint32 eventId); +MANGOS_DLL_SPEC uint32 GetScriptId(const char *name); +MANGOS_DLL_SPEC ScriptMgr::ScriptNameMap const& GetScriptNames(); + +#endif diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 71d53bfa2..b73204cac 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -52,6 +52,7 @@ #include "Util.h" #include "TemporarySummon.h" #include "ScriptCalls.h" +#include "ScriptMgr.h" #include "SkillDiscovery.h" #include "Formulas.h" #include "GridNotifiers.h" diff --git a/src/game/Transports.cpp b/src/game/Transports.cpp index 39a954a4a..5514fe73f 100644 --- a/src/game/Transports.cpp +++ b/src/game/Transports.cpp @@ -28,6 +28,7 @@ #include "DBCStores.h" #include "ProgressBar.h" #include "ScriptCalls.h" +#include "ScriptMgr.h" void MapManager::LoadTransports() { diff --git a/src/game/WaypointManager.cpp b/src/game/WaypointManager.cpp index 603a4eed1..b064521a3 100644 --- a/src/game/WaypointManager.cpp +++ b/src/game/WaypointManager.cpp @@ -23,6 +23,7 @@ #include "ProgressBar.h" #include "MapManager.h" #include "ObjectMgr.h" +#include "ScriptMgr.h" INSTANTIATE_SINGLETON_1(WaypointManager); diff --git a/src/game/World.cpp b/src/game/World.cpp index 740c9e851..56a63fe06 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -45,6 +45,7 @@ #include "ItemEnchantmentMgr.h" #include "MapManager.h" #include "ScriptCalls.h" +#include "ScriptMgr.h" #include "CreatureAIRegistry.h" #include "Policies/SingletonImp.h" #include "BattleGroundMgr.h" @@ -922,7 +923,7 @@ void World::SetInitialWorldSettings() sObjectMgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts) sLog.outString( "Loading Script Names..."); - sObjectMgr.LoadScriptNames(); + sScriptMgr.LoadScriptNames(); sLog.outString( "Loading InstanceTemplate..." ); sObjectMgr.LoadInstanceTemplate(); @@ -1080,10 +1081,10 @@ void World::SetInitialWorldSettings() sObjectMgr.LoadTavernAreaTriggers(); sLog.outString( "Loading AreaTrigger script names..." ); - sObjectMgr.LoadAreaTriggerScripts(); + sScriptMgr.LoadAreaTriggerScripts(); sLog.outString( "Loading event id script names..." ); - sObjectMgr.LoadEventIdScripts(); + sScriptMgr.LoadEventIdScripts(); sLog.outString( "Loading Graveyard-zone links..."); sObjectMgr.LoadGraveyardZones(); @@ -1150,7 +1151,7 @@ void World::SetInitialWorldSettings() sObjectMgr.LoadNpcTextId(); // must be after load Creature and LoadGossipText sLog.outString( "Loading Gossip scripts..." ); - sObjectMgr.LoadGossipScripts(); // must be before gossip menu options + sScriptMgr.LoadGossipScripts(); // must be before gossip menu options sLog.outString( "Loading Gossip menus..." ); sObjectMgr.LoadGossipMenu(); @@ -1167,7 +1168,7 @@ void World::SetInitialWorldSettings() sObjectMgr.LoadTrainers(); // must be after load CreatureTemplate, TrainerTemplate sLog.outString( "Loading Waypoint scripts..." ); // before loading from creature_movement - sObjectMgr.LoadCreatureMovementScripts(); + sScriptMgr.LoadCreatureMovementScripts(); sLog.outString( "Loading Waypoints..." ); sLog.outString(); @@ -1228,16 +1229,16 @@ void World::SetInitialWorldSettings() ///- Load and initialize scripts sLog.outString( "Loading Scripts..." ); sLog.outString(); - sObjectMgr.LoadQuestStartScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate - sObjectMgr.LoadQuestEndScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate - sObjectMgr.LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data) - sObjectMgr.LoadGameObjectScripts(); // must be after load Creature/Gameobject(Template/Data) - sObjectMgr.LoadEventScripts(); // must be after load Creature/Gameobject(Template/Data) + sScriptMgr.LoadQuestStartScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate + sScriptMgr.LoadQuestEndScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate + sScriptMgr.LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data) + sScriptMgr.LoadGameObjectScripts(); // must be after load Creature/Gameobject(Template/Data) + sScriptMgr.LoadEventScripts(); // must be after load Creature/Gameobject(Template/Data) sLog.outString( ">>> Scripts loaded" ); sLog.outString(); sLog.outString( "Loading Scripts text locales..." ); // must be after Load*Scripts calls - sObjectMgr.LoadDbScriptStrings(); + sScriptMgr.LoadDbScriptStrings(); sLog.outString( "Loading CreatureEventAI Texts..."); sEventAIMgr.LoadCreatureEventAI_Texts(false); // false, will checked in LoadCreatureEventAI_Scripts diff --git a/src/game/pchdef.h b/src/game/pchdef.h index 9b7515d95..b6e2a3e1b 100644 --- a/src/game/pchdef.h +++ b/src/game/pchdef.h @@ -10,3 +10,4 @@ #include "Opcodes.h" #include "SharedDefines.h" #include "ObjectMgr.h" +#include "ScriptMgr.h" diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 7ee1cf738..c0a3f2701 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10911" + #define REVISION_NR "10912" #endif // __REVISION_NR_H__ diff --git a/win/VC100/game.vcxproj b/win/VC100/game.vcxproj index 7460ecca4..186acf256 100644 --- a/win/VC100/game.vcxproj +++ b/win/VC100/game.vcxproj @@ -474,6 +474,7 @@ + @@ -616,6 +617,7 @@ + diff --git a/win/VC100/game.vcxproj.filters b/win/VC100/game.vcxproj.filters index d82100fc1..3c993a234 100644 --- a/win/VC100/game.vcxproj.filters +++ b/win/VC100/game.vcxproj.filters @@ -198,6 +198,9 @@ World/Handlers + + World/Handlers + World/Handlers @@ -597,6 +600,9 @@ World/Handlers + + World/Handlers + World/Handlers diff --git a/win/VC80/game.vcproj b/win/VC80/game.vcproj index 39fa82d13..937f7fb4d 100644 --- a/win/VC80/game.vcproj +++ b/win/VC80/game.vcproj @@ -917,6 +917,14 @@ RelativePath="..\..\src\game\ScriptCalls.h" > + + + + diff --git a/win/VC90/game.vcproj b/win/VC90/game.vcproj index 56fbe7250..7d6b96eb8 100644 --- a/win/VC90/game.vcproj +++ b/win/VC90/game.vcproj @@ -910,6 +910,14 @@ RelativePath="..\..\src\game\ScriptCalls.h" > + + + +