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 | } |