From aba7134301e0fe49cb3a6b157d226e1405753237 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sat, 2 Jun 2012 00:33:51 +0300 Subject: [PATCH] on_metadata_inventory_{move,offer,take} --- builtin/item.lua | 41 +++++++++++++++++ doc/lua_api.txt | 31 +++++++++++++ src/guiInventoryMenu.cpp | 23 +++++++--- src/inventorymanager.cpp | 91 ++++++++++++++++++++++++++++++------- src/scriptapi.cpp | 97 +++++++++++++++++++++++++++++++++++++++- src/scriptapi.h | 16 +++++++ 6 files changed, 275 insertions(+), 24 deletions(-) diff --git a/builtin/item.lua b/builtin/item.lua index d30b439aa..eb8c556de 100644 --- a/builtin/item.lua +++ b/builtin/item.lua @@ -262,6 +262,41 @@ function minetest.node_dig(pos, node, digger) end end +function minetest.node_metadata_inventory_move_allow_all(pos, from_list, + from_index, to_list, to_index, count, player) + minetest.log("verbose", "node_metadata_inventory_move_allow_all") + local meta = minetest.env:get_meta(pos) + local inv = meta:get_inventory() + + local from_stack = inv:get_stack(from_list, from_index) + local taken_items = from_stack:take_item(count) + inv:set_stack(from_list, from_index, from_stack) + + local to_stack = inv:get_stack(to_list, to_index) + to_stack:add_item(taken_items) + inv:set_stack(to_list, to_index, to_stack) +end + +function minetest.node_metadata_inventory_offer_allow_all(pos, listname, index, stack, player) + minetest.log("verbose", "node_metadata_inventory_offer_allow_all") + local meta = minetest.env:get_meta(pos) + local inv = meta:get_inventory() + local the_stack = inv:get_stack(listname, index) + the_stack:add_item(stack) + inv:set_stack(listname, index, the_stack) + return ItemStack("") +end + +function minetest.node_metadata_inventory_take_allow_all(pos, listname, index, count, player) + minetest.log("verbose", "node_metadata_inventory_take_allow_all") + local meta = minetest.env:get_meta(pos) + local inv = meta:get_inventory() + local the_stack = inv:get_stack(listname, index) + local taken_items = the_stack:take_item(count) + inv:set_stack(listname, index, the_stack) + return taken_items +end + -- This is used to allow mods to redefine minetest.item_place and so on local function redef_wrapper(table, name) return function(...) @@ -295,6 +330,12 @@ minetest.nodedef_default = { on_punch = redef_wrapper(minetest, 'node_punch'), -- minetest.node_punch on_dig = redef_wrapper(minetest, 'node_dig'), -- minetest.node_dig + on_receive_fields = nil, + + on_metadata_inventory_move = minetest.node_metadata_inventory_move_allow_all, + on_metadata_inventory_offer = minetest.node_metadata_inventory_offer_allow_all, + on_metadata_inventory_take = minetest.node_metadata_inventory_take_allow_all, + -- Node properties drawtype = "normal", visual_scale = 1.0, diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 73d7b3641..f8615b130 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1039,7 +1039,38 @@ Node definition (register_node) on_receive_fields = func(pos, formname, fields, sender), ^ fields = {name1 = value1, name2 = value2, ...} + ^ Called when an UI form (eg. sign text input) returns data ^ default: nil + + on_metadata_inventory_move = func(pos, from_list, from_index, + to_list, to_index, count, player), + ^ Called when a player wants to move items inside the metadata + ^ Should move items, or some items, if permitted. If not, should do + nothing. + ^ The engine ensures the action is valid, i.e. the stack fits at the + given position + ^ default: minetest.node_metadata_inventory_move_allow_all + + on_metadata_inventory_offer = func(pos, listname, index, stack, player), + ^ Called when a player wants to put something into the metadata + inventory + ^ Should check if the action is permitted (the engine ensures the + action is valid, i.e. the stack fits at the given position) + ^ If permitted, modify the metadata inventory and return the + "leftover" stack (normally nil). + ^ If not permitted, return itemstack. + ^ default: minetest.node_metadata_inventory_offer_allow_all + + on_metadata_inventory_take = func(pos, listname, index, count, player), + ^ Called when a player wants to take something out of the metadata + inventory + ^ Should check if the action is permitted (the engine ensures the + action is valid, i.e. there's a stack of at least “count” items at + that position) + ^ If permitted, modify the metadata inventory and return the + stack of items + ^ If not permitted, return nil. + ^ default: minetest.node_metadata_inventory_take_allow_all } Recipe: (register_craft) diff --git a/src/guiInventoryMenu.cpp b/src/guiInventoryMenu.cpp index 823addd1b..51001eee3 100644 --- a/src/guiInventoryMenu.cpp +++ b/src/guiInventoryMenu.cpp @@ -526,24 +526,35 @@ bool GUIInventoryMenu::OnEvent(const SEvent& event) u32 s_count = 0; if(s.isValid()) - { + do{ // breakable inv_s = m_invmgr->getInventory(s.inventoryloc); - assert(inv_s); + + if(!inv_s){ + errorstream<<"InventoryMenu: The selected inventory location " + <<"\""<getList(s.listname); if(list == NULL){ errorstream<<"InventoryMenu: The selected inventory list \"" <= list->getSize()){ + break; + } + + if((u32)s.i >= list->getSize()){ errorstream<<"InventoryMenu: The selected inventory list \"" <getItem(s.i).count; + break; } - } + + s_count = list->getItem(s.i).count; + }while(0); bool identical = (m_selected_item != NULL) && s.isValid() && (inv_selected == inv_s) && diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp index b04a1c177..46f744f8b 100644 --- a/src/inventorymanager.cpp +++ b/src/inventorymanager.cpp @@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "utility.h" #include "craftdef.h" +#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" + /* InventoryLocation */ @@ -197,27 +199,82 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame <<", to_list=\""<moveItem(from_i, list_to, to_i, count); + + // Handle node metadata move + if(from_inv.type == InventoryLocation::NODEMETA && + to_inv.type == InventoryLocation::NODEMETA && + from_inv.p == to_inv.p) + { + lua_State *L = player->getEnv()->getLua(); + int count0 = count; + if(count0 == 0) + count0 = list_from->getItem(from_i).count; + infostream<getDescription()<<" moving "<getEnv()->getLua(); + int count0 = count; + if(count0 == 0) + count0 = list_from->getItem(from_i).count; + infostream<getDescription()<<" taking "<addItem(to_i, return_stack); + list_to->addItem(return_stack); // Force return of everything + } + // Handle node metadata offer + else if(to_inv.type == InventoryLocation::NODEMETA) + { + lua_State *L = player->getEnv()->getLua(); + int count0 = count; + if(count0 == 0) + count0 = list_from->getItem(from_i).count; + ItemStack offer_stack = list_from->takeItem(from_i, count0); + infostream<getDescription()<<" offering " + <addItem(from_i, reject_stack); + list_from->addItem(reject_stack); // Force return of everything + } + // Handle regular move + else + { + /* + This performs the actual movement + + If something is wrong (source item is empty, destination is the + same as source), nothing happens + */ + list_from->moveItem(from_i, list_to, to_i, count); + + infostream<<"IMoveAction::apply(): moved " + <<" count="<ndef(); + + // If node doesn't exist, we don't know what callback to call + MapNode node = get_env(L)->getMap().getNodeNoEx(p); + if(node.getContent() == CONTENT_IGNORE) + return; + + // Push callback function on stack + if(!get_item_callback(L, ndef->get(node).name.c_str(), + "on_metadata_inventory_move")) + return; + + // function(pos, from_list, from_index, to_list, to_index, count, player) + push_v3s16(L, p); + lua_pushstring(L, from_list.c_str()); + lua_pushinteger(L, from_index + 1); + lua_pushstring(L, to_list.c_str()); + lua_pushinteger(L, to_index + 1); + lua_pushinteger(L, count); + objectref_get_or_create(L, player); + if(lua_pcall(L, 7, 0, 0)) + script_error(L, "error: %s", lua_tostring(L, -1)); +} + +ItemStack scriptapi_node_on_metadata_inventory_offer(lua_State *L, v3s16 p, + const std::string &listname, int index, ItemStack &stack, + ServerActiveObject *player) +{ + realitycheck(L); + assert(lua_checkstack(L, 20)); + StackUnroller stack_unroller(L); + + INodeDefManager *ndef = get_server(L)->ndef(); + + // If node doesn't exist, we don't know what callback to call + MapNode node = get_env(L)->getMap().getNodeNoEx(p); + if(node.getContent() == CONTENT_IGNORE) + return stack; + + // Push callback function on stack + if(!get_item_callback(L, ndef->get(node).name.c_str(), + "on_metadata_inventory_offer")) + return stack; + + // Call function(pos, listname, index, stack, player) + push_v3s16(L, p); + lua_pushstring(L, listname.c_str()); + lua_pushinteger(L, index + 1); + LuaItemStack::create(L, stack); + objectref_get_or_create(L, player); + if(lua_pcall(L, 5, 1, 0)) + script_error(L, "error: %s", lua_tostring(L, -1)); + return read_item(L, -1); +} + +ItemStack scriptapi_node_on_metadata_inventory_take(lua_State *L, v3s16 p, + const std::string &listname, int index, int count, + ServerActiveObject *player) +{ + realitycheck(L); + assert(lua_checkstack(L, 20)); + StackUnroller stack_unroller(L); + + INodeDefManager *ndef = get_server(L)->ndef(); + + // If node doesn't exist, we don't know what callback to call + MapNode node = get_env(L)->getMap().getNodeNoEx(p); + if(node.getContent() == CONTENT_IGNORE) + return ItemStack(); + + // Push callback function on stack + if(!get_item_callback(L, ndef->get(node).name.c_str(), + "on_metadata_inventory_take")) + return ItemStack(); + + // Call function(pos, listname, index, count, player) + push_v3s16(L, p); + lua_pushstring(L, listname.c_str()); + lua_pushinteger(L, index + 1); + lua_pushinteger(L, count); + objectref_get_or_create(L, player); + if(lua_pcall(L, 5, 1, 0)) + script_error(L, "error: %s", lua_tostring(L, -1)); + return read_item(L, -1); +} + /* environment */ diff --git a/src/scriptapi.h b/src/scriptapi.h index e6c16eba6..13083500d 100644 --- a/src/scriptapi.h +++ b/src/scriptapi.h @@ -82,12 +82,28 @@ bool scriptapi_node_on_punch(lua_State *L, v3s16 p, MapNode node, ServerActiveObject *puncher); bool scriptapi_node_on_dig(lua_State *L, v3s16 p, MapNode node, ServerActiveObject *digger); +// Node constructor void scriptapi_node_on_construct(lua_State *L, v3s16 p, MapNode node); +// Node destructor void scriptapi_node_on_destruct(lua_State *L, v3s16 p, MapNode node); +// Called when a metadata form returns values void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p, const std::string &formname, const std::map &fields, ServerActiveObject *sender); +// Moves items +void scriptapi_node_on_metadata_inventory_move(lua_State *L, v3s16 p, + const std::string &from_list, int from_index, + const std::string &to_list, int to_index, + int count, ServerActiveObject *player); +// Inserts items, returns rejected items +ItemStack scriptapi_node_on_metadata_inventory_offer(lua_State *L, v3s16 p, + const std::string &listname, int index, ItemStack &stack, + ServerActiveObject *player); +// Takes items, returns taken items +ItemStack scriptapi_node_on_metadata_inventory_take(lua_State *L, v3s16 p, + const std::string &listname, int index, int count, + ServerActiveObject *player); /* luaentity */ // Returns true if succesfully added into Lua; false otherwise. -- 2.25.1