Merge remote-tracking branch 'angavrilov/master'

develop
Kelly Martin 2012-04-13 15:36:18 -05:00
commit 0387a3c017
17 changed files with 832 additions and 75 deletions

@ -663,6 +663,14 @@ Job module
Units module Units module
------------ ------------
* ``dfhack.units.getPosition(unit)``
Returns true *x,y,z* of the unit; may be not equal to unit.pos if caged.
* ``dfhack.units.getContainer(unit)``
Returns the container (cage) item or *nil*.
* ``dfhack.units.setNickname(unit,nick)`` * ``dfhack.units.setNickname(unit,nick)``
Sets the unit's nickname properly. Sets the unit's nickname properly.
@ -699,6 +707,10 @@ Units module
Items module Items module
------------ ------------
* ``dfhack.items.getPosition(item)``
Returns true *x,y,z* of the item; may be not equal to item.pos if in inventory.
* ``dfhack.items.getOwner(item)`` * ``dfhack.items.getOwner(item)``
Returns the owner unit or *nil*. Returns the owner unit or *nil*.
@ -708,6 +720,22 @@ Items module
Replaces the owner of the item. If unit is *nil*, removes ownership. Replaces the owner of the item. If unit is *nil*, removes ownership.
Returns *false* in case of error. 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 Maps module
----------- -----------

@ -900,6 +900,12 @@ a lua list containing them.</p>
<div class="section" id="units-module"> <div class="section" id="units-module">
<h3><a class="toc-backref" href="#id16">Units module</a></h3> <h3><a class="toc-backref" href="#id16">Units module</a></h3>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">dfhack.units.getPosition(unit)</tt></p>
<p>Returns true <em>x,y,z</em> of the unit; may be not equal to unit.pos if caged.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.getContainer(unit)</tt></p>
<p>Returns the container (cage) item or <em>nil</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.setNickname(unit,nick)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.units.setNickname(unit,nick)</tt></p>
<p>Sets the unit's nickname properly.</p> <p>Sets the unit's nickname properly.</p>
</li> </li>
@ -929,6 +935,9 @@ a lua list containing them.</p>
<div class="section" id="items-module"> <div class="section" id="items-module">
<h3><a class="toc-backref" href="#id17">Items module</a></h3> <h3><a class="toc-backref" href="#id17">Items module</a></h3>
<ul> <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; may be not equal to item.pos if in inventory.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.items.getOwner(item)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.items.getOwner(item)</tt></p>
<p>Returns the owner unit or <em>nil</em>.</p> <p>Returns the owner unit or <em>nil</em>.</p>
</li> </li>
@ -936,6 +945,18 @@ a lua list containing them.</p>
<p>Replaces the owner of the item. If unit is <em>nil</em>, removes ownership. <p>Replaces the owner of the item. If unit is <em>nil</em>, removes ownership.
Returns <em>false</em> in case of error.</p> Returns <em>false</em> in case of error.</p>
</li> </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> </ul>
</div> </div>
<div class="section" id="maps-module"> <div class="section" id="maps-module">

@ -128,17 +128,6 @@ void compound_identity::Init(Core *core)
// they are called in an undefined order. // they are called in an undefined order.
for (compound_identity *p = list; p; p = p->next) for (compound_identity *p = list; p; p = p->next)
p->doInit(core); p->doInit(core);
//FIXME: ... nuked. the group was empty...
/*
// Read pre-filled vtable ptrs
OffsetGroup *ptr_table = core->vinfo->getGroup("vtable");
for (virtual_identity *p = list; p; p = p->next) {
void * tmp;
if (ptr_table->getSafeAddress(p->getName(),tmp))
p->vtable_ptr = tmp;
}
*/
} }
bitfield_identity::bitfield_identity(size_t size, bitfield_identity::bitfield_identity(size_t size,
@ -223,17 +212,23 @@ virtual_identity::virtual_identity(size_t size, TAllocateFn alloc,
{ {
} }
/* Vtable name to identity lookup. */
static std::map<std::string, virtual_identity*> name_lookup; static std::map<std::string, virtual_identity*> name_lookup;
/* Vtable pointer to identity lookup. */
std::map<void*, virtual_identity*> virtual_identity::known;
void virtual_identity::doInit(Core *core) void virtual_identity::doInit(Core *core)
{ {
struct_identity::doInit(core); struct_identity::doInit(core);
name_lookup[getOriginalName()] = this; auto vtname = getOriginalName();
} name_lookup[vtname] = this;
/* Vtable to identity lookup. */ vtable_ptr = core->vinfo->getVTable(vtname);
std::map<void*, virtual_identity*> virtual_identity::known; if (vtable_ptr)
known[vtable_ptr] = this;
}
virtual_identity *virtual_identity::get(virtual_ptr instance_ptr) virtual_identity *virtual_identity::get(virtual_ptr instance_ptr)
{ {
@ -265,8 +260,10 @@ virtual_identity *virtual_identity::get(virtual_ptr instance_ptr)
<< ", previous 0x" << unsigned(p->vtable_ptr) << std::dec << std::endl; << ", previous 0x" << unsigned(p->vtable_ptr) << std::dec << std::endl;
abort(); abort();
} else if (!p->vtable_ptr) { } else if (!p->vtable_ptr) {
std::cerr << "class '" << p->getName() << "': vtable = 0x" uint32_t pv = unsigned(vtable);
<< std::hex << unsigned(vtable) << std::dec << std::endl; pv -= Core::getInstance().vinfo->getRebaseDelta();
std::cerr << "<vtable-address name='" << p->getOriginalName() << "' value='0x"
<< std::hex << pv << std::dec << "'/>" << std::endl;
} }
known[vtable] = p; known[vtable] = p;

@ -45,6 +45,7 @@ distribution.
#include "modules/Items.h" #include "modules/Items.h"
#include "modules/Materials.h" #include "modules/Materials.h"
#include "modules/Maps.h" #include "modules/Maps.h"
#include "modules/MapCache.h"
#include "LuaWrapper.h" #include "LuaWrapper.h"
#include "LuaTools.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 * * Per-world persistent configuration storage API *
**************************************************/ **************************************************/
@ -599,6 +627,7 @@ static const luaL_Reg dfhack_job_funcs[] = {
static const LuaWrapper::FunctionReg dfhack_units_module[] = { static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, getContainer),
WRAPM(Units, setNickname), WRAPM(Units, setNickname),
WRAPM(Units, getVisibleName), WRAPM(Units, getVisibleName),
WRAPM(Units, getNemesis), WRAPM(Units, getNemesis),
@ -610,12 +639,57 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
{ NULL, NULL } { NULL, NULL }
}; };
static int units_getPosition(lua_State *state)
{
return push_pos(state, Units::getPosition(get_checked_arg<df::unit>(state,1)));
}
static const luaL_Reg dfhack_units_funcs[] = {
{ "getPosition", units_getPosition },
{ 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[] = { static const LuaWrapper::FunctionReg dfhack_items_module[] = {
WRAPM(Items, getOwner), WRAPM(Items, getOwner),
WRAPM(Items, setOwner), 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 } { NULL, NULL }
}; };
static bool maps_isBlockBurrowTile(df::burrow *burrow, df::map_block *block, int x, int y) static bool maps_isBlockBurrowTile(df::burrow *burrow, df::map_block *block, int x, int y)
{ {
return Maps::isBlockBurrowTile(burrow, block, df::coord2d(x,y)); return Maps::isBlockBurrowTile(burrow, block, df::coord2d(x,y));
@ -642,14 +716,8 @@ static const LuaWrapper::FunctionReg dfhack_maps_module[] = {
static int maps_listBurrowBlocks(lua_State *state) 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; 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); push_pointer_vector(state, pvec);
return 1; return 1;
} }
@ -672,7 +740,7 @@ void OpenDFHackApi(lua_State *state)
LuaWrapper::SetFunctionWrappers(state, dfhack_module); LuaWrapper::SetFunctionWrappers(state, dfhack_module);
OpenModule(state, "gui", dfhack_gui_module); OpenModule(state, "gui", dfhack_gui_module);
OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs); OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs);
OpenModule(state, "units", dfhack_units_module); OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs);
OpenModule(state, "items", dfhack_items_module); OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs);
OpenModule(state, "maps", dfhack_maps_module, dfhack_maps_funcs); OpenModule(state, "maps", dfhack_maps_module, dfhack_maps_funcs);
} }

@ -118,7 +118,8 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem)
string type, name, value; string type, name, value;
const char *cstr_type = pMemEntry->Value(); const char *cstr_type = pMemEntry->Value();
type = cstr_type; type = cstr_type;
if(type == "global-address") bool is_vtable = (type == "vtable-address");
if(is_vtable || type == "global-address")
{ {
const char *cstr_key = pMemEntry->Attribute("name"); const char *cstr_key = pMemEntry->Attribute("name");
if(!cstr_key) if(!cstr_key)
@ -129,7 +130,11 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem)
cerr << "Dummy symbol table entry: " << cstr_key << endl; cerr << "Dummy symbol table entry: " << cstr_key << endl;
continue; continue;
} }
mem->setAddress(cstr_key, strtol(cstr_value, 0, 0)); uint32_t addr = strtol(cstr_value, 0, 0);
if (is_vtable)
mem->setVTable(cstr_key, addr);
else
mem->setAddress(cstr_key, addr);
} }
else if (type == "md5-hash") else if (type == "md5-hash")
{ {

@ -203,6 +203,18 @@ namespace DFHack
return ENUM_ATTR(tiletype_shape, passable_flow, tileShape(tiletype)); return ENUM_ATTR(tiletype_shape, passable_flow, tileShape(tiletype));
} }
inline
bool isWalkable(df::tiletype tiletype)
{
return ENUM_ATTR(tiletype_shape, walkable, tileShape(tiletype));
}
inline
bool isWalkableUp(df::tiletype tiletype)
{
return ENUM_ATTR(tiletype_shape, walkable_up, tileShape(tiletype));
}
inline inline
bool isWallTerrain(df::tiletype tiletype) bool isWallTerrain(df::tiletype tiletype)
{ {

@ -51,13 +51,15 @@ namespace DFHack
std::vector <std::string> md5_list; std::vector <std::string> md5_list;
std::vector <uint32_t> PE_list; std::vector <uint32_t> PE_list;
std::map <std::string, uint32_t> Addresses; std::map <std::string, uint32_t> Addresses;
std::map <std::string, uint32_t> VTables;
uint32_t base; uint32_t base;
int rebase_delta;
std::string version; std::string version;
OSType OS; OSType OS;
public: public:
VersionInfo() VersionInfo()
{ {
base = 0; base = 0; rebase_delta = 0;
version = "invalid"; version = "invalid";
OS = OS_BAD; OS = OS_BAD;
}; };
@ -66,12 +68,15 @@ namespace DFHack
md5_list = rhs.md5_list; md5_list = rhs.md5_list;
PE_list = rhs.PE_list; PE_list = rhs.PE_list;
Addresses = rhs.Addresses; Addresses = rhs.Addresses;
VTables = rhs.VTables;
base = rhs.base; base = rhs.base;
rebase_delta = rhs.rebase_delta;
version = rhs.version; version = rhs.version;
OS = rhs.OS; OS = rhs.OS;
}; };
uint32_t getBase () const { return base; }; uint32_t getBase () const { return base; };
int getRebaseDelta() const { return rebase_delta; }
void setBase (const uint32_t _base) { base = _base; }; void setBase (const uint32_t _base) { base = _base; };
void rebaseTo(const uint32_t new_base) void rebaseTo(const uint32_t new_base)
{ {
@ -79,13 +84,11 @@ namespace DFHack
int64_t newx = new_base; int64_t newx = new_base;
int64_t rebase = newx - old; int64_t rebase = newx - old;
base = new_base; base = new_base;
auto iter = Addresses.begin(); rebase_delta += rebase;
while (iter != Addresses.end()) for (auto iter = Addresses.begin(); iter != Addresses.end(); ++iter)
{ iter->second += rebase;
uint32_t & ref = (*iter).second; for (auto iter = VTables.begin(); iter != VTables.end(); ++iter)
ref += rebase; iter->second += rebase;
iter ++;
}
}; };
void addMD5 (const std::string & _md5) void addMD5 (const std::string & _md5)
@ -125,6 +128,7 @@ namespace DFHack
value = (T) (*i).second; value = (T) (*i).second;
return true; return true;
}; };
uint32_t getAddress (const std::string& key) const uint32_t getAddress (const std::string& key) const
{ {
auto i = Addresses.find(key); auto i = Addresses.find(key);
@ -133,6 +137,18 @@ namespace DFHack
return (*i).second; return (*i).second;
} }
void setVTable (const std::string& key, const uint32_t value)
{
VTables[key] = value;
};
void *getVTable (const std::string& key) const
{
auto i = VTables.find(key);
if(i == VTables.end())
return 0;
return (void*)i->second;
}
void setOS(const OSType os) void setOS(const OSType os)
{ {
OS = os; OS = os;

@ -42,6 +42,10 @@ namespace df
struct itemdef; struct itemdef;
} }
namespace MapExtras {
class MapCache;
}
/** /**
* \defgroup grp_items Items module and its types * \defgroup grp_items Items module and its types
* @ingroup grp_modules * @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); DFHACK_EXPORT bool setOwner(df::item *item, df::unit *unit);
/// which item is it contained in? /// which item is it contained in?
DFHACK_EXPORT int32_t getItemContainerID(const df::item * item); DFHACK_EXPORT df::item *getContainer(df::item *item);
DFHACK_EXPORT df::item *getItemContainer(const df::item * item);
/// which items does it contain? /// 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);
} }
} }

@ -262,12 +262,12 @@ extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, d
DFHACK_EXPORT df::burrow *findBurrowByName(std::string name); DFHACK_EXPORT df::burrow *findBurrowByName(std::string name);
void listBurrowBlocks(std::vector<df::map_block*> *pvec, df::burrow *burrow); DFHACK_EXPORT void listBurrowBlocks(std::vector<df::map_block*> *pvec, df::burrow *burrow);
df::block_burrow *getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create = false); DFHACK_EXPORT df::block_burrow *getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create = false);
bool isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile); DFHACK_EXPORT bool isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile);
bool setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable); DFHACK_EXPORT bool setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable);
inline bool isBurrowTile(df::burrow *burrow, df::coord tile) { inline bool isBurrowTile(df::burrow *burrow, df::coord tile) {
return isBlockBurrowTile(burrow, getTileBlock(tile), tile); return isBlockBurrowTile(burrow, getTileBlock(tile), tile);

@ -193,6 +193,11 @@ DFHACK_EXPORT int32_t GetDwarfCivId ( void );
DFHACK_EXPORT void CopyNameTo(df::unit *creature, df::language_name * target); DFHACK_EXPORT void CopyNameTo(df::unit *creature, df::language_name * target);
/// Returns the true position of the unit (non-trivial in case of caged).
DFHACK_EXPORT df::coord getPosition(df::unit *unit);
DFHACK_EXPORT df::item *getContainer(df::unit *unit);
DFHACK_EXPORT void setNickname(df::unit *unit, std::string nick); DFHACK_EXPORT void setNickname(df::unit *unit, std::string nick);
DFHACK_EXPORT df::language_name *getVisibleName(df::unit *unit); DFHACK_EXPORT df::language_name *getVisibleName(df::unit *unit);

@ -86,6 +86,21 @@ function copyall(table)
return rv return rv
end 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() function dfhack.persistent:__tostring()
return "<persistent "..self.entry_id..":"..self.key.."=\"" return "<persistent "..self.entry_id..":"..self.key.."=\""
..self.value.."\":"..table.concat(self.ints,",")..">" ..self.value.."\":"..table.concat(self.ints,",")..">"

@ -39,6 +39,7 @@ using namespace std;
#include "modules/Materials.h" #include "modules/Materials.h"
#include "modules/Items.h" #include "modules/Items.h"
#include "modules/Units.h" #include "modules/Units.h"
#include "modules/MapCache.h"
#include "ModuleFactory.h" #include "ModuleFactory.h"
#include "Core.h" #include "Core.h"
#include "Error.h" #include "Error.h"
@ -46,6 +47,7 @@ using namespace std;
#include "df/world.h" #include "df/world.h"
#include "df/item.h" #include "df/item.h"
#include "df/building.h"
#include "df/tool_uses.h" #include "df/tool_uses.h"
#include "df/itemdef_weaponst.h" #include "df/itemdef_weaponst.h"
#include "df/itemdef_trapcompst.h" #include "df/itemdef_trapcompst.h"
@ -65,6 +67,8 @@ using namespace std;
#include "df/job_item.h" #include "df/job_item.h"
#include "df/general_ref.h" #include "df/general_ref.h"
#include "df/general_ref_unit_itemownerst.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 DFHack;
using namespace df::enums; using namespace df::enums;
@ -454,6 +458,8 @@ bool Items::setOwner(df::item *item, df::unit *unit)
vector_erase_at(item->itemrefs, i); vector_erase_at(item->itemrefs, i);
} }
item->flags.bits.owned = false;
if (unit) if (unit)
{ {
auto ref = df::allocate<df::general_ref_unit_itemownerst>(); auto ref = df::allocate<df::general_ref_unit_itemownerst>();
@ -466,50 +472,193 @@ bool Items::setOwner(df::item *item, df::unit *unit)
insert_into_vector(unit->owned_items, item->id); insert_into_vector(unit->owned_items, item->id);
item->itemrefs.push_back(ref); item->itemrefs.push_back(ref);
} }
else
item->flags.bits.owned = false;
return true; return true;
} }
df::item *Items::getContainer(df::item * item)
int32_t Items::getItemContainerID(const df::item * item)
{ {
CHECK_NULL_POINTER(item);
for (size_t i = 0; i < item->itemrefs.size(); i++) for (size_t i = 0; i < item->itemrefs.size(); i++)
{ {
df::general_ref *ref = item->itemrefs[i]; df::general_ref *ref = item->itemrefs[i];
if (ref->getType() == general_ref_type::CONTAINED_IN_ITEM) 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++) for (size_t i = 0; i < item->itemrefs.size(); i++)
{ {
df::general_ref *ref = item->itemrefs[i]; df::general_ref *ref = item->itemrefs[i];
if (ref->getType() == general_ref_type::CONTAINED_IN_ITEM) if (ref->getType() != general_ref_type::CONTAINS_ITEM)
return ref->getItem(); continue;
auto child = ref->getItem();
if (child)
items->push_back(child);
} }
return NULL;
} }
bool Items::getContainedItems(const df::item * item, std::vector<int32_t> &items) 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 Units::getPosition(unit);
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;
}
static void removeRef(std::vector<df::general_ref*> &vec, df::general_ref_type type, int id)
{ {
return readItemRefs(item, general_ref_type::CONTAINS_ITEM, items); for (int i = vec.size()-1; i >= 0; i--)
{
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)
{ {
values.clear(); if (item->flags.bits.on_ground)
{
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)
{ {
df::general_ref *ref = item->itemrefs[i]; bool found = false;
if (ref->getType() == type)
values.push_back(ref->getID()); 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())
{
item2->flags.bits.weight_computed = false;
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<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;
} }
return !values.empty(); item->pos = container->pos;
item->flags.bits.in_inventory = true;
container->flags.bits.container = true;
container->flags.bits.weight_computed = false;
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; if (item_counts) return;
item_counts = new T_item_counts[16]; 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; if (!block) return;

@ -40,6 +40,7 @@ using namespace std;
// we connect to those // we connect to those
#include "modules/Units.h" #include "modules/Units.h"
#include "modules/Items.h"
#include "modules/Materials.h" #include "modules/Materials.h"
#include "modules/Translation.h" #include "modules/Translation.h"
#include "ModuleFactory.h" #include "ModuleFactory.h"
@ -500,6 +501,34 @@ void Units::CopyNameTo(df::unit * creature, df::language_name * target)
Translation::copyName(&creature->name, target); Translation::copyName(&creature->name, target);
} }
df::coord Units::getPosition(df::unit *unit)
{
CHECK_NULL_POINTER(unit);
if (unit->flags1.bits.caged)
{
auto cage = getContainer(unit);
if (cage)
return Items::getPosition(cage);
}
return unit->pos;
}
df::item *Units::getContainer(df::unit *unit)
{
CHECK_NULL_POINTER(unit);
for (size_t i = 0; i < unit->refs.size(); i++)
{
df::general_ref *ref = unit->refs[i];
if (ref->getType() == general_ref_type::CONTAINED_IN_ITEM)
return ref->getItem();
}
return NULL;
}
void Units::setNickname(df::unit *unit, std::string nick) void Units::setNickname(df::unit *unit, std::string nick)
{ {
CHECK_NULL_POINTER(unit); CHECK_NULL_POINTER(unit);

@ -97,6 +97,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(feature feature.cpp) DFHACK_PLUGIN(feature feature.cpp)
DFHACK_PLUGIN(lair lair.cpp) DFHACK_PLUGIN(lair lair.cpp)
DFHACK_PLUGIN(zone zone.cpp) DFHACK_PLUGIN(zone zone.cpp)
DFHACK_PLUGIN(burrows burrows.cpp)
# not yet. busy with other crud again... # not yet. busy with other crud again...
#DFHACK_PLUGIN(versionosd versionosd.cpp) #DFHACK_PLUGIN(versionosd versionosd.cpp)
endif() endif()

@ -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 // Don't move items if they're already at the cursor
if (pos_cursor != pos_item) if (pos_cursor != pos_item)
{ Items::moveToGround(MC, itm, pos_cursor);
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);
}
} }
else // destroy else // destroy
{ {

@ -0,0 +1,413 @@
#include "Core.h"
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Gui.h"
#include "modules/Job.h"
#include "modules/Maps.h"
#include "modules/MapCache.h"
#include "modules/World.h"
#include "TileTypes.h"
#include "DataDefs.h"
#include "df/ui.h"
#include "df/world.h"
#include "df/unit.h"
#include "df/burrow.h"
#include "df/map_block.h"
#include "df/job.h"
#include "df/job_list_link.h"
#include "MiscUtils.h"
#include <stdlib.h>
using std::vector;
using std::string;
using std::endl;
using namespace DFHack;
using namespace df::enums;
using namespace dfproto;
using df::global::ui;
using df::global::world;
/*
* Initialization.
*/
static command_result burrow(color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("burrows");
static void init_map(color_ostream &out);
static void deinit_map(color_ostream &out);
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(
"burrow", "Miscellaneous burrow control.", burrow, false,
" burrow enable options...\n"
" burrow disable options...\n"
" Enable or disable features of the plugin.\n"
" See below for a list and explanation.\n"
"Implemented features:\n"
" auto-grow\n"
" When a wall inside a burrow with a name ending in '+' is dug\n"
" out, the burrow is extended to newly-revealed adjacent walls.\n"
" Digging 1-wide corridors with the miner inside the burrow is SLOW.\n"
));
if (Core::getInstance().isMapLoaded())
init_map(out);
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
deinit_map(out);
return CR_OK;
}
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
{
switch (event) {
case SC_MAP_LOADED:
deinit_map(out);
if (df::global::game_mode &&
*df::global::game_mode == GAMEMODE_DWARF)
init_map(out);
break;
case SC_MAP_UNLOADED:
deinit_map(out);
break;
default:
break;
}
return CR_OK;
}
/*
* State change tracking.
*/
static int name_burrow_id = -1;
static void handle_burrow_rename(color_ostream &out, df::burrow *burrow);
static void detect_burrow_renames(color_ostream &out)
{
if (ui->main.mode == ui_sidebar_mode::Burrows &&
ui->burrows.in_edit_name_mode &&
ui->burrows.sel_id >= 0)
{
name_burrow_id = ui->burrows.sel_id;
}
else if (name_burrow_id >= 0)
{
auto burrow = df::burrow::find(name_burrow_id);
name_burrow_id = -1;
if (burrow)
handle_burrow_rename(out, burrow);
}
}
struct DigJob {
int id;
df::job_type job;
df::coord pos;
df::tiletype old_tile;
};
static int next_job_id_save = 0;
static std::map<int,DigJob> diggers;
static void handle_dig_complete(color_ostream &out, df::job_type job, df::coord pos,
df::tiletype old_tile, df::tiletype new_tile);
static void detect_digging(color_ostream &out)
{
for (auto it = diggers.begin(); it != diggers.end();)
{
auto worker = df::unit::find(it->first);
if (!worker || !worker->job.current_job ||
worker->job.current_job->id != it->second.id)
{
//out.print("Dig job %d expired.\n", it->second.id);
df::coord pos = it->second.pos;
if (auto block = Maps::getTileBlock(pos))
{
df::tiletype new_tile = block->tiletype[pos.x&15][pos.y&15];
//out.print("Tile %d -> %d\n", it->second.old_tile, new_tile);
if (new_tile != it->second.old_tile)
{
handle_dig_complete(out, it->second.job, pos, it->second.old_tile, new_tile);
//if (worker && !worker->job.current_job)
// worker->counters.think_counter = worker->counters.job_counter = 0;
}
}
auto cur = it; ++it; diggers.erase(cur);
}
else
++it;
}
std::vector<df::job*> jvec;
if (Job::listNewlyCreated(&jvec, &next_job_id_save))
{
for (size_t i = 0; i < jvec.size(); i++)
{
auto job = jvec[i];
auto type = ENUM_ATTR(job_type, type, job->job_type);
if (type != job_type_class::Digging)
continue;
auto worker = Job::getWorker(job);
if (!worker)
continue;
df::coord pos = job->pos;
auto block = Maps::getTileBlock(pos);
if (!block)
continue;
auto &info = diggers[worker->id];
//out.print("New dig job %d.\n", job->id);
info.id = job->id;
info.job = job->job_type;
info.pos = pos;
info.old_tile = block->tiletype[pos.x&15][pos.y&15];
}
}
}
static bool active = false;
static bool auto_grow = false;
static std::vector<int> grow_burrows;
DFhackCExport command_result plugin_onupdate(color_ostream &out)
{
if (!active || !auto_grow)
return CR_OK;
detect_burrow_renames(out);
detect_digging(out);
return CR_OK;
}
/*
* Config and processing
*/
static void parse_names()
{
auto &list = ui->burrows.list;
grow_burrows.clear();
for (size_t i = 0; i < list.size(); i++)
{
auto burrow = list[i];
if (!burrow->name.empty() && burrow->name[burrow->name.size()-1] == '+')
grow_burrows.push_back(burrow->id);
}
}
static void reset_tracking()
{
name_burrow_id = -1;
diggers.clear();
next_job_id_save = 0;
}
static void init_map(color_ostream &out)
{
auto config = Core::getInstance().getWorld()->GetPersistentData("burrows/config");
if (config.isValid())
{
auto_grow = !!(config.ival(0) & 1);
}
parse_names();
reset_tracking();
active = true;
if (auto_grow && !grow_burrows.empty())
out.print("Auto-growing %d burrows.\n", grow_burrows.size());
}
static void deinit_map(color_ostream &out)
{
active = false;
auto_grow = false;
reset_tracking();
}
static PersistentDataItem create_config(color_ostream &out)
{
bool created;
auto rv = Core::getInstance().getWorld()->GetPersistentData("burrows/config", &created);
if (created && rv.isValid())
rv.ival(0) = 0;
if (!rv.isValid())
out.printerr("Could not write configuration.");
return rv;
}
static void enable_auto_grow(color_ostream &out, bool enable)
{
if (enable == auto_grow)
return;
auto config = create_config(out);
if (!config.isValid())
return;
if (enable)
config.ival(0) |= 1;
else
config.ival(0) &= ~1;
auto_grow = enable;
if (enable)
{
parse_names();
reset_tracking();
}
}
static void handle_burrow_rename(color_ostream &out, df::burrow *burrow)
{
parse_names();
}
static void add_to_burrows(std::vector<df::burrow*> &burrows, df::coord pos)
{
for (size_t i = 0; i < burrows.size(); i++)
Maps::setBurrowTile(burrows[i], pos, true);
}
static void add_walls_to_burrows(color_ostream &out, std::vector<df::burrow*> &burrows,
MapExtras::MapCache &mc, df::coord pos1, df::coord pos2)
{
for (int x = pos1.x; x <= pos2.x; x++)
{
for (int y = pos1.y; y <= pos2.y; y++)
{
for (int z = pos1.z; z <= pos2.z; z++)
{
df::coord pos(x,y,z);
auto tile = mc.tiletypeAt(pos);
if (isWallTerrain(tile))
add_to_burrows(burrows, pos);
}
}
}
}
static void handle_dig_complete(color_ostream &out, df::job_type job, df::coord pos,
df::tiletype old_tile, df::tiletype new_tile)
{
if (!isWalkable(new_tile))
return;
std::vector<df::burrow*> to_grow;
for (size_t i = 0; i < grow_burrows.size(); i++)
{
auto b = df::burrow::find(grow_burrows[i]);
if (b && Maps::isBurrowTile(b, pos))
to_grow.push_back(b);
}
//out.print("%d to grow.\n", to_grow.size());
if (to_grow.empty())
return;
MapExtras::MapCache mc;
if (!isWalkable(old_tile))
{
add_walls_to_burrows(out, to_grow, mc, pos+df::coord(-1,-1,0), pos+df::coord(1,1,0));
if (isWalkableUp(new_tile))
add_to_burrows(to_grow, pos+df::coord(0,0,1));
if (tileShape(new_tile) == tiletype_shape::RAMP)
{
add_walls_to_burrows(out, to_grow, mc,
pos+df::coord(-1,-1,1), pos+df::coord(1,1,1));
}
}
if (LowPassable(new_tile) && !LowPassable(old_tile))
{
add_to_burrows(to_grow, pos-df::coord(0,0,1));
if (tileShape(new_tile) == tiletype_shape::RAMP_TOP)
{
add_walls_to_burrows(out, to_grow, mc,
pos+df::coord(-1,-1,-1), pos+df::coord(1,1,-1));
}
}
}
static command_result burrow(color_ostream &out, vector <string> &parameters)
{
CoreSuspender suspend;
if (!active)
{
out.printerr("The plugin cannot be used without map.\n");
return CR_FAILURE;
}
string cmd;
if (!parameters.empty())
cmd = parameters[0];
if (cmd == "enable" || cmd == "disable")
{
if (parameters.size() < 2)
return CR_WRONG_USAGE;
bool state = (cmd == "enable");
for (int i = 1; i < parameters.size(); i++)
{
string &option = parameters[i];
if (option == "auto-grow")
enable_auto_grow(out, state);
else
return CR_WRONG_USAGE;
}
}
else
{
if (!parameters.empty() && cmd != "?")
out.printerr("Invalid command: %s\n", cmd.c_str());
return CR_WRONG_USAGE;
}
return CR_OK;
}