diff --git a/NEWS b/NEWS index b1ce46815..84c54e1cc 100644 --- a/NEWS +++ b/NEWS @@ -1,11 +1,17 @@ DFHack Future Internals Fixes + plugins/dwarfmonitor: correct date display (month index, separator) + scripts/putontable: added to the readme New Plugins New Scripts gui/stockpiles: an in-game interface for saving and loading stockpile settings files. + position: Reports the current date, time, month, and season, plus + some location info. Port/update of position.py + hfs-pit: Digs a hole to hell under the cursor. Replaces needs_porting/hellhole.cpp Misc Improvements + further work on needs_porting DFHack 0.40.19-r1 Internals: diff --git a/Readme.rst b/Readme.rst index aa44be116..0c1586cb6 100644 --- a/Readme.rst +++ b/Readme.rst @@ -2344,6 +2344,20 @@ For example, to grow 40 plump helmet spawn:: growcrops plump 40 +hfs-pit +======= +Creates a pit to the underworld at the cursor. + +Takes three arguments: diameter of the pit in tiles, whether to wall off +the pit, and whether to insert stairs. If no arguments are given, the default +is "hfs-pit 1 0 0", ie single-tile wide with no walls or stairs. + + hfs-pit 4 0 1 + hfs-pit 2 1 0 + +First example is a four-across pit with stairs but no walls; second is a +two-across pit with stairs but no walls. + lever ===== Allow manipulation of in-game levers from the dfhack console. @@ -2414,6 +2428,16 @@ Example:: multicmd locate-ore iron ; digv +position +======== +Reports the current time: date, clock time, month, and season. Also reports +location: z-level, cursor position, window size, and mouse location. + +putontable +========== +Makes item appear on the table, like in adventure mode shops. Arguments: '-a' +or '--all' for all items. + quicksave ========= diff --git a/needs_porting/SegmentedFinder.h b/needs_porting/SegmentedFinder.h deleted file mode 100644 index b3fe5aecf..000000000 --- a/needs_porting/SegmentedFinder.h +++ /dev/null @@ -1,543 +0,0 @@ -#ifndef SEGMENTED_FINDER_H -#define SEGMENTED_FINDER_H -#include -#include -#include - -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 - bool Find (needleType needle, const uint8_t increment , vector &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 - bool Filter (needleType needle, vector &found, vector &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 & 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 - bool Find (const needleType needle, const uint8_t increment, vector &found, comparator oper) - { - found.clear(); - for(size_t i = 0; i < segments.size(); i++) - { - segments[i]->Find(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(needle, oper, start, length); - } - return 0; - } - - template - bool Filter (const needleType needle, vector &found, comparator oper) - { - vector newfound; - for(size_t i = 0; i < segments.size(); i++) - { - segments[i]->Filter(needle, found, newfound, oper); - } - found.clear(); - found = newfound; - return !(found.empty()); - } - - template - bool Incremental (needleType needle, const uint8_t increment ,vector &found, comparator oper) - { - if(found.empty()) - { - return Find (needle,increment,found,oper); - } - else - { - return Filter (needle,found,oper); - } - } - - template - 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 - T Read(uint64_t address) - { - return *Translate(address); - } - - template - bool Read(uint64_t address, T& target) - { - T * test = Translate(address); - if(test) - { - target = *test; - return true; - } - return false; - } - private: - DFHack::Context * _DF; - vector segments; -}; - -template -bool equalityP (SegmentedFinder* s, T *x, T y) -{ - return (*x) == y; -} - -struct vecTriplet -{ - uint32_t start; - uint32_t finish; - uint32_t alloc_finish; -}; - -template -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(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(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(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(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(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(*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/_notes.txt b/needs_porting/_notes.txt index 041e0932d..cdd364d12 100644 --- a/needs_porting/_notes.txt +++ b/needs_porting/_notes.txt @@ -1,30 +1,9 @@ -Notes by PeridexisErrant, on the needs_porting scripts and plugins: - -I deleted: - attachtest.py obsolete - digger.cpp less useful than digger2, replaced by autochop - digger2.cpp replaced by digfort - dfstatus.cpp replaced by dfstatus.lua - drawtile.cpp replaced by tiletypes - fix-3708.cpp obsolete, bug fixed in vanilla - lair.cpp replaced by lair - reveal.py replaced by reveal - treedump.py replaced by prospect & autochop - veinlook.cpp replaced by prospect - veinswap.cpp replaced by changevein - - -To investigate further: - creaturemanager.cpp modify skills and labors of creatures, kill creatures, etc; impressive but I suspect most functions implemented elsewhere - digpattern.cpp allows multi-Z designations. Obsolete, or is there more here? - incrementalsearch.cpp linux-only memory stuff; unqualified to judge - SegementedFinder.h more memory stuff - - -To port: - copypaste.cpp high value target - a proof of concept plugin to allow copy-pasting in DF; does both terrain and buildings/constructions - dfbauxtite.cpp changes material of mechanisms to bauxtite (ie magma-safe) - hellhole.cpp instantly creates a hole to the HFS - hotkeynotedump.py outputs a list of hotkeys and names; most useful before keybindings were possible. Trival to port but low value. - itemdesignator.cpp mostly replaced by Falconne's enhanced stocks, but could port the interesting 'set fire to things' function - position.py outputs very detailed time& place info +TODO: + copypaste.cpp + high value target - a proof of concept plugin to allow copy-pasting in DF; does both terrain and buildings/constructions + creaturemanager.cpp + modify skills and labors of creatures, kill creatures, etc; impressive but I suspect most functions implemented elsewhere + +In progress: + hotkey-notes.lua + prints list of hotkeys with name and jump position diff --git a/needs_porting/dfbauxite.cpp b/needs_porting/dfbauxite.cpp deleted file mode 100644 index 3a2fdb978..000000000 --- a/needs_porting/dfbauxite.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* -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 -#include -#include -#include -#include -#include -#include -using namespace std; - - -#include -#include -#include -#include -#include -#include -#include -using namespace DFHack; - - -int main () -{ - DFHack::Process *proc; - DFHack::memory_info *meminfo; - DFHack::DfVector *items_vector; - DFHack::t_item_df40d item_40d; - DFHack::t_matglossPair item_40d_material; - vector 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 (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/digpattern.cpp b/needs_porting/digpattern.cpp deleted file mode 100644 index 90d960ba1..000000000 --- a/needs_porting/digpattern.cpp +++ /dev/null @@ -1,259 +0,0 @@ -#include -#include // for memset -#include -#include -#include -#include -#include -#include -using namespace std; - -#include -#include -using namespace MapExtras; -//#include - -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 : Dig upwards times (default 5)" << endl - << "-d : Dig downwards 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/hellhole.cpp b/needs_porting/hellhole.cpp deleted file mode 100644 index a38d14cbf..000000000 --- a/needs_porting/hellhole.cpp +++ /dev/null @@ -1,1281 +0,0 @@ -// Burn a hole straight to hell! - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -using namespace std; - -#include -#include -#include -using namespace DFHack; - - -#ifdef LINUX_BUILD -#include -void waitmsec (int delay) -{ - usleep(delay); -} -#else -#include -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=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 global_features, - std::map > 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 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 > 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/hotkey-notes.lua b/needs_porting/hotkey-notes.lua new file mode 100644 index 000000000..a84506512 --- /dev/null +++ b/needs_porting/hotkey-notes.lua @@ -0,0 +1,40 @@ +-- prints info on assigned hotkeys to the console + +local hotkeys = {'F1 ', 'F2 ', 'F3 ', 'F4 ', 'F5 ', 'F6 ', + 'F7 ', 'F8 ', 'F9 ', 'F10', 'F11', 'F12'} + +for i=1, #hotkeys do + local hk = hotkeys[i] + hk = {id=hk} + -- PLACEHOLDER PROPERTIES ONLY! + hk.name = '_name' + hk.x = df.global.window_x + hk.y = df.global.window_y + hk.z = df.global.window_z + + print(hk.id..' '..hk.name..' X= '..hk.x..', Y= '..hk.y..', Z= '..hk.z) +end + +--[[ +# the (very) old Python version... +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() +]]-- diff --git a/needs_porting/hotkeynotedump.py b/needs_porting/hotkeynotedump.py deleted file mode 100644 index 77cd0b811..000000000 --- a/needs_porting/hotkeynotedump.py +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index e70e09527..000000000 --- a/needs_porting/incrementalsearch.cpp +++ /dev/null @@ -1,1064 +0,0 @@ -// this is an incremental search tool. It only works on Linux. -// here be dragons... and ugly code :P -#include -#include -#include -#include -#include -#include -#include -#include -#include -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 -#endif - -#include -#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 & selected_ranges) -{ - vector 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:" <>"; - 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 & selected_ranges, - vector & ranges) -{ - DFHack::Process * p = DF->getProcess(); - - vector 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 -bool Incremental ( vector &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 & selected_ranges) -{ - vector 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 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(test1,alignment,found, equalityP); - break; - case 2: - sf.Incremental(test1,alignment,found, equalityP); - break; - case 4: - sf.Incremental(test1,alignment,found, equalityP); - break; - } - DF->Detach(); - } -} - -void FindVectorByLength(DFHack::ContextManager & DFMgr, - vector & selected_ranges ) -{ - vector ranges; - - int element_size; - do - { - getNumber("Select searched vector item size in bytes",element_size, 4); - } while (element_size < 1); - - uint32_t length; - vector 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(0,4,found,vectorAll); - //sf.Filter(length * element_size,found,vectorLength); - sf.Incremental(length * element_size, 4 , found, vectorLength); - DF->Detach(); - } -} - -void FindVectorByObjectRawname(DFHack::ContextManager & DFMgr, - vector & selected_ranges) -{ - vector ranges; - vector 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(0,4,found, vectorAll); - sf.Filter(select.c_str(),found, vectorString); - DF->Detach(); - } -} - -void FindVectorByFirstObjectRawname(DFHack::ContextManager & DFMgr, - vector & selected_ranges) -{ - vector ranges; - vector 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(0,4,found, vectorAll); - sf.Filter(select.c_str(),found, vectorStringFirst); - DF->Detach(); - } -} - -struct VectorSizeFunctor : public binary_function -{ - VectorSizeFunctor(SegmentedFinder & sf):sf_(sf){} - bool operator()( uint64_t lhs, uint64_t rhs) - { - vecTriplet* left = sf_.Translate(lhs); - vecTriplet* right = sf_.Translate(rhs); - return ((left->finish - left->start) < (right->finish - right->start)); - } - SegmentedFinder & sf_; -}; - -void FindVectorByBounds(DFHack::ContextManager & DFMgr, - vector & selected_ranges) -{ - vector ranges; - vector 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(0,4,found, vectorAll); - sf.Filter(select,found, vectorAddrWithin); - // sort by size of vector - std::sort(found.begin(), found.end(), VectorSizeFunctor(sf)); - DF->Detach(); - } -} - -void FindPtrVectorsByObjectAddress(DFHack::ContextManager & DFMgr, - vector & selected_ranges) -{ - vector ranges; - vector 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(0,4,found, vectorAll); - sf.Filter(select,found, vectorOfPtrWithin); - DF->Detach(); - } -} - -void FindStrBufs(DFHack::ContextManager & DFMgr, - vector & selected_ranges) -{ - vector ranges; - vector 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 & selected_ranges) -{ - vector ranges; - vector 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 & selected_ranges) -{ - vector ranges; - vector 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 &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 & selected_ranges) -{ - vector found; - vector 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(x); - select.insert(y); - select.insert(z); - } - else - { - select.insert(x); - select.insert(y); - select.insert(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 & selected_ranges) -{ - vector ranges; - - int element_size; - do - { - getNumber("Set search granularity",element_size, 4); - } while (element_size < 1); - - vector found; - set 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(select,element_size,found, equalityP); - 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 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 & selected_ranges) -{ - vector ranges; - int element_size; - do - { - getNumber("Set search granularity",element_size, 4); - } while (element_size < 1); - - vector found; - set 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(select,element_size,found, equalityP); - 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 &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 &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(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(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 & selected_ranges) -{ - vector ranges; - vector allVectors; - vector filtVectors; - vector to_filter; - - readRanges(DF, selected_ranges, ranges); - - cout << "stealing memory..." << endl; - SegmentedFinder sf(ranges, DF); - cout << "looking for vectors..." << endl; - sf.Find(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(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("ABBEY",to_filter, vectorStringFirst); - uint64_t lang_addr = to_filter[0]; - - // find dwarven language word table - to_filter = filtVectors; - sf.Filter("kulet",to_filter, vectorStringFirst); - kulet_vector = to_filter[0]; - - // find vector of languages - to_filter = filtVectors; - sf.Filter("DWARF",to_filter, vectorStringFirst); - - // verify - for(size_t i = 0; i < to_filter.size(); i++) - { - vecTriplet * vec = sf.Translate(to_filter[i]); - if(((vec->finish - vec->start) / 4) == 4) // verified - { - DWARF_vector = to_filter[i]; - DWARF_object = sf.Read(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(257 * 4,4,to_filter,vectorLength); - sf.Filter("IRON",to_filter, vectorString); - sf.Filter("ONYX",to_filter, vectorString); - sf.Filter("RAW_ADAMANTINE",to_filter, vectorString); - sf.Filter("BLOODSTONE",to_filter, vectorString); - printFound(to_filter,"inorganics"); - - // organics vector - to_filter = filtVectors; - sf.Filter(52 * 4,to_filter,vectorLength); - sf.Filter("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst); - printFound(to_filter,"organics"); - - // new organics vector - to_filter = filtVectors; - sf.Filter("MUSHROOM_HELMET_PLUMP",to_filter, vectorString); - sf.Filter("MEADOW-GRASS",to_filter, vectorString); - sf.Filter("TUNNEL_TUBE",to_filter, vectorString); - sf.Filter("WEED_BLADE",to_filter, vectorString); - sf.Filter("EYEBALL",to_filter, vectorString); - printFound(to_filter,"organics 31.19"); - - // tree vector - to_filter = filtVectors; - sf.Filter(31 * 4,to_filter,vectorLength); - sf.Filter("MANGROVE",to_filter, vectorStringFirst); - printFound(to_filter,"trees"); - - // plant vector - to_filter = filtVectors; - sf.Filter(21 * 4,to_filter,vectorLength); - sf.Filter("MUSHROOM_HELMET_PLUMP",to_filter, vectorStringFirst); - printFound(to_filter,"plants"); - - // color descriptors - //AMBER, 112 - to_filter = filtVectors; - sf.Filter(112 * 4,to_filter,vectorLength); - sf.Filter("AMBER",to_filter, vectorStringFirst); - printFound(to_filter,"color descriptors"); - if(!to_filter.empty()) - { - uint64_t vec = to_filter[0]; - vecTriplet *vtColors = sf.Translate(vec); - uint32_t colorObj = sf.Read(vtColors->start); - cout << "Amber color:" << hex << "0x" << colorObj << endl; - // TODO: find string 'amber', the floats - } - - // all descriptors - //AMBER, 338 - to_filter = filtVectors; - sf.Filter(338 * 4,to_filter,vectorLength); - sf.Filter("AMBER",to_filter, vectorStringFirst); - printFound(to_filter,"all descriptors"); - - // creature type - //ELEPHANT, ?? (demons abound) - to_filter = filtVectors; - //sf.Find(338 * 4,4,to_filter,vectorLength); - sf.Filter("ELEPHANT",to_filter, vectorString); - sf.Filter("CAT",to_filter, vectorString); - sf.Filter("DWARF",to_filter, vectorString); - sf.Filter("WAMBLER_FLUFFY",to_filter, vectorString); - sf.Filter("TOAD",to_filter, vectorString); - sf.Filter("DEMON_1",to_filter, vectorString); - - vector toad_first = to_filter; - vector elephant_first = to_filter; - sf.Filter("TOAD",toad_first, vectorStringFirst); - sf.Filter("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(to_use); - uint32_t elephant = sf.Read(vtCretypes->start); - uint64_t Eoffset; - cout << "Elephant: 0x" << hex << elephant << endl; - cout << "Elephant: rawname = 0x0" << endl; - uint8_t letter_E = 'E'; - Eoffset = sf.FindInRange (letter_E,equalityP, elephant, 0x300 ); - if(Eoffset) - { - cout << "Elephant: big E = 0x" << hex << Eoffset - elephant << endl; - } - Eoffset = sf.FindInRange ("FEMALE",vectorStringFirst, elephant, 0x300 ); - if(Eoffset) - { - cout << "Elephant: caste vector = 0x" << hex << Eoffset - elephant << endl; - } - Eoffset = sf.FindInRange ("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 (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(to_use); - uint32_t toad = sf.Read(vtCretypes->start); - uint64_t Eoffset; - cout << "Toad: 0x" << hex << toad << endl; - cout << "Toad: rawname = 0x0" << endl; - Eoffset = sf.FindInRange (0xF9,equalityP, toad, 0x300 ); - if(Eoffset) - { - cout << "Toad: character (not reliable) = 0x" << hex << Eoffset - toad << endl; - } - Eoffset = sf.FindInRange ("FEMALE",vectorStringFirst, toad, 0x300 ); - if(Eoffset) - { - cout << "Toad: caste vector = 0x" << hex << Eoffset - toad << endl; - } - Eoffset = sf.FindInRange ("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 (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 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 deleted file mode 100644 index 63b41eb72..000000000 --- a/needs_porting/itemdesignator.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// Item designator - -#include -#include -#include -#include -#include -using namespace std; - -#include -#include -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 p_items (p, vector_addr); - uint32_t numItems = p_items.size(); - - map< string, map > > itemmap; - map< string, map< string, vector< dfh_item > > >::iterator it1; - int failedItems = 0; - map 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 >::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/position.py b/needs_porting/position.py deleted file mode 100644 index 122440589..000000000 --- a/needs_porting/position.py +++ /dev/null @@ -1,71 +0,0 @@ -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/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 8a90b3378..98e593542 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -1722,10 +1722,10 @@ struct dwarf_monitor_hook : public df::viewscreen_dwarfmodest int y = 0; ostringstream date_str; - auto month = World::ReadCurrentMonth(); + auto month = World::ReadCurrentMonth() + 1; auto day = World::ReadCurrentDay(); - date_str << "Date:" << World::ReadCurrentYear() << "/" << - ((month < 10) ? "0" : "") << month << "/" << + date_str << "Date:" << World::ReadCurrentYear() << "-" << + ((month < 10) ? "0" : "") << month << "-" << ((day < 10) ? "0" : "") << day; OutputString(COLOR_GREY, x, y, date_str.str()); diff --git a/scripts/hfs-pit.lua b/scripts/hfs-pit.lua new file mode 100644 index 000000000..9592d0a31 --- /dev/null +++ b/scripts/hfs-pit.lua @@ -0,0 +1,88 @@ +-- Creates a pit under the target leading straight to the Underworld. Type '?' for help. +-- Based on script by IndigoFenix, @ https://gist.github.com/IndigoFenix/8776696 + +args={...} + +if args[1] == '?' then + print("Example usage: 'hfs-pit 2 1 1'") + print("First parameter is size of the pit in all directions.") + print("Second parameter is 1 to wall off the sides of the pit on all layers except the underworld, or anything else to leave them open.") + print("Third parameter is 1 to add stairs. Stairs are buggy; they will not reveal the bottom until you dig somewhere, but underworld creatures will path in.") + print("If no arguments are given, the default is 'hfs-pit 1 0 0', ie single-tile wide with no walls or stairs.") + return +end + +pos = copyall(df.global.cursor) +size = tonumber(args[1]) +if size == nil or size < 1 then size = 1 end + +wallOff = tonumber(args[2]) +stairs = tonumber(args[3]) + +--Get the layer of the underworld +for index,value in ipairs(df.global.world.cur_savegame.map_features) do + local featureType=value:getType() + if featureType==9 then --Underworld + underworldLayer = value.layer + end +end + +if pos.x==-30000 then + qerror("Select a location by placing the cursor") +end +local x = 0 +local y = 0 +for x=pos.x-size,pos.x+size,1 do + for y=pos.y-size,pos.y+size,1 do + z=1 + local hitAir = false + local hitCeiling = false + while z <= pos.z do + local block = dfhack.maps.ensureTileBlock(x,y,z) + if block then + if block.tiletype[x%16][y%16] ~= 335 then + hitAir = true + end + if hitAir == true then + if not hitCeiling then + if block.global_feature ~= underworldLayer or z > 10 then hitCeiling = true end + if stairs == 1 and x == pos.x and y == pos.y then + if block.tiletype[x%16][y%16] == 32 then + if z == pos.z then + block.tiletype[x%16][y%16] = 56 + else + block.tiletype[x%16][y%16] = 55 + end + else + block.tiletype[x%16][y%16] = 57 + end + end + end + if hitCeiling == true then + if block.designation[x%16][y%16].flow_size > 0 or wallOff == 1 then needsWall = true else needsWall = false end + if (x == pos.x-size or x == pos.x+size or y == pos.y-size or y == pos.y+size) and z==pos.z then + --Do nothing, this is the lip of the hole + elseif x == pos.x-size and y == pos.y-size then if needsWall == true then block.tiletype[x%16][y%16]=320 end + elseif x == pos.x-size and y == pos.y+size then if needsWall == true then block.tiletype[x%16][y%16]=321 end + elseif x == pos.x+size and y == pos.y+size then if needsWall == true then block.tiletype[x%16][y%16]=322 end + elseif x == pos.x+size and y == pos.y-size then if needsWall == true then block.tiletype[x%16][y%16]=323 end + elseif x == pos.x-size or x == pos.x+size then if needsWall == true then block.tiletype[x%16][y%16]=324 end + elseif y == pos.y-size or y == pos.y+size then if needsWall == true then block.tiletype[x%16][y%16]=325 end + elseif stairs == 1 and x == pos.x and y == pos.y then + if z == pos.z then block.tiletype[x%16][y%16]=56 + else block.tiletype[x%16][y%16]=55 end + else block.tiletype[x%16][y%16]=32 + end + block.designation[x%16][y%16].hidden = false + --block.designation[x%16][y%16].liquid_type = true -- if true, magma. if false, water. + block.designation[x%16][y%16].flow_size = 0 + dfhack.maps.enableBlockUpdates(block) + block.designation[x%16][y%16].flow_forbid = false + end + end + block.designation[x%16][y%16].hidden = false + end + z = z+1 + end + end +end \ No newline at end of file diff --git a/scripts/position.lua b/scripts/position.lua new file mode 100644 index 000000000..8c3dbe72a --- /dev/null +++ b/scripts/position.lua @@ -0,0 +1,43 @@ +--prints current time and position + +local months = { + 'Granite, in early Spring.', + 'Slate, in mid Spring.', + 'Felsite, in late Spring.', + 'Hematite, in early Summer.', + 'Malachite, in mid Summer.', + 'Galena, in late Summer.', + 'Limestone, in early Autumn.', + 'Sandstone, in mid Autumn.', + 'Timber, in late Autumn.', + 'Moonstone, in early Winter.', + 'Opal, in mid Winter.', + 'Obsidian, in late Winter.', +} + +--Fortress mode counts 1200 ticks per day and 403200 per year +--Adventurer mode counts 86400 ticks to a day and 29030400 ticks per year +--Twelve months per year, 28 days to every month, 336 days per year + +local julian_day = math.floor(df.global.cur_year_tick / 1200) + 1 +local month = math.floor(julian_day / 28) + 1 --days and months are 1-indexed +local day = julian_day % 28 + +local time_of_day = math.floor(df.global.cur_year_tick_advmode / 336) +local second = time_of_day % 60 +local minute = math.floor(time_of_day / 60) % 60 +local hour = math.floor(time_of_day / 3600) % 24 + +print('Time:') +print(' The time is '..string.format('%02d:%02d:%02d', hour, minute, second)) +print(' The date is '..string.format('%05d-%02d-%02d', df.global.cur_year, month, day)) +print(' It is the month of '..months[month]) +--TODO: print(' It is the Age of '..age_name) + +print('Place:') +print(' The z-level is z='..df.global.window_z) +print(' The cursor is at x='..df.global.cursor.x..', y='..df.global.cursor.y) +print(' The window is '..df.global.gps.dimx..' tiles wide and '..df.global.gps.dimy..' tiles high') +if df.global.gps.mouse_x == -1 then print(' The mouse is not in the DF window') else +print(' The mouse is at x='..df.global.gps.mouse_x..', y='..df.global.gps.mouse_y..' within the window') end +--TODO: print(' The fortress is at '..x, y..' on the world map ('..worldsize..' square)')