summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
Diffstat (limited to 'library')
-rw-r--r--library/CMakeLists.txt5
-rw-r--r--library/Console-linux.cpp6
-rw-r--r--library/Core.cpp119
-rw-r--r--library/Hooks-darwin.cpp6
-rw-r--r--library/Hooks-linux.cpp2
-rw-r--r--library/LuaApi.cpp233
-rw-r--r--library/LuaTools.cpp6
-rw-r--r--library/LuaTypes.cpp26
-rw-r--r--library/LuaWrapper.cpp89
-rw-r--r--library/Process-darwin.cpp113
-rw-r--r--library/RemoteClient.cpp21
-rw-r--r--library/RemoteServer.cpp2
-rw-r--r--library/RemoteTools.cpp16
-rw-r--r--library/VersionInfoFactory.cpp8
-rw-r--r--library/include/Console.h12
-rw-r--r--library/include/Core.h8
-rw-r--r--library/include/DataFuncs.h11
-rw-r--r--library/include/Hooks.h6
-rw-r--r--library/include/LuaWrapper.h1
-rw-r--r--library/include/PluginManager.h6
-rw-r--r--library/include/SDL_events.h210
-rw-r--r--library/include/SDL_keyboard.h61
-rw-r--r--library/include/SDL_keysym.h329
-rw-r--r--library/include/modules/World.h31
-rw-r--r--library/lua/dfhack.lua13
-rw-r--r--library/lua/memscan.lua455
-rw-r--r--library/lua/utils.lua46
-rw-r--r--library/modules/Gui.cpp45
-rw-r--r--library/modules/Materials.cpp4
-rw-r--r--library/modules/Units.cpp71
-rw-r--r--library/modules/World.cpp10
31 files changed, 1794 insertions, 177 deletions
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 2035a5ce..73f6c9ec 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -267,8 +267,11 @@ SET_TARGET_PROPERTIES(dfhack PROPERTIES DEBUG_POSTFIX "-debug" )
IF(APPLE)
SET(SDL_LIBRARY ${CMAKE_INSTALL_PREFIX}/libs/SDL.framework)
+ SET(CXX_LIBRARY ${CMAKE_INSTALL_PREFIX}/libs/libstdc++.6.dylib)
+ SET(ZIP_LIBRARY /usr/lib/libz.dylib)
TARGET_LINK_LIBRARIES(dfhack ${SDL_LIBRARY})
-# TARGET_LINK_LIBRARIES(dfhack /usr/lib/libc++.dylib)
+ TARGET_LINK_LIBRARIES(dfhack ${CXX_LIBRARY})
+ TARGET_LINK_LIBRARIES(dfhack ${ZIP_LIBRARY})
SET_TARGET_PROPERTIES(dfhack PROPERTIES VERSION 1.0.0)
SET_TARGET_PROPERTIES(dfhack PROPERTIES SOVERSION 1.0.0)
ENDIF()
diff --git a/library/Console-linux.cpp b/library/Console-linux.cpp
index c547f841..6b4de736 100644
--- a/library/Console-linux.cpp
+++ b/library/Console-linux.cpp
@@ -264,7 +264,7 @@ namespace DFHack
void color(Console::color_value index)
{
if(!rawmode)
- fprintf(dfout_C,getANSIColor(index));
+ fprintf(dfout_C, "%s", getANSIColor(index));
else
{
const char * colstr = getANSIColor(index);
@@ -716,6 +716,8 @@ void Console::add_text(color_value color, const std::string &text)
lock_guard <recursive_mutex> g(*wlock);
if (inited)
d->print_text(color, text);
+ else
+ fwrite(text.data(), 1, text.size(), stderr);
}
int Console::get_columns(void)
@@ -770,4 +772,4 @@ void Console::msleep (unsigned int msec)
{
if (msec > 1000) sleep(msec/1000000);
usleep((msec % 1000000) * 1000);
-} \ No newline at end of file
+}
diff --git a/library/Core.cpp b/library/Core.cpp
index 94d408b8..f30e19c2 100644
--- a/library/Core.cpp
+++ b/library/Core.cpp
@@ -68,6 +68,8 @@ using namespace DFHack;
#include <fstream>
#include "tinythread.h"
+#include "SDL_events.h"
+
using namespace tthread;
using namespace df::enums;
using df::global::init;
@@ -262,16 +264,12 @@ static bool init_run_script(color_ostream &out, lua_State *state, void *info)
return true;
}
-static command_result runLuaScript(color_ostream &out, std::string filename, vector<string> &args)
+static command_result runLuaScript(color_ostream &out, std::string name, vector<string> &args)
{
ScriptArgs data;
- data.pcmd = &filename;
+ data.pcmd = &name;
data.pargs = &args;
-#ifndef LINUX_BUILD
- filename = toLower(filename);
-#endif
-
bool ok = Lua::RunCoreQueryLoop(out, Lua::Core::State, init_run_script, &data);
return ok ? CR_OK : CR_FAILURE;
@@ -279,29 +277,29 @@ static command_result runLuaScript(color_ostream &out, std::string filename, vec
command_result Core::runCommand(color_ostream &out, const std::string &command)
{
- fprintf(stderr,"Inside runCommand");
- fprintf(stderr," with command %s\n",command.c_str());
+ //fprintf(stderr,"Inside runCommand");
+ //fprintf(stderr," with command %s\n",command.c_str());
if (!command.empty())
{
- fprintf(stderr,"Command is not empty, tokenizing\n");
+ //fprintf(stderr,"Command is not empty, tokenizing\n");
vector <string> parts;
Core::cheap_tokenise(command,parts);
- fprintf(stderr,"Tokenized, got %d parts\n",parts.size());
+ //fprintf(stderr,"Tokenized, got %d parts\n",parts.size());
if(parts.size() == 0)
return CR_NOT_IMPLEMENTED;
string first = parts[0];
- fprintf(stderr,"Erasing beginning\n");
+ //fprintf(stderr,"Erasing beginning\n");
parts.erase(parts.begin());
- fprintf(stderr,"I think we're about there\n");
+ //fprintf(stderr,"I think we're about there\n");
if (first[0] == '#')
return CR_OK;
cerr << "Invoking: " << command << endl;
- fprintf(stderr,"Returning with the next recursion\n");
+ //fprintf(stderr,"Returning with the next recursion\n");
return runCommand(out, first, parts);
}
else
@@ -617,7 +615,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first, ve
{
auto filename = getHackPath() + "scripts/" + first + ".lua";
if (fileExists(filename))
- res = runLuaScript(con, filename, parts);
+ res = runLuaScript(con, first, parts);
else
con.printerr("%s is not a recognized command.\n", first.c_str());
}
@@ -682,7 +680,7 @@ void fIOthread(void * iodata)
{
string command = "";
int ret = con.lineedit("[DFHack]# ",command, main_history);
- fprintf(stderr,"Command: [%s]\n",command.c_str());
+ //fprintf(stderr,"Command: [%s]\n",command.c_str());
if(ret == -2)
{
cerr << "Console is shutting down properly." << endl;
@@ -696,13 +694,13 @@ void fIOthread(void * iodata)
else if(ret)
{
// a proper, non-empty command was entered
- fprintf(stderr,"Adding command to history\n");
+ //fprintf(stderr,"Adding command to history\n");
main_history.add(command);
- fprintf(stderr,"Saving history\n");
+ //fprintf(stderr,"Saving history\n");
main_history.save("dfhack.history");
}
- fprintf(stderr,"Running command\n");
+ //fprintf(stderr,"Running command\n");
auto rv = core->runCommand(con, command);
@@ -813,14 +811,19 @@ bool Core::Init()
}
cerr << "Version: " << vinfo->getVersion() << endl;
+ // Init global object pointers
+ df::global::InitGlobals();
+
cerr << "Initializing Console.\n";
// init the console.
bool is_text_mode = false;
if(init && init->display.flag.is_set(init_display_flags::TEXT))
{
is_text_mode = true;
+ con.init(true);
+ cerr << "Console is not available. Use dfhack-run to send commands.\n";
}
- if(con.init(is_text_mode))
+ else if(con.init(false))
cerr << "Console is running.\n";
else
fatal ("Console has failed to initialize!\n", false);
@@ -835,7 +838,6 @@ bool Core::Init()
*/
// initialize data defs
virtual_identity::Init(this);
- df::global::InitGlobals();
// initialize common lua context
Lua::Core::Init(con);
@@ -845,12 +847,15 @@ bool Core::Init()
cerr << "Initializing Plugins.\n";
// create plugin manager
plug_mgr = new PluginManager(this);
- cerr << "Starting IO thread.\n";
- // create IO thread
IODATA *temp = new IODATA;
temp->core = this;
temp->plug_mgr = plug_mgr;
- thread * IO = new thread(fIOthread, (void *) temp);
+ if (!is_text_mode)
+ {
+ cerr << "Starting IO thread.\n";
+ // create IO thread
+ thread * IO = new thread(fIOthread, (void *) temp);
+ }
cerr << "Starting DF input capture thread.\n";
// set up hotkey capture
HotkeyMutex = new mutex();
@@ -1218,29 +1223,30 @@ bool Core::ncurses_wgetch(int in, int & out)
return true;
}
-int Core::UnicodeAwareSym(const SDL_KeyboardEvent& ke)
+int UnicodeAwareSym(const SDL::KeyboardEvent& ke)
{
// Assume keyboard layouts don't change the order of numbers:
- if( '0' <= ke.keysym.sym && ke.keysym.sym <= '9') return ke.keysym.sym;
- if(SDLK_F1 <= ke.keysym.sym && ke.keysym.sym <= SDLK_F12) return ke.keysym.sym;
+ if( '0' <= ke.ksym.sym && ke.ksym.sym <= '9') return ke.ksym.sym;
+ if(SDL::K_F1 <= ke.ksym.sym && ke.ksym.sym <= SDL::K_F12) return ke.ksym.sym;
// These keys are mapped to the same control codes as Ctrl-?
- switch (ke.keysym.sym) {
- case SDLK_RETURN:
- case SDLK_KP_ENTER:
- case SDLK_TAB:
- case SDLK_ESCAPE:
- case SDLK_DELETE:
- return ke.keysym.sym;
- default:
- break;
+ switch (ke.ksym.sym)
+ {
+ case SDL::K_RETURN:
+ case SDL::K_KP_ENTER:
+ case SDL::K_TAB:
+ case SDL::K_ESCAPE:
+ case SDL::K_DELETE:
+ return ke.ksym.sym;
+ default:
+ break;
}
- int unicode = ke.keysym.unicode;
+ int unicode = ke.ksym.unicode;
// convert Ctrl characters to their 0x40-0x5F counterparts:
if (unicode < ' ')
- {
+ {
unicode += 'A' - 1;
}
@@ -1248,7 +1254,7 @@ int Core::UnicodeAwareSym(const SDL_KeyboardEvent& ke)
if('A' < unicode && unicode < 'Z')
{
unicode += 'a' - 'A';
- }
+ }
// convert various other punctuation marks:
if('\"' == unicode) unicode = '\'';
@@ -1265,29 +1271,30 @@ int Core::UnicodeAwareSym(const SDL_KeyboardEvent& ke)
return unicode;
}
+
//MEMO: return false if event is consumed
-int Core::DFH_SDL_Event(SDL_Event* ev)
+int Core::DFH_SDL_Event(SDL::Event* ev)
{
// do NOT process events before we are ready.
if(!started) return true;
if(!ev)
return true;
- if(ev && (ev->type == SDL_KEYDOWN || ev->type == SDL_KEYUP))
+ if(ev && (ev->type == SDL::ET_KEYDOWN || ev->type == SDL::ET_KEYUP))
{
- SDL_KeyboardEvent * ke = (SDL_KeyboardEvent *)ev;
+ auto ke = (SDL::KeyboardEvent *)ev;
- if(ke->state == SDL_PRESSED && !hotkey_states[ke->keysym.sym])
+ if(ke->state == SDL::BTN_PRESSED && !hotkey_states[ke->ksym.sym])
{
- hotkey_states[ke->keysym.sym] = true;
+ hotkey_states[ke->ksym.sym] = true;
int mod = 0;
- if (ke->keysym.mod & KMOD_SHIFT) mod |= 1;
- if (ke->keysym.mod & KMOD_CTRL) mod |= 2;
- if (ke->keysym.mod & KMOD_ALT) mod |= 4;
+ if (ke->ksym.mod & SDL::KMOD_SHIFT) mod |= 1;
+ if (ke->ksym.mod & SDL::KMOD_CTRL) mod |= 2;
+ if (ke->ksym.mod & SDL::KMOD_ALT) mod |= 4;
// Use unicode so Windows gives the correct value for the
// user's Input Language
- if((ke->keysym.unicode & 0xff80) == 0)
+ if((ke->ksym.unicode & 0xff80) == 0)
{
int key = UnicodeAwareSym(*ke);
SelectHotkey(key, mod);
@@ -1295,12 +1302,12 @@ int Core::DFH_SDL_Event(SDL_Event* ev)
else
{
// Pretend non-ascii characters don't happen:
- SelectHotkey(ke->keysym.sym, mod);
+ SelectHotkey(ke->ksym.sym, mod);
}
}
- else if(ke->state == SDL_RELEASED)
+ else if(ke->state == SDL::BTN_RELEASED)
{
- hotkey_states[ke->keysym.sym] = false;
+ hotkey_states[ke->ksym.sym] = false;
}
}
return true;
@@ -1317,8 +1324,8 @@ bool Core::SelectHotkey(int sym, int modifiers)
while (screen->child)
screen = screen->child;
- if (sym == SDLK_KP_ENTER)
- sym = SDLK_RETURN;
+ if (sym == SDL::K_KP_ENTER)
+ sym = SDL::K_RETURN;
std::string cmd;
@@ -1341,7 +1348,7 @@ bool Core::SelectHotkey(int sym, int modifiers)
if (cmd.empty()) {
// Check the hotkey keybindings
- int idx = sym - SDLK_F1;
+ int idx = sym - SDL::K_F1;
if(idx >= 0 && idx < 8)
{
if (modifiers & 1)
@@ -1396,13 +1403,13 @@ static bool parseKeySpec(std::string keyspec, int *psym, int *pmod, std::string
}
if (keyspec.size() == 1 && keyspec[0] >= 'A' && keyspec[0] <= 'Z') {
- *psym = SDLK_a + (keyspec[0]-'A');
+ *psym = SDL::K_a + (keyspec[0]-'A');
return true;
} else if (keyspec.size() == 2 && keyspec[0] == 'F' && keyspec[1] >= '1' && keyspec[1] <= '9') {
- *psym = SDLK_F1 + (keyspec[1]-'1');
+ *psym = SDL::K_F1 + (keyspec[1]-'1');
return true;
} else if (keyspec == "Enter") {
- *psym = SDLK_RETURN;
+ *psym = SDL::K_RETURN;
return true;
} else
return false;
diff --git a/library/Hooks-darwin.cpp b/library/Hooks-darwin.cpp
index 347881ee..ef89105d 100644
--- a/library/Hooks-darwin.cpp
+++ b/library/Hooks-darwin.cpp
@@ -83,8 +83,8 @@ DFhackCExport void SDL_Quit(void)
}
// called by DF to check input events
-static int (*_SDL_PollEvent)(SDL_Event* event) = 0;
-DFhackCExport int SDL_PollEvent(SDL_Event* event)
+static int (*_SDL_PollEvent)(SDL::Event* event) = 0;
+DFhackCExport int SDL_PollEvent(SDL::Event* event)
{
pollevent_again:
// if SDL returns 0 here, it means there are no more events. return 0
@@ -140,7 +140,7 @@ DFhackCExport int SDL_Init(uint32_t flags)
fprintf(stderr,"dfhack: saving real SDL functions\n");
_SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init");
_SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit");
- _SDL_PollEvent = (int (*)(SDL_Event*))dlsym(RTLD_NEXT,"SDL_PollEvent");
+ _SDL_PollEvent = (int (*)(SDL::Event*))dlsym(RTLD_NEXT,"SDL_PollEvent");
fprintf(stderr,"dfhack: saved real SDL functions\n");
// check if we got them
diff --git a/library/Hooks-linux.cpp b/library/Hooks-linux.cpp
index 3628aab6..ef1a765c 100644
--- a/library/Hooks-linux.cpp
+++ b/library/Hooks-linux.cpp
@@ -79,7 +79,7 @@ DFhackCExport int SDL_PollEvent(SDL::Event* event)
{
DFHack::Core & c = DFHack::Core::getInstance();
// if we consume the event, ask SDL for more.
- if(!c.SDL_Event(event))
+ if(!c.DFH_SDL_Event(event))
goto pollevent_again;
}
return orig_return;
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 6a550db8..631b3c49 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -84,6 +84,8 @@ distribution.
using namespace DFHack;
using namespace DFHack::LuaWrapper;
+void dfhack_printerr(lua_State *S, const std::string &str);
+
void Lua::Push(lua_State *state, const Units::NoblePosition &pos)
{
lua_createtable(state, 0, 3);
@@ -640,10 +642,37 @@ static void OpenModule(lua_State *state, const char *mname,
/***** DFHack module *****/
+static std::string getOSType()
+{
+ switch (Core::getInstance().vinfo->getOS())
+ {
+ case OS_WINDOWS:
+ return "windows";
+
+ case OS_LINUX:
+ return "linux";
+
+ case OS_APPLE:
+ return "darwin";
+
+ default:
+ return "unknown";
+ }
+}
+
+static std::string getDFVersion() { return Core::getInstance().vinfo->getVersion(); }
+
+static std::string getDFPath() { return Core::getInstance().p->getPath(); }
+static std::string getHackPath() { return Core::getInstance().getHackPath(); }
+
static bool isWorldLoaded() { return Core::getInstance().isWorldLoaded(); }
static bool isMapLoaded() { return Core::getInstance().isMapLoaded(); }
static const LuaWrapper::FunctionReg dfhack_module[] = {
+ WRAP(getOSType),
+ WRAP(getDFVersion),
+ WRAP(getDFPath),
+ WRAP(getHackPath),
WRAP(isWorldLoaded),
WRAP(isMapLoaded),
WRAPM(Translation, TranslateName),
@@ -715,6 +744,8 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, isDead),
WRAPM(Units, isAlive),
WRAPM(Units, isSane),
+ WRAPM(Units, isDwarf),
+ WRAPM(Units, isCitizen),
WRAPM(Units, getAge),
WRAPM(Units, getProfessionName),
WRAPM(Units, getCasteProfessionName),
@@ -988,6 +1019,207 @@ static const luaL_Reg dfhack_constructions_funcs[] = {
{ NULL, NULL }
};
+/***** Internal module *****/
+
+static void *checkaddr(lua_State *L, int idx, bool allow_null = false)
+{
+ luaL_checkany(L, idx);
+ void *rv;
+ if (lua_isnil(L, idx))
+ rv = NULL;
+ else if (lua_type(L, idx) == LUA_TNUMBER)
+ rv = (void*)lua_tounsigned(L, idx);
+ else
+ rv = Lua::CheckDFObject(L, NULL, idx);
+ if (!rv && !allow_null)
+ luaL_argerror(L, idx, "null pointer");
+ return rv;
+}
+
+static uint32_t getBase() { return Core::getInstance().p->getBase(); }
+
+static const LuaWrapper::FunctionReg dfhack_internal_module[] = {
+ WRAP(getBase),
+ { NULL, NULL }
+};
+
+static int internal_getAddress(lua_State *L)
+{
+ const char *name = luaL_checkstring(L, 1);
+ uint32_t addr = Core::getInstance().vinfo->getAddress(name);
+ if (addr)
+ lua_pushnumber(L, addr);
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+static int internal_setAddress(lua_State *L)
+{
+ std::string name = luaL_checkstring(L, 1);
+ uint32_t addr = (uint32_t)checkaddr(L, 2, true);
+ internal_getAddress(L);
+
+ // Set the address
+ Core::getInstance().vinfo->setAddress(name, addr);
+
+ auto fields = df::global::_identity.getFields();
+
+ for (int i = 0; fields && fields[i].mode != struct_field_info::END; ++i)
+ {
+ if (fields[i].name != name)
+ continue;
+
+ *(void**)fields[i].offset = (void*)addr;
+ }
+
+ // Print via printerr, so that it is definitely logged to stderr.log.
+ std::string msg = stl_sprintf("<global-address name='%s' value='0x%x'/>", name.c_str(), addr);
+ dfhack_printerr(L, msg);
+
+ return 1;
+}
+
+static int internal_getVTable(lua_State *L)
+{
+ const char *name = luaL_checkstring(L, 1);
+ uint32_t addr = (uint32_t)Core::getInstance().vinfo->getVTable(name);
+ if (addr)
+ lua_pushnumber(L, addr);
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+static int internal_getMemRanges(lua_State *L)
+{
+ std::vector<DFHack::t_memrange> ranges;
+ Core::getInstance().p->getMemRanges(ranges);
+
+ lua_newtable(L);
+
+ for(size_t i = 0; i < ranges.size(); i++)
+ {
+ lua_newtable(L);
+ lua_pushnumber(L, (uint32_t)ranges[i].start);
+ lua_setfield(L, -2, "start_addr");
+ lua_pushnumber(L, (uint32_t)ranges[i].end);
+ lua_setfield(L, -2, "end_addr");
+ lua_pushstring(L, ranges[i].name);
+ lua_setfield(L, -2, "name");
+ lua_pushboolean(L, ranges[i].read);
+ lua_setfield(L, -2, "read");
+ lua_pushboolean(L, ranges[i].write);
+ lua_setfield(L, -2, "write");
+ lua_pushboolean(L, ranges[i].execute);
+ lua_setfield(L, -2, "execute");
+ lua_pushboolean(L, ranges[i].shared);
+ lua_setfield(L, -2, "shared");
+ lua_pushboolean(L, ranges[i].valid);
+ lua_setfield(L, -2, "valid");
+ lua_rawseti(L, -2, i+1);
+ }
+
+ return 1;
+}
+
+static int internal_memmove(lua_State *L)
+{
+ void *dest = checkaddr(L, 1);
+ void *src = checkaddr(L, 2);
+ int size = luaL_checkint(L, 3);
+ if (size < 0) luaL_argerror(L, 1, "negative size");
+ memmove(dest, src, size);
+ return 0;
+}
+
+static int internal_memcmp(lua_State *L)
+{
+ void *dest = checkaddr(L, 1);
+ void *src = checkaddr(L, 2);
+ int size = luaL_checkint(L, 3);
+ if (size < 0) luaL_argerror(L, 1, "negative size");
+ lua_pushinteger(L, memcmp(dest, src, size));
+ return 1;
+}
+
+static int internal_memscan(lua_State *L)
+{
+ uint8_t *haystack = (uint8_t*)checkaddr(L, 1);
+ int hcount = luaL_checkint(L, 2);
+ int hstep = luaL_checkint(L, 3);
+ if (hstep == 0) luaL_argerror(L, 3, "zero step");
+ void *needle = checkaddr(L, 4);
+ int nsize = luaL_checkint(L, 5);
+ if (nsize < 0) luaL_argerror(L, 5, "negative size");
+
+ for (int i = 0; i <= hcount; i++)
+ {
+ uint8_t *p = haystack + i*hstep;
+ if (memcmp(p, needle, nsize) == 0) {
+ lua_pushinteger(L, i);
+ lua_pushinteger(L, (lua_Integer)p);
+ return 2;
+ }
+ }
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static int internal_diffscan(lua_State *L)
+{
+ lua_settop(L, 8);
+ void *old_data = checkaddr(L, 1);
+ void *new_data = checkaddr(L, 2);
+ int start_idx = luaL_checkint(L, 3);
+ int end_idx = luaL_checkint(L, 4);
+ int eltsize = luaL_checkint(L, 5);
+ bool has_oldv = !lua_isnil(L, 6);
+ bool has_newv = !lua_isnil(L, 7);
+ bool has_diffv = !lua_isnil(L, 8);
+
+#define LOOP(esz, etype) \
+ case esz: { \
+ etype *pold = (etype*)old_data; \
+ etype *pnew = (etype*)new_data; \
+ etype oldv = (etype)luaL_optint(L, 6, 0); \
+ etype newv = (etype)luaL_optint(L, 7, 0); \
+ etype diffv = (etype)luaL_optint(L, 8, 0); \
+ for (int i = start_idx; i < end_idx; i++) { \
+ if (pold[i] == pnew[i]) continue; \
+ if (has_oldv && pold[i] != oldv) continue; \
+ if (has_newv && pnew[i] != newv) continue; \
+ if (has_diffv && etype(pnew[i]-pold[i]) != diffv) continue; \
+ lua_pushinteger(L, i); return 1; \
+ } \
+ break; \
+ }
+ switch (eltsize) {
+ LOOP(1, uint8_t);
+ LOOP(2, uint16_t);
+ LOOP(4, uint32_t);
+ default:
+ luaL_argerror(L, 5, "invalid element size");
+ }
+#undef LOOP
+
+ lua_pushnil(L);
+ return 1;
+}
+
+static const luaL_Reg dfhack_internal_funcs[] = {
+ { "getAddress", internal_getAddress },
+ { "setAddress", internal_setAddress },
+ { "getVTable", internal_getVTable },
+ { "getMemRanges", internal_getMemRanges },
+ { "memmove", internal_memmove },
+ { "memcmp", internal_memcmp },
+ { "memscan", internal_memscan },
+ { "diffscan", internal_diffscan },
+ { NULL, NULL }
+};
+
/************************
* Main Open function *
@@ -1007,4 +1239,5 @@ void OpenDFHackApi(lua_State *state)
OpenModule(state, "burrows", dfhack_burrows_module, dfhack_burrows_funcs);
OpenModule(state, "buildings", dfhack_buildings_module, dfhack_buildings_funcs);
OpenModule(state, "constructions", dfhack_constructions_module);
+ OpenModule(state, "internal", dfhack_internal_module, dfhack_internal_funcs);
}
diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp
index f794f6b4..752c341b 100644
--- a/library/LuaTools.cpp
+++ b/library/LuaTools.cpp
@@ -66,6 +66,8 @@ using namespace DFHack::LuaWrapper;
lua_State *DFHack::Lua::Core::State = NULL;
+void dfhack_printerr(lua_State *S, const std::string &str);
+
inline void AssertCoreSuspend(lua_State *state)
{
assert(!Lua::IsCoreContext(state) || DFHack::Core::getInstance().isSuspended());
@@ -96,8 +98,6 @@ static void check_valid_ptr_index(lua_State *state, int val_index)
}
}
-static void dfhack_printerr(lua_State *S, const std::string &str);
-
static void signal_typeid_error(color_ostream *out, lua_State *state,
type_identity *type, const char *msg,
int val_index, bool perr, bool signal)
@@ -233,7 +233,7 @@ static int lua_dfhack_println(lua_State *S)
return 0;
}
-static void dfhack_printerr(lua_State *S, const std::string &str)
+void dfhack_printerr(lua_State *S, const std::string &str)
{
if (color_ostream *out = Lua::GetOutput(S))
out->printerr("%s\n", str.c_str());
diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp
index c58c25d1..8548c5d0 100644
--- a/library/LuaTypes.cpp
+++ b/library/LuaTypes.cpp
@@ -636,13 +636,35 @@ static int meta_struct_next(lua_State *state)
}
/**
+ * Field lookup for primitive refs: behave as a quasi-array with numeric indices.
+ */
+static type_identity *find_primitive_field(lua_State *state, int field, const char *mode, uint8_t **ptr)
+{
+ if (lua_type(state, field) == LUA_TNUMBER)
+ {
+ int idx = lua_tointeger(state, field);
+ if (idx < 0)
+ field_error(state, 2, "negative index", mode);
+
+ lua_rawgetp(state, UPVAL_METATABLE, &DFHACK_IDENTITY_FIELD_TOKEN);
+ auto id = (type_identity *)lua_touserdata(state, -1);
+ lua_pop(state, 1);
+
+ *ptr += int(id->byte_size()) * idx;
+ return id;
+ }
+
+ return (type_identity*)find_field(state, field, mode);
+}
+
+/**
* Metamethod: __index for primitives, i.e. simple object references.
* Fields point to identity, or NULL for metafields.
*/
static int meta_primitive_index(lua_State *state)
{
uint8_t *ptr = get_object_addr(state, 1, 2, "read");
- auto type = (type_identity*)find_field(state, 2, "read");
+ auto type = find_primitive_field(state, 2, "read", &ptr);
if (!type)
return 1;
type->lua_read(state, 2, ptr);
@@ -655,7 +677,7 @@ static int meta_primitive_index(lua_State *state)
static int meta_primitive_newindex(lua_State *state)
{
uint8_t *ptr = get_object_addr(state, 1, 2, "write");
- auto type = (type_identity*)find_field(state, 2, "write");
+ auto type = find_primitive_field(state, 2, "write", &ptr);
if (!type)
field_error(state, 2, "builtin property or method", "write");
type->lua_write(state, 2, ptr, 3);
diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp
index 471dba64..9f2fc2f1 100644
--- a/library/LuaWrapper.cpp
+++ b/library/LuaWrapper.cpp
@@ -447,10 +447,21 @@ Lua::ObjectClass Lua::IsDFObject(lua_State *state, int val_index)
}
static const char *const primitive_types[] = {
- "string", NULL
+ "string",
+ "int8_t", "uint8_t", "int16_t", "uint16_t",
+ "int32_t", "uint32_t", "int64_t", "uint64_t",
+ "bool", "float", "double",
+ NULL
};
static type_identity *const primitive_identities[] = {
- df::identity_traits<std::string>::get(), NULL
+ df::identity_traits<std::string>::get(),
+ df::identity_traits<int8_t>::get(), df::identity_traits<uint8_t>::get(),
+ df::identity_traits<int16_t>::get(), df::identity_traits<uint16_t>::get(),
+ df::identity_traits<int32_t>::get(), df::identity_traits<uint32_t>::get(),
+ df::identity_traits<int64_t>::get(), df::identity_traits<uint64_t>::get(),
+ df::identity_traits<bool>::get(),
+ df::identity_traits<float>::get(), df::identity_traits<double>::get(),
+ NULL
};
/**
@@ -644,12 +655,32 @@ static int meta_new(lua_State *state)
{
int argc = lua_gettop(state);
- if (argc != 1)
- luaL_error(state, "Usage: object:new() or df.new(object)");
+ if (argc != 1 && argc != 2)
+ luaL_error(state, "Usage: object:new() or df.new(object) or df.new(ptype,count)");
type_identity *id = get_object_identity(state, 1, "df.new()", true);
- void *ptr = id->allocate();
+ void *ptr;
+
+ // Support arrays of primitive types
+ if (argc == 2)
+ {
+ int cnt = luaL_checkint(state, 2);
+ if (cnt <= 0)
+ luaL_error(state, "Invalid array size in df.new()");
+ if (id->type() != IDTYPE_PRIMITIVE)
+ luaL_error(state, "Cannot allocate arrays of non-primitive types.");
+
+ size_t sz = id->byte_size() * cnt;
+ ptr = malloc(sz);
+ if (ptr)
+ memset(ptr, 0, sz);
+ }
+ else
+ {
+ ptr = id->allocate();
+ }
+
if (!ptr)
luaL_error(state, "Cannot allocate %s", id->getFullName().c_str());
@@ -666,6 +697,48 @@ static int meta_new(lua_State *state)
return 1;
}
+/**
+ * Method: type casting of pointers.
+ */
+static int meta_reinterpret_cast(lua_State *state)
+{
+ int argc = lua_gettop(state);
+
+ if (argc != 2)
+ luaL_error(state, "Usage: df.reinterpret_cast(type,ptr)");
+
+ type_identity *id = get_object_identity(state, 1, "df.reinterpret_cast()", true);
+
+ // Find the raw pointer value
+ void *ptr;
+
+ if (lua_isnil(state, 2))
+ ptr = NULL;
+ else if (lua_isnumber(state, 2))
+ ptr = (void*)lua_tounsigned(state, 2);
+ else
+ {
+ ptr = get_object_internal(state, NULL, 2, false, true);
+ if (!ptr)
+ luaL_error(state, "Invalid pointer argument in df.reinterpret_cast.\n");
+ }
+
+ // Convert it to the appropriate representation
+ if (ptr == NULL)
+ {
+ lua_pushnil(state);
+ }
+ else if (lua_isuserdata(state, 1))
+ {
+ lua_getmetatable(state, 1);
+ push_object_ref(state, ptr);
+ }
+ else
+ push_object_internal(state, id, ptr);
+
+ return 1;
+}
+
static void invoke_resize(lua_State *state, int table, lua_Integer size)
{
lua_getfield(state, table, "resize");
@@ -1433,6 +1506,10 @@ static int DoAttach(lua_State *state)
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_NEW_NAME);
lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPETABLE_TOKEN);
+ lua_pushcclosure(state, meta_reinterpret_cast, 1);
+ lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_CAST_NAME);
+
+ lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPETABLE_TOKEN);
lua_pushcclosure(state, meta_assign, 1);
lua_setfield(state, LUA_REGISTRYINDEX, DFHACK_ASSIGN_NAME);
@@ -1463,6 +1540,8 @@ static int DoAttach(lua_State *state)
lua_setfield(state, -2, "assign");
lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_IS_INSTANCE_NAME);
lua_setfield(state, -2, "is_instance");
+ lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_CAST_NAME);
+ lua_setfield(state, -2, "reinterpret_cast");
lua_pushlightuserdata(state, NULL);
lua_setfield(state, -2, "NULL");
diff --git a/library/Process-darwin.cpp b/library/Process-darwin.cpp
index a4b95186..5a97d9e0 100644
--- a/library/Process-darwin.cpp
+++ b/library/Process-darwin.cpp
@@ -124,34 +124,99 @@ string Process::doReadClassName (void * vptr)
return raw.substr(start,end-start);
}
-//FIXME: cross-reference with ELF segment entries?
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <mach/vm_region.h>
+#include <mach/vm_statistics.h>
+#include <dlfcn.h>
+
+const char *
+inheritance_strings[] = {
+ "SHARE", "COPY", "NONE", "DONATE_COPY",
+};
+
+const char *
+behavior_strings[] = {
+ "DEFAULT", "RANDOM", "SEQUENTIAL", "RESQNTL", "WILLNEED", "DONTNEED",
+};
+
void Process::getMemRanges( vector<t_memrange> & ranges )
{
- char buffer[1024];
- char permissions[5]; // r/-, w/-, x/-, p/s, 0
- FILE *mapFile = ::fopen("/proc/self/maps", "r");
- size_t start, end, offset, device1, device2, node;
+ kern_return_t kr;
+ task_t the_task;
- while (fgets(buffer, 1024, mapFile))
- {
- t_memrange temp;
- temp.name[0] = 0;
- sscanf(buffer, "%zx-%zx %s %zx %2zx:%2zx %zu %[^\n]",
- &start,
- &end,
- (char*)&permissions,
- &offset, &device1, &device2, &node,
- (char*)temp.name);
- temp.start = (void *) start;
- temp.end = (void *) end;
- temp.read = permissions[0] == 'r';
- temp.write = permissions[1] == 'w';
- temp.execute = permissions[2] == 'x';
- temp.shared = permissions[3] == 's';
- temp.valid = true;
- ranges.push_back(temp);
- }
+ the_task = mach_task_self();
+
+ vm_size_t vmsize;
+ vm_address_t address;
+ vm_region_basic_info_data_t info;
+ mach_msg_type_number_t info_count;
+ vm_region_flavor_t flavor;
+ memory_object_name_t object;
+
+ kr = KERN_SUCCESS;
+ address = 0;
+
+ do {
+ flavor = VM_REGION_BASIC_INFO;
+ info_count = VM_REGION_BASIC_INFO_COUNT;
+ kr = vm_region(the_task, &address, &vmsize, flavor,
+ (vm_region_info_t)&info, &info_count, &object);
+ if (kr == KERN_SUCCESS) {
+ if (info.reserved==1) {
+ address += vmsize;
+ continue;
+ }
+ Dl_info dlinfo;
+ int dlcheck;
+ dlcheck = dladdr((const void*)address, &dlinfo);
+ if (dlcheck==0) {
+ dlinfo.dli_fname = "";
+ }
+
+ t_memrange temp;
+ strncpy( temp.name, dlinfo.dli_fname, 1023 );
+ temp.name[1023] = 0;
+ temp.start = (void *) address;
+ temp.end = (void *) (address+vmsize);
+ temp.read = (info.protection & VM_PROT_READ);
+ temp.write = (info.protection & VM_PROT_WRITE);
+ temp.execute = (info.protection & VM_PROT_EXECUTE);
+ temp.shared = info.shared;
+ temp.valid = true;
+ ranges.push_back(temp);
+
+ fprintf(stderr,
+ "%08x-%08x %8uK %c%c%c/%c%c%c %11s %6s %10s uwir=%hu sub=%u dlname: %s\n",
+ address, (address + vmsize), (vmsize >> 10),
+ (info.protection & VM_PROT_READ) ? 'r' : '-',
+ (info.protection & VM_PROT_WRITE) ? 'w' : '-',
+ (info.protection & VM_PROT_EXECUTE) ? 'x' : '-',
+ (info.max_protection & VM_PROT_READ) ? 'r' : '-',
+ (info.max_protection & VM_PROT_WRITE) ? 'w' : '-',
+ (info.max_protection & VM_PROT_EXECUTE) ? 'x' : '-',
+ inheritance_strings[info.inheritance],
+ (info.shared) ? "shared" : "-",
+ behavior_strings[info.behavior],
+ info.user_wired_count,
+ info.reserved,
+ dlinfo.dli_fname);
+
+ address += vmsize;
+ } else if (kr != KERN_INVALID_ADDRESS) {
+
+ /*if (the_task != MACH_PORT_NULL) {
+ mach_port_deallocate(mach_task_self(), the_task);
+ }*/
+ return;
+ }
+ } while (kr != KERN_INVALID_ADDRESS);
+
+
+/* if (the_task != MACH_PORT_NULL) {
+ mach_port_deallocate(mach_task_self(), the_task);
+ }*/
}
uint32_t Process::getBase()
diff --git a/library/RemoteClient.cpp b/library/RemoteClient.cpp
index a1ac2ec9..4d30988c 100644
--- a/library/RemoteClient.cpp
+++ b/library/RemoteClient.cpp
@@ -329,17 +329,19 @@ bool sendRemoteMessage(CSimpleSocket *socket, int16_t id, const MessageLite *msg
int size = size_ready ? msg->GetCachedSize() : msg->ByteSize();
int fullsz = size + sizeof(RPCMessageHeader);
- std::auto_ptr<uint8_t> data(new uint8_t[fullsz]);
- RPCMessageHeader *hdr = (RPCMessageHeader*)data.get();
+ uint8_t *data = new uint8_t[fullsz];
+ RPCMessageHeader *hdr = (RPCMessageHeader*)data;
hdr->id = id;
hdr->size = size;
- uint8_t *pstart = data.get() + sizeof(RPCMessageHeader);
+ uint8_t *pstart = data + sizeof(RPCMessageHeader);
uint8_t *pend = msg->SerializeWithCachedSizesToArray(pstart);
assert((pend - pstart) == size);
- return (socket->Send(data.get(), fullsz) == fullsz);
+ int got = socket->Send(data, fullsz);
+ delete[] data;
+ return (got == fullsz);
}
command_result RemoteFunctionBase::execute(color_ostream &out,
@@ -402,9 +404,9 @@ command_result RemoteFunctionBase::execute(color_ostream &out,
return CR_LINK_FAILURE;
}
- std::auto_ptr<uint8_t> buf(new uint8_t[header.size]);
+ uint8_t *buf = new uint8_t[header.size];
- if (!readFullBuffer(p_client->socket, buf.get(), header.size))
+ if (!readFullBuffer(p_client->socket, buf, header.size))
{
out.printerr("In call to %s::%s: I/O error in receive %d bytes of data.\n",
this->proto.c_str(), this->name.c_str(), header.size);
@@ -413,18 +415,20 @@ command_result RemoteFunctionBase::execute(color_ostream &out,
switch (header.id) {
case RPC_REPLY_RESULT:
- if (!output->ParseFromArray(buf.get(), header.size))
+ if (!output->ParseFromArray(buf, header.size))
{
out.printerr("In call to %s::%s: error parsing received result.\n",
this->proto.c_str(), this->name.c_str());
+ delete[] buf;
return CR_LINK_FAILURE;
}
+ delete[] buf;
return CR_OK;
case RPC_REPLY_TEXT:
text_data.Clear();
- if (text_data.ParseFromArray(buf.get(), header.size))
+ if (text_data.ParseFromArray(buf, header.size))
text_decoder.decode(&text_data);
else
out.printerr("In call to %s::%s: received invalid text data.\n",
@@ -434,5 +438,6 @@ command_result RemoteFunctionBase::execute(color_ostream &out,
default:
break;
}
+ delete[] buf;
}
}
diff --git a/library/RemoteServer.cpp b/library/RemoteServer.cpp
index ed47890f..53428f2b 100644
--- a/library/RemoteServer.cpp
+++ b/library/RemoteServer.cpp
@@ -220,7 +220,7 @@ void ServerConnection::threadFn()
}
if (memcmp(header.magic, RPCHandshakeHeader::REQUEST_MAGIC, sizeof(header.magic)) ||
- header.version != 1)
+ header.version < 1 || header.version > 255)
{
out << "In RPC server: invalid handshake header." << endl;
return;
diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp
index 689c783a..95c495e9 100644
--- a/library/RemoteTools.cpp
+++ b/library/RemoteTools.cpp
@@ -379,19 +379,19 @@ static command_result GetWorldInfo(color_ostream &stream,
if (!ui || !world || !Core::getInstance().isWorldLoaded())
return CR_NOT_FOUND;
- t_gamemodes mode;
- if (!Core::getInstance().getWorld()->ReadGameMode(mode))
- mode.g_type = GAMETYPE_DWARF_MAIN;
+ df::game_type gt = game_type::DWARF_MAIN;
+ if (df::global::gametype)
+ gt = *df::global::gametype;
out->set_save_dir(world->cur_savegame.save_dir);
if (world->world_data->name.has_name)
describeName(out->mutable_world_name(), &world->world_data->name);
- switch (mode.g_type)
+ switch (gt)
{
- case GAMETYPE_DWARF_MAIN:
- case GAMETYPE_DWARF_RECLAIM:
+ case game_type::DWARF_MAIN:
+ case game_type::DWARF_RECLAIM:
out->set_mode(GetWorldInfoOut::MODE_DWARF);
out->set_civ_id(ui->civ_id);
out->set_site_id(ui->site_id);
@@ -399,7 +399,7 @@ static command_result GetWorldInfo(color_ostream &stream,
out->set_race_id(ui->race_id);
break;
- case GAMETYPE_ADVENTURE_MAIN:
+ case game_type::ADVENTURE_MAIN:
out->set_mode(GetWorldInfoOut::MODE_ADVENTURE);
if (auto unit = vector_get(world->units.active, 0))
@@ -423,7 +423,7 @@ static command_result GetWorldInfo(color_ostream &stream,
}
break;
- case GAMETYPE_VIEW_LEGENDS:
+ case game_type::VIEW_LEGENDS:
out->set_mode(GetWorldInfoOut::MODE_LEGENDS);
break;
diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp
index 36dbd9aa..4ac53dd1 100644
--- a/library/VersionInfoFactory.cpp
+++ b/library/VersionInfoFactory.cpp
@@ -105,9 +105,15 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem)
// this is wrong... I'm not going to do base image relocation on linux though.
mem->setBase(0x0);
}
+ else if(os == "darwin")
+ {
+ mem->setOS(OS_APPLE);
+ // this is wrong... I'm not going to do base image relocation on linux though.
+ mem->setBase(0x0);
+ }
else
{
- throw Error::SymbolsXmlBadAttribute("os-type");
+ return; // ignore it if it's invalid
}
// process additional entries
diff --git a/library/include/Console.h b/library/include/Console.h
index 196a1c27..ba59324e 100644
--- a/library/include/Console.h
+++ b/library/include/Console.h
@@ -65,20 +65,20 @@ namespace DFHack
bool save (const char * filename)
{
std::ofstream outfile (filename);
- fprintf(stderr,"Save: Initialized stream\n");
+ //fprintf(stderr,"Save: Initialized stream\n");
if(outfile.bad())
return false;
- fprintf(stderr,"Save: Iterating...\n");
+ //fprintf(stderr,"Save: Iterating...\n");
for(auto iter = history.begin();iter < history.end(); iter++)
{
- fprintf(stderr,"Save: Dumping %s\n",(*iter).c_str());
+ //fprintf(stderr,"Save: Dumping %s\n",(*iter).c_str());
outfile << *iter << std::endl;
- fprintf(stderr,"Save: Flushing\n");
+ //fprintf(stderr,"Save: Flushing\n");
outfile.flush();
}
- fprintf(stderr,"Save: Closing\n");
+ //fprintf(stderr,"Save: Closing\n");
outfile.close();
- fprintf(stderr,"Save: Done\n");
+ //fprintf(stderr,"Save: Done\n");
return true;
}
/// add a command to the history
diff --git a/library/include/Core.h b/library/include/Core.h
index 2810ff14..e4d1080d 100644
--- a/library/include/Core.h
+++ b/library/include/Core.h
@@ -33,7 +33,6 @@ distribution.
#include <stdint.h>
#include "Console.h"
#include "modules/Graphic.h"
-#include "SDL_events.h"
#include "RemoteClient.h"
@@ -86,14 +85,14 @@ namespace DFHack
{
friend int ::SDL_NumJoysticks(void);
friend void ::SDL_Quit(void);
- friend int ::SDL_PollEvent(SDL_Event *);
+ friend int ::SDL_PollEvent(SDL::Event *);
friend int ::SDL_Init(uint32_t flags);
friend int ::wgetch(WINDOW * w);
friend int ::egg_init(void);
friend int ::egg_shutdown(void);
friend int ::egg_tick(void);
friend int ::egg_prerender(void);
- friend int ::egg_sdl_event(SDL_Event* event);
+ friend int ::egg_sdl_event(SDL::Event* event);
friend int ::egg_curses_event(int orig_return);
public:
/// Get the single Core instance or make one.
@@ -170,7 +169,7 @@ namespace DFHack
int Update (void);
int TileUpdate (void);
int Shutdown (void);
- int DFH_SDL_Event(SDL_Event* event);
+ int DFH_SDL_Event(SDL::Event* event);
bool ncurses_wgetch(int in, int & out);
void onUpdate(color_ostream &out);
@@ -215,7 +214,6 @@ namespace DFHack
tthread::mutex * HotkeyMutex;
tthread::condition_variable * HotkeyCond;
- int UnicodeAwareSym(const SDL_KeyboardEvent& ke);
bool SelectHotkey(int key, int modifiers);
// for state change tracking
diff --git a/library/include/DataFuncs.h b/library/include/DataFuncs.h
index aff04128..637a532f 100644
--- a/library/include/DataFuncs.h
+++ b/library/include/DataFuncs.h
@@ -160,6 +160,17 @@ INSTANTIATE_WRAPPERS(6, (OSTREAM_ARG,A1,A2,A3,A4,A5,A6), (out,vA1,vA2,vA3,vA4,vA
#define FW_TARGS class A1, class A2, class A3, class A4, class A5, class A6, class A7
INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4,A5,A6,A7))
+INSTANTIATE_WRAPPERS(7, (A1,A2,A3,A4,A5,A6,A7), (vA1,vA2,vA3,vA4,vA5,vA6,vA7),
+ LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3);
+ LOAD_ARG(A4); LOAD_ARG(A5); LOAD_ARG(A6);
+ LOAD_ARG(A7);)
+INSTANTIATE_WRAPPERS(7, (OSTREAM_ARG,A1,A2,A3,A4,A5,A6,A7), (out,vA1,vA2,vA3,vA4,vA5,vA6,vA7),
+ LOAD_OSTREAM(out); LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3);
+ LOAD_ARG(A4); LOAD_ARG(A5); LOAD_ARG(A6); LOAD_ARG(A7);)
+#undef FW_TARGS
+
+#define FW_TARGS class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8
+INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4,A5,A6,A7,A8))
#undef FW_TARGS
#undef FW_TARGSC
diff --git a/library/include/Hooks.h b/library/include/Hooks.h
index 83a39ea1..418a5ce3 100644
--- a/library/include/Hooks.h
+++ b/library/include/Hooks.h
@@ -33,8 +33,6 @@ distribution.
#include <string>
#include <stdint.h>
-#include "SDL.h"
-
// function and variable pointer... we don't try to understand what SDL does here
typedef void * fPtr;
typedef void * vPtr;
@@ -48,7 +46,7 @@ namespace SDL
// be declared as friend functions/known
DFhackCExport int SDL_NumJoysticks(void);
DFhackCExport void SDL_Quit(void);
-DFhackCExport int SDL_PollEvent(SDL_Event* event);
+DFhackCExport int SDL_PollEvent(SDL::Event* event);
DFhackCExport int SDL_Init(uint32_t flags);
DFhackCExport int wgetch(WINDOW * win);
@@ -65,7 +63,7 @@ DFhackCExport int egg_tick(void);
DFhackCExport int egg_prerender(void);
// hook - called for each SDL event, can filter both the event and the return value
-DFhackCExport int egg_sdl_event(SDL_Event* event);
+DFhackCExport int egg_sdl_event(SDL::Event* event);
// hook - ncurses event. return -1 to consume
DFhackCExport int egg_curses_event(int orig_return);
diff --git a/library/include/LuaWrapper.h b/library/include/LuaWrapper.h
index 97b2e698..9e449022 100644
--- a/library/include/LuaWrapper.h
+++ b/library/include/LuaWrapper.h
@@ -77,6 +77,7 @@ namespace DFHack { namespace LuaWrapper {
#define DFHACK_ASSIGN_NAME "DFHack::Assign"
#define DFHACK_IS_INSTANCE_NAME "DFHack::IsInstance"
#define DFHACK_DELETE_NAME "DFHack::Delete"
+#define DFHACK_CAST_NAME "DFHack::Cast"
extern LuaToken DFHACK_EMPTY_TABLE_TOKEN;
diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h
index 31633dfe..b76df437 100644
--- a/library/include/PluginManager.h
+++ b/library/include/PluginManager.h
@@ -61,11 +61,11 @@ namespace DFHack
struct DFLibrary;
// Open a plugin library
- DFLibrary * OpenPlugin (const char * filename);
+ DFHACK_EXPORT DFLibrary * OpenPlugin (const char * filename);
// find a symbol inside plugin
- void * LookupPlugin (DFLibrary * plugin ,const char * function);
+ DFHACK_EXPORT void * LookupPlugin (DFLibrary * plugin ,const char * function);
// Close a plugin library
- void ClosePlugin (DFLibrary * plugin);
+ DFHACK_EXPORT void ClosePlugin (DFLibrary * plugin);
struct DFHACK_EXPORT CommandReg {
const char *name;
diff --git a/library/include/SDL_events.h b/library/include/SDL_events.h
new file mode 100644
index 00000000..0457dbca
--- /dev/null
+++ b/library/include/SDL_events.h
@@ -0,0 +1,210 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+
+// Fake - only structs. Shamelessly pilfered from the SDL library.
+// Needed for processing its event types without polluting our namespaces with C garbage
+
+#pragma once
+#include "SDL_keyboard.h"
+
+namespace SDL
+{
+ enum ButtonState
+ {
+ BTN_RELEASED = 0,
+ BTN_PRESSED = 1
+ };
+
+ /** Event enumerations */
+ enum EventType
+ {
+ ET_NOEVENT = 0, /**< Unused (do not remove) */
+ ET_ACTIVEEVENT, /**< Application loses/gains visibility */
+ ET_KEYDOWN, /**< Keys pressed */
+ ET_KEYUP, /**< Keys released */
+ ET_MOUSEMOTION, /**< Mouse moved */
+ ET_MOUSEBUTTONDOWN, /**< Mouse button pressed */
+ ET_MOUSEBUTTONUP, /**< Mouse button released */
+ ET_JOYAXISMOTION, /**< Joystick axis motion */
+ ET_JOYBALLMOTION, /**< Joystick trackball motion */
+ ET_JOYHATMOTION, /**< Joystick hat position change */
+ ET_JOYBUTTONDOWN, /**< Joystick button pressed */
+ ET_JOYBUTTONUP, /**< Joystick button released */
+ ET_QUIT, /**< User-requested quit */
+ ET_SYSWMEVENT, /**< System specific event */
+ ET_EVENT_RESERVEDA, /**< Reserved for future use.. */
+ ET_EVENT_RESERVEDB, /**< Reserved for future use.. */
+ ET_VIDEORESIZE, /**< User resized video mode */
+ ET_VIDEOEXPOSE, /**< Screen needs to be redrawn */
+ ET_EVENT_RESERVED2, /**< Reserved for future use.. */
+ ET_EVENT_RESERVED3, /**< Reserved for future use.. */
+ ET_EVENT_RESERVED4, /**< Reserved for future use.. */
+ ET_EVENT_RESERVED5, /**< Reserved for future use.. */
+ ET_EVENT_RESERVED6, /**< Reserved for future use.. */
+ ET_EVENT_RESERVED7, /**< Reserved for future use.. */
+ /** Events ET_USEREVENT through ET_MAXEVENTS-1 are for your use */
+ ET_USEREVENT = 24,
+ /** This last event is only for bounding internal arrays
+ * It is the number of bits in the event mask datatype -- Uint32
+ */
+ ET_NUMEVENTS = 32
+ };
+
+ /** Application visibility event structure */
+ struct ActiveEvent
+ {
+ uint8_t type; /**< ET_ACTIVEEVENT */
+ uint8_t gain; /**< Whether given states were gained or lost (1/0) */
+ uint8_t state; /**< A mask of the focus states */
+ };
+
+ /** Keyboard event structure */
+ struct KeyboardEvent
+ {
+ uint8_t type; /**< ET_KEYDOWN or ET_KEYUP */
+ uint8_t which; /**< The keyboard device index */
+ uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */
+ keysym ksym;
+ };
+
+ /** Mouse motion event structure */
+ struct MouseMotionEvent
+ {
+ uint8_t type; /**< ET_MOUSEMOTION */
+ uint8_t which; /**< The mouse device index */
+ uint8_t state; /**< The current button state */
+ uint16_t x, y; /**< The X/Y coordinates of the mouse */
+ int16_t xrel; /**< The relative motion in the X direction */
+ int16_t yrel; /**< The relative motion in the Y direction */
+ };
+
+ /** Mouse button event structure */
+ struct MouseButtonEvent
+ {
+ uint8_t type; /**< ET_MOUSEBUTTONDOWN or ET_MOUSEBUTTONUP */
+ uint8_t which; /**< The mouse device index */
+ uint8_t button; /**< The mouse button index */
+ uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */
+ uint16_t x, y; /**< The X/Y coordinates of the mouse at press time */
+ };
+
+ /** Joystick axis motion event structure */
+ struct JoyAxisEvent
+ {
+ uint8_t type; /**< ET_JOYAXISMOTION */
+ uint8_t which; /**< The joystick device index */
+ uint8_t axis; /**< The joystick axis index */
+ int16_t value; /**< The axis value (range: -32768 to 32767) */
+ };
+
+ /** Joystick trackball motion event structure */
+ struct JoyBallEvent
+ {
+ uint8_t type; /**< ET_JOYBALLMOTION */
+ uint8_t which; /**< The joystick device index */
+ uint8_t ball; /**< The joystick trackball index */
+ int16_t xrel; /**< The relative motion in the X direction */
+ int16_t yrel; /**< The relative motion in the Y direction */
+ };
+
+ /** Joystick hat position change event structure */
+ struct JoyHatEvent
+ {
+ uint8_t type; /**< ET_JOYHATMOTION */
+ uint8_t which; /**< The joystick device index */
+ uint8_t hat; /**< The joystick hat index */
+ uint8_t value; /**< The hat position value:
+ * SDL_HAT_LEFTUP SDL_HAT_UP SDL_HAT_RIGHTUP
+ * SDL_HAT_LEFT SDL_HAT_CENTERED SDL_HAT_RIGHT
+ * SDL_HAT_LEFTDOWN SDL_HAT_DOWN SDL_HAT_RIGHTDOWN
+ * Note that zero means the POV is centered.
+ */
+ };
+
+ /** Joystick button event structure */
+ struct JoyButtonEvent
+ {
+ uint8_t type; /**< ET_JOYBUTTONDOWN or ET_JOYBUTTONUP */
+ uint8_t which; /**< The joystick device index */
+ uint8_t button; /**< The joystick button index */
+ uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */
+ };
+
+ /** The "window resized" event
+ * When you get this event, you are responsible for setting a new video
+ * mode with the new width and height.
+ */
+ struct ResizeEvent
+ {
+ uint8_t type; /**< ET_VIDEORESIZE */
+ int w; /**< New width */
+ int h; /**< New height */
+ };
+
+ /** The "screen redraw" event */
+ struct ExposeEvent
+ {
+ uint8_t type; /**< ET_VIDEOEXPOSE */
+ };
+
+ /** The "quit requested" event */
+ struct QuitEvent
+ {
+ uint8_t type; /**< ET_QUIT */
+ };
+
+ /** A user-defined event type */
+ struct UserEvent
+ {
+ uint8_t type; /**< ETL_USEREVENT through ET_NUMEVENTS-1 */
+ int code; /**< User defined event code */
+ void *data1; /**< User defined data pointer */
+ void *data2; /**< User defined data pointer */
+ };
+
+ /** If you want to use this event, you should include SDL_syswm.h */
+ struct SysWMmsg;
+ struct SysWMEvent
+ {
+ uint8_t type;
+ SysWMmsg *msg;
+ };
+
+ /** General event structure */
+ union Event
+ {
+ uint8_t type;
+ ActiveEvent active;
+ KeyboardEvent key;
+ MouseMotionEvent motion;
+ MouseButtonEvent button;
+ JoyAxisEvent jaxis;
+ JoyBallEvent jball;
+ JoyHatEvent jhat;
+ JoyButtonEvent jbutton;
+ ResizeEvent resize;
+ ExposeEvent expose;
+ QuitEvent quit;
+ UserEvent user;
+ SysWMEvent syswm;
+ };
+} \ No newline at end of file
diff --git a/library/include/SDL_keyboard.h b/library/include/SDL_keyboard.h
new file mode 100644
index 00000000..f0d325f5
--- /dev/null
+++ b/library/include/SDL_keyboard.h
@@ -0,0 +1,61 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+
+// Fake - only structs. Shamelessly pilfered from the SDL library.
+// Needed for processing its event types without polluting our namespaces with C garbage
+
+#pragma once
+#include "SDL_keysym.h"
+#include <stdint.h>
+
+namespace SDL
+{
+ /** Keysym structure
+ *
+ * - The scancode is hardware dependent, and should not be used by general
+ * applications. If no hardware scancode is available, it will be 0.
+ *
+ * - The 'unicode' translated character is only available when character
+ * translation is enabled by the SDL_EnableUNICODE() API. If non-zero,
+ * this is a UNICODE character corresponding to the keypress. If the
+ * high 9 bits of the character are 0, then this maps to the equivalent
+ * ASCII character:
+ * @code
+ * char ch;
+ * if ( (keysym.unicode & 0xFF80) == 0 ) {
+ * ch = keysym.unicode & 0x7F;
+ * } else {
+ * An international character..
+ * }
+ * @endcode
+ */
+ typedef struct keysym
+ {
+ uint8_t scancode; /**< hardware specific scancode */
+ Key sym; /**< SDL virtual keysym */
+ Mod mod; /**< current key modifiers */
+ uint16_t unicode; /**< translated character */
+ } keysym;
+
+ /** This is the mask which refers to all hotkey bindings */
+ #define ALL_HOTKEYS 0xFFFFFFFF
+} \ No newline at end of file
diff --git a/library/include/SDL_keysym.h b/library/include/SDL_keysym.h
new file mode 100644
index 00000000..4f01cfa9
--- /dev/null
+++ b/library/include/SDL_keysym.h
@@ -0,0 +1,329 @@
+/*
+ SDL - Simple DirectMedia Layer
+ Copyright (C) 1997-2009 Sam Lantinga
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ Sam Lantinga
+ slouken@libsdl.org
+*/
+
+// Fake - only structs. Shamelessly pilfered from the SDL library.
+// Needed for processing its event types without polluting our namespaces with C garbage
+
+#pragma once
+
+namespace SDL
+{
+ /** What we really want is a mapping of every raw key on the keyboard.
+ * To support international keyboards, we use the range 0xA1 - 0xFF
+ * as international virtual keycodes. We'll follow in the footsteps of X11...
+ * @brief The names of the keys
+ */
+ enum Key
+ {
+ /** @name ASCII mapped keysyms
+ * The keyboard syms have been cleverly chosen to map to ASCII
+ */
+ /*@{*/
+ K_UNKNOWN = 0,
+ K_FIRST = 0,
+ K_BACKSPACE = 8,
+ K_TAB = 9,
+ K_CLEAR = 12,
+ K_RETURN = 13,
+ K_PAUSE = 19,
+ K_ESCAPE = 27,
+ K_SPACE = 32,
+ K_EXCLAIM = 33,
+ K_QUOTEDBL = 34,
+ K_HASH = 35,
+ K_DOLLAR = 36,
+ K_AMPERSAND = 38,
+ K_QUOTE = 39,
+ K_LEFTPAREN = 40,
+ K_RIGHTPAREN = 41,
+ K_ASTERISK = 42,
+ K_PLUS = 43,
+ K_COMMA = 44,
+ K_MINUS = 45,
+ K_PERIOD = 46,
+ K_SLASH = 47,
+ K_0 = 48,
+ K_1 = 49,
+ K_2 = 50,
+ K_3 = 51,
+ K_4 = 52,
+ K_5 = 53,
+ K_6 = 54,
+ K_7 = 55,
+ K_8 = 56,
+ K_9 = 57,
+ K_COLON = 58,
+ K_SEMICOLON = 59,
+ K_LESS = 60,
+ K_EQUALS = 61,
+ K_GREATER = 62,
+ K_QUESTION = 63,
+ K_AT = 64,
+ /*
+ Skip uppercase letters
+ */
+ K_LEFTBRACKET = 91,
+ K_BACKSLASH = 92,
+ K_RIGHTBRACKET = 93,
+ K_CARET = 94,
+ K_UNDERSCORE = 95,
+ K_BACKQUOTE = 96,
+ K_a = 97,
+ K_b = 98,
+ K_c = 99,
+ K_d = 100,
+ K_e = 101,
+ K_f = 102,
+ K_g = 103,
+ K_h = 104,
+ K_i = 105,
+ K_j = 106,
+ K_k = 107,
+ K_l = 108,
+ K_m = 109,
+ K_n = 110,
+ K_o = 111,
+ K_p = 112,
+ K_q = 113,
+ K_r = 114,
+ K_s = 115,
+ K_t = 116,
+ K_u = 117,
+ K_v = 118,
+ K_w = 119,
+ K_x = 120,
+ K_y = 121,
+ K_z = 122,
+ K_DELETE = 127,
+ /* End of ASCII mapped keysyms */
+ /*@}*/
+
+ /** @name International keyboard syms */
+ /*@{*/
+ K_WORLD_0 = 160, /* 0xA0 */
+ K_WORLD_1 = 161,
+ K_WORLD_2 = 162,
+ K_WORLD_3 = 163,
+ K_WORLD_4 = 164,
+ K_WORLD_5 = 165,
+ K_WORLD_6 = 166,
+ K_WORLD_7 = 167,
+ K_WORLD_8 = 168,
+ K_WORLD_9 = 169,
+ K_WORLD_10 = 170,
+ K_WORLD_11 = 171,
+ K_WORLD_12 = 172,
+ K_WORLD_13 = 173,
+ K_WORLD_14 = 174,
+ K_WORLD_15 = 175,
+ K_WORLD_16 = 176,
+ K_WORLD_17 = 177,
+ K_WORLD_18 = 178,
+ K_WORLD_19 = 179,
+ K_WORLD_20 = 180,
+ K_WORLD_21 = 181,
+ K_WORLD_22 = 182,
+ K_WORLD_23 = 183,
+ K_WORLD_24 = 184,
+ K_WORLD_25 = 185,
+ K_WORLD_26 = 186,
+ K_WORLD_27 = 187,
+ K_WORLD_28 = 188,
+ K_WORLD_29 = 189,
+ K_WORLD_30 = 190,
+ K_WORLD_31 = 191,
+ K_WORLD_32 = 192,
+ K_WORLD_33 = 193,
+ K_WORLD_34 = 194,
+ K_WORLD_35 = 195,
+ K_WORLD_36 = 196,
+ K_WORLD_37 = 197,
+ K_WORLD_38 = 198,
+ K_WORLD_39 = 199,
+ K_WORLD_40 = 200,
+ K_WORLD_41 = 201,
+ K_WORLD_42 = 202,
+ K_WORLD_43 = 203,
+ K_WORLD_44 = 204,
+ K_WORLD_45 = 205,
+ K_WORLD_46 = 206,
+ K_WORLD_47 = 207,
+ K_WORLD_48 = 208,
+ K_WORLD_49 = 209,
+ K_WORLD_50 = 210,
+ K_WORLD_51 = 211,
+ K_WORLD_52 = 212,
+ K_WORLD_53 = 213,
+ K_WORLD_54 = 214,
+ K_WORLD_55 = 215,
+ K_WORLD_56 = 216,
+ K_WORLD_57 = 217,
+ K_WORLD_58 = 218,
+ K_WORLD_59 = 219,
+ K_WORLD_60 = 220,
+ K_WORLD_61 = 221,
+ K_WORLD_62 = 222,
+ K_WORLD_63 = 223,
+ K_WORLD_64 = 224,
+ K_WORLD_65 = 225,
+ K_WORLD_66 = 226,
+ K_WORLD_67 = 227,
+ K_WORLD_68 = 228,
+ K_WORLD_69 = 229,
+ K_WORLD_70 = 230,
+ K_WORLD_71 = 231,
+ K_WORLD_72 = 232,
+ K_WORLD_73 = 233,
+ K_WORLD_74 = 234,
+ K_WORLD_75 = 235,
+ K_WORLD_76 = 236,
+ K_WORLD_77 = 237,
+ K_WORLD_78 = 238,
+ K_WORLD_79 = 239,
+ K_WORLD_80 = 240,
+ K_WORLD_81 = 241,
+ K_WORLD_82 = 242,
+ K_WORLD_83 = 243,
+ K_WORLD_84 = 244,
+ K_WORLD_85 = 245,
+ K_WORLD_86 = 246,
+ K_WORLD_87 = 247,
+ K_WORLD_88 = 248,
+ K_WORLD_89 = 249,
+ K_WORLD_90 = 250,
+ K_WORLD_91 = 251,
+ K_WORLD_92 = 252,
+ K_WORLD_93 = 253,
+ K_WORLD_94 = 254,
+ K_WORLD_95 = 255, /* 0xFF */
+ /*@}*/
+
+ /** @name Numeric keypad */
+ /*@{*/
+ K_KP0 = 256,
+ K_KP1 = 257,
+ K_KP2 = 258,
+ K_KP3 = 259,
+ K_KP4 = 260,
+ K_KP5 = 261,
+ K_KP6 = 262,
+ K_KP7 = 263,
+ K_KP8 = 264,
+ K_KP9 = 265,
+ K_KP_PERIOD = 266,
+ K_KP_DIVIDE = 267,
+ K_KP_MULTIPLY = 268,
+ K_KP_MINUS = 269,
+ K_KP_PLUS = 270,
+ K_KP_ENTER = 271,
+ K_KP_EQUALS = 272,
+ /*@}*/
+
+ /** @name Arrows + Home/End pad */
+ /*@{*/
+ K_UP = 273,
+ K_DOWN = 274,
+ K_RIGHT = 275,
+ K_LEFT = 276,
+ K_INSERT = 277,
+ K_HOME = 278,
+ K_END = 279,
+ K_PAGEUP = 280,
+ K_PAGEDOWN = 281,
+ /*@}*/
+
+ /** @name Function keys */
+ /*@{*/
+ K_F1 = 282,
+ K_F2 = 283,
+ K_F3 = 284,
+ K_F4 = 285,
+ K_F5 = 286,
+ K_F6 = 287,
+ K_F7 = 288,
+ K_F8 = 289,
+ K_F9 = 290,
+ K_F10 = 291,
+ K_F11 = 292,
+ K_F12 = 293,
+ K_F13 = 294,
+ K_F14 = 295,
+ K_F15 = 296,
+ /*@}*/
+
+ /** @name Key state modifier keys */
+ /*@{*/
+ K_NUMLOCK = 300,
+ K_CAPSLOCK = 301,
+ K_SCROLLOCK = 302,
+ K_RSHIFT = 303,
+ K_LSHIFT = 304,
+ K_RCTRL = 305,
+ K_LCTRL = 306,
+ K_RALT = 307,
+ K_LALT = 308,
+ K_RMETA = 309,
+ K_LMETA = 310,
+ K_LSUPER = 311, /**< Left "Windows" key */
+ K_RSUPER = 312, /**< Right "Windows" key */
+ K_MODE = 313, /**< "Alt Gr" key */
+ K_COMPOSE = 314, /**< Multi-key compose key */
+ /*@}*/
+
+ /** @name Miscellaneous function keys */
+ /*@{*/
+ K_HELP = 315,
+ K_PRINT = 316,
+ K_SYSREQ = 317,
+ K_BREAK = 318,
+ K_MENU = 319,
+ K_POWER = 320, /**< Power Macintosh power key */
+ K_EURO = 321, /**< Some european keyboards */
+ K_UNDO = 322, /**< Atari keyboard has Undo */
+ /*@}*/
+
+ /* Add any other keys here */
+
+ K_LAST
+ };
+
+ /** Enumeration of valid key mods (possibly OR'd together) */
+ enum Mod {
+ KMOD_NONE = 0x0000,
+ KMOD_LSHIFT= 0x0001,
+ KMOD_RSHIFT= 0x0002,
+ KMOD_LCTRL = 0x0040,
+ KMOD_RCTRL = 0x0080,
+ KMOD_LALT = 0x0100,
+ KMOD_RALT = 0x0200,
+ KMOD_LMETA = 0x0400,
+ KMOD_RMETA = 0x0800,
+ KMOD_NUM = 0x1000,
+ KMOD_CAPS = 0x2000,
+ KMOD_MODE = 0x4000,
+ KMOD_RESERVED = 0x8000,
+ KMOD_CTRL = (KMOD_LCTRL|KMOD_RCTRL),
+ KMOD_SHIFT = (KMOD_LSHIFT|KMOD_RSHIFT),
+ KMOD_ALT = (KMOD_LALT|KMOD_RALT),
+ KMOD_META = (KMOD_LMETA|KMOD_RMETA)
+ };
+} \ No newline at end of file
diff --git a/library/include/modules/World.h b/library/include/modules/World.h
index 81ebfbd6..8b0fe3f5 100644
--- a/library/include/modules/World.h
+++ b/library/include/modules/World.h
@@ -35,32 +35,15 @@ distribution.
#include "Module.h"
#include <ostream>
+#include "DataDefs.h"
+
namespace DFHack
{
- /**
- * \ingroup grp_world
- */
- enum GameMode
- {
- GAMEMODE_DWARF,
- GAMEMODE_ADVENTURE,
- GAMEMODENUM,
- GAMEMODE_NONE
- };
- /**
- * \ingroup grp_world
- */
- enum GameType
- {
- GAMETYPE_DWARF_MAIN,
- GAMETYPE_ADVENTURE_MAIN,
- GAMETYPE_VIEW_LEGENDS,
- GAMETYPE_DWARF_RECLAIM,
- GAMETYPE_DWARF_ARENA,
- GAMETYPE_ADVENTURE_ARENA,
- GAMETYPENUM,
- GAMETYPE_NONE
- };
+ typedef df::game_mode GameMode;
+ typedef df::game_type GameType;
+
+#define GAMEMODE_ADVENTURE df::enums::game_mode::ADVENTURE
+
/**
* \ingroup grp_world
*/
diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua
index 926600c0..4cdb4c95 100644
--- a/library/lua/dfhack.lua
+++ b/library/lua/dfhack.lua
@@ -273,19 +273,24 @@ end
-- Command scripts
-dfhack.scripts = dfhack.scripts or {}
+dfhack.internal.scripts = dfhack.internal.scripts or {}
-function dfhack.run_script(file,...)
- local env = dfhack.scripts[file]
+local scripts = dfhack.internal.scripts
+local hack_path = dfhack.getHackPath()
+
+function dfhack.run_script(name,...)
+ local key = string.lower(name)
+ local file = hack_path..'scripts/'..name..'.lua'
+ local env = scripts[key]
if env == nil then
env = {}
setmetatable(env, { __index = base_env })
- dfhack.scripts[file] = env
end
local f,perr = loadfile(file, 't', env)
if f == nil then
error(perr)
end
+ scripts[key] = env
return f(...)
end
diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua
new file mode 100644
index 00000000..95b9197b
--- /dev/null
+++ b/library/lua/memscan.lua
@@ -0,0 +1,455 @@
+-- Utilities for offset scan scripts.
+
+local _ENV = mkmodule('memscan')
+
+local utils = require('utils')
+
+-- A length-checked view on a memory buffer
+
+CheckedArray = CheckedArray or {}
+
+function CheckedArray.new(type,saddr,eaddr)
+ local data = df.reinterpret_cast(type,saddr)
+ local esize = data:sizeof()
+ local count = math.floor((eaddr-saddr)/esize)
+ local obj = {
+ type = type, start = saddr, size = count*esize,
+ esize = esize, data = data, count = count
+ }
+ setmetatable(obj, CheckedArray)
+ return obj
+end
+
+function CheckedArray:__len()
+ return self.count
+end
+function CheckedArray:__index(idx)
+ if type(idx) == number then
+ if idx >= self.count then
+ error('Index out of bounds: '..tostring(idx))
+ end
+ return self.data[idx]
+ else
+ return CheckedArray[idx]
+ end
+end
+function CheckedArray:__newindex(idx, val)
+ if idx >= self.count then
+ error('Index out of bounds: '..tostring(idx))
+ end
+ self.data[idx] = val
+end
+function CheckedArray:addr2idx(addr, round)
+ local off = addr - self.start
+ if off >= 0 and off < self.size and (round or (off % self.esize) == 0) then
+ return math.floor(off / self.esize), off
+ end
+end
+function CheckedArray:idx2addr(idx)
+ if idx >= 0 and idx < self.count then
+ return self.start + idx*self.esize
+ end
+end
+
+-- Search methods
+
+function CheckedArray:find(data,sidx,eidx,reverse)
+ local dcnt = #data
+ sidx = math.max(0, sidx or 0)
+ eidx = math.min(self.count, eidx or self.count)
+ if (eidx - sidx) >= dcnt and dcnt > 0 then
+ return dfhack.with_temp_object(
+ df.new(self.type, dcnt),
+ function(buffer)
+ for i = 1,dcnt do
+ buffer[i-1] = data[i]
+ end
+ local cnt = eidx - sidx - dcnt
+ local step = self.esize
+ local sptr = self.start + sidx*step
+ local ksize = dcnt*step
+ if reverse then
+ local idx, addr = dfhack.internal.memscan(sptr + cnt*step, cnt, -step, buffer, ksize)
+ if idx then
+ return sidx + cnt - idx, addr
+ end
+ else
+ local idx, addr = dfhack.internal.memscan(sptr, cnt, step, buffer, ksize)
+ if idx then
+ return sidx + idx, addr
+ end
+ end
+ end
+ )
+ end
+end
+function CheckedArray:find_one(data,sidx,eidx,reverse)
+ local idx, addr = self:find(data,sidx,eidx,reverse)
+ if idx then
+ -- Verify this is the only match
+ if reverse then
+ eidx = idx+#data-1
+ else
+ sidx = idx+1
+ end
+ if self:find(data,sidx,eidx,reverse) then
+ return nil
+ end
+ end
+ return idx, addr
+end
+function CheckedArray:list_changes(old_arr,old_val,new_val,delta)
+ if old_arr.type ~= self.type or old_arr.count ~= self.count then
+ error('Incompatible arrays')
+ end
+ local eidx = self.count
+ local optr = old_arr.start
+ local nptr = self.start
+ local esize = self.esize
+ local rv
+ local sidx = 0
+ while true do
+ local idx = dfhack.internal.diffscan(optr, nptr, sidx, eidx, esize, old_val, new_val, delta)
+ if not idx then
+ break
+ end
+ rv = rv or {}
+ rv[#rv+1] = idx
+ sidx = idx+1
+ end
+ return rv
+end
+function CheckedArray:filter_changes(prev_list,old_arr,old_val,new_val,delta)
+ if old_arr.type ~= self.type or old_arr.count ~= self.count then
+ error('Incompatible arrays')
+ end
+ local eidx = self.count
+ local optr = old_arr.start
+ local nptr = self.start
+ local esize = self.esize
+ local rv
+ for i=1,#prev_list do
+ local idx = prev_list[i]
+ if idx < 0 or idx >= eidx then
+ error('Index out of bounds: '..idx)
+ end
+ if dfhack.internal.diffscan(optr, nptr, idx, idx+1, esize, old_val, new_val, delta) then
+ rv = rv or {}
+ rv[#rv+1] = idx
+ end
+ end
+ return rv
+end
+
+-- A raw memory area class
+
+MemoryArea = MemoryArea or {}
+MemoryArea.__index = MemoryArea
+
+function MemoryArea.new(astart, aend)
+ local obj = {
+ start_addr = astart, end_addr = aend, size = aend - astart,
+ int8_t = CheckedArray.new('int8_t',astart,aend),
+ uint8_t = CheckedArray.new('uint8_t',astart,aend),
+ int16_t = CheckedArray.new('int16_t',astart,aend),
+ uint16_t = CheckedArray.new('uint16_t',astart,aend),
+ int32_t = CheckedArray.new('int32_t',astart,aend),
+ uint32_t = CheckedArray.new('uint32_t',astart,aend)
+ }
+ setmetatable(obj, MemoryArea)
+ return obj
+end
+
+function MemoryArea:__gc()
+ df.delete(self.buffer)
+end
+
+function MemoryArea:__tostring()
+ return string.format('<MemoryArea: %x..%x>', self.start_addr, self.end_addr)
+end
+function MemoryArea:contains_range(start,size)
+ return start >= self.start_addr and (start+size) <= self.end_addr
+end
+function MemoryArea:contains_obj(obj,count)
+ local size, base = df.sizeof(obj)
+ return size and base and self:contains_range(base, size*(count or 1))
+end
+
+function MemoryArea:clone()
+ local buffer = df.new('int8_t', self.size)
+ local _, base = buffer:sizeof()
+ local rv = MemoryArea.new(base, base+self.size)
+ rv.buffer = buffer
+ return rv
+end
+function MemoryArea:copy_from(area2)
+ if area2.size ~= self.size then
+ error('Size mismatch')
+ end
+ dfhack.internal.memmove(self.start_addr, area2.start_addr, self.size)
+end
+function MemoryArea:delete()
+ setmetatable(self, nil)
+ df.delete(self.buffer)
+ for k,v in pairs(self) do self[k] = nil end
+end
+
+-- Static data segment search
+
+local function find_data_segment()
+ local data_start, data_end
+
+ for i,mem in ipairs(dfhack.internal.getMemRanges()) do
+ if data_end then
+ if mem.start_addr == data_end and mem.read and mem.write then
+ data_end = mem.end_addr
+ else
+ break
+ end
+ elseif mem.read and mem.write
+ and (string.match(mem.name,'/dwarfort%.exe$')
+ or string.match(mem.name,'/Dwarf_Fortress$'))
+ then
+ data_start = mem.start_addr
+ data_end = mem.end_addr
+ end
+ end
+
+ return data_start, data_end
+end
+
+function get_data_segment()
+ local s, e = find_data_segment()
+ if s and e then
+ return MemoryArea.new(s, e)
+ end
+end
+
+-- Register a found offset, or report an error.
+
+function found_offset(name,val)
+ local cval = dfhack.internal.getAddress(name)
+
+ if not val then
+ print('Could not find offset '..name)
+ if not cval and not utils.prompt_yes_no('Continue with the script?') then
+ error('User quit')
+ end
+ return
+ end
+
+ if df.isvalid(val) then
+ _,val = val:sizeof()
+ end
+
+ print(string.format('Found offset %s: %x', name, val))
+
+ if cval then
+ if cval ~= val then
+ error(string.format('Mismatch with the current value: %x',val))
+ end
+ else
+ dfhack.internal.setAddress(name, val)
+ end
+end
+
+-- Offset of a field within struct
+
+function field_ref(handle,...)
+ local items = table.pack(...)
+ for i=1,items.n-1 do
+ handle = handle[items[i]]
+ end
+ return handle:_field(items[items.n])
+end
+
+function field_offset(type,...)
+ local handle = df.reinterpret_cast(type,1)
+ local _,addr = df.sizeof(field_ref(handle,...))
+ return addr-1
+end
+
+function MemoryArea:object_by_field(addr,type,...)
+ if not addr then
+ return nil
+ end
+ local base = addr - field_offset(type,...)
+ local obj = df.reinterpret_cast(type, base)
+ if not self:contains_obj(obj) then
+ obj = nil
+ end
+ return obj, base
+end
+
+-- Validation
+
+function is_valid_vector(ref,size)
+ local ints = df.reinterpret_cast('uint32_t', ref)
+ return ints[0] <= ints[1] and ints[1] <= ints[2]
+ and (size == nil or (ints[1] - ints[0]) % size == 0)
+end
+
+-- Difference search helper
+
+DiffSearcher = DiffSearcher or {}
+DiffSearcher.__index = DiffSearcher
+
+function DiffSearcher.new(area)
+ local obj = { area = area }
+ setmetatable(obj, DiffSearcher)
+ return obj
+end
+
+function DiffSearcher:begin_search(type)
+ self.type = type
+ self.old_value = nil
+ self.search_sets = nil
+ if not self.save_area then
+ self.save_area = self.area:clone()
+ end
+end
+function DiffSearcher:advance_search(new_value,delta)
+ if self.search_sets then
+ local nsets = #self.search_sets
+ local ovec = self.save_area[self.type]
+ local nvec = self.area[self.type]
+ local new_set
+ if nsets > 0 then
+ local last_set = self.search_sets[nsets]
+ new_set = nvec:filter_changes(last_set,ovec,self.old_value,new_value,delta)
+ else
+ new_set = nvec:list_changes(ovec,self.old_value,new_value,delta)
+ end
+ if new_set then
+ self.search_sets[nsets+1] = new_set
+ self.old_value = new_value
+ self.save_area:copy_from(self.area)
+ return #new_set, new_set
+ end
+ else
+ self.old_value = new_value
+ self.search_sets = {}
+ self.save_area:copy_from(self.area)
+ return #self.save_area[self.type], nil
+ end
+end
+function DiffSearcher:reset()
+ self.search_sets = nil
+ if self.save_area then
+ self.save_area:delete()
+ self.save_area = nil
+ end
+end
+function DiffSearcher:idx2addr(idx)
+ return self.area[self.type]:idx2addr(idx)
+end
+
+-- Interactive search utility
+
+function DiffSearcher:find_interactive(prompt,data_type,condition_cb)
+ enum = enum or {}
+
+ -- Loop for restarting search from scratch
+ while true do
+ print('\n'..prompt)
+
+ self:begin_search(data_type)
+
+ local found = false
+ local ccursor = 0
+
+ -- Loop through choices
+ while true do
+ print('')
+
+ local ok, value, delta = condition_cb(ccursor)
+
+ ccursor = ccursor + 1
+
+ if not ok then
+ break
+ end
+
+ -- Search for it in the memory
+ local cnt, set = self:advance_search(value, delta)
+ if not cnt then
+ dfhack.printerr(' Converged to zero candidates; probably a mistake somewhere.')
+ break
+ elseif set and cnt == 1 then
+ -- To confirm, wait for two 1-candidate results in a row
+ if found then
+ local addr = self:idx2addr(set[1])
+ print(string.format(' Confirmed address: %x\n', addr))
+ return addr, set[1]
+ else
+ found = true
+ end
+ end
+
+ print(' '..cnt..' candidates remaining.')
+ end
+
+ if not utils.prompt_yes_no('\nRetry search from the start?') then
+ return nil
+ end
+ end
+end
+
+function DiffSearcher:find_menu_cursor(prompt,data_type,choices,enum)
+ enum = enum or {}
+
+ return self:find_interactive(
+ prompt, data_type,
+ function(ccursor)
+ local choice
+
+ -- Select the next value to search for
+ if type(choices) == 'function' then
+ choice = choices(ccursor)
+
+ if not choice then
+ return false
+ end
+ else
+ choice = choices[(ccursor % #choices) + 1]
+ end
+
+ -- Ask the user to select it
+ if enum ~= 'noprompt' then
+ local cname = enum[choice] or choice
+ if type(choice) == 'string' and type(cname) == 'number' then
+ choice, cname = cname, choice
+ end
+ if cname ~= choice then
+ cname = cname..' ('..choice..')'
+ end
+
+ print(' Please select: '..cname)
+ if not utils.prompt_yes_no(' Continue?', true) then
+ return false
+ end
+ end
+
+ return true, choice
+ end
+ )
+end
+
+function DiffSearcher:find_counter(prompt,data_type,delta,action_prompt)
+ delta = delta or 1
+
+ return self:find_interactive(
+ prompt, data_type,
+ function(ccursor)
+ if ccursor > 0 then
+ print(" "..(action_prompt or 'Please do the action.'))
+ end
+ if not utils.prompt_yes_no(' Continue?', true) then
+ return false
+ end
+ return true, nil, delta
+ end
+ )
+end
+
+return _ENV
diff --git a/library/lua/utils.lua b/library/lua/utils.lua
index e67801f4..93ee840c 100644
--- a/library/lua/utils.lua
+++ b/library/lua/utils.lua
@@ -361,4 +361,50 @@ function insert_or_update(vector,item,field,cmp)
return added,cur,pos
end
+-- Ask a yes-no question
+function prompt_yes_no(msg,default)
+ local prompt = msg
+ if default == nil then
+ prompt = prompt..' (y/n): '
+ elseif default then
+ prompt = prompt..' (y/n)[y]: '
+ else
+ prompt = prompt..' (y/n)[n]: '
+ end
+ while true do
+ local rv = dfhack.lineedit(prompt)
+ if rv then
+ if string.match(rv,'^[Yy]') then
+ return true
+ elseif string.match(rv,'^[Nn]') then
+ return false
+ elseif rv == 'abort' then
+ error('User abort in utils.prompt_yes_no()')
+ elseif rv == '' and default ~= nil then
+ return default
+ end
+ end
+ end
+end
+
+-- Ask for input with check function
+function prompt_input(prompt,check,quit_str)
+ quit_str = quit_str or '~~~'
+ while true do
+ local rv = dfhack.lineedit(prompt)
+ if rv == quit_str then
+ return nil
+ end
+ local rtbl = table.pack(check(rv))
+ if rtbl[1] then
+ return table.unpack(rtbl,2,rtbl.n)
+ end
+ end
+end
+
+function check_number(text)
+ local nv = tonumber(text)
+ return nv ~= nil, nv
+end
+
return _ENV \ No newline at end of file
diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp
index e1810522..cd44401f 100644
--- a/library/modules/Gui.cpp
+++ b/library/modules/Gui.cpp
@@ -58,12 +58,14 @@ using namespace DFHack;
#include "df/viewscreen_layer_overall_healthst.h"
#include "df/viewscreen_layer_assigntradest.h"
#include "df/viewscreen_layer_militaryst.h"
+#include "df/viewscreen_layer_stockpilest.h"
#include "df/viewscreen_petst.h"
#include "df/viewscreen_tradegoodsst.h"
#include "df/viewscreen_storesst.h"
#include "df/ui_unit_view_mode.h"
#include "df/ui_sidebar_menus.h"
#include "df/ui_look_list.h"
+#include "df/ui_advmode.h"
#include "df/job.h"
#include "df/ui_build_selector.h"
#include "df/building_workshopst.h"
@@ -273,7 +275,9 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode)
break;
case Burrows:
- if (ui->burrows.in_add_units_mode)
+ if (ui->burrows.in_confirm_delete)
+ focus += "/ConfirmDelete";
+ else if (ui->burrows.in_add_units_mode)
focus += "/AddUnits";
else if (ui->burrows.in_edit_name_mode)
focus += "/EditName";
@@ -288,6 +292,16 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode)
}
}
+DEFINE_GET_FOCUS_STRING_HANDLER(dungeonmode)
+{
+ using df::global::ui_advmode;
+
+ if (!ui_advmode)
+ return;
+
+ focus += "/" + enum_item_key(ui_advmode->menu);
+}
+
DEFINE_GET_FOCUS_STRING_HANDLER(unitlist)
{
focus += "/" + enum_item_key(screen->page);
@@ -407,6 +421,35 @@ DEFINE_GET_FOCUS_STRING_HANDLER(stores)
focus += "/Items";
}
+DEFINE_GET_FOCUS_STRING_HANDLER(layer_stockpile)
+{
+ auto list1 = getLayerList(screen, 0);
+ auto list2 = getLayerList(screen, 1);
+ auto list3 = getLayerList(screen, 2);
+ if (!list1 || !list2 || !list3 || !screen->settings) return;
+
+ auto group = screen->cur_group;
+ if (group != vector_get(screen->group_ids, list1->cursor))
+ return;
+
+ focus += "/" + enum_item_key(group);
+
+ auto bits = vector_get(screen->group_bits, list1->cursor);
+ if (bits.whole && !(bits.whole & screen->settings->flags.whole))
+ {
+ focus += "/Off";
+ return;
+ }
+
+ focus += "/On";
+
+ if (list2->bright || list3->bright || screen->list_ids.empty()) {
+ focus += "/" + enum_item_key(screen->cur_list);
+
+ if (list3->bright)
+ focus += (screen->item_names.empty() ? "/None" : "/Item");
+ }
+}
std::string Gui::getFocusString(df::viewscreen *top)
{
diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp
index f49dd82e..f8f99f81 100644
--- a/library/modules/Materials.cpp
+++ b/library/modules/Materials.cpp
@@ -761,8 +761,8 @@ bool Materials::ReadCreatureTypesEx (void)
{
df::body_part_raw *bp = ca->body_info.body_parts[k];
t_bodypart part;
- part.id = bp->part_code;
- part.category = bp->part_name;
+ part.id = bp->token;
+ part.category = bp->category;
caste.bodypart.push_back(part);
}
using namespace df::enums::mental_attribute_type;
diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp
index dd26109e..ee383cc0 100644
--- a/library/modules/Units.cpp
+++ b/library/modules/Units.cpp
@@ -613,12 +613,45 @@ df::nemesis_record *Units::getNemesis(df::unit *unit)
return NULL;
}
+static bool casteFlagSet(int race, int caste, df::caste_raw_flags flag)
+{
+ auto creature = df::creature_raw::find(race);
+ if (!creature)
+ return false;
+
+ auto craw = vector_get(creature->caste, caste);
+ if (!craw)
+ return false;
+
+ return craw->flags.is_set(flag);
+}
+
+static bool isCrazed(df::unit *unit)
+{
+ if (unit->flags3.bits.scuttle)
+ return false;
+ if (unit->curse.rem_tags1.bits.CRAZED)
+ return false;
+ if (unit->curse.add_tags1.bits.CRAZED)
+ return true;
+ return casteFlagSet(unit->race, unit->caste, caste_raw_flags::CRAZED);
+}
+
+static bool isOpposedToLife(df::unit *unit)
+{
+ if (unit->curse.rem_tags1.bits.OPPOSED_TO_LIFE)
+ return false;
+ if (unit->curse.add_tags1.bits.OPPOSED_TO_LIFE)
+ return true;
+ return casteFlagSet(unit->race, unit->caste, caste_raw_flags::CANNOT_UNDEAD);
+}
bool DFHack::Units::isDead(df::unit *unit)
{
CHECK_NULL_POINTER(unit);
- return unit->flags1.bits.dead;
+ return unit->flags1.bits.dead ||
+ unit->flags3.bits.ghostly;
}
bool DFHack::Units::isAlive(df::unit *unit)
@@ -636,8 +669,11 @@ bool DFHack::Units::isSane(df::unit *unit)
if (unit->flags1.bits.dead ||
unit->flags3.bits.ghostly ||
- unit->curse.add_tags1.bits.OPPOSED_TO_LIFE ||
- unit->curse.add_tags1.bits.CRAZED)
+ isOpposedToLife(unit) ||
+ unit->unknown8.unk2)
+ return false;
+
+ if (unit->unknown8.normal_race == unit->unknown8.were_race && isCrazed(unit))
return false;
switch (unit->mood)
@@ -657,19 +693,38 @@ bool DFHack::Units::isCitizen(df::unit *unit)
{
CHECK_NULL_POINTER(unit);
+ // Copied from the conditions used to decide game over,
+ // except that the game appears to let melancholy/raving
+ // dwarves count as citizens.
+
+ if (!isDwarf(unit) || !isSane(unit))
+ return false;
+
+ if (unit->flags1.bits.marauder ||
+ unit->flags1.bits.invader_origin ||
+ unit->flags1.bits.active_invader ||
+ unit->flags1.bits.forest ||
+ unit->flags1.bits.merchant ||
+ unit->flags1.bits.diplomat)
+ return false;
+
+ if (unit->flags1.bits.tame)
+ return true;
+
return unit->civ_id == ui->civ_id &&
- !unit->flags1.bits.merchant &&
- !unit->flags1.bits.diplomat &&
+ unit->civ_id != -1 &&
+ !unit->flags2.bits.underworld &&
!unit->flags2.bits.resident &&
- !unit->flags1.bits.dead &&
- !unit->flags3.bits.ghostly;
+ !unit->flags2.bits.visitor_uninvited &&
+ !unit->flags2.bits.visitor;
}
bool DFHack::Units::isDwarf(df::unit *unit)
{
CHECK_NULL_POINTER(unit);
- return unit->race == ui->race_id;
+ return unit->race == ui->race_id ||
+ unit->unknown8.normal_race == ui->race_id;
}
double DFHack::Units::getAge(df::unit *unit, bool true_age)
diff --git a/library/modules/World.cpp b/library/modules/World.cpp
index 4b50b44c..393e7cbf 100644
--- a/library/modules/World.cpp
+++ b/library/modules/World.cpp
@@ -85,7 +85,7 @@ World::World()
if(df::global::current_weather)
d->StartedWeather = true;
- if (df::global::game_mode && df::global::control_mode)
+ if (df::global::gamemode && df::global::gametype)
d->StartedMode = true;
d->Inited = true;
@@ -132,8 +132,8 @@ bool World::ReadGameMode(t_gamemodes& rd)
{
if(d->Inited && d->StartedMode)
{
- rd.g_mode = (DFHack::GameMode)*df::global::control_mode;
- rd.g_type = (DFHack::GameType)*df::global::game_mode;
+ rd.g_mode = (DFHack::GameMode)*df::global::gamemode;
+ rd.g_type = (DFHack::GameType)*df::global::gametype;
return true;
}
return false;
@@ -142,8 +142,8 @@ bool World::WriteGameMode(const t_gamemodes & wr)
{
if(d->Inited && d->StartedMode)
{
- *df::global::control_mode = wr.g_mode;
- *df::global::game_mode = wr.g_type;
+ *df::global::gamemode = wr.g_mode;
+ *df::global::gametype = wr.g_type;
return true;
}
return false;