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,
119 ServerActiveObject *user, const PointedThing &pointed)
121 SCRIPTAPI_PRECHECKHEADER
123 int error_handler = PUSH_ERROR_HANDLER(L);
125 if (!getItemCallback(item.name.c_str(), "on_secondary_use"))
128 LuaItemStack::create(L, item);
129 objectrefGetOrCreate(L, user);
130 pushPointedThing(pointed);
131 PCALL_RES(lua_pcall(L, 3, 1, error_handler));
132 if (!lua_isnil(L, -1)) {
134 item = read_item(L, -1, getServer()->idef());
135 } catch (LuaError &e) {
136 throw LuaError(std::string(e.what()) + ". item=" + item.name);
139 lua_pop(L, 2); // Pop item and error handler
143 bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
144 const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
146 SCRIPTAPI_PRECHECKHEADER
148 int error_handler = PUSH_ERROR_HANDLER(L);
150 lua_getglobal(L, "core");
151 lua_getfield(L, -1, "on_craft");
152 LuaItemStack::create(L, item);
153 objectrefGetOrCreate(L, user);
155 // Push inventory list
156 std::vector<ItemStack> items;
157 for (u32 i = 0; i < old_craft_grid->getSize(); i++) {
158 items.push_back(old_craft_grid->getItem(i));
160 push_items(L, items);
162 InvRef::create(L, craft_inv);
163 PCALL_RES(lua_pcall(L, 4, 1, error_handler));
164 if (!lua_isnil(L, -1)) {
166 item = read_item(L, -1, getServer()->idef());
167 } catch (LuaError &e) {
168 throw LuaError(std::string(e.what()) + ". item=" + item.name);
171 lua_pop(L, 2); // Pop item and error handler
175 bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
176 const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
178 SCRIPTAPI_PRECHECKHEADER
179 sanity_check(old_craft_grid);
180 int error_handler = PUSH_ERROR_HANDLER(L);
182 lua_getglobal(L, "core");
183 lua_getfield(L, -1, "craft_predict");
184 LuaItemStack::create(L, item);
185 objectrefGetOrCreate(L, user);
187 //Push inventory list
188 std::vector<ItemStack> items;
189 for (u32 i = 0; i < old_craft_grid->getSize(); i++) {
190 items.push_back(old_craft_grid->getItem(i));
192 push_items(L, items);
194 InvRef::create(L, craft_inv);
195 PCALL_RES(lua_pcall(L, 4, 1, error_handler));
196 if (!lua_isnil(L, -1)) {
198 item = read_item(L, -1, getServer()->idef());
199 } catch (LuaError &e) {
200 throw LuaError(std::string(e.what()) + ". item=" + item.name);
203 lua_pop(L, 2); // Pop item and error handler
207 // Retrieves core.registered_items[name][callbackname]
208 // If that is nil or on error, return false and stack is unchanged
209 // If that is a function, returns true and pushes the
210 // function onto the stack
211 // If core.registered_items[name] doesn't exist, core.nodedef_default
212 // is tried instead so unknown items can still be manipulated to some degree
213 bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname,
216 lua_State* L = getStack();
218 lua_getglobal(L, "core");
219 lua_getfield(L, -1, "registered_items");
220 lua_remove(L, -2); // Remove core
221 luaL_checktype(L, -1, LUA_TTABLE);
222 lua_getfield(L, -1, name);
223 lua_remove(L, -2); // Remove registered_items
225 if (lua_type(L, -1) != LUA_TTABLE) {
226 // Report error and clean up
227 errorstream << "Item \"" << name << "\" not defined";
229 errorstream << " at position " << PP(*p);
230 errorstream << std::endl;
233 // Try core.nodedef_default instead
234 lua_getglobal(L, "core");
235 lua_getfield(L, -1, "nodedef_default");
237 luaL_checktype(L, -1, LUA_TTABLE);
240 setOriginFromTable(-1);
242 lua_getfield(L, -1, callbackname);
243 lua_remove(L, -2); // Remove item def
244 // Should be a function or nil
245 if (lua_type(L, -1) == LUA_TFUNCTION) {
249 if (!lua_isnil(L, -1)) {
250 errorstream << "Item \"" << name << "\" callback \""
251 << callbackname << "\" is not a function" << std::endl;
257 void ScriptApiItem::pushPointedThing(const PointedThing &pointed, bool hitpoint)
259 lua_State* L = getStack();
261 push_pointed_thing(L, pointed, false, hitpoint);