diff options
author | XTZGZoReX <none@none> | 2010-08-06 19:23:43 +0200 |
---|---|---|
committer | XTZGZoReX <none@none> | 2010-08-06 19:23:43 +0200 |
commit | 946adf469c14deeaf202cba5378fb5edfd792bd6 (patch) | |
tree | ce27f0aaa34c6cd06fbdf234ec31ff6abc9ce80c /src/server/game/Scripting/ScriptMgr.cpp | |
parent | 2562a4651f94e2dc40ccce108a2497c2c26bfff6 (diff) |
*** New core <-> script library interface - complete rewrite of the old one.
* Removed the misdesigned on_events script/hooks.
* Lots of related cleanups and assertions.
* The interface is now fully object-oriented.
** Scripts no longer use function pointers.
** Scripts no longer use the general-purpose Script struct for everything.
** Script types are split into separate classes which must be inherited depending on what functionality is desired.
* Several script types have been added to allow extending functionality in a code-only manner (some script types require
assignment in the recently added ScriptName columns in the database, though).
** SpellHandlerScript: Wrapper around spell scripts (returns new SpellScript objects (`spell_script_names`.`ScriptName`)).
** ServerScript: Allows scripting events that occur in the network layer.
** WorldScript: Allows scripting certain world-global events.
** FormulaScript: Allows hooking and interfering with core formulas.
** *MapScript: Allows hooking different map types (including world, instance, and battleground maps (`instance_template`.`ScriptName`)).
** ItemScript: Allows scripting of items (like the old interface (`item_template`.`ScriptName`)).
** CreatureScript: Allows scripting of creatures/AI (like the old interface (`creature_template`.`ScriptName`)).
** GameObjectScript: Allows scripting of gameobjects (like the old interface (`gameobject_template`.`ScriptName`)).
** AreaTriggerScript: Allows scripting triggered area triggers (like the old interface (`areatrigger_scripts`.`ScriptName`)).
** OutdoorPvPScript: Script which should return OutdoorPvP objects for use by OutdoorPvPMgr (`outdoorpvp_template`.`ScriptName`).
** CommandScript: Allows extending the in-core command table.
** WeatherScript: Allows scripting of weather changes (`game_weather`.`ScriptName`).
** AuctionHouseScript: Allows scripting of auction events.
** ConditionScript: Allows scripting of conditions (`conditions`.`ScriptName`).
** DynamicObjectScript: Allows scripting of dynamicobjects.
** TransportScript: Allows scripting of transport events (`transports`.`ScriptName`).
* OutdoorPvP objects are now created through scripts. This effectively means that they'll need to be moved to scripts
before the they're functional again.
* The whole idea with this new interface is to allow expanding core functionality without touching core code. If further
hooks are needed to expand functionality of the core, let us know; we'll add them, if we agree that it is appropriate
to do so.
*** NOTE: The scripts project will _not_ build before it has been adapted to the new interface.
*** Thanks to everyone who helped out with related preparations and suggestions!
--HG--
branch : trunk
Diffstat (limited to 'src/server/game/Scripting/ScriptMgr.cpp')
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.cpp | 1282 |
1 files changed, 965 insertions, 317 deletions
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 5f6cce4917d..8e660f7116e 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -11,69 +11,34 @@ #include "ScriptLoader.h" #include "ScriptSystem.h" -int num_sc_scripts; -Script *m_scripts[MAX_SCRIPTS]; - -void FillSpellSummary(); -void LoadOverridenSQLData(); - -void ScriptMgr::LoadDatabase() -{ - pSystemMgr.LoadVersion(); - pSystemMgr.LoadScriptTexts(); - pSystemMgr.LoadScriptTextsCustom(); - pSystemMgr.LoadScriptWaypoints(); -} - -struct TSpellSummary { - uint8 Targets; // set of enum SelectTarget - uint8 Effects; // set of enum SelectEffect -}extern *SpellSummary; - -ScriptMgr::ScriptMgr() -{ - -} -ScriptMgr::~ScriptMgr() -{ - -} - -void ScriptMgr::ScriptsInit() -{ - //Trinity Script startup - /*sLog.outString(" _____ _ _ _ ____ _ _"); - sLog.outString("|_ _| __(_)_ __ (_) |_ _ _/ ___| ___ _ __(_)_ __ | |_ "); - sLog.outString(" | || '__| | '_ \\| | __| | | \\___ \\ / __| \'__| | \'_ \\| __|"); - sLog.outString(" | || | | | | | | | |_| |_| |___) | (__| | | | |_) | |_ "); - sLog.outString(" |_||_| |_|_| |_|_|\\__|\\__, |____/ \\___|_| |_| .__/ \\__|"); - sLog.outString(" |___/ |_| "); - sLog.outString(""); - sLog.outString("");*/ - - //Load database (must be called after SD2Config.SetSource). - LoadDatabase(); - - sLog.outString("Loading C++ scripts"); - barGoLink bar(1); - bar.step(); - sLog.outString(""); - - for (uint16 i =0; i<MAX_SCRIPTS; ++i) - m_scripts[i]=NULL; - - FillSpellSummary(); - - AddScripts(); - - sLog.outString(">> Loaded %i C++ Scripts.", num_sc_scripts); - - sLog.outString(">> Load Overriden SQL Data."); - LoadOverridenSQLData(); -} - -//********************************* -//*** Functions used globally *** +// Utility macros to refer to the script registry. +#define SCR_REG_MAP(T) ScriptRegistry<T>::ScriptMap +#define SCR_REG_LST(T) ScriptRegistry<T>::ScriptPointerList + +// Utility macros for looping over scripts. +#define FOR_SCRIPTS(T,C,E) \ + if (SCR_REG_LST(T).empty()) \ + return; \ + for (SCR_REG_MAP(T)::iterator C = SCR_REG_LST(T).begin(); \ + C != SCR_REG_LST(T).end(); ++C) +#define FOR_SCRIPTS_RET(T,C,E,R) \ + if (SCR_REG_LST(T).empty()) \ + return R; \ + for (SCR_REG_MAP(T)::iterator C = SCR_REG_LST(T).begin(); \ + C != SCR_REG_LST(T).end(); ++C) +#define FOREACH_SCRIPT(T) \ + FOR_SCRIPTS(T, itr, end) \ + itr->second + +// Utility macros for finding specific scripts. +#define GET_SCRIPT(T,I,V) \ + T* V = ScriptRegistry<T>::GetScriptById(I); \ + if (!V) \ + return; +#define GET_SCRIPT_RET(T,I,V,R) \ + T* V = ScriptRegistry<T>::GetScriptById(I); \ + if (!V) \ + return R; void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) { @@ -89,7 +54,7 @@ void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) return; } - const StringTextData* pData = pSystemMgr.GetTextData(iTextEntry); + const StringTextData* pData = sScriptSystemMgr.GetTextData(iTextEntry); if (!pData) { @@ -102,9 +67,7 @@ void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) if (pData->uiSoundId) { if (GetSoundEntriesStore()->LookupEntry(pData->uiSoundId)) - { pSource->SendPlaySound(pData->uiSoundId, false); - } else sLog.outError("TSCR: DoScriptText entry %i tried to process invalid sound id %u.", iTextEntry, pData->uiSoundId); } @@ -117,7 +80,7 @@ void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) sLog.outError("TSCR: DoScriptText entry %i tried to process emote for invalid TypeId (%u).", iTextEntry, pSource->GetTypeId()); } - switch(pData->uiType) + switch (pData->uiType) { case CHAT_TYPE_SAY: pSource->MonsterSay(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); @@ -132,437 +95,1122 @@ void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) pSource->MonsterTextEmote(iTextEntry, pTarget ? pTarget->GetGUID() : 0, true); break; case CHAT_TYPE_WHISPER: - { - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) - pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID()); - else - sLog.outError("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); - } + { + if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) + pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID()); + else + sLog.outError("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); + break; + } case CHAT_TYPE_BOSS_WHISPER: - { - if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) - pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID(), true); - else - sLog.outError("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); - } + { + if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) + pSource->MonsterWhisper(iTextEntry, pTarget->GetGUID(), true); + else + sLog.outError("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", iTextEntry); + break; + } case CHAT_TYPE_ZONE_YELL: pSource->MonsterYellToZone(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0); break; } } -void Script::RegisterSelf() +ScriptMgr::ScriptMgr() +{ +} + +ScriptMgr::~ScriptMgr() +{ + #define SCR_CLEAR(T) \ + FOR_SCRIPTS(T, itr, end) \ + delete itr->second; \ + SCR_REG_LST(T).clear(); + + // Clear scripts for every script type. + SCR_CLEAR(SpellHandlerScript); + SCR_CLEAR(AuraHandlerScript); + SCR_CLEAR(ServerScript); + SCR_CLEAR(WorldScript); + SCR_CLEAR(FormulaScript); + SCR_CLEAR(WorldMapScript); + SCR_CLEAR(InstanceMapScript); + SCR_CLEAR(BattlegroundMapScript); + SCR_CLEAR(ItemScript); + SCR_CLEAR(CreatureScript); + SCR_CLEAR(GameObjectScript); + SCR_CLEAR(AreaTriggerScript); + SCR_CLEAR(BattlegroundScript); + SCR_CLEAR(OutdoorPvPScript); + SCR_CLEAR(CommandScript); + SCR_CLEAR(WeatherScript); + SCR_CLEAR(AuctionHouseScript); + SCR_CLEAR(ConditionScript); + SCR_CLEAR(VehicleScript); + SCR_CLEAR(DynamicObjectScript); + SCR_CLEAR(TransportScript); + + #undef SCR_CLEAR +} + +void ScriptMgr::Initialize() { - // try to find scripts which try to use another script's allocated memory - // that means didn't allocate memory for script - for (uint16 i = 0; i < MAX_SCRIPTS; ++i) + LoadDatabase(); + + sLog.outString("Loading C++ scripts"); + barGoLink bar(1); + bar.step(); + sLog.outString(""); + + FillSpellSummary(); + AddScripts(); + + sLog.outString(">> Loaded %u C++ scripts", GetScriptCount()); +} + +void ScriptMgr::LoadDatabase() +{ + sScriptSystemMgr.LoadVersion(); + sScriptSystemMgr.LoadScriptTexts(); + sScriptSystemMgr.LoadScriptTextsCustom(); + sScriptSystemMgr.LoadScriptWaypoints(); +} + +struct TSpellSummary +{ + uint8 Targets; // set of enum SelectTarget + uint8 Effects; // set of enum SelectEffect +} *SpellSummary; + +void ScriptMgr::FillSpellSummary() +{ + SpellSummary = new TSpellSummary[GetSpellStore()->GetNumRows()]; + + SpellEntry const* pTempSpell; + + for (uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i) { - // somebody forgot to allocate memory for a script by a method like this: newscript = new Script - if (m_scripts[i] == this) + SpellSummary[i].Effects = 0; + SpellSummary[i].Targets = 0; + + pTempSpell = GetSpellStore()->LookupEntry(i); + //This spell doesn't exist + if (!pTempSpell) + continue; + + for (uint32 j = 0; j < 3; ++j) { - sLog.outError("ScriptName: '%s' - Forgot to allocate memory, so this script and/or the script before that can't work.", Name.c_str()); - // don't register it - // and don't delete it because its memory is used for another script - return; + //Spell targets self + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SELF-1); + + //Spell targets a single enemy + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_DST_TARGET_ENEMY) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_ENEMY-1); + + //Spell targets AoE at enemy + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_SRC || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_DST || + pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_DEST_DYNOBJ_ENEMY) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_ENEMY-1); + + //Spell targets an enemy + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_DST_TARGET_ENEMY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_SRC || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_AREA_ENEMY_DST || + pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_DEST_DYNOBJ_ENEMY) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_ENEMY-1); + + //Spell targets a single friend(or self) + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ALLY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_PARTY) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_SINGLE_FRIEND-1); + + //Spell targets aoe friends + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_TARGET || + pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_AOE_FRIEND-1); + + //Spell targets any friend(or self) + if (pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ALLY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_PARTY || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_CASTER || + pTempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_PARTY_TARGET || + pTempSpell->EffectImplicitTargetA[j] == TARGET_SRC_CASTER) + SpellSummary[i].Targets |= 1 << (SELECT_TARGET_ANY_FRIEND-1); + + //Make sure that this spell includes a damage effect + if (pTempSpell->Effect[j] == SPELL_EFFECT_SCHOOL_DAMAGE || + pTempSpell->Effect[j] == SPELL_EFFECT_INSTAKILL || + pTempSpell->Effect[j] == SPELL_EFFECT_ENVIRONMENTAL_DAMAGE || + pTempSpell->Effect[j] == SPELL_EFFECT_HEALTH_LEECH) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_DAMAGE-1); + + //Make sure that this spell includes a healing effect (or an apply aura with a periodic heal) + if (pTempSpell->Effect[j] == SPELL_EFFECT_HEAL || + pTempSpell->Effect[j] == SPELL_EFFECT_HEAL_MAX_HEALTH || + pTempSpell->Effect[j] == SPELL_EFFECT_HEAL_MECHANICAL || + (pTempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA && pTempSpell->EffectApplyAuraName[j] == 8)) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_HEALING-1); + + //Make sure that this spell applies an aura + if (pTempSpell->Effect[j] == SPELL_EFFECT_APPLY_AURA) + SpellSummary[i].Effects |= 1 << (SELECT_EFFECT_AURA-1); } } +} - int id = GetScriptId(Name.c_str()); - if (id) +void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::list<SpellScript *> & script_vector) +{ + SpellScriptsBounds bounds = objmgr.GetSpellScriptsBounds(spell_id); + + for (SpellScriptsMap::iterator itr = bounds.first; itr != bounds.second; ++itr) { - // try to find the script in assigned scripts - bool IsExist = false; - for (uint16 i = 0; i < MAX_SCRIPTS; ++i) - { - if (m_scripts[i]) - { - // if the assigned script's name and the new script's name is the same - if (m_scripts[i]->Name == Name) - { - IsExist = true; - break; - } - } - } + SpellHandlerScript* tmpscript = ScriptRegistry<SpellHandlerScript>::GetScriptById(itr->second); + if (!tmpscript) + continue; - // if the script doesn't assigned -> assign it! - if (!IsExist) + SpellScript* script = tmpscript->GetSpellScript(); + + if (!script) { - m_scripts[id] = this; - ++num_sc_scripts; + sLog.outError("Spell script %s for spell %u returned a NULL SpellScript pointer!", tmpscript->ToString(), spell_id); + continue; } - // if the script is already assigned -> delete it! - else + + script_vector.push_back(script); + } +} + +void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::vector<std::pair<SpellScript *, SpellScriptsMap::iterator> > & script_vector) +{ + SpellScriptsBounds bounds = objmgr.GetSpellScriptsBounds(spell_id); + script_vector.reserve(std::distance(bounds.first, bounds.second)); + + for (SpellScriptsMap::iterator itr = bounds.first; itr != bounds.second; ++itr) + { + SpellHandlerScript* tmpscript = ScriptRegistry<SpellHandlerScript>::GetScriptById(itr->second); + if (!tmpscript) + continue; + + SpellScript* script = tmpscript->GetSpellScript(); + + if (!script) { - // TODO: write a better error message than this one :) - sLog.outError("ScriptName: '%s' already assigned with the same ScriptName, so the script can't work.", Name.c_str()); - delete this; + sLog.outError("Spell script %s for spell %u returned a NULL SpellScript pointer!", tmpscript->ToString(), spell_id); + continue; } + + script_vector.push_back(std::make_pair(script, itr)); } - else - { - if (Name.find("example") == std::string::npos) - sLog.outErrorDb("TrinityScript: RegisterSelf, but script named %s does not have ScriptName assigned in database.",(this)->Name.c_str()); - delete this; +} + +void ScriptMgr::OnNetworkStart() +{ + FOREACH_SCRIPT(ServerScript)->OnNetworkStart(); +} + +void ScriptMgr::OnNetworkStop() +{ + FOREACH_SCRIPT(ServerScript)->OnNetworkStop(); +} + +void ScriptMgr::OnSocketOpen(WorldSocket* socket) +{ + ASSERT(socket); + + FOREACH_SCRIPT(ServerScript)->OnSocketOpen(socket); +} + +void ScriptMgr::OnSocketClose(WorldSocket* socket, bool wasNew) +{ + ASSERT(socket); + + FOREACH_SCRIPT(ServerScript)->OnSocketClose(socket, wasNew); +} + +void ScriptMgr::OnPacketReceive(WorldSocket* socket, WorldPacket& packet) +{ + ASSERT(socket); + + FOREACH_SCRIPT(ServerScript)->OnPacketReceive(socket, packet); +} + +void ScriptMgr::OnPacketSend(WorldSocket* socket, WorldPacket& packet) +{ + ASSERT(socket); + + FOREACH_SCRIPT(ServerScript)->OnPacketSend(socket, packet); +} + +void ScriptMgr::OnUnknownPacketReceive(WorldSocket* socket, WorldPacket& packet) +{ + ASSERT(socket); + + FOREACH_SCRIPT(ServerScript)->OnUnknownPacketReceive(socket, packet); +} + +void ScriptMgr::OnOpenStateChange(bool open) +{ + FOREACH_SCRIPT(WorldScript)->OnOpenStateChange(open); +} + +void ScriptMgr::OnConfigLoad(bool reload) +{ + FOREACH_SCRIPT(WorldScript)->OnConfigLoad(reload); +} + +void ScriptMgr::OnMotdChange(std::string& newMotd) +{ + FOREACH_SCRIPT(WorldScript)->OnMotdChange(newMotd); +} + +void ScriptMgr::OnShutdown(ShutdownExitCode code, ShutdownMask mask) +{ + FOREACH_SCRIPT(WorldScript)->OnShutdown(code, mask); +} + +void ScriptMgr::OnShutdownCancel() +{ + FOREACH_SCRIPT(WorldScript)->OnShutdownCancel(); +} + +void ScriptMgr::OnWorldUpdate(uint32 diff) +{ + FOREACH_SCRIPT(WorldScript)->OnUpdate(NULL, diff); +} + +void ScriptMgr::OnHonorCalculation(float& honor, uint8 level, uint32 count) +{ + FOREACH_SCRIPT(FormulaScript)->OnHonorCalculation(honor, level, count); +} + +void ScriptMgr::OnHonorCalculation(uint32& honor, uint8 level, uint32 count) +{ + FOREACH_SCRIPT(FormulaScript)->OnHonorCalculation(honor, level, count); +} + +void ScriptMgr::OnGetGrayLevel(uint8& grayLevel, uint8 playerLevel) +{ + FOREACH_SCRIPT(FormulaScript)->OnGetGrayLevel(grayLevel, playerLevel); +} + +void ScriptMgr::OnGetColorCode(XPColorChar& color, uint8 playerLevel, uint8 mobLevel) +{ + FOREACH_SCRIPT(FormulaScript)->OnGetColorCode(color, playerLevel, mobLevel); +} + +void ScriptMgr::OnGetZeroDifference(uint8& diff, uint8 playerLevel) +{ + FOREACH_SCRIPT(FormulaScript)->OnGetZeroDifference(diff, playerLevel); +} + +void ScriptMgr::OnGetBaseGain(uint32& gain, uint8 playerLevel, uint8 mobLevel, ContentLevels content) +{ + FOREACH_SCRIPT(FormulaScript)->OnGetBaseGain(gain, playerLevel, mobLevel, content); +} + +void ScriptMgr::OnGetGain(uint32& gain, Player* player, Unit* unit) +{ + ASSERT(player); + ASSERT(unit); + + FOREACH_SCRIPT(FormulaScript)->OnGetGain(gain, player, unit); +} + +void ScriptMgr::OnGetGroupRate(float& rate, uint32 count, bool isRaid) +{ + FOREACH_SCRIPT(FormulaScript)->OnGetGroupRate(rate, count, isRaid); +} + +#define SCR_MAP_BGN(M,V,I,E,C,T) \ + if (V->GetEntry()->T()) \ + { \ + FOR_SCRIPTS(M, I, E) \ + { \ + MapEntry const* C = I->second->GetEntry(); \ + if (!C) \ + continue; \ + if (entry->MapID == V->GetId()) \ + { + +#define SCR_MAP_END \ + break; \ + } \ + } \ } + +void ScriptMgr::OnCreateMap(Map* map) +{ + ASSERT(map); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnCreate(map); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnCreate((InstanceMap*)map); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnCreate((BattleGroundMap*)map); + SCR_MAP_END; } -void ScriptMgr::OnLogin(Player *pPlayer) +void ScriptMgr::OnDestroyMap(Map* map) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnLogin) return; - tmpscript->pOnLogin(pPlayer); + ASSERT(map); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnDestroy(map); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnDestroy((InstanceMap*)map); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnDestroy((BattleGroundMap*)map); + SCR_MAP_END; } -void ScriptMgr::OnLogout(Player *pPlayer) +void ScriptMgr::OnLoadGridMap(Map* map, uint32 gx, uint32 gy) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnLogout) return; - tmpscript->pOnLogout(pPlayer); + ASSERT(map); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnLoadGridMap(map, gx, gy); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnLoadGridMap((InstanceMap*)map, gx, gy); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnLoadGridMap((BattleGroundMap*)map, gx, gy); + SCR_MAP_END; } -void ScriptMgr::OnPVPKill(Player *killer, Player *killed) +void ScriptMgr::OnUnloadGridMap(Map* map, uint32 gx, uint32 gy) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnPVPKill) return; - tmpscript->pOnPVPKill(killer, killed); + ASSERT(map); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnUnloadGridMap(map, gx, gy); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnUnloadGridMap((InstanceMap*)map, gx, gy); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnUnloadGridMap((BattleGroundMap*)map, gx, gy); + SCR_MAP_END; } -bool ScriptMgr::OnSpellCast (Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, uint32 i, SpellEntry const *spell) +void ScriptMgr::OnPlayerEnter(Map* map, Player* player) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnSpellCast) return true; - return tmpscript->pOnSpellCast(pUnitTarget,pItemTarget,pGoTarget,i,spell); + ASSERT(map); + ASSERT(player); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnPlayerEnter(map, player); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnPlayerEnter((InstanceMap*)map, player); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnPlayerEnter((BattleGroundMap*)map, player); + SCR_MAP_END; } -uint32 ScriptMgr::OnGetXP(Player *pPlayer, uint32 amount) +void ScriptMgr::OnPlayerLeave(Map* map, Player* player) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnGetXP) return amount; - return tmpscript->pOnGetXP(pPlayer,amount); + ASSERT(map); + ASSERT(player); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnPlayerLeave(map, player); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnPlayerLeave((InstanceMap*)map, player); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnPlayerLeave((BattleGroundMap*)map, player); + SCR_MAP_END; } -uint32 ScriptMgr::OnGetMoney(Player *pPlayer, int32 amount) +void ScriptMgr::OnMapUpdate(Map* map, uint32 diff) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnGetMoney) return amount; - return tmpscript->pOnGetMoney(pPlayer,amount); + ASSERT(map); + + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsContinent); + itr->second->OnUpdate(map, diff); + SCR_MAP_END; + + SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon); + itr->second->OnUpdate((InstanceMap*)map, diff); + SCR_MAP_END; + + SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleGround); + itr->second->OnUpdate((BattleGroundMap*)map, diff); + SCR_MAP_END; } -bool ScriptMgr::OnPlayerChat(Player *pPlayer, const char *text) +#undef SCR_MAP_BGN +#undef SCR_MAP_END + +InstanceData* ScriptMgr::CreateInstanceData(InstanceMap* map) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnPlayerChat) return true; - return tmpscript->pOnPlayerChat(pPlayer,text); + ASSERT(map); + + GET_SCRIPT_RET(InstanceMapScript, map->GetScriptId(), tmpscript, NULL); + return tmpscript->OnGetInstanceData(map); } -void ScriptMgr::OnServerStartup() +bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Item* target) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnServerStartup) return; - tmpscript->pOnServerStartup(); + ASSERT(caster); + ASSERT(target); + + GET_SCRIPT_RET(ItemScript, target->GetProto()->ScriptId, tmpscript, false); + return tmpscript->OnDummyEffect(caster, spellId, effIndex, target); } -void ScriptMgr::OnServerShutdown() +bool ScriptMgr::OnQuestAccept(Player* player, Item* item, Quest const* quest) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnServerShutdown) return; - tmpscript->pOnServerShutdown(); + ASSERT(player); + ASSERT(item); + ASSERT(quest); + + GET_SCRIPT_RET(ItemScript, item->GetProto()->ScriptId, tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestAccept(player, item, quest); } -void ScriptMgr::OnAreaChange(Player *pPlayer, AreaTableEntry const *pArea) +bool ScriptMgr::OnItemUse(Player* player, Item* item, SpellCastTargets const& targets) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnAreaChange) return; - tmpscript->pOnAreaChange(pPlayer, pArea); + ASSERT(player); + ASSERT(item); + + GET_SCRIPT_RET(ItemScript, item->GetProto()->ScriptId, tmpscript, false); + return tmpscript->OnUse(player, item, targets); } -bool ScriptMgr::OnItemClick (Player *pPlayer, Item *pItem) +bool ScriptMgr::OnItemExpire(Player* player, ItemPrototype const* proto) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnItemClick) return true; - return tmpscript->pOnItemClick(pPlayer,pItem); + ASSERT(player); + ASSERT(proto); + + GET_SCRIPT_RET(ItemScript, proto->ScriptId, tmpscript, false); + return tmpscript->OnExpire(player, proto); } -bool ScriptMgr::OnItemOpen (Player *pPlayer, Item *pItem) +bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Creature* target) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnItemOpen) return true; - return tmpscript->pOnItemOpen(pPlayer,pItem); + ASSERT(caster); + ASSERT(target); + + GET_SCRIPT_RET(CreatureScript, target->GetScriptId(), tmpscript, false); + return tmpscript->OnDummyEffect(caster, spellId, effIndex, target); } -bool ScriptMgr::OnGoClick (Player *pPlayer, GameObject *pGameObject) +bool ScriptMgr::OnGossipHello(Player* player, Creature* creature) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnGoClick) return true; - return tmpscript->pOnGoClick(pPlayer,pGameObject); + ASSERT(player); + ASSERT(creature); + + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipHello(player, creature); } -void ScriptMgr::OnCreatureKill (Player *pPlayer, Creature *pCreature) +bool ScriptMgr::OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) { - Script *tmpscript = m_scripts[GetScriptId("scripted_on_events")]; - if (!tmpscript || !tmpscript->pOnCreatureKill) return; - tmpscript->pOnCreatureKill(pPlayer,pCreature); + ASSERT(player); + ASSERT(creature); + + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipSelect(player, creature, sender, action); } -char const* ScriptMgr::ScriptsVersion() +bool ScriptMgr::OnGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code) { - return "Integrated Trinity Scripts"; + ASSERT(player); + ASSERT(creature); + ASSERT(code); + + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipSelectCode(player, creature, sender, action, code); } -bool ScriptMgr::GossipHello (Player * pPlayer, Creature* pCreature) +bool ScriptMgr::OnQuestAccept(Player* player, Creature* creature, Quest const* quest) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pGossipHello) return false; + ASSERT(player); + ASSERT(creature); + ASSERT(quest); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGossipHello(pPlayer, pCreature); + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestAccept(player, creature, quest); } -bool ScriptMgr::GossipSelect(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction) +bool ScriptMgr::OnQuestSelect(Player* player, Creature* creature, Quest const* quest) { - sLog.outDebug("TSCR: Gossip selection, sender: %d, action: %d", uiSender, uiAction); + ASSERT(player); + ASSERT(creature); + ASSERT(quest); + + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestSelect(player, creature, quest); +} - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pGossipSelect) return false; +bool ScriptMgr::OnQuestComplete(Player* player, Creature* creature, Quest const* quest) +{ + ASSERT(player); + ASSERT(creature); + ASSERT(quest); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGossipSelect(pPlayer, pCreature, uiSender, uiAction); + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestComplete(player, creature, quest); } -bool ScriptMgr::GossipSelectWithCode(Player* pPlayer, Creature* pCreature, uint32 uiSender, uint32 uiAction, const char* sCode) +bool ScriptMgr::OnQuestReward(Player* player, Creature* creature, Quest const* quest, uint32 opt) { - sLog.outDebug("TSCR: Gossip selection with code, sender: %d, action: %d", uiSender, uiAction); + ASSERT(player); + ASSERT(creature); + ASSERT(quest); - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pGossipSelectWithCode) return false; + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestReward(player, creature, quest, opt); +} - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGossipSelectWithCode(pPlayer, pCreature, uiSender, uiAction, sCode); +uint32 ScriptMgr::GetDialogStatus(Player* player, Creature* creature) +{ + ASSERT(player); + ASSERT(creature); + + // TODO: 100 is a funny magic number to have hanging around here... + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, 100); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnDialogStatus(player, creature); } -bool ScriptMgr::GOSelect(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction) +CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature) { - if (!pGO) - return false; - sLog.outDebug("TSCR: Gossip selection, sender: %d, action: %d", uiSender, uiAction); + ASSERT(creature); - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOSelect) return false; + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, NULL); + return tmpscript->OnGetAI(); +} - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOSelect(pPlayer, pGO, uiSender, uiAction); +void ScriptMgr::OnCreatureUpdate(Creature* creature, uint32 diff) +{ + ASSERT(creature); + + GET_SCRIPT(CreatureScript, creature->GetScriptId(), tmpscript); + tmpscript->OnUpdate(creature, diff); } -bool ScriptMgr::GOSelectWithCode(Player* pPlayer, GameObject* pGO, uint32 uiSender, uint32 uiAction, const char* sCode) +bool ScriptMgr::OnGossipHello(Player* player, GameObject* go) { - if (!pGO) - return false; - sLog.outDebug("TSCR: Gossip selection, sender: %d, action: %d",uiSender, uiAction); + ASSERT(player); + ASSERT(go); - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOSelectWithCode) return false; + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipHello(player, go); +} - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOSelectWithCode(pPlayer, pGO, uiSender ,uiAction, sCode); +bool ScriptMgr::OnGossipSelect(Player* player, GameObject* go, uint32 sender, uint32 action) +{ + ASSERT(player); + ASSERT(go); + + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipSelect(player, go, sender, action); } -bool ScriptMgr::QuestAccept(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +bool ScriptMgr::OnGossipSelectCode(Player* player, GameObject* go, uint32 sender, uint32 action, const char* code) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pQuestAccept) return false; + ASSERT(player); + ASSERT(go); + ASSERT(code); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestAccept(pPlayer, pCreature, pQuest); + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnGossipSelectCode(player, go, sender, action, code); } -bool ScriptMgr::QuestSelect(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +bool ScriptMgr::OnQuestAccept(Player* player, GameObject* go, Quest const* quest) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pQuestSelect) return false; + ASSERT(player); + ASSERT(go); + ASSERT(quest); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestSelect(pPlayer, pCreature, pQuest); + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestAccept(player, go, quest); } -bool ScriptMgr::QuestComplete(Player* pPlayer, Creature* pCreature, Quest const* pQuest) +bool ScriptMgr::OnQuestReward(Player* player, GameObject* go, Quest const* quest, uint32 opt) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pQuestComplete) return false; + ASSERT(player); + ASSERT(go); + ASSERT(quest); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pQuestComplete(pPlayer, pCreature, pQuest); + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnQuestReward(player, go, quest, opt); } -bool ScriptMgr::ChooseReward(Player* pPlayer, Creature* pCreature, Quest const* pQuest, uint32 opt) +uint32 ScriptMgr::GetDialogStatus(Player* player, GameObject* go) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pChooseReward) return false; + ASSERT(player); + ASSERT(go); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pChooseReward(pPlayer, pCreature, pQuest, opt); + // TODO: 100 is a funny magic number to have hanging around here... + GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, 100); + player->PlayerTalkClass->ClearMenus(); + return tmpscript->OnDialogStatus(player, go); } -uint32 ScriptMgr::NPCDialogStatus(Player* pPlayer, Creature* pCreature) +void ScriptMgr::OnGameObjectDestroyed(Player* player, GameObject* go, uint32 eventId) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->pNPCDialogStatus) return 100; + ASSERT(player); + ASSERT(go); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pNPCDialogStatus(pPlayer, pCreature); + GET_SCRIPT(GameObjectScript, go->GetScriptId(), tmpscript); + tmpscript->OnDestroyed(player, go, eventId); } -uint32 ScriptMgr::GODialogStatus(Player* pPlayer, GameObject* pGO) +void ScriptMgr::OnGameObjectUpdate(GameObject* go, uint32 diff) { - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGODialogStatus) return 100; + ASSERT(go); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGODialogStatus(pPlayer, pGO); + GET_SCRIPT(GameObjectScript, go->GetScriptId(), tmpscript); + tmpscript->OnUpdate(go, diff); } -bool ScriptMgr::ItemHello(Player* pPlayer, Item* pItem, Quest const* pQuest) +bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, GameObject* target) { - Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; - if (!tmpscript || !tmpscript->pItemHello) return false; + ASSERT(caster); + ASSERT(target); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pItemHello(pPlayer, pItem, pQuest); + GET_SCRIPT_RET(GameObjectScript, target->GetScriptId(), tmpscript, false); + return tmpscript->OnDummyEffect(caster, spellId, effIndex, target); } -bool ScriptMgr::ItemQuestAccept(Player* pPlayer, Item* pItem, Quest const* pQuest) +bool ScriptMgr::OnTrigger(Player* player, AreaTriggerEntry const* trigger) { - Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; - if (!tmpscript || !tmpscript->pItemQuestAccept) return false; + ASSERT(player); + ASSERT(trigger); + + GET_SCRIPT_RET(AreaTriggerScript, trigger->id, tmpscript, false); + return tmpscript->OnTrigger(player, trigger); +} - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pItemQuestAccept(pPlayer, pItem, pQuest); +BattleGround* ScriptMgr::CreateBattleground(BattleGroundTypeId typeId) +{ + // TODO: Implement script-side battlegrounds. + ASSERT(false); + return NULL; } -bool ScriptMgr::GOHello(Player* pPlayer, GameObject* pGO) +OutdoorPvP* ScriptMgr::CreateOutdoorPvP(OutdoorPvPData const* data) { - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOHello) return false; + ASSERT(data); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOHello(pPlayer, pGO); + GET_SCRIPT_RET(OutdoorPvPScript, data->ScriptId, tmpscript, NULL); + return tmpscript->OnGetOutdoorPvP(); } -bool ScriptMgr::GOQuestAccept(Player* pPlayer, GameObject* pGO, Quest const* pQuest) +std::vector<ChatCommand*> ScriptMgr::GetChatCommands() { - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOQuestAccept) return false; + std::vector<ChatCommand*> table; + + FOR_SCRIPTS_RET(CommandScript, itr, end, table) + table.push_back(itr->second->OnGetCommands()); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOQuestAccept(pPlayer, pGO, pQuest); + return table; } -bool ScriptMgr::GOChooseReward(Player* pPlayer, GameObject* pGO, Quest const* pQuest, uint32 opt) +void ScriptMgr::OnWeatherChange(Weather* weather, WeatherState state, float grade) { - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript || !tmpscript->pGOChooseReward) return false; + ASSERT(weather); - pPlayer->PlayerTalkClass->ClearMenus(); - return tmpscript->pGOChooseReward(pPlayer, pGO, pQuest, opt); + GET_SCRIPT(WeatherScript, weather->GetScriptId(), tmpscript); + tmpscript->OnChange(weather, state, grade); } -void ScriptMgr::GODestroyed(Player* pPlayer, GameObject* pGO, uint32 destroyedEvent) +void ScriptMgr::OnWeatherUpdate(Weather* weather, uint32 diff) { - Script *tmpscript = m_scripts[pGO->GetGOInfo()->ScriptId]; - if (!tmpscript) return; - tmpscript->pGODestroyed(pPlayer, pGO, destroyedEvent); + ASSERT(weather); + + GET_SCRIPT(WeatherScript, weather->GetScriptId(), tmpscript); + tmpscript->OnUpdate(weather, diff); } -bool ScriptMgr::AreaTrigger(Player* pPlayer, AreaTriggerEntry const* atEntry) +void ScriptMgr::OnAuctionAdd(AuctionHouseObject* ah, AuctionEntry* entry) { - Script *tmpscript = m_scripts[GetAreaTriggerScriptId(atEntry->id)]; - if (!tmpscript || !tmpscript->pAreaTrigger) return false; + ASSERT(ah); + ASSERT(entry); - return tmpscript->pAreaTrigger(pPlayer, atEntry); + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionAdd(ah, entry); } -CreatureAI* ScriptMgr::GetAI(Creature* pCreature) +void ScriptMgr::OnRemoveAuction(AuctionHouseObject* ah, AuctionEntry* entry) { - Script *tmpscript = m_scripts[pCreature->GetScriptId()]; - if (!tmpscript || !tmpscript->GetAI) return NULL; + ASSERT(ah); + ASSERT(entry); - return tmpscript->GetAI(pCreature); + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionRemove(ah, entry); } -bool ScriptMgr::ItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets) +void ScriptMgr::OnAuctionSuccessful(AuctionHouseObject* ah, AuctionEntry* entry) { - Script *tmpscript = m_scripts[pItem->GetProto()->ScriptId]; - if (!tmpscript || !tmpscript->pItemUse) return false; + ASSERT(ah); + ASSERT(entry); - return tmpscript->pItemUse(pPlayer, pItem, targets); + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionSuccessful(ah, entry); } -bool ScriptMgr::ItemExpire(Player* pPlayer, ItemPrototype const * pItemProto) +void ScriptMgr::OnAuctionExpire(AuctionHouseObject* ah, AuctionEntry* entry) { - Script *tmpscript = m_scripts[pItemProto->ScriptId]; - if (!tmpscript || !tmpscript->pItemExpire) return true; + ASSERT(ah); + ASSERT(entry); - return tmpscript->pItemExpire(pPlayer, pItemProto); + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionExpire(ah, entry); } -bool ScriptMgr::EffectDummyCreature(Unit *caster, uint32 spellId, uint32 effIndex, Creature *crTarget) +bool ScriptMgr::OnConditionCheck(Condition* condition, Player* player, Unit* targetOverride) { - Script *tmpscript = m_scripts[crTarget->GetScriptId()]; + ASSERT(condition); + ASSERT(player); + + GET_SCRIPT_RET(ConditionScript, condition->mScriptId, tmpscript, true); + return tmpscript->OnConditionCheck(condition, player, targetOverride); +} - if (!tmpscript || !tmpscript->pEffectDummyCreature) return false; +void ScriptMgr::OnInstall(Vehicle* veh) +{ + ASSERT(veh); - return tmpscript->pEffectDummyCreature(caster, spellId, effIndex, crTarget); + FOREACH_SCRIPT(VehicleScript)->OnInstall(veh); } -bool ScriptMgr::EffectDummyGameObj(Unit *caster, uint32 spellId, uint32 effIndex, GameObject *gameObjTarget) +void ScriptMgr::OnUninstall(Vehicle* veh) { - Script *tmpscript = m_scripts[gameObjTarget->GetGOInfo()->ScriptId]; + ASSERT(veh); - if (!tmpscript || !tmpscript->pEffectDummyGameObj) return false; + FOREACH_SCRIPT(VehicleScript)->OnUninstall(veh); +} - return tmpscript->pEffectDummyGameObj(caster, spellId, effIndex, gameObjTarget); +void ScriptMgr::OnDie(Vehicle* veh) +{ + ASSERT(veh); + + FOREACH_SCRIPT(VehicleScript)->OnDie(veh); } -bool ScriptMgr::EffectDummyItem(Unit *caster, uint32 spellId, uint32 effIndex, Item *itemTarget) +void ScriptMgr::OnReset(Vehicle* veh) { - Script *tmpscript = m_scripts[itemTarget->GetProto()->ScriptId]; + ASSERT(veh); + + FOREACH_SCRIPT(VehicleScript)->OnReset(veh); +} - if (!tmpscript || !tmpscript->pEffectDummyItem) return false; +void ScriptMgr::OnInstallAccessory(Vehicle* veh, Creature* accessory) +{ + ASSERT(veh); + ASSERT(accessory); - return tmpscript->pEffectDummyItem(caster, spellId, effIndex, itemTarget); + FOREACH_SCRIPT(VehicleScript)->OnInstallAccessory(veh, accessory); } -InstanceData* ScriptMgr::CreateInstanceData(Map *map) +void ScriptMgr::OnAddPassenger(Vehicle* veh, Unit* passenger, int8 seatId) { - if (!map->IsDungeon()) return NULL; + ASSERT(veh); + ASSERT(passenger); - Script *tmpscript = m_scripts[((InstanceMap*)map)->GetScriptId()]; - if (!tmpscript || !tmpscript->GetInstanceData) return NULL; + FOREACH_SCRIPT(VehicleScript)->OnAddPassenger(veh, passenger, seatId); +} - return tmpscript->GetInstanceData(map); +void ScriptMgr::OnRemovePassenger(Vehicle* veh, Unit* passenger) +{ + ASSERT(veh); + ASSERT(passenger); + + FOREACH_SCRIPT(VehicleScript)->OnRemovePassenger(veh, passenger); } -void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::list<SpellScript *> & script_vector) +void ScriptMgr::OnDynamicObjectUpdate(DynamicObject* dynobj, uint32 diff) { - SpellScriptsBounds bounds = objmgr.GetSpellScriptsBounds(spell_id); - for (SpellScriptsMap::iterator itr = bounds.first; itr != bounds.second; ++itr) - { - Script *tmpscript = m_scripts[itr->second]; - if (!tmpscript || !tmpscript->GetSpellScript) continue; - script_vector.push_back(tmpscript->GetSpellScript()); - } + ASSERT(dynobj); + + FOR_SCRIPTS(DynamicObjectScript, itr, end) + itr->second->OnUpdate(dynobj, diff); } -void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::vector<std::pair<SpellScript *, SpellScriptsMap::iterator> > & script_vector) +void ScriptMgr::OnAddPassenger(Transport* transport, Player* player) { - SpellScriptsBounds bounds = objmgr.GetSpellScriptsBounds(spell_id); - script_vector.reserve(std::distance(bounds.first, bounds.second)); - for (SpellScriptsMap::iterator itr = bounds.first; itr != bounds.second; ++itr) + ASSERT(transport); + ASSERT(player); + + GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript); + tmpscript->OnAddPassenger(transport, player); +} + +void ScriptMgr::OnAddCreaturePassenger(Transport* transport, Creature* creature) +{ + ASSERT(transport); + ASSERT(creature); + + GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript); + tmpscript->OnAddCreaturePassenger(transport, creature); +} + +void ScriptMgr::OnRemovePassenger(Transport* transport, Player* player) +{ + ASSERT(transport); + ASSERT(player); + + GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript); + tmpscript->OnRemovePassenger(transport, player); +} + +void ScriptMgr::OnTransportUpdate(Transport* transport, uint32 diff) +{ + ASSERT(transport); + + GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript); + tmpscript->OnUpdate(transport, diff); +} + +void SpellHandlerScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<SpellHandlerScript>::AddScript(this); +} + +void AuraHandlerScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<AuraHandlerScript>::AddScript(this); +} + +void ServerScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<ServerScript>::AddScript(this); +} + +void WorldScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<WorldScript>::AddScript(this); +} + +void FormulaScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<FormulaScript>::AddScript(this); +} + +void WorldMapScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<WorldMapScript>::AddScript(this); +} + +void InstanceMapScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<InstanceMapScript>::AddScript(this); +} + +void BattlegroundMapScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<BattlegroundMapScript>::AddScript(this); +} + +void AreaTriggerScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<AreaTriggerScript>::AddScript(this); +} + +void ItemScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<ItemScript>::AddScript(this); +} + +void CreatureScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<CreatureScript>::AddScript(this); +} + +void GameObjectScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<GameObjectScript>::AddScript(this); +} + +void BattlegroundScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<BattlegroundScript>::AddScript(this); +} + +void OutdoorPvPScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<OutdoorPvPScript>::AddScript(this); +} + +void CommandScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<CommandScript>::AddScript(this); +} + +void WeatherScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<WeatherScript>::AddScript(this); +} + +void AuctionHouseScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<AuctionHouseScript>::AddScript(this); +} + +void ConditionScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<ConditionScript>::AddScript(this); +} + +void VehicleScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<VehicleScript>::AddScript(this); +} + +void DynamicObjectScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<DynamicObjectScript>::AddScript(this); +} + +void TransportScript::RegisterSelf() +{ + ScriptMgr::ScriptRegistry<TransportScript>::AddScript(this); +} + +template<class TScript> +void ScriptMgr::ScriptRegistry<TScript>::AddScript(TScript* const script) +{ + ASSERT(script); + + // See if the script is using the same memory as another script. If this happens, it means that + // someone forgot to allocate new memory for a script. + for (ScriptMap::iterator it = ScriptPointerList.begin(); it != ScriptPointerList.end(); ++it) { - Script *tmpscript = m_scripts[itr->second]; - if (!tmpscript || !tmpscript->GetSpellScript) continue; - script_vector.push_back(std::make_pair(tmpscript->GetSpellScript(), itr)); + if (it->second == script) + { + sLog.outError("Script '%s' forgot to allocate memory, so this script and/or the script before that can't work.", + script->ToString()); + + return; + } + } + + // Get an ID for the script. An ID only exists if it's a script that is assigned in the database + // through a script name (or similar). + uint32 id = GetScriptId(script->ToString()); + if (id) + { + // Try to find an existing script. + bool existing = false; + for (ScriptMap::iterator it = ScriptPointerList.begin(); it != ScriptPointerList.end(); ++it) + { + // If the script names match... + if (it->second->GetName() == script->GetName()) + { + // ... It exists. + existing = true; + break; + } + } + + // If the script isn't assigned -> assign it! + if (!existing) + { + ScriptPointerList[id] = script; + sScriptMgr.IncrementScriptCount(); + } + else + { + // If the script is already assigned -> delete it! + sLog.outError("Script '%s' already assigned with the same script name, so the script can't work.", + script->ToString()); + + delete script; + } + } + else if (script->IsDatabaseBound()) + { + // The script uses a script name from database, but isn't assigned to anything. + if (script->GetName().find("example") == std::string::npos) + sLog.outErrorDb("Script named '%s' does not have a script name assigned in database.", + script->ToString()); + + delete script; + } + else + { + // We're dealing with a code-only script; just add it. + ScriptPointerList[_scriptIdCounter++] = script; + sScriptMgr.IncrementScriptCount(); } } + +// Instantiate static members of ScriptMgr::ScriptRegistry. +template<class TScript> std::map<uint32, TScript*> ScriptMgr::ScriptRegistry<TScript>::ScriptPointerList; +template<class TScript> uint32 ScriptMgr::ScriptRegistry<TScript>::_scriptIdCounter; + +// Specialize for each script type class like so: +template class ScriptMgr::ScriptRegistry<SpellHandlerScript>; +template class ScriptMgr::ScriptRegistry<AuraHandlerScript>; +template class ScriptMgr::ScriptRegistry<ServerScript>; +template class ScriptMgr::ScriptRegistry<WorldScript>; +template class ScriptMgr::ScriptRegistry<FormulaScript>; +template class ScriptMgr::ScriptRegistry<WorldMapScript>; +template class ScriptMgr::ScriptRegistry<InstanceMapScript>; +template class ScriptMgr::ScriptRegistry<BattlegroundMapScript>; +template class ScriptMgr::ScriptRegistry<ItemScript>; +template class ScriptMgr::ScriptRegistry<CreatureScript>; +template class ScriptMgr::ScriptRegistry<GameObjectScript>; +template class ScriptMgr::ScriptRegistry<AreaTriggerScript>; +template class ScriptMgr::ScriptRegistry<BattlegroundScript>; +template class ScriptMgr::ScriptRegistry<OutdoorPvPScript>; +template class ScriptMgr::ScriptRegistry<CommandScript>; +template class ScriptMgr::ScriptRegistry<WeatherScript>; +template class ScriptMgr::ScriptRegistry<AuctionHouseScript>; +template class ScriptMgr::ScriptRegistry<ConditionScript>; +template class ScriptMgr::ScriptRegistry<VehicleScript>; +template class ScriptMgr::ScriptRegistry<DynamicObjectScript>; +template class ScriptMgr::ScriptRegistry<TransportScript>; + +// Undefine utility macros. +#undef GET_SCRIPT_RET +#undef GET_SCRIPT +#undef FOREACH_SCRIPT +#undef FOR_SCRIPTS_RET +#undef FOR_SCRIPTS +#undef SCR_REG_LST +#undef SCR_REG_MAP |