From 2d8611a4803edc6bd37030ac303230fee208f718 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Thu, 12 Apr 2012 18:37:27 +0400
Subject: [PATCH] Add core api for moving items between ground and containers.
---
LUA_API.rst | 20 ++++
Lua API.html | 15 +++
library/LuaApi.cpp | 73 +++++++++++--
library/include/modules/Items.h | 18 ++--
library/lua/dfhack.lua | 15 +++
library/modules/Items.cpp | 177 +++++++++++++++++++++++++++++---
library/modules/Maps.cpp | 2 +-
plugins/autodump.cpp | 10 +-
8 files changed, 289 insertions(+), 41 deletions(-)
diff --git a/LUA_API.rst b/LUA_API.rst
index fc86070c3..df997008c 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -699,6 +699,10 @@ Units module
Items module
------------
+* ``dfhack.items.getPosition(item)``
+
+ Returns true *x,y,z* of the item.
+
* ``dfhack.items.getOwner(item)``
Returns the owner unit or *nil*.
@@ -708,6 +712,22 @@ Items module
Replaces the owner of the item. If unit is *nil*, removes ownership.
Returns *false* in case of error.
+* ``dfhack.items.getContainer(item)``
+
+ Returns the container item or *nil*.
+
+* ``dfhack.items.getContainedItems(item)``
+
+ Returns a list of items contained in this one.
+
+* ``dfhack.items.moveToGround(item,pos)``
+
+ Move the item to the ground at position. Returns *false* if impossible.
+
+* ``dfhack.items.moveToContainer(item,container)``
+
+ Move the item to the container. Returns *false* if impossible.
+
Maps module
-----------
diff --git a/Lua API.html b/Lua API.html
index 7c3eeddb9..4be1050fb 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -929,6 +929,9 @@ a lua list containing them.
+dfhack.items.getPosition(item)
+Returns true x,y,z of the item.
+
dfhack.items.getOwner(item)
Returns the owner unit or nil.
@@ -936,6 +939,18 @@ a lua list containing them.
Replaces the owner of the item. If unit is nil, removes ownership.
Returns false in case of error.
+dfhack.items.getContainer(item)
+Returns the container item or nil.
+
+dfhack.items.getContainedItems(item)
+Returns a list of items contained in this one.
+
+dfhack.items.moveToGround(item,pos)
+Move the item to the ground at position. Returns false if impossible.
+
+dfhack.items.moveToContainer(item,container)
+Move the item to the container. Returns false if impossible.
+
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index febc59026..25f654b8c 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -45,6 +45,7 @@ distribution.
#include "modules/Items.h"
#include "modules/Materials.h"
#include "modules/Maps.h"
+#include "modules/MapCache.h"
#include "LuaWrapper.h"
#include "LuaTools.h"
@@ -85,6 +86,33 @@ void push_pointer_vector(lua_State *state, const std::vector
&pvec)
}
}
+template
+T *get_checked_arg(lua_State *state, int arg)
+{
+ luaL_checkany(state, arg);
+
+ auto ptr = Lua::GetDFObject(state, arg);
+ if (!ptr)
+ luaL_argerror(state, arg, "invalid type");
+ return ptr;
+}
+
+int push_pos(lua_State *state, df::coord pos)
+{
+ if (!pos.isValid())
+ {
+ lua_pushnil(state);
+ return 1;
+ }
+ else
+ {
+ lua_pushinteger(state, pos.x);
+ lua_pushinteger(state, pos.y);
+ lua_pushinteger(state, pos.z);
+ return 3;
+ }
+}
+
/**************************************************
* Per-world persistent configuration storage API *
**************************************************/
@@ -610,12 +638,47 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
{ NULL, NULL }
};
+static bool items_moveToGround(df::item *item, df::coord pos)
+{
+ MapExtras::MapCache mc;
+ return Items::moveToGround(mc, item, pos);
+}
+
+static bool items_moveToContainer(df::item *item, df::item *container)
+{
+ MapExtras::MapCache mc;
+ return Items::moveToContainer(mc, item, container);
+}
+
static const LuaWrapper::FunctionReg dfhack_items_module[] = {
WRAPM(Items, getOwner),
WRAPM(Items, setOwner),
+ WRAPM(Items, getContainer),
+ WRAPN(moveToGround, items_moveToGround),
+ WRAPN(moveToContainer, items_moveToContainer),
{ NULL, NULL }
};
+static int items_getPosition(lua_State *state)
+{
+ return push_pos(state, Items::getPosition(get_checked_arg(state,1)));
+}
+
+static int items_getContainedItems(lua_State *state)
+{
+ std::vector pvec;
+ Items::getContainedItems(get_checked_arg(state,1),&pvec);
+ push_pointer_vector(state, pvec);
+ return 1;
+}
+
+static const luaL_Reg dfhack_items_funcs[] = {
+ { "getPosition", items_getPosition },
+ { "getContainedItems", items_getContainedItems },
+ { NULL, NULL }
+};
+
+
static bool maps_isBlockBurrowTile(df::burrow *burrow, df::map_block *block, int x, int y)
{
return Maps::isBlockBurrowTile(burrow, block, df::coord2d(x,y));
@@ -642,14 +705,8 @@ static const LuaWrapper::FunctionReg dfhack_maps_module[] = {
static int maps_listBurrowBlocks(lua_State *state)
{
- luaL_checkany(state, 1);
-
- auto ptr = Lua::GetDFObject(state, 1);
- if (!ptr)
- luaL_argerror(state, 1, "invalid burrow type");
-
std::vector pvec;
- Maps::listBurrowBlocks(&pvec, ptr);
+ Maps::listBurrowBlocks(&pvec, get_checked_arg(state,1));
push_pointer_vector(state, pvec);
return 1;
}
@@ -673,6 +730,6 @@ void OpenDFHackApi(lua_State *state)
OpenModule(state, "gui", dfhack_gui_module);
OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs);
OpenModule(state, "units", dfhack_units_module);
- OpenModule(state, "items", dfhack_items_module);
+ OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs);
OpenModule(state, "maps", dfhack_maps_module, dfhack_maps_funcs);
}
diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h
index 9bab02cc8..e7720fa91 100644
--- a/library/include/modules/Items.h
+++ b/library/include/modules/Items.h
@@ -42,6 +42,10 @@ namespace df
struct itemdef;
}
+namespace MapExtras {
+ class MapCache;
+}
+
/**
* \defgroup grp_items Items module and its types
* @ingroup grp_modules
@@ -128,13 +132,15 @@ DFHACK_EXPORT df::unit *getOwner(df::item *item);
DFHACK_EXPORT bool setOwner(df::item *item, df::unit *unit);
/// which item is it contained in?
-DFHACK_EXPORT int32_t getItemContainerID(const df::item * item);
-DFHACK_EXPORT df::item *getItemContainer(const df::item * item);
+DFHACK_EXPORT df::item *getContainer(df::item *item);
/// which items does it contain?
-DFHACK_EXPORT bool getContainedItems(const df::item * item, /*output*/ std::vector &items);
+DFHACK_EXPORT void getContainedItems(df::item *item, /*output*/ std::vector *items);
+
+/// Returns the true position of the item.
+DFHACK_EXPORT df::coord getPosition(df::item *item);
+
+DFHACK_EXPORT bool moveToGround(MapExtras::MapCache &mc, df::item *item, df::coord pos);
+DFHACK_EXPORT bool moveToContainer(MapExtras::MapCache &mc, df::item *item, df::item *container);
-/// read item references, filtered by class
-DFHACK_EXPORT bool readItemRefs(const df::item * item, const df::general_ref_type type,
- /*output*/ std::vector &values);
}
}
\ No newline at end of file
diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua
index a6606d152..626f60bec 100644
--- a/library/lua/dfhack.lua
+++ b/library/lua/dfhack.lua
@@ -86,6 +86,21 @@ function copyall(table)
return rv
end
+function pos2xyz(pos)
+ local x = pos.x
+ if x and x ~= -30000 then
+ return x, pos.y, pos.z
+ end
+end
+
+function xyz2pos(x,y,z)
+ if x then
+ return {x=x,y=y,z=z}
+ else
+ return {x=-30000,y=-30000,z=-30000}
+ end
+end
+
function dfhack.persistent:__tostring()
return ""
diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp
index 20b95bc23..ca15ed278 100644
--- a/library/modules/Items.cpp
+++ b/library/modules/Items.cpp
@@ -39,6 +39,7 @@ using namespace std;
#include "modules/Materials.h"
#include "modules/Items.h"
#include "modules/Units.h"
+#include "modules/MapCache.h"
#include "ModuleFactory.h"
#include "Core.h"
#include "Error.h"
@@ -46,6 +47,7 @@ using namespace std;
#include "df/world.h"
#include "df/item.h"
+#include "df/building.h"
#include "df/tool_uses.h"
#include "df/itemdef_weaponst.h"
#include "df/itemdef_trapcompst.h"
@@ -65,6 +67,8 @@ using namespace std;
#include "df/job_item.h"
#include "df/general_ref.h"
#include "df/general_ref_unit_itemownerst.h"
+#include "df/general_ref_contains_itemst.h"
+#include "df/general_ref_contained_in_itemst.h"
using namespace DFHack;
using namespace df::enums;
@@ -472,44 +476,183 @@ bool Items::setOwner(df::item *item, df::unit *unit)
return true;
}
-
-int32_t Items::getItemContainerID(const df::item * item)
+df::item *Items::getContainer(df::item * item)
{
+ CHECK_NULL_POINTER(item);
+
for (size_t i = 0; i < item->itemrefs.size(); i++)
{
df::general_ref *ref = item->itemrefs[i];
if (ref->getType() == general_ref_type::CONTAINED_IN_ITEM)
- return ref->getID();
+ return ref->getItem();
}
- return -1;
+
+ return NULL;
}
-df::item *Items::getItemContainer(const df::item * item)
+void Items::getContainedItems(df::item *item, std::vector *items)
{
+ CHECK_NULL_POINTER(item);
+
+ items->clear();
+
for (size_t i = 0; i < item->itemrefs.size(); i++)
{
df::general_ref *ref = item->itemrefs[i];
- if (ref->getType() == general_ref_type::CONTAINED_IN_ITEM)
- return ref->getItem();
+ if (ref->getType() != general_ref_type::CONTAINS_ITEM)
+ continue;
+
+ auto child = ref->getItem();
+ if (child)
+ items->push_back(child);
}
- return NULL;
}
-bool Items::getContainedItems(const df::item * item, std::vector &items)
+df::coord Items::getPosition(df::item *item)
{
- return readItemRefs(item, general_ref_type::CONTAINS_ITEM, items);
+ CHECK_NULL_POINTER(item);
+
+ if (item->flags.bits.in_inventory ||
+ item->flags.bits.in_chest ||
+ item->flags.bits.in_building)
+ {
+ for (size_t i = 0; i < item->itemrefs.size(); i++)
+ {
+ df::general_ref *ref = item->itemrefs[i];
+
+ switch (ref->getType())
+ {
+ case general_ref_type::CONTAINED_IN_ITEM:
+ if (auto item2 = ref->getItem())
+ return getPosition(item2);
+ break;
+
+ case general_ref_type::UNIT_HOLDER:
+ if (auto unit = ref->getUnit())
+ return unit->pos;
+ break;
+
+ case general_ref_type::BUILDING_HOLDER:
+ if (auto bld = ref->getBuilding())
+ return df::coord(bld->centerx, bld->centery, bld->z);
+ break;
+ }
+ }
+ }
+
+ return item->pos;
}
-bool Items::readItemRefs(const df::item * item, df::general_ref_type type, std::vector &values)
+static void removeRef(std::vector &vec, df::general_ref_type type, int id)
{
- values.clear();
+ for (int i = vec.size()-1; i >= 0; i--)
+ {
+ df::general_ref *ref = vec[i];
+ if (ref->getType() != type || ref->getID() != id)
+ continue;
- for (size_t i = 0; i < item->itemrefs.size(); i++)
+ vector_erase_at(vec, i);
+ delete ref;
+ }
+}
+
+static bool detachItem(MapExtras::MapCache &mc, df::item *item)
+{
+ if (item->flags.bits.on_ground)
{
- df::general_ref *ref = item->itemrefs[i];
- if (ref->getType() == type)
- values.push_back(ref->getID());
+ if (!mc.removeItemOnGround(item))
+ Core::printerr("Item was marked on_ground, but not in block: %d (%d,%d,%d)\n",
+ item->id, item->pos.x, item->pos.y, item->pos.z);
+
+ item->flags.bits.on_ground = false;
+ return true;
}
+ else if (item->flags.bits.in_inventory)
+ {
+ bool found = false;
- return !values.empty();
+ for (int i = item->itemrefs.size()-1; i >= 0; i--)
+ {
+ df::general_ref *ref = item->itemrefs[i];
+
+ switch (ref->getType())
+ {
+ case general_ref_type::CONTAINED_IN_ITEM:
+ if (auto item2 = ref->getItem())
+ removeRef(item2->itemrefs, general_ref_type::CONTAINS_ITEM, item->id);
+ break;
+
+ case general_ref_type::UNIT_HOLDER:
+ case general_ref_type::BUILDING_HOLDER:
+ return false;
+
+ default:
+ continue;
+ }
+
+ found = true;
+ vector_erase_at(item->itemrefs, i);
+ delete ref;
+ }
+
+ if (!found)
+ return false;
+
+ item->flags.bits.in_inventory = false;
+ return true;
+ }
+ else
+ return false;
+}
+
+static void putOnGround(MapExtras::MapCache &mc, df::item *item, df::coord pos)
+{
+ item->pos = pos;
+ item->flags.bits.on_ground = true;
+
+ if (!mc.addItemOnGround(item))
+ Core::printerr("Could not add item %d to ground at (%d,%d,%d)\n",
+ item->id, pos.x, pos.y, pos.z);
+}
+
+bool DFHack::Items::moveToGround(MapExtras::MapCache &mc, df::item *item, df::coord pos)
+{
+ CHECK_NULL_POINTER(item);
+
+ if (!detachItem(mc, item))
+ return false;
+
+ putOnGround(mc, item, pos);
+ return true;
+}
+
+bool DFHack::Items::moveToContainer(MapExtras::MapCache &mc, df::item *item, df::item *container)
+{
+ CHECK_NULL_POINTER(item);
+ CHECK_NULL_POINTER(container);
+
+ if (!detachItem(mc, item))
+ return false;
+
+ auto ref1 = df::allocate();
+ auto ref2 = df::allocate();
+
+ if (!ref1 || !ref2)
+ {
+ delete ref1; delete ref2;
+ Core::printerr("Could not allocate container refs.\n");
+ putOnGround(mc, item, getPosition(container));
+ return false;
+ }
+
+ item->pos = container->pos;
+ item->flags.bits.in_inventory = true;
+ container->flags.bits.container = true;
+
+ ref1->item_id = item->id;
+ container->itemrefs.push_back(ref1);
+ ref2->item_id = container->id;
+ item->itemrefs.push_back(ref2);
+
+ return true;
}
diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp
index c0aa9b634..fce80d775 100644
--- a/library/modules/Maps.cpp
+++ b/library/modules/Maps.cpp
@@ -596,7 +596,7 @@ void MapExtras::Block::init_item_counts()
if (item_counts) return;
item_counts = new T_item_counts[16];
- memset(item_counts, 0, sizeof(T_item_counts));
+ memset(item_counts, 0, sizeof(T_item_counts)*16);
if (!block) return;
diff --git a/plugins/autodump.cpp b/plugins/autodump.cpp
index a71555b7a..2620d9dea 100644
--- a/plugins/autodump.cpp
+++ b/plugins/autodump.cpp
@@ -182,15 +182,7 @@ static command_result autodump_main(color_ostream &out, vector & parame
// Don't move items if they're already at the cursor
if (pos_cursor != pos_item)
- {
- if (!MC.removeItemOnGround(itm))
- out.printerr("Item %d wasn't in the source block.\n", itm->id);
-
- itm->pos = pos_cursor;
-
- if (!MC.addItemOnGround(itm))
- out.printerr("Could not add item %d to destination block.\n", itm->id);
- }
+ Items::moveToGround(MC, itm, pos_cursor);
}
else // destroy
{