Petr Mrázek 2011-04-11 12:48:28 +02:00
commit 77f0885d9e
8 changed files with 460 additions and 119 deletions

@ -870,7 +870,7 @@
<Offset name="flags2" description="Second set of flags" /> <Offset name="flags2" description="Second set of flags" />
<Offset name="caste" description="Caste of the creature. Same as sex most of the time." /> <Offset name="caste" description="Caste of the creature. Same as sex most of the time." />
<Offset name="sex" description="Sex of the creature." /> <Offset name="sex" description="Sex of the creature." />
<Offset name="id" description="Unique ID of the creature, probably index into some global vector.." /> <Offset name="id" description="Unique ID of the creature, seems to be used for binary search in the creature vector." />
<Offset name="civ" description="What civ the creature belongs to." /> <Offset name="civ" description="What civ the creature belongs to." />
<Group name="advanced"> <Group name="advanced">
<Offset name="pickup_equipment_bit" description="Setting this makes creatures re-check the status of their equip." /> <Offset name="pickup_equipment_bit" description="Setting this makes creatures re-check the status of their equip." />
@ -995,7 +995,9 @@
<Offset name="item_improvement_subindex" /> <Offset name="item_improvement_subindex" />
<Offset name="item_improvement_index" /> <Offset name="item_improvement_index" />
<Offset name="item_improvement_quality" /> <Offset name="item_improvement_quality" />
<Offset name="item_type_accessor" /> (in the vtable) <Offset name="item_wear_accessor" />
<Offset name="item_ref_vector" description="Contains the owner among other things"/>
<Offset name="owner_ref_id_field" description="Creature ID offset in general_ref_unit_itemownerst"/>
</Group> </Group>
<Group name="World"> <Group name="World">
<Address name="current_tick" description="Current time of the year" /> <Address name="current_tick" description="Current time of the year" />
@ -2948,6 +2950,17 @@
<Address name="control_mode" value="0x8c3de90" /> <Address name="control_mode" value="0x8c3de90" />
<Address name="game_mode" value="0x8c3deA0" /> <Address name="game_mode" value="0x8c3deA0" />
</Group> </Group>
<Group name="Items">
<Address name="items_vector" value="0x940b1fc" />
<Offset name="item_type_accessor" value="0x0" />
<Offset name="item_subtype_accessor" value="0x4" />
<Offset name="item_subindex_accessor" value="0x8" />
<Offset name="item_index_accessor" value="0xC" />
<Offset name="item_quality_accessor" value="0x25C" />
<Offset name="item_wear_accessor" value="0xCC" />
<Offset name="item_ref_vector" value="0x24" />
<Offset name="owner_ref_id_field" value="0x4" />
</Group>
</Offsets> </Offsets>
</Version> </Version>
</DFHack> </DFHack>

