diff options
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 |