summaryrefslogtreecommitdiff
path: root/library/include
diff options
context:
space:
mode:
authorTimothy Collett2012-09-10 11:54:56 -0400
committerTimothy Collett2012-09-10 11:54:56 -0400
commit96abc903abb93b7bf7418f2da3455ee6da5ad942 (patch)
treea5326ef1dbd492086b319c888854e707c59d2a56 /library/include
parent274d6038adce5797b58cee78a330eb5d639bf59e (diff)
parent21904fd607d0f2037782e28ff7284300663931ab (diff)
downloaddfhack-96abc903abb93b7bf7418f2da3455ee6da5ad942.tar.gz
dfhack-96abc903abb93b7bf7418f2da3455ee6da5ad942.tar.bz2
dfhack-96abc903abb93b7bf7418f2da3455ee6da5ad942.tar.xz
Merge branch 'master' of http://github.com/peterix/dfhack
Diffstat (limited to 'library/include')
-rw-r--r--library/include/ColorText.h44
-rw-r--r--library/include/Core.h26
-rw-r--r--library/include/DataDefs.h12
-rw-r--r--library/include/DataFuncs.h15
-rw-r--r--library/include/DataIdentity.h40
-rw-r--r--library/include/LuaTools.h47
-rw-r--r--library/include/MemAccess.h3
-rw-r--r--library/include/PluginManager.h25
-rw-r--r--library/include/VTableInterpose.h173
-rw-r--r--library/include/modules/Buildings.h5
-rw-r--r--library/include/modules/Gui.h8
-rw-r--r--library/include/modules/Screen.h176
-rw-r--r--library/include/modules/Units.h3
13 files changed, 515 insertions, 62 deletions
diff --git a/library/include/ColorText.h b/library/include/ColorText.h
index 0cc286dc..50d1f362 100644
--- a/library/include/ColorText.h
+++ b/library/include/ColorText.h
@@ -41,30 +41,32 @@ namespace dfproto
namespace DFHack
{
+ enum color_value
+ {
+ COLOR_RESET = -1,
+ COLOR_BLACK = 0,
+ COLOR_BLUE,
+ COLOR_GREEN,
+ COLOR_CYAN,
+ COLOR_RED,
+ COLOR_MAGENTA,
+ COLOR_BROWN,
+ COLOR_GREY,
+ COLOR_DARKGREY,
+ COLOR_LIGHTBLUE,
+ COLOR_LIGHTGREEN,
+ COLOR_LIGHTCYAN,
+ COLOR_LIGHTRED,
+ COLOR_LIGHTMAGENTA,
+ COLOR_YELLOW,
+ COLOR_WHITE,
+ COLOR_MAX = COLOR_WHITE
+ };
+
class DFHACK_EXPORT color_ostream : public std::ostream
{
public:
- enum color_value
- {
- COLOR_RESET = -1,
- COLOR_BLACK = 0,
- COLOR_BLUE,
- COLOR_GREEN,
- COLOR_CYAN,
- COLOR_RED,
- COLOR_MAGENTA,
- COLOR_BROWN,
- COLOR_GREY,
- COLOR_DARKGREY,
- COLOR_LIGHTBLUE,
- COLOR_LIGHTGREEN,
- COLOR_LIGHTCYAN,
- COLOR_LIGHTRED,
- COLOR_LIGHTMAGENTA,
- COLOR_YELLOW,
- COLOR_WHITE,
- COLOR_MAX = COLOR_WHITE
- };
+ typedef DFHack::color_value color_value;
private:
color_value cur_color;
diff --git a/library/include/Core.h b/library/include/Core.h
index 653298d8..e1f1cf3f 100644
--- a/library/include/Core.h
+++ b/library/include/Core.h
@@ -75,7 +75,9 @@ namespace DFHack
SC_MAP_UNLOADED = 3,
SC_VIEWSCREEN_CHANGED = 4,
SC_CORE_INITIALIZED = 5,
- SC_BEGIN_UNLOAD = 6
+ SC_BEGIN_UNLOAD = 6,
+ SC_PAUSED = 7,
+ SC_UNPAUSED = 8
};
// Core is a singleton. Why? Because it is closely tied to SDL calls. It tracks the global state of DF.
@@ -172,6 +174,10 @@ namespace DFHack
struct Private;
Private *d;
+ friend class CoreSuspendClaimer;
+ int ClaimSuspend(bool force_base);
+ void DisclaimSuspend(int level);
+
bool Init();
int Update (void);
int TileUpdate (void);
@@ -179,6 +185,7 @@ namespace DFHack
int DFH_SDL_Event(SDL::Event* event);
bool ncurses_wgetch(int in, int & out);
+ void doUpdate(color_ostream &out, bool first_update);
void onUpdate(color_ostream &out);
void onStateChange(color_ostream &out, state_change_event event);
@@ -228,6 +235,7 @@ namespace DFHack
// for state change tracking
void *last_local_map_ptr;
df::viewscreen *top_viewscreen;
+ bool last_pause_state;
// Very important!
bool started;
@@ -246,4 +254,20 @@ namespace DFHack
CoreSuspender(Core *core) : core(core) { core->Suspend(); }
~CoreSuspender() { core->Resume(); }
};
+
+ /** Claims the current thread already has the suspend lock.
+ * Strictly for use in callbacks from DF.
+ */
+ class CoreSuspendClaimer {
+ Core *core;
+ int level;
+ public:
+ CoreSuspendClaimer(bool base = false) : core(&Core::getInstance()) {
+ level = core->ClaimSuspend(base);
+ }
+ CoreSuspendClaimer(Core *core, bool base = false) : core(core) {
+ level = core->ClaimSuspend(base);
+ }
+ ~CoreSuspendClaimer() { core->DisclaimSuspend(level); }
+ };
}
diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h
index 7f4d94c8..6b3aeb3e 100644
--- a/library/include/DataDefs.h
+++ b/library/include/DataDefs.h
@@ -28,6 +28,7 @@ distribution.
#include <sstream>
#include <vector>
#include <map>
+#include <set>
#include "Core.h"
#include "BitArray.h"
@@ -292,6 +293,8 @@ namespace DFHack
typedef virtual_class *virtual_ptr;
#endif
+ class DFHACK_EXPORT VMethodInterposeLinkBase;
+
class DFHACK_EXPORT virtual_identity : public struct_identity {
static std::map<void*, virtual_identity*> known;
@@ -299,6 +302,9 @@ namespace DFHack
void *vtable_ptr;
+ friend class VMethodInterposeLinkBase;
+ std::vector<VMethodInterposeLinkBase*> interpose_list;
+
protected:
virtual void doInit(Core *core);
@@ -306,10 +312,14 @@ namespace DFHack
bool can_allocate() { return struct_identity::can_allocate() && (vtable_ptr != NULL); }
+ void *get_vmethod_ptr(int index);
+ bool set_vmethod_ptr(int index, void *ptr);
+
public:
virtual_identity(size_t size, TAllocateFn alloc,
const char *dfhack_name, const char *original_name,
virtual_identity *parent, const struct_field_info *fields);
+ ~virtual_identity();
virtual identity_type type() { return IDTYPE_CLASS; }
@@ -337,6 +347,8 @@ namespace DFHack
: (this == get(instance_ptr));
}
+ template<class P> static P get_vmethod_ptr(P selector);
+
public:
bool can_instantiate() { return can_allocate(); }
virtual_ptr instantiate() { return can_instantiate() ? (virtual_ptr)do_allocate() : NULL; }
diff --git a/library/include/DataFuncs.h b/library/include/DataFuncs.h
index 637a532f..52039566 100644
--- a/library/include/DataFuncs.h
+++ b/library/include/DataFuncs.h
@@ -75,28 +75,31 @@ namespace df {
cur_lua_ostream_argument name(state);
#define INSTANTIATE_RETURN_TYPE(FArgs) \
- template<FW_TARGSC class RT> struct return_type<RT (*) FArgs> { typedef RT type; }; \
- template<FW_TARGSC class RT, class CT> struct return_type<RT (CT::*) FArgs> { typedef RT type; };
+ template<FW_TARGSC class RT> struct return_type<RT (*) FArgs> { \
+ typedef RT type; \
+ static const bool is_method = false; \
+ }; \
+ template<FW_TARGSC class RT, class CT> struct return_type<RT (CT::*) FArgs> { \
+ typedef RT type; \
+ typedef CT class_type; \
+ static const bool is_method = true; \
+ };
#define INSTANTIATE_WRAPPERS(Count, FArgs, Args, Loads) \
template<FW_TARGS> struct function_wrapper<void (*) FArgs, true> { \
- static const bool is_method = false; \
static const int num_args = Count; \
static void execute(lua_State *state, int base, void (*cb) FArgs) { Loads; INVOKE_VOID(cb Args); } \
}; \
template<FW_TARGSC class RT> struct function_wrapper<RT (*) FArgs, false> { \
- static const bool is_method = false; \
static const int num_args = Count; \
static void execute(lua_State *state, int base, RT (*cb) FArgs) { Loads; INVOKE_RV(cb Args); } \
}; \
template<FW_TARGSC class CT> struct function_wrapper<void (CT::*) FArgs, true> { \
- static const bool is_method = true; \
static const int num_args = Count+1; \
static void execute(lua_State *state, int base, void (CT::*cb) FArgs) { \
LOAD_CLASS() Loads; INVOKE_VOID((self->*cb) Args); } \
}; \
template<FW_TARGSC class RT, class CT> struct function_wrapper<RT (CT::*) FArgs, false> { \
- static const bool is_method = true; \
static const int num_args = Count+1; \
static void execute(lua_State *state, int base, RT (CT::*cb) FArgs) { \
LOAD_CLASS(); Loads; INVOKE_RV((self->*cb) Args); } \
diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h
index dcd0ae97..0f5fd9e7 100644
--- a/library/include/DataIdentity.h
+++ b/library/include/DataIdentity.h
@@ -115,6 +115,8 @@ namespace DFHack
virtual void lua_item_read(lua_State *state, int fname_idx, void *ptr, int idx);
virtual void lua_item_write(lua_State *state, int fname_idx, void *ptr, int idx, int val_index);
+ virtual bool is_readonly() { return false; }
+
virtual bool resize(void *ptr, int size) { return false; }
virtual bool erase(void *ptr, int index) { return false; }
virtual bool insert(void *ptr, int index, void *pitem) { return false; }
@@ -343,6 +345,33 @@ namespace df
}
};
+ template<class T>
+ class ro_stl_container_identity : public container_identity {
+ const char *name;
+
+ public:
+ ro_stl_container_identity(const char *name, type_identity *item, enum_identity *ienum = NULL)
+ : container_identity(sizeof(T), &allocator_fn<T>, item, ienum), name(name)
+ {}
+
+ std::string getFullName(type_identity *item) {
+ return name + container_identity::getFullName(item);
+ }
+
+ virtual bool is_readonly() { return true; }
+ virtual bool resize(void *ptr, int size) { return false; }
+ virtual bool erase(void *ptr, int size) { return false; }
+ virtual bool insert(void *ptr, int idx, void *item) { return false; }
+
+ protected:
+ virtual int item_count(void *ptr, CountMode) { return ((T*)ptr)->size(); }
+ virtual void *item_pointer(type_identity *item, void *ptr, int idx) {
+ auto iter = (*(T*)ptr).begin();
+ for (; idx > 0; idx--) ++iter;
+ return (void*)&*iter;
+ }
+ };
+
class bit_array_identity : public bit_container_identity {
public:
/*
@@ -517,6 +546,10 @@ namespace df
static container_identity *get();
};
+ template<class T> struct identity_traits<std::set<T> > {
+ static container_identity *get();
+ };
+
template<> struct identity_traits<BitArray<int> > {
static bit_array_identity identity;
static bit_container_identity *get() { return &identity; }
@@ -580,6 +613,13 @@ namespace df
}
template<class T>
+ inline container_identity *identity_traits<std::set<T> >::get() {
+ typedef std::set<T> container;
+ static ro_stl_container_identity<container> identity("set", identity_traits<T>::get());
+ return &identity;
+ }
+
+ template<class T>
inline bit_container_identity *identity_traits<BitArray<T> >::get() {
static bit_array_identity identity(identity_traits<T>::get());
return &identity;
diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h
index d3c7a65d..6b1afb88 100644
--- a/library/include/LuaTools.h
+++ b/library/include/LuaTools.h
@@ -192,6 +192,16 @@ namespace DFHack {namespace Lua {
}
/**
+ * Call through to the function with try/catch for C++ exceptions.
+ */
+ DFHACK_EXPORT int CallWithCatch(lua_State *, int (*fn)(lua_State*), const char *context = NULL);
+
+ template<int (*cb)(lua_State*)>
+ int CallWithCatchWrapper(lua_State *state) {
+ return CallWithCatch(state, cb);
+ }
+
+ /**
* Invoke lua function via pcall. Returns true if success.
* If an error is signalled, and perr is true, it is printed and popped from the stack.
*/
@@ -300,9 +310,18 @@ namespace DFHack {namespace Lua {
DFHACK_EXPORT bool IsCoreContext(lua_State *state);
- DFHACK_EXPORT int NewEvent(lua_State *state);
- DFHACK_EXPORT void MakeEvent(lua_State *state, void *key);
- DFHACK_EXPORT void InvokeEvent(color_ostream &out, lua_State *state, void *key, int num_args);
+ namespace Event {
+ struct DFHACK_EXPORT Owner {
+ virtual ~Owner() {}
+ virtual void on_count_changed(int new_cnt, int delta) {}
+ virtual void on_invoked(lua_State *state, int nargs, bool from_c) {}
+ };
+
+ DFHACK_EXPORT void New(lua_State *state, Owner *owner = NULL);
+ DFHACK_EXPORT void Make(lua_State *state, void *key, Owner *owner = NULL);
+ DFHACK_EXPORT void SetPrivateCallback(lua_State *state, int ev_idx);
+ DFHACK_EXPORT void Invoke(color_ostream &out, lua_State *state, void *key, int num_args);
+ }
class StackUnwinder {
lua_State *state;
@@ -355,18 +374,24 @@ namespace DFHack {namespace Lua {
}
}
- class DFHACK_EXPORT Notification {
+ class DFHACK_EXPORT Notification : public Event::Owner {
lua_State *state;
void *key;
function_identity_base *handler;
+ int count;
public:
Notification(function_identity_base *handler = NULL)
- : state(NULL), key(NULL), handler(handler) {}
+ : state(NULL), key(NULL), handler(handler), count(0) {}
+ int get_listener_count() { return count; }
lua_State *get_state() { return state; }
function_identity_base *get_handler() { return handler; }
+ lua_State *state_if_count() { return (count > 0) ? state : NULL; }
+
+ void on_count_changed(int new_cnt, int) { count = new_cnt; }
+
void invoke(color_ostream &out, int nargs);
void bind(lua_State *state, const char *name);
@@ -378,7 +403,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out) { \
handler(out); \
- if (name##_event.get_state()) { \
+ if (name##_event.state_if_count()) { \
name##_event.invoke(out, 0); \
} \
}
@@ -387,7 +412,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out, arg_type1 arg1) { \
handler(out, arg1); \
- if (auto state = name##_event.get_state()) { \
+ if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
name##_event.invoke(out, 1); \
} \
@@ -397,7 +422,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2) { \
handler(out, arg1, arg2); \
- if (auto state = name##_event.get_state()) { \
+ if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \
name##_event.invoke(out, 2); \
@@ -408,7 +433,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3) { \
handler(out, arg1, arg2, arg3); \
- if (auto state = name##_event.get_state()) { \
+ if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \
DFHack::Lua::Push(state, arg3); \
@@ -420,7 +445,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3, arg_type4 arg4) { \
handler(out, arg1, arg2, arg3, arg4); \
- if (auto state = name##_event.get_state()) { \
+ if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \
DFHack::Lua::Push(state, arg3); \
@@ -433,7 +458,7 @@ namespace DFHack {namespace Lua {
static DFHack::Lua::Notification name##_event(df::wrap_function(handler, true)); \
void name(color_ostream &out, arg_type1 arg1, arg_type2 arg2, arg_type3 arg3, arg_type4 arg4, arg_type5 arg5) { \
handler(out, arg1, arg2, arg3, arg4, arg5); \
- if (auto state = name##_event.get_state()) { \
+ if (auto state = name##_event.state_if_count()) { \
DFHack::Lua::Push(state, arg1); \
DFHack::Lua::Push(state, arg2); \
DFHack::Lua::Push(state, arg3); \
diff --git a/library/include/MemAccess.h b/library/include/MemAccess.h
index c51df3c6..0e5f618e 100644
--- a/library/include/MemAccess.h
+++ b/library/include/MemAccess.h
@@ -283,6 +283,9 @@ namespace DFHack
/// modify permisions of memory range
bool setPermisions(const t_memrange & range,const t_memrange &trgrange);
+
+ /// write a possibly read-only memory area
+ bool patchMemory(void *target, const void* src, size_t count);
private:
VersionInfo * my_descriptor;
PlatformSpecific *d;
diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h
index 5da9fc92..25b05ad4 100644
--- a/library/include/PluginManager.h
+++ b/library/include/PluginManager.h
@@ -173,31 +173,16 @@ namespace DFHack
PluginManager * parent;
plugin_state state;
- struct LuaCommand {
- Plugin *owner;
- std::string name;
- int (*command)(lua_State *state);
- LuaCommand(Plugin *owner, std::string name) : owner(owner), name(name) {}
- };
+ struct LuaCommand;
std::map<std::string, LuaCommand*> lua_commands;
static int lua_cmd_wrapper(lua_State *state);
- struct LuaFunction {
- Plugin *owner;
- std::string name;
- function_identity_base *identity;
- LuaFunction(Plugin *owner, std::string name) : owner(owner), name(name) {}
- };
+ struct LuaFunction;
std::map<std::string, LuaFunction*> lua_functions;
static int lua_fun_wrapper(lua_State *state);
void push_function(lua_State *state, LuaFunction *fn);
- struct LuaEvent {
- LuaFunction handler;
- Lua::Notification *event;
- bool active;
- LuaEvent(Plugin *owner, std::string name) : handler(owner,name), active(false) {}
- };
+ struct LuaEvent;
std::map<std::string, LuaEvent*> lua_events;
void index_lua(DFLibrary *lib);
@@ -209,7 +194,7 @@ namespace DFHack
command_result (*plugin_onupdate)(color_ostream &);
command_result (*plugin_onstatechange)(color_ostream &, state_change_event);
RPCService* (*plugin_rpcconnect)(color_ostream &);
- command_result (*plugin_eval_ruby)(const char*);
+ command_result (*plugin_eval_ruby)(color_ostream &, const char*);
};
class DFHACK_EXPORT PluginManager
{
@@ -238,7 +223,7 @@ namespace DFHack
{
return all_plugins.size();
}
- command_result (*eval_ruby)(const char*);
+ command_result (*eval_ruby)(color_ostream &, const char*);
// DATA
private:
tthread::mutex * cmdlist_mutex;
diff --git a/library/include/VTableInterpose.h b/library/include/VTableInterpose.h
new file mode 100644
index 00000000..bb7a37ce
--- /dev/null
+++ b/library/include/VTableInterpose.h
@@ -0,0 +1,173 @@
+/*
+https://github.com/peterix/dfhack
+Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#pragma once
+
+#include "DataFuncs.h"
+
+namespace DFHack
+{
+ template<bool> struct StaticAssert;
+ template<> struct StaticAssert<true> {};
+
+#define STATIC_ASSERT(condition) { StaticAssert<(condition)>(); }
+
+ /* Wrapping around compiler-specific representation of pointers to methods. */
+
+#if defined(_MSC_VER)
+#define METHOD_POINTER_SIZE (sizeof(void*)*2)
+#elif defined(__GXX_ABI_VERSION)
+#define METHOD_POINTER_SIZE (sizeof(void*)*2)
+#else
+#error Unknown compiler type
+#endif
+
+#define ASSERT_METHOD_POINTER(type) \
+ STATIC_ASSERT(df::return_type<type>::is_method && sizeof(type)==METHOD_POINTER_SIZE);
+
+ DFHACK_EXPORT bool is_vmethod_pointer_(void*);
+ DFHACK_EXPORT int vmethod_pointer_to_idx_(void*);
+ DFHACK_EXPORT void* method_pointer_to_addr_(void*);
+ DFHACK_EXPORT void addr_to_method_pointer_(void*,void*);
+
+ template<class T> bool is_vmethod_pointer(T ptr) {
+ ASSERT_METHOD_POINTER(T);
+ return is_vmethod_pointer_(&ptr);
+ }
+ template<class T> int vmethod_pointer_to_idx(T ptr) {
+ ASSERT_METHOD_POINTER(T);
+ return vmethod_pointer_to_idx_(&ptr);
+ }
+ template<class T> void *method_pointer_to_addr(T ptr) {
+ ASSERT_METHOD_POINTER(T);
+ return method_pointer_to_addr_(&ptr);
+ }
+ template<class T> T addr_to_method_pointer(void *addr) {
+ ASSERT_METHOD_POINTER(T);
+ T rv;
+ addr_to_method_pointer_(&rv, addr);
+ return rv;
+ }
+
+ /* Access to vmethod pointers from the vtable. */
+
+ template<class P>
+ P virtual_identity::get_vmethod_ptr(P selector)
+ {
+ typedef typename df::return_type<P>::class_type host_class;
+ virtual_identity &identity = host_class::_identity;
+ int idx = vmethod_pointer_to_idx(selector);
+ return addr_to_method_pointer<P>(identity.get_vmethod_ptr(idx));
+ }
+
+ /* VMethod interpose API.
+
+ This API allows replacing an entry in the original vtable
+ with code defined by DFHack, while retaining ability to
+ call the original code. The API can be safely used from
+ plugins, and multiple hooks for the same vmethod are
+ automatically chained in undefined order.
+
+ Usage:
+
+ struct my_hack : df::someclass {
+ typedef df::someclass interpose_base;
+
+ DEFINE_VMETHOD_INTERPOSE(void, foo, (int arg)) {
+ // If needed by the code, claim the suspend lock.
+ // DO NOT USE THE USUAL CoreSuspender, OR IT WILL DEADLOCK!
+ // CoreSuspendClaimer suspend;
+ ...
+ INTERPOSE_NEXT(foo)(arg) // call the original
+ ...
+ }
+ };
+
+ IMPLEMENT_VMETHOD_INTERPOSE(my_hack, foo);
+
+ void init() {
+ if (!INTERPOSE_HOOK(my_hack, foo).apply())
+ error();
+ }
+
+ void shutdown() {
+ INTERPOSE_HOOK(my_hack, foo).remove();
+ }
+ */
+
+#define DEFINE_VMETHOD_INTERPOSE(rtype, name, args) \
+ typedef rtype (interpose_base::*interpose_ptr_##name)args; \
+ static DFHack::VMethodInterposeLink<interpose_base,interpose_ptr_##name> interpose_##name; \
+ rtype interpose_fn_##name args
+
+#define IMPLEMENT_VMETHOD_INTERPOSE(class,name) \
+ DFHack::VMethodInterposeLink<class::interpose_base,class::interpose_ptr_##name> \
+ class::interpose_##name(&class::interpose_base::name, &class::interpose_fn_##name);
+
+#define INTERPOSE_NEXT(name) (this->*interpose_##name.chain)
+#define INTERPOSE_HOOK(class, name) (class::interpose_##name)
+
+ class DFHACK_EXPORT VMethodInterposeLinkBase {
+ /*
+ These link objects try to:
+ 1) Allow multiple hooks into the same vmethod
+ 2) Auto-remove hooks when a plugin is unloaded.
+ */
+
+ virtual_identity *host; // Class with the vtable
+ int vmethod_idx;
+ void *interpose_method; // Pointer to the code of the interposing method
+ void *chain_mptr; // Pointer to the chain field below
+
+ void *saved_chain; // Previous pointer to the code
+ VMethodInterposeLinkBase *next, *prev; // Other hooks for the same method
+
+ void set_chain(void *chain);
+ public:
+ VMethodInterposeLinkBase(virtual_identity *host, int vmethod_idx, void *interpose_method, void *chain_mptr);
+ ~VMethodInterposeLinkBase();
+
+ bool is_applied() { return saved_chain != NULL; }
+ bool apply();
+ void remove();
+ };
+
+ template<class Base, class Ptr>
+ class VMethodInterposeLink : public VMethodInterposeLinkBase {
+ public:
+ Ptr chain;
+
+ operator Ptr () { return chain; }
+
+ template<class Ptr2>
+ VMethodInterposeLink(Ptr target, Ptr2 src)
+ : VMethodInterposeLinkBase(
+ &Base::_identity,
+ vmethod_pointer_to_idx(target),
+ method_pointer_to_addr(src),
+ &chain
+ )
+ { src = target; /* check compatibility */ }
+ };
+}
diff --git a/library/include/modules/Buildings.h b/library/include/modules/Buildings.h
index 6e0a2205..639df686 100644
--- a/library/include/modules/Buildings.h
+++ b/library/include/modules/Buildings.h
@@ -93,6 +93,11 @@ DFHACK_EXPORT bool Read (const uint32_t index, t_building & building);
DFHACK_EXPORT bool ReadCustomWorkshopTypes(std::map <uint32_t, std::string> & btypes);
/**
+ * Sets the owner unit for the building.
+ */
+DFHACK_EXPORT bool setOwner(df::building *building, df::unit *owner);
+
+/**
* Find the building located at the specified tile.
* Does not work on civzones.
*/
diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h
index e7155c43..273d84ce 100644
--- a/library/include/modules/Gui.h
+++ b/library/include/modules/Gui.h
@@ -55,8 +55,6 @@ namespace DFHack
*/
namespace Gui
{
- inline df::viewscreen *getCurViewscreen() { return Core::getTopViewscreen(); }
-
DFHACK_EXPORT std::string getFocusString(df::viewscreen *top);
// Full-screen item details view
@@ -113,7 +111,11 @@ namespace DFHack
* Gui screens
*/
/// Get the current top-level view-screen
- DFHACK_EXPORT df::viewscreen * GetCurrentScreen();
+ DFHACK_EXPORT df::viewscreen *getCurViewscreen(bool skip_dismissed = false);
+
+ inline std::string getCurFocus(bool skip_dismissed = false) {
+ return getFocusString(getCurViewscreen(skip_dismissed));
+ }
/// get the size of the window buffer
DFHACK_EXPORT bool getWindowSize(int32_t & width, int32_t & height);
diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h
new file mode 100644
index 00000000..492e1eec
--- /dev/null
+++ b/library/include/modules/Screen.h
@@ -0,0 +1,176 @@
+/*
+https://github.com/peterix/dfhack
+Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#pragma once
+#include "Export.h"
+#include "Module.h"
+#include "BitArray.h"
+#include "ColorText.h"
+#include <string>
+
+#include "DataDefs.h"
+#include "df/graphic.h"
+#include "df/viewscreen.h"
+
+/**
+ * \defgroup grp_screen utilities for painting to the screen
+ * @ingroup grp_screen
+ */
+
+namespace DFHack
+{
+ class Core;
+
+ /**
+ * The Screen module
+ * \ingroup grp_modules
+ * \ingroup grp_screen
+ */
+ namespace Screen
+ {
+ /// Data structure describing all properties a screen tile can have
+ struct Pen {
+ // Ordinary text symbol
+ char ch;
+ int8_t fg, bg;
+ bool bold;
+
+ // Graphics tile
+ int tile;
+ enum TileMode {
+ AsIs, // Tile colors used without modification
+ CharColor, // The fg/bg pair is used
+ TileColor // The fields below are used
+ } tile_mode;
+ int8_t tile_fg, tile_bg;
+
+ Pen(char ch = 0, int8_t fg = 7, int8_t bg = 0, int tile = 0, bool color_tile = false)
+ : ch(ch), fg(fg&7), bg(bg), bold(!!(fg&8)),
+ tile(tile), tile_mode(color_tile ? CharColor : AsIs), tile_fg(0), tile_bg(0)
+ {}
+ Pen(char ch, int8_t fg, int8_t bg, bool bold, int tile = 0, bool color_tile = false)
+ : ch(ch), fg(fg), bg(bg), bold(bold),
+ tile(tile), tile_mode(color_tile ? CharColor : AsIs), tile_fg(0), tile_bg(0)
+ {}
+ Pen(char ch, int8_t fg, int8_t bg, int tile, int8_t tile_fg, int8_t tile_bg)
+ : ch(ch), fg(fg&7), bg(bg), bold(!!(fg&8)),
+ tile(tile), tile_mode(TileColor), tile_fg(tile_fg), tile_bg(tile_bg)
+ {}
+ Pen(char ch, int8_t fg, int8_t bg, bool bold, int tile, int8_t tile_fg, int8_t tile_bg)
+ : ch(ch), fg(fg), bg(bg), bold(bold),
+ tile(tile), tile_mode(TileColor), tile_fg(tile_fg), tile_bg(tile_bg)
+ {}
+ };
+
+ DFHACK_EXPORT df::coord2d getMousePos();
+ DFHACK_EXPORT df::coord2d getWindowSize();
+
+ /// Returns the state of [GRAPHICS:YES/NO]
+ DFHACK_EXPORT bool inGraphicsMode();
+
+ /// Paint one screen tile with the given pen
+ DFHACK_EXPORT bool paintTile(const Pen &pen, int x, int y);
+
+ /// Paint a string onto the screen. Ignores ch and tile of pen.
+ DFHACK_EXPORT bool paintString(const Pen &pen, int x, int y, const std::string &text);
+
+ /// Fills a rectangle with one pen. Possibly more efficient than a loop over paintTile.
+ DFHACK_EXPORT bool fillRect(const Pen &pen, int x1, int y1, int x2, int y2);
+
+ /// Draws a standard dark gray window border with a title string
+ DFHACK_EXPORT bool drawBorder(const std::string &title);
+
+ /// Wipes the screen to full black
+ DFHACK_EXPORT bool clear();
+
+ /// Requests repaint
+ DFHACK_EXPORT bool invalidate();
+
+ /// Find a loaded graphics tile from graphics raws.
+ DFHACK_EXPORT bool findGraphicsTile(const std::string &page, int x, int y, int *ptile, int *pgs = NULL);
+
+ // Push and remove viewscreens
+ DFHACK_EXPORT bool show(df::viewscreen *screen, df::viewscreen *before = NULL);
+ DFHACK_EXPORT void dismiss(df::viewscreen *screen, bool to_first = false);
+ DFHACK_EXPORT bool isDismissed(df::viewscreen *screen);
+ }
+
+ class DFHACK_EXPORT dfhack_viewscreen : public df::viewscreen {
+ df::coord2d last_size;
+ void check_resize();
+
+ protected:
+ bool text_input_mode;
+
+ public:
+ dfhack_viewscreen();
+ virtual ~dfhack_viewscreen();
+
+ static bool is_instance(df::viewscreen *screen);
+
+ virtual void logic();
+ virtual void render();
+
+ virtual int8_t movies_okay() { return 1; }
+ virtual bool key_conflict(df::interface_key key);
+
+ virtual bool is_lua_screen() { return false; }
+
+ virtual std::string getFocusString() = 0;
+ virtual void onShow() {};
+ virtual void onDismiss() {};
+ };
+
+ class DFHACK_EXPORT dfhack_lua_viewscreen : public dfhack_viewscreen {
+ std::string focus;
+
+ void update_focus(lua_State *L, int idx);
+
+ bool safe_call_lua(int (*pf)(lua_State *), int args, int rvs);
+ static dfhack_lua_viewscreen *get_self(lua_State *L);
+
+ static int do_destroy(lua_State *L);
+ static int do_render(lua_State *L);
+ static int do_notify(lua_State *L);
+ static int do_input(lua_State *L);
+
+ public:
+ dfhack_lua_viewscreen(lua_State *L, int table_idx);
+ virtual ~dfhack_lua_viewscreen();
+
+ static df::viewscreen *get_pointer(lua_State *L, int idx, bool make);
+
+ virtual bool is_lua_screen() { return true; }
+ virtual std::string getFocusString() { return focus; }
+
+ virtual void render();
+ virtual void logic();
+ virtual void help();
+ virtual void resize(int w, int h);
+ virtual void feed(std::set<df::interface_key> *keys);
+
+ virtual void onShow();
+ virtual void onDismiss();
+ };
+}
diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h
index 7bf4f101..9003dc3a 100644
--- a/library/include/modules/Units.h
+++ b/library/include/modules/Units.h
@@ -226,6 +226,9 @@ DFHACK_EXPORT bool getNoblePositions(std::vector<NoblePosition> *pvec, df::unit
DFHACK_EXPORT std::string getProfessionName(df::unit *unit, bool ignore_noble = false, bool plural = false);
DFHACK_EXPORT std::string getCasteProfessionName(int race, int caste, df::profession pid, bool plural = false);
+
+DFHACK_EXPORT int8_t getProfessionColor(df::unit *unit, bool ignore_noble = false);
+DFHACK_EXPORT int8_t getCasteProfessionColor(int race, int caste, df::profession pid);
}
}
#endif