/* Copyright (C) 2006 - 2008 TrinityScript 
 * This program is free software licensed under GPL version 2
 * Please see the included DOCS/LICENSE.TXT for more information */
#include "ScriptPCH.h"
#include "Config.h"
#include "DatabaseEnv.h"
#include "DBCStores.h"
#include "ObjectMgr.h"
#include "ProgressBar.h"
#include "ScriptLoader.h"
#include "ScriptSystem.h"
// Utility macros to refer to the script registry.
#define SCR_REG_MAP(T) ScriptRegistry::ScriptMap
#define SCR_REG_LST(T) ScriptRegistry::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::GetScriptById(I); \
    if (!V) \
        return;
#define GET_SCRIPT_RET(T,I,V,R) \
    T* V = ScriptRegistry::GetScriptById(I); \
    if (!V) \
        return R;
void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget)
{
    if (!pSource)
    {
        sLog.outError("TSCR: DoScriptText entry %i, invalid Source pointer.", iTextEntry);
        return;
    }
    if (iTextEntry >= 0)
    {
        sLog.outError("TSCR: DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), iTextEntry);
        return;
    }
    const StringTextData* pData = sScriptSystemMgr.GetTextData(iTextEntry);
    if (!pData)
    {
        sLog.outError("TSCR: DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), iTextEntry);
        return;
    }
    sLog.outDebug("TSCR: DoScriptText: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u", iTextEntry, pData->uiSoundId, pData->uiType, pData->uiLanguage, pData->uiEmote);
    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);
    }
    if (pData->uiEmote)
    {
        if (pSource->GetTypeId() == TYPEID_UNIT || pSource->GetTypeId() == TYPEID_PLAYER)
            ((Unit*)pSource)->HandleEmoteCommand(pData->uiEmote);
        else
            sLog.outError("TSCR: DoScriptText entry %i tried to process emote for invalid TypeId (%u).", iTextEntry, pSource->GetTypeId());
    }
    switch (pData->uiType)
    {
        case CHAT_TYPE_SAY:
            pSource->MonsterSay(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0);
            break;
        case CHAT_TYPE_YELL:
            pSource->MonsterYell(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0);
            break;
        case CHAT_TYPE_TEXT_EMOTE:
            pSource->MonsterTextEmote(iTextEntry, pTarget ? pTarget->GetGUID() : 0);
            break;
        case CHAT_TYPE_BOSS_EMOTE:
            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);
            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);
            break;
        }
        case CHAT_TYPE_ZONE_YELL:
            pSource->MonsterYellToZone(iTextEntry, pData->uiLanguage, pTarget ? pTarget->GetGUID() : 0);
            break;
    }
}
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()
{
    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)
    {
        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)
        {
            //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);
        }
    }
}
void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::list & script_vector)
{
    SpellScriptsBounds bounds = objmgr.GetSpellScriptsBounds(spell_id);
    for (SpellScriptsMap::iterator itr = bounds.first; itr != bounds.second; ++itr)
    {
        SpellHandlerScript* tmpscript = ScriptRegistry::GetScriptById(itr->second);
        if (!tmpscript)
            continue;
        SpellScript* script = tmpscript->GetSpellScript();
        if (!script)
        {
            sLog.outError("Spell script %s for spell %u returned a NULL SpellScript pointer!", tmpscript->ToString(), spell_id);
            continue;
        }
        script_vector.push_back(script);
    }
}
void ScriptMgr::CreateSpellScripts(uint32 spell_id, std::vector > & 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::GetScriptById(itr->second);
        if (!tmpscript)
            continue;
        SpellScript* script = tmpscript->GetSpellScript();
        if (!script)
        {
            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));
    }
}
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::OnDestroyMap(Map* map)
{
    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::OnLoadGridMap(Map* map, uint32 gx, uint32 gy)
{
    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::OnUnloadGridMap(Map* map, uint32 gx, uint32 gy)
{
    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;
}
void ScriptMgr::OnPlayerEnter(Map* map, Player* player)
{
    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;
}
void ScriptMgr::OnPlayerLeave(Map* map, Player* player)
{
    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;
}
void ScriptMgr::OnMapUpdate(Map* map, uint32 diff)
{
    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;
}
#undef SCR_MAP_BGN
#undef SCR_MAP_END
InstanceData* ScriptMgr::CreateInstanceData(InstanceMap* map)
{
    ASSERT(map);
    GET_SCRIPT_RET(InstanceMapScript, map->GetScriptId(), tmpscript, NULL);
    return tmpscript->OnGetInstanceData(map);
}
bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Item* target)
{
    ASSERT(caster);
    ASSERT(target);
    GET_SCRIPT_RET(ItemScript, target->GetProto()->ScriptId, tmpscript, false);
    return tmpscript->OnDummyEffect(caster, spellId, effIndex, target);
}
bool ScriptMgr::OnQuestAccept(Player* player, Item* item, Quest const* quest)
{
    ASSERT(player);
    ASSERT(item);
    ASSERT(quest);
    GET_SCRIPT_RET(ItemScript, item->GetProto()->ScriptId, tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnQuestAccept(player, item, quest);
}
bool ScriptMgr::OnItemUse(Player* player, Item* item, SpellCastTargets const& targets)
{
    ASSERT(player);
    ASSERT(item);
    GET_SCRIPT_RET(ItemScript, item->GetProto()->ScriptId, tmpscript, false);
    return tmpscript->OnUse(player, item, targets);
}
bool ScriptMgr::OnItemExpire(Player* player, ItemPrototype const* proto)
{
    ASSERT(player);
    ASSERT(proto);
    GET_SCRIPT_RET(ItemScript, proto->ScriptId, tmpscript, false);
    return tmpscript->OnExpire(player, proto);
}
bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, Creature* target)
{
    ASSERT(caster);
    ASSERT(target);
    GET_SCRIPT_RET(CreatureScript, target->GetScriptId(), tmpscript, false);
    return tmpscript->OnDummyEffect(caster, spellId, effIndex, target);
}
bool ScriptMgr::OnGossipHello(Player* player, Creature* creature)
{
    ASSERT(player);
    ASSERT(creature);
    GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnGossipHello(player, creature);
}
bool ScriptMgr::OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action)
{
    ASSERT(player);
    ASSERT(creature);
    GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnGossipSelect(player, creature, sender, action);
}
bool ScriptMgr::OnGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code)
{
    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::OnQuestAccept(Player* player, Creature* creature, Quest const* quest)
{
    ASSERT(player);
    ASSERT(creature);
    ASSERT(quest);
    GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnQuestAccept(player, creature, quest);
}
bool ScriptMgr::OnQuestSelect(Player* player, Creature* creature, Quest const* quest)
{
    ASSERT(player);
    ASSERT(creature);
    ASSERT(quest);
    GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnQuestSelect(player, creature, quest);
}
bool ScriptMgr::OnQuestComplete(Player* player, Creature* creature, Quest const* quest)
{
    ASSERT(player);
    ASSERT(creature);
    ASSERT(quest);
    GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnQuestComplete(player, creature, quest);
}
bool ScriptMgr::OnQuestReward(Player* player, Creature* creature, Quest const* quest, uint32 opt)
{
    ASSERT(player);
    ASSERT(creature);
    ASSERT(quest);
    GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnQuestReward(player, creature, quest, opt);
}
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);
}
CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature)
{
    ASSERT(creature);
    GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, NULL);
    return tmpscript->OnGetAI(creature);
}
void ScriptMgr::OnCreatureUpdate(Creature* creature, uint32 diff)
{
    ASSERT(creature);
    GET_SCRIPT(CreatureScript, creature->GetScriptId(), tmpscript);
    tmpscript->OnUpdate(creature, diff);
}
bool ScriptMgr::OnGossipHello(Player* player, GameObject* go)
{
    ASSERT(player);
    ASSERT(go);
    GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnGossipHello(player, go);
}
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::OnGossipSelectCode(Player* player, GameObject* go, uint32 sender, uint32 action, const char* code)
{
    ASSERT(player);
    ASSERT(go);
    ASSERT(code);
    GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnGossipSelectCode(player, go, sender, action, code);
}
bool ScriptMgr::OnQuestAccept(Player* player, GameObject* go, Quest const* quest)
{
    ASSERT(player);
    ASSERT(go);
    ASSERT(quest);
    GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnQuestAccept(player, go, quest);
}
bool ScriptMgr::OnQuestReward(Player* player, GameObject* go, Quest const* quest, uint32 opt)
{
    ASSERT(player);
    ASSERT(go);
    ASSERT(quest);
    GET_SCRIPT_RET(GameObjectScript, go->GetScriptId(), tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnQuestReward(player, go, quest, opt);
}
uint32 ScriptMgr::GetDialogStatus(Player* player, GameObject* go)
{
    ASSERT(player);
    ASSERT(go);
    // 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);
}
void ScriptMgr::OnGameObjectDestroyed(Player* player, GameObject* go, uint32 eventId)
{
    ASSERT(player);
    ASSERT(go);
    GET_SCRIPT(GameObjectScript, go->GetScriptId(), tmpscript);
    tmpscript->OnDestroyed(player, go, eventId);
}
void ScriptMgr::OnGameObjectUpdate(GameObject* go, uint32 diff)
{
    ASSERT(go);
    GET_SCRIPT(GameObjectScript, go->GetScriptId(), tmpscript);
    tmpscript->OnUpdate(go, diff);
}
bool ScriptMgr::OnDummyEffect(Unit* caster, uint32 spellId, SpellEffIndex effIndex, GameObject* target)
{
    ASSERT(caster);
    ASSERT(target);
    GET_SCRIPT_RET(GameObjectScript, target->GetScriptId(), tmpscript, false);
    return tmpscript->OnDummyEffect(caster, spellId, effIndex, target);
}
bool ScriptMgr::OnTrigger(Player* player, AreaTriggerEntry const* trigger)
{
    ASSERT(player);
    ASSERT(trigger);
    GET_SCRIPT_RET(AreaTriggerScript, trigger->id, tmpscript, false);
    return tmpscript->OnTrigger(player, trigger);
}
BattleGround* ScriptMgr::CreateBattleground(BattleGroundTypeId typeId)
{
    // TODO: Implement script-side battlegrounds.
    ASSERT(false);
    return NULL;
}
OutdoorPvP* ScriptMgr::CreateOutdoorPvP(OutdoorPvPData const* data)
{
    ASSERT(data);
    GET_SCRIPT_RET(OutdoorPvPScript, data->ScriptId, tmpscript, NULL);
    return tmpscript->OnGetOutdoorPvP();
}
std::vector ScriptMgr::GetChatCommands()
{
    std::vector table;
    FOR_SCRIPTS_RET(CommandScript, itr, end, table)
        table.push_back(itr->second->OnGetCommands());
    return table;
}
void ScriptMgr::OnWeatherChange(Weather* weather, WeatherState state, float grade)
{
    ASSERT(weather);
    GET_SCRIPT(WeatherScript, weather->GetScriptId(), tmpscript);
    tmpscript->OnChange(weather, state, grade);
}
void ScriptMgr::OnWeatherUpdate(Weather* weather, uint32 diff)
{
    ASSERT(weather);
    GET_SCRIPT(WeatherScript, weather->GetScriptId(), tmpscript);
    tmpscript->OnUpdate(weather, diff);
}
void ScriptMgr::OnAuctionAdd(AuctionHouseObject* ah, AuctionEntry* entry)
{
    ASSERT(ah);
    ASSERT(entry);
    FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionAdd(ah, entry);
}
void ScriptMgr::OnRemoveAuction(AuctionHouseObject* ah, AuctionEntry* entry)
{
    ASSERT(ah);
    ASSERT(entry);
    FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionRemove(ah, entry);
}
void ScriptMgr::OnAuctionSuccessful(AuctionHouseObject* ah, AuctionEntry* entry)
{
    ASSERT(ah);
    ASSERT(entry);
    FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionSuccessful(ah, entry);
}
void ScriptMgr::OnAuctionExpire(AuctionHouseObject* ah, AuctionEntry* entry)
{
    ASSERT(ah);
    ASSERT(entry);
    FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionExpire(ah, entry);
}
bool ScriptMgr::OnConditionCheck(Condition* condition, Player* player, Unit* targetOverride)
{
    ASSERT(condition);
    ASSERT(player);
    GET_SCRIPT_RET(ConditionScript, condition->mScriptId, tmpscript, true);
    return tmpscript->OnConditionCheck(condition, player, targetOverride);
}
void ScriptMgr::OnInstall(Vehicle* veh)
{
    ASSERT(veh);
    FOREACH_SCRIPT(VehicleScript)->OnInstall(veh);
}
void ScriptMgr::OnUninstall(Vehicle* veh)
{
    ASSERT(veh);
    FOREACH_SCRIPT(VehicleScript)->OnUninstall(veh);
}
void ScriptMgr::OnDie(Vehicle* veh)
{
    ASSERT(veh);
    FOREACH_SCRIPT(VehicleScript)->OnDie(veh);
}
void ScriptMgr::OnReset(Vehicle* veh)
{
    ASSERT(veh);
    FOREACH_SCRIPT(VehicleScript)->OnReset(veh);
}
void ScriptMgr::OnInstallAccessory(Vehicle* veh, Creature* accessory)
{
    ASSERT(veh);
    ASSERT(accessory);
    FOREACH_SCRIPT(VehicleScript)->OnInstallAccessory(veh, accessory);
}
void ScriptMgr::OnAddPassenger(Vehicle* veh, Unit* passenger, int8 seatId)
{
    ASSERT(veh);
    ASSERT(passenger);
    FOREACH_SCRIPT(VehicleScript)->OnAddPassenger(veh, passenger, seatId);
}
void ScriptMgr::OnRemovePassenger(Vehicle* veh, Unit* passenger)
{
    ASSERT(veh);
    ASSERT(passenger);
    FOREACH_SCRIPT(VehicleScript)->OnRemovePassenger(veh, passenger);
}
void ScriptMgr::OnDynamicObjectUpdate(DynamicObject* dynobj, uint32 diff)
{
    ASSERT(dynobj);
    FOR_SCRIPTS(DynamicObjectScript, itr, end)
        itr->second->OnUpdate(dynobj, diff);
}
void ScriptMgr::OnAddPassenger(Transport* transport, Player* player)
{
    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::AddScript(this);
}
void AuraHandlerScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void ServerScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void WorldScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void FormulaScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void WorldMapScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void InstanceMapScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void BattlegroundMapScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void AreaTriggerScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void ItemScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void CreatureScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void GameObjectScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void BattlegroundScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void OutdoorPvPScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void CommandScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void WeatherScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void AuctionHouseScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void ConditionScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void VehicleScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void DynamicObjectScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
void TransportScript::RegisterSelf()
{
    ScriptMgr::ScriptRegistry::AddScript(this);
}
template
void ScriptMgr::ScriptRegistry::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)
    {
        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 std::map ScriptMgr::ScriptRegistry::ScriptPointerList;
template uint32 ScriptMgr::ScriptRegistry::_scriptIdCounter;
// Specialize for each script type class like so:
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
template class ScriptMgr::ScriptRegistry;
// 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