events.cpp

main 1023 lines · 32 KB Raw
Alex Alex Commit Server upload 18/10/2026 23:38
1/**
2 * The Forgotten Server - a free and open-source MMORPG server emulator
3 * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include "otpch.h"
21
22#include "events.h"
23#include "tools.h"
24#include "item.h"
25#include "player.h"
26
27#include <set>
28
29Events::Events() :
30 scriptInterface("Event Interface")
31{
32 scriptInterface.initState();
33}
34
35bool Events::load()
36{
37 pugi::xml_document doc;
38 pugi::xml_parse_result result = doc.load_file("data/events/events.xml");
39 if (!result) {
40 printXMLError("Error - Events::load", "data/events/events.xml", result);
41 return false;
42 }
43
44 info = {};
45
46 std::set<std::string> classes;
47 for (auto eventNode : doc.child("events").children()) {
48 if (!eventNode.attribute("enabled").as_bool()) {
49 continue;
50 }
51
52 const std::string& className = eventNode.attribute("class").as_string();
53 auto res = classes.insert(className);
54 if (res.second) {
55 const std::string& lowercase = asLowerCaseString(className);
56 if (scriptInterface.loadFile("data/events/scripts/" + lowercase + ".lua") != 0) {
57 std::cout << "[Warning - Events::load] Can not load script: " << lowercase << ".lua" << std::endl;
58 std::cout << scriptInterface.getLastLuaError() << std::endl;
59 }
60 }
61
62 const std::string& methodName = eventNode.attribute("method").as_string();
63 const int32_t event = scriptInterface.getMetaEvent(className, methodName);
64 if (className == "Creature") {
65 if (methodName == "onChangeOutfit") {
66 info.creatureOnChangeOutfit = event;
67 } else if (methodName == "onAreaCombat") {
68 info.creatureOnAreaCombat = event;
69 } else if (methodName == "onTargetCombat") {
70 info.creatureOnTargetCombat = event;
71 } else if (methodName == "onHear") {
72 info.creatureOnHear = event;
73 } else {
74 std::cout << "[Warning - Events::load] Unknown creature method: " << methodName << std::endl;
75 }
76 } else if (className == "Party") {
77 if (methodName == "onJoin") {
78 info.partyOnJoin = event;
79 } else if (methodName == "onLeave") {
80 info.partyOnLeave = event;
81 } else if (methodName == "onDisband") {
82 info.partyOnDisband = event;
83 } else if (methodName == "onShareExperience") {
84 info.partyOnShareExperience = event;
85 } else {
86 std::cout << "[Warning - Events::load] Unknown party method: " << methodName << std::endl;
87 }
88 } else if (className == "Player") {
89 if (methodName == "onBrowseField") {
90 info.playerOnBrowseField = event;
91 } else if (methodName == "onLook") {
92 info.playerOnLook = event;
93 } else if (methodName == "onLookInBattleList") {
94 info.playerOnLookInBattleList = event;
95 } else if (methodName == "onLookInTrade") {
96 info.playerOnLookInTrade = event;
97 } else if (methodName == "onLookInShop") {
98 info.playerOnLookInShop = event;
99 } else if (methodName == "onTradeRequest") {
100 info.playerOnTradeRequest = event;
101 } else if (methodName == "onTradeAccept") {
102 info.playerOnTradeAccept = event;
103 } else if (methodName == "onTradeCompleted") {
104 info.playerOnTradeCompleted = event;
105 } else if (methodName == "onMoveItem") {
106 info.playerOnMoveItem = event;
107 } else if (methodName == "onItemMoved") {
108 info.playerOnItemMoved = event;
109 } else if (methodName == "onMoveCreature") {
110 info.playerOnMoveCreature = event;
111 } else if (methodName == "onReportRuleViolation") {
112 info.playerOnReportRuleViolation = event;
113 } else if (methodName == "onReportBug") {
114 info.playerOnReportBug = event;
115 } else if (methodName == "onTurn") {
116 info.playerOnTurn = event;
117 } else if (methodName == "onGainExperience") {
118 info.playerOnGainExperience = event;
119 } else if (methodName == "onLoseExperience") {
120 info.playerOnLoseExperience = event;
121 } else if (methodName == "onGainSkillTries") {
122 info.playerOnGainSkillTries = event;
123 } else if (methodName == "onWrapItem") {
124 info.playerOnWrapItem = event;
125 } else {
126 std::cout << "[Warning - Events::load] Unknown player method: " << methodName << std::endl;
127 }
128 } else if (className == "Monster") {
129 if (methodName == "onDropLoot") {
130 info.monsterOnDropLoot = event;
131 } else if (methodName == "onSpawn") {
132 info.monsterOnSpawn = event;
133 } else {
134 std::cout << "[Warning - Events::load] Unknown monster method: " << methodName << std::endl;
135 }
136 } else {
137 std::cout << "[Warning - Events::load] Unknown class: " << className << std::endl;
138 }
139 }
140 return true;
141}
142
143// Monster
144bool Events::eventMonsterOnSpawn(Monster* monster, const Position& position, bool startup, bool artificial)
145{
146 // Monster:onSpawn(position, startup, artificial)
147 if (info.monsterOnSpawn == -1) {
148 return true;
149 }
150
151 if (!scriptInterface.reserveScriptEnv()) {
152 std::cout << "[Error - Events::monsterOnSpawn] Call stack overflow" << std::endl;
153 return false;
154 }
155
156 ScriptEnvironment* env = scriptInterface.getScriptEnv();
157 env->setScriptId(info.monsterOnSpawn, &scriptInterface);
158
159 lua_State* L = scriptInterface.getLuaState();
160 scriptInterface.pushFunction(info.monsterOnSpawn);
161
162 LuaScriptInterface::pushUserdata<Monster>(L, monster);
163 LuaScriptInterface::setMetatable(L, -1, "Monster");
164 LuaScriptInterface::pushPosition(L, position);
165 LuaScriptInterface::pushBoolean(L, startup);
166 LuaScriptInterface::pushBoolean(L, artificial);
167
168 return scriptInterface.callFunction(4);
169}
170
171// Creature
172bool Events::eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit)
173{
174 // Creature:onChangeOutfit(outfit) or Creature.onChangeOutfit(self, outfit)
175 if (info.creatureOnChangeOutfit == -1) {
176 return true;
177 }
178
179 if (!scriptInterface.reserveScriptEnv()) {
180 std::cout << "[Error - Events::eventCreatureOnChangeOutfit] Call stack overflow" << std::endl;
181 return false;
182 }
183
184 ScriptEnvironment* env = scriptInterface.getScriptEnv();
185 env->setScriptId(info.creatureOnChangeOutfit, &scriptInterface);
186
187 lua_State* L = scriptInterface.getLuaState();
188 scriptInterface.pushFunction(info.creatureOnChangeOutfit);
189
190 LuaScriptInterface::pushUserdata<Creature>(L, creature);
191 LuaScriptInterface::setCreatureMetatable(L, -1, creature);
192
193 LuaScriptInterface::pushOutfit(L, outfit);
194
195 return scriptInterface.callFunction(2);
196}
197
198ReturnValue Events::eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bool aggressive)
199{
200 // Creature:onAreaCombat(tile, aggressive) or Creature.onAreaCombat(self, tile, aggressive)
201 if (info.creatureOnAreaCombat == -1) {
202 return RETURNVALUE_NOERROR;
203 }
204
205 if (!scriptInterface.reserveScriptEnv()) {
206 std::cout << "[Error - Events::eventCreatureOnAreaCombat] Call stack overflow" << std::endl;
207 return RETURNVALUE_NOTPOSSIBLE;
208 }
209
210 ScriptEnvironment* env = scriptInterface.getScriptEnv();
211 env->setScriptId(info.creatureOnAreaCombat, &scriptInterface);
212
213 lua_State* L = scriptInterface.getLuaState();
214 scriptInterface.pushFunction(info.creatureOnAreaCombat);
215
216 if (creature) {
217 LuaScriptInterface::pushUserdata<Creature>(L, creature);
218 LuaScriptInterface::setCreatureMetatable(L, -1, creature);
219 } else {
220 lua_pushnil(L);
221 }
222
223 LuaScriptInterface::pushUserdata<Tile>(L, tile);
224 LuaScriptInterface::setMetatable(L, -1, "Tile");
225
226 LuaScriptInterface::pushBoolean(L, aggressive);
227
228 ReturnValue returnValue;
229 if (scriptInterface.protectedCall(L, 3, 1) != 0) {
230 returnValue = RETURNVALUE_NOTPOSSIBLE;
231 LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
232 } else {
233 returnValue = LuaScriptInterface::getNumber<ReturnValue>(L, -1);
234 lua_pop(L, 1);
235 }
236
237 scriptInterface.resetScriptEnv();
238 return returnValue;
239}
240
241ReturnValue Events::eventCreatureOnTargetCombat(Creature* creature, Creature* target)
242{
243 // Creature:onTargetCombat(target) or Creature.onTargetCombat(self, target)
244 if (info.creatureOnTargetCombat == -1) {
245 return RETURNVALUE_NOERROR;
246 }
247
248 if (!scriptInterface.reserveScriptEnv()) {
249 std::cout << "[Error - Events::eventCreatureOnTargetCombat] Call stack overflow" << std::endl;
250 return RETURNVALUE_NOTPOSSIBLE;
251 }
252
253 ScriptEnvironment* env = scriptInterface.getScriptEnv();
254 env->setScriptId(info.creatureOnTargetCombat, &scriptInterface);
255
256 lua_State* L = scriptInterface.getLuaState();
257 scriptInterface.pushFunction(info.creatureOnTargetCombat);
258
259 if (creature) {
260 LuaScriptInterface::pushUserdata<Creature>(L, creature);
261 LuaScriptInterface::setCreatureMetatable(L, -1, creature);
262 } else {
263 lua_pushnil(L);
264 }
265
266 LuaScriptInterface::pushUserdata<Creature>(L, target);
267 LuaScriptInterface::setCreatureMetatable(L, -1, target);
268
269 ReturnValue returnValue;
270 if (scriptInterface.protectedCall(L, 2, 1) != 0) {
271 returnValue = RETURNVALUE_NOTPOSSIBLE;
272 LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
273 } else {
274 returnValue = LuaScriptInterface::getNumber<ReturnValue>(L, -1);
275 lua_pop(L, 1);
276 }
277
278 scriptInterface.resetScriptEnv();
279 return returnValue;
280}
281
282void Events::eventCreatureOnHear(Creature* creature, Creature* speaker, const std::string& words, SpeakClasses type)
283{
284 // Creature:onHear(speaker, words, type)
285 if (info.creatureOnHear == -1) {
286 return;
287 }
288
289 if (!scriptInterface.reserveScriptEnv()) {
290 std::cout << "[Error - Events::eventCreatureOnHear] Call stack overflow" << std::endl;
291 return;
292 }
293
294 ScriptEnvironment* env = scriptInterface.getScriptEnv();
295 env->setScriptId(info.creatureOnHear, &scriptInterface);
296
297 lua_State* L = scriptInterface.getLuaState();
298 scriptInterface.pushFunction(info.creatureOnHear);
299
300 LuaScriptInterface::pushUserdata<Creature>(L, creature);
301 LuaScriptInterface::setCreatureMetatable(L, -1, creature);
302
303 LuaScriptInterface::pushUserdata<Creature>(L, speaker);
304 LuaScriptInterface::setCreatureMetatable(L, -1, speaker);
305
306 LuaScriptInterface::pushString(L, words);
307 lua_pushnumber(L, type);
308
309 scriptInterface.callVoidFunction(4);
310}
311
312// Party
313bool Events::eventPartyOnJoin(Party* party, Player* player)
314{
315 // Party:onJoin(player) or Party.onJoin(self, player)
316 if (info.partyOnJoin == -1) {
317 return true;
318 }
319
320 if (!scriptInterface.reserveScriptEnv()) {
321 std::cout << "[Error - Events::eventPartyOnJoin] Call stack overflow" << std::endl;
322 return false;
323 }
324
325 ScriptEnvironment* env = scriptInterface.getScriptEnv();
326 env->setScriptId(info.partyOnJoin, &scriptInterface);
327
328 lua_State* L = scriptInterface.getLuaState();
329 scriptInterface.pushFunction(info.partyOnJoin);
330
331 LuaScriptInterface::pushUserdata<Party>(L, party);
332 LuaScriptInterface::setMetatable(L, -1, "Party");
333
334 LuaScriptInterface::pushUserdata<Player>(L, player);
335 LuaScriptInterface::setMetatable(L, -1, "Player");
336
337 return scriptInterface.callFunction(2);
338}
339
340bool Events::eventPartyOnLeave(Party* party, Player* player)
341{
342 // Party:onLeave(player) or Party.onLeave(self, player)
343 if (info.partyOnLeave == -1) {
344 return true;
345 }
346
347 if (!scriptInterface.reserveScriptEnv()) {
348 std::cout << "[Error - Events::eventPartyOnLeave] Call stack overflow" << std::endl;
349 return false;
350 }
351
352 ScriptEnvironment* env = scriptInterface.getScriptEnv();
353 env->setScriptId(info.partyOnLeave, &scriptInterface);
354
355 lua_State* L = scriptInterface.getLuaState();
356 scriptInterface.pushFunction(info.partyOnLeave);
357
358 LuaScriptInterface::pushUserdata<Party>(L, party);
359 LuaScriptInterface::setMetatable(L, -1, "Party");
360
361 LuaScriptInterface::pushUserdata<Player>(L, player);
362 LuaScriptInterface::setMetatable(L, -1, "Player");
363
364 return scriptInterface.callFunction(2);
365}
366
367bool Events::eventPartyOnDisband(Party* party)
368{
369 // Party:onDisband() or Party.onDisband(self)
370 if (info.partyOnDisband == -1) {
371 return true;
372 }
373
374 if (!scriptInterface.reserveScriptEnv()) {
375 std::cout << "[Error - Events::eventPartyOnDisband] Call stack overflow" << std::endl;
376 return false;
377 }
378
379 ScriptEnvironment* env = scriptInterface.getScriptEnv();
380 env->setScriptId(info.partyOnDisband, &scriptInterface);
381
382 lua_State* L = scriptInterface.getLuaState();
383 scriptInterface.pushFunction(info.partyOnDisband);
384
385 LuaScriptInterface::pushUserdata<Party>(L, party);
386 LuaScriptInterface::setMetatable(L, -1, "Party");
387
388 return scriptInterface.callFunction(1);
389}
390
391void Events::eventPartyOnShareExperience(Party* party, uint64_t& exp)
392{
393 // Party:onShareExperience(exp) or Party.onShareExperience(self, exp)
394 if (info.partyOnShareExperience == -1) {
395 return;
396 }
397
398 if (!scriptInterface.reserveScriptEnv()) {
399 std::cout << "[Error - Events::eventPartyOnShareExperience] Call stack overflow" << std::endl;
400 return;
401 }
402
403 ScriptEnvironment* env = scriptInterface.getScriptEnv();
404 env->setScriptId(info.partyOnShareExperience, &scriptInterface);
405
406 lua_State* L = scriptInterface.getLuaState();
407 scriptInterface.pushFunction(info.partyOnShareExperience);
408
409 LuaScriptInterface::pushUserdata<Party>(L, party);
410 LuaScriptInterface::setMetatable(L, -1, "Party");
411
412 lua_pushnumber(L, exp);
413
414 if (scriptInterface.protectedCall(L, 2, 1) != 0) {
415 LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
416 } else {
417 exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
418 lua_pop(L, 1);
419 }
420
421 scriptInterface.resetScriptEnv();
422}
423
424// Player
425bool Events::eventPlayerOnBrowseField(Player* player, const Position& position)
426{
427 // Player:onBrowseField(position) or Player.onBrowseField(self, position)
428 if (info.playerOnBrowseField == -1) {
429 return true;
430 }
431
432 if (!scriptInterface.reserveScriptEnv()) {
433 std::cout << "[Error - Events::eventPlayerOnBrowseField] Call stack overflow" << std::endl;
434 return false;
435 }
436
437 ScriptEnvironment* env = scriptInterface.getScriptEnv();
438 env->setScriptId(info.playerOnBrowseField, &scriptInterface);
439
440 lua_State* L = scriptInterface.getLuaState();
441 scriptInterface.pushFunction(info.playerOnBrowseField);
442
443 LuaScriptInterface::pushUserdata<Player>(L, player);
444 LuaScriptInterface::setMetatable(L, -1, "Player");
445
446 LuaScriptInterface::pushPosition(L, position);
447
448 return scriptInterface.callFunction(2);
449}
450
451void Events::eventPlayerOnLook(Player* player, const Position& position, Thing* thing, uint8_t stackpos, int32_t lookDistance)
452{
453 // Player:onLook(thing, position, distance) or Player.onLook(self, thing, position, distance)
454 if (info.playerOnLook == -1) {
455 return;
456 }
457
458 if (!scriptInterface.reserveScriptEnv()) {
459 std::cout << "[Error - Events::eventPlayerOnLook] Call stack overflow" << std::endl;
460 return;
461 }
462
463 ScriptEnvironment* env = scriptInterface.getScriptEnv();
464 env->setScriptId(info.playerOnLook, &scriptInterface);
465
466 lua_State* L = scriptInterface.getLuaState();
467 scriptInterface.pushFunction(info.playerOnLook);
468
469 LuaScriptInterface::pushUserdata<Player>(L, player);
470 LuaScriptInterface::setMetatable(L, -1, "Player");
471
472 if (Creature* creature = thing->getCreature()) {
473 LuaScriptInterface::pushUserdata<Creature>(L, creature);
474 LuaScriptInterface::setCreatureMetatable(L, -1, creature);
475 } else if (Item* item = thing->getItem()) {
476 LuaScriptInterface::pushUserdata<Item>(L, item);
477 LuaScriptInterface::setItemMetatable(L, -1, item);
478 } else {
479 lua_pushnil(L);
480 }
481
482 LuaScriptInterface::pushPosition(L, position, stackpos);
483 lua_pushnumber(L, lookDistance);
484
485 scriptInterface.callVoidFunction(4);
486}
487
488void Events::eventPlayerOnLookInBattleList(Player* player, Creature* creature, int32_t lookDistance)
489{
490 // Player:onLookInBattleList(creature, position, distance) or Player.onLookInBattleList(self, creature, position, distance)
491 if (info.playerOnLookInBattleList == -1) {
492 return;
493 }
494
495 if (!scriptInterface.reserveScriptEnv()) {
496 std::cout << "[Error - Events::eventPlayerOnLookInBattleList] Call stack overflow" << std::endl;
497 return;
498 }
499
500 ScriptEnvironment* env = scriptInterface.getScriptEnv();
501 env->setScriptId(info.playerOnLookInBattleList, &scriptInterface);
502
503 lua_State* L = scriptInterface.getLuaState();
504 scriptInterface.pushFunction(info.playerOnLookInBattleList);
505
506 LuaScriptInterface::pushUserdata<Player>(L, player);
507 LuaScriptInterface::setMetatable(L, -1, "Player");
508
509 LuaScriptInterface::pushUserdata<Creature>(L, creature);
510 LuaScriptInterface::setCreatureMetatable(L, -1, creature);
511
512 lua_pushnumber(L, lookDistance);
513
514 scriptInterface.callVoidFunction(3);
515}
516
517void Events::eventPlayerOnLookInTrade(Player* player, Player* partner, Item* item, int32_t lookDistance)
518{
519 // Player:onLookInTrade(partner, item, distance) or Player.onLookInTrade(self, partner, item, distance)
520 if (info.playerOnLookInTrade == -1) {
521 return;
522 }
523
524 if (!scriptInterface.reserveScriptEnv()) {
525 std::cout << "[Error - Events::eventPlayerOnLookInTrade] Call stack overflow" << std::endl;
526 return;
527 }
528
529 ScriptEnvironment* env = scriptInterface.getScriptEnv();
530 env->setScriptId(info.playerOnLookInTrade, &scriptInterface);
531
532 lua_State* L = scriptInterface.getLuaState();
533 scriptInterface.pushFunction(info.playerOnLookInTrade);
534
535 LuaScriptInterface::pushUserdata<Player>(L, player);
536 LuaScriptInterface::setMetatable(L, -1, "Player");
537
538 LuaScriptInterface::pushUserdata<Player>(L, partner);
539 LuaScriptInterface::setMetatable(L, -1, "Player");
540
541 LuaScriptInterface::pushUserdata<Item>(L, item);
542 LuaScriptInterface::setItemMetatable(L, -1, item);
543
544 lua_pushnumber(L, lookDistance);
545
546 scriptInterface.callVoidFunction(4);
547}
548
549bool Events::eventPlayerOnLookInShop(Player* player, const ItemType* itemType, uint8_t count)
550{
551 // Player:onLookInShop(itemType, count) or Player.onLookInShop(self, itemType, count)
552 if (info.playerOnLookInShop == -1) {
553 return true;
554 }
555
556 if (!scriptInterface.reserveScriptEnv()) {
557 std::cout << "[Error - Events::eventPlayerOnLookInShop] Call stack overflow" << std::endl;
558 return false;
559 }
560
561 ScriptEnvironment* env = scriptInterface.getScriptEnv();
562 env->setScriptId(info.playerOnLookInShop, &scriptInterface);
563
564 lua_State* L = scriptInterface.getLuaState();
565 scriptInterface.pushFunction(info.playerOnLookInShop);
566
567 LuaScriptInterface::pushUserdata<Player>(L, player);
568 LuaScriptInterface::setMetatable(L, -1, "Player");
569
570 LuaScriptInterface::pushUserdata<const ItemType>(L, itemType);
571 LuaScriptInterface::setMetatable(L, -1, "ItemType");
572
573 lua_pushnumber(L, count);
574
575 return scriptInterface.callFunction(3);
576}
577
578bool Events::eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
579{
580 // Player:onMoveItem(item, count, fromPosition, toPosition) or Player.onMoveItem(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
581 if (info.playerOnMoveItem == -1) {
582 return true;
583 }
584
585 if (!scriptInterface.reserveScriptEnv()) {
586 std::cout << "[Error - Events::eventPlayerOnMoveItem] Call stack overflow" << std::endl;
587 return false;
588 }
589
590 ScriptEnvironment* env = scriptInterface.getScriptEnv();
591 env->setScriptId(info.playerOnMoveItem, &scriptInterface);
592
593 lua_State* L = scriptInterface.getLuaState();
594 scriptInterface.pushFunction(info.playerOnMoveItem);
595
596 LuaScriptInterface::pushUserdata<Player>(L, player);
597 LuaScriptInterface::setMetatable(L, -1, "Player");
598
599 LuaScriptInterface::pushUserdata<Item>(L, item);
600 LuaScriptInterface::setItemMetatable(L, -1, item);
601
602 lua_pushnumber(L, count);
603 LuaScriptInterface::pushPosition(L, fromPosition);
604 LuaScriptInterface::pushPosition(L, toPosition);
605
606 LuaScriptInterface::pushCylinder(L, fromCylinder);
607 LuaScriptInterface::pushCylinder(L, toCylinder);
608
609 return scriptInterface.callFunction(7);
610}
611
612void Events::eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
613{
614 // Player:onItemMoved(item, count, fromPosition, toPosition) or Player.onItemMoved(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
615 if (info.playerOnItemMoved == -1) {
616 return;
617 }
618
619 if (!scriptInterface.reserveScriptEnv()) {
620 std::cout << "[Error - Events::eventPlayerOnItemMoved] Call stack overflow" << std::endl;
621 return;
622 }
623
624 ScriptEnvironment* env = scriptInterface.getScriptEnv();
625 env->setScriptId(info.playerOnItemMoved, &scriptInterface);
626
627 lua_State* L = scriptInterface.getLuaState();
628 scriptInterface.pushFunction(info.playerOnItemMoved);
629
630 LuaScriptInterface::pushUserdata<Player>(L, player);
631 LuaScriptInterface::setMetatable(L, -1, "Player");
632
633 LuaScriptInterface::pushUserdata<Item>(L, item);
634 LuaScriptInterface::setItemMetatable(L, -1, item);
635
636 lua_pushnumber(L, count);
637 LuaScriptInterface::pushPosition(L, fromPosition);
638 LuaScriptInterface::pushPosition(L, toPosition);
639
640 LuaScriptInterface::pushCylinder(L, fromCylinder);
641 LuaScriptInterface::pushCylinder(L, toCylinder);
642
643 scriptInterface.callVoidFunction(7);
644}
645
646bool Events::eventPlayerOnMoveCreature(Player* player, Creature* creature, const Position& fromPosition, const Position& toPosition)
647{
648 // Player:onMoveCreature(creature, fromPosition, toPosition) or Player.onMoveCreature(self, creature, fromPosition, toPosition)
649 if (info.playerOnMoveCreature == -1) {
650 return true;
651 }
652
653 if (!scriptInterface.reserveScriptEnv()) {
654 std::cout << "[Error - Events::eventPlayerOnMoveCreature] Call stack overflow" << std::endl;
655 return false;
656 }
657
658 ScriptEnvironment* env = scriptInterface.getScriptEnv();
659 env->setScriptId(info.playerOnMoveCreature, &scriptInterface);
660
661 lua_State* L = scriptInterface.getLuaState();
662 scriptInterface.pushFunction(info.playerOnMoveCreature);
663
664 LuaScriptInterface::pushUserdata<Player>(L, player);
665 LuaScriptInterface::setMetatable(L, -1, "Player");
666
667 LuaScriptInterface::pushUserdata<Creature>(L, creature);
668 LuaScriptInterface::setCreatureMetatable(L, -1, creature);
669
670 LuaScriptInterface::pushPosition(L, fromPosition);
671 LuaScriptInterface::pushPosition(L, toPosition);
672
673 return scriptInterface.callFunction(4);
674}
675
676void Events::eventPlayerOnReportRuleViolation(Player* player, const std::string& targetName, uint8_t reportType, uint8_t reportReason, const std::string& comment, const std::string& translation)
677{
678 // Player:onReportRuleViolation(targetName, reportType, reportReason, comment, translation)
679 if (info.playerOnReportRuleViolation == -1) {
680 return;
681 }
682
683 if (!scriptInterface.reserveScriptEnv()) {
684 std::cout << "[Error - Events::eventPlayerOnReportRuleViolation] Call stack overflow" << std::endl;
685 return;
686 }
687
688 ScriptEnvironment* env = scriptInterface.getScriptEnv();
689 env->setScriptId(info.playerOnReportRuleViolation, &scriptInterface);
690
691 lua_State* L = scriptInterface.getLuaState();
692 scriptInterface.pushFunction(info.playerOnReportRuleViolation);
693
694 LuaScriptInterface::pushUserdata<Player>(L, player);
695 LuaScriptInterface::setMetatable(L, -1, "Player");
696
697 LuaScriptInterface::pushString(L, targetName);
698
699 lua_pushnumber(L, reportType);
700 lua_pushnumber(L, reportReason);
701
702 LuaScriptInterface::pushString(L, comment);
703 LuaScriptInterface::pushString(L, translation);
704
705 scriptInterface.callVoidFunction(6);
706}
707
708bool Events::eventPlayerOnReportBug(Player* player, const std::string& message, const Position& position, uint8_t category)
709{
710 // Player:onReportBug(message, position, category)
711 if (info.playerOnReportBug == -1) {
712 return true;
713 }
714
715 if (!scriptInterface.reserveScriptEnv()) {
716 std::cout << "[Error - Events::eventPlayerOnReportBug] Call stack overflow" << std::endl;
717 return false;
718 }
719
720 ScriptEnvironment* env = scriptInterface.getScriptEnv();
721 env->setScriptId(info.playerOnReportBug, &scriptInterface);
722
723 lua_State* L = scriptInterface.getLuaState();
724 scriptInterface.pushFunction(info.playerOnReportBug);
725
726 LuaScriptInterface::pushUserdata<Player>(L, player);
727 LuaScriptInterface::setMetatable(L, -1, "Player");
728
729 LuaScriptInterface::pushString(L, message);
730 LuaScriptInterface::pushPosition(L, position);
731 lua_pushnumber(L, category);
732
733 return scriptInterface.callFunction(4);
734}
735
736bool Events::eventPlayerOnTurn(Player* player, Direction direction)
737{
738 // Player:onTurn(direction) or Player.onTurn(self, direction)
739 if (info.playerOnTurn == -1) {
740 return true;
741 }
742
743 if (!scriptInterface.reserveScriptEnv()) {
744 std::cout << "[Error - Events::eventPlayerOnTurn] Call stack overflow" << std::endl;
745 return false;
746 }
747
748 ScriptEnvironment* env = scriptInterface.getScriptEnv();
749 env->setScriptId(info.playerOnTurn, &scriptInterface);
750
751 lua_State* L = scriptInterface.getLuaState();
752 scriptInterface.pushFunction(info.playerOnTurn);
753
754 LuaScriptInterface::pushUserdata<Player>(L, player);
755 LuaScriptInterface::setMetatable(L, -1, "Player");
756
757 lua_pushnumber(L, direction);
758
759 return scriptInterface.callFunction(2);
760}
761
762bool Events::eventPlayerOnTradeRequest(Player* player, Player* target, Item* item)
763{
764 // Player:onTradeRequest(target, item)
765 if (info.playerOnTradeRequest == -1) {
766 return true;
767 }
768
769 if (!scriptInterface.reserveScriptEnv()) {
770 std::cout << "[Error - Events::eventPlayerOnTradeRequest] Call stack overflow" << std::endl;
771 return false;
772 }
773
774 ScriptEnvironment* env = scriptInterface.getScriptEnv();
775 env->setScriptId(info.playerOnTradeRequest, &scriptInterface);
776
777 lua_State* L = scriptInterface.getLuaState();
778 scriptInterface.pushFunction(info.playerOnTradeRequest);
779
780 LuaScriptInterface::pushUserdata<Player>(L, player);
781 LuaScriptInterface::setMetatable(L, -1, "Player");
782
783 LuaScriptInterface::pushUserdata<Player>(L, target);
784 LuaScriptInterface::setMetatable(L, -1, "Player");
785
786 LuaScriptInterface::pushUserdata<Item>(L, item);
787 LuaScriptInterface::setItemMetatable(L, -1, item);
788
789 return scriptInterface.callFunction(3);
790}
791
792bool Events::eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem)
793{
794 // Player:onTradeAccept(target, item, targetItem)
795 if (info.playerOnTradeAccept == -1) {
796 return true;
797 }
798
799 if (!scriptInterface.reserveScriptEnv()) {
800 std::cout << "[Error - Events::eventPlayerOnTradeAccept] Call stack overflow" << std::endl;
801 return false;
802 }
803
804 ScriptEnvironment* env = scriptInterface.getScriptEnv();
805 env->setScriptId(info.playerOnTradeAccept, &scriptInterface);
806
807 lua_State* L = scriptInterface.getLuaState();
808 scriptInterface.pushFunction(info.playerOnTradeAccept);
809
810 LuaScriptInterface::pushUserdata<Player>(L, player);
811 LuaScriptInterface::setMetatable(L, -1, "Player");
812
813 LuaScriptInterface::pushUserdata<Player>(L, target);
814 LuaScriptInterface::setMetatable(L, -1, "Player");
815
816 LuaScriptInterface::pushUserdata<Item>(L, item);
817 LuaScriptInterface::setItemMetatable(L, -1, item);
818
819 LuaScriptInterface::pushUserdata<Item>(L, targetItem);
820 LuaScriptInterface::setItemMetatable(L, -1, targetItem);
821
822 return scriptInterface.callFunction(4);
823}
824
825void Events::eventPlayerOnTradeCompleted(Player* player, Player* target, Item* item, Item* targetItem, bool isSuccess)
826{
827 // Player:onTradeCompleted(target, item, targetItem, isSuccess)
828 if (info.playerOnTradeCompleted == -1) {
829 return;
830 }
831
832 if (!scriptInterface.reserveScriptEnv()) {
833 std::cout << "[Error - Events::eventPlayerOnTradeCompleted] Call stack overflow" << std::endl;
834 return;
835 }
836
837 ScriptEnvironment* env = scriptInterface.getScriptEnv();
838 env->setScriptId(info.playerOnTradeCompleted, &scriptInterface);
839
840 lua_State* L = scriptInterface.getLuaState();
841 scriptInterface.pushFunction(info.playerOnTradeCompleted);
842
843 LuaScriptInterface::pushUserdata<Player>(L, player);
844 LuaScriptInterface::setMetatable(L, -1, "Player");
845
846 LuaScriptInterface::pushUserdata<Player>(L, target);
847 LuaScriptInterface::setMetatable(L, -1, "Player");
848
849 LuaScriptInterface::pushUserdata<Item>(L, item);
850 LuaScriptInterface::setItemMetatable(L, -1, item);
851
852 LuaScriptInterface::pushUserdata<Item>(L, targetItem);
853 LuaScriptInterface::setItemMetatable(L, -1, targetItem);
854
855 LuaScriptInterface::pushBoolean(L, isSuccess);
856
857 return scriptInterface.callVoidFunction(5);
858}
859
860void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp)
861{
862 // Player:onGainExperience(source, exp, rawExp)
863 // rawExp gives the original exp which is not multiplied
864 if (info.playerOnGainExperience == -1) {
865 return;
866 }
867
868 if (!scriptInterface.reserveScriptEnv()) {
869 std::cout << "[Error - Events::eventPlayerOnGainExperience] Call stack overflow" << std::endl;
870 return;
871 }
872
873 ScriptEnvironment* env = scriptInterface.getScriptEnv();
874 env->setScriptId(info.playerOnGainExperience, &scriptInterface);
875
876 lua_State* L = scriptInterface.getLuaState();
877 scriptInterface.pushFunction(info.playerOnGainExperience);
878
879 LuaScriptInterface::pushUserdata<Player>(L, player);
880 LuaScriptInterface::setMetatable(L, -1, "Player");
881
882 if (source) {
883 LuaScriptInterface::pushUserdata<Creature>(L, source);
884 LuaScriptInterface::setCreatureMetatable(L, -1, source);
885 } else {
886 lua_pushnil(L);
887 }
888
889 lua_pushnumber(L, exp);
890 lua_pushnumber(L, rawExp);
891
892 if (scriptInterface.protectedCall(L, 4, 1) != 0) {
893 LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
894 } else {
895 exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
896 lua_pop(L, 1);
897 }
898
899 scriptInterface.resetScriptEnv();
900}
901
902void Events::eventPlayerOnLoseExperience(Player* player, uint64_t& exp)
903{
904 // Player:onLoseExperience(exp)
905 if (info.playerOnLoseExperience == -1) {
906 return;
907 }
908
909 if (!scriptInterface.reserveScriptEnv()) {
910 std::cout << "[Error - Events::eventPlayerOnLoseExperience] Call stack overflow" << std::endl;
911 return;
912 }
913
914 ScriptEnvironment* env = scriptInterface.getScriptEnv();
915 env->setScriptId(info.playerOnLoseExperience, &scriptInterface);
916
917 lua_State* L = scriptInterface.getLuaState();
918 scriptInterface.pushFunction(info.playerOnLoseExperience);
919
920 LuaScriptInterface::pushUserdata<Player>(L, player);
921 LuaScriptInterface::setMetatable(L, -1, "Player");
922
923 lua_pushnumber(L, exp);
924
925 if (scriptInterface.protectedCall(L, 2, 1) != 0) {
926 LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
927 } else {
928 exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
929 lua_pop(L, 1);
930 }
931
932 scriptInterface.resetScriptEnv();
933}
934
935void Events::eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries)
936{
937 // Player:onGainSkillTries(skill, tries)
938 if (info.playerOnGainSkillTries == -1) {
939 return;
940 }
941
942 if (!scriptInterface.reserveScriptEnv()) {
943 std::cout << "[Error - Events::eventPlayerOnGainSkillTries] Call stack overflow" << std::endl;
944 return;
945 }
946
947 ScriptEnvironment* env = scriptInterface.getScriptEnv();
948 env->setScriptId(info.playerOnGainSkillTries, &scriptInterface);
949
950 lua_State* L = scriptInterface.getLuaState();
951 scriptInterface.pushFunction(info.playerOnGainSkillTries);
952
953 LuaScriptInterface::pushUserdata<Player>(L, player);
954 LuaScriptInterface::setMetatable(L, -1, "Player");
955
956 lua_pushnumber(L, skill);
957 lua_pushnumber(L, tries);
958
959 if (scriptInterface.protectedCall(L, 3, 1) != 0) {
960 LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
961 } else {
962 tries = LuaScriptInterface::getNumber<uint64_t>(L, -1);
963 lua_pop(L, 1);
964 }
965
966 scriptInterface.resetScriptEnv();
967}
968
969void Events::eventPlayerOnWrapItem(Player* player, Item* item)
970{
971 // Player:onWrapItem(item)
972 if (info.playerOnWrapItem == -1) {
973 return;
974 }
975
976 if (!scriptInterface.reserveScriptEnv()) {
977 std::cout << "[Error - Events::eventPlayerOnWrapItem] Call stack overflow" << std::endl;
978 return;
979 }
980
981 ScriptEnvironment* env = scriptInterface.getScriptEnv();
982 env->setScriptId(info.playerOnWrapItem, &scriptInterface);
983
984 lua_State* L = scriptInterface.getLuaState();
985 scriptInterface.pushFunction(info.playerOnWrapItem);
986
987 LuaScriptInterface::pushUserdata<Player>(L, player);
988 LuaScriptInterface::setMetatable(L, -1, "Player");
989
990 LuaScriptInterface::pushUserdata<Item>(L, item);
991 LuaScriptInterface::setItemMetatable(L, -1, item);
992
993 scriptInterface.callVoidFunction(2);
994}
995
996void Events::eventMonsterOnDropLoot(Monster* monster, Container* corpse)
997{
998 // Monster:onDropLoot(corpse)
999 if (info.monsterOnDropLoot == -1) {
1000 return;
1001 }
1002
1003 if (!scriptInterface.reserveScriptEnv()) {
1004 std::cout << "[Error - Events::eventMonsterOnDropLoot] Call stack overflow" << std::endl;
1005 return;
1006 }
1007
1008 ScriptEnvironment* env = scriptInterface.getScriptEnv();
1009 env->setScriptId(info.monsterOnDropLoot, &scriptInterface);
1010
1011 lua_State* L = scriptInterface.getLuaState();
1012 scriptInterface.pushFunction(info.monsterOnDropLoot);
1013
1014 LuaScriptInterface::pushUserdata<Monster>(L, monster);
1015 LuaScriptInterface::setMetatable(L, -1, "Monster");
1016
1017 LuaScriptInterface::pushUserdata<Container>(L, corpse);
1018 LuaScriptInterface::setMetatable(L, -1, "Container");
1019
1020 return scriptInterface.callVoidFunction(2);
1021}
1022
1023
Top