summaryrefslogtreecommitdiff
path: root/needs_porting
diff options
context:
space:
mode:
authorPetr Mrázek2012-03-01 00:01:24 +0100
committerPetr Mrázek2012-03-01 00:01:24 +0100
commit07b4044336176e8277f3adaa2e03c406e77b6b76 (patch)
tree9019b2ea3ff92b8c77dc464c46d8026d63bbd7ac /needs_porting
parent1f2782d5b86ee62d821ec0c7e33833048fc06b20 (diff)
downloaddfhack-07b4044336176e8277f3adaa2e03c406e77b6b76.tar.gz
dfhack-07b4044336176e8277f3adaa2e03c406e77b6b76.tar.bz2
dfhack-07b4044336176e8277f3adaa2e03c406e77b6b76.tar.xz
Nuke more!
Diffstat (limited to 'needs_porting')
-rw-r--r--needs_porting/SegmentedFinder.h543
-rw-r--r--needs_porting/attachtest.py53
-rw-r--r--needs_porting/copypaste.cpp479
-rw-r--r--needs_porting/creaturemanager.cpp1428
-rw-r--r--needs_porting/dfbauxite.cpp161
-rw-r--r--needs_porting/dfstatus.cpp206
-rw-r--r--needs_porting/digger.cpp363
-rw-r--r--needs_porting/digger2.cpp180
-rw-r--r--needs_porting/digpattern.cpp259
-rw-r--r--needs_porting/drawtile.cpp315
-rw-r--r--needs_porting/fix-3708.cpp217
-rw-r--r--needs_porting/hellhole.cpp1281
-rw-r--r--needs_porting/hotkeynotedump.py20
-rw-r--r--needs_porting/incrementalsearch.cpp1064
-rw-r--r--needs_porting/itemdesignator.cpp148
-rw-r--r--needs_porting/lair.cpp74
-rw-r--r--needs_porting/position.py71
-rw-r--r--needs_porting/reveal.py93
-rw-r--r--needs_porting/treedump.py52
-rw-r--r--needs_porting/veinlook.cpp1117
-rw-r--r--needs_porting/veinswap.cpp229
21 files changed, 8353 insertions, 0 deletions
diff --git a/needs_porting/SegmentedFinder.h b/needs_porting/SegmentedFinder.h
new file mode 100644
index 00000000..b3fe5aec
--- /dev/null
+++ b/needs_porting/SegmentedFinder.h
@@ -0,0 +1,543 @@
+#ifndef SEGMENTED_FINDER_H
+#define SEGMENTED_FINDER_H
+#include <malloc.h>
+#include <iosfwd>
+#include <iterator>
+
+class SegmentedFinder;
+class SegmentFinder
+{
+ public:
+ SegmentFinder(DFHack::t_memrange & mr, DFHack::Context * DF, SegmentedFinder * SF)
+ {
+ _DF = DF;
+ mr_ = mr;
+ valid=false;
+ if(mr.valid)
+ {
+ mr_.buffer = (uint8_t *)malloc (mr_.end - mr_.start);
+ _SF = SF;
+ try
+ {
+ DF->ReadRaw(mr_.start,(mr_.end - mr_.start),mr_.buffer);
+ valid = true;
+ }
+ catch (DFHack::Error::MemoryAccessDenied &)
+ {
+ free(mr_.buffer);
+ valid = false;
+ mr.valid = false; // mark the range passed in as bad
+ cout << "Range 0x" << hex << mr_.start << " - 0x" << mr_.end;
+
+ if (strlen(mr_.name) != 0)
+ cout << " (" << mr_.name << ")";
+
+ cout << dec << " not readable." << endl;
+ cout << "Skipping this range on future scans." << endl;
+ }
+ }
+ }
+ ~SegmentFinder()
+ {
+ if(valid)
+ free(mr_.buffer);
+ }
+ bool isValid()
+ {
+ return valid;
+ }
+ template <class needleType, class hayType, typename comparator >
+ bool Find (needleType needle, const uint8_t increment , vector <uint64_t> &newfound, comparator oper)
+ {
+ if(!valid) return !newfound.empty();
+ //loop
+ for(uint64_t offset = 0; offset < (mr_.end - mr_.start) - sizeof(hayType); offset += increment)
+ {
+ if( oper(_SF,(hayType *)(mr_.buffer + offset), needle) )
+ newfound.push_back(mr_.start + offset);
+ }
+ return !newfound.empty();
+ }
+
+ template < class needleType, class hayType, typename comparator >
+ uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length)
+ {
+ if(!valid) return 0;
+ uint64_t stopper = min((mr_.end - mr_.start) - sizeof(hayType), (start - mr_.start) - sizeof(hayType) + length);
+ //loop
+ for(uint64_t offset = start - mr_.start; offset < stopper; offset +=1)
+ {
+ if( oper(_SF,(hayType *)(mr_.buffer + offset), needle) )
+ return mr_.start + offset;
+ }
+ return 0;
+ }
+
+ template <class needleType, class hayType, typename comparator >
+ bool Filter (needleType needle, vector <uint64_t> &found, vector <uint64_t> &newfound, comparator oper)
+ {
+ if(!valid) return !newfound.empty();
+ for( uint64_t i = 0; i < found.size(); i++)
+ {
+ if(mr_.isInRange(found[i]))
+ {
+ uint64_t corrected = found[i] - mr_.start;
+ if( oper(_SF,(hayType *)(mr_.buffer + corrected), needle) )
+ newfound.push_back(found[i]);
+ }
+ }
+ return !newfound.empty();
+ }
+ private:
+ friend class SegmentedFinder;
+ SegmentedFinder * _SF;
+ DFHack::Context * _DF;
+ DFHack::t_memrange mr_;
+ bool valid;
+};
+
+class SegmentedFinder
+{
+ public:
+ SegmentedFinder(vector <DFHack::t_memrange>& ranges, DFHack::Context * DF)
+ {
+ _DF = DF;
+ for(size_t i = 0; i < ranges.size(); i++)
+ {
+ segments.push_back(new SegmentFinder(ranges[i], DF, this));
+ }
+ }
+ ~SegmentedFinder()
+ {
+ for(size_t i = 0; i < segments.size(); i++)
+ {
+ delete segments[i];
+ }
+ }
+ SegmentFinder * getSegmentForAddress (uint64_t addr)
+ {
+ for(size_t i = 0; i < segments.size(); i++)
+ {
+ if(segments[i]->mr_.isInRange(addr))
+ {
+ return segments[i];
+ }
+ }
+ return 0;
+ }
+ template <class needleType, class hayType, typename comparator >
+ bool Find (const needleType needle, const uint8_t increment, vector <uint64_t> &found, comparator oper)
+ {
+ found.clear();
+ for(size_t i = 0; i < segments.size(); i++)
+ {
+ segments[i]->Find<needleType,hayType,comparator>(needle, increment, found, oper);
+ }
+ return !(found.empty());
+ }
+
+ template < class needleType, class hayType, typename comparator >
+ uint64_t FindInRange (needleType needle, comparator oper, uint64_t start, uint64_t length)
+ {
+ SegmentFinder * sf = getSegmentForAddress(start);
+ if(sf)
+ {
+ return sf->FindInRange<needleType,hayType,comparator>(needle, oper, start, length);
+ }
+ return 0;
+ }
+
+ template <class needleType, class hayType, typename comparator >
+ bool Filter (const needleType needle, vector <uint64_t> &found, comparator oper)
+ {
+ vector <uint64_t> newfound;
+ for(size_t i = 0; i < segments.size(); i++)
+ {
+ segments[i]->Filter<needleType,hayType,comparator>(needle, found, newfound, oper);
+ }
+ found.clear();
+ found = newfound;
+ return !(found.empty());
+ }
+
+ template <class needleType, class hayType, typename comparator >
+ bool Incremental (needleType needle, const uint8_t increment ,vector <uint64_t> &found, comparator oper)
+ {
+ if(found.empty())
+ {
+ return Find <needleType, hayType, comparator>(needle,increment,found,oper);
+ }
+ else
+ {
+ return Filter <needleType, hayType, comparator>(needle,found,oper);
+ }
+ }
+
+ template <typename T>
+ T * Translate(uint64_t address)
+ {
+ for(size_t i = 0; i < segments.size(); i++)
+ {
+ if(segments[i]->mr_.isInRange(address))
+ {
+ return (T *) (segments[i]->mr_.buffer + address - segments[i]->mr_.start);
+ }
+ }
+ return 0;
+ }
+
+ template <typename T>
+ T Read(uint64_t address)
+ {
+ return *Translate<T>(address);
+ }
+
+ template <typename T>
+ bool Read(uint64_t address, T& target)
+ {
+ T * test = Translate<T>(address);
+ if(test)
+ {
+ target = *test;
+ return true;
+ }
+ return false;
+ }
+ private:
+ DFHack::Context * _DF;
+ vector <SegmentFinder *> segments;
+};
+
+template <typename T>
+bool equalityP (SegmentedFinder* s, T *x, T y)
+{
+ return (*x) == y;
+}
+
+struct vecTriplet
+{
+ uint32_t start;
+ uint32_t finish;
+ uint32_t alloc_finish;
+};
+
+template <typename Needle>
+bool vectorLength (SegmentedFinder* s, vecTriplet *x, Needle &y)
+{
+ if(x->start <= x->finish && x->finish <= x->alloc_finish)
+ if((x->finish - x->start) == y)
+ return true;
+ return false;
+}
+
+// find a vector of 32bit pointers, where an object pointed to has a string 'y' as the first member
+bool vectorString (SegmentedFinder* s, vecTriplet *x, const char *y)
+{
+ uint32_t object_ptr;
+ // iterate over vector of pointers
+ for(uint32_t idx = x->start; idx < x->finish; idx += sizeof(uint32_t))
+ {
+ // deref ptr idx, get ptr to object
+ if(!s->Read(idx,object_ptr))
+ {
+ return false;
+ }
+ // deref ptr to first object, get ptr to string
+ uint32_t string_ptr;
+ if(!s->Read(object_ptr,string_ptr))
+ return false;
+ // get string location in our local cache
+ char * str = s->Translate<char>(string_ptr);
+ if(!str)
+ return false;
+ if(strcmp(y, str) == 0)
+ return true;
+ }
+ return false;
+}
+
+// find a vector of 32bit pointers, where the first object pointed to has a string 'y' as the first member
+bool vectorStringFirst (SegmentedFinder* s, vecTriplet *x, const char *y)
+{
+ uint32_t object_ptr;
+ uint32_t idx = x->start;
+ // deref ptr idx, get ptr to object
+ if(!s->Read(idx,object_ptr))
+ {
+ return false;
+ }
+ // deref ptr to first object, get ptr to string
+ uint32_t string_ptr;
+ if(!s->Read(object_ptr,string_ptr))
+ return false;
+ // get string location in our local cache
+ char * str = s->Translate<char>(string_ptr);
+ if(!str)
+ return false;
+ if(strcmp(y, str) == 0)
+ return true;
+ return false;
+}
+
+// test if the address is between vector.start and vector.finish
+// not very useful alone, but could be a good step to filter some things
+bool vectorAddrWithin (SegmentedFinder* s, vecTriplet *x, uint32_t address)
+{
+ if(address < x->finish && address >= x->start)
+ return true;
+ return false;
+}
+
+// test if an object address is within the vector of pointers
+//
+bool vectorOfPtrWithin (SegmentedFinder* s, vecTriplet *x, uint32_t address)
+{
+ uint32_t object_ptr;
+ for(uint32_t idx = x->start; idx < x->finish; idx += sizeof(uint32_t))
+ {
+ if(!s->Read(idx,object_ptr))
+ {
+ return false;
+ }
+ if(object_ptr == address)
+ return true;
+ }
+ return false;
+}
+
+bool vectorAll (SegmentedFinder* s, vecTriplet *x, int )
+{
+ if(x->start <= x->finish && x->finish <= x->alloc_finish)
+ {
+ if(s->getSegmentForAddress(x->start) == s->getSegmentForAddress(x->finish)
+ && s->getSegmentForAddress(x->finish) == s->getSegmentForAddress(x->alloc_finish))
+ return true;
+ }
+ return false;
+}
+
+class Bytestreamdata
+{
+ public:
+ void * object;
+ uint32_t length;
+ uint32_t allocated;
+ uint32_t n_used;
+};
+
+class Bytestream
+{
+public:
+ Bytestream(void * obj, uint32_t len, bool alloc = false)
+ {
+ d = new Bytestreamdata();
+ d->allocated = alloc;
+ d->object = obj;
+ d->length = len;
+ d->n_used = 1;
+ constant = false;
+ }
+ Bytestream()
+ {
+ d = new Bytestreamdata();
+ d->allocated = false;
+ d->object = 0;
+ d->length = 0;
+ d->n_used = 1;
+ constant = false;
+ }
+ Bytestream( Bytestream & bs)
+ {
+ d =bs.d;
+ d->n_used++;
+ constant = false;
+ }
+ Bytestream( const Bytestream & bs)
+ {
+ d =bs.d;
+ d->n_used++;
+ constant = true;
+ }
+ ~Bytestream()
+ {
+ d->n_used --;
+ if(d->allocated && d->object && d->n_used == 0)
+ {
+ free (d->object);
+ free (d);
+ }
+ }
+ bool Allocate(size_t bytes)
+ {
+ if(constant)
+ return false;
+ if(d->allocated)
+ {
+ d->object = realloc(d->object, bytes);
+ }
+ else
+ {
+ d->object = malloc( bytes );
+ }
+
+ if(d->object)
+ {
+ d->allocated = bytes;
+ return true;
+ }
+ else
+ {
+ d->allocated = 0;
+ return false;
+ }
+ }
+ template < class T >
+ bool insert( T what )
+ {
+ if(constant)
+ return false;
+ if(d->length+sizeof(T) >= d->allocated)
+ Allocate((d->length+sizeof(T)) * 2);
+ (*(T *)( (uint64_t)d->object + d->length)) = what;
+ d->length += sizeof(T);
+ return true;
+ }
+ Bytestreamdata * d;
+ bool constant;
+};
+std::ostream& operator<< ( std::ostream& out, Bytestream& bs )
+{
+ if(bs.d->object)
+ {
+ out << "bytestream " << dec << bs.d->length << "/" << bs.d->allocated << " bytes" << endl;
+ for(size_t i = 0; i < bs.d->length; i++)
+ {
+ out << hex << (int) ((uint8_t *) bs.d->object)[i] << " ";
+ }
+ out << endl;
+ }
+ else
+ {
+ out << "empty bytestresm" << endl;
+ }
+ return out;
+}
+
+std::istream& operator>> ( std::istream& out, Bytestream& bs )
+{
+ string read;
+ while(!out.eof())
+ {
+ string tmp;
+ out >> tmp;
+ read.append(tmp);
+ }
+ cout << read << endl;
+ bs.d->length = 0;
+ size_t first = read.find_first_of("\"");
+ size_t last = read.find_last_of("\"");
+ size_t start = first + 1;
+ if(first == read.npos)
+ {
+ std::transform(read.begin(), read.end(), read.begin(), (int(*)(int)) tolower);
+ bs.Allocate(read.size()); // overkill. size / 2 should be good, but this is safe
+ int state = 0;
+ char big = 0;
+ char small = 0;
+ string::iterator it = read.begin();
+ // iterate through string, construct a bytestream out of 00-FF bytes
+ while(it != read.end())
+ {
+ char reads = *it;
+ if((reads >='0' && reads <= '9'))
+ {
+ if(state == 0)
+ {
+ big = reads - '0';
+ state = 1;
+ }
+ else if(state == 1)
+ {
+ small = reads - '0';
+ state = 0;
+ bs.insert<char>(big*16 + small);
+ }
+ }
+ if((reads >= 'a' && reads <= 'f'))
+ {
+ if(state == 0)
+ {
+ big = reads - 'a' + 10;
+ state = 1;
+ }
+ else if(state == 1)
+ {
+ small = reads - 'a' + 10;
+ state = 0;
+ bs.insert<char>(big*16 + small);
+ }
+ }
+ it++;
+ }
+ // we end in state= 1. should we add or should we trim... or throw errors?
+ // I decided on adding
+ if (state == 1)
+ {
+ small = 0;
+ bs.insert<char>(big*16 + small);
+ }
+ }
+ else
+ {
+ if(last == first)
+ {
+ // only one "
+ last = read.size();
+ }
+ size_t length = last - start;
+ // construct bytestream out of stuff between ""
+ bs.d->length = length;
+ if(length)
+ {
+ // todo: Bytestream should be able to handle this without external code
+ bs.Allocate(length);
+ bs.d->length = length;
+ const char* strstart = read.c_str();
+ memcpy(bs.d->object, strstart + start, length);
+ }
+ else
+ {
+ bs.d->object = 0;
+ }
+ }
+ cout << bs;
+ return out;
+}
+
+bool findBytestream (SegmentedFinder* s, void *addr, Bytestream compare )
+{
+ if(memcmp(addr, compare.d->object, compare.d->length) == 0)
+ return true;
+ return false;
+}
+
+bool findString (SegmentedFinder* s, uint32_t *addr, const char * compare )
+{
+ // read string pointer, translate to local scheme
+ char *str = s->Translate<char>(*addr);
+ // verify
+ if(!str)
+ return false;
+ if(strcmp(str, compare) == 0)
+ return true;
+ return false;
+}
+
+bool findStrBuffer (SegmentedFinder* s, uint32_t *addr, const char * compare )
+{
+ if(memcmp((const char *)addr, compare, strlen(compare)) == 0)
+ return true;
+ return false;
+}
+
+#endif // SEGMENTED_FINDER_H
diff --git a/needs_porting/attachtest.py b/needs_porting/attachtest.py
new file mode 100644
index 00000000..e734e1ba
--- /dev/null
+++ b/needs_porting/attachtest.py
@@ -0,0 +1,53 @@
+import time
+from pydfhack import ContextManager
+
+df_cm = ContextManager("Memory.xml")
+df = None
+
+def test_attach():
+ global df
+
+ if not df:
+ df = df_cm.get_single_context()
+
+ if not df.attach():
+ print "Unable to attach!"
+ return False
+ elif not df.detach():
+ print "Unabled to detach!"
+ return False
+ else:
+ return True
+
+def suspend_test():
+ global df
+
+ if not df:
+ df = df_cm.get_single_context()
+
+ print "Testing suspend/resume"
+
+ df.attach()
+
+ t1 = time.time()
+
+ for i in xrange(1000):
+ df.suspend()
+
+ if i % 10 == 0:
+ print "%i%%" % (i / 10.0,)
+
+ df.resume()
+
+ t2 = time.time()
+
+ df.detach()
+
+ print "suspend test done in $0.9f seconds" % (t2 - t1)
+
+if __name__ == "__main__":
+ if test_attach():
+ suspend_test()
+
+ print "Done. Press any key to continue"
+ raw_input() \ No newline at end of file
diff --git a/needs_porting/copypaste.cpp b/needs_porting/copypaste.cpp
new file mode 100644
index 00000000..4f584241
--- /dev/null
+++ b/needs_porting/copypaste.cpp
@@ -0,0 +1,479 @@
+// Console version of DF copy paste, proof of concept
+// By belal
+
+#include <iostream>
+#include <iomanip>
+#include <climits>
+#include <vector>
+#include <sstream>
+#include <ctime>
+#include <cstdio>
+#include <fstream>
+
+#define DFHACK_WANT_MISCUTILS
+#define DFHACK_WANT_TILETYPES
+#include <DFHack.h>
+#include "modules/WindowIO.h"
+
+using namespace DFHack;
+//bool waitTillCursorState(DFHack::Context *DF, bool On);
+//bool waitTillCursorPositionState(DFHack::Context *DF, int32_t x,int32_t y, int32_t z);
+
+//change this if you are having problems getting correct results, lower if you would like to go faster
+//const int WAIT_AMT = 25;
+
+void sort(uint32_t &a,uint32_t &b)
+{
+ if(a > b){
+ uint32_t c = b;
+ b = a;
+ a = c;
+ }
+}
+void sort(int32_t &a,int32_t &b)
+{
+ if(a > b){
+ int16_t c = b;
+ b = a;
+ a = c;
+ }
+}
+void printVecOfVec(ostream &out, vector<vector<vector<string> > >vec,char sep)
+{
+ for(size_t k=0;k<vec.size();k++)
+ {
+ for(size_t i =0;i<vec[k].size();i++)
+ {
+ for(size_t j=0;j<vec[k][i].size();j++)
+ {
+ out << vec[k][i][j];
+ if(j==vec[k][i].size()-1)
+ {
+ out << "\n";
+ }
+ else
+ {
+ out << sep;
+ }
+ }
+ }
+ out << "#<\n";
+ }
+}
+int main (int numargs, const char ** args)
+{
+ map<string, string> buildCommands;
+ buildCommands["building_stockpilest"]="";
+ buildCommands["building_zonest"]="";
+ buildCommands["building_construction_blueprintst"]="";
+ buildCommands["building_wagonst"]="";
+ buildCommands["building_armor_standst"]="a";
+ buildCommands["building_bedst"]="b";
+ buildCommands["building_seatst"]="c";
+ buildCommands["building_burial_receptaclest"]="n";
+ buildCommands["building_doorst"]="d";
+ buildCommands["building_floodgatest"]="x";
+ buildCommands["building_floor_hatchst"]="H";
+ buildCommands["building_wall_gratest"]="W";
+ buildCommands["building_floor_gratest"]="G";
+ buildCommands["building_vertical_barsst"]="B";
+ buildCommands["building_floor_barsst"]="alt-b";
+ buildCommands["building_cabinetst"]="f";
+ buildCommands["building_containerst"]="h";
+ buildCommands["building_shopst"]="";
+ buildCommands["building_workshopst"]="";
+ buildCommands["building_alchemists_laboratoryst"]="wa";
+ buildCommands["building_carpenters_workshopst"]="wc";
+ buildCommands["building_farmers_workshopst"]="ww";
+ buildCommands["building_masons_workshopst"]="wm";
+ buildCommands["building_craftdwarfs_workshopst"]="wr";
+ buildCommands["building_jewelers_workshopst"]="wj";
+ buildCommands["building_metalsmiths_workshopst"]="wf";
+ buildCommands["building_magma_forgest"]="";
+ buildCommands["building_bowyers_workshopst"]="wb";
+ buildCommands["building_mechanics_workshopst"]="wt";
+ buildCommands["building_siege_workshopst"]="ws";
+ buildCommands["building_butchers_shopst"]="wU";
+ buildCommands["building_leather_worksst"]="we";
+ buildCommands["building_tanners_shopst"]="wn";
+ buildCommands["building_clothiers_shopst"]="wk";
+ buildCommands["building_fisheryst"]="wh";
+ buildCommands["building_stillst"]="wl";
+ buildCommands["building_loomst"]="wo";
+ buildCommands["building_quernst"]="wq";
+ buildCommands["building_kennelsst"]="k";
+ buildCommands["building_kitchenst"]="wz";
+ buildCommands["building_asheryst"]="wy";
+ buildCommands["building_dyers_shopst"]="wd";
+ buildCommands["building_millstonest"]="wM";
+ buildCommands["building_farm_plotst"]="p";
+ buildCommands["building_weapon_rackst"]="r";
+ buildCommands["building_statuest"]="s";
+ buildCommands["building_tablest"]="t";
+ buildCommands["building_paved_roadst"]="o";
+ buildCommands["building_bridgest"]="g";
+ buildCommands["building_wellst"]="l";
+ buildCommands["building_siege enginest"]="i";
+ buildCommands["building_catapultst"]="ic";
+ buildCommands["building_ballistast"]="ib";
+ buildCommands["building_furnacest"]="";
+ buildCommands["building_wood_furnacest"]="ew";
+ buildCommands["building_smelterst"]="es";
+ buildCommands["building_glass_furnacest"]="ek";
+ buildCommands["building_kilnst"]="ek";
+ buildCommands["building_magma_smelterst"]="es";
+ buildCommands["building_magma_glass_furnacest"]="ek";
+ buildCommands["building_magma_kilnst"]="ek";
+ buildCommands["building_glass_windowst"]="y";
+ buildCommands["building_gem_windowst"]="Y";
+ buildCommands["building_tradedepotst"]="D";
+ buildCommands["building_mechanismst"]="";
+ buildCommands["building_leverst"]="Tl";
+ buildCommands["building_pressure_platest"]="Tp";
+ buildCommands["building_cage_trapst"]="Tc";
+ buildCommands["building_stonefall_trapst"]="Ts";
+ buildCommands["building_weapon_trapst"]="Tw";
+ buildCommands["building_spikest"]="";
+ buildCommands["building_animal_trapst"]="m";
+ buildCommands["building_screw_pumpst"]="Ms";
+ buildCommands["building_water_wheelst"]="Mw";
+ buildCommands["building_windmillst"]="Mm";
+ buildCommands["building_gear_assemblyst"]="Mg";
+ buildCommands["building_horizontal_axlest"]="Mh";
+ buildCommands["building_vertical_axlest"]="Mv";
+ buildCommands["building_supportst"]="S";
+ buildCommands["building_cagest"]="j";
+ buildCommands["building_archery_targetst"]="A";
+ buildCommands["building_restraintst"]="v";
+
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context *DF = DFMgr.getSingleContext();
+
+ try
+ {
+ DF->Attach();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+
+ DFHack::Gui *Gui = DF->getGui();
+ DFHack::VersionInfo* mem = DF->getMemoryInfo();
+ DFHack::Process * p = DF->getProcess();
+ OffsetGroup * OG_Maps = mem->getGroup("Maps");
+ OffsetGroup * OG_MapBlock = OG_Maps->getGroup("block");
+ OffsetGroup * OG_LocalFt = OG_Maps->getGroup("features")->getGroup("local");
+ uint32_t designations = OG_MapBlock->getOffset("designation");
+ uint32_t block_feature1 = OG_MapBlock->getOffset("feature_local");
+ uint32_t block_feature2 = OG_MapBlock->getOffset("feature_global");
+ uint32_t region_x_offset = OG_Maps->getAddress("region_x");
+ uint32_t region_y_offset = OG_Maps->getAddress("region_y");
+ uint32_t region_z_offset = OG_Maps->getAddress("region_z");
+ uint32_t feature1_start_ptr = OG_LocalFt->getAddress("start_ptr");
+ int32_t regionX, regionY, regionZ;
+
+ // read position of the region inside DF world
+ p->readDWord (region_x_offset, (uint32_t &)regionX);
+ p->readDWord (region_y_offset, (uint32_t &)regionY);
+ p->readDWord (region_z_offset, (uint32_t &)regionZ);
+ while(1){
+ int32_t cx1,cy1,cz1;
+ cx1 = -30000;
+ while(cx1 == -30000)
+ {
+ DF->ForceResume();
+ cout << "Set cursor at first position, then press any key";
+ cin.ignore();
+ DF->Suspend();
+ Gui->getCursorCoords(cx1,cy1,cz1);
+ }
+
+ uint32_t tx1,ty1,tz1;
+ tx1 = cx1/16;
+ ty1 = cy1/16;
+ tz1 = cz1;
+
+ int32_t cx2,cy2,cz2;
+ cx2 = -30000;
+ while(cx2 == -30000)
+ {
+ DF->Resume();
+ cout << "Set cursor at second position, then press any key";
+ cin.ignore();
+ DF->Suspend();
+ Gui->getCursorCoords(cx2,cy2,cz2);
+ }
+ uint32_t tx2,ty2,tz2;
+ tx2 = cx2/16;
+ ty2 = cy2/16;
+ tz2 = cz2;
+ sort(tx1,tx2);
+ sort(ty1,ty2);
+ sort(tz1,tz2);
+ sort(cx1,cx2);
+ sort(cy1,cy2);
+ sort(cz1,cz2);
+
+ vector <vector<vector<string> > >dig(cz2-cz1+1,vector<vector<string> >(cy2-cy1+1,vector<string>(cx2-cx1+1)));
+ vector <vector<vector<string> > >build(cz2-cz1+1,vector<vector<string> >(cy2-cy1+1,vector<string>(cx2-cx1+1)));
+ mapblock40d block;
+ DFHack::Maps *Maps = DF->getMaps();
+ Maps->Start();
+ for(uint32_t y = ty1;y<=ty2;y++)
+ {
+ for(uint32_t x = tx1;x<=tx2;x++)
+ {
+ for(uint32_t z = tz1;z<=tz2;z++)
+ {
+ if(Maps->isValidBlock(x,y,z))
+ {
+ if(Maps->ReadBlock40d(x,y,z,&block))
+ {
+ int ystart,yend,xstart,xend;
+ ystart=xstart=0;
+ yend=xend=15;
+ if(y == ty2)
+ {
+ yend = cy2 % 16;
+ }
+ if(y == ty1)
+ {
+ ystart = cy1 % 16;
+ }
+ if(x == tx2)
+ {
+ xend = cx2 % 16;
+ }
+ if(x == tx1)
+ {
+ xstart = cx1 % 16;
+ }
+ int zidx = z-tz1;
+ for(int yy = ystart; yy <= yend;yy++)
+ {
+ int yidx = yy+(16*(y-ty1)-(cy1%16));
+ for(int xx = xstart; xx <= xend;xx++)
+ {
+ int xidx = xx+(16*(x-tx1)-(cx1%16));
+ int16_t tt = block.tiletypes[xx][yy];
+ DFHack::TileShape ts = DFHack::tileShape(tt);
+ if(DFHack::isOpenTerrain(tt) || DFHack::isFloorTerrain(tt))
+ {
+ dig[zidx][yidx][xidx] = "d";
+ }
+ else if(DFHack::STAIR_DOWN == ts)
+ {
+ dig [zidx][yidx][xidx] = "j";
+ build [zidx][yidx][xidx] = "Cd";
+ }
+ else if(DFHack::STAIR_UP == ts)
+ {
+ dig [zidx][yidx][xidx] = "u";
+ build [zidx][yidx][xidx] = "Cu";
+ }
+ else if(DFHack::STAIR_UPDOWN == ts)
+ {
+ dig [zidx][yidx][xidx] = "i";
+ build [zidx][yidx][xidx] = "Cx";
+ }
+ else if(DFHack::isRampTerrain(tt))
+ {
+ dig [zidx][yidx][xidx] = "r";
+ build [zidx][yidx][xidx] = "Cr";
+ }
+ else if(DFHack::isWallTerrain(tt))
+ {
+ build [zidx][yidx][xidx] = "Cw";
+ }
+ }
+ yidx++;
+ }
+ }
+ }
+ }
+ }
+ }
+ DFHack::Buildings * Bld = DF->getBuildings();
+ std::map <uint32_t, std::string> custom_workshop_types;
+ uint32_t numBuildings;
+ if(Bld->Start(numBuildings))
+ {
+ Bld->ReadCustomWorkshopTypes(custom_workshop_types);
+ for(uint32_t i = 0; i < numBuildings; i++)
+ {
+ DFHack::t_building temp;
+ Bld->Read(i, temp);
+ if(temp.type != 0xFFFFFFFF) // check if type isn't invalid
+ {
+ std::string typestr;
+ mem->resolveClassIDToClassname(temp.type, typestr);
+ if(temp.z == cz1 && cx1 <= temp.x1 && cx2 >= temp.x2 && cy1 <= temp.y1 && cy2 >= temp.y2)
+ {
+ string currStr = build[temp.z-cz1][temp.y1-cy1][temp.x1-cx1];
+ stringstream stream;
+ string newStr = buildCommands[typestr];
+ if(temp.x1 != temp.x2)
+ {
+ stream << "(" << temp.x2-temp.x1+1 << "x" << temp.y2-temp.y1+1 << ")";
+ newStr += stream.str();
+ }
+ build[temp.z-cz1][temp.y1-cy1][temp.x1-cx1] = newStr + currStr;
+ }
+ }
+ }
+ }
+// for testing purposes
+ //ofstream outfile("test.txt");
+// printVecOfVec(outfile, dig,'\t');
+// outfile << endl;
+// printVecOfVec(outfile, build,'\t');
+// outfile << endl;
+// outfile.close();
+
+ int32_t cx3,cy3,cz3,cx4,cy4,cz4;
+ uint32_t tx3,ty3,tz3,tx4,ty4,tz4;
+ char result;
+ while(1){
+ cx3 = -30000;
+ while(cx3 == -30000){
+ DF->Resume();
+ cout << "Set cursor at new position, then press any key:";
+ result = cin.get();
+ DF->Suspend();
+ Gui->getCursorCoords(cx3,cy3,cz3);
+ }
+ if(result == 'q'){
+ break;
+ }
+ cx4 = cx3+cx2-cx1;
+ cy4 = cy3+cy2-cy1;
+ cz4 = cz3+cz2-cz1;
+ tx3=cx3/16;
+ ty3=cy3/16;
+ tz3=cz3;
+ tx4=cx4/16;
+ ty4=cy4/16;
+ tz4=cz4;
+ DFHack::WindowIO * Win = DF->getWindowIO();
+ designations40d designationBlock;
+ for(uint32_t y = ty3;y<=ty4;y++)
+ {
+ for(uint32_t x = tx3;x<=tx4;x++)
+ {
+ for(uint32_t z = tz3;z<=tz4;z++)
+ {
+ Maps->Start();
+ Maps->ReadBlock40d(x,y,z,&block);
+ Maps->ReadDesignations(x,y,z,&designationBlock);
+ int ystart,yend,xstart,xend;
+ ystart=xstart=0;
+ yend=xend=15;
+ if(y == ty4){
+ yend = cy4 % 16;
+ }
+ if(y == ty3){
+ ystart = cy3 % 16;
+ }
+ if(x == tx4){
+ xend = cx4 % 16;
+ }
+ if(x == tx3){
+ xstart = cx3 % 16;
+ }
+ int zidx = z-tz3;
+ for(int yy = ystart; yy <= yend;yy++){
+ int yidx = yy+(16*(y-ty3)-(cy3%16));
+ for(int xx = xstart; xx <= xend;xx++){
+ int xidx = xx+(16*(x-tx3)-(cx3%16));
+ if(dig[zidx][yidx][xidx] != ""){
+ char test = dig[zidx][yidx][xidx].c_str()[0];
+ switch (test){
+ case 'd':
+ designationBlock[xx][yy].bits.dig = DFHack::designation_default;
+ break;
+ case 'i':
+ designationBlock[xx][yy].bits.dig = DFHack::designation_ud_stair;
+ break;
+ case 'u':
+ designationBlock[xx][yy].bits.dig = DFHack::designation_u_stair;
+ break;
+ case 'j':
+ designationBlock[xx][yy].bits.dig = DFHack::designation_d_stair;
+ break;
+ case 'r':
+ designationBlock[xx][yy].bits.dig = DFHack::designation_ramp;
+ break;
+ }
+
+ }
+ }
+ yidx++;
+ }
+ Maps->Start();
+ Maps->WriteDesignations(x,y,z,&designationBlock);
+ }
+ }
+ }
+ }
+ }
+ DF->Detach();
+ #ifndef LINUX_BUILD
+ std::cout << "Done. Press any key to continue" << std::endl;
+ cin.ignore();
+ #endif
+ return 0;
+}
+/*
+bool waitTillCursorState(DFHack::Context *DF, bool On)
+{
+ DFHack::WindowIO * w = DF->getWindowIO();
+ DFHack::Position * p = DF->getPosition();
+ int32_t x,y,z;
+ int tryCount = 0;
+ DF->Suspend();
+ bool cursorResult = p->getCursorCoords(x,y,z);
+ while(tryCount < 50 && On && !cursorResult || !On && cursorResult)
+ {
+ DF->Resume();
+ w->TypeSpecial(DFHack::WAIT,1,WAIT_AMT);
+ tryCount++;
+ DF->Suspend();
+ cursorResult = p->getCursorCoords(x,y,z);
+ }
+ if(tryCount >= 50)
+ {
+ cerr << "Something went wrong, cursor at x: " << x << " y: " << y << " z: " << z << endl;
+ return false;
+ }
+ DF->Resume();
+ return true;
+}
+bool waitTillCursorPositionState(DFHack::Context *DF, int32_t x,int32_t y, int32_t z)
+{
+ DFHack::WindowIO * w = DF->getWindowIO();
+ DFHack::Position * p = DF->getPosition();
+ int32_t x2,y2,z2;
+ int tryCount = 0;
+ DF->Suspend();
+ bool cursorResult = p->getCursorCoords(x2,y2,z2);
+ while(tryCount < 50 && (x != x2 || y != y2 || z != z2))
+ {
+ DF->Resume();
+ w->TypeSpecial(DFHack::WAIT,1,WAIT_AMT);
+ tryCount++;
+ DF->Suspend();
+ cursorResult = p->getCursorCoords(x2,y2,z2);
+ }
+ if(tryCount >= 50)
+ {
+ cerr << "Something went wrong, cursor at x: " << x2 << " y: " << y2 << " z: " << z2 << endl;
+ return false;
+ }
+ DF->Resume();
+ return true;
+}*/ \ No newline at end of file
diff --git a/needs_porting/creaturemanager.cpp b/needs_porting/creaturemanager.cpp
new file mode 100644
index 00000000..0d65e9f6
--- /dev/null
+++ b/needs_porting/creaturemanager.cpp
@@ -0,0 +1,1428 @@
+/*********************************************
+ * Purpose:
+ *
+ * - Display creatures
+ * - Modify skills and labors of creatures
+ * - Kill creatures
+ * - Etc.
+ *
+ * Version: 0.1.1
+ * Date: 2011-04-07
+ * Author: raoulxq (based on creaturedump.cpp from peterix)
+
+ * Todo:
+ * - Option to add/remove single skills
+ * - Ghosts/Merchants/etc. should be tagged as not own creatures
+ * - Filter by nickname with -n
+ * - Filter by first name with -fn
+ * - Filter by last name with -ln
+ * - Add pattern matching (or at least matching) to -n/-fn/-ln
+ * - Set nickname with --setnick (only if -i is given)
+ * - Show skills/labors only when -ss/-sl/-v is given or a skill/labor is changed
+ * - Make -1 the default for everything but -i
+ * - Imply -i if first argument is a number
+ * - Search for nick/profession if first argument is a string without - (i.e. no switch)
+ * - Switch --showhappy (show dwarf's experiences which make her un-/happy)
+ * - Switch --makefriendly
+ * - Switch --listskills, showing first 3 important skills
+
+ * Done:
+ * - More space for "Current Job"
+ * - Attempted to revive creature(s) with --revive, but it doesn't work (flag is there but invisible)
+ * - Switch -rcs, remove civil skills
+ * - Switch -rms, remove military skills (who would want that?)
+ * - Allow comma separated list of IDs for -i
+ * - '-c all' shows all creatures
+ * - Rename from skillmodify.cpp to creature.cpp
+ * - Kill creature(s) with --kill
+ * - Hide skills with level 0 and 0 experience points
+ * - Add --showallflags flag to display all flags (default: display a few important ones)
+ * - Add --showdead flag to also display dead creatures
+ * - Display more creature flags
+ * - Show creature type (again)
+ * - Add switch -1/--summary to only display one line for every creature. Good for an overview.
+ * - Display current job (has been there all the time, but not shown in Windows due to missing memory offsets)
+ * - Remove magic numbers
+ * - Show social skills only when -ss is given
+ * - Hide hauler labors when +sh is given
+ * - Add -v for verbose
+ * - Override forbidden mass-designation with -f
+ * - Option to add/remove single labors
+ * - Switches -ras and rl should only be possible with -nn or -i
+ * - Switch -rh removes hauler jobs
+ * - Dead creatures should not be displayed
+ * - Childs should not get labors assigned to
+ * - Babies should not get labors assigned to
+ * - Switch -al <n> adds labor number n
+ * - Switch -rl <n> removes labor number n
+ * - Switch -ral removes all labors
+ * - Switch -ll lists all available labors
+ *********************************************
+*/
+
+#include <iostream>
+#include <climits>
+#include <string.h>
+#include <vector>
+#include <locale>
+#include <stdio.h>
+using namespace std;
+
+#define DFHACK_WANT_MISCUTILS
+#include <DFHack.h>
+#include <modules/Units.h>
+
+/* Note about magic numbers:
+ * If you have an idea how to better solve this, tell me. Currently I'd be
+ * either dependent on Toady One's implementation (#defining numbers) or
+ * Memory.xml (#defining text). I voted for Toady One's numbers to be more
+ * stable, but could be wrong.
+ *
+ * Ideally there would be a flag "is_military" or "is_social" in Memory.xml.
+ */
+
+/* Social skills */
+#define SKILL_PERSUASION 72
+#define SKILL_NEGOTIATION 73
+#define SKILL_JUDGING_INTENT 74
+#define SKILL_INTIMIDATION 79
+#define SKILL_CONVERSATION 80
+#define SKILL_COMEDY 81
+#define SKILL_FLATTERY 82
+#define SKILL_CONSOLING 83
+#define SKILL_PACIFICATION 84
+
+/* Misc skills */
+#define SKILL_WEAPONSMITHING 27
+#define SKILL_ARMORSMITHING 28
+#define SKILL_RECORD_KEEPING 77
+#define SKILL_WAX_WORKING 115
+
+/* Some military skills */
+#define SKILL_COORDINATION 95
+#define SKILL_BALANCE 96
+#define SKILL_LEADERSHIP 97
+#define SKILL_TEACHING 98
+#define SKILL_FIGHTING 99
+#define SKILL_ARCHERY 100
+#define SKILL_WRESTLING 101
+#define SKILL_BITING 102
+#define SKILL_STRIKING 103
+#define SKILL_KICKING 104
+#define SKILL_DODGING 105
+
+#define LABOR_STONE_HAULING 1
+#define LABOR_WOOD_HAULING 2
+#define LABOR_BURIAL 3
+#define LABOR_FOOD_HAULING 4
+#define LABOR_REFUSE_HAULING 5
+#define LABOR_ITEM_HAULING 6
+#define LABOR_FURNITURE_HAULING 7
+#define LABOR_ANIMAL_HAULING 8
+#define LABOR_CLEANING 9
+#define LABOR_FEED_PATIENTS_PRISONERS 22
+#define LABOR_RECOVERING_WOUNDED 23
+
+#define PROFESSION_CHILD 96
+#define PROFESSION_BABY 97
+
+#define NOT_SET INT_MIN
+#define MAX_MOOD 4
+#define NO_MOOD -1
+
+bool quiet=true;
+bool verbose = false;
+bool showhauler = true;
+bool showsocial = false;
+bool showfirstlineonly = false;
+bool showdead = false;
+bool showallflags = false;
+
+int hauler_labors[] = {
+ LABOR_STONE_HAULING
+ ,LABOR_WOOD_HAULING
+ ,LABOR_BURIAL
+ ,LABOR_FOOD_HAULING
+ ,LABOR_REFUSE_HAULING
+ ,LABOR_ITEM_HAULING
+ ,LABOR_FURNITURE_HAULING
+ ,LABOR_ANIMAL_HAULING
+ ,LABOR_CLEANING
+ ,LABOR_FEED_PATIENTS_PRISONERS
+ ,LABOR_RECOVERING_WOUNDED
+};
+
+int social_skills[] =
+{
+ SKILL_PERSUASION
+ ,SKILL_NEGOTIATION
+ ,SKILL_JUDGING_INTENT
+ ,SKILL_INTIMIDATION
+ ,SKILL_CONVERSATION
+ ,SKILL_COMEDY
+ ,SKILL_FLATTERY
+ ,SKILL_CONSOLING
+ ,SKILL_PACIFICATION
+};
+
+int military_skills[] =
+{
+ SKILL_COORDINATION
+ ,SKILL_BALANCE
+ ,SKILL_LEADERSHIP
+ ,SKILL_TEACHING
+ ,SKILL_FIGHTING
+ ,SKILL_ARCHERY
+ ,SKILL_WRESTLING
+ ,SKILL_BITING
+ ,SKILL_STRIKING
+ ,SKILL_KICKING
+ ,SKILL_DODGING
+};
+
+void usage(int argc, const char * argv[])
+{
+ cout
+ << "Usage:" << endl
+ << argv[0] << " [option 1] [option 2] [...]" << endl
+ << endl
+ << "Display options:" << endl
+ << "-q : Suppress \"Press any key to continue\" at program termination" << endl
+ << "-v : Increase verbosity" << endl
+ << endl
+
+ << "Choosing which creatures to display and/or modify "
+ << "(note that all criteria" << endl << "must match, so adding "
+ << " more narrows things down):" << endl
+ << "-i id1[,id2,...]: Only show/modify creature with this id" << endl
+ << "-c creature : Show/modify this creature type instead of dwarves" << endl
+ << " ('all' to show all creatures)" << endl
+ << "-nn/--nonicks : Only show/modify creatures with no custom nickname (migrants)" << endl
+ << "--nicks : Only show/modify creatures with custom nickname" << endl
+ << "--showdead : Also show/modify dead creatures" << endl
+ << "--type : Show/modify all creatures of given type" << endl
+ << " : Can be used multiple times" << endl
+ << " types:" << endl
+ << " * dead: all dead creatures" << endl
+ << " * demon: all demons" << endl
+ << " * diplomat: all diplomats" << endl
+ << " * FB: all forgotten beasts" << endl
+ << " * female: all female creatures" << endl
+ << " * ghost: all ghosts" << endl
+ << " * male: all male creatures" << endl
+ << " * merchants: all merchants (including pack animals)" << endl
+ << " * neuter: all neuter creatuers" << endl
+ << " * pregnant: all pregnant creatures" << endl
+ << " * tame: all tame creatues" << endl
+ << " * wild: all wild creatures" << endl
+
+ << endl
+
+ << "What information to display:" << endl
+ << "-saf : Show all flags of a creature" << endl
+ << "--showallflags : Show all flags of a creature" << endl
+ << "-ll/--listlabors: List available labors" << endl
+ << "-ss : Show social skills" << endl
+ << "+sh : Hide hauler labors" << endl
+ << "-1/--summary : Only display one line per creature" << endl
+
+ << endl
+
+ << "Options to modify selected creatures:" << endl
+ << "-al <n> : Add labor <n> to creature" << endl
+ << "-rl <n> : Remove labor <n> from creature" << endl
+ << "-ras : Remove all skills from creature (i.e. set them to zero)" << endl
+ << "-rcs : Remove civil skills from creature (i.e. set them to zero)" << endl
+ << "-rms : Remove military skills from creature (i.e. set them to zero)" << endl
+ << "-ral : Remove all labors from creature" << endl
+ << "-ah : Add hauler labors (stone hauling, etc.) to creature" << endl
+ << "-rh : Remove hauler labors (stone hauling, etc.) from creature" << endl
+ // Disabling mood doesn't work as intented
+ << "--setmood <n> : Set mood to n (-1 = no mood, max=4, buggy!)" << endl
+ << "--kill : Kill creature(s) (leaves behind corpses)" << endl
+ << "--erase : Remove creature(s) from game without killing" << endl
+ << "--tame : Tames animals, recruits intelligent creatures." << endl
+ << "--slaugher : Mark a creature for slaughter, even sentients" << endl
+ << "--butcher : Same as --slaugher" << endl
+ // Doesn't seem to work
+ //<< "--revive : Attempt to revive creature(s) (remove dead and killed flag)" << endl
+ // Setting happiness doesn't work really, because hapiness is recalculated
+ //<< "--sethappiness <n> : Set happiness to n" << endl
+ << "-f : Force an action" << endl
+ << endl
+ << "Examples:" << endl
+ << endl
+ << "Show all dwarfs:" << endl
+ << argv[0] << " -c Dwarf" << endl
+ << endl
+ << "Show summary of all creatures (spoiler: includes unknown creatures):" << endl
+ << argv[0] << " -1 -c all" << endl
+ << endl
+ << "Kill that nasty ogre" << endl
+ << argv[0] << " -i 52 --kill" << endl
+ << endl
+ << "Check that the ogre is really dead" << endl
+ << argv[0] << " -c ogre --showdead" << endl
+ << endl
+ << "Remove all skills from dwarfs 15 and 32:" << endl
+ << argv[0] << " -i 15,32 -ras" << endl
+ << endl
+ << "Remove all skills and labors from dwarfs with no custom nickname:" << endl
+ << argv[0] << " -c DWARF -nn -ras -ral" << endl
+ << endl
+ << "Add hauling labors to all dwarfs without nickname (e.g. migrants):" << endl
+ << argv[0] << " -c DWARF -nn -ah" << endl
+ << endl
+ << "Show list of labor ids:" << endl
+ << argv[0] << " -c DWARF -ll" << endl
+ << endl
+ << "Add engraving labor to all dwarfs without nickname (get the labor id from the list above):" << endl
+ << argv[0] << " -c DWARF -nn -al 13" << endl
+ << endl
+ << "Make Urist, Stodir and Ingish miners:" << endl
+ << argv[0] << " -i 31,42,77 -al 0" << endl
+ << endl
+ << "Make all demons friendly:" << endl
+ << argv[0] << " --type demon --tame" << endl
+ ;
+ if (quiet == false) {
+ cout << "Press any key to continue" << endl;
+ cin.ignore();
+ }
+}
+
+DFHack::Materials * Materials;
+DFHack::VersionInfo *mem;
+DFHack::Creatures * Creatures = NULL;
+
+// Note that toCaps() changes the string itself and I'm using it a few times in
+// an unsafe way below. Didn't crash yet however.
+std::string toCaps(std::string s)
+{
+ const int length = s.length();
+ std::locale loc("");
+ bool caps=true;
+ if (length == 0) {
+ return s;
+ }
+ for(int i=0; i!=length ; ++i)
+ {
+ if (caps)
+ {
+ s[i] = std::toupper(s[i],loc);
+ caps = false;
+ }
+ else if (s[i] == '_' || s[i] == ' ')
+ {
+ s[i] = ' ';
+ caps = true;
+ }
+ else
+ {
+ s[i] = std::tolower(s[i],loc);
+ }
+ }
+ return s;
+}
+
+int strtoint(const string &str)
+{
+ stringstream ss(str);
+ int result;
+ return ss >> result ? result : -1;
+}
+
+
+// A C++ standard library function should be used instead
+bool is_in(int m, int set[], int set_size)
+{
+ for (int i=0; i<set_size; i++)
+ {
+ if (m == set[i])
+ return true;
+ }
+ return false;
+}
+
+int * find_int(std::vector<int> v, int comp)
+{
+ for (size_t i=0; i<v.size(); i++)
+ {
+ //fprintf(stderr, "Comparing %d with %d and returning %x...\n", v[i], comp, &v[i]);
+ if (v[i] == comp)
+ return &v[i];
+ }
+ return NULL;
+}
+
+
+
+void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature, int index)
+{
+
+
+ DFHack::Translation *Tran = DF->getTranslation();
+ DFHack::VersionInfo *mem = DF->getMemoryInfo();
+
+ string type="(no type)";
+ if (Materials->raceEx[creature.race].rawname[0])
+ {
+ type = toCaps(Materials->raceEx[creature.race].rawname);
+ }
+
+ string name="(no name)";
+ if(creature.name.nickname[0])
+ {
+ name = creature.name.nickname;
+ }
+ else
+ {
+ if(creature.name.first_name[0])
+ {
+ name = toCaps(creature.name.first_name);
+
+ string transName = Tran->TranslateName(creature.name,false);
+ if(!transName.empty())
+ {
+ name += " " + toCaps(transName);
+ }
+ }
+ }
+
+ string profession="";
+ try {
+ profession = mem->getProfession(creature.profession);
+ }
+ catch (exception& e)
+ {
+ cout << "Error retrieving creature profession: " << e.what() << endl;
+ }
+ if(creature.custom_profession[0])
+ {
+ profession = creature.custom_profession;
+ }
+
+
+ string jobid;
+ stringstream ss;
+ ss << "(" << creature.current_job.jobId << ")";
+ jobid = ss.str();
+
+ string job="No Job/On Break" + (creature.current_job.jobId == 0 ? "" : jobid);
+ if(creature.current_job.active)
+ {
+ job=mem->getJob(creature.current_job.jobId);
+
+ int p=job.size();
+ while (p>0 && (job[p]==' ' || job[p]=='\t'))
+ p--;
+ if (p <= 1) // Display numeric jobID if unknown job
+ {
+ job = jobid;
+ }
+ }
+
+ if (showfirstlineonly)
+ {
+ printf("%3d", index);
+ printf(" %-17s", type.c_str());
+ printf(" %-24s", name.c_str());
+ printf(" %-16s", toCaps(profession).c_str());
+ printf(" %-38s", job.c_str());
+ printf(" %5d", creature.happiness);
+ if (showdead)
+ {
+ printf(" %-5s", creature.flags1.bits.dead ? "Dead" : "Alive");
+ }
+
+ printf("\n");
+
+ return;
+ }
+ else
+ {
+ printf("ID: %d", index);
+ printf(", %s", type.c_str());
+ printf(", %s", name.c_str());
+ printf(", %s", toCaps(profession).c_str());
+ printf(", Job: %s", job.c_str());
+ printf(", Happiness: %d", creature.happiness);
+ printf("\n");
+ printf("Origin: %p\n", creature.origin);
+ printf("Civ #: %d\n", creature.civ);
+ }
+
+ if((creature.mood != NO_MOOD) && (creature.mood<=MAX_MOOD))
+ {
+ cout << "Creature is in a strange mood (mood=" << creature.mood << "), skill: " << mem->getSkill(creature.mood_skill) << endl;
+ vector<DFHack::t_material> mymat;
+ if(Creatures->ReadJob(&creature, mymat))
+ {
+ for(unsigned int i = 0; i < mymat.size(); i++)
+ {
+ printf("\t%s(%d)\t%d %d %d - %.8x\n", Materials->getDescription(mymat[i]).c_str(), mymat[i].itemType, mymat[i].subType, mymat[i].subIndex, mymat[i].index, mymat[i].flags);
+ }
+ }
+ }
+
+ if(creature.has_default_soul)
+ {
+ // Print out skills
+ int skillid;
+ int skillrating;
+ int skillexperience;
+ string skillname;
+
+ cout << setiosflags(ios::left);
+
+ for(unsigned int i = 0; i < creature.defaultSoul.numSkills;i++)
+ {
+ skillid = creature.defaultSoul.skills[i].id;
+ bool is_social = is_in(skillid, social_skills, sizeof(social_skills)/sizeof(social_skills[0]));
+ if (!is_social || (is_social && showsocial))
+ {
+ skillrating = creature.defaultSoul.skills[i].rating;
+ skillexperience = creature.defaultSoul.skills[i].experience;
+ try
+ {
+ skillname = mem->getSkill(skillid);
+ }
+ catch(DFHack::Error::AllMemdef &e)
+ {
+ skillname = "Unknown skill";
+ cout << e.what() << endl;
+ }
+ if (skillrating > 0 || skillexperience > 0)
+ {
+ cout << "(Skill " << int(skillid) << ") " << setw(16) << skillname << ": "
+ << skillrating << "/" << skillexperience << endl;
+ }
+ }
+ }
+
+ for(unsigned int i = 0; i < NUM_CREATURE_LABORS;i++)
+ {
+ if(!creature.labors[i])
+ continue;
+ string laborname;
+ try
+ {
+ laborname = mem->getLabor(i);
+ }
+ catch(exception &)
+ {
+ laborname = "(Undefined)";
+ }
+ bool is_labor = is_in(i, hauler_labors, sizeof(hauler_labors)/sizeof(hauler_labors[0]));
+ if (!is_labor || (is_labor && showhauler))
+ cout << "(Labor " << i << ") " << setw(16) << laborname << endl;
+ }
+ }
+
+ if (creature.pregnancy_timer > 0)
+ cout << "Pregnant: " << creature.pregnancy_timer << " ticks to "
+ << "birth." << endl;
+
+ if (showallflags)
+ {
+ DFHack::t_creaturflags1 f1 = creature.flags1;
+ DFHack::t_creaturflags2 f2 = creature.flags2;
+ DFHack::t_creaturflags3 f3 = creature.flags3;
+
+ if(f1.bits.dead){cout << "Flag: dead" << endl; }
+ if(f1.bits.had_mood){cout<<toCaps("Flag: had_mood") << endl; }
+ if(f1.bits.marauder){cout<<toCaps("Flag: marauder") << endl; }
+ if(f1.bits.drowning){cout<<toCaps("Flag: drowning") << endl; }
+ if(f1.bits.merchant){cout<<toCaps("Flag: merchant") << endl; }
+ if(f1.bits.forest){cout<<toCaps("Flag: forest") << endl; }
+ if(f1.bits.left){cout<<toCaps("Flag: left") << endl; }
+ if(f1.bits.rider){cout<<toCaps("Flag: rider") << endl; }
+ if(f1.bits.incoming){cout<<toCaps("Flag: incoming") << endl; }
+ if(f1.bits.diplomat){cout<<toCaps("Flag: diplomat") << endl; }
+ if(f1.bits.zombie){cout<<toCaps("Flag: zombie") << endl; }
+ if(f1.bits.skeleton){cout<<toCaps("Flag: skeleton") << endl; }
+ if(f1.bits.can_swap){cout<<toCaps("Flag: can_swap") << endl; }
+ if(f1.bits.on_ground){cout<<toCaps("Flag: on_ground") << endl; }
+ if(f1.bits.projectile){cout<<toCaps("Flag: projectile") << endl; }
+ if(f1.bits.active_invader){cout<<toCaps("Flag: active_invader") << endl; }
+ if(f1.bits.hidden_in_ambush){cout<<toCaps("Flag: hidden_in_ambush") << endl; }
+ if(f1.bits.invader_origin){cout<<toCaps("Flag: invader_origin") << endl; }
+ if(f1.bits.coward){cout<<toCaps("Flag: coward") << endl; }
+ if(f1.bits.hidden_ambusher){cout<<toCaps("Flag: hidden_ambusher") << endl; }
+ if(f1.bits.invades){cout<<toCaps("Flag: invades") << endl; }
+ if(f1.bits.check_flows){cout<<toCaps("Flag: check_flows") << endl; }
+ if(f1.bits.ridden){cout<<toCaps("Flag: ridden") << endl; }
+ if(f1.bits.caged){cout<<toCaps("Flag: caged") << endl; }
+ if(f1.bits.tame){cout<<toCaps("Flag: tame") << endl; }
+ if(f1.bits.chained){cout<<toCaps("Flag: chained") << endl; }
+ if(f1.bits.royal_guard){cout<<toCaps("Flag: royal_guard") << endl; }
+ if(f1.bits.fortress_guard){cout<<toCaps("Flag: fortress_guard") << endl; }
+ if(f1.bits.suppress_wield){cout<<toCaps("Flag: suppress_wield") << endl; }
+ if(f1.bits.important_historical_figure){cout<<toCaps("Flag: important_historical_figure") << endl; }
+
+ if(f2.bits.swimming){cout<<toCaps("Flag: swimming") << endl; }
+ if(f2.bits.sparring){cout<<toCaps("Flag: sparring") << endl; }
+ if(f2.bits.no_notify){cout<<toCaps("Flag: no_notify") << endl; }
+ if(f2.bits.unused){cout<<toCaps("Flag: unused") << endl; }
+ if(f2.bits.calculated_nerves){cout<<toCaps("Flag: calculated_nerves") << endl; }
+ if(f2.bits.calculated_bodyparts){cout<<toCaps("Flag: calculated_bodyparts") << endl; }
+ if(f2.bits.important_historical_figure){cout<<toCaps("Flag: important_historical_figure") << endl; }
+ if(f2.bits.killed){cout<<toCaps("Flag: killed") << endl; }
+ if(f2.bits.cleanup_1){cout<<toCaps("Flag: cleanup_1") << endl; }
+ if(f2.bits.cleanup_2){cout<<toCaps("Flag: cleanup_2") << endl; }
+ if(f2.bits.cleanup_3){cout<<toCaps("Flag: cleanup_3") << endl; }
+ if(f2.bits.for_trade){cout<<toCaps("Flag: for_trade") << endl; }
+ if(f2.bits.trade_resolved){cout<<toCaps("Flag: trade_resolved") << endl; }
+ if(f2.bits.has_breaks){cout<<toCaps("Flag: has_breaks") << endl; }
+ if(f2.bits.gutted){cout<<toCaps("Flag: gutted") << endl; }
+ if(f2.bits.circulatory_spray){cout<<toCaps("Flag: circulatory_spray") << endl; }
+ if(f2.bits.locked_in_for_trading){cout<<toCaps("Flag: locked_in_for_trading") << endl; }
+ if(f2.bits.slaughter){cout<<toCaps("Flag: slaughter") << endl; }
+ if(f2.bits.underworld){cout<<toCaps("Flag: underworld") << endl; }
+ if(f2.bits.resident){cout<<toCaps("Flag: resident") << endl; }
+ if(f2.bits.cleanup_4){cout<<toCaps("Flag: cleanup_4") << endl; }
+ if(f2.bits.calculated_insulation){cout<<toCaps("Flag: calculated_insulation") << endl; }
+ if(f2.bits.visitor_uninvited){cout<<toCaps("Flag: visitor_uninvited") << endl; }
+ if(f2.bits.visitor){cout<<toCaps("Flag: visitor") << endl; }
+ if(f2.bits.calculated_inventory){cout<<toCaps("Flag: calculated_inventory") << endl; }
+ if(f2.bits.vision_good){cout<<toCaps("Flag: vision_good") << endl; }
+ if(f2.bits.vision_damaged){cout<<toCaps("Flag: vision_damaged") << endl; }
+ if(f2.bits.vision_missing){cout<<toCaps("Flag: vision_missing") << endl; }
+ if(f2.bits.breathing_good){cout<<toCaps("Flag: breathing_good") << endl; }
+ if(f2.bits.breathing_problem){cout<<toCaps("Flag: breathing_problem") << endl; }
+ if(f2.bits.roaming_wilderness_population_source){cout<<toCaps("Flag: roaming_wilderness_population_source") << endl; }
+ if(f2.bits.roaming_wilderness_population_source_not_a_map_feature){cout<<toCaps("Flag: roaming_wilderness_population_source_not_a_map_feature") << endl; }
+
+ if(f3.bits.announce_titan){cout<<toCaps("Flag: announce_titan") << endl; }
+ if(f3.bits.scuttle){cout<<toCaps("Flag: scuttle") << endl; }
+ if(f3.bits.ghostly){cout<<toCaps("Flag: ghostly") << endl; }
+ }
+ else
+ {
+ /* FLAGS 1 */
+ if(creature.flags1.bits.dead) { cout << "Flag: Dead" << endl; }
+ if(creature.flags1.bits.on_ground) { cout << "Flag: On the ground" << endl; }
+ if(creature.flags1.bits.tame) { cout << "Flag: Tame" << endl; }
+ if(creature.flags1.bits.royal_guard) { cout << "Flag: Royal guard" << endl; }
+ if(creature.flags1.bits.fortress_guard) { cout << "Flag: Fortress guard" << endl; }
+
+ /* FLAGS 2 */
+ if(creature.flags2.bits.killed) { cout << "Flag: Killed by kill function" << endl; }
+ if(creature.flags2.bits.resident) { cout << "Flag: Resident" << endl; }
+ if(creature.flags2.bits.gutted) { cout << "Flag: Gutted" << endl; }
+ if(creature.flags2.bits.slaughter) { cout << "Flag: Marked for slaughter" << endl; }
+ if(creature.flags2.bits.underworld) { cout << "Flag: From the underworld" << endl; }
+
+ /* FLAGS 3 */
+ if(creature.flags3.bits.ghostly) { cout << "Flag: Ghost" << endl; }
+
+ if(creature.flags1.bits.had_mood && (creature.mood == -1 || creature.mood == 8 ) )
+ {
+ string artifact_name = Tran->TranslateName(creature.artifact_name,false);
+ cout << "Artifact: " << artifact_name << endl;
+ }
+ }
+ cout << endl;
+}
+
+class creature_filter
+{
+public:
+
+ enum sex_filter
+ {
+ SEX_FEMALE = 0,
+ SEX_MALE = 1,
+ SEX_ANY = 254, // Our magin number for ignoring sex.
+ SEX_NEUTER = 255
+ };
+
+ bool dead;
+ bool demon;
+ bool diplomat;
+ bool find_nonicks;
+ bool find_nicks;
+ bool forgotten_beast;
+ bool ghost;
+ bool merchant;
+ bool pregnant;
+ bool tame;
+ bool wild;
+
+ sex_filter sex;
+
+ string creature_type;
+ std::vector<int> creature_id;
+
+ #define DEFAULT_CREATURE_STR "Default"
+
+ creature_filter()
+ {
+ // By default we only select dwarves, except that if we use the
+ // --type option we want to default to everyone. So we start out
+ // with a special string, and if remains unchanged after all
+ // the options have been processed we turn it to DWARF.
+ creature_type = DEFAULT_CREATURE_STR;
+
+ dead = false;
+ demon = false;
+ diplomat = false;
+ find_nonicks = false;
+ find_nicks = false;
+ forgotten_beast = false;
+ ghost = false;
+ merchant = false;
+ pregnant = false;
+ sex = SEX_ANY;
+ tame = false;
+ wild = false;
+ }
+
+ // If the creature type is still the default, then change it to allow
+ // for all creatures. If the creature type has been explicitly set,
+ // then don't alter it.
+ void defaultTypeToAll()
+ {
+ if (creature_type == DEFAULT_CREATURE_STR)
+ creature_type = "";
+ }
+
+ // If the creature type is still the default, change it to DWARF
+ void defaultTypeToDwarf()
+ {
+ if (creature_type == DEFAULT_CREATURE_STR)
+ creature_type = "Dwarf";
+ }
+
+ void process_type(string type)
+ {
+ type = toCaps(type);
+
+ // If we're going by type, then by default all species are
+ // permitted.
+ defaultTypeToAll();
+
+ if (type == "Dead")
+ {
+ dead = true;
+ showdead = true;
+ }
+ else if (type == "Demon")
+ demon = true;
+ else if (type == "Diplomat")
+ diplomat = true;
+ else if (type == "Fb" || type == "Beast")
+ forgotten_beast = true;
+ else if (type == "Ghost")
+ ghost = true;
+ else if (type == "Merchant")
+ merchant = true;
+ else if (type == "Pregnant")
+ pregnant = true;
+ else if (type == "Tame")
+ tame = true;
+ else if (type == "Wild")
+ wild = true;
+ else if (type == "Male")
+ sex = SEX_MALE;
+ else if (type == "Female")
+ sex = SEX_FEMALE;
+ else if (type == "Neuter")
+ sex = SEX_NEUTER;
+ else
+ {
+ cerr << "ERROR: Unknown type '" << type << "'" << endl;
+ }
+ }
+
+ void doneProcessingOptions()
+ {
+ string temp = toCaps(creature_type);
+ creature_type = temp;
+
+ defaultTypeToDwarf();
+ }
+
+ bool creatureMatches(const DFHack::t_creature & creature,
+ uint32_t creature_idx)
+ {
+ // A list of ids overrides everything else.
+ if (creature_id.size() > 0)
+ return (find_int(creature_id, creature_idx));
+
+ // If it's not a list of ids, it has not match all given criteria.
+
+ const DFHack::t_creaturflags1 &f1 = creature.flags1;
+ const DFHack::t_creaturflags2 &f2 = creature.flags2;
+ const DFHack::t_creaturflags3 &f3 = creature.flags3;
+
+ if(f1.bits.dead && !showdead)
+ return false;
+
+ bool hasnick = (creature.name.nickname[0] != '\0');
+ if(hasnick && find_nonicks)
+ return false;
+ if(!hasnick && find_nicks)
+ return false;
+
+ string race_name = string(Materials->raceEx[creature.race].rawname);
+
+ if(!creature_type.empty() && creature_type != toCaps(race_name))
+ return false;
+
+ if(dead && !f1.bits.dead)
+ return false;
+ if(demon && !f2.bits.underworld)
+ return false;
+ if(diplomat && !f1.bits.diplomat)
+ return false;
+ if(forgotten_beast && !f2.bits.visitor_uninvited)
+ return false;
+ if(ghost && !f3.bits.ghostly)
+ return false;
+ if(merchant && !f1.bits.merchant)
+ return false;
+ if(pregnant && creature.pregnancy_timer == 0)
+ return false;
+ if (sex != SEX_ANY && creature.sex != (uint8_t) sex)
+ return false;
+ if(tame && !f1.bits.tame)
+ return false;
+
+ if(wild && !f2.bits.roaming_wilderness_population_source &&
+ !f2.bits.roaming_wilderness_population_source_not_a_map_feature)
+ {
+ return false;
+ }
+
+ return true;
+ }
+};
+
+int main (int argc, const char* argv[])
+{
+ // let's be more useful when double-clicked on windows
+#ifndef LINUX_BUILD
+ quiet = false;
+#endif
+ creature_filter filter;
+
+ bool remove_skills = false;
+ bool remove_civil_skills = false;
+ bool remove_military_skills = false;
+ bool remove_labors = false;
+ bool kill_creature = false;
+ bool erase_creature = false;
+ bool revive_creature = false;
+ bool make_hauler = false;
+ bool remove_hauler = false;
+ bool add_labor = false;
+ int add_labor_n = NOT_SET;
+ bool remove_labor = false;
+ int remove_labor_n = NOT_SET;
+ bool set_happiness = false;
+ int set_happiness_n = NOT_SET;
+ bool set_mood = false;
+ int set_mood_n = NOT_SET;
+ bool list_labors = false;
+ bool force_massdesignation = false;
+ bool tame_creature = false;
+ bool slaughter_creature = false;
+
+ if (argc == 1) {
+ usage(argc, argv);
+ return 1;
+ }
+
+ for(int i = 1; i < argc; i++)
+ {
+ string arg_cur = argv[i];
+ string arg_next = "";
+ int arg_next_int = NOT_SET;
+ /* Check if argv[i+1] is a number >= 0 */
+ if (i < argc-1) {
+ arg_next = argv[i+1];
+ arg_next_int = strtoint(arg_next);
+ if (arg_next != "0" && arg_next_int == 0) {
+ arg_next_int = NOT_SET;
+ }
+ }
+
+ if(arg_cur == "-q")
+ {
+ quiet = true;
+ }
+ else if(arg_cur == "+q")
+ {
+ quiet = false;
+ }
+ else if(arg_cur == "-v")
+ {
+ verbose = true;
+ }
+ else if(arg_cur == "-1" || arg_cur == "--summary")
+ {
+ showfirstlineonly = true;
+ }
+ else if(arg_cur == "-ss" || arg_cur == "--showsocial")
+ {
+ showsocial = true;
+ }
+ else if(arg_cur == "+sh" || arg_cur == "-nosh" || arg_cur == "--noshowhauler")
+ {
+ showhauler = false;
+ }
+ else if(arg_cur == "--showdead")
+ {
+ showdead = true;
+ }
+ else if(arg_cur == "--showallflags" || arg_cur == "-saf")
+ {
+ showallflags = true;
+ }
+ else if(arg_cur == "-ras")
+ {
+ remove_skills = true;
+ }
+ else if(arg_cur == "-rcs")
+ {
+ remove_civil_skills = true;
+ }
+ else if(arg_cur == "-rms")
+ {
+ remove_military_skills = true;
+ }
+ else if(arg_cur == "-f")
+ {
+ force_massdesignation = true;
+ }
+ // list labors
+ else if(arg_cur == "-ll" || arg_cur == "--listlabors")
+ {
+ list_labors = true;
+ }
+ // add single labor
+ else if(arg_cur == "-al" && i < argc-1)
+ {
+ if (arg_next_int == NOT_SET || arg_next_int >= NUM_CREATURE_LABORS) {
+ usage(argc, argv);
+ return 1;
+ }
+ add_labor = true;
+ add_labor_n = arg_next_int;
+ i++;
+ }
+ // remove single labor
+ else if(arg_cur == "-rl" && i < argc-1)
+ {
+ if (arg_next_int == NOT_SET || arg_next_int >= NUM_CREATURE_LABORS) {
+ usage(argc, argv);
+ return 1;
+ }
+ remove_labor = true;
+ remove_labor_n = arg_next_int;
+ i++;
+ }
+ else if(arg_cur == "--setmood" && i < argc-1)
+ {
+ if (arg_next_int < NO_MOOD || arg_next_int > MAX_MOOD) {
+ usage(argc, argv);
+ return 1;
+ }
+ set_mood = true;
+ set_mood_n = arg_next_int;
+ i++;
+ }
+ else if(arg_cur == "--sethappiness" && i < argc-1)
+ {
+ if (arg_next_int < 1 || arg_next_int >= 2000) {
+ usage(argc, argv);
+ return 1;
+ }
+ set_happiness = true;
+ set_happiness_n = arg_next_int;
+ i++;
+ }
+ else if(arg_cur == "--kill")
+ {
+ kill_creature = true;
+ showallflags = true;
+ showdead = true;
+ }
+ else if(arg_cur == "--erase")
+ {
+ erase_creature = true;
+ showallflags = true;
+ showdead = true;
+ }
+ else if(arg_cur == "--revive")
+ {
+ revive_creature = true;
+ showdead = true;
+ showallflags = true;
+ }
+ else if(arg_cur == "-ral")
+ {
+ remove_labors = true;
+ }
+ else if(arg_cur == "-ah")
+ {
+ make_hauler = true;
+ }
+ else if(arg_cur == "-rh")
+ {
+ remove_hauler = true;
+ }
+ else if(arg_cur == "-nn" || arg_cur == "--nonicks")
+ {
+ filter.find_nonicks = true;
+ }
+ else if(arg_cur == "--nicks")
+ {
+ filter.find_nicks = true;
+ }
+ else if(arg_cur == "-c" && i < argc-1)
+ {
+ filter.creature_type = argv[i+1];
+ i++;
+ }
+ else if(arg_cur == "-i" && i < argc-1)
+ {
+ std::stringstream ss(argv[i+1]);
+ int num;
+ while (ss >> num) {
+ filter.creature_id.push_back(num);
+ ss.ignore(1);
+ }
+
+ filter.creature_type = ""; // if -i is given, match all creatures
+ showdead = true;
+ i++;
+ }
+ else if(arg_cur == "--type" && i < argc-1)
+ {
+ filter.process_type(arg_next);
+ i++;
+ }
+ else if (arg_cur == "--tame")
+ tame_creature = true;
+ else if (arg_cur == "--slaugher" || arg_cur == "--butcher")
+ slaughter_creature = true;
+ else
+ {
+ if (arg_cur != "-h") {
+ cout << "Unknown option '" << arg_cur << "'" << endl;
+ cout << endl;
+ }
+ usage(argc, argv);
+ return 1;
+ }
+ }
+
+ filter.doneProcessingOptions();
+
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context* DF;
+ try
+ {
+ DF = DFMgr.getSingleContext();
+ DF->Attach();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ if (quiet == false)
+ {
+ cin.ignore();
+ }
+ return 1;
+ }
+
+ Creatures = DF->getCreatures();
+ Materials = DF->getMaterials();
+ DFHack::Translation * Tran = DF->getTranslation();
+
+ uint32_t numCreatures;
+ if(!Creatures->Start(numCreatures))
+ {
+ cerr << "Can't get creatures" << endl;
+ if (quiet == false)
+ {
+ cin.ignore();
+ }
+ return 1;
+ }
+ if(!numCreatures)
+ {
+ cerr << "No creatures to print" << endl;
+ if (quiet == false)
+ {
+ cin.ignore();
+ }
+ return 1;
+ }
+
+ mem = DF->getMemoryInfo();
+ Materials->ReadInorganicMaterials();
+ Materials->ReadOrganicMaterials();
+ Materials->ReadWoodMaterials();
+ Materials->ReadPlantMaterials();
+ Materials->ReadCreatureTypes();
+ Materials->ReadCreatureTypesEx();
+ Materials->ReadDescriptorColors();
+
+ if(!Tran->Start())
+ {
+ cerr << "Can't get name tables" << endl;
+ return 1;
+ }
+
+ // List all available labors (reproduces contents of Memory.xml)
+ if (list_labors == true) {
+ string laborname;
+ for (int i=0; i < NUM_CREATURE_LABORS; i++) {
+ try {
+ laborname = mem->getLabor(i);
+ cout << "Labor " << int(i) << ": " << laborname << endl;
+ }
+ catch (exception&) {
+ if (verbose)
+ {
+ laborname = "Unknown";
+ cout << "Labor " << int(i) << ": " << laborname << endl;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (showfirstlineonly)
+ {
+ printf("ID Type Name/nickname Job title Current job Happy%s\n", showdead?" Dead ":"");
+ printf("--- ----------------- ------------------------ ---------------- -------------------------------------- -----%s\n", showdead?" -----":"");
+ }
+
+ vector<uint32_t> addrs;
+ for(uint32_t creature_idx = 0; creature_idx < numCreatures; creature_idx++)
+ {
+ DFHack::t_creature creature;
+ Creatures->ReadCreature(creature_idx,creature);
+ /* Check if we want to display/change this creature or skip it */
+ if(filter.creatureMatches(creature, creature_idx))
+ {
+ printCreature(DF,creature,creature_idx);
+ addrs.push_back(creature.origin);
+
+ bool dochange = (
+ remove_skills || remove_civil_skills || remove_military_skills
+ || remove_labors || add_labor || remove_labor
+ || make_hauler || remove_hauler
+ || kill_creature || erase_creature
+ || revive_creature
+ || set_happiness
+ || set_mood
+ || tame_creature || slaughter_creature
+ );
+
+ if (toCaps(filter.creature_type) == "Dwarf"
+ && (creature.profession == PROFESSION_CHILD || creature.profession == PROFESSION_BABY))
+ {
+ dochange = false;
+ }
+
+ bool allow_massdesignation =
+ filter.creature_id.size()==0 ||
+ toCaps(filter.creature_type) != "Dwarf" ||
+ filter.find_nonicks == true ||
+ force_massdesignation;
+ if (dochange == true && allow_massdesignation == false)
+ {
+ cout
+ << "Not changing creature because none of -c (other than dwarf), -i or -nn was" << endl
+ << "selected. Add -f (force) to override this safety measure." << endl;
+ dochange = false;
+ }
+
+ if (dochange)
+ {
+ if(creature.has_default_soul)
+ {
+ if (kill_creature && !creature.flags1.bits.dead)
+ {
+ DFHack::t_creaturflags1 f1 = creature.flags1;
+ DFHack::t_creaturflags2 f2 = creature.flags2;
+ DFHack::t_creaturflags3 f3 = creature.flags3;
+
+ f3.bits.scuttle = true;
+
+ cout << "Writing flags..." << endl;
+ if (!Creatures->WriteFlags(creature_idx, f1.whole,
+ f2.whole, f3.whole))
+ {
+ cout << "Error writing creature flags!" << endl;
+ }
+ // We want the flags to be shown after our
+ // modification, but they are not read back
+ creature.flags1 = f1;
+ creature.flags2 = f2;
+ creature.flags3 = f3;
+ }
+
+ if (erase_creature && !creature.flags1.bits.dead)
+ {
+ /*
+ [quote author=Eldrick Tobin link=topic=58809.msg2178545#msg2178545 date=1302638055]
+
+ After extensive testing that just ate itself -.-;
+
+ Runesmith does not unset the following:
+ - Active Invader (sets if they are just about the invade, as Currently
+ Invading removes this one)
+ - Hidden Ambusher (Just in Case, however it is still set when an Active Invader)
+ - Hidden in Ambush (Just in Case, however it is still set when an Active Invader,
+ until discovery)
+ - Incoming (Sets if something is here yet... wave X of a siege here)
+ - Invader -Fleeing/Leaving
+ - Currently Invading
+
+ When it nukes something it basically just sets them to 'dead'. It does not also
+ set them to 'killed'. Show dead will show everything (short of 'vanished'/'deleted'
+ I'd suspect) so one CAN go through the intensive process to revive a broken siege. These
+ particular flags are not visible at the same exact time so multiple passes -even through
+ a narrow segment- are advised.
+
+ Problem I ran into (last thing before I mention something more DFHack related):
+ I set the Killed Flag (but not dead), and I got mortally wounded siegers that refused to
+ just pift in Magma. [color=purple]Likely missing upper torsoes on examination[/color].
+
+ */
+ /* This is from an invading creature's flags:
+
+ ID: 560, Crocodile Cave, Nako, Standard, Job: No Job, Happiness: 100
+ Flag: Marauder
+ Flag: Can Swap
+ Flag: Active Invader
+ Flag: Invader Origin
+ Flag: Coward
+ Flag: Hidden Ambusher
+ Flag: Invades
+ Flag: Ridden
+ Flag: Calculated Nerves
+ Flag: Calculated Bodyparts
+ Flag: Calculated Insulation
+ Flag: Vision Good
+ Flag: Breathing Good
+
+ */
+
+ DFHack::t_creaturflags1 f1 = creature.flags1;
+ DFHack::t_creaturflags2 f2 = creature.flags2;
+
+ f1.bits.dead = 1;
+ f2.bits.killed = 1;
+ f1.bits.active_invader = 0; /*!< 17: Active invader (for organized ones) */
+ f1.bits.hidden_ambusher = 0; /*!< 21: Active marauder/invader moving inward? */
+ f1.bits.hidden_in_ambush = 0;
+ f1.bits.invades = 0; /*!< 22: Marauder resident/invader moving in all the way */
+
+ cout << "Writing flags..." << endl;
+ if (!Creatures->WriteFlags(creature_idx, f1.whole, f2.whole))
+ {
+ cout << "Error writing creature flags!" << endl;
+ }
+ // We want the flags to be shown after our modification, but they are not read back
+ creature.flags1 = f1;
+ creature.flags2 = f2;
+ }
+
+
+ if (revive_creature && creature.flags1.bits.dead)
+ {
+ DFHack::t_creaturflags1 f1 = creature.flags1;
+ DFHack::t_creaturflags2 f2 = creature.flags2;
+
+ f1.bits.dead = 0;
+ f2.bits.killed = 0;
+ f1.bits.active_invader = 1; /*!< 17: Active invader (for organized ones) */
+ f1.bits.hidden_ambusher = 1; /*!< 21: Active marauder/invader moving inward? */
+ f1.bits.hidden_in_ambush = 1;
+ f1.bits.invades = 1; /*!< 22: Marauder resident/invader moving in all the way */
+
+ cout << "Writing flags..." << endl;
+ if (!Creatures->WriteFlags(creature_idx, f1.whole, f2.whole))
+ {
+ cout << "Error writing creature flags!" << endl;
+ }
+ // We want the flags to be shown after our modification, but they are not read back
+ creature.flags1 = f1;
+ creature.flags2 = f2;
+ }
+
+ if (set_mood)
+ {
+ /* Doesn't really work to disable a mood */
+ cout << "Setting mood to " << set_mood_n << "..." << endl;
+ Creatures->WriteMood(creature_idx, set_mood_n);
+ DFHack::t_creaturflags1 f1 = creature.flags1;
+ DFHack::t_creaturflags2 f2 = creature.flags2;
+ f1.bits.has_mood = (set_mood_n == NO_MOOD ? 0 : 1);
+ if (!Creatures->WriteFlags(creature_idx, f1.whole, f2.whole))
+ {
+ cout << "Error writing creature flags!" << endl;
+ }
+ creature.flags1 = f1;
+ creature.flags2 = f2;
+ }
+
+ if (set_happiness)
+ {
+ cout << "Setting happiness to " << set_happiness_n << "..." << endl;
+ Creatures->WriteHappiness(creature_idx, set_happiness_n);
+ }
+
+ if (remove_skills || remove_civil_skills || remove_military_skills)
+ {
+ DFHack::t_soul & soul = creature.defaultSoul;
+
+ cout << "Removing skills..." << endl;
+
+ for(unsigned int sk = 0; sk < soul.numSkills;sk++)
+ {
+ bool is_military = is_in(soul.skills[sk].id, military_skills, sizeof(military_skills)/sizeof(military_skills[0]));
+ if (remove_skills
+ || (remove_civil_skills && !is_military)
+ || (remove_military_skills && is_military))
+ {
+ soul.skills[sk].rating=0;
+ soul.skills[sk].experience=0;
+ }
+ }
+
+ // Doesn't work anyways, so better leave it alone
+ //soul.numSkills=0;
+ if (Creatures->WriteSkills(creature_idx, soul) == true) {
+ cout << "Success writing skills." << endl;
+ } else {
+ cout << "Error writing skills." << endl;
+ }
+ }
+
+ if (add_labor || remove_labor || remove_labors || make_hauler || remove_hauler)
+ {
+ if (add_labor) {
+ cout << "Adding labor " << add_labor_n << "..." << endl;
+ creature.labors[add_labor_n] = 1;
+ }
+
+ if (remove_labor) {
+ cout << "Removing labor " << remove_labor_n << "..." << endl;
+ creature.labors[remove_labor_n] = 0;
+ }
+
+ if (remove_labors) {
+ cout << "Removing labors..." << endl;
+ for(unsigned int lab = 0; lab < NUM_CREATURE_LABORS; lab++) {
+ creature.labors[lab] = 0;
+ }
+ }
+
+ if (remove_hauler) {
+ for (int labs=0;
+ labs < sizeof(hauler_labors)/sizeof(hauler_labors[0]);
+ labs++)
+ {
+ creature.labors[hauler_labors[labs]] = 0;
+ }
+ }
+
+ if (make_hauler) {
+ cout << "Setting hauler labors..." << endl;
+ for (int labs=0;
+ labs < sizeof(hauler_labors)/sizeof(hauler_labors[0]);
+ labs++)
+ {
+ creature.labors[hauler_labors[labs]] = 1;
+ }
+ }
+ if (Creatures->WriteLabors(creature_idx, creature.labors) == true) {
+ cout << "Success writing labors." << endl;
+ } else {
+ cout << "Error writing labors." << endl;
+ }
+ }
+
+ if (tame_creature)
+ {
+ bool tame = true;
+
+ DFHack::t_creaturflags1 f1 = creature.flags1;
+ DFHack::t_creaturflags2 f2 = creature.flags2;
+
+ // Site residents are intelligent, so don't
+ // tame them.
+ if (f2.bits.resident)
+ tame = false;
+
+ f1.bits.diplomat = false;
+ f1.bits.merchant = false;
+ f2.bits.resident = false;
+ f2.bits.underworld = false;
+ f2.bits.visitor_uninvited = false;
+ f2.bits.roaming_wilderness_population_source = false;
+ f2.bits.roaming_wilderness_population_source_not_a_map_feature = false;
+
+ // Creatures which already belong to a civ might
+ // be intelligent, so don't tame them.
+ if (creature.civ == -1)
+ f1.bits.tame = tame;
+
+ if (!Creatures->WriteFlags(creature_idx,
+ f1.whole, f2.whole))
+ {
+ cout << "Error writing creature flags!" << endl;
+ }
+
+ int32_t civ = Creatures->GetDwarfCivId();
+ if (!Creatures->WriteCiv(creature_idx, civ))
+ {
+ cout << "Error writing creature civ!" << endl;
+ }
+ creature.flags1 = f1;
+ creature.flags2 = f2;
+ }
+
+ if (slaughter_creature)
+ {
+ DFHack::t_creaturflags1 f1 = creature.flags1;
+ DFHack::t_creaturflags2 f2 = creature.flags2;
+
+ f2.bits.slaughter = true;
+
+ if (!Creatures->WriteFlags(creature_idx,
+ f1.whole, f2.whole))
+ {
+ cout << "Error writing creature flags!" << endl;
+ }
+ creature.flags1 = f1;
+ creature.flags2 = f2;
+ }
+ }
+ else
+ {
+ cout << "Error removing skills: Creature has no default soul." << endl;
+ }
+ printCreature(DF,creature,creature_idx);
+ } /* End remove skills/labors */
+ } /* if (print creature) */
+ } /* End for(all creatures) */
+ } /* End if (we need to walk creatures) */
+
+ Creatures->Finish();
+ DF->Detach();
+ if (quiet == false)
+ {
+ cout << "Done. Press any key to continue" << endl;
+ cin.ignore();
+ }
+ return 0;
+}
diff --git a/needs_porting/dfbauxite.cpp b/needs_porting/dfbauxite.cpp
new file mode 100644
index 00000000..3a2fdb97
--- /dev/null
+++ b/needs_porting/dfbauxite.cpp
@@ -0,0 +1,161 @@
+/*
+DFBauxite - Converts all your mechanisms to bauxite (for use in magma).
+Author: Alex Legg
+
+Based on code from and uses DFHack - www.sourceforge.net/projects/dfhack
+*/
+
+#include <sstream>
+#include <iostream>
+#include <string.h>
+#include <cstdlib>
+#include <assert.h>
+#include <string>
+#include <vector>
+using namespace std;
+
+
+#include <DFIntegers.h>
+#include <DFExport.h>
+#include <DFError.h>
+#include <DFVector.h>
+#include <DFMemInfo.h>
+#include <DFProcess.h>
+#include <DFTypes.h>
+using namespace DFHack;
+
+
+int main ()
+{
+ DFHack::Process *proc;
+ DFHack::memory_info *meminfo;
+ DFHack::DfVector <uint32_t> *items_vector;
+ DFHack::t_item_df40d item_40d;
+ DFHack::t_matglossPair item_40d_material;
+ vector<DFHack::t_matgloss> stoneMat;
+ uint32_t item_material_offset;
+ uint32_t temp;
+ int32_t type;
+ int items;
+ int found = 0, converted = 0;
+
+ DFHack::ContextManager DF("Memory.xml");
+ try
+ {
+ DF.Attach();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+
+ // Find out which material is bauxite
+ if(!DF.ReadStoneMatgloss(stoneMat))
+ {
+ cout << "Materials not supported for this version of DF, exiting." << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ DF.Detach();
+ return EXIT_FAILURE;
+ }
+ int bauxiteIndex = -1;
+ for (int i = 0; i < stoneMat.size();i++)
+ {
+ if(strcmp(stoneMat[i].id, "BAUXITE") == 0)
+ {
+ bauxiteIndex = i;
+ break;
+ }
+ }
+ if(bauxiteIndex == -1)
+ {
+ cout << "Cannot locate bauxite in the DF raws, exiting" << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ DF.Detach();
+ return EXIT_FAILURE;
+ }
+
+ // Get some basics needed for full access
+ proc = DF.getProcess();
+ meminfo = proc->getDescriptor();
+
+ // Get the object name/ID mapping
+ //FIXME: work on the 'supported features' system required
+
+ // Check availability of required addresses and offsets (doing custom stuff here)
+
+ items = meminfo->getAddress("items");
+ item_material_offset = meminfo->getOffset("item_materials");
+ if( !items || ! item_material_offset)
+ {
+ cout << "Items not supported for this DF version, exiting" << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ DF.Detach();
+ return EXIT_FAILURE;
+ }
+
+ items_vector = new DFHack::DfVector <uint32_t> (proc, items);
+ for(uint32_t i = 0; i < items_vector->size(); i++)
+ {
+ // get pointer to object
+ temp = items_vector->at (i);
+ // read object
+ proc->read (temp, sizeof (DFHack::t_item_df40d), (uint8_t *) &item_40d);
+
+ // resolve object type
+ type = -1;
+
+ // skip things we can't identify
+ if(!meminfo->resolveObjectToClassID (temp, type))
+ continue;
+ string classname;
+ if(!meminfo->resolveClassIDToClassname (type, classname))
+ continue;
+
+ if(classname == "item_trapparts")
+ {
+ proc->read (temp + item_material_offset, sizeof (DFHack::t_matglossPair), (uint8_t *) &item_40d_material);
+
+ cout << dec << "Mechanism at x:" << item_40d.x << " y:" << item_40d.y << " z:" << item_40d.z << " ID:" << item_40d.ID << endl;
+
+ if (item_40d_material.index != bauxiteIndex)
+ {
+ item_40d_material.index = bauxiteIndex;
+ proc->write (temp + item_material_offset, sizeof (DFHack::t_matglossPair), (uint8_t *) &item_40d_material);
+ converted++;
+ }
+
+ found++;
+ }
+ }
+
+
+ if (found == 0)
+ {
+ cout << "No mechanisms to convert" << endl;
+ } else {
+ cout << found << " mechanisms found" << endl;
+ cout << converted << " mechanisms converted" << endl;
+ }
+
+ DF.Resume();
+ DF.Detach();
+
+ delete items_vector;
+
+#ifndef LINUX_BUILD
+ cout << "Done. Press any key to continue" << endl;
+ cin.ignore();
+#endif
+
+ return 0;
+}
diff --git a/needs_porting/dfstatus.cpp b/needs_porting/dfstatus.cpp
new file mode 100644
index 00000000..91c6f658
--- /dev/null
+++ b/needs_porting/dfstatus.cpp
@@ -0,0 +1,206 @@
+/*
+ * dfstatus.cpp
+*/
+
+#include <curses.h>
+
+#ifndef LINUX_BUILD
+ #include <windows.h>
+#endif
+
+#include <time.h>
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <sstream>
+#include <climits>
+#include <vector>
+#include <cstring>
+#include <string>
+//#include <conio.h> //to break on keyboard input
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+using namespace std;
+#include <DFHack.h>
+#include <DFVector.h>
+#include <extra/stopwatch.h>
+
+WINDOW *create_newwin(int height, int width, int starty, int startx);
+
+ int32_t drinkCount = 0;
+ int32_t mealsCount = 0;
+ int32_t plantCount = 0;
+ int32_t fishCount = 0;
+ int32_t meatCount = 0;
+ int32_t logsCount = 0;
+ int32_t barCount = 0;
+ int32_t clothCount = 0;
+ int32_t ironBars = 0;
+ int32_t pigIronBars = 0;
+ int32_t goldBars = 0;
+ int32_t silverBars = 0;
+ int32_t copperBars = 0;
+ int32_t steelBars = 0;
+ int32_t fuel = 0;
+ uint64_t start_time = 0;
+ uint64_t end_time = 0;
+ uint64_t total_time = 0;
+
+WINDOW *create_newwin(int height, int width, int starty, int startx){
+ WINDOW *local_win;
+
+ local_win = newwin(height, width, starty, startx);
+ box(local_win, 0, 0); /* 0, 0 gives default characters
+ * for the vertical and horizontal
+ * lines */
+ //first row
+ mvwprintw(local_win,2 ,2,"Drinks : %d", drinkCount);
+ mvwprintw(local_win,4 ,2,"Meals : %d", mealsCount);
+ mvwprintw(local_win,6 ,2,"Plants : %d", plantCount);
+ mvwprintw(local_win,7 ,2,"Fish : %d", fishCount);
+ mvwprintw(local_win,8 ,2,"Meat : %d", meatCount);
+ mvwprintw(local_win,10,2,"Logs : %d", logsCount);
+ mvwprintw(local_win,12,2,"Cloth : %d", clothCount);
+ //second row
+ mvwprintw(local_win,2,22,"Iron Bars : %d", ironBars);
+ mvwprintw(local_win,3,22,"Gold Bars : %d", goldBars);
+ mvwprintw(local_win,4,22,"Silver Bars : %d", silverBars);
+ mvwprintw(local_win,5,22,"Copper Bars : %d", copperBars);
+ mvwprintw(local_win,6,22,"Steel Bars : %d", steelBars);
+ mvwprintw(local_win,7,22,"Pig iron Bars : %d", pigIronBars);
+ mvwprintw(local_win,9,22,"Fuel : %d", fuel);
+ total_time += end_time - start_time;
+ mvwprintw(local_win,14,2,"Time: %d ms last update, %d ms total", end_time - start_time, total_time);
+
+ wrefresh(local_win); // paint the screen and all components.
+
+ return local_win;
+}
+
+int main()
+{
+ WINDOW *my_win;
+ int startx, starty, width, height;
+
+ DFHack::Process * p;
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context * DF;
+ DFHack::Materials * Materials;
+ try{ //is DF running?
+ DF = DFMgr.getSingleContext();
+ DF->Attach();
+ Materials = DF->getMaterials();
+ Materials->ReadAllMaterials();
+ DF->Resume();
+ }
+ catch (exception& e){
+ cerr << e.what() << endl;
+ return 1;
+ }
+ //init and Attach
+ ofstream file("dfstatus_errors.txt");
+ streambuf* strm_buffer = cerr.rdbuf(); // save cerr's output buffer
+ cerr.rdbuf (file.rdbuf()); // redirect output into the file
+
+ initscr(); //start curses.
+ nonl();
+ intrflush(stdscr, FALSE);
+ keypad(stdscr, TRUE);
+ do{
+ drinkCount = 0;
+ mealsCount = 0;
+ plantCount = 0;
+ fishCount = 0;
+ meatCount = 0;
+ logsCount = 0;
+ barCount = 0;
+ clothCount = 0;
+ ironBars = 0;
+ pigIronBars = 0;
+ goldBars = 0;
+ silverBars = 0;
+ copperBars = 0;
+ steelBars = 0;
+ fuel = 0;
+
+ //FILE * pFile;
+ //pFile = fopen("dump.txt","w");
+ start_time = GetTimeMs64();
+ if(!DF->Suspend())
+ {
+ break;
+ }
+
+ //DFHack::Gui * Gui = DF->getGui();
+
+ DFHack::Items * Items = DF->getItems();
+ Items->Start();
+
+ DFHack::VersionInfo * mem = DF->getMemoryInfo();
+ p = DF->getProcess();
+
+ DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
+ DFHack::DfVector <uint32_t> p_items (p, itemGroup->getAddress("items_vector"));
+ uint32_t size = p_items.size();
+
+ DFHack::dfh_item itm; //declare itm
+ //memset(&itm, 0, sizeof(DFHack::dfh_item)); //seems to set every value in itm to 0
+
+ for(unsigned int idx = 0; idx < size; idx++) //fill our item variables with this loop
+ {
+ Items->readItem(p_items[idx], itm);
+
+ if (itm.base.flags.owned) //only count what we actually own.
+ continue;
+
+ string s0 = Items->getItemClass(itm.matdesc.itemType).c_str();
+ string s1 = Items->getItemDescription(itm, Materials).c_str();
+
+ if( s0 == "drink" ) {drinkCount += itm.quantity;}
+ else if(s0 == "food"){mealsCount += itm.quantity;}
+ else if(s0 == "plant"){plantCount += itm.quantity;}
+ else if(s0 == "fish"){fishCount += itm.quantity;}
+ else if(s0 == "meat"){meatCount += itm.quantity;}
+ else if(s0 == "wood"){logsCount += itm.quantity;}
+ else if(s0 == "cloth"){clothCount += itm.quantity;}
+ else if(s0 == "bar") //need to break it down by ItemDescription to get the different types of bars.
+ {
+ barCount = barCount + itm.quantity;
+ if(s1.find("PIG_IRON")!=string::npos){pigIronBars++;}
+ else if(s1.find("IRON")!=string::npos){ironBars++;}
+ else if(s1.find("GOLD")!=string::npos){goldBars++;}
+ else if(s1.find("SILVER")!=string::npos){silverBars++;}
+ else if(s1.find("COPPER")!=string::npos){copperBars++;}
+ else if(s1.find("STEEL")!=string::npos){steelBars++;}
+ else if(s1.find("COAL")!=string::npos){fuel++;}
+ }
+ /*if(s0 != "boulder" && s0 != "thread"){
+ fprintf(pFile,"%5d: %12s - %64s - [%d]\n", idx, Items->getItemClass(itm.matdesc.itemType).c_str(), Items->getItemDescription(itm, Materials).c_str(), itm.quantity);
+ }*/
+ }
+ DF->Resume();
+ end_time = GetTimeMs64();
+ //printf("%d - %d\n", (clock()/CLOCKS_PER_SEC),(clock()/CLOCKS_PER_SEC)%60);
+ height = LINES;
+ width = COLS;
+ starty = (LINES - height) / 2;
+ startx = (COLS - width) / 2;
+
+ my_win = create_newwin(height, width, starty, startx);
+
+#ifdef LINUX_BUILD
+ sleep(10);
+#else
+ Sleep(10000);
+#endif
+
+ } while(true);
+
+ endwin(); /* End curses mode */
+ cerr.rdbuf (strm_buffer); // restore old output buffer
+ file.close();
+
+ return 0;
+} \ No newline at end of file
diff --git a/needs_porting/digger.cpp b/needs_porting/digger.cpp
new file mode 100644
index 00000000..86a9b84b
--- /dev/null
+++ b/needs_porting/digger.cpp
@@ -0,0 +1,363 @@
+// digger.cpp
+
+// NOTE currently only works with trees
+
+// TODO add a sort of "sub-target" to dig() to make it able to designate stone as well
+
+#include <iostream>
+#include <vector>
+#include <list>
+#include <cstdlib>
+#include <algorithm>
+#include <assert.h>
+using namespace std;
+
+#include <DFHack.h>
+#include <DFTileTypes.h>
+#include <argstream.h>
+
+// counts the occurances of a certain element in a vector
+// used to determine of a given tile is a target
+int vec_count(vector<uint16_t>& vec, uint16_t t)
+{
+ int count = 0;
+ for (uint32_t i = 0; i < vec.size(); ++i)
+ {
+ if (vec[i] == t)
+ ++count;
+ }
+ return count;
+}
+
+// splits a string on a certain char
+//
+// src is the string to split
+// delim is the delimiter to split the string around
+// tokens is filled with every occurance between delims
+void string_split(vector<string>& tokens, const std::string& src, const std::string& delim)
+{
+ std::string::size_type start = 0;
+ std::string::size_type end;
+ while (true)
+ {
+ end = src.find(delim, start);
+ tokens.push_back(src.substr(start, end - start));
+ if (end == std::string::npos) // last token handled
+ break;
+ start = end + delim.size(); // skip next delim
+ }
+}
+
+// this is used to parse the command line options
+void parse_int_csv(vector<uint16_t>& targets, const std::string& src)
+{
+ std::string::size_type start = 0;
+ std::string::size_type end;
+ while (true)
+ {
+ end = src.find(",", start);
+ targets.push_back(atoi(src.substr(start, end - start).c_str()));
+ if (end == std::string::npos) // last token handled
+ break;
+ start = end + 1; // skip next delim
+ }
+}
+
+struct DigTarget
+{
+ DigTarget() :
+ source_distance(0),
+ grid_x(0), grid_y(0),
+ local_x(0), local_y(0),
+ real_x(0), real_y(0), z(0)
+ {
+ }
+
+ DigTarget(
+ int realx, int realy, int _z,
+ int sourcex, int sourcey, int sourcez) :
+ real_x(realx), real_y(realy), z(_z)
+ {
+ grid_x = realx/16;
+ grid_y = realy/16;
+
+ local_x = realx%16;
+ local_y = realy%16;
+
+ source_distance = manhattan_distance(
+ real_x, real_y, z,
+ sourcex, sourcey, sourcez);
+ }
+
+ DigTarget(
+ int gridx, int gridy, int _z,
+ int localx, int localy,
+ int sourcex, int sourcey, int sourcez) :
+ grid_x(gridx), grid_y(gridy),
+ local_x(localx), local_y(localy),
+ z(_z)
+ {
+ real_x = (grid_x*16)+local_x;
+ real_y = (grid_y*16)+local_y;
+
+ source_distance = manhattan_distance(
+ real_x, real_y, z,
+ sourcex, sourcey, sourcez);
+ }
+
+ int source_distance; // the distance to the source coords, used for sorting
+
+ int grid_x, grid_y; // what grid the target is in
+ int local_x, local_y; // on what coord in the grid the target is in (0-16)
+ int real_x, real_y; // real coordinates for target, thats grid*16+local
+ int z; // z position for target, stored plain since there arent z grids
+
+ bool operator<(const DigTarget& o) const { return source_distance < o.source_distance; }
+
+private:
+ // calculates the manhattan distance between two coords
+ int manhattan_distance(int x, int y, int z, int xx, int yy, int zz)
+ {
+ return abs(x-xx)+abs(y-yy)+abs(z-zz);
+ }
+};
+
+int dig(DFHack::Maps* Maps,
+ vector<uint16_t>& targets,
+ int num = -1,
+ const int x_source = 0,
+ const int y_source = 0,
+ const int z_source = 0,
+ bool verbose = false)
+{
+ if (num == 0)
+ return 0; // max limit of 0, nothing to do
+
+ uint32_t x_max,y_max,z_max;
+ DFHack::designations40d designations;
+ DFHack::tiletypes40d tiles;
+ Maps->getSize(x_max,y_max,z_max);
+
+ // every tile found, will later be sorted by distance to source
+ vector<DigTarget> candidates;
+
+ if (verbose)
+ cout << "source is " << x_source << " " << y_source << " " << z_source << endl;
+
+ // 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++)
+ {
+ if(Maps->isValidBlock(x,y,z))
+ {
+ // read block designations and tiletype
+ Maps->ReadDesignations(x,y,z, &designations);
+ Maps->ReadTileTypes(x,y,z, &tiles);
+
+ // search all tiles for dig targets:
+ // visible, not yet marked for dig and matching tile type
+ for(uint32_t lx = 0; lx < 16; lx++)
+ {
+ for(uint32_t ly = 0; ly < 16; ly++)
+ {
+ if (/*designations[lx][ly].bits.hidden == 0 && */
+ designations[lx][ly].bits.dig == 0 &&
+ vec_count(targets, DFHack::tileShape(tiles[lx][ly])) > 0)
+ {
+ DigTarget dt(
+ x, y, z,
+ lx, ly,
+ x_source, y_source, z_source);
+ candidates.push_back(dt);
+
+ if (verbose)
+ {
+ cout << "target found at " << dt.real_x << " " << dt.real_y << " " << dt.z;
+ cout << ", " << dt.source_distance << " tiles to source" << endl;
+ }
+ }
+ } // local y
+ } // local x
+ }
+ }
+ }
+ }
+
+ // if we found more tiles than was requested, sort them by distance to source,
+ // keep the front 'num' elements and drop the rest
+ if (num != -1 && candidates.size() > (unsigned int)num)
+ {
+ sort(candidates.begin(), candidates.end());
+ candidates.resize(num);
+ }
+ num = candidates.size();
+
+ if (verbose)
+ cout << "=== proceeding to designating targets ===" << endl;
+
+ // mark the tiles for actual digging
+ for (vector<DigTarget>::const_iterator i = candidates.begin(); i != candidates.end(); ++i)
+ {
+ if (verbose)
+ {
+ cout << "designating at " << (*i).real_x << " " << (*i).real_y << " " << (*i).z;
+ cout << ", " << (*i).source_distance << " tiles to source" << endl;
+ }
+
+ // TODO this could probably be made much better, theres a big chance the trees are on the same grid
+ Maps->ReadDesignations((*i).grid_x, (*i).grid_y, (*i).z, &designations);
+ designations[(*i).local_x][(*i).local_y].bits.dig = DFHack::designation_default;
+ Maps->WriteDesignations((*i).grid_x, (*i).grid_y, (*i).z, &designations);
+
+ // Mark as dirty so the jobs are properly picked up by the dwarves
+ Maps->WriteDirtyBit((*i).grid_x, (*i).grid_y, (*i).z, true);
+ }
+
+ return num;
+}
+
+void test()
+{
+ //////////////////////////
+ // DigTarget
+ {
+ DigTarget dt(
+ 20, 35, 16,
+ 10, 12, 14);
+
+ assert(dt.grid_x == 1);
+ assert(dt.grid_y == 2);
+
+ assert(dt.local_x == 4);
+ assert(dt.local_y == 3);
+
+ assert(dt.real_x == 20);
+ assert(dt.real_y == 35);
+
+ assert(dt.z == 16);
+ assert(dt.source_distance == 35);
+ }
+ {
+ DigTarget dt(
+ 2, 4, 16,
+ 5, 10,
+ 10, 12, 14);
+
+ assert(dt.grid_x == 2);
+ assert(dt.grid_y == 4);
+
+ assert(dt.local_x == 5);
+ assert(dt.local_y == 10);
+
+ assert(dt.real_x == 37);
+ assert(dt.real_y == 74);
+
+ assert(dt.z == 16);
+ assert(dt.source_distance == 91);
+ }
+
+ //////////////////////////
+ // string splitter
+ {
+ vector<string> tokens;
+ string src = "10,9,11";
+ string delim = ",";
+ string_split(tokens, src, delim);
+
+ assert(tokens.size() == 3);
+ assert(tokens[0] == "10");
+ assert(tokens[1] == "9");
+ assert(tokens[2] == "11");
+ }
+ {
+ vector<string> tokens;
+ string src = "10";
+ string delim = ",";
+ string_split(tokens, src, delim);
+
+ assert(tokens.size() == 1);
+ assert(tokens[0] == "10");
+ }
+ {
+ vector<uint16_t> targets;
+ parse_int_csv(targets, "9,10");
+ assert(targets[0] == 9);
+ assert(targets[1] == 10);
+ }
+}
+
+int main (int argc, char** argv)
+{
+ //test();
+
+ // Command line options
+ string s_targets;
+ string s_origin;
+ bool verbose;
+ int max = 10;
+ argstream as(argc,argv);
+
+ as >>option('v',"verbose",verbose,"Active verbose mode")
+ >>parameter('o',"origin",s_origin,"Close to where we should designate targets, format: x,y,z")
+ >>parameter('t',"targets",s_targets,"What kinds of tile we should designate, format: type1,type2")
+ >>parameter('m',"max",max,"The maximum limit of designated targets")
+ >>help();
+
+ // some commands need extra care
+ vector<uint16_t> targets;
+ parse_int_csv(targets, s_targets);
+
+ vector<uint16_t> origin;
+ parse_int_csv(origin, s_origin);
+
+ // sane check
+ if (!as.isOk())
+ {
+ cout << as.errorLog();
+ }
+ else if (targets.size() == 0 || origin.size() != 3)
+ {
+ cout << as.usage();
+ }
+ else
+ {
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context *DF = DFMgr.getSingleContext();
+ try
+ {
+ DF->Attach();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+ DFHack::Maps *Maps = DF->getMaps();
+ if (Maps && Maps->Start())
+ {
+ int count = dig(Maps, targets, max, origin[0],origin[1],origin[2], verbose);
+ cout << count << " targets designated" << endl;
+ Maps->Finish();
+
+ if (!DF->Detach())
+ {
+ cerr << "Unable to detach DF process" << endl;
+ }
+ }
+ else
+ {
+ cerr << "Unable to init map" << endl;
+ }
+ }
+ #ifndef LINUX_BUILD
+ cout << "Done. Press any key to continue" << endl;
+ cin.ignore();
+ #endif
+ return 0;
+}
diff --git a/needs_porting/digger2.cpp b/needs_porting/digger2.cpp
new file mode 100644
index 00000000..ea34b8c2
--- /dev/null
+++ b/needs_porting/digger2.cpp
@@ -0,0 +1,180 @@
+/**
+ * @file digger2.cpp
+ * @author rOut
+ *
+ * Improved digger tool.
+ *
+ * Takes a text file as first an only argument.
+ * The text file is read as a grid, and every character represents a designation for a tile.
+ * Allowed characters are 'd' for dig, 'u' for up stairs, 'j' for down stairs, 'i' for up and down stairs, 'h' for channel, 'r' for upward ramp and 'x' to remove designation.
+ * Other characters don't do anything and can be used for padding.
+ * The designation pattern is the wrote in game memory, centered on the current cursor position. Thus, the game needs to be in designation mode or, perhaps, any other mode that have a cursor.
+ */
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string>
+#include <list>
+#include <cstdlib>
+#include <algorithm>
+#include <assert.h>
+using namespace std;
+
+#include <DFHack.h>
+#include <DFTileTypes.h>
+#define BLOCK_SIZE 16
+
+
+void dig(DFHack::Maps* layers, DFHack::Gui* Gui, ::std::vector< ::std::string >& dig_map, bool verbose = false)
+{
+ int32_t x_cent;
+ int32_t y_cent;
+ int32_t z_cent;
+ Gui->getCursorCoords(x_cent, y_cent, z_cent);
+
+// ::std::cout << "x_cent: " << x_cent << " y_cent: " << y_cent << " z_cent: " << z_cent << ::std::endl;
+
+ int32_t z_from = z_cent;
+ int32_t z = 0;
+
+ uint32_t x_max;
+ uint32_t y_max;
+ uint32_t z_max;
+ layers->getSize(x_max, y_max, z_max);
+
+// ::std::cout << "x_max: " << x_max << " y_max: " << y_max << " z_max: " << z_max << ::std::endl;
+
+ int32_t dig_height = dig_map.size();
+ int32_t y_from = y_cent - (dig_height / 2);
+// ::std::cout << "dig_height: " << dig_height << ::std::endl;
+// ::std::cout << "y_from: " << y_from << ::std::endl;
+
+ int32_t y = 0;
+ DFHack::designations40d designations;
+ DFHack::tiletypes40d tiles;
+ ::std::vector< ::std::string >::iterator str_it;
+ for (str_it = dig_map.begin(); str_it != dig_map.end(); ++str_it) {
+ int32_t dig_width = str_it->size();
+ int32_t x_from = x_cent - (dig_width / 2);
+
+// ::std::cout << "x_cent: " << x_cent << " y_cent: " << y_cent << " z_cent: " << z_cent << ::std::endl;
+// ::std::cout << "dig_width: " << dig_width << ::std::endl;
+// ::std::cout << "x_from: " << x_from << ::std::endl;
+
+ int32_t x = 0;
+ ::std::string::iterator chr_it;
+ for (chr_it = str_it->begin(); chr_it != str_it ->end(); ++chr_it)
+ {
+ int32_t x_grid = (x_from + x) / BLOCK_SIZE;
+ int32_t y_grid = (y_from + y) / BLOCK_SIZE;
+ int32_t z_grid = z_from + z;
+ int32_t x_locl = (x_from + x) - x_grid * BLOCK_SIZE;
+ int32_t y_locl = (y_from + y) - y_grid * BLOCK_SIZE;
+ int32_t z_locl = 0;
+
+ if (x_grid >= 0 && y_grid >= 0 && x_grid < x_max && y_grid < y_max)
+ {
+ // TODO this could probably be made much better, theres a big chance the trees are on the same grid
+ layers->ReadDesignations(x_grid, y_grid, z_grid, &designations);
+ layers->ReadTileTypes(x_grid, y_grid, z_grid, &tiles);
+
+// ::std::cout << ::std::hex << "designations: " << designations[x_locl][y_locl].bits.dig << ::std::dec << ::std::endl;
+ DFHack::naked_designation & des = designations[x_locl][y_locl].bits;
+ if ( DFHack::tileShape(tiles[x_locl][y_locl]) == DFHack::WALL)
+ {
+ switch ((char) *chr_it)
+ {
+ case 'd':
+ des.dig = DFHack::designation_default;
+ break;
+ case 'u':
+ des.dig = DFHack::designation_u_stair;
+ break;
+ case 'j':
+ des.dig = DFHack::designation_d_stair;
+ break;
+ case 'i':
+ des.dig = DFHack::designation_ud_stair;
+ break;
+ case 'h':
+ des.dig = DFHack::designation_channel;
+ break;
+ case 'r':
+ des.dig = DFHack::designation_ramp;
+ break;
+ case 'x':
+ des.dig = DFHack::designation_no;
+ break;
+ }
+
+ if (verbose)
+ {
+ ::std::cout << "designating " << (char) *chr_it << " at " << x_from + x << " " << y_from + y << " " << z_from + z << ::std::endl;
+ }
+
+ layers->WriteDesignations(x_grid, y_grid, z_grid, &designations);
+
+ // Mark as dirty so the jobs are properly picked up by the dwarves
+ layers->WriteDirtyBit(x_grid, y_grid, z_grid, true);
+ }
+ }
+
+ ++x;
+ }
+ ++y;
+ }
+}
+
+int main(int argc, char** argv) {
+ if(argc < 2) {
+ ::std::cout << "gimme a file!" << ::std::endl;
+ return 1;
+ }
+
+ ::std::ifstream map_in(argv[1]);
+
+ ::std::vector< ::std::string > dig_map;
+ while (map_in.good() && !map_in.eof() && !map_in.bad()) {
+ ::std::string line;
+ map_in >> line;
+
+ dig_map.push_back(line);
+ }
+ dig_map.resize(dig_map.size() - 1);
+
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context * DF = DFMgr.getSingleContext();
+
+ try {
+ DF->Attach();
+ } catch (::std::exception& e) {
+ ::std::cerr << e.what() << ::std::endl;
+#ifndef LINUX_BUILD
+ ::std::cin.ignore();
+#endif
+ return 1;
+ }
+
+ DFHack::Maps *layers = DF->getMaps();
+ if (layers && layers->Start()) {
+
+ dig(layers, DF->getGui(), dig_map, true);
+
+ ::std::cout << "Finished digging" << ::std::endl;
+ layers->Finish();
+
+ if (!DF->Detach()) {
+ ::std::cerr << "Unable to detach DF process" << ::std::endl;
+ }
+
+ } else {
+ ::std::cerr << "Unable to init map" << ::std::endl;
+ }
+
+#ifndef LINUX_BUILD
+ ::std::cout << "Done. Press any key to continue" << ::std::endl;
+ ::std::cin.ignore();
+#endif
+ return 0;
+}
diff --git a/needs_porting/digpattern.cpp b/needs_porting/digpattern.cpp
new file mode 100644
index 00000000..90d960ba
--- /dev/null
+++ b/needs_porting/digpattern.cpp
@@ -0,0 +1,259 @@
+#include <iostream>
+#include <string.h> // for memset
+#include <string>
+#include <vector>
+#include <stack>
+#include <map>
+#include <stdio.h>
+#include <cstdlib>
+using namespace std;
+
+#include <DFHack.h>
+#include <extra/MapExtras.h>
+using namespace MapExtras;
+//#include <argstream.h>
+
+void usage(int argc, const char * argv[])
+{
+ cout
+ << "Usage:" << endl
+ << argv[0] << " [option 1] [option 2] [...]" << endl
+ << "-q : Suppress \"Press any key to continue\" at program termination" << endl
+ << "-u <n> : Dig upwards <n> times (default 5)" << endl
+ << "-d <n> : Dig downwards <n> times (default 5)" << endl
+ ;
+}
+
+void digat(MapCache * MCache, DFHack::DFCoord xy)
+{
+ int16_t tt;
+ tt = MCache->tiletypeAt(xy);
+ if(!DFHack::isWallTerrain(tt))
+ return;
+
+ // found a good tile, dig+unset material
+ DFHack::t_designation des = MCache->designationAt(xy);
+
+ if(MCache->testCoord(xy))
+ {
+ MCache->clearMaterialAt(xy);
+
+ if(des.bits.dig == DFHack::designation_no)
+ des.bits.dig = DFHack::designation_default;
+ MCache->setDesignationAt(xy,des);
+ }
+}
+
+int strtoint(const string &str)
+{
+ stringstream ss(str);
+ int result;
+ return ss >> result ? result : -1;
+}
+
+typedef struct
+{
+ int16_t x;
+ int16_t y;
+} pos;
+
+int main (int argc, const char* argv[])
+{
+ // Command line options
+ bool updown = false;
+ bool quiet = true;
+ // let's be more useful when double-clicked on windows
+ #ifndef LINUX_BUILD
+ quiet = false;
+ #endif
+ int dig_up_n = 5;
+ int dig_down_n = 5;
+
+ for(int i = 1; i < argc; i++)
+ {
+ string arg_cur = argv[i];
+ string arg_next = "";
+ int arg_next_int = -99999;
+ /* Check if argv[i+1] is a number >= 0 */
+ if (i < argc-1) {
+ arg_next = argv[i+1];
+ arg_next_int = strtoint(arg_next);
+ if (arg_next != "0" && arg_next_int == 0) {
+ arg_next_int = -99999;
+ }
+ }
+ if (arg_cur == "-x")
+ {
+ updown = true;
+ }
+ else if (arg_cur == "-q")
+ {
+ quiet = true;
+ }
+ else if(arg_cur == "-u" && i < argc-1)
+ {
+ if (arg_next_int < 0 || arg_next_int >= 99999) {
+ usage(argc, argv);
+ return 1;
+ }
+ dig_up_n = arg_next_int;
+ i++;
+ }
+ else if(arg_cur == "-d" && i < argc-1)
+ {
+ if (arg_next_int < 0 || arg_next_int >= 99999) {
+ usage(argc, argv);
+ return 1;
+ }
+ dig_down_n = arg_next_int;
+ i++;
+ }
+ else
+ {
+ usage(argc, argv);
+ return 1;
+ }
+ }
+
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context * DF;
+ try
+ {
+ DF = DFMgr.getSingleContext();
+ DF->Attach();
+ }
+ catch (exception& e)
+ {
+ cerr << "Error getting context: " << e.what() << endl;
+ if (!quiet)
+ cin.ignore();
+
+ return 1;
+ }
+
+ uint32_t x_max,y_max,z_max;
+ DFHack::Maps * Maps = DF->getMaps();
+ DFHack::Gui * Gui = DF->getGui();
+
+ // init the map
+ if(!Maps->Start())
+ {
+ cerr << "Can't init map. Make sure you have a map loaded in DF." << endl;
+ DF->Detach();
+ if (!quiet)
+ cin.ignore();
+
+ return 1;
+ }
+
+ int32_t cx, cy, cz;
+ Maps->getSize(x_max,y_max,z_max);
+ uint32_t tx_max = x_max * 16;
+ uint32_t ty_max = y_max * 16;
+
+ Gui->getCursorCoords(cx,cy,cz);
+ if (cx == -30000)
+ {
+ cerr << "Cursor is not active. Point the cursor at the position to dig at." << endl;
+ DF->Detach();
+ if (!quiet)
+ {
+ cin.ignore();
+ }
+ return 1;
+ }
+
+ DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz);
+ if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1)
+ {
+ cerr << "I won't dig the borders. That would be cheating!" << endl;
+ DF->Detach();
+ if (!quiet)
+ {
+ cin.ignore();
+ }
+ return 1;
+ }
+ MapCache * MCache = new MapCache(Maps);
+
+ DFHack::t_designation des = MCache->designationAt(xy);
+ int16_t tt = MCache->tiletypeAt(xy);
+ int16_t veinmat = MCache->veinMaterialAt(xy);
+
+ /*
+ if( veinmat == -1 )
+ {
+ cerr << "This tile is non-vein. Bye :)" << endl;
+ delete MCache;
+ DF->Detach();
+ if (!quiet) {
+ cin.ignore();
+ }
+ return 1;
+ }
+ */
+ printf("Digging at (%d/%d/%d), tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole);
+
+ // 1 < xy.x < tx_max - 1
+ // 1 < xy.y < ty_max - 1
+ // xy.z
+
+ // X____
+ // X_XXX
+ // XXXXX
+ // __XXX
+ // __XXX
+ // _____
+ pos map[] =
+ {
+ { 0,0 }
+ , { 0,1 }
+ , { 0,2 } , { 2,2 }, { 3,2 }, { 4,2 }
+ , { 0,3 }, { 1,3 }, { 2,3 }, { 3,3 }, { 4,3 }
+ , { 2,4 }, { 3,4 }, { 4,4 }
+ // this is mirrored, goes left instead of right
+ , {-2,2 }, {-3,2 }, {-4,2 }
+ , {-1,3 }, {-2,3 }, {-3,3 }, {-4,3 }
+ , {-2,4 }, {-3,4 }, {-4,4 }
+ };
+
+ DFHack::DFCoord npos = xy;
+
+ if (dig_up_n > 0)
+ {
+ for (int j = 0; j < dig_up_n; j++)
+ {
+ for (int i = 0; i < sizeof(map)/sizeof(map[0]); i++)
+ {
+ npos=xy;
+ npos.x += map[i].x;
+ npos.y -= 4*j + map[i].y;
+ printf("Digging at (%d/%d/%d)\n", npos.x, npos.y, npos.z);
+ digat(MCache, npos);
+ }
+ }
+ }
+ if (dig_down_n > 0)
+ {
+ for (int j = 0; j < dig_down_n; j++)
+ {
+ for (int i = 0; i < sizeof(map)/sizeof(map[0]); i++)
+ {
+ npos=xy;
+ npos.x += map[i].x;
+ npos.y += 4*j + map[i].y;
+ printf("Digging at (%d/%d/%d)\n", npos.x, npos.y, npos.z);
+ digat(MCache, npos);
+ }
+ }
+ }
+
+ MCache->WriteAll();
+ delete MCache;
+ DF->Detach();
+ if (!quiet) {
+ cout << "Done. Press any key to continue" << endl;
+ cin.ignore();
+ }
+ return 0;
+}
diff --git a/needs_porting/drawtile.cpp b/needs_porting/drawtile.cpp
new file mode 100644
index 00000000..72f2beb0
--- /dev/null
+++ b/needs_porting/drawtile.cpp
@@ -0,0 +1,315 @@
+//
+
+#include <iostream>
+#include <vector>
+#include <map>
+#include <cstdlib>
+#include <limits>
+using namespace std;
+
+#include <conio.h>
+
+
+#include <DFHack.h>
+#include <DFTileTypes.h>
+
+//Avoid including Windows.h because it causes name clashes
+extern "C" __declspec(dllimport) void __stdcall Sleep(unsigned long milliseconds);
+
+//Trim
+#define WHITESPACE " \t\r\n"
+inline string trimr(const string & s, const string & t = WHITESPACE)
+{
+ string d (s);
+ string::size_type i (d.find_last_not_of (t));
+ if (i == string::npos)
+ return "";
+ else
+ return d.erase (d.find_last_not_of (t) + 1) ;
+}
+inline string triml(const string & s, const string & t = WHITESPACE)
+{
+ string d (s);
+ return d.erase (0, s.find_first_not_of (t)) ;
+}
+inline string trim(const string & s, const string & t = WHITESPACE)
+{
+ string d (s);
+ return triml(trimr(d, t), t);
+}
+
+void printtiletype( int i ){
+ printf("%s\n%4i ; %-13s ; %-11s ; %c ; %-12s ; %s\n",
+ ( DFHack::tileTypeTable[i].name ? DFHack::tileTypeTable[i].name : "[invalid tile]" ),
+ i,
+ ( DFHack::tileTypeTable[i].name ? DFHack::TileShapeString[ DFHack::tileTypeTable[i].shape ] : "" ),
+ ( DFHack::tileTypeTable[i].name ? DFHack::TileMaterialString[ DFHack::tileTypeTable[i].material ] : "" ),
+ ( DFHack::tileTypeTable[i].variant ? '0'+ DFHack::tileTypeTable[i].variant : ' ' ),
+ ( DFHack::tileTypeTable[i].special ? DFHack::TileSpecialString[ DFHack::tileTypeTable[i].special ] : "" ),
+ ( DFHack::tileTypeTable[i].direction.whole ? DFHack::tileTypeTable[i].direction.getStr() : "" ),
+ 0
+ );
+}
+
+
+int main (void)
+{
+ int32_t x,y,z,tx,ty;
+ //DFHack::designations40d designations;
+ DFHack::tiletypes40d tiles;
+ //DFHack::t_temperatures temp1,temp2;
+ uint32_t x_max,y_max,z_max;
+ int32_t oldT, newT;
+ int count, dirty;
+
+ //Brush defaults
+ DFHack::TileShape BrushClass = DFHack::WALL;
+ DFHack::TileMaterial BrushMat = DFHack::tilematerial_invalid;
+ int BrushType = -1;
+
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context *DF;
+ DFHack::Maps * Maps;
+ DFHack::Gui * Gui;
+ try
+ {
+ DF=DFMgr.getSingleContext();
+ DF->Attach();
+ Maps = DF->getMaps();
+ Maps->Start();
+ Maps->getSize(x_max,y_max,z_max);
+ Gui = DF->getGui();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+ bool end = false;
+ cout << "Welcome to the Tile Drawing tool.\nType 'help' or ? for a list of available commands, 'q' to quit" << endl;
+ string mode = "wall";
+ string command = "";
+
+ while(!end)
+ {
+ DF->Resume();
+
+ cout << endl << ":";
+ getline(cin, command);
+ int ch = command[0];
+ if(command.length()<=0) ch=0;
+ if( ((int)command.find("help")) >=0 ) ch='?'; //under windows, find was casting unsigned!
+ switch(ch)
+ {
+ case '?':
+ cout << "Modes:" << endl
+ << "O - draw Open Space" << endl
+ << "M - draw material only (shape unchanged)" << endl
+ << "m number - use Material value entered" << endl
+ << "r - use Rock/stone material" << endl
+ << "l - use Soil material" << endl
+ << "v - use Vein material" << endl
+ << "H - draw tile shape only (material unchanged)" << endl
+ << "h number - draw Tile Shape value entered" << endl
+ << "w - draw Wall tiles" << endl
+ << "f - draw Floor tiles" << endl
+ << "t number - draw exact tile type entered" << endl
+ << "Commands:" << endl
+ << "p - print tile shapes and materials, and current brush" << endl
+ << "P - print all tile types" << endl
+ << "q - quit" << endl
+ << "help OR ? - print this list of commands" << endl
+ << "d - being drawing" << endl
+ << endl
+ << "Usage:\nChoose a mode (default is walls), then enter 'd' to being drawing.\nMove the cursor in DF wherever you want to draw.\nPress any key to pause drawing." << endl;
+ break;
+ case 'p':
+ //Classes
+ printf("\nTile Type Classes:\n");
+ for(int i=0;i<DFHack::tileshape_count;++i)
+ {
+ printf("%4i ; %s\n", i, DFHack::TileShapeString[i] ,0 );
+ }
+ //Materials
+ printf("\nTile Type Materials:\n");
+ for(int i=0;i<DFHack::tilematerial_count;++i)
+ {
+ printf("%4i ; %s\n", i, DFHack::TileMaterialString[i] ,0 );
+ }
+ //fall through...
+ case 10:
+ case 13:
+ case 0:
+ //Print current cursor & brush settings.
+ cout << "\nCurrent Brush:\n";
+ cout << "tile = ";
+ if(BrushClass<0) cout<<"(not drawing)"; else cout<<DFHack::TileShapeString[BrushClass]; cout << endl;
+ cout << "mat = ";
+ if(BrushMat<0) cout<<"(not drawing)"; else cout<<DFHack::TileMaterialString[BrushMat]; cout << endl;
+ cout << "type = ";
+ if(BrushType<0){
+ cout<<"(not drawing)";
+ }else{
+ printtiletype(BrushType);
+ }
+ break;
+ case 'P':
+ cout << "\nAll Valid Tile Types:\n";
+ for(int i=0;i<TILE_TYPE_ARRAY_LENGTH;++i)
+ {
+ if( DFHack::tileTypeTable[i].name )
+ printtiletype(i);
+ }
+ case 'w':
+ BrushType=-1;
+ BrushClass = DFHack::WALL;
+ cout << "Tile brush shape set to Wall." << endl;
+ break;
+ case 'f':
+ BrushType=-1;
+ BrushClass = DFHack::FLOOR;
+ cout << "Tile brush shape set to Floor." << endl;
+ break;
+ case 'h':
+ BrushType=-1;
+ BrushClass = (DFHack::TileShape)atol( command.c_str()+1 );
+ cout << "Tile brush shape set to " << BrushClass << endl;
+ break;
+ case 'M':
+ BrushClass = DFHack::tileshape_invalid;
+ cout << "Tile brush will not draw tile shape." << endl;
+ break;
+ case 'r':
+ BrushType=-1;
+ BrushMat = DFHack::STONE;
+ cout << "Tile brush material set to Rock." << endl;
+ break;
+ case 'l':
+ BrushType=-1;
+ BrushMat = DFHack::SOIL;
+ cout << "Tile brush material set to Soil." << endl;
+ break;
+ case 'v':
+ BrushType=-1;
+ BrushMat = DFHack::VEIN;
+ cout << "Tile brush material set to Vein." << endl;
+ break;
+ case 'm':
+ BrushType=-1;
+ BrushMat = (DFHack::TileMaterial)atol( command.c_str()+1 );
+ cout << "Tile brush material set to " << BrushMat << endl;
+ break;
+ case 'H':
+ BrushMat = DFHack::tilematerial_invalid;
+ cout << "Tile brush will not draw material." << endl;
+ break;
+ case 'O':
+ BrushType=-1;
+ BrushClass = DFHack::EMPTY;
+ BrushMat = DFHack::AIR;
+ cout << "Tile brush will draw Open Space." << endl;
+ break;
+ case 't':
+ BrushClass = DFHack::tileshape_invalid ;
+ BrushMat = DFHack::tilematerial_invalid;
+ BrushType = atol( command.c_str()+1 );
+ cout << "Tile brush type set to:" << endl;
+ printtiletype(BrushType);
+ break;
+ case 'q':
+ end = true;
+ cout << "Bye!" << endl;
+ break;
+ case 'd':
+ {
+ count=0;
+ cout << "Beginning to draw at cursor." << endl << "Press any key to stop drawing." << endl;
+ //DF->Suspend();
+ kbhit(); //throw away, just to be sure.
+ for(;;)
+ {
+ if(!Maps->Start())
+ {
+ cout << "Can't see any DF map loaded." << endl;
+ break;
+ }
+ if(!Gui->getCursorCoords(x,y,z))
+ {
+ cout << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl;
+ break;
+ }
+ //cout << "cursor coords: " << x << "/" << y << "/" << z << endl;
+ tx=x%16; ty=y%16;
+
+ if(!Maps->isValidBlock(x/16,y/16,z))
+ {
+ cout << "Invalid block." << endl;
+ break;
+ }
+
+ //Read the tiles.
+ dirty=0;
+ Maps->ReadTileTypes((x/16),(y/16),z, &tiles);
+ oldT = tiles[tx][ty];
+
+ newT = -1;
+ if( 0<BrushType ){
+ //Explicit tile type set. Trust the user.
+ newT = BrushType;
+ }else if( 0==BrushMat && 0==BrushClass ){
+ //Special case, Empty Air.
+ newT = 32;
+ }else if( BrushMat>=0 && BrushClass>=0 && ( BrushClass != DFHack::tileTypeTable[oldT].shape || BrushMat != DFHack::tileTypeTable[oldT].material) ){
+ //Set tile material and class
+ newT = DFHack::findTileType(BrushClass,BrushMat, DFHack::tileTypeTable[oldT].variant , DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction );
+ if(newT<0) newT = DFHack::findTileType(BrushClass,BrushMat, DFHack::tilevariant_invalid, DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction );
+ if(newT<0) newT = DFHack::findTileType(BrushClass,BrushMat, DFHack::tilevariant_invalid , DFHack::tileTypeTable[oldT].special , (uint32_t)0 );
+ }else if( BrushMat<0 && BrushClass>=0 && BrushClass != DFHack::tileTypeTable[oldT].shape ){
+ //Set current tile class only, as accurately as can be expected
+ newT = DFHack::findSimilarTileType(oldT,BrushClass);
+ }else if( BrushClass<0 && BrushMat>=0 && BrushMat != DFHack::tileTypeTable[oldT].material ){
+ //Set current tile material only
+ newT = DFHack::findTileType(DFHack::tileTypeTable[oldT].shape,BrushMat, DFHack::tileTypeTable[oldT].variant , DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction );
+ if(newT<0) newT = DFHack::findTileType(DFHack::tileTypeTable[oldT].shape,BrushMat, DFHack::tilevariant_invalid , DFHack::tileTypeTable[oldT].special , DFHack::tileTypeTable[oldT].direction );
+ if(newT<0) newT = DFHack::findTileType(DFHack::tileTypeTable[oldT].shape,BrushMat, DFHack::tilevariant_invalid , DFHack::tileTypeTable[oldT].special , (uint32_t)0 );
+ }
+ //If no change, skip it (couldn't find a good tile type, or already what we want)
+ if ( newT > 0 && oldT != newT ){
+ //Set new tile type
+ tiles[tx][ty] = newT;
+ dirty=-1;
+ }
+ //If anything was changed, write it all.
+ if (dirty)
+ {
+ //Maps->WriteDesignations(x/16,y/16,z/16, &designations);
+ Maps->WriteTileTypes(x/16,y/16,z, &tiles);
+ printf("(%4d,%4d,%4d)",x,y,z);
+ ++count;
+ }
+
+ Maps->Finish();
+
+ Sleep(10);
+ if( kbhit() ) break;
+ }
+ cin.clear();
+ cout << endl << count << " tiles were drawn." << endl << "Drawing halted. Entering command mode." << endl;
+ }
+ continue;
+ break;
+ default:
+ cout << "Unknown command: " << command << endl;
+ }
+
+ }
+ DF->Detach();
+ #ifndef LINUX_BUILD
+ cout << "Done. Press any key to continue" << endl;
+ cin.ignore();
+ #endif
+ return 0;
+}
diff --git a/needs_porting/fix-3708.cpp b/needs_porting/fix-3708.cpp
new file mode 100644
index 00000000..2cfaed91
--- /dev/null
+++ b/needs_porting/fix-3708.cpp
@@ -0,0 +1,217 @@
+/* Fixes bug 3708 (Ghosts that can't be engraved on a slab).
+
+ Cause of the bug:
+
+ In order to be engraved on a slab, the creature must be
+ a historical figure, i.e. be in the historical figure list
+ of the Legends mode. It seems that caravan guards are not
+ added to that list until they do something notable, e.g.
+ kill a goblin. Unfortunately, their own death doesn't
+ trigger this sometimes.
+
+ Solution:
+
+ Steal a historical figure entry from a dead goblin, by
+ replacing the IDs in the structures; also overwrite his
+ name, race and profession to make the menus make slightly
+ more sense.
+
+ Downsides:
+
+ - Obviously, this is an ugly hack.
+ - The Legends mode still lists the guard as belonging to
+ the goblin civilization, and killed by whoever killed the
+ original goblin. There might be other inconsistencies.
+
+ Positive sides:
+
+ - Avoids messing with tricky creature control code,
+ by allowing the ghost to be removed naturally.
+ */
+
+#include <iostream>
+#include <climits>
+#include <string.h>
+#include <vector>
+#include <list>
+#include <stdio.h>
+using namespace std;
+
+#define DFHACK_WANT_MISCUTILS
+#include <DFHack.h>
+
+enum likeType
+{
+ FAIL = 0,
+ MATERIAL = 1,
+ ITEM = 2,
+ FOOD = 3
+};
+
+DFHack::Materials * Materials;
+DFHack::VersionInfo *mem;
+DFHack::Creatures * Creatures = NULL;
+
+void printCreature(DFHack::Context * DF, const DFHack::t_creature & creature)
+{
+ cout << "Address: " << hex << creature.origin << dec << ", creature race: " << Materials->raceEx[creature.race].rawname
+ << ", position: " << creature.x << "x " << creature.y << "y "<< creature.z << "z" << endl
+ << "Name: " << creature.name.first_name;
+
+ if (creature.name.nickname[0])
+ cout << " `" << creature.name.nickname << "'";
+
+ DFHack::Translation * Tran = DF->getTranslation();
+
+ cout << " " << Tran->TranslateName(creature.name,false)
+ << " (" << Tran->TranslateName(creature.name,true) << ")" << endl;
+
+ cout << "Profession: " << mem->getProfession(creature.profession);
+
+ if(creature.custom_profession[0])
+ cout << ", custom: " << creature.custom_profession;
+
+ uint32_t dayoflife = creature.birth_year*12*28 + creature.birth_time/1200;
+ cout << endl
+ << "Born on the year " << creature.birth_year
+ << ", month " << (creature.birth_time/1200/28)
+ << ", day " << ((creature.birth_time/1200) % 28 + 1)
+ << ", " << dayoflife << " days lived." << endl << endl;
+}
+
+
+int main (int numargs, char ** args)
+{
+ DFHack::World * World;
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context* DF;
+ try
+ {
+ DF = DFMgr.getSingleContext();
+ DF->Attach();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+
+ Creatures = DF->getCreatures();
+ Materials = DF->getMaterials();
+ World = DF->getWorld();
+ DFHack::Translation * Tran = DF->getTranslation();
+
+ uint32_t numCreatures;
+ if(!Creatures->Start(numCreatures))
+ {
+ cerr << "Can't get creatures" << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+
+ Materials->ReadCreatureTypes();
+ Materials->ReadCreatureTypesEx();
+
+ mem = DF->getMemoryInfo();
+ DFHack::Process *p = DF->getProcess();
+
+ if(!Tran->Start())
+ {
+ cerr << "Can't get name tables" << endl;
+ return 1;
+ }
+
+ DFHack::OffsetGroup *ogc = mem->getGroup("Creatures")->getGroup("creature");
+ uint32_t o_flags3 = ogc->getOffset("flags3");
+ uint32_t o_c_hfid = ogc->getGroup("advanced")->getOffset("hist_figure_id");
+
+ std::list<uint32_t> goblins;
+ std::list<uint32_t> ghosts;
+
+ for(uint32_t i = 0; i < numCreatures; i++)
+ {
+ DFHack::t_creature temp;
+ Creatures->ReadCreature(i,temp);
+
+ int32_t hfid = p->readDWord(temp.origin + o_c_hfid);
+
+ if (hfid > 0) {
+ if (temp.flags1.bits.dead) {
+ std::string name = Materials->raceEx[temp.race].rawname;
+ if (name == "GOBLIN")
+ goblins.push_back(i);
+ }
+ } else {
+ uint32_t flags3 = p->readDWord(temp.origin + o_flags3);
+ if (!(flags3 & 0x1000))
+ continue;
+
+ ghosts.push_back(i);
+ }
+ }
+
+ if (goblins.size() >= ghosts.size() && ghosts.size() > 0)
+ {
+ DFHack::OffsetGroup *grp_figures = mem->getGroup("Legends")->getGroup("figures");
+ uint32_t f_vector = p->readDWord(grp_figures->getAddress("vector"));
+ uint32_t f_id = grp_figures->getOffset("figure_id");
+ uint32_t f_unit = grp_figures->getOffset("unit_id");
+ uint32_t f_name = grp_figures->getOffset("name");
+ uint32_t f_race = grp_figures->getOffset("race");
+ uint32_t f_profession = grp_figures->getOffset("profession");
+
+ for (std::list<uint32_t>::iterator it = ghosts.begin(); it != ghosts.end(); ++it)
+ {
+ int i = *it;
+ DFHack::t_creature ghost;
+ Creatures->ReadCreature(i,ghost);
+
+ printCreature(DF,ghost);
+
+ int igoblin = goblins.front();
+ goblins.pop_front();
+ DFHack::t_creature goblin;
+ Creatures->ReadCreature(igoblin,goblin);
+
+ printCreature(DF,goblin);
+
+ int32_t hfid = p->readDWord(goblin.origin + o_c_hfid);
+ uint32_t fptr = p->readDWord(f_vector + 4*hfid);
+
+ if (p->readDWord(fptr + f_id) != hfid ||
+ p->readDWord(fptr + f_unit) != goblin.id ||
+ p->readWord(fptr + f_race) != goblin.race)
+ {
+ cout << "Data structure inconsistency detected, aborting.";
+ break;
+ }
+
+ if (1) {
+ p->writeDWord(goblin.origin + o_c_hfid, -1);
+ p->writeDWord(ghost.origin + o_c_hfid, hfid);
+ p->writeDWord(fptr + f_unit, ghost.id);
+ p->writeWord(fptr + f_race, ghost.race);
+ p->writeWord(fptr + f_profession, ghost.profession);
+ Creatures->CopyNameTo(ghost, fptr + f_name);
+ cout << "Pair succesfully patched." << endl << endl;
+ }
+ }
+ }
+ else
+ {
+ cout << "No suitable ghosts, or not enough goblins." << endl;
+ }
+
+ Creatures->Finish();
+ DF->Detach();
+ #ifndef LINUX_BUILD
+ cout << "Done. Press any key to continue" << endl;
+ cin.ignore();
+ #endif
+ return 0;
+}
diff --git a/needs_porting/hellhole.cpp b/needs_porting/hellhole.cpp
new file mode 100644
index 00000000..a38d14cb
--- /dev/null
+++ b/needs_porting/hellhole.cpp
@@ -0,0 +1,1281 @@
+// Burn a hole straight to hell!
+
+#include <stdlib.h>
+#include <time.h>
+
+#include <iostream>
+#include <vector>
+#include <map>
+#include <stddef.h>
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+using namespace std;
+
+#include <DFHack.h>
+#include <DFTileTypes.h>
+#include <modules/Gui.h>
+using namespace DFHack;
+
+
+#ifdef LINUX_BUILD
+#include <unistd.h>
+void waitmsec (int delay)
+{
+ usleep(delay);
+}
+#else
+#include <windows.h>
+void waitmsec (int delay)
+{
+ Sleep(delay);
+}
+#endif
+
+#define minmax(MinV,V,MaxV) (max((MinV),min((MaxV),(V))))
+
+//User interaction enums.
+//Pit Type (these only have meaning within hellhole, btw)
+#define PITTYPEMACRO \
+ X(pitTypeChasm,"Bottomless Chasm" ) \
+ X(pitTypeEerie,"Bottomless Eerie Pit" ) \
+ X(pitTypeFloor,"Pit with floor" ) \
+ X(pitTypeSolid,"Solid Pillar" ) \
+ X(pitTypeOasis,"Oasis Pit (ends at magma, no hell access)" ) \
+ X(pitTypeOPool,"Oasis Pool, with partial aquifer (default 5 z-levels)" ) \
+ X(pitTypeMagma,"Magma Pit (similar to volcano, no hell access)" ) \
+ X(pitTypeMPool,"Magma Pool (default 5 z-levels)" )
+//end PITTYPEMACRO
+
+#define X(name,desc) name,
+enum e_pitType
+{
+ pitTypeInvalid=-1,
+ PITTYPEMACRO
+ pitTypeCount,
+};
+#undef X
+
+
+#define X(name,desc) desc,
+const char * pitTypeDesc[pitTypeCount+1] =
+{
+ PITTYPEMACRO
+ ""
+};
+#undef X
+
+
+
+
+int getyesno( const char * msg , int default_value )
+{
+ const int bufferlen=4;
+ static char buf[bufferlen];
+ memset(buf,0,bufferlen);
+ while (-1)
+ {
+ if (msg) printf("\n%s (default=%s)\n:" , msg , (default_value?"yes":"no") );
+ fflush(stdin);
+ fgets(buf,bufferlen,stdin);
+ switch (buf[0])
+ {
+ case 0:
+ case 0x0d:
+ case 0x0a:
+ return default_value;
+ case 'y':
+ case 'Y':
+ case 'T':
+ case 't':
+ case '1':
+ return -1;
+ case 'n':
+ case 'N':
+ case 'F':
+ case 'f':
+ case '0':
+ return 0;
+ }
+ }
+ return 0;
+}
+
+int getint( const char * msg , int min, int max, int default_value ) {
+ const int bufferlen=16;
+ static char buf[bufferlen];
+ int n=0;
+ memset(buf,0,bufferlen);
+ while (-1)
+ {
+ if (msg) printf("\n%s (default=%d)\n:" , msg , default_value);
+ fflush(stdin);
+ fgets(buf,bufferlen,stdin);
+ if ( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] )
+ {
+ return default_value;
+ }
+ if ( sscanf(buf,"%d", &n) )
+ {
+ if (n>=min && n<=max )
+ {
+ return n;
+ }
+ }
+ }
+}
+
+int getint( const char * msg , int min, int max )
+{
+ const int bufferlen=16;
+ static char buf[bufferlen];
+ int n=0;
+ memset(buf,0,bufferlen);
+ while (-1)
+ {
+ if (msg)
+ {
+ printf("\n%s \n:" , msg );
+ }
+ fflush(stdin);
+ fgets(buf,bufferlen,stdin);
+
+ if ( !buf[0] || 0x0a==buf[0] || 0x0d==buf[0] )
+ {
+ continue;
+ }
+ if ( sscanf(buf,"%d", &n) )
+ {
+ if (n>=min && n<=max )
+ {
+ return n;
+ }
+ }
+ }
+}
+
+
+
+//Interactive, get pit type from user
+e_pitType selectPitType()
+{
+ while ( -1 )
+ {
+ printf("Enter the type of hole to dig:\n" );
+ for (int n=0;n<pitTypeCount;++n)
+ {
+ printf("%2d) %s\n", n, pitTypeDesc[n] );
+ }
+ printf(":");
+ return (e_pitType)getint(NULL, 0, pitTypeCount-1 );
+ }
+}
+
+
+void drawcircle(const int radius, unsigned char pattern[16][16], unsigned char v )
+{
+ //Small circles get better randomness if handled manually
+ if ( 1==radius )
+ {
+ pattern[7][7]=v;
+ if ( (rand()&1) ) pattern[6][7]=v;
+ if ( (rand()&1) ) pattern[8][7]=v;
+ if ( (rand()&1) ) pattern[7][6]=v;
+ if ( (rand()&1) ) pattern[7][8]=v;
+
+ }
+ else if ( 2==radius )
+ {
+ pattern[7][7]=v;
+ pattern[7][5]=v;
+ pattern[7][6]=v;
+ pattern[7][8]=v;
+ pattern[7][9]=v;
+ pattern[6][7]=v;
+ pattern[8][7]=v;
+ pattern[9][7]=v;
+ pattern[6][6]=v;
+ pattern[6][8]=v;
+ pattern[8][6]=v;
+ pattern[8][8]=v;
+ pattern[5][7]=v;
+
+ if ( (rand()&1) ) pattern[6][5]=v;
+ if ( (rand()&1) ) pattern[5][6]=v;
+ if ( (rand()&1) ) pattern[8][5]=v;
+ if ( (rand()&1) ) pattern[9][6]=v;
+ if ( (rand()&1) ) pattern[6][9]=v;
+ if ( (rand()&1) ) pattern[5][8]=v;
+ if ( (rand()&1) ) pattern[8][9]=v;
+ if ( (rand()&1) ) pattern[9][8]=v;
+ }
+ else
+ {
+ //radius 3 or larger, simple circle calculation.
+ int x,y;
+ for (y=0-radius; y<=radius; ++y)
+ {
+ for (x=0-radius; x<=radius; ++x)
+ {
+ if (x*x+y*y <= radius*radius + (rand()&31-8) )
+ {
+ pattern[ minmax(0,7+x,15) ][ minmax(0,7+y,15) ]=v;
+ }
+ }
+ }
+ //Prevent boxy patterns with a quick modification on edges
+ if (rand()&1) pattern[ 7 ][ minmax(0,7+radius+1,15) ] = v;
+ if (rand()&1) pattern[ 7 ][ minmax(0,7-radius-1,15) ] = v;
+ if (rand()&1) pattern[ minmax(0,7+radius+1,15) ][ 7 ] = v;
+ if (rand()&1) pattern[ minmax(0,7-radius-1,15) ][ 7 ] = v;
+ }
+}
+
+//Check all neighbors for a given value n.
+//If found, and v>=0, replace with v.
+//Returns number of neighbors found.
+int checkneighbors(unsigned char pattern[16][16], int x, int y, unsigned char n , char v )
+{
+ int r=0;
+ if ( x>0 && y>0 && n==pattern[x-1][y-1] )
+ {
+ ++r;
+ if (v>-1) pattern[x][y]=v;
+ }
+ if ( x>0 && n==pattern[x-1][y ] )
+ {
+ ++r;
+ if (v>-1) pattern[x][y]=v;
+ }
+ if ( y>0 && n==pattern[x ][y-1] )
+ {
+ ++r;
+ if (v>-1) pattern[x][y]=v;
+ }
+ if ( x<15 && n==pattern[x+1][y ] )
+ {
+ ++r;
+ if (v>-1) pattern[x][y]=v;
+ }
+ if ( x<15 && y>0 && n==pattern[x+1][y-1] )
+ {
+ ++r;
+ if (v>-1) pattern[x][y]=v;
+ }
+ if ( x<15 && y<15 && n==pattern[x+1][y+1] )
+ {
+ ++r;
+ if (v>-1) pattern[x][y]=v;
+ }
+ if ( y<15 && n==pattern[x ][y+1] )
+ {
+ ++r;
+ if (v>-1) pattern[x][y]=v;
+ }
+ if ( x>0 && y<15 && n==pattern[x-1][y+1] )
+ {
+ ++r;
+ if (v>-1) pattern[x][y]=v;
+ }
+ return r;
+}
+//convenience
+int checkneighbors(unsigned char pattern[16][16], int x, int y, unsigned char n )
+{
+ return checkneighbors(pattern,x,y,n,-1);
+}
+
+void settileat(unsigned char pattern[16][16], const unsigned char needle, const unsigned char v, const int index )
+{
+ int ok=0;
+ int safety=256*256;
+ int y,x,i=0;
+ //Scan for sequential index
+ while ( !ok && --safety )
+ {
+ for (y=0 ; !ok && y<16 ; ++y )
+ {
+ for (x=0 ; !ok && x<16 ; ++x )
+ {
+ if ( needle==pattern[x][y] )
+ {
+ ++i;
+ if ( index==i )
+ {
+ //Got it!
+ pattern[x][y]=v;
+ ok=-1;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+//FIXME: good candidate for adding to dfhack. Maybe the Maps should have those cached so they can be queried?
+//Is a given feature present at the given tile?
+int isfeature(
+ vector<DFHack::t_feature> global_features,
+ std::map <DFHack::DFCoord, std::vector<DFHack::t_feature *> > local_features,
+ const mapblock40d &block, const DFCoord &pc, const int x, const int y, const e_feature Feat
+)
+{
+ //const TileRow * tp;
+ //tp = getTileTypeP(block.tiletypes[x][y]);
+ const t_designation * d;
+ d = &block.designation[x][y];
+
+ if ( block.local_feature > -1 && d->bits.feature_local ) {
+ if ( Feat==local_features[pc][block.local_feature]->type ) return Feat;
+ }
+ if ( block.global_feature > -1 && d->bits.feature_global ) {
+ if ( Feat==global_features[block.global_feature].type ) return Feat;
+ }
+
+ return 0;
+}
+
+// FIXME: use block cache, break into manageable bits
+int main (void)
+{
+ srand ( (unsigned int)time(NULL) );
+
+ //Message of intent
+ cout <<
+ "DF Hole" << endl <<
+ "This tool will instantly dig a chasm, pit, pipe, etc through hell, wherever your cursor is." << endl <<
+ "This can not be undone! End program now if you don't want hellish fun." << endl
+ ;
+
+ //User selection of settings should have it own routine, a structure for settings, I know
+ //sloppy mess, but this is just a demo utility.
+
+ //Pit Types.
+ e_pitType pittype = selectPitType();
+
+ //Here are all the settings.
+ //Default values are set here.
+ int pitdepth=0;
+ int roof=-1;
+ int holeradius=6;
+ int wallthickness=1;
+ int wallpillar=1;
+ int holepillar=1;
+ int exposehell = 0;
+ int fillmagma=0;
+ int fillwater=0;
+ int stopatmagma=0;
+ int exposemagma=0;
+ int aquify=0;
+
+ //The Tile Type to use for the walls lining the hole
+ //263 is semi-molten rock, 331 is obsidian
+ uint32_t whell=263, wmolten=263, wmagma=331, wcave=331;
+ //The Tile Type to use for the hole's floor at bottom of the map
+ //35 is chasm, 42 is eerie pit , 340 is obsidian floor, 344 is featstone floor, 264 is 'magma flow' floor
+ uint32_t floor=35, cap=340;
+ int floorvar=0;
+
+
+ //Modify default settings based on pit type.
+ switch ( pittype )
+ {
+ case pitTypeChasm:
+ floor=35;
+ break;
+ case pitTypeEerie:
+ floor=42;
+ break;
+ case pitTypeFloor:
+ floor=344;
+ floorvar=3;
+ break;
+ case pitTypeSolid:
+ holeradius=0;
+ wallthickness=7;
+ wallpillar=4;
+ break;
+ case pitTypeOasis:
+ stopatmagma=-1;
+ fillwater=-1;
+ holeradius=5;
+ wallthickness=2;
+ //aquify=-1;
+ floor=340;
+ floorvar=3;
+ break;
+ case pitTypeOPool:
+ pitdepth=5;
+ fillwater=-1;
+ holeradius=5;
+ wallthickness=2;
+ //aquify=-1;
+ floor=340;
+ floorvar=3;
+ break;
+ case pitTypeMagma:
+ stopatmagma=-1;
+ exposemagma=-1;
+ wallthickness=2;
+ fillmagma=-1;
+ floor=264;
+ break;
+ case pitTypeMPool:
+ pitdepth=5;
+ wallthickness=2;
+ fillmagma=-1;
+ floor=340;
+ floorvar=3;
+ break;
+ }
+
+
+ //Should tiles be revealed?
+ int reveal=0;
+
+
+ int accept = getyesno("Use default settings?",1);
+
+ while ( !accept )
+ {
+ //Pit Depth
+ pitdepth = getint( "Enter max depth (0 for bottom of map)", 0, INT_MAX, pitdepth );
+
+ //Hole Size
+ holeradius = getint( "Enter hole radius, 0 to 16", 0, 16, holeradius );
+
+ //Wall thickness
+ wallthickness = getint( "Enter wall thickness, 0 to 16", 0, 16, wallthickness );
+
+ //Obsidian Pillars
+ holepillar = getint( "Number of Obsidian Pillars in hole, 0 to 255", 0, 255, holepillar );
+ wallpillar = getint( "Number of Obsidian Pillars in wall, 0 to 255", 0, 255, wallpillar );
+
+ //Open Hell?
+ exposehell=getyesno("Expose the pit to hell (no walls in hell)?",exposehell);
+
+ //Stop when magma sea is hit?
+ stopatmagma=getyesno("Stop at magma sea?",stopatmagma);
+ exposemagma=getyesno("Expose magma sea (no walls in magma)?",exposemagma);
+
+ //Fill?
+ fillmagma=getyesno("Fill with magma?",fillmagma);
+ if (fillmagma) aquify=fillwater=0;
+ fillwater=getyesno("Fill with water?",fillwater);
+ //aquify=getyesno("Aquifer?",aquify);
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ //Print settings.
+ //If a settings struct existed, this could be in a routine
+ printf("Using Settings:\n");
+ printf("Pit Type......: %d = %s\n", pittype, pitTypeDesc[pittype]);
+ printf("Depth.........: %d\n", pitdepth);
+ printf("Hole Radius...: %d\n", holeradius);
+ printf("Wall Thickness: %d\n", wallthickness);
+ printf("Pillars, Hole.: %d\n", holepillar);
+ printf("Pillars, Wall.: %d\n", wallpillar);
+ printf("Expose Hell...: %c\n", (exposehell?'Y':'N') );
+ printf("Stop at Magma.: %c\n", (stopatmagma?'Y':'N') );
+ printf("Expose Magma..: %c\n", (exposemagma?'Y':'N') );
+ printf("Magma Fill....: %c\n", (fillmagma?'Y':'N') );
+ printf("Water Fill....: %c\n", (fillwater?'Y':'N') );
+ printf("Aquifer.......: %c\n", (aquify?'Y':'N') );
+
+ accept = getyesno("Accept these settings?",1);
+ }
+
+
+ int64_t n;
+ uint32_t x_max,y_max,z_max;
+
+
+ //Pattern to dig
+ unsigned char pattern[16][16];
+
+
+ for (int regen=1;regen; )
+ {
+ regen=0;
+
+ memset(pattern,0,sizeof(pattern));
+
+ //Calculate a randomized circle.
+ //These values found through experimentation.
+ int x=0, y=0, n=0;
+
+ //Two concentric irregular circles
+ //Outer circle, solid.
+ if ( wallthickness )
+ {
+ drawcircle(holeradius+wallthickness, pattern, 2);
+ }
+ //Inner circle, hole.
+ if ( holeradius )
+ {
+ drawcircle(holeradius, pattern, 1);
+ }
+
+
+ //Post-process to be certain the wall totally encloses hole.
+ if (wallthickness)
+ {
+ for (y=0;y<16;++y)
+ {
+ for (x=0;x<16;++x)
+ {
+ if ( 1==pattern[x][y] )
+ {
+ //No hole at edges.
+ if ( x<1 || x>14 || y<1 || y>14 )
+ {
+ pattern[x][y]=2;
+ }
+ }
+ else if ( 0==pattern[x][y] )
+ {
+ //check neighbors
+ checkneighbors( pattern , x,y, 1, 2);
+ }
+ }
+ }
+ }
+
+ //Makes sure that somewhere random gets a vertical pillar of rock which is safe
+ //to dig stairs down, to permit access to anywhere within the pit from the top.
+ for (n=holepillar; n ; --n)
+ {
+ settileat( pattern , 1 , 3 , rand()&255 );
+ }
+ for (n=wallpillar; n ; --n)
+ {
+ settileat( pattern , 2 , 3 , rand()&255 );
+ }
+
+ //Note:
+ //At this point, the pattern holds:
+ //0 for all tiles which will be ignored.
+ //1 for all tiles set to empty pit space.
+ //2 for all normal walls.
+ //3 for the straight obsidian top-to-bottom wall.
+ //4 is randomized between wall or floor (!not implemented!)
+
+ printf("\nPattern:\n");
+ const char patternkey[] = ".cW!?567890123";
+
+ //Print the pattern
+ for (y=0;y<16;++y)
+ {
+ for (x=0;x<16;++x)
+ {
+ cout << patternkey[ pattern[x][y] ];
+ }
+ cout << endl;
+ }
+ cout << endl;
+
+ regen = !getyesno("Acceptable Pattern?",1);
+ }
+
+ //Post-process settings to fix problems here
+ if (pitdepth<1)
+ {
+ pitdepth=INT_MAX;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+
+ cerr << "Loading memory map..." << endl;
+
+ //Connect to DF!
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context *DF = DFMgr.getSingleContext();
+
+
+
+ //Init
+ cerr << "Attaching to DF..." << endl;
+ try
+ {
+ DF->Attach();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+
+ // init the map
+ DFHack::Maps *Mapz = DF->getMaps();
+ if (!Mapz->Start())
+ {
+ cerr << "Can't init map. Exiting." << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+
+ Mapz->getSize(x_max,y_max,z_max);
+
+
+ //Get cursor
+ int32_t cursorX, cursorY, cursorZ;
+ DFHack::Gui *Gui = DF->getGui();
+ Gui->getCursorCoords(cursorX,cursorY,cursorZ);
+ if (-30000==cursorX)
+ {
+ cout << "No cursor position found. Exiting." << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+
+ //Block coordinates
+ int32_t bx=cursorX/16, by=cursorY/16, bz=cursorZ;
+ //Tile coordinates within block
+ int32_t tx=cursorX%16, ty=cursorY%16, tz=cursorZ;
+
+ /*
+ //Access the DF interface to pause the game.
+ //Copied from the reveal tool.
+ DFHack::Gui *Gui =DF->getGui();
+ cout << "Pausing..." << endl;
+ Gui->SetPauseState(true);
+ DF->Resume();
+ waitmsec(1000);
+ DF->Suspend();
+ */
+
+ //Verify that every z-level at this location exists.
+ for (int32_t Z = 0; Z<= bz ;Z++)
+ {
+ if ( ! Mapz->isValidBlock(bx,by,Z) )
+ {
+ cout << "This block does't exist! Exiting." << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+ }
+
+ //Get all the map features.
+ vector<DFHack::t_feature> global_features;
+ if (!Mapz->ReadGlobalFeatures(global_features))
+ {
+ cout << "Couldn't load global features! Probably a version problem." << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+
+ std::map <DFHack::DFCoord, std::vector<DFHack::t_feature *> > local_features;
+ if (!Mapz->ReadLocalFeatures(local_features))
+ {
+ cout << "Couldn't load local features! Probably a version problem." << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+
+ //Get info on current tile, to determine how to generate the pit
+ mapblock40d topblock;
+ Mapz->ReadBlock40d( bx, by, bz , &topblock );
+ //Related block info
+ DFCoord pc(bx,by);
+ mapblock40d block;
+ const TileRow * tp;
+ t_designation * d;
+
+ //////////////////////////////////////
+ //From top to bottom, dig this thing.
+ //////////////////////////////////////
+
+ //Top level, cap.
+ //Might make this an option in the future
+ //For now, no wall means no cap.
+ if (wallthickness)
+ {
+ Mapz->ReadBlock40d( bx, by, bz , &block );
+ for (uint32_t x=0;x<16;++x)
+ {
+ for (uint32_t y=0;y<16;++y)
+ {
+ if ( (pattern[x][y]>1) || (roof && pattern[x][y]) )
+ {
+ tp = getTileRow(block.tiletypes[x][y]);
+ d = &block.designation[x][y];
+ //Only modify this level if it's 'empty'
+ if ( EMPTY != tp->shape && RAMP_TOP != tp->shape && STAIR_DOWN != tp->shape && DFHack::BROOK_TOP != tp->shape)
+ {
+ continue;
+ }
+
+ //Need a floor for empty space.
+ if (reveal)
+ {
+ d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden;
+ }
+ //Always clear the dig designation.
+ d->bits.dig = designation_no;
+ //unlock fluids, so they fall down the pit.
+ d->bits.flow_forbid = d->bits.liquid_static=0;
+ block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1;
+ //Remove aquifer, to prevent bugginess
+ d->bits.water_table=0;
+ //Set the tile.
+ block.tiletypes[x][y] = cap + rand()%4;
+ }
+ }
+ }
+ //Write the block.
+ Mapz->WriteBlockFlags(bx,by,bz, block.blockflags );
+ Mapz->WriteDesignations(bx,by,bz, &block.designation );
+ Mapz->WriteTileTypes(bx,by,bz, &block.tiletypes );
+ Mapz->WriteDirtyBit(bx,by,bz,1);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ //All levels in between.
+ int done=0;
+ uint32_t t,v;
+ int32_t z = bz-1;
+ int32_t bottom = max(0,bz-pitdepth-1);
+ assert( bottom>=0 && bottom<=bz );
+ for ( ; !done && z>=bottom ; --z)
+ {
+ int watercount=0;
+ int magmacount=0;
+ int moltencount=0;
+ int rockcount=0;
+ int veincount=0;
+ int emptycount=0;
+ int hellcount=0;
+ int templecount=0;
+ int adamcount=0;
+ int featcount=0;
+ int tpat;
+
+ cout << z << endl;
+ assert( Mapz->isValidBlock(bx,by,z) );
+ if (!Mapz->ReadBlock40d( bx, by, z , &block ))
+ {
+ cout << "Bad block! " << bx << "," << by << "," << z << endl;
+ }
+
+ //Pre-process this z-level, to get some tile statistics.
+ for (int32_t x=0;x<16;++x)
+ {
+ for (int32_t y=0;y<16;++y)
+ {
+ t=0;
+ tp = getTileRow(block.tiletypes[x][y]);
+ d = &block.designation[x][y];
+ tpat=pattern[x][y];
+
+ //Tile type material categories
+ switch ( tp->material )
+ {
+ case AIR:
+ ++emptycount;
+ break;
+ case MAGMA:
+ ++moltencount;
+ break;
+ case VEIN:
+ ++veincount;
+ break;
+ case FEATSTONE:
+ case HFS:
+ case OBSIDIAN:
+ //basicly, ignored.
+ break;
+ default:
+ if ( EMPTY == tp->shape || RAMP_TOP == tp->shape || STAIR_DOWN == tp->shape )
+ {
+ ++emptycount;
+ }
+ else
+ {
+ ++rockcount;
+ }
+ break;
+ }
+
+ //Magma and water
+ if ( d->bits.flow_size )
+ {
+ if (d->bits.liquid_type)
+ {
+ ++magmacount;
+ }
+ else
+ {
+ ++watercount;
+ }
+ }
+
+
+ //Check for Features
+ if ( block.local_feature > -1 || block.global_feature > -1 )
+ {
+ //Count tiles which actually are in the feature.
+ //It is possible for a block to have a feature, but no tiles to be feature.
+ if ( d->bits.feature_global || d->bits.feature_local )
+ {
+ //All features
+ ++featcount;
+
+ if ( d->bits.feature_global && d->bits.feature_local )
+ {
+ cout << "warn:tile is global and local at same time!" << endl;
+ }
+
+ n=0;
+ if ( block.global_feature > -1 && d->bits.feature_global )
+ {
+ n=global_features[block.global_feature].type;
+ switch ( n )
+ {
+ case feature_Other:
+ //no count
+ break;
+ case feature_Adamantine_Tube:
+ ++adamcount;
+ break;
+ case feature_Underworld:
+ ++hellcount;
+ break;
+ case feature_Hell_Temple:
+ ++templecount;
+ break;
+ default:
+ //something here. for debugging, it may be interesting to know.
+ if (n) cout << '(' << n << ')';
+ }
+ }
+
+ n=0;
+ if ( block.local_feature > -1 && d->bits.feature_local )
+ {
+ n=local_features[pc][block.local_feature]->type;
+ switch ( n )
+ {
+ case feature_Other:
+ //no count
+ break;
+ case feature_Adamantine_Tube:
+ ++adamcount;
+ break;
+ case feature_Underworld:
+ ++hellcount;
+ break;
+ case feature_Hell_Temple:
+ ++templecount;
+ break;
+ default:
+ //something here. for debugging, it may be interesting to know.
+ if (n) cout << '[' << n << ']';
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ //If stopping at magma, and no no non-feature stone in this layer, and magma found, then we're either at
+ //or below the magma sea / molten rock.
+ if ( stopatmagma && (moltencount || magmacount) && (!exposemagma || !rockcount) )
+ {
+ //If not exposing magma, quit at the first sign of magma.
+ //If exposing magma, quite once magma is exposed.
+ done=-1;
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ //Some checks, based on settings and stats collected
+ //First check, are we at illegal depth?
+ if ( !done && hellcount && stopatmagma )
+ {
+ //Panic!
+ done=-1;
+ tpat=0;
+ cout << "error: illegal breach of hell!" << endl;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ //Actually process the current z-level.
+ //These loops do the work.
+ for (int32_t x=0;!done && x<16;++x)
+ {
+ for (int32_t y=0;!done && y<16;++y)
+ {
+ t=0;
+ tp = getTileRow(block.tiletypes[x][y]);
+ d = &block.designation[x][y];
+ tpat=pattern[x][y];
+
+ //Up front, remove aquifer, to prevent bugginess
+ //It may be added back if aquify is set.
+ d->bits.water_table=0;
+
+ //Change behaviour based on settings and stats from this z-level
+
+ //In hell?
+ if ( tpat && tpat!=3 && isfeature(global_features, local_features,block,pc,x,y,feature_Underworld ) )
+ {
+ if ( exposehell )
+ {
+ tpat=0;
+ }
+ }
+
+ //Expose magma?
+ if ( tpat && tpat!=3 && exposemagma )
+ {
+ //Leave certain tiles unchanged.
+ switch ( tp->material )
+ {
+ case HFS:
+ case FEATSTONE:
+ case MAGMA:
+ tpat=0;
+ default:
+ break;
+ }
+ //Adamantine may be left unchanged...
+ if ( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) )
+ {
+ tpat=0;
+ }
+ //Leave magma sea unchanged.
+ if ( d->bits.flow_size && d->bits.liquid_type)
+ {
+ tpat=0;
+ }
+ }
+
+
+ //For all situations...
+ //Special modification for walls, always for adamantine.
+ if ( isfeature(global_features, local_features,block,pc,x,y,feature_Adamantine_Tube ) )
+ {
+ if ( 2==pattern[x][y] || 3==pattern[x][y] )
+ {
+ tpat=2;
+ }
+ }
+
+
+ //Border or space?
+ switch (tpat)
+ {
+ case 0:
+ continue;
+ break;
+ case 1:
+ //Empty Space
+ t=32;
+ //d->bits.light = topblock.designation[x][y].bits.light;
+ //d->bits.skyview = topblock.designation[x][y].bits.skyview;
+ //d->bits.subterranean = topblock.designation[x][y].bits.subterranean;
+
+ //Erase special markers?
+ //d->bits.feature_global = d->bits.feature_local = 0;
+
+ //Water? Magma?
+ if (fillmagma || fillwater)
+ {
+ d->bits.flow_size=7;
+ d->bits.water_stagnant = false;
+ d->bits.water_salt = false;
+ if (fillmagma)
+ {
+ d->bits.liquid_type=liquid_magma;
+ }
+ else
+ {
+ d->bits.liquid_type=liquid_water;
+ }
+ }
+ else
+ {
+ //Otherwise, remove all liquids.
+ d->bits.flow_size=0;
+ d->bits.water_stagnant = false;
+ d->bits.water_salt = false;
+ d->bits.liquid_type = liquid_water;
+ }
+
+ break;
+ case 2:
+ //Wall.
+ //First guess based on current material
+ switch ( tp->material )
+ {
+ case OBSIDIAN:
+ t=wmagma;
+ break;
+ case MAGMA:
+ t=wmolten;
+ break;
+ case HFS:
+ //t=whell;
+ break;
+ case VEIN:
+ t=440; //Solid vein block
+ break;
+ case FEATSTONE:
+ t=335; //Solid feature stone block
+ break;
+ default:
+ t=wcave;
+ }
+ //Adamantine (a local feature) trumps veins.
+ {
+ //Local Feature?
+ if ( block.local_feature > -1 )
+ {
+ switch ( n=local_features[pc][block.local_feature]->type )
+ {
+ case feature_Underworld:
+ case feature_Hell_Temple:
+ //Only adopt these if there is no global feature present
+ if ( block.global_feature >-1 )
+ {
+ break;
+ }
+ case feature_Adamantine_Tube:
+ //Always for adamantine, sometimes for others
+ //Whatever the feature is made of. "featstone wall"
+ d->bits.feature_global = 0;
+ d->bits.feature_local = 1;
+ t=335;
+ break;
+ }
+ }
+ //Global Feature?
+ else if (block.global_feature > -1 && !d->bits.feature_local )
+ {
+ switch ( n=global_features[block.global_feature].type )
+ {
+ case feature_Adamantine_Tube:
+ case feature_Underworld:
+ case feature_Hell_Temple:
+ //Whatever the feature is made of. "featstone wall"
+ d->bits.feature_global = 1;
+ t=335;
+ break;
+ }
+ }
+ }
+
+ //Erase any liquids, as they cause problems.
+ d->bits.flow_size=0;
+ d->bits.water_stagnant = false;
+ d->bits.water_salt = false;
+ d->bits.liquid_type=liquid_water;
+
+ //Placing an aquifer?
+ //(bugged, these aquifers don't generate water!)
+ if ( aquify )
+ {
+ //Only normal stone types can be aquified
+ if ( tp->material!=MAGMA && tp->material!=FEATSTONE && tp->material!=HFS )
+ {
+ //Only place next to the hole.
+ //If no hole, place in middle.
+ if ( checkneighbors(pattern,x,y,1) || (7==x && 7==y) )
+ {
+ d->bits.water_table = 1;
+ //t=265; //soil wall
+ }
+ }
+ }
+ break;
+ case 3:
+ ////No obsidian walls on bottom of map!
+ //if(z<1 && (d->bits.feature_global || d->bits.feature_local) ) {
+ // t=335;
+ //}
+
+ //Special wall, always sets to obsidian, to give a stairway
+ t=331;
+
+ //Erase special markers
+ d->bits.feature_global = d->bits.feature_local = 0;
+
+ //Erase any liquids, as they cause problems.
+ d->bits.flow_size=0;
+ d->bits.water_stagnant = false;
+ d->bits.water_salt = false;
+ d->bits.liquid_type=liquid_water;
+ break;
+ default:
+ cout << ".error,bad pattern.";
+ }
+
+ //For all tiles.
+ if (reveal)
+ {
+ d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden;
+ }
+ //Always clear the dig designation.
+ d->bits.dig=designation_no;
+ //Make it underground, because it is capped
+ d->bits.subterranean=1;
+ d->bits.light=0;
+ d->bits.skyview=0;
+ //unlock fluids, so they fall down the pit.
+ d->bits.flow_forbid = d->bits.liquid_static=0;
+ block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1;
+ //Set the tile.
+ block.tiletypes[x][y] = t;
+
+ }
+ }
+
+ //Write the block.
+ Mapz->WriteBlockFlags(bx,by,z, block.blockflags );
+ Mapz->WriteDesignations(bx,by,z, &block.designation );
+ Mapz->WriteTileTypes(bx,by,z, &block.tiletypes );
+ Mapz->WriteDirtyBit(bx,by,z,1);
+
+ }
+
+ //Re-process the last z-level handled above.
+ z++;
+ assert( z>=0 );
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ //The bottom level is special.
+ if (-1)
+ {
+ if (!Mapz->ReadBlock40d( bx, by, z , &block ))
+ {
+ cout << "Bad block! " << bx << "," << by << "," << z << endl;
+ }
+ for (uint32_t x=0;x<16;++x)
+ {
+ for (uint32_t y=0;y<16;++y)
+ {
+ t=floor;
+ v=floorvar;
+ tp = getTileRow(block.tiletypes[x][y]);
+ d = &block.designation[x][y];
+
+ if ( exposehell )
+ {
+ //Leave hell tiles unchanged when exposing hell.
+ if ( isfeature(global_features,local_features,block,pc,x,y,feature_Underworld) )
+ {
+ continue;
+ }
+ }
+
+ //Does expose magma need anything at this level?
+ if ( exposemagma && stopatmagma )
+ {
+ continue;
+ }
+
+ switch (pattern[x][y])
+ {
+ case 0:
+ continue;
+ break;
+ case 1:
+ //Empty becomes floor.
+
+ //Base floor type on the z-level first, features, then tile type.
+ if (!z) {
+ //Bottom of map, use the floor specified, always.
+ break;
+ }
+
+ ////Only place floor where ground is already solid when exposing
+ //if( EMPTY == tp->c || RAMP_TOP == tp->c || STAIR_DOWN == tp->c ){
+ // continue;
+ //}
+
+ if ( d->bits.feature_global || d->bits.feature_global ) {
+ //Feature Floor!
+ t=344;
+ break;
+ }
+
+ //Tile material check.
+ switch ( tp->material )
+ {
+ case OBSIDIAN:
+ t=340;
+ v=3;
+ break;
+ case MAGMA:
+ v=0;
+ t=264; //magma flow
+ break;
+ case HFS:
+ //should only happen at bottom of map
+ break;
+ case VEIN:
+ t=441; //vein floor
+ v=3;
+ break;
+ case FEATSTONE:
+ t=344;
+ v=3;
+ break;
+ }
+
+ break;
+ case 2:
+ case 3:
+ //Walls already drawn.
+ //Ignore.
+ continue;
+ break;
+ }
+
+ //For all tiles.
+ if (reveal) d->bits.hidden = 0; //topblock.designation[x][y].bits.hidden;
+ //Always clear the dig designation.
+ d->bits.dig=designation_no;
+ //unlock fluids
+ d->bits.flow_forbid = d->bits.liquid_static=0;
+ block.blockflags.bits.liquid_1 = block.blockflags.bits.liquid_2 = 1;
+
+ //Set the tile.
+ block.tiletypes[x][y] = t + ( v ? rand()&v : 0 );
+ }
+ }
+ //Write the block.
+ Mapz->WriteBlockFlags(bx,by,z, block.blockflags );
+ Mapz->WriteDesignations(bx,by,z, &block.designation );
+ Mapz->WriteTileTypes(bx,by,z, &block.tiletypes );
+ Mapz->WriteDirtyBit(bx,by,z,1);
+ }
+
+ DF->Detach();
+#ifndef LINUX_BUILD
+ cout << "Done. Press any key to continue" << endl;
+ cin.ignore();
+#endif
+ return 0;
+}
diff --git a/needs_porting/hotkeynotedump.py b/needs_porting/hotkeynotedump.py
new file mode 100644
index 00000000..77cd0b81
--- /dev/null
+++ b/needs_porting/hotkeynotedump.py
@@ -0,0 +1,20 @@
+from context import Context, ContextManager
+
+cm = ContextManager("Memory.xml")
+df = cm.get_single_context()
+
+df.attach()
+
+gui = df.gui
+
+print "Hotkeys"
+
+hotkeys = gui.read_hotkeys()
+
+for key in hotkeys:
+ print "x: %d\ny: %d\tz: %d\ttext: %s" % (key.x, key.y, key.z, key.name)
+
+df.detach()
+
+print "Done. Press any key to continue"
+raw_input() \ No newline at end of file
diff --git a/needs_porting/incrementalsearch.cpp b/needs_porting/incrementalsearch.cpp
new file mode 100644
index 00000000..e70e0952
--- /dev/null
+++ b/needs_porting/incrementalsearch.cpp
@@ -0,0 +1,1064 @@
+// this is an incremental search tool. It only works on Linux.
+// here be dragons... and ugly code :P
+#include <iostream>
+#include <climits>
+#include <vector>
+#include <map>
+#include <set>
+#include <ctime>
+#include <string.h>
+#include <stdio.h>
+#include <algorithm>
+using namespace std;
+
+#ifndef LINUX_BUILD
+ #define WINVER 0x0500
+ // this one prevents windows from infecting the global namespace with filth
+ #define NOMINMAX
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+#endif
+
+#include <DFHack.h>
+#include "SegmentedFinder.h"
+
+inline void printRange(DFHack::t_memrange * tpr)
+{
+ std::cout << std::hex << tpr->start << " - " << tpr->end << "|" << (tpr->read ? "r" : "-") << (tpr->write ? "w" : "-") << (tpr->execute ? "x" : "-") << "|" << tpr->name << std::endl;
+}
+
+/*
+ * Since the start and/or end of a memory range can change each time we
+ * detach and re-attach to the DF process, we save the indexes of the
+ * memory ranges we want to look at, and re-read the ranges each time
+ * we re-attach. Hopefully we won't encounter any circumstances where
+ * entire new ranges are added or removed...
+ */
+bool getRanges(DFHack::Process * p, vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+ ranges.clear();
+ selected_ranges.clear();
+ p->getMemRanges(ranges);
+ cout << "Which range to search? (default is 1-4)" << endl;
+ for(size_t i = 0; i< ranges.size();i++)
+ {
+ cout << dec << "(" << i << ") ";
+ printRange(&(ranges[i]));
+ }
+ int start, end;
+ while(1)
+ {
+ string select;
+ cout << ">>";
+ std::getline(cin, select);
+ if(select.empty())
+ {
+ // empty input, assume default. observe the length of the memory
+ // range vector these are hardcoded values, intended for my
+ // convenience only
+ if(p->getDescriptor()->getOS() == DFHack::OS_WINDOWS)
+ {
+ start = min(11, (int)ranges.size());
+ end = min(14, (int)ranges.size());
+ }
+ else if(p->getDescriptor()->getOS() == DFHack::OS_LINUX)
+ {
+ start = min(2, (int)ranges.size());
+ end = min(4, (int)ranges.size());
+ }
+ else
+ {
+ start = 1;
+ end = 1;
+ }
+ break;
+ }
+ // I like the C variants here. much less object clutter
+ else if(sscanf(select.c_str(), "%d-%d", &start, &end) == 2)
+ {
+ start = min(start, (int)ranges.size());
+ end = min(end, (int)ranges.size());
+ break;
+ }
+ else
+ {
+ continue;
+ }
+ break;
+ }
+ cout << "selected ranges:" <<endl;
+
+ for (int i = start; i <= end; i++)
+ {
+ // check if readable
+ if (ranges[i].read)
+ {
+ selected_ranges.push_back(i);
+ printRange(&(ranges[i]));
+ }
+ }
+
+ return true;
+}
+
+bool getNumber (string prompt, int & output, int def, bool pdef = true)
+{
+ cout << prompt;
+ if(pdef)
+ cout << " default=" << def << endl;
+ while (1)
+ {
+ string select;
+ cout << ">>";
+ std::getline(cin, select);
+ if(select.empty())
+ {
+ output = def;
+ break;
+ }
+ else if( sscanf(select.c_str(), "%d", &output) == 1 )
+ {
+ break;
+ }
+ else
+ {
+ continue;
+ }
+ }
+ return true;
+}
+
+bool getString (string prompt, string & output)
+{
+ cout << prompt;
+ cout << ">>";
+ string select;
+ std::getline(cin, select);
+ if(select.empty())
+ {
+ return false;
+ }
+ else
+ {
+ output = select;
+ return true;
+ }
+}
+
+bool readRanges(DFHack::Context * DF, vector <int>& selected_ranges,
+ vector <DFHack::t_memrange>& ranges)
+{
+ DFHack::Process * p = DF->getProcess();
+
+ vector <DFHack::t_memrange> new_ranges;
+ new_ranges.clear();
+ p->getMemRanges(new_ranges);
+
+ for (size_t i = 0; i < selected_ranges.size(); i++)
+ {
+ int idx = selected_ranges[i];
+
+ if (ranges.size() == i)
+ // First time ranges vector has been filled in.
+ ranges.push_back(new_ranges[idx]);
+ // If something was wrong with the range on one memory read,
+ // don't read it again.
+ else if(ranges[i].valid)
+ ranges[i] = new_ranges[idx];
+ }
+
+ return true;
+}
+
+
+template <class T>
+bool Incremental ( vector <uint64_t> &found, const char * what, T& output,
+ const char *singular = "address", const char *plural = "addresses", bool numberz = false )
+{
+ string select;
+ if(found.empty())
+ {
+ cout << "search ready - insert " << what << ", 'p' for results, 'p #' to limit number of results" << endl;
+ }
+ else if( found.size() == 1)
+ {
+ cout << "Found single "<< singular <<"!" << endl;
+ cout << hex << "0x" << found[0] << endl;
+ }
+ else
+ {
+ cout << "Found " << dec << found.size() << " " << plural <<"." << endl;
+ }
+ incremental_more:
+ cout << ">>";
+ std::getline(cin, select);
+ size_t num = 0;
+ if( sscanf(select.c_str(),"p %zd", &num) && num > 0)
+ {
+ cout << "Found "<< plural <<":" << endl;
+ for(size_t i = 0; i < min(found.size(), num);i++)
+ {
+ cout << hex << "0x" << found[i] << endl;
+ }
+ goto incremental_more;
+ }
+ else if(select == "p")
+ {
+ cout << "Found "<< plural <<":" << endl;
+ for(size_t i = 0; i < found.size();i++)
+ {
+ cout << hex << "0x" << found[i] << endl;
+ }
+ goto incremental_more;
+ }
+ else if(select == "q")
+ {
+ return false;
+ }
+ else if(select.empty())
+ {
+ goto incremental_more;
+ }
+ else
+ {
+ if(numberz)
+ {
+ if( sscanf(select.c_str(),"0x%x", &output) == 1 )
+ {
+ //cout << dec << output << endl;
+ return true;
+ }
+ if( sscanf(select.c_str(),"%d", &output) == 1 )
+ {
+ //cout << dec << output << endl;
+ return true;
+ }
+ }
+ stringstream ss (stringstream::in | stringstream::out);
+ ss << select;
+ ss >> output;
+ cout << output;
+ if(!ss.fail())
+ {
+ return true;
+ }
+ cout << "not a valid value for type: " << what << endl;
+ goto incremental_more;
+ }
+}
+
+void FindIntegers(DFHack::ContextManager & DFMgr,
+ vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+
+ // input / validation of variable size
+ int size;
+ do
+ {
+ getNumber("Select variable size (1,2,4 bytes)",size, 4);
+ } while (size != 1 && size != 2 && size != 4);
+ // input / validation of variable alignment (default is to use the same alignment as size)
+ int alignment;
+ do
+ {
+ getNumber("Select variable alignment (1,2,4 bytes)",alignment, size);
+ } while (alignment != 1 && alignment != 2 && alignment != 4);
+
+ uint32_t test1;
+ vector <uint64_t> found;
+ found.reserve(100);
+ while(Incremental(found, "integer",test1,"address", "addresses",true))
+ {
+ DFMgr.Refresh();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ readRanges(DF, selected_ranges, ranges);
+ SegmentedFinder sf(ranges,DF);
+ switch(size)
+ {
+ case 1:
+ sf.Incremental<uint8_t,uint8_t>(test1,alignment,found, equalityP<uint8_t>);
+ break;
+ case 2:
+ sf.Incremental<uint16_t,uint16_t>(test1,alignment,found, equalityP<uint16_t>);
+ break;
+ case 4:
+ sf.Incremental<uint32_t,uint32_t>(test1,alignment,found, equalityP<uint32_t>);
+ break;
+ }
+ DF->Detach();
+ }
+}
+
+void FindVectorByLength(DFHack::ContextManager & DFMgr,
+ vector <int>& selected_ranges )
+{
+ vector <DFHack::t_memrange> ranges;
+
+ int element_size;
+ do
+ {
+ getNumber("Select searched vector item size in bytes",element_size, 4);
+ } while (element_size < 1);
+
+ uint32_t length;
+ vector <uint64_t> found;
+ found.reserve(100);
+ while (Incremental(found, "vector length",length,"vector","vectors"))
+ {
+ DFMgr.Refresh();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ readRanges(DF, selected_ranges, ranges);
+ SegmentedFinder sf(ranges,DF);
+ //sf.Incremental<int ,vecTriplet>(0,4,found,vectorAll);
+ //sf.Filter<uint32_t,vecTriplet>(length * element_size,found,vectorLength<uint32_t>);
+ sf.Incremental<uint32_t,vecTriplet>(length * element_size, 4 , found, vectorLength<uint32_t>);
+ DF->Detach();
+ }
+}
+
+void FindVectorByObjectRawname(DFHack::ContextManager & DFMgr,
+ vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+ vector <uint64_t> found;
+ string select;
+
+ while (Incremental(found, "raw name",select,"vector","vectors"))
+ {
+ DFMgr.Refresh();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ readRanges(DF, selected_ranges, ranges);
+ SegmentedFinder sf(ranges,DF);
+ sf.Find<int ,vecTriplet>(0,4,found, vectorAll);
+ sf.Filter<const char * ,vecTriplet>(select.c_str(),found, vectorString);
+ DF->Detach();
+ }
+}
+
+void FindVectorByFirstObjectRawname(DFHack::ContextManager & DFMgr,
+ vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+ vector <uint64_t> found;
+ string select;
+ while (Incremental(found, "raw name",select,"vector","vectors"))
+ {
+ DFMgr.Refresh();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ readRanges(DF, selected_ranges, ranges);
+ SegmentedFinder sf(ranges,DF);
+ sf.Find<int ,vecTriplet>(0,4,found, vectorAll);
+ sf.Filter<const char * ,vecTriplet>(select.c_str(),found, vectorStringFirst);
+ DF->Detach();
+ }
+}
+
+struct VectorSizeFunctor : public binary_function<uint64_t, uint64_t, bool>
+{
+ VectorSizeFunctor(SegmentedFinder & sf):sf_(sf){}
+ bool operator()( uint64_t lhs, uint64_t rhs)
+ {
+ vecTriplet* left = sf_.Translate<vecTriplet>(lhs);
+ vecTriplet* right = sf_.Translate<vecTriplet>(rhs);
+ return ((left->finish - left->start) < (right->finish - right->start));
+ }
+ SegmentedFinder & sf_;
+};
+
+void FindVectorByBounds(DFHack::ContextManager & DFMgr,
+ vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+ vector <uint64_t> found;
+ uint32_t select;
+ while (Incremental(found, "address between vector.start and vector.end",select,"vector","vectors"))
+ {
+ DFMgr.Refresh();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ readRanges(DF, selected_ranges, ranges);
+ SegmentedFinder sf(ranges,DF);
+ sf.Find<int ,vecTriplet>(0,4,found, vectorAll);
+ sf.Filter<uint32_t ,vecTriplet>(select,found, vectorAddrWithin);
+ // sort by size of vector
+ std::sort(found.begin(), found.end(), VectorSizeFunctor(sf));
+ DF->Detach();
+ }
+}
+
+void FindPtrVectorsByObjectAddress(DFHack::ContextManager & DFMgr,
+ vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+ vector <uint64_t> found;
+ uint32_t select;
+ while (Incremental(found, "object address",select,"vector","vectors"))
+ {
+ DFMgr.Refresh();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ readRanges(DF, selected_ranges, ranges);
+ SegmentedFinder sf(ranges,DF);
+ sf.Find<int ,vecTriplet>(0,4,found, vectorAll);
+ sf.Filter<uint32_t ,vecTriplet>(select,found, vectorOfPtrWithin);
+ DF->Detach();
+ }
+}
+
+void FindStrBufs(DFHack::ContextManager & DFMgr,
+ vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+ vector <uint64_t> found;
+ string select;
+ while (Incremental(found,"buffer",select,"buffer","buffers"))
+ {
+ DFMgr.Refresh();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ readRanges(DF, selected_ranges, ranges);
+ SegmentedFinder sf(ranges,DF);
+ sf.Find< const char * ,uint32_t>(select.c_str(),1,found, findStrBuffer);
+ DF->Detach();
+ }
+}
+
+
+
+void FindStrings(DFHack::ContextManager & DFMgr,
+ vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+ vector <uint64_t> found;
+ string select;
+ while (Incremental(found,"string",select,"string","strings"))
+ {
+ DFMgr.Refresh();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ readRanges(DF, selected_ranges, ranges);
+ SegmentedFinder sf(ranges,DF);
+ sf.Incremental< const char * ,uint32_t>(select.c_str(),1,found, findString);
+ DF->Detach();
+ }
+}
+
+void FindData(DFHack::ContextManager & DFMgr,
+ vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+ vector <uint64_t> found;
+ Bytestream select;
+ while (Incremental(found,"byte stream",select,"byte stream","byte streams"))
+ {
+ DFMgr.Refresh();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ readRanges(DF, selected_ranges, ranges);
+ SegmentedFinder sf(ranges,DF);
+ sf.Incremental< Bytestream ,uint32_t>(select,1,found, findBytestream);
+ DF->Detach();
+ }
+}
+
+bool TriggerIncremental ( vector <uint64_t> &found )
+{
+ string select;
+ if(found.empty())
+ {
+ cout << "search ready - position the DF cursor and hit enter when ready" << endl;
+ }
+ else if( found.size() == 1 )
+ {
+ cout << "Found single coord!" << endl;
+ cout << hex << "0x" << found[0] << endl;
+ }
+ else
+ {
+ cout << "Found " << dec << found.size() << " coords." << endl;
+ }
+ incremental_more:
+ cout << ">>";
+ std::getline(cin, select);
+ size_t num = 0;
+ if( sscanf(select.c_str(),"p %zd", &num) && num > 0)
+ {
+ cout << "Found coords:" << endl;
+ for(size_t i = 0; i < min(found.size(), num);i++)
+ {
+ cout << hex << "0x" << found[i] << endl;
+ }
+ goto incremental_more;
+ }
+ else if(select == "p")
+ {
+ cout << "Found coords:" << endl;
+ for(size_t i = 0; i < found.size();i++)
+ {
+ cout << hex << "0x" << found[i] << endl;
+ }
+ goto incremental_more;
+ }
+ else if(select == "q")
+ {
+ return false;
+ }
+ else return true;
+}
+
+void FindCoords(DFHack::ContextManager & DFMgr, vector <int>& selected_ranges)
+{
+ vector <uint64_t> found;
+ vector <DFHack::t_memrange> ranges;
+
+ int size = 4;
+ do
+ {
+ getNumber("Select coord size (2,4 bytes)",size, 4);
+ } while (size != 2 && size != 4);
+ while (TriggerIncremental(found))
+ {
+ DFMgr.Refresh();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ readRanges(DF, selected_ranges, ranges);
+ DFHack::Gui * pos = DF->getGui();
+ pos->Start();
+ int32_t x, y, z;
+ pos->getCursorCoords(x,y,z);
+ cout << "Searching for: " << dec << x << ":" << y << ":" << z << endl;
+ Bytestream select;
+ if(size == 2)
+ {
+ select.insert<uint16_t>(x);
+ select.insert<uint16_t>(y);
+ select.insert<uint16_t>(z);
+ }
+ else
+ {
+ select.insert<uint32_t>(x);
+ select.insert<uint32_t>(y);
+ select.insert<uint32_t>(z);
+ }
+ cout << select << endl;
+ SegmentedFinder sf(ranges,DF);
+ sf.Incremental< Bytestream ,uint32_t>(select,1,found, findBytestream);
+ DF->Detach();
+ }
+}
+
+void PtrTrace(DFHack::ContextManager & DFMgr,
+ vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+
+ int element_size;
+ do
+ {
+ getNumber("Set search granularity",element_size, 4);
+ } while (element_size < 1);
+
+ vector <uint64_t> found;
+ set <uint64_t> check; // to detect circles
+ uint32_t select;
+ while (Incremental(found,"address",select,"addresses","addresses",true))
+ {
+ DFMgr.Refresh();
+ found.clear();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ readRanges(DF, selected_ranges, ranges);
+ SegmentedFinder sf(ranges,DF);
+ cout <<"Starting: 0x" << hex << select << endl;
+ while(sf.getSegmentForAddress(select))
+ {
+ sf.Incremental<uint32_t,uint32_t>(select,element_size,found, equalityP<uint32_t>);
+ if(found.empty())
+ {
+ cout << ".";
+ cout.flush();
+ select -=element_size;
+ continue;
+ }
+ cout << endl;
+ cout <<"Object start: 0x" << hex << select << endl;
+ cout <<"Pointer: 0x" << hex << found[0] << endl;
+ // make sure we don't go in circles'
+ if(check.count(select))
+ {
+ break;
+ }
+ check.insert(select);
+ // ascend
+ select = found[0];
+ found.clear();
+ }
+ DF->Detach();
+ }
+}
+/*
+{
+ vector <uint64_t> found;
+ Bytestream select;
+ while (Incremental(found,"byte stream",select,"byte stream","byte streams"))
+ {
+ DFMgr.Refresh();
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ SegmentedFinder sf(ranges,DF);
+ sf.Incremental< Bytestream ,uint32_t>(select,1,found, findBytestream);
+ DF->Detach();
+ }
+}
+*/
+void DataPtrTrace(DFHack::ContextManager & DFMgr,
+ vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+ int element_size;
+ do
+ {
+ getNumber("Set search granularity",element_size, 4);
+ } while (element_size < 1);
+
+ vector <uint64_t> found;
+ set <uint64_t> check; // to detect circles
+ uint32_t select;
+ Bytestream bs_select;
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ DF->Attach();
+ DFMgr.Refresh();
+ readRanges(DF, selected_ranges, ranges);
+ found.clear();
+ SegmentedFinder sf(ranges,DF);
+ while(found.empty())
+ {
+ Incremental(found,"byte stream",bs_select,"byte stream","byte streams");
+
+ sf.Incremental< Bytestream ,uint32_t>(bs_select,1,found, findBytestream);
+ }
+ select = found[0];
+
+
+
+
+ cout <<"Starting: 0x" << hex << select << endl;
+ while(sf.getSegmentForAddress(select))
+ {
+ sf.Incremental<uint32_t,uint32_t>(select,element_size,found, equalityP<uint32_t>);
+ if(found.empty())
+ {
+ cout << ".";
+ cout.flush();
+ select -=element_size;
+ continue;
+ }
+ cout << endl;
+ cout <<"Object start: 0x" << hex << select << endl;
+ cout <<"Pointer: 0x" << hex << found[0] << endl;
+ // make sure we don't go in circles'
+ if(check.count(select))
+ {
+ break;
+ }
+ check.insert(select);
+ // ascend
+ select = found[0];
+ found.clear();
+ }
+ DF->Detach();
+}
+
+void printFound(vector <uint64_t> &found, const char * what)
+{
+ cout << what << ":" << endl;
+ for(size_t i = 0; i < found.size();i++)
+ {
+ cout << hex << "0x" << found[i] << endl;
+ }
+}
+
+void printFoundStrVec(vector <uint64_t> &found, const char * what, SegmentedFinder & s)
+{
+ cout << what << ":" << endl;
+ for(size_t i = 0; i < found.size();i++)
+ {
+ cout << hex << "0x" << found[i] << endl;
+ cout << "--------------------------" << endl;
+ vecTriplet * vt = s.Translate<vecTriplet>(found[i]);
+ if(vt)
+ {
+ int j = 0;
+ for(uint32_t idx = vt->start; idx < vt->finish; idx += sizeof(uint32_t))
+ {
+ uint32_t object_ptr;
+ // deref ptr idx, get ptr to object
+ if(!s.Read(idx,object_ptr))
+ {
+ cout << "BAD!" << endl;
+ break;
+ }
+ // deref ptr to first object, get ptr to string
+ uint32_t string_ptr;
+ if(!s.Read(object_ptr,string_ptr))
+ {
+ cout << "BAD!" << endl;
+ break;
+ }
+ // get string location in our local cache
+ char * str = s.Translate<char>(string_ptr);
+ if(!str)
+ {
+ cout << "BAD!" << endl;
+ break;
+ }
+ cout << dec << j << ":" << hex << "0x" << object_ptr << " : " << str << endl;
+ j++;
+ }
+ }
+ else
+ {
+ cout << "BAD!" << endl;
+ break;
+ }
+ cout << "--------------------------" << endl;
+ }
+}
+
+// meh
+#pragma pack(1)
+struct tilecolors
+{
+ uint16_t fore;
+ uint16_t back;
+ uint16_t bright;
+};
+#pragma pack()
+
+void autoSearch(DFHack::Context * DF, vector <int>& selected_ranges)
+{
+ vector <DFHack::t_memrange> ranges;
+ vector <uint64_t> allVectors;
+ vector <uint64_t> filtVectors;
+ vector <uint64_t> to_filter;
+
+ readRanges(DF, selected_ranges, ranges);
+
+ cout << "stealing memory..." << endl;
+ SegmentedFinder sf(ranges, DF);
+ cout << "looking for vectors..." << endl;
+ sf.Find<int ,vecTriplet>(0,4,allVectors, vectorAll);
+/*
+ // trim vectors. anything with > 10000 entries is not interesting
+ for(uint64_t i = 0; i < allVectors.size();i++)
+ {
+ vecTriplet* vtrip = sf.Translate<vecTriplet>(allVectors[i]);
+ if(vtrip)
+ {
+ uint64_t length = (vtrip->finish - vtrip->start) / 4;
+ if(length < 10000 )
+ {
+ filtVectors.push_back(allVectors[i]);
+ }
+ }
+ }
+*/
+ filtVectors = allVectors;
+ cout << "-------------------" << endl;
+ cout << "!!LANGUAGE TABLES!!" << endl;
+ cout << "-------------------" << endl;
+
+ uint64_t kulet_vector;
+ uint64_t word_table_offset;
+ uint64_t DWARF_vector;
+ uint64_t DWARF_object;
+
+ // find lang vector (neutral word table)
+ to_filter = filtVectors;
+ sf.Filter<const char * ,vecTriplet>("ABBEY",to_filter, vectorStringFirst);
+ uint64_t lang_addr = to_filter[0];
+
+ // find dwarven language word table
+ to_filter = filtVectors;
+ sf.Filter<const char * ,vecTriplet>("kulet",to_filter, vectorStringFirst);
+ kulet_vector = to_filter[0];
+
+ // find vector of languages
+ to_filter = filtVectors;
+ sf.Filter<const char * ,vecTriplet>("DWARF",to_filter, vectorStringFirst);
+
+ // verify
+ for(size_t i = 0; i < to_filter.size(); i++)
+ {
+ vecTriplet * vec = sf.Translate<vecTriplet>(to_filter[i]);
+ if(((vec->finish - vec->start) / 4) == 4) // verified
+ {
+ DWARF_vector = to_filter[i];
+ DWARF_object = sf.Read<uint32_t>(vec->start);
+ // compute word table offset from dwarf word table and dwarf language object addresses
+ word_table_offset = kulet_vector - DWARF_object;
+ break;
+ }
+ }
+ cout << "translation vector: " << hex << "0x" << DWARF_vector << endl;
+ cout << "lang vector: " << hex << "0x" << lang_addr << endl;
+ cout << "word table offset: " << hex << "0x" << word_table_offset << endl;
+
+ cout << "-------------" << endl;
+ cout << "!!MATERIALS!!" << endl;
+ cout << "-------------" << endl;
+ // inorganics vector
+ to_filter = filtVectors;
+ //sf.Find<uint32_t,vecTriplet>(257 * 4,4,to_filter,vectorLength<uint32_t>);
+ sf.Filter<const char * ,vecTriplet>("IRON",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("ONYX",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("RAW_ADAMANTINE",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("BLOODSTONE",to_filter, vectorString);
+ printFound(to_filter,"inorganics");
+
+ // organics vector
+ to_filter = filtVectors;
+ sf.Filter<uint32_t,vecTriplet>(52 * 4,to_filter,vectorLength<uint32_t>);
+ sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst);
+ printFound(to_filter,"organics");
+
+ // new organics vector
+ to_filter = filtVectors;
+ sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("MEADOW-GRASS",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("TUNNEL_TUBE",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("WEED_BLADE",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("EYEBALL",to_filter, vectorString);
+ printFound(to_filter,"organics 31.19");
+
+ // tree vector
+ to_filter = filtVectors;
+ sf.Filter<uint32_t,vecTriplet>(31 * 4,to_filter,vectorLength<uint32_t>);
+ sf.Filter<const char * ,vecTriplet>("MANGROVE",to_filter, vectorStringFirst);
+ printFound(to_filter,"trees");
+
+ // plant vector
+ to_filter = filtVectors;
+ sf.Filter<uint32_t,vecTriplet>(21 * 4,to_filter,vectorLength<uint32_t>);
+ sf.Filter<const char * ,vecTriplet>("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst);
+ printFound(to_filter,"plants");
+
+ // color descriptors
+ //AMBER, 112
+ to_filter = filtVectors;
+ sf.Filter<uint32_t,vecTriplet>(112 * 4,to_filter,vectorLength<uint32_t>);
+ sf.Filter<const char * ,vecTriplet>("AMBER",to_filter, vectorStringFirst);
+ printFound(to_filter,"color descriptors");
+ if(!to_filter.empty())
+ {
+ uint64_t vec = to_filter[0];
+ vecTriplet *vtColors = sf.Translate<vecTriplet>(vec);
+ uint32_t colorObj = sf.Read<uint32_t>(vtColors->start);
+ cout << "Amber color:" << hex << "0x" << colorObj << endl;
+ // TODO: find string 'amber', the floats
+ }
+
+ // all descriptors
+ //AMBER, 338
+ to_filter = filtVectors;
+ sf.Filter<uint32_t,vecTriplet>(338 * 4,to_filter,vectorLength<uint32_t>);
+ sf.Filter<const char * ,vecTriplet>("AMBER",to_filter, vectorStringFirst);
+ printFound(to_filter,"all descriptors");
+
+ // creature type
+ //ELEPHANT, ?? (demons abound)
+ to_filter = filtVectors;
+ //sf.Find<uint32_t,vecTriplet>(338 * 4,4,to_filter,vectorLength<uint32_t>);
+ sf.Filter<const char * ,vecTriplet>("ELEPHANT",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("CAT",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("DWARF",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("WAMBLER_FLUFFY",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("TOAD",to_filter, vectorString);
+ sf.Filter<const char * ,vecTriplet>("DEMON_1",to_filter, vectorString);
+
+ vector <uint64_t> toad_first = to_filter;
+ vector <uint64_t> elephant_first = to_filter;
+ sf.Filter<const char * ,vecTriplet>("TOAD",toad_first, vectorStringFirst);
+ sf.Filter<const char * ,vecTriplet>("ELEPHANT",elephant_first, vectorStringFirst);
+ printFoundStrVec(toad_first,"toad-first creature types",sf);
+ printFound(elephant_first,"elephant-first creature types");
+ printFound(to_filter,"all creature types");
+
+ uint64_t to_use = 0;
+ if(!elephant_first.empty())
+ {
+ to_use = elephant_first[0];
+ vecTriplet *vtCretypes = sf.Translate<vecTriplet>(to_use);
+ uint32_t elephant = sf.Read<uint32_t>(vtCretypes->start);
+ uint64_t Eoffset;
+ cout << "Elephant: 0x" << hex << elephant << endl;
+ cout << "Elephant: rawname = 0x0" << endl;
+ uint8_t letter_E = 'E';
+ Eoffset = sf.FindInRange<uint8_t,uint8_t> (letter_E,equalityP<uint8_t>, elephant, 0x300 );
+ if(Eoffset)
+ {
+ cout << "Elephant: big E = 0x" << hex << Eoffset - elephant << endl;
+ }
+ Eoffset = sf.FindInRange<const char *,vecTriplet> ("FEMALE",vectorStringFirst, elephant, 0x300 );
+ if(Eoffset)
+ {
+ cout << "Elephant: caste vector = 0x" << hex << Eoffset - elephant << endl;
+ }
+ Eoffset = sf.FindInRange<const char *,vecTriplet> ("SKIN",vectorStringFirst, elephant, 0x2000 );
+ if(Eoffset)
+ {
+ cout << "Elephant: extract? vector = 0x" << hex << Eoffset - elephant << endl;
+ }
+ tilecolors eletc = {7,0,0};
+ Bytestream bs_eletc(&eletc, sizeof(tilecolors));
+ cout << bs_eletc;
+ Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_eletc, findBytestream, elephant, 0x300 );
+ if(Eoffset)
+ {
+ cout << "Elephant: colors = 0x" << hex << Eoffset - elephant << endl;
+ }
+ //cout << "Amber color:" << hex << "0x" << colorObj << endl;
+ // TODO: find string 'amber', the floats
+ }
+ if(!toad_first.empty())
+ {
+ to_use = toad_first[0];
+ vecTriplet *vtCretypes = sf.Translate<vecTriplet>(to_use);
+ uint32_t toad = sf.Read<uint32_t>(vtCretypes->start);
+ uint64_t Eoffset;
+ cout << "Toad: 0x" << hex << toad << endl;
+ cout << "Toad: rawname = 0x0" << endl;
+ Eoffset = sf.FindInRange<uint8_t,uint8_t> (0xF9,equalityP<uint8_t>, toad, 0x300 );
+ if(Eoffset)
+ {
+ cout << "Toad: character (not reliable) = 0x" << hex << Eoffset - toad << endl;
+ }
+ Eoffset = sf.FindInRange<const char *,vecTriplet> ("FEMALE",vectorStringFirst, toad, 0x300 );
+ if(Eoffset)
+ {
+ cout << "Toad: caste vector = 0x" << hex << Eoffset - toad << endl;
+ }
+ Eoffset = sf.FindInRange<const char *,vecTriplet> ("SKIN",vectorStringFirst, toad, 0x2000 );
+ if(Eoffset)
+ {
+ cout << "Toad: extract? vector = 0x" << hex << Eoffset - toad << endl;
+ }
+ tilecolors toadtc = {2,0,0};
+ Bytestream bs_toadc(&toadtc, sizeof(tilecolors));
+ Eoffset = sf.FindInRange<Bytestream,tilecolors> (bs_toadc, findBytestream, toad, 0x300 );
+ if(Eoffset)
+ {
+ cout << "Toad: colors = 0x" << hex << Eoffset - toad << endl;
+ }
+ }
+ if(to_use)
+ {
+
+ }
+}
+
+int main (void)
+{
+ string select;
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context * DF = DFMgr.getSingleContext();
+ try
+ {
+ DF->Attach();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+ DFHack::Process * p = DF->getProcess();
+ vector <int> selected_ranges;
+ getRanges(p, selected_ranges);
+
+ string prompt =
+ "Select search type: 1=number(default), 2=vector by length, 3=vector>object>string,\n"
+ " 4=string, 5=automated offset search, 6=vector by address in its array,\n"
+ " 7=pointer vector by address of an object, 8=vector>first object>string\n"
+ " 9=string buffers, 10=known data, 11=backpointers, 12=data+backpointers\n"
+ " 13=coord lookup\n"
+ " 0= exit\n";
+ int mode;
+ bool finish = 0;
+ do
+ {
+ getNumber(prompt,mode, 1, false);
+ switch (mode)
+ {
+ case 0:
+ finish = 1;
+ break;
+ case 1:
+ DF->Detach();
+ FindIntegers(DFMgr, selected_ranges);
+ break;
+ case 2:
+ DF->Detach();
+ FindVectorByLength(DFMgr, selected_ranges);
+ break;
+ case 3:
+ DF->Detach();
+ FindVectorByObjectRawname(DFMgr, selected_ranges);
+ break;
+ case 4:
+ DF->Detach();
+ FindStrings(DFMgr, selected_ranges);
+ break;
+ case 5:
+ autoSearch(DF,selected_ranges);
+ break;
+ case 6:
+ DF->Detach();
+ FindVectorByBounds(DFMgr,selected_ranges);
+ break;
+ case 7:
+ DF->Detach();
+ FindPtrVectorsByObjectAddress(DFMgr,selected_ranges);
+ break;
+ case 8:
+ DF->Detach();
+ FindVectorByFirstObjectRawname(DFMgr, selected_ranges);
+ break;
+ case 9:
+ DF->Detach();
+ FindStrBufs(DFMgr, selected_ranges);
+ break;
+ case 10:
+ DF->Detach();
+ FindData(DFMgr, selected_ranges);
+ break;
+ case 11:
+ DF->Detach();
+ PtrTrace(DFMgr, selected_ranges);
+ break;
+ case 12:
+ DF->Detach();
+ DataPtrTrace(DFMgr, selected_ranges);
+ break;
+ case 13:
+ DF->Detach();
+ FindCoords(DFMgr, selected_ranges);
+ break;
+ default:
+ cout << "Unknown function, try again." << endl;
+ }
+ } while ( !finish );
+ #ifndef LINUX_BUILD
+ cout << "Done. Press any key to continue" << endl;
+ cin.ignore();
+ #endif
+ return 0;
+}
diff --git a/needs_porting/itemdesignator.cpp b/needs_porting/itemdesignator.cpp
new file mode 100644
index 00000000..63b41eb7
--- /dev/null
+++ b/needs_porting/itemdesignator.cpp
@@ -0,0 +1,148 @@
+// Item designator
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <climits>
+#include <vector>
+using namespace std;
+
+#include <DFHack.h>
+#include <DFVector.h>
+using namespace DFHack;
+
+int main ()
+{
+
+ DFHack::ContextManager CM ("Memory.xml");
+ DFHack::Context * DF;
+ DFHack::VersionInfo *mem;
+ DFHack::Gui * Gui;
+ DFHack::Materials * Mats;
+ DFHack::Items * Items;
+ cout << "This utility lets you mass-designate items by type and material." << endl
+ << "Like set on fire all MICROCLINE item_stone..." << endl
+ << "Some unusual combinations might be untested and cause the program to crash..."<< endl
+ << "so, watch your step and backup your fort" << endl;
+ try
+ {
+ DF = CM.getSingleContext();
+ DF->Attach();
+ mem = DF->getMemoryInfo();
+ Gui = DF->getGui();
+ Mats = DF->getMaterials();
+ Mats->ReadAllMaterials();
+ Items = DF->getItems();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+ DFHack::Process * p = DF->getProcess();
+ DFHack::OffsetGroup* itemGroup = mem->getGroup("Items");
+ unsigned vector_addr = itemGroup->getAddress("items_vector");
+ DFHack::DfVector <uint32_t> p_items (p, vector_addr);
+ uint32_t numItems = p_items.size();
+
+ map< string, map<string,vector< dfh_item > > > itemmap;
+ map< string, map< string, vector< dfh_item > > >::iterator it1;
+ int failedItems = 0;
+ map <string, int > bad_mat_items;
+ for(uint32_t i=0; i< numItems; i++)
+ {
+ DFHack::dfh_item temp;
+ Items->readItem(p_items[i],temp);
+ string typestr = Items->getItemClass(temp);
+ string material = Mats->getDescription(temp.matdesc);
+ itemmap[typestr][material].push_back(temp);
+ }
+
+ int i =0;
+ for( it1 = itemmap.begin(); it1!=itemmap.end();it1++)
+ {
+ cout << i << ": " << it1->first << "\n";
+ i++;
+ }
+ if(i == 0)
+ {
+ cout << "No items found" << endl;
+ DF->Detach();
+ return 0;
+ }
+ cout << endl << "Select an item type from the list:";
+ int number;
+ string in;
+ stringstream ss;
+ getline(cin, in);
+ ss.str(in);
+ ss >> number;
+ int j = 0;
+ it1 = itemmap.begin();
+ while(j < number && it1!=itemmap.end())
+ {
+ it1++;
+ j++;
+ }
+ cout << it1->first << "\n";
+ map<string,vector<dfh_item> >::iterator it2;
+ i=0;
+ for(it2 = it1->second.begin();it2!=it1->second.end();it2++){
+ cout << i << ":\t" << it2->first << " [" << it2->second.size() << "]" << endl;
+ i++;
+ }
+ cout << endl << "Select a material type: ";
+ int number2;
+ ss.clear();
+ getline(cin, in);
+ ss.str(in);
+ ss >> number2;
+
+ decideAgain:
+ cout << "Select a designation - (d)ump, (f)orbid, (m)melt, set on fi(r)e :" << flush;
+ string designationType;
+ getline(cin,designationType);
+ DFHack::t_itemflags changeFlag = {0};
+ if(designationType == "d" || designationType == "dump")
+ {
+ changeFlag.dump = 1;
+ }
+ else if(designationType == "f" || designationType == "forbid")
+ {
+ changeFlag.forbid = 1;
+ }
+ else if(designationType == "m" || designationType == "melt")
+ {
+ changeFlag.melt = 1;
+ }
+ else if(designationType == "r" || designationType == "fire")
+ {
+ changeFlag.on_fire = 1;
+ }
+ else
+ {
+ goto decideAgain;
+ }
+ j=0;
+ it2= it1->second.begin();
+ while(j < number2 && it2!=it1->second.end())
+ {
+ it2++;
+ j++;
+ }
+ for(uint32_t k = 0;k< it2->second.size();k++)
+ {
+ DFHack::dfh_item & t = it2->second[k];
+ t.base.flags.whole |= changeFlag.whole;
+ Items->writeItem(t);
+ }
+ DF->Detach();
+#ifndef LINUX_BUILD
+ cout << "Done. Press any key to continue" << endl;
+ cin.ignore();
+#endif
+ return 0;
+}
diff --git a/needs_porting/lair.cpp b/needs_porting/lair.cpp
new file mode 100644
index 00000000..7bf3ddc2
--- /dev/null
+++ b/needs_porting/lair.cpp
@@ -0,0 +1,74 @@
+// This is a simple bit writer... it marks the whole map as a creature lair, preventing item scatter.
+
+#include <iostream>
+#include <vector>
+#include <map>
+using namespace std;
+#include <DFHack.h>
+#include <extra/termutil.h>
+
+int main (void)
+{
+ bool temporary_terminal = TemporaryTerminal();
+ uint32_t x_max,y_max,z_max;
+ DFHack::occupancies40d occupancies;
+
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context *DF;
+ try
+ {
+ DF = DFMgr.getSingleContext();
+ DF->Attach();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ if(temporary_terminal)
+ cin.ignore();
+ return 1;
+ }
+
+ DFHack::Maps *Maps =DF->getMaps();
+
+ // init the map
+ if(!Maps->Start())
+ {
+ cerr << "Can't init map." << endl;
+ if(temporary_terminal)
+ cin.ignore();
+ return 1;
+ }
+
+ cout << "Designating, please wait..." << endl;
+
+ Maps->getSize(x_max,y_max,z_max);
+ 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->isValidBlock(x,y,z))
+ {
+ // read block designations
+ Maps->ReadOccupancy(x,y,z, &occupancies);
+ //Maps->ReadTileTypes(x,y,z, &tiles);
+ // change the monster_lair flag to 1
+ for (uint32_t i = 0; i < 16;i++) for (uint32_t j = 0; j < 16;j++)
+ {
+ // add tile type chack here
+ occupancies[i][j].bits.monster_lair = 1;
+ }
+ // write the designations back
+ Maps->WriteOccupancy(x,y,z, &occupancies);
+ }
+ }
+ }
+ }
+ if(temporary_terminal)
+ {
+ cout << "The map has been marked as a creature lair. Items shouldn't scatter." << endl;
+ cin.ignore();
+ }
+ return 0;
+}
diff --git a/needs_porting/position.py b/needs_porting/position.py
new file mode 100644
index 00000000..12244058
--- /dev/null
+++ b/needs_porting/position.py
@@ -0,0 +1,71 @@
+import sys
+from pydfhack import ContextManager
+
+df_cm = ContextManager("Memory.xml")
+df = df_cm.get_single_context()
+
+if not df.attach():
+ print "Unable to attach!"
+ print "Press any key to continue"
+
+ raw_input()
+ sys.exit(1)
+
+gui = df.gui
+
+if gui is not None:
+ maps = df.maps
+ world = df.world
+
+ have_maps = maps.start()
+ world.start()
+
+ gm = world.read_game_mode()
+
+ if gm is not None:
+ print gm
+
+ date_tuple = (world.read_current_year(), world.read_current_month(), world.read_current_day(), world.read_current_tick())
+
+ print "Year: %d Month: %d Day: %d Tick: %d" % date_tuple
+
+ v_coords = gui.get_view_coords()
+ c_coords = gui.get_cursor_coords()
+ w_coords = (-1, -1, -1)
+ world_pos_string = ""
+
+ if have_maps is True:
+ w_coords = maps.getPosition()
+
+ x = (v_coords[0] + w_coords[0]) * 48
+ y = (v_coords[1] + w_coords[1]) * 48
+ z = (v_coords[2] + w_coords[2])
+
+ world_pos_string = " world: %d/%d/%d" % (x, y, z)
+
+ print "Map world offset: %d/%d/%d embark squares" % w_coords
+
+ if v_coords != (-1, -1, -1):
+ print "view coords: %d/%d/%d" % v_coords
+
+ if have_maps is True:
+ print world_pos_string
+
+ if c_coords != (-1, -1, -1):
+ print "cursor coords: %d/%d/%d" % c_coords
+
+ if have_maps is True:
+ print world_pos_string
+
+ window_size = gui.get_window_size()
+
+ if window_size != (-1, -1):
+ print "window size : %d %d" % window_size
+else:
+ print "cursor and window parameters are unsupported on your version of DF"
+
+if not df.detach():
+ print "Unable to detach!"
+
+print "Done. Press any key to continue"
+raw_input() \ No newline at end of file
diff --git a/needs_porting/reveal.py b/needs_porting/reveal.py
new file mode 100644
index 00000000..268e1a3a
--- /dev/null
+++ b/needs_porting/reveal.py
@@ -0,0 +1,93 @@
+import time
+from context import ContextManager
+
+class HideBlock(object):
+ __slots__ = [ "x", "y", "z", "hiddens" ]
+
+ def __init__(self, *args, **kwargs):
+ self.x = 0
+ self.y = 0
+ self.z = 0
+ self.hiddens = [[0 for i in xrange(16)] for j in xrange(16)]
+
+df_cm = ContextManager("Memory.xml")
+df = df_cm.get_single_context()
+
+df.attach()
+
+m = df.maps
+w = df.world
+
+print "Pausing..."
+
+w.start()
+
+#this mimics the hack in the C++ reveal tool that attempts to ensure that DF isn't in the middle of
+#a frame update
+w.set_pause_state(True)
+df.resume()
+time.sleep(1)
+df.suspend()
+
+w.finish()
+
+m.start()
+
+print "Revealing, please wait..."
+
+m_x, m_y, m_z = m.size
+hide_blocks = []
+
+for x in xrange(m_x):
+ for y in xrange(m_y):
+ for z in xrange(m_z):
+ if m.is_valid_block(x, y, z):
+ hb = HideBlock()
+
+ hb.x = x
+ hb.y = y
+ hb.z = z
+
+ d = m.read_designations(x, y, z)
+
+ for k_i, i in enumerate(d):
+ for k_j, j in enumerate(i):
+ hb.hiddens[k_i][k_j] = j.bits.hidden
+
+ j.bits.hidden = 0
+
+ hide_blocks.append(hb)
+
+ m.write_designations(x, y, z, d)
+
+m.finish()
+df.detach()
+
+print "Map revealed. The game has been paused for you."
+print "Unpausing can unleash the forces of hell!"
+print "Press any key to unreveal."
+print "Close to keep the map revealed !!FOREVER!!"
+
+raw_input()
+
+print "Unrevealing...please wait"
+
+df.attach()
+m = df.maps
+m.start()
+
+for h in hide_blocks:
+ d = m.read_designations(h.x, h.y, h.z)
+
+ for k_i, i in enumerate(h.hiddens):
+ for k_j, j in enumerate(i):
+ d[k_i][k_j].bits.hidden = j
+
+ m.write_designations(h.x, h.y, h.z, d)
+
+m.finish()
+
+print "Done. Press any key to continue"
+raw_input()
+
+df.detach() \ No newline at end of file
diff --git a/needs_porting/treedump.py b/needs_porting/treedump.py
new file mode 100644
index 00000000..f6017c94
--- /dev/null
+++ b/needs_porting/treedump.py
@@ -0,0 +1,52 @@
+from context import Context, ContextManager
+
+cm = ContextManager("Memory.xml")
+df = cm.get_single_context()
+
+df.attach()
+
+gui = df.gui
+veg = df.vegetation
+mps = df.maps
+mat = df.materials
+
+x, y, z = gui.get_cursor_coords()
+
+num_veg = veg.start()
+
+if x == -30000:
+ print "----==== Trees ====----"
+
+ for i in xrange(num_veg):
+ t = veg.read(i)
+
+ print "%d/%d/%d, %d:%d" % (t.x, t.y, t.z, t.type, t.material)
+else:
+ #new method, gets the list of trees in a block. can show farm plants
+ if mps.start():
+ pos_tuple = (x, y, z)
+ trees = mps.read_vegetation(x / 16, y / 16, z)
+
+ if trees is not None:
+ for t in trees:
+ if (t.x, t.y, t.z) == pos_tuple:
+ print "----==== Tree at %d/%d/%d ====----" % pos_tuple
+ print str(t)
+ break
+ mps.finish()
+
+ #old method, get the tree from the global vegetation vector. can't show farm plants
+ for i in xrange(num_veg):
+ t = veg.read(i)
+
+ if (t.x, t.y, t.z) == pos_tuple:
+ print "----==== Tree at %d/%d/%d ====----" % pos_tuple
+ print str(t)
+ break
+
+veg.finish()
+
+df.detach()
+
+print "Done. Press any key to continue"
+raw_input() \ No newline at end of file
diff --git a/needs_porting/veinlook.cpp b/needs_porting/veinlook.cpp
new file mode 100644
index 00000000..c5837a25
--- /dev/null
+++ b/needs_porting/veinlook.cpp
@@ -0,0 +1,1117 @@
+#include <string.h> // for memset
+#include <string>
+#include <fstream>
+#include <iostream>
+#include <iomanip>
+#include <vector>
+#include <map>
+#include <bitset>
+using namespace std;
+
+#include <sstream>
+// the header name comes from the build system.
+#include <curses.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <locale.h>
+#include <math.h>
+
+#define DFHACK_WANT_MISCUTILS
+#define DFHACK_WANT_TILETYPES
+#include <DFHack.h>
+
+using namespace DFHack;
+
+
+string error;
+Context * pDF = 0;
+
+
+struct t_tempz
+{
+ int32_t limit;
+ int character;
+};
+
+t_tempz temp_limits[]=
+{
+ {50, '.'},
+ {100, '+'},
+ {500, '*'},
+ {1000, '#'},
+ {2000, '!'}
+};
+#define NUM_LIMITS 5
+
+static void finish(int sig);
+
+int gotoxy(int x, int y)
+{
+ wmove(stdscr, y , x );
+ return 0;
+}
+
+void putch(int x, int y, int znak, int color)
+{
+ attron(COLOR_PAIR(color));
+ mvwaddch(stdscr, y, x, znak);
+ attroff(COLOR_PAIR(color));
+}
+void putwch(int x, int y, int znak, int color)
+{
+ attron(COLOR_PAIR(color));
+ mvwaddch(stdscr, y, x, znak);
+ attroff(COLOR_PAIR(color));
+}
+/*
+ enum TileClass
+ {
+ EMPTY,
+
+ WALL,
+ PILLAR,
+ FORTIFICATION,
+
+ STAIR_UP,
+ STAIR_DOWN,
+ STAIR_UPDOWN,
+
+ RAMP,
+
+ FLOOR,
+ TREE_DEAD,
+ TREE_OK,
+ SAPLING_DEAD,
+ SAPLING_OK,
+ SHRUB_DEAD,
+ SHRUB_OK,
+ BOULDER,
+ PEBBLES
+ };*/
+
+void puttile(int x, int y, int tiletype, int color)
+{
+ unsigned int znak;
+ switch(tileShape(tiletype))
+ {
+ case EMPTY:
+ znak = ' ';
+ break;
+ case PILLAR:
+ case WALL:
+ attron(COLOR_PAIR(color));
+ mvwaddwstr(stdscr, y, x, L"\u2593");
+ attroff(COLOR_PAIR(color));
+ //znak = ;
+ return;
+ case FORTIFICATION:
+ znak = '#';
+ break;
+ case STAIR_DOWN:
+ znak = '>';
+ break;
+ case STAIR_UP:
+ znak = '<';
+ break;
+ case STAIR_UPDOWN:
+ znak = '=';
+ break;
+ case RAMP:
+ attron(COLOR_PAIR(color));
+ mvwaddwstr(stdscr, y, x, L"\u25B2");
+ attroff(COLOR_PAIR(color));
+ return;
+ case RAMP_TOP:
+ attron(COLOR_PAIR(color));
+ mvwaddwstr(stdscr, y, x, L"\u25BC");
+ attroff(COLOR_PAIR(color));
+ return;
+ case FLOOR:
+ znak = '.';
+ break;
+ case TREE_DEAD:
+ case TREE_OK:
+ attron(COLOR_PAIR(color));
+ mvwaddwstr(stdscr, y, x, L"\u2663");
+ attroff(COLOR_PAIR(color));
+ return;
+ case SAPLING_DEAD:
+ case SAPLING_OK:
+ attron(COLOR_PAIR(color));
+ mvwaddwstr(stdscr, y, x, L"\u03C4");
+ attroff(COLOR_PAIR(color));
+ return;
+ case SHRUB_DEAD:
+ case SHRUB_OK:
+ attron(COLOR_PAIR(color));
+ mvwaddwstr(stdscr, y, x, L"\u2666");
+ attroff(COLOR_PAIR(color));
+ return;
+ case BOULDER:
+ case PEBBLES:
+ znak= '*';
+ break;
+ }
+ attron(COLOR_PAIR(color));
+ mvwaddch(stdscr, y, x, znak);
+ attroff(COLOR_PAIR(color));
+}
+
+int cprintf(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ int i = vwprintw(stdscr,fmt, ap);
+ va_end(ap);
+ return i;
+}
+
+void clrscr()
+{
+ wbkgd(stdscr, COLOR_PAIR(COLOR_BLACK));
+ wclear(stdscr);
+}
+
+/*
+ enum TileMaterial
+ {
+ AIR,
+ SOIL,
+ STONE,
+ FEATSTONE, // whatever it is
+ OBSIDIAN,
+
+ VEIN,
+ ICE,
+ GRASS,
+ GRASS2,
+ GRASS_DEAD,
+ GRASS_DRY,
+ DRIFTWOOD,
+ HFS,
+ MAGMA,
+ CAMPFIRE,
+ FIRE,
+ ASHES,
+ CONSTRUCTED
+ };
+*/
+int pickColor(int tiletype)
+{
+ switch(tileMaterial(tiletype))
+ {
+ case AIR:
+ return COLOR_BLACK;
+ case STONE:
+ case FEATSTONE:
+ case OBSIDIAN:
+ case CONSTRUCTED:
+ case ASHES:
+ default:
+ return COLOR_WHITE;
+ case SOIL:
+ case GRASS_DEAD:
+ case GRASS_DRY:
+ case DRIFTWOOD:
+ return COLOR_YELLOW;
+ case ICE:
+ return COLOR_CYAN;
+ case VEIN:
+ return COLOR_MAGENTA;
+ case GRASS:
+ case GRASS2:
+ return COLOR_GREEN;
+ case HFS:
+ case MAGMA:
+ case CAMPFIRE:
+ case FIRE:
+ return COLOR_RED;
+ }
+
+}
+
+/*
+address = absolute address of dump start
+length = length in bytes
+*/
+void hexdump (DFHack::Context* DF, uint32_t address, uint32_t length, int filenum)
+{
+ uint32_t reallength;
+ uint32_t lines;
+ lines = (length / 16) + 1;
+ reallength = lines * 16;
+ char *buf = new char[reallength];
+ ofstream myfile;
+
+ stringstream ss;
+ ss << "hexdump" << filenum << ".txt";
+ string name = ss.str();
+
+ myfile.open (name.c_str());
+
+ DF->ReadRaw(address, reallength, (uint8_t *) buf);
+ for (size_t i = 0; i < lines; i++)
+ {
+ // leading offset
+ myfile << "0x" << hex << setw(4) << i*16 << " ";
+ // groups
+ for(int j = 0; j < 4; j++)
+ {
+ // bytes
+ for(int k = 0; k < 4; k++)
+ {
+ int idx = i * 16 + j * 4 + k;
+
+ myfile << hex << setw(2) << int(static_cast<unsigned char>(buf[idx])) << " ";
+ }
+ myfile << " ";
+ }
+ myfile << endl;
+ }
+ delete buf;
+ myfile.close();
+}
+
+// p = attached process
+// blockaddr = address of the block
+// blockX, blockY = local map X and Y coords in 16x16 of the block
+// printX, printX = where to print stuff on the screen
+/*
+void do_features(Process* p, uint32_t blockaddr, uint32_t blockX, uint32_t blockY, int printX, int printY, vector<DFHack::t_matgloss> &stonetypes)
+{
+ memory_info* mem = p->getDescriptor();
+ uint32_t block_feature1 = mem->getOffset("map_data_feature_local");
+ uint32_t block_feature2 = mem->getOffset("map_data_feature_global");
+ uint32_t region_x_offset = mem->getAddress("region_x");
+ uint32_t region_y_offset = mem->getAddress("region_y");
+ uint32_t region_z_offset = mem->getAddress("region_z");
+ uint32_t feature1_start_ptr = mem->getAddress("local_feature_start_ptr");
+ int32_t regionX, regionY, regionZ;
+
+ // read position of the region inside DF world
+ p->readDWord (region_x_offset, (uint32_t &)regionX);
+ p->readDWord (region_y_offset, (uint32_t &)regionY);
+ p->readDWord (region_z_offset, (uint32_t &)regionZ);
+ // local feature present ?
+ int16_t idx = p->readWord(blockaddr + block_feature1);
+ if(idx != -1)
+ {
+ gotoxy(printX,printY);
+ cprintf("local feature present: %d", idx);
+
+ uint64_t block48_x = blockX / 3 + regionX;
+ gotoxy(printX,printY+1);
+ cprintf("blockX: %d, regionX: %d\nbigblock_x: %d\n", blockX, regionX, block48_x);
+
+ // region X coord offset by 8 big blocks (48x48 tiles)
+ uint16_t region_x_plus8 = ( block48_x + 8 ) / 16;
+ //uint16_t v12b = block48_x / 16;
+ //cout << "v12: " << v12 << " : " << v12b << endl;
+ // plain region Y coord
+ uint64_t region_y_local = (blockY / 3 + regionY) / 16;
+ gotoxy(printX,printY+2);
+ cprintf("region_y_local: %d\n", region_y_local);
+
+ // deref pointer to the humongo-structure
+ uint32_t base = p->readDWord(feature1_start_ptr);
+ gotoxy(printX,printY+3);
+ cprintf("region_y_local: 0x%x\n", base);
+
+ // this is just a few pointers to arrays of 16B (4 DWORD) structs
+ uint32_t array_elem = p->readDWord(base + (region_x_plus8 / 16) * 4);
+ gotoxy(printX,printY+4);
+ cprintf("array_elem: 0x%x\n", array_elem);
+
+ // second element of the struct is a pointer
+ uint32_t wtf = p->readDWord(array_elem + (16*(region_y_local/16)) + 4); // rounding!
+ gotoxy(printX,printY+5);
+ cprintf("wtf : 0x%x @ 0x%x\n", wtf, array_elem + (16*(region_y_local/16)) );
+ if(wtf)
+ {
+ //v14 = v10 + 24 * ((signed __int16)_tX + 16 * v9 % 16);
+ uint32_t feat_vector = wtf + 24 * (16 * (region_x_plus8 % 16) + (region_y_local % 16));
+ gotoxy(printX,printY+6);
+ cprintf("local feature vector: 0x%x\n", feat_vector);
+ DfVector<uint32_t> p_features(p, feat_vector);
+ gotoxy(printX,printY + 7);
+ cprintf("feature %d addr: 0x%x\n", idx, p_features[idx]);
+ if(idx >= p_features.size())
+ {
+ gotoxy(printX,printY + 8);
+ cprintf("ERROR, out of vector bounds.");
+ }
+ else
+ {
+ string name = p->readClassName(p->readDWord( p_features[idx] ));
+ bool discovered = p->readDWord( p_features[idx] + 4 );
+ gotoxy(printX,printY+8);
+ cprintf("%s", name.c_str());
+ if(discovered)
+ {
+ gotoxy(printX,printY+9);
+ cprintf("You've discovered it already!");
+ }
+
+ if(name == "feature_init_deep_special_tubest")
+ {
+ int32_t master_type = p->readWord( p_features[idx] + 0x30 );
+ int32_t slave_type = p->readDWord( p_features[idx] + 0x34 );
+ char * matname = "unknown";
+ // is stone?
+ if(master_type == 0)
+ {
+ matname = stonetypes[slave_type].id;
+ }
+ gotoxy(printX,printY+10);
+ cprintf("material %d/%d : %s", master_type, slave_type, matname);
+
+ }
+ }
+ }
+ }
+ // global feature present
+ idx = p->readWord(blockaddr + block_feature2);
+ if(idx != -1)
+ {
+ gotoxy(printX,printY+11);
+ cprintf( "global feature present: %d\n", idx);
+ DfVector<uint32_t> p_features (p,mem->getAddress("global_feature_vector"));
+ if(idx < p_features.size())
+ {
+ uint32_t feat_ptr = p->readDWord(p_features[idx] + mem->getOffset("global_feature_funcptr_"));
+ gotoxy(printX,printY+12);
+ cprintf("feature descriptor?: 0x%x\n", feat_ptr);
+ string name = p->readClassName(p->readDWord( feat_ptr));
+ bool discovered = p->readDWord( feat_ptr + 4 );
+ gotoxy(printX,printY+13);
+ cprintf("%s", name.c_str());
+ if(discovered)
+ {
+ gotoxy(printX,printY+14);
+ cout << "You've discovered it already!" << endl;
+ }
+ if(name == "feature_init_underworld_from_layerst")
+ {
+ int16_t master_type = p->readWord( feat_ptr + 0x34 );
+ int32_t slave_type = p->readDWord( feat_ptr + 0x38 );
+ char * matname = "unknown";
+ // is stone?
+ if(master_type == 0)
+ {
+ matname = stonetypes[slave_type].id;
+ }
+ gotoxy(printX,printY+15);
+ cprintf("material %d/%d : %s", master_type, slave_type, matname);
+ }
+ }
+ }
+}
+*/
+void do_features(Context* DF, mapblock40d * block, uint32_t blockX, uint32_t blockY, int printX, int printY, vector<DFHack::t_matgloss> &stonetypes)
+{
+ Maps * Maps = DF->getMaps();
+ Process * p = DF->getProcess();
+ if(!Maps)
+ return;
+ vector<DFHack::t_feature> global_features;
+ std::map <DFHack::DFCoord, std::vector<DFHack::t_feature *> > local_features;
+ if(!Maps->ReadGlobalFeatures(global_features))
+ return;
+ if(!Maps->ReadLocalFeatures(local_features))
+ return;
+
+ DFCoord pc(blockX, blockY);
+ int16_t idx =block->global_feature;
+ if(idx != -1)
+ {
+ t_feature &ftr =global_features[idx];
+ gotoxy(printX,printY);
+ cprintf( "global feature present: %d @ 0x%x\n", idx, ftr.origin);
+ if(ftr.discovered )
+ {
+ gotoxy(printX,printY+1);
+ cprintf("You've discovered it already!");
+ }
+
+ char * matname = (char *) "unknown";
+ // is stone?
+ if(ftr.main_material == 0)
+ {
+ matname = stonetypes[ftr.sub_material].id;
+ }
+ gotoxy(printX,printY+2);
+ cprintf("%d:%s, material %d/%d : %s", ftr.type, sa_feature(ftr.type), ftr.main_material, ftr.sub_material, matname);
+ {
+ gotoxy(printX,printY+3);
+ string name = p->readClassName(p->readDWord( ftr.origin ));
+ cprintf("%s", name.c_str());
+ }
+ }
+ idx =block->local_feature;
+ if(idx != -1)
+ {
+ vector <t_feature *> &ftrv = local_features[pc];
+ if(idx < ftrv.size())
+ {
+ t_feature & ftr = *ftrv[idx];
+ gotoxy(printX,printY + 4);
+ cprintf( "local feature present: %d @ 0x%x\n", idx, ftr.origin);
+ if(ftr.discovered )
+ {
+ gotoxy(printX,printY+ 5);
+ cprintf("You've discovered it already!");
+ }
+ char * matname = (char *) "unknown";
+ // is stone?
+ if(ftr.main_material == 0)
+ {
+ matname = stonetypes[ftr.sub_material].id;
+ }
+ gotoxy(printX,printY+6);
+ cprintf("%d:%s, material %d/%d : %s", ftr.type, sa_feature(ftr.type), ftr.main_material, ftr.sub_material, matname);
+
+ gotoxy(printX,printY+7);
+ string name = p->readClassName(p->readDWord( ftr.origin ));
+ cprintf("%s", name.c_str());
+ }
+ else
+ {
+ gotoxy(printX,printY + 4);
+ cprintf( "local feature vector overflow: %d", idx);
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ /* initialize your non-curses data structures here */
+
+ signal(SIGINT, finish); /* arrange interrupts to terminate */
+ setlocale(LC_ALL,"");
+ initscr(); /* initialize the curses library */
+ keypad(stdscr, TRUE); /* enable keyboard mapping */
+ nonl(); /* tell curses not to do NL->CR/NL on output */
+ cbreak(); /* take input chars one at a time, no wait for \n */
+ noecho(); /* don't echo input */
+ //nodelay(stdscr, true);
+
+ keypad(stdscr, TRUE);
+ scrollok(stdscr, TRUE);
+
+ if (has_colors())
+ {
+ start_color();
+
+ /*
+ * Simple color assignment, often all we need.
+ */
+ init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK);
+ init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
+ init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK);
+ init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK);
+ init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
+
+ init_color(COLOR_CYAN, 700, 700, 700); // lt grey
+ init_color(COLOR_MAGENTA, 500, 500, 500); // dk grey
+ init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
+ init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK);
+ init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
+ }
+
+ int x_max,y_max,z_max;
+ uint32_t x_max_a,y_max_a,z_max_a;
+ /*
+ uint16_t tiletypes[16][16];
+ DFHack::t_designation designations[16][16];
+ uint8_t regionoffsets[16];
+ */
+ map <int16_t, uint32_t> materials;
+ materials.clear();
+ mapblock40d blocks[3][3];
+ vector<DFHack::t_effect_df40d> effects;
+ vector< vector <uint16_t> > layerassign;
+ vector<t_vein> veinVector;
+ vector<t_frozenliquidvein> IceVeinVector;
+ vector<t_spattervein> splatter;
+ vector<t_grassvein> grass;
+ vector<t_worldconstruction> wconstructs;
+ t_temperatures b_temp1;
+ t_temperatures b_temp2;
+
+ DFHack::Materials * Mats = 0;
+ DFHack::Maps * Maps = 0;
+
+
+ DFHack::ContextManager DFMgr("Memory.xml");
+ DFHack::Context* DF;
+ try
+ {
+ pDF = DF = DFMgr.getSingleContext();
+ DF->Attach();
+ Maps = DF->getMaps();
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ finish(0);
+ }
+ bool hasmats = true;
+ try
+ {
+ Mats = DF->getMaterials();
+ }
+ catch (exception&)
+ {
+ hasmats = false;
+ }
+
+ // init the map
+ if(!Maps->Start())
+ {
+ error = "Can't find a map to look at.";
+ finish(0);
+ }
+
+ Maps->getSize(x_max_a,y_max_a,z_max_a);
+ x_max = x_max_a;
+ y_max = y_max_a;
+ z_max = z_max_a;
+
+ bool hasInorgMats = false;
+ bool hasPlantMats = false;
+ bool hasCreatureMats = false;
+
+ if(hasmats)
+ {
+ // get stone matgloss mapping
+ if(Mats->ReadInorganicMaterials())
+ {
+ hasInorgMats = true;
+ }
+ if(Mats->ReadCreatureTypes())
+ {
+ hasCreatureMats = true;
+ }
+ if(Mats->ReadOrganicMaterials())
+ {
+ hasPlantMats = true;
+ }
+ }
+/*
+ // get region geology
+ if(!DF.ReadGeology( layerassign ))
+ {
+ error = "Can't read local geology.";
+ pDF = 0;
+ finish(0);
+ }
+*/
+ // FIXME: could fail on small forts
+ int cursorX = x_max/2 - 1;
+ int cursorY = y_max/2 - 1;
+ int cursorZ = z_max/2 - 1;
+
+
+ bool dig = false;
+ bool dump = false;
+ bool digbit = false;
+ bool dotwiddle;
+ unsigned char twiddle = 0;
+ int vein = 0;
+ int filenum = 0;
+ bool dirtybit = false;
+ uint32_t blockaddr = 0;
+ uint32_t blockaddr2 = 0;
+ t_blockflags bflags;
+ bflags.whole = 0;
+ enum e_tempmode
+ {
+ TEMP_NO,
+ TEMP_1,
+ TEMP_2,
+ WATER_SALT,
+ WATER_STAGNANT
+ };
+ e_tempmode temperature = TEMP_NO;
+
+ // resume so we don't block DF while we wait for input
+ DF->Resume();
+
+ for (;;)
+ {
+ dig = false;
+ dump = false;
+ dotwiddle = false;
+ digbit = false;
+
+ int c = getch(); /* refresh, accept single keystroke of input */
+ flushinp();
+ clrscr();
+ /* process the command keystroke */
+ switch(c)
+ {
+ case KEY_DOWN:
+ cursorY ++;
+ break;
+ case KEY_UP:
+ cursorY --;
+ break;
+ case KEY_LEFT:
+ cursorX --;
+ break;
+ case KEY_RIGHT:
+ cursorX ++;
+ break;
+ case KEY_NPAGE:
+ cursorZ --;
+ break;
+ case KEY_PPAGE:
+ cursorZ ++;
+ break;
+ case '+':
+ vein ++;
+ break;
+ case 'd':
+ dig = true;
+ break;
+ case 'o':
+ dump = true;
+ break;
+ case '-':
+ vein --;
+ break;
+ case 'z':
+ digbit = true;
+ break;
+ case '/':
+ if(twiddle != 0) twiddle--;
+ break;
+ case '*':
+ twiddle++;
+ break;
+ case 't':
+ dotwiddle = true;
+ break;
+ case 'b':
+ temperature = TEMP_NO;
+ break;
+ case 'n':
+ temperature = TEMP_1;
+ break;
+ case 'm':
+ temperature = TEMP_2;
+ break;
+ case 'c':
+ temperature = WATER_SALT;
+ break;
+ case 'v':
+ temperature = WATER_STAGNANT;
+ break;
+ case 27: // escape key
+ DF->Detach();
+ return 0;
+ break;
+ default:
+ break;
+ }
+ cursorX = max(cursorX, 0);
+ cursorY = max(cursorY, 0);
+ cursorZ = max(cursorZ, 0);
+
+ cursorX = min(cursorX, x_max - 1);
+ cursorY = min(cursorY, y_max - 1);
+ cursorZ = min(cursorZ, z_max - 1);
+
+ if(twiddle > 31)
+ twiddle = 31;
+
+ // clear data before we suspend
+ memset(blocks,0,sizeof(blocks));
+ veinVector.clear();
+ IceVeinVector.clear();
+ effects.clear();
+ splatter.clear();
+ grass.clear();
+ dirtybit = 0;
+
+ // Supend, read/write data
+ DF->Suspend();
+ // restart cleared modules
+ Maps->Start();
+ if(hasmats)
+ {
+ Mats->Start();
+ if(hasInorgMats)
+ {
+ Mats->ReadInorganicMaterials();
+ }
+ if(hasPlantMats)
+ {
+ Mats->ReadOrganicMaterials();
+ }
+ if(hasCreatureMats)
+ {
+ Mats->ReadCreatureTypes();
+ }
+ }
+ /*
+ if(DF.InitReadEffects(effectnum))
+ {
+ for(uint32_t i = 0; i < effectnum;i++)
+ {
+ t_effect_df40d effect;
+ DF.ReadEffect(i,effect);
+ effects.push_back(effect);
+ }
+ }
+ */
+ for(int i = -1; i <= 1; i++) for(int j = -1; j <= 1; j++)
+ {
+ mapblock40d * Block = &blocks[i+1][j+1];
+ if(Maps->isValidBlock(cursorX+i,cursorY+j,cursorZ))
+ {
+ Maps->ReadBlock40d(cursorX+i,cursorY+j,cursorZ, Block);
+ // extra processing of the block in the middle
+ if(i == 0 && j == 0)
+ {
+ if(hasInorgMats)
+ do_features(DF, Block, cursorX, cursorY, 50,10, Mats->inorganic);
+ // read veins
+ Maps->ReadVeins(cursorX+i,cursorY+j,cursorZ,&veinVector,&IceVeinVector,&splatter,&grass, &wconstructs);
+
+ // get pointer to block
+ blockaddr = Maps->getBlockPtr(cursorX+i,cursorY+j,cursorZ);
+ blockaddr2 = Block->origin;
+
+ // dig all veins and trees
+ if(dig)
+ {
+ for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
+ {
+ int16_t tiletype = Block->tiletypes[x][y];
+ TileShape tc = tileShape(tiletype);
+ TileMaterial tm = tileMaterial(tiletype);
+ if( tc == WALL && tm == VEIN || tc == TREE_OK || tc == TREE_DEAD)
+ {
+ Block->designation[x][y].bits.dig = designation_default;
+ }
+ }
+ Maps->WriteDesignations(cursorX+i,cursorY+j,cursorZ, &(Block->designation));
+ }
+
+ // read temperature data
+ Maps->ReadTemperatures(cursorX+i,cursorY+j,cursorZ,&b_temp1, &b_temp2 );
+ if(dotwiddle)
+ {
+ bitset<32> bs ((int)Block->designation[0][0].whole);
+ bs.flip(twiddle);
+ Block->designation[0][0].whole = bs.to_ulong();
+ Maps->WriteDesignations(cursorX+i,cursorY+j,cursorZ, &(Block->designation));
+ dotwiddle = false;
+ }
+
+ // do a dump of the block data
+ if(dump)
+ {
+ hexdump(DF,blockaddr,0x1E00,filenum);
+ filenum++;
+ }
+ // read/write dirty bit of the block
+ Maps->ReadDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit);
+ Maps->ReadBlockFlags(cursorX+i,cursorY+j,cursorZ,bflags);
+ if(digbit)
+ {
+ dirtybit = !dirtybit;
+ Maps->WriteDirtyBit(cursorX+i,cursorY+j,cursorZ,dirtybit);
+ }
+ }
+ }
+ }
+ // Resume, print stuff to the terminal
+ DF->Resume();
+ for(int i = -1; i <= 1; i++) for(int j = -1; j <= 1; j++)
+ {
+ mapblock40d * Block = &blocks[i+1][j+1];
+ for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
+ {
+ int color = COLOR_BLACK;
+ color = pickColor(Block->tiletypes[x][y]);
+ /*
+ if(!Block->designation[x][y].bits.hidden)
+ {
+ puttile(x+(i+1)*16,y+(j+1)*16,Block->tiletypes[x][y], color);
+ }
+ else*/
+ {
+
+ attron(A_STANDOUT);
+ puttile(x+(i+1)*16,y+(j+1)*16,Block->tiletypes[x][y], color);
+ attroff(A_STANDOUT);
+
+ }
+ }
+ // print effects for the center tile
+ /*
+ if(i == 0 && j == 0)
+ {
+ for(uint zz = 0; zz < effects.size();zz++)
+ {
+ if(effects[zz].z == cursorZ && !effects[zz].isHidden)
+ {
+ // block coords to tile coords
+ uint16_t x = effects[zz].x - (cursorX * 16);
+ uint16_t y = effects[zz].y - (cursorY * 16);
+ if(x < 16 && y < 16)
+ {
+ putch(x + 16,y + 16,'@',COLOR_WHITE);
+ }
+ }
+ }
+ }
+ */
+ }
+ gotoxy(50,0);
+ cprintf("arrow keys, PGUP, PGDN = navigate");
+ gotoxy(50,1);
+ cprintf("+,- = switch vein");
+ gotoxy(50,2);
+ uint32_t mineralsize = veinVector.size();
+ uint32_t icesize = IceVeinVector.size();
+ uint32_t splattersize = splatter.size();
+ uint32_t grasssize = grass.size();
+ uint32_t wconstrsize = wconstructs.size();
+ uint32_t totalVeinSize = mineralsize+ icesize + splattersize + grasssize + wconstrsize;
+ if(vein == totalVeinSize) vein = totalVeinSize - 1;
+ if(vein < -1) vein = -1;
+ cprintf("X %d/%d, Y %d/%d, Z %d/%d. Vein %d of %d",cursorX+1,x_max,cursorY+1,y_max,cursorZ,z_max,vein+1,totalVeinSize);
+ if(!veinVector.empty() || !IceVeinVector.empty() || !splatter.empty() || !grass.empty() || !wconstructs.empty())
+ {
+ if(vein != -1 && vein < totalVeinSize)
+ {
+ uint32_t realvein = 0;
+ if(vein < mineralsize)
+ {
+ realvein = vein;
+ //iterate through vein rows
+ for(uint32_t j = 0;j<16;j++)
+ {
+ //iterate through the bits
+ for (uint32_t k = 0; k< 16;k++)
+ {
+ // and the bit array with a one-bit mask, check if the bit is set
+ bool set = !!(((1 << k) & veinVector[realvein].assignment[j]) >> k);
+ if(set)
+ {
+ putch(k+16,j+16,'$',COLOR_RED);
+ }
+ }
+ }
+ if(hasInorgMats)
+ {
+ gotoxy(50,3);
+ cprintf("Mineral: %s",Mats->inorganic[veinVector[vein].type].id);
+ }
+ }
+ else if (vein < mineralsize + icesize)
+ {
+ realvein = vein - mineralsize;
+ t_frozenliquidvein &frozen = IceVeinVector[realvein];
+ for(uint32_t i = 0;i<16;i++)
+ {
+ for (uint32_t j = 0; j< 16;j++)
+ {
+ int color = COLOR_BLACK;
+ int tile = frozen.tiles[i][j];
+ color = pickColor(tile);
+
+ attron(A_STANDOUT);
+ puttile(i+16,j+16,tile, color);
+ attroff(A_STANDOUT);
+ }
+ }
+ gotoxy(50,3);
+ cprintf("ICE");
+ }
+ else if(vein < mineralsize + icesize + splattersize)
+ {
+ realvein = vein - mineralsize - icesize;
+ for(uint32_t yyy = 0; yyy < 16; yyy++)
+ {
+ for(uint32_t xxx = 0; xxx < 16; xxx++)
+ {
+ uint8_t intensity = splatter[realvein].intensity[xxx][yyy];
+ if(intensity)
+ {
+ attron(A_STANDOUT);
+ putch(xxx+16,yyy+16,'*', COLOR_RED);
+ attroff(A_STANDOUT);
+ }
+ }
+ }
+ if(hasCreatureMats)
+ {
+ gotoxy(50,3);
+ cprintf("Spatter: %s",PrintSplatterType(splatter[realvein].mat1,splatter[realvein].mat2,Mats->race).c_str());
+ }
+ }
+ else if(vein < mineralsize + icesize + splattersize + grasssize)
+ {
+ realvein = vein - mineralsize - icesize - splattersize;
+ t_grassvein & grassy =grass[realvein];
+ for(uint32_t yyy = 0; yyy < 16; yyy++)
+ {
+ for(uint32_t xxx = 0; xxx < 16; xxx++)
+ {
+ uint8_t intensity = grassy.intensity[xxx][yyy];
+ if(intensity)
+ {
+ attron(A_STANDOUT);
+ putch(xxx+16,yyy+16,'X', COLOR_RED);
+ attroff(A_STANDOUT);
+ }
+ }
+ }
+ if(hasPlantMats)
+ {
+ gotoxy(50,3);
+ cprintf("Grass: 0x%x, %s",grassy.address_of, Mats->organic[grassy.material].id);
+ }
+ }
+ else
+ {
+ realvein = vein - mineralsize - icesize - splattersize - grasssize;
+ t_worldconstruction & wconstr=wconstructs[realvein];
+ for(uint32_t j = 0; j < 16; j++)
+ {
+ for(uint32_t k = 0; k < 16; k++)
+ {
+ bool set = !!(((1 << k) & wconstr.assignment[j]) >> k);
+ if(set)
+ {
+ putch(k+16,j+16,'$',COLOR_RED);
+ }
+ }
+ }
+ if(hasInorgMats)
+ {
+ gotoxy(50,3);
+ cprintf("Road: 0x%x, %d - %s", wconstr.address_of, wconstr.material,Mats->inorganic[wconstr.material].id);
+ }
+ }
+ }
+ }
+ mapblock40d * Block = &blocks[1][1];
+ t_temperatures * ourtemp;
+ if(temperature == TEMP_NO)
+ {
+ for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
+ {
+ if((Block->occupancy[x][y].whole & (1 << twiddle)))
+ {
+ putch(x + 16,y + 16,'@',COLOR_WHITE);
+ }
+ }
+ }
+ else if(temperature == WATER_SALT)
+ {
+ for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
+ {
+ if(Block->designation[x][y].bits.water_salt)
+ {
+ putch(x + 16,y + 16,'@',COLOR_WHITE);
+ }
+ }
+ gotoxy (50,8);
+ cprintf ("Salt water");
+ }
+ else if(temperature == WATER_STAGNANT)
+ {
+ for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
+ {
+ if(Block->designation[x][y].bits.water_stagnant)
+ {
+ putch(x + 16,y + 16,'@',COLOR_WHITE);
+ }
+ }
+ gotoxy (50,8);
+ cprintf ("Stagnant water");
+ }
+ else
+ {
+ if(temperature == TEMP_1)
+ ourtemp = &b_temp1;
+ else if(temperature == TEMP_2)
+ ourtemp = &b_temp2;
+ uint64_t sum = 0;
+ uint16_t min, max;
+ min = max = (*ourtemp)[0][0];
+ for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
+ {
+ uint16_t temp = (*ourtemp)[x][y];
+ if(temp < min) min = temp;
+ if(temp > max) max = temp;
+ sum += temp;
+ }
+ uint64_t average = sum/256;
+ gotoxy (50,8);
+ if(temperature == TEMP_1)
+ cprintf ("temperature1 [°U] (min,avg,max): %d,%d,%d", min, average, max);
+ else if(temperature == TEMP_2)
+ cprintf ("temperature2 [°U] (min,avg,max): %d,%d,%d", min, average, max);
+
+ for(int x = 0; x < 16; x++) for(int y = 0; y < 16; y++)
+ {
+ int32_t temper = (int32_t) (*ourtemp)[x][y];
+ temper -= average;
+ uint32_t abs_temp = abs(temper);
+ int color;
+ unsigned char character = ' ';
+ if(temper >= 0)
+ color = COLOR_RED;
+ else
+ color = COLOR_BLUE;
+
+ for(int i = 0; i < NUM_LIMITS; i++)
+ {
+ if(temp_limits[i].limit < abs_temp)
+ character = temp_limits[i].character;
+ else break;
+ }
+ if( character != ' ')
+ {
+ putch(x + 16,y + 16,character,color);
+ }
+ }
+ }
+ gotoxy (50,4);
+ cprintf("block address 0x%x, flags 0x%08x",blockaddr, bflags.whole);
+ gotoxy (50,5);
+ cprintf("dirty bit: %d, twiddle: %d",dirtybit,twiddle);
+ gotoxy (50,6);
+ cprintf ("d - dig veins, o - dump map block, z - toggle dirty bit");
+ gotoxy (50,7);
+ cprintf ("b - no temperature, n - temperature 1, m - temperature 2");
+ wrefresh(stdscr);
+ }
+ pDF = 0;
+ finish(0);
+}
+
+static void finish(int sig)
+{
+ // ugly
+ if(pDF)
+ {
+ pDF->ForceResume();
+ pDF->Detach();
+ }
+ endwin();
+ if(!error.empty())
+ {
+ cerr << error << endl;
+ }
+ exit(0);
+}
diff --git a/needs_porting/veinswap.cpp b/needs_porting/veinswap.cpp
new file mode 100644
index 00000000..66838610
--- /dev/null
+++ b/needs_porting/veinswap.cpp
@@ -0,0 +1,229 @@
+#include <stdlib.h>
+#include <iostream>
+#include <vector>
+#include <map>
+#include <cstdlib>
+#include <limits>
+using namespace std;
+
+#include <conio.h>
+
+#include <DFHack.h>
+#include <DFTileTypes.h>
+#include <extra/MapExtras.h>
+
+
+//Globals
+DFHack::Context *DF;
+DFHack::Maps *maps;
+DFHack::Gui *gui;
+DFHack::Materials *mats;
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+int main (void)
+{
+ int32_t
+ cx,cy,z, //cursor coords
+ tx,ty, //tile coords within block
+ bx,by; //block coords
+ //DFHack::designations40d designations;
+ //DFHack::tiletypes40d tiles;
+ //DFHack::t_temperatures temp1,temp2;
+ uint32_t x_max,y_max,z_max;
+
+ DFHack::ContextManager DFMgr("Memory.xml");
+ try
+ {
+
+ DF=DFMgr.getSingleContext();
+ DF->Attach();
+ maps = DF->getMaps();
+ maps->Start();
+ maps->getSize(x_max,y_max,z_max);
+ gui = DF->getGui();
+ mats = DF->getMaterials();
+ mats->ReadAllMaterials();
+ if(!mats->ReadInorganicMaterials())
+ {
+ printf("Error: Could not load materials!\n");
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+ }
+ catch (exception& e)
+ {
+ cerr << e.what() << endl;
+ #ifndef LINUX_BUILD
+ cin.ignore();
+ #endif
+ return 1;
+ }
+
+
+
+ bool end = false;
+ cout << "Welcome to the Vein Swap tool.\nType 'help' or ? for a list of available commands, 'q' to quit" << endl;
+ string mode = "";
+ string command = "";
+
+ while(!end)
+ {
+ DF->Resume();
+
+ cout << endl << ":";
+ getline(cin, command);
+ int ch = command[0];
+ if(command.length()<=0) ch=0;
+ if( ((int)command.find("help")) >=0 ) ch='?'; //under windows, find was casting unsigned!
+
+ //Process user command.
+ switch(ch)
+ {
+ case 'h':
+ case '?':
+ cout << "" << endl
+ << "Commands:" << endl
+ << "p - print vein at cursor" << endl
+ << "m - print all inorganic material types" << endl
+ << "r MatTo - replace the vein at cursor with MatTo" << endl
+ << "R Percent MatFrom MatTo - replace Percent of MatFrom veins with MatTo veins" << endl
+ << "help OR ? - print this list of commands" << endl
+ << "q - quit" << endl
+ << endl
+ << "Usage:\n\t" << endl;
+ break;
+ case 'p':
+ case 10:
+ case 13:
+ case 0:
+ {
+ //Print current cursor
+ mats->ReadAllMaterials();
+
+ if(!maps->Start())
+ {
+ cout << "Can't see any DF map loaded." << endl;
+ break;
+ }
+ if(!gui->getCursorCoords(cx,cy,z))
+ {
+ cout << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl;
+ break;
+ }
+ //cout << "cursor coords: " << x << "/" << y << "/" << z << endl;
+ tx=cx%16; ty=cy%16;
+ bx=cx/16; by=cy/16;
+ DFHack::DFCoord xyz(cx,cy,z);
+
+ printf("Cursor[%d,%d,%d] Block(%d,%d) Tile(%d,%d)\n", cx,cy,z, bx,by, tx,ty );
+
+ if(!maps->isValidBlock(bx,by,z))
+ {
+ cout << "Invalid block." << endl;
+ break;
+ }
+
+ vector<DFHack::t_vein> veinVector;
+ int found=0;
+ maps->ReadVeins(bx,by,z,&veinVector);
+ printf("Veins in block (%d):\n",veinVector.size());
+ for(unsigned long i=0;i<veinVector.size();++i){
+ found = veinVector[i].getassignment(tx,ty);
+ printf("\t%c %4d %s\n",
+ (found ? '*' : ' '),
+ veinVector[i].type,
+ mats->inorganic[veinVector[i].type].id
+ );
+ }
+ printf("Cursor is%s in vein.\n", (found?"":" not") );
+
+ maps->Finish();
+ DF->Resume();
+ }
+ break;
+ case 'v':
+ break;
+ case 'm':
+ break;
+ case 'R':
+ break;
+ case 'q':
+ end = true;
+ cout << "Bye!" << endl;
+ break;
+ case 'r':
+ DF->Suspend();
+ do{
+ //Process parameters
+ long matto = atol( command.c_str()+1 );
+ if( matto < 0 || matto >= (long)mats->inorganic.size() ){
+ cout << "Invalid material: " << matto << endl;
+ break;
+ }
+
+ if(!maps->Start())
+ {
+ cout << "Can't see any DF map loaded." << endl;
+ break;
+ }
+ if(!gui->getCursorCoords(cx,cy,z))
+ {
+ cout << "Can't get cursor coords! Make sure you have a cursor active in DF." << endl;
+ break;
+ }
+ tx=cx%16; ty=cy%16;
+ bx=cx/16; by=cy/16;
+ printf("Cursor[%d,%d,%d] Block(%d,%d) Tile(%d,%d)\n", cx,cy,z, bx,by, tx,ty );
+
+ if(!maps->isValidBlock(bx,by,z))
+ {
+ cout << "Invalid block." << endl;
+ break;
+ }
+
+ //MapExtras::MapCache MC(maps);
+ //MapExtras::Block B(maps,DFHack::DFCoord(bx,by,z));
+
+ vector<DFHack::t_vein> veinVector;
+ int v=-1; //the vector pointed to by the cursor
+
+ mats->ReadAllMaterials();
+
+ maps->ReadVeins(bx,by,z,&veinVector);
+ for(unsigned long i=0 ; v<0 && i<veinVector.size() ; ++i){
+ if( veinVector[i].getassignment(tx,ty) )
+ v=i;
+ }
+ printf("Replacing %d %s with %d %s...\n", veinVector[v].type, mats->inorganic[veinVector[v].type].id, matto, mats->inorganic[matto].id );
+printf("%X\n",veinVector[v].vtable);
+ vector<DFHack::t_vein> veinTable;
+
+ veinVector[v].type = matto;
+ maps->WriteVein( &veinVector[v] );
+
+
+ maps->Finish();
+
+ cout << endl << "Finished." << endl;
+ }while(0);
+ DF->Resume();
+ break;
+ default:
+ cout << "Unknown command: " << command << endl;
+ }//end switch
+
+ }//end while
+
+ DF->Detach();
+ //#ifndef LINUX_BUILD
+ //cout << "Done. Press any key to continue" << endl;
+ //cin.ignore();
+ //#endif
+ return 0;
+}