]> git.lizzy.rs Git - minetest.git/blob - src/script/cpp_api/s_item.cpp
Add a callback: minetest.register_on_craft(itemstack, player,
[minetest.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         // Push callback function on stack
38         if(!getItemCallback(item.name.c_str(), "on_drop"))
39                 return false;
40
41         // Call function
42         LuaItemStack::create(L, item);
43         objectrefGetOrCreate(dropper);
44         pushFloatPos(L, pos);
45         if(lua_pcall(L, 3, 1, 0))
46                 scriptError("error: %s", lua_tostring(L, -1));
47         if(!lua_isnil(L, -1))
48                 item = read_item(L,-1, getServer());
49         return true;
50 }
51
52 bool ScriptApiItem::item_OnPlace(ItemStack &item,
53                 ServerActiveObject *placer, const PointedThing &pointed)
54 {
55         SCRIPTAPI_PRECHECKHEADER
56
57         // Push callback function on stack
58         if(!getItemCallback(item.name.c_str(), "on_place"))
59                 return false;
60
61         // Call function
62         LuaItemStack::create(L, item);
63         objectrefGetOrCreate(placer);
64         pushPointedThing(pointed);
65         if(lua_pcall(L, 3, 1, 0))
66                 scriptError("error: %s", lua_tostring(L, -1));
67         if(!lua_isnil(L, -1))
68                 item = read_item(L,-1, getServer());
69         return true;
70 }
71
72 bool ScriptApiItem::item_OnUse(ItemStack &item,
73                 ServerActiveObject *user, const PointedThing &pointed)
74 {
75         SCRIPTAPI_PRECHECKHEADER
76
77         // Push callback function on stack
78         if(!getItemCallback(item.name.c_str(), "on_use"))
79                 return false;
80
81         // Call function
82         LuaItemStack::create(L, item);
83         objectrefGetOrCreate(user);
84         pushPointedThing(pointed);
85         if(lua_pcall(L, 3, 1, 0))
86                 scriptError("error: %s", lua_tostring(L, -1));
87         if(!lua_isnil(L, -1))
88                 item = read_item(L,-1, getServer());
89         return true;
90 }
91
92 bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
93                 const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
94 {
95         SCRIPTAPI_PRECHECKHEADER
96
97         lua_getglobal(L, "minetest");
98         lua_getfield(L, -1, "on_craft");
99         LuaItemStack::create(L, item);
100         objectrefGetOrCreate(user);
101         
102         //Push inventory list
103         std::vector<ItemStack> items;
104         for(u32 i=0; i<old_craft_grid->getSize(); i++)
105                 items.push_back(old_craft_grid->getItem(i));
106         push_items(L, items);
107
108         InvRef::create(L, craft_inv);
109         if(lua_pcall(L, 4, 1, 0))
110                 scriptError("error: %s", lua_tostring(L, -1));
111         if(!lua_isnil(L, -1))
112                 item = read_item(L,-1, getServer());
113         return true;
114 }
115
116 bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
117                 const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
118 {
119         SCRIPTAPI_PRECHECKHEADER
120
121         lua_getglobal(L, "minetest");
122         lua_getfield(L, -1, "craft_predict");
123         LuaItemStack::create(L, item);
124         objectrefGetOrCreate(user);
125         
126         //Push inventory list
127         std::vector<ItemStack> items;
128         for(u32 i=0; i<old_craft_grid->getSize(); i++)
129                 items.push_back(old_craft_grid->getItem(i));
130         push_items(L, items);
131
132         InvRef::create(L, craft_inv);
133         if(lua_pcall(L, 4, 1, 0))
134                 scriptError("error: %s", lua_tostring(L, -1));
135         if(!lua_isnil(L, -1))
136                 item = read_item(L,-1, getServer());
137         return true;
138 }
139
140 // Retrieves minetest.registered_items[name][callbackname]
141 // If that is nil or on error, return false and stack is unchanged
142 // If that is a function, returns true and pushes the
143 // function onto the stack
144 // If minetest.registered_items[name] doesn't exist, minetest.nodedef_default
145 // is tried instead so unknown items can still be manipulated to some degree
146 bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname)
147 {
148         lua_State* L = getStack();
149
150         lua_getglobal(L, "minetest");
151         lua_getfield(L, -1, "registered_items");
152         lua_remove(L, -2);
153         luaL_checktype(L, -1, LUA_TTABLE);
154         lua_getfield(L, -1, name);
155         lua_remove(L, -2);
156         // Should be a table
157         if(lua_type(L, -1) != LUA_TTABLE)
158         {
159                 // Report error and clean up
160                 errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
161                 lua_pop(L, 1);
162
163                 // Try minetest.nodedef_default instead
164                 lua_getglobal(L, "minetest");
165                 lua_getfield(L, -1, "nodedef_default");
166                 lua_remove(L, -2);
167                 luaL_checktype(L, -1, LUA_TTABLE);
168         }
169         lua_getfield(L, -1, callbackname);
170         lua_remove(L, -2);
171         // Should be a function or nil
172         if(lua_type(L, -1) == LUA_TFUNCTION)
173         {
174                 return true;
175         }
176         else if(lua_isnil(L, -1))
177         {
178                 lua_pop(L, 1);
179                 return false;
180         }
181         else
182         {
183                 errorstream<<"Item \""<<name<<"\" callback \""
184                         <<callbackname<<" is not a function"<<std::endl;
185                 lua_pop(L, 1);
186                 return false;
187         }
188 }
189
190 void ScriptApiItem::pushPointedThing(const PointedThing& pointed)
191 {
192         lua_State* L = getStack();
193
194         lua_newtable(L);
195         if(pointed.type == POINTEDTHING_NODE)
196         {
197                 lua_pushstring(L, "node");
198                 lua_setfield(L, -2, "type");
199                 push_v3s16(L, pointed.node_undersurface);
200                 lua_setfield(L, -2, "under");
201                 push_v3s16(L, pointed.node_abovesurface);
202                 lua_setfield(L, -2, "above");
203         }
204         else if(pointed.type == POINTEDTHING_OBJECT)
205         {
206                 lua_pushstring(L, "object");
207                 lua_setfield(L, -2, "type");
208                 objectrefGet(pointed.object_id);
209                 lua_setfield(L, -2, "ref");
210         }
211         else
212         {
213                 lua_pushstring(L, "nothing");
214                 lua_setfield(L, -2, "type");
215         }
216 }
217
218