Merge remote branch 'rusanon/master'

develop
doomchild 2010-05-05 17:25:08 -05:00
commit ccc234fc4a
29 changed files with 1442 additions and 52 deletions

7
.gitignore vendored

@ -21,3 +21,10 @@ build*/
#fake curses header
examples/fake-curses.h
# Python binding binaries
*.pyc
dfhack/python/pydfhack/_pydfhack.so
dfhack/python/PyDFHack.egg-info
dfhack/python/build
dfhack/python/dist

@ -0,0 +1,6 @@
mkdir build-real
cd build-real
cmake ..\.. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE:string=Release --trace > trace-stdout.txt 2> trace-stderr.txt
mingw32-make 2> log.txt
pause
dir file.xxx

@ -58,7 +58,13 @@ struct DF_API
PyObject* vegetation;
PyObject* gui;
PyObject* mem_info_type;
PyObject* position_type;
PyObject* material_type;
PyObject* creature_type;
PyObject* map_type;
PyObject* translate_type;
PyObject* construction_type;
PyObject* vegetation_type;
PyObject* gui_type;
@ -95,6 +101,7 @@ static int DF_API_init(DF_API* self, PyObject* args, PyObject* kwds)
self->vegetation = NULL;
self->gui = NULL;
self->position_type = (PyObject*)&DF_Position_type;
self->map_type = (PyObject*)&DF_Map_type;
self->vegetation_type = (PyObject*)&DF_Vegetation_type;
self->gui_type = (PyObject*)&DF_GUI_type;
@ -206,7 +213,10 @@ static PyObject* DF_API_getMemoryInfo(DF_API* self, void* closure)
{
if(self->api_Ptr != NULL)
{
self->mem_info = PyObject_Call((PyObject*)&DF_MemInfo_type, NULL, NULL);
PyObject *apiarg;
apiarg = PyTuple_New(1);
PyTuple_SetItem(apiarg, 0, (PyObject*)self);
self->mem_info = PyObject_CallObject(self->mem_info_type, apiarg);
if(self->mem_info != NULL)
{
@ -235,7 +245,10 @@ static PyObject* DF_API_getPosition(DF_API* self, void* closure)
{
if(self->api_Ptr != NULL)
{
self->position = PyObject_Call((PyObject*)&DF_Position_type, NULL, NULL);
PyObject *apiarg;
apiarg = PyTuple_New(1);
PyTuple_SetItem(apiarg, 0, (PyObject*)self);
self->position = PyObject_CallObject(self->position_type, apiarg);
if(self->position != NULL)
{
@ -264,7 +277,10 @@ static PyObject* DF_API_getMaterial(DF_API* self, void* closure)
{
if(self->api_Ptr != NULL)
{
self->material = PyObject_Call((PyObject*)&DF_Material_type, NULL, NULL);
PyObject *apiarg;
apiarg = PyTuple_New(1);
PyTuple_SetItem(apiarg, 0, (PyObject*)self);
self->material = PyObject_CallObject(self->material_type, apiarg);
if(self->material != NULL)
{
@ -293,7 +309,10 @@ static PyObject* DF_API_getCreature(DF_API* self, void* closure)
{
if(self->api_Ptr != NULL)
{
self->creature = PyObject_Call((PyObject*)&DF_CreatureManager_type, NULL, NULL);
PyObject *apiarg;
apiarg = PyTuple_New(1);
PyTuple_SetItem(apiarg, 0, (PyObject*)self);
self->creature = PyObject_CallObject(self->creature_type, apiarg);
if(self->creature != NULL)
{
@ -322,7 +341,10 @@ static PyObject* DF_API_getMap(DF_API* self, void* closure)
{
if(self->api_Ptr != NULL)
{
self->map = PyObject_CallObject(self->map_type, NULL);
PyObject *apiarg;
apiarg = PyTuple_New(1);
PyTuple_SetItem(apiarg, 0, (PyObject*)self);
self->map = PyObject_CallObject(self->map_type, apiarg);
if(self->map != NULL)
{
@ -351,7 +373,10 @@ static PyObject* DF_API_getTranslation(DF_API* self, void* closure)
{
if(self->api_Ptr != NULL)
{
self->translate = PyObject_Call((PyObject*)&DF_Translate_type, NULL, NULL);
PyObject *apiarg;
apiarg = PyTuple_New(1);
PyTuple_SetItem(apiarg, 0, (PyObject*)self);
self->translate = PyObject_CallObject(self->translate_type, apiarg);
if(self->translate != NULL)
{
@ -380,7 +405,10 @@ static PyObject* DF_API_getConstruction(DF_API* self, void* closure)
{
if(self->api_Ptr != NULL)
{
self->construction = PyObject_Call((PyObject*)&DF_Construction_type, NULL, NULL);
PyObject *apiarg;
apiarg = PyTuple_New(1);
PyTuple_SetItem(apiarg, 0, (PyObject*)self);
self->construction = PyObject_CallObject(self->construction_type, apiarg);
if(self->construction != NULL)
{
@ -409,7 +437,10 @@ static PyObject* DF_API_getVegetation(DF_API* self, void* closure)
{
if(self->api_Ptr != NULL)
{
self->vegetation = PyObject_CallObject(self->vegetation_type, NULL);
PyObject *apiarg;
apiarg = PyTuple_New(1);
PyTuple_SetItem(apiarg, 0, (PyObject*)self);
self->vegetation = PyObject_CallObject(self->vegetation_type, apiarg);
if(self->vegetation != NULL)
{
@ -438,7 +469,10 @@ static PyObject* DF_API_getGUI(DF_API* self, void* closure)
{
if(self->api_Ptr != NULL)
{
self->gui = PyObject_CallObject(self->gui_type, NULL);
PyObject *apiarg;
apiarg = PyTuple_New(1);
PyTuple_SetItem(apiarg, 0, (PyObject*)self);
self->gui = PyObject_CallObject(self->gui_type, apiarg);
if(self->gui != NULL)
{
@ -457,6 +491,105 @@ static PyObject* DF_API_getGUI(DF_API* self, void* closure)
Py_RETURN_NONE;
}
static PyObject* DF_API_getMemInfoType(DF_API* self, void* closure)
{
return self->mem_info_type;
}
static int DF_API_setMemInfoType(DF_API* self, PyObject* value)
{
if(PyType_Check(value) <= 0)
{
PySys_WriteStdout("failed type check");
PyErr_SetString(PyExc_TypeError, "value must be a type object");
return -1;
}
if(PyObject_IsSubclass(value, (PyObject*)&DF_MemInfo_type) <= 0)
{
PySys_WriteStdout("failed subclass check");
PyErr_SetString(PyExc_TypeError, "value must be descended from _pydfhack._MemInfo");
return -1;
}
self->mem_info_type = value;
return 0;
}
static PyObject* DF_API_getPositionType(DF_API* self, void* closure)
{
return self->position_type;
}
static int DF_API_setPositionType(DF_API* self, PyObject* value)
{
if(PyType_Check(value) <= 0)
{
PySys_WriteStdout("failed type check");
PyErr_SetString(PyExc_TypeError, "value must be a type object");
return -1;
}
if(PyObject_IsSubclass(value, (PyObject*)&DF_Position_type) <= 0)
{
PySys_WriteStdout("failed subclass check");
PyErr_SetString(PyExc_TypeError, "value must be descended from _pydfhack._PositionManager");
return -1;
}
self->position_type = value;
return 0;
}
static PyObject* DF_API_getMaterialType(DF_API* self, void* closure)
{
return self->material_type;
}
static int DF_API_setMaterialType(DF_API* self, PyObject* value)
{
if(PyType_Check(value) <= 0)
{
PySys_WriteStdout("failed type check");
PyErr_SetString(PyExc_TypeError, "value must be a type object");
return -1;
}
if(PyObject_IsSubclass(value, (PyObject*)&DF_Material_type) <= 0)
{
PySys_WriteStdout("failed subclass check");
PyErr_SetString(PyExc_TypeError, "value must be descended from pydfhack._MaterialManager");
return -1;
}
self->material_type = value;
return 0;
}
static PyObject* DF_API_getCreatureType(DF_API* self, void* closure)
{
return self->creature_type;
}
static int DF_API_setCreatureType(DF_API* self, PyObject* value)
{
if(PyType_Check(value) <= 0)
{
PySys_WriteStdout("failed type check");
PyErr_SetString(PyExc_TypeError, "value must be a type object");
return -1;
}
if(PyObject_IsSubclass(value, (PyObject*)&DF_CreatureManager_type) <= 0)
{
PySys_WriteStdout("failed subclass check");
PyErr_SetString(PyExc_TypeError, "value must be descended from pydfhack._CreatureManager");
return -1;
}
self->creature_type = value;
return 0;
}
static PyObject* DF_API_getMapType(DF_API* self, void* closure)
{
@ -482,6 +615,54 @@ static int DF_API_setMapType(DF_API* self, PyObject* value)
return 0;
}
static PyObject* DF_API_getTranslateType(DF_API* self, void* closure)
{
return self->translate_type;
}
static int DF_API_setTranslateType(DF_API* self, PyObject* value)
{
if(PyType_Check(value) <= 0)
{
PySys_WriteStdout("failed type check");
PyErr_SetString(PyExc_TypeError, "value must be a type object");
return -1;
}
if(PyObject_IsSubclass(value, (PyObject*)&DF_Translate_type) <= 0)
{
PySys_WriteStdout("failed subclass check");
PyErr_SetString(PyExc_TypeError, "value must be descended from pydfhack._TranslateManager");
return -1;
}
self->translate_type = value;
return 0;
}
static PyObject* DF_API_getConstructionType(DF_API* self, void* closure)
{
return self->construction_type;
}
static int DF_API_setConstructionType(DF_API* self, PyObject* value)
{
if(PyType_Check(value) <= 0)
{
PySys_WriteStdout("failed type check");
PyErr_SetString(PyExc_TypeError, "value must be a type object");
return -1;
}
if(PyObject_IsSubclass(value, (PyObject*)&DF_Construction_type) <= 0)
{
PySys_WriteStdout("failed subclass check");
PyErr_SetString(PyExc_TypeError, "value must be descended from pydfhack._ConstructionManager");
return -1;
}
self->construction_type = value;
return 0;
}
static PyObject* DF_API_getVegetationType(DF_API* self, void* closure)
{
@ -546,7 +727,13 @@ static PyGetSetDef DF_API_getterSetters[] =
{"constructions", (getter)DF_API_getConstruction, NULL, "constructions", NULL},
{"vegetation", (getter)DF_API_getVegetation, NULL, "vegetation", NULL},
{"gui", (getter)DF_API_getGUI, NULL, "gui", NULL},
{"_mem_info_mgr_type", (getter)DF_API_getMemInfoType, (setter)DF_API_setMemInfoType, "_mem_info_mgr_type", NULL},
{"_position_mgr_type", (getter)DF_API_getPositionType, (setter)DF_API_setPositionType, "_position_mgr_type", NULL},
{"_material_mgr_type", (getter)DF_API_getMaterialType, (setter)DF_API_setMaterialType, "_material_mgr_type", NULL},
{"_creature_mgr_type", (getter)DF_API_getCreatureType, (setter)DF_API_setCreatureType, "_creature_mgr_type", NULL},
{"_map_mgr_type", (getter)DF_API_getMapType, (setter)DF_API_setMapType, "_map_mgr_type", NULL},
{"_translate_mgr_type", (getter)DF_API_getTranslateType, (setter)DF_API_setTranslateType, "_translate_mgr_type", NULL},
{"_construction_mgr_type", (getter)DF_API_getConstructionType, (setter)DF_API_setConstructionType, "_construction_mgr_type", NULL},
{"_vegetation_mgr_type", (getter)DF_API_getVegetationType, (setter)DF_API_setVegetationType, "_vegetation_mgr_type", NULL},
{"_gui_mgr_type", (getter)DF_API_getGUIType, (setter)DF_API_setGUIType, "_gui_mgr_type", NULL},
{NULL} // Sentinel

@ -61,7 +61,12 @@ static void DoImports()
{
if(FlagsModule == NULL)
{
FlagsModule = PyImport_ImportModule("pydfhackflags");
FlagsModule = PyImport_ImportModule("pydfhack.pydfhackflags");
if (PyErr_Occurred())
{
PyErr_Print();
return ;
}
CreatureFlags1_type = PyObject_GetAttrString(FlagsModule, "CreatureFlags1");
CreatureFlags2_type = PyObject_GetAttrString(FlagsModule, "CreatureFlags2");
@ -72,7 +77,12 @@ static void DoImports()
}
if(TypesModule == NULL)
{
TypesModule = PyImport_ImportModule("pydftypes");
TypesModule = PyImport_ImportModule("pydfhack.pydftypes");
if (PyErr_Occurred())
{
PyErr_Print();
return ;
}
Note_type = PyObject_GetAttrString(TypesModule, "Note");
Construction_type = PyObject_GetAttrString(TypesModule, "Construction");

@ -0,0 +1,284 @@
#!python
"""Bootstrap setuptools installation
If you want to use setuptools in your package's setup.py, just include this
file in the same directory with it, and add this to the top of your setup.py::
from ez_setup import use_setuptools
use_setuptools()
If you want to require a specific version of setuptools, set a download
mirror, or use an alternate download directory, you can do so by supplying
the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import sys
DEFAULT_VERSION = "0.6c11"
DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
md5_data = {
'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090',
'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4',
'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7',
'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5',
'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de',
'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b',
'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2',
'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086',
'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
}
import sys, os
try: from hashlib import md5
except ImportError: from md5 import md5
def _validate_md5(egg_name, data):
if egg_name in md5_data:
digest = md5(data).hexdigest()
if digest != md5_data[egg_name]:
print >>sys.stderr, (
"md5 validation of %s failed! (Possible download problem?)"
% egg_name
)
sys.exit(2)
return data
def use_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
download_delay=15
):
"""Automatically find/download setuptools and make it available on sys.path
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end with
a '/'). `to_dir` is the directory where setuptools will be downloaded, if
it is not already available. If `download_delay` is specified, it should
be the number of seconds that will be paused before initiating a download,
should one be required. If an older version of setuptools is installed,
this routine will print a message to ``sys.stderr`` and raise SystemExit in
an attempt to abort the calling script.
"""
was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
def do_download():
egg = download_setuptools(version, download_base, to_dir, download_delay)
sys.path.insert(0, egg)
import setuptools; setuptools.bootstrap_install_from = egg
try:
import pkg_resources
except ImportError:
return do_download()
try:
pkg_resources.require("setuptools>="+version); return
except pkg_resources.VersionConflict, e:
if was_imported:
print >>sys.stderr, (
"The required version of setuptools (>=%s) is not available, and\n"
"can't be installed while this script is running. Please install\n"
" a more recent version first, using 'easy_install -U setuptools'."
"\n\n(Currently using %r)"
) % (version, e.args[0])
sys.exit(2)
else:
del pkg_resources, sys.modules['pkg_resources'] # reload ok
return do_download()
except pkg_resources.DistributionNotFound:
return do_download()
def download_setuptools(
version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
delay = 15
):
"""Download setuptools from a specified location and return its filename
`version` should be a valid setuptools version number that is available
as an egg for download under the `download_base` URL (which should end
with a '/'). `to_dir` is the directory where the egg will be downloaded.
`delay` is the number of seconds to pause before an actual download attempt.
"""
import urllib2, shutil
egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
url = download_base + egg_name
saveto = os.path.join(to_dir, egg_name)
src = dst = None
if not os.path.exists(saveto): # Avoid repeated downloads
try:
from distutils import log
if delay:
log.warn("""
---------------------------------------------------------------------------
This script requires setuptools version %s to run (even to display
help). I will attempt to download it for you (from
%s), but
you may need to enable firewall access for this script first.
I will start the download in %d seconds.
(Note: if this machine does not have network access, please obtain the file
%s
and place it in this directory before rerunning this script.)
---------------------------------------------------------------------------""",
version, download_base, delay, url
); from time import sleep; sleep(delay)
log.warn("Downloading %s", url)
src = urllib2.urlopen(url)
# Read/write all in one block, so we don't create a corrupt file
# if the download is interrupted.
data = _validate_md5(egg_name, src.read())
dst = open(saveto,"wb"); dst.write(data)
finally:
if src: src.close()
if dst: dst.close()
return os.path.realpath(saveto)
def main(argv, version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
try:
import setuptools
except ImportError:
egg = None
try:
egg = download_setuptools(version, delay=0)
sys.path.insert(0,egg)
from setuptools.command.easy_install import main
return main(list(argv)+[egg]) # we're done here
finally:
if egg and os.path.exists(egg):
os.unlink(egg)
else:
if setuptools.__version__ == '0.0.1':
print >>sys.stderr, (
"You have an obsolete version of setuptools installed. Please\n"
"remove it from your system entirely before rerunning this script."
)
sys.exit(2)
req = "setuptools>="+version
import pkg_resources
try:
pkg_resources.require(req)
except pkg_resources.VersionConflict:
try:
from setuptools.command.easy_install import main
except ImportError:
from easy_install import main
main(list(argv)+[download_setuptools(delay=0)])
sys.exit(0) # try to force an exit
else:
if argv:
from setuptools.command.easy_install import main
main(argv)
else:
print "Setuptools version",version,"or greater has been installed."
print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
def update_md5(filenames):
"""Update our built-in md5 registry"""
import re
for name in filenames:
base = os.path.basename(name)
f = open(name,'rb')
md5_data[base] = md5(f.read()).hexdigest()
f.close()
data = [" %r: %r,\n" % it for it in md5_data.items()]
data.sort()
repl = "".join(data)
import inspect
srcfile = inspect.getsourcefile(sys.modules[__name__])
f = open(srcfile, 'rb'); src = f.read(); f.close()
match = re.search("\nmd5_data = {\n([^}]+)}", src)
if not match:
print >>sys.stderr, "Internal error!"
sys.exit(2)
src = src[:match.start(1)] + repl + src[match.end(1):]
f = open(srcfile,'w')
f.write(src)
f.close()
if __name__=='__main__':
if len(sys.argv)>2 and sys.argv[1]=='--md5update':
update_md5(sys.argv[2:])
else:
main(sys.argv[1:])

@ -1,28 +0,0 @@
import pydfhack, os
class API(pydfhack._API):
for file in ["Memory.xml", os.path.join("..","..","output","Memory.xml")]:
if os.path.isfile(file):
datafile = file
break
else:
raise ImportError, "Memory.xml not found."
def __init__(self, *args, **kwds):
pydfhack._API.__init__(self, API.datafile)
self._map_mgr_type = Map
self._vegetation_mgr_type = Vegetation
self._gui_mgr_type = GUI
class Map(pydfhack._MapManager):
def __init__(self, *args, **kwds):
pydfhack._MapManager.__init__(self, args, kwds)
class Vegetation(pydfhack._VegetationManager):
def __init__(self, *args, **kwds):
pydfhack._VegetationManager.__init__(self, args, kwds)
class GUI(pydfhack._GUIManager):
def __init__(self, *args, **kwds):
pydfhack._GUIManager.__init__(self, args, kwds)

@ -62,7 +62,7 @@ static PyMethodDef module_methods[] =
{NULL} //Sentinel
};
PyMODINIT_FUNC initpydfhack(void)
PyMODINIT_FUNC init_pydfhack(void)
{
PyObject* module;
@ -102,7 +102,7 @@ PyMODINIT_FUNC initpydfhack(void)
if(PyType_Ready(&DF_GUI_type) < 0)
return;
module = Py_InitModule3("pydfhack", module_methods, "pydfhack extension module");
module = Py_InitModule3("_pydfhack", module_methods, "pydfhack extension module");
Py_INCREF(&DF_API_type);
Py_INCREF(&DF_MemInfo_type);

@ -0,0 +1 @@
from .pydfapi import API

@ -0,0 +1,139 @@
# -*- coding: utf-8 -*-
"""
Module for high-level abstraction of tiles
"""
from collections import namedtuple
from .pydftypes import Rectangle
from .mixins import NoStart
from .decorators import suspend
class Point(object):
x = None
y = None
z = None
block = False
def __init__(self, x, y, z, block=False):
self.x = x
self.y = y
self.z = z
self.block = block
def get_block(self):
if not self.block:
return Point(self.x/16, self.y/16, self.z, True)
else:
return self
@property
def xyz(self):
return (self.x, self.y, self.z)
@property
def rect(self):
"""
Return block coords in form (x1, y1, x2, y2)
"""
block = self.get_block()
x1 = block.x * 16
y1 = block.y * 16
return Rectangle(x1, y1, x1+15, y1+15)
def __repr__(self):
b = ''
if self.block:
b = ', Block'
return "<Point(X:{0.x}, Y:{0.y}, Z:{0.z}{1})>".format(self, b)
class Block(NoStart):
"""
16x16 tiles block
"""
api = None
tiles = None
coords = None
x1 = None
y1 = None
def __init__(self, api, coords):
"""
api is instance of API, which is used for read/write operations
coords is Point object
"""
self.api = api
if not isinstance(coords, Point):
raise Exception(u"coords parameter should be Point")
coords = coords.get_block()
self.coords = coords
self.rect = self.coords.rect
self.reload()
@suspend
def reload(self):
tile_types = self.api.maps.Read_Tile_Types(point=self.coords)
tile_flags = self.api.maps.Read_Designations(point=self.coords)
if self.tiles:
for x in range(16):
for y in range(16):
self.tiles[x][y].update(ttype=tile_types[x][y], flags=tile_flags[x][y])
else:
self.tiles = []
for x in range(16):
row = []
for y in range(16):
row.append(Tile(self, tile_types[x][y], tile_flags[x][y], self.rect.x1 + x, self.rect.y1 + y, self.coords.z))
self.tiles.append(row)
@suspend
def save(self):
tile_types = map(lambda x:range(16), range(16))
tile_flags = map(lambda x:range(16), range(16))
for x in range(16):
for y in range(16):
tile_types[x][y] = self.tiles[x][y].ttype
tile_flags[x][y] = self.tiles[x][y].flags
self.api.maps.Write_Tile_Types(point=self.coords, tiles=tile_types)
# Designations are bugged
#self.api.maps.Write_Designations(point=self.coords, tiles=tile_flags)
def get_tile(self, x=0, y=0, z=0, point=None):
if point:
x, y, z = point.xyz
if z == self.coords.z and (self.rect.y1 <= y <= self.rect.y2) and (self.rect.x1 <= x <= self.rect.x2):
return self.tiles[x%16][y%16]
else:
raise Exception("This tile does not belong to this block")
def __repr__(self):
return "<Block(X:{2}-{4}, Y:{3}-{5}, Z:{1.z})>".format(self, self.coords, *self.coords.rect)
class Tile(object):
coords = None
block = None
ttype = None
temperature = None
flags = None
def __init__(self, block, ttype, flags, x=0, y=0, z=0, point=None):
self.ttype = ttype
self.flags = flags
if not point:
point = Point(x, y, z)
self.coords = point
self.block = block
def update(self, ttype, flags):
self.ttype = ttype
self.flags = flags
def reload(self):
self.block.reload()
def save(self):
self.block.save()
def __repr__(self):
return "<Tile({0.ttype} at {1.x}, {1.y}, {1.z})>".format(self, self.coords)

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
"""
Python class for DF_Hack::Construction
"""
from ._pydfhack import _ConstructionManager
from .mixins import NeedsStart
from .decorators import suspend
class Construction(NeedsStart, _ConstructionManager):
api = None
cls = _ConstructionManager
def __init__(self, api, *args, **kwds):
self.cls.__init__(self, args, kwds)
self.api = api
@suspend
def Read(self, *args, **kw):
return self.cls.Read(self, *args, **kw)

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
"""
Python class for DF_Hack::Creature
"""
from ._pydfhack import _CreatureManager
from .mixins import NeedsStart
from .decorators import suspend
class Creature(NeedsStart, _CreatureManager):
api = None
cls = _CreatureManager
def __init__(self, api, *args, **kwds):
self.cls.__init__(self, args, kwds)
self.api = api
@suspend
def Read_Creature(self, *args, **kw):
return self.cls.Read_Creature(self, *args, **kw)
@suspend
def Get_Dwarf_Race_Index(self, *args, **kw):
return self.cls.Get_Dwarf_Race_Index(self, *args, **kw)
@suspend
def Write_Labors(self, *args, **kw):
return self.cls.Write_Labors(self, *args, **kw)
@suspend
def Read_Creature_In_Box(self, *args, **kw):
return self.cls.Read_Creature_In_Box(self, *args, **kw)
@suspend
def Get_Dwarf_Civ_id(self, *args, **kw):
return self.cls.Get_Dwarf_Civ_id(self, *args, **kw)

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
"""
Decorators for bound classes
"""
from decorator import decorator
@decorator
def suspend(func, self, *args, **kw):
"""
This decorator will try to suspend DF and start needed module before running func.
If DF was resumed when decorator was run, it will try to resume back after executing func
"""
susp = not self.api.is_attached or self.api.is_suspended
if self.prepare():
res = func(self, *args, **kw)
if not susp:
self.api.Resume()
return res
else:
raise Exception(u"Could not suspend/start")

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
"""
Python class for DF_Hack::GUI
"""
from ._pydfhack import _GUIManager
class GUI(_GUIManager):
api = None
started = False
def __init__(self, api, *args, **kwds):
_GUIManager.__init__(self, args, kwds)
self.api = api
def prepare(self):
"""
Enforce Suspend/Start
"""
if self.api.prepare():
if not self.started:
self.started = self.Start()
return self.started
else:
return False

@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
"""
Python class for DF_Hack::Maps
"""
from ._pydfhack import _MapManager
from .mixins import NeedsStart
from .decorators import suspend
from .blocks import Block, Point
class Map(NeedsStart, _MapManager):
api = None
cls = _MapManager
def __init__(self, api, *args, **kwds):
self.cls.__init__(self, args, kwds)
self.api = api
@suspend
def get_size(self):
return self.size
@suspend
def Is_Valid_Block(self, x=0, y=0, z=0, point=None):
"""
Checks if coords are valid
"""
if point:
point = point.get_block()
x, y, z = point.xyz
return self.cls.Is_Valid_Block(self, x, y, z)
@suspend
def Read_Tile_Types(self, x=0, y=0, z=0, point=None):
"""
Returns 16x16 block in form of list of lists.
Should be called either by point or x,y,z coords. Coords are in block form.
"""
if point:
point = point.get_block()
x, y, z = point.xyz
return self.cls.Read_Tile_Types(self, x, y, z)
@suspend
def Write_Tile_Types(self, x=0, y=0, z=0, tiles=None, point=None):
if point:
point = point.get_block()
x, y, z = point.xyz
return self.cls.Write_Tile_Types(self, x, y, z, tiles)
@suspend
def Read_Designations(self, x=0, y=0, z=0, point=None):
"""
Returns 16x16 block in form of list of lists.
"""
if point:
point = point.get_block()
x, y, z = point.xyz
return self.cls.Read_Designations(self, x, y, z)
@suspend
def Write_Designations(self, x=0, y=0, z=0, tiles=None, point=None):
if point:
point = point.get_block()
x, y, z = point.xyz
return self.cls.Write_Designations(self, x, y, z, tiles)
@suspend
def Write_Occupancy(self, *args, **kw):
return self.cls.Write_Occupancy(self, *args, **kw)
@suspend
def Write_Dirty_Bit(self, *args, **kw):
return self.cls.Write_Dirty_Bit(self, *args, **kw)
@suspend
def Write_Block_Flags(self, *args, **kw):
return self.cls.Write_Block_Flags(self, *args, **kw)
@suspend
def Read_Region_Offsets(self, *args, **kw):
return self.cls.Read_Region_Offsets(self, *args, **kw)
@suspend
def Read_Dirty_Bit(self, *args, **kw):
return self.cls.Read_Dirty_Bit(self, *args, **kw)
@suspend
def Read_Occupancy(self, *args, **kw):
return self.cls.Read_Occupancy(self, *args, **kw)
@suspend
def Read_Block_Flags(self, *args, **kw):
return self.cls.Read_Block_Flags(self, *args, **kw)
@suspend
def Read_Geology(self, *args, **kw):
return self.cls.Read_Geology(self, *args, **kw)
@suspend
def Read_Block_40d(self, *args, **kw):
return self.cls.Read_Block_40d(self, *args, **kw)
@suspend
def get_block(self, point):
point = point.get_block()
block = Block(api=self.api, coords=point)
return block
@suspend
def get_tile(self, x=0, y=0, z=0, point=None):
if not point:
point = Point(x, y, z)
block = Block(api=self.api, coords=point.get_block())
return block.get_tile(point=point)

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
"""
Python class for DF_Hack::Materials
"""
from ._pydfhack import _MaterialsManager
from .mixins import NoStart
from .decorators import suspend
class Materials(NoStart, _MaterialsManager):
api = None
cls = _MaterialsManager
def __init__(self, api, *args, **kwds):
cls.__init__(self, args, kwds)
self.api = api
@suspend
def Read_Wood_Materials(self, *args, **kw):
return self.cls.Read_Wood_Materials(self, *args, **kw)
@suspend
def Read_Plant_Materials(self, *args, **kw):
return self.cls.Read_Plant_Materials(self, *args, **kw)
@suspend
def Read_Inorganic_Materials(self, *args, **kw):
return self.cls.Read_Inorganic_Materials(self, *args, **kw)
@suspend
def Read_Descriptor_Colors(self, *args, **kw):
return self.cls.Read_Descriptor_Colors(self, *args, **kw)
@suspend
def Read_Creature_Types(self, *args, **kw):
return self.cls.Read_Creature_Types(self, *args, **kw)
@suspend
def Read_Organic_Materials(self, *args, **kw):
return self.cls.Read_Organic_Materials(self, *args, **kw)
@suspend
def Read_Creature_Types_Ex(self, *args, **kw):
return self.cls.Read_Creature_Types_Ex(self, *args, **kw)

@ -0,0 +1,98 @@
# -*- coding: utf-8 -*-
"""
Python class for DF_Hack::MemInfo
"""
from ._pydfhack import _MemInfo
from .mixins import NoStart
from .decorators import suspend
class MemInfo(NoStart, _MemInfo):
api = None
cls = _MemInfo
def __init__(self, api, *args, **kwds):
self.cls.__init__(self, args, kwds)
self.api = api
## Properties:
# version
# base
## No idea if these should work only on suspend. To check later.
def Rebase_All(self, *args, **kw):
return self.cls.Rebase_All(self, *args, **kw)
def Set_String(self, *args, **kw):
return self.cls.Set_String(self, *args, **kw)
def Resolve_Object_To_Class_ID(self, *args, **kw):
return self.cls.Resolve_Object_To_Class_ID(self, *args, **kw)
def Get_Trait(self, *args, **kw):
return self.cls.Get_Trait(self, *args, **kw)
def Get_Job(self, *args, **kw):
return self.cls.Get_Job(self, *args, **kw)
def Rebase_VTable(self, *args, **kw):
return self.cls.Rebase_VTable(self, *args, **kw)
def Get_String(self, *args, **kw):
return self.cls.Get_String(self, *args, **kw)
def Get_Trait_Name(self, *args, **kw):
return self.cls.Get_Trait_Name(self, *args, **kw)
def Set_Job(self, *args, **kw):
return self.cls.Set_Job(self, *args, **kw)
def Set_Offset(self, *args, **kw):
return self.cls.Set_Offset(self, *args, **kw)
def Rebase_Addresses(self, *args, **kw):
return self.cls.Rebase_Addresses(self, *args, **kw)
def Resolve_Classname_To_Class_ID(self, *args, **kw):
return self.cls.Resolve_Classname_To_Class_ID(self, *args, **kw)
def Set_Labor(self, *args, **kw):
return self.cls.Set_Labor(self, *args, **kw)
def Get_Skill(self, *args, **kw):
return self.cls.Get_Skill(self, *args, **kw)
def Set_Profession(self, *args, **kw):
return self.cls.Set_Profession(self, *args, **kw)
def Get_Profession(self, *args, **kw):
return self.cls.Get_Profession(self, *args, **kw)
def Get_Offset(self, *args, **kw):
return self.cls.Get_Offset(self, *args, **kw)
def Get_HexValue(self, *args, **kw):
return self.cls.Get_HexValue(self, *args, **kw)
def Set_Address(self, *args, **kw):
return self.cls.Set_Address(self, *args, **kw)
def Set_HexValue(self, *args, **kw):
return self.cls.Set_HexValue(self, *args, **kw)
def Get_Address(self, *args, **kw):
return self.cls.Get_Address(self, *args, **kw)
def Set_Trait(self, *args, **kw):
return self.cls.Set_Trait(self, *args, **kw)
def Resolve_Classname_To_VPtr(self, *args, **kw):
return self.cls.Resolve_Classname_To_VPtr(self, *args, **kw)
def Get_Labor(self, *args, **kw):
return self.cls.Get_Labor(self, *args, **kw)
def Set_Skill(self, *args, **kw):
return self.cls.Set_Skill(self, *args, **kw)
def Resolve_Class_ID_To_Classname(self, *args, **kw):
return self.cls.Resolve_Class_ID_To_Classname(self, *args, **kw)

@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
"""
Mix-ins for bound classes
"""
class NeedsStart(object):
"""
This mixin enforces Start/Finish routines
"""
started = False
def prepare(self):
"""
Enforce Suspend/Start
"""
if self.api.prepare():
if not self.started:
self.Start()
return self.started
else:
return False
def Start(self):
if self.started:
return True
if self.api.prepare():
self.started = self.cls.Start(self)
if self.started:
self.api.started.append(self)
return self.started
else:
return False
start = Start
def Finish(self):
if self.started:
self.cls.Finish(self)
self.started = False
if self in self.api.started:
self.api.started.remove(self)
finish = Finish
class NoStart(object):
"""
This mixin enforces Suspend, and disables Start/Finish
"""
def prepare(self):
"""
Enforce Suspend
"""
return self.api.prepare()
def Start(self):
raise Exception("{0.cls} does not need Start()".format(self))
start = Start
def Finish(self):
raise Exception("{0.cls} does not need Finish()".format(self))
finish = Finish

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
"""
Python class for DF_Hack::Position
"""
from ._pydfhack import _PositionManager
from .blocks import Point, Block
from .mixins import NoStart
from .decorators import suspend
class Position(NoStart, _PositionManager):
api = None
cls = _PositionManager
def __init__(self, api, *args, **kwds):
self.cls.__init__(self, args, kwds)
self.api = api
@suspend
def get_cursor(self):
coords = self.cursor_coords
if coords:
return Point(*coords)
else:
return None
@suspend
def get_window_size(self):
wsize = self.window_size
return wsize
@suspend
def get_view_coords(self):
coords = self.view_coords
return Point(*coords)
@suspend
def get_cursor_tile(self):
point = self.get_cursor()
if point:
tile = self.api.maps.get_tile(point=point)
return tile
else:
return None

@ -0,0 +1,71 @@
import _pydfhack, os, copy
from .blocks import Point, Block
from .meminfo import MemInfo
from .position import Position
from .materials import Materials
from .creature import Creature
from .map import Map
from .translation import Translation
from .construction import Construction
from .vegetation import Vegetation
from .gui import GUI
class API(_pydfhack._API):
started = None
path = os.path.dirname(os.path.abspath(__file__))
datafile = os.path.join(path, "Memory.xml")
if not os.path.isfile(datafile):
raise ImportError, "Memory.xml not found."
# Rude hack to bypass xml location restrictions
datafile = "./" + "../"*20 + datafile
def prepare(self):
"""
Enforce Attach/Suspend behavior.
Return True if succeeded, else False
"""
r = True
if not self.is_attached:
r = self.Attach()
if r and not self.is_suspended:
r = self.Suspend()
return r
def __init__(self, *args, **kwds):
_pydfhack._API.__init__(self, API.datafile)
self._mem_info_mgr_type = MemInfo
self._position_mgr_type = Position
self._material_mgr_type = Materials
self._creature_mgr_type = Creature
self._map_mgr_type = Map
self._translate_mgr_type = Translation
self._construction_mgr_type = Construction
self._vegetation_mgr_type = Vegetation
self._gui_mgr_type = GUI
self.started = []
def Attach(self, *args, **kw):
print "API.Attach()"
return _pydfhack._API.Attach(self, *args, **kw)
def Detach(self, *args, **kw):
print "API.Detach()"
return _pydfhack._API.Detach(self, *args, **kw)
def Suspend(self, *args, **kw):
print "API.Suspend()"
return _pydfhack._API.Suspend(self, *args, **kw)
def Resume(self):
print "API.Resume()"
# Reference counting is fcked, so leave it alone for now
## Explicitly Finish() all started modules
#print self.started
#started = copy.copy(self.started)
#print started
#for m in started:
# print m
# m.Finish()
#self.started = []
return _pydfhack._API.Resume(self)

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
"""
Python class for DF_Hack::Translation
"""
from ._pydfhack import _TranslationManager
from .mixins import NeedsStart
from .decorators import suspend
class Translation(NeedsStart, _TranslationManager):
api = None
cls = _TranslationManager
def __init__(self, api, *args, **kwds):
self.cls.__init__(self, args, kwds)
self.api = api
def get_dictionaries(self):
return self.dictionaries
def Translate_Name(self, *args, **kw):
return self.cls.Translate_Name(self, *args, **kw)

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
"""
Python class for DF_Hack::Vegetation
"""
from ._pydfhack import _VegetationManager
from .mixins import NeedsStart
from .decorators import suspend
class Vegetation(NeedsStart, _VegetationManager):
api = None
cls = _VegetationManager
def __init__(self, api, *args, **kwds):
self.cls.__init__(self, args, kwds)
self.api = api
@suspend
def Read(self, *args, **kw):
return self.cls.Read(self, *args, **kw)

@ -1,12 +1,59 @@
# -*- coding: utf-8 -*-
from distutils.core import setup, Extension
try:
from setuptools import setup, find_packages
except ImportError:
from ez_setup import use_setuptools
use_setuptools()
from setuptools import setup, find_packages
from distutils.core import Extension
from os import path
import platform
e = Extension("pydfhack",
sources=["DF_API.cpp", "DF_Buildings.cpp", "DF_Constructions.cpp", "DF_CreatureManager.cpp", "DF_GUI.cpp", "DF_Maps.cpp", "DF_Material.cpp", "DF_Position.cpp", "DF_Translate.cpp", "DF_Vegetation.cpp", "pydfhack.cpp"],
include_dirs=["../", "../include", "../depends/md5", "../depends/tinyxml"],
library_dirs=["..\\..\\output"],
#extra_compile_args=["-w"],
libraries=["libdfhack"],
export_symbols=["initpydfhack", "ReadRaw", "WriteRaw"])
if platform.system() == 'Windows':
# dfhack.lib location can differ, search for it
for libdir in ["..", path.join("..",".."), path.join("..", "..", "output"), path.join("..", "..", "output", "Release")]:
if path.isfile(path.join(libdir, "dfhack.lib")):
lib_dirs = libdir
libraries=["dfhack"]
break
if path.isfile(path.join(libdir, "libdfhack.dll")):
lib_dirs = libdir
libraries = ["libdfhack"]
break
else:
raise Exception("dfhack.lib is not found")
osspec = dict(library_dirs=[lib_dirs],
libraries=libraries)
setup(name="PyDFHack", version="1.0", ext_modules=[e])
elif platform.system() == 'Linux':
osspec = dict(extra_compile_args=["-DLINUX_BUILD", "-w"],
library_dirs=[path.join("..","..","output")],
libraries=["dfhack"])
e = Extension("pydfhack._pydfhack",
sources=["DF_API.cpp", "DF_Buildings.cpp", "DF_Constructions.cpp", "DF_CreatureManager.cpp",\
"DF_GUI.cpp", "DF_Maps.cpp", "DF_Material.cpp", "DF_Position.cpp", "DF_Translate.cpp",\
"DF_Vegetation.cpp", "pydfhack.cpp"],
include_dirs=["../", path.join("..", "include"), path.join("..","depends","md5"), path.join("..","depends","tinyxml")],
export_symbols=["init_pydfhack", "ReadRaw", "WriteRaw"],
**osspec)
for file in ["Memory.xml", path.join("..","..","output","Memory.xml")]:
if path.isfile(file):
datafile = file
break
else:
raise Exception("Memory.xml is not found.")
setup(
name="PyDFHack",
description="Python wrapper and bindings for DFHack library",
version="1.0",
packages=find_packages(exclude=['ez_setup']),
data_files=[('pydfhack', [datafile])],
include_package_data=True,
test_suite='nose.collector',
zip_safe=False,
ext_modules=[e],
)

@ -0,0 +1,38 @@
#!/usr/bin/python
import sys
import pydfhack
DF = pydfhack.API("Memory.xml")
DF.Attach()
pos = DF.position
maps = DF.maps
refc = dict(pydfhack=pydfhack, API=pydfhack.API, DF=DF, pos=pos, maps=maps)
cursor = pos.get_cursor()
msize = maps.get_size()
block = None
tile = None
if cursor:
block = maps.get_block(point=cursor)
if block:
tile = block.get_tile(point=cursor)
DF.Resume()
locs = dict(pydfhack=pydfhack, API=pydfhack.API, DF=DF, pos=pos, maps=maps, msize=msize, cursor=cursor, block=block, tile=tile)
banner = """DFHack Shell\n\n"""\
"""\tpydfhack = {pydfhack}\n"""\
"""\tAPI = {API}\n"""\
"""\tDF = {DF}\n"""\
"""\tpos = {pos}\n"""\
"""\tmaps = {maps}\n"""\
"""\tmsize = {msize}\n"""\
"""\tcursor = {cursor}\n"""\
"""\tblock = {block}\n"""\
"""\ttile = {tile}\n""".format(**locs)
from IPython.Shell import IPShellEmbed
shell = IPShellEmbed()
shell.set_banner(shell.IP.BANNER + '\n\n' + banner)
shell(local_ns=locs, global_ns={})
DF.Detach()

@ -0,0 +1,45 @@
#!/usr/bin/python
import sys
import pydfhack
from pydfhack.blocks import Point
DF = pydfhack.API("Memory.xml")
DF.Attach()
pos = DF.position
maps = DF.maps
cursor = pos.get_cursor()
refc = dict(pydfhack=pydfhack, API=pydfhack.API, DF=DF, pos=pos, maps=maps)
msize = maps.get_size()
print msize
locs = dict(pydfhack=pydfhack, API=pydfhack.API, DF=DF, pos=pos, maps=maps, msize=msize, cursor=cursor)
for z in range(msize[2]):
trees = 0
saplings = 0
dead_saplings = 0
for x in range(msize[0]):
for y in range(msize[1]):
p = Point(x, y, z, True)
block = maps.get_block(point=p)
changed = False
if not block.tiles:
break
for tx in range(16):
for ty in range(16):
tile = block.tiles[tx][ty]
if tile.ttype == 24:
trees += 1
elif tile.ttype == 231:
saplings += 1
tile.ttype = 24
changed = True
elif tile.ttype == 392:
dead_saplings += 1
tile.ttype = 24
changed = True
if changed:
block.save()
print "Saved block {0}".format(block)
print "Z-Level {0}: Trees {1}, Saplings {2}, Dead saplings {3}".format(z, trees, saplings, dead_saplings)
DF.Resume()
DF.Detach()

@ -74,6 +74,10 @@ TARGET_LINK_LIBRARIES(dfspatterdump dfhack)
ADD_EXECUTABLE(dfcatsplosion catsplosion.cpp)
TARGET_LINK_LIBRARIES(dfcatsplosion dfhack)
# flows - check flows impact on fps
ADD_EXECUTABLE(dfflows flows.cpp)
TARGET_LINK_LIBRARIES(dfflows dfhack)
IF(UNIX)
SET(CURSES_NEED_WIDE "YES")
SET(CURSES_NEED_NCURSES "NO")

@ -0,0 +1,83 @@
// This is a reveal program. It reveals the map.
#include <iostream>
#include <integers.h>
#include <vector>
using namespace std;
#include <DFTypes.h>
#include <DFHackAPI.h>
#include <modules/Maps.h>
int main (void)
{
uint32_t x_max,y_max,z_max;
DFHack::designations40d designations;
DFHack::API DF("Memory.xml");
try
{
DF.Attach();
}
catch (exception& e)
{
cerr << e.what() << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
DFHack::Maps *Maps =DF.getMaps();
// init the map
if(!Maps->Start())
{
cerr << "Can't init map." << endl;
#ifndef LINUX_BUILD
cin.ignore();
#endif
return 1;
}
DFHack::t_blockflags bflags;
Maps->getSize(x_max,y_max,z_max);
// walk the map, count flowing tiles, magma, water
uint32_t flow1=0, flow2=0, flowboth=0, water=0, magma=0;
cout << "Counting flows and liquids .";
for(uint32_t x = 0; x< x_max;x++)
{
for(uint32_t y = 0; y< y_max;y++)
{
for(uint32_t z = 0; z< z_max;z++)
{
if(Maps->isValidBlock(x,y,z))
{
Maps->ReadBlockFlags(x, y, z, bflags);
Maps->ReadDesignations(x, y, z, &designations);
if (bflags.bits.liquid_1)
flow1++;
if (bflags.bits.liquid_2)
flow2++;
if (bflags.bits.liquid_1 && bflags.bits.liquid_2)
flowboth++;
for (uint32_t i = 0; i < 16;i++) for (uint32_t j = 0; j < 16;j++)
{
if (designations[i][j].bits.liquid_type == DFHack::liquid_magma)
magma++;
if (designations[i][j].bits.liquid_type == DFHack::liquid_water)
water++;
}
// Maps->WriteDesignations(x, y, z, &designations);
// Maps->WriteBlockFlags(x, y, z, bflags);
cout << ".";
}
}
}
}
cout << endl << "Done." << endl;
cout << "Blocks with liquid_1=true: " << flow1 << endl;
cout << "Blocks with liquid_2=true: " << flow2 << endl;
cout << "Blocks with both: " << flowboth << endl;
cout << "Water tiles: " << water << endl;
cout << "Magma tiles: " << magma << endl;
return 0;
}

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
import pydfhack
DF = pydfhack._API("Memory.xml")
from pydfhack import API
DF = API("Memory.xml")
if DF.Attach():
Mats = DF.materials