]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/cpp_api/s_item.cpp
Add on_secondary_use when right clicking an item in the air
[dragonfireclient.git] / src / script / cpp_api / s_item.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "cpp_api/s_item.h"
21 #include "cpp_api/s_internal.h"
22 #include "common/c_converter.h"
23 #include "common/c_content.h"
24 #include "lua_api/l_item.h"
25 #include "lua_api/l_inventory.h"
26 #include "server.h"
27 #include "log.h"
28 #include "util/pointedthing.h"
29 #include "inventory.h"
30 #include "inventorymanager.h"
31
32 bool ScriptApiItem::item_OnDrop(ItemStack &item,
33                 ServerActiveObject *dropper, v3f pos)
34 {
35         SCRIPTAPI_PRECHECKHEADER
36
37         int error_handler = PUSH_ERROR_HANDLER(L);
38
39         // Push callback function on stack
40         if (!getItemCallback(item.name.c_str(), "on_drop"))
41                 return false;
42
43         // Call function
44         LuaItemStack::create(L, item);
45         objectrefGetOrCreate(L, dropper);
46         pushFloatPos(L, pos);
47         PCALL_RES(lua_pcall(L, 3, 1, error_handler));
48         if (!lua_isnil(L, -1)) {
49                 try {
50                         item = read_item(L,-1, getServer());
51                 } catch (LuaError &e) {
52                         throw LuaError(std::string(e.what()) + ". item=" + item.name);
53                 }
54         }
55         lua_pop(L, 2);  // Pop item and error handler
56         return true;
57 }
58
59 bool ScriptApiItem::item_OnPlace(ItemStack &item,
60                 ServerActiveObject *placer, const PointedThing &pointed)
61 {
62         SCRIPTAPI_PRECHECKHEADER
63
64         int error_handler = PUSH_ERROR_HANDLER(L);
65
66         // Push callback function on stack
67         if (!getItemCallback(item.name.c_str(), "on_place"))
68                 return false;
69
70         // Call function
71         LuaItemStack::create(L, item);
72         objectrefGetOrCreate(L, placer);
73         pushPointedThing(pointed);
74         PCALL_RES(lua_pcall(L, 3, 1, error_handler));
75         if (!lua_isnil(L, -1)) {
76                 try {
77                         item = read_item(L,-1, getServer());
78                 } catch (LuaError &e) {
79                         throw LuaError(std::string(e.what()) + ". item=" + item.name);
80                 }
81         }
82         lua_pop(L, 2);  // Pop item and error handler
83         return true;
84 }
85
86 bool ScriptApiItem::item_OnUse(ItemStack &item,
87                 ServerActiveObject *user, const PointedThing &pointed)
88 {
89         SCRIPTAPI_PRECHECKHEADER
90
91         int error_handler = PUSH_ERROR_HANDLER(L);
92
93         // Push callback function on stack
94         if (!getItemCallback(item.name.c_str(), "on_use"))
95                 return false;
96
97         // Call function
98         LuaItemStack::create(L, item);
99         objectrefGetOrCreate(L, user);
100         pushPointedThing(pointed);
101         PCALL_RES(lua_pcall(L, 3, 1, error_handler));
102         if(!lua_isnil(L, -1)) {
103                 try {
104                         item = read_item(L,-1, getServer());
105                 } catch (LuaError &e) {
106                         throw LuaError(std::string(e.what()) + ". item=" + item.name);
107                 }
108         }
109         lua_pop(L, 2);  // Pop item and error handler
110         return true;
111 }
112
113 bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, ServerActiveObject *user)
114 {
115         SCRIPTAPI_PRECHECKHEADER
116         
117         int error_handler = PUSH_ERROR_HANDLER(L);
118         
119         if (!getItemCallback(item.name.c_str(), "on_secondary_use"))
120                 return false;
121         
122         LuaItemStack::create(L, item);
123         objectrefGetOrCreate(L, user);
124         PointedThing pointed;
125         pointed.type = POINTEDTHING_NOTHING;
126         pushPointedThing(pointed);
127         PCALL_RES(lua_pcall(L, 3, 1, error_handler));
128         if (!lua_isnil(L, -1)) {
129                 try {
130                         item = read_item(L, -1, getServer());
131                 } catch (LuaError &e) {
132                         throw LuaError(std::string(e.what()) + ". item=" + item.name);
133                 }
134         }
135         lua_pop(L, 2);  // Pop item and error handler
136         return true;
137 }
138
139 bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
140                 const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
141 {
142         SCRIPTAPI_PRECHECKHEADER
143
144         int error_handler = PUSH_ERROR_HANDLER(L);
145
146         lua_getglobal(L, "core");
147         lua_getfield(L, -1, "on_craft");
148         LuaItemStack::create(L, item);
149         objectrefGetOrCreate(L, user);
150
151         // Push inventory list
152         std::vector<ItemStack> items;
153         for (u32 i = 0; i < old_craft_grid->getSize(); i++) {
154                 items.push_back(old_craft_grid->getItem(i));
155         }
156         push_items(L, items);
157
158         InvRef::create(L, craft_inv);
159         PCALL_RES(lua_pcall(L, 4, 1, error_handler));
160         if (!lua_isnil(L, -1)) {
161                 try {
162                         item = read_item(L,-1, getServer());
163                 } catch (LuaError &e) {
164                         throw LuaError(std::string(e.what()) + ". item=" + item.name);
165                 }
166         }
167         lua_pop(L, 2);  // Pop item and error handler
168         return true;
169 }
170
171 bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
172                 const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
173 {
174         SCRIPTAPI_PRECHECKHEADER
175
176         int error_handler = PUSH_ERROR_HANDLER(L);
177
178         lua_getglobal(L, "core");
179         lua_getfield(L, -1, "craft_predict");
180         LuaItemStack::create(L, item);
181         objectrefGetOrCreate(L, user);
182
183         //Push inventory list
184         std::vector<ItemStack> items;
185         for (u32 i = 0; i < old_craft_grid->getSize(); i++) {
186                 items.push_back(old_craft_grid->getItem(i));
187         }
188         push_items(L, items);
189
190         InvRef::create(L, craft_inv);
191         PCALL_RES(lua_pcall(L, 4, 1, error_handler));
192         if (!lua_isnil(L, -1)) {
193                 try {
194                         item = read_item(L,-1, getServer());
195                 } catch (LuaError &e) {
196                         throw LuaError(std::string(e.what()) + ". item=" + item.name);
197                 }
198         }
199         lua_pop(L, 2);  // Pop item and error handler
200         return true;
201 }
202
203 // Retrieves core.registered_items[name][callbackname]
204 // If that is nil or on error, return false and stack is unchanged
205 // If that is a function, returns true and pushes the
206 // function onto the stack
207 // If core.registered_items[name] doesn't exist, core.nodedef_default
208 // is tried instead so unknown items can still be manipulated to some degree
209 bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname)
210 {
211         lua_State* L = getStack();
212
213         lua_getglobal(L, "core");
214         lua_getfield(L, -1, "registered_items");
215         lua_remove(L, -2); // Remove core
216         luaL_checktype(L, -1, LUA_TTABLE);
217         lua_getfield(L, -1, name);
218         lua_remove(L, -2); // Remove registered_items
219         // Should be a table
220         if(lua_type(L, -1) != LUA_TTABLE)
221         {
222                 // Report error and clean up
223                 errorstream << "Item \"" << name << "\" not defined" << std::endl;
224                 lua_pop(L, 1);
225
226                 // Try core.nodedef_default instead
227                 lua_getglobal(L, "core");
228                 lua_getfield(L, -1, "nodedef_default");
229                 lua_remove(L, -2);
230                 luaL_checktype(L, -1, LUA_TTABLE);
231         }
232
233         setOriginFromTable(-1);
234
235         lua_getfield(L, -1, callbackname);
236         lua_remove(L, -2); // Remove item def
237         // Should be a function or nil
238         if (lua_type(L, -1) == LUA_TFUNCTION) {
239                 return true;
240         } else if (!lua_isnil(L, -1)) {
241                 errorstream << "Item \"" << name << "\" callback \""
242                         << callbackname << "\" is not a function" << std::endl;
243         }
244         lua_pop(L, 1);
245         return false;
246 }
247
248 void ScriptApiItem::pushPointedThing(const PointedThing& pointed)
249 {
250         lua_State* L = getStack();
251
252         lua_newtable(L);
253         if(pointed.type == POINTEDTHING_NODE)
254         {
255                 lua_pushstring(L, "node");
256                 lua_setfield(L, -2, "type");
257                 push_v3s16(L, pointed.node_undersurface);
258                 lua_setfield(L, -2, "under");
259                 push_v3s16(L, pointed.node_abovesurface);
260                 lua_setfield(L, -2, "above");
261         }
262         else if(pointed.type == POINTEDTHING_OBJECT)
263         {
264                 lua_pushstring(L, "object");
265                 lua_setfield(L, -2, "type");
266                 objectrefGet(L, pointed.object_id);
267                 lua_setfield(L, -2, "ref");
268         }
269         else
270         {
271                 lua_pushstring(L, "nothing");
272                 lua_setfield(L, -2, "type");
273         }
274 }
275