diff --git a/LUA_API.rst b/LUA_API.rst
index dab299741..422ba6b49 100644
--- a/LUA_API.rst
+++ b/LUA_API.rst
@@ -503,6 +503,10 @@ C++ function wrappers
Thin wrappers around C++ functions, similar to the ones for virtual methods.
+* ``dfhack.TranslateName(name,in_english,only_last_name)``
+
+ Convert a language_name or only the last name part to string.
+
Gui module
----------
@@ -558,3 +562,22 @@ Job module
* ``dfhack.job.is_item_equal(job_item1,job_item2)``
Compares important fields in the job item structures.
+
+Units module
+------------
+
+* ``dfhack.units.getVisibleName(unit)``
+
+ Returns the name visible in game, accounting for false identities.
+
+* ``dfhack.units.isDead(unit)``
+
+ The unit is completely dead and passive.
+
+* ``dfhack.units.isAlive(unit)``
+
+ The unit isn't dead or undead.
+
+* ``dfhack.units.isSane(unit)``
+
+ The unit is capable of rational action, i.e. not dead, insane or zombie.
diff --git a/Lua API.html b/Lua API.html
index 877bdbd88..ab64eea9a 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -338,6 +338,7 @@ ul.auto-toc {
C++ function wrappers
@@ -761,6 +762,11 @@ However, currently every entry has a 180+-byte dead-weight overhead.
Thin wrappers around C++ functions, similar to the ones for virtual methods.
+
+dfhack.TranslateName(name,in_english,only_last_name)
+Convert a language_name or only the last name part to string.
+
+
@@ -810,6 +816,23 @@ The is_bright boolean actually seems to invert the brightness.
+
+
+
+dfhack.units.getVisibleName(unit)
+Returns the name visible in game, accounting for false identities.
+
+dfhack.units.isDead(unit)
+The unit is completely dead and passive.
+
+dfhack.units.isAlive(unit)
+The unit isn't dead or undead.
+
+dfhack.units.isSane(unit)
+The unit is capable of rational action, i.e. not dead, insane or zombie.
+
+
+
diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp
index 5afd1156b..5a87c931d 100644
--- a/library/LuaTools.cpp
+++ b/library/LuaTools.cpp
@@ -40,6 +40,8 @@ distribution.
#include "modules/World.h"
#include "modules/Gui.h"
#include "modules/Job.h"
+#include "modules/Translation.h"
+#include "modules/Units.h"
#include "LuaWrapper.h"
#include "LuaTools.h"
@@ -641,9 +643,9 @@ static const luaL_Reg dfhack_funcs[] = {
{ NULL, NULL }
};
-/*
- * Per-world persistent configuration storage.
- */
+/**************************************************
+ * Per-world persistent configuration storage API *
+ **************************************************/
static PersistentDataItem persistent_by_struct(lua_State *state, int idx)
{
@@ -783,6 +785,7 @@ static int dfhack_persistent_save(lua_State *state)
lua_settop(state, 1);
+ // Retrieve existing or create a new entry
PersistentDataItem ref;
bool added = false;
@@ -804,6 +807,7 @@ static int dfhack_persistent_save(lua_State *state)
ref = Core::getInstance().getWorld()->GetPersistentData(str);
}
+ // Auto-add if not found
if (!ref.isValid())
{
ref = Core::getInstance().getWorld()->AddPersistentData(str);
@@ -812,6 +816,7 @@ static int dfhack_persistent_save(lua_State *state)
added = true;
}
+ // Copy data from lua to C++ memory
lua_getfield(state, 1, "value");
if (const char *str = lua_tostring(state, -1))
ref.val() = str;
@@ -830,6 +835,7 @@ static int dfhack_persistent_save(lua_State *state)
}
lua_pop(state, 1);
+ // Reinitialize lua from C++ and return
read_persistent(state, ref, false);
lua_pushboolean(state, added);
return 2;
@@ -856,6 +862,10 @@ static void OpenPersistent(lua_State *state)
lua_pop(state, 1);
}
+/************************
+ * Wrappers for C++ API *
+ ************************/
+
static void OpenModule(lua_State *state, const char *mname, const LuaWrapper::FunctionReg *reg)
{
luaL_getsubtable(state, lua_gettop(state), mname);
@@ -867,6 +877,11 @@ static void OpenModule(lua_State *state, const char *mname, const LuaWrapper::Fu
#define WRAP(function) { #function, df::wrap_function(&function) }
#define WRAPN(name, function) { #name, df::wrap_function(&function) }
+static const LuaWrapper::FunctionReg dfhack_module[] = {
+ WRAPM(Translation, TranslateName),
+ { NULL, NULL }
+};
+
static const LuaWrapper::FunctionReg dfhack_gui_module[] = {
WRAPM(Gui, getSelectedWorkshopJob),
WRAPM(Gui, getSelectedJob),
@@ -889,6 +904,18 @@ static const LuaWrapper::FunctionReg dfhack_job_module[] = {
{ NULL, NULL }
};
+static const LuaWrapper::FunctionReg dfhack_units_module[] = {
+ WRAPM(Units, getVisibleName),
+ WRAPM(Units, isDead),
+ WRAPM(Units, isAlive),
+ WRAPM(Units, isSane),
+ { NULL, NULL }
+};
+
+/************************
+ * Main Open function *
+ ************************/
+
lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
{
if (!state)
@@ -917,8 +944,10 @@ lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
OpenPersistent(state);
+ LuaWrapper::SetFunctionWrappers(state, dfhack_module);
OpenModule(state, "gui", dfhack_gui_module);
OpenModule(state, "job", dfhack_job_module);
+ OpenModule(state, "units", dfhack_units_module);
lua_setglobal(state, "dfhack");
diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp
index 01c110643..00344d6a2 100644
--- a/library/RemoteTools.cpp
+++ b/library/RemoteTools.cpp
@@ -256,7 +256,7 @@ void DFHack::describeUnit(BasicUnitInfo *info, df::unit *unit,
info->set_pos_y(unit->pos.y);
info->set_pos_z(unit->pos.z);
- auto name = Units::GetVisibleName(unit);
+ auto name = Units::getVisibleName(unit);
if (name->has_name)
describeName(info->mutable_name(), name);
diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h
index 0fd75bf1f..b966a39be 100644
--- a/library/include/modules/Units.h
+++ b/library/include/modules/Units.h
@@ -193,7 +193,7 @@ DFHACK_EXPORT void CopyNameTo(df::unit *creature, df::language_name * target);
DFHACK_EXPORT bool RemoveOwnedItemByIdx(const uint32_t index, int32_t id);
DFHACK_EXPORT bool RemoveOwnedItemByPtr(df::unit * unit, int32_t id);
-DFHACK_EXPORT df::language_name *GetVisibleName(df::unit *unit);
+DFHACK_EXPORT df::language_name *getVisibleName(df::unit *unit);
DFHACK_EXPORT bool isDead(df::unit *unit);
DFHACK_EXPORT bool isAlive(df::unit *unit);
diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua
index 1101367fc..9e2cdf257 100644
--- a/library/lua/dfhack.lua
+++ b/library/lua/dfhack.lua
@@ -58,9 +58,10 @@ end
-- Misc functions
function printall(table)
- if table == nil then return end
- for k,v in pairs(table) do
- print(k," = "..tostring(v))
+ if type(table) == 'table' or df.isvalid(table) == 'ref' then
+ for k,v in pairs(table) do
+ print(string.format("%-23s\t = %s",tostring(k),tostring(v)))
+ end
end
end
diff --git a/library/modules/Translation.cpp b/library/modules/Translation.cpp
index 7b5fa654c..bc0724707 100644
--- a/library/modules/Translation.cpp
+++ b/library/modules/Translation.cpp
@@ -35,6 +35,7 @@ using namespace std;
#include "Types.h"
#include "ModuleFactory.h"
#include "Core.h"
+#include "Error.h"
using namespace DFHack;
using namespace df::enums;
@@ -93,6 +94,8 @@ void addNameWord (string &out, const string &word)
string Translation::TranslateName(const df::language_name * name, bool inEnglish, bool onlyLastPart)
{
+ CHECK_NULL_POINTER(name);
+
string out;
string word;
diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp
index f6259bd3b..3dc5d1b04 100644
--- a/library/modules/Units.cpp
+++ b/library/modules/Units.cpp
@@ -527,8 +527,10 @@ void Units::CopyNameTo(df::unit * creature, df::language_name * target)
Translation::copyName(&creature->name, target);
}
-df::language_name *Units::GetVisibleName(df::unit *unit)
+df::language_name *Units::getVisibleName(df::unit *unit)
{
+ CHECK_NULL_POINTER(unit);
+
df::historical_figure *figure = df::historical_figure::find(unit->hist_figure_id);
if (figure)
@@ -555,11 +557,15 @@ df::language_name *Units::GetVisibleName(df::unit *unit)
bool DFHack::Units::isDead(df::unit *unit)
{
+ CHECK_NULL_POINTER(unit);
+
return unit->flags1.bits.dead;
}
bool DFHack::Units::isAlive(df::unit *unit)
{
+ CHECK_NULL_POINTER(unit);
+
return !unit->flags1.bits.dead &&
!unit->flags3.bits.ghostly &&
!unit->curse.add_tags1.bits.NOT_LIVING;
@@ -567,23 +573,22 @@ bool DFHack::Units::isAlive(df::unit *unit)
bool DFHack::Units::isSane(df::unit *unit)
{
+ CHECK_NULL_POINTER(unit);
+
if (unit->flags1.bits.dead ||
unit->flags3.bits.ghostly ||
unit->curse.add_tags1.bits.OPPOSED_TO_LIFE ||
unit->curse.add_tags1.bits.CRAZED)
return false;
- if (unit->flags1.bits.has_mood)
+ switch (unit->mood)
{
- switch (unit->mood)
- {
- case mood_type::Melancholy:
- case mood_type::Raving:
- case mood_type::Berserk:
- return false;
- default:
- break;
- }
+ case mood_type::Melancholy:
+ case mood_type::Raving:
+ case mood_type::Berserk:
+ return false;
+ default:
+ break;
}
return true;