/*
 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see .
 */
#include "ScriptMgr.h"
#include "AchievementMgr.h"
#include "AreaTrigger.h"
#include "AreaTriggerAI.h"
#include "ChatCommand.h"
#include "Conversation.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "CreatureAIImpl.h"
#include "CreatureAISelector.h"
#include "DB2Stores.h"
#include "Errors.h"
#include "GameObject.h"
#include "GossipDef.h"
#include "InstanceScript.h"
#include "Item.h"
#include "LFGScripts.h"
#include "Log.h"
#include "Map.h"
#include "MapManager.h"
#include "ObjectMgr.h"
#include "OutdoorPvPMgr.h"
#include "Player.h"
#include "ScriptReloadMgr.h"
#include "ScriptSystem.h"
#include "SmartAI.h"
#include "SpellInfo.h"
#include "SpellMgr.h"
#include "SpellScript.h"
#include "Timer.h"
#include "Transport.h"
#include "Vehicle.h"
#include "Weather.h"
#include "WorldPacket.h"
#include 
// Trait which indicates whether this script type
// must be assigned in the database.
template
struct is_script_database_bound
    : std::false_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
        : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
template<>
struct is_script_database_bound
    : std::true_type { };
enum Spells
{
    SPELL_HOTSWAP_VISUAL_SPELL_EFFECT = 40162 // 59084
};
class ScriptRegistryInterface
{
public:
    ScriptRegistryInterface() { }
    virtual ~ScriptRegistryInterface() { }
    ScriptRegistryInterface(ScriptRegistryInterface const&) = delete;
    ScriptRegistryInterface(ScriptRegistryInterface&&) = delete;
    ScriptRegistryInterface& operator= (ScriptRegistryInterface const&) = delete;
    ScriptRegistryInterface& operator= (ScriptRegistryInterface&&) = delete;
    /// Removes all scripts associated with the given script context.
    /// Requires ScriptRegistryBase::SwapContext to be called after all transfers have finished.
    virtual void ReleaseContext(std::string const& context) = 0;
    /// Injects and updates the changed script objects.
    virtual void SwapContext(bool initialize) = 0;
    /// Removes the scripts used by this registry from the given container.
    /// Used to find unused script names.
    virtual void RemoveUsedScriptsFromContainer(std::unordered_set& scripts) = 0;
    /// Unloads the script registry.
    virtual void Unload() = 0;
    /// Updates the scripts to reflect the current id
    virtual void SyncScriptNames() = 0;
};
template
class ScriptRegistry;
class ScriptRegistryCompositum
    : public ScriptRegistryInterface
{
    ScriptRegistryCompositum() { }
    template
    friend class ScriptRegistry;
    /// Type erasure wrapper for objects
    class DeleteableObjectBase
    {
    public:
        DeleteableObjectBase() { }
        virtual ~DeleteableObjectBase() { }
        DeleteableObjectBase(DeleteableObjectBase const&) = delete;
        DeleteableObjectBase& operator= (DeleteableObjectBase const&) = delete;
    };
    template
    class DeleteableObject
        : public DeleteableObjectBase
    {
    public:
        DeleteableObject(T&& object)
            : _object(std::forward(object)) { }
    private:
        T _object;
    };
public:
    void SetScriptNameInContext(std::string const& scriptname, std::string const& context)
    {
        ASSERT(_scriptnames_to_context.find(scriptname) == _scriptnames_to_context.end(),
               "Scriptname was assigned to this context already!");
        _scriptnames_to_context.insert(std::make_pair(scriptname, context));
    }
    std::string const& GetScriptContextOfScriptName(std::string const& scriptname) const
    {
        auto itr = _scriptnames_to_context.find(scriptname);
        ASSERT(itr != _scriptnames_to_context.end() &&
               "Given scriptname doesn't exist!");
        return itr->second;
    }
    void ReleaseContext(std::string const& context) final override
    {
        for (auto const registry : _registries)
            registry->ReleaseContext(context);
        // Clear the script names in context after calling the release hooks
        // since it's possible that new references to a shared library
        // are acquired when releasing.
        for (auto itr = _scriptnames_to_context.begin();
                        itr != _scriptnames_to_context.end();)
            if (itr->second == context)
                itr = _scriptnames_to_context.erase(itr);
            else
                ++itr;
    }
    void SwapContext(bool initialize) final override
    {
        for (auto const registry : _registries)
            registry->SwapContext(initialize);
        DoDelayedDelete();
    }
    void RemoveUsedScriptsFromContainer(std::unordered_set& scripts) final override
    {
        for (auto const registry : _registries)
            registry->RemoveUsedScriptsFromContainer(scripts);
    }
    void Unload() final override
    {
        for (auto const registry : _registries)
            registry->Unload();
    }
    void SyncScriptNames() final override
    {
        for (auto const registry : _registries)
            registry->SyncScriptNames();
    }
    template
    void QueueForDelayedDelete(T&& any)
    {
        _delayed_delete_queue.push_back(
    std::make_unique<
                DeleteableObject::type>
            >(std::forward(any))
        );
    }
    static ScriptRegistryCompositum* Instance()
    {
        static ScriptRegistryCompositum instance;
        return &instance;
    }
private:
    void Register(ScriptRegistryInterface* registry)
    {
        _registries.insert(registry);
    }
    void DoDelayedDelete()
    {
        _delayed_delete_queue.clear();
    }
    std::unordered_set _registries;
    std::vector> _delayed_delete_queue;
    std::unordered_map<
        std::string /*script name*/,
        std::string /*context*/
    > _scriptnames_to_context;
};
#define sScriptRegistryCompositum ScriptRegistryCompositum::Instance()
template
class SpecializedScriptRegistry;
// This is the global static registry of scripts.
template
class ScriptRegistry final
    : public SpecializedScriptRegistry<
        ScriptType, is_script_database_bound::value>
{
    ScriptRegistry()
    {
        sScriptRegistryCompositum->Register(this);
    }
public:
    static ScriptRegistry* Instance()
    {
        static ScriptRegistry instance;
        return &instance;
    }
    void LogDuplicatedScriptPointerError(ScriptType const* first, ScriptType const* second)
    {
        // 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.
        TC_LOG_ERROR("scripts", "Script '%s' has same memory pointer as '%s'.",
            first->GetName().c_str(), second->GetName().c_str());
    }
};
class ScriptRegistrySwapHookBase
{
public:
    ScriptRegistrySwapHookBase() { }
    virtual ~ScriptRegistrySwapHookBase() { }
    ScriptRegistrySwapHookBase(ScriptRegistrySwapHookBase const&) = delete;
    ScriptRegistrySwapHookBase(ScriptRegistrySwapHookBase&&) = delete;
    ScriptRegistrySwapHookBase& operator= (ScriptRegistrySwapHookBase const&) = delete;
    ScriptRegistrySwapHookBase& operator= (ScriptRegistrySwapHookBase&&) = delete;
    /// Called before the actual context release happens
    virtual void BeforeReleaseContext(std::string const& /*context*/) { }
    /// Called before SwapContext
    virtual void BeforeSwapContext(bool /*initialize*/) { }
    /// Called before Unload
    virtual void BeforeUnload() { }
    /// Called manually to sync scriptnames
    virtual void OnScriptNamesSync() { };
};
template
class ScriptRegistrySwapHooks
    : public ScriptRegistrySwapHookBase
{
};
template
class UnsupportedScriptRegistrySwapHooks
    : public ScriptRegistrySwapHookBase
{
public:
    void BeforeReleaseContext(std::string const& context) final override
    {
        auto const bounds = static_cast(this)->_ids_of_contexts.equal_range(context);
        ASSERT(bounds.first == bounds.second);
    }
};
/// This hook is responsible for swapping Creature, GameObject and AreaTrigger AI's
template
class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks
    : public ScriptRegistrySwapHookBase
{
    template
    class AIFunctionMapWorker
    {
    public:
        template
        AIFunctionMapWorker(T&& worker)
            : _worker(std::forward(worker)) { }
        void Visit(std::unordered_map& objects)
        {
            _worker(objects);
        }
        template
        void Visit(std::unordered_map&) { }
    private:
        W _worker;
    };
    class AsyncCastHotswapEffectEvent : public BasicEvent
    {
    public:
        explicit AsyncCastHotswapEffectEvent(Unit* owner) : owner_(owner) { }
        bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
        {
            owner_->CastSpell(owner_, SPELL_HOTSWAP_VISUAL_SPELL_EFFECT, true);
            return true;
        }
    private:
        Unit* owner_;
    };
    // Hook which is called before a creature is swapped
    static void UnloadResetScript(Creature* creature)
    {
        // Remove deletable events only,
        // otherwise it causes crashes with non-deletable spell events.
        creature->m_Events.KillAllEvents(false);
        if (creature->IsCharmed())
            creature->RemoveCharmedBy(nullptr);
        ASSERT(!creature->IsCharmed(),
               "There is a disabled AI which is still loaded.");
        if (creature->IsAlive())
            creature->AI()->EnterEvadeMode();
    }
    static void UnloadDestroyScript(Creature* creature)
    {
        bool const destroyed = creature->AIM_Destroy();
        ASSERT(destroyed,
               "Destroying the AI should never fail here!");
        (void)destroyed;
        ASSERT(!creature->AI(),
               "The AI should be null here!");
    }
    // Hook which is called before a gameobject is swapped
    static void UnloadResetScript(GameObject* gameobject)
    {
        gameobject->AI()->Reset();
    }
    static void UnloadDestroyScript(GameObject* gameobject)
    {
        gameobject->AIM_Destroy();
        ASSERT(!gameobject->AI(),
               "The AI should be null here!");
    }
    // Hook which is called before a areatrigger is swapped
    static void UnloadResetScript(AreaTrigger* at)
    {
        at->AI()->OnRemove();
    }
    static void UnloadDestroyScript(AreaTrigger* at)
    {
        at->AI_Destroy();
        ASSERT(!at->AI(),
            "The AI should be null here!");
    }
    // Hook which is called after a creature was swapped
    static void LoadInitializeScript(Creature* creature)
    {
        ASSERT(!creature->AI(),
               "The AI should be null here!");
        if (creature->IsAlive())
            creature->ClearUnitState(UNIT_STATE_EVADE);
        bool const created = creature->AIM_Create();
        ASSERT(created,
               "Creating the AI should never fail here!");
        (void)created;
    }
    static void LoadResetScript(Creature* creature)
    {
        if (!creature->IsAlive())
            return;
        creature->AI()->InitializeAI();
        if (creature->GetVehicleKit())
            creature->GetVehicleKit()->Reset();
        creature->AI()->EnterEvadeMode();
        // Cast a dummy visual spell asynchronously here to signal
        // that the AI was hot swapped
        creature->m_Events.AddEvent(new AsyncCastHotswapEffectEvent(creature),
            creature->m_Events.CalculateTime(0s));
    }
    // Hook which is called after a gameobject was swapped
    static void LoadInitializeScript(GameObject* gameobject)
    {
        ASSERT(!gameobject->AI(),
               "The AI should be null here!");
        gameobject->AIM_Initialize();
    }
    static void LoadResetScript(GameObject* gameobject)
    {
        gameobject->AI()->Reset();
    }
    // Hook which is called after a areatrigger was swapped
    static void LoadInitializeScript(AreaTrigger* at)
    {
        ASSERT(!at->AI(),
            "The AI should be null here!");
        at->AI_Initialize();
    }
    static void LoadResetScript(AreaTrigger* at)
    {
        at->AI()->OnCreate();
    }
    static Creature* GetEntityFromMap(std::common_type, Map* map, ObjectGuid const& guid)
    {
        return map->GetCreature(guid);
    }
    static GameObject* GetEntityFromMap(std::common_type, Map* map, ObjectGuid const& guid)
    {
        return map->GetGameObject(guid);
    }
    static AreaTrigger* GetEntityFromMap(std::common_type, Map* map, ObjectGuid const& guid)
    {
        return map->GetAreaTrigger(guid);
    }
    static auto VisitObjectsToSwapOnMap(std::unordered_set const& idsToRemove)
    {
        return [&idsToRemove](Map* map, auto&& visitor)
        {
            auto evaluator = [&](std::unordered_map& objects)
            {
                for (auto object : objects)
                {
                    // When the script Id of the script isn't removed in this
                    // context change, do nothing.
                    uint32 aiId = object.second->AI() ? object.second->AI()->GetId() : 0;
                    if (idsToRemove.find(aiId) != idsToRemove.end() || (aiId == 0 && object.second->GetScriptId()))
                        visitor(object.second);
                }
            };
            AIFunctionMapWorker::type> worker(std::move(evaluator));
            TypeContainerVisitor containerVisitor(worker);
            containerVisitor.Visit(map->GetObjectsStore());
        };
    }
    static auto VisitObjectsWhereIdWasUpdated()
    {
        return [](Map* map, auto&& visitor)
        {
            auto evaluator = [&](std::unordered_map& objects)
            {
                for (auto object : objects)
                {
                    if (object.second->AI())
                    {
                        ASSERT(object.second->AI()->GetId());
                        uint32 aiId = object.second->AI()->GetId();
                        uint32 scriptId = FactorySelector::GetSelectedAIId(object.second);
                        ASSERT(scriptId);
                        if (aiId == scriptId)
                        {
                            // Skip if the ai id matches
                            continue;
                        }
                        if (!sObjectMgr->IsScriptDatabaseBound(scriptId)
                            && !sObjectMgr->IsScriptDatabaseBound(aiId))
                        {
                            // Skip if we are dealing with two selectable AI scripts
                            continue;
                        }
                        visitor(object.second);
                    }
                    else
                        visitor(object.second);
                }
            };
            AIFunctionMapWorker::type> worker(std::move(evaluator));
            TypeContainerVisitor containerVisitor(worker);
            containerVisitor.Visit(map->GetObjectsStore());
        };
    }
    template
    static void DestroyScriptIdsWithVisitor(T&& visitor)
    {
        // First reset all swapped scripts safe by guid
        sMapMgr->DoForAllMaps([&](Map* map)
        {
            std::vector guidsToReset;
            visitor(map, [&](ObjectType* object)
            {
                if (object->AI())
                    guidsToReset.push_back(object->GetGUID());
            });
            for (ObjectGuid const& guid : guidsToReset)
            {
                if (auto entity = GetEntityFromMap(std::common_type{}, map, guid))
                    UnloadResetScript(entity);
            }
            visitor(map, [&](ObjectType* object)
            {
                // Destroy the scripts instantly
                UnloadDestroyScript(object);
            });
        });
    }
    template
    static void InitializeScriptIdsWithVisitor(T&& visitor)
    {
        sMapMgr->DoForAllMaps([&](Map* map)
        {
            std::vector guidsToReset;
            visitor(map, [&](ObjectType* object)
            {
                if (!object->AI())
                {
                    // Initialize the script
                    LoadInitializeScript(object);
                    guidsToReset.push_back(object->GetGUID());
                }
            });
            for (ObjectGuid const& guid : guidsToReset)
            {
                // Reset the script
                if (auto entity = GetEntityFromMap(std::common_type{}, map, guid))
                {
                    if (!entity->AI())
                        LoadInitializeScript(entity);
                    LoadResetScript(entity);
                }
            }
        });
    }
public:
    void BeforeReleaseContext(std::string const& context) final override
    {
        auto idsToRemove = static_cast(this)->GetScriptIDsToRemove(context);
        DestroyScriptIdsWithVisitor(VisitObjectsToSwapOnMap(idsToRemove));
        // Add the new ids which are removed to the global ids to remove set
        ids_removed_.insert(idsToRemove.begin(), idsToRemove.end());
    }
    void BeforeSwapContext(bool initialize) override
    {
        // Never swap creature or gameobject scripts when initializing
        if (initialize)
            return;
        // Add the recently added scripts to the deleted scripts to replace
        // default AI's with recently added core scripts.
        ids_removed_.insert(static_cast(this)->GetRecentlyAddedScriptIDs().begin(),
                            static_cast(this)->GetRecentlyAddedScriptIDs().end());
        auto const visitor = VisitObjectsToSwapOnMap(ids_removed_);
        DestroyScriptIdsWithVisitor(visitor);
        InitializeScriptIdsWithVisitor(visitor);
        ids_removed_.clear();
    }
    void BeforeUnload() final override
    {
        ASSERT(ids_removed_.empty());
    }
    void OnScriptNamesSync() final override
    {
        auto const visitor = VisitObjectsWhereIdWasUpdated();
        DestroyScriptIdsWithVisitor(visitor);
        InitializeScriptIdsWithVisitor(visitor);
    }
private:
    std::unordered_set ids_removed_;
};
// This hook is responsible for swapping CreatureAI's
template
class ScriptRegistrySwapHooks
    : public CreatureGameObjectAreaTriggerScriptRegistrySwapHooks<
        Creature, CreatureScript, Base
      > { };
// This hook is responsible for swapping GameObjectAI's
template
class ScriptRegistrySwapHooks
    : public CreatureGameObjectAreaTriggerScriptRegistrySwapHooks<
        GameObject, GameObjectScript, Base
      > { };
// This hook is responsible for swapping AreaTriggerAI's
template
class ScriptRegistrySwapHooks
    : public CreatureGameObjectAreaTriggerScriptRegistrySwapHooks<
    AreaTrigger, AreaTriggerEntityScript, Base
    > { };
/// This hook is responsible for swapping BattlefieldScripts
template
class ScriptRegistrySwapHooks
        : public UnsupportedScriptRegistrySwapHooks { };
/// This hook is responsible for swapping BattlegroundScript's
template
class ScriptRegistrySwapHooks
    : public UnsupportedScriptRegistrySwapHooks { };
/// This hook is responsible for swapping OutdoorPvP's
template
class ScriptRegistrySwapHooks
    : public ScriptRegistrySwapHookBase
{
public:
    ScriptRegistrySwapHooks() : swapped(false) { }
    void BeforeReleaseContext(std::string const& context) final override
    {
        auto const bounds = static_cast(this)->_ids_of_contexts.equal_range(context);
        if ((!swapped) && (bounds.first != bounds.second))
        {
            swapped = true;
            sOutdoorPvPMgr->Die();
        }
    }
    void BeforeSwapContext(bool initialize) override
    {
        // Never swap outdoor pvp scripts when initializing
        if ((!initialize) && swapped)
        {
            sOutdoorPvPMgr->InitOutdoorPvP();
            swapped = false;
        }
    }
    void BeforeUnload() final override
    {
        ASSERT(!swapped);
    }
private:
    bool swapped;
};
/// This hook is responsible for swapping InstanceMapScript's
template
class ScriptRegistrySwapHooks
    : public ScriptRegistrySwapHookBase
{
public:
    ScriptRegistrySwapHooks()  : swapped(false) { }
    void BeforeReleaseContext(std::string const& context) final override
    {
        auto const bounds = static_cast(this)->_ids_of_contexts.equal_range(context);
        if (bounds.first != bounds.second)
            swapped = true;
    }
    void BeforeSwapContext(bool /*initialize*/) override
    {
        swapped = false;
    }
    void BeforeUnload() final override
    {
        ASSERT(!swapped);
    }
private:
    bool swapped;
};
/// This hook is responsible for swapping SceneScript's
template
class ScriptRegistrySwapHooks
    : public ScriptRegistrySwapHookBase
{
public:
    ScriptRegistrySwapHooks() : swapped(false) { }
    void BeforeReleaseContext(std::string const& context) final override
    {
        auto const bounds = static_cast(this)->_ids_of_contexts.equal_range(context);
        if (bounds.first != bounds.second)
            swapped = true;
    }
    void BeforeSwapContext(bool /*initialize*/) override
    {
        swapped = false;
    }
    void BeforeUnload() final override
    {
        ASSERT(!swapped);
    }
private:
    bool swapped;
};
/// This hook is responsible for swapping QuestScript's
template
class ScriptRegistrySwapHooks
    : public ScriptRegistrySwapHookBase
{
public:
    ScriptRegistrySwapHooks() : swapped(false) { }
    void BeforeReleaseContext(std::string const& context) final override
    {
        auto const bounds = static_cast(this)->_ids_of_contexts.equal_range(context);
        if (bounds.first != bounds.second)
            swapped = true;
    }
    void BeforeSwapContext(bool /*initialize*/) override
    {
        swapped = false;
    }
    void BeforeUnload() final override
    {
        ASSERT(!swapped);
    }
private:
    bool swapped;
};
/// This hook is responsible for swapping SpellScriptLoader's
template
class ScriptRegistrySwapHooks
    : public ScriptRegistrySwapHookBase
{
public:
    ScriptRegistrySwapHooks() : swapped(false) { }
    void BeforeReleaseContext(std::string const& context) final override
    {
        auto const bounds = static_cast(this)->_ids_of_contexts.equal_range(context);
        if (bounds.first != bounds.second)
            swapped = true;
    }
    void BeforeSwapContext(bool /*initialize*/) override
    {
        if (swapped)
        {
            sObjectMgr->ValidateSpellScripts();
            swapped = false;
        }
    }
    void BeforeUnload() final override
    {
        ASSERT(!swapped);
    }
private:
    bool swapped;
};
// Database bound script registry
template
class SpecializedScriptRegistry
    : public ScriptRegistryInterface,
      public ScriptRegistrySwapHooks>
{
    template
    friend class UnsupportedScriptRegistrySwapHooks;
    template
    friend class ScriptRegistrySwapHooks;
    template
    friend class CreatureGameObjectAreaTriggerScriptRegistrySwapHooks;
public:
    SpecializedScriptRegistry() { }
    typedef std::unordered_map<
        uint32 /*script id*/,
        std::unique_ptr
    > ScriptStoreType;
    typedef typename ScriptStoreType::iterator ScriptStoreIteratorType;
    void ReleaseContext(std::string const& context) final override
    {
        this->BeforeReleaseContext(context);
        auto const bounds = _ids_of_contexts.equal_range(context);
        for (auto itr = bounds.first; itr != bounds.second; ++itr)
            _scripts.erase(itr->second);
    }
    void SwapContext(bool initialize) final override
    {
      this->BeforeSwapContext(initialize);
      _recently_added_ids.clear();
    }
    void RemoveUsedScriptsFromContainer(std::unordered_set& scripts) final override
    {
        for (auto const& script : _scripts)
            scripts.erase(script.second->GetName());
    }
    void Unload() final override
    {
        this->BeforeUnload();
        ASSERT(_recently_added_ids.empty(),
               "Recently added script ids should be empty here!");
        _scripts.clear();
        _ids_of_contexts.clear();
    }
    void SyncScriptNames() final override
    {
        this->OnScriptNamesSync();
    }
    // Adds a database bound script
    void AddScript(ScriptType* script)
    {
        ASSERT(script,
               "Tried to call AddScript with a nullpointer!");
        ASSERT(!sScriptMgr->GetCurrentScriptContext().empty(),
               "Tried to register a script without being in a valid script context!");
        std::unique_ptr script_ptr(script);
        // Get an ID for the script.
        uint32 const id = sObjectMgr->GetScriptId(script->GetName());
        // Try to find an existing script.
        for (auto const& stored_script : _scripts)
        {
            // If the script names match...
            if (stored_script.second->GetName() == script->GetName())
            {
                // If the script is already assigned -> delete it!
                ABORT_MSG("Script '%s' already assigned with the same script name, "
                    "so the script can't work.", script->GetName().c_str());
                // Error that should be fixed ASAP.
                sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr));
                ABORT();
                return;
            }
        }
        // If the script isn't assigned -> assign it!
        _scripts.insert(std::make_pair(id, std::move(script_ptr)));
        _ids_of_contexts.insert(std::make_pair(sScriptMgr->GetCurrentScriptContext(), id));
        _recently_added_ids.insert(id);
        sScriptRegistryCompositum->SetScriptNameInContext(script->GetName(),
            sScriptMgr->GetCurrentScriptContext());
    }
    // Gets a script by its ID (assigned by ObjectMgr).
    ScriptType* GetScriptById(uint32 id)
    {
        auto const itr = _scripts.find(id);
        if (itr != _scripts.end())
            return itr->second.get();
        return nullptr;
    }
    ScriptStoreType& GetScripts()
    {
        return _scripts;
    }
protected:
    // Returns the script id's which are registered to a certain context
    std::unordered_set GetScriptIDsToRemove(std::string const& context) const
    {
        // Create a set of all ids which are removed
        std::unordered_set scripts_to_remove;
        auto const bounds = _ids_of_contexts.equal_range(context);
        for (auto itr = bounds.first; itr != bounds.second; ++itr)
            scripts_to_remove.insert(itr->second);
        return scripts_to_remove;
    }
    std::unordered_set const& GetRecentlyAddedScriptIDs() const
    {
        return _recently_added_ids;
    }
private:
    ScriptStoreType _scripts;
    // Scripts of a specific context
    std::unordered_multimap _ids_of_contexts;
    // Script id's which were registered recently
    std::unordered_set _recently_added_ids;
};
/// This hook is responsible for swapping CommandScript's
template
class ScriptRegistrySwapHooks
    : public ScriptRegistrySwapHookBase
{
public:
    void BeforeReleaseContext(std::string const& /*context*/) final override
    {
        Trinity::ChatCommands::InvalidateCommandMap();
    }
    void BeforeSwapContext(bool /*initialize*/) override
    {
        Trinity::ChatCommands::InvalidateCommandMap();
    }
    void BeforeUnload() final override
    {
        Trinity::ChatCommands::InvalidateCommandMap();
    }
};
// Database unbound script registry
template
class SpecializedScriptRegistry
    : public ScriptRegistryInterface,
      public ScriptRegistrySwapHooks>
{
    template
    friend class ScriptRegistrySwapHooks;
public:
    typedef std::unordered_multimap> ScriptStoreType;
    typedef typename ScriptStoreType::iterator ScriptStoreIteratorType;
    SpecializedScriptRegistry() { }
    void ReleaseContext(std::string const& context) final override
    {
        this->BeforeReleaseContext(context);
        _scripts.erase(context);
    }
    void SwapContext(bool initialize) final override
    {
        this->BeforeSwapContext(initialize);
    }
    void RemoveUsedScriptsFromContainer(std::unordered_set& scripts) final override
    {
        for (auto const& script : _scripts)
            scripts.erase(script.second->GetName());
    }
    void Unload() final override
    {
        this->BeforeUnload();
        _scripts.clear();
    }
    void SyncScriptNames() final override
    {
    }
    // Adds a non database bound script
    void AddScript(ScriptType* script)
    {
        ASSERT(script,
               "Tried to call AddScript with a nullpointer!");
        ASSERT(!sScriptMgr->GetCurrentScriptContext().empty(),
               "Tried to register a script without being in a valid script context!");
        std::unique_ptr script_ptr(script);
        for (auto const& entry : _scripts)
            if (entry.second.get() == script)
            {
                static_cast*>(this)->
                    LogDuplicatedScriptPointerError(script, entry.second.get());
                sScriptRegistryCompositum->QueueForDelayedDelete(std::move(script_ptr));
                return;
            }
        // We're dealing with a code-only script, just add it.
        _scripts.insert(std::make_pair(sScriptMgr->GetCurrentScriptContext(), std::move(script_ptr)));
    }
    ScriptStoreType& GetScripts()
    {
        return _scripts;
    }
private:
    ScriptStoreType _scripts;
};
// Utility macros to refer to the script registry.
#define SCR_REG_MAP(T) ScriptRegistry::ScriptStoreType
#define SCR_REG_ITR(T) ScriptRegistry::ScriptStoreIteratorType
#define SCR_REG_LST(T) ScriptRegistry::Instance()->GetScripts()
// Utility macros for looping over scripts.
#define FOR_SCRIPTS(T, C, E) \
    if (!SCR_REG_LST(T).empty()) \
        for (SCR_REG_ITR(T) 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_ITR(T) 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::Instance()->GetScriptById(I); \
    if (!V) \
        return;
#define GET_SCRIPT_RET(T, I, V, R) \
    T* V = ScriptRegistry::Instance()->GetScriptById(I); \
    if (!V) \
        return R;
ScriptObject::ScriptObject(char const* name) : _name(name)
{
    sScriptMgr->IncreaseScriptCount();
}
ScriptObject::~ScriptObject()
{
    sScriptMgr->DecreaseScriptCount();
}
ScriptMgr::ScriptMgr()
    : _scriptCount(0), _scriptIdUpdated(false), _script_loader_callback(nullptr)
{
}
ScriptMgr::~ScriptMgr() = default;
ScriptMgr* ScriptMgr::instance()
{
    static ScriptMgr instance;
    return &instance;
}
void ScriptMgr::Initialize()
{
    ASSERT(sSpellMgr->GetSpellInfo(SPELL_HOTSWAP_VISUAL_SPELL_EFFECT, DIFFICULTY_NONE)
           && "Reload hotswap spell effect for creatures isn't valid!");
    uint32 oldMSTime = getMSTime();
    LoadDatabase();
    TC_LOG_INFO("server.loading", "Loading C++ scripts");
    FillSpellSummary();
    // Load core scripts
    SetScriptContext(GetNameOfStaticContext());
    // SmartAI
    AddSC_SmartScripts();
    // LFGScripts
    lfg::AddSC_LFGScripts();
    // Load all static linked scripts through the script loader function.
    ASSERT(_script_loader_callback,
           "Script loader callback wasn't registered!");
    _script_loader_callback();
    // Initialize all dynamic scripts
    // and finishes the context switch to do
    // bulk loading
    sScriptReloadMgr->Initialize();
    // Loads all scripts from the current context
    sScriptMgr->SwapScriptContext(true);
    // Print unused script names.
    std::unordered_set unusedScriptNames = sObjectMgr->GetAllDBScriptNames();
    // Remove the used scripts from the given container.
    sScriptRegistryCompositum->RemoveUsedScriptsFromContainer(unusedScriptNames);
    for (std::string const& scriptName : unusedScriptNames)
    {
        // Avoid complaining about empty script names since the
        // script name container contains a placeholder as the 0 element.
        if (scriptName.empty())
            continue;
        TC_LOG_ERROR("sql.sql", "Script '%s' is referenced by the database, but does not exist in the core!", scriptName.c_str());
    }
    TC_LOG_INFO("server.loading", ">> Loaded %u C++ scripts in %u ms",
        GetScriptCount(), GetMSTimeDiffToNow(oldMSTime));
}
void ScriptMgr::NotifyScriptIDUpdate()
{
    _scriptIdUpdated = true;
}
void ScriptMgr::SyncScripts()
{
    if (_scriptIdUpdated)
    {
        _scriptIdUpdated = false;
        sScriptRegistryCompositum->SyncScriptNames();
    }
}
void ScriptMgr::SetScriptContext(std::string const& context)
{
    _currentContext = context;
}
void ScriptMgr::SwapScriptContext(bool initialize)
{
    sScriptRegistryCompositum->SwapContext(initialize);
    _currentContext.clear();
}
std::string const& ScriptMgr::GetNameOfStaticContext()
{
    static std::string const name = "___static___";
    return name;
}
void ScriptMgr::ReleaseScriptContext(std::string const& context)
{
    sScriptRegistryCompositum->ReleaseContext(context);
}
std::shared_ptr
    ScriptMgr::AcquireModuleReferenceOfScriptName(std::string const& scriptname) const
{
#ifdef TRINITY_API_USE_DYNAMIC_LINKING
    // Returns the reference to the module of the given scriptname
    return ScriptReloadMgr::AcquireModuleReferenceOfContext(
        sScriptRegistryCompositum->GetScriptContextOfScriptName(scriptname));
#else
    (void)scriptname;
    // Something went wrong when this function is used in
    // a static linked context.
    WPAbort();
#endif // #ifndef TRINITY_API_USE_DYNAMIC_LINKING
}
void ScriptMgr::Unload()
{
    sScriptRegistryCompositum->Unload();
    UnitAI::AISpellInfo.clear();
}
void ScriptMgr::LoadDatabase()
{
    sScriptSystemMgr->LoadScriptWaypoints();
    sScriptSystemMgr->LoadScriptSplineChains();
}
void ScriptMgr::FillSpellSummary()
{
    UnitAI::FillAISpellInfo();
}
template
void CreateSpellOrAuraScripts(uint32 spellId, std::vector& scriptVector, F&& extractor, O* objectInvoker)
{
    SpellScriptsBounds bounds = sObjectMgr->GetSpellScriptsBounds(spellId);
    for (auto itr = bounds.first; itr != bounds.second; ++itr)
    {
        // When the script is disabled continue with the next one
        if (!itr->second.second)
            continue;
        SpellScriptLoader* tmpscript = sScriptMgr->GetSpellScriptLoader(itr->second.first);
        if (!tmpscript)
            continue;
        T* script = (*tmpscript.*extractor)();
        if (!script)
            continue;
        script->_Init(&tmpscript->GetName(), spellId);
        if (!script->_Load(objectInvoker))
        {
            delete script;
            continue;
        }
        scriptVector.push_back(script);
    }
}
void ScriptMgr::CreateSpellScripts(uint32 spellId, std::vector& scriptVector, Spell* invoker) const
{
    CreateSpellOrAuraScripts(spellId, scriptVector, &SpellScriptLoader::GetSpellScript, invoker);
}
void ScriptMgr::CreateAuraScripts(uint32 spellId, std::vector& scriptVector, Aura* invoker) const
{
    CreateSpellOrAuraScripts(spellId, scriptVector, &SpellScriptLoader::GetAuraScript, invoker);
}
SpellScriptLoader* ScriptMgr::GetSpellScriptLoader(uint32 scriptId)
{
    return ScriptRegistry::Instance()->GetScriptById(scriptId);
}
void ScriptMgr::OnNetworkStart()
{
    FOREACH_SCRIPT(ServerScript)->OnNetworkStart();
}
void ScriptMgr::OnNetworkStop()
{
    FOREACH_SCRIPT(ServerScript)->OnNetworkStop();
}
void ScriptMgr::OnSocketOpen(std::shared_ptr socket)
{
    ASSERT(socket);
    FOREACH_SCRIPT(ServerScript)->OnSocketOpen(socket);
}
void ScriptMgr::OnSocketClose(std::shared_ptr socket)
{
    ASSERT(socket);
    FOREACH_SCRIPT(ServerScript)->OnSocketClose(socket);
}
void ScriptMgr::OnPacketReceive(WorldSession* session, WorldPacket const& packet)
{
    if (SCR_REG_LST(ServerScript).empty())
        return;
    WorldPacket copy(packet);
    FOREACH_SCRIPT(ServerScript)->OnPacketReceive(session, copy);
}
void ScriptMgr::OnPacketSend(WorldSession* session, WorldPacket const& packet)
{
    ASSERT(session);
    if (SCR_REG_LST(ServerScript).empty())
        return;
    WorldPacket copy(packet);
    FOREACH_SCRIPT(ServerScript)->OnPacketSend(session, copy);
}
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::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask)
{
    FOREACH_SCRIPT(WorldScript)->OnShutdownInitiate(code, mask);
}
void ScriptMgr::OnShutdownCancel()
{
    FOREACH_SCRIPT(WorldScript)->OnShutdownCancel();
}
void ScriptMgr::OnWorldUpdate(uint32 diff)
{
    FOREACH_SCRIPT(WorldScript)->OnUpdate(diff);
}
void ScriptMgr::OnHonorCalculation(float& honor, uint8 level, float multiplier)
{
    FOREACH_SCRIPT(FormulaScript)->OnHonorCalculation(honor, level, multiplier);
}
void ScriptMgr::OnGrayLevelCalculation(uint8& grayLevel, uint8 playerLevel)
{
    FOREACH_SCRIPT(FormulaScript)->OnGrayLevelCalculation(grayLevel, playerLevel);
}
void ScriptMgr::OnColorCodeCalculation(XPColorChar& color, uint8 playerLevel, uint8 mobLevel)
{
    FOREACH_SCRIPT(FormulaScript)->OnColorCodeCalculation(color, playerLevel, mobLevel);
}
void ScriptMgr::OnZeroDifferenceCalculation(uint8& diff, uint8 playerLevel)
{
    FOREACH_SCRIPT(FormulaScript)->OnZeroDifferenceCalculation(diff, playerLevel);
}
void ScriptMgr::OnBaseGainCalculation(uint32& gain, uint8 playerLevel, uint8 mobLevel)
{
    FOREACH_SCRIPT(FormulaScript)->OnBaseGainCalculation(gain, playerLevel, mobLevel);
}
void ScriptMgr::OnGainCalculation(uint32& gain, Player* player, Unit* unit)
{
    ASSERT(player);
    ASSERT(unit);
    FOREACH_SCRIPT(FormulaScript)->OnGainCalculation(gain, player, unit);
}
void ScriptMgr::OnGroupRateCalculation(float& rate, uint32 count, bool isRaid)
{
    FOREACH_SCRIPT(FormulaScript)->OnGroupRateCalculation(rate, count, isRaid);
}
#define SCR_MAP_BGN(M, V, I, E, C, T) \
    if (V->GetEntry() && V->GetEntry()->T()) \
    { \
        FOR_SCRIPTS(M, I, E) \
        { \
            MapEntry const* C = I->second->GetEntry(); \
            if (!C) \
                continue; \
            if (C->ID == V->GetId()) \
            {
#define SCR_MAP_END \
                return; \
            } \
        } \
    }
void ScriptMgr::OnCreateMap(Map* map)
{
    ASSERT(map);
    SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
        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, IsWorldMap);
        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, GridMap* gmap, uint32 gx, uint32 gy)
{
    ASSERT(map);
    ASSERT(gmap);
    SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
        itr->second->OnLoadGridMap(map, gmap, gx, gy);
    SCR_MAP_END;
    SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon);
        itr->second->OnLoadGridMap((InstanceMap*)map, gmap, gx, gy);
    SCR_MAP_END;
    SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleground);
        itr->second->OnLoadGridMap((BattlegroundMap*)map, gmap, gx, gy);
    SCR_MAP_END;
}
void ScriptMgr::OnUnloadGridMap(Map* map, GridMap* gmap, uint32 gx, uint32 gy)
{
    ASSERT(map);
    ASSERT(gmap);
    SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
        itr->second->OnUnloadGridMap(map, gmap, gx, gy);
    SCR_MAP_END;
    SCR_MAP_BGN(InstanceMapScript, map, itr, end, entry, IsDungeon);
        itr->second->OnUnloadGridMap((InstanceMap*)map, gmap, gx, gy);
    SCR_MAP_END;
    SCR_MAP_BGN(BattlegroundMapScript, map, itr, end, entry, IsBattleground);
        itr->second->OnUnloadGridMap((BattlegroundMap*)map, gmap, gx, gy);
    SCR_MAP_END;
}
void ScriptMgr::OnPlayerEnterMap(Map* map, Player* player)
{
    ASSERT(map);
    ASSERT(player);
    FOREACH_SCRIPT(PlayerScript)->OnMapChanged(player);
    SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
        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::OnPlayerLeaveMap(Map* map, Player* player)
{
    ASSERT(map);
    ASSERT(player);
    SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap);
        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, IsWorldMap);
        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
InstanceScript* ScriptMgr::CreateInstanceData(InstanceMap* map)
{
    ASSERT(map);
    GET_SCRIPT_RET(InstanceMapScript, map->GetScriptId(), tmpscript, nullptr);
    return tmpscript->GetInstanceScript(map);
}
bool ScriptMgr::OnQuestAccept(Player* player, Item* item, Quest const* quest)
{
    ASSERT(player);
    ASSERT(item);
    ASSERT(quest);
    GET_SCRIPT_RET(ItemScript, item->GetScriptId(), tmpscript, false);
    player->PlayerTalkClass->ClearMenus();
    return tmpscript->OnQuestAccept(player, item, quest);
}
bool ScriptMgr::OnItemUse(Player* player, Item* item, SpellCastTargets const& targets, ObjectGuid castId)
{
    ASSERT(player);
    ASSERT(item);
    GET_SCRIPT_RET(ItemScript, item->GetScriptId(), tmpscript, false);
    return tmpscript->OnUse(player, item, targets, castId);
}
bool ScriptMgr::OnItemExpire(Player* player, ItemTemplate const* proto)
{
    ASSERT(player);
    ASSERT(proto);
    GET_SCRIPT_RET(ItemScript, proto->ScriptId, tmpscript, false);
    return tmpscript->OnExpire(player, proto);
}
bool ScriptMgr::OnItemRemove(Player* player, Item* item)
{
    ASSERT(player);
    ASSERT(item);
    GET_SCRIPT_RET(ItemScript, item->GetScriptId(), tmpscript, false);
    return tmpscript->OnRemove(player, item);
}
bool ScriptMgr::OnCastItemCombatSpell(Player* player, Unit* victim, SpellInfo const* spellInfo, Item* item)
{
    ASSERT(player);
    ASSERT(victim);
    ASSERT(spellInfo);
    ASSERT(item);
    GET_SCRIPT_RET(ItemScript, item->GetScriptId(), tmpscript, true);
    return tmpscript->OnCastItemCombatSpell(player, victim, spellInfo, item);
}
bool ScriptMgr::CanCreateCreatureAI(uint32 scriptId) const
{
    return !!ScriptRegistry::Instance()->GetScriptById(scriptId);
}
CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature)
{
    ASSERT(creature);
    GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, nullptr);
    return tmpscript->GetAI(creature);
}
bool ScriptMgr::CanCreateGameObjectAI(uint32 scriptId) const
{
    return !!ScriptRegistry::Instance()->GetScriptById(scriptId);
}
GameObjectAI* ScriptMgr::GetGameObjectAI(GameObject* gameobject)
{
    ASSERT(gameobject);
    GET_SCRIPT_RET(GameObjectScript, gameobject->GetScriptId(), tmpscript, nullptr);
    return tmpscript->GetAI(gameobject);
}
bool ScriptMgr::CanCreateAreaTriggerAI(uint32 scriptId) const
{
    return !!ScriptRegistry::Instance()->GetScriptById(scriptId);
}
AreaTriggerAI* ScriptMgr::GetAreaTriggerAI(AreaTrigger* areatrigger)
{
    ASSERT(areatrigger);
    GET_SCRIPT_RET(AreaTriggerEntityScript, areatrigger->GetScriptId(), tmpscript, nullptr);
    return tmpscript->GetAI(areatrigger);
}
bool ScriptMgr::OnAreaTrigger(Player* player, AreaTriggerEntry const* trigger, bool entered)
{
    ASSERT(player);
    ASSERT(trigger);
    GET_SCRIPT_RET(AreaTriggerScript, sObjectMgr->GetAreaTriggerScriptId(trigger->ID), tmpscript, false);
    return entered ? tmpscript->OnTrigger(player, trigger) : tmpscript->OnExit(player, trigger);
}
Battlefield* ScriptMgr::CreateBattlefield(uint32 scriptId)
{
    GET_SCRIPT_RET(BattlefieldScript, scriptId, tmpscript, nullptr);
    return tmpscript->GetBattlefield();
}
Battleground* ScriptMgr::CreateBattleground(BattlegroundTypeId /*typeId*/)
{
    /// @todo Implement script-side battlegrounds.
    ABORT();
    return nullptr;
}
OutdoorPvP* ScriptMgr::CreateOutdoorPvP(uint32 scriptId)
{
    GET_SCRIPT_RET(OutdoorPvPScript, scriptId, tmpscript, nullptr);
    return tmpscript->GetOutdoorPvP();
}
Trinity::ChatCommands::ChatCommandTable ScriptMgr::GetChatCommands()
{
    Trinity::ChatCommands::ChatCommandTable table;
    FOR_SCRIPTS(CommandScript, itr, end)
    {
        Trinity::ChatCommands::ChatCommandTable cmds = itr->second->GetCommands();
        std::move(cmds.begin(), cmds.end(), std::back_inserter(table));
    }
    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, AuctionPosting* auction)
{
    ASSERT(ah);
    ASSERT(auction);
    FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionAdd(ah, auction);
}
void ScriptMgr::OnAuctionRemove(AuctionHouseObject* ah, AuctionPosting* auction)
{
    ASSERT(ah);
    ASSERT(auction);
    FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionRemove(ah, auction);
}
void ScriptMgr::OnAuctionSuccessful(AuctionHouseObject* ah, AuctionPosting* auction)
{
    ASSERT(ah);
    ASSERT(auction);
    FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionSuccessful(ah, auction);
}
void ScriptMgr::OnAuctionExpire(AuctionHouseObject* ah, AuctionPosting* auction)
{
    ASSERT(ah);
    ASSERT(auction);
    FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionExpire(ah, auction);
}
bool ScriptMgr::OnConditionCheck(Condition const* condition, ConditionSourceInfo& sourceInfo)
{
    ASSERT(condition);
    GET_SCRIPT_RET(ConditionScript, condition->ScriptId, tmpscript, true);
    return tmpscript->OnConditionCheck(condition, sourceInfo);
}
void ScriptMgr::OnInstall(Vehicle* veh)
{
    ASSERT(veh);
    ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
    GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
    tmpscript->OnInstall(veh);
}
void ScriptMgr::OnUninstall(Vehicle* veh)
{
    ASSERT(veh);
    ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
    GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
    tmpscript->OnUninstall(veh);
}
void ScriptMgr::OnReset(Vehicle* veh)
{
    ASSERT(veh);
    ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
    GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
    tmpscript->OnReset(veh);
}
void ScriptMgr::OnInstallAccessory(Vehicle* veh, Creature* accessory)
{
    ASSERT(veh);
    ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
    ASSERT(accessory);
    GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
    tmpscript->OnInstallAccessory(veh, accessory);
}
void ScriptMgr::OnAddPassenger(Vehicle* veh, Unit* passenger, int8 seatId)
{
    ASSERT(veh);
    ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
    ASSERT(passenger);
    GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
    tmpscript->OnAddPassenger(veh, passenger, seatId);
}
void ScriptMgr::OnRemovePassenger(Vehicle* veh, Unit* passenger)
{
    ASSERT(veh);
    ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT);
    ASSERT(passenger);
    GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript);
    tmpscript->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 ScriptMgr::OnRelocate(Transport* transport, uint32 waypointId, uint32 mapId, float x, float y, float z)
{
    GET_SCRIPT(TransportScript, transport->GetScriptId(), tmpscript);
    tmpscript->OnRelocate(transport, waypointId, mapId, x, y, z);
}
void ScriptMgr::OnStartup()
{
    FOREACH_SCRIPT(WorldScript)->OnStartup();
}
void ScriptMgr::OnShutdown()
{
    FOREACH_SCRIPT(WorldScript)->OnShutdown();
}
// Achievement
void ScriptMgr::OnAchievementCompleted(Player* player, AchievementEntry const* achievement)
{
    ASSERT(player);
    ASSERT(achievement);
    GET_SCRIPT(AchievementScript, sAchievementMgr->GetAchievementScriptId(achievement->ID), tmpscript);
    tmpscript->OnCompleted(player, achievement);
}
bool ScriptMgr::OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target)
{
    ASSERT(source);
    // target can be NULL.
    GET_SCRIPT_RET(AchievementCriteriaScript, scriptId, tmpscript, false);
    return tmpscript->OnCheck(source, target);
}
// Player
void ScriptMgr::OnPVPKill(Player* killer, Player* killed)
{
    FOREACH_SCRIPT(PlayerScript)->OnPVPKill(killer, killed);
}
void ScriptMgr::OnCreatureKill(Player* killer, Creature* killed)
{
    FOREACH_SCRIPT(PlayerScript)->OnCreatureKill(killer, killed);
}
void ScriptMgr::OnPlayerKilledByCreature(Creature* killer, Player* killed)
{
    FOREACH_SCRIPT(PlayerScript)->OnPlayerKilledByCreature(killer, killed);
}
void ScriptMgr::OnPlayerLevelChanged(Player* player, uint8 oldLevel)
{
    FOREACH_SCRIPT(PlayerScript)->OnLevelChanged(player, oldLevel);
}
void ScriptMgr::OnPlayerFreeTalentPointsChanged(Player* player, uint32 points)
{
    FOREACH_SCRIPT(PlayerScript)->OnFreeTalentPointsChanged(player, points);
}
void ScriptMgr::OnPlayerTalentsReset(Player* player, bool noCost)
{
    FOREACH_SCRIPT(PlayerScript)->OnTalentsReset(player, noCost);
}
void ScriptMgr::OnPlayerMoneyChanged(Player* player, int64& amount)
{
    FOREACH_SCRIPT(PlayerScript)->OnMoneyChanged(player, amount);
}
void ScriptMgr::OnPlayerMoneyLimit(Player* player, int64 amount)
{
    FOREACH_SCRIPT(PlayerScript)->OnMoneyLimit(player, amount);
}
void ScriptMgr::OnGivePlayerXP(Player* player, uint32& amount, Unit* victim)
{
    FOREACH_SCRIPT(PlayerScript)->OnGiveXP(player, amount, victim);
}
void ScriptMgr::OnPlayerReputationChange(Player* player, uint32 factionID, int32& standing, bool incremental)
{
    FOREACH_SCRIPT(PlayerScript)->OnReputationChange(player, factionID, standing, incremental);
}
void ScriptMgr::OnPlayerDuelRequest(Player* target, Player* challenger)
{
    FOREACH_SCRIPT(PlayerScript)->OnDuelRequest(target, challenger);
}
void ScriptMgr::OnPlayerDuelStart(Player* player1, Player* player2)
{
    FOREACH_SCRIPT(PlayerScript)->OnDuelStart(player1, player2);
}
void ScriptMgr::OnPlayerDuelEnd(Player* winner, Player* loser, DuelCompleteType type)
{
    FOREACH_SCRIPT(PlayerScript)->OnDuelEnd(winner, loser, type);
}
void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg)
{
    FOREACH_SCRIPT(PlayerScript)->OnChat(player, type, lang, msg);
}
void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Player* receiver)
{
    FOREACH_SCRIPT(PlayerScript)->OnChat(player, type, lang, msg, receiver);
}
void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group)
{
    FOREACH_SCRIPT(PlayerScript)->OnChat(player, type, lang, msg, group);
}
void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild)
{
    FOREACH_SCRIPT(PlayerScript)->OnChat(player, type, lang, msg, guild);
}
void ScriptMgr::OnPlayerChat(Player* player, uint32 type, uint32 lang, std::string& msg, Channel* channel)
{
    FOREACH_SCRIPT(PlayerScript)->OnChat(player, type, lang, msg, channel);
}
void ScriptMgr::OnPlayerClearEmote(Player* player)
{
    FOREACH_SCRIPT(PlayerScript)->OnClearEmote(player);
}
void ScriptMgr::OnPlayerTextEmote(Player* player, uint32 textEmote, uint32 emoteNum, ObjectGuid guid)
{
    FOREACH_SCRIPT(PlayerScript)->OnTextEmote(player, textEmote, emoteNum, guid);
}
void ScriptMgr::OnPlayerSpellCast(Player* player, Spell* spell, bool skipCheck)
{
    FOREACH_SCRIPT(PlayerScript)->OnSpellCast(player, spell, skipCheck);
}
void ScriptMgr::OnPlayerLogin(Player* player, bool firstLogin)
{
    FOREACH_SCRIPT(PlayerScript)->OnLogin(player, firstLogin);
}
void ScriptMgr::OnPlayerLogout(Player* player)
{
    FOREACH_SCRIPT(PlayerScript)->OnLogout(player);
}
void ScriptMgr::OnPlayerCreate(Player* player)
{
    FOREACH_SCRIPT(PlayerScript)->OnCreate(player);
}
void ScriptMgr::OnPlayerDelete(ObjectGuid guid, uint32 accountId)
{
    FOREACH_SCRIPT(PlayerScript)->OnDelete(guid, accountId);
}
void ScriptMgr::OnPlayerFailedDelete(ObjectGuid guid, uint32 accountId)
{
    FOREACH_SCRIPT(PlayerScript)->OnFailedDelete(guid, accountId);
}
void ScriptMgr::OnPlayerSave(Player* player)
{
    FOREACH_SCRIPT(PlayerScript)->OnSave(player);
}
void ScriptMgr::OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent, uint8 extendState)
{
    FOREACH_SCRIPT(PlayerScript)->OnBindToInstance(player, difficulty, mapid, permanent, extendState);
}
void ScriptMgr::OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea)
{
    FOREACH_SCRIPT(PlayerScript)->OnUpdateZone(player, newZone, newArea);
}
void ScriptMgr::OnQuestStatusChange(Player* player, uint32 questId)
{
    FOREACH_SCRIPT(PlayerScript)->OnQuestStatusChange(player, questId);
}
void ScriptMgr::OnPlayerRepop(Player* player)
{
    FOREACH_SCRIPT(PlayerScript)->OnPlayerRepop(player);
}
void ScriptMgr::OnMovieComplete(Player* player, uint32 movieId)
{
    FOREACH_SCRIPT(PlayerScript)->OnMovieComplete(player, movieId);
}
void ScriptMgr::OnPlayerChoiceResponse(Player* player, uint32 choiceId, uint32 responseId)
{
    FOREACH_SCRIPT(PlayerScript)->OnPlayerChoiceResponse(player, choiceId, responseId);
}
// Account
void ScriptMgr::OnAccountLogin(uint32 accountId)
{
    FOREACH_SCRIPT(AccountScript)->OnAccountLogin(accountId);
}
void ScriptMgr::OnFailedAccountLogin(uint32 accountId)
{
    FOREACH_SCRIPT(AccountScript)->OnFailedAccountLogin(accountId);
}
void ScriptMgr::OnEmailChange(uint32 accountId)
{
    FOREACH_SCRIPT(AccountScript)->OnEmailChange(accountId);
}
void ScriptMgr::OnFailedEmailChange(uint32 accountId)
{
    FOREACH_SCRIPT(AccountScript)->OnFailedEmailChange(accountId);
}
void ScriptMgr::OnPasswordChange(uint32 accountId)
{
    FOREACH_SCRIPT(AccountScript)->OnPasswordChange(accountId);
}
void ScriptMgr::OnFailedPasswordChange(uint32 accountId)
{
    FOREACH_SCRIPT(AccountScript)->OnFailedPasswordChange(accountId);
}
// Guild
void ScriptMgr::OnGuildAddMember(Guild* guild, Player* player, uint8 plRank)
{
    FOREACH_SCRIPT(GuildScript)->OnAddMember(guild, player, plRank);
}
void ScriptMgr::OnGuildRemoveMember(Guild* guild, ObjectGuid guid, bool isDisbanding, bool isKicked)
{
    FOREACH_SCRIPT(GuildScript)->OnRemoveMember(guild, guid, isDisbanding, isKicked);
}
void ScriptMgr::OnGuildMOTDChanged(Guild* guild, const std::string& newMotd)
{
    FOREACH_SCRIPT(GuildScript)->OnMOTDChanged(guild, newMotd);
}
void ScriptMgr::OnGuildInfoChanged(Guild* guild, const std::string& newInfo)
{
    FOREACH_SCRIPT(GuildScript)->OnInfoChanged(guild, newInfo);
}
void ScriptMgr::OnGuildCreate(Guild* guild, Player* leader, const std::string& name)
{
    FOREACH_SCRIPT(GuildScript)->OnCreate(guild, leader, name);
}
void ScriptMgr::OnGuildDisband(Guild* guild)
{
    FOREACH_SCRIPT(GuildScript)->OnDisband(guild);
}
void ScriptMgr::OnGuildMemberWitdrawMoney(Guild* guild, Player* player, uint64 &amount, bool isRepair)
{
    FOREACH_SCRIPT(GuildScript)->OnMemberWitdrawMoney(guild, player, amount, isRepair);
}
void ScriptMgr::OnGuildMemberDepositMoney(Guild* guild, Player* player, uint64 &amount)
{
    FOREACH_SCRIPT(GuildScript)->OnMemberDepositMoney(guild, player, amount);
}
void ScriptMgr::OnGuildItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId,
            bool isDestBank, uint8 destContainer, uint8 destSlotId)
{
    FOREACH_SCRIPT(GuildScript)->OnItemMove(guild, player, pItem, isSrcBank, srcContainer, srcSlotId, isDestBank, destContainer, destSlotId);
}
void ScriptMgr::OnGuildEvent(Guild* guild, uint8 eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank)
{
    FOREACH_SCRIPT(GuildScript)->OnEvent(guild, eventType, playerGuid1, playerGuid2, newRank);
}
void ScriptMgr::OnGuildBankEvent(Guild* guild, uint8 eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint64 itemOrMoney, uint16 itemStackCount, uint8 destTabId)
{
    FOREACH_SCRIPT(GuildScript)->OnBankEvent(guild, eventType, tabId, playerGuid, itemOrMoney, itemStackCount, destTabId);
}
// Group
void ScriptMgr::OnGroupAddMember(Group* group, ObjectGuid guid)
{
    ASSERT(group);
    FOREACH_SCRIPT(GroupScript)->OnAddMember(group, guid);
}
void ScriptMgr::OnGroupInviteMember(Group* group, ObjectGuid guid)
{
    ASSERT(group);
    FOREACH_SCRIPT(GroupScript)->OnInviteMember(group, guid);
}
void ScriptMgr::OnGroupRemoveMember(Group* group, ObjectGuid guid, RemoveMethod method, ObjectGuid kicker, char const* reason)
{
    ASSERT(group);
    FOREACH_SCRIPT(GroupScript)->OnRemoveMember(group, guid, method, kicker, reason);
}
void ScriptMgr::OnGroupChangeLeader(Group* group, ObjectGuid newLeaderGuid, ObjectGuid oldLeaderGuid)
{
    ASSERT(group);
    FOREACH_SCRIPT(GroupScript)->OnChangeLeader(group, newLeaderGuid, oldLeaderGuid);
}
void ScriptMgr::OnGroupDisband(Group* group)
{
    ASSERT(group);
    FOREACH_SCRIPT(GroupScript)->OnDisband(group);
}
// Unit
void ScriptMgr::OnHeal(Unit* healer, Unit* reciever, uint32& gain)
{
    FOREACH_SCRIPT(UnitScript)->OnHeal(healer, reciever, gain);
}
void ScriptMgr::OnDamage(Unit* attacker, Unit* victim, uint32& damage)
{
    FOREACH_SCRIPT(UnitScript)->OnDamage(attacker, victim, damage);
}
void ScriptMgr::ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage)
{
    FOREACH_SCRIPT(UnitScript)->ModifyPeriodicDamageAurasTick(target, attacker, damage);
}
void ScriptMgr::ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage)
{
    FOREACH_SCRIPT(UnitScript)->ModifyMeleeDamage(target, attacker, damage);
}
void ScriptMgr::ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage, SpellInfo const* spellInfo)
{
    FOREACH_SCRIPT(UnitScript)->ModifySpellDamageTaken(target, attacker, damage, spellInfo);
}
// Conversation
void ScriptMgr::OnConversationCreate(Conversation* conversation, Unit* creator)
{
    ASSERT(conversation);
    GET_SCRIPT(ConversationScript, conversation->GetScriptId(), tmpscript);
    tmpscript->OnConversationCreate(conversation, creator);
}
void ScriptMgr::OnConversationLineStarted(Conversation* conversation, uint32 lineId, Player* sender)
{
    ASSERT(conversation);
    ASSERT(sender);
    GET_SCRIPT(ConversationScript, conversation->GetScriptId(), tmpscript);
    tmpscript->OnConversationLineStarted(conversation, lineId, sender);
}
// Scene
void ScriptMgr::OnSceneStart(Player* player, uint32 sceneInstanceID, SceneTemplate const* sceneTemplate)
{
    ASSERT(player);
    ASSERT(sceneTemplate);
    GET_SCRIPT(SceneScript, sceneTemplate->ScriptId, tmpscript);
    tmpscript->OnSceneStart(player, sceneInstanceID, sceneTemplate);
}
void ScriptMgr::OnSceneTrigger(Player* player, uint32 sceneInstanceID, SceneTemplate const* sceneTemplate, std::string const& triggerName)
{
    ASSERT(player);
    ASSERT(sceneTemplate);
    GET_SCRIPT(SceneScript, sceneTemplate->ScriptId, tmpscript);
    tmpscript->OnSceneTriggerEvent(player, sceneInstanceID, sceneTemplate, triggerName);
}
void ScriptMgr::OnSceneCancel(Player* player, uint32 sceneInstanceID, SceneTemplate const* sceneTemplate)
{
    ASSERT(player);
    ASSERT(sceneTemplate);
    GET_SCRIPT(SceneScript, sceneTemplate->ScriptId, tmpscript);
    tmpscript->OnSceneCancel(player, sceneInstanceID, sceneTemplate);
}
void ScriptMgr::OnSceneComplete(Player* player, uint32 sceneInstanceID, SceneTemplate const* sceneTemplate)
{
    ASSERT(player);
    ASSERT(sceneTemplate);
    GET_SCRIPT(SceneScript, sceneTemplate->ScriptId, tmpscript);
    tmpscript->OnSceneComplete(player, sceneInstanceID, sceneTemplate);
}
void ScriptMgr::OnQuestStatusChange(Player* player, Quest const* quest, QuestStatus oldStatus, QuestStatus newStatus)
{
    ASSERT(player);
    ASSERT(quest);
    GET_SCRIPT(QuestScript, quest->GetScriptId(), tmpscript);
    tmpscript->OnQuestStatusChange(player, quest, oldStatus, newStatus);
}
void ScriptMgr::OnQuestAcknowledgeAutoAccept(Player* player, Quest const* quest)
{
    ASSERT(player);
    ASSERT(quest);
    GET_SCRIPT(QuestScript, quest->GetScriptId(), tmpscript);
    tmpscript->OnAcknowledgeAutoAccept(player, quest);
}
void ScriptMgr::OnQuestObjectiveChange(Player* player, Quest const* quest, QuestObjective const& objective, int32 oldAmount, int32 newAmount)
{
    ASSERT(player);
    ASSERT(quest);
    GET_SCRIPT(QuestScript, quest->GetScriptId(), tmpscript);
    tmpscript->OnQuestObjectiveChange(player, quest, objective, oldAmount, newAmount);
}
void ScriptMgr::ModifyVehiclePassengerExitPos(Unit* passenger, Vehicle* vehicle, Position& pos)
{
    FOREACH_SCRIPT(UnitScript)->ModifyVehiclePassengerExitPos(passenger, vehicle, pos);
    FOREACH_SCRIPT(CreatureScript)->ModifyVehiclePassengerExitPos(passenger, vehicle, pos);
}
SpellScriptLoader::SpellScriptLoader(char const* name)
    : ScriptObject(name)
{
    ScriptRegistry::Instance()->AddScript(this);
}
ServerScript::ServerScript(char const* name)
    : ScriptObject(name)
{
    ScriptRegistry::Instance()->AddScript(this);
}
ServerScript::~ServerScript() = default;
WorldScript::WorldScript(char const* name)
    : ScriptObject(name)
{
    ScriptRegistry::Instance()->AddScript(this);
}
WorldScript::~WorldScript() = default;
FormulaScript::FormulaScript(char const* name)
    : ScriptObject(name)
{
    ScriptRegistry::Instance()->AddScript(this);
}
FormulaScript::~FormulaScript() = default;
UnitScript::UnitScript(char const* name)
    : ScriptObject(name)
{
    ScriptRegistry::Instance()->AddScript(this);
}
UnitScript::~UnitScript() = default;
WorldMapScript::WorldMapScript(char const* name, uint32 mapId)
    : ScriptObject(name), MapScript