killerbng icon

Auto learn spells

killerbng | PRO | 03/01/19 11:52:32 PM UTC | 0 ⭐ | 271 👁️ | Never ⏰ | []
C++ |

8.96 KB

|

None

|

0 👍

/

0 👎

#include "ScriptPCH.h"
#include "DatabaseEnv.h"
#include "Util.h"
#include "World.h"
#include "ObjectMgr.h"
 
#include <unordered_map>
#include <memory>
#include <boost/any.hpp>
#include <functional>
 
 
constexpr bool LoadNonFreeSpells = true;
 
namespace LevelUpActions
{
    const std::unordered_map<uint32, std::array<uint32, 2>> trainers = 
    {
        {CLASS_WARRIOR, {26332, 26332}},
        {CLASS_PALADIN, {20406, 20406}},
        {CLASS_DRUID, {26324, 12042}},
        {CLASS_MAGE, {26326, 28956}},
        {CLASS_WARLOCK, {23534, 16266}},
        {CLASS_PRIEST, {16660, 17510}},
        {CLASS_HUNTER, {17505, 16673}},
        {CLASS_ROGUE, {26329, 26329}},
        {CLASS_SHAMAN, {17520, 17520}},
        {CLASS_DEATH_KNIGHT, {31084, 31084}}
    };
 
 
    enum class ActionType : uint16
    {
        LearnSpell = 1,
        LearnAllSpells,
        ApplyAura,
        ModifyMoney,
        AddItem
    };
 
 
    class Action
    {
    public:
        virtual void Process(Player*) = 0;
        virtual ~Action() {};
    };
 
    namespace detail
    {
 
 
        template <typename D>
        class Action_Impl : public Action
        {
        public:
            Action_Impl(std::vector<boost::any>&& params) : params(params) {}
 
            void Process(Player* player)
            {
                static_cast<D*>(this)->Process(player);
            }
 
        protected:
            std::vector<boost::any> params;
        };
 
 
#define DEFINE_TAG(x) \
        struct x {} x##_;
 
 
        DEFINE_TAG(float_tag);
        DEFINE_TAG(int32_tag);
        DEFINE_TAG(uint32_tag);
        DEFINE_TAG(vector_uint32_tag);
 
 
#define EXTRACT_F(x) void ExtractOne(std::vector<boost::any>& v, Tokenizer& tok, std::size_t i, x)
 
        EXTRACT_F(float_tag)
        {
            v.push_back(boost::any{ std::stof(tok[i]) });
        }
 
        EXTRACT_F(int32_tag)
        {
            v.push_back(boost::any{ std::stoi(tok[i]) });
        }
 
        EXTRACT_F(uint32_tag)
        {
            auto res = std::stoi(tok[i]);
            if (res < 0)
                res = 0;
            v.push_back(boost::any{ static_cast<uint32>(res) });
        }
 
        EXTRACT_F(vector_uint32_tag)
        {
            std::vector<uint32> vec;
            for (uint32 k = i; k < tok.size(); ++k, ++i)
            {
                vec.push_back(std::stoi(tok[k]));
            }
            v.push_back(boost::any{ vec });
        }
 
 
        template <typename Type, typename... Types>
        void Extract(std::vector<boost::any>& v, Tokenizer& tok, std::size_t i, Type type, Types... types)
        {
            ExtractOne(v, tok, i++, type);
            Extract(v, tok, i, types...);
        }
 
        template <typename... Types>
        void Extract(std::vector<boost::any>& v, Tokenizer& tok, std::size_t i) {}
 
 
        template <typename... Types>
        std::vector<boost::any> ExtractTypes(std::string params, std::size_t i, Types... types)
        {
            Tokenizer tokenizer{ params, ' ' };
            std::vector<boost::any> ret;
            if(tokenizer.size())
                Extract<Types...>(ret, tokenizer, 0, types...);
            return ret;
        }
    }
 
#define CLASS_IMPL(x) class x : public detail::Action_Impl<x>
 
 
    CLASS_IMPL(LearnSpellAction)
    {
    public:
        using Action_Impl::Action_Impl;
 
        void Process(Player* player)
        {
            uint32 spellId = boost::any_cast<uint32>(params[0]);
            if (!player->HasSpell(spellId))
                player->LearnSpell(spellId, false);
        }
    };
 
    CLASS_IMPL(LearnAllSpellsAction)
    {
    public:
        using Action_Impl::Action_Impl;
 
        void Process(Player* player)
        {
            auto itr = trainers.find(player->getClass());
            if(itr != trainers.end())
            {
                for (const auto& trainerId : itr->second)
                {
                    auto spells = sObjectMgr->GetNpcTrainerSpells(trainerId);
                    if (spells)
                    {
                        for (const auto& spell : spells->spellList)
                        {
                            const auto& sp = spell.second;
                            if (sp.MoneyCost && !LoadNonFreeSpells)
                                continue;
 
                            if (!sp.ReqSkillLine && !sp.ReqSkillRank && sp.ReqLevel <= player->getLevel() && !player->HasSpell(sp.SpellID))
                                player->LearnSpell(sp.SpellID, false);
                        }
                    }
                }
            }
        }
    };
 
    CLASS_IMPL(ApplyAuraAction)
    {
    public:
        using Action_Impl::Action_Impl;
 
        void Process(Player* player)
        {
            uint32 spellId = boost::any_cast<uint32>(params[0]);
            player->AddAura(spellId, player);
        }
    };
 
    CLASS_IMPL(ModifyMoneyAction)
    {
    public:
        using Action_Impl::Action_Impl;
 
        void Process(Player* player)
        {
            int32 money = boost::any_cast<int32>(params[0]);
            player->ModifyMoney(money);
        }
    };
 
    CLASS_IMPL(AddItemAction)
    {
    public:
        using Action_Impl::Action_Impl;
 
        void Process(Player* player)
        {
            uint32 itemId = boost::any_cast<uint32>(params[0]);
            uint32 count = boost::any_cast<uint32>(params[1]);
            player->AddItem(itemId, count);
        }
    };
 
    const std::unordered_map<ActionType, std::function<std::unique_ptr<Action>(std::string params)>> typeFactory =
    {
        {
          ActionType::LearnSpell, [] (std::string params) {
            auto vec = detail::ExtractTypes(params, 0, detail::uint32_tag_);
            return std::unique_ptr<Action>(new LearnSpellAction(std::move(vec))); }
        },
 
        {
          ActionType::LearnAllSpells, [] (std::string params) {
            auto vec = detail::ExtractTypes(params, 0, detail::vector_uint32_tag_);
            return std::unique_ptr<Action>(new LearnAllSpellsAction(std::move(vec))); }
        },
 
        {
          ActionType::ApplyAura, [] (std::string params) {
            auto vec = detail::ExtractTypes(params, 0, detail::uint32_tag_);
            return std::unique_ptr<Action>(new ApplyAuraAction(std::move(vec))); }
        },
 
        {
          ActionType::ModifyMoney, [] (std::string params) {
            auto vec = detail::ExtractTypes(params, 0, detail::int32_tag_);
            return std::unique_ptr<Action>(new ModifyMoneyAction(std::move(vec))); }
        },
 
        {
          ActionType::AddItem, [] (std::string params) {
            auto vec = detail::ExtractTypes(params, 0, detail::uint32_tag_, detail::uint32_tag_);
            return std::unique_ptr<Action>(new AddItemAction(std::move(vec))); }
        }
    };
 
 
 
 
    std::unordered_multimap<int32, std::unique_ptr<Action>> actionHolder;
 
    class OnLevelupActions : public PlayerScript
    {
    public:
        OnLevelupActions() : PlayerScript("OnLevelupSpells") {}
 
        void OnLevelChanged(Player* player, uint8 oldLevel) override
        {
            int32 newLevel = player->getLevel();
            auto levelPairItr = actionHolder.equal_range(newLevel);
            auto autoPairItr = actionHolder.equal_range(-1);
 
            if (levelPairItr.first != levelPairItr.second)
            {
                while (levelPairItr.first != levelPairItr.second)
                {
                    levelPairItr.first->second->Process(player);
                    ++levelPairItr.first;
                }
            }
 
            if (autoPairItr.first != autoPairItr.second)
            {
                while (autoPairItr.first != autoPairItr.second)
                {
                    autoPairItr.first->second->Process(player);
                    ++autoPairItr.first;
                }
            }
        }
    };
 
    class LoadActions : public WorldScript
    {
    public:
        LoadActions() : WorldScript("LoadActionsLevelup") {}
 
 
        void OnStartup() override
        {
            const auto actionResult = WorldDatabase.Query("SELECT `Level`, `Action`, `Params` FROM `levelup_actions`");
 
            if (!actionResult)
                return;
 
 
            do {
                Field* fields = actionResult->Fetch();
 
                int32 level = fields[0].GetInt32();
                uint32 action = fields[1].GetUInt32();
                std::string params = fields[2].GetString();
 
 
                auto itr = typeFactory.find(static_cast<ActionType>(action));
                if (itr != typeFactory.end())
                    actionHolder.insert({ level, itr->second(params) });
 
            } while (actionResult->NextRow());
        }
 
    };
}
 
void AddSC_LevelUpActions()
{
    new LevelUpActions::OnLevelupActions;
    new LevelUpActions::LoadActions;
}

Comments