3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
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"
28 #include "util/pointedthing.h"
29 #include "inventory.h"
30 #include "inventorymanager.h"
32 bool ScriptApiItem::item_OnDrop(ItemStack &item,
33 ServerActiveObject *dropper, v3f pos)
35 SCRIPTAPI_PRECHECKHEADER
37 int error_handler = PUSH_ERROR_HANDLER(L);
39 // Push callback function on stack
40 if (!getItemCallback(item.name.c_str(), "on_drop"))
44 LuaItemStack::create(L, item);
45 objectrefGetOrCreate(L, dropper);
47 PCALL_RES(lua_pcall(L, 3, 1, error_handler));
48 if (!lua_isnil(L, -1)) {
50 item = read_item(L, -1, getServer()->idef());
51 } catch (LuaError &e) {
52 throw LuaError(std::string(e.what()) + ". item=" + item.name);
55 lua_pop(L, 2); // Pop item and error handler
59 bool ScriptApiItem::item_OnPlace(ItemStack &item,
60 ServerActiveObject *placer, const PointedThing &pointed)
62 SCRIPTAPI_PRECHECKHEADER
64 int error_handler = PUSH_ERROR_HANDLER(L);
66 // Push callback function on stack
67 if (!getItemCallback(item.name.c_str(), "on_place"))
71 LuaItemStack::create(L, item);
76 objectrefGetOrCreate(L, placer);
78 pushPointedThing(pointed);
79 PCALL_RES(lua_pcall(L, 3, 1, error_handler));
80 if (!lua_isnil(L, -1)) {
82 item = read_item(L, -1, getServer()->idef());
83 } catch (LuaError &e) {
84 throw LuaError(std::string(e.what()) + ". item=" + item.name);
87 lua_pop(L, 2); // Pop item and error handler
91 bool ScriptApiItem::item_OnUse(ItemStack &item,
92 ServerActiveObject *user, const PointedThing &pointed)
94 SCRIPTAPI_PRECHECKHEADER
96 int error_handler = PUSH_ERROR_HANDLER(L);
98 // Push callback function on stack
99 if (!getItemCallback(item.name.c_str(), "on_use"))
103 LuaItemStack::create(L, item);
104 objectrefGetOrCreate(L, user);
105 pushPointedThing(pointed);
106 PCALL_RES(lua_pcall(L, 3, 1, error_handler));
107 if(!lua_isnil(L, -1)) {
109 item = read_item(L, -1, getServer()->idef());
110 } catch (LuaError &e) {
111 throw LuaError(std::string(e.what()) + ". item=" + item.name);
114 lua_pop(L, 2); // Pop item and error handler
118 bool ScriptApiItem::item_OnSecondaryUse(ItemStack &item, ServerActiveObject *user)
120 SCRIPTAPI_PRECHECKHEADER
122 int error_handler = PUSH_ERROR_HANDLER(L);
124 if (!getItemCallback(item.name.c_str(), "on_secondary_use"))
127 LuaItemStack::create(L, item);
128 objectrefGetOrCreate(L, user);
129 PointedThing pointed;
130 pointed.type = POINTEDTHING_NOTHING;
131 pushPointedThing(pointed);
132 PCALL_RES(lua_pcall(L, 3, 1, error_handler));
133 if (!lua_isnil(L, -1)) {
135 item = read_item(L, -1, getServer()->idef());
136 } catch (LuaError &e) {
137 throw LuaError(std::string(e.what()) + ". item=" + item.name);
140 lua_pop(L, 2); // Pop item and error handler
144 bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
145 const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
147 SCRIPTAPI_PRECHECKHEADER
149 int error_handler = PUSH_ERROR_HANDLER(L);
151 lua_getglobal(L, "core");
152 lua_getfield(L, -1, "on_craft");
153 LuaItemStack::create(L, item);
154 objectrefGetOrCreate(L, user);
156 // Push inventory list
157 std::vector<ItemStack> items;
158 for (u32 i = 0; i < old_craft_grid->getSize(); i++) {
159 items.push_back(old_craft_grid->getItem(i));
161 push_items(L, items);
163 InvRef::create(L, craft_inv);
164 PCALL_RES(lua_pcall(L, 4, 1, error_handler));
165 if (!lua_isnil(L, -1)) {
167 item = read_item(L, -1, getServer()->idef());
168 } catch (LuaError &e) {
169 throw LuaError(std::string(e.what()) + ". item=" + item.name);
172 lua_pop(L, 2); // Pop item and error handler
176 bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
177 const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
179 SCRIPTAPI_PRECHECKHEADER
180 sanity_check(old_craft_grid);
181 int error_handler = PUSH_ERROR_HANDLER(L);
183 lua_getglobal(L, "core");
184 lua_getfield(L, -1, "craft_predict");
185 LuaItemStack::create(L, item);
186 objectrefGetOrCreate(L, user);
188 //Push inventory list
189 std::vector<ItemStack> items;
190 for (u32 i = 0; i < old_craft_grid->getSize(); i++) {
191 items.push_back(old_craft_grid->getItem(i));
193 push_items(L, items);
195 InvRef::create(L, craft_inv);
196 PCALL_RES(lua_pcall(L, 4, 1, error_handler));
197 if (!lua_isnil(L, -1)) {
199 item = read_item(L, -1, getServer()->idef());
200 } catch (LuaError &e) {
201 throw LuaError(std::string(e.what()) + ". item=" + item.name);
204 lua_pop(L, 2); // Pop item and error handler
208 // Retrieves core.registered_items[name][callbackname]
209 // If that is nil or on error, return false and stack is unchanged
210 // If that is a function, returns true and pushes the
211 // function onto the stack
212 // If core.registered_items[name] doesn't exist, core.nodedef_default
213 // is tried instead so unknown items can still be manipulated to some degree
214 bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname,
217 lua_State* L = getStack();
219 lua_getglobal(L, "core");
220 lua_getfield(L, -1, "registered_items");
221 lua_remove(L, -2); // Remove core
222 luaL_checktype(L, -1, LUA_TTABLE);
223 lua_getfield(L, -1, name);
224 lua_remove(L, -2); // Remove registered_items
226 if (lua_type(L, -1) != LUA_TTABLE) {
227 // Report error and clean up
228 errorstream << "Item \"" << name << "\" not defined";
230 errorstream << " at position " << PP(*p);
231 errorstream << std::endl;
234 // Try core.nodedef_default instead
235 lua_getglobal(L, "core");
236 lua_getfield(L, -1, "nodedef_default");
238 luaL_checktype(L, -1, LUA_TTABLE);
241 setOriginFromTable(-1);
243 lua_getfield(L, -1, callbackname);
244 lua_remove(L, -2); // Remove item def
245 // Should be a function or nil
246 if (lua_type(L, -1) == LUA_TFUNCTION) {
250 if (!lua_isnil(L, -1)) {
251 errorstream << "Item \"" << name << "\" callback \""
252 << callbackname << "\" is not a function" << std::endl;
258 void ScriptApiItem::pushPointedThing(const PointedThing &pointed, bool hitpoint)
260 lua_State* L = getStack();
262 push_pointed_thing(L, pointed, false, hitpoint);