cleaning up in needs_porting

Removed obsolete plugins.  Started hotkeys port.  Mostly-finished
position port.  Corrected dwarfmonitor date display.  Documented
putontable.lua in readme.
develop
PeridexisErrant 2014-12-15 23:11:23 +11:00
parent 8e6fcac92e
commit f3826abc0c
11 changed files with 111 additions and 1990 deletions

@ -1,9 +1,14 @@
DFHack Future DFHack Future
Internals Internals
Fixes Fixes
plugins/dwarfmonitor: correct date display (month index, separator)
scripts/putontable: added to the readme
New Plugins New Plugins
New Scripts New Scripts
position: Reports the current date, time, month, and season, plus
some location info. Port/update of position.py
Misc Improvements Misc Improvements
further work on needs_porting
DFHack 0.40.19-r1 DFHack 0.40.19-r1
Internals: Internals:

@ -2399,6 +2399,16 @@ Example::
multicmd locate-ore iron ; digv multicmd locate-ore iron ; digv
position
========
Reports the current date, time, month, and season. Location reporting is a
work in progress.
putontable
==========
Makes item appear on the table, like in adventure mode shops. Arguments: '-a'
or '--all' for all items.
quicksave quicksave
========= =========

@ -1,543 +0,0 @@
#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

@ -1,30 +1,13 @@
Notes by PeridexisErrant, on the needs_porting scripts and plugins: TODO:
copypaste.cpp
I deleted: high value target - a proof of concept plugin to allow copy-pasting in DF; does both terrain and buildings/constructions
attachtest.py obsolete creaturemanager.cpp
digger.cpp less useful than digger2, replaced by autochop modify skills and labors of creatures, kill creatures, etc; impressive but I suspect most functions implemented elsewhere
digger2.cpp replaced by digfort dfbauxtite.cpp
dfstatus.cpp replaced by dfstatus.lua changes material of mechanisms to bauxtite (ie magma-safe)
drawtile.cpp replaced by tiletypes hellhole.cpp
fix-3708.cpp obsolete, bug fixed in vanilla instantly creates a hole to the HFS
lair.cpp replaced by lair
reveal.py replaced by reveal In progress:
treedump.py replaced by prospect & autochop hotkey-notes.lua
veinlook.cpp replaced by prospect prints list of hotkeys with name and jump position
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

@ -1,259 +0,0 @@
#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;
}

@ -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()
]]--

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

File diff suppressed because it is too large Load Diff

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

@ -1720,10 +1720,10 @@ struct dwarf_monitor_hook : public df::viewscreen_dwarfmodest
int y = 0; int y = 0;
ostringstream date_str; ostringstream date_str;
auto month = World::ReadCurrentMonth(); auto month = World::ReadCurrentMonth() + 1;
auto day = World::ReadCurrentDay(); auto day = World::ReadCurrentDay();
date_str << "Date:" << World::ReadCurrentYear() << "/" << date_str << "Date:" << World::ReadCurrentYear() << "-" <<
((month < 10) ? "0" : "") << month << "/" << ((month < 10) ? "0" : "") << month << "-" <<
((day < 10) ? "0" : "") << day; ((day < 10) ? "0" : "") << day;
OutputString(COLOR_GREY, x, y, date_str.str()); OutputString(COLOR_GREY, x, y, date_str.str());

@ -0,0 +1,40 @@
--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 = (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])
print('Place:')
print(' Local window is at x='..df.global.window_x
..' y='..df.global.window_y..' z='..df.global.window_z)
--TODO: add cursor, regional/embark square co-ords, window size?