Merge remote branch 'upstream/master'

Conflicts:
	tools/playground/CMakeLists.txt
develop
Raoul XQ 2011-04-12 12:38:49 +02:00
commit 05f33853e1
14 changed files with 681 additions and 437 deletions

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<DFHack> <DFHack>
<Base name="DF40d.xx"> <Base name="DF40d.xx">
<Offsets> <Offsets>
<Group name="vector" description="An STL vector."> <Group name="vector" description="An STL vector.">
<HexValue name="sizeof" description="The total size in bytes." /> <HexValue name="sizeof" description="The total size in bytes." />
<Offset name="start" description="The offset where the actual start/end/alloc_end triplet is." /> <Offset name="start" description="The offset where the actual start/end/alloc_end triplet is." />
@ -31,16 +31,16 @@
<Offset name="second_words" description="Array of 7 indexes into the language vectors."/> <Offset name="second_words" description="Array of 7 indexes into the language vectors."/>
</Group> </Group>
</Offsets> </Offsets>
</Base> </Base>
<Version name="40d" base="DF40d.xx" os="windows"> <Version name="40d" base="DF40d.xx" os="windows">
<MD5 value="2c686c26307dcccd7c36cc79737ebe4f" /> <MD5 value="2c686c26307dcccd7c36cc79737ebe4f" />
<PETimeStamp value="0x48C330DF" /> <PETimeStamp value="0x48C330DF" />
<Offsets> <Offsets>
<Group name="vector"> <Group name="vector">
<HexValue name="sizeof" value="0x10" /> <HexValue name="sizeof" value="0x10" />
<Offset name="start" value="0x4" /> <Offset name="start" value="0x4" />
<!-- <!--
Maybe (fits offsets): Maybe (fits offsets):
Vector layout in MSVC 8: Vector layout in MSVC 8:
DWORD Allocator? DWORD Allocator?
DWORD Start DWORD Start
@ -61,8 +61,8 @@
<Offset name="nick" value="0x1C" /> <Offset name="nick" value="0x1C" />
<Offset name="second_words" value="0x38" /> <Offset name="second_words" value="0x38" />
</Group> </Group>
</Offsets> </Offsets>
</Version> </Version>
<Base name="DF2010"> <Base name="DF2010">
<Traits> <Traits>
<Trait name="Nervousness" id="0" level_5="Is a nervous wreck" level_4="Is always tense and jittery" level_3="Is often nervous" level_2="Has a calm demeanor" level_1="Has a very calm demeanor" level_0="Has an incredibly calm demeanor" /> <Trait name="Nervousness" id="0" level_5="Is a nervous wreck" level_4="Is always tense and jittery" level_3="Is often nervous" level_2="Has a calm demeanor" level_1="Has a very calm demeanor" level_0="Has an incredibly calm demeanor" />
@ -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" />
@ -1914,33 +1916,12 @@
<Address name="language_vector" value="0x016e553c"/> <Address name="language_vector" value="0x016e553c"/>
<Address name="translation_vector" value="0x016e551c"/> <Address name="translation_vector" value="0x016e551c"/>
</Group> </Group>
<!-- <Group name="Items" valid="false" />
<Group name="Vegetation" valid="false">
<Address name="vector"/>
<Offset name="tree_desc_offset" valid="true"/>
</Group>
-->
<Group name="Items" valid="false">
<!-- most of those seem completely unused! -->
<Address name="items_vector" />
List of offsets in the VTable :
<Offset name="item_type_accessor" />
<Offset name="item_subtype_accessor" />
<Offset name="item_subindex_accessor" />
<Offset name="item_index_accessor" />
<Offset name="item_quality_accessor" />
<Offset name="item_improvement_vector" />
<Offset name="item_improvement_subindex" />
<Offset name="item_improvement_index" />
<Offset name="item_improvement_quality" />
<Offset name="item_type_accessor" /> (in the vtable)
</Group>
<Group name="World" valid="false"> <Group name="World" valid="false">
<Address name="current_tick" description="Current time of the year" /> <Address name="current_tick" description="Current time of the year" />
<Address name="current_year" description="Current year" /> <Address name="current_year" description="Current year" />
<Address name="current_weather" value="0x14c9bb8" valid="true" /> <Address name="current_weather" value="0x14c9bb8" valid="true" />
</Group> </Group>
</Offsets> </Offsets>
</Version> </Version>
<Version name="v0.31.19 SDL" os="windows" base="v0.31.18 SDL"> <Version name="v0.31.19 SDL" os="windows" base="v0.31.18 SDL">
@ -1964,10 +1945,6 @@
<Group name="creature"> <Group name="creature">
<Group name="advanced"> <Group name="advanced">
<!--
<Offset name="pregnancy" value="0x214" /> maybe?
<Offset name="pregnancy_ptr" value="0x218" /> maybe?
-->
<Offset name="birth_year" value="0x224" /> <Offset name="birth_year" value="0x224" />
<Offset name="birth_time" value="0x228" /> <Offset name="birth_time" value="0x228" />
<Offset name="inventory_vector" value="0x288" /> <Offset name="inventory_vector" value="0x288" />
@ -1984,15 +1961,6 @@
</Group> </Group>
<Group name="job" valid="false"> <Group name="job" valid="false">
<Offset name="id" valid="true" /> <Offset name="id" valid="true" />
<Offset name="materials_vector" /> MISSING!
<Offset name="type" /> MISSING!
<Group name="material">
<Offset name="flags" /> MISSING!
<Offset name="maintype" /> MISSING!
<Offset name="sectype1" /> MISSING!
<Offset name="sectype2" /> MISSING!
<Offset name="sectype3" /> MISSING!
</Group>
</Group> </Group>
</Group> </Group>
<Group name="Maps" valid="true"> <Group name="Maps" valid="true">
@ -2074,22 +2042,6 @@
<Address name="language_vector" value="0x0171ea94"/> <Address name="language_vector" value="0x0171ea94"/>
<Address name="translation_vector" value="0x0171eab4"/> <Address name="translation_vector" value="0x0171eab4"/>
</Group> </Group>
<!--
<Group name="Items" valid="false">
<Address name="items_vector" />
List of offsets in the VTable :
<Offset name="item_type_accessor" />
<Offset name="item_subtype_accessor" />
<Offset name="item_subindex_accessor" />
<Offset name="item_index_accessor" />
<Offset name="item_quality_accessor" />
<Offset name="item_improvement_vector" />
<Offset name="item_improvement_subindex" />
<Offset name="item_improvement_index" />
<Offset name="item_improvement_quality" />
<Offset name="item_type_accessor" /> (in the vtable)
</Group>
-->
</Offsets> </Offsets>
</Version> </Version>
<Version name="v0.31.20 SDL" os="windows" base="v0.31.19 SDL" rebase="0x6000" > <Version name="v0.31.20 SDL" os="windows" base="v0.31.19 SDL" rebase="0x6000" >
@ -2179,11 +2131,6 @@
</Group> </Group>
<Group name="Maps"> <Group name="Maps">
<Group name="block"> <Group name="block">
<!--
<Offset name="vein_vector" value="0x8" />
<Offset name="feature_local" value="0x24" />
<Offset name="feature_global" value="0x28" />
-->
<Offset name="mystery_offset" value="0x2C" /> <Offset name="mystery_offset" value="0x2C" />
<Offset name="vegetation_vector" value="0x64" /> <Offset name="vegetation_vector" value="0x64" />
<Offset name="type" value="0x7e" /> <Offset name="type" value="0x7e" />
@ -2948,6 +2895,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>

@ -319,6 +319,17 @@ uint32_t OffsetGroup::getAddress (const string & key)
throw Error::MissingMemoryDefinition("address", getFullName() + key); throw Error::MissingMemoryDefinition("address", getFullName() + key);
} }
// Get named offset, return bool instead of throwing exceptions
bool OffsetGroup::getSafeAddress (const string & key, uint32_t & out)
{
uint32_Iter iter = OGd->addresses.find(key);
if(iter != OGd->addresses.end() && (*iter).second.first == IS_VALID)
{
out = (*iter).second.second;
return true;
}
return false;
}
// Get named offset // Get named offset
int32_t OffsetGroup::getOffset (const string & key) int32_t OffsetGroup::getOffset (const string & key)
@ -335,6 +346,18 @@ int32_t OffsetGroup::getOffset (const string & key)
throw Error::MissingMemoryDefinition("offset", getFullName() + key); throw Error::MissingMemoryDefinition("offset", getFullName() + key);
} }
// Get named offset, return bool instead of throwing exceptions
bool OffsetGroup::getSafeOffset (const string & key, int32_t & out)
{
int32_Iter iter = OGd->offsets.find(key);
if(iter != OGd->offsets.end() && (*iter).second.first == IS_VALID)
{
out = (*iter).second.second;
return true;
}
return false;
}
// Get named numerical value // Get named numerical value
uint32_t OffsetGroup::getHexValue (const string & key) uint32_t OffsetGroup::getHexValue (const string & key)

@ -37,9 +37,9 @@ extern "C" {
DFHACK_EXPORT int Items_Start(DFHackObject* items); DFHACK_EXPORT int Items_Start(DFHackObject* items);
DFHACK_EXPORT int Items_Finish(DFHackObject* items); DFHACK_EXPORT int Items_Finish(DFHackObject* items);
DFHACK_EXPORT char* Items_getItemDescription(DFHackObject* items, uint32_t itemptr, DFHackObject* mats); DFHACK_EXPORT char* Items_getItemDescription(DFHackObject* items, dfh_item* item, DFHackObject* mats);
DFHACK_EXPORT char* Items_getItemClass(DFHackObject* items, int32_t index); DFHACK_EXPORT char* Items_getItemClass(DFHackObject* items, int32_t index);
DFHACK_EXPORT int Items_getItemData(DFHackObject* items, uint32_t itemptr, t_item* item); DFHACK_EXPORT int Items_getItemData(DFHackObject* items, uint32_t itemptr, dfh_item* item);
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -106,73 +106,6 @@ struct t_name
bool has_name; bool has_name;
}; };
//raw
struct t_item_df40d
{
uint32_t vtable;
uint16_t x;
uint16_t y;
uint16_t z;
uint32_t flags;
uint32_t unk1;
uint32_t unk2;
uint32_t ID;
// not complete
};
//From http://dwarffortresswiki.net/index.php/User:Rick/Memory_research
//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 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
// 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 unk8 : 1; // unknown function
unsigned int unk9 : 1; // unknown function
unsigned int unk10 : 1; // unknown function
unsigned int unk11 : 1; // unknown function
};
union t_itemflags
{
uint32_t whole;
naked_itemflags bits;
};
struct t_note struct t_note
{ {
char symbol; char symbol;
@ -197,7 +130,7 @@ struct t_settlement
int16_t local_y1; int16_t local_y1;
int16_t local_y2; int16_t local_y2;
}; };
struct t_attrib struct t_attrib
{ {
uint32_t level; uint32_t level;

@ -77,6 +77,9 @@ namespace DFHack
std::string getString (const std::string & key); std::string getString (const std::string & key);
OffsetGroup * getGroup ( const std::string & name ); OffsetGroup * getGroup ( const std::string & name );
bool getSafeOffset (const std::string & key, int32_t & out);
bool getSafeAddress (const std::string & key, uint32_t & out);
void setOffset (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID); void setOffset (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);
void setOffsetValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID); void setOffsetValidity(const std::string& key, const DFHack::INVAL_TYPE inval = IS_VALID);
void setAddress (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID); void setAddress (const std::string& key, const std::string& value, const DFHack::INVAL_TYPE inval = IS_VALID);

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

@ -3,23 +3,105 @@
#define CL_MOD_ITEMS #define CL_MOD_ITEMS
/* /*
* Creatures * Items!
*/ */
#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;
//From http://dwarffortresswiki.net/index.php/User:Rick/Memory_research
//They all seem to be valid on 40d as well
union t_itemflags
{
uint32_t whole;
struct
{
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 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; // 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; // 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
};
};
struct t_item struct t_item
{ {
uint32_t vtable;
int16_t x;
int16_t y;
int16_t z;
t_itemflags flags;
};
struct dfh_item
{
t_item base;
t_material matdesc; t_material matdesc;
int32_t quantity; int32_t quantity;
int32_t quality; int32_t quality;
int16_t wear_level;
uint32_t origin;
}; };
/*
//raw
struct t_item_df40d
{
uint32_t vtable;
uint16_t x;
uint16_t y;
uint16_t z;
uint32_t flags;
uint32_t unk1;
uint32_t unk2;
uint32_t ID;
// not complete
};
*/
struct t_improvement struct t_improvement
{ {
t_material matdesc; t_material matdesc;
@ -33,9 +115,16 @@ public:
~Items(); ~Items();
bool Start(); bool Start();
bool Finish(); bool Finish();
std::string getItemDescription(uint32_t itemptr, Materials * Materials); /// get a string describing an item
std::string getItemDescription(const dfh_item & item, Materials * Materials);
/// get a short name for an item
std::string getItemClass(int32_t index); std::string getItemClass(int32_t index);
bool getItemData(uint32_t itemptr, t_item & item); /// read an item, including the extra attributes
bool readItem(uint32_t itemptr, dfh_item & item);
/// write item base (position and flags only = t_item part of dfh_item)
bool writeItem(const dfh_item & item);
/// who owns this item we already read?
int32_t getItemOwnerID(const dfh_item & item);
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,100 +90,154 @@ 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:
ItemDesc(uint32_t VTable, Process * p); ItemDesc(uint32_t VTable, Process * p);
bool getItem(uint32_t itemptr, t_item & item); bool readItem(uint32_t itemptr, dfh_item & item);
std::string className; std::string className;
uint32_t vtable; uint32_t vtable;
uint32_t mainType; uint32_t mainType;
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
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; if(!p)
uint64_t funcText = p->readQuad(function);
if( funcText == 0xCCCCCCCCCCC3C033LL )
{ {
this->constant = 0;
return; return;
} }
if( funcText == 0xCCCCCCCCC3FFC883LL ) uint32_t ptr = function;
{ int data_reg = -1;
/* or eax,-1; ret; */ uint64_t v = p->readQuad(ptr);
this->constant = -1;
return; if (do_match(ptr, v, 2, 0xFFFF, 0xC033) ||
} do_match(ptr, v, 2, 0xFFFF, 0xC031)) // XOR EAX, EAX
if( (funcText&0xFFFFFFFFFF0000FFLL) == 0xCCCCC300000000B8LL )
{
/* mov eax, xx; ret; */
this->constant = (funcText>>8) & 0xffff;
return;
}
if( (funcText&0xFFFFFF0000FFFFFFLL) == 0xC300000000818B66LL )
{ {
/* mov ax, [ecx+xx]; ret; */ data_reg = 0;
this->type = ACCESSOR_INDIRECT; this->constant = 0;
this->offset1 = (funcText>>24) & 0xffff;
return;
} }
if( (funcText&0x000000FF00FFFFFFLL) == 0x000000C300418B66LL ) else if (do_match(ptr, v, 3, 0xFFFFFF, 0xFFC883)) // OR EAX, -1
{ {
/* mov ax, [ecx+xx]; ret; (shorter instruction)*/ data_reg = 0;
this->type = ACCESSOR_INDIRECT; this->constant = -1;
this->offset1 = (funcText>>24) & 0xff;
return;
} }
if( (funcText&0x00000000FF00FFFFLL) == 0x00000000C300418BLL ) else if (do_match(ptr, v, 5, 0xFF, 0xB8)) // MOV EAX,imm
{ {
/* mov eax, [ecx+xx]; ret; */ data_reg = 0;
this->type = ACCESSOR_INDIRECT; this->constant = (v>>8) & 0xFFFFFFFF;
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 +250,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;
} }
@ -222,41 +279,65 @@ int32_t Accessor::getValue(uint32_t objectPtr)
} }
} }
// FIXME: turn into a proper factory with caching
Accessor * buildAccessor (OffsetGroup * I, Process * p, const char * name, uint32_t vtable)
{
int32_t offset;
if(I->getSafeOffset("item_type_accessor",offset))
return new Accessor( p->readDWord( vtable + offset ), p);
else
{
fprintf(stderr,"Missing offset for item accessor \"%s\"\n", name);
return new Accessor(-1,0); // dummy accessor. always returns -1
}
}
ItemDesc::ItemDesc(uint32_t VTable, Process *p) ItemDesc::ItemDesc(uint32_t VTable, Process *p)
{ {
int32_t funcOffsetA, funcOffsetB, funcOffsetC, funcOffsetD, funcOffsetQuality, funcOffsetWear;
OffsetGroup * Items = p->getDescriptor()->getGroup("Items"); OffsetGroup * Items = p->getDescriptor()->getGroup("Items");
uint32_t funcOffsetA = Items->getOffset("item_type_accessor");
uint32_t funcOffsetB = Items->getOffset("item_subtype_accessor"); /*
uint32_t funcOffsetC = Items->getOffset("item_subindex_accessor"); * FIXME: and what about types, different sets of methods depending on class?
uint32_t funcOffsetD = Items->getOffset("item_index_accessor"); * what about more complex things than constants and integers?
uint32_t funcOffsetQuality = Items->getOffset("item_quality_accessor"); * If this is to be generally useful, it needs much more power.
*/
AMainType = buildAccessor(Items, p, "item_type_accessor", VTable);
ASubType = buildAccessor(Items, p, "item_subtype_accessor", VTable);
ASubIndex = buildAccessor(Items, p, "item_subindex_accessor", VTable);
AIndex = buildAccessor(Items, p, "item_index_accessor", VTable);
AQuality = buildAccessor(Items, p, "item_quality_accessor", VTable);
AWear = buildAccessor(Items, p, "item_wear_accessor", VTable);
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);
this->className.resize(this->className.size()-2); this->className.resize(this->className.size()-2);
this->AMainType = new Accessor( p->readDWord( VTable + funcOffsetA ), p);
this->ASubType = new Accessor( p->readDWord( VTable + funcOffsetB ), 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->hasDecoration = false; this->hasDecoration = false;
if(this->AMainType->isConstant()) if(AMainType->isConstant())
this->mainType = this->AMainType->getValue(0); mainType = this->AMainType->getValue(0);
else else
{ {
fprintf(stderr, "Bad item main type at function %p\n", (void*) p->readDWord( VTable + funcOffsetA )); fprintf(stderr, "Bad item main type at function %p\n", (void*) p->readDWord( VTable + funcOffsetA ));
this->mainType = 0; mainType = 0;
} }
} }
bool ItemDesc::getItem(uint32_t itemptr, DFHack::t_item &item) bool ItemDesc::readItem(uint32_t itemptr, DFHack::dfh_item &item)
{ {
item.matdesc.itemType = this->AMainType->getValue(itemptr); p->read(itemptr, sizeof(t_item), (uint8_t*)&item.base);
item.matdesc.subType = this->ASubType->getValue(itemptr); item.matdesc.itemType = AMainType->getValue(itemptr);
item.matdesc.subIndex = this->ASubIndex->getValue(itemptr); item.matdesc.subType = ASubType->getValue(itemptr);
item.matdesc.index = this->AIndex->getValue(itemptr); item.matdesc.subIndex = ASubIndex->getValue(itemptr);
item.quality = this->AQuality->getValue(itemptr); item.matdesc.index = AIndex->getValue(itemptr);
item.quality = AQuality->getValue(itemptr);
item.quantity = 1; /* TODO */ item.quantity = 1; /* TODO */
item.origin = itemptr;
// FIXME: use templates. seriously.
// 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 +348,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 +358,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()
@ -301,7 +386,7 @@ Items::~Items()
delete d; delete d;
} }
bool Items::getItemData(uint32_t itemptr, DFHack::t_item &item) bool Items::readItem(uint32_t itemptr, DFHack::dfh_item &item)
{ {
std::map<uint32_t, ItemDesc *>::iterator it; std::map<uint32_t, ItemDesc *>::iterator it;
Process * p = d->owner; Process * p = d->owner;
@ -318,7 +403,57 @@ bool Items::getItemData(uint32_t itemptr, DFHack::t_item &item)
else else
desc = it->second; desc = it->second;
return desc->getItem(itemptr, item); return desc->readItem(itemptr, item);
}
bool Items::writeItem(const DFHack::dfh_item &item)
{
if(item.origin)
{
d->owner->write(item.origin, sizeof(t_item),(uint8_t *)&(item.base));
return true;
}
return false;
}
/*
void Items::setItemFlags(uint32_t itemptr, t_itemflags new_flags)
{
d->owner->writeDWord(itemptr + 0x0C, new_flags.whole);
}
*/
int32_t Items::getItemOwnerID(const DFHack::dfh_item &item)
{
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, item.origin + 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)
@ -348,8 +483,9 @@ std::string Items::getItemClass(int32_t index)
return out; return out;
} }
std::string Items::getItemDescription(uint32_t itemptr, Materials * Materials) std::string Items::getItemDescription(const dfh_item & item, Materials * Materials)
{ {
/*
DFHack::t_item item; DFHack::t_item item;
std::string out; std::string out;
@ -368,128 +504,7 @@ std::string Items::getItemDescription(uint32_t itemptr, Materials * Materials)
out.append(Materials->getDescription(item.matdesc)); out.append(Materials->getDescription(item.matdesc));
out.append(" "); out.append(" ");
out.append(this->getItemClass(item.matdesc.itemType)); out.append(this->getItemClass(item.matdesc.itemType));
return out; */
} //return out;
return getItemClass(item.matdesc.itemType);
// The OLD items code follows (40d era)
// TODO: merge with the current Items module
/*
bool API::InitReadItems(uint32_t & numitems)
{
try
{
int items = d->offset_descriptor->getAddress ("items");
d->item_material_offset = d->offset_descriptor->getOffset ("item_materials");
d->p_itm = new DfVector (d->p, items);
d->itemsInited = true;
numitems = d->p_itm->getSize();
return true;
}
catch (Error::AllMemdef&)
{
d->itemsInited = false;
numitems = 0;
throw;
}
}
bool API::getItemIndexesInBox(vector<uint32_t> &indexes,
const uint16_t x1, const uint16_t y1, const uint16_t z1,
const uint16_t x2, const uint16_t y2, const uint16_t z2)
{
if(!d->itemsInited) return false;
indexes.clear();
uint32_t size = d->p_itm->getSize();
struct temp2{
uint16_t coords[3];
uint32_t flags;
};
temp2 temp2;
for(uint32_t i =0;i<size;i++){
uint32_t temp = d->p_itm->at(i);
d->p->read(temp+sizeof(uint32_t),5 * sizeof(uint16_t), (uint8_t *) &temp2);
if(temp2.flags & (1 << 0)){
if (temp2.coords[0] >= x1 && temp2.coords[0] < x2)
{
if (temp2.coords[1] >= y1 && temp2.coords[1] < y2)
{
if (temp2.coords[2] >= z1 && temp2.coords[2] < z2)
{
indexes.push_back(i);
}
}
}
}
}
return true;
}
bool API::ReadItem (const uint32_t index, t_item & item)
{
if (!d->itemsInited) return false;
t_item_df40d item_40d;
// read pointer from vector at position
uint32_t temp = d->p_itm->at (index);
//read building from memory
d->p->read (temp, sizeof (t_item_df40d), (uint8_t *) &item_40d);
// transform
int32_t type = -1;
d->offset_descriptor->resolveObjectToClassID (temp, type);
item.origin = temp;
item.vtable = item_40d.vtable;
item.x = item_40d.x;
item.y = item_40d.y;
item.z = item_40d.z;
item.type = type;
item.ID = item_40d.ID;
item.flags.whole = item_40d.flags;
//TODO certain item types (creature based, threads, seeds, bags do not have the first matType byte, instead they have the material index only located at 0x68
d->p->read (temp + d->item_material_offset, sizeof (t_matglossPair), (uint8_t *) &item.material);
//for(int i = 0; i < 0xCC; i++){ // used for item research
// uint8_t byte = MreadByte(temp+i);
// item.bytes.push_back(byte);
//}
return true;
}
void API::FinishReadItems()
{
if(d->p_itm)
{
delete d->p_itm;
d->p_itm = NULL;
}
d->itemsInited = false;
}
*/
/*
bool API::ReadItemTypes(vector< vector< t_itemType > > & itemTypes)
{
memory_info * minfo = d->offset_descriptor;
int matgloss_address = minfo->getAddress("matgloss");
int matgloss_skip = minfo->getHexValue("matgloss_skip");
int item_type_name_offset = minfo->getOffset("item_type_name");
for(int i = 8;i<20;i++)
{
DfVector p_temp (d->p, matgloss_address + i*matgloss_skip);
vector< t_itemType > typesForVec;
for(uint32_t j =0; j<p_temp.getSize();j++)
{
t_itemType currType;
uint32_t temp = *(uint32_t *) p_temp[j];
// Mread(temp+40,sizeof(name),(uint8_t *) name);
d->p->readSTLString(temp+4,currType.id,128);
d->p->readSTLString(temp+item_type_name_offset,currType.name,128);
//stringsForVec.push_back(string(name));
typesForVec.push_back(currType);
}
itemTypes.push_back(typesForVec);
}
return true;
} }
*/

@ -54,11 +54,11 @@ int Items_Finish(DFHackObject* items)
//FIXME: beware of bad null-termination! I haven't tested anything here, but it seems that it could be corrupting or truncating strings. //FIXME: beware of bad null-termination! I haven't tested anything here, but it seems that it could be corrupting or truncating strings.
char* Items_getItemDescription(DFHackObject* items, uint32_t itemptr, DFHackObject* mats) char* Items_getItemDescription(DFHackObject* items, dfh_item * item, DFHackObject* mats)
{ {
if(items != NULL && mats != NULL) if(items != NULL && mats != NULL)
{ {
std::string desc = ((DFHack::Items*)items)->getItemDescription(itemptr, (DFHack::Materials*)mats); std::string desc = ((DFHack::Items*)items)->getItemDescription(*item, (DFHack::Materials*)mats);
if(desc.size() > 0) if(desc.size() > 0)
{ {
@ -112,11 +112,11 @@ char* Items_getItemClass(DFHackObject* items, int32_t index)
return NULL; return NULL;
} }
int Items_getItemData(DFHackObject* items, uint32_t itemptr, t_item* item) int Items_getItemData(DFHackObject* items, uint32_t itemptr, dfh_item* item)
{ {
if(items != NULL) if(items != NULL)
{ {
return ((DFHack::Items*)items)->getItemData(itemptr, *item); return ((DFHack::Items*)items)->readItem(itemptr, *item);
} }
return -1; return -1;

@ -544,50 +544,50 @@ std::string Materials::getDescription(t_material & mat)
//type of material only so we know which vector to retrieve //type of material only so we know which vector to retrieve
std::string Materials::getType(t_material & mat) std::string Materials::getType(t_material & mat)
{ {
if((mat.subIndex<419) || (mat.subIndex>618)) if((mat.subIndex<419) || (mat.subIndex>618))
{ {
if((mat.subIndex<19) || (mat.subIndex>218)) if((mat.subIndex<19) || (mat.subIndex>218))
{ {
if(mat.subIndex) if(mat.subIndex)
{ {
if(mat.subIndex>0x292) if(mat.subIndex>0x292)
{ {
return "unknown"; return "unknown";
} }
else else
{ {
if(mat.subIndex>=this->other.size()) if(mat.subIndex>=this->other.size())
{ {
if(mat.subIndex<0) if(mat.subIndex<0)
return "any"; return "any";
if(mat.subIndex>=this->raceEx.size()) if(mat.subIndex>=this->raceEx.size())
return "unknown"; return "unknown";
return "racex"; return "racex";
} }
else else
{ {
if (mat.index==-1) if (mat.index==-1)
return "other"; return "other";
else else
return "other derivate"; return "other derivate";
} }
} }
} }
else else
return "inorganic"; return "inorganic";
} }
else else
{ {
if (mat.index>=this->raceEx.size()) if (mat.index>=this->raceEx.size())
return "unknown"; return "unknown";
return "racex extract"; return "racex extract";
} }
} }
else else
{ {
return "organic"; return "organic";
} }
} }

@ -1,28 +1,19 @@
/* /*
* dumps vtables, items types and class name for all items in game * Simple, pretty item dump example.
* best used this way : ./dfitemdump | sort -ug
*/ */
// THIS IS NOT A GOOD EXAMPLE! #include <cstdio>
// ... just look at all the magic numbers.
// I'm not fixing it though.
// ~px
#include <stdio.h>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <climits> #include <climits>
#include <vector> #include <vector>
#include <cstring>
using namespace std; using namespace std;
#include <DFHack.h> #include <DFHack.h>
#include <dfhack/DFVector.h> #include <dfhack/DFVector.h>
DFHack::Materials * Materials;
DFHack::Items * Items;
int main () int main ()
{ {
DFHack::Process * p; DFHack::Process * p;
@ -42,17 +33,36 @@ int main ()
#endif #endif
return 1; return 1;
} }
DFHack::Materials * Materials = DF->getMaterials();
Materials->ReadAllMaterials();
DFHack::Items * Items = DF->getItems();
Items->Start();
DFHack::VersionInfo * mem = DF->getMemoryInfo(); DFHack::VersionInfo * mem = DF->getMemoryInfo();
Materials = DF->getMaterials();
Materials->ReadAllMaterials();
p = DF->getProcess(); p = DF->getProcess();
// FIXME: tools should never be exposed to DFHack internals!
DFHack::OffsetGroup* itemGroup = mem->getGroup("Items"); DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
DFHack::DfVector <uint32_t> p_items (p, itemGroup->getAddress("items_vector")); DFHack::DfVector <uint32_t> p_items (p, itemGroup->getAddress("items_vector"));
uint32_t size = p_items.size(); uint32_t size = p_items.size();
Items = DF->getItems();
for(int i = 0; i < size; i++)
{
DFHack::dfh_item itm;
memset(&itm, 0, sizeof(DFHack::dfh_item));
Items->readItem(p_items[i],itm);
printf(
"%5d: %08x %08x (%d,%d,%d) #%08x [%d] %s - %s\n",
i, itm.origin, itm.base.flags.whole,
itm.base.x, itm.base.y, itm.base.z,
itm.base.vtable,
itm.wear_level,
Items->getItemClass(itm.matdesc.itemType).c_str(),
Items->getItemDescription(itm, Materials).c_str()
);
}
/*
printf("type\tvtable\tname\tquality\tdecorate\n"); printf("type\tvtable\tname\tquality\tdecorate\n");
for (i=0;i<size;i++) for (i=0;i<size;i++)
{ {
@ -78,9 +88,9 @@ int main ()
uint32_t quality = 0; uint32_t quality = 0;
bool hasDecorations; bool hasDecorations;
string desc = p->readClassName(vtable); string desc = p->readClassName(vtable);
DFHack::t_item itm; DFHack::dfh_item itm;
Items->getItemData(p_items[i], itm); Items->readItem(p_items[i], itm);
if ( (funct0&0xFFFFFFFFFF000000LL) != 0xCCCCC30000000000LL ) if ( (funct0&0xFFFFFFFFFF000000LL) != 0xCCCCC30000000000LL )
{ {
@ -226,7 +236,7 @@ int main ()
} }
printf("\n"); printf("\n");
} }
*/
#ifndef LINUX_BUILD #ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl; cout << "Done. Press any key to continue" << endl;
cin.ignore(); cin.ignore();

@ -86,6 +86,8 @@ DFHACK_TOOL(dfhellhole hellhole.cpp)
# Allows mass-modify, esp. for all immigrants # Allows mass-modify, esp. for all immigrants
DFHACK_TOOL(dfskillmodify skillmodify.cpp) DFHACK_TOOL(dfskillmodify skillmodify.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,176 @@
/*
* Confiscates and dumps garbage owned by dwarfs.
*/
#include <cstdio>
#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::dfh_item itm;
Items->readItem(curItem, itm);
if (!itm.base.flags.owned)
continue;
bool confiscate = false;
bool dump = false;
if (itm.base.flags.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.base.flags.on_ground)
{
printf("Confiscating and dumping litter: \t");
confiscate = true;
dump = true;
}
else if (confiscate_all)
{
printf("Confiscating: \t");
confiscate = true;
}
if (confiscate)
{
itm.base.flags.owned = 0;
if (dump)
itm.base.flags.dump = 1;
if (!dry_run)
Items->writeItem(itm);
printf(
"%s (wear %d)",
Items->getItemDescription(itm, Materials).c_str(),
itm.wear_level
);
int32_t owner = Items->getItemOwnerID(itm);
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, itm.origin, itm.base.flags.whole,
itm.base.x, itm.base.y, itm.base.z,
itm.base.vtable,
itm.wear_level,
Items->getItemClass(itm.matdesc.itemType).c_str(),
Items->getItemDescription(itm, Materials).c_str(),
info.c_str()
);
*/
}
}
#ifndef LINUX_BUILD
cout << "Done. Press any key to continue" << endl;
cin.ignore();
#endif
return 0;
}