diff --git a/Memory.xml b/Memory.xml
index d40c4a737..d92156255 100644
--- a/Memory.xml
+++ b/Memory.xml
@@ -870,7 +870,7 @@
-
+
@@ -995,7 +995,9 @@
- (in the vtable)
+
+
+
@@ -2948,6 +2950,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/include/dfhack/DFTypes.h b/library/include/dfhack/DFTypes.h
index 3983122f8..f53e5afa3 100644
--- a/library/include/dfhack/DFTypes.h
+++ b/library/include/dfhack/DFTypes.h
@@ -124,46 +124,46 @@ struct t_item_df40d
//They all seem to be valid on 40d as well
struct naked_itemflags
{
- unsigned int on_ground : 1; // Item on ground
- unsigned int in_job : 1; // item currently being used in a job
- unsigned int in_inventory : 1; // Item in a creatures inventory
- unsigned int u_ngrd1 : 1; // only occurs when not on ground, unknown function
+ unsigned int on_ground : 1; // 0000 0001 Item on ground
+ unsigned int in_job : 1; // 0000 0002 Item currently being used in a job
+ unsigned int u_ngrd1 : 1; // 0000 0004 unknown, unseen
+ unsigned int in_inventory : 1; // 0000 0008 Item in a creature or workshop inventory
+
+ unsigned int u_ngrd2 : 1; // 0000 0010 unknown, lost (artifact)?, unseen
+ unsigned int in_building : 1; // 0000 0020 Part of a building (including mechanisms, bodies in coffins)
+ unsigned int u_ngrd3 : 1; // 0000 0040 unknown, unseen
+ unsigned int dead_dwarf : 1; // 0000 0080 Dwarf's dead body or body part
+
+ unsigned int rotten : 1; // 0000 0100 Rotten food
+ unsigned int spider_web : 1; // 0000 0200 Thread in spider web
+ unsigned int construction : 1; // 0000 0400 Material used in construction
+ unsigned int u_ngrd5 : 1; // 0000 0800 unknown, unseen
+
+ unsigned int unk3 : 1; // 0000 1000 unknown, unseen
+ unsigned int u_ngrd6 : 1; // 0000 2000 unknown, unseen
+ unsigned int foreign : 1; // 0000 4000 Item is imported
+ unsigned int u_ngrd7 : 1; // 0000 8000 unknown, unseen
+
+ unsigned int owned : 1; // 0001 0000 Item is owned by a dwarf
+ unsigned int unk4 : 1; // 0002 0000 unknown, unseen
+ unsigned int artifact1 : 1; // 0004 0000 Artifact ?
+ unsigned int forbid : 1; // 0008 0000 Forbidden item
- unsigned int in_workshop : 1; // Item is in a workshops inventory
- unsigned int u_ngrd2 : 1; // only occurs when not on ground, unknown function
- unsigned int u_ngrd3 : 1; // only occurs when not on ground, unknown function
- unsigned int rotten : 1; // Item is rotten
-
- unsigned int unk1 : 1; // unknown function
- unsigned int u_ngrd4 : 1; // only occurs when not on ground, unknown function
- unsigned int unk2 : 1; // unknown function
- unsigned int u_ngrd5 : 1; // only occurs when not on ground, unknown function
-
- unsigned int unk3 : 1; // unknown function
- unsigned int u_ngrd6 : 1; // only occurs when not on ground, unknown function
- unsigned int narrow : 1; // Item is narrow
- unsigned int u_ngrd7 : 1; // only occurs when not on ground, unknown function
-
- unsigned int worn : 1; // item shows wear
- unsigned int unk4 : 1; // unknown function
- unsigned int u_ngrd8 : 1; // only occurs when not on ground, unknown function
- unsigned int forbid : 1; // designate forbid item
-
- unsigned int unk5 : 1; // unknown function
- unsigned int dump : 1; // designate dump item
- unsigned int on_fire: 1; //indicates if item is on fire, Will Set Item On Fire if Set!
- unsigned int melt : 1; // designate melt item, if item cannot be melted, does nothing it seems
+ unsigned int unk5 : 1; // 0010 0000 unknown, unseen
+ unsigned int dump : 1; // 0020 0000 Designated for dumping
+ unsigned int on_fire: 1; // 0040 0000 Indicates if item is on fire, Will Set Item On Fire if Set!
+ unsigned int melt : 1; // 0080 0000 Designated for melting, if applicable
// 0100 0000 - 8000 0000
- unsigned int hidden : 1; // designate hide item
- unsigned int u_ngrd9 : 1; // only occurs when not on ground, unknown function
- unsigned int unk6 : 1; // unknown function
- unsigned int unk7 : 1; // unknown function
+ unsigned int hidden : 1; // 0100 0000 Hidden item
+ unsigned int in_chest : 1; // 0200 0000 Stored in chest/part of well?
+ unsigned int unk6 : 1; // 0400 0000 unknown, unseen
+ unsigned int artifact2 : 1; // 0800 0000 Artifact ?
- unsigned int unk8 : 1; // unknown function
- unsigned int unk9 : 1; // unknown function
- unsigned int unk10 : 1; // unknown function
- unsigned int unk11 : 1; // unknown function
+ unsigned int unk8 : 1; // 1000 0000 unknown, unseen
+ unsigned int unk9 : 1; // 2000 0000 unknown, set when viewing details
+ unsigned int unk10 : 1; // 4000 0000 unknown, unseen
+ unsigned int unk11 : 1; // 8000 0000 unknown, unseen
};
union t_itemflags
diff --git a/library/include/dfhack/modules/Creatures.h b/library/include/dfhack/modules/Creatures.h
index 1585692ba..6a1218dd8 100644
--- a/library/include/dfhack/modules/Creatures.h
+++ b/library/include/dfhack/modules/Creatures.h
@@ -321,6 +321,8 @@ namespace DFHack
bool ReadInventoryIdx(const uint32_t index, std::vector & item);
bool ReadInventoryPtr(const uint32_t index, std::vector & item);
+ int32_t FindIndexById(int32_t id);
+
/* Getters */
uint32_t GetDwarfRaceIndex ( void );
int32_t GetDwarfCivId ( void );
diff --git a/library/include/dfhack/modules/Items.h b/library/include/dfhack/modules/Items.h
index 11e59f77f..4b6021eed 100644
--- a/library/include/dfhack/modules/Items.h
+++ b/library/include/dfhack/modules/Items.h
@@ -7,17 +7,29 @@
*/
#include "dfhack/DFExport.h"
#include "dfhack/DFModule.h"
+#include "dfhack/DFTypes.h"
+
namespace DFHack
{
class Context;
class DFContextShared;
+struct t_item_header
+{
+ int16_t x;
+ int16_t y;
+ int16_t z;
+ t_itemflags flags;
+};
+
struct t_item
{
+ t_item_header header;
t_material matdesc;
int32_t quantity;
int32_t quality;
+ int16_t wear_level;
};
struct t_improvement
@@ -36,6 +48,8 @@ public:
std::string getItemDescription(uint32_t itemptr, Materials * Materials);
std::string getItemClass(int32_t index);
bool getItemData(uint32_t itemptr, t_item & item);
+ int32_t getItemOwnerID(uint32_t itemptr);
+ void setItemFlags(uint32_t itemptr, t_itemflags new_flags);
private:
class Private;
Private* d;
diff --git a/library/modules/Creatures.cpp b/library/modules/Creatures.cpp
index 2e589d967..9e91a1e76 100644
--- a/library/modules/Creatures.cpp
+++ b/library/modules/Creatures.cpp
@@ -106,6 +106,8 @@ struct Creatures::Private
uint32_t creature_module;
uint32_t dwarf_race_index_addr;
uint32_t dwarf_civ_id_addr;
+ bool IdMapReady;
+ std::map IdMap;
DfVector *p_cre;
DFContextShared *d;
Process *owner;
@@ -123,6 +125,7 @@ Creatures::Creatures(DFContextShared* _d)
d->owner = _d->p;
d->Inited = false;
d->Started = false;
+ d->IdMapReady = false;
d->p_cre = NULL;
d->d->InitReadNames(); // throws on error
VersionInfo * minfo = d->d->offset_descriptor;
@@ -228,6 +231,7 @@ bool Creatures::Start( uint32_t &numcreatures )
d->p_cre = new DfVector (d->owner, d->creatures.vector);
d->Started = true;
numcreatures = d->p_cre->size();
+ d->IdMapReady = false;
return true;
}
return false;
@@ -407,6 +411,35 @@ int32_t Creatures::ReadCreatureInBox (int32_t index, t_creature & furball,
return -1;
}
+int32_t Creatures::FindIndexById(int32_t creature_id)
+{
+ if (!d->Started || !d->Ft_basic)
+ return -1;
+
+ if (!d->IdMapReady)
+ {
+ d->IdMap.clear();
+
+ Process * p = d->owner;
+ Private::t_offsets &offs = d->creatures;
+
+ uint32_t size = d->p_cre->size();
+ for (uint32_t index = 0; index < size; index++)
+ {
+ uint32_t temp = d->p_cre->at(index);
+ int32_t id = p->readDWord (temp + offs.id_offset);
+ d->IdMap[id] = index;
+ }
+ }
+
+ std::map::iterator it;
+ it = d->IdMap.find(creature_id);
+ if(it == d->IdMap.end())
+ return -1;
+ else
+ return it->second;
+}
+
bool Creatures::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS])
{
if(!d->Started || !d->Ft_advanced) return false;
diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp
index e398f8e16..d29753b7d 100644
--- a/library/modules/Items.cpp
+++ b/library/modules/Items.cpp
@@ -51,13 +51,19 @@ enum accessor_type {ACCESSOR_CONSTANT, ACCESSOR_INDIRECT, ACCESSOR_DOUBLE_INDIRE
/* this is used to store data about the way accessors work */
class DFHACK_EXPORT Accessor
{
+public:
+ enum DataWidth {
+ Data32 = 0,
+ DataSigned16,
+ DataUnsigned16
+ };
private:
accessor_type type;
int32_t constant;
- uint32_t offset1;
- uint32_t offset2;
+ int32_t offset1;
+ int32_t offset2;
Process * p;
- uint32_t dataWidth;
+ DataWidth dataWidth;
public:
Accessor(uint32_t function, Process * p);
Accessor(accessor_type type, int32_t constant, uint32_t offset1, uint32_t offset2, uint32_t dataWidth, Process * p);
@@ -84,6 +90,7 @@ private:
Accessor * ASubIndex;
Accessor * AIndex;
Accessor * AQuality;
+ Accessor * AWear;
Process * p;
bool hasDecoration;
public:
@@ -95,89 +102,138 @@ public:
std::vector improvement;
};
+inline bool do_match(uint32_t &ptr, uint64_t val, int size, uint64_t mask, uint64_t check)
+{
+ if ((val & mask) == check) {
+ ptr += size;
+ return true;
+ }
+ return false;
+}
+
+static bool match_MEM_ACCESS(uint32_t &ptr, uint64_t v, int isize, int in_reg, int &out_reg, int &offset)
+{
+ // ESP & EBP are hairy
+ if (in_reg == 4 || in_reg == 5)
+ return false;
+
+ if ((v & 7) != in_reg)
+ return false;
+
+ out_reg = (v>>3) & 7;
+
+ switch ((v>>6)&3) {
+ case 0: // MOV REG2, [REG]
+ offset = 0;
+ ptr += isize+1;
+ return true;
+ case 1: // MOV REG2, [REG+offset8]
+ offset = (signed char)(v >> 8);
+ ptr += isize+2;
+ return true;
+ case 2: // MOV REG2, [REG+offset32]
+ offset = (signed int)(v >> 8);
+ ptr += isize+5;
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool match_MOV_MEM(uint32_t &ptr, uint64_t v, int in_reg, int &out_reg, int &offset, Accessor::DataWidth &size)
+{
+ int prefix = 0;
+ size = Accessor::Data32;
+ if ((v & 0xFF) == 0x8B) { // MOV
+ v >>= 8;
+ prefix = 1;
+ }
+ else if ((v & 0xFFFF) == 0x8B66) { // MOV 16-bit
+ v >>= 16;
+ prefix = 2;
+ size = Accessor::DataUnsigned16;
+ }
+ else if ((v & 0xFFFF) == 0xBF0F) { // MOVSX
+ v >>= 16;
+ prefix = 2;
+ size = Accessor::DataSigned16;
+ }
+ else if ((v & 0xFFFF) == 0xB70F) { // MOVZ
+ v >>= 16;
+ prefix = 2;
+ size = Accessor::DataUnsigned16;
+ }
+ else
+ return false;
+
+ return match_MEM_ACCESS(ptr, v, prefix, in_reg, out_reg, offset);
+}
// FIXME: this is crazy
Accessor::Accessor(uint32_t function, Process *p)
{
this->p = p;
- this->constant = 0;
- this->offset1 = 0;
- this->offset2 = 0;
this->type = ACCESSOR_CONSTANT;
- this->dataWidth = 2;
- uint64_t funcText = p->readQuad(function);
- if( funcText == 0xCCCCCCCCCCC3C033LL )
+ uint32_t ptr = function;
+ uint64_t v = p->readQuad(ptr);
+ int data_reg = -1;
+
+ if (do_match(ptr, v, 2, 0xFFFF, 0xC033) ||
+ do_match(ptr, v, 2, 0xFFFF, 0xC031)) // XOR EAX, EAX
{
- return;
+ data_reg = 0;
+ this->constant = 0;
}
- if( funcText == 0xCCCCCCCCC3FFC883LL )
+ else if (do_match(ptr, v, 3, 0xFFFFFF, 0xFFC883)) // OR EAX, -1
{
- /* or eax,-1; ret; */
+ data_reg = 0;
this->constant = -1;
- return;
- }
- if( (funcText&0xFFFFFFFFFF0000FFLL) == 0xCCCCC300000000B8LL )
- {
- /* mov eax, xx; ret; */
- this->constant = (funcText>>8) & 0xffff;
- return;
}
- if( (funcText&0xFFFFFF0000FFFFFFLL) == 0xC300000000818B66LL )
+ else if (do_match(ptr, v, 5, 0xFF, 0xB8)) // MOV EAX,imm
{
- /* mov ax, [ecx+xx]; ret; */
- this->type = ACCESSOR_INDIRECT;
- this->offset1 = (funcText>>24) & 0xffff;
- return;
- }
- if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL )
- {
- /* mov ax, [ecx+xx]; ret; (shorter instruction)*/
- this->type = ACCESSOR_INDIRECT;
- this->offset1 = (funcText>>24) & 0xff;
- return;
- }
- if( (funcText&0x00000000FF00FFFFLL) == 0x00000000C300418BLL )
- {
- /* mov eax, [ecx+xx]; ret; */
- this->type = ACCESSOR_INDIRECT;
- this->offset1 = (funcText>>16) & 0xff;
- this->dataWidth = 4;
- return;
+ data_reg = 0;
+ this->constant = (v>>8) & 0xFFFFFFFF;
}
- if( (funcText&0xFFFFFFFF0000FFFFLL) == 0x8B6600000000818BLL )
+ else
{
- uint64_t funcText2 = p->readQuad(function+8);
- if( (funcText2&0xFFFFFFFFFFFF00FFLL) == 0xCCCCCCCCCCC30040LL )
+ DataWidth xsize;
+ int ptr_reg = 1, tmp; // ECX
+
+ // MOV REG,[ESP+4]
+ if (do_match(ptr, v, 4, 0xFFFFC7FFU, 0x0424448B))
{
- this->type = ACCESSOR_DOUBLE_INDIRECT;
- this->offset1 = (funcText>>16) & 0xffff;
- this->offset2 = (funcText2>>8) & 0xff;
- return;
+ ptr_reg = (v>>11)&7;
+ v = p->readQuad(ptr);
+ }
+
+ if (match_MOV_MEM(ptr, v, ptr_reg, tmp, this->offset1, xsize)) {
+ data_reg = tmp;
+ this->type = ACCESSOR_INDIRECT;
+ this->dataWidth = xsize;
+
+ if (xsize == Data32)
+ {
+ v = p->readQuad(ptr);
+
+ if (match_MOV_MEM(ptr, v, data_reg, tmp, this->offset2, xsize)) {
+ data_reg = tmp;
+ this->type = ACCESSOR_DOUBLE_INDIRECT;
+ this->dataWidth = xsize;
+ }
+ }
}
}
- if( (funcText&0xFFFFFF0000FFFFFFLL) == 0xC30000000081BF0FLL )
- {
- /* movsx eax, word ptr [ecx+xx]; ret */
- this->type = ACCESSOR_INDIRECT;
- this->offset1 = (funcText>>24) & 0xffff;
- return;
- }
- if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C30041BF0FLL )
- {
- /* movsx eax, word ptr [ecx+xx]; ret (shorter opcode)*/
- this->type = ACCESSOR_INDIRECT;
- this->offset1 = (funcText>>24) & 0xff;
+
+ v = p->readQuad(ptr);
+
+ if (data_reg == 0 && do_match(ptr, v, 1, 0xFF, 0xC3)) // RET
return;
- }
- if( (funcText&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL )
+ else
{
- /* mov eax, [ecx+xx]; ret; */
- this->type = ACCESSOR_INDIRECT;
- this->offset1 = (funcText>>16) & 0xffff;
- this->dataWidth = 4;
- return;
+ this->type = ACCESSOR_CONSTANT;
+ this->constant = 0;
+ printf("bad accessor @0x%x\n", function);
}
- printf("bad accessor @0x%x\n", function);
}
bool Accessor::isConstant()
@@ -190,29 +246,26 @@ bool Accessor::isConstant()
int32_t Accessor::getValue(uint32_t objectPtr)
{
+ int32_t offset = this->offset1;
+
switch(this->type)
{
case ACCESSOR_CONSTANT:
return this->constant;
break;
- case ACCESSOR_INDIRECT:
- switch(this->dataWidth)
- {
- case 2:
- return (int16_t) p->readWord(objectPtr + this->offset1);
- case 4:
- return p->readDWord(objectPtr + this->offset1);
- default:
- return -1;
- }
- break;
case ACCESSOR_DOUBLE_INDIRECT:
+ objectPtr = p->readDWord(objectPtr + this->offset1);
+ offset = this->offset2;
+ // fallthrough
+ case ACCESSOR_INDIRECT:
switch(this->dataWidth)
{
- case 2:
- return (int16_t) p->readWord(p->readDWord(objectPtr + this->offset1) + this->offset2);
- case 4:
- return p->readDWord(p->readDWord(objectPtr + this->offset1) + this->offset2);
+ case Data32:
+ return p->readDWord(objectPtr + offset);
+ case DataSigned16:
+ return (int16_t) p->readWord(objectPtr + offset);
+ case DataUnsigned16:
+ return (uint16_t) p->readWord(objectPtr + offset);
default:
return -1;
}
@@ -230,6 +283,7 @@ ItemDesc::ItemDesc(uint32_t VTable, Process *p)
uint32_t funcOffsetC = Items->getOffset("item_subindex_accessor");
uint32_t funcOffsetD = Items->getOffset("item_index_accessor");
uint32_t funcOffsetQuality = Items->getOffset("item_quality_accessor");
+ uint32_t funcOffsetWear = Items->getOffset("item_wear_accessor");
this->vtable = VTable;
this->p = p;
this->className = p->readClassName(VTable).substr(5);
@@ -239,6 +293,7 @@ ItemDesc::ItemDesc(uint32_t VTable, Process *p)
this->ASubIndex = new Accessor( p->readDWord( VTable + funcOffsetC ), p);
this->AIndex = new Accessor( p->readDWord( VTable + funcOffsetD ), p);
this->AQuality = new Accessor( p->readDWord( VTable + funcOffsetQuality ), p);
+ this->AWear = new Accessor( p->readDWord( VTable + funcOffsetWear ), p);
this->hasDecoration = false;
if(this->AMainType->isConstant())
this->mainType = this->AMainType->getValue(0);
@@ -251,12 +306,16 @@ ItemDesc::ItemDesc(uint32_t VTable, Process *p)
bool ItemDesc::getItem(uint32_t itemptr, DFHack::t_item &item)
{
+ this->p->read(itemptr+4, sizeof(t_item_header), (uint8_t*)&item.header);
item.matdesc.itemType = this->AMainType->getValue(itemptr);
item.matdesc.subType = this->ASubType->getValue(itemptr);
item.matdesc.subIndex = this->ASubIndex->getValue(itemptr);
item.matdesc.index = this->AIndex->getValue(itemptr);
item.quality = this->AQuality->getValue(itemptr);
item.quantity = 1; /* TODO */
+ // Note: this accessor returns a 32-bit value with the higher
+ // half sometimes containing garbage, so the cast is essential:
+ item.wear_level = (int16_t)this->AWear->getValue(itemptr);
return true;
}
@@ -267,6 +326,9 @@ class Items::Private
Process * owner;
std::map descType;
std::map descVTable;
+ uint32_t refVectorOffset;
+ uint32_t refIDOffset;
+ uint32_t ownerRefVTable;
};
Items::Items(DFContextShared * d_)
@@ -274,6 +336,7 @@ Items::Items(DFContextShared * d_)
d = new Private;
d->d = d_;
d->owner = d_->p;
+ d->ownerRefVTable = d->refVectorOffset = d->refIDOffset = 0;
}
bool Items::Start()
@@ -321,6 +384,45 @@ bool Items::getItemData(uint32_t itemptr, DFHack::t_item &item)
return desc->getItem(itemptr, item);
}
+void Items::setItemFlags(uint32_t itemptr, t_itemflags new_flags)
+{
+ d->owner->writeDWord(itemptr + 0x0C, new_flags.whole);
+}
+
+int32_t Items::getItemOwnerID(uint32_t itemptr)
+{
+ if (!d->refVectorOffset)
+ {
+ OffsetGroup * Items = d->owner->getDescriptor()->getGroup("Items");
+ d->refVectorOffset = Items->getOffset("item_ref_vector");
+ d->refIDOffset = Items->getOffset("owner_ref_id_field");
+ }
+
+ DFHack::DfVector p_refs(d->owner, itemptr + d->refVectorOffset);
+ uint32_t size = p_refs.size();
+
+ for (uint32_t i=0;iowner->readDWord(curRef);
+
+ if (!d->ownerRefVTable)
+ {
+ std::string className = d->owner->readClassName(vtbl);
+ if (className == "general_ref_unit_itemownerst")
+ d->ownerRefVTable = vtbl;
+ else
+ continue;
+ }
+ else if (d->ownerRefVTable != vtbl)
+ continue;
+
+ return d->owner->readDWord(curRef + d->refIDOffset);
+ }
+
+ return -1;
+}
+
std::string Items::getItemClass(int32_t index)
{
std::map::iterator it;
diff --git a/tools/playground/CMakeLists.txt b/tools/playground/CMakeLists.txt
index 2a2054ac4..5ff77de1c 100644
--- a/tools/playground/CMakeLists.txt
+++ b/tools/playground/CMakeLists.txt
@@ -80,6 +80,8 @@ DFHACK_TOOL(dfprinttiletypes printtiletypes.cpp)
# Will have many options in the future.
DFHACK_TOOL(dfhellhole hellhole.cpp)
+DFHACK_TOOL(dfcleanowned cleanowned.cpp)
+
# this needs the C bindings
IF(BUILD_DFHACK_C_BINDINGS)
# The C bindings won't be real C bindings until this compiles.
diff --git a/tools/playground/cleanowned.cpp b/tools/playground/cleanowned.cpp
new file mode 100644
index 000000000..116754dc8
--- /dev/null
+++ b/tools/playground/cleanowned.cpp
@@ -0,0 +1,175 @@
+/*
+ * Confiscates and dumps garbage owned by dwarfs.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+using namespace std;
+
+#include
+#include
+#include
+
+int main (int argc, char *argv[])
+{
+ bool dump_scattered = false;
+ bool confiscate_all = false;
+ bool dry_run = false;
+ int wear_dump_level = 65536;
+
+ for(int i = 1; i < argc; i++)
+ {
+ char *arg = argv[i];
+ if (arg[0] != '-')
+ continue;
+
+ for (; *arg; arg++) {
+ switch (arg[0]) {
+ case 'd':
+ dry_run = true;
+ break;
+ case 'l':
+ dump_scattered = true;
+ break;
+ case 'a':
+ confiscate_all = true;
+ break;
+ case 'x':
+ wear_dump_level = 1;
+ break;
+ case 'X':
+ wear_dump_level = 2;
+ break;
+ }
+ }
+ }
+
+ DFHack::Process * p;
+ unsigned int i,j;
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context * DF;
+ try
+ {
+ DF = DFMgr.getSingleContext();
+ DF->Attach();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+#ifndef LINUX_BUILD
+ cin.ignore();
+#endif
+ return 1;
+ }
+
+ DFHack::VersionInfo * mem = DF->getMemoryInfo();
+ DFHack::Materials *Materials = DF->getMaterials();
+ DFHack::Items *Items = DF->getItems();
+ DFHack::Creatures *Creatures = DF->getCreatures();
+ DFHack::Translation *Tran = DF->getTranslation();
+
+ Materials->ReadAllMaterials();
+ uint32_t num_creatures;
+ Creatures->Start(num_creatures);
+ Tran->Start();
+
+ p = DF->getProcess();
+ DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
+ unsigned vector_addr = itemGroup->getAddress("items_vector");
+ DFHack::DfVector p_items (p, vector_addr);
+ uint32_t size = p_items.size();
+
+ printf("Found total %d items.\n", size);
+
+ for (i=0;igetItemData(curItem, itm);
+
+ if (!itm.header.flags.bits.owned)
+ continue;
+
+ bool confiscate = false;
+ bool dump = false;
+
+ if (itm.header.flags.bits.rotten)
+ {
+ printf("Confiscating a rotten item: \t");
+ confiscate = true;
+ }
+ else if (itm.wear_level >= wear_dump_level)
+ {
+ printf("Confiscating and dumping a worn item: \t");
+ confiscate = true;
+ dump = true;
+ }
+ else if (dump_scattered && itm.header.flags.bits.on_ground)
+ {
+ printf("Confiscating and dumping litter: \t");
+ confiscate = true;
+ dump = true;
+ }
+ else if (confiscate_all)
+ {
+ printf("Confiscating: \t");
+ confiscate = true;
+ }
+
+ if (confiscate)
+ {
+ itm.header.flags.bits.owned = 0;
+ if (dump)
+ itm.header.flags.bits.dump = 1;
+
+ if (!dry_run)
+ Items->setItemFlags(curItem, itm.header.flags);
+
+ printf(
+ "%s (wear %d)",
+ Items->getItemDescription(curItem, Materials).c_str(),
+ itm.wear_level
+ );
+
+ int32_t owner = Items->getItemOwnerID(curItem);
+ int32_t owner_index = Creatures->FindIndexById(owner);
+ std::string info;
+
+ if (owner_index >= 0)
+ {
+ DFHack::t_creature temp;
+ Creatures->ReadCreature(owner_index,temp);
+ temp.name.first_name[0] = toupper(temp.name.first_name[0]);
+ info = temp.name.first_name;
+ if (temp.name.nickname[0])
+ info += std::string(" '") + temp.name.nickname + "'";
+ info += " ";
+ info += Tran->TranslateName(temp.name,false);
+ printf(", owner %s", info.c_str());
+ }
+
+ printf("\n");
+
+/* printf(
+ "%5d: %08x %08x (%d,%d,%d) #%08x [%d] %s - %s %s\n",
+ i, curItem, itm.header.flags.whole,
+ itm.header.x, itm.header.y, itm.header.z,
+ p->readDWord(curItem),
+ itm.wear_level,
+ Items->getItemClass(itm.matdesc.itemType).c_str(),
+ Items->getItemDescription(curItem, Materials).c_str(),
+ info.c_str()
+ );*/
+ }
+ }
+
+#ifndef LINUX_BUILD
+ cout << "Done. Press any key to continue" << endl;
+ cin.ignore();
+#endif
+ return 0;
+}