View difference between Paste ID: Nf9pE6gp and hTVu9wBy
SHOW: | | - or go back to the newest paste.
1
#include "ScriptPCH.h"
2
#include "DatabaseEnv.h"
3
#include "Util.h"
4
#include "World.h"
5
#include "ObjectMgr.h"
6
7
#include <unordered_map>
8
#include <memory>
9
#include <boost/any.hpp>
10
#include <functional>
11
12
13
constexpr bool LoadNonFreeSpells = true;
14
15
namespace LevelUpActions
16
{
17
    const std::unordered_map<uint32, std::array<uint32, 2>> trainers = 
18
    {
19
        {CLASS_WARRIOR, {26332, 26332}},
20
        {CLASS_PALADIN, {20406, 20406}},
21
        {CLASS_DRUID, {26324, 12042}},
22
        {CLASS_MAGE, {26326, 28956}},
23
        {CLASS_WARLOCK, {23534, 16266}},
24
        {CLASS_PRIEST, {16660, 17510}},
25
        {CLASS_HUNTER, {17505, 16673}},
26
        {CLASS_ROGUE, {26329, 26329}},
27
        {CLASS_SHAMAN, {17520, 17520}},
28
        {CLASS_DEATH_KNIGHT, {31084, 31084}}
29
    };
30
31
32
    enum class ActionType : uint16
33
    {
34
        LearnSpell = 1,
35
        LearnAllSpells,
36
        ApplyAura,
37
        ModifyMoney,
38
        AddItem
39
    };
40
41
42
    class Action
43
    {
44
    public:
45
        virtual void Process(Player*) = 0;
46
        virtual ~Action() {};
47
    };
48
49
    namespace detail
50
    {
51
52
53
        template <typename D>
54
        class Action_Impl : public Action
55
        {
56
        public:
57
            Action_Impl(std::vector<boost::any>&& params) : params(params) {}
58
59
            void Process(Player* player)
60
            {
61
                static_cast<D*>(this)->Process(player);
62
            }
63
64
        protected:
65
            std::vector<boost::any> params;
66
        };
67
68
69
#define DEFINE_TAG(x) \
70
        struct x {} x##_;
71
72
73
        DEFINE_TAG(float_tag);
74
        DEFINE_TAG(int32_tag);
75
        DEFINE_TAG(uint32_tag);
76
        DEFINE_TAG(vector_uint32_tag);
77
78
79
#define EXTRACT_F(x) void ExtractOne(std::vector<boost::any>& v, Tokenizer& tok, std::size_t i, x)
80
81
        EXTRACT_F(float_tag)
82
        {
83
            v.push_back(boost::any{ std::stof(tok[i]) });
84
        }
85
86
        EXTRACT_F(int32_tag)
87
        {
88
            v.push_back(boost::any{ std::stoi(tok[i]) });
89
        }
90
91
        EXTRACT_F(uint32_tag)
92
        {
93
            auto res = std::stoi(tok[i]);
94
            if (res < 0)
95
                res = 0;
96
            v.push_back(boost::any{ static_cast<uint32>(res) });
97
        }
98
99
        EXTRACT_F(vector_uint32_tag)
100
        {
101
            std::vector<uint32> vec;
102
            for (uint32 k = i; k < tok.size(); ++k, ++i)
103
            {
104
                vec.push_back(std::stoi(tok[k]));
105
            }
106
            v.push_back(boost::any{ vec });
107
        }
108
109
110
        template <typename Type, typename... Types>
111
        void Extract(std::vector<boost::any>& v, Tokenizer& tok, std::size_t i, Type type, Types... types)
112
        {
113
            ExtractOne(v, tok, i++, type);
114
            Extract(v, tok, i, types...);
115
        }
116
117
        template <typename... Types>
118
        void Extract(std::vector<boost::any>& v, Tokenizer& tok, std::size_t i) {}
119
120
121
        template <typename... Types>
122
        std::vector<boost::any> ExtractTypes(std::string params, std::size_t i, Types... types)
123
        {
124
            Tokenizer tokenizer{ params, ' ' };
125
            std::vector<boost::any> ret;
126
            if(tokenizer.size())
127
                Extract<Types...>(ret, tokenizer, 0, types...);
128
            return ret;
129
        }
130
    }
131
132
#define CLASS_IMPL(x) class x : public detail::Action_Impl<x>
133
134
135
    CLASS_IMPL(LearnSpellAction)
136
    {
137
    public:
138
        using Action_Impl::Action_Impl;
139
140
        void Process(Player* player)
141
        {
142
            uint32 spellId = boost::any_cast<uint32>(params[0]);
143
            if (!player->HasSpell(spellId))
144
                player->LearnSpell(spellId, false);
145
        }
146
    };
147
148
    CLASS_IMPL(LearnAllSpellsAction)
149
    {
150
    public:
151
        using Action_Impl::Action_Impl;
152
153
        void Process(Player* player)
154
        {
155
            auto itr = trainers.find(player->getClass());
156
            if(itr != trainers.end())
157
            {
158
                for (const auto& trainerId : itr->second)
159
                {
160
                    auto spells = sObjectMgr->GetNpcTrainerSpells(trainerId);
161
                    if (spells)
162
                    {
163
                        for (const auto& spell : spells->spellList)
164
                        {
165
                            const auto& sp = spell.second;
166
                            if (sp.MoneyCost && !LoadNonFreeSpells)
167
                                continue;
168
169
                            if (!sp.ReqSkillLine && !sp.ReqSkillRank && sp.ReqLevel <= player->getLevel() && !player->HasSpell(sp.SpellID))
170
                                player->LearnSpell(sp.SpellID, false);
171
                        }
172
                    }
173
                }
174
            }
175
        }
176
    };
177
178
    CLASS_IMPL(ApplyAuraAction)
179
    {
180
    public:
181
        using Action_Impl::Action_Impl;
182
183
        void Process(Player* player)
184
        {
185
            uint32 spellId = boost::any_cast<uint32>(params[0]);
186
            player->AddAura(spellId, player);
187
        }
188
    };
189
190
    CLASS_IMPL(ModifyMoneyAction)
191
    {
192
    public:
193
        using Action_Impl::Action_Impl;
194
195
        void Process(Player* player)
196
        {
197
            int32 money = boost::any_cast<int32>(params[0]);
198
            player->ModifyMoney(money);
199
        }
200
    };
201
202
    CLASS_IMPL(AddItemAction)
203
    {
204
    public:
205
        using Action_Impl::Action_Impl;
206
207
        void Process(Player* player)
208
        {
209
            uint32 itemId = boost::any_cast<uint32>(params[0]);
210
            uint32 count = boost::any_cast<uint32>(params[1]);
211
            player->AddItem(itemId, count);
212
        }
213
    };
214
215
    const std::unordered_map<ActionType, std::function<std::unique_ptr<Action>(std::string params)>> typeFactory =
216
    {
217
        {
218
          ActionType::LearnSpell, [] (std::string params) {
219
            auto vec = detail::ExtractTypes(params, 0, detail::uint32_tag_);
220
            return std::unique_ptr<Action>(new LearnSpellAction(std::move(vec))); }
221
        },
222
223
        {
224
          ActionType::LearnAllSpells, [] (std::string params) {
225
            auto vec = detail::ExtractTypes(params, 0, detail::vector_uint32_tag_);
226
            return std::unique_ptr<Action>(new LearnAllSpellsAction(std::move(vec))); }
227
        },
228
229
        {
230
          ActionType::ApplyAura, [] (std::string params) {
231
            auto vec = detail::ExtractTypes(params, 0, detail::uint32_tag_);
232
            return std::unique_ptr<Action>(new ApplyAuraAction(std::move(vec))); }
233
        },
234
235
        {
236
          ActionType::ModifyMoney, [] (std::string params) {
237
            auto vec = detail::ExtractTypes(params, 0, detail::int32_tag_);
238
            return std::unique_ptr<Action>(new ModifyMoneyAction(std::move(vec))); }
239
        },
240
241
        {
242
          ActionType::AddItem, [] (std::string params) {
243
            auto vec = detail::ExtractTypes(params, 0, detail::uint32_tag_, detail::uint32_tag_);
244
            return std::unique_ptr<Action>(new AddItemAction(std::move(vec))); }
245
        }
246
    };
247
248
249
250
251
    std::unordered_multimap<int32, std::unique_ptr<Action>> actionHolder;
252
253
    class OnLevelupActions : public PlayerScript
254
    {
255
    public:
256
        OnLevelupActions() : PlayerScript("OnLevelupSpells") {}
257
258
        void OnLevelChanged(Player* player, uint8 oldLevel) override
259
        {
260
            int32 newLevel = player->getLevel();
261
            auto levelPairItr = actionHolder.equal_range(newLevel);
262
            auto autoPairItr = actionHolder.equal_range(-1);
263
264
            if (levelPairItr.first != levelPairItr.second)
265
            {
266
                while (levelPairItr.first != levelPairItr.second)
267
                {
268
                    levelPairItr.first->second->Process(player);
269
                    ++levelPairItr.first;
270
                }
271
            }
272
273
            if (autoPairItr.first != autoPairItr.second)
274
            {
275
                while (autoPairItr.first != autoPairItr.second)
276
                {
277
                    autoPairItr.first->second->Process(player);
278
                    ++autoPairItr.first;
279
                }
280
            }
281
        }
282
    };
283
284
    class LoadActions : public WorldScript
285
    {
286
    public:
287
        LoadActions() : WorldScript("LoadActionsLevelup") {}
288
289
290
        void OnStartup() override
291
        {
292
            const auto actionResult = WorldDatabase.Query("SELECT `Level`, `Action`, `Params` FROM `levelup_actions`");
293
294
            if (!actionResult)
295
                return;
296
297
298
            do {
299
                Field* fields = actionResult->Fetch();
300
301
                int32 level = fields[0].GetInt32();
302
                uint32 action = fields[1].GetUInt32();
303
                std::string params = fields[2].GetString();
304
305
306
                auto itr = typeFactory.find(static_cast<ActionType>(action));
307
                if (itr != typeFactory.end())
308
                    actionHolder.insert({ level, itr->second(params) });
309
310
            } while (actionResult->NextRow());
311
        }
312
313
    };
314
}
315
316
void AddSC_LevelUpActions()
317
{
318
    new LevelUpActions::OnLevelupActions;
319
    new LevelUpActions::LoadActions;
320
}