1 /*
2 * Copyright (C) 2006-2019 Christopho, Solarus - http://www.solarus-games.org
3 *
4 * Solarus is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Solarus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include "solarus/core/Debug.h"
18 #include "solarus/core/Equipment.h"
19 #include "solarus/core/EquipmentItem.h"
20 #include "solarus/core/EquipmentItemUsage.h"
21 #include "solarus/core/Game.h"
22 #include "solarus/core/Map.h"
23 #include "solarus/entities/Entities.h"
24 #include "solarus/entities/Hero.h"
25 #include "solarus/entities/Pickable.h"
26 #include "solarus/graphics/Sprite.h"
27 #include "solarus/lua/LuaContext.h"
28 #include "solarus/lua/LuaTools.h"
29 #include "solarus/movements/Movement.h"
30
31 namespace Solarus {
32
33 /**
34 * Name of the Lua table representing the item module.
35 */
36 const std::string LuaContext::item_module_name = "sol.item";
37
38 /**
39 * \brief Initializes the item features provided to Lua.
40 */
register_item_module()41 void LuaContext::register_item_module() {
42
43 const std::vector<luaL_Reg> methods = {
44 { "get_name", item_api_get_name },
45 { "get_game", item_api_get_game },
46 { "get_map", item_api_get_map },
47 { "get_savegame_variable", item_api_get_savegame_variable },
48 { "set_savegame_variable", item_api_set_savegame_variable },
49 { "get_amount_savegame_variable", item_api_get_amount_savegame_variable },
50 { "set_amount_savegame_variable", item_api_set_amount_savegame_variable },
51 { "is_obtainable", item_api_is_obtainable },
52 { "set_obtainable", item_api_set_obtainable },
53 { "is_assignable", item_api_is_assignable },
54 { "set_assignable", item_api_set_assignable },
55 { "is_being_used", item_api_is_being_used },
56 { "get_can_disappear", item_api_get_can_disappear },
57 { "set_can_disappear", item_api_set_can_disappear },
58 { "get_brandish_when_picked", item_api_get_brandish_when_picked },
59 { "set_brandish_when_picked", item_api_set_brandish_when_picked },
60 { "get_shadow", item_api_get_shadow },
61 { "set_shadow", item_api_set_shadow },
62 { "get_sound_when_picked", item_api_get_sound_when_picked },
63 { "set_sound_when_picked", item_api_set_sound_when_picked },
64 { "get_sound_when_brandished", item_api_get_sound_when_brandished },
65 { "set_sound_when_brandished", item_api_set_sound_when_brandished },
66 { "has_variant", item_api_has_variant },
67 { "get_variant", item_api_get_variant },
68 { "set_variant", item_api_set_variant },
69 { "has_amount", item_api_has_amount },
70 { "get_amount", item_api_get_amount },
71 { "set_amount", item_api_set_amount },
72 { "add_amount", item_api_add_amount },
73 { "remove_amount", item_api_remove_amount },
74 { "get_max_amount", item_api_get_max_amount },
75 { "set_max_amount", item_api_set_max_amount },
76 { "set_finished", item_api_set_finished }
77 };
78
79 const std::vector<luaL_Reg> metamethods = {
80 { "__gc", userdata_meta_gc },
81 { "__newindex", userdata_meta_newindex_as_table },
82 { "__index", userdata_meta_index_as_table },
83 };
84
85 register_type(item_module_name, {}, methods, metamethods);
86 }
87
88 /**
89 * \brief Returns whether a value is a userdata of type item.
90 * \param l A Lua context.
91 * \param index An index in the stack.
92 * \return true if the value at this index is an item.
93 */
is_item(lua_State * l,int index)94 bool LuaContext::is_item(lua_State* l, int index) {
95 return is_userdata(l, index, item_module_name);
96 }
97
98 /**
99 * \brief Checks that the userdata at the specified index of the stack is an
100 * equipment item and returns it.
101 * \param l A Lua context.
102 * \param index An index in the stack.
103 * \return The equipment item.
104 */
check_item(lua_State * l,int index)105 std::shared_ptr<EquipmentItem> LuaContext::check_item(lua_State* l, int index) {
106 return std::static_pointer_cast<EquipmentItem>(check_userdata(
107 l, index, item_module_name
108 ));
109 }
110
111 /**
112 * \brief Pushes an equipment item userdata onto the stack.
113 * \param l A Lua context.
114 * \param item An item.
115 */
push_item(lua_State * l,EquipmentItem & item)116 void LuaContext::push_item(lua_State* l, EquipmentItem& item) {
117
118 push_userdata(l, item);
119 }
120
121 /**
122 * \brief Implementation of item:get_name().
123 * \param l The Lua context that is calling this function.
124 * \return Number of values to return to Lua.
125 */
item_api_get_name(lua_State * l)126 int LuaContext::item_api_get_name(lua_State* l) {
127
128 return state_boundary_handle(l, [&] {
129 EquipmentItem& item = *check_item(l, 1);
130
131 push_string(l, item.get_name());
132 return 1;
133 });
134 }
135
136 /**
137 * \brief Implementation of item:get_game().
138 * \param l The Lua context that is calling this function.
139 * \return Number of values to return to Lua.
140 */
item_api_get_game(lua_State * l)141 int LuaContext::item_api_get_game(lua_State* l) {
142
143 return state_boundary_handle(l, [&] {
144 EquipmentItem& item = *check_item(l, 1);
145
146 push_game(l, item.get_savegame());
147 return 1;
148 });
149 }
150
151 /**
152 * \brief Implementation of item:get_map().
153 * \param l The Lua context that is calling this function.
154 * \return Number of values to return to Lua.
155 */
item_api_get_map(lua_State * l)156 int LuaContext::item_api_get_map(lua_State* l) {
157
158 return state_boundary_handle(l, [&] {
159 EquipmentItem& item = *check_item(l, 1);
160
161 Game* game = item.get_game();
162 if (game != nullptr) {
163 push_map(l, game->get_current_map());
164 }
165 else {
166 lua_pushnil(l);
167 }
168 return 1;
169 });
170 }
171
172 /**
173 * \brief Implementation of item:get_savegame_variable().
174 * \param l The Lua context that is calling this function.
175 * \return Number of values to return to Lua.
176 */
item_api_get_savegame_variable(lua_State * l)177 int LuaContext::item_api_get_savegame_variable(lua_State* l) {
178
179 return state_boundary_handle(l, [&] {
180 EquipmentItem& item = *check_item(l, 1);
181
182 const std::string& savegame_variable = item.get_savegame_variable();
183 if (savegame_variable.empty()) {
184 lua_pushnil(l);
185 }
186 else {
187 push_string(l, savegame_variable);
188 }
189 return 1;
190 });
191 }
192
193 /**
194 * \brief Implementation of item:set_savegame_variable().
195 * \param l The Lua context that is calling this function.
196 * \return Number of values to return to Lua.
197 */
item_api_set_savegame_variable(lua_State * l)198 int LuaContext::item_api_set_savegame_variable(lua_State* l) {
199
200 return state_boundary_handle(l, [&] {
201 EquipmentItem& item = *check_item(l, 1);
202 std::string savegame_variable;
203 if (!lua_isnil(l, 2)) {
204 savegame_variable = LuaTools::check_string(l, 2);
205 }
206
207 if (!savegame_variable.empty()
208 && !LuaTools::is_valid_lua_identifier(savegame_variable)) {
209 LuaTools::arg_error(l, 2,
210 std::string("savegame variable identifier expected, got '")
211 + savegame_variable + "'");
212 }
213
214 item.set_savegame_variable(savegame_variable);
215
216 return 0;
217 });
218 }
219
220 /**
221 * \brief Implementation of item:get_amount_savegame_variable().
222 * \param l The Lua context that is calling this function.
223 * \return Number of values to return to Lua.
224 */
item_api_get_amount_savegame_variable(lua_State * l)225 int LuaContext::item_api_get_amount_savegame_variable(lua_State* l) {
226
227 return state_boundary_handle(l, [&] {
228 EquipmentItem& item = *check_item(l, 1);
229
230 const std::string& amount_savegame_variable = item.get_amount_savegame_variable();
231 if (amount_savegame_variable.empty()) {
232 lua_pushnil(l);
233 }
234 else {
235 push_string(l, amount_savegame_variable);
236 }
237 return 1;
238 });
239 }
240
241 /**
242 * \brief Implementation of item:set_amount_savegame_variable().
243 * \param l The Lua context that is calling this function.
244 * \return Number of values to return to Lua.
245 */
item_api_set_amount_savegame_variable(lua_State * l)246 int LuaContext::item_api_set_amount_savegame_variable(lua_State* l) {
247
248 return state_boundary_handle(l, [&] {
249 EquipmentItem& item = *check_item(l, 1);
250 std::string amount_savegame_variable;
251 if (lua_gettop(l) >= 2) {
252 amount_savegame_variable = LuaTools::check_string(l, 2);
253 }
254
255 if (!amount_savegame_variable.empty()
256 && !LuaTools::is_valid_lua_identifier(amount_savegame_variable)) {
257 LuaTools::arg_error(l, 2,
258 std::string("savegame variable identifier expected, got '")
259 + amount_savegame_variable + "'");
260 }
261
262 item.set_amount_savegame_variable(amount_savegame_variable);
263
264 return 0;
265 });
266 }
267
268 /**
269 * \brief Implementation of item:is_obtainable().
270 * \param l The Lua context that is calling this function.
271 * \return Number of values to return to Lua.
272 */
item_api_is_obtainable(lua_State * l)273 int LuaContext::item_api_is_obtainable(lua_State* l) {
274
275 return state_boundary_handle(l, [&] {
276 EquipmentItem& item = *check_item(l, 1);
277
278 lua_pushboolean(l, item.is_obtainable());
279 return 1;
280 });
281 }
282
283 /**
284 * \brief Implementation of item:set_obtainable().
285 * \param l The Lua context that is calling this function.
286 * \return Number of values to return to Lua.
287 */
item_api_set_obtainable(lua_State * l)288 int LuaContext::item_api_set_obtainable(lua_State* l) {
289
290 return state_boundary_handle(l, [&] {
291 EquipmentItem& item = *check_item(l, 1);
292 bool obtainable = LuaTools::opt_boolean(l, 2, true);
293
294 item.set_obtainable(obtainable);
295
296 return 0;
297 });
298 }
299
300 /**
301 * \brief Implementation of item:is_assignable().
302 * \param l The Lua context that is calling this function.
303 * \return Number of values to return to Lua.
304 */
item_api_is_assignable(lua_State * l)305 int LuaContext::item_api_is_assignable(lua_State* l) {
306
307 return state_boundary_handle(l, [&] {
308 EquipmentItem& item = *check_item(l, 1);
309
310 lua_pushboolean(l, item.is_assignable());
311 return 1;
312 });
313 }
314
315 /**
316 * \brief Implementation of item:set_assignable().
317 * \param l The Lua context that is calling this function.
318 * \return Number of values to return to Lua.
319 */
item_api_set_assignable(lua_State * l)320 int LuaContext::item_api_set_assignable(lua_State* l) {
321
322 return state_boundary_handle(l, [&] {
323 EquipmentItem& item = *check_item(l, 1);
324 bool assignable = LuaTools::opt_boolean(l, 2, true);
325
326 item.set_assignable(assignable);
327
328 return 0;
329 });
330 }
331
332 /**
333 * \brief Implementation of item:is_being_used().
334 * \param l The Lua context that is calling this function.
335 * \return Number of values to return to Lua.
336 */
item_api_is_being_used(lua_State * l)337 int LuaContext::item_api_is_being_used(lua_State* l) {
338
339 return state_boundary_handle(l, [&] {
340 const EquipmentItem& item = *check_item(l, 1);
341
342 lua_pushboolean(l, item.is_being_used());
343 return 1;
344 });
345 }
346
347 /**
348 * \brief Implementation of item:get_can_disappear().
349 * \param l The Lua context that is calling this function.
350 * \return Number of values to return to Lua.
351 */
item_api_get_can_disappear(lua_State * l)352 int LuaContext::item_api_get_can_disappear(lua_State* l) {
353
354 return state_boundary_handle(l, [&] {
355 EquipmentItem& item = *check_item(l, 1);
356
357 lua_pushboolean(l, item.get_can_disappear());
358 return 1;
359 });
360 }
361
362 /**
363 * \brief Implementation of item:set_can_disappear().
364 * \param l The Lua context that is calling this function.
365 * \return Number of values to return to Lua.
366 */
item_api_set_can_disappear(lua_State * l)367 int LuaContext::item_api_set_can_disappear(lua_State* l) {
368
369 return state_boundary_handle(l, [&] {
370 EquipmentItem& item = *check_item(l, 1);
371 bool can_disappear = LuaTools::opt_boolean(l, 2, true);
372
373 item.set_can_disappear(can_disappear);
374
375 return 0;
376 });
377 }
378
379 /**
380 * \brief Implementation of item:get_brandish_when_picked().
381 * \param l The Lua context that is calling this function.
382 * \return Number of values to return to Lua.
383 */
item_api_get_brandish_when_picked(lua_State * l)384 int LuaContext::item_api_get_brandish_when_picked(lua_State* l) {
385
386 return state_boundary_handle(l, [&] {
387 EquipmentItem& item = *check_item(l, 1);
388
389 lua_pushboolean(l, item.get_brandish_when_picked());
390 return 1;
391 });
392 }
393
394 /**
395 * \brief Implementation of item:set_brandish_when_picked().
396 * \param l The Lua context that is calling this function.
397 * \return Number of values to return to Lua.
398 */
item_api_set_brandish_when_picked(lua_State * l)399 int LuaContext::item_api_set_brandish_when_picked(lua_State* l) {
400
401 return state_boundary_handle(l, [&] {
402 EquipmentItem& item = *check_item(l, 1);
403 bool brandish_when_picked = LuaTools::opt_boolean(l, 2, true);
404
405 item.set_brandish_when_picked(brandish_when_picked);
406
407 return 0;
408 });
409 }
410
411 /**
412 * \brief Implementation of item:get_shadow().
413 * \param l The Lua context that is calling this function.
414 * \return Number of values to return to Lua.
415 */
item_api_get_shadow(lua_State * l)416 int LuaContext::item_api_get_shadow(lua_State* l) {
417
418 return state_boundary_handle(l, [&] {
419 EquipmentItem& item = *check_item(l, 1);
420
421 const std::string& shadow = item.get_shadow();
422 if (shadow.empty()) {
423 lua_pushnil(l);
424 }
425 else {
426 push_string(l, shadow);
427 }
428 return 1;
429 });
430 }
431
432 /**
433 * \brief Implementation of item:set_shadow().
434 * \param l The Lua context that is calling this function.
435 * \return Number of values to return to Lua.
436 */
item_api_set_shadow(lua_State * l)437 int LuaContext::item_api_set_shadow(lua_State* l) {
438
439 return state_boundary_handle(l, [&] {
440 EquipmentItem& item = *check_item(l, 1);
441 std::string shadow;
442 if (!lua_isnil(l, 2)) {
443 shadow = LuaTools::check_string(l, 2);
444 }
445
446 item.set_shadow(shadow);
447
448 return 0;
449 });
450 }
451
452 /**
453 * \brief Implementation of item:get_sound_when_picked().
454 * \param l The Lua context that is calling this function.
455 * \return Number of values to return to Lua.
456 */
item_api_get_sound_when_picked(lua_State * l)457 int LuaContext::item_api_get_sound_when_picked(lua_State* l) {
458
459 return state_boundary_handle(l, [&] {
460 EquipmentItem& item = *check_item(l, 1);
461
462 const std::string& sound_when_picked = item.get_sound_when_picked();
463 if (sound_when_picked.empty()) {
464 lua_pushnil(l);
465 }
466 else {
467 push_string(l, sound_when_picked);
468 }
469 return 1;
470 });
471 }
472
473 /**
474 * \brief Implementation of item:set_sound_when_picked().
475 * \param l The Lua context that is calling this function.
476 * \return Number of values to return to Lua.
477 */
item_api_set_sound_when_picked(lua_State * l)478 int LuaContext::item_api_set_sound_when_picked(lua_State* l) {
479
480 return state_boundary_handle(l, [&] {
481 EquipmentItem& item = *check_item(l, 1);
482 std::string sound_when_picked;
483 if (!lua_isnil(l, 2)) {
484 sound_when_picked = LuaTools::check_string(l, 2);
485 }
486
487 item.set_sound_when_picked(sound_when_picked);
488
489 return 0;
490 });
491 }
492
493 /**
494 * \brief Implementation of item:get_sound_when_brandished().
495 * \param l The Lua context that is calling this function.
496 * \return Number of values to return to Lua.
497 */
item_api_get_sound_when_brandished(lua_State * l)498 int LuaContext::item_api_get_sound_when_brandished(lua_State* l) {
499
500 return state_boundary_handle(l, [&] {
501 EquipmentItem& item = *check_item(l, 1);
502
503 const std::string& sound_when_brandished = item.get_sound_when_brandished();
504 if (sound_when_brandished.empty()) {
505 lua_pushnil(l);
506 }
507 else {
508 push_string(l, sound_when_brandished);
509 }
510 return 1;
511 });
512 }
513
514 /**
515 * \brief Implementation of item:set_sound_when_brandished().
516 * \param l The Lua context that is calling this function.
517 * \return Number of values to return to Lua.
518 */
item_api_set_sound_when_brandished(lua_State * l)519 int LuaContext::item_api_set_sound_when_brandished(lua_State* l) {
520
521 return state_boundary_handle(l, [&] {
522 EquipmentItem& item = *check_item(l, 1);
523 std::string sound_when_brandished;
524 if (!lua_isnil(l, 2)) {
525 sound_when_brandished = LuaTools::check_string(l, 2);
526 }
527
528 item.set_sound_when_brandished(sound_when_brandished);
529
530 return 0;
531 });
532 }
533
534 /**
535 * \brief Implementation of item:has_variant().
536 * \param l The Lua context that is calling this function.
537 * \return Number of values to return to Lua.
538 */
item_api_has_variant(lua_State * l)539 int LuaContext::item_api_has_variant(lua_State* l) {
540
541 return state_boundary_handle(l, [&] {
542 EquipmentItem& item = *check_item(l, 1);
543 int variant = 1;
544 if (lua_gettop(l) >= 2) {
545 variant = LuaTools::check_int(l, 2);
546 }
547
548 lua_pushboolean(l, item.get_variant() >= variant);
549 return 1;
550 });
551 }
552
553 /**
554 * \brief Implementation of item:get_variant().
555 * \param l The Lua context that is calling this function.
556 * \return Number of values to return to Lua.
557 */
item_api_get_variant(lua_State * l)558 int LuaContext::item_api_get_variant(lua_State* l) {
559
560 return state_boundary_handle(l, [&] {
561 EquipmentItem& item = *check_item(l, 1);
562
563 if (!item.is_saved()) {
564 LuaTools::error(l, std::string("Item '") + item.get_name() + "' is not saved");
565 }
566
567 lua_pushinteger(l, item.get_variant());
568 return 1;
569 });
570 }
571
572 /**
573 * \brief Implementation of item:set_variant().
574 * \param l The Lua context that is calling this function.
575 * \return Number of values to return to Lua.
576 */
item_api_set_variant(lua_State * l)577 int LuaContext::item_api_set_variant(lua_State* l) {
578
579 return state_boundary_handle(l, [&] {
580 EquipmentItem& item = *check_item(l, 1);
581 int variant = LuaTools::check_int(l, 2);
582
583 if (!item.is_saved()) {
584 LuaTools::error(l, std::string("Item '") + item.get_name() + "' is not saved");
585 }
586
587 item.set_variant(variant);
588
589 return 0;
590 });
591 }
592
593 /**
594 * \brief Implementation of item:has_amount().
595 * \param l The Lua context that is calling this function.
596 * \return Number of values to return to Lua.
597 */
item_api_has_amount(lua_State * l)598 int LuaContext::item_api_has_amount(lua_State* l) {
599
600 return state_boundary_handle(l, [&] {
601 EquipmentItem& item = *check_item(l, 1);
602 if (lua_gettop(l) >= 2) {
603 int amount = LuaTools::check_int(l, 2);
604 if (!item.has_amount()) {
605 LuaTools::error(l, std::string("Item '") + item.get_name() + "' has no amount");
606 }
607 lua_pushboolean(l, item.get_amount() >= amount);
608 }
609 else {
610 lua_pushboolean(l, item.has_amount());
611 }
612 return 1;
613 });
614 }
615
616 /**
617 * \brief Implementation of item:get_amount().
618 * \param l The Lua context that is calling this function.
619 * \return Number of values to return to Lua.
620 */
item_api_get_amount(lua_State * l)621 int LuaContext::item_api_get_amount(lua_State* l) {
622
623 return state_boundary_handle(l, [&] {
624 EquipmentItem& item = *check_item(l, 1);
625
626 if (!item.has_amount()) {
627 lua_pushnil(l);
628 }
629 else {
630 lua_pushinteger(l, item.get_amount());
631 }
632 return 1;
633 });
634 }
635
636 /**
637 * \brief Implementation of item:set_amount().
638 * \param l The Lua context that is calling this function.
639 * \return Number of values to return to Lua.
640 */
item_api_set_amount(lua_State * l)641 int LuaContext::item_api_set_amount(lua_State* l) {
642
643 return state_boundary_handle(l, [&] {
644 EquipmentItem& item = *check_item(l, 1);
645 int amount = LuaTools::check_int(l, 2);
646
647 if (!item.has_amount()) {
648 LuaTools::error(l, std::string("Item '") + item.get_name() + "' has no amount");
649 }
650
651 item.set_amount(amount);
652
653 return 0;
654 });
655 }
656
657 /**
658 * \brief Implementation of item:add_amount().
659 * \param l The Lua context that is calling this function.
660 * \return Number of values to return to Lua.
661 */
item_api_add_amount(lua_State * l)662 int LuaContext::item_api_add_amount(lua_State* l) {
663
664 return state_boundary_handle(l, [&] {
665 EquipmentItem& item = *check_item(l, 1);
666 int amount = LuaTools::check_int(l, 2);
667
668 if (!item.has_amount()) {
669 LuaTools::error(l, std::string("Item '") + item.get_name() + "' has no amount");
670 }
671
672 if (amount < 0) {
673 LuaTools::arg_error(l, 2, "Invalid amount value: must be positive or zero");
674 }
675
676 item.set_amount(item.get_amount() + amount);
677
678 return 0;
679 });
680 }
681
682 /**
683 * \brief Implementation of item:remove_amount().
684 * \param l The Lua context that is calling this function.
685 * \return Number of values to return to Lua.
686 */
item_api_remove_amount(lua_State * l)687 int LuaContext::item_api_remove_amount(lua_State* l) {
688
689 return state_boundary_handle(l, [&] {
690 EquipmentItem& item = *check_item(l, 1);
691 int amount = LuaTools::check_int(l, 2);
692
693 if (!item.has_amount()) {
694 LuaTools::error(l, std::string("Item '") + item.get_name() + "' has no amount");
695 }
696
697 if (amount < 0) {
698 LuaTools::arg_error(l, 2, "Invalid amount value: must be positive or zero");
699 }
700
701 item.set_amount(item.get_amount() - amount);
702
703 return 0;
704 });
705 }
706
707 /**
708 * \brief Implementation of item:get_max_amount().
709 * \param l The Lua context that is calling this function.
710 * \return Number of values to return to Lua.
711 */
item_api_get_max_amount(lua_State * l)712 int LuaContext::item_api_get_max_amount(lua_State* l) {
713
714 return state_boundary_handle(l, [&] {
715 EquipmentItem& item = *check_item(l, 1);
716
717 if (!item.has_amount()) {
718 LuaTools::error(l, std::string("Item '") + item.get_name() + "' has no amount");
719 }
720
721 lua_pushinteger(l, item.get_max_amount());
722 return 1;
723 });
724 }
725
726 /**
727 * \brief Implementation of item:set_max_amount().
728 * \param l The Lua context that is calling this function.
729 * \return Number of values to return to Lua.
730 */
item_api_set_max_amount(lua_State * l)731 int LuaContext::item_api_set_max_amount(lua_State* l) {
732
733 return state_boundary_handle(l, [&] {
734 EquipmentItem& item = *check_item(l, 1);
735 int max_amount = LuaTools::check_int(l, 2);
736
737 if (!item.has_amount()) {
738 LuaTools::error(l, std::string("Item '") + item.get_name() + "' has no amount");
739 }
740
741 if (max_amount < 0) {
742 LuaTools::arg_error(l, 2, "Invalid amount value: must be positive or zero");
743 }
744
745 item.set_max_amount(max_amount);
746
747 return 0;
748 });
749 }
750
751 /**
752 * \brief Implementation of item:set_finished().
753 * \param l The Lua context that is calling this function.
754 * \return Number of values to return to Lua.
755 */
item_api_set_finished(lua_State * l)756 int LuaContext::item_api_set_finished(lua_State* l) {
757
758 return state_boundary_handle(l, [&] {
759 EquipmentItem& item = *check_item(l, 1);
760
761 // Retrieve the equipment item from the hero.
762 Hero& hero = *item.get_game()->get_hero();
763 if (hero.is_using_item()) { // Do nothing if the script has already changed the hero's state.
764
765 EquipmentItemUsage& item_usage = hero.get_item_being_used();
766 item_usage.set_finished();
767 }
768
769 return 0;
770 });
771 }
772
773 /**
774 * \brief Calls the on_started() method of a Lua equipment item.
775 *
776 * Does nothing if the method is not defined.
777 *
778 * \param item An equipment item.
779 */
item_on_started(EquipmentItem & item)780 void LuaContext::item_on_started(EquipmentItem& item) {
781
782 if (!userdata_has_field(item, "on_started")) {
783 return;
784 }
785 run_on_main([this,&item](lua_State* l){
786 push_item(l, item);
787 on_started();
788 lua_pop(l, 1);
789 });
790 }
791
792 /**
793 * \brief Calls the on_finished() method of a Lua equipment item.
794 *
795 * Does nothing if the method is not defined.
796 *
797 * \param item An equipment item.
798 */
item_on_finished(EquipmentItem & item)799 void LuaContext::item_on_finished(EquipmentItem& item) {
800 run_on_main([this,&item](lua_State* l){
801 push_item(l, item);
802 if (userdata_has_field(item, "on_finished")) {
803 on_finished();
804 }
805 remove_timers(-1); // Stop timers and menus associated to this item.
806 remove_menus(-1);
807 lua_pop(l, 1);
808 });
809 }
810
811 /**
812 * \brief Calls the on_update() method of a Lua equipment item.
813 *
814 * Does nothing if the method is not defined.
815 *
816 * \param item An equipment item.
817 */
item_on_update(EquipmentItem & item)818 void LuaContext::item_on_update(EquipmentItem& item) {
819
820 // This particular method is tried so often that we want to save optimize
821 // the std::string construction.
822 static const std::string method_name = "on_update";
823 if (!userdata_has_field(item, method_name)) {
824 return;
825 }
826 run_on_main([this,&item](lua_State* l){
827 push_item(l, item);
828 on_update();
829 lua_pop(l, 1);
830 });
831 }
832
833 /**
834 * \brief Calls the on_suspended() method of a Lua equipment item.
835 *
836 * Does nothing if the method is not defined.
837 *
838 * \param item An equipment item.
839 * \param suspended true if the game is suspended.
840 */
item_on_suspended(EquipmentItem & item,bool suspended)841 void LuaContext::item_on_suspended(EquipmentItem& item, bool suspended) {
842
843 if (!userdata_has_field(item, "on_suspended")) {
844 return;
845 }
846 run_on_main([this,&item,suspended](lua_State* l){
847 push_item(l, item);
848 on_suspended(suspended);
849 lua_pop(l, 1);
850 });
851 }
852
853 /**
854 * \brief Calls the on_created() method of a Lua equipment item.
855 *
856 * Does nothing if the method is not defined.
857 *
858 * \param item An equipment item.
859 */
item_on_created(EquipmentItem & item)860 void LuaContext::item_on_created(EquipmentItem& item) {
861
862 if (!userdata_has_field(item, "on_created")) {
863 return;
864 }
865 run_on_main([this,&item](lua_State* l){
866 push_item(l, item);
867 on_created();
868 lua_pop(l, 1);
869 });
870 }
871
872 /**
873 * \brief Calls the on_map_changed() method of a Lua equipment item.
874 *
875 * Does nothing if the method is not defined.
876 *
877 * \param item An equipment item.
878 * \param map A map.
879 */
item_on_map_changed(EquipmentItem & item,Map & map)880 void LuaContext::item_on_map_changed(EquipmentItem& item, Map& map) {
881
882 if (!userdata_has_field(item, "on_map_changed")) {
883 return;
884 }
885 run_on_main([this,&item,&map](lua_State* l){
886 push_item(l, item);
887 on_map_changed(map);
888 lua_pop(l, 1);
889 });
890 }
891
892 /**
893 * \brief Calls the on_pickable_created() method of a Lua equipment item.
894 *
895 * Does nothing if the method is not defined.
896 *
897 * \param item An equipment item.
898 * \param pickable The instance of pickable item that has just appeared.
899 */
item_on_pickable_created(EquipmentItem & item,Pickable & pickable)900 void LuaContext::item_on_pickable_created(EquipmentItem& item,
901 Pickable& pickable) {
902
903 if (!userdata_has_field(item, "on_pickable_created")) {
904 return;
905 }
906
907 run_on_main([this,&item,&pickable](lua_State* l){
908 push_item(l, item);
909 on_pickable_created(pickable);
910 lua_pop(l, 1);
911 });
912 }
913
914 /**
915 * \brief Calls the on_obtaining() method of a Lua equipment item.
916 *
917 * Does nothing if the method is not defined.
918 *
919 * \param item An equipment item.
920 * \param treasure The treasure being obtained.
921 */
item_on_obtaining(EquipmentItem & item,const Treasure & treasure)922 void LuaContext::item_on_obtaining(EquipmentItem& item, const Treasure& treasure) {
923
924 if (!userdata_has_field(item, "on_obtaining")) {
925 return;
926 }
927 run_on_main([this,&item,&treasure](lua_State* l){
928 push_item(l, item);
929 on_obtaining(treasure);
930 lua_pop(l, 1);
931 });
932 }
933
934 /**
935 * \brief Calls the on_obtained() method of a Lua equipment item.
936 *
937 * Does nothing if the method is not defined.
938 *
939 * \param item An equipment item.
940 * \param treasure The treasure just obtained.
941 */
item_on_obtained(EquipmentItem & item,const Treasure & treasure)942 void LuaContext::item_on_obtained(EquipmentItem& item, const Treasure& treasure) {
943
944 if (!userdata_has_field(item, "on_obtained")) {
945 return;
946 }
947 run_on_main([this,&item,&treasure](lua_State* l){
948 push_item(l, item);
949 on_obtained(treasure);
950 lua_pop(l, 1);
951 });
952 }
953
954 /**
955 * \brief Calls the on_variant_changed() method of a Lua equipment item.
956 *
957 * Does nothing if the method is not defined.
958 *
959 * \param item An equipment item.
960 * \param variant The possession state.
961 */
item_on_variant_changed(EquipmentItem & item,int variant)962 void LuaContext::item_on_variant_changed(EquipmentItem& item, int variant) {
963
964 if (!userdata_has_field(item, "on_variant_changed")) {
965 return;
966 }
967 run_on_main([this,&item,variant](lua_State* l){
968 push_item(l, item);
969 on_variant_changed(variant);
970 lua_pop(l, 1);
971 });
972 }
973
974 /**
975 * \brief Calls the on_amount_changed() method of a Lua equipment item.
976 *
977 * Does nothing if the method is not defined.
978 *
979 * \param item An equipment item.
980 * \param amount The amount of this item.
981 */
item_on_amount_changed(EquipmentItem & item,int amount)982 void LuaContext::item_on_amount_changed(EquipmentItem& item, int amount) {
983
984 if (!userdata_has_field(item, "on_amount_changed")) {
985 return;
986 }
987 run_on_main([this,&item,amount](lua_State* l){
988 push_item(l, item);
989 on_amount_changed(amount);
990 lua_pop(l, 1);
991 });
992 }
993
994 /**
995 * \brief Calls the on_using() method of a Lua equipment item.
996 *
997 * Does nothing if the method is not defined.
998 *
999 * \param item An equipment item.
1000 */
item_on_using(EquipmentItem & item)1001 void LuaContext::item_on_using(EquipmentItem& item) {
1002
1003 if (!userdata_has_field(item, "on_using")) {
1004 return;
1005 }
1006 run_on_main([this,&item](lua_State* l){
1007 push_item(l, item);
1008 on_using();
1009 lua_pop(l, 1);
1010 });
1011 }
1012
1013 /**
1014 * \brief Calls the on_ability_used() method of a Lua equipment item.
1015 *
1016 * Does nothing if the method is not defined.
1017 *
1018 * \param item An equipment item.
1019 * \param ability The ability just used.
1020 */
item_on_ability_used(EquipmentItem & item,Ability ability)1021 void LuaContext::item_on_ability_used(EquipmentItem& item, Ability ability) {
1022
1023 if (!userdata_has_field(item, "on_ability_used")) {
1024 return;
1025 }
1026 run_on_main([this,&item,ability](lua_State* l){
1027 push_item(l, item);
1028 on_ability_used(ability);
1029 lua_pop(l, 1);
1030 });
1031 }
1032
1033 /**
1034 * \brief Calls the on_npc_interaction() method of a Lua equipment item.
1035 *
1036 * Does nothing if the method is not defined.
1037 *
1038 * \param item An equipment item.
1039 * \param npc An NPC.
1040 */
item_on_npc_interaction(EquipmentItem & item,Npc & npc)1041 void LuaContext::item_on_npc_interaction(EquipmentItem& item, Npc& npc) {
1042
1043 if (!userdata_has_field(item, "on_npc_interaction")) {
1044 return;
1045 }
1046 run_on_main([this,&item,&npc](lua_State* l){
1047 push_item(l, item);
1048 on_npc_interaction(npc);
1049 lua_pop(l, 1);
1050 });
1051 }
1052
1053 /**
1054 * \brief Calls the on_npc_interaction_item() method of a Lua equipment item.
1055 *
1056 * Does nothing if the method is not defined.
1057 *
1058 * \param item The equipment item linked to the NPC.
1059 * \param npc An NPC.
1060 * \param item_used The equipment item used.
1061 * \return true if an interaction occurred.
1062 */
item_on_npc_interaction_item(EquipmentItem & item,Npc & npc,EquipmentItem & item_used)1063 bool LuaContext::item_on_npc_interaction_item(EquipmentItem& item, Npc& npc,
1064 EquipmentItem& item_used) {
1065
1066 if (!userdata_has_field(item, "on_npc_interaction_item")) {
1067 return false;
1068 }
1069
1070 //TODO make this on main
1071
1072 push_item(current_l, item);
1073 bool result = on_npc_interaction_item(npc, item_used);
1074 lua_pop(current_l, 1);
1075 return result;
1076 }
1077
1078 /**
1079 * \brief Calls the on_npc_collision_fire() method of a Lua equipment item.
1080 *
1081 * Does nothing if the method is not defined.
1082 *
1083 * \param item An equipment item.
1084 * \param npc An NPC.
1085 */
item_on_npc_collision_fire(EquipmentItem & item,Npc & npc)1086 void LuaContext::item_on_npc_collision_fire(EquipmentItem& item, Npc& npc) {
1087
1088 if (!userdata_has_field(item, "on_npc_collision_fire")) {
1089 return;
1090 }
1091 run_on_main([this,&item,&npc](lua_State* l){
1092 push_item(l, item);
1093 on_npc_collision_fire(npc);
1094 lua_pop(l, 1);
1095 });
1096 }
1097
1098 }
1099
1100