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