Merge branch 'master' of git://github.com/peterix/dfhack

develop
Espen Wiborg 2012-01-23 10:43:07 +01:00
commit 0cf3ee3dc6
91 changed files with 6137 additions and 2666 deletions

@ -1093,6 +1093,14 @@
<Address name='ui_look_list'/>
<Address name='ui_look_cursor'/>
<Address name='ui_workshop_job_cursor'/>
<Address name='ui_workshop_in_add'/>
<Address name='job_next_id'/>
<Address name='ui_building_item_cursor'/>
<Address name='ui_selected_unit'/>
<Address name='ui_unit_view_mode'/>
<Address name='cur_year'/>
<Address name='cur_year_tick'/>
<Address name='gps'/>
</Group>
</Offsets>
</Base>
@ -2343,6 +2351,17 @@
<Address name='ui_look_list' value='0x185c104'/>
<Address name='ui_look_cursor' value='0xedeb98'/>
<Address name='ui_workshop_job_cursor' value='0x14ec79c'/>
<Address name='ui_workshop_in_add' value='0xeb0992'/>
<Address name='job_next_id' value='0xe18290'/>
<Address name='ui_building_item_cursor' value='0xef7264'/>
<Address name='ui_selected_unit' value='0xef2430'/>
<Address name='ui_unit_view_mode' value='0xec4a5c'/>
<Address name='cur_year' value='0xef7268'/>
<Address name='cur_year_tick' value='0xec5170'/>
<Address name='gps' value='0xb34d10'/>
</Group>
</Offsets>
cmake
@ -3225,8 +3244,19 @@
<Address name='ui_sidebar_menus' value='0x958aa40'/>
<Address name='ui_build_selector' value='0x8df9b20'/>
<Address name='ui_look_list' value='0x961d840'/>
<!--<Address name='ui_look_cursor' value=''/>-->
<Address name='ui_look_cursor' value='0x93f06dc'/>
<Address name='ui_workshop_job_cursor' value='0x93f0644'/>
<Address name='ui_workshop_in_add' value='0x93f0651'/>
<Address name='job_next_id' value='0x961d940'/>
<Address name='ui_building_item_cursor' value='0x93f0648'/>
<Address name='ui_selected_unit' value='0x93f06d0'/>
<Address name='ui_unit_view_mode' value='0x93f06d8'/>
<Address name='cur_year' value='0x93f0600'/>
<Address name='cur_year_tick' value='0x93f0620'/>
<Address name='gps' value='0x8c3e000'/>
</Group>
</Offsets>
</Version>

@ -2,3 +2,4 @@ call "%VS100COMNTOOLS%vsvars32.bat"
cd VC2010
msbuild /m /p:Platform=Win32 /p:Configuration=Release ALL_BUILD.vcxproj
cd ..
pause

@ -39,7 +39,6 @@ include/SDL_keyboard.h
include/SDL_keysym.h
include/TileTypes.h
include/Types.h
include/Vector.h
include/VersionInfo.h
include/VersionInfoFactory.h
include/Virtual.h
@ -49,6 +48,7 @@ include/modules/Units.h
include/modules/Engravings.h
include/modules/Gui.h
include/modules/Items.h
include/modules/Job.h
include/modules/kitchen.h
include/modules/Maps.h
include/modules/MapCache.h
@ -89,6 +89,7 @@ modules/Units.cpp
modules/Engravings.cpp
modules/Gui.cpp
modules/Items.cpp
modules/Job.cpp
modules/kitchen.cpp
modules/Maps.cpp
modules/Materials.cpp

@ -1094,11 +1094,8 @@ MODULE_GETTER(Maps);
MODULE_GETTER(Gui);
MODULE_GETTER(World);
MODULE_GETTER(Materials);
MODULE_GETTER(Items);
MODULE_GETTER(Translation);
MODULE_GETTER(Vegetation);
MODULE_GETTER(Buildings);
MODULE_GETTER(Constructions);
MODULE_GETTER(Vermin);
MODULE_GETTER(Notes);
MODULE_GETTER(Graphic);

@ -35,6 +35,8 @@ distribution.
// must be last due to MS stupidity
#include "DataDefs.h"
#include "MiscUtils.h"
using namespace DFHack;
/* The order of global object constructor calls is
@ -154,10 +156,55 @@ void virtual_identity::Init(Core *core)
// Read pre-filled vtable ptrs
OffsetGroup *ptr_table = core->vinfo->getGroup("vtable");
for (virtual_identity *p = list; p; p = p->next) {
uint32_t tmp;
void * tmp;
if (ptr_table->getSafeAddress(p->getName(),tmp))
p->vtable_ptr = (void*)tmp;
p->vtable_ptr = tmp;
}
}
std::string DFHack::bitfieldToString(const void *p, int size, const bitfield_item_info *items)
{
std::string res;
const char *data = (const char*)p;
for (int i = 0; i < size*8; i++) {
unsigned v;
if (items[i].size > 1) {
unsigned pdv = *(unsigned*)&data[i/8];
v = (pdv >> (i%8)) & ((1 << items[i].size)-1);
} else {
v = (data[i/8]>>(i%8)) & 1;
}
if (v) {
if (!res.empty())
res += ' ';
if (items[i].name)
res += items[i].name;
else
res += stl_sprintf("UNK_%d", i);
if (items[i].size > 1)
res += stl_sprintf("=%u", v);
}
if (items[i].size > 1)
i += items[i].size-1;
}
return res;
}
int DFHack::findBitfieldField(const std::string &name, int size, const bitfield_item_info *items)
{
for (int i = 0; i < size*8; i++) {
if (items[i].name && items[i].name == name)
return i;
}
return -1;
}
#define SIMPLE_GLOBAL(name,tname) \
@ -169,7 +216,7 @@ DF_KNOWN_GLOBALS
void DFHack::InitDataDefGlobals(Core *core) {
OffsetGroup *global_table = core->vinfo->getGroup("global");
uint32_t tmp;
void * tmp;
#define SIMPLE_GLOBAL(name,tname) \
if (global_table->getSafeAddress(#name,tmp)) df::global::name = (tname*)tmp;

@ -27,8 +27,6 @@ distribution.
#include "Core.h"
#include "MiscUtils.h"
#ifndef LINUX_BUILD
#include <Windows.h>
#else
@ -36,6 +34,71 @@ distribution.
#include <ctime>
#endif
#include <ctype.h>
#include <stdarg.h>
std::string stl_sprintf(const char *fmt, ...) {
va_list lst;
va_start(lst, fmt);
std::string rv = stl_vsprintf(fmt, lst);
va_end(lst);
return rv;
}
std::string stl_vsprintf(const char *fmt, va_list args) {
std::vector<char> buf;
buf.resize(4096);
for (;;) {
int rsz = vsnprintf(&buf[0], buf.size(), fmt, args);
if (rsz < 0)
buf.resize(buf.size()*2);
else if (unsigned(rsz) > buf.size())
buf.resize(rsz+1);
else
return std::string(&buf[0], rsz);
}
}
bool split_string(std::vector<std::string> *out,
const std::string &str, const std::string &separator, bool squash_empty)
{
out->clear();
size_t start = 0, pos;
if (!separator.empty())
{
while ((pos = str.find(separator,start)) != std::string::npos)
{
if (pos > start || !squash_empty)
out->push_back(str.substr(start, pos-start));
start = pos + separator.size();
}
}
if (start < str.size() || !squash_empty)
out->push_back(str.substr(start));
return out->size() > 1;
}
std::string toUpper(const std::string &str)
{
std::string rv(str.size(),' ');
for (unsigned i = 0; i < str.size(); ++i)
rv[i] = toupper(str[i]);
return rv;
}
std::string toLower(const std::string &str)
{
std::string rv(str.size(),' ');
for (unsigned i = 0; i < str.size(); ++i)
rv[i] = tolower(str[i]);
return rv;
}
#ifdef LINUX_BUILD // Linux
uint64_t GetTimeMs64()
{

@ -111,8 +111,8 @@ Process::~Process()
string Process::doReadClassName (void * vptr)
{
//FIXME: BAD!!!!!
int typeinfo = Process::readDWord((uint32_t)vptr - 0x4);
int typestring = Process::readDWord(typeinfo + 0x4);
char * typeinfo = Process::readPtr(((char *)vptr - 0x4));
char * typestring = Process::readPtr(typeinfo + 0x4);
string raw = readCString(typestring);
size_t start = raw.find_first_of("abcdefghijklmnopqrstuvwxyz");// trim numbers
size_t end = raw.length();
@ -138,8 +138,8 @@ void Process::getMemRanges( vector<t_memrange> & ranges )
(char*)&permissions,
&offset, &device1, &device2, &node,
(char*)&temp.name);
temp.start = start;
temp.end = end;
temp.start = (void *) start;
temp.end = (void *) end;
temp.read = permissions[0] == 'r';
temp.write = permissions[1] == 'w';
temp.execute = permissions[2] == 'x';
@ -214,7 +214,7 @@ bool Process::setPermisions(const t_memrange & range,const t_memrange &trgrange)
if(trgrange.read)protect|=PROT_READ;
if(trgrange.write)protect|=PROT_WRITE;
if(trgrange.execute)protect|=PROT_EXEC;
result=mprotect((void *)range.start, range.end-range.start,protect);
result=mprotect((void *)range.start, (size_t)range.end-(size_t)range.start,protect);
return result==0;
}

@ -112,7 +112,7 @@ namespace DFHack
uint32_t my_pid;
IMAGE_NT_HEADERS pe_header;
IMAGE_SECTION_HEADER * sections;
uint32_t base;
char * base;
};
}
Process::Process(VersionInfoFactory * factory)
@ -134,7 +134,7 @@ Process::Process(VersionInfoFactory * factory)
}
// got base ;)
d->base = (uint32_t)hmod;
d->base = (char *)hmod;
// read from this process
try
@ -161,7 +161,7 @@ Process::Process(VersionInfoFactory * factory)
identified = true;
// give the process a data model and memory layout fixed for the base of first module
my_descriptor = new VersionInfo(*vinfo);
my_descriptor->RebaseAll(d->base);
my_descriptor->RebaseAll((uint32_t)d->base);
// keep track of created memory_info object so we can destroy it later
my_descriptor->setParentProcess(this);
for(size_t i = 0; i < threads_ids.size();i++)
@ -236,7 +236,7 @@ struct HeapBlock
ULONG reserved;
};
*/
void HeapNodes(DWORD pid, map<uint64_t, unsigned int> & heaps)
void HeapNodes(DWORD pid, map<char *, unsigned int> & heaps)
{
// Create debug buffer
PDEBUG_BUFFER db = RtlCreateQueryDebugBuffer(0, FALSE);
@ -247,7 +247,7 @@ void HeapNodes(DWORD pid, map<uint64_t, unsigned int> & heaps)
// Go through each of the heap nodes and dispaly the information
for (unsigned int i = 0; i < heapNodeCount; i++)
{
heaps[heapInfo[i].Base] = i;
heaps[(char *)heapInfo[i].Base] = i;
}
// Clean up the buffer
RtlDestroyQueryDebugBuffer( db );
@ -257,9 +257,9 @@ void HeapNodes(DWORD pid, map<uint64_t, unsigned int> & heaps)
void Process::getMemRanges( vector<t_memrange> & ranges )
{
MEMORY_BASIC_INFORMATION MBI;
map<uint64_t, unsigned int> heaps;
map<char *, unsigned int> heaps;
uint64_t movingStart = 0;
map <uint64_t, string> nameMap;
map <char *, string> nameMap;
// get page size
SYSTEM_INFO si;
@ -277,18 +277,18 @@ void Process::getMemRanges( vector<t_memrange> & ranges )
if( !(MBI.State & MEM_COMMIT) /*|| !(MBI.Type & MEM_PRIVATE)*/ )
continue;
t_memrange temp;
temp.start = (uint64_t) MBI.BaseAddress;
temp.end = ((uint64_t)MBI.BaseAddress + (uint64_t)MBI.RegionSize);
temp.start = (char *) MBI.BaseAddress;
temp.end = ((char *)MBI.BaseAddress + (uint64_t)MBI.RegionSize);
temp.read = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READONLY || MBI.Protect & PAGE_READWRITE;
temp.write = MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_READWRITE;
temp.execute = MBI.Protect & PAGE_EXECUTE_READ || MBI.Protect & PAGE_EXECUTE_READWRITE || MBI.Protect & PAGE_EXECUTE;
temp.valid = true;
if(!GetModuleBaseName(d->my_handle, (HMODULE) temp.start, temp.name, 1024))
{
if(nameMap.count(temp.start))
if(nameMap.count((char *)temp.start))
{
// potential buffer overflow...
strcpy(temp.name, nameMap[temp.start].c_str());
strcpy(temp.name, nameMap[(char *)temp.start].c_str());
}
else
{
@ -298,9 +298,9 @@ void Process::getMemRanges( vector<t_memrange> & ranges )
else
{
// could be a heap?
if(heaps.count(temp.start))
if(heaps.count((char *)temp.start))
{
sprintf(temp.name,"HEAP %d",heaps[temp.start]);
sprintf(temp.name,"HEAP %d",heaps[(char*)temp.start]);
}
else temp.name[0]=0;
}
@ -320,7 +320,7 @@ void Process::getMemRanges( vector<t_memrange> & ranges )
nm.append(temp.name);
nm.append(" : ");
nm.append(sectionName);
nameMap[temp.start + d->sections[i].VirtualAddress] = nm;
nameMap[(char *)temp.start + d->sections[i].VirtualAddress] = nm;
}
}
else
@ -333,14 +333,14 @@ void Process::getMemRanges( vector<t_memrange> & ranges )
uint32_t Process::getBase()
{
if(d)
return d->base;
return (uint32_t) d->base;
return 0x400000;
}
string Process::doReadClassName (void * vptr)
{
int rtti = readDWord((uint32_t)vptr - 0x4);
int typeinfo = readDWord(rtti + 0xC);
char * rtti = readPtr((char *)vptr - 0x4);
char * typeinfo = readPtr(rtti + 0xC);
string raw = readCString(typeinfo + 0xC); // skips the .?AV
raw.resize(raw.length() - 2);// trim @@ from end
return raw;
@ -367,7 +367,7 @@ bool Process::setPermisions(const t_memrange & range,const t_memrange &trgrange)
if(trgrange.read && trgrange.write && trgrange.execute)newprotect=PAGE_EXECUTE_READWRITE;
DWORD oldprotect=0;
bool result;
result=VirtualProtect((LPVOID)range.start,range.end-range.start,newprotect,&oldprotect);
result=VirtualProtect((LPVOID)range.start,(char *)range.end-(char *)range.start,newprotect,&oldprotect);
return result;
}

@ -158,6 +158,8 @@ namespace DFHack
{
typedef pair <INVAL_TYPE, uint32_t> nullableUint32;
typedef map <string, nullableUint32 >::iterator uint32_Iter;
typedef pair <INVAL_TYPE, char *> nullableBytePtr;
typedef map <string, nullableBytePtr >::iterator byteptr_Iter;
typedef pair <INVAL_TYPE, int32_t> nullableInt32;
typedef map <string, nullableInt32 >::iterator int32_Iter;
typedef pair <INVAL_TYPE, string> nullableString;
@ -166,7 +168,7 @@ namespace DFHack
class OffsetGroupPrivate
{
public:
map <string, nullableUint32 > addresses;
map <string, nullableBytePtr > addresses;
map <string, nullableUint32 > hexvals;
map <string, nullableInt32 > offsets;
map <string, nullableString > strings;
@ -183,7 +185,7 @@ void OffsetGroup::createOffset(const string & key)
void OffsetGroup::createAddress(const string & key)
{
OGd->addresses[key] = nullableUint32(NOT_SET, 0);
OGd->addresses[key] = nullableBytePtr(NOT_SET, (char*) 0);
}
void OffsetGroup::createHexValue(const string & key)
@ -227,10 +229,10 @@ void OffsetGroup::setOffsetValidity (const string & key, const INVAL_TYPE inval)
void OffsetGroup::setAddress (const string & key, const string & value, const INVAL_TYPE inval)
{
uint32_Iter it = OGd->addresses.find(key);
byteptr_Iter it = OGd->addresses.find(key);
if(it != OGd->addresses.end())
{
uint32_t address = strtol(value.c_str(), NULL, 16);
char * address = (char *) strtol(value.c_str(), NULL, 16);
if((*it).second.second == address)
std::cout << "Pointless address setting: " << this->getFullName() + key << endl;
(*it).second.second = address;
@ -244,7 +246,7 @@ void OffsetGroup::setAddressValidity (const string & key, const INVAL_TYPE inval
{
if(inval != NOT_SET)
{
uint32_Iter it = OGd->addresses.find(key);
byteptr_Iter it = OGd->addresses.find(key);
if(it != OGd->addresses.end())
{
(*it).second.first = inval;
@ -305,9 +307,9 @@ void OffsetGroup::setStringValidity (const string & key, const INVAL_TYPE inval)
}
// Get named address
uint32_t OffsetGroup::getAddress (const string & key)
char * OffsetGroup::getAddress (const string & key)
{
uint32_Iter iter = OGd->addresses.find(key);
byteptr_Iter iter = OGd->addresses.find(key);
if(iter != OGd->addresses.end())
{
@ -321,9 +323,9 @@ uint32_t OffsetGroup::getAddress (const string & key)
}
// Get named offset, return bool instead of throwing exceptions
bool OffsetGroup::getSafeAddress (const string & key, uint32_t & out)
bool OffsetGroup::getSafeAddress (const string & key, void * & out)
{
uint32_Iter iter = OGd->addresses.find(key);
byteptr_Iter iter = OGd->addresses.find(key);
if(iter != OGd->addresses.end() && (*iter).second.first == IS_VALID)
{
out = (*iter).second.second;
@ -410,7 +412,7 @@ OffsetGroup * OffsetGroup::createGroup(const std::string &name)
void OffsetGroup::RebaseAddresses(int32_t offset)
{
for(uint32_Iter iter = OGd->addresses.begin(); iter != OGd->addresses.end(); iter++)
for(byteptr_Iter iter = OGd->addresses.begin(); iter != OGd->addresses.end(); iter++)
{
if(iter->second.first)
OGd->addresses[iter->first].second = iter->second.second + offset;
@ -470,18 +472,19 @@ std::string OffsetGroup::getFullName()
std::string OffsetGroup::PrintOffsets(int indentation)
{
byteptr_Iter addriter;
uint32_Iter iter;
ostringstream ss;
indentr i(indentation);
typedef pair <uint32_t, pair< string, nullableUint32 > > horrible;
typedef pair <void *, pair< string, nullableBytePtr > > horrible;
vector < horrible > addrsorter;
for(iter = OGd->addresses.begin(); iter != OGd->addresses.end(); iter++)
for(addriter = OGd->addresses.begin(); addriter != OGd->addresses.end(); addriter++)
{
if(!(*iter).second.first)
addrsorter.push_back( make_pair( 0, *iter ) );
if(!(*addriter).second.first)
addrsorter.push_back( make_pair( (void *)0, *addriter ) );
else
{
addrsorter.push_back( make_pair( (*iter).second.second, *iter ) );
addrsorter.push_back( make_pair( (*addriter).second.second, *addriter ) );
}
}
std::sort(addrsorter.begin(), addrsorter.end(), compare_pair_first<>());
@ -569,7 +572,7 @@ void OffsetGroup::setInvalid(INVAL_TYPE invalidity)
if(invalidity == NOT_SET)
return;
uint32_Iter iter;
byteptr_Iter iter;
for(iter = OGd->addresses.begin(); iter != OGd->addresses.end(); iter++)
{
if((*iter).second.first)
@ -581,17 +584,18 @@ void OffsetGroup::setInvalid(INVAL_TYPE invalidity)
if((*iter2).second.first)
(*iter2).second.first = invalidity;
}
for(iter = OGd->hexvals.begin(); iter != OGd->hexvals.end(); iter++)
{
if((*iter).second.first)
(*iter).second.first = invalidity;
}
strings_Iter iter3;
for(iter3 = OGd->strings.begin(); iter3 != OGd->strings.end(); iter3++)
uint32_Iter iter3;
for(iter3 = OGd->hexvals.begin(); iter3 != OGd->hexvals.end(); iter3++)
{
if((*iter3).second.first)
(*iter3).second.first = invalidity;
}
strings_Iter iter5;
for(iter5 = OGd->strings.begin(); iter5 != OGd->strings.end(); iter5++)
{
if((*iter5).second.first)
(*iter5).second.first = invalidity;
}
groups_Iter iter4;
for(iter4 = OGd->groups.begin(); iter4 != OGd->groups.end(); iter4++)
{
@ -603,7 +607,7 @@ std::vector<OffsetKey> OffsetGroup::getKeys() const
std::vector<OffsetKey> ret;
OffsetKey K;
K.keytype=IS_ADDRESS;
for(uint32_Iter iter = OGd->addresses.begin(); iter != OGd->addresses.end(); iter++)
for(byteptr_Iter iter = OGd->addresses.begin(); iter != OGd->addresses.end(); iter++)
{
K.key=iter->first;
K.inval=iter->second.first;
@ -1015,7 +1019,7 @@ void VersionInfo::setClassChild (t_class * parent, const char * name, const char
// FIXME: This in now DEPRECATED!
bool VersionInfo::resolveObjectToClassID(const uint32_t address, int32_t & classid)
bool VersionInfo::resolveObjectToClassID(const char * address, int32_t & classid)
{
uint32_t vtable = d->p->readDWord(address);
// try to find the vtable in our cache

@ -50,6 +50,18 @@ namespace DFHack
if(bits)
memset(bits, 0, size);
}
void extend (T index)
{
uint32_t newsize = (index / 8) + 1;
if (newsize <= size)
return;
uint8_t *newbits = new uint8_t[newsize];
memset(newbits, 0, newsize);
memcpy(newbits, bits, size);
delete[] bits;
bits = newbits;
size = newsize;
}
void set (T index, bool value = true)
{
if(!value)
@ -58,7 +70,8 @@ namespace DFHack
return;
}
uint32_t byte = index / 8;
if(byte < size)
extend(index);
//if(byte < size)
{
uint8_t bit = 1 << (index % 8);
bits[byte] |= bit;
@ -76,7 +89,8 @@ namespace DFHack
void toggle (T index)
{
uint32_t byte = index / 8;
if(byte < size)
extend(index);
//if(byte < size)
{
uint8_t bit = 1 << (index % 8);
bits[byte] ^= bit;

@ -58,12 +58,9 @@ namespace DFHack
class Gui;
class World;
class Materials;
class Items;
class Translation;
class Vegetation;
class Buildings;
class Constructions;
class Vermin;
class Notes;
class VersionInfo;
class VersionInfoFactory;
@ -113,18 +110,12 @@ namespace DFHack
World * getWorld();
/// get the materials module
Materials * getMaterials();
/// get the items module
Items * getItems();
/// get the translation module
Translation * getTranslation();
/// get the vegetation module
Vegetation * getVegetation();
/// get the buildings module
Buildings * getBuildings();
/// get the constructions module
Constructions * getConstructions();
/// get the vermin module
Vermin * getVermin();
/// get the notes module
Notes * getNotes();
/// get the graphic module
@ -179,12 +170,9 @@ namespace DFHack
Gui * pGui;
World * pWorld;
Materials * pMaterials;
Items * pItems;
Translation * pTranslation;
Vegetation * pVegetation;
Buildings * pBuildings;
Constructions * pConstructions;
Vermin * pVermin;
Notes * pNotes;
Graphic * pGraphic;
} s_mods;

@ -111,15 +111,66 @@ namespace DFHack
return T::_identity.is_instance(ptr) ? static_cast<T*>(ptr) : NULL;
}
#define VIRTUAL_CAST_VAR(var,type,input) type *var = virtual_cast<type>(input)
template<class T>
inline T *strict_virtual_cast(virtual_ptr ptr) {
return T::_identity.is_direct_instance(ptr) ? static_cast<T*>(ptr) : NULL;
}
#define STRICT_VIRTUAL_CAST_VAR(var,type,input) type *var = strict_virtual_cast<type>(input)
void InitDataDefGlobals(Core *core);
template<class T>
T *ifnull(T *a, T *b) { return a ? a : b; }
// Enums
template<class T, T start, bool (*isvalid)(T)>
inline T next_enum_item_(T v) {
v = T(int(v) + 1);
return isvalid(v) ? v : start;
}
template<class T>
struct enum_list_attr {
int size;
const T *items;
};
// Bitfields
struct bitfield_item_info {
const char *name;
int size;
};
DFHACK_EXPORT std::string bitfieldToString(const void *p, int size, const bitfield_item_info *items);
DFHACK_EXPORT int findBitfieldField(const std::string &name, int size, const bitfield_item_info *items);
template<class T>
inline int findBitfieldField(const T &val, const std::string &name) {
return findBitfieldField(name, sizeof(val.whole), val.get_items());
}
template<class T>
inline std::string bitfieldToString(const T &val) {
return bitfieldToString(&val.whole, sizeof(val.whole), val.get_items());
}
}
template<class T>
int linear_index(const DFHack::enum_list_attr<T> &lst, T val) {
for (int i = 0; i < lst.size; i++)
if (lst.items[i] == val)
return i;
return -1;
}
inline int linear_index(const DFHack::enum_list_attr<const char*> &lst, const std::string &val) {
for (int i = 0; i < lst.size; i++)
if (lst.items[i] == val)
return i;
return -1;
}
namespace df
@ -127,6 +178,8 @@ namespace df
using DFHack::virtual_ptr;
using DFHack::virtual_identity;
using DFHack::virtual_class;
using DFHack::bitfield_item_info;
using DFHack::enum_list_attr;
using DFHack::BitArray;
template<class T>
@ -158,6 +211,18 @@ namespace df
}
};
template<class EnumType, class IntType1, class IntType2>
inline bool operator== (enum_field<EnumType,IntType1> a, enum_field<EnumType,IntType2> b)
{
return EnumType(a) == EnumType(b);
}
template<class EnumType, class IntType1, class IntType2>
inline bool operator!= (enum_field<EnumType,IntType1> a, enum_field<EnumType,IntType2> b)
{
return EnumType(a) != EnumType(b);
}
namespace enums {}
}
@ -167,6 +232,11 @@ namespace df
#define ENUM_FIRST_ITEM(enum) (df::enums::enum::_first_item_of_##enum)
#define ENUM_LAST_ITEM(enum) (df::enums::enum::_last_item_of_##enum)
#define ENUM_NEXT_ITEM(enum,val) \
(DFHack::next_enum_item_<df::enum,ENUM_FIRST_ITEM(enum),df::enums::enum::is_valid>(val))
#define FOR_ENUM_ITEMS(enum,iter) \
for(df::enum iter = ENUM_FIRST_ITEM(enum); iter < ENUM_LAST_ITEM(enum); iter = df::enum(1+int(iter)))
namespace df {
#define DF_KNOWN_GLOBALS \
GLOBAL(cursor,cursor) \
@ -176,11 +246,20 @@ namespace df {
GLOBAL(gview,interface) \
GLOBAL(init,init) \
GLOBAL(d_init,d_init) \
SIMPLE_GLOBAL(job_next_id,int) \
SIMPLE_GLOBAL(ui_look_cursor,int) \
SIMPLE_GLOBAL(ui_workshop_job_cursor,int) \
SIMPLE_GLOBAL(ui_building_item_cursor,int) \
SIMPLE_GLOBAL(ui_workshop_in_add,bool) \
SIMPLE_GLOBAL(ui_selected_unit,int) \
SIMPLE_GLOBAL(cur_year,int) \
SIMPLE_GLOBAL(cur_year_tick,int) \
GLOBAL(ui_sidebar_menus,ui_sidebar_menus) \
GLOBAL(ui_build_selector,ui_build_selector) \
GLOBAL(ui_look_list,ui_look_list)
GLOBAL(ui_look_list,ui_look_list) \
GLOBAL(ui_unit_view_mode, ui_unit_view_mode) \
GLOBAL(gps, graphic) \
#define SIMPLE_GLOBAL(name,tname) \
namespace global { extern DFHACK_EXPORT tname *name; }
@ -190,3 +269,7 @@ DF_KNOWN_GLOBALS
#undef GLOBAL
#undef SIMPLE_GLOBAL
}
// A couple of headers that have to be included at once
#include "df/coord2d.h"
#include "df/coord.h"

@ -72,8 +72,8 @@ namespace DFHack
*/
struct DFHACK_EXPORT t_memrange
{
uint64_t start;
uint64_t end;
void * start;
void * end;
// memory range name (if any)
char name[1024];
// permission to read
@ -84,7 +84,7 @@ namespace DFHack
bool execute : 1;
// is a shared region
bool shared : 1;
inline bool isInRange( uint64_t address)
inline bool isInRange( void * address)
{
if (address >= start && address < end) return true;
return false;
@ -104,99 +104,110 @@ namespace DFHack
Process(VersionInfoFactory * known_versions);
~Process();
/// read a 8-byte integer
uint64_t readQuad(const uint32_t address)
uint64_t readQuad(const void * address)
{
return *(uint64_t *)address;
}
/// read a 8-byte integer
void readQuad(const uint32_t address, uint64_t & value)
void readQuad(const void * address, uint64_t & value)
{
value = *(uint64_t *)address;
};
/// write a 8-byte integer
void writeQuad(const uint32_t address, const uint64_t value)
void writeQuad(const void * address, const uint64_t value)
{
(*(uint64_t *)address) = value;
};
/// read a 4-byte integer
uint32_t readDWord(const uint32_t address)
uint32_t readDWord(const void * address)
{
return *(uint32_t *)address;
}
/// read a 4-byte integer
void readDWord(const uint32_t address, uint32_t & value)
void readDWord(const void * address, uint32_t & value)
{
value = *(uint32_t *)address;
};
/// write a 4-byte integer
void writeDWord(const uint32_t address, const uint32_t value)
void writeDWord(const void * address, const uint32_t value)
{
(*(uint32_t *)address) = value;
};
/// read a pointer
char * readPtr(const void * address)
{
return *(char **)address;
}
/// read a pointer
void readPtr(const void * address, char * & value)
{
value = *(char **)address;
};
/// read a float
float readFloat(const uint32_t address)
float readFloat(const void * address)
{
return *(float*)address;
}
/// write a float
void readFloat(const uint32_t address, float & value)
void readFloat(const void * address, float & value)
{
value = *(float*)address;
};
/// read a 2-byte integer
uint16_t readWord(const uint32_t address)
uint16_t readWord(const void * address)
{
return *(uint16_t *)address;
}
/// read a 2-byte integer
void readWord(const uint32_t address, uint16_t & value)
void readWord(const void * address, uint16_t & value)
{
value = *(uint16_t *)address;
};
/// write a 2-byte integer
void writeWord(const uint32_t address, const uint16_t value)
void writeWord(const void * address, const uint16_t value)
{
(*(uint16_t *)address) = value;
};
/// read a byte
uint8_t readByte(const uint32_t address)
uint8_t readByte(const void * address)
{
return *(uint8_t *)address;
}
/// read a byte
void readByte(const uint32_t address, uint8_t & value)
void readByte(const void * address, uint8_t & value)
{
value = *(uint8_t *)address;
};
/// write a byte
void writeByte(const uint32_t address, const uint8_t value)
void writeByte(const void * address, const uint8_t value)
{
(*(uint8_t *)address) = value;
};
/// read an arbitrary amount of bytes
void read( uint32_t address, uint32_t length, uint8_t* buffer)
void read(void * address, uint32_t length, uint8_t* buffer)
{
memcpy(buffer, (void *) address, length);
};
/// write an arbitrary amount of bytes
void write(uint32_t address, uint32_t length, uint8_t* buffer)
void write(void * address, uint32_t length, uint8_t* buffer)
{
memcpy((void *) address, buffer, length);
};
/// read an STL string
const std::string readSTLString (uint32_t offset)
const std::string readSTLString (void * offset)
{
std::string * str = (std::string *) offset;
return *str;
};
/// read an STL string
size_t readSTLString (uint32_t offset, char * buffer, size_t bufcapacity)
size_t readSTLString (void * offset, char * buffer, size_t bufcapacity)
{
if(!bufcapacity || bufcapacity == 1)
return 0;
@ -209,7 +220,7 @@ namespace DFHack
* write an STL string
* @return length written
*/
size_t writeSTLString(const uint32_t address, const std::string writeString)
size_t writeSTLString(const void * address, const std::string writeString)
{
std::string * str = (std::string *) address;
str->assign(writeString);
@ -219,7 +230,7 @@ namespace DFHack
* attempt to copy a string from source address to target address. may truncate or leak, depending on platform
* @return length copied
*/
size_t copySTLString(const uint32_t address, const uint32_t target)
size_t copySTLString(const void * address, const uint32_t target)
{
std::string * strsrc = (std::string *) address;
std::string * str = (std::string *) target;
@ -239,7 +250,7 @@ namespace DFHack
}
/// read a null-terminated C string
const std::string readCString (uint32_t offset)
const std::string readCString (void * offset)
{
return std::string((char *) offset);
};

@ -66,34 +66,200 @@ void print_bits ( T val, DFHack::Console& out )
out.print(strs.str().c_str());
}
//FIXME: Error 8 error C4519: default template arguments are only allowed on a class template
template <typename CT, typename FT, typename AT/* = FT*/>
CT *binsearch_in_vector(std::vector<CT*> &vec, FT CT::*field, AT value)
/*
* Binary search in vectors.
*/
template <typename FT>
int linear_index(const std::vector<FT> &vec, FT key)
{
for (unsigned i = 0; i < vec.size(); i++)
if (vec[i] == key)
return i;
return -1;
}
template <typename FT>
int linear_index(const std::vector<FT*> &vec, const FT &key)
{
for (unsigned i = 0; i < vec.size(); i++)
if (vec[i] && *vec[i] == key)
return i;
return -1;
}
template <typename FT>
int binsearch_index(const std::vector<FT> &vec, FT key, bool exact = true)
{
// Returns the index of the value >= the key
int min = -1, max = (int)vec.size();
CT **p = vec.data();
FT key = (FT)value;
const FT *p = vec.data();
for (;;)
{
int mid = (min + max)>>1;
if (mid == min)
return exact ? -1 : max;
FT midv = p[mid];
if (midv == key)
return mid;
else if (midv < key)
min = mid;
else
max = mid;
}
}
template <typename CT, typename FT>
int linear_index(const std::vector<CT*> &vec, FT CT::*field, FT key)
{
return NULL;
for (unsigned i = 0; i < vec.size(); i++)
if (vec[i]->*field == key)
return i;
return -1;
}
template <typename CT, typename FT>
int binsearch_index(const std::vector<CT*> &vec, FT CT::*field, FT key, bool exact = true)
{
// Returns the index of the value >= the key
int min = -1, max = (int)vec.size();
CT *const *p = vec.data();
for (;;)
{
int mid = (min + max)>>1;
if (mid == min)
return exact ? -1 : max;
FT midv = p[mid]->*field;
if (midv == key)
return mid;
else if (midv < key)
min = mid;
else
max = mid;
}
}
template <typename CT>
inline int binsearch_index(const std::vector<CT*> &vec, typename CT::key_field_type key, bool exact = true)
{
return p[mid];
return CT::binsearch_index(vec, key, exact);
}
else if (midv < key)
template <typename CT>
inline int binsearch_index(const std::vector<CT*> &vec, typename CT::key_pointer_type key, bool exact = true)
{
min = mid;
return CT::binsearch_index(vec, key, exact);
}
template<typename FT, typename KT>
inline bool vector_contains(const std::vector<FT> &vec, KT key)
{
return binsearch_index(vec, key) >= 0;
}
template<typename CT, typename FT>
inline bool vector_contains(const std::vector<CT*> &vec, FT CT::*field, FT key)
{
return binsearch_index(vec, field, key) >= 0;
}
template<typename T>
inline T vector_get(const std::vector<T> &vec, unsigned idx, const T &defval = T())
{
if (idx < vec.size())
return vec[idx];
else
return defval;
}
template<typename T>
inline void vector_insert_at(std::vector<T> &vec, unsigned idx, const T &val)
{
max = mid;
vec.insert(vec.begin()+idx, val);
}
template<typename T>
inline void vector_erase_at(std::vector<T> &vec, unsigned idx)
{
if (idx < vec.size())
vec.erase(vec.begin()+idx);
}
template<typename FT>
unsigned insert_into_vector(std::vector<FT> &vec, FT key, bool *inserted = NULL)
{
unsigned pos = (unsigned)binsearch_index(vec, key, false);
bool to_ins = (pos >= vec.size() || vec[pos] != key);
if (inserted) *inserted = to_ins;
if (to_ins)
vector_insert_at(vec, pos, key);
return pos;
}
template<typename CT, typename FT>
unsigned insert_into_vector(std::vector<CT*> &vec, FT CT::*field, CT *obj, bool *inserted = NULL)
{
unsigned pos = (unsigned)binsearch_index(vec, field, obj->*field, false);
bool to_ins = (pos >= vec.size() || vec[pos] != obj);
if (inserted) *inserted = to_ins;
if (to_ins)
vector_insert_at(vec, pos, obj);
return pos;
}
template <typename CT, typename KT>
CT *binsearch_in_vector(const std::vector<CT*> &vec, KT value)
{
int idx = binsearch_index(vec, value);
return idx < 0 ? NULL : vec[idx];
}
template <typename CT, typename FT>
CT *binsearch_in_vector(const std::vector<CT*> &vec, FT CT::*field, FT value)
{
int idx = binsearch_index(vec, field, value);
return idx < 0 ? NULL : vec[idx];
}
/*
* List
*/
template<typename Link>
Link *linked_list_append(Link *head, Link *tail)
{
while (head->next)
head = head->next;
head->next = tail;
tail->prev = head;
return tail;
}
template<typename Link>
Link *linked_list_insert_after(Link *pos, Link *link)
{
link->next = pos->next;
if (pos->next)
pos->next->prev = link;
link->prev = pos;
pos->next = link;
return link;
}
/*
* MISC
*/
DFHACK_EXPORT bool split_string(std::vector<std::string> *out,
const std::string &str, const std::string &separator,
bool squash_empty = false);
DFHACK_EXPORT std::string toUpper(const std::string &str);
DFHACK_EXPORT std::string toLower(const std::string &str);
inline bool bits_match(unsigned required, unsigned ok, unsigned mask)
{
return (required & mask) == (required & mask & ok);
}
/**
@ -102,3 +268,6 @@ CT *binsearch_in_vector(std::vector<CT*> &vec, FT CT::*field, AT value)
* source: http://stackoverflow.com/questions/1861294/how-to-calculate-execution-time-of-a-code-snippet-in-c
*/
DFHACK_EXPORT uint64_t GetTimeMs64();
DFHACK_EXPORT std::string stl_sprintf(const char *fmt, ...);
DFHACK_EXPORT std::string stl_vsprintf(const char *fmt, va_list args);

@ -35,13 +35,11 @@ namespace DFHack
Module* createGui();
Module* createWorld();
Module* createMaterials();
Module* createItems();
Module* createTranslation();
Module* createVegetation();
Module* createBuildings();
Module* createConstructions();
Module* createMaps();
Module* createVermin();
Module* createNotes();
Module* createGraphic();
}

@ -43,7 +43,7 @@ namespace DFHack
{
class Core;
class PluginManager;
struct virtual_identity;
class virtual_identity;
enum command_result
{

@ -1,96 +0,0 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#pragma once
#ifndef DFVECTOR_H_INCLUDED
#define DFVECTOR_H_INCLUDED
#include "Pragma.h"
#include "Export.h"
#include "VersionInfo.h"
#include "MemAccess.h"
#include <string.h>
#include <vector>
namespace DFHack
{
template <class T>
class DFHACK_EXPORT DfVector
{
private:
std::vector<T> * real_vec;
public:
DfVector(uint32_t address)
{
real_vec = (std::vector<T> *) address;
};
~DfVector()
{
};
// get offset of the specified index
inline const T& operator[] (uint32_t index)
{
// FIXME: vector out of bounds exception
//assert(index < size);
return real_vec->at(index);
};
// get offset of the specified index
inline const T& at (uint32_t index)
{
//assert(index < size);
return real_vec->at(index);
};
// update value at index
bool set(uint32_t index, T value)
{
if (index >= real_vec->size())
return false;
real_vec->at(index) = value;
return true;
}
// remove value
bool remove(uint32_t index)
{
if (index >= real_vec->size())
return false;
// Remove the item
real_vec->erase(real_vec->begin() + index);
return true;
}
// get vector size
inline uint32_t size ()
{
return real_vec->size();
};
// get vector start
inline const T * start ()
{
return real_vec->data();
};
};
}
#endif // DFVECTOR_H_INCLUDED

@ -88,13 +88,13 @@ namespace DFHack
OffsetGroup * createGroup ( const std::string & name );
int32_t getOffset (const std::string & key);
uint32_t getAddress (const std::string & key);
char * getAddress (const std::string & key);
uint32_t getHexValue (const std::string & key);
std::string getString (const std::string & key);
OffsetGroup * getGroup ( const std::string & name );
bool getSafeOffset (const std::string & key, int32_t & out);
bool getSafeAddress (const std::string & key, uint32_t & out);
bool getSafeAddress (const std::string & key, void * & out);
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);
@ -189,7 +189,7 @@ namespace DFHack
* uses memory reading directly, needs suspend. input = address of the object
* fails if it's unable to read from memory
*/
bool resolveObjectToClassID (const uint32_t address, int32_t & classID);
bool resolveObjectToClassID (const char * address, int32_t & classID);
/**
* Get a ClassID when you know the classname. can fail if the class is not in the cache

@ -1,3 +1,3 @@
*.h
*.inc
static*.inc
*.xml

@ -0,0 +1,45 @@
coord(const coord2d &c, uint16_t _z) : x(c.x), y(c.y), z(_z) {}
coord(uint16_t _x, uint16_t _y, uint16_t _z) : x(_x), y(_y), z(_z) {}
operator coord2d() const { return coord2d(x,y); }
bool isValid() const { return x != -30000; }
void clear() { x = y = z = -30000; }
bool operator==(const coord &other) const
{
return (x == other.x) && (y == other.y) && (z == other.z);
}
bool operator!=(const coord &other) const
{
return (x != other.x) || (y != other.y) || (z != other.z);
}
bool operator<(const coord &other) const
{
if (x != other.x) return (x < other.x);
if (y != other.y) return (y < other.y);
return z < other.z;
}
coord operator/(int number) const
{
return coord(x/number, y/number, z);
}
coord operator*(int number) const
{
return coord(x*number, y*number, z);
}
coord operator%(int number) const
{
return coord(x%number, y%number, z);
}
coord operator-(int number) const
{
return coord(x,y,z-number);
}
coord operator+(int number) const
{
return coord(x,y,z+number);
}

@ -0,0 +1,32 @@
coord2d(uint16_t _x, uint16_t _y) : x(_x), y(_y) {}
bool isValid() const { return x != -30000; }
void clear() { x = y = -30000; }
bool operator==(const coord2d &other) const
{
return (x == other.x) && (y == other.y);
}
bool operator!=(const coord2d &other) const
{
return (x != other.x) || (y != other.y);
}
bool operator<(const coord2d &other) const
{
if (x != other.x) return (x < other.x);
return y < other.y;
}
coord2d operator/(int number) const
{
return coord2d(x/number, y/number);
}
coord2d operator*(int number) const
{
return coord2d(x*number, y*number);
}
coord2d operator%(int number) const
{
return coord2d(x%number, y%number);
}

@ -0,0 +1,8 @@
unsigned size() const { return x.size(); }
coord operator[] (unsigned idx) const {
if (idx >= x.size() || idx >= y.size() || idx >= z.size())
return coord();
else
return coord(x[idx], y[idx], z[idx]);
}

@ -23,27 +23,20 @@ distribution.
*/
#pragma once
#ifndef CL_MOD_BUILDINGS
#define CL_MOD_BUILDINGS
/**
* \defgroup grp_buildings Building module parts - also includes zones and stockpiles
* @ingroup grp_modules
*/
#include "Export.h"
#include "Module.h"
#ifdef __cplusplus
namespace DFHack
{
#endif
namespace Simple
{
namespace Buildings
{
/**
* Structure for holding a read DF building object
* \ingroup grp_buildings
*/
struct t_building
{
uint32_t origin;
uint32_t vtable;
uint32_t x1;
uint32_t y1;
uint32_t x2;
@ -51,35 +44,28 @@ namespace DFHack
uint32_t z;
t_matglossPair material;
uint32_t type;
// FIXME: not complete, we need building presence bitmaps for stuff like farm plots and stockpiles, orientation (N,E,S,W) and state (open/closed)
int32_t custom_type;
void * origin;
};
#ifdef __cplusplus
/**
* The Buildings module - allows reading DF buildings
* \ingroup grp_modules
* \ingroup grp_buildings
*/
class DFHACK_EXPORT Buildings : public Module
{
public:
Buildings();
~Buildings();
bool Start(uint32_t & numBuildings);
// read one building at offset
bool Read (const uint32_t index, t_building & building);
bool Finish();
DFHACK_EXPORT uint32_t getNumBuildings ();
/**
* read building by index
*/
DFHACK_EXPORT bool Read (const uint32_t index, t_building & building);
// read a vector of names
bool ReadCustomWorkshopTypes(std::map <uint32_t, std::string> & btypes);
// returns -1 on error, >= 0 for real value
int32_t GetCustomWorkshopType(t_building & building);
/**
* read mapping from custom_type value to building RAW name
* custom_type of -1 implies ordinary building
*/
DFHACK_EXPORT bool ReadCustomWorkshopTypes(std::map <uint32_t, std::string> & btypes);
private:
struct Private;
Private *d;
};
}
#endif // __cplusplus
#endif
}
}

@ -74,7 +74,7 @@ namespace DFHack
uint32_t unk6;
/// Address of the read object in DF memory. Added by DFHack.
uint32_t origin;
t_construction * origin;
};
#pragma pack (pop)
class DFContextShared;

@ -97,7 +97,7 @@ namespace DFHack
struct dfh_engraving
{
t_engraving s;
uint32_t origin;
t_engraving * origin;
};
/**
* The Engravings module - allows reading engravings :D

@ -32,6 +32,13 @@ distribution.
#include "BitArray.h"
#include <string>
namespace df {
struct viewscreen;
struct job;
struct unit;
struct item;
};
/**
* \defgroup grp_gui query DF's GUI state
* @ingroup grp_modules
@ -39,6 +46,45 @@ distribution.
namespace DFHack
{
class Core;
// Full-screen item details view
DFHACK_EXPORT bool item_details_hotkey(Core *, df::viewscreen *top);
// 'u'nits or 'j'obs full-screen view
DFHACK_EXPORT bool unitjobs_hotkey(Core *, df::viewscreen *top);
// A job is selected in a workshop
DFHACK_EXPORT bool workshop_job_hotkey(Core *c, df::viewscreen *top);
// Building material selection mode
DFHACK_EXPORT bool build_selector_hotkey(Core *c, df::viewscreen *top);
// A unit is selected in the 'v' mode
DFHACK_EXPORT bool view_unit_hotkey(Core *c, df::viewscreen *top);
// Above + the inventory page is selected.
DFHACK_EXPORT bool unit_inventory_hotkey(Core *c, df::viewscreen *top);
// In workshop_job_hotkey, returns the job
DFHACK_EXPORT df::job *getSelectedWorkshopJob(Core *c, bool quiet = false);
// A job is selected in a workshop, or unitjobs
DFHACK_EXPORT bool any_job_hotkey(Core *c, df::viewscreen *top);
DFHACK_EXPORT df::job *getSelectedJob(Core *c, bool quiet = false);
// A unit is selected via 'v', 'k', unitjobs, or
// a full-screen item view of a cage or suchlike
DFHACK_EXPORT bool any_unit_hotkey(Core *c, df::viewscreen *top);
DFHACK_EXPORT df::unit *getSelectedUnit(Core *c, bool quiet = false);
// An item is selected via 'v'->inventory, 'k', 't', or
// a full-screen item view of a container. Note that in the
// last case, the highlighted contained item is returned, not
// the container itself.
DFHACK_EXPORT bool any_item_hotkey(Core *c, df::viewscreen *top);
DFHACK_EXPORT df::item *getSelectedItem(Core *c, bool quiet = false);
// Show a plain announcement, or a titan-style popup message
DFHACK_EXPORT void showAnnouncement(std::string message, int color = 7, bool bright = true);
DFHACK_EXPORT void showPopupAnnouncement(std::string message, int color = 7, bool bright = true);
class DFContextShared;
/**
* A GUI screen

@ -32,6 +32,17 @@ distribution.
#include "Virtual.h"
#include "modules/Materials.h"
#include "MemAccess.h"
#include "DataDefs.h"
#include "df/item.h"
#include "df/item_type.h"
#include "df/general_ref.h"
namespace df
{
struct itemdef;
}
/**
* \defgroup grp_items Items module and its types
* @ingroup grp_modules
@ -39,401 +50,47 @@ distribution.
namespace DFHack
{
struct DFHACK_EXPORT ItemTypeInfo {
df::item_type type;
int16_t subtype;
class Context;
class DFContextShared;
class Units;
/**
* Item flags. A bit fuzzy.
* Mostly from http://dwarffortresswiki.net/index.php/User:Rick/Memory_research
* \ingroup grp_items
*/
union t_itemflags
{
uint32_t whole; ///< the whole struct. all 32 bits of it, as an integer
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 hostile : 1; ///< 0000 0004 Item owned by hostile
unsigned int in_inventory : 1; ///< 0000 0008 Item in a creature or workshop inventory
unsigned int unk1 : 1; ///< 0000 0010 unknown, lost (artifact)?, unusable, unseen
unsigned int in_building : 1; ///< 0000 0020 Part of a building (including mechanisms, bodies in coffins)
unsigned int unk2 : 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 unk3 : 1; ///< 0000 0800 unknown, unseen, unusable
df::itemdef *custom;
unsigned int unk4 : 1; ///< 0000 1000 unknown, unseen
unsigned int murder : 1; ///< 0000 2000 Implies murder - used in fell moods
unsigned int foreign : 1; ///< 0000 4000 Item is imported
unsigned int trader : 1; ///< 0000 8000 Item ownwed by trader
public:
ItemTypeInfo(df::item_type type_ = df::enums::item_type::NONE, int16_t subtype_ = -1) {
decode(type_, subtype_);
}
template<class T> ItemTypeInfo(T *ptr) { decode(ptr); }
unsigned int owned : 1; ///< 0001 0000 Item is owned by a dwarf
unsigned int garbage_colect : 1; ///< 0002 0000 Marked for deallocation by DF it seems
unsigned int artifact1 : 1; ///< 0004 0000 Artifact ?
unsigned int forbid : 1; ///< 0008 0000 Forbidden item
bool isValid() const {
return (type != df::enums::item_type::NONE) && (subtype == -1 || custom);
}
unsigned int unk6 : 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
bool decode(df::item_type type_, int16_t subtype_ = -1);
bool decode(df::item *ptr);
unsigned int hidden : 1; ///< 0100 0000 Hidden item
unsigned int in_chest : 1; ///< 0200 0000 Stored in chest/part of well?
unsigned int unk7 : 1; ///< 0400 0000 unknown, unseen
unsigned int artifact2 : 1; ///< 0800 0000 Artifact ?
template<class T> bool decode(T *ptr) {
return ptr ? decode(ptr->item_type, ptr->item_subtype) : decode(df::enums::item_type::NONE);
}
unsigned int unk8 : 1; ///< 1000 0000 unknown, unseen, common
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
};
};
std::string getToken();
std::string toString();
/**
* Describes relationship of an item with other objects
* \ingroup grp_items
*/
struct t_itemref : public t_virtual
{
int32_t value;
};
bool find(const std::string &token);
struct df_contaminant
{
int16_t material;
int32_t mat_index;
int16_t mat_state; // FIXME: enum or document in text
int16_t temperature;
int16_t temperature_fraction; // maybe...
int32_t size; ///< 1-24=spatter, 25-49=smear, 50-* = coating
bool matches(const df::job_item &item, MaterialInfo *mat = NULL);
};
/**
* A partial mirror of a DF base type for items
* \ingroup grp_items
*/
class df_item
{
public:
// 4
int16_t x;
int16_t y;
// 8
int16_t z;
// C
t_itemflags flags;
// 10
uint32_t age;
// 14
uint32_t id;
// 18
std::vector<void *> unk1;
// 24 L, 28 W
std::vector<t_itemref *> itemrefs;
// 30 L, 38 W - these were mostly unset (0xCC with malloc patch)
int16_t mystery_meat[12];
// 48 L, 50 W
int32_t mystery1;
// 4C L, 54 W
int32_t mystery2;
// 50 L, 58 W
int32_t mystery3;
// 54 L, 5C W
int32_t mystery4;
// 58 L, 60 W
int32_t mystery5;
// 5C L, 64 W - pointer to vector of contaminants
std::vector <df_contaminant *> * contaminants;
// 60 L, 6C W - temperature in Urists
int16_t temperature;
// 62 L, 6E W - temperature fraction (maybe, just a guess)
int16_t temperature_fraction;
public:
// 0x0
virtual t_itemType getType();
virtual t_itemSubtype getSubtype();
virtual t_materialType getMaterial();
virtual t_materialIndex getMaterialIndex();
// 0x10
virtual void setSubType(t_itemSubtype);
virtual void setMaterial(t_materialType mat);
virtual void setMaterialIndex (t_materialIndex submat);
virtual t_materialType getMaterial2(); // weird
// 0x20
virtual t_materialIndex getMaterialIndex2(); // weird
virtual void fn9(void);
virtual void fn10(void);
virtual void fn11(void);
// 0x30
virtual void fn12(void);
virtual void fn13(void);
virtual void fn14(void);
virtual void fn15(void);
// 0x40
virtual void fn16(void);
virtual void fn17(void);
virtual void fn18(void);
virtual void fn19(void);
// 0x50
virtual void fn20(void);
virtual void fn21(void);
virtual void fn22(void);
virtual void fn23(void);
// 0x60
virtual void fn24(void);
virtual void fn25(void);
virtual void fn26(void);
virtual void fn27(void);
// 0x70
virtual void fn28(void);
virtual void fn29(void);
virtual void fn30(void);
virtual void fn31(void);
// 0x80
virtual void fn32(void);
virtual void fn33(void);
virtual void fn34(void);
virtual void fn35(void);
// 0x90
virtual void fn36(void);
virtual void fn37(void);
virtual void fn38(void);
virtual void fn39(void);
// 0xA0
virtual void fn40(void);
virtual void fn41(void);
virtual void fn42(void);
virtual void fn43(void);
// 0xB0
virtual void fn44(void);
virtual void fn45(void);
virtual void fn46(void);
virtual void fn47(void);
// 0xC0
virtual void fn48(void);
virtual void fn49(void);
virtual void fn50(void);
virtual int16_t getWear(void); // 0 = normal, 1 = x, 2 = X, 3 = XX
// 0xD0
virtual void setWear(int16_t wear); // also zeroes wear timer?
virtual void fn53(void);
virtual void fn54(void);
virtual void fn55(void);
// 0xE0
virtual void fn56(void);
virtual void fn57(void);
virtual void fn58(void);
virtual void fn59(void);
// 0xF0
virtual void fn60(void);
virtual void fn61(void);
virtual void fn62(void);
virtual void fn63(void);
// 0x100
virtual void fn64(void);
virtual void fn65(void);
virtual void fn66(void);
virtual void fn67(void);
// 0x110
virtual void fn68(void);
virtual void fn69(void);
virtual void fn70(void);
virtual void fn71(void);
// 0x120
virtual void fn72(void);
virtual void fn73(void);
virtual void fn74(void);
virtual void fn75(void);
// 0x130
virtual void fn76(void);
virtual void fn77(void);
virtual void fn78(void);
virtual void fn79(void);
// 0x140
virtual void fn80(void);
virtual void fn81(void);
virtual void fn82(void);
virtual void fn83(void);
// 0x150
virtual void fn84(void);
virtual void fn85(void);
virtual void fn86(void);
virtual void fn87(void);
// 0x160
virtual void fn88(void);
virtual void fn89(void);
virtual void fn90(void);
virtual void fn91(void);
// 0x170
virtual void fn92(void);
virtual void fn93(void);
virtual void fn94(void);
virtual void fn95(void);
// 0x180
virtual void fn96(void);
virtual void fn97(void);
virtual void fn98(void);
virtual void fn99(void);
// 0x190
virtual void fn100(void);
virtual void fn101(void);
virtual void fn102(void);
virtual void fn103(void);
// 0x1A0
virtual void fn104(void);
virtual void fn105(void);
virtual void fn106(void);
virtual void fn107(void);
// 0x1B0
virtual void fn108(void);
virtual void fn109(void);
virtual void fn110(void);
virtual void fn111(void);
// 0x1C0
virtual void fn112(void);
virtual void fn113(void);
virtual void fn114(void);
virtual void fn115(void);
// 0x1D0
virtual void fn116(void);
virtual void fn117(void);
virtual void fn118(void);
virtual void fn119(void);
// 0x1E0
virtual void fn120(void);
virtual void fn121(void);
virtual void fn122(void);
virtual void fn123(void);
// 0x1F0
virtual void fn124(void);
virtual void fn125(void);
virtual void fn126(void);
virtual void fn127(void);
// 0x200
virtual void fn128(void);
virtual void fn129(void);
virtual void fn130(void);
virtual void fn131(void);
// 0x210
virtual void fn132(void);
virtual int32_t getStackSize( void );
virtual void fn134(void);
virtual void fn135(void);
// 0x220
virtual void fn136(void);
virtual void fn137(void);
virtual void fn138(void);
virtual void fn139(void);
// 0x230
virtual void fn140(void);
virtual void fn141(void);
virtual void fn142(void);
virtual void fn143(void);
// 0x240
virtual void fn144(void);
virtual void fn145(void);
virtual void fn146(void);
virtual void fn147(void);
// 0x250
virtual void fn148(void);
virtual void fn149(void);
virtual void fn150(void);
virtual int16_t getQuality( void );
// 0x260
virtual void fn152(void);
virtual void fn153(void);
virtual void fn154(void);
virtual void fn155(void);
// 0x270
virtual void fn156(void);
virtual void fn157(void);
virtual void fn158(void);
virtual void fn159(void);
// 0x280
virtual void fn160(void);
virtual void fn161(void);
virtual void fn162(void);
virtual void fn163(void);
// 0x290
virtual void fn164(void);
virtual void fn165(void);
virtual void fn166(void);
virtual void fn167(void);
// 0x2A0
virtual void fn168(void); // value returned (int) = first param to descriprion construction function
virtual void fn169(void);
virtual void fn170(void);
virtual void fn171(void);
// 0x2B0
virtual void fn172(void);
virtual void fn173(void);
virtual void fn174(void);
virtual void fn175(void);
// 0x2C0
virtual void fn176(void);
virtual void fn177(void);
//virtual std::string *getItemDescription ( std::string * str, int sizes = 0); // 0 = stacked, 1 = singular, 2 = plural
virtual std::string *getItemDescription ( std::string * str, int sizes = 0); // 0 = stacked, 1 = singular, 2 = plural
virtual void fn179(void);
// 0x2D0
virtual void fn180(void);
virtual void fn181(void);
virtual void fn182(void);
virtual void fn183(void);
// 0x2E0
virtual void fn184(void);
virtual void fn185(void);
virtual void fn186(void);
virtual void fn187(void);
// 0x2F0
virtual void fn188(void);
virtual void fn189(void);
virtual void fn190(void);
virtual void fn191(void);
// 0x300
virtual void fn192(void);
virtual void fn193(void);
virtual void fn194(void);
virtual void fn195(void);
// 0x310
virtual void fn196(void);
virtual void fn197(void);
virtual void fn198(void);
virtual void fn199(void);
// 0x320
virtual void fn200(void);
virtual void fn201(void);
virtual void fn202(void);
virtual void fn203(void);
// 0x330
virtual void fn204(void);
virtual void fn205(void);
virtual void fn206(void);
virtual void fn207(void);
// 0x340
virtual void fn208(void);
virtual void fn209(void);
virtual void fn210(void);
virtual void fn211(void);
// 0x350
virtual void fn212(void);
virtual void fn213(void);
virtual void fn214(void);
virtual void fn215(void);
// 0x360
virtual void fn216(void);
virtual void fn217(void);
inline bool operator== (const ItemTypeInfo &a, const ItemTypeInfo &b) {
return a.type == b.type && a.subtype == b.subtype;
}
inline bool operator!= (const ItemTypeInfo &a, const ItemTypeInfo &b) {
return a.type != b.type || a.subtype != b.subtype;
}
// and this should be all 218 of them
// fn numbers start with 0
};
class Context;
class DFContextShared;
class Units;
/**
* Type for holding an item read from DF
@ -441,11 +98,11 @@ public:
*/
struct dfh_item
{
df_item *origin; // where this was read from
df::item *origin; // where this was read from
int16_t x;
int16_t y;
int16_t z;
t_itemflags flags;
df::item_flags flags;
uint32_t age;
uint32_t id;
t_material matdesc;
@ -454,154 +111,37 @@ struct dfh_item
int16_t wear_level;
};
/**
* Type for holding item improvements. broken/unused.
* \ingroup grp_items
*/
struct t_improvement
{
t_material matdesc;
int32_t quality;
};
/**
* The Items module
* \ingroup grp_modules
* \ingroup grp_items
*/
class DFHACK_EXPORT Items : public Module
namespace Simple
{
public:
/**
* All the known item types as an enum
* From http://df.magmawiki.com/index.php/DF2010:Item_token
*/
enum item_types
namespace Items
{
BAR, ///< Bars, such as metal, fuel, or soap.
SMALLGEM, ///< Cut gemstones usable in jeweler's workshop
BLOCKS, ///< Blocks of any kind.
ROUGH, ///< Rough gemstones.
BOULDER, ///< or IT_STONE - raw mined stone.
STONE = BOULDER,
WOOD, ///< Wooden logs.
DOOR, ///< Doors.
FLOODGATE, ///< Floodgates.
BED, ///< Beds.
CHAIR, ///< Chairs and thrones.
CHAIN, ///< Restraints.
FLASK, ///< Flasks.
GOBLET, ///< Goblets.
INSTRUMENT, ///< Musical instruments. Subtypes come from item_instrument.txt
TOY, ///< Toys. Subtypes come from item_toy.txt
WINDOW, ///< Glass windows.
CAGE, ///< Cages.
BARREL, ///< Barrels.
BUCKET, ///< Buckets.
ANIMALTRAP, ///< Animal traps.
TABLE, ///< Tables.
COFFIN, ///< Coffins.
STATUE, ///< Statues.
CORPSE, ///< Corpses.
WEAPON, ///< Weapons. Subtypes come from item_weapon.txt
ARMOR, ///< Armor and clothing worn on the upper body. Subtypes come from item_armor.txt
SHOES, ///< Armor and clothing worn on the feet. Subtypes come from item_shoes.txt
SHIELD, ///< Shields and bucklers. Subtypes come from item_shield.txt
HELM, ///< Armor and clothing worn on the head. Subtypes come from item_helm.txt
GLOVES, ///< Armor and clothing worn on the hands. Subtypes come from item_gloves.txt
BOX, ///< Chests (wood), coffers (stone), boxes (glass), and bags (cloth or leather).
BIN, ///< Bins.
ARMORSTAND, ///< Armor stands.
WEAPONRACK, ///< Weapon racks.
CABINET, ///< Cabinets.
FIGURINE, ///< Figurines.
AMULET, ///< Amulets.
SCEPTER, ///< Scepters.
AMMO, ///< Ammunition for hand-held weapons. Subtypes come from item_ammo.txt
CROWN, ///< Crowns.
RING, ///< Rings.
EARRING, ///< Earrings.
BRACELET, ///< Bracelets.
GEM, ///< Large gems.
ANVIL, ///< Anvils.
CORPSEPIECE,///< Body parts.
REMAINS, ///< Dead vermin bodies.
MEAT, ///< Butchered meat.
FISH, ///< Prepared fish.
FISH_RAW, ///< Unprepared fish.
VERMIN, ///< Live vermin.
PET, ///< Tame vermin.
SEEDS, ///< Seeds from plants.
PLANT, ///< Plants.
SKIN_TANNED,///< Tanned skins.
LEAVES, ///< Leaves, usually from quarry bushes.
THREAD, ///< Thread gathered from webs or made at the farmer's workshop.
CLOTH, ///< Cloth made at the loom.
TOTEM, ///< Skull totems.
PANTS, ///< Armor and clothing worn on the legs. Subtypes come from item_pants.txt
BACKPACK, ///< Backpacks.
QUIVER, ///< Quivers.
CATAPULTPARTS, ///< Catapult parts.
BALLISTAPARTS, ///< Ballista parts.
SIEGEAMMO, ///< Siege engine ammunition. Subtypes come from item_siegeammo.txt
BALLISTAARROWHEAD, ///< Ballista arrow heads.
TRAPPARTS, ///< Mechanisms.
TRAPCOMP, ///< Trap components. Subtypes come from item_trapcomp.txt
DRINK, ///< Alcoholic drinks.
POWDER_MISC,///< Powders such as flour, gypsum plaster, dye, or sand.
CHEESE, ///< Pieces of cheese.
FOOD, ///< Prepared meals. Subtypes come from item_food.txt
LIQUID_MISC,///< Liquids such as water, lye, and extracts.
COIN, ///< Coins.
GLOB, ///< Fat, tallow, pastes/pressed objects, and small bits of molten rock/metal.
ROCK, ///< Small rocks (usually sharpened and/or thrown in adventurer mode)
PIPE_SECTION, ///< Pipe sections.
HATCH_COVER, ///< Hatch covers.
GRATE, ///< Grates.
QUERN, ///< Querns.
MILLSTONE, ///< Millstones.
SPLINT, ///< Splints.
CRUTCH, ///< Crutches.
TRACTION_BENCH, ///< Traction benches.
ORTHOPEDIC_CAST, ///< Casts.
TOOL, ///< Tools. Subtypes come from item_tool.txt
SLAB, ///< Slabs.
EGG, ///< Eggs.
};
public:
Items();
~Items();
bool Start();
bool Finish();
/// Read the item vector from DF into a supplied vector
bool readItemVector(std::vector<df_item *> &items);
/// Look for a particular item by ID
df_item * findItemByID(int32_t id);
DFHACK_EXPORT df::item * findItemByID(int32_t id);
/// Make a partial copy of a DF item
bool copyItem(df_item * source, dfh_item & target);
DFHACK_EXPORT bool copyItem(df::item * source, dfh_item & target);
/// write copied item back to its origin
bool writeItem(const dfh_item & item);
DFHACK_EXPORT bool writeItem(const dfh_item & item);
/// get the class name of an item
std::string getItemClass(const df_item * item);
DFHACK_EXPORT std::string getItemClass(const df::item * item);
/// who owns this item we already read?
int32_t getItemOwnerID(const df_item * item);
DFHACK_EXPORT int32_t getItemOwnerID(const df::item * item);
/// which item is it contained in?
int32_t getItemContainerID(const df_item * item);
DFHACK_EXPORT int32_t getItemContainerID(const df::item * item);
/// which items does it contain?
bool getContainedItems(const df_item * item, /*output*/ std::vector<int32_t> &items);
DFHACK_EXPORT bool getContainedItems(const df::item * item, /*output*/ std::vector<int32_t> &items);
/// wipe out the owner records
bool removeItemOwner(df_item * item, Units *creatures);
DFHACK_EXPORT bool removeItemOwner(df::item * item, Units *creatures);
/// read item references, filtered by class
bool readItemRefs(const df_item * item, const ClassNameCheck &classname,
DFHACK_EXPORT bool readItemRefs(const df::item * item, const df::general_ref_type type,
/*output*/ std::vector<int32_t> &values);
/// get list of item references that are unknown along with their values
bool unknownRefs(const df_item * item, /*output*/ std::vector<std::pair<std::string, int32_t> >& refs);
private:
class Private;
Private* d;
};
}
}
}

@ -0,0 +1,59 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#pragma once
#ifndef CL_MOD_JOB
#define CL_MOD_JOB
#include "Export.h"
#include "Module.h"
#include <ostream>
namespace df
{
struct job;
struct job_item;
struct job_item_filter;
struct building;
}
namespace DFHack
{
// Duplicate the job structure. It is not linked into any DF lists.
DFHACK_EXPORT df::job *cloneJobStruct(df::job *job);
// Delete a cloned structure.
DFHACK_EXPORT void deleteJobStruct(df::job *job);
DFHACK_EXPORT bool operator== (const df::job_item &a, const df::job_item &b);
DFHACK_EXPORT bool operator== (const df::job &a, const df::job &b);
DFHACK_EXPORT void printJobDetails(Core *c, df::job *job);
DFHACK_EXPORT df::building *getJobHolder(df::job *job);
DFHACK_EXPORT bool linkJobIntoWorld(df::job *job, bool new_id = true);
}
#endif

@ -149,7 +149,7 @@ namespace DFHack
/// placeholder
bool discovered;
/// this is NOT part of the DF feature, but an address of the feature as seen by DFhack.
uint32_t origin;
void * origin;
};

@ -34,11 +34,113 @@ distribution.
#include "Types.h"
#include "BitArray.h"
#include "DataDefs.h"
#include "df/material.h"
#include <vector>
#include <string>
namespace df
{
struct item;
struct inorganic_raw;
struct plant_raw;
struct creature_raw;
struct historical_figure;
struct material_vec_ref;
struct job_item;
union job_material_category;
union dfhack_material_category;
union job_item_flags1;
union job_item_flags2;
union job_item_flags3;
}
namespace DFHack
{
struct DFHACK_EXPORT MaterialInfo {
static const int NUM_BUILTIN = 19;
static const int GROUP_SIZE = 200;
static const int CREATURE_BASE = NUM_BUILTIN;
static const int FIGURE_BASE = NUM_BUILTIN + GROUP_SIZE;
static const int PLANT_BASE = NUM_BUILTIN + GROUP_SIZE*2;
static const int END_BASE = NUM_BUILTIN + GROUP_SIZE*3;
int16_t type;
int32_t index;
df::material *material;
enum Mode {
Builtin,
Inorganic,
Creature,
Plant
};
Mode mode;
int16_t subtype;
df::inorganic_raw *inorganic;
df::creature_raw *creature;
df::plant_raw *plant;
df::historical_figure *figure;
public:
MaterialInfo(int16_t type = -1, int32_t index = -1) { decode(type, index); }
template<class T> MaterialInfo(T *ptr) { decode(ptr); }
bool isValid() const { return material != NULL; }
bool decode(int16_t type, int32_t index = -1);
bool decode(df::item *item);
bool decode(const df::material_vec_ref &vr, int idx);
template<class T> bool decode(T *ptr) {
// Assume and exploit a certain naming convention
return ptr ? decode(ptr->mat_type, ptr->mat_index) : decode(-1);
}
bool find(const std::string &token);
bool findBuiltin(const std::string &token);
bool findInorganic(const std::string &token);
bool findPlant(const std::string &token, const std::string &subtoken);
bool findCreature(const std::string &token, const std::string &subtoken);
std::string toString(uint16_t temp = 10015, bool named = true);
bool isAnyCloth();
void getMatchBits(df::job_item_flags1 &ok, df::job_item_flags1 &mask);
void getMatchBits(df::job_item_flags2 &ok, df::job_item_flags2 &mask);
void getMatchBits(df::job_item_flags3 &ok, df::job_item_flags3 &mask);
df::craft_material_class getCraftClass();
bool matches(const MaterialInfo &mat)
{
if (!mat.isValid()) return true;
return (type == mat.type) &&
(mat.index == -1 || index == mat.index);
}
bool matches(const df::job_material_category &cat);
bool matches(const df::dfhack_material_category &cat);
bool matches(const df::job_item &item);
};
DFHACK_EXPORT bool parseJobMaterialCategory(df::job_material_category *cat, const std::string &token);
DFHACK_EXPORT bool parseJobMaterialCategory(df::dfhack_material_category *cat, const std::string &token);
inline bool operator== (const MaterialInfo &a, const MaterialInfo &b) {
return a.type == b.type && a.index == b.index;
}
inline bool operator!= (const MaterialInfo &a, const MaterialInfo &b) {
return a.type != b.type || a.index != b.index;
}
typedef int32_t t_materialIndex;
typedef int16_t t_materialType, t_itemType, t_itemSubtype;

@ -557,7 +557,7 @@ namespace DFHack
int16_t unk_280;
int32_t unk_284;
std::vector<df_item *> inventory; // 288 - vector of item pointers
std::vector<df::item *> inventory; // 288 - vector of item pointers
std::vector<int32_t> owned_items; // 298 - vector of item IDs
std::vector<uint32_t> unk_2a8;
std::vector<uint32_t> unk_2b8;
@ -777,8 +777,8 @@ namespace DFHack
bool ReadJob(const df_unit * unit, std::vector<t_material> & mat);
bool ReadInventoryByIdx(const uint32_t index, std::vector<df_item *> & item);
bool ReadInventoryByPtr(const df_unit * unit, std::vector<df_item *> & item);
bool ReadInventoryByIdx(const uint32_t index, std::vector<df::item *> & item);
bool ReadInventoryByPtr(const df_unit * unit, std::vector<df::item *> & item);
bool ReadOwnedItemsByIdx(const uint32_t index, std::vector<int32_t> & item);
bool ReadOwnedItemsByPtr(const df_unit * unit, std::vector<int32_t> & item);
@ -807,8 +807,6 @@ namespace DFHack
void CopyNameTo(df_unit *creature, df_name * target);
protected:
friend class Items;
bool RemoveOwnedItemByIdx(const uint32_t index, int32_t id);
bool RemoveOwnedItemByPtr(df_unit * unit, int32_t id);

@ -1,86 +1,38 @@
#pragma once
#ifndef CL_MOD_VERMIN
#define CL_MOD_VERMIN
/**
* \defgroup grp_vermin Wild vermin (ants, bees, etc)
* @ingroup grp_vermin
*/
#include "Export.h"
#include "Module.h"
#ifdef __cplusplus
namespace DFHack
namespace DFHack { namespace Simple { namespace Vermin
{
#endif
/**
* Structure for holding a read DF vermin spawn point object
* \ingroup grp_vermin
*/
struct t_spawnPoint
struct t_vermin
{
uint32_t origin;
void * origin;
int16_t race;
uint16_t type;
int16_t caste;
uint16_t x;
uint16_t y;
uint16_t z;
bool in_use;
uint8_t unknown;
uint32_t countdown;
bool visible:1;
bool is_colony:1; /// Is vermin object a colony?
};
#ifdef __cplusplus
class DFContextShared;
class SpawnPoints;
static const uint16_t TYPE_WILD_COLONY = 0xFFFF;
/**
* The Vermin module - allows reading DF vermin
* \ingroup grp_modules
* \ingroup grp_vermin
* Get number of vermin objects
*/
class DFHACK_EXPORT Vermin : public Module
{
public:
Vermin();
~Vermin();
bool Finish();
// NOTE: caller must call delete on result when done.
SpawnPoints* getSpawnPoints();
private:
struct Private;
Private *d;
friend class SpawnPoints;
};
class DFHACK_EXPORT SpawnPoints
{
public:
static const uint16_t TYPE_WILD_COLONY = 0xFFFF;
protected:
SpawnPoints(Vermin * v);
public:
~SpawnPoints();
size_t size();
bool Read (const uint32_t index, t_spawnPoint & point);
bool Write (const uint32_t index, t_spawnPoint & point);
bool isValid();
static bool isWildColony(t_spawnPoint & point);
private:
Vermin* v;
std::vector <void*> * p_sp;
friend class Vermin;
};
}
#endif // __cplusplus
#endif
DFHACK_EXPORT uint32_t getNumVermin();
/**
* Read from vermin object
*/
DFHACK_EXPORT bool Read (const uint32_t index, t_vermin & point);
/**
* Write into vermin object
*/
DFHACK_EXPORT bool Write (const uint32_t index, t_vermin & point);
} } } // end DFHack::Simple::Vermin

@ -80,6 +80,30 @@ namespace DFHack
GameType g_type;
};
class DFContextShared;
class DFHACK_EXPORT PersistentDataItem {
friend class World;
int id;
std::string key_value;
std::string *str_value;
int *int_values;
public:
static const int NumInts = 7;
bool isValid() { return id != 0; }
const std::string &key() { return key_value; }
std::string &val() { return *str_value; }
int &ival(int i) { return int_values[i]; }
PersistentDataItem() : id(0), str_value(0), int_values(0) {}
PersistentDataItem(int id, const std::string &key, std::string *sv, int *iv)
: id(id), key_value(key), str_value(sv), int_values(iv) {}
};
/**
* The World module
* \ingroup grp_modules
@ -108,6 +132,14 @@ namespace DFHack
bool ReadGameMode(t_gamemodes& rd);
bool WriteGameMode(const t_gamemodes & wr); // this is very dangerous
std::string ReadWorldFolder();
// Store data in fake historical figure names.
// This ensures that the values are stored in save games.
PersistentDataItem AddPersistentData(const std::string &key);
PersistentDataItem GetPersistentData(const std::string &key);
void GetPersistentData(std::vector<PersistentDataItem> *vec, const std::string &key);
void DeletePersistentData(const PersistentDataItem &item);
private:
struct Private;
Private *d;

@ -30,9 +30,9 @@ distribution.
#include "Module.h"
#include "Types.h"
#include "VersionInfo.h"
#include "modules/Materials.h"
#include "modules/Items.h"
#include "Core.h"
#include "modules/Items.h"
/**
* \defgroup grp_kitchen Kitchen settings
* @ingroup grp_modules
@ -40,6 +40,8 @@ distribution.
namespace DFHack
{
namespace Simple
{
namespace Kitchen
{
typedef uint8_t t_exclusionType;
@ -52,45 +54,33 @@ const t_itemSubtype limitSubtype = 0; // used to store limit as an entry in the
const t_exclusionType limitExclusion = 4; // used to store limit as an entry in the exclusion list
/**
* Kitchen exclusions manipulator class. Currently geared towards plants and seeds.
* @ingroup grp_kitchen
* Kitchen exclusions manipulator. Currently geared towards plants and seeds.
* \ingroup grp_modules
* \ingroup grp_kitchen
*/
class DFHACK_EXPORT Exclusions
{
public:
/// ctor
Exclusions(DFHack::Core& core_);
/// dtor
~Exclusions();
/// print the exclusion list, with the material index also translated into its token (for organics) - for debug really
void debug_print() const;
/// remove this material from the exclusion list if it is in it
void allowPlantSeedCookery(t_materialIndex materialIndex);
// print the exclusion list, with the material index also translated into its token (for organics) - for debug really
DFHACK_EXPORT void debug_print(Core &);
/// add this material to the exclusion list, if it is not already in it
void denyPlantSeedCookery(t_materialIndex materialIndex);
// remove this material from the exclusion list if it is in it
DFHACK_EXPORT void allowPlantSeedCookery(t_materialIndex materialIndex);
/// fills a map with info from the limit info storage entries in the exclusion list
void fillWatchMap(std::map<t_materialIndex, unsigned int>& watchMap) const;
// add this material to the exclusion list, if it is not already in it
DFHACK_EXPORT void denyPlantSeedCookery(t_materialIndex materialIndex);
/// removes a limit info storage entry from the exclusion list if it's present
void removeLimit(t_materialIndex materialIndex);
// fills a map with info from the limit info storage entries in the exclusion list
DFHACK_EXPORT void fillWatchMap(std::map<t_materialIndex, unsigned int>& watchMap);
/// add a limit info storage item to the exclusion list, or alters an existing one
void setLimit(t_materialIndex materialIndex, unsigned int limit);
// removes a limit info storage entry from the exclusion list if it's present
DFHACK_EXPORT void removeLimit(t_materialIndex materialIndex);
/// clears all limit info storage items from the exclusion list
void clearLimits();
// add a limit info storage item to the exclusion list, or alters an existing one
DFHACK_EXPORT void setLimit(t_materialIndex materialIndex, unsigned int limit);
/// the size of the exclusions vectors (they are all the same size - if not, there is a problem!)
std::size_t size() const;
private:
class Private;
Private* d;
};
// clears all limit info storage items from the exclusion list
DFHACK_EXPORT void clearLimits();
DFHACK_EXPORT std::size_t size();
}
}
}

@ -32,180 +32,65 @@ using namespace std;
#include "VersionInfo.h"
#include "MemAccess.h"
#include "Vector.h"
#include "Types.h"
#include "Error.h"
#include "modules/Buildings.h"
#include "ModuleFactory.h"
#include "Core.h"
using namespace DFHack;
using namespace DFHack::Simple;
//raw
struct t_building_df40d
{
uint32_t vtable;
uint32_t x1;
uint32_t y1;
uint32_t centerx;
uint32_t x2;
uint32_t y2;
uint32_t centery;
uint32_t z;
uint32_t height;
t_matglossPair material;
// not complete
};
struct Buildings::Private
{
uint32_t buildings_vector;
uint32_t custom_workshop_vector;
uint32_t building_custom_workshop_type;
uint32_t custom_workshop_type;
uint32_t custom_workshop_name;
int32_t custom_workshop_id;
DfVector <uint32_t> * p_bld;
Process * owner;
bool Inited;
bool hasCustomWorkshops;
bool Started;
};
Module* DFHack::createBuildings()
{
return new Buildings();
}
#include "DataDefs.h"
#include "df/world.h"
#include "df/building_def.h"
#include "df/building.h"
#include "df/building_workshopst.h"
Buildings::Buildings()
{
Core & c = Core::getInstance();
d = new Private;
d->p_bld = NULL;
d->Inited = d->Started = d->hasCustomWorkshops = false;
VersionInfo * mem = c.vinfo;
d->owner = c.p;
OffsetGroup * OG_build = mem->getGroup("Buildings");
d->Inited = true;
try
{
d->buildings_vector = OG_build->getAddress ("buildings_vector");
}
catch(DFHack::Error::AllMemdef &e)
{
cerr << "Buildings not available... " << e.what() << endl;
d->Inited = false;
}
if(d->Inited)
{
try
{
d->custom_workshop_vector = OG_build->getAddress("custom_workshop_vector");
d->building_custom_workshop_type = OG_build->getOffset("building_custom_workshop_type");
d->custom_workshop_type = OG_build->getOffset("custom_workshop_type");
d->custom_workshop_name = OG_build->getOffset("custom_workshop_name");
mem->resolveClassnameToClassID("building_custom_workshop", d->custom_workshop_id);
d->hasCustomWorkshops = true;
}
catch(DFHack::Error::AllMemdef &e)
{
cerr << "Custom workshops not available. Memory Definition: " << e.what() << endl;
}
}
}
using namespace df::enums;
using df::global::world;
using df::building_def;
Buildings::~Buildings()
uint32_t Buildings::getNumBuildings()
{
if(d->Started)
Finish();
delete d;
}
bool Buildings::Start(uint32_t & numbuildings)
{
if(!d->Inited)
return false;
d->p_bld = new DfVector <uint32_t> (d->buildings_vector);
numbuildings = d->p_bld->size();
d->Started = true;
return true;
return world->buildings.all.size();
}
bool Buildings::Read (const uint32_t index, t_building & building)
{
if(!d->Started)
return false;
t_building_df40d bld_40d;
// read pointer from vector at position
uint32_t temp = d->p_bld->at (index);
//d->p_bld->read(index,(uint8_t *)&temp);
//read building from memory
d->owner->read (temp, sizeof (t_building_df40d), (uint8_t *) &bld_40d);
Core & c = Core::getInstance();
df::building *bld_40d = world->buildings.all[index];
// transform
int32_t type = -1;
d->owner->getDescriptor()->resolveObjectToClassID (temp, type);
building.origin = temp;
building.vtable = bld_40d.vtable;
building.x1 = bld_40d.x1;
building.x2 = bld_40d.x2;
building.y1 = bld_40d.y1;
building.y2 = bld_40d.y2;
building.z = bld_40d.z;
building.material = bld_40d.material;
c.vinfo->resolveObjectToClassID ( (char *)bld_40d, type);
building.x1 = bld_40d->x1;
building.x2 = bld_40d->x2;
building.y1 = bld_40d->y1;
building.y2 = bld_40d->y2;
building.z = bld_40d->z;
building.material.index = bld_40d->mat_index;
building.material.type = bld_40d->mat_type;
building.type = type;
return true;
}
bool Buildings::Finish()
{
if(d->p_bld)
{
delete d->p_bld;
d->p_bld = NULL;
}
d->Started = false;
building.custom_type = bld_40d->getCustomType();
building.origin = (void *) &bld_40d;
return true;
}
bool Buildings::ReadCustomWorkshopTypes(map <uint32_t, string> & btypes)
{
if(!d->Inited)
return false;
if(!d->hasCustomWorkshops)
return false;
Process * p = d->owner;
DfVector <uint32_t> p_matgloss (d->custom_workshop_vector);
uint32_t size = p_matgloss.size();
Core & c = Core::getInstance();
vector <building_def *> & bld_def = world->raws.buildings.all;
uint32_t size = bld_def.size();
btypes.clear();
for (uint32_t i = 0; i < size;i++)
c.con.print("Probing vector at 0x%x for custom workshops.\n", &bld_def);
for (auto iter = bld_def.begin(); iter != bld_def.end();iter++)
{
string out = p->readSTLString (p_matgloss[i] + d->custom_workshop_name);
uint32_t type = p->readDWord (p_matgloss[i] + d->custom_workshop_type);
#ifdef DEBUG
cout << out << ": " << type << endl;
#endif
btypes[type] = out;
building_def * temp = *iter;
btypes[temp->id] = temp->code;
c.con.print("%d : %s\n",temp->id, temp->code.c_str());
}
return true;
}
int32_t Buildings::GetCustomWorkshopType(t_building & building)
{
if(!d->Inited)
return false;
if(!d->hasCustomWorkshops)
return false;
int32_t type = (int32_t)building.type;
int32_t ret = -1;
if(type != -1 && type == d->custom_workshop_id)
{
// read the custom workshop subtype
ret = (int32_t) d->owner->readDWord(building.origin + d->building_custom_workshop_type);
}
return ret;
}

@ -33,7 +33,6 @@ using namespace std;
#include "VersionInfo.h"
#include "MemAccess.h"
#include "Vector.h"
#include "Types.h"
#include "modules/Constructions.h"
#include "ModuleFactory.h"
@ -43,10 +42,7 @@ using namespace DFHack;
struct Constructions::Private
{
uint32_t construction_vector;
// translation
DfVector <uint32_t> * p_cons;
vector <t_construction *> * p_cons;
Process * owner;
bool Inited;
bool Started;
@ -62,10 +58,9 @@ Constructions::Constructions()
Core & c = Core::getInstance();
d = new Private;
d->owner = c.p;
d->p_cons = 0;
d->Inited = d->Started = false;
VersionInfo * mem = c.vinfo;
d->construction_vector = mem->getGroup("Constructions")->getAddress ("vector");
d->p_cons = (decltype(d->p_cons)) mem->getGroup("Constructions")->getAddress ("vector");
d->Inited = true;
}
@ -78,7 +73,6 @@ Constructions::~Constructions()
bool Constructions::Start(uint32_t & numconstructions)
{
d->p_cons = new DfVector <uint32_t> (d->construction_vector);
numconstructions = d->p_cons->size();
d->Started = true;
return true;
@ -89,24 +83,14 @@ bool Constructions::Read (const uint32_t index, t_construction & construction)
{
if(!d->Started) return false;
// read pointer from vector at position
uint32_t temp = d->p_cons->at (index);
//read construction from memory
d->owner->read (temp, sizeof (t_construction), (uint8_t *) &construction);
// transform
construction.origin = temp;
t_construction * orig = d->p_cons->at(index);
construction = *orig;
construction.origin = orig;
return true;
}
bool Constructions::Finish()
{
if(d->p_cons)
{
delete d->p_cons;
d->p_cons = NULL;
}
d->Started = false;
return true;
}

@ -31,8 +31,7 @@ distribution.
using namespace std;
#include "VersionInfo.h"
//#include "MemAccess.h"
#include "Vector.h"
#include "MemAccess.h"
#include "Types.h"
#include "modules/Engravings.h"
#include "ModuleFactory.h"
@ -43,8 +42,7 @@ using namespace DFHack;
struct Engravings::Private
{
uint32_t engraving_vector;
// translation
DfVector <uint32_t> * p_engr;
vector <t_engraving *> * p_engr;
Process * owner;
bool Inited;
@ -61,9 +59,8 @@ Engravings::Engravings()
Core & c = Core::getInstance();
d = new Private;
d->owner = c.p;
d->p_engr = 0;
d->Inited = d->Started = false;
d->engraving_vector = c.vinfo->getGroup("Engravings")->getAddress ("vector");
d->p_engr = (decltype(d->p_engr)) c.vinfo->getGroup("Engravings")->getAddress ("vector");
d->Inited = true;
}
@ -76,7 +73,8 @@ Engravings::~Engravings()
bool Engravings::Start(uint32_t & numengravings)
{
d->p_engr = new DfVector <uint32_t> (d->engraving_vector);
if(!d->Inited)
return false;
numengravings = d->p_engr->size();
d->Started = true;
return true;
@ -88,13 +86,10 @@ bool Engravings::Read (const uint32_t index, dfh_engraving & engraving)
if(!d->Started) return false;
// read pointer from vector at position
uint32_t temp = d->p_engr->at (index);
//read construction from memory
d->owner->read (temp, sizeof (t_engraving), (uint8_t *) &(engraving.s));
engraving.s = *d->p_engr->at (index);
// transform
engraving.origin = temp;
engraving.origin = d->p_engr->at (index);
return true;
}
@ -108,11 +103,6 @@ bool Engravings::Write (const dfh_engraving & engraving)
bool Engravings::Finish()
{
if(d->p_engr)
{
delete d->p_engr;
d->p_engr = NULL;
}
d->Started = false;
return true;
}

@ -37,7 +37,6 @@ using namespace std;
#include "Error.h"
#include "VersionInfo.h"
#include "MemAccess.h"
#include "Vector.h"
#include "ModuleFactory.h"
#include "Core.h"

@ -38,11 +38,29 @@ using namespace std;
#include "ModuleFactory.h"
#include "Core.h"
#include "PluginManager.h"
#include "MiscUtils.h"
using namespace DFHack;
#include "DataDefs.h"
#include "df/world.h"
#include "df/cursor.h"
#include "df/viewscreen_dwarfmodest.h"
#include "df/viewscreen_unitjobsst.h"
#include "df/viewscreen_itemst.h"
#include "df/ui.h"
#include "df/ui_unit_view_mode.h"
#include "df/ui_sidebar_menus.h"
#include "df/ui_look_list.h"
#include "df/job.h"
#include "df/ui_build_selector.h"
#include "df/building_workshopst.h"
#include "df/building_furnacest.h"
#include "df/general_ref.h"
#include "df/unit_inventory_item.h"
#include "df/report.h"
#include "df/popup_message.h"
using namespace df::enums;
// Predefined common guard functions
@ -61,6 +79,18 @@ bool DFHack::dwarfmode_hotkey(Core *, df::viewscreen *top)
return !!strict_virtual_cast<df::viewscreen_dwarfmodest>(top);
}
bool DFHack::unitjobs_hotkey(Core *, df::viewscreen *top)
{
// Require the main dwarf mode screen
return !!strict_virtual_cast<df::viewscreen_unitjobsst>(top);
}
bool DFHack::item_details_hotkey(Core *, df::viewscreen *top)
{
// Require the main dwarf mode screen
return !!strict_virtual_cast<df::viewscreen_itemst>(top);
}
bool DFHack::cursor_hotkey(Core *c, df::viewscreen *top)
{
if (!dwarfmode_hotkey(c, top))
@ -73,6 +103,347 @@ bool DFHack::cursor_hotkey(Core *c, df::viewscreen *top)
return true;
}
bool DFHack::workshop_job_hotkey(Core *c, df::viewscreen *top)
{
using namespace ui_sidebar_mode;
using df::global::ui;
using df::global::world;
using df::global::ui_workshop_in_add;
using df::global::ui_workshop_job_cursor;
if (!dwarfmode_hotkey(c,top))
return false;
switch (ui->main.mode) {
case QueryBuilding:
{
if (!ui_workshop_job_cursor) // allow missing
return false;
df::building *selected = world->selected_building;
if (!virtual_cast<df::building_workshopst>(selected) &&
!virtual_cast<df::building_furnacest>(selected))
return false;
// No jobs?
if (selected->jobs.empty() ||
selected->jobs[0]->job_type == job_type::DestroyBuilding)
return false;
// Add job gui activated?
if (ui_workshop_in_add && *ui_workshop_in_add)
return false;
return true;
};
default:
return false;
}
}
bool DFHack::build_selector_hotkey(Core *c, df::viewscreen *top)
{
using namespace ui_sidebar_mode;
using df::global::ui;
using df::global::ui_build_selector;
if (!dwarfmode_hotkey(c,top))
return false;
switch (ui->main.mode) {
case Build:
{
if (!ui_build_selector) // allow missing
return false;
// Not selecting, or no choices?
if (ui_build_selector->building_type < 0 ||
ui_build_selector->stage != 2 ||
ui_build_selector->choices.empty())
return false;
return true;
};
default:
return false;
}
}
bool DFHack::view_unit_hotkey(Core *c, df::viewscreen *top)
{
using df::global::ui;
using df::global::world;
using df::global::ui_selected_unit;
if (!dwarfmode_hotkey(c,top))
return false;
if (ui->main.mode != ui_sidebar_mode::ViewUnits)
return false;
if (!ui_selected_unit) // allow missing
return false;
return vector_get(world->units.other[0], *ui_selected_unit) != NULL;
}
bool DFHack::unit_inventory_hotkey(Core *c, df::viewscreen *top)
{
using df::global::ui_unit_view_mode;
if (!view_unit_hotkey(c,top))
return false;
if (!ui_unit_view_mode)
return false;
return ui_unit_view_mode->value == df::ui_unit_view_mode::Inventory;
}
df::job *DFHack::getSelectedWorkshopJob(Core *c, bool quiet)
{
using df::global::world;
using df::global::ui_workshop_job_cursor;
if (!workshop_job_hotkey(c, c->getTopViewscreen())) {
if (!quiet)
c->con.printerr("Not in a workshop, or no job is highlighted.\n");
return NULL;
}
df::building *selected = world->selected_building;
int idx = *ui_workshop_job_cursor;
if (idx < 0 || idx >= selected->jobs.size())
{
c->con.printerr("Invalid job cursor index: %d\n", idx);
return NULL;
}
return selected->jobs[idx];
}
bool DFHack::any_job_hotkey(Core *c, df::viewscreen *top)
{
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitjobsst, top))
return vector_get(screen->jobs, screen->cursor_pos) != NULL;
return workshop_job_hotkey(c,top);
}
df::job *DFHack::getSelectedJob(Core *c, bool quiet)
{
df::viewscreen *top = c->getTopViewscreen();
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitjobsst, top))
{
df::job *job = vector_get(screen->jobs, screen->cursor_pos);
if (!job && !quiet)
c->con.printerr("Selected unit has no job\n");
return job;
}
else
return getSelectedWorkshopJob(c, quiet);
}
static df::unit *getAnyUnit(Core *c, df::viewscreen *top)
{
using namespace ui_sidebar_mode;
using df::global::ui;
using df::global::world;
using df::global::ui_look_cursor;
using df::global::ui_look_list;
using df::global::ui_selected_unit;
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitjobsst, top))
return vector_get(screen->units, screen->cursor_pos);
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_itemst, top))
{
df::general_ref *ref = vector_get(screen->entry_ref, screen->cursor_pos);
return ref ? ref->getUnit() : NULL;
}
if (!dwarfmode_hotkey(c,top))
return NULL;
switch (ui->main.mode) {
case ViewUnits:
{
if (!ui_selected_unit)
return NULL;
return vector_get(world->units.other[0], *ui_selected_unit);
}
case LookAround:
{
if (!ui_look_list || !ui_look_cursor)
return NULL;
auto item = vector_get(ui_look_list->items, *ui_look_cursor);
if (item && item->type == df::ui_look_list::T_items::Unit)
return item->unit;
else
return NULL;
}
default:
return NULL;
}
}
bool DFHack::any_unit_hotkey(Core *c, df::viewscreen *top)
{
return getAnyUnit(c, top) != NULL;
}
df::unit *DFHack::getSelectedUnit(Core *c, bool quiet)
{
df::unit *unit = getAnyUnit(c, c->getTopViewscreen());
if (!unit && !quiet)
c->con.printerr("No unit is selected in the UI.\n");
return unit;
}
static df::item *getAnyItem(Core *c, df::viewscreen *top)
{
using namespace ui_sidebar_mode;
using df::global::ui;
using df::global::world;
using df::global::ui_look_cursor;
using df::global::ui_look_list;
using df::global::ui_unit_view_mode;
using df::global::ui_building_item_cursor;
using df::global::ui_sidebar_menus;
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_itemst, top))
{
df::general_ref *ref = vector_get(screen->entry_ref, screen->cursor_pos);
return ref ? ref->getItem() : NULL;
}
if (!dwarfmode_hotkey(c,top))
return NULL;
switch (ui->main.mode) {
case ViewUnits:
{
if (!ui_unit_view_mode || !ui_look_cursor || !ui_sidebar_menus)
return NULL;
if (ui_unit_view_mode->value != df::ui_unit_view_mode::Inventory)
return NULL;
auto inv_item = vector_get(ui_sidebar_menus->unit.inv_items, *ui_look_cursor);
return inv_item ? inv_item->item : NULL;
}
case LookAround:
{
if (!ui_look_list || !ui_look_cursor)
return NULL;
auto item = vector_get(ui_look_list->items, *ui_look_cursor);
if (item && item->type == df::ui_look_list::T_items::Item)
return item->item;
else
return NULL;
}
case BuildingItems:
{
if (!ui_building_item_cursor)
return NULL;
VIRTUAL_CAST_VAR(selected, df::building_actual, world->selected_building);
if (!selected)
return NULL;
auto inv_item = vector_get(selected->contained_items, *ui_building_item_cursor);
return inv_item ? inv_item->item : NULL;
}
default:
return NULL;
}
}
bool DFHack::any_item_hotkey(Core *c, df::viewscreen *top)
{
return getAnyItem(c, top) != NULL;
}
df::item *DFHack::getSelectedItem(Core *c, bool quiet)
{
df::item *item = getAnyItem(c, c->getTopViewscreen());
if (!item && !quiet)
c->con.printerr("No item is selected in the UI.\n");
return item;
}
//
void DFHack::showAnnouncement(std::string message, int color, bool bright)
{
using df::global::world;
using df::global::cur_year;
using df::global::cur_year_tick;
int year = 0, year_time = 0;
if (cur_year && cur_year_tick)
{
year = *cur_year;
year_time = *cur_year_tick;
}
else if (!world->status.reports.empty())
{
// Fallback: copy from the last report
df::report *last = world->status.reports.back();
year = last->year;
year_time = last->time;
}
bool continued = false;
while (!message.empty())
{
df::report *new_rep = new df::report();
new_rep->color = color;
new_rep->bright = bright;
new_rep->year = year;
new_rep->time = year_time;
new_rep->flags.bits.continuation = continued;
new_rep->flags.bits.announcement = true;
int size = std::min(message.size(), 73U);
new_rep->text = message.substr(0, size);
message = message.substr(size);
continued = true;
// Add the object to the lists
new_rep->id = world->status.next_report_id++;
world->status.reports.push_back(new_rep);
world->status.announcements.push_back(new_rep);
world->status.display_timer = 2000;
}
}
void DFHack::showPopupAnnouncement(std::string message, int color, bool bright)
{
using df::global::world;
df::popup_message *popup = new df::popup_message();
popup->text = message;
popup->color = color;
popup->bright = bright;
world->status.popups.push_back(popup);
}
//
Module* DFHack::createGui()
@ -91,16 +462,23 @@ struct Gui::Private
}
bool Started;
uint32_t window_x_offset;
uint32_t window_y_offset;
uint32_t window_z_offset;
uint32_t cursor_xyz_offset;
uint32_t designation_xyz_offset;
uint32_t mouse_xy_offset;
uint32_t window_dims_offset;
int32_t * window_x_offset;
int32_t * window_y_offset;
int32_t * window_z_offset;
struct xyz
{
int32_t x;
int32_t y;
int32_t z;
} * cursor_xyz_offset, * designation_xyz_offset;
struct xy
{
int32_t x;
int32_t y;
} * mouse_xy_offset, * window_dims_offset;
bool StartedScreen;
uint32_t screen_tiles_ptr_offset;
void * screen_tiles_ptr_offset;
Process * owner;
};
@ -157,19 +535,33 @@ Gui::Gui()
try
{
OG_Position = mem->getGroup("Position");
d->window_x_offset = OG_Position->getAddress ("window_x");
d->window_y_offset = OG_Position->getAddress ("window_y");
d->window_z_offset = OG_Position->getAddress ("window_z");
d->cursor_xyz_offset = OG_Position->getAddress ("cursor_xyz");
d->window_dims_offset = OG_Position->getAddress ("window_dims");
d->window_x_offset = (int32_t *) OG_Position->getAddress ("window_x");
d->window_y_offset = (int32_t *) OG_Position->getAddress ("window_y");
d->window_z_offset = (int32_t *) OG_Position->getAddress ("window_z");
d->cursor_xyz_offset = (Private::xyz *) OG_Position->getAddress ("cursor_xyz");
d->window_dims_offset = (Private::xy *) OG_Position->getAddress ("window_dims");
d->Started = true;
}
catch(Error::All &){};
OG_Position->getSafeAddress("mouse_xy", d->mouse_xy_offset);
OG_Position->getSafeAddress("designation_xyz", d->designation_xyz_offset);
try
{
d->screen_tiles_ptr_offset = OG_Position->getAddress ("screen_tiles_pointer");
d->mouse_xy_offset = (Private::xy *) OG_Position->getAddress ("mouse_xy");
}
catch(Error::All &)
{
d->mouse_xy_offset = 0;
};
try
{
d->designation_xyz_offset = (Private::xyz *) OG_Position->getAddress ("designation_xyz");
}
catch(Error::All &)
{
d->designation_xyz_offset = 0;
};
try
{
d->screen_tiles_ptr_offset = (void *) OG_Position->getAddress ("screen_tiles_pointer");
d->StartedScreen = true;
}
catch(Error::All &){};
@ -299,10 +691,10 @@ bool Gui::getScreenTiles (int32_t width, int32_t height, t_screen screen[])
{
if(!d->StartedScreen) return false;
uint32_t screen_addr = d->owner->readDWord(d->screen_tiles_ptr_offset);
void * screen_addr = (void *) d->owner->readDWord(d->screen_tiles_ptr_offset);
uint8_t* tiles = new uint8_t[width*height*4/* + 80 + width*height*4*/];
d->owner->read (screen_addr, (width*height*4/* + 80 + width*height*4*/), (uint8_t *) tiles);
d->owner->read (screen_addr, (width*height*4/* + 80 + width*height*4*/), tiles);
for(int32_t iy=0; iy<height; iy++)
{

@ -1,4 +1,4 @@
/*
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
@ -36,166 +36,382 @@ using namespace std;
#include "Types.h"
#include "VersionInfo.h"
#include "MemAccess.h"
#include "Vector.h"
#include "modules/Materials.h"
#include "modules/Items.h"
#include "modules/Units.h"
#include "ModuleFactory.h"
#include "Core.h"
#include "Virtual.h"
#include "MiscUtils.h"
#include "df/world.h"
#include "df/item.h"
#include "df/tool_uses.h"
#include "df/itemdef_weaponst.h"
#include "df/itemdef_trapcompst.h"
#include "df/itemdef_toyst.h"
#include "df/itemdef_toolst.h"
#include "df/itemdef_instrumentst.h"
#include "df/itemdef_armorst.h"
#include "df/itemdef_ammost.h"
#include "df/itemdef_siegeammost.h"
#include "df/itemdef_glovesst.h"
#include "df/itemdef_shoesst.h"
#include "df/itemdef_shieldst.h"
#include "df/itemdef_helmst.h"
#include "df/itemdef_pantsst.h"
#include "df/itemdef_foodst.h"
#include "df/trapcomp_flags.h"
#include "df/job_item.h"
#include "df/general_ref.h"
using namespace DFHack;
Module* DFHack::createItems()
using namespace DFHack::Simple;
using namespace df::enums;
using df::global::world;
#define ITEMDEF_VECTORS \
ITEM(WEAPON, weapons, itemdef_weaponst) \
ITEM(TRAPCOMP, trapcomps, itemdef_trapcompst) \
ITEM(TOY, toys, itemdef_toyst) \
ITEM(TOOL, tools, itemdef_toolst) \
ITEM(INSTRUMENT, instruments, itemdef_instrumentst) \
ITEM(ARMOR, armor, itemdef_armorst) \
ITEM(AMMO, ammo, itemdef_ammost) \
ITEM(SIEGEAMMO, siege_ammo, itemdef_siegeammost) \
ITEM(GLOVES, gloves, itemdef_glovesst) \
ITEM(SHOES, shoes, itemdef_shoesst) \
ITEM(SHIELD, shields, itemdef_shieldst) \
ITEM(HELM, helms, itemdef_helmst) \
ITEM(PANTS, pants, itemdef_pantsst) \
ITEM(FOOD, food, itemdef_foodst)
bool ItemTypeInfo::decode(df::item_type type_, int16_t subtype_)
{
return new Items();
}
using namespace df::enums::item_type;
class Items::Private
{
public:
Process * owner;
std::map<int32_t, df_item *> idLookupTable;
uint32_t refVectorOffset;
uint32_t idFieldOffset;
uint32_t itemVectorAddress;
type = type_;
subtype = subtype_;
custom = NULL;
df::world_raws::T_itemdefs &defs = df::global::world->raws.itemdefs;
switch (type_) {
case NONE:
return false;
#define ITEM(type,vec,tclass) \
case type: \
custom = vector_get(defs.vec, subtype); \
break;
ITEMDEF_VECTORS
#undef ITEM
ClassNameCheck isOwnerRefClass;
ClassNameCheck isContainerRefClass;
ClassNameCheck isContainsRefClass;
default:
break;
}
// Similar to isOwnerRefClass. Value is unique to each creature, but
// different than the creature's id.
ClassNameCheck isUnitHolderRefClass;
return isValid();
}
// One of these is present for each creature contained in a cage.
// The value is similar to that for isUnitHolderRefClass, different
// than the creature's ID but unique for each creature.
ClassNameCheck isCagedUnitRefClass;
bool ItemTypeInfo::decode(df::item *ptr)
{
if (!ptr)
return decode(item_type::NONE);
else
return decode(ptr->getType(), ptr->getSubtype());
}
// ID of bulding containing/holding the item.
ClassNameCheck isBuildingHolderRefClass;
std::string ItemTypeInfo::getToken()
{
std::string rv = ENUM_KEY_STR(item_type, type);
if (custom)
rv += ":" + custom->id;
else if (subtype != -1)
rv += stl_sprintf(":%d", subtype);
return rv;
}
// Building ID of lever/etc which triggers bridge/etc holding
// this mechanism.
ClassNameCheck isTriggeredByRefClass;
std::string ItemTypeInfo::toString()
{
using namespace df::enums::item_type;
switch (type) {
#define ITEM(type,vec,tclass) \
case type: \
if (VIRTUAL_CAST_VAR(cv, df::tclass, custom)) \
return cv->name;
ITEMDEF_VECTORS
#undef ITEM
default:
break;
}
// Building ID of bridge/etc which is triggered by lever/etc holding
// this mechanism.
ClassNameCheck isTriggerTargetRefClass;
return toLower(ENUM_KEY_STR(item_type, type));
}
// Civilization ID of owner of item, for items not owned by the
// fortress.
ClassNameCheck isEntityOwnerRefClass;
bool ItemTypeInfo::find(const std::string &token)
{
using namespace df::enums::item_type;
// Item has been offered to the caravan. The value is the
// civilization ID of
ClassNameCheck isOfferedRefClass;
std::vector<std::string> items;
split_string(&items, token, ":");
// Item is in a depot for trade. Purpose of value is unknown, but is
// different for each item, even in the same depot at the same time.
ClassNameCheck isTradingRefClass;
type = NONE;
subtype = -1;
custom = NULL;
// Item is flying or falling through the air. The value seems to
// be the ID for a "projectile information" object.
ClassNameCheck isProjectileRefClass;
if (items.size() < 1 || items.size() > 2)
return false;
std::set<std::string> knownItemRefTypes;
};
if (items[0] == "NONE")
return true;
Items::Items()
FOR_ENUM_ITEMS(item_type, i)
{
Core & c = Core::getInstance();
d = new Private;
d->owner = c.p;
DFHack::OffsetGroup* itemGroup = c.vinfo->getGroup("Items");
d->itemVectorAddress = itemGroup->getAddress("items_vector");
d->idFieldOffset = itemGroup->getOffset("id");
d->refVectorOffset = itemGroup->getOffset("item_ref_vector");
d->isOwnerRefClass = ClassNameCheck("general_ref_unit_itemownerst");
d->isContainerRefClass = ClassNameCheck("general_ref_contained_in_itemst");
d->isContainsRefClass = ClassNameCheck("general_ref_contains_itemst");
d->isUnitHolderRefClass = ClassNameCheck("general_ref_unit_holderst");
d->isCagedUnitRefClass = ClassNameCheck("general_ref_contains_unitst");
d->isBuildingHolderRefClass
= ClassNameCheck("general_ref_building_holderst");
d->isTriggeredByRefClass = ClassNameCheck("general_ref_building_triggerst");
d->isTriggerTargetRefClass
= ClassNameCheck("general_ref_building_triggertargetst");
d->isEntityOwnerRefClass = ClassNameCheck("general_ref_entity_itemownerst");
d->isOfferedRefClass = ClassNameCheck("general_ref_entity_offeredst");
d->isTradingRefClass = ClassNameCheck("general_ref_unit_tradebringerst");
d->isProjectileRefClass = ClassNameCheck("general_ref_projectilest");
std::vector<std::string> known_names;
ClassNameCheck::getKnownClassNames(known_names);
for (size_t i = 0; i < known_names.size(); i++)
const char *key = ENUM_ATTR(item_type, key, i);
if (key && key == items[0])
{
if (known_names[i].find("general_ref_") == 0)
d->knownItemRefTypes.insert(known_names[i]);
type = i;
break;
}
}
bool Items::Start()
{
d->idLookupTable.clear();
if (type == NONE)
return false;
if (items.size() == 1)
return true;
df::world_raws::T_itemdefs &defs = df::global::world->raws.itemdefs;
switch (type) {
#define ITEM(type,vec,tclass) \
case type: \
for (int i = 0; i < defs.vec.size(); i++) { \
if (defs.vec[i]->id == items[1]) { \
subtype = i; custom = defs.vec[i]; return true; \
} \
} \
break;
ITEMDEF_VECTORS
#undef ITEM
default:
break;
}
bool Items::Finish()
{
return true;
return (subtype >= 0);
}
bool Items::readItemVector(std::vector<df_item *> &items)
bool ItemTypeInfo::matches(const df::job_item &item, MaterialInfo *mat)
{
std::vector <df_item *> *p_items = (std::vector <df_item *> *) d->itemVectorAddress;
using namespace df::enums::item_type;
d->idLookupTable.clear();
items.resize(p_items->size());
if (!isValid())
return mat ? mat->matches(item) : false;
for (unsigned i = 0; i < p_items->size(); i++)
{
df_item * ptr = p_items->at(i);
items[i] = ptr;
d->idLookupTable[ptr->id] = ptr;
df::job_item_flags1 ok1, mask1, item_ok1, item_mask1;
df::job_item_flags2 ok2, mask2, item_ok2, item_mask2;
df::job_item_flags3 ok3, mask3, item_ok3, item_mask3;
ok1.whole = mask1.whole = item_ok1.whole = item_mask1.whole = 0;
ok2.whole = mask2.whole = item_ok2.whole = item_mask2.whole = 0;
ok3.whole = mask3.whole = item_ok3.whole = item_mask3.whole = 0;
if (mat) {
mat->getMatchBits(ok1, mask1);
mat->getMatchBits(ok2, mask2);
mat->getMatchBits(ok3, mask3);
}
return true;
#define OK(id,name) item_ok##id.bits.name = true
#define RQ(id,name) item_mask##id.bits.name = true
// Set up the flag mask
RQ(1,millable); RQ(1,sharpenable); RQ(1,distillable); RQ(1,processable); RQ(1,bag);
RQ(1,extract_bearing_plant); RQ(1,extract_bearing_fish); RQ(1,extract_bearing_vermin);
RQ(1,processable_to_vial); RQ(1,processable_to_bag); RQ(1,processable_to_barrel);
RQ(1,solid); RQ(1,tameable_vermin); RQ(1,sand_bearing); RQ(1,milk); RQ(1,milkable);
RQ(1,not_bin); RQ(1,lye_bearing);
RQ(2,dye); RQ(2,dyeable); RQ(2,dyed); RQ(2,glass_making); RQ(2,screw);
RQ(2,building_material); RQ(2,fire_safe); RQ(2,magma_safe); RQ(2,non_economic);
RQ(2,totemable); RQ(2,plaster_containing); RQ(2,body_part); RQ(2,lye_milk_free);
RQ(2,blunt); RQ(2,unengraved); RQ(2,hair_wool);
RQ(3,any_raw_material); RQ(3,non_pressed); RQ(3,food_storage);
// Compute the ok mask
OK(1,solid);
OK(1,not_bin);
// TODO: furniture, ammo, finished good, craft
switch (type) {
case PLANT:
OK(1,millable); OK(1,processable);
OK(1,distillable);
OK(1,extract_bearing_plant);
OK(1,processable_to_vial);
OK(1,processable_to_bag);
OK(1,processable_to_barrel);
break;
case BOULDER:
OK(1,sharpenable);
OK(2,non_economic);
case BAR:
OK(3,any_raw_material);
case BLOCKS:
case WOOD:
OK(2,building_material);
OK(2,fire_safe); OK(2,magma_safe);
break;
case VERMIN:
OK(1,extract_bearing_fish);
OK(1,extract_bearing_vermin);
OK(1,tameable_vermin);
OK(1,milkable);
break;
case DRINK:
item_ok1.bits.solid = false;
break;
case ROUGH:
OK(2,glass_making);
break;
case ANIMALTRAP:
case CAGE:
OK(1,milk);
OK(1,milkable);
break;
case BUCKET:
case FLASK:
OK(1,milk);
break;
case TOOL:
OK(1,lye_bearing);
OK(1,milk);
OK(2,lye_milk_free);
OK(2,blunt);
if (VIRTUAL_CAST_VAR(def, df::itemdef_toolst, custom)) {
df::enum_field<df::tool_uses,int16_t> key(tool_uses::FOOD_STORAGE);
if (linear_index(def->tool_use, key) >= 0)
OK(3,food_storage);
} else {
OK(3,food_storage);
}
break;
case BARREL:
OK(1,lye_bearing);
OK(1,milk);
OK(2,lye_milk_free);
OK(3,food_storage);
break;
case BOX:
OK(1,bag); OK(1,sand_bearing); OK(1,milk);
OK(2,dye); OK(2,plaster_containing);
break;
case BIN:
item_ok1.bits.not_bin = false;
break;
case LIQUID_MISC:
item_ok1.bits.solid = false;
OK(1,milk);
break;
case POWDER_MISC:
OK(2,dye);
case GLOB:
OK(3,any_raw_material);
OK(3,non_pressed);
break;
case THREAD:
case CLOTH:
OK(2,dyeable); OK(2,dyed);
break;
case WEAPON:
case AMMO:
case ROCK:
OK(2,blunt);
break;
case TRAPCOMP:
if (VIRTUAL_CAST_VAR(def, df::itemdef_trapcompst, custom)) {
if (def->flags.is_set(trapcomp_flags::IS_SCREW))
OK(2,screw);
} else {
OK(2,screw);
}
OK(2,blunt);
break;
case CORPSE:
case CORPSEPIECE:
OK(2,totemable);
OK(2,body_part);
OK(2,hair_wool);
break;
case SLAB:
OK(2,unengraved);
break;
case ANVIL:
OK(2,fire_safe); OK(2,magma_safe);
break;
default:
break;
}
df_item * Items::findItemByID(int32_t id)
{
if (id < 0)
return 0;
if ((item_ok1.whole & ~item_mask1.whole) ||
(item_ok2.whole & ~item_mask2.whole) ||
(item_ok3.whole & ~item_mask3.whole))
Core::getInstance().con.printerr("ItemTypeInfo.matches inconsistent\n");
if (d->idLookupTable.empty())
{
std::vector<df_item *> tmp;
readItemVector(tmp);
}
#undef OK
#undef RQ
return d->idLookupTable[id];
return bits_match(item.flags1.whole, ok1.whole, mask1.whole) &&
bits_match(item.flags2.whole, ok2.whole, mask2.whole) &&
bits_match(item.flags3.whole, ok3.whole, mask3.whole) &&
bits_match(item.flags1.whole, item_ok1.whole, item_mask1.whole) &&
bits_match(item.flags2.whole, item_ok2.whole, item_mask2.whole) &&
bits_match(item.flags3.whole, item_ok3.whole, item_mask3.whole);
}
Items::~Items()
df::item * Items::findItemByID(int32_t id)
{
Finish();
delete d;
if (id < 0)
return 0;
return df::item::find(id);
}
bool Items::copyItem(df_item * itembase, DFHack::dfh_item &item)
bool Items::copyItem(df::item * itembase, DFHack::dfh_item &item)
{
if(!itembase)
return false;
df_item * itreal = (df_item *) itembase;
df::item * itreal = (df::item *) itembase;
item.origin = itembase;
item.x = itreal->x;
item.y = itreal->y;
item.z = itreal->z;
item.x = itreal->pos.x;
item.y = itreal->pos.y;
item.z = itreal->pos.z;
item.id = itreal->id;
item.age = itreal->age;
item.flags = itreal->flags;
@ -209,87 +425,72 @@ bool Items::copyItem(df_item * itembase, DFHack::dfh_item &item)
return true;
}
int32_t Items::getItemOwnerID(const DFHack::df_item * item)
int32_t Items::getItemOwnerID(const df::item * item)
{
std::vector<int32_t> vals;
if (readItemRefs(item, d->isOwnerRefClass, vals))
return vals[0];
else
for (uint32_t i = 0; i < item->itemrefs.size(); i++)
{
df::general_ref *ref = item->itemrefs[i];
if (ref->getType() == df::general_ref_type::UNIT_ITEMOWNER)
return ref->getID();
}
return -1;
}
int32_t Items::getItemContainerID(const DFHack::df_item * item)
int32_t Items::getItemContainerID(const df::item * item)
{
std::vector<int32_t> vals;
if (readItemRefs(item, d->isContainerRefClass, vals))
return vals[0];
else
for (uint32_t i = 0; i < item->itemrefs.size(); i++)
{
df::general_ref *ref = item->itemrefs[i];
if (ref->getType() == df::general_ref_type::CONTAINED_IN_ITEM)
return ref->getID();
}
return -1;
}
bool Items::getContainedItems(const DFHack::df_item * item, std::vector<int32_t> &items)
bool Items::getContainedItems(const df::item * item, std::vector<int32_t> &items)
{
return readItemRefs(item, d->isContainsRefClass, items);
return readItemRefs(item, df::general_ref_type::CONTAINS_ITEM, items);
}
bool Items::readItemRefs(const df_item * item, const ClassNameCheck &classname, std::vector<int32_t> &values)
bool Items::readItemRefs(const df::item * item, df::general_ref_type type, std::vector<int32_t> &values)
{
const std::vector <t_itemref *> &p_refs = item->itemrefs;
values.clear();
for (uint32_t i=0; i<p_refs.size(); i++)
for (uint32_t i = 0; i < item->itemrefs.size(); i++)
{
if (classname(d->owner, p_refs[i]->vptr))
values.push_back(int32_t(p_refs[i]->value));
df::general_ref *ref = item->itemrefs[i];
if (ref->getType() == type)
values.push_back(ref->getID());
}
return !values.empty();
}
bool Items::unknownRefs(const df_item * item, std::vector<std::pair<std::string, int32_t> >& refs)
{
refs.clear();
const std::vector <t_itemref *> &p_refs = item->itemrefs;
for (uint32_t i=0; i<p_refs.size(); i++)
{
std::string name = p_refs[i]->getClassName();
if (d->knownItemRefTypes.find(name) == d->knownItemRefTypes.end())
{
refs.push_back(pair<string, int32_t>(name, p_refs[i]->value));
}
}
return (refs.size() > 0);
}
bool Items::removeItemOwner(df_item * item, Units *creatures)
bool Items::removeItemOwner(df::item * item, Units *creatures)
{
std::vector <t_itemref *> &p_refs = item->itemrefs;
for (uint32_t i=0; i<p_refs.size(); i++)
for (uint32_t i = 0; i < item->itemrefs.size(); i++)
{
if (!d->isOwnerRefClass(d->owner, p_refs[i]->vptr))
df::general_ref *ref = item->itemrefs[i];
if (ref->getType() != df::general_ref_type::UNIT_ITEMOWNER)
continue;
int32_t & oid = p_refs[i]->value;
int32_t ix = creatures->FindIndexById(oid);
df_unit *unit = (df_unit *)ref->getUnit();
if (ix < 0 || !creatures->RemoveOwnedItemByIdx(ix, item->id))
if (unit == NULL || !creatures->RemoveOwnedItemByPtr(unit, item->id))
{
cerr << "RemoveOwnedItemIdx: CREATURE " << ix << " ID " << item->id << " FAILED!" << endl;
cerr << "RemoveOwnedItemIdx: CREATURE " << ref->getID() << " ID " << item->id << " FAILED!" << endl;
return false;
}
p_refs.erase(p_refs.begin() + i--);
delete ref;
item->itemrefs.erase(item->itemrefs.begin() + i--);
}
item->flags.owned = 0;
item->flags.bits.owned = 0;
return true;
}
std::string Items::getItemClass(const df_item * item)
std::string Items::getItemClass(const df::item * item)
{
const t_virtual * virt = (t_virtual *) item;
return virt->getClassName();

@ -0,0 +1,256 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "Internal.h"
#include <string>
#include <vector>
#include <map>
#include <cassert>
using namespace std;
#include "Core.h"
#include "PluginManager.h"
#include "MiscUtils.h"
#include "modules/Job.h"
#include "modules/Materials.h"
#include "modules/Items.h"
#include "DataDefs.h"
#include "df/world.h"
#include "df/ui.h"
#include "df/job.h"
#include "df/job_item.h"
#include "df/job_list_link.h"
#include "df/general_ref.h"
#include "df/general_ref_unit_workerst.h"
#include "df/general_ref_building_holderst.h"
using namespace DFHack;
using namespace df::enums;
df::job *DFHack::cloneJobStruct(df::job *job)
{
df::job *pnew = new df::job(*job);
// Clean out transient fields
pnew->flags.whole = 0;
pnew->flags.bits.repeat = job->flags.bits.repeat;
pnew->flags.bits.suspend = job->flags.bits.suspend;
pnew->list_link = NULL;
pnew->completion_timer = -1;
pnew->items.clear();
pnew->misc_links.clear();
// Clone refs
for (int i = pnew->references.size()-1; i >= 0; i--)
{
df::general_ref *ref = pnew->references[i];
if (virtual_cast<df::general_ref_unit_workerst>(ref))
vector_erase_at(pnew->references, i);
else
pnew->references[i] = ref->clone();
}
// Clone items
for (int i = pnew->job_items.size()-1; i >= 0; i--)
pnew->job_items[i] = new df::job_item(*pnew->job_items[i]);
return pnew;
}
void DFHack::deleteJobStruct(df::job *job)
{
if (!job)
return;
// Only allow free-floating job structs
assert(!job->list_link && job->items.empty() && job->misc_links.empty());
for (int i = job->references.size()-1; i >= 0; i--)
delete job->references[i];
for (int i = job->job_items.size()-1; i >= 0; i--)
delete job->job_items[i];
delete job;
}
#define CMP(field) (a.field == b.field)
bool DFHack::operator== (const df::job_item &a, const df::job_item &b)
{
if (!(CMP(item_type) && CMP(item_subtype) &&
CMP(mat_type) && CMP(mat_index) &&
CMP(flags1.whole) && CMP(quantity) && CMP(vector_id) &&
CMP(flags2.whole) && CMP(flags3.whole) &&
CMP(metal_ore) && CMP(reaction_class) &&
CMP(has_material_reaction_product) &&
CMP(min_dimension) && CMP(reagent_index) &&
CMP(reaction_id) && CMP(has_tool_use) &&
CMP(contains.size())))
return false;
for (int i = a.contains.size()-1; i >= 0; i--)
if (a.contains[i] != b.contains[i])
return false;
return true;
}
bool DFHack::operator== (const df::job &a, const df::job &b)
{
if (!(CMP(job_type) && CMP(unk2) &&
CMP(mat_type) && CMP(mat_index) &&
CMP(item_subtype) && CMP(item_category.whole) &&
CMP(hist_figure_id) && CMP(material_category.whole) &&
CMP(reaction_name) && CMP(job_items.size())))
return false;
for (int i = a.job_items.size()-1; i >= 0; i--)
if (!(*a.job_items[i] == *b.job_items[i]))
return false;
return true;
}
static void print_job_item_details(Core *c, df::job *job, unsigned idx, df::job_item *item)
{
ItemTypeInfo info(item);
c->con << " Input Item " << (idx+1) << ": " << info.toString();
if (item->quantity != 1)
c->con << "; quantity=" << item->quantity;
if (item->min_dimension >= 0)
c->con << "; min_dimension=" << item->min_dimension;
c->con << endl;
MaterialInfo mat(item);
if (mat.isValid() || item->metal_ore >= 0) {
c->con << " material: " << mat.toString();
if (item->metal_ore >= 0)
c->con << "; ore of " << MaterialInfo(0,item->metal_ore).toString();
c->con << endl;
}
if (item->flags1.whole)
c->con << " flags1: " << bitfieldToString(item->flags1) << endl;
if (item->flags2.whole)
c->con << " flags2: " << bitfieldToString(item->flags2) << endl;
if (item->flags3.whole)
c->con << " flags3: " << bitfieldToString(item->flags3) << endl;
if (!item->reaction_class.empty())
c->con << " reaction class: " << item->reaction_class << endl;
if (!item->has_material_reaction_product.empty())
c->con << " reaction product: " << item->has_material_reaction_product << endl;
if (item->has_tool_use >= 0)
c->con << " tool use: " << ENUM_KEY_STR(tool_uses, item->has_tool_use) << endl;
}
void DFHack::printJobDetails(Core *c, df::job *job)
{
c->con.color(job->flags.bits.suspend ? Console::COLOR_DARKGREY : Console::COLOR_GREY);
c->con << "Job " << job->id << ": " << ENUM_KEY_STR(job_type,job->job_type);
if (job->flags.whole)
c->con << " (" << bitfieldToString(job->flags) << ")";
c->con << endl;
c->con.reset_color();
df::item_type itype = ENUM_ATTR(job_type, item, job->job_type);
MaterialInfo mat(job);
if (itype == item_type::FOOD)
mat.decode(-1);
if (mat.isValid() || job->material_category.whole)
{
c->con << " material: " << mat.toString();
if (job->material_category.whole)
c->con << " (" << bitfieldToString(job->material_category) << ")";
c->con << endl;
}
if (job->item_subtype >= 0 || job->item_category.whole)
{
ItemTypeInfo iinfo(itype, job->item_subtype);
c->con << " item: " << iinfo.toString()
<< " (" << bitfieldToString(job->item_category) << ")" << endl;
}
if (job->hist_figure_id >= 0)
c->con << " figure: " << job->hist_figure_id << endl;
if (!job->reaction_name.empty())
c->con << " reaction: " << job->reaction_name << endl;
for (unsigned i = 0; i < job->job_items.size(); i++)
print_job_item_details(c, job, i, job->job_items[i]);
}
df::building *DFHack::getJobHolder(df::job *job)
{
for (unsigned i = 0; i < job->references.size(); i++)
{
VIRTUAL_CAST_VAR(ref, df::general_ref_building_holderst, job->references[i]);
if (ref)
return ref->getBuilding();
}
return NULL;
}
bool DFHack::linkJobIntoWorld(df::job *job, bool new_id)
{
using df::global::world;
using df::global::job_next_id;
assert(!job->list_link);
if (new_id) {
job->id = (*job_next_id)++;
job->list_link = new df::job_list_link();
job->list_link->item = job;
linked_list_append(&world->job_list, job->list_link);
return true;
} else {
df::job_list_link *ins_pos = &world->job_list;
while (ins_pos->next && ins_pos->next->item->id < job->id)
ins_pos = ins_pos->next;
if (ins_pos->next && ins_pos->next->item->id == job->id)
return false;
job->list_link = new df::job_list_link();
job->list_link->item = job;
linked_list_insert_after(ins_pos, job->list_link);
return true;
}
}

@ -37,7 +37,6 @@ using namespace std;
#include "Error.h"
#include "VersionInfo.h"
#include "MemAccess.h"
#include "Vector.h"
#include "ModuleFactory.h"
#include "Core.h"
@ -96,7 +95,7 @@ struct Maps::Private
FEATURES
*/
// FIXME: replace with a struct pointer, eventually. needs to be mapped out first
uint32_t world_data;
char * world_data;
uint32_t local_f_start; // offset from world_data
// FIXME: replace by virtual function call
uint32_t local_material;
@ -122,7 +121,7 @@ struct Maps::Private
set <uint32_t> unknown_veins;
// map between feature address and the read object
map <uint32_t, t_feature> local_feature_store;
map <void *, t_feature> local_feature_store;
map <DFCoord, vector <t_feature *> > m_local_feature;
vector <t_feature> v_global_feature;
@ -508,13 +507,13 @@ bool Maps::StartFeatures()
Process * p = d->owner;
Private::t_offsets &off = d->offsets;
uint32_t base = 0;
uint32_t global_feature_vector = 0;
char * base = 0;
char * global_feature_vector = 0;
uint32_t world = p->readDWord(off.world_data);
char * world = p->readPtr( (void *) off.world_data);
if(!world) return false;
base = p->readDWord(world + off.local_f_start);
global_feature_vector = p->readDWord(off.world_data) + off.global_vector;
base = p->readPtr(world + off.local_f_start);
global_feature_vector = p->readPtr(off.world_data) + off.global_vector;
// deref pointer to the humongo-structure
if(!base)
@ -549,22 +548,21 @@ bool Maps::StartFeatures()
// base = pointer to local feature structure (inside world data struct)
// bigregion is 16x16 regions. for each bigregion in X dimension:
uint32_t mega_column = p->readDWord(base + bigregion_x * 4);
char * mega_column = p->readPtr(base + bigregion_x * 4);
// 16B structs, second DWORD of the struct is a pointer
uint32_t loc_f_array16x16 = p->readDWord(mega_column + offset_elem + (sizeof_elem * bigregion_y));
char * loc_f_array16x16 = p->readPtr(mega_column + offset_elem + (sizeof_elem * bigregion_y));
if(loc_f_array16x16)
{
uint32_t feat_vector = loc_f_array16x16 + sizeof_16vec * sub_x + sizeof_vec * sub_y;
DfVector<uint32_t> p_features(feat_vector);
uint32_t size = p_features.size();
vector <char *> * p_features = (vector <char *> *) (loc_f_array16x16 + sizeof_16vec * sub_x + sizeof_vec * sub_y);
uint32_t size = p_features->size();
DFCoord pc(blockX,blockY);
std::vector<t_feature *> tempvec;
for(uint32_t i = 0; i < size; i++)
{
uint32_t cur_ptr = p_features[i];
char * cur_ptr = p_features->at(i);
map <uint32_t, t_feature>::iterator it;
map <void *, t_feature>::iterator it;
it = d->local_feature_store.find(cur_ptr);
// do we already have the feature?
if(it != d->local_feature_store.end())
@ -579,7 +577,7 @@ bool Maps::StartFeatures()
// create, add to store
t_feature tftemp;
tftemp.discovered = false; //= p->readDWord(cur_ptr + 4);
tftemp.origin = cur_ptr;
tftemp.origin = (t_feature *) cur_ptr;
string name = p->readClassName((void *)p->readDWord( cur_ptr ));
if(name == "feature_init_deep_special_tubest")
{
@ -611,17 +609,15 @@ bool Maps::StartFeatures()
const uint32_t global_feature_funcptr = off.global_funcptr;
const uint32_t glob_main_mat_offset = off.global_material;
const uint32_t glob_sub_mat_offset = off.global_submaterial;
DfVector<uint32_t> p_features (global_feature_vector);
vector <char *> * p_features = (vector <char *> *) global_feature_vector;
d->v_global_feature.clear();
uint32_t size = p_features.size();
uint32_t size = p_features->size();
d->v_global_feature.reserve(size);
for(uint32_t i = 0; i < size; i++)
{
t_feature temp;
uint32_t feat_ptr = p->readDWord(p_features[i] + global_feature_funcptr );
char * feat_ptr = p->readPtr(p_features->at(i) + global_feature_funcptr );
temp.origin = feat_ptr;
//temp.discovered = p->readDWord( feat_ptr + 4 ); // maybe, placeholder
temp.discovered = false;
// FIXME: use the memory_info cache mechanisms
@ -896,17 +892,18 @@ bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
Process *p = d->owner;
// get needed addresses and offsets. Now this is what I call crazy.
uint16_t worldSizeX, worldSizeY;
uint32_t regions, geoblocks_vector_addr;
char *regions;
char *geoblocks_vector_addr;
Private::t_offsets &off = d->offsets;
// get world size
uint32_t world = p->readDWord(off.world_data);
char * world = p->readPtr(off.world_data);
p->readWord (world + off.world_size_x, worldSizeX);
p->readWord (world + off.world_size_y, worldSizeY);
regions = p->readDWord ( world + off.world_regions); // ptr2_region_array
regions = p->readPtr ( world + off.world_regions); // ptr2_region_array
geoblocks_vector_addr = world + off.world_geoblocks_vector;
// read the geoblock vector
DfVector <uint32_t> geoblocks (geoblocks_vector_addr);
vector <char *> & geoblocks = *(vector <char *> *)(geoblocks_vector_addr);
// iterate over 8 surrounding regions + local region
for (int i = eNorthWest; i < eBiomeCount; i++)
@ -925,8 +922,8 @@ bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
/// regions are a 2d array. consists of pointers to arrays of regions
/// regions are of region_size size
// get pointer to column of regions
uint32_t geoX;
p->readDWord (regions + bioRX*4, geoX);
char * geoX;
p->readPtr (regions + bioRX*4, geoX);
// get index into geoblock vector
uint16_t geoindex;
@ -935,11 +932,11 @@ bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
/// geology blocks are assigned to regions from a vector
// get the geoblock from the geoblock vector using the geoindex
// read the matgloss pointer from the vector into temp
uint32_t geoblock_off = geoblocks[geoindex];
char * geoblock_off = geoblocks[geoindex];
/// geology blocks have a vector of layer descriptors
// get the vector with pointer to layers
DfVector <uint32_t> geolayers (geoblock_off + off.geolayer_geoblock_offset); // let's hope
vector <char *> & geolayers = *(vector <char *> *)(geoblock_off + off.geolayer_geoblock_offset);
// make sure we don't load crap
assert (geolayers.size() > 0 && geolayers.size() <= 16);
@ -949,7 +946,7 @@ bool Maps::ReadGeology (vector < vector <uint16_t> >& assign)
for (uint32_t j = 0;j < geolayers.size();j++)
{
// read pointer to a layer
uint32_t geol_offset = geolayers[j];
char * geol_offset = geolayers[j];
// read word at pointer + 2, store in our geology vectors
d->v_geology[i].push_back (p->readWord (geol_offset + off.type_inside_geolayer));
}

@ -35,12 +35,465 @@ using namespace std;
#include "modules/Materials.h"
#include "VersionInfo.h"
#include "MemAccess.h"
#include "Vector.h"
#include "Error.h"
#include "ModuleFactory.h"
#include "Core.h"
#include "MiscUtils.h"
#include "df/world.h"
#include "df/ui.h"
#include "df/item.h"
#include "df/inorganic_raw.h"
#include "df/plant_raw.h"
#include "df/plant_raw_flags.h"
#include "df/creature_raw.h"
#include "df/historical_figure.h"
#include "df/job_item.h"
#include "df/job_material_category.h"
#include "df/dfhack_material_category.h"
#include "df/matter_state.h"
#include "df/material_vec_ref.h"
using namespace DFHack;
using namespace df::enums;
bool MaterialInfo::decode(df::item *item)
{
if (!item)
return decode(-1);
else
return decode(item->getActualMaterial(), item->getActualMaterialIndex());
}
bool MaterialInfo::decode(const df::material_vec_ref &vr, int idx)
{
if (idx < 0 || idx >= vr.mat_type.size() || idx >= vr.mat_index.size())
return decode(-1);
else
return decode(vr.mat_type[idx], vr.mat_index[idx]);
}
bool MaterialInfo::decode(int16_t type, int32_t index)
{
this->type = type;
this->index = index;
material = NULL;
mode = Builtin; subtype = 0;
inorganic = NULL; plant = NULL; creature = NULL;
figure = NULL;
df::world_raws &raws = df::global::world->raws;
if (type < 0 || type >= sizeof(raws.mat_table.builtin)/sizeof(void*))
return false;
if (index < 0)
{
material = raws.mat_table.builtin[type];
}
else if (type == 0)
{
mode = Inorganic;
inorganic = df::inorganic_raw::find(index);
if (!inorganic)
return false;
material = &inorganic->material;
}
else if (type < CREATURE_BASE)
{
material = raws.mat_table.builtin[type];
}
else if (type < FIGURE_BASE)
{
mode = Creature;
subtype = type-CREATURE_BASE;
creature = df::creature_raw::find(index);
if (!creature || subtype >= creature->material.size())
return false;
material = creature->material[subtype];
}
else if (type < PLANT_BASE)
{
mode = Creature;
subtype = type-FIGURE_BASE;
figure = df::historical_figure::find(index);
if (!figure)
return false;
creature = df::creature_raw::find(figure->race);
if (!creature || subtype >= creature->material.size())
return false;
material = creature->material[subtype];
}
else if (type < END_BASE)
{
mode = Plant;
subtype = type-PLANT_BASE;
plant = df::plant_raw::find(index);
if (!plant || subtype >= plant->material.size())
return false;
material = plant->material[subtype];
}
else
{
material = raws.mat_table.builtin[type];
}
return (material != NULL);
}
bool MaterialInfo::find(const std::string &token)
{
std::vector<std::string> items;
split_string(&items, token, ":");
if (items[0] == "INORGANIC")
return findInorganic(vector_get(items,1));
if (items[0] == "CREATURE_MAT" || items[0] == "CREATURE")
return findCreature(vector_get(items,1), vector_get(items,2));
if (items[0] == "PLANT_MAT" || items[0] == "PLANT")
return findPlant(vector_get(items,1), vector_get(items,2));
if (items.size() == 1)
{
if (findBuiltin(items[0]))
return true;
if (findInorganic(items[0]))
return true;
if (findPlant(items[0], ""))
return true;
}
else if (items.size() == 2)
{
if (findPlant(items[0], items[1]))
return true;
if (findCreature(items[0], items[1]))
return true;
}
return false;
}
bool MaterialInfo::findBuiltin(const std::string &token)
{
if (token.empty())
return decode(-1);
if (token == "NONE") {
decode(-1);
return true;
}
df::world_raws &raws = df::global::world->raws;
for (int i = 1; i < NUM_BUILTIN; i++)
if (raws.mat_table.builtin[i]->id == token)
return decode(i, -1);
return decode(-1);
}
bool MaterialInfo::findInorganic(const std::string &token)
{
if (token.empty())
return decode(-1);
if (token == "NONE") {
decode(0, -1);
return true;
}
df::world_raws &raws = df::global::world->raws;
for (unsigned i = 0; i < raws.inorganics.size(); i++)
{
df::inorganic_raw *p = raws.inorganics[i];
if (p->id == token)
return decode(0, i);
}
return decode(-1);
}
bool MaterialInfo::findPlant(const std::string &token, const std::string &subtoken)
{
if (token.empty())
return decode(-1);
df::world_raws &raws = df::global::world->raws;
for (unsigned i = 0; i < raws.plants.all.size(); i++)
{
df::plant_raw *p = raws.plants.all[i];
if (p->id != token)
continue;
// As a special exception, return the structural material with empty subtoken
if (subtoken.empty())
return decode(p->material_defs.type_basic_mat, p->material_defs.idx_basic_mat);
for (unsigned j = 0; j < p->material.size(); j++)
if (p->material[j]->id == subtoken)
return decode(PLANT_BASE+j, i);
break;
}
return decode(-1);
}
bool MaterialInfo::findCreature(const std::string &token, const std::string &subtoken)
{
if (token.empty() || subtoken.empty())
return decode(-1);
df::world_raws &raws = df::global::world->raws;
for (unsigned i = 0; i < raws.creatures.all.size(); i++)
{
df::creature_raw *p = raws.creatures.all[i];
if (p->creature_id != token)
continue;
for (unsigned j = 0; j < p->material.size(); j++)
if (p->material[j]->id == subtoken)
return decode(CREATURE_BASE+j, i);
break;
}
return decode(-1);
}
std::string MaterialInfo::toString(uint16_t temp, bool named)
{
if (type == -1)
return "NONE";
if (!material)
return stl_sprintf("INVALID %d:%d", type, index);
df::matter_state state = matter_state::Solid;
if (temp >= material->heat.melting_point)
state = matter_state::Liquid;
if (temp >= material->heat.boiling_point)
state = matter_state::Gas;
std::string name = material->state_name[state];
if (!material->prefix.empty())
name = material->prefix + " " + name;
if (named && figure)
name += stl_sprintf(" of HF %d", index);
return name;
}
df::craft_material_class MaterialInfo::getCraftClass()
{
if (!material)
return craft_material_class::None;
if (type == 0 && index == -1)
return craft_material_class::Stone;
FOR_ENUM_ITEMS(material_flags, i)
{
df::craft_material_class ccv = ENUM_ATTR(material_flags, type, i);
if (ccv == craft_material_class::None)
continue;
if (material->flags.is_set(i))
return ccv;
}
return craft_material_class::None;
}
bool MaterialInfo::isAnyCloth()
{
using namespace df::enums::material_flags;
return material && (
material->flags.is_set(THREAD_PLANT) ||
material->flags.is_set(SILK) ||
material->flags.is_set(YARN)
);
}
bool MaterialInfo::matches(const df::job_material_category &cat)
{
if (!material)
return false;
#define TEST(bit,flag) if (cat.bits.bit && material->flags.is_set(flag)) return true;
using namespace df::enums::material_flags;
TEST(plant, STRUCTURAL_PLANT_MAT);
TEST(wood, WOOD);
TEST(cloth, THREAD_PLANT);
TEST(silk, SILK);
TEST(leather, LEATHER);
TEST(bone, BONE);
TEST(shell, SHELL);
TEST(wood2, WOOD);
TEST(soap, SOAP);
TEST(tooth, TOOTH);
TEST(horn, HORN);
TEST(pearl, PEARL);
TEST(yarn, YARN);
return false;
}
bool MaterialInfo::matches(const df::dfhack_material_category &cat)
{
if (!material)
return false;
df::job_material_category mc;
mc.whole = cat.whole;
if (matches(mc))
return true;
using namespace df::enums::material_flags;
using namespace df::enums::inorganic_flags;
TEST(metal, IS_METAL);
TEST(stone, IS_STONE);
if (cat.bits.stone && type == 0 && index == -1)
return true;
if (cat.bits.sand && inorganic && inorganic->flags.is_set(SOIL_SAND))
return true;
TEST(glass, IS_GLASS);
if (cat.bits.clay && linear_index(material->reaction_product.id, std::string("FIRED_MAT")) >= 0)
return true;
return false;
}
#undef TEST
bool MaterialInfo::matches(const df::job_item &item)
{
if (!isValid()) return false;
df::job_item_flags1 ok1, mask1;
getMatchBits(ok1, mask1);
df::job_item_flags2 ok2, mask2;
getMatchBits(ok2, mask2);
df::job_item_flags3 ok3, mask3;
getMatchBits(ok3, mask3);
return bits_match(item.flags1.whole, ok1.whole, mask1.whole) &&
bits_match(item.flags2.whole, ok2.whole, mask2.whole) &&
bits_match(item.flags3.whole, ok3.whole, mask3.whole);
}
void MaterialInfo::getMatchBits(df::job_item_flags1 &ok, df::job_item_flags1 &mask)
{
ok.whole = mask.whole = 0;
if (!isValid()) return;
#define MAT_FLAG(name) material->flags.is_set(df::enums::material_flags::name)
#define FLAG(field, name) (field && field->flags.is_set(name))
#define TEST(bit, check) \
mask.bits.bit = true; ok.bits.bit = !!(check);
bool structural = MAT_FLAG(STRUCTURAL_PLANT_MAT);
TEST(millable, structural && FLAG(plant, plant_raw_flags::MILL));
TEST(sharpenable, MAT_FLAG(IS_STONE));
TEST(distillable, structural && FLAG(plant, plant_raw_flags::DRINK));
TEST(processable, structural && FLAG(plant, plant_raw_flags::THREAD));
TEST(bag, isAnyCloth() || MAT_FLAG(LEATHER));
TEST(cookable, MAT_FLAG(EDIBLE_COOKED));
TEST(extract_bearing_plant, structural && FLAG(plant, plant_raw_flags::EXTRACT_STILL_VIAL));
TEST(extract_bearing_fish, false);
TEST(extract_bearing_vermin, false);
TEST(processable_to_vial, structural && FLAG(plant, plant_raw_flags::EXTRACT_VIAL));
TEST(processable_to_bag, structural && FLAG(plant, plant_raw_flags::LEAVES));
TEST(processable_to_barrel, structural && FLAG(plant, plant_raw_flags::EXTRACT_BARREL));
TEST(solid, !(MAT_FLAG(ALCOHOL_PLANT) ||
MAT_FLAG(ALCOHOL_CREATURE) ||
MAT_FLAG(LIQUID_MISC_PLANT) ||
MAT_FLAG(LIQUID_MISC_CREATURE) ||
MAT_FLAG(LIQUID_MISC_OTHER)));
TEST(tameable_vermin, false);
TEST(sharpenable, MAT_FLAG(IS_STONE));
TEST(milk, linear_index(material->reaction_product.id, std::string("CHEESE_MAT")) >= 0);
//04000000 - "milkable" - vtable[107],1,1
}
void MaterialInfo::getMatchBits(df::job_item_flags2 &ok, df::job_item_flags2 &mask)
{
ok.whole = mask.whole = 0;
if (!isValid()) return;
bool is_cloth = isAnyCloth();
TEST(dye, MAT_FLAG(IS_DYE));
TEST(dyeable, is_cloth);
TEST(dyed, is_cloth);
TEST(sewn_imageless, is_cloth);
TEST(glass_making, MAT_FLAG(CRYSTAL_GLASSABLE));
TEST(fire_safe, material->heat.melting_point > 11000);
TEST(magma_safe, material->heat.melting_point > 12000);
TEST(deep_material, FLAG(inorganic, df::enums::inorganic_flags::DEEP_ANY));
TEST(non_economic, inorganic && !(df::global::ui && df::global::ui->economic_stone[index]));
TEST(plant, plant);
TEST(silk, MAT_FLAG(SILK));
TEST(leather, MAT_FLAG(LEATHER));
TEST(bone, MAT_FLAG(BONE));
TEST(shell, MAT_FLAG(SHELL));
TEST(totemable, false);
TEST(horn, MAT_FLAG(HORN));
TEST(pearl, MAT_FLAG(PEARL));
TEST(soap, MAT_FLAG(SOAP));
TEST(ivory_tooth, MAT_FLAG(TOOTH));
//TEST(hair_wool, MAT_FLAG(YARN));
TEST(yarn, MAT_FLAG(YARN));
}
void MaterialInfo::getMatchBits(df::job_item_flags3 &ok, df::job_item_flags3 &mask)
{
ok.whole = mask.whole = 0;
if (!isValid()) return;
TEST(hard, MAT_FLAG(ITEMS_HARD));
}
#undef MAT_FLAG
#undef FLAG
#undef TEST
bool DFHack::parseJobMaterialCategory(df::job_material_category *cat, const std::string &token)
{
cat->whole = 0;
std::vector<std::string> items;
split_string(&items, toLower(token), ",", true);
for (unsigned i = 0; i < items.size(); i++)
{
int id = findBitfieldField(*cat, items[i]);
if (id < 0)
return false;
cat->whole |= (1 << id);
}
return true;
}
bool DFHack::parseJobMaterialCategory(df::dfhack_material_category *cat, const std::string &token)
{
cat->whole = 0;
std::vector<std::string> items;
split_string(&items, toLower(token), ",", true);
for (unsigned i = 0; i < items.size(); i++)
{
int id = findBitfieldField(*cat, items[i]);
if (id < 0)
return false;
cat->whole |= (1 << id);
}
return true;
}
Module* DFHack::createMaterials()
{
@ -52,8 +505,8 @@ class Materials::Private
public:
Process * owner;
OffsetGroup * OG_Materials;
uint32_t vector_races;
uint32_t vector_other;
void * vector_races;
void * vector_other;
};
Materials::Materials()
@ -67,10 +520,10 @@ Materials::Materials()
df_inorganic = 0;
OffsetGroup *OG_Materials = d->OG_Materials = c.vinfo->getGroup("Materials");
{
OG_Materials->getSafeAddress("inorganics",(uint32_t &)df_inorganic);
OG_Materials->getSafeAddress("organics_all",(uint32_t &)df_organic);
OG_Materials->getSafeAddress("organics_plants",(uint32_t &)df_plants);
OG_Materials->getSafeAddress("organics_trees",(uint32_t &)df_trees);
OG_Materials->getSafeAddress("inorganics",(void * &)df_inorganic);
OG_Materials->getSafeAddress("organics_all",(void * &)df_organic);
OG_Materials->getSafeAddress("organics_plants",(void * &)df_plants);
OG_Materials->getSafeAddress("organics_trees",(void * &)df_trees);
d->vector_races = OG_Materials->getAddress("creature_type_vector");
}
}
@ -111,16 +564,16 @@ bool t_matglossInorganic::isGem()
}
// good for now
inline bool ReadNamesOnly(Process* p, uint32_t address, vector<t_matgloss> & names)
inline bool ReadNamesOnly(Process* p, void * address, vector<t_matgloss> & names)
{
DfVector <uint32_t> p_matgloss (address);
uint32_t size = p_matgloss.size();
vector <string *> * p_names = (vector <string *> *) address;
uint32_t size = p_names->size();
names.clear();
names.reserve (size);
for (uint32_t i = 0; i < size;i++)
{
t_matgloss mat;
mat.id = *(std::string *)p_matgloss[i];
mat.id = *p_names->at(i);
names.push_back(mat);
}
return true;
@ -159,21 +612,21 @@ bool Materials::CopyInorganicMaterials (std::vector<t_matglossInorganic> & inorg
bool Materials::CopyOrganicMaterials (std::vector<t_matgloss> & organic)
{
if(df_organic)
return ReadNamesOnly(d->owner, (uint32_t) df_organic, organic );
return ReadNamesOnly(d->owner, (void *) df_organic, organic );
else return false;
}
bool Materials::CopyWoodMaterials (std::vector<t_matgloss> & tree)
{
if(df_trees)
return ReadNamesOnly(d->owner, (uint32_t) df_trees, tree );
return ReadNamesOnly(d->owner, (void *) df_trees, tree );
else return false;
}
bool Materials::CopyPlantMaterials (std::vector<t_matgloss> & plant)
{
if(df_plants)
return ReadNamesOnly(d->owner, (uint32_t) df_plants, plant );
return ReadNamesOnly(d->owner, (void *) df_plants, plant );
else return false;
}
@ -185,7 +638,7 @@ bool Materials::ReadCreatureTypes (void)
bool Materials::ReadOthers(void)
{
Process * p = d->owner;
uint32_t matBase = d->OG_Materials->getAddress ("other");
char * matBase = d->OG_Materials->getAddress ("other");
uint32_t i = 0;
std::string * ptr;
@ -194,7 +647,7 @@ bool Materials::ReadOthers(void)
while(1)
{
t_matglossOther mat;
ptr = (std::string *) p->readDWord(matBase + i*4);
ptr = (std::string *) p->readPtr(matBase + i*4);
if(ptr==0)
break;
mat.id = *ptr;
@ -208,7 +661,7 @@ bool Materials::ReadDescriptorColors (void)
{
Process * p = d->owner;
OffsetGroup * OG_Descriptors = p->getDescriptor()->getGroup("Materials")->getGroup("descriptors");
DfVector <uint32_t> p_colors (OG_Descriptors->getAddress ("colors_vector"));
vector <char *> & p_colors = *(vector<char*> *) OG_Descriptors->getAddress ("colors_vector");
uint32_t size = p_colors.size();
color.clear();
@ -237,7 +690,7 @@ bool Materials::ReadCreatureTypesEx (void)
uint32_t sizeof_string = OG_string->getHexValue ("sizeof");
OffsetGroup * OG_Mats = mem->getGroup("Materials");
DfVector <uint32_t> p_races (OG_Mats->getAddress ("creature_type_vector"));
vector <char *> & p_races = *(vector<char*> *) OG_Mats->getAddress ("creature_type_vector");
OffsetGroup * OG_Creature = OG_Mats->getGroup("creature");
uint32_t castes_vector_offset = OG_Creature->getOffset ("caste_vector");
@ -287,13 +740,13 @@ bool Materials::ReadCreatureTypesEx (void)
mat.tilecolor.back = p->readWord( p_races[i] + tile_color_offset + 2 );
mat.tilecolor.bright = p->readWord( p_races[i] + tile_color_offset + 4 );
DfVector <uint32_t> p_castes(p_races[i] + castes_vector_offset);
vector <char *> & p_castes = *(vector<char*> *) (p_races[i] + castes_vector_offset);
sizecas = p_castes.size();
for (uint32_t j = 0; j < sizecas;j++)
{
/* caste name */
t_creaturecaste caste;
uint32_t caste_start = p_castes[j];
char * caste_start = p_castes[j];
caste.id = p->readSTLString (caste_start);
caste.singular = p->readSTLString (caste_start + sizeof_string);
caste.plural = p->readSTLString (caste_start + 2 * sizeof_string);
@ -303,13 +756,13 @@ bool Materials::ReadCreatureTypesEx (void)
{
/* color mod reading */
// Caste + offset > color mod vector
DfVector <uint32_t> p_colormod(caste_start + caste_colormod_offset);
vector <char *> & p_colormod = *(vector<char*> *) (caste_start + caste_colormod_offset);
sizecolormod = p_colormod.size();
caste.ColorModifier.resize(sizecolormod);
for(uint32_t k = 0; k < sizecolormod;k++)
{
// color mod [0] -> color list
DfVector <uint32_t> p_colorlist(p_colormod[k]);
vector <uint32_t> & p_colorlist = *(vector<uint32_t> *) (p_colormod[k]);
sizecolorlist = p_colorlist.size();
caste.ColorModifier[k].colorlist.resize(sizecolorlist);
for(uint32_t l = 0; l < sizecolorlist; l++)
@ -320,7 +773,7 @@ bool Materials::ReadCreatureTypesEx (void)
caste.ColorModifier[k].enddate = p->readDWord( p_colormod[k] + color_modifier_enddate_offset );
}
/* body parts */
DfVector <uint32_t> p_bodypart(caste_start + caste_bodypart_offset);
vector <char *> & p_bodypart = *(vector<char*> *) (caste_start + caste_bodypart_offset);
caste.bodypart.empty();
sizebp = p_bodypart.size();
for(uint32_t k = 0; k < sizebp; k++)
@ -338,7 +791,7 @@ bool Materials::ReadCreatureTypesEx (void)
}
mat.castes.push_back(caste);
}
DfVector <uint32_t> p_extract(p_races[i] + extract_vector_offset);
vector <void *> & p_extract = *(vector<void*> *) (p_races[i] + extract_vector_offset);
for(uint32_t j = 0; j < p_extract.size(); j++)
{
t_creatureextract extract;

@ -33,7 +33,6 @@ using namespace std;
#include "modules/Translation.h"
#include "VersionInfo.h"
#include "MemAccess.h"
#include "Vector.h"
#include "Types.h"
#include "ModuleFactory.h"
#include "Core.h"
@ -46,8 +45,8 @@ Module* DFHack::createTranslation()
struct Translation::Private
{
uint32_t genericAddress;
uint32_t transAddress;
void * genericAddress;
void * transAddress;
uint32_t word_table_offset;
uint32_t sizeof_string;
@ -97,15 +96,15 @@ bool Translation::Start()
return false;
Process * p = c.p;
Finish();
DfVector <uint32_t> genericVec (d->genericAddress);
DfVector <uint32_t> transVec (d->transAddress);
vector <char *> & genericVec = *(vector <char *> *) d->genericAddress;
vector <char *> & transVec = *(vector <char *> *) d->transAddress;
DFDict & translations = d->dicts.translations;
DFDict & foreign_languages = d->dicts.foreign_languages;
translations.resize(10);
for (uint32_t i = 0;i < genericVec.size();i++)
{
uint32_t genericNamePtr = genericVec.at(i);
char * genericNamePtr = genericVec[i];
for(int j=0; j<10;j++)
{
string word = p->readSTLString (genericNamePtr + j * d->sizeof_string);
@ -116,11 +115,11 @@ bool Translation::Start()
foreign_languages.resize(transVec.size());
for (uint32_t i = 0; i < transVec.size();i++)
{
uint32_t transPtr = transVec.at(i);
DfVector <uint32_t> trans_names_vec (transPtr + d->word_table_offset);
char * transPtr = transVec.at(i);
vector <void *> & trans_names_vec = *(vector <void *> *) (transPtr + d->word_table_offset);
for (uint32_t j = 0;j < trans_names_vec.size();j++)
{
uint32_t transNamePtr = trans_names_vec.at(j);
void * transNamePtr = trans_names_vec[j];
string name = p->readSTLString (transNamePtr);
foreign_languages[i].push_back (name);
}
@ -191,8 +190,6 @@ bool Translation::readName(t_name & name, df_name * source)
bool Translation::copyName(df_name * source, df_name * target)
{
uint8_t buf[28];
if (source == target)
return true;
Core & c = Core::getInstance();

@ -36,7 +36,6 @@ using namespace std;
#include "VersionInfo.h"
#include "MemAccess.h"
#include "Vector.h"
#include "Error.h"
#include "Types.h"
@ -54,8 +53,8 @@ struct Units::Private
bool Inited;
bool Started;
uint32_t dwarf_race_index_addr;
uint32_t dwarf_civ_id_addr;
void * dwarf_race_index_addr;
void * dwarf_civ_id_addr;
bool IdMapReady;
std::map<int32_t, int32_t> IdMap;
@ -86,8 +85,8 @@ Units::Units()
try
{
creatures = (vector <df_unit *> *) OG_Creatures->getAddress ("vector");
d->dwarf_race_index_addr = OG_Creatures->getAddress("current_race");
d->dwarf_civ_id_addr = OG_Creatures->getAddress("current_civ");
d->dwarf_race_index_addr = (void *) OG_Creatures->getAddress("current_race");
d->dwarf_civ_id_addr = (void *) OG_Creatures->getAddress("current_civ");
}
catch(Error::All&){};
d->Inited = true;
@ -137,7 +136,6 @@ int32_t Units::GetCreatureInBox (int32_t index, df_unit ** furball,
return -1;
Process *p = d->owner;
uint16_t coords[3];
uint32_t size = creatures->size();
while (uint32_t(index) < size)
{
@ -551,7 +549,7 @@ bool Creatures::ReadJob(const t_creature * furball, vector<t_material> & mat)
return true;
}
*/
bool Units::ReadInventoryByIdx(const uint32_t index, std::vector<df_item *> & item)
bool Units::ReadInventoryByIdx(const uint32_t index, std::vector<df::item *> & item)
{
if(!d->Started) return false;
if(index >= creatures->size()) return false;
@ -559,7 +557,7 @@ bool Units::ReadInventoryByIdx(const uint32_t index, std::vector<df_item *> & it
return this->ReadInventoryByPtr(temp, item);
}
bool Units::ReadInventoryByPtr(const df_unit * temp, std::vector<df_item *> & items)
bool Units::ReadInventoryByPtr(const df_unit * temp, std::vector<df::item *> & items)
{
if(!d->Started) return false;
items = temp->inventory;
@ -576,7 +574,6 @@ bool Units::ReadOwnedItemsByIdx(const uint32_t index, std::vector<int32_t> & ite
bool Units::ReadOwnedItemsByPtr(const df_unit * temp, std::vector<int32_t> & items)
{
unsigned int i;
if(!d->Started) return false;
items = temp->owned_items;
return true;

@ -32,7 +32,6 @@ using namespace std;
#include "VersionInfo.h"
#include "MemAccess.h"
#include "Vector.h"
#include "Types.h"
#include "modules/Vegetation.h"
#include "modules/Translation.h"

@ -37,150 +37,48 @@ using namespace std;
#include "ModuleFactory.h"
#include "Core.h"
using namespace DFHack;
using namespace DFHack::Simple;
struct Vermin::Private
{
uint32_t spawn_points_vector;
uint32_t race_offset;
uint32_t type_offset;
uint32_t position_offset;
uint32_t in_use_offset;
uint32_t unknown_offset;
uint32_t countdown_offset;
Process * owner;
bool Inited;
bool Started;
};
Module* DFHack::createVermin()
{
return new Vermin();
}
#include <stdio.h>
Vermin::Vermin()
{
Core & c = Core::getInstance();
d = new Private;
d->owner = c.p;
d->Inited = d->Started = false;
VersionInfo * mem = c.vinfo;
OffsetGroup * OG_vermin = mem->getGroup("Vermin");
OffsetGroup * OG_spawn = OG_vermin->getGroup("Spawn Points");
d->Inited = true;
try
{
d->spawn_points_vector = OG_spawn->getAddress("vector");
d->race_offset = OG_spawn->getOffset("race");
d->type_offset = OG_spawn->getOffset("type");
d->position_offset = OG_spawn->getOffset("position");
d->in_use_offset = OG_spawn->getOffset("in_use");
d->unknown_offset = OG_spawn->getOffset("unknown");
d->countdown_offset = OG_spawn->getOffset("countdown");
}
catch(DFHack::Error::AllMemdef &e)
{
cerr << "Vermin not available... " << e.what() << endl;
d->Inited = false;
}
}
bool Vermin::Finish()
{
return true;
}
Vermin::~Vermin()
{
delete d;
}
// NOTE: caller must call delete on result when done.
SpawnPoints* Vermin::getSpawnPoints()
{
if (!d->Inited)
{
cerr << "Couldn't get spawn points: Vermin module not inited" << endl;
return NULL;
}
return new SpawnPoints(this);
}
SpawnPoints::SpawnPoints(Vermin* v_)
{
v = v_;
p_sp = NULL;
if (!v->d->Inited)
{
cerr << "Couldn't get spawn points: Vermin module not inited" << endl;
return;
}
p_sp = (vector <void*>*) (v->d->spawn_points_vector);
}
SpawnPoints::~SpawnPoints()
{
}
#include "DataDefs.h"
#include "df/world.h"
#include "df/vermin.h"
using namespace df::enums;
using df::global::world;
size_t SpawnPoints::size()
uint32_t Vermin::getNumVermin()
{
if (!isValid())
return 0;
return p_sp->size();
return df::vermin::get_vector().size();
}
bool SpawnPoints::Read (const uint32_t index, t_spawnPoint & sp)
bool Vermin::Read (const uint32_t index, t_vermin & sp)
{
if(!isValid())
return false;
// read pointer from vector at position
uint32_t temp = (uint32_t) p_sp->at (index);
sp.origin = temp;
sp.race = v->d->owner->readWord(temp + v->d->race_offset);
sp.type = v->d->owner->readWord(temp + v->d->type_offset);
sp.in_use = v->d->owner->readByte(temp + v->d->in_use_offset);
sp.unknown = v->d->owner->readByte(temp + v->d->unknown_offset);
sp.countdown = v->d->owner->readDWord(temp + v->d->countdown_offset);
// Three consecutive 16 bit numbers for x/y/z
v->d->owner->read(temp + v->d->position_offset, 6, (uint8_t*) &sp.x);
df::vermin *verm = df::vermin::find(index);
if (!verm) return false;
sp.origin = verm;
sp.race = verm->race;
sp.caste = verm->caste;
sp.visible = verm->visible;
sp.countdown = verm->countdown;
sp.x = verm->pos.x;
sp.y = verm->pos.y;
sp.z = verm->pos.z;
sp.is_colony = verm->flags.bits.is_colony;
return true;
}
bool SpawnPoints::Write (const uint32_t index, t_spawnPoint & sp)
bool Vermin::Write (const uint32_t index, t_vermin & sp)
{
if(!isValid())
return false;
// read pointer from vector at position
uint32_t temp = (uint32_t) p_sp->at (index);
v->d->owner->writeWord(temp + v->d->race_offset, sp.race);
v->d->owner->writeWord(temp + v->d->type_offset, sp.type);
v->d->owner->writeByte(temp + v->d->in_use_offset, sp.in_use);
v->d->owner->writeByte(temp + v->d->unknown_offset, sp.unknown);
v->d->owner->writeDWord(temp + v->d->countdown_offset, sp.countdown);
// Three consecutive 16 bit numbers for x/y/z
v->d->owner->write(temp + v->d->position_offset, 6, (uint8_t*) &sp.x);
df::vermin *verm = df::vermin::find(index);
if (!verm) return false;
verm->race = sp.race;
verm->caste = sp.caste;
verm->visible = sp.visible;
verm->countdown = sp.countdown;
verm->pos.x = sp.x;
verm->pos.y = sp.y;
verm->pos.z = sp.z;
verm->flags.bits.is_colony = sp.is_colony;
return true;
}
bool SpawnPoints::isWildColony(t_spawnPoint & point)
{
return (point.type == TYPE_WILD_COLONY);
}
bool SpawnPoints::isValid()
{
return (v != NULL && v->d->Inited && p_sp != NULL);
}

@ -38,6 +38,12 @@ using namespace std;
#include "ModuleFactory.h"
#include "Core.h"
#include "MiscUtils.h"
#include "DataDefs.h"
#include "df/world.h"
#include "df/historical_figure.h"
using namespace DFHack;
Module* DFHack::createWorld()
@ -54,22 +60,22 @@ struct World::Private
bool Inited;
bool PauseInited;
uint32_t pause_state_offset;
void * pause_state_offset;
bool StartedTime;
uint32_t year_offset;
uint32_t tick_offset;
void * year_offset;
void * tick_offset;
bool StartedWeather;
uint32_t weather_offset;
char * weather_offset;
bool StartedMode;
uint32_t gamemode_offset;
uint32_t controlmode_offset;
uint32_t controlmodecopy_offset;
void * gamemode_offset;
void * controlmode_offset;
void * controlmodecopy_offset;
bool StartedFolder;
uint32_t folder_name_offset;
void * folder_name_offset;
Process * owner;
};
@ -241,3 +247,71 @@ string World::ReadWorldFolder()
}
return string("");
}
static PersistentDataItem dataFromHFig(df::historical_figure *hfig)
{
return PersistentDataItem(hfig->id, hfig->name.first_name, &hfig->name.nickname, hfig->name.words);
}
PersistentDataItem World::AddPersistentData(const std::string &key)
{
std::vector<df::historical_figure*> &hfvec = df::historical_figure::get_vector();
int new_id = -100;
if (hfvec.size() > 0 && hfvec[0]->id <= new_id)
new_id = hfvec[0]->id-1;
df::historical_figure *hfig = new df::historical_figure();
hfig->id = new_id;
hfig->name.has_name = true;
hfig->name.first_name = key;
memset(hfig->name.words, 0xFF, sizeof(hfig->name.words));
hfvec.insert(hfvec.begin(), hfig);
return dataFromHFig(hfig);
}
PersistentDataItem World::GetPersistentData(const std::string &key)
{
std::vector<df::historical_figure*> &hfvec = df::historical_figure::get_vector();
for (unsigned i = 0; i < hfvec.size(); i++)
{
df::historical_figure *hfig = hfvec[i];
if (hfig->id >= 0)
break;
if (hfig->name.has_name && hfig->name.first_name == key)
return dataFromHFig(hfig);
}
return PersistentDataItem();
}
void World::GetPersistentData(std::vector<PersistentDataItem> *vec, const std::string &key)
{
std::vector<df::historical_figure*> &hfvec = df::historical_figure::get_vector();
for (unsigned i = 0; i < hfvec.size(); i++)
{
df::historical_figure *hfig = hfvec[i];
if (hfig->id >= 0)
break;
if (hfig->name.has_name && hfig->name.first_name == key)
vec->push_back(dataFromHFig(hfig));
}
}
void World::DeletePersistentData(const PersistentDataItem &item)
{
if (item.id > -100)
return;
std::vector<df::historical_figure*> &hfvec = df::historical_figure::get_vector();
int idx = binsearch_index(hfvec, item.id);
if (idx >= 0) {
delete hfvec[idx];
hfvec.erase(hfvec.begin()+idx);
}
}

@ -9,78 +9,45 @@
#include <set>
using namespace std;
#include "Types.h"
#include "VersionInfo.h"
#include "MemAccess.h"
#include "Vector.h"
#include "modules/Materials.h"
#include "modules/Items.h"
#include "modules/Units.h"
#include "Types.h"
#include "Error.h"
#include "modules/kitchen.h"
#include "ModuleFactory.h"
#include "Core.h"
#include "Virtual.h"
using namespace DFHack;
using namespace DFHack::Simple;
namespace DFHack
{
namespace Kitchen
{
class Exclusions::Private
{
public:
Private (DFHack::Core& core_)
: core(core_)
, itemTypes (*((std::vector<t_itemType >*)(addr(core_,0))))
, itemSubtypes (*((std::vector<t_itemSubtype >*)(addr(core_,1))))
, materialTypes (*((std::vector<t_materialType >*)(addr(core_,2))))
, materialIndices (*((std::vector<t_materialIndex>*)(addr(core_,3))))
, exclusionTypes (*((std::vector<t_exclusionType>*)(addr(core_,4))))
{
};
DFHack::Core& core;
std::vector<t_itemType>& itemTypes; // the item types vector of the kitchen exclusion list
std::vector<t_itemSubtype>& itemSubtypes; // the item subtype vector of the kitchen exclusion list
std::vector<t_materialType>& materialTypes; // the material subindex vector of the kitchen exclusion list
std::vector<t_materialIndex>& materialIndices; // the material index vector of the kitchen exclusion list
std::vector<t_exclusionType>& exclusionTypes; // the exclusion type vector of the kitchen excluions list
#include "DataDefs.h"
#include "df/world.h"
#include "df/ui.h"
#include "df/item_type.h"
#include "df/plant_raw.h"
static uint32_t addr(const DFHack::Core& core, int index)
{
static uint32_t start = core.vinfo->getAddress("kitchen_limits");
return start + sizeof(std::vector<int>) * index;
};
};
using namespace df::enums;
using df::global::world;
using df::global::ui;
Exclusions::Exclusions(Core & c)
void Kitchen::debug_print(Core &core)
{
d = new Private(c);
};
Exclusions::~Exclusions()
{
delete d;
};
void Exclusions::debug_print() const
{
d->core.con.print("Kitchen Exclusions\n");
Materials& materialsModule= *d->core.getMaterials();
core.con.print("Kitchen Exclusions\n");
for(std::size_t i = 0; i < size(); ++i)
{
d->core.con.print("%2u: IT:%2i IS:%i MT:%3i MI:%2i ET:%i %s\n",
core.con.print("%2u: IT:%2i IS:%i MT:%3i MI:%2i ET:%i %s\n",
i,
d->itemTypes[i],
d->itemSubtypes[i],
d->materialTypes[i],
d->materialIndices[i],
d->exclusionTypes[i],
materialsModule.df_organic->at(d->materialIndices[i])->ID.c_str()
ui->kitchen.item_types[i],
ui->kitchen.item_subtypes[i],
ui->kitchen.mat_types[i],
ui->kitchen.mat_indices[i],
ui->kitchen.exc_types[i],
(ui->kitchen.mat_types[i] >= 419 && ui->kitchen.mat_types[i] <= 618) ? world->raws.plants.all[ui->kitchen.mat_indices[i]]->id.c_str() : "n/a"
);
}
d->core.con.print("\n");
core.con.print("\n");
}
void Exclusions::allowPlantSeedCookery(t_materialIndex materialIndex)
void Kitchen::allowPlantSeedCookery(t_materialIndex materialIndex)
{
bool match = false;
do
@ -89,9 +56,9 @@ namespace Kitchen
std::size_t matchIndex = 0;
for(std::size_t i = 0; i < size(); ++i)
{
if(d->materialIndices[i] == materialIndex
&& (d->itemTypes[i] == DFHack::Items::SEEDS || d->itemTypes[i] == DFHack::Items::PLANT)
&& d->exclusionTypes[i] == cookingExclusion
if(ui->kitchen.mat_indices[i] == materialIndex
&& (ui->kitchen.item_types[i] == df::item_type::SEEDS || ui->kitchen.item_types[i] == df::item_type::PLANT)
&& ui->kitchen.exc_types[i] == cookingExclusion
)
{
match = true;
@ -100,63 +67,62 @@ namespace Kitchen
}
if(match)
{
d->itemTypes.erase(d->itemTypes.begin() + matchIndex);
d->itemSubtypes.erase(d->itemSubtypes.begin() + matchIndex);
d->materialIndices.erase(d->materialIndices.begin() + matchIndex);
d->materialTypes.erase(d->materialTypes.begin() + matchIndex);
d->exclusionTypes.erase(d->exclusionTypes.begin() + matchIndex);
ui->kitchen.item_types.erase(ui->kitchen.item_types.begin() + matchIndex);
ui->kitchen.item_subtypes.erase(ui->kitchen.item_subtypes.begin() + matchIndex);
ui->kitchen.mat_indices.erase(ui->kitchen.mat_indices.begin() + matchIndex);
ui->kitchen.mat_types.erase(ui->kitchen.mat_types.begin() + matchIndex);
ui->kitchen.exc_types.erase(ui->kitchen.exc_types.begin() + matchIndex);
}
} while(match);
};
void Exclusions::denyPlantSeedCookery(t_materialIndex materialIndex)
void Kitchen::denyPlantSeedCookery(t_materialIndex materialIndex)
{
Materials *mats = d->core.getMaterials();
df_plant_type *type = mats->df_organic->at(materialIndex);
df::plant_raw *type = world->raws.plants.all[materialIndex];
bool SeedAlreadyIn = false;
bool PlantAlreadyIn = false;
for(std::size_t i = 0; i < size(); ++i)
{
if(d->materialIndices[i] == materialIndex
&& d->exclusionTypes[i] == cookingExclusion)
if(ui->kitchen.mat_indices[i] == materialIndex
&& ui->kitchen.exc_types[i] == cookingExclusion)
{
if(d->itemTypes[i] == DFHack::Items::SEEDS)
if(ui->kitchen.item_types[i] == df::item_type::SEEDS)
SeedAlreadyIn = true;
else if (d->itemTypes[i] == DFHack::Items::PLANT)
else if (ui->kitchen.item_types[i] == df::item_type::PLANT)
PlantAlreadyIn = true;
}
}
if(!SeedAlreadyIn)
{
d->itemTypes.push_back(DFHack::Items::SEEDS);
d->itemSubtypes.push_back(organicSubtype);
d->materialTypes.push_back(type->material_type_seed);
d->materialIndices.push_back(materialIndex);
d->exclusionTypes.push_back(cookingExclusion);
ui->kitchen.item_types.push_back(df::item_type::SEEDS);
ui->kitchen.item_subtypes.push_back(organicSubtype);
ui->kitchen.mat_types.push_back(type->material_defs.type_seed);
ui->kitchen.mat_indices.push_back(materialIndex);
ui->kitchen.exc_types.push_back(cookingExclusion);
}
if(!PlantAlreadyIn)
{
d->itemTypes.push_back(DFHack::Items::PLANT);
d->itemSubtypes.push_back(organicSubtype);
d->materialTypes.push_back(type->material_type_basic_mat);
d->materialIndices.push_back(materialIndex);
d->exclusionTypes.push_back(cookingExclusion);
ui->kitchen.item_types.push_back(df::item_type::PLANT);
ui->kitchen.item_subtypes.push_back(organicSubtype);
ui->kitchen.mat_types.push_back(type->material_defs.type_basic_mat);
ui->kitchen.mat_indices.push_back(materialIndex);
ui->kitchen.exc_types.push_back(cookingExclusion);
}
};
void Exclusions::fillWatchMap(std::map<t_materialIndex, unsigned int>& watchMap) const
void Kitchen::fillWatchMap(std::map<t_materialIndex, unsigned int>& watchMap)
{
watchMap.clear();
for(std::size_t i = 0; i < size(); ++i)
{
if(d->itemTypes[i] == limitType && d->itemSubtypes[i] == limitSubtype && d->exclusionTypes[i] == limitExclusion)
if(ui->kitchen.item_subtypes[i] == limitType && ui->kitchen.item_subtypes[i] == limitSubtype && ui->kitchen.exc_types[i] == limitExclusion)
{
watchMap[d->materialIndices[i]] = (unsigned int) d->materialTypes[i];
watchMap[ui->kitchen.mat_indices[i]] = (unsigned int) ui->kitchen.mat_types[i];
}
}
};
void Exclusions::removeLimit(t_materialIndex materialIndex)
void Kitchen::removeLimit(t_materialIndex materialIndex)
{
bool match = false;
do
@ -165,10 +131,10 @@ namespace Kitchen
std::size_t matchIndex = 0;
for(std::size_t i = 0; i < size(); ++i)
{
if(d->itemTypes[i] == limitType
&& d->itemSubtypes[i] == limitSubtype
&& d->materialIndices[i] == materialIndex
&& d->exclusionTypes[i] == limitExclusion)
if(ui->kitchen.item_types[i] == limitType
&& ui->kitchen.item_subtypes[i] == limitSubtype
&& ui->kitchen.mat_indices[i] == materialIndex
&& ui->kitchen.exc_types[i] == limitExclusion)
{
match = true;
matchIndex = i;
@ -176,30 +142,30 @@ namespace Kitchen
}
if(match)
{
d->itemTypes.erase(d->itemTypes.begin() + matchIndex);
d->itemSubtypes.erase(d->itemSubtypes.begin() + matchIndex);
d->materialTypes.erase(d->materialTypes.begin() + matchIndex);
d->materialIndices.erase(d->materialIndices.begin() + matchIndex);
d->exclusionTypes.erase(d->exclusionTypes.begin() + matchIndex);
ui->kitchen.item_types.erase(ui->kitchen.item_types.begin() + matchIndex);
ui->kitchen.item_subtypes.erase(ui->kitchen.item_subtypes.begin() + matchIndex);
ui->kitchen.mat_types.erase(ui->kitchen.mat_types.begin() + matchIndex);
ui->kitchen.mat_indices.erase(ui->kitchen.mat_indices.begin() + matchIndex);
ui->kitchen.exc_types.erase(ui->kitchen.exc_types.begin() + matchIndex);
}
} while(match);
};
void Exclusions::setLimit(t_materialIndex materialIndex, unsigned int limit)
void Kitchen::setLimit(t_materialIndex materialIndex, unsigned int limit)
{
removeLimit(materialIndex);
if(limit > seedLimit)
{
limit = seedLimit;
}
d->itemTypes.push_back(limitType);
d->itemSubtypes.push_back(limitSubtype);
d->materialIndices.push_back(materialIndex);
d->materialTypes.push_back((t_materialType) (limit < seedLimit) ? limit : seedLimit);
d->exclusionTypes.push_back(limitExclusion);
ui->kitchen.item_types.push_back(limitType);
ui->kitchen.item_subtypes.push_back(limitSubtype);
ui->kitchen.mat_indices.push_back(materialIndex);
ui->kitchen.mat_types.push_back((t_materialType) (limit < seedLimit) ? limit : seedLimit);
ui->kitchen.exc_types.push_back(limitExclusion);
};
void Exclusions::clearLimits()
void Kitchen::clearLimits()
{
bool match = false;
do
@ -208,9 +174,9 @@ namespace Kitchen
std::size_t matchIndex;
for(std::size_t i = 0; i < size(); ++i)
{
if(d->itemTypes[i] == limitType
&& d->itemSubtypes[i] == limitSubtype
&& d->exclusionTypes[i] == limitExclusion)
if(ui->kitchen.item_types[i] == limitType
&& ui->kitchen.item_subtypes[i] == limitSubtype
&& ui->kitchen.exc_types[i] == limitExclusion)
{
match = true;
matchIndex = i;
@ -218,17 +184,16 @@ namespace Kitchen
}
if(match)
{
d->itemTypes.erase(d->itemTypes.begin() + matchIndex);
d->itemSubtypes.erase(d->itemSubtypes.begin() + matchIndex);
d->materialIndices.erase(d->materialIndices.begin() + matchIndex);
d->materialTypes.erase(d->materialTypes.begin() + matchIndex);
d->exclusionTypes.erase(d->exclusionTypes.begin() + matchIndex);
ui->kitchen.item_types.erase(ui->kitchen.item_types.begin() + matchIndex);
ui->kitchen.item_subtypes.erase(ui->kitchen.item_subtypes.begin() + matchIndex);
ui->kitchen.mat_indices.erase(ui->kitchen.mat_indices.begin() + matchIndex);
ui->kitchen.mat_types.erase(ui->kitchen.mat_types.begin() + matchIndex);
ui->kitchen.exc_types.erase(ui->kitchen.exc_types.begin() + matchIndex);
}
} while(match);
};
size_t Exclusions::size() const
size_t Kitchen::size()
{
return d->itemTypes.size();
};
}
return ui->kitchen.item_types.size();
};

@ -1 +1 @@
Subproject commit 7a730830c515fea701ff73b33cb604f48a4531fc
Subproject commit d5abec61f72f113e023219fed19c4022363de953

@ -61,6 +61,9 @@ DFHACK_PLUGIN(initflags initflags.cpp)
DFHACK_PLUGIN(stockpiles stockpiles.cpp)
DFHACK_PLUGIN(rename rename.cpp)
DFHACK_PLUGIN(fixwagons fixwagons.cpp)
DFHACK_PLUGIN(jobutils jobutils.cpp)
DFHACK_PLUGIN(regrass regrass.cpp)
DFHACK_PLUGIN(workflow workflow.cpp)
#DFHACK_PLUGIN(versionosd versionosd.cpp)
# this is the skeleton plugin. If you want to make your own, make a copy and then change it

@ -15,20 +15,20 @@ public:
ANYBYTE=0x101,DWORD_,ANYDWORD,ADDRESS
};
Hexsearch(const SearchArgType &args,uint64_t startpos,uint64_t endpos);
Hexsearch(const SearchArgType &args,char * startpos,char * endpos);
~Hexsearch();
void Reset(){pos_=startpos_;};
void SetStart(uint64_t pos){pos_=pos;};
void SetStart(char * pos){pos_=pos;};
uint64_t FindNext();
std::vector<uint64_t> FindAll();
void * FindNext();
std::vector<void *> FindAll();
private:
bool Compare(int a,int b);
void ReparseArgs();
SearchArgType args_;
uint64_t pos_,startpos_,endpos_;
char * pos_,* startpos_,* endpos_;
std::vector<int> BadCharShifts,GoodSuffixShift;
void PrepareGoodSuffixTable();
void PrepareBadCharShift();

@ -20,7 +20,7 @@ if mypos then
engine.poked(modpos+0x1c,count) --max size for div
else
modpos,modsize=engine.loadmod("dfusion/migrants/migrants.o","Migrants")
modpos,modsize=engine.loadmod("dfusion/migrants/migrants.o","Migrants",400)
print(string.format("Loaded module @:%x",modpos))
count=0
for _,v in pairs(names) do

@ -1,7 +1,7 @@
#include "hexsearch.h"
Hexsearch::Hexsearch(const SearchArgType &args,uint64_t startpos,uint64_t endpos):args_(args),pos_(startpos),startpos_(startpos),endpos_(endpos)
Hexsearch::Hexsearch(const SearchArgType &args,char * startpos,char * endpos):args_(args),pos_(startpos),startpos_(startpos),endpos_(endpos)
{
ReparseArgs();
}
@ -52,7 +52,7 @@ void Hexsearch::ReparseArgs()
}
}
}
uint64_t Hexsearch::FindNext() //TODO rewrite using Boyer-Moore algorithm
void * Hexsearch::FindNext() //TODO rewrite using Boyer-Moore algorithm
{
DFHack::Core &inst=DFHack::Core::getInstance();
DFHack::Process *p=inst.p;
@ -81,16 +81,16 @@ uint64_t Hexsearch::FindNext() //TODO rewrite using Boyer-Moore algorithm
return pos_-args_.size();
}
}
pos_++;
pos_ = pos_ + 1;
}
delete [] buf;
return 0;
}
std::vector<uint64_t> Hexsearch::FindAll()
std::vector<void *> Hexsearch::FindAll()
{
std::vector<uint64_t> ret;
uint64_t cpos=pos_;
std::vector<void *> ret;
void * cpos=pos_;
while(cpos!=0)
{
cpos=FindNext();

@ -2,14 +2,14 @@
int lua::Hexsearch::find(lua_State *L)
{
lua::state st(L);
uint64_t pos=p->FindNext();
void * pos=p->FindNext();
st.push(pos);
return 1;
}
int lua::Hexsearch::findall(lua_State *L)
{
lua::state st(L);
std::vector<uint64_t> pos=p->FindAll();
std::vector<void *> pos=p->FindAll();
st.newtable();
for(unsigned i=0;i<pos.size();i++)
{
@ -22,10 +22,10 @@ int lua::Hexsearch::findall(lua_State *L)
lua::Hexsearch::Hexsearch(lua_State *L,int id):tblid(id)
{
lua::state st(L);
uint64_t start,end;
char * start,* end;
::Hexsearch::SearchArgType args;
start=st.as<uint32_t>(1);
end=st.as<uint32_t>(2);
start= (char *)st.as<uint32_t>(1);
end=(char *)st.as<uint32_t>(2);
for(int i=3;i<=st.gettop();i++)
{
args.push_back(st.as<int>(i));

@ -32,7 +32,7 @@ static int LoadMod(lua_State *L)
buf=new char[size];
f.GetText(buf);
//std::cout<<"poking @:"<<std::hex<<pos<<"size :"<<size<<std::endl;
DFHack::Core::getInstance().p->write(pos,size,(uint8_t*)buf);
DFHack::Core::getInstance().p->write((void *) pos,size,(uint8_t*)buf);
delete [] buf;
st.push(pos);
st.push(size);
@ -183,6 +183,18 @@ static int Call_Df(lua_State *L)
st.push(f.CallFunction(ptr,conv,args));
return 1;
}
static int Suspend_Df(lua_State *L)
{
lua::state st(L);
DFHack::Core::getInstance().Suspend();
return 0;
}
static int Resume_Df(lua_State *L)
{
lua::state st(L);
DFHack::Core::getInstance().Resume();
return 0;
}
const luaL_Reg lua_misc_func[]=
{
{"loadmod",LoadMod},
@ -193,6 +205,8 @@ const luaL_Reg lua_misc_func[]=
{"newmod",NewMod},
{"getpushvalue",Get_PushValue},
{"calldf",Call_Df},
{"suspend",Suspend_Df},
{"resume",Resume_Df},
{NULL,NULL}
};
void lua::RegisterMisc(lua::state &st)

@ -14,7 +14,7 @@ static int lua_Process_readDWord(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
uint32_t ret=c->readDWord(st.as<uint32_t>(1));
uint32_t ret=c->readDWord( (void *) st.as<uint32_t>(1));
st.push(ret);
return 1;
}
@ -22,14 +22,14 @@ static int lua_Process_writeDWord(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c->writeDWord(st.as<uint32_t>(1),st.as<uint32_t>(2));
c->writeDWord((void *) st.as<uint32_t>(1),st.as<uint32_t>(2));
return 0;
}
static int lua_Process_readFloat(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
float ret=c->readFloat(st.as<uint32_t>(1));
float ret=c->readFloat((void *) st.as<uint32_t>(1));
st.push(ret);
return 1;
}
@ -38,7 +38,7 @@ static int lua_Process_readWord(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
uint16_t ret=c->readWord(st.as<uint32_t>(1));
uint16_t ret=c->readWord((void *) st.as<uint32_t>(1));
st.push(ret);
return 1;
}
@ -47,14 +47,14 @@ static int lua_Process_writeWord(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c->writeWord(st.as<uint32_t>(1),st.as<uint16_t>(2));
c->writeWord((void *) st.as<uint32_t>(1),st.as<uint16_t>(2));
return 0;
}
static int lua_Process_readByte(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
uint8_t ret=c->readByte(st.as<uint32_t>(1));
uint8_t ret=c->readByte((void *) st.as<uint32_t>(1));
st.push(ret);
return 1;
}
@ -63,7 +63,7 @@ static int lua_Process_writeByte(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c->writeByte(st.as<uint32_t>(1),st.as<uint8_t>(2));
c->writeByte((void *) st.as<uint32_t>(1),st.as<uint8_t>(2));
return 0;
}
static int lua_Process_read(lua_State *S)
@ -77,7 +77,7 @@ static int lua_Process_read(lua_State *S)
buf=(uint8_t*)lua_touserdata(st,3);
else
buf=new uint8_t[len];
c->read(st.as<uint32_t>(1),len,buf);
c->read((void *) st.as<uint32_t>(1),len,buf);
st.pushlightuserdata(buf);
return 1;
}
@ -85,14 +85,14 @@ static int lua_Process_write(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c-> write(st.as<uint32_t>(1),st.as<uint32_t>(2),static_cast<uint8_t*>(lua_touserdata(st,3)));
c-> write((void *) st.as<uint32_t>(1),st.as<uint32_t>(2),static_cast<uint8_t*>(lua_touserdata(st,3)));
return 0;
}
static int lua_Process_readSTLString (lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
std::string r=c->readSTLString(st.as<uint32_t>(1));
std::string r=c->readSTLString((void *) st.as<uint32_t>(1));
st.push(r);
return 1;
}
@ -101,14 +101,14 @@ static int lua_Process_writeSTLString(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c->writeSTLString(st.as<uint32_t>(1),st.as<std::string>(2));
c->writeSTLString((void *) st.as<uint32_t>(1),st.as<std::string>(2));
return 0;
}
static int lua_Process_copySTLString(lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
c->copySTLString(st.as<uint32_t>(1),st.as<uint32_t>(2));
c->copySTLString((void *) st.as<uint32_t>(1),st.as<uint32_t>(2));
return 0;
}
static int lua_Process_doReadClassName(lua_State *S)
@ -131,7 +131,7 @@ static int lua_Process_readCString (lua_State *S)
{
lua::state st(S);
DFHack::Process* c=GetProcessPtr(st);
std::string r=c->readCString(st.as<uint32_t>(1));
std::string r=c->readCString((void *) st.as<uint32_t>(1));
st.push(r);
return 1;
}
@ -226,10 +226,10 @@ static int lua_Process_setPermisions(lua_State *S)
DFHack::t_memrange range,trange;
st.getfield("start",1);
range.start=st.as<uint64_t>();
range.start= (void *)st.as<uint64_t>();
st.pop();
st.getfield("end",1);
range.end=st.as<uint64_t>();
range.end= (void *)st.as<uint64_t>();
st.pop();
st.getfield("read",2);

@ -16,7 +16,7 @@ int OffsetGroup::getOffset(lua_State *L)
int OffsetGroup::getAddress(lua_State *L)
{
lua::state st(L);
uint32_t ret=p->getAddress(st.as<std::string>(1));
uint32_t ret= (uint32_t)p->getAddress(st.as<std::string>(1));
st.push(ret);
return 1;
}
@ -57,7 +57,7 @@ int OffsetGroup::getSafeOffset(lua_State *L)
int OffsetGroup::getSafeAddress(lua_State *L)
{
lua::state st(L);
uint32_t out;
void * out;
bool ret=p->getSafeAddress(st.as<std::string>(1),out);
st.push(ret);
st.push(out);
@ -286,7 +286,7 @@ static int __lua_resolveObjectToClassID(lua_State *S)
{
lua::state st(S);
int32_t ret;
bool output=DFHack::Core::getInstance().vinfo->resolveObjectToClassID(st.as<uint32_t>(1),ret);
bool output=DFHack::Core::getInstance().vinfo->resolveObjectToClassID((char *)st.as<uint32_t>(1),ret);
st.push(output);
st.push(ret);
return 2;
@ -329,7 +329,7 @@ static int __lua_getOffset(lua_State *S)
static int __lua_getAddress(lua_State *S)
{
lua::state st(S);
uint32_t ret=DFHack::Core::getInstance().vinfo->getAddress(st.as<std::string>(1));
void * ret=DFHack::Core::getInstance().vinfo->getAddress(st.as<std::string>(1));
st.push(ret);
return 1;
}
@ -392,7 +392,7 @@ static int __lua_getSafeOffset(lua_State *S)
static int __lua_getSafeAddress(lua_State *S)
{
lua::state st(S);
uint32_t out;
void * out;
bool ret=DFHack::Core::getInstance().vinfo->getSafeAddress(st.as<std::string>(1),out);
st.push(ret);
st.push(out);

@ -5,28 +5,34 @@
#include <sstream>
#include <climits>
#include <vector>
#include <string>
#include <algorithm>
#include <set>
using namespace std;
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <vector>
#include <string>
#include <algorithm>
#include <modules/Maps.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Maps.h"
#include "modules/Gui.h"
#include "modules/Items.h"
#include "modules/Materials.h"
#include "modules/MapCache.h"
#include <modules/Gui.h>
#include <modules/Items.h>
#include <modules/Materials.h>
#include <modules/MapCache.h>
#include "DataDefs.h"
#include "df/item.h"
#include "df/world.h"
#include "df/general_ref.h"
using namespace DFHack;
using MapExtras::Block;
using MapExtras::MapCache;
using df::global::world;
DFhackCExport command_result df_autodump(Core * c, vector <string> & parameters);
DFhackCExport command_result df_autodump_destroy_here(Core * c, vector <string> & parameters);
DFhackCExport command_result df_autodump_destroy_item(Core * c, vector <string> & parameters);
DFhackCExport const char * plugin_name ( void )
{
@ -39,6 +45,18 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
commands.push_back(PluginCommand("autodump",
"Teleport items marked for dumping to the cursor.",
df_autodump));
commands.push_back(PluginCommand(
"autodump-destroy-here", "Destroy items marked for dumping under cursor.",
df_autodump_destroy_here, cursor_hotkey,
" Identical to autodump destroy-here, but intended for use as keybinding.\n"
));
commands.push_back(PluginCommand(
"autodump-destroy-item", "Destroy the selected item.",
df_autodump_destroy_item, any_item_hotkey,
" Destroy the selected item. The item may be selected\n"
" in the 'k' list, or inside a container. If called\n"
" again before the game is resumed, cancels destroy.\n"
));
return CR_OK;
}
@ -49,15 +67,18 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
typedef std::map <DFCoord, uint32_t> coordmap;
DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters)
static command_result autodump_main(Core * c, vector <string> & parameters)
{
// Command line options
bool destroy = false;
bool here = false;
if(parameters.size() > 0)
{
string & p = parameters[0];
if(p == "destroy")
destroy = true;
else if (p == "destroy-here")
destroy = here = true;
else if(p == "?" || p == "help")
{
c->con.print(
@ -67,31 +88,22 @@ DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters
"Be aware that any active dump item tasks still point at the item.\n\n"
"Options:\n"
"destroy - instead of dumping, destroy the items instantly.\n"
"destroy-here - only affect the tile under cursor.\n"
);
return CR_OK;
}
}
c->Suspend();
DFHack::occupancies40d * occupancies;
DFHack::VersionInfo *mem = c->vinfo;
DFHack::Gui * Gui = c->getGui();
DFHack::Items * Items = c->getItems();
DFHack::Maps *Maps = c->getMaps();
vector <df_item*> p_items;
if(!Items->readItemVector(p_items))
{
c->con.printerr("Can't access the item vector.\n");
c->Resume();
return CR_FAILURE;
}
std::size_t numItems = p_items.size();
std::size_t numItems = world->items.all.size();
// init the map
if(!Maps->Start())
{
c->con.printerr("Can't initialize map.\n");
c->Resume();
return CR_FAILURE;
}
MapCache MC (Maps);
@ -100,28 +112,28 @@ DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters
int cx, cy, cz;
DFCoord pos_cursor;
if(!destroy)
if(!destroy || here)
{
if (!Gui->getCursorCoords(cx,cy,cz))
{
c->con.printerr("Cursor position not found. Please enabled the cursor.\n");
c->Resume();
return CR_FAILURE;
}
pos_cursor = DFCoord(cx,cy,cz);
}
if (!destroy)
{
{
Block * b = MC.BlockAt(pos_cursor / 16);
if(!b)
{
c->con.printerr("Cursor is in an invalid/uninitialized area. Place it over a floor.\n");
c->Resume();
return CR_FAILURE;
}
uint16_t ttype = MC.tiletypeAt(pos_cursor);
if(!DFHack::isFloorTerrain(ttype))
{
c->con.printerr("Cursor should be placed over a floor.\n");
c->Resume();
return CR_FAILURE;
}
}
@ -130,8 +142,8 @@ DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters
// proceed with the dumpification operation
for(std::size_t i=0; i< numItems; i++)
{
df_item * itm = p_items[i];
DFCoord pos_item(itm->x, itm->y, itm->z);
df::item * itm = world->items.all[i];
DFCoord pos_item(itm->pos.x, itm->pos.y, itm->pos.z);
// keep track how many items are at places. all items.
coordmap::iterator it = counts.find(pos_item);
@ -147,22 +159,22 @@ DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters
// iterator is valid here, we use it later to decrement the pile counter if the item is moved
// only dump the stuff marked for dumping and laying on the ground
if ( !itm->flags.dump
|| !itm->flags.on_ground
|| itm->flags.construction
|| itm->flags.hidden
|| itm->flags.in_building
|| itm->flags.in_chest
|| itm->flags.in_inventory
|| itm->flags.construction
if ( !itm->flags.bits.dump
|| !itm->flags.bits.on_ground
|| itm->flags.bits.construction
|| itm->flags.bits.hidden
|| itm->flags.bits.in_building
|| itm->flags.bits.in_chest
|| itm->flags.bits.in_inventory
|| itm->flags.bits.artifact1
)
continue;
if(!destroy) // move to cursor
{
// Change flags to indicate the dump was completed, as if by super-dwarfs
itm->flags.dump = false;
itm->flags.forbid = true;
itm->flags.bits.dump = false;
itm->flags.bits.forbid = true;
// Don't move items if they're already at the cursor
if (pos_cursor == pos_item)
@ -173,7 +185,7 @@ DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters
{
// yes...
cerr << "Moving from block to block!" << endl;
df_block * bl_src = Maps->getBlock(itm->x /16, itm->y/16, itm->z);
df_block * bl_src = Maps->getBlock(itm->pos.x /16, itm->pos.y/16, itm->pos.z);
df_block * bl_tgt = Maps->getBlock(cx /16, cy/16, cz);
if(bl_src)
{
@ -194,13 +206,20 @@ DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters
}
// Move the item
itm->x = pos_cursor.x;
itm->y = pos_cursor.y;
itm->z = pos_cursor.z;
itm->pos.x = pos_cursor.x;
itm->pos.y = pos_cursor.y;
itm->pos.z = pos_cursor.z;
}
else // destroy
{
itm->flags.garbage_colect = true;
if (here && pos_item != pos_cursor)
continue;
itm->flags.bits.garbage_colect = true;
// Cosmetic changes: make them disappear from view instantly
itm->flags.bits.forbid = true;
itm->flags.bits.hidden = true;
}
// keeping track of item pile sizes ;)
it->second --;
@ -238,7 +257,92 @@ DFhackCExport command_result df_autodump (Core * c, vector <string> & parameters
// Is this necessary? Is "forbid" a dirtyable attribute like "dig" is?
Maps->WriteDirtyBit(cx/16, cy/16, cz, true);
}
c->Resume();
c->con.print("Done. %d items %s.\n", dumped_total, destroy ? "marked for desctruction" : "quickdumped");
c->con.print("Done. %d items %s.\n", dumped_total, destroy ? "marked for destruction" : "quickdumped");
return CR_OK;
}
DFhackCExport command_result df_autodump(Core * c, vector <string> & parameters)
{
CoreSuspender suspend(c);
return autodump_main(c, parameters);
}
DFhackCExport command_result df_autodump_destroy_here(Core * c, vector <string> & parameters)
{
// HOTKEY COMMAND; CORE ALREADY SUSPENDED
if (!parameters.empty())
return CR_WRONG_USAGE;
vector<string> args;
args.push_back("destroy-here");
return autodump_main(c, args);
}
static std::map<int, df::item_flags> pending_destroy;
static int last_frame = 0;
DFhackCExport command_result df_autodump_destroy_item(Core * c, vector <string> & parameters)
{
// HOTKEY COMMAND; CORE ALREADY SUSPENDED
if (!parameters.empty())
return CR_WRONG_USAGE;
df::item *item = getSelectedItem(c);
if (!item)
return CR_FAILURE;
// Allow undoing the destroy
if (df::global::world->frame_counter != last_frame)
{
last_frame = df::global::world->frame_counter;
pending_destroy.clear();
}
if (pending_destroy.count(item->id))
{
df::item_flags old_flags = pending_destroy[item->id];
pending_destroy.erase(item->id);
item->flags.bits.garbage_colect = false;
item->flags.bits.hidden = old_flags.bits.hidden;
item->flags.bits.dump = old_flags.bits.dump;
item->flags.bits.forbid = old_flags.bits.forbid;
return CR_OK;
}
// Check the item is good to destroy
if (item->flags.bits.garbage_colect)
{
c->con.printerr("Item is already marked for destroy.\n");
return CR_FAILURE;
}
if (item->flags.bits.construction ||
item->flags.bits.in_building ||
item->flags.bits.artifact1)
{
c->con.printerr("Choosing not to destroy buildings, constructions and artifacts.\n");
return CR_FAILURE;
}
for (unsigned i = 0; i < item->itemrefs.size(); i++)
{
df::general_ref *ref = item->itemrefs[i];
if (ref->getType() == df::general_ref_type::UNIT_HOLDER)
{
c->con.printerr("Choosing not to destroy items in unit inventory.\n");
return CR_FAILURE;
}
}
// Set the flags
pending_destroy[item->id] = item->flags;
item->flags.bits.garbage_colect = true;
item->flags.bits.hidden = true;
item->flags.bits.dump = true;
item->flags.bits.forbid = true;
return CR_OK;
}

@ -1,100 +1,71 @@
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Maps.h>
#include <modules/Items.h>
#include <modules/Units.h>
#include <modules/Gui.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "DataDefs.h"
#include "df/world.h"
#include "df/map_block.h"
#include "df/block_square_event.h"
#include "df/block_square_event_material_spatterst.h"
#include "df/item_actual.h"
#include "df/unit.h"
#include "df/unit_spatter.h"
#include "df/matter_state.h"
#include "df/cursor.h"
#include "df/builtin_mats.h"
#include "df/contaminant.h"
using namespace DFHack;
#include <vector>
#include <string>
#include <string.h>
using std::vector;
using std::string;
using namespace DFHack;
DFhackCExport command_result clean (Core * c, vector <string> & parameters);
DFhackCExport command_result spotclean (Core * c, vector <string> & parameters);
DFhackCExport const char * plugin_name ( void )
{
return "cleaners";
}
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("clean","Removes contaminants from map tiles, items and creatures.",clean));
commands.push_back(PluginCommand("spotclean","Cleans map tile under cursor.",spotclean,cursor_hotkey));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}
using df::global::world;
using df::global::cursor;
command_result cleanmap (Core * c, bool snow, bool mud)
{
const uint32_t water_idx = 6;
const uint32_t mud_idx = 12;
vector<DFHack::t_spattervein *> splatter;
DFHack::Maps *Mapz = c->getMaps();
// init the map
if(!Mapz->Start())
{
c->con << "Can't init map." << std::endl;
c->Resume();
return CR_FAILURE;
}
uint32_t x_max,y_max,z_max;
Mapz->getSize(x_max,y_max,z_max);
int num_blocks = 0;
int blocks_total = 0;
// walk the map
for(uint32_t x = 0; x< x_max;x++)
{
for(uint32_t y = 0; y< y_max;y++)
{
for(uint32_t z = 0; z< z_max;z++)
// Invoked from clean(), already suspended
int num_blocks = 0, blocks_total = world->map.map_blocks.size();
for (int i = 0; i < blocks_total; i++)
{
df_block * block = Mapz->getBlock(x,y,z);
if(block)
{
blocks_total ++;
df::map_block *block = world->map.map_blocks[i];
bool cleaned = false;
Mapz->SortBlockEvents(x,y,z,0,0,&splatter);
for(int i = 0; i < 16; i++)
for(int j = 0; j < 16; j++)
for(int x = 0; x < 16; x++)
{
for(int y = 0; y < 16; y++)
{
block->occupancy[i][j].bits.arrow_color = 0;
block->occupancy[i][j].bits.broken_arrows_variant = 0;
block->occupancy[x][y].bits.arrow_color = 0;
block->occupancy[x][y].bits.arrow_variant = 0;
}
}
for(uint32_t i = 0; i < splatter.size(); i++)
for (int j = 0; j < block->block_events.size(); j++)
{
DFHack::t_spattervein * vein = splatter[i];
df::block_square_event *evt = block->block_events[j];
if (evt->getType() != df::block_square_event_type::material_spatter)
continue;
// type verified - recast to subclass
df::block_square_event_material_spatterst *spatter = (df::block_square_event_material_spatterst *)evt;
// filter snow
if(!snow
&& vein->mat1 == DFHack::Materials::WATER
&& vein->matter_state == DFHack::state_powder)
&& spatter->mat_type == df::builtin_mats::WATER
&& spatter->mat_state == df::matter_state::Powder)
continue;
// filter mud
if(!mud
&& vein->mat1 == DFHack::Materials::MUD
&& vein->matter_state == DFHack::state_solid)
&& spatter->mat_type == df::builtin_mats::MUD
&& spatter->mat_state == df::matter_state::Solid)
continue;
Mapz->RemoveBlockEvent(x,y,z,(t_virtual *) vein);
delete evt;
block->block_events.erase(block->block_events.begin() + j);
j--;
cleaned = true;
}
num_blocks += cleaned;
}
}
}
}
if(num_blocks)
c->con.print("Cleaned %d of %d map blocks.\n", num_blocks, blocks_total);
return CR_OK;
@ -102,30 +73,19 @@ command_result cleanmap (Core * c, bool snow, bool mud)
command_result cleanitems (Core * c)
{
DFHack::Items * Items = c->getItems();
vector <df_item*> p_items;
if(!Items->readItemVector(p_items))
{
c->con.printerr("Can't access the item vector.\n");
c->Resume();
return CR_FAILURE;
}
std::size_t numItems = p_items.size();
// Invoked from clean(), already suspended
int cleaned_items = 0, cleaned_total = 0;
for (std::size_t i = 0; i < numItems; i++)
for (int i = 0; i < world->items.all.size(); i++)
{
df_item * itm = p_items[i];
if(!itm->contaminants)
continue;
if (itm->contaminants->size())
// currently, all item classes extend item_actual, so this should be safe
df::item_actual *item = (df::item_actual *)world->items.all[i];
if (item->contaminants && item->contaminants->size())
{
for(int j = 0; j < itm->contaminants->size(); j++)
delete itm->contaminants->at(j);
for (int j = 0; j < item->contaminants->size(); j++)
delete item->contaminants->at(j);
cleaned_items++;
cleaned_total += itm->contaminants->size();
itm->contaminants->clear();
cleaned_total += item->contaminants->size();
item->contaminants->clear();
}
}
if (cleaned_total)
@ -135,27 +95,19 @@ command_result cleanitems (Core * c)
command_result cleanunits (Core * c)
{
DFHack::Units * Creatures = c->getUnits();
uint32_t num_creatures;
if (!Creatures->Start(num_creatures))
{
c->con.printerr("Can't read unit list!\n");
c->Resume();
return CR_FAILURE;
}
// Invoked from clean(), already suspended
int num_units = world->units.all.size();
int cleaned_units = 0, cleaned_total = 0;
for (std::size_t i = 0; i < num_creatures; i++)
for (int i = 0; i < num_units; i++)
{
df_unit *unit = Creatures->creatures->at(i);
int num = unit->contaminants.size();
if (num)
df::unit *unit = world->units.all[i];
if (unit->body.spatters.size())
{
for(int j = 0; j < unit->contaminants.size(); j++)
delete unit->contaminants.at(j);
for (int j = 0; j < unit->body.spatters.size(); j++)
delete unit->body.spatters[j];
cleaned_units++;
cleaned_total += num;
unit->contaminants.clear();
cleaned_total += unit->body.spatters.size();
unit->body.spatters.clear();
}
}
if (cleaned_total)
@ -163,33 +115,39 @@ command_result cleanunits (Core * c)
return CR_OK;
}
// This is slightly different from what's in the Maps module - it takes tile coordinates rather than block coordinates
df::map_block *getBlock (int32_t x, int32_t y, int32_t z)
{
if ((x < 0) || (y < 0) || (z < 0))
return NULL;
if ((x >= world->map.x_count) || (y >= world->map.y_count) || (z >= world->map.z_count))
return NULL;
return world->map.block_index[x >> 4][y >> 4][z];
}
DFhackCExport command_result spotclean (Core * c, vector <string> & parameters)
{
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
vector<DFHack::t_spattervein *> splatter;
DFHack::Maps *Mapz = c->getMaps();
DFHack::Gui *Gui = c->getGui();
// init the map
if(!Mapz->Start())
if (cursor->x == -30000)
{
c->con.printerr("Can't init map.\n");
c->con.printerr("The cursor is not active.\n");
return CR_FAILURE;
}
int32_t cursorX, cursorY, cursorZ;
Gui->getCursorCoords(cursorX,cursorY,cursorZ);
if(cursorX == -30000)
df::map_block *block = getBlock(cursor->x, cursor->y, cursor->z);
if (block == NULL)
{
c->con.printerr("The cursor is not active.\n");
c->con.printerr("Invalid map block selected!\n");
return CR_FAILURE;
}
int32_t blockX = cursorX / 16, blockY = cursorY / 16;
int32_t tileX = cursorX % 16, tileY = cursorY % 16;
df_block *b = Mapz->getBlock(blockX,blockY,cursorZ);
vector <t_spattervein *> spatters;
Mapz->SortBlockEvents(blockX, blockY, cursorZ, 0,0, &spatters);
for(int i = 0; i < spatters.size(); i++)
for (int i = 0; i < block->block_events.size(); i++)
{
spatters[i]->intensity[tileX][tileY] = 0;
df::block_square_event *evt = block->block_events[i];
if (evt->getType() != df::block_square_event_type::material_spatter)
continue;
// type verified - recast to subclass
df::block_square_event_material_spatterst *spatter = (df::block_square_event_material_spatterst *)evt;
spatter->amount[cursor->x % 16][cursor->y % 16] = 0;
}
return CR_OK;
}
@ -239,7 +197,7 @@ DFhackCExport command_result clean (Core * c, vector <string> & parameters)
"snow - also remove snow\n"
"mud - also remove mud\n"
"Example: clean all mud snow\n"
"This removes all spatter, including mud and snow from map tiles."
"This removes all spatter, including mud and snow from map tiles.\n"
);
return CR_OK;
}
@ -253,3 +211,21 @@ DFhackCExport command_result clean (Core * c, vector <string> & parameters)
c->Resume();
return CR_OK;
}
DFhackCExport const char * plugin_name ( void )
{
return "cleaners";
}
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("clean","Removes contaminants from map tiles, items and creatures.",clean));
commands.push_back(PluginCommand("spotclean","Cleans map tile under cursor.",spotclean,cursor_hotkey));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}

@ -9,17 +9,22 @@
using namespace std;
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include <vector>
#include <string>
#include <modules/Maps.h>
#include <modules/Items.h>
#include <modules/Units.h>
#include <modules/Materials.h>
#include <modules/Translation.h>
#include "modules/Maps.h"
#include "modules/Items.h"
#include "modules/Units.h"
#include "modules/Materials.h"
#include "modules/Translation.h"
using namespace DFHack;
using namespace DFHack::Simple;
#include "DataDefs.h"
#include "df/world.h"
using df::global::world;
DFhackCExport command_result df_cleanowned (Core * c, vector <string> & parameters);
@ -89,7 +94,6 @@ DFhackCExport command_result df_cleanowned (Core * c, vector <string> & paramete
}
c->Suspend();
DFHack::Materials *Materials = c->getMaterials();
DFHack::Items *Items = c->getItems();
DFHack::Units *Creatures = c->getUnits();
DFHack::Translation *Tran = c->getTranslation();
@ -99,28 +103,20 @@ DFhackCExport command_result df_cleanowned (Core * c, vector <string> & paramete
ok &= Creatures->Start(num_creatures);
ok &= Tran->Start();
vector<df_item *> p_items;
ok &= Items->readItemVector(p_items);
if(!ok)
{
c->con.printerr("Can't continue due to offset errors.\n");
c->Resume();
return CR_FAILURE;
}
c->con.print("Found total %d items.\n", p_items.size());
c->con.print("Found total %d items.\n", world->items.all.size());
for (std::size_t i=0; i < p_items.size(); i++)
for (std::size_t i=0; i < world->items.all.size(); i++)
{
df_item * item = p_items[i];
df::item * item = world->items.all[i];
bool confiscate = false;
bool dump = false;
if (!item->flags.owned)
if (!item->flags.bits.owned)
{
int32_t owner = Items->getItemOwnerID(item);
int32_t owner = Items::getItemOwnerID(item);
if (owner >= 0)
{
c->con.print("Fixing a misflagged item: ");
c->con.print("Fixing a misflagged item: \t");
confiscate = true;
}
else
@ -129,23 +125,21 @@ DFhackCExport command_result df_cleanowned (Core * c, vector <string> & paramete
}
}
std::string name = Items->getItemClass(item);
if (item->flags.rotten)
if (item->flags.bits.rotten)
{
c->con.print("Confiscating a rotten item: \t");
confiscate = true;
}
else if (item->flags.on_ground)
else if (item->flags.bits.on_ground)
{
int32_t type = item->getType();
if(type == Items::MEAT ||
type == Items::FISH ||
type == Items::VERMIN ||
type == Items::PET ||
type == Items::PLANT ||
type == Items::CHEESE ||
type == Items::FOOD
if(type == df::item_type::MEAT ||
type == df::item_type::FISH ||
type == df::item_type::VERMIN ||
type == df::item_type::PET ||
type == df::item_type::PLANT ||
type == df::item_type::CHEESE ||
type == df::item_type::FOOD
)
{
confiscate = true;
@ -189,7 +183,7 @@ DFhackCExport command_result df_cleanowned (Core * c, vector <string> & paramete
item->getWear()
);
int32_t owner = Items->getItemOwnerID(item);
int32_t owner = Items::getItemOwnerID(item);
int32_t owner_index = Creatures->FindIndexById(owner);
std::string info;
@ -206,10 +200,10 @@ DFhackCExport command_result df_cleanowned (Core * c, vector <string> & paramete
if (!dry_run)
{
if (!Items->removeItemOwner(item, Creatures))
if (!Items::removeItemOwner(item, Creatures))
c->con.print("(unsuccessfully) ");
if (dump)
item->flags.dump = 1;
item->flags.bits.dump = 1;
}
c->con.print("\n");
}

@ -1,15 +1,16 @@
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include <vector>
#include <string>
#include <modules/Vermin.h>
#include "modules/Vermin.h"
#include "modules/Materials.h"
using std::vector;
using std::string;
using namespace DFHack;
#include <DFHack.h>
using namespace DFHack::Simple;
DFhackCExport command_result colonies (Core * c, vector <string> & parameters);
@ -32,10 +33,9 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
return CR_OK;
}
void destroyColonies(DFHack::SpawnPoints *points);
void convertColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials);
void showColonies(Core *c, DFHack::SpawnPoints *points,
DFHack::Materials *Materials);
void destroyColonies();
void convertColonies(Materials *Materials);
void showColonies(Core *c, Materials *Materials);
DFhackCExport command_result colonies (Core * c, vector <string> & parameters)
{
@ -71,54 +71,42 @@ DFhackCExport command_result colonies (Core * c, vector <string> & parameters)
}
c->Suspend();
Vermin * vermin = c->getVermin();
Materials * materials = c->getMaterials();
SpawnPoints *points = vermin->getSpawnPoints();
if(!points || !points->isValid())
{
c->con.printerr("vermin not supported for this DF version\n");
c->Resume();
return CR_FAILURE;
}
materials->ReadCreatureTypesEx();
if (destroy)
destroyColonies(points);
destroyColonies();
else if (convert)
convertColonies(points, materials);
convertColonies(materials);
else
showColonies(c, points, materials);
delete points;
showColonies(c, materials);
vermin->Finish();
materials->Finish();
c->Resume();
return CR_OK;
}
void destroyColonies(DFHack::SpawnPoints *points)
//FIXME: this is probably bullshit
void destroyColonies()
{
uint32_t numSpawnPoints = points->size();
uint32_t numSpawnPoints = Vermin::getNumVermin();
for (uint32_t i = 0; i < numSpawnPoints; i++)
{
DFHack::t_spawnPoint sp;
points->Read(i, sp);
Vermin::t_vermin sp;
Vermin::Read(i, sp);
if (sp.in_use && DFHack::SpawnPoints::isWildColony(sp))
if (sp.visible && sp.is_colony)
{
sp.in_use = false;
points->Write(i, sp);
sp.visible = false;
Vermin::Write(i, sp);
}
}
}
// Convert all colonies to honey bees.
void convertColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials)
void convertColonies(Materials *Materials)
{
int bee_idx = -1;
for (size_t i = 0; i < Materials->raceEx.size(); i++)
@ -134,39 +122,38 @@ void convertColonies(DFHack::SpawnPoints *points, DFHack::Materials *Materials)
return;
}
uint32_t numSpawnPoints = points->size();
uint32_t numSpawnPoints = Vermin::getNumVermin();
for (uint32_t i = 0; i < numSpawnPoints; i++)
{
DFHack::t_spawnPoint sp;
points->Read(i, sp);
Vermin::t_vermin sp;
Vermin::Read(i, sp);
if (sp.in_use && DFHack::SpawnPoints::isWildColony(sp))
if (sp.visible && sp.is_colony)
{
sp.race = bee_idx;
points->Write(i, sp);
Vermin::Write(i, sp);
}
}
}
void showColonies(Core *c, DFHack::SpawnPoints *points,
DFHack::Materials *Materials)
void showColonies(Core *c, Materials *Materials)
{
uint32_t numSpawnPoints = points->size();
uint32_t numSpawnPoints = Vermin::getNumVermin();
int numColonies = 0;
for (uint32_t i = 0; i < numSpawnPoints; i++)
{
DFHack::t_spawnPoint sp;
Vermin::t_vermin sp;
points->Read(i, sp);
Vermin::Read(i, sp);
if (sp.in_use && DFHack::SpawnPoints::isWildColony(sp))
if (sp.visible && sp.is_colony)
{
numColonies++;
string race="(no race)";
if(sp.race != -1)
race = Materials->raceEx[sp.race].id;
c->con.print("Spawn point %u: %s at %d:%d:%d\n", i,
c->con.print("Colony %u: %s at %d:%d:%d\n", i,
race.c_str(), sp.x, sp.y, sp.z);
}
}

@ -1,56 +1,35 @@
// De-ramp. All ramps marked for removal are replaced with given tile (presently, normal floor).
#include <iostream>
#include <vector>
#include <map>
#include <stddef.h>
#include <assert.h>
#include <string.h>
using namespace std;
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Maps.h>
#include <TileTypes.h>
using namespace DFHack;
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
DFhackCExport command_result df_deramp (Core * c, vector <string> & parameters);
#include "DataDefs.h"
#include "df/world.h"
#include "df/map_block.h"
#include "df/tile_dig_designation.h"
#include "TileTypes.h"
DFhackCExport const char * plugin_name ( void )
{
return "deramp";
}
using std::vector;
using std::string;
using namespace DFHack;
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("deramp",
"De-ramp. All ramps marked for removal are replaced with floors.",
df_deramp));
return CR_OK;
}
using df::global::world;
using namespace DFHack;
DFhackCExport command_result plugin_shutdown ( Core * c )
// This is slightly different from what's in the Maps module - it takes tile coordinates rather than block coordinates
df::map_block *getBlock (int32_t x, int32_t y, int32_t z)
{
return CR_OK;
if ((x < 0) || (y < 0) || (z < 0))
return NULL;
if ((x >= world->map.x_count) || (y >= world->map.y_count) || (z >= world->map.z_count))
return NULL;
return world->map.block_index[x >> 4][y >> 4][z];
}
DFhackCExport command_result df_deramp (Core * c, vector <string> & parameters)
{
uint32_t x_max,y_max,z_max;
uint32_t num_blocks = 0;
uint32_t bytes_read = 0;
DFHack::designations40d designations;
DFHack::tiletypes40d tiles;
DFHack::tiletypes40d tilesAbove;
//DFHack::TileRow *ptile;
int32_t oldT, newT;
bool dirty= false;
int count=0;
int countbad=0;
for(int i = 0; i < parameters.size();i++)
{
if(parameters[i] == "help" || parameters[i] == "?")
@ -62,97 +41,74 @@ DFhackCExport command_result df_deramp (Core * c, vector <string> & parameters)
return CR_OK;
}
}
c->Suspend();
DFHack::Maps *Mapz = c->getMaps();
// init the map
if (!Mapz->Start())
{
c->con.printerr("Can't init map.\n");
c->Resume();
return CR_FAILURE;
}
Mapz->getSize(x_max,y_max,z_max);
CoreSuspender suspend(c);
uint8_t zeroes [16][16] = {0};
int count = 0;
int countbad = 0;
// walk the map
for (uint32_t x = 0; x< x_max;x++)
{
for (uint32_t y = 0; y< y_max;y++)
{
for (uint32_t z = 0; z< z_max;z++)
int num_blocks = 0, blocks_total = world->map.map_blocks.size();
for (int i = 0; i < blocks_total; i++)
{
if (Mapz->getBlock(x,y,z))
{
dirty= false;
Mapz->ReadDesignations(x,y,z, &designations);
Mapz->ReadTileTypes(x,y,z, &tiles);
if (Mapz->getBlock(x,y,z+1))
{
Mapz->ReadTileTypes(x,y,z+1, &tilesAbove);
}
else
{
memset(&tilesAbove,0,sizeof(tilesAbove));
}
df::map_block *block = world->map.map_blocks[i];
df::map_block *above = getBlock(block->map_pos.x, block->map_pos.y, block->map_pos.z + 1);
for (uint32_t ty=0;ty<16;++ty)
for (int x = 0; x < 16; x++)
{
for (uint32_t tx=0;tx<16;++tx)
for (int y = 0; y < 16; y++)
{
//Only the remove ramp designation (ignore channel designation, etc)
oldT = tiles[tx][ty];
if ( DFHack::designation_default == designations[tx][ty].bits.dig
&& DFHack::RAMP==DFHack::tileShape(oldT))
int16_t oldT = block->tiletype[x][y];
if ((tileShape(oldT) == RAMP) &&
(block->designation[x][y].bits.dig == df::tile_dig_designation::Default))
{
// Current tile is a ramp.
// Set current tile, as accurately as can be expected
newT = DFHack::findSimilarTileType(oldT,DFHack::FLOOR);
int16_t newT = findSimilarTileType(oldT, FLOOR);
// If no change, skip it (couldn't find a good tile type)
if ( oldT == newT) continue;
if (oldT == newT)
continue;
// Set new tile type, clear designation
tiles[tx][ty] = newT;
designations[tx][ty].bits.dig = DFHack::designation_no;
block->tiletype[x][y] = newT;
block->designation[x][y].bits.dig = df::tile_dig_designation::No;
// Check the tile above this one, in case a downward slope needs to be removed.
if ( DFHack::RAMP_TOP == DFHack::tileShape(tilesAbove[tx][ty]) )
{
tilesAbove[tx][ty] = 32;
}
dirty= true;
++count;
if ((above) && (tileShape(above->tiletype[x][y]) == RAMP_TOP))
above->tiletype[x][y] = 32; // open space
count++;
}
// ramp fixer
else if(DFHack::RAMP!=DFHack::tileShape(oldT) && DFHack::RAMP_TOP == DFHack::tileShape(tilesAbove[tx][ty]))
else if ((tileShape(oldT) != RAMP)
&& (above) && (tileShape(above->tiletype[x][y]) == RAMP_TOP))
{
tilesAbove[tx][ty] = 32;
above->tiletype[x][y] = 32; // open space
countbad++;
dirty = true;
}
}
}
//If anything was changed, write it all.
if (dirty)
{
Mapz->WriteDesignations(x,y,z, &designations);
Mapz->WriteTileTypes(x,y,z, &tiles);
if (Mapz->getBlock(x,y,z+1))
{
Mapz->WriteTileTypes(x,y,z+1, &tilesAbove);
}
dirty = false;
}
}
}
}
}
c->Resume();
if (count)
c->con.print("Found and changed %d tiles.\n", count);
if (countbad)
c->con.print("Fixed %d bad down ramps.\n", countbad);
return CR_OK;
}
DFhackCExport const char * plugin_name ( void )
{
return "deramp";
}
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("deramp",
"De-ramp. All ramps marked for removal are replaced with floors.",
df_deramp));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}

@ -17,7 +17,7 @@ static tthread::mutex* mymutex=0;
struct memory_data
{
size_t addr;
void * addr;
size_t len;
size_t refresh;
int state;
@ -57,7 +57,7 @@ bool isAddr(uint32_t *trg,vector<t_memrange> & ranges)
{
if(trg[0]%4==0)
for(size_t i=0;i<ranges.size();i++)
if(ranges[i].isInRange(trg[0]))
if(ranges[i].isInRange((void *)trg[0]))
return true;
return false;
@ -131,7 +131,7 @@ DFhackCExport command_result plugin_onupdate ( Core * c )
timeLast = time2;
c->p->read(memdata.addr,memdata.len,memdata.buf);
outputHex(memdata.buf,memdata.lbuf,memdata.len,memdata.addr,c,memdata.ranges);
outputHex(memdata.buf,memdata.lbuf,memdata.len,(size_t)memdata.addr,c,memdata.ranges);
memcpy(memdata.lbuf, memdata.buf, memdata.len);
if(memdata.refresh==0)
Deinit();
@ -143,7 +143,7 @@ DFhackCExport command_result memview (Core * c, vector <string> & parameters)
{
mymutex->lock();
c->p->getMemRanges(memdata.ranges);
memdata.addr=convert(parameters[0],true);
memdata.addr=(void *)convert(parameters[0],true);
if(memdata.addr==0)
{
Deinit();

@ -19,9 +19,9 @@ using namespace DFHack;
struct t_vecTriplet
{
uint32_t start;
uint32_t end;
uint32_t alloc_end;
void * start;
void * end;
void * alloc_end;
};
DFhackCExport command_result df_vectors (Core * c,
@ -74,7 +74,7 @@ static bool mightBeVec(vector<t_memrange> &heap_ranges,
// Vector length might not be a multiple of 4 if, for example,
// it's a vector of uint8_t or uint16_t. However, the actual memory
// allocated to the vector should be 4 byte aligned.
if ((vec->start % 4 != 0) || (vec->alloc_end % 4 != 0))
if (((int)vec->start % 4 != 0) || ((int)vec->alloc_end % 4 != 0))
return false;
for (size_t i = 0; i < heap_ranges.size(); i++)
@ -88,7 +88,7 @@ static bool mightBeVec(vector<t_memrange> &heap_ranges,
return false;
}
static bool inAnyRange(vector<t_memrange> &ranges, uint32_t ptr)
static bool inAnyRange(vector<t_memrange> &ranges, void * ptr)
{
for (size_t i = 0; i < ranges.size(); i++)
{
@ -141,7 +141,7 @@ static void vectorsUsage(Console &con)
static void printVec(Console &con, const char* msg, t_vecTriplet *vec,
uint32_t start, uint32_t pos)
{
uint32_t length = vec->end - vec->start;
uint32_t length = (int)vec->end - (int)vec->start;
uint32_t offset = pos - start;
con.print("%8s offset %06p, addr %010p, start %010p, length %u\n",
@ -193,15 +193,15 @@ DFhackCExport command_result df_vectors (Core * c, vector <string> & parameters)
{
t_memrange &range = heap_ranges[i];
if (!range.isInRange(start))
if (!range.isInRange((void *)start))
continue;
// Found the range containing the start
if (!range.isInRange(end))
if (!range.isInRange((void *)end))
{
con.print("Scanning %u bytes would read past end of memory "
"range.\n", bytes);
uint32_t diff = end - range.end;
uint32_t diff = end - (int)range.end;
con.print("Cutting bytes down by %u.\n", diff);
end = (uint32_t) range.end;
@ -242,7 +242,7 @@ DFhackCExport command_result df_vectors (Core * c, vector <string> & parameters)
{
uint32_t ptr = * ( (uint32_t*) pos);
if (inAnyRange(heap_ranges, ptr))
if (inAnyRange(heap_ranges, (void *) ptr))
{
t_vecTriplet* vec = (t_vecTriplet*) ptr;
@ -320,7 +320,7 @@ DFhackCExport command_result df_clearvec (Core * c, vector <string> & parameters
continue;
}
if (!inAnyRange(heap_ranges, addr))
if (!inAnyRange(heap_ranges, (void *) addr))
{
con << addr_str << " not in any valid address range." << std::endl;
continue;
@ -338,7 +338,7 @@ DFhackCExport command_result df_clearvec (Core * c, vector <string> & parameters
addr = * ( (uint32_t*) addr);
vec = (t_vecTriplet*) addr;
if (inAnyRange(heap_ranges, addr) && mightBeVec(heap_ranges, vec))
if (inAnyRange(heap_ranges, (void *) addr) && mightBeVec(heap_ranges, vec))
{
valid = true;
ptr = true;

@ -1 +1 @@
Subproject commit 355674a508d72349983455f04791b4481b6c1515
Subproject commit c114ec5f995aec69631187212254309464f82775

@ -1,76 +1,56 @@
// Dry Buckets : Remove all "water" objects from buckets scattered around the fortress
#include <iostream>
#include <iomanip>
#include <sstream>
#include <climits>
#include <vector>
#include <set>
using namespace std;
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <vector>
#include <string>
#include <algorithm>
#include <modules/Items.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "DataDefs.h"
#include "df/world.h"
#include "df/item.h"
#include "df/builtin_mats.h"
using std::string;
using std::vector;
using namespace DFHack;
DFhackCExport command_result df_drybuckets (Core * c, vector <string> & parameters);
using df::global::world;
DFhackCExport const char * plugin_name ( void )
DFhackCExport command_result df_drybuckets (Core * c, vector <string> & parameters)
{
return "drybuckets";
}
if (!parameters.empty())
return CR_WRONG_USAGE;
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("drybuckets", "Removes water from buckets.", df_drybuckets));
return CR_OK;
}
CoreSuspender suspend(c);
DFhackCExport command_result plugin_shutdown ( Core * c )
int dried_total = 0;
for (int i = 0; i < world->items.all.size(); i++)
{
df::item *item = world->items.all[i];
if ((item->getType() == df::item_type::LIQUID_MISC) && (item->getMaterial() == df::builtin_mats::WATER))
{
item->flags.bits.garbage_colect = 1;
dried_total++;
}
}
if (dried_total)
c->con.print("Done. %d buckets of water marked for emptying.\n", dried_total);
return CR_OK;
}
DFhackCExport command_result df_drybuckets (Core * c, vector <string> & parameters)
{
if(parameters.size() > 0)
{
string & p = parameters[0];
if(p == "?" || p == "help")
DFhackCExport const char * plugin_name ( void )
{
c->con.print("This utility removes all objects of type LIQUID_MISC:NONE and material WATER:NONE - that is, water stored in buckets.\n");
return CR_OK;
}
return "drybuckets";
}
c->Suspend();
DFHack::Items * Items = c->getItems();
vector <df_item *> p_items;
if(!Items->readItemVector(p_items))
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
c->con.printerr("Can't access the item vector.\n");
c->Resume();
return CR_FAILURE;
commands.clear();
commands.push_back(PluginCommand("drybuckets", "Removes water from buckets.", df_drybuckets));
return CR_OK;
}
std::size_t numItems = p_items.size();
int dried_total = 0;
for (std::size_t i = 0; i < numItems; i++)
{
df_item *item = p_items[i];
if ((item->getType() == Items::LIQUID_MISC) && (item->getMaterial() == Materials::WATER))
DFhackCExport command_result plugin_shutdown ( Core * c )
{
item->flags.garbage_colect = 1;
dried_total++;
}
}
c->Resume();
c->con.print("Done. %d buckets of water emptied.\n", dried_total);
return CR_OK;
}

@ -1,21 +1,20 @@
// foo
// vi:expandtab:sw=4
#include <iostream>
#include <vector>
#include <map>
#include <stddef.h>
#include <assert.h>
#include <string.h>
using namespace std;
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <VersionInfo.h>
#include <modules/Units.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "DataDefs.h"
#include "df/ui.h"
#include "df/world.h"
#include "df/unit.h"
using std::string;
using std::vector;
using namespace DFHack;
using df::global::world;
using df::global::ui;
// dfhack interface
DFhackCExport const char * plugin_name ( void )
{
@ -33,22 +32,16 @@ DFhackCExport command_result plugin_onupdate ( Core * c )
{
if (!enable_fastdwarf)
return CR_OK;
df_unit *cre;
DFHack::Units * cr = c->getUnits();
static vector <df_unit*> *v = cr->creatures;
uint32_t race = cr->GetDwarfRaceIndex();
uint32_t civ = cr->GetDwarfCivId();
if (!v)
{
c->con.printerr("Unable to locate creature vector. Fastdwarf cancelled.\n");
}
int32_t race = ui->race_id;
int32_t civ = ui->civ_id;
for (unsigned i=0 ; i<v->size() ; ++i)
for (int i = 0; i < world->units.all.size(); i++)
{
cre = v->at(i);
if (cre->race == race && cre->civ == civ && cre->job_counter > 0)
cre->job_counter = 0;
// could also patch the cre->current_job->counter
df::unit *unit = world->units.all[i];
if (unit->race == race && unit->civ_id == civ && unit->counters.job_counter > 0)
unit->counters.job_counter = 0;
// could also patch the unit->job.current_job->completion_timer
}
return CR_OK;
}
@ -65,7 +58,9 @@ static command_result fastdwarf (Core * c, vector <string> & parameters)
}
else
{
c->con.print("Makes your minions move at ludicrous speeds.\nActivate with 'fastdwarf 1', deactivate with 'fastdwarf 0'.\nCurrent state: %d.\n", enable_fastdwarf);
c->con.print("Makes your minions move at ludicrous speeds.\n"
"Activate with 'fastdwarf 1', deactivate with 'fastdwarf 0'.\n"
"Current state: %d.\n", enable_fastdwarf);
}
return CR_OK;

@ -6,12 +6,12 @@
#include <map>
#include <vector>
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Maps.h>
#include <modules/MapCache.h>
#include <modules/Gui.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Maps.h"
#include "modules/MapCache.h"
#include "modules/Gui.h"
using std::stack;
using MapExtras::MapCache;
using namespace DFHack;

@ -1,26 +1,22 @@
// I'll fix his little red wagon...
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include <DataDefs.h>
#include <df/world.h>
#include <df/historical_entity.h>
#include <df/entity_raw.h>
#include <df/creature_raw.h>
#include <df/caste_raw.h>
#include "DataDefs.h"
#include "df/world.h"
#include "df/historical_entity.h"
#include "df/entity_raw.h"
#include "df/creature_raw.h"
#include "df/caste_raw.h"
using std::string;
using std::vector;
using namespace DFHack;
using df::global::world;
using df::historical_entity;
using df::entity_raw_flags;
using df::creature_raw;
using df::creature_raw_flags;
command_result df_fixwagons (Core *c, vector<string> &parameters)
{
@ -29,11 +25,11 @@ command_result df_fixwagons (Core *c, vector<string> &parameters)
CoreSuspender suspend(c);
int32_t wagon_creature = -1, wagon_puller_creature = -1;
creature_raw *wagon, *wagon_puller;
df::creature_raw *wagon, *wagon_puller;
for (int i = 0; i < world->raws.creatures.all.size(); i++)
{
creature_raw *cr = world->raws.creatures.all[i];
if (cr->flags.is_set(creature_raw_flags::EQUIPMENT_WAGON) && (wagon_creature == -1))
df::creature_raw *cr = world->raws.creatures.all[i];
if (cr->flags.is_set(df::creature_raw_flags::EQUIPMENT_WAGON) && (wagon_creature == -1))
{
wagon = cr;
wagon_creature = i;
@ -58,8 +54,8 @@ command_result df_fixwagons (Core *c, vector<string> &parameters)
for (int i = 0; i < world->entities.all.size(); i++)
{
bool updated = false;
historical_entity *ent = world->entities.all[i];
if (!ent->entity_raw->flags.is_set(entity_raw_flags::COMMON_DOMESTIC_PULL))
df::historical_entity *ent = world->entities.all[i];
if (!ent->entity_raw->flags.is_set(df::entity_raw_flags::COMMON_DOMESTIC_PULL))
continue;
if (ent->resources.animals.wagon_races.size() == 0)
{

@ -1,93 +1,75 @@
// This tool counts static tiles and active flows of water and magma.
#include <iostream>
#include <vector>
#include <map>
#include <stddef.h>
#include <string.h>
using namespace std;
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Maps.h>
using namespace DFHack;
DFhackCExport command_result df_flows (Core * c, vector <string> & parameters);
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
DFhackCExport const char * plugin_name ( void )
{
return "flows";
}
#include "DataDefs.h"
#include "df/world.h"
#include "df/map_block.h"
#include "df/tile_liquid.h"
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("flows",
"Counts map blocks with flowing liquids.",
df_flows));
return CR_OK;
}
using std::string;
using std::vector;
using namespace DFHack;
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}
using df::global::world;
DFhackCExport command_result df_flows (Core * c, vector <string> & parameters)
{
uint32_t x_max,y_max,z_max;
DFHack::designations40d designations;
DFHack::Maps *Maps;
CoreSuspender suspend(c);
c->Suspend();
Maps = c->getMaps();
// init the map
if(!Maps->Start())
{
c->con.printerr("Can't init map.\n");
c->Resume();
return CR_FAILURE;
}
DFHack::t_blockflags bflags;
Maps->getSize(x_max,y_max,z_max);
// walk the map, count flowing tiles, magma, water
uint32_t flow1=0, flow2=0, flowboth=0, water=0, magma=0;
int flow1 = 0, flow2 = 0, flowboth = 0, water = 0, magma = 0;
c->con.print("Counting flows and liquids ...\n");
for(uint32_t x = 0; x< x_max;x++)
{
for(uint32_t y = 0; y< y_max;y++)
{
for(uint32_t z = 0; z< z_max;z++)
{
if(Maps->getBlock(x,y,z))
for (int i = 0; i < world->map.map_blocks.size(); i++)
{
Maps->ReadBlockFlags(x, y, z, bflags);
Maps->ReadDesignations(x, y, z, &designations);
if (bflags.bits.liquid_1)
df::map_block *cur = world->map.map_blocks[i];
if (cur->flags.is_set(df::block_flags::UpdateLiquid))
flow1++;
if (bflags.bits.liquid_2)
if (cur->flags.is_set(df::block_flags::UpdateLiquidTwice))
flow2++;
if (bflags.bits.liquid_1 && bflags.bits.liquid_2)
if (cur->flags.is_set(df::block_flags::UpdateLiquid) && cur->flags.is_set(df::block_flags::UpdateLiquidTwice))
flowboth++;
for (uint32_t i = 0; i < 16;i++) for (uint32_t j = 0; j < 16;j++)
for (int x = 0; x < 16; x++)
{
if (designations[i][j].bits.liquid_type == DFHack::liquid_magma)
for (int y = 0; y < 16; y++)
{
// only count tiles with actual liquid in them
if (cur->designation[x][y].bits.flow_size == 0)
continue;
if (cur->designation[x][y].bits.liquid_type == df::tile_liquid::Magma)
magma++;
if (designations[i][j].bits.liquid_type == DFHack::liquid_water)
if (cur->designation[x][y].bits.liquid_type == df::tile_liquid::Water)
water++;
}
}
}
c->con.print("Blocks with liquid_1=true: %d\n", flow1);
c->con.print("Blocks with liquid_2=true: %d\n", flow2);
c->con.print("Blocks with both: %d\n", flowboth);
c->con.print("Water tiles: %d\n", water);
c->con.print("Magma tiles: %d\n", magma);
return CR_OK;
}
DFhackCExport const char * plugin_name ( void )
{
return "flows";
}
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("flows",
"Counts map blocks with flowing liquids.",
df_flows));
return CR_OK;
}
c->con.print("Blocks with liquid_1=true: %d\n"
"Blocks with liquid_2=true: %d\n"
"Blocks with both: %d\n"
"Water tiles: %d\n"
"Magma tiles: %d\n"
,flow1, flow2, flowboth, water, magma
);
c->Resume();
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}

@ -1,56 +1,34 @@
// Designate all matching plants for gathering/cutting
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <stddef.h>
#include <assert.h>
#include <string.h>
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Maps.h>
#include <modules/Materials.h>
#include <modules/Vegetation.h>
#include <TileTypes.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "DataDefs.h"
#include "TileTypes.h"
#include "df/world.h"
#include "df/map_block.h"
#include "df/tile_dig_designation.h"
#include "df/plant_raw.h"
#include "modules/Vegetation.h"
#include <set>
using namespace std;
using std::string;
using std::vector;
using std::set;
using namespace DFHack;
DFhackCExport command_result df_getplants (Core * c, vector <string> & parameters);
DFhackCExport const char * plugin_name ( void )
{
return "getplants";
}
DFhackCExport command_result plugin_init ( Core * c, vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("getplants", "Cut down all of the specified trees or gather all of the specified shrubs", df_getplants));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}
using df::global::world;
DFhackCExport command_result df_getplants (Core * c, vector <string> & parameters)
{
uint32_t x_max,y_max,z_max;
designations40d designations;
tiletypes40d tiles;
t_blockflags blockflags;
string plantMatStr = "";
set<int> plantIDs;
set<string> plantNames;
bool deselect = false, exclude = false, treesonly = false, shrubsonly = false;
bool dirty = false;
int count = 0;
for (size_t i = 0; i < parameters.size(); i++)
{
@ -77,16 +55,16 @@ DFhackCExport command_result df_getplants (Core * c, vector <string> & parameter
exclude = true;
else plantNames.insert(parameters[i]);
}
c->Suspend();
Materials *mats = c->getMaterials();
for (vector<df_plant_type *>::const_iterator it = mats->df_organic->begin(); it != mats->df_organic->end(); it++)
CoreSuspender suspend(c);
for (int i = 0; i < world->raws.plants.all.size(); i++)
{
df_plant_type &plant = **it;
if (plantNames.find(plant.ID) != plantNames.end())
df::plant_raw *plant = world->raws.plants.all[i];
if (plantNames.find(plant->id) != plantNames.end())
{
plantNames.erase(plant.ID);
plantIDs.insert(it - mats->df_organic->begin());
plantNames.erase(plant->id);
plantIDs.insert(i);
}
}
if (plantNames.size() > 0)
@ -95,58 +73,33 @@ DFhackCExport command_result df_getplants (Core * c, vector <string> & parameter
for (set<string>::const_iterator it = plantNames.begin(); it != plantNames.end(); it++)
c->con.printerr(" %s", it->c_str());
c->con.printerr("\n");
c->Resume();
return CR_FAILURE;
}
if (plantIDs.size() == 0)
{
c->con.print("Valid plant IDs:\n");
for (vector<df_plant_type *>::const_iterator it = mats->df_organic->begin(); it != mats->df_organic->end(); it++)
for (int i = 0; i < world->raws.plants.all.size(); i++)
{
df_plant_type &plant = **it;
if (plant.flags.is_set(PLANT_GRASS))
df::plant_raw *plant = world->raws.plants.all[i];
if (plant->flags.is_set(df::plant_raw_flags::GRASS))
continue;
c->con.print("* (%s) %s - %s\n", plant.flags.is_set(PLANT_TREE) ? "tree" : "shrub", plant.ID.c_str(), plant.name.c_str());
c->con.print("* (%s) %s - %s\n", plant->flags.is_set(df::plant_raw_flags::TREE) ? "tree" : "shrub", plant->id.c_str(), plant->name.c_str());
}
c->Resume();
return CR_OK;
}
Maps *maps = c->getMaps();
// init the map
if (!maps->Start())
{
c->con.printerr("Can't init map.\n");
c->Resume();
return CR_FAILURE;
}
maps->getSize(x_max,y_max,z_max);
// walk the map
for (uint32_t x = 0; x < x_max; x++)
{
for (uint32_t y = 0; y < y_max; y++)
count = 0;
for (int i = 0; i < world->map.map_blocks.size(); i++)
{
for (uint32_t z = 0; z < z_max; z++)
{
if (maps->getBlock(x,y,z))
{
dirty = false;
maps->ReadDesignations(x,y,z, &designations);
maps->ReadTileTypes(x,y,z, &tiles);
maps->ReadBlockFlags(x,y,z, blockflags);
vector<df_plant *> *plants;
if (maps->ReadVegetation(x, y, z, plants))
{
for (vector<df_plant *>::const_iterator it = plants->begin(); it != plants->end(); it++)
df::map_block *cur = world->map.map_blocks[i];
bool dirty = false;
for (int j = 0; j < cur->plants.size(); j++)
{
const df_plant &plant = **it;
uint32_t tx = plant.x % 16;
uint32_t ty = plant.y % 16;
if (plantIDs.find(plant.material) != plantIDs.end())
const df_plant *plant = (df_plant *)cur->plants[i];
int x = plant->x % 16;
int y = plant->y % 16;
if (plantIDs.find(plant->material) != plantIDs.end())
{
if (exclude)
continue;
@ -156,42 +109,47 @@ DFhackCExport command_result df_getplants (Core * c, vector <string> & parameter
if (!exclude)
continue;
}
TileShape shape = tileShape(tiles[tx][ty]);
if (plant.is_shrub && (treesonly || shape != SHRUB_OK))
TileShape shape = tileShape(cur->tiletype[x][y]);
if (plant->is_shrub && (treesonly || shape != SHRUB_OK))
continue;
if (!plant.is_shrub && (shrubsonly || (shape != TREE_OK && shape != TREE_DEAD)))
if (!plant->is_shrub && (shrubsonly || (shape != TREE_OK && shape != TREE_DEAD)))
continue;
if (designations[tx][ty].bits.hidden)
if (cur->designation[x][y].bits.hidden)
continue;
if (deselect && designations[tx][ty].bits.dig != designation_no)
if (deselect && cur->designation[x][y].bits.dig != df::tile_dig_designation::No)
{
designations[tx][ty].bits.dig = designation_no;
cur->designation[x][y].bits.dig = df::tile_dig_designation::No;
dirty = true;
++count;
}
if (!deselect && designations[tx][ty].bits.dig != designation_default)
if (!deselect && cur->designation[x][y].bits.dig != df::tile_dig_designation::Default)
{
designations[tx][ty].bits.dig = designation_default;
cur->designation[x][y].bits.dig = df::tile_dig_designation::Default;
dirty = true;
++count;
}
}
}
// If anything was changed, write it all.
if (dirty)
{
blockflags.bits.designated = 1;
maps->WriteDesignations(x,y,z, &designations);
maps->WriteBlockFlags(x,y,z, blockflags);
dirty = false;
}
cur->flags.set(df::block_flags::Designated);
}
if (count)
c->con.print("Updated %d plant designations.\n", count);
return CR_OK;
}
DFhackCExport const char * plugin_name ( void )
{
return "getplants";
}
DFhackCExport command_result plugin_init ( Core * c, vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("getplants", "Cut down all of the specified trees or gather all of the specified shrubs", df_getplants));
return CR_OK;
}
c->Resume();
if (count)
c->con.print("Updated %d plant designations.\n", count);
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}

@ -1,10 +1,10 @@
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include <DataDefs.h>
#include <df/d_init.h>
#include "DataDefs.h"
#include "df/d_init.h"
using std::vector;
using std::string;
@ -51,10 +51,7 @@ DFhackCExport command_result twaterlvl(Core * c, vector <string> & parameters)
DFhackCExport command_result tidlers(Core * c, vector <string> & parameters)
{
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
df::d_init_idlers iv = df::d_init_idlers(int(d_init->idlers) + 1);
if (!d_init_idlers::is_valid(iv))
iv = ENUM_FIRST_ITEM(d_init_idlers);
d_init->idlers = iv;
c->con << "Toggled the display of idlers to " << ENUM_KEY_STR(d_init_idlers, iv) << endl;
d_init->idlers = ENUM_NEXT_ITEM(d_init_idlers, d_init->idlers);
c->con << "Toggled the display of idlers to " << ENUM_KEY_STR(d_init_idlers, d_init->idlers) << endl;
return CR_OK;
}

@ -0,0 +1,416 @@
#include "Core.h"
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "MiscUtils.h"
#include "modules/Materials.h"
#include "modules/Items.h"
#include "modules/Gui.h"
#include "modules/Job.h"
#include "DataDefs.h"
#include "df/world.h"
#include "df/ui.h"
#include "df/ui_build_selector.h"
#include "df/ui_build_item_req.h"
#include "df/build_req_choice_genst.h"
#include "df/build_req_choice_specst.h"
#include "df/building_workshopst.h"
#include "df/building_furnacest.h"
#include "df/job.h"
#include "df/job_item.h"
#include "df/job_list_link.h"
#include "df/item.h"
#include "df/tool_uses.h"
#include "df/general_ref.h"
using std::vector;
using std::string;
using std::endl;
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::ui;
using df::global::ui_build_selector;
using df::global::ui_workshop_job_cursor;
using df::global::job_next_id;
/* Plugin registration */
static bool job_material_hotkey(Core *c, df::viewscreen *top);
static command_result job_material(Core *c, vector <string> & parameters);
static command_result job_duplicate(Core *c, vector <string> & parameters);
static command_result job_cmd(Core *c, vector <string> & parameters);
DFhackCExport const char * plugin_name ( void )
{
return "jobutils";
}
DFhackCExport command_result plugin_init (Core *c, std::vector <PluginCommand> &commands)
{
commands.clear();
if (!world || !ui)
return CR_FAILURE;
commands.push_back(
PluginCommand(
"job", "General job query and manipulation.",
job_cmd, false,
" job [query]\n"
" Print details of the current job.\n"
" job list\n"
" Print details of all jobs in the workshop.\n"
" job item-material <item-idx> <material[:subtoken]>\n"
" Replace the exact material id in the job item.\n"
" job item-type <item-idx> <type[:subtype]>\n"
" Replace the exact item type id in the job item.\n"
)
);
if (ui_workshop_job_cursor || ui_build_selector) {
commands.push_back(
PluginCommand(
"job-material", "Alter the material of the selected job.",
job_material, job_material_hotkey,
" job-material <inorganic-token>\n"
"Intended to be used as a keybinding:\n"
" - In 'q' mode, when a job is highlighted within a workshop\n"
" or furnace, changes the material of the job.\n"
" - In 'b' mode, during selection of building components\n"
" positions the cursor over the first available choice\n"
" with the matching material.\n"
)
);
}
if (ui_workshop_job_cursor && job_next_id) {
commands.push_back(
PluginCommand(
"job-duplicate", "Duplicate the selected job in a workshop.",
job_duplicate, workshop_job_hotkey,
" - In 'q' mode, when a job is highlighted within a workshop\n"
" or furnace building, instantly duplicates the job.\n"
)
);
}
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}
/* UI state guards */
static bool job_material_hotkey(Core *c, df::viewscreen *top)
{
return workshop_job_hotkey(c, top) ||
build_selector_hotkey(c, top);
}
/* job-material implementation */
static command_result job_material_in_job(Core *c, MaterialInfo &new_mat)
{
df::job *job = getSelectedWorkshopJob(c);
if (!job)
return CR_FAILURE;
if (!new_mat.isValid() || new_mat.type != 0)
{
c->con.printerr("New job material isn't inorganic: %s\n",
new_mat.toString().c_str());
return CR_FAILURE;
}
MaterialInfo cur_mat(job);
if (!cur_mat.isValid() || cur_mat.type != 0)
{
c->con.printerr("Current job material isn't inorganic: %s\n",
cur_mat.toString().c_str());
return CR_FAILURE;
}
df::craft_material_class old_class = cur_mat.getCraftClass();
if (old_class == craft_material_class::None)
{
c->con.printerr("Unexpected current material type: %s\n",
cur_mat.toString().c_str());
return CR_FAILURE;
}
if (new_mat.getCraftClass() != old_class)
{
c->con.printerr("New material %s does not satisfy requirement: %s\n",
new_mat.toString().c_str(), ENUM_KEY_STR(craft_material_class, old_class));
return CR_FAILURE;
}
for (unsigned i = 0; i < job->job_items.size(); i++)
{
df::job_item *item = job->job_items[i];
MaterialInfo item_mat(item);
if (item_mat != cur_mat)
{
c->con.printerr("Job item %d has different material: %s\n",
i, item_mat.toString().c_str());
return CR_FAILURE;
}
if (!new_mat.matches(*item))
{
c->con.printerr("Job item %d requirements not satisfied by %s.\n",
i, new_mat.toString().c_str());
return CR_FAILURE;
}
}
// Apply the substitution
job->mat_type = new_mat.type;
job->mat_index = new_mat.index;
for (unsigned i = 0; i < job->job_items.size(); i++)
{
df::job_item *item = job->job_items[i];
item->mat_type = new_mat.type;
item->mat_index = new_mat.index;
}
c->con << "Applied material '" << new_mat.toString()
<< "' to job " << ENUM_KEY_STR(job_type,job->job_type) << endl;
return CR_OK;
}
static bool build_choice_matches(df::ui_build_item_req *req, df::build_req_choicest *choice,
MaterialInfo &new_mat, bool ignore_select)
{
if (VIRTUAL_CAST_VAR(gen, df::build_req_choice_genst, choice))
{
if (gen->mat_type == new_mat.type &&
gen->mat_index == new_mat.index &&
(ignore_select || gen->used_count < gen->candidates.size()))
{
return true;
}
}
else if (VIRTUAL_CAST_VAR(spec, df::build_req_choice_specst, choice))
{
if (spec->candidate &&
spec->candidate->getActualMaterial() == new_mat.type &&
spec->candidate->getActualMaterialIndex() == new_mat.index &&
(ignore_select || !req->candidate_selected[spec->candidate_id]))
{
return true;
}
}
return false;
}
static command_result job_material_in_build(Core *c, MaterialInfo &new_mat)
{
df::ui_build_selector *sel = ui_build_selector;
df::ui_build_item_req *req = sel->requirements[ui_build_selector->req_index];
// Loop through matching choices
bool matches = build_choice_matches(req, sel->choices[sel->sel_index], new_mat, true);
int size = sel->choices.size();
int base = (matches ? sel->sel_index + 1 : 0);
for (unsigned i = 0; i < size; i++)
{
int idx = (base + i) % size;
if (build_choice_matches(req, sel->choices[idx], new_mat, false))
{
sel->sel_index = idx;
return CR_OK;
}
}
c->con.printerr("Could not find material in list: %s\n", new_mat.toString().c_str());
return CR_FAILURE;
}
static command_result job_material(Core * c, vector <string> & parameters)
{
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
MaterialInfo new_mat;
if (parameters.size() == 1)
{
if (!new_mat.find(parameters[0])) {
c->con.printerr("Could not find material: %s\n", parameters[0].c_str());
return CR_WRONG_USAGE;
}
}
else
return CR_WRONG_USAGE;
if (ui->main.mode == ui_sidebar_mode::QueryBuilding)
return job_material_in_job(c, new_mat);
if (ui->main.mode == ui_sidebar_mode::Build)
return job_material_in_build(c, new_mat);
return CR_WRONG_USAGE;
}
/* job-duplicate implementation */
static command_result job_duplicate(Core * c, vector <string> & parameters)
{
if (!parameters.empty())
return CR_WRONG_USAGE;
df::job *job = getSelectedWorkshopJob(c);
if (!job)
return CR_FAILURE;
if (!job->misc_links.empty() ||
(job->job_items.empty() &&
job->job_type != job_type::CollectSand &&
job->job_type != job_type::CollectClay))
{
c->con.printerr("Cannot duplicate job %s\n", ENUM_KEY_STR(job_type,job->job_type));
return CR_FAILURE;
}
df::building *building = world->selected_building;
if (building->jobs.size() >= 10)
{
c->con.printerr("Job list is already full.\n");
return CR_FAILURE;
}
// Actually clone
df::job *pnew = cloneJobStruct(job);
linkJobIntoWorld(pnew);
vector_insert_at(building->jobs, ++*ui_workshop_job_cursor, pnew);
return CR_OK;
}
/* Main job command implementation */
static df::job_item *getJobItem(Core *c, df::job *job, std::string idx)
{
if (!job)
return NULL;
int v = atoi(idx.c_str());
if (v < 1 || v > job->job_items.size()) {
c->con.printerr("Invalid item index.\n");
return NULL;
}
return job->job_items[v-1];
}
static command_result job_cmd(Core * c, vector <string> & parameters)
{
CoreSuspender suspend(c);
std::string cmd = (parameters.empty() ? "query" : parameters[0]);
if (cmd == "query" || cmd == "list")
{
df::job *job = getSelectedWorkshopJob(c);
if (!job)
return CR_WRONG_USAGE;
if (cmd == "query") {
printJobDetails(c, job);
} else {
df::building *selected = world->selected_building;
for (unsigned i = 0; i < selected->jobs.size(); i++)
printJobDetails(c, selected->jobs[i]);
}
}
else if (cmd == "item-material")
{
if (parameters.size() != 3)
return CR_WRONG_USAGE;
df::job *job = getSelectedWorkshopJob(c);
df::job_item *item = getJobItem(c, job, parameters[1]);
if (!item)
return CR_WRONG_USAGE;
ItemTypeInfo iinfo(item);
MaterialInfo minfo;
if (!minfo.find(parameters[2])) {
c->con.printerr("Could not find the specified material.\n");
return CR_FAILURE;
}
if (minfo.isValid() && !iinfo.matches(*item, &minfo)) {
c->con.printerr("Material does not match the requirements.\n");
printJobDetails(c, job);
return CR_FAILURE;
}
if (job->mat_type != -1 &&
job->mat_type == item->mat_type &&
job->mat_index == item->mat_index)
{
job->mat_type = minfo.type;
job->mat_index = minfo.index;
}
item->mat_type = minfo.type;
item->mat_index = minfo.index;
c->con << "Job item updated." << endl;
if (item->item_type < 0 && minfo.isValid())
c->con.printerr("WARNING: Due to a probable bug, creature & plant material subtype\n"
" is ignored unless the item type is also specified.\n");
printJobDetails(c, job);
return CR_OK;
}
else if (cmd == "item-type")
{
if (parameters.size() != 3)
return CR_WRONG_USAGE;
df::job *job = getSelectedWorkshopJob(c);
df::job_item *item = getJobItem(c, job, parameters[1]);
if (!item)
return CR_WRONG_USAGE;
ItemTypeInfo iinfo;
MaterialInfo minfo(item);
if (!iinfo.find(parameters[2])) {
c->con.printerr("Could not find the specified item type.\n");
return CR_FAILURE;
}
if (iinfo.isValid() && !iinfo.matches(*item, &minfo)) {
c->con.printerr("Item type does not match the requirements.\n");
printJobDetails(c, job);
return CR_FAILURE;
}
item->item_type = iinfo.type;
item->item_subtype = iinfo.subtype;
c->con << "Job item updated." << endl;
printJobDetails(c, job);
return CR_OK;
}
else
return CR_WRONG_USAGE;
return CR_OK;
}

@ -11,14 +11,14 @@ using std::endl;
using std::set;
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Vegetation.h>
#include <modules/Maps.h>
#include <modules/Gui.h>
#include <TileTypes.h>
#include <modules/MapCache.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Vegetation.h"
#include "modules/Maps.h"
#include "modules/Gui.h"
#include "TileTypes.h"
#include "modules/MapCache.h"
using namespace MapExtras;
using namespace DFHack;

@ -2,12 +2,12 @@
using namespace std;
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include <vector>
#include <string>
#include <modules/World.h>
#include "modules/World.h"
#include <stdlib.h>
using namespace DFHack;
@ -166,7 +166,7 @@ DFhackCExport command_result mode (Core * c, vector <string> & parameters)
c->Suspend();
world->WriteGameMode(gm);
c->Resume();
cout << endl;
c->con << endl;
}
return CR_OK;
}

@ -6,14 +6,14 @@
#include <string>
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Vegetation.h>
#include <modules/Maps.h>
#include <modules/Gui.h>
#include <TileTypes.h>
#include <modules/MapCache.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Vegetation.h"
#include "modules/Maps.h"
#include "modules/Gui.h"
#include "TileTypes.h"
#include "modules/MapCache.h"
using std::vector;
using std::string;

@ -4,23 +4,22 @@
#include <iomanip>
#include <climits>
#include <vector>
#include <string>
#include <sstream>
#include <ctime>
#include <cstdio>
using namespace std;
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <vector>
#include <string>
#include <modules/Units.h>
#include <modules/Maps.h>
#include <modules/Gui.h>
#include <modules/Materials.h>
#include <modules/MapCache.h>
#include <MiscUtils.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Units.h"
#include "modules/Maps.h"
#include "modules/Gui.h"
#include "modules/Materials.h"
#include "modules/MapCache.h"
#include "MiscUtils.h"
using std::vector;
using std::string;
@ -54,7 +53,6 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
DFhackCExport command_result df_cprobe (Core * c, vector <string> & parameters)
{
Console & con = c->con;
BEGIN_PROBE:
c->Suspend();
DFHack::Gui *Gui = c->getGui();
DFHack::Units * cr = c->getUnits();
@ -135,7 +133,7 @@ DFhackCExport command_result df_probe (Core * c, vector <string> & parameters)
MapExtras::Block * b = mc.BlockAt(cursor/16);
mapblock40d & block = b->raw;
if(b)
if(b && b->valid)
{
con.print("block addr: 0x%x\n\n", block.origin);
/*
@ -285,6 +283,10 @@ DFhackCExport command_result df_probe (Core * c, vector <string> & parameters)
con << "mystery: " << block.mystery << endl;
con << std::endl;
}
else
{
con.printerr("No data.\n");
}
}
}
c->Resume();

@ -13,11 +13,14 @@
#include <vector>
using namespace std;
#include <DFHack.h>
#include <modules/MapCache.h>
#include "Core.h"
#include <Console.h>
#include <PluginManager.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/MapCache.h"
#include "DataDefs.h"
#include "df/world.h"
using namespace DFHack;
@ -85,10 +88,30 @@ struct compare_pair_second
}
};
static void printMatdata(DFHack::Console & con, const matdata &data)
{
con << std::setw(9) << data.count;
if(data.lower_z != data.upper_z)
con <<" Z:" << std::setw(4) << data.lower_z << ".." << data.upper_z << std::endl;
else
con <<" Z:" << std::setw(4) << data.lower_z << std::endl;
}
static int getValue(const df_inorganic_type &info)
{
return info.mat.MATERIAL_VALUE;
}
static int getValue(const df_plant_type &info)
{
return info.value;
}
// printMats() accepts a vector of pointers to t_matgloss so that it can
// deal t_matgloss and all subclasses.
template <typename T>
void printMats(DFHack::Console & con, MatMap &mat, std::vector<T*> &materials)
void printMats(DFHack::Console & con, MatMap &mat, std::vector<T*> &materials, bool show_value)
{
unsigned int total = 0;
MatSorter sorting_vector;
@ -108,12 +131,10 @@ void printMats(DFHack::Console & con, MatMap &mat, std::vector<T*> &materials)
continue;
}
T* mat = materials[it->first];
con << std::setw(25) << mat->ID << " : "
<< std::setw(9) << it->second.count;
if(it->second.lower_z != it->second.upper_z)
con <<" Z:" << std::setw(4) << it->second.lower_z << ".." << it->second.upper_z << std::endl;
else
con <<" Z:" << std::setw(4) << it->second.lower_z << std::endl;
con << std::setw(25) << mat->ID << " : ";
if (show_value)
con << std::setw(3) << getValue(*mat) << " : ";
printMatdata(con, it->second);
total += it->second.count;
}
@ -121,7 +142,7 @@ void printMats(DFHack::Console & con, MatMap &mat, std::vector<T*> &materials)
}
void printVeins(DFHack::Console & con, MatMap &mat_map,
DFHack::Materials* mats)
DFHack::Materials* mats, bool show_value)
{
MatMap ores;
MatMap gems;
@ -140,13 +161,13 @@ void printVeins(DFHack::Console & con, MatMap &mat_map,
}
con << "Ores:" << std::endl;
printMats(con, ores, *mats->df_inorganic);
printMats(con, ores, *mats->df_inorganic, show_value);
con << "Gems:" << std::endl;
printMats(con, gems, *mats->df_inorganic);
printMats(con, gems, *mats->df_inorganic, show_value);
con << "Other vein stone:" << std::endl;
printMats(con, rest, *mats->df_inorganic);
printMats(con, rest, *mats->df_inorganic, show_value);
}
DFhackCExport command_result prospector (Core * c, vector <string> & parameters);
@ -174,13 +195,18 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
bool showPlants = true;
bool showSlade = true;
bool showTemple = true;
bool showValue = false;
Console & con = c->con;
for(int i = 0; i < parameters.size();i++)
{
if (parameters[0] == "all")
if (parameters[i] == "all")
{
showHidden = true;
}
if (parameters[i] == "value")
{
showValue = true;
}
else if(parameters[i] == "help" || parameters[i] == "?")
{
c->con.print("Prints a big list of all the present minerals.\n"
@ -188,6 +214,7 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
"\n"
"Options:\n"
"all - Scan the whole map, as if it was revealed.\n"
"value - Show material value in the output.\n"
);
return CR_OK;
}
@ -231,6 +258,10 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
MatMap plantMats;
MatMap treeMats;
matdata liquidWater;
matdata liquidMagma;
matdata aquiferTiles;
if (!(showSlade && maps->ReadGlobalFeatures(globalFeatures)))
{
con.printerr("Unable to read global features; slade won't be listed!\n");
@ -282,6 +313,8 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
}
}
int global_z = df::global::world->map.region_z + z;
// Iterate over all the tiles in the block
for(uint32_t y = 0; y < 16; y++)
{
@ -301,6 +334,7 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
if (des.bits.water_table)
{
hasAquifer = true;
aquiferTiles.add(global_z);
}
// Check for lairs
@ -309,6 +343,15 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
hasLair = true;
}
// Check for liquid
if (des.bits.flow_size)
{
if (des.bits.liquid_type == liquid_magma)
liquidMagma.add(global_z);
else
liquidWater.add(global_z);
}
uint16_t type = b->TileTypeAt(coord);
const DFHack::TileRow *info = DFHack::getTileRow(type);
@ -330,17 +373,17 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
}
// Count the material type
baseMats[info->material].add(z);
baseMats[info->material].add(global_z);
// Find the type of the tile
switch (info->material)
{
case DFHack::SOIL:
case DFHack::STONE:
layerMats[b->baseMaterialAt(coord)].add(z);
layerMats[b->baseMaterialAt(coord)].add(global_z);
break;
case DFHack::VEIN:
veinMats[b->veinMaterialAt(coord)].add(z);
veinMats[b->veinMaterialAt(coord)].add(global_z);
break;
case DFHack::FEATSTONE:
if (blockFeatureLocal && des.bits.feature_local)
@ -348,7 +391,7 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
if (blockFeatureLocal->type == DFHack::feature_Adamantine_Tube
&& blockFeatureLocal->main_material == 0) // stone
{
veinMats[blockFeatureLocal->sub_material].add(z);
veinMats[blockFeatureLocal->sub_material].add(global_z);
}
else if (showTemple
&& blockFeatureLocal->type == DFHack::feature_Hell_Temple)
@ -361,7 +404,7 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
&& blockFeatureGlobal->type == DFHack::feature_Underworld
&& blockFeatureGlobal->main_material == 0) // stone
{
layerMats[blockFeatureGlobal->sub_material].add(z);
layerMats[blockFeatureGlobal->sub_material].add(global_z);
}
break;
case DFHack::OBSIDIAN:
@ -386,9 +429,9 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
if (showHidden || !b->DesignationAt(loc).bits.hidden)
{
if(plant.is_shrub)
plantMats[plant.material].add(z);
plantMats[plant.material].add(global_z);
else
treeMats[plant.material].add(z);
treeMats[plant.material].add(global_z);
}
}
}
@ -409,22 +452,44 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector <string> & par
con << std::setw(25) << DFHack::TileMaterialString[it->first] << " : " << it->second.count << std::endl;
}
if (liquidWater.count || liquidMagma.count)
{
con << std::endl << "Liquids:" << std::endl;
if (liquidWater.count)
{
con << std::setw(25) << "WATER" << " : ";
printMatdata(con, liquidWater);
}
if (liquidWater.count)
{
con << std::setw(25) << "MAGMA" << " : ";
printMatdata(con, liquidMagma);
}
}
con << std::endl << "Layer materials:" << std::endl;
printMats(con, layerMats, *mats->df_inorganic);
printMats(con, layerMats, *mats->df_inorganic, showValue);
printVeins(con, veinMats, mats);
printVeins(con, veinMats, mats, showValue);
if (showPlants)
{
con << "Shrubs:" << std::endl;
printMats(con, plantMats, *mats->df_organic);
printMats(con, plantMats, *mats->df_organic, showValue);
con << "Wood in trees:" << std::endl;
printMats(con, treeMats, *mats->df_organic);
printMats(con, treeMats, *mats->df_organic, showValue);
}
if (hasAquifer)
{
con << "Has aquifer" << std::endl;
con << "Has aquifer";
if (aquiferTiles.count)
{
con << " : ";
printMatdata(con, aquiferTiles);
}
else
con << std::endl;
}
if (hasDemonTemple)

@ -0,0 +1,82 @@
// All above-ground soil not covered by buildings will be covered with grass.
// Necessary for worlds generated prior to version 0.31.19 - otherwise, outdoor shrubs and trees no longer grow.
#include "Core.h"
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "DataDefs.h"
#include "df/world.h"
#include "df/map_block.h"
#include "TileTypes.h"
using std::string;
using std::vector;
using namespace DFHack;
using df::global::world;
DFhackCExport command_result df_regrass (Core * c, vector <string> & parameters)
{
if (!parameters.empty())
return CR_WRONG_USAGE;
CoreSuspender suspend(c);
int count = 0;
for (int i = 0; i < world->map.map_blocks.size(); i++)
{
df::map_block *cur = world->map.map_blocks[i];
for (int x = 0; x < 16; x++)
{
for (int y = 0; y < 16; y++)
{
if (DFHack::tileShape(cur->tiletype[x][y]) != DFHack::FLOOR)
continue;
if (DFHack::tileMaterial(cur->tiletype[x][y]) != DFHack::SOIL)
continue;
if (cur->designation[x][y].bits.subterranean)
continue;
if (cur->occupancy[x][y].bits.building)
continue;
switch (rand() % 8)
{
// light grass
case 0: cur->tiletype[x][y] = 0x015C; break;
case 1: cur->tiletype[x][y] = 0x015D; break;
case 2: cur->tiletype[x][y] = 0x015E; break;
case 3: cur->tiletype[x][y] = 0x015F; break;
// dark grass
case 4: cur->tiletype[x][y] = 0x018E; break;
case 5: cur->tiletype[x][y] = 0x018F; break;
case 6: cur->tiletype[x][y] = 0x0190; break;
case 7: cur->tiletype[x][y] = 0x0191; break;
}
count++;
}
}
}
if (count)
c->con.print("Regrew %d tiles of grass.\n", count);
return CR_OK;
}
DFhackCExport const char *plugin_name ( void )
{
return "regrass";
}
DFhackCExport command_result plugin_init (Core *c, std::vector<PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("regrass", "Regrows all surface grass, restoring outdoor plant growth for pre-0.31.19 worlds.", df_regrass));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( Core * c )
{
return CR_OK;
}

@ -1,12 +1,18 @@
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include <DataDefs.h>
#include <df/ui.h>
#include <df/world.h>
#include <df/squad.h>
#include "modules/Gui.h"
#include "DataDefs.h"
#include "df/ui.h"
#include "df/world.h"
#include "df/squad.h"
#include "df/unit.h"
#include "df/unit_soul.h"
#include "df/historical_figure.h"
#include "df/language_name.h"
#include <stdlib.h>
@ -30,7 +36,15 @@ DFhackCExport command_result plugin_init (Core *c, std::vector <PluginCommand> &
{
commands.clear();
if (world && ui) {
commands.push_back(PluginCommand("rename", "Rename various things.", rename));
commands.push_back(PluginCommand(
"rename", "Rename various things.", rename, false,
" rename squad <index> \"name\"\n"
" rename hotkey <index> \"name\"\n"
" (identified by ordinal index)\n"
" rename unit \"nickname\"\n"
" rename unit-profession \"custom profession\"\n"
" (a unit must be highlighted in the ui)\n"
));
}
return CR_OK;
}
@ -40,12 +54,17 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
return CR_OK;
}
static command_result usage(Core *c)
static void set_nickname(df::language_name *name, std::string nick)
{
c->con << "Usage:" << endl
<< " rename squad <index> \"name\"" << endl
<< " rename hotkey <index> \"name\"" << endl;
return CR_OK;
if (!name->has_name)
{
*name = df::language_name();
name->language = 0;
name->has_name = true;
}
name->nickname = nick;
}
static command_result rename(Core * c, vector <string> &parameters)
@ -56,34 +75,72 @@ static command_result rename(Core * c, vector <string> &parameters)
if (!parameters.empty())
cmd = parameters[0];
if (cmd == "squad") {
if (cmd == "squad")
{
if (parameters.size() != 3)
return usage(c);
return CR_WRONG_USAGE;
std::vector<df::squad*> &squads = world->squads.all;
int id = atoi(parameters[1].c_str());
if (id < 1 || id > squads.size()) {
c->con.printerr("Invalid squad index\n");
return usage(c);
return CR_WRONG_USAGE;
}
squads[id-1]->alias = parameters[2];
} else if (cmd == "hotkey") {
}
else if (cmd == "hotkey")
{
if (parameters.size() != 3)
return usage(c);
return CR_WRONG_USAGE;
int id = atoi(parameters[1].c_str());
if (id < 1 || id > 16) {
c->con.printerr("Invalid hotkey index\n");
return usage(c);
return CR_WRONG_USAGE;
}
ui->main.hotkeys[id-1].name = parameters[2];
} else {
}
else if (cmd == "unit")
{
if (parameters.size() != 2)
return CR_WRONG_USAGE;
df::unit *unit = getSelectedUnit(c);
if (!unit)
return CR_WRONG_USAGE;
// There are 3 copies of the name, and the one
// in the unit is not the authoritative one.
// This is the reason why military units often
// lose nicknames set from Dwarf Therapist.
set_nickname(&unit->name, parameters[1]);
if (unit->status.current_soul)
set_nickname(&unit->status.current_soul->name, parameters[1]);
df::historical_figure *figure = df::historical_figure::find(unit->hist_figure_id);
if (figure)
set_nickname(&figure->name, parameters[1]);
}
else if (cmd == "unit-profession")
{
if (parameters.size() != 2)
return CR_WRONG_USAGE;
df::unit *unit = getSelectedUnit(c);
if (!unit)
return CR_WRONG_USAGE;
unit->custom_profession = parameters[1];
}
else
{
if (!parameters.empty() && cmd != "?")
c->con.printerr("Invalid command: %s\n", cmd.c_str());
return usage(c);
return CR_WRONG_USAGE;
}
return CR_OK;

@ -3,13 +3,13 @@
#include <map>
#include <vector>
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Maps.h>
#include <modules/World.h>
#include <modules/MapCache.h>
#include <modules/Gui.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Maps.h"
#include "modules/World.h"
#include "modules/MapCache.h"
#include "modules/Gui.h"
using MapExtras::MapCache;
using namespace DFHack;

@ -8,14 +8,17 @@
#include "Core.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Materials.h"
#include "modules/Items.h"
#include "modules/World.h"
#include "modules/kitchen.h"
#include <VersionInfo.h>
#include "VersionInfo.h"
#include "df/world.h"
#include "df/plant_raw.h"
#include "df/item_flags.h"
using DFHack::t_materialType;
using DFHack::t_materialIndex;
using namespace DFHack;
using namespace DFHack::Simple;
using df::global::world;
const int buffer = 20; // seed number buffer - 20 is reasonable
bool running = false; // whether seedwatch is counting the seeds or not
@ -23,22 +26,22 @@ bool running = false; // whether seedwatch is counting the seeds or not
// abbreviations for the standard plants
std::map<std::string, std::string> abbreviations;
bool ignoreSeeds(DFHack::t_itemflags& f) // seeds with the following flags should not be counted
bool ignoreSeeds(df::item_flags& f) // seeds with the following flags should not be counted
{
return
f.dump ||
f.forbid ||
f.garbage_colect ||
f.hidden ||
f.hostile ||
f.on_fire ||
f.rotten ||
f.trader ||
f.in_building ||
f.in_job;
f.bits.dump ||
f.bits.forbid ||
f.bits.garbage_colect ||
f.bits.hidden ||
f.bits.hostile ||
f.bits.on_fire ||
f.bits.rotten ||
f.bits.trader ||
f.bits.in_building ||
f.bits.in_job;
};
void printHelp(DFHack::Core& core) // prints help
void printHelp(Core& core) // prints help
{
core.con.print(
"Watches the numbers of seeds available and enables/disables seed and plant cooking.\n"
@ -92,36 +95,32 @@ std::string searchAbbreviations(std::string in)
}
};
DFhackCExport DFHack::command_result df_seedwatch(DFHack::Core* pCore, std::vector<std::string>& parameters)
DFhackCExport command_result df_seedwatch(Core* pCore, std::vector<std::string>& parameters)
{
DFHack::Core& core = *pCore;
Core& core = *pCore;
if(!core.isValid())
{
return DFHack::CR_FAILURE;
return CR_FAILURE;
}
core.Suspend();
DFHack::Materials& materialsModule = *core.getMaterials();
std::vector<DFHack::t_matgloss> organics;
materialsModule.CopyOrganicMaterials(organics);
std::map<std::string, t_materialIndex> materialsReverser;
for(std::size_t i = 0; i < organics.size(); ++i)
for(std::size_t i = 0; i < world->raws.plants.all.size(); ++i)
{
materialsReverser[organics[i].id] = i;
materialsReverser[world->raws.plants.all[i]->id] = i;
}
DFHack::World *w = core.getWorld();
DFHack::t_gamemodes gm;
World *w = core.getWorld();
t_gamemodes gm;
w->ReadGameMode(gm);// FIXME: check return value
// if game mode isn't fortress mode
if(gm.g_mode != DFHack::GAMEMODE_DWARF || gm.g_type != DFHack::GAMETYPE_DWARF_MAIN)
if(gm.g_mode != GAMEMODE_DWARF || gm.g_type != GAMETYPE_DWARF_MAIN)
{
// just print the help
printHelp(core);
core.Resume();
return DFHack::CR_OK;
return CR_OK;
}
std::string par;
@ -147,8 +146,7 @@ DFhackCExport DFHack::command_result df_seedwatch(DFHack::Core* pCore, std::vect
}
else if(par == "clear")
{
DFHack::Kitchen::Exclusions kitchenExclusions(core);
kitchenExclusions.clearLimits();
Kitchen::clearLimits();
core.con.print("seedwatch watchlist cleared\n");
}
else if(par == "info")
@ -162,9 +160,8 @@ DFhackCExport DFHack::command_result df_seedwatch(DFHack::Core* pCore, std::vect
{
core.con.print("seedwatch is not supervising. Use 'seedwatch start' to start supervision.\n");
}
DFHack::Kitchen::Exclusions kitchenExclusions(core);
std::map<t_materialIndex, unsigned int> watchMap;
kitchenExclusions.fillWatchMap(watchMap);
Kitchen::fillWatchMap(watchMap);
if(watchMap.empty())
{
core.con.print("The watch list is empty.\n");
@ -174,16 +171,15 @@ DFhackCExport DFHack::command_result df_seedwatch(DFHack::Core* pCore, std::vect
core.con.print("The watch list is:\n");
for(std::map<t_materialIndex, unsigned int>::const_iterator i = watchMap.begin(); i != watchMap.end(); ++i)
{
core.con.print("%s : %u\n", organics[i->first].id.c_str(), i->second);
core.con.print("%s : %u\n", world->raws.plants.all[i->first]->id.c_str(), i->second);
}
}
}
else if(par == "debug")
{
DFHack::Kitchen::Exclusions kitchenExclusions(core);
std::map<t_materialIndex, unsigned int> watchMap;
kitchenExclusions.fillWatchMap(watchMap);
kitchenExclusions.debug_print();
Kitchen::fillWatchMap(watchMap);
Kitchen::debug_print(core);
}
/*
else if(par == "dumpmaps")
@ -208,8 +204,7 @@ DFhackCExport DFHack::command_result df_seedwatch(DFHack::Core* pCore, std::vect
std::string token = searchAbbreviations(par);
if(materialsReverser.count(token) > 0)
{
DFHack::Kitchen::Exclusions kitchenExclusions(core);
kitchenExclusions.removeLimit(materialsReverser[token]);
Kitchen::removeLimit(materialsReverser[token]);
core.con.print("%s is not being watched\n", token.c_str());
}
else
@ -225,8 +220,7 @@ DFhackCExport DFHack::command_result df_seedwatch(DFHack::Core* pCore, std::vect
{
for(std::map<std::string, std::string>::const_iterator i = abbreviations.begin(); i != abbreviations.end(); ++i)
{
DFHack::Kitchen::Exclusions kitchenExclusions(core);
if(materialsReverser.count(i->second) > 0) kitchenExclusions.setLimit(materialsReverser[i->second], limit);
if(materialsReverser.count(i->second) > 0) Kitchen::setLimit(materialsReverser[i->second], limit);
}
}
else
@ -234,8 +228,7 @@ DFhackCExport DFHack::command_result df_seedwatch(DFHack::Core* pCore, std::vect
std::string token = searchAbbreviations(parameters[0]);
if(materialsReverser.count(token) > 0)
{
DFHack::Kitchen::Exclusions kitchenExclusions(core);
kitchenExclusions.setLimit(materialsReverser[token], limit);
Kitchen::setLimit(materialsReverser[token], limit);
core.con.print("%s is being watched.\n", token.c_str());
}
else
@ -250,7 +243,7 @@ DFhackCExport DFHack::command_result df_seedwatch(DFHack::Core* pCore, std::vect
}
core.Resume();
return DFHack::CR_OK;
return CR_OK;
}
DFhackCExport const char* plugin_name(void)
@ -258,10 +251,10 @@ DFhackCExport const char* plugin_name(void)
return "seedwatch";
}
DFhackCExport DFHack::command_result plugin_init(DFHack::Core* pCore, std::vector<DFHack::PluginCommand>& commands)
DFhackCExport command_result plugin_init(Core* pCore, std::vector<PluginCommand>& commands)
{
commands.clear();
commands.push_back(DFHack::PluginCommand("seedwatch", "Switches cookery based on quantity of seeds, to keep reserves", df_seedwatch));
commands.push_back(PluginCommand("seedwatch", "Switches cookery based on quantity of seeds, to keep reserves", df_seedwatch));
// fill in the abbreviations map, with abbreviations for the standard plants
abbreviations["bs"] = "SLIVER_BARB";
abbreviations["bt"] = "TUBER_BLOATED";
@ -284,14 +277,14 @@ DFhackCExport DFHack::command_result plugin_init(DFHack::Core* pCore, std::vecto
abbreviations["vh"] = "HERB_VALLEY";
abbreviations["ws"] = "BERRIES_STRAW_WILD";
abbreviations["wv"] = "VINE_WHIP";
return DFHack::CR_OK;
return CR_OK;
}
DFhackCExport DFHack::command_result plugin_onstatechange(DFHack::Core* pCore, DFHack::state_change_event event)
DFhackCExport command_result plugin_onstatechange(Core* pCore, state_change_event event)
{
switch (event) {
case DFHack::SC_GAME_LOADED:
case DFHack::SC_GAME_UNLOADED:
case SC_GAME_LOADED:
case SC_GAME_UNLOADED:
if (running)
pCore->con.printerr("seedwatch deactivated due to game load/unload\n");
running = false;
@ -300,73 +293,67 @@ DFhackCExport DFHack::command_result plugin_onstatechange(DFHack::Core* pCore, D
break;
}
return DFHack::CR_OK;
return CR_OK;
}
DFhackCExport DFHack::command_result plugin_onupdate(DFHack::Core* pCore)
DFhackCExport command_result plugin_onupdate(Core* pCore)
{
if (running)
{
// reduce processing rate
static int counter = 0;
if (++counter < 500)
return DFHack::CR_OK;
return CR_OK;
counter = 0;
DFHack::Core& core = *pCore;
DFHack::World *w = core.getWorld();
DFHack::t_gamemodes gm;
Core& core = *pCore;
World *w = core.getWorld();
t_gamemodes gm;
w->ReadGameMode(gm);// FIXME: check return value
// if game mode isn't fortress mode
if(gm.g_mode != DFHack::GAMEMODE_DWARF || gm.g_type != DFHack::GAMETYPE_DWARF_MAIN)
if(gm.g_mode != GAMEMODE_DWARF || gm.g_type != GAMETYPE_DWARF_MAIN)
{
// stop running.
running = false;
core.con.printerr("seedwatch deactivated due to game mode switch\n");
return DFHack::CR_OK;
return CR_OK;
}
// this is dwarf mode, continue
std::map<t_materialIndex, unsigned int> seedCount; // the number of seeds
DFHack::Items& itemsModule = *core.getItems();
itemsModule.Start();
std::vector<DFHack::df_item*> items;
itemsModule.readItemVector(items);
DFHack::df_item * item;
// count all seeds and plants by RAW material
for(std::size_t i = 0; i < items.size(); ++i)
for(std::size_t i = 0; i < world->items.all.size(); ++i)
{
item = items[i];
df::item * item = world->items.all[i];
t_materialIndex materialIndex = item->getMaterialIndex();
switch(item->getType())
{
case DFHack::Items::SEEDS:
case df::item_type::SEEDS:
if(!ignoreSeeds(item->flags)) ++seedCount[materialIndex];
break;
case DFHack::Items::PLANT:
case df::item_type::PLANT:
break;
}
}
itemsModule.Finish();
DFHack::Kitchen::Exclusions kitchenExclusions(core);
std::map<t_materialIndex, unsigned int> watchMap;
kitchenExclusions.fillWatchMap(watchMap);
Kitchen::fillWatchMap(watchMap);
for(auto i = watchMap.begin(); i != watchMap.end(); ++i)
{
if(seedCount[i->first] <= i->second)
{
kitchenExclusions.denyPlantSeedCookery(i->first);
Kitchen::denyPlantSeedCookery(i->first);
}
else if(i->second + buffer < seedCount[i->first])
{
kitchenExclusions.allowPlantSeedCookery(i->first);
Kitchen::allowPlantSeedCookery(i->first);
}
}
}
return DFHack::CR_OK;
return CR_OK;
}
DFhackCExport DFHack::command_result plugin_shutdown(DFHack::Core* pCore)
DFhackCExport command_result plugin_shutdown(Core* pCore)
{
return DFHack::CR_OK;
return CR_OK;
}

@ -1,14 +1,14 @@
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <DataDefs.h>
#include <df/world.h>
#include <df/ui.h>
#include <df/building_stockpilest.h>
#include <df/selection_rect.h>
#include <df/viewscreen_dwarfmodest.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "DataDefs.h"
#include "df/world.h"
#include "df/ui.h"
#include "df/building_stockpilest.h"
#include "df/selection_rect.h"
#include "df/viewscreen_dwarfmodest.h"
using std::vector;
using std::string;

@ -1 +1 @@
Subproject commit 1b28039e2c93daa3c2f69f5e2a000ff8c96ee1f8
Subproject commit 92627e39cb3502812cd5a131716d3d1da8ef625a

@ -11,14 +11,14 @@ using std::endl;
using std::set;
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Vegetation.h>
#include <modules/Maps.h>
#include <modules/Gui.h>
#include <TileTypes.h>
#include <modules/MapCache.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Vegetation.h"
#include "modules/Maps.h"
#include "modules/Gui.h"
#include "TileTypes.h"
#include "modules/MapCache.h"
using namespace MapExtras;
using namespace DFHack;

@ -5,13 +5,13 @@
#include <map>
#include <vector>
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Maps.h>
#include <modules/World.h>
#include <modules/MapCache.h>
#include <modules/Gui.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Maps.h"
#include "modules/World.h"
#include "modules/MapCache.h"
#include "modules/Gui.h"
using MapExtras::MapCache;
using namespace DFHack;

@ -1,10 +1,10 @@
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Maps.h>
#include <modules/Gui.h>
#include <modules/MapCache.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Maps.h"
#include "modules/Gui.h"
#include "modules/MapCache.h"
#include <vector>
#include <cstdio>
#include <stack>
@ -459,6 +459,100 @@ static digmask diag5[5] =
},
};
static digmask diag5r[5] =
{
{
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
},
{
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
},
{
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
},
{
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
},
{
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
{0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0},
{0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0},
{0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0},
{0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0},
{1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1},
},
};
static digmask ladder[3] =
{
{
@ -517,6 +611,64 @@ static digmask ladder[3] =
},
};
static digmask ladderr[3] =
{
{
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
},
{
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
},
{
{0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0},
{0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},
},
};
static digmask all_tiles =
{
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
@ -560,7 +712,9 @@ enum explo_how
{
EXPLO_NOTHING,
EXPLO_DIAG5,
EXPLO_DIAG5R,
EXPLO_LADDER,
EXPLO_LADDERR,
EXPLO_CLEAR,
EXPLO_CROSS,
};
@ -653,6 +807,10 @@ DFhackCExport command_result expdig (Core * c, vector <string> & parameters)
{
how = EXPLO_DIAG5;
}
else if(parameters[i] == "diag5r")
{
how = EXPLO_DIAG5R;
}
else if(parameters[i] == "clear")
{
how = EXPLO_CLEAR;
@ -661,6 +819,10 @@ DFhackCExport command_result expdig (Core * c, vector <string> & parameters)
{
how = EXPLO_LADDER;
}
else if(parameters[i] == "ladderr")
{
how = EXPLO_LADDERR;
}
else if(parameters[i] == "cross")
{
how = EXPLO_CROSS;
@ -674,7 +836,9 @@ DFhackCExport command_result expdig (Core * c, vector <string> & parameters)
"There are two variables that can be set: pattern and filter.\n"
"Patterns:\n"
" diag5 = diagonals separated by 5 tiles\n"
" diag5r = diag5 rotated 90 degrees\n"
" ladder = A 'ladder' pattern\n"
"ladderr = ladder rotated 90 degrees\n"
" clear = Just remove all dig designations\n"
" cross = A cross, exactly in the middle of the map.\n"
"Filters:\n"
@ -719,6 +883,19 @@ DFhackCExport command_result expdig (Core * c, vector <string> & parameters)
}
}
}
else if(how == EXPLO_DIAG5R)
{
int which;
for(uint32_t x = 0; x < x_max; x++)
{
for(int32_t y = 0 ; y < y_max; y++)
{
which = (4*x + 1000-y) % 5;
stamp_pattern(maps, x,y_max - 1 - y, z_level, diag5r[which],
how, what, x_max, y_max);
}
}
}
else if(how == EXPLO_LADDER)
{
int which;
@ -732,6 +909,19 @@ DFhackCExport command_result expdig (Core * c, vector <string> & parameters)
}
}
}
else if(how == EXPLO_LADDERR)
{
int which;
for(int32_t y = 0 ; y < y_max; y++)
{
which = y % 3;
for(uint32_t x = 0; x < x_max; x++)
{
stamp_pattern(maps, x, y, z_level, ladderr[which],
how, what, x_max, y_max);
}
}
}
else if(how == EXPLO_CROSS)
{
// middle + recentering for the image

@ -8,11 +8,11 @@
#include <string.h>
using namespace std;
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include <modules/Graphic.h>
#include <modules/Gui.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Graphic.h"
#include "modules/Gui.h"
using namespace DFHack;
DFhackCExport command_result df_versionosd (Core * c, vector <string> & parameters);

@ -1,10 +1,10 @@
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include <vector>
#include <string>
#include <modules/World.h>
#include "modules/World.h"
using std::vector;
using std::string;

File diff suppressed because it is too large Load Diff