1 #include "lua_hooks.h"
2 #include "special_owners.h"
3 #include "mrt/logger.h"
4 #include "mrt/random.h"
5 #include "object.h"
6 #include "world.h"
7 #include "resource_manager.h"
8 #include "game_monitor.h"
9 #include "player_manager.h"
10 #include "player_slot.h"
11 #include "tmx/map.h"
12 #include "sound/mixer.h"
13 #include "game.h"
14 #include <assert.h>
15 #include <stdexcept>
16 #include "var.h"
17 #include "config.h"
18 #include "clunk/object.h"
19
20 #define LUA_TRY try
21 #define LUA_CATCH(where) catch(const std::exception &e) {\
22 lua_pushstring(L, e.what());\
23 lua_error(L);\
24 return 0;\
25 } catch(...) {\
26 lua_pushstring(L, "unknown exception");\
27 lua_error(L);\
28 return 0;\
29 }
30
31 static std::string next_map;
32
getNextMap()33 const std::string & LuaHooks::getNextMap() { return next_map; }
resetNextMap()34 void LuaHooks::resetNextMap() { next_map.clear(); }
35
36
lua_hooks_print(lua_State * L)37 static int lua_hooks_print(lua_State *L) {
38 LUA_TRY {
39 int n = lua_gettop(L);
40 std::string str;
41 for (int i = 1; i <= n; i++) {
42 const char *v = lua_tostring(L, i);
43 str += v?v: "(nil)";
44 str += '\t';
45 }
46 LOG_DEBUG(("[lua] %s", str.c_str()));
47
48 return 0;
49 } LUA_CATCH("lua_hooks_print")
50 }
51
52
lua_hooks_spawn_random(lua_State * L)53 static int lua_hooks_spawn_random(lua_State *L) {
54 LUA_TRY {
55 int args = lua_gettop(L);
56 if (args < 2) {
57 lua_pushstring(L, "spawn_random requires object and animation");
58 lua_error(L);
59 return 0;
60 }
61 const char *object = lua_tostring(L, 1), *animation = lua_tostring(L, 2);
62 if (object == NULL)
63 throw_ex(("object argument could not be converted to string"));
64 if (animation == NULL)
65 throw_ex(("animation argument could not be converted to string"));
66 Object *obj = ResourceManager->createObject(object, animation);
67
68 //Matrix<int> matrix;
69 //World->get_impassability_matrix(matrix, obj, NULL);
70 const Matrix<int> &matrix = Map->get_impassability_matrix(0);
71
72 const v2<int> tile_size = Map->getPathTileSize();
73 if (obj->size.is0())
74 throw_ex(("object size must not be 0,0"));
75
76 v2<int> obj_size = ((obj->size.convert<int>() - 1) / tile_size) + 1;
77 LOG_DEBUG(("searching random %dx%d spot", obj_size.x, obj_size.y));
78
79 int w = matrix.get_width(), h = matrix.get_height();
80 std::vector<v2<int> > spots;
81 for(int y = 0; y < h - obj_size.y + 1; ++y)
82 for(int x= 0; x < w - obj_size.x + 1; ++x) {
83 for(int yy = 0; yy < obj_size.y; ++yy)
84 for(int xx = 0; xx < obj_size.x; ++xx) {
85 int im = matrix.get(y + yy, x + xx);
86 if (im < 0 || im >= 100)
87 goto skip;
88
89 }
90 spots.push_back(v2<int>(x, y));
91 skip: ;
92 }
93
94 size_t n = spots.size();
95 if (n == 0)
96 throw_ex(("no spots found"));
97
98 int idx = mrt::random(n);
99 LOG_DEBUG(("found %u spots. get #%d", (unsigned)n, idx));
100 v2<float> pos = (spots[idx] * tile_size).convert<float>();
101
102 //LOG_DEBUG(("map : %s", matrix.dump().c_str()));
103 obj_size = tile_size * obj_size / 2;
104 World->addObject(obj, pos + obj_size.convert<float>() - obj->size / 2);
105
106 lua_pushinteger(L, obj->get_id());
107 return 1;
108 } LUA_CATCH("lua_hooks_spawn_random")
109 }
110
lua_hooks_map_size(lua_State * L)111 static int lua_hooks_map_size(lua_State *L) {
112 LUA_TRY {
113 v2<int> map_size = Map->get_size();
114 lua_pushinteger(L, map_size.x);
115 lua_pushinteger(L, map_size.y);
116 return 2;
117 } LUA_CATCH("lua_hooks_map_size")
118 }
119
lua_hooks_load_map(lua_State * L)120 static int lua_hooks_load_map(lua_State *L) {
121 LUA_TRY {
122 int n = lua_gettop(L);
123 if (n < 1) {
124 lua_pushstring(L, "load_map requires map name");
125 lua_error(L);
126 return 0;
127 }
128 const char * name = lua_tostring(L, 1);
129 if (name == NULL)
130 throw_ex(("load_map's 1st argument is not a string"));
131 next_map = name;
132 return 0;
133 } LUA_CATCH("lua_hooks_load_map")
134 }
135
136
lua_hooks_object_exists(lua_State * L)137 static int lua_hooks_object_exists(lua_State *L) {
138 LUA_TRY {
139 int n = lua_gettop(L);
140 if (n < 1) {
141 lua_pushstring(L, "object_exists requires object id");
142 lua_error(L);
143 return 0;
144 }
145 int id = lua_tointeger(L, 1);
146 const Object *o = World->getObjectByID(id);
147
148 bool strict = (n >= 2)? lua_toboolean(L, 2) != 0: false;
149
150 bool exists = o?!o->is_dead():false;
151 if (exists && !strict && o->get_state() == "broken")
152 exists = false;
153
154 lua_pushboolean(L, exists?1:0);
155 return 1;
156 } LUA_CATCH("lua_hooks_object_exists")
157 }
158
lua_hooks_object_property(lua_State * L)159 static int lua_hooks_object_property(lua_State *L) {
160 LUA_TRY {
161 int n = lua_gettop(L);
162 if (n < 2) {
163 lua_pushstring(L, "object_property requires object id and property name");
164 lua_error(L);
165 return 0;
166 }
167 int id = lua_tointeger(L, 1);
168 const Object *o = World->getObjectByID(id);
169 if (o == NULL) {
170 lua_pushnil(L);
171 return 1;
172 }
173 const char *cprop = lua_tostring(L, 2);
174 if (cprop == NULL)
175 throw_ex(("property argument could not be converted to string"));
176
177 std::string prop = cprop;
178 if (prop == "classname") {
179 lua_pushstring(L, o->classname.c_str());
180 return 1;
181 } else if (prop == "registered_name") {
182 lua_pushstring(L, o->registered_name.c_str());
183 return 1;
184 } else if (prop == "animation") {
185 lua_pushstring(L, o->animation.c_str());
186 return 1;
187 } else if (prop == "hp") {
188 lua_pushinteger(L, o->hp);
189 return 1;
190 }
191
192 lua_pushstring(L, mrt::format_string("object_property: unknown property %s", prop.c_str()).c_str());
193 lua_error(L);
194 return 0;
195
196 } LUA_CATCH("lua_hooks_object_property")
197 }
198
lua_hooks_set_object_property(lua_State * L)199 static int lua_hooks_set_object_property(lua_State *L) {
200 LUA_TRY {
201 int n = lua_gettop(L);
202 if (n < 3) {
203 lua_pushstring(L, "object_property requires object id, property name and value");
204 lua_error(L);
205 return 0;
206 }
207 int id = lua_tointeger(L, 1);
208 Object *o = World->getObjectByID(id);
209 if (o == NULL) {
210 return 0;
211 }
212 const char *cprop = lua_tostring(L, 2);
213 if (cprop == NULL)
214 throw_ex(("property argument could not be converted to string"));
215
216 std::string prop = cprop;
217 if (prop == "animation") {
218 const char *value = lua_tostring(L, 3);
219 if (value == NULL)
220 throw_ex(("property value for '%s' could not be converted to string", cprop));
221
222 o->init(value);
223 return 0;
224 }
225
226 lua_pushstring(L, mrt::format_string("set_object_property: unknown property %s", prop.c_str()).c_str());
227 lua_error(L);
228 return 0;
229
230 } LUA_CATCH("lua_hooks_set_object_property")
231 }
232
lua_hooks_set_slot_property(lua_State * L)233 static int lua_hooks_set_slot_property(lua_State *L) {
234 LUA_TRY {
235 int n = lua_gettop(L);
236 if (n < 3) {
237 lua_pushstring(L, "set_slot_property requires object id, property name and property value");
238 lua_error(L);
239 return 0;
240 }
241 int id = lua_tointeger(L, 1);
242 if (id < 1)
243 throw_ex(("slot #%d is invalid", id));
244 PlayerSlot &slot = PlayerManager->get_slot(id - 1);
245
246 const char *cprop = lua_tostring(L, 2);
247 if (cprop == NULL)
248 throw_ex(("property argument could not be converted to string"));
249
250 std::string prop = cprop;
251
252 if (prop == "classname") {
253 const char *value = lua_tostring(L, 3);
254 if (value == NULL)
255 throw_ex(("`value' argument could not be converted to string"));
256
257 slot.classname = value;
258 return 0;
259 } else if (prop == "animation") {
260 const char *value = lua_tostring(L, 3);
261 if (value == NULL)
262 throw_ex(("`value' argument could not be converted to string"));
263
264 slot.animation = value;
265 return 0;
266 } else if (prop == "spawn_limit") {
267 slot.spawn_limit = lua_tointeger(L, 3);
268 return 0;
269 }
270
271 lua_pushstring(L, mrt::format_string("slot_property: unknown property %s", prop.c_str()).c_str());
272 lua_error(L);
273 return 0;
274
275 } LUA_CATCH("slot_property")
276 }
277
lua_hooks_display_hint(lua_State * L)278 static int lua_hooks_display_hint(lua_State *L) {
279 LUA_TRY {
280 int n = lua_gettop(L);
281 if (n < 3) {
282 lua_pushstring(L, "display_hint requires slot_id, area and message-id");
283 lua_error(L);
284 return 0;
285 }
286 int id = lua_tointeger(L, 1);
287 if (id < 1)
288 throw_ex(("slot #%d is invalid", id));
289 PlayerSlot &slot = PlayerManager->get_slot(id - 1);
290
291 const char *area = lua_tostring(L, 2);
292 if (area == NULL)
293 throw_ex(("area argument could not be converted to string"));
294
295 const char *message = lua_tostring(L, 3);
296 if (message == NULL)
297 throw_ex(("message-id argument could not be converted to string"));
298
299 slot.displayTooltip(area, message);
300
301 return 0;
302 } LUA_CATCH("display_hint")
303 }
304
lua_hooks_remove_hints(lua_State * L)305 static int lua_hooks_remove_hints(lua_State *L) {
306 LUA_TRY {
307 int n = lua_gettop(L);
308 if (n < 1) {
309 lua_pushstring(L, "remove_hints requires slot_id");
310 lua_error(L);
311 return 0;
312 }
313 int id = lua_tointeger(L, 1);
314 if (id < 1)
315 throw_ex(("slot #%d is invalid", id));
316 PlayerSlot &slot = PlayerManager->get_slot(id - 1);
317 slot.removeTooltips();
318
319 return 0;
320 } LUA_CATCH("remove_hints")
321 }
322
lua_hooks_slot_property(lua_State * L)323 static int lua_hooks_slot_property(lua_State *L) {
324 LUA_TRY {
325 int n = lua_gettop(L);
326 if (n < 2) {
327 lua_pushstring(L, "slot_property requires object id and property name");
328 lua_error(L);
329 return 0;
330 }
331 int id = lua_tointeger(L, 1);
332 if (id < 1)
333 throw_ex(("slot #%d is invalid", id));
334 PlayerSlot &slot = PlayerManager->get_slot(id - 1);
335
336 const char *cprop = lua_tostring(L, 2);
337 if (cprop == NULL)
338 throw_ex(("name could not be converted to string"));
339
340 const std::string prop = cprop;
341 if (prop == "classname") {
342 lua_pushstring(L, slot.classname.c_str());
343 return 1;
344 } else if (prop == "animation") {
345 lua_pushstring(L, slot.animation.c_str());
346 return 1;
347 } else if (prop == "spawn_limit") {
348 lua_pushinteger(L, slot.spawn_limit);
349 return 1;
350 } else if (prop == "id") {
351 lua_pushinteger(L, slot.id);
352 return 1;
353 }
354
355 lua_pushstring(L, mrt::format_string("object_property: unknown property %s", prop.c_str()).c_str());
356 lua_error(L);
357 return 0;
358
359 } LUA_CATCH("slot_property")
360 }
361
lua_hooks_kill_object(lua_State * L)362 static int lua_hooks_kill_object(lua_State *L) {
363 LUA_TRY {
364 int n = lua_gettop(L);
365 if (n < 1) {
366 lua_pushstring(L, "kill object requres object id as first argument");
367 lua_error(L);
368 return 0;
369 }
370 int id = lua_tointeger(L, 1);
371 bool system = (n >= 2)? lua_toboolean(L, 2) != 0: false;
372
373 Object *o = World->getObjectByID(id);
374 if (o == NULL)
375 return 0;
376
377 if (system) {
378 o->Object::emit("death", NULL);
379 } else {
380 o->emit("death", NULL);
381 }
382 return 0;
383 } LUA_CATCH("kill_object")
384 }
385
386
lua_hooks_show_item(lua_State * L)387 static int lua_hooks_show_item(lua_State *L) {
388 LUA_TRY {
389 int n = lua_gettop(L);
390 if (n < 1) {
391 lua_pushstring(L, "show_item requires item's property as first argument");
392 lua_error(L);
393 return 0;
394 }
395 const char *prop = lua_tostring(L, 1);
396 if (prop == NULL) {
397 lua_pushstring(L, "show_item's first argument must be string");
398 lua_error(L);
399 return 0;
400 }
401 GameItem &item = GameMonitor->find(prop);
402 if (item.hidden || World->getObjectByID(item.id) == NULL)
403 item.respawn();
404
405 lua_pushinteger(L, item.id);
406 return 1;
407 } LUA_CATCH("show_item")
408 }
409
lua_hooks_kill_item(lua_State * L)410 static int lua_hooks_kill_item(lua_State *L) {
411 LUA_TRY {
412 int n = lua_gettop(L);
413 if (n < 1) {
414 lua_pushstring(L, "kill_item requires item's property as first argument");
415 lua_error(L);
416 return 0;
417 }
418 const char *prop = lua_tostring(L, 1);
419 if (prop == NULL) {
420 lua_pushstring(L, "kill_item's first argument must be string");
421 lua_error(L);
422 return 0;
423 }
424 GameItem &item = GameMonitor->find(prop);
425 Object *o = World->getObjectByID(item.id);
426 if (o != NULL && !o->is_dead())
427 o->emit("death", NULL);
428 return 0;
429 } LUA_CATCH("kill_item")
430 }
431
lua_hooks_play_tune(lua_State * L)432 static int lua_hooks_play_tune(lua_State *L) {
433 LUA_TRY {
434 int n = lua_gettop(L);
435 if (n < 1) {
436 lua_pushstring(L, "play_tune requre tune name");
437 lua_error(L);
438 return 0;
439 }
440 const char *name = lua_tostring(L, 1);
441 if (name == NULL) {
442 lua_pushstring(L, "tune name must be string");
443 lua_error(L);
444 return 0;
445 }
446 bool loop = true;
447 if (n >= 2) {
448 loop = lua_toboolean(L, 2) != 0;
449 }
450
451 Mixer->play(name, loop);
452 return 0;
453 } LUA_CATCH("play_tune")
454 }
455
lua_hooks_reset_tune(lua_State * L)456 static int lua_hooks_reset_tune(lua_State *L) {
457 LUA_TRY {
458 Mixer->reset();
459 return 0;
460 } LUA_CATCH("reset_tune")
461 }
462
lua_hooks_hide_item(lua_State * L)463 static int lua_hooks_hide_item(lua_State *L) {
464 LUA_TRY {
465 int n = lua_gettop(L);
466 if (n < 1) {
467 lua_pushstring(L, "hide_item requires item's property as first argument");
468 lua_error(L);
469 return 0;
470 }
471 const char *prop = lua_tostring(L, 1);
472 if (prop == NULL) {
473 lua_pushstring(L, "hide_item's first argument must be string");
474 lua_error(L);
475 return 0;
476 }
477 GameItem &item = GameMonitor->find(prop);
478 item.hidden = true;
479 item.kill();
480
481 return 0;
482 } LUA_CATCH("hide_item")
483 }
484
lua_hooks_item_exists(lua_State * L)485 static int lua_hooks_item_exists(lua_State *L) {
486 LUA_TRY {
487 int n = lua_gettop(L);
488 if (n < 1) {
489 lua_pushstring(L, "item_exists requires item's property as first argument");
490 lua_error(L);
491 return 0;
492 }
493 const char *prop = lua_tostring(L, 1);
494 if (prop == NULL) {
495 lua_pushstring(L, "item_exists' first argument must be string");
496 lua_error(L);
497 return 0;
498 }
499 bool strict = (n >= 2)? lua_toboolean(L, 2) != 0: false;
500
501 GameItem &item = GameMonitor->find(prop);
502 const Object *o = World->getObjectByID(item.id);
503
504 bool exists = o?!o->is_dead():false;
505 if (exists && !strict && o->get_state() == "broken")
506 exists = false;
507
508 lua_pushboolean(L, exists?1:0);
509 return 1;
510 } LUA_CATCH("item_exists")
511 }
512
513
lua_hooks_spawn(lua_State * L)514 static int lua_hooks_spawn(lua_State *L) {
515 LUA_TRY {
516 int n = lua_gettop(L);
517 if (n < 4) {
518 lua_pushstring(L, "spawn() requires at least 4 arguments: classname, animation, x, y");
519 lua_error(L);
520 return 0;
521 }
522 const char *classname = lua_tostring(L, 1);
523 if (classname == NULL) {
524 lua_pushstring(L, "spawn: first argument must be string");
525 lua_error(L);
526 return 0;
527 }
528 const char *animation = lua_tostring(L, 2);
529 if (animation == NULL) {
530 lua_pushstring(L, "spawn: first argument must be string");
531 lua_error(L);
532 return 0;
533 }
534
535 int x = lua_tointeger(L, 3);
536 int y = lua_tointeger(L, 4);
537
538 Object *o = ResourceManager->createObject(classname, animation);
539 // if (z)
540 // o->set_z(z, true);
541 o->add_owner(OWNER_MAP);
542
543 // if (dir)
544 // o->set_direction(dir);
545
546 World->addObject(o, v2<float>(x, y) - o->size / 2);
547 lua_pushinteger(L, o->get_id());
548 return 1;
549 } LUA_CATCH("spawn")
550 }
551
lua_hooks_game_over(lua_State * L)552 static int lua_hooks_game_over(lua_State *L) {
553 LUA_TRY {
554 int n = lua_gettop(L);
555 if (n < 4) {
556 lua_pushstring(L, "game_over() requires at least 4 arguments: area, message, time and win");
557 lua_error(L);
558 return 0;
559 }
560
561 const char *area = lua_tostring(L, 1);
562 if (area == NULL) {
563 lua_pushstring(L, "game_over: first argument must be string");
564 lua_error(L);
565 return 0;
566 }
567
568 const char *message = lua_tostring(L, 2);
569 if (message == NULL) {
570 lua_pushstring(L, "game_over: second argument must be string");
571 lua_error(L);
572 return 0;
573 }
574 lua_Number time = lua_tonumber(L, 3);
575 bool win = lua_toboolean(L, 4) != 0;
576 GameMonitor->game_over(area, message, (float)time, win);
577 } LUA_CATCH("game_over")
578 return 0;
579 }
580
lua_hooks_set_timer(lua_State * L)581 static int lua_hooks_set_timer(lua_State *L) {
582 LUA_TRY {
583 int n = lua_gettop(L);
584 if (n < 4) {
585 lua_pushstring(L, "set_timer: requires at least 4 arguments: area, message, time and win");
586 lua_error(L);
587 return 0;
588 }
589
590 const char *area = lua_tostring(L, 1);
591 if (area == NULL) {
592 lua_pushstring(L, "set_timer: first argument must be string");
593 lua_error(L);
594 return 0;
595 }
596
597 const char *message = lua_tostring(L, 2);
598 if (message == NULL) {
599 lua_pushstring(L, "set_timer: second argument must be string");
600 lua_error(L);
601 return 0;
602 }
603
604 lua_Number time = lua_tonumber(L, 3);
605 bool win = lua_toboolean(L, 4) != 0;
606 GameMonitor->setTimer(area, message, (float)time, win);
607 } LUA_CATCH("set_timer")
608 return 0;
609 }
610
lua_hooks_reset_timer(lua_State * L)611 static int lua_hooks_reset_timer(lua_State *L) {
612 LUA_TRY {
613 GameMonitor->resetTimer();
614 } LUA_CATCH("reset_timer")
615 return 0;
616 }
617
618
lua_hooks_display_message(lua_State * L)619 static int lua_hooks_display_message(lua_State *L) {
620 LUA_TRY {
621 int n = lua_gettop(L);
622 if (n < 4) {
623 lua_pushstring(L, "display_message: requires at least 4 arguments: area, message, time and global");
624 lua_error(L);
625 return 0;
626 }
627
628 const char *area = lua_tostring(L, 1);
629 if (area == NULL) {
630 lua_pushstring(L, "display_message: first argument must be string");
631 lua_error(L);
632 return 0;
633 }
634
635 const char *message = lua_tostring(L, 2);
636 if (message == NULL) {
637 lua_pushstring(L, "display_message: second argument must be string");
638 lua_error(L);
639 return 0;
640 }
641 lua_Number time = lua_tonumber(L, 3);
642 bool global = lua_toboolean(L, 4) != 0;
643 GameMonitor->displayMessage(area, message, (float)time, global);
644 } LUA_CATCH("display_message")
645 return 0;
646 }
647
lua_hooks_hide_message(lua_State * L)648 static int lua_hooks_hide_message(lua_State *L) {
649 LUA_TRY {
650 GameMonitor->hideMessage();
651 } LUA_CATCH("hide_message")
652 return 0;
653 }
654
lua_hooks_damage_map(lua_State * L)655 static int lua_hooks_damage_map(lua_State *L) {
656 LUA_TRY {
657 int n = lua_gettop(L);
658 if (n < 3) {
659 lua_pushstring(L, "damage map: requires at least 3 arguments: x, y and hp");
660 lua_error(L);
661 return 0;
662 }
663 float x = (float)lua_tonumber(L, 1);
664 float y = (float)lua_tonumber(L, 2);
665 int hp = lua_tointeger(L, 3);
666 float r = 0;
667 if (n > 3)
668 r = (float)lua_tonumber(L, 4);
669
670 if (r > 0)
671 Map->damage(v2<float>(x, y), hp, r);
672 else
673 Map->damage(v2<float>(x, y), hp);
674 } LUA_CATCH("damage_map")
675 return 0;
676 }
677
lua_hooks_enable_ai(lua_State * L)678 static int lua_hooks_enable_ai(lua_State *L) {
679 LUA_TRY {
680 int n = lua_gettop(L);
681 if (n < 1) {
682 lua_pushstring(L, "enable_ai: requires classname");
683 lua_error(L);
684 return 0;
685 }
686 const char *classname = lua_tostring(L, 1);
687 if (classname == NULL) {
688 lua_pushstring(L, "enable_ai: first argument must be string");
689 lua_error(L);
690 return 0;
691 }
692 GameMonitor->disable(classname, false);
693 } LUA_CATCH("enable_ai")
694 return 0;
695 }
696
lua_hooks_disable_ai(lua_State * L)697 static int lua_hooks_disable_ai(lua_State *L) {
698 LUA_TRY {
699 int n = lua_gettop(L);
700 if (n < 1) {
701 lua_pushstring(L, "disable_ai: requires classname");
702 lua_error(L);
703 return 0;
704 }
705 const char *classname = lua_tostring(L, 1);
706 if (classname == NULL) {
707 lua_pushstring(L, "disable_ai: first argument must be string");
708 lua_error(L);
709 return 0;
710 }
711 GameMonitor->disable(classname, true);
712 } LUA_CATCH("disable_ai")
713 return 0;
714 }
715
lua_hooks_visual_effect(lua_State * L)716 static int lua_hooks_visual_effect(lua_State *L) {
717 LUA_TRY {
718 int n = lua_gettop(L);
719 if (n < 2) {
720 lua_pushstring(L, "visual_effect: requires name and duration");
721 lua_error(L);
722 return 0;
723 }
724 const char *name = lua_tostring(L, 1);
725 if (name == NULL) {
726 lua_pushstring(L, "visual_effect: first argument must be a string");
727 lua_error(L);
728 return 0;
729 }
730 float d = (float)lua_tonumber(L, 2);
731 std::string effect = name;
732
733 if (effect == "shaking") {
734 int i = (n >= 3)?lua_tointeger(L, 3) : 4;
735
736 Game->shake(d, i);
737 } else throw_ex(("unknown visual effect name: %s", name));
738 } LUA_CATCH("visual_effect")
739 return 0;
740 }
741
lua_hooks_add_effect(lua_State * L)742 static int lua_hooks_add_effect(lua_State *L) {
743 LUA_TRY {
744 int n = lua_gettop(L);
745 if (n < 3) {
746 lua_pushstring(L, "add_effect requires object id, effect name and duration");
747 lua_error(L);
748 return 0;
749 }
750
751 int id = lua_tointeger(L, 1);
752 Object *o = World->getObjectByID(id);
753
754 if (o == NULL) {
755 return 0;
756 }
757
758 const char * effect = lua_tostring(L, 2);
759 if (effect == NULL)
760 throw_ex(("effect name could not be converted to string"));
761 float duration = lua_tonumber(L, 3);
762 LOG_DEBUG(("adding effect %s for %g seconds", effect, duration));
763
764 o->add_effect(effect, duration);
765 return 0;
766 } LUA_CATCH("add_effect")
767 }
768
lua_hooks_remove_effect(lua_State * L)769 static int lua_hooks_remove_effect(lua_State *L) {
770 LUA_TRY {
771 int n = lua_gettop(L);
772 if (n < 2) {
773 lua_pushstring(L, "add_effect requires object id and effect name.");
774 lua_error(L);
775 return 0;
776 }
777
778 int id = lua_tointeger(L, 1);
779 Object *o = World->getObjectByID(id);
780
781 if (o == NULL) {
782 return 0;
783 }
784
785 const char * effect = lua_tostring(L, 2);
786 if (effect == NULL)
787 throw_ex(("effect name could not be converted to string"));
788
789 o->remove_effect(effect);
790 return 0;
791 } LUA_CATCH("remove_effect")
792 }
793
lua_hooks_add_waypoint_object(lua_State * L)794 static int lua_hooks_add_waypoint_object(lua_State *L) {
795 LUA_TRY {
796 int n = lua_gettop(L);
797 if (n < 2) {
798 lua_pushstring(L, "set_waypoint requires source object id and destination object id");
799 lua_error(L);
800 return 0;
801 }
802
803 int src_id = lua_tointeger(L, 1);
804 int dst_id = lua_tointeger(L, 2);
805 Object *src = World->getObjectByID(src_id);
806 const Object *dst = World->getObjectByID(dst_id);
807 if (src == NULL || dst == NULL) {
808 if (src == NULL)
809 LOG_ERROR(("object %d does not exists", src_id));
810 if (dst == NULL)
811 LOG_ERROR(("object %d does not exists", dst_id));
812 return 0;
813 }
814
815 v2<int> dst_pos;
816 dst->get_center_position(dst_pos);
817
818 Way way;
819 way.push_back(dst_pos);
820
821 src->set_way(way);
822 return 0;
823 } LUA_CATCH("add_waypoint_object")
824 }
825
lua_hooks_add_waypoints(lua_State * L)826 static int lua_hooks_add_waypoints(lua_State *L) {
827 LUA_TRY {
828 int n = lua_gettop(L);
829 if (n < 2 || !lua_istable(L, 2)) {
830 lua_pushstring(L, "add_waypoints requires object id and array");
831 lua_error(L);
832 return 0;
833 }
834 int id = lua_tointeger(L, 1);
835 Object *o = World->getObjectByID(id);
836 if (o == NULL)
837 return 0;
838
839 Way way;
840
841 lua_pushnil(L); /* first key */
842 while (lua_next(L, 2) != 0) {
843 int idx = lua_gettop(L);
844
845 lua_pushnil(L);
846 std::vector<int> pos;
847 while(lua_next(L, idx)) {
848 pos.push_back(lua_tointeger(L, -1));
849 lua_pop(L, 1);
850 }
851
852 //LOG_DEBUG(("pos.size = %u", (unsigned)pos.size()));
853 if (pos.size() < 2)
854 throw_ex(("invalid waypoint on position %u", (unsigned)way.size()));
855
856 way.push_back(v2<int>(pos[0], pos[1]));
857 lua_pop(L, 1); /* removes `value'; keeps `key' for next iteration */
858 }
859
860 o->set_way(way);
861
862 return 0;
863 } LUA_CATCH("add_waypoints")
864 }
865
866
lua_hooks_has_waypoints(lua_State * L)867 static int lua_hooks_has_waypoints(lua_State *L) {
868 LUA_TRY {
869 int n = lua_gettop(L);
870 if (n < 1) {
871 lua_pushstring(L, "has_waypoints requires object id");
872 lua_error(L);
873 return 0;
874 }
875 int id = lua_tointeger(L, 1);
876 Object *o = World->getObjectByID(id);
877 lua_pushboolean(L, o != NULL && o->is_driven()? 1:0);
878 return 1;
879 } LUA_CATCH("has_waypoints")
880 }
881
lua_hooks_set_config_override(lua_State * L)882 static int lua_hooks_set_config_override(lua_State *L) {
883 LUA_TRY {
884 int n = lua_gettop(L);
885 if (n < 2) {
886 lua_pushstring(L, "set_config_override requires key name and override value");
887 lua_error(L);
888 return 0;
889 }
890 const char * name = lua_tostring(L, 1);
891 const char *value = lua_tostring(L, 2);
892 if (name == NULL || value == NULL) {
893 lua_pushstring(L, mrt::format_string("set_config_override: %s argument must be a string", (name == NULL)?"first":"second").c_str());
894 lua_error(L);
895 return 0;
896 }
897
898 Var var;
899 var.fromString(value);
900 Config->setOverride(name, var);
901 Config->invalidateCachedValues();
902
903 } LUA_CATCH("set_config_override")
904 return 0;
905 }
906
lua_hooks_play_sound(lua_State * L)907 static int lua_hooks_play_sound(lua_State *L) {
908 LUA_TRY {
909 int n = lua_gettop(L);
910 if (n < 2) {
911 lua_pushstring(L, "play_sound requires object_id(0 == listener), sound and optionally loop flag and gain level. ");
912 lua_error(L);
913 return 0;
914 }
915 int object_id = lua_tointeger(L, 1);
916 Object *o = NULL;
917 if (object_id > 0) {
918 o = World->getObjectByID(object_id);
919 if (o == NULL)
920 throw_ex(("object with id %d not found", object_id));
921 }
922
923 const char * name = lua_tostring(L, 2);
924 if (name == NULL) {
925 lua_pushstring(L, "play_sound: second argument(sound name) must be a string");
926 lua_error(L);
927 return 0;
928 }
929
930 bool loop = false;
931 float gain = 1.0f;
932 if (n >= 3)
933 loop = lua_toboolean(L, 3) != 0;
934 if (n >= 4)
935 gain = lua_tonumber(L, 4);
936 Mixer->playSample(o, name, loop, gain);
937
938 } LUA_CATCH("play_sound")
939 return 0;
940 }
941
lua_hooks_stop_sound(lua_State * L)942 static int lua_hooks_stop_sound(lua_State *L) {
943 LUA_TRY {
944 int n = lua_gettop(L);
945 if (n < 1) {
946 lua_pushstring(L, "stop_sound requires object_id(0 == listener) and sound. ");
947 lua_error(L);
948 return 0;
949 }
950 int object_id = lua_tointeger(L, 1);
951 const Object *o = NULL;
952 if (object_id > 0) {
953 o = World->getObjectByID(object_id);
954 if (o == NULL)
955 throw_ex(("object with id %d not found", object_id));
956 }
957
958 const char * name = NULL;
959 if (n >= 2) {
960 name = lua_tostring(L, 2);
961 if (name == NULL) {
962 lua_pushstring(L, "stop_sound: second argument(sound name) must be a string");
963 lua_error(L);
964 return 0;
965 }
966 }
967
968 clunk::Object *co = o->get_clunk_object();
969 if (co == NULL)
970 return 0;
971
972 if (name == NULL)
973 co->cancel_all();
974 else
975 co->cancel(name);
976
977 } LUA_CATCH("stop_sound")
978 return 0;
979 }
980
981
lua_hooks_random(lua_State * L)982 static int lua_hooks_random(lua_State *L) {
983 LUA_TRY {
984 int n = lua_gettop(L);
985 if (n < 1) {
986 lua_pushstring(L, "random requires upper limit value");
987 lua_error(L);
988 return 0;
989 }
990 n = lua_tointeger(L, 1);
991 lua_pushinteger(L, mrt::random(n));
992 return 1;
993 } LUA_CATCH("random")
994 }
995
996
lua_hooks_players_number(lua_State * L)997 static int lua_hooks_players_number(lua_State *L) {
998 int pn = (int)PlayerManager->get_slots_count();
999
1000 int n = lua_gettop(L);
1001 if (n >= 1) {
1002 bool active = lua_toboolean(L, 1) != 0;
1003 if (active)
1004 pn -= PlayerManager->get_free_slots_count();
1005 }
1006
1007 lua_pushinteger(L, pn);
1008 return 1;
1009 }
1010
lua_hooks_set_specials(lua_State * L)1011 static int lua_hooks_set_specials(lua_State *L) {
1012 LUA_TRY {
1013 int n = lua_gettop(L);
1014 if (n < 1 || !lua_istable(L, 1)) {
1015 lua_pushstring(L, "set_specials requires table as first argument");
1016 lua_error(L);
1017 return 0;
1018 }
1019 std::vector<int> specials;
1020 lua_pushnil(L); /* first key */
1021 while (lua_next(L, 1) != 0) {
1022 /* `key' is at index -2 and `value' at index -1 */
1023 //printf("%s - %s\n", lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1)));
1024 int id = lua_tointeger(L, -1);
1025 specials.push_back(id);
1026 lua_pop(L, 1); /* removes `value'; keeps `key' for next iteration */
1027 }
1028 GameMonitor->setSpecials(specials);
1029 return 0;
1030 } LUA_CATCH("lua_random")
1031 }
1032
1033
1034
lua_hooks_play_animation(lua_State * L)1035 static int lua_hooks_play_animation(lua_State *L) {
1036 LUA_TRY {
1037 int n = lua_gettop(L);
1038 if (n < 2) {
1039 lua_pushstring(L, "play_animation requires object id, pose name and optional loop/mode flag");
1040 lua_error(L);
1041 return 0;
1042 }
1043 int id = lua_tointeger(L, 1);
1044 Object *o = World->getObjectByID(id);
1045 if (o == NULL)
1046 return 0;
1047
1048 const char *pose = lua_tostring(L, 2);
1049 if (pose == NULL)
1050 throw_ex(("pose name could not be converted to string"));
1051
1052 if (n > 2) {
1053 bool loop = lua_toboolean(L, 3) != 0;
1054 o->play(pose, loop);
1055 } else {
1056 o->play_now(pose);
1057 }
1058 return 0;
1059 } LUA_CATCH("play_animation")
1060 }
1061
lua_hooks_cancel_animation(lua_State * L)1062 static int lua_hooks_cancel_animation(lua_State *L) {
1063 LUA_TRY {
1064 int n = lua_gettop(L);
1065 if (n < 1) {
1066 lua_pushstring(L, "cancel_animation requires object id, and optional mode(0 - current, 1 - all, 2 - repeatable)");
1067 lua_error(L);
1068 return 0;
1069 }
1070 int id = lua_tointeger(L, 1);
1071 Object *o = World->getObjectByID(id);
1072 if (o == NULL)
1073 return 0;
1074
1075 int mode = n > 1 ? lua_tointeger(L, 2): 0;
1076 switch(mode) {
1077 case 0:
1078 o->cancel();
1079 break;
1080 case 1:
1081 o->cancel_all();
1082 break;
1083 case 2:
1084 o->cancel_repeatable();
1085 break;
1086 default:
1087 throw_ex(("invalid mode %d", mode));
1088 }
1089
1090 return 0;
1091 } LUA_CATCH("cancel_animation")
1092 }
1093
lua_hooks_get_state(lua_State * L)1094 static int lua_hooks_get_state(lua_State *L) {
1095 LUA_TRY {
1096 int n = lua_gettop(L);
1097 if (n < 1) {
1098 lua_pushstring(L, "get_state requires object id");
1099 lua_error(L);
1100 return 0;
1101 }
1102 int id = lua_tointeger(L, 1);
1103
1104 Object *o = World->getObjectByID(id);
1105 lua_pushstring(L, o != NULL? o->get_state().c_str(): "");
1106 return 1;
1107 } LUA_CATCH("get_state")
1108 }
1109
lua_hooks_start_timer(lua_State * L)1110 static int lua_hooks_start_timer(lua_State *L) {
1111 LUA_TRY {
1112 int n = lua_gettop(L);
1113 if (n < 2) {
1114 lua_pushstring(L, "start_timer requires timer-name, period and optional repeat flag (default -> false)");
1115 lua_error(L);
1116 return 0;
1117 }
1118 const char *name = lua_tostring(L, 1);
1119 if (name == NULL) {
1120 lua_pushstring(L, "start_timer: could not convert first argument to string.");
1121 lua_error(L);
1122 return 0;
1123 }
1124 const float period = lua_tonumber(L, 2);
1125 const bool repeat = n >= 3? (lua_toboolean(L, 3) != 0) : false;
1126 GameMonitor->startGameTimer(name, period, repeat);
1127 return 0;
1128 } LUA_CATCH("lua_hooks_start_timer")
1129 }
1130
lua_hooks_stop_timer(lua_State * L)1131 static int lua_hooks_stop_timer(lua_State *L) {
1132 LUA_TRY {
1133 int n = lua_gettop(L);
1134 if (n < 1) {
1135 lua_pushstring(L, "stop_timer requires timer-name");
1136 lua_error(L);
1137 return 0;
1138 }
1139 const char *name = lua_tostring(L, 1);
1140 if (name == NULL) {
1141 lua_pushstring(L, "stop_timer: could not convert first argument to string.");
1142 lua_error(L);
1143 return 0;
1144 }
1145 GameMonitor->stopGameTimer(name);
1146 return 0;
1147 } LUA_CATCH("lua_hooks_stop_timer")
1148 }
1149
lua_hooks_group_add(lua_State * L)1150 static int lua_hooks_group_add(lua_State *L) {
1151 LUA_TRY {
1152 int n = lua_gettop(L);
1153 if (n < 4) {
1154 lua_pushstring(L, "group_add requires object id, group-object-name, classname and animation");
1155 lua_error(L);
1156 return 0;
1157 }
1158 int id = lua_tointeger(L, 1);
1159 Object *o = World->getObjectByID(id);
1160 if (o == NULL)
1161 return 0;
1162
1163 const char *name = lua_tostring(L, 2);
1164 const char *cname = lua_tostring(L, 3);
1165 const char *aname = lua_tostring(L, 4);
1166 if (name == NULL || cname == NULL || aname == NULL)
1167 throw_ex(("name: %s, cname: %s, aname: %s: some argument(s) cannot be converted", name, cname, aname));
1168
1169 Object *child = o->add(name, cname, aname, v2<float>(), Centered);
1170 lua_pushinteger(L, child->get_id());
1171 return 1;
1172 } LUA_CATCH("group_add")
1173 }
1174
lua_hooks_group_has(lua_State * L)1175 static int lua_hooks_group_has(lua_State *L) {
1176 LUA_TRY {
1177 int n = lua_gettop(L);
1178 if (n < 2) {
1179 lua_pushstring(L, "group_has requires object id and group-object-name");
1180 lua_error(L);
1181 return 0;
1182 }
1183
1184 int id = lua_tointeger(L, 1);
1185 Object *o = World->getObjectByID(id);
1186 if (o == NULL) {
1187 lua_pushinteger(L, 0);
1188 return 1;
1189 }
1190
1191 const char *name = lua_tostring(L, 2);
1192 if (name == NULL)
1193 throw_ex(("name cannot be converted to the string"));
1194
1195 lua_pushinteger(L, o->has(name)? o->get(name)->get_id(): 0);
1196 return 1;
1197 } LUA_CATCH("group_has")
1198 }
1199
lua_hooks_group_remove(lua_State * L)1200 static int lua_hooks_group_remove(lua_State *L) {
1201 LUA_TRY {
1202 int n = lua_gettop(L);
1203 if (n < 2) {
1204 lua_pushstring(L, "group_remove requires object id and group-object-name");
1205 lua_error(L);
1206 return 0;
1207 }
1208 int id = lua_tointeger(L, 1);
1209 Object *o = World->getObjectByID(id);
1210 if (o == NULL) {
1211 return 0;
1212 }
1213
1214 const char *name = lua_tostring(L, 2);
1215 if (name == NULL)
1216 throw_ex(("name cannot be converted to the string"));
1217
1218 o->remove(name);
1219 return 0;
1220 } LUA_CATCH("group_remove")
1221 }
1222
1223 #include "campaign.h"
1224
lua_hooks_get_difficulty(lua_State * L)1225 static int lua_hooks_get_difficulty(lua_State *L) {
1226 LUA_TRY {
1227 const Campaign *campaign = GameMonitor->getCampaign();
1228 if (campaign == NULL)
1229 throw_ex(("get_difficulty could be used only from campaign script"));
1230
1231 std::string profile;
1232 Config->get("engine.profile", profile, std::string());
1233
1234 int difficulty;
1235 Config->get("campaign." + profile + "." + campaign->name + ".difficulty", difficulty, 1);
1236 lua_pushinteger(L, difficulty);
1237 return 1;
1238 } LUA_CATCH("get_difficulty");
1239 }
1240
1241 #include "finder.h"
1242
load(const std::string & name)1243 void LuaHooks::load(const std::string &name) {
1244 LOG_DEBUG(("loading lua code from %s...", name.c_str()));
1245
1246 mrt::Chunk data;
1247 Finder->load(data, name, false);
1248 std::string::size_type p = name.find('/');
1249 state.load(p != std::string::npos? name.substr(p + 1): name, data);
1250
1251 //Utility:
1252 lua_register(state, "print", lua_hooks_print);
1253 lua_register(state, "random", lua_hooks_random);
1254
1255 //Game flow / messages / timers
1256 lua_register(state, "game_over", lua_hooks_game_over);
1257 lua_register(state, "display_message", lua_hooks_display_message);
1258 lua_register(state, "hide_message", lua_hooks_hide_message);
1259 lua_register(state, "set_timer", lua_hooks_set_timer);
1260 lua_register(state, "reset_timer", lua_hooks_reset_timer);
1261 lua_register(state, "damage_map", lua_hooks_damage_map);
1262 lua_register(state, "load_map", lua_hooks_load_map);
1263 lua_register(state, "visual_effect", lua_hooks_visual_effect);
1264 lua_register(state, "set_config_override", lua_hooks_set_config_override);
1265 lua_register(state, "map_size", lua_hooks_map_size);
1266 lua_register(state, "set_specials", lua_hooks_set_specials);
1267
1268 //low level timer
1269 lua_register(state, "start_timer", lua_hooks_start_timer);
1270 lua_register(state, "stop_timer", lua_hooks_stop_timer);
1271
1272 //Sound
1273 lua_register(state, "play_sound", lua_hooks_play_sound);
1274 lua_register(state, "stop_sound", lua_hooks_stop_sound);
1275 lua_register(state, "play_tune", lua_hooks_play_tune);
1276 lua_register(state, "reset_tune", lua_hooks_reset_tune);
1277
1278 //Players management
1279 lua_register(state, "players_number", lua_hooks_players_number);
1280 lua_register(state, "set_slot_property", lua_hooks_set_slot_property);
1281 lua_register(state, "slot_property", lua_hooks_slot_property);
1282 lua_register(state, "display_hint", lua_hooks_display_hint);
1283 lua_register(state, "remove_hints", lua_hooks_remove_hints);
1284
1285 //Items management:
1286 lua_register(state, "item_exists", lua_hooks_item_exists);
1287 lua_register(state, "show_item", lua_hooks_show_item);
1288 lua_register(state, "hide_item", lua_hooks_hide_item);
1289 lua_register(state, "kill_item", lua_hooks_kill_item);
1290
1291 //AI related
1292 lua_register(state, "enable_ai", lua_hooks_enable_ai);
1293 lua_register(state, "disable_ai", lua_hooks_disable_ai);
1294 lua_register(state, "add_waypoint_object", lua_hooks_add_waypoint_object);
1295 lua_register(state, "add_waypoints", lua_hooks_add_waypoints);
1296 lua_register(state, "has_waypoints", lua_hooks_has_waypoints);
1297
1298 //Object related functions :
1299 lua_register(state, "spawn", lua_hooks_spawn);
1300 lua_register(state, "spawn_random", lua_hooks_spawn_random);
1301 lua_register(state, "object_exists", lua_hooks_object_exists);
1302 lua_register(state, "object_property", lua_hooks_object_property);
1303 lua_register(state, "set_object_property", lua_hooks_set_object_property);
1304 lua_register(state, "kill_object", lua_hooks_kill_object);
1305 lua_register(state, "add_effect", lua_hooks_add_effect);
1306 lua_register(state, "remove_effect", lua_hooks_remove_effect);
1307 lua_register(state, "play_animation", lua_hooks_play_animation);
1308 lua_register(state, "cancel_animation", lua_hooks_cancel_animation);
1309 lua_register(state, "get_state", lua_hooks_get_state);
1310
1311 //object grouping stuff
1312 lua_register(state, "group_add", lua_hooks_group_add);
1313 lua_register(state, "group_has", lua_hooks_group_has);
1314 lua_register(state, "group_remove", lua_hooks_group_remove);
1315
1316 lua_register(state, "get_difficulty", lua_hooks_get_difficulty);
1317
1318
1319 state.call(0, LUA_MULTRET);
1320
1321 has_on_tick = check_function("on_tick");
1322 has_on_spawn = check_function("on_spawn");
1323 has_on_load = check_function("on_load");
1324 has_on_tooltip = check_function("on_tooltip");
1325 has_on_timer = check_function("on_timer");
1326 }
1327
check_function(const std::string & name)1328 bool LuaHooks::check_function(const std::string &name) {
1329 lua_settop(state, 0);
1330
1331 lua_getglobal(state, name.c_str());
1332 bool r = !(lua_isnoneornil(state, -1));
1333
1334 LOG_DEBUG(("checking for function: %s: %c", name.c_str(), r?'+':'-'));
1335 lua_pop(state, 1);
1336
1337 return r;
1338 }
1339
on_spawn(const std::string & classname,const std::string & animation,const std::string & property)1340 const bool LuaHooks::on_spawn(const std::string &classname, const std::string &animation, const std::string &property) {
1341 if (!has_on_spawn)
1342 return true;
1343
1344 lua_settop(state, 0);
1345
1346 lua_getglobal(state, "on_spawn");
1347 lua_pushstring(state, classname.c_str());
1348 lua_pushstring(state, animation.c_str());
1349 lua_pushstring(state, property.c_str());
1350
1351 state.call(3, 1);
1352 bool r = lua_toboolean(state, 1) != 0;
1353 lua_pop(state, 1);
1354 LOG_DEBUG(("on spawn returns %s", r?"true":"false"));
1355
1356 return r;
1357 }
1358
on_load()1359 void LuaHooks::on_load() {
1360 if (!has_on_load)
1361 return;
1362
1363 lua_settop(state, 0);
1364
1365 LOG_DEBUG(("calling on_load()"));
1366 lua_getglobal(state, "on_load");
1367 state.call(0, 0);
1368 }
1369
1370
on_tick(const float dt)1371 void LuaHooks::on_tick(const float dt) {
1372 if (!has_on_tick)
1373 return;
1374
1375 lua_settop(state, 0);
1376
1377 lua_getglobal(state, "on_tick");
1378 lua_pushnumber(state, dt);
1379
1380 state.call(1, 0);
1381 }
1382
on_tooltip(const std::string & event,const int slot_id,const std::string & area,const std::string & message)1383 void LuaHooks::on_tooltip(const std::string &event, const int slot_id, const std::string & area, const std::string & message) {
1384 if (!has_on_tooltip)
1385 return;
1386
1387 lua_settop(state, 0);
1388
1389 lua_getglobal(state, "on_tooltip");
1390
1391 lua_pushstring(state, event.c_str());
1392 lua_pushinteger(state, slot_id + 1);
1393 lua_pushstring(state, area.c_str());
1394 lua_pushstring(state, message.c_str());
1395
1396 state.call(4, 0);
1397 }
1398
on_timer(const std::string & name)1399 void LuaHooks::on_timer(const std::string &name) {
1400 if (!has_on_timer)
1401 return;
1402
1403 lua_getglobal(state, "on_timer");
1404 lua_pushstring(state, name.c_str());
1405 state.call(1, 0);
1406 }
1407
call(const std::string & method)1408 void LuaHooks::call(const std::string &method) {
1409 LOG_DEBUG(("calling %s()", method.c_str()));
1410 lua_settop(state, 0);
1411
1412 lua_getglobal(state, method.c_str());
1413 state.call(0, 0);
1414 }
1415
call1(const std::string & method,const int id)1416 void LuaHooks::call1(const std::string &method, const int id) {
1417 LOG_DEBUG(("calling %s(%d)", method.c_str(), id));
1418 lua_settop(state, 0);
1419
1420 lua_getglobal(state, method.c_str());
1421 lua_pushinteger(state, id);
1422
1423 state.call(1, 0);
1424 }
1425
clear()1426 void LuaHooks::clear() {
1427 state.clear();
1428 has_on_tick = has_on_spawn = has_on_load = has_on_tooltip = has_on_timer = false;
1429 }
1430
LuaHooks()1431 LuaHooks::LuaHooks() : has_on_tick(false), has_on_spawn(false), has_on_load(false), has_on_tooltip(false), has_on_timer(false) {}
1432