aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/guiInventoryMenu.cpp23
-rw-r--r--src/inventorymanager.cpp91
-rw-r--r--src/scriptapi.cpp97
-rw-r--r--src/scriptapi.h16
4 files changed, 203 insertions, 24 deletions
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 "
+ <<"\""<<s.inventoryloc.dump()<<"\" doesn't exist"
+ <<std::endl;
+ s.i = -1; // make it invalid again
+ break;
+ }
InventoryList *list = inv_s->getList(s.listname);
if(list == NULL){
errorstream<<"InventoryMenu: The selected inventory list \""
<<s.listname<<"\" does not exist"<<std::endl;
s.i = -1; // make it invalid again
- } else if((u32)s.i >= list->getSize()){
+ break;
+ }
+
+ if((u32)s.i >= list->getSize()){
errorstream<<"InventoryMenu: The selected inventory list \""
<<s.listname<<"\" is too small (i="<<s.i<<", size="
<<list->getSize()<<")"<<std::endl;
s.i = -1; // make it invalid again
- } else{
- s_count = 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=\""<<to_list<<"\""<<std::endl;
return;
}
- /*
- 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);
+
+ // 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<<player->getDescription()<<" moving "<<count0
+ <<" items inside node at "<<PP(from_inv.p)<<std::endl;
+ scriptapi_node_on_metadata_inventory_move(L, from_inv.p,
+ from_list, from_i, to_list, to_i, count0, player);
+ }
+ // Handle node metadata take
+ else if(from_inv.type == InventoryLocation::NODEMETA)
+ {
+ lua_State *L = player->getEnv()->getLua();
+ int count0 = count;
+ if(count0 == 0)
+ count0 = list_from->getItem(from_i).count;
+ infostream<<player->getDescription()<<" taking "<<count0
+ <<" items from node at "<<PP(from_inv.p)<<std::endl;
+ ItemStack return_stack = scriptapi_node_on_metadata_inventory_take(
+ L, from_inv.p, from_list, from_i, count0, player);
+ if(return_stack.count == 0)
+ infostream<<"Node metadata gave no items"<<std::endl;
+ return_stack = list_to->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<<player->getDescription()<<" offering "
+ <<offer_stack.count<<" items to node at "
+ <<PP(to_inv.p)<<std::endl;
+ ItemStack reject_stack = scriptapi_node_on_metadata_inventory_offer(
+ L, to_inv.p, to_list, to_i, offer_stack, player);
+ if(reject_stack.count == offer_stack.count)
+ infostream<<"Node metadata rejected all items"<<std::endl;
+ else if(reject_stack.count != 0)
+ infostream<<"Node metadata rejected some items"<<std::endl;
+ reject_stack = list_from->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="<<count
+ <<" from inv=\""<<from_inv.dump()<<"\""
+ <<" list=\""<<from_list<<"\""
+ <<" i="<<from_i
+ <<" to inv=\""<<to_inv.dump()<<"\""
+ <<" list=\""<<to_list<<"\""
+ <<" i="<<to_i
+ <<std::endl;
+ }
mgr->setInventoryModified(from_inv);
if(inv_from != inv_to)
mgr->setInventoryModified(to_inv);
-
- infostream<<"IMoveAction::apply(): moved at "
- <<" count="<<count<<"\""
- <<" from inv=\""<<from_inv.dump()<<"\""
- <<" list=\""<<from_list<<"\""
- <<" i="<<from_i
- <<" to inv=\""<<to_inv.dump()<<"\""
- <<" list=\""<<to_list<<"\""
- <<" i="<<to_i
- <<std::endl;
}
void IMoveAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index f9ec58582..213fb47f9 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -1470,7 +1470,7 @@ private:
ItemStack &item = o->m_stack;
u32 takecount = 1;
if(!lua_isnone(L, 2))
- takecount = lua_tointeger(L, 2);
+ takecount = luaL_checkinteger(L, 2);
ItemStack taken = item.takeItem(takecount);
create(L, taken);
return 1;
@@ -5014,6 +5014,101 @@ void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
script_error(L, "error: %s", lua_tostring(L, -1));
}
+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)
+{
+ 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;
+
+ // 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<std::string, std::string> &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.