Add core api for moving items between ground and containers.

develop
Alexander Gavrilov 2012-04-12 18:37:27 +04:00
parent 38a8c43a25
commit 2d8611a480
8 changed files with 289 additions and 41 deletions

@ -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
-----------

@ -929,6 +929,9 @@ a lua list containing them.</p>
<div class="section" id="items-module">
<h3><a class="toc-backref" href="#id17">Items module</a></h3>
<ul>
<li><p class="first"><tt class="docutils literal">dfhack.items.getPosition(item)</tt></p>
<p>Returns true <em>x,y,z</em> of the item.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.items.getOwner(item)</tt></p>
<p>Returns the owner unit or <em>nil</em>.</p>
</li>
@ -936,6 +939,18 @@ a lua list containing them.</p>
<p>Replaces the owner of the item. If unit is <em>nil</em>, removes ownership.
Returns <em>false</em> in case of error.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.items.getContainer(item)</tt></p>
<p>Returns the container item or <em>nil</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.items.getContainedItems(item)</tt></p>
<p>Returns a list of items contained in this one.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.items.moveToGround(item,pos)</tt></p>
<p>Move the item to the ground at position. Returns <em>false</em> if impossible.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.items.moveToContainer(item,container)</tt></p>
<p>Move the item to the container. Returns <em>false</em> if impossible.</p>
</li>
</ul>
</div>
<div class="section" id="maps-module">

@ -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<T*> &pvec)
}
}
template<class T>
T *get_checked_arg(lua_State *state, int arg)
{
luaL_checkany(state, arg);
auto ptr = Lua::GetDFObject<T>(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<df::item>(state,1)));
}
static int items_getContainedItems(lua_State *state)
{
std::vector<df::item*> pvec;
Items::getContainedItems(get_checked_arg<df::item>(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<df::burrow>(state, 1);
if (!ptr)
luaL_argerror(state, 1, "invalid burrow type");
std::vector<df::map_block*> pvec;
Maps::listBurrowBlocks(&pvec, ptr);
Maps::listBurrowBlocks(&pvec, get_checked_arg<df::burrow>(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);
}

@ -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<int32_t> &items);
DFHACK_EXPORT void getContainedItems(df::item *item, /*output*/ std::vector<df::item*> *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<int32_t> &values);
}
}

@ -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 "<persistent "..self.entry_id..":"..self.key.."=\""
..self.value.."\":"..table.concat(self.ints,",")..">"

@ -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<df::item*> *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);
}
}
df::coord Items::getPosition(df::item *item)
{
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 NULL;
}
bool Items::getContainedItems(const df::item * item, std::vector<int32_t> &items)
return item->pos;
}
static void removeRef(std::vector<df::general_ref*> &vec, df::general_ref_type type, int id)
{
for (int i = vec.size()-1; i >= 0; i--)
{
return readItemRefs(item, general_ref_type::CONTAINS_ITEM, items);
df::general_ref *ref = vec[i];
if (ref->getType() != type || ref->getID() != id)
continue;
vector_erase_at(vec, i);
delete ref;
}
}
bool Items::readItemRefs(const df::item * item, df::general_ref_type type, std::vector<int32_t> &values)
static bool detachItem(MapExtras::MapCache &mc, df::item *item)
{
if (item->flags.bits.on_ground)
{
values.clear();
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);
for (size_t i = 0; i < item->itemrefs.size(); i++)
item->flags.bits.on_ground = false;
return true;
}
else if (item->flags.bits.in_inventory)
{
bool found = false;
for (int i = item->itemrefs.size()-1; i >= 0; i--)
{
df::general_ref *ref = item->itemrefs[i];
if (ref->getType() == type)
values.push_back(ref->getID());
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;
}
return !values.empty();
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<df::general_ref_contains_itemst>();
auto ref2 = df::allocate<df::general_ref_contained_in_itemst>();
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;
}

@ -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;

@ -182,15 +182,7 @@ static command_result autodump_main(color_ostream &out, vector <string> & 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
{