@ -124,46 +124,46 @@ struct t_item_df40d
//They all seem to be valid on 40d as well //They all seem to be valid on 40d as well
struct naked_itemflags struct naked_itemflags
{ {
unsigned int on_ground : 1; // Item on ground unsigned int on_ground : 1; // 0000 0001 Item on ground
unsigned int in_job : 1; // item currently being used in a job unsigned int in_job : 1; // 0000 0002 Item currently being used in a job
unsigned int in_inventory : 1; // Item in a creatures inventory unsigned int u_ngrd1 : 1; // 0000 0004 unknown, unseen
unsigned int u_ngrd1 : 1; // only occurs when not on ground, unknown function unsigned int in_inventory : 1; // 0000 0008 Item in a creature or workshop inventory
unsigned int in_workshop : 1; // Item is in a workshops inventory unsigned int u_ngrd2 : 1; // 0000 0010 unknown, lost (artifact)?, unseen
unsigned int u_ngrd2 : 1; // only occurs when not on ground, unknown function unsigned int in_building : 1; // 0000 0020 Part of a building (including mechanisms, bodies in coffins)
unsigned int u_ngrd3 : 1; // only occurs when not on ground, unknown function unsigned int u_ngrd3 : 1; // 0000 0040 unknown, unseen
unsigned int rotten : 1; // Item is rotten unsigned int dead_dwarf : 1; // 0000 0080 Dwarf's dead body or body part
unsigned int unk1 : 1; // unknown function unsigned int rotten : 1; // 0000 0100 Rotten food
unsigned int u_ngrd4 : 1; // only occurs when not on ground, unknown function unsigned int spider_web : 1; // 0000 0200 Thread in spider web
unsigned int unk2 : 1; // unknown function unsigned int construction : 1; // 0000 0400 Material used in construction
unsigned int u_ngrd5 : 1; // only occurs when not on ground, unknown function unsigned int u_ngrd5 : 1; // 0000 0800 unknown, unseen
unsigned int unk3 : 1; // unknown function unsigned int unk3 : 1; // 0000 1000 unknown, unseen
unsigned int u_ngrd6 : 1; // only occurs when not on ground, unknown function unsigned int u_ngrd6 : 1; // 0000 2000 unknown, unseen
unsigned int narrow : 1; // Item is narrow unsigned int foreign : 1; // 0000 4000 Item is imported
unsigned int u_ngrd7 : 1; // only occurs when not on ground, unknown function unsigned int u_ngrd7 : 1; // 0000 8000 unknown, unseen
unsigned int worn : 1; // item shows wear unsigned int owned : 1; // 0001 0000 Item is owned by a dwarf
unsigned int unk4 : 1; // unknown function unsigned int unk4 : 1; // 0002 0000 unknown, unseen
unsigned int u_ngrd8 : 1; // only occurs when not on ground, unknown function unsigned int artifact1 : 1; // 0004 0000 Artifact ?
unsigned int forbid : 1; // designate forbid item unsigned int forbid : 1; // 0008 0000 Forbidden item
unsigned int unk5 : 1; // unknown function unsigned int unk5 : 1; // 0010 0000 unknown, unseen
unsigned int dump : 1; // designate dump item unsigned int dump : 1; // 0020 0000 Designated for dumping
unsigned int on_fire: 1; //indicates if item is on fire, Will Set Item On Fire if Set! unsigned int on_fire: 1; // 0040 0000 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 melt : 1; // 0080 0000 Designated for melting, if applicable
// 0100 0000 - 8000 0000 // 0100 0000 - 8000 0000
unsigned int hidden : 1; // designate hide item unsigned int hidden : 1; // 0100 0000 Hidden item
unsigned int u_ngrd9 : 1; // only occurs when not on ground, unknown function unsigned int in_chest : 1; // 0200 0000 Stored in chest/part of well?
unsigned int unk6 : 1; // unknown function unsigned int unk6 : 1; // 0400 0000 unknown, unseen
unsigned int unk7 : 1; // unknown function unsigned int artifact2 : 1; // 0800 0000 Artifact ?
unsigned int unk8 : 1; // unknown function unsigned int unk8 : 1; // 1000 0000 unknown, unseen
unsigned int unk9 : 1; // unknown function unsigned int unk9 : 1; // 2000 0000 unknown, set when viewing details
unsigned int unk10 : 1; // unknown function unsigned int unk10 : 1; // 4000 0000 unknown, unseen
unsigned int unk11 : 1; // unknown function unsigned int unk11 : 1; // 8000 0000 unknown, unseen
}; };
union t_itemflags union t_itemflags

@ -321,6 +321,8 @@ namespace DFHack
bool ReadInventoryIdx(const uint32_t index, std::vector<uint32_t> & item); bool ReadInventoryIdx(const uint32_t index, std::vector<uint32_t> & item);
bool ReadInventoryPtr(const uint32_t index, std::vector<uint32_t> & item); bool ReadInventoryPtr(const uint32_t index, std::vector<uint32_t> & item);
int32_t FindIndexById(int32_t id);
/* Getters */ /* Getters */
uint32_t GetDwarfRaceIndex ( void ); uint32_t GetDwarfRaceIndex ( void );
int32_t GetDwarfCivId ( void ); int32_t GetDwarfCivId ( void );

@ -7,17 +7,29 @@
*/ */
#include "dfhack/DFExport.h" #include "dfhack/DFExport.h"
#include "dfhack/DFModule.h" #include "dfhack/DFModule.h"
#include "dfhack/DFTypes.h"
namespace DFHack namespace DFHack
{ {
class Context; class Context;
class DFContextShared; class DFContextShared;
struct t_item_header
{
int16_t x;
int16_t y;
int16_t z;
t_itemflags flags;
};
struct t_item struct t_item
{ {
t_item_header header;
t_material matdesc; t_material matdesc;
int32_t quantity; int32_t quantity;
int32_t quality; int32_t quality;
int16_t wear_level;
}; };
struct t_improvement struct t_improvement
@ -36,6 +48,8 @@ public:
std::string getItemDescription(uint32_t itemptr, Materials * Materials); std::string getItemDescription(uint32_t itemptr, Materials * Materials);
std::string getItemClass(int32_t index); std::string getItemClass(int32_t index);
bool getItemData(uint32_t itemptr, t_item & item); bool getItemData(uint32_t itemptr, t_item & item);
int32_t getItemOwnerID(uint32_t itemptr);
void setItemFlags(uint32_t itemptr, t_itemflags new_flags);
private: private:
class Private; class Private;
Private* d; Private* d;

@ -106,6 +106,8 @@ struct Creatures::Private
uint32_t creature_module; uint32_t creature_module;
uint32_t dwarf_race_index_addr; uint32_t dwarf_race_index_addr;
uint32_t dwarf_civ_id_addr; uint32_t dwarf_civ_id_addr;
bool IdMapReady;
std::map<int32_t, int32_t> IdMap;
DfVector <uint32_t> *p_cre; DfVector <uint32_t> *p_cre;
DFContextShared *d; DFContextShared *d;
Process *owner; Process *owner;
@ -123,6 +125,7 @@ Creatures::Creatures(DFContextShared* _d)
d->owner = _d->p; d->owner = _d->p;
d->Inited = false; d->Inited = false;
d->Started = false; d->Started = false;
d->IdMapReady = false;
d->p_cre = NULL; d->p_cre = NULL;
d->d->InitReadNames(); // throws on error d->d->InitReadNames(); // throws on error
VersionInfo * minfo = d->d->offset_descriptor; VersionInfo * minfo = d->d->offset_descriptor;
@ -228,6 +231,7 @@ bool Creatures::Start( uint32_t &numcreatures )
d->p_cre = new DfVector <uint32_t> (d->owner, d->creatures.vector); d->p_cre = new DfVector <uint32_t> (d->owner, d->creatures.vector);
d->Started = true; d->Started = true;
numcreatures = d->p_cre->size(); numcreatures = d->p_cre->size();
d->IdMapReady = false;
return true; return true;
} }
return false; return false;
@ -407,6 +411,35 @@ int32_t Creatures::ReadCreatureInBox (int32_t index, t_creature & furball,
return -1; 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<int32_t,int32_t>::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]) bool Creatures::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS])
{ {
if(!d->Started || !d->Ft_advanced) return false; if(!d->Started || !d->Ft_advanced) return false;

@ -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 */ /* this is used to store data about the way accessors work */
class DFHACK_EXPORT Accessor class DFHACK_EXPORT Accessor
{ {
public:
enum DataWidth {
Data32 = 0,
DataSigned16,
DataUnsigned16
};
private: private:
accessor_type type; accessor_type type;
int32_t constant; int32_t constant;
uint32_t offset1; int32_t offset1;
uint32_t offset2; int32_t offset2;
Process * p; Process * p;
uint32_t dataWidth; DataWidth dataWidth;
public: public:
Accessor(uint32_t function, Process * p); Accessor(uint32_t function, Process * p);
Accessor(accessor_type type, int32_t constant, uint32_t offset1, uint32_t offset2, uint32_t dataWidth, 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 * ASubIndex;
Accessor * AIndex; Accessor * AIndex;
Accessor * AQuality; Accessor * AQuality;
Accessor * AWear;
Process * p; Process * p;
bool hasDecoration; bool hasDecoration;
public: public:
@ -95,89 +102,138 @@ public:
std::vector<ItemImprovementDesc> improvement; std::vector<ItemImprovementDesc> 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 // FIXME: this is crazy
Accessor::Accessor(uint32_t function, Process *p) Accessor::Accessor(uint32_t function, Process *p)
{ {
this->p = p; this->p = p;
this->constant = 0;
this->offset1 = 0;
this->offset2 = 0;
this->type = ACCESSOR_CONSTANT; this->type = ACCESSOR_CONSTANT;
this->dataWidth = 2; uint32_t ptr = function;
uint64_t funcText = p->readQuad(function); uint64_t v = p->readQuad(ptr);
if( funcText == 0xCCCCCCCCCCC3C033LL ) 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; 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; */ data_reg = 0;
this->type = ACCESSOR_INDIRECT; this->constant = (v>>8) & 0xFFFFFFFF;
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;
} }
if( (funcText&0xFFFFFFFF0000FFFFLL) == 0x8B6600000000818BLL ) else
{ {
uint64_t funcText2 = p->readQuad(function+8); DataWidth xsize;
if( (funcText2&0xFFFFFFFFFFFF00FFLL) == 0xCCCCCCCCCCC30040LL ) int ptr_reg = 1, tmp; // ECX
// MOV REG,[ESP+4]
if (do_match(ptr, v, 4, 0xFFFFC7FFU, 0x0424448B))
{ {
this->type = ACCESSOR_DOUBLE_INDIRECT; ptr_reg = (v>>11)&7;
this->offset1 = (funcText>>16) & 0xffff; v = p->readQuad(ptr);
this->offset2 = (funcText2>>8) & 0xff; }
return;
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 )
{ v = p->readQuad(ptr);
/* movsx eax, word ptr [ecx+xx]; ret */
this->type = ACCESSOR_INDIRECT; if (data_reg == 0 && do_match(ptr, v, 1, 0xFF, 0xC3)) // RET
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;
return; return;
} else
if( (funcText&0xFFFFFFFF0000FFFFLL) == 0xCCC300000000818BLL )
{ {
/* mov eax, [ecx+xx]; ret; */ this->type = ACCESSOR_CONSTANT;
this->type = ACCESSOR_INDIRECT; this->constant = 0;
this->offset1 = (funcText>>16) & 0xffff; printf("bad accessor @0x%x\n", function);
this->dataWidth = 4;
return;
} }
printf("bad accessor @0x%x\n", function);
} }
bool Accessor::isConstant() bool Accessor::isConstant()
@ -190,29 +246,26 @@ bool Accessor::isConstant()
int32_t Accessor::getValue(uint32_t objectPtr) int32_t Accessor::getValue(uint32_t objectPtr)
{ {
int32_t offset = this->offset1;
switch(this->type) switch(this->type)
{ {
case ACCESSOR_CONSTANT: case ACCESSOR_CONSTANT:
return this->constant; return this->constant;
break; 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: case ACCESSOR_DOUBLE_INDIRECT:
objectPtr = p->readDWord(objectPtr + this->offset1);
offset = this->offset2;
// fallthrough
case ACCESSOR_INDIRECT:
switch(this->dataWidth) switch(this->dataWidth)
{ {
case 2: case Data32:
return (int16_t) p->readWord(p->readDWord(objectPtr + this->offset1) + this->offset2); return p->readDWord(objectPtr + offset);
case 4: case DataSigned16:
return p->readDWord(p->readDWord(objectPtr + this->offset1) + this->offset2); return (int16_t) p->readWord(objectPtr + offset);
case DataUnsigned16:
return (uint16_t) p->readWord(objectPtr + offset);
default: default:
return -1; return -1;
} }
@ -230,6 +283,7 @@ ItemDesc::ItemDesc(uint32_t VTable, Process *p)
uint32_t funcOffsetC = Items->getOffset("item_subindex_accessor"); uint32_t funcOffsetC = Items->getOffset("item_subindex_accessor");
uint32_t funcOffsetD = Items->getOffset("item_index_accessor"); uint32_t funcOffsetD = Items->getOffset("item_index_accessor");
uint32_t funcOffsetQuality = Items->getOffset("item_quality_accessor"); uint32_t funcOffsetQuality = Items->getOffset("item_quality_accessor");
uint32_t funcOffsetWear = Items->getOffset("item_wear_accessor");
this->vtable = VTable; this->vtable = VTable;
this->p = p; this->p = p;
this->className = p->readClassName(VTable).substr(5); 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->ASubIndex = new Accessor( p->readDWord( VTable + funcOffsetC ), p);
this->AIndex = new Accessor( p->readDWord( VTable + funcOffsetD ), p); this->AIndex = new Accessor( p->readDWord( VTable + funcOffsetD ), p);
this->AQuality = new Accessor( p->readDWord( VTable + funcOffsetQuality ), p); this->AQuality = new Accessor( p->readDWord( VTable + funcOffsetQuality ), p);
this->AWear = new Accessor( p->readDWord( VTable + funcOffsetWear ), p);
this->hasDecoration = false; this->hasDecoration = false;
if(this->AMainType->isConstant()) if(this->AMainType->isConstant())
this->mainType = this->AMainType->getValue(0); 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) 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.itemType = this->AMainType->getValue(itemptr);
item.matdesc.subType = this->ASubType->getValue(itemptr); item.matdesc.subType = this->ASubType->getValue(itemptr);
item.matdesc.subIndex = this->ASubIndex->getValue(itemptr); item.matdesc.subIndex = this->ASubIndex->getValue(itemptr);
item.matdesc.index = this->AIndex->getValue(itemptr); item.matdesc.index = this->AIndex->getValue(itemptr);
item.quality = this->AQuality->getValue(itemptr); item.quality = this->AQuality->getValue(itemptr);
item.quantity = 1; /* TODO */ 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; return true;
} }
@ -267,6 +326,9 @@ class Items::Private
Process * owner; Process * owner;
std::map<int32_t, ItemDesc *> descType; std::map<int32_t, ItemDesc *> descType;
std::map<uint32_t, ItemDesc *> descVTable; std::map<uint32_t, ItemDesc *> descVTable;
uint32_t refVectorOffset;
uint32_t refIDOffset;
uint32_t ownerRefVTable;
}; };
Items::Items(DFContextShared * d_) Items::Items(DFContextShared * d_)
@ -274,6 +336,7 @@ Items::Items(DFContextShared * d_)
d = new Private; d = new Private;
d->d = d_; d->d = d_;
d->owner = d_->p; d->owner = d_->p;
d->ownerRefVTable = d->refVectorOffset = d->refIDOffset = 0;
} }
bool Items::Start() bool Items::Start()
@ -321,6 +384,45 @@ bool Items::getItemData(uint32_t itemptr, DFHack::t_item &item)
return desc->getItem(itemptr, 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<uint32_t> p_refs(d->owner, itemptr + d->refVectorOffset);
uint32_t size = p_refs.size();
for (uint32_t i=0;i<size;i++)
{
uint32_t curRef = p_refs[i];
uint32_t vtbl = d->owner->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::string Items::getItemClass(int32_t index)
{ {
std::map<int32_t, ItemDesc *>::iterator it; std::map<int32_t, ItemDesc *>::iterator it;

@ -80,6 +80,8 @@ DFHACK_TOOL(dfprinttiletypes printtiletypes.cpp)
# Will have many options in the future. # Will have many options in the future.
DFHACK_TOOL(dfhellhole hellhole.cpp) DFHACK_TOOL(dfhellhole hellhole.cpp)
DFHACK_TOOL(dfcleanowned cleanowned.cpp)
# this needs the C bindings # this needs the C bindings
IF(BUILD_DFHACK_C_BINDINGS) IF(BUILD_DFHACK_C_BINDINGS)
# The C bindings won't be real C bindings until this compiles. # The C bindings won't be real C bindings until this compiles.

@ -0,0 +1,175 @@
/*
* Confiscates and dumps garbage owned by dwarfs.
*/
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <climits>
#include <vector>
using namespace std;
#include <DFHack.h>
#include <dfhack/DFVector.h>
#include <dfhack/DFTypes.h>
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 <uint32_t> p_items (p, vector_addr);
uint32_t size = p_items.size();
printf("Found total %d items.\n", size);
for (i=0;i<size;i++)
{
uint32_t curItem = p_items[i];
DFHack::t_item itm;
Items->getItemData(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;
}