Merge remote-tracking branch 'DFHack/develop'

develop
Japa Illo 2017-06-20 10:51:52 +05:30
commit 96f9faea28
33 changed files with 500 additions and 784 deletions

@ -193,6 +193,9 @@ tweak condition-material
# Adds an option to clear currently-bound hotkeys # Adds an option to clear currently-bound hotkeys
tweak hotkey-clear tweak hotkey-clear
# Allows lowercase letters in embark profile names, and allows exiting the name prompt without saving
tweak embark-profile-name
# Misc. UI tweaks # Misc. UI tweaks
tweak block-labors # Prevents labors that can't be used from being toggled tweak block-labors # Prevents labors that can't be used from being toggled
tweak civ-view-agreement tweak civ-view-agreement

@ -106,6 +106,29 @@ of DFhack, rather than plugins or scripts.
.. _cls: .. _cls:
alias
-----
The ``alias`` command allows configuring aliases to other DFHack commands.
Aliases are resolved immediately after built-in commands, which means that an
alias cannot override a built-in command, but can override a command implemented
by a plugin or script.
Usage:
:``alias list``: lists all configured aliases
:``alias add <name> <command> [arguments...]``: adds an alias
:``alias replace <name> <command> [arguments...]``: replaces an existing
alias with a new command, or adds the alias if it does not already exist
:``alias delete <name>``: removes the specified alias
Aliases can be given additional arguments when created and invoked, which will
be passed to the underlying command in order. An example with `devel/print-args`::
[DFHack]# alias add pargs devel/print-args example
[DFHack]# pargs text
example
text
cls cls
--- ---
Clear the terminal. Does not delete command history. Clear the terminal. Does not delete command history.

@ -1059,6 +1059,13 @@ Units module
Returns true *x,y,z* of the unit, or *nil* if invalid; may be not equal to unit.pos if caged. Returns true *x,y,z* of the unit, or *nil* if invalid; may be not equal to unit.pos if caged.
* ``dfhack.getUnitsInBox(x1,y1,z1,x2,y2,z2[,filter])``
Returns a table of all units within the specified coordinates. If the ``filter``
argument is given, only units where ``filter(unit)`` returns true will be included.
Note that ``pos2xyz()`` cannot currently be used to convert coordinate objects to
the arguments required by this function.
* ``dfhack.units.getGeneralRef(unit, type)`` * ``dfhack.units.getGeneralRef(unit, type)``
Searches for a general_ref with the given type. Searches for a general_ref with the given type.
@ -1128,6 +1135,10 @@ Units module
The unit is an alive sane citizen of the fortress; wraps the The unit is an alive sane citizen of the fortress; wraps the
same checks the game uses to decide game-over by extinction. same checks the game uses to decide game-over by extinction.
* ``dfhack.units.isVisible(unit)``
The unit is visible on the map.
* ``dfhack.units.getAge(unit[,true_age])`` * ``dfhack.units.getAge(unit[,true_age])``
Returns the age of the unit in years as a floating-point value. Returns the age of the unit in years as a floating-point value.
@ -1293,6 +1304,10 @@ Maps module
Checks if the given df::coord or x,y,z in local tile coordinates are valid. Checks if the given df::coord or x,y,z in local tile coordinates are valid.
* ``dfhack.maps.isTileVisible(coords)``, or ``isTileVisible(x,y,z)``
Checks if the given df::coord or x,y,z in local tile coordinates is visible.
* ``dfhack.maps.getTileBlock(coords)``, or ``getTileBlock(x,y,z)`` * ``dfhack.maps.getTileBlock(coords)``, or ``getTileBlock(x,y,z)``
Returns a map block object for given df::coord or x,y,z in local tile coordinates. Returns a map block object for given df::coord or x,y,z in local tile coordinates.
@ -1634,25 +1649,25 @@ Basic painting functions:
Checks if [GRAPHICS:YES] was specified in init. Checks if [GRAPHICS:YES] was specified in init.
* ``dfhack.screen.paintTile(pen,x,y[,char,tile])`` * ``dfhack.screen.paintTile(pen,x,y[,char,tile,map])``
Paints a tile using given parameters. See below for a description of pen. Paints a tile using given parameters. See below for a description of pen.
Returns *false* if coordinates out of bounds, or other error. Returns *false* if coordinates out of bounds, or other error.
* ``dfhack.screen.readTile(x,y)`` * ``dfhack.screen.readTile(x,y[,map])``
Retrieves the contents of the specified tile from the screen buffers. Retrieves the contents of the specified tile from the screen buffers.
Returns a pen object, or *nil* if invalid or TrueType. Returns a pen object, or *nil* if invalid or TrueType.
* ``dfhack.screen.paintString(pen,x,y,text)`` * ``dfhack.screen.paintString(pen,x,y,text[,map])``
Paints the string starting at *x,y*. Uses the string characters Paints the string starting at *x,y*. Uses the string characters
in sequence to override the ``ch`` field of pen. in sequence to override the ``ch`` field of pen.
Returns *true* if painting at least one character succeeded. Returns *true* if painting at least one character succeeded.
* ``dfhack.screen.fillRect(pen,x1,y1,x2,y2)`` * ``dfhack.screen.fillRect(pen,x1,y1,x2,y2[,map])``
Fills the rectangle specified by the coordinates with the given pen. Fills the rectangle specified by the coordinates with the given pen.
Returns *true* if painting at least one character succeeded. Returns *true* if painting at least one character succeeded.

@ -1,10 +1,10 @@
/* make sure to sync this with the base theme's css filename */ /* make sure to sync this with the base theme's css filename */
@import url("alabaster.css"); @import url("alabaster.css");
.kbd {
/* Keybinding CSS from the DF wiki; applies to :kbd:`` directives. /* Keybinding CSS from the DF wiki; applies to :kbd:`` directives.
* Use this directive for all keypresses, to make them look like keys. * Use this directive for all keypresses, to make them look like keys.
*/ */
.kbd {
border: 1px solid #aaa; border: 1px solid #aaa;
border-radius: 0.2em; border-radius: 0.2em;
-webkit-border-radius: 0.2em; -webkit-border-radius: 0.2em;
@ -28,13 +28,21 @@
src: url("cp437.ttf"); src: url("cp437.ttf");
} }
.guilabel {
/* In-game text CSS from the DF wiki; applies to :guilabel:`` directives. /* In-game text CSS from the DF wiki; applies to :guilabel:`` directives.
* Use this for any text from an in-game announcement or menu. * Use this for any text from an in-game announcement or menu.
*/ */
.guilabel {
color: #CBC7C0; color: #CBC7C0;
font-family: cp437, 'fixedsys', monospace; font-family: cp437, 'fixedsys', monospace;
background: #000000; background: #000000;
font-size: 0.95em; font-size: 0.95em;
padding: 0.05em 0.4em; padding: 0.05em 0.4em;
} }
/* Override hyphenation from Sphinx's basic.css (excessive) */
div.body p, div.body dd, div.body li, div.body blockquote {
-moz-hyphens: manual;
-ms-hyphens: manual;
-webkit-hyphens: manual;
hyphens: manual;
}

@ -358,6 +358,7 @@ IF(APPLE)
TARGET_LINK_LIBRARIES(dfhack ${SDL_LIBRARY}) TARGET_LINK_LIBRARIES(dfhack ${SDL_LIBRARY})
TARGET_LINK_LIBRARIES(dfhack ${CXX_LIBRARY}) TARGET_LINK_LIBRARIES(dfhack ${CXX_LIBRARY})
TARGET_LINK_LIBRARIES(dfhack ${ZIP_LIBRARY}) TARGET_LINK_LIBRARIES(dfhack ${ZIP_LIBRARY})
TARGET_LINK_LIBRARIES(dfhack ncurses)
SET_TARGET_PROPERTIES(dfhack PROPERTIES VERSION 1.0.0) SET_TARGET_PROPERTIES(dfhack PROPERTIES VERSION 1.0.0)
SET_TARGET_PROPERTIES(dfhack PROPERTIES SOVERSION 1.0.0) SET_TARGET_PROPERTIES(dfhack PROPERTIES SOVERSION 1.0.0)
ENDIF() ENDIF()

@ -373,7 +373,7 @@ static command_result enableLuaScript(color_ostream &out, std::string name, bool
return ok ? CR_OK : CR_FAILURE; return ok ? CR_OK : CR_FAILURE;
} }
static command_result runRubyScript(color_ostream &out, PluginManager *plug_mgr, std::string name, vector<string> &args) static command_result runRubyScript(color_ostream &out, PluginManager *plug_mgr, std::string filename, vector<string> &args)
{ {
if (!plug_mgr->ruby || !plug_mgr->ruby->is_enabled()) if (!plug_mgr->ruby || !plug_mgr->ruby->is_enabled())
return CR_FAILURE; return CR_FAILURE;
@ -383,7 +383,7 @@ static command_result runRubyScript(color_ostream &out, PluginManager *plug_mgr,
rbcmd += "'" + args[i] + "', "; rbcmd += "'" + args[i] + "', ";
rbcmd += "]\n"; rbcmd += "]\n";
rbcmd += "catch(:script_finished) { load './hack/scripts/" + name + ".rb' }"; rbcmd += "catch(:script_finished) { load '" + filename + "' }";
return plug_mgr->ruby->eval_ruby(out, rbcmd.c_str()); return plug_mgr->ruby->eval_ruby(out, rbcmd.c_str());
} }
@ -603,6 +603,7 @@ string getBuiltinCommand(std::string cmd)
cmd == "disable" || cmd == "disable" ||
cmd == "plug" || cmd == "plug" ||
cmd == "keybinding" || cmd == "keybinding" ||
cmd == "alias" ||
cmd == "fpause" || cmd == "fpause" ||
cmd == "cls" || cmd == "cls" ||
cmd == "die" || cmd == "die" ||
@ -650,6 +651,7 @@ void ls_helper(color_ostream &con, const PluginCommand &pcmd)
command_result Core::runCommand(color_ostream &con, const std::string &first_, vector<string> &parts) command_result Core::runCommand(color_ostream &con, const std::string &first_, vector<string> &parts)
{ {
std::string first = first_; std::string first = first_;
command_result res;
if (!first.empty()) if (!first.empty())
{ {
if(first.find('\\') != std::string::npos) if(first.find('\\') != std::string::npos)
@ -787,8 +789,6 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
if(parts.size()) if(parts.size())
{ {
command_result res = CR_OK;
for (size_t i = 0; i < parts.size(); i++) for (size_t i = 0; i < parts.size(); i++)
{ {
std::string part = parts[i]; std::string part = parts[i];
@ -994,6 +994,10 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
con << " (aliased to " << builtin_cmd << ")"; con << " (aliased to " << builtin_cmd << ")";
con << std::endl; con << std::endl;
} }
else if (IsAlias(parts[0]))
{
con << " is an alias: " << GetAliasCommand(parts[0]) << std::endl;
}
else if (plug) else if (plug)
{ {
con << " is a command implemented by the plugin " << plug->getName() << std::endl; con << " is a command implemented by the plugin " << plug->getName() << std::endl;
@ -1063,6 +1067,42 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
<< Gui::getFocusString(Core::getTopViewscreen()) << endl; << Gui::getFocusString(Core::getTopViewscreen()) << endl;
} }
} }
else if (builtin == "alias")
{
if (parts.size() >= 3 && (parts[0] == "add" || parts[0] == "replace"))
{
const string &name = parts[1];
vector<string> cmd(parts.begin() + 2, parts.end());
if (!AddAlias(name, cmd, parts[0] == "replace"))
{
con.printerr("Could not add alias %s - already exists\n", name.c_str());
return CR_FAILURE;
}
}
else if (parts.size() >= 2 && (parts[0] == "delete" || parts[0] == "clear"))
{
if (!RemoveAlias(parts[1]))
{
con.printerr("Could not remove alias %s\n", parts[1].c_str());
return CR_FAILURE;
}
}
else if (parts.size() >= 1 && (parts[0] == "list"))
{
auto aliases = ListAliases();
for (auto p : aliases)
{
con << p.first << ": " << join_strings(" ", p.second) << endl;
}
}
else
{
con << "Usage: " << endl
<< " alias add|replace <name> <command...>" << endl
<< " alias delete|clear <name> <command...>" << endl
<< " alias list" << endl;
}
}
else if (builtin == "fpause") else if (builtin == "fpause")
{ {
World::SetPauseState(true); World::SetPauseState(true);
@ -1126,13 +1166,9 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
} }
else if (builtin == "sc-script") else if (builtin == "sc-script")
{ {
if (parts.size() < 1) if (parts.empty() || parts[0] == "help" || parts[0] == "?")
{ {
con << "Usage: sc-script add|remove|list|help SC_EVENT [path-to-script] [...]" << endl; con << "Usage: sc-script add|remove|list|help SC_EVENT [path-to-script] [...]" << endl;
return CR_WRONG_USAGE;
}
if (parts[0] == "help" || parts[0] == "?")
{
con << "Valid event names (SC_ prefix is optional):" << endl; con << "Valid event names (SC_ prefix is optional):" << endl;
for (int i = SC_WORLD_LOADED; i <= SC_UNPAUSED; i++) for (int i = SC_WORLD_LOADED; i <= SC_UNPAUSED; i++)
{ {
@ -1222,9 +1258,13 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
} }
else if (RunAlias(con, first, parts, res))
{
return res;
}
else else
{ {
command_result res = plug_mgr->InvokeCommand(con, first, parts); res = plug_mgr->InvokeCommand(con, first, parts);
if(res == CR_NOT_IMPLEMENTED) if(res == CR_NOT_IMPLEMENTED)
{ {
string completed; string completed;
@ -1236,7 +1276,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v
if ( lua ) if ( lua )
res = runLuaScript(con, first, parts); res = runLuaScript(con, first, parts);
else if ( filename != "" && plug_mgr->ruby && plug_mgr->ruby->is_enabled() ) else if ( filename != "" && plug_mgr->ruby && plug_mgr->ruby->is_enabled() )
res = runRubyScript(con, plug_mgr, first, parts); res = runRubyScript(con, plug_mgr, filename, parts);
else if ( try_autocomplete(con, first, completed) ) else if ( try_autocomplete(con, first, completed) )
res = CR_NOT_IMPLEMENTED; res = CR_NOT_IMPLEMENTED;
else else
@ -1409,7 +1449,8 @@ Core::Core()
hotkey_set = false; hotkey_set = false;
HotkeyMutex = 0; HotkeyMutex = 0;
HotkeyCond = 0; HotkeyCond = 0;
misc_data_mutex=0; alias_mutex = 0;
misc_data_mutex = 0;
last_world_data_ptr = NULL; last_world_data_ptr = NULL;
last_local_map_ptr = NULL; last_local_map_ptr = NULL;
last_pause_state = false; last_pause_state = false;
@ -1530,6 +1571,7 @@ bool Core::Init()
// Init global object pointers // Init global object pointers
df::global::InitGlobals(); df::global::InitGlobals();
alias_mutex = new recursive_mutex();
cerr << "Initializing Console.\n"; cerr << "Initializing Console.\n";
// init the console. // init the console.
@ -2580,6 +2622,64 @@ std::vector<std::string> Core::ListKeyBindings(std::string keyspec)
return rv; return rv;
} }
bool Core::AddAlias(const std::string &name, const std::vector<std::string> &command, bool replace)
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
if (!IsAlias(name) || replace)
{
aliases[name] = command;
return true;
}
return false;
}
bool Core::RemoveAlias(const std::string &name)
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
if (IsAlias(name))
{
aliases.erase(name);
return true;
}
return false;
}
bool Core::IsAlias(const std::string &name)
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
return aliases.find(name) != aliases.end();
}
bool Core::RunAlias(color_ostream &out, const std::string &name,
const std::vector<std::string> &parameters, command_result &result)
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
if (!IsAlias(name))
{
return false;
}
const string &first = aliases[name][0];
vector<string> parts(aliases[name].begin() + 1, aliases[name].end());
parts.insert(parts.end(), parameters.begin(), parameters.end());
result = runCommand(out, first, parts);
return true;
}
std::map<std::string, std::vector<std::string>> Core::ListAliases()
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
return aliases;
}
std::string Core::GetAliasCommand(const std::string &name, const std::string &default_)
{
tthread::lock_guard<tthread::recursive_mutex> lock(*alias_mutex);
if (IsAlias(name))
return join_strings(" ", aliases[name]);
else
return default_;
}
///////////////// /////////////////
// ClassNameCheck // ClassNameCheck

@ -59,15 +59,16 @@ typedef struct interpose_s
};*/ };*/
#define DYLD_INTERPOSE(_replacment,_replacee) \ #define DYLD_INTERPOSE(_replacement,_replacee) \
__attribute__((used)) static struct{ const void* replacment; const void* replacee; } \ __attribute__((used)) static struct{ const void* replacment; const void* replacee; } \
_interpose_##_replacee __attribute__ ((section ("__DATA,__interpose"))) = \ _interpose_##_replacee __attribute__ ((section ("__DATA,__interpose"))) = \
{ (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee }; { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee };
DYLD_INTERPOSE(DFH_SDL_Init,SDL_Init); DYLD_INTERPOSE(DFH_SDL_Init,SDL_Init);
DYLD_INTERPOSE(DFH_SDL_PollEvent,SDL_PollEvent); DYLD_INTERPOSE(DFH_SDL_PollEvent,SDL_PollEvent);
DYLD_INTERPOSE(DFH_SDL_Quit,SDL_Quit); DYLD_INTERPOSE(DFH_SDL_Quit,SDL_Quit);
DYLD_INTERPOSE(DFH_SDL_NumJoysticks,SDL_NumJoysticks); DYLD_INTERPOSE(DFH_SDL_NumJoysticks,SDL_NumJoysticks);
DYLD_INTERPOSE(DFH_wgetch,wgetch);
/******************************************************************************* /*******************************************************************************
* SDL part starts here * * SDL part starts here *
@ -127,16 +128,11 @@ DFhackCExport int SDL_PushEvent(SDL::Event* event)
} }
struct WINDOW; struct WINDOW;
DFhackCExport int wgetch(WINDOW *win) DFhackCExport int DFH_wgetch(WINDOW *win)
{ {
static int (*_wgetch)(WINDOW * win) = (int (*)( WINDOW * )) dlsym(RTLD_NEXT, "wgetch");
if(!_wgetch)
{
exit(EXIT_FAILURE);
}
DFHack::Core & c = DFHack::Core::getInstance(); DFHack::Core & c = DFHack::Core::getInstance();
wgetch_again: wgetch_again:
int in = _wgetch(win); int in = wgetch(win);
int out; int out;
if(c.ncurses_wgetch(in, out)) if(c.ncurses_wgetch(in, out))
{ {

@ -1444,6 +1444,26 @@ static const LuaWrapper::FunctionReg dfhack_module[] = {
/***** Gui module *****/ /***** Gui module *****/
static int gui_getDwarfmodeViewDims(lua_State *state)
{
auto dims = Gui::getDwarfmodeViewDims();
lua_newtable(state);
Lua::TableInsert(state, "map_x1", dims.map_x1);
Lua::TableInsert(state, "map_x2", dims.map_x2);
Lua::TableInsert(state, "menu_x1", dims.menu_x1);
Lua::TableInsert(state, "menu_x2", dims.menu_x2);
Lua::TableInsert(state, "area_x1", dims.area_x1);
Lua::TableInsert(state, "area_x2", dims.area_x2);
Lua::TableInsert(state, "y1", dims.y1);
Lua::TableInsert(state, "y2", dims.y2);
Lua::TableInsert(state, "map_y1", dims.map_y1);
Lua::TableInsert(state, "map_y2", dims.map_y2);
Lua::TableInsert(state, "menu_on", dims.menu_on);
Lua::TableInsert(state, "area_on", dims.area_on);
Lua::TableInsert(state, "menu_forced", dims.menu_forced);
return 1;
}
static const LuaWrapper::FunctionReg dfhack_gui_module[] = { static const LuaWrapper::FunctionReg dfhack_gui_module[] = {
WRAPM(Gui, getCurViewscreen), WRAPM(Gui, getCurViewscreen),
WRAPM(Gui, getFocusString), WRAPM(Gui, getFocusString),
@ -1454,6 +1474,10 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = {
WRAPM(Gui, getSelectedItem), WRAPM(Gui, getSelectedItem),
WRAPM(Gui, getSelectedBuilding), WRAPM(Gui, getSelectedBuilding),
WRAPM(Gui, getSelectedPlant), WRAPM(Gui, getSelectedPlant),
WRAPM(Gui, getAnyUnit),
WRAPM(Gui, getAnyItem),
WRAPM(Gui, getAnyBuilding),
WRAPM(Gui, getAnyPlant),
WRAPM(Gui, writeToGamelog), WRAPM(Gui, writeToGamelog),
WRAPM(Gui, makeAnnouncement), WRAPM(Gui, makeAnnouncement),
WRAPM(Gui, addCombatReport), WRAPM(Gui, addCombatReport),
@ -1463,6 +1487,12 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = {
WRAPM(Gui, showPopupAnnouncement), WRAPM(Gui, showPopupAnnouncement),
WRAPM(Gui, showAutoAnnouncement), WRAPM(Gui, showAutoAnnouncement),
WRAPM(Gui, revealInDwarfmodeMap), WRAPM(Gui, revealInDwarfmodeMap),
WRAPM(Gui, getDepthAt),
{ NULL, NULL }
};
static const luaL_Reg dfhack_gui_funcs[] = {
{ "getDwarfmodeViewDims", gui_getDwarfmodeViewDims },
{ NULL, NULL } { NULL, NULL }
}; };
@ -1542,6 +1572,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, isSane), WRAPM(Units, isSane),
WRAPM(Units, isDwarf), WRAPM(Units, isDwarf),
WRAPM(Units, isCitizen), WRAPM(Units, isCitizen),
WRAPM(Units, isVisible),
WRAPM(Units, getAge), WRAPM(Units, getAge),
WRAPM(Units, getKillCount), WRAPM(Units, getKillCount),
WRAPM(Units, getNominalSkill), WRAPM(Units, getNominalSkill),
@ -1608,9 +1639,40 @@ static int units_getNoblePositions(lua_State *state)
return 1; return 1;
} }
static int units_getUnitsInBox(lua_State *state)
{
std::vector<df::unit*> units;
int x1 = luaL_checkint(state, 1);
int y1 = luaL_checkint(state, 2);
int z1 = luaL_checkint(state, 3);
int x2 = luaL_checkint(state, 4);
int y2 = luaL_checkint(state, 5);
int z2 = luaL_checkint(state, 6);
bool ok = Units::getUnitsInBox(units, x1, y1, z1, x2, y2, z2);
if (ok && !lua_isnone(state, 7))
{
luaL_checktype(state, 7, LUA_TFUNCTION);
units.erase(std::remove_if(units.begin(), units.end(), [&state](df::unit *unit) -> bool {
lua_dup(state); // copy function
Lua::PushDFObject(state, unit);
lua_call(state, 1, 1);
bool ret = lua_toboolean(state, -1);
lua_pop(state, 1); // remove return value
return !ret;
}), units.end());
}
Lua::PushVector(state, units);
lua_pushboolean(state, ok);
return 2;
}
static const luaL_Reg dfhack_units_funcs[] = { static const luaL_Reg dfhack_units_funcs[] = {
{ "getPosition", units_getPosition }, { "getPosition", units_getPosition },
{ "getNoblePositions", units_getNoblePositions }, { "getNoblePositions", units_getNoblePositions },
{ "getUnitsInBox", units_getUnitsInBox },
{ NULL, NULL } { NULL, NULL }
}; };
@ -1757,6 +1819,13 @@ static int maps_isValidTilePos(lua_State *L)
return 1; return 1;
} }
static int maps_isTileVisible(lua_State *L)
{
auto pos = CheckCoordXYZ(L, 1, true);
lua_pushboolean(L, Maps::isTileVisible(pos));
return 1;
}
static int maps_getTileBlock(lua_State *L) static int maps_getTileBlock(lua_State *L)
{ {
auto pos = CheckCoordXYZ(L, 1, true); auto pos = CheckCoordXYZ(L, 1, true);
@ -1805,6 +1874,7 @@ static int maps_getTileBiomeRgn(lua_State *L)
static const luaL_Reg dfhack_maps_funcs[] = { static const luaL_Reg dfhack_maps_funcs[] = {
{ "isValidTilePos", maps_isValidTilePos }, { "isValidTilePos", maps_isValidTilePos },
{ "isTileVisible", maps_isTileVisible },
{ "getTileBlock", maps_getTileBlock }, { "getTileBlock", maps_getTileBlock },
{ "ensureTileBlock", maps_ensureTileBlock }, { "ensureTileBlock", maps_ensureTileBlock },
{ "getTileType", maps_getTileType }, { "getTileType", maps_getTileType },
@ -2066,7 +2136,8 @@ static int screen_paintTile(lua_State *L)
} }
if (lua_gettop(L) >= 5 && !lua_isnil(L, 5)) if (lua_gettop(L) >= 5 && !lua_isnil(L, 5))
pen.tile = luaL_checkint(L, 5); pen.tile = luaL_checkint(L, 5);
lua_pushboolean(L, Screen::paintTile(pen, x, y)); bool map = lua_toboolean(L, 6);
lua_pushboolean(L, Screen::paintTile(pen, x, y, map));
return 1; return 1;
} }
@ -2074,7 +2145,8 @@ static int screen_readTile(lua_State *L)
{ {
int x = luaL_checkint(L, 1); int x = luaL_checkint(L, 1);
int y = luaL_checkint(L, 2); int y = luaL_checkint(L, 2);
Pen pen = Screen::readTile(x, y); bool map = lua_toboolean(L, 3);
Pen pen = Screen::readTile(x, y, map);
Lua::Push(L, pen); Lua::Push(L, pen);
return 1; return 1;
} }
@ -2086,7 +2158,8 @@ static int screen_paintString(lua_State *L)
int x = luaL_checkint(L, 2); int x = luaL_checkint(L, 2);
int y = luaL_checkint(L, 3); int y = luaL_checkint(L, 3);
const char *text = luaL_checkstring(L, 4); const char *text = luaL_checkstring(L, 4);
lua_pushboolean(L, Screen::paintString(pen, x, y, text)); bool map = lua_toboolean(L, 5);
lua_pushboolean(L, Screen::paintString(pen, x, y, text, map));
return 1; return 1;
} }
@ -2098,7 +2171,8 @@ static int screen_fillRect(lua_State *L)
int y1 = luaL_checkint(L, 3); int y1 = luaL_checkint(L, 3);
int x2 = luaL_checkint(L, 4); int x2 = luaL_checkint(L, 4);
int y2 = luaL_checkint(L, 5); int y2 = luaL_checkint(L, 5);
lua_pushboolean(L, Screen::fillRect(pen, x1, y1, x2, y2)); bool map = lua_toboolean(L, 6);
lua_pushboolean(L, Screen::fillRect(pen, x1, y1, x2, y2, map));
return 1; return 1;
} }
@ -2144,7 +2218,8 @@ int screen_show(lua_State *L)
static int screen_dismiss(lua_State *L) static int screen_dismiss(lua_State *L)
{ {
df::viewscreen *screen = dfhack_lua_viewscreen::get_pointer(L, 1, false); df::viewscreen *screen = dfhack_lua_viewscreen::get_pointer(L, 1, false);
Screen::dismiss(screen); bool to_first = lua_toboolean(L, 2);
Screen::dismiss(screen, to_first);
return 0; return 0;
} }
@ -2805,7 +2880,7 @@ void OpenDFHackApi(lua_State *state)
OpenRandom(state); OpenRandom(state);
LuaWrapper::SetFunctionWrappers(state, dfhack_module); LuaWrapper::SetFunctionWrappers(state, dfhack_module);
OpenModule(state, "gui", dfhack_gui_module); OpenModule(state, "gui", dfhack_gui_module, dfhack_gui_funcs);
OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs); OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs);
OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs); OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs);
OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs); OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs);

@ -109,13 +109,14 @@ namespace DFHack
friend void ::DFH_SDL_Quit(void); friend void ::DFH_SDL_Quit(void);
friend int ::DFH_SDL_PollEvent(SDL::Event *); friend int ::DFH_SDL_PollEvent(SDL::Event *);
friend int ::DFH_SDL_Init(uint32_t flags); friend int ::DFH_SDL_Init(uint32_t flags);
friend int ::DFH_wgetch(WINDOW * w);
#else #else
friend int ::SDL_NumJoysticks(void); friend int ::SDL_NumJoysticks(void);
friend void ::SDL_Quit(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 ::SDL_Init(uint32_t flags);
#endif
friend int ::wgetch(WINDOW * w); friend int ::wgetch(WINDOW * w);
#endif
friend int ::egg_init(void); friend int ::egg_init(void);
friend int ::egg_shutdown(void); friend int ::egg_shutdown(void);
friend int ::egg_tick(void); friend int ::egg_tick(void);
@ -169,6 +170,14 @@ namespace DFHack
std::vector<std::string> ListKeyBindings(std::string keyspec); std::vector<std::string> ListKeyBindings(std::string keyspec);
int8_t getModstate() { return modstate; } int8_t getModstate() { return modstate; }
bool AddAlias(const std::string &name, const std::vector<std::string> &command, bool replace = false);
bool RemoveAlias(const std::string &name);
bool IsAlias(const std::string &name);
bool RunAlias(color_ostream &out, const std::string &name,
const std::vector<std::string> &parameters, command_result &result);
std::map<std::string, std::vector<std::string>> ListAliases();
std::string GetAliasCommand(const std::string &name, const std::string &default_ = "");
std::string getHackPath(); std::string getHackPath();
bool isWorldLoaded() { return (last_world_data_ptr != NULL); } bool isWorldLoaded() { return (last_world_data_ptr != NULL); }
@ -255,6 +264,9 @@ namespace DFHack
tthread::mutex * HotkeyMutex; tthread::mutex * HotkeyMutex;
tthread::condition_variable * HotkeyCond; tthread::condition_variable * HotkeyCond;
std::map<std::string, std::vector<std::string>> aliases;
tthread::recursive_mutex * alias_mutex;
bool SelectHotkey(int key, int modifiers); bool SelectHotkey(int key, int modifiers);
// for state change tracking // for state change tracking

@ -52,6 +52,7 @@ DFhackCExport int DFH_SDL_NumJoysticks(void);
DFhackCExport void DFH_SDL_Quit(void); DFhackCExport void DFH_SDL_Quit(void);
DFhackCExport int DFH_SDL_PollEvent(SDL::Event* event); DFhackCExport int DFH_SDL_PollEvent(SDL::Event* event);
DFhackCExport int DFH_SDL_Init(uint32_t flags); DFhackCExport int DFH_SDL_Init(uint32_t flags);
DFhackCExport int DFH_wgetch(WINDOW * win);
#endif #endif
DFhackCExport int SDL_NumJoysticks(void); DFhackCExport int SDL_NumJoysticks(void);
DFhackCExport void SDL_Quit(void); DFhackCExport void SDL_Quit(void);

@ -140,7 +140,7 @@ namespace DFHack
int map_y1, map_y2; int map_y1, map_y2;
bool menu_on, area_on, menu_forced; bool menu_on, area_on, menu_forced;
rect2d map() { return mkrect_xy(map_x1, y1, map_x2, y2); } rect2d map() { return mkrect_xy(map_x1, map_y1, map_x2, map_y2); }
rect2d menu() { return mkrect_xy(menu_x1, y1, menu_x2, y2); } rect2d menu() { return mkrect_xy(menu_x1, y1, menu_x2, y2); }
}; };

@ -263,6 +263,9 @@ extern DFHACK_EXPORT void getPosition(int32_t& x, int32_t& y, int32_t& z);
extern DFHACK_EXPORT bool isValidTilePos(int32_t x, int32_t y, int32_t z); extern DFHACK_EXPORT bool isValidTilePos(int32_t x, int32_t y, int32_t z);
inline bool isValidTilePos(df::coord pos) { return isValidTilePos(pos.x, pos.y, pos.z); } inline bool isValidTilePos(df::coord pos) { return isValidTilePos(pos.x, pos.y, pos.z); }
extern DFHACK_EXPORT bool isTileVisible(int32_t x, int32_t y, int32_t z);
inline bool isTileVisible(df::coord pos) { return isTileVisible(pos.x, pos.y, pos.z); }
/** /**
* Get the map block or NULL if block is not valid * Get the map block or NULL if block is not valid
*/ */

@ -189,7 +189,7 @@ namespace DFHack
DFHACK_EXPORT bool paintTile(const Pen &pen, int x, int y, bool map = false); DFHACK_EXPORT bool paintTile(const Pen &pen, int x, int y, bool map = false);
/// Retrieves one screen tile from the buffer /// Retrieves one screen tile from the buffer
DFHACK_EXPORT Pen readTile(int x, int y); DFHACK_EXPORT Pen readTile(int x, int y, bool map = false);
/// Paint a string onto the screen. Ignores ch and tile of pen. /// 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, bool map = false); DFHACK_EXPORT bool paintString(const Pen &pen, int x, int y, const std::string &text, bool map = false);
@ -297,7 +297,8 @@ namespace DFHack
}; };
namespace Hooks { namespace Hooks {
GUI_HOOK_DECLARE(set_tile, void, (const Pen &pen, int x, int y, bool map)); GUI_HOOK_DECLARE(get_tile, Pen, (int x, int y, bool map));
GUI_HOOK_DECLARE(set_tile, bool, (const Pen &pen, int x, int y, bool map));
} }
} }

@ -23,10 +23,9 @@ distribution.
*/ */
#pragma once #pragma once
#ifndef CL_MOD_CREATURES
#define CL_MOD_CREATURES
/* /*
* Creatures * Units
*/ */
#include "Export.h" #include "Export.h"
#include "modules/Items.h" #include "modules/Items.h"
@ -60,151 +59,24 @@ namespace DFHack
{ {
namespace Units namespace Units
{ {
/**
* \ingroup grp_units
*/
struct t_skill
{
uint32_t id;
uint32_t rating;
uint32_t experience;
};
/**
* \ingroup grp_units
*/
struct t_job
{
bool active;
uint32_t jobId;
uint8_t jobType;
uint32_t occupationPtr;
};
/**
* \ingroup grp_units
*/
struct t_like
{
int16_t type;
int16_t itemClass;
int16_t itemIndex;
t_matglossPair material;
bool active;
uint32_t mystery;
};
// FIXME: THIS IS VERY, VERY BAD. static const int MAX_COLORS = 15;
#define NUM_CREATURE_LABORS 96
#define NUM_CREATURE_TRAITS 30
#define NUM_CREATURE_MENTAL_ATTRIBUTES 13
#define NUM_CREATURE_PHYSICAL_ATTRIBUTES 6
/**
* Structure for holding a copy of a DF unit's soul
* \ingroup grp_units
*/
struct t_soul
{
uint8_t numSkills;
t_skill skills[256];
//uint8_t numLikes;
//t_like likes[32];
uint16_t traits[NUM_CREATURE_TRAITS];
t_attrib analytical_ability;
t_attrib focus;
t_attrib willpower;
t_attrib creativity;
t_attrib intuition;
t_attrib patience;
t_attrib memory;
t_attrib linguistic_ability;
t_attrib spatial_sense;
t_attrib musicality;
t_attrib kinesthetic_sense;
t_attrib empathy;
t_attrib social_awareness;
};
#define MAX_COLORS 15
struct df_unit;
/**
* Structure for holding a limited copy of a DF unit
* \ingroup grp_units
*/
struct t_unit
{
df::unit * origin;
uint16_t x;
uint16_t y;
uint16_t z;
uint32_t race;
int32_t civ;
df::unit_flags1 flags1;
df::unit_flags2 flags2;
df::unit_flags3 flags3;
t_name name;
int16_t mood;
int16_t mood_skill;
t_name artifact_name;
uint8_t profession;
std::string custom_profession;
// enabled labors
uint8_t labors[NUM_CREATURE_LABORS];
t_job current_job;
uint32_t happiness;
uint32_t id;
t_attrib strength;
t_attrib agility;
t_attrib toughness;
t_attrib endurance;
t_attrib recuperation;
t_attrib disease_resistance;
int32_t squad_leader_id;
uint8_t sex;
uint16_t caste;
uint32_t pregnancy_timer; //Countdown timer to giving birth
//bool has_default_soul;
//t_soul defaultSoul;
uint32_t nbcolors;
uint32_t color[MAX_COLORS];
int32_t birth_year;
uint32_t birth_time;
};
/** /**
* The Creatures module - allows reading all non-vermin creatures and their properties * The Units module - allows reading all non-vermin units and their properties
* \ingroup grp_modules
* \ingroup grp_units
*/ */
DFHACK_EXPORT bool isValid();
/* Read Functions */ /* Read Functions */
// Read creatures in a box, starting with index. Returns -1 if no more creatures // Read units in a box, starting with index. Returns -1 if no more units
// found. Call repeatedly do get all creatures in a specified box (uses tile coords) // found. Call repeatedly do get all units in a specified box (uses tile coords)
DFHACK_EXPORT int32_t getNumCreatures(); DFHACK_EXPORT int32_t getNumUnits();
DFHACK_EXPORT int32_t GetCreatureInBox(const int32_t index, df::unit ** furball, DFHACK_EXPORT df::unit *getUnit(const int32_t index);
const uint16_t x1, const uint16_t y1,const uint16_t z1, DFHACK_EXPORT bool getUnitsInBox(std::vector<df::unit*> &units,
const uint16_t x2, const uint16_t y2,const uint16_t z2); int16_t x1, int16_t y1, int16_t z1,
DFHACK_EXPORT df::unit * GetCreature(const int32_t index); int16_t x2, int16_t y2, int16_t z2);
DFHACK_EXPORT void CopyCreature(df::unit * source, t_unit & target);
DFHACK_EXPORT bool ReadJob(const df::unit * unit, std::vector<t_material> & mat);
DFHACK_EXPORT bool ReadInventoryByIdx(const uint32_t index, std::vector<df::item *> & item);
DFHACK_EXPORT bool ReadInventoryByPtr(const df::unit * unit, std::vector<df::item *> & item);
DFHACK_EXPORT int32_t FindIndexById(int32_t id);
/* Getters */
DFHACK_EXPORT uint32_t GetDwarfRaceIndex ( void );
DFHACK_EXPORT int32_t GetDwarfCivId ( void );
DFHACK_EXPORT void CopyNameTo(df::unit *creature, df::language_name * target); DFHACK_EXPORT int32_t findIndexById(int32_t id);
/// Returns the true position of the unit (non-trivial in case of caged). /// Returns the true position of the unit (non-trivial in case of caged).
DFHACK_EXPORT df::coord getPosition(df::unit *unit); DFHACK_EXPORT df::coord getPosition(df::unit *unit);
@ -244,6 +116,7 @@ DFHACK_EXPORT bool isAvailableForAdoption(df::unit* unit);
DFHACK_EXPORT bool isOwnCiv(df::unit* unit); DFHACK_EXPORT bool isOwnCiv(df::unit* unit);
DFHACK_EXPORT bool isOwnGroup(df::unit* unit); DFHACK_EXPORT bool isOwnGroup(df::unit* unit);
DFHACK_EXPORT bool isOwnRace(df::unit* unit); DFHACK_EXPORT bool isOwnRace(df::unit* unit);
DFHACK_EXPORT bool isVisible(df::unit* unit);
DFHACK_EXPORT std::string getRaceNameById(int32_t race_id); DFHACK_EXPORT std::string getRaceNameById(int32_t race_id);
DFHACK_EXPORT std::string getRaceName(df::unit* unit); DFHACK_EXPORT std::string getRaceName(df::unit* unit);
@ -309,4 +182,3 @@ DFHACK_EXPORT df::activity_event *getMainSocialEvent(df::unit *unit);
} }
} }
#endif

@ -221,6 +221,7 @@ function Painter:init(args)
self.y = self.y1 self.y = self.y1
self.cur_pen = to_pen(args.pen or COLOR_GREY) self.cur_pen = to_pen(args.pen or COLOR_GREY)
self.cur_key_pen = to_pen(args.key_pen or COLOR_LIGHTGREEN) self.cur_key_pen = to_pen(args.key_pen or COLOR_LIGHTGREEN)
self.to_map = false
end end
function Painter.new(rect, pen) function Painter.new(rect, pen)
@ -295,6 +296,11 @@ function Painter:key_pen(pen,...)
return self return self
end end
function Painter:map(to_map)
self.to_map = to_map
return self
end
function Painter:clear() function Painter:clear()
dscreen.fillRect(CLEAR_PEN, self.clip_x1, self.clip_y1, self.clip_x2, self.clip_y2) dscreen.fillRect(CLEAR_PEN, self.clip_x1, self.clip_y1, self.clip_x2, self.clip_y2)
return self return self
@ -308,20 +314,20 @@ function Painter:fill(x1,y1,x2,y2,pen,bg,bold)
y1 = math.max(y1+self.y1,self.clip_y1) y1 = math.max(y1+self.y1,self.clip_y1)
x2 = math.min(x2+self.x1,self.clip_x2) x2 = math.min(x2+self.x1,self.clip_x2)
y2 = math.min(y2+self.y1,self.clip_y2) y2 = math.min(y2+self.y1,self.clip_y2)
dscreen.fillRect(to_pen(self.cur_pen,pen,bg,bold),x1,y1,x2,y2) dscreen.fillRect(to_pen(self.cur_pen,pen,bg,bold),x1,y1,x2,y2,self.to_map)
return self return self
end end
function Painter:char(char,pen,...) function Painter:char(char,pen,...)
if self:isValidPos() then if self:isValidPos() then
dscreen.paintTile(to_pen(self.cur_pen, pen, ...), self.x, self.y, char) dscreen.paintTile(to_pen(self.cur_pen, pen, ...), self.x, self.y, char, nil, self.to_map)
end end
return self:advance(1, nil) return self:advance(1, nil)
end end
function Painter:tile(char,tile,pen,...) function Painter:tile(char,tile,pen,...)
if self:isValidPos() then if self:isValidPos() then
dscreen.paintTile(to_pen(self.cur_pen, pen, ...), self.x, self.y, char, tile) dscreen.paintTile(to_pen(self.cur_pen, pen, ...), self.x, self.y, char, tile, self.to_map)
end end
return self:advance(1, nil) return self:advance(1, nil)
end end
@ -340,7 +346,8 @@ function Painter:string(text,pen,...)
dscreen.paintString( dscreen.paintString(
to_pen(self.cur_pen, pen, ...), to_pen(self.cur_pen, pen, ...),
self.x+dx, self.y, self.x+dx, self.y,
string.sub(text,dx+1,len) string.sub(text,dx+1,len),
self.to_map
) )
end end
end end

@ -15,33 +15,30 @@ AREA_MAP_WIDTH = 23
MENU_WIDTH = 30 MENU_WIDTH = 30
function getPanelLayout() function getPanelLayout()
local sw, sh = dscreen.getWindowSize() local dims = dfhack.gui.getDwarfmodeViewDims()
local view_height = sh-2
local view_rb = sw-1
local area_x2 = sw-AREA_MAP_WIDTH-2
local menu_x2 = sw-MENU_WIDTH-2
local menu_x1 = area_x2-MENU_WIDTH-1
local area_pos = df.global.ui_area_map_width local area_pos = df.global.ui_area_map_width
local menu_pos = df.global.ui_menu_width local menu_pos = df.global.ui_menu_width
local rv = {}
if area_pos < 3 then if dims.menu_forced then
rv.area_map = gui.mkdims_xy(area_x2+1,1,view_rb-1,view_height) menu_pos = area_pos - 1
view_rb = area_x2
end end
if menu_pos < area_pos or df.global.ui.main.mode ~= 0 then
if menu_pos >= area_pos then local rv = {
menu_pos = menu_pos,
area_pos = area_pos,
map = gui.mkdims_xy(dims.map_x1, dims.map_y1, dims.map_x2, dims.map_y2),
}
if dims.menu_forced then
rv.menu_forced = true rv.menu_forced = true
menu_pos = area_pos-1
end end
local menu_x = menu_x2 if dims.menu_on then
if menu_pos < 2 then menu_x = menu_x1 end rv.menu = gui.mkdims_xy(dims.menu_x1, dims.y1, dims.menu_x2, dims.y2)
rv.menu = gui.mkdims_xy(menu_x+1,1,view_rb-1,view_height)
view_rb = menu_x
end end
rv.area_pos = area_pos if dims.area_on then
rv.menu_pos = menu_pos rv.area_map = gui.mkdims_xy(dims.area_x1, dims.y1, dims.area_x2, dims.y2)
rv.map = gui.mkdims_xy(1,1,view_rb-1,view_height) end
return rv return rv
end end

@ -248,16 +248,17 @@ function render_text(obj,dc,x0,y0,pen,dpen,disabled)
if token.text or token.key then if token.text or token.key then
local text = ''..(getval(token.text) or '') local text = ''..(getval(token.text) or '')
local keypen local keypen = dfhack.pen.parse(token.key_pen or COLOR_LIGHTGREEN)
if dc then if dc then
local tpen = getval(token.pen) local tpen = getval(token.pen)
if disabled or is_disabled(token) then if disabled or is_disabled(token) then
dc:pen(getval(token.dpen) or tpen or dpen) dc:pen(getval(token.dpen) or tpen or dpen)
keypen = COLOR_GREEN if keypen.fg ~= COLOR_BLACK then
keypen.bold = false
end
else else
dc:pen(tpen or pen) dc:pen(tpen or pen)
keypen = COLOR_LIGHTGREEN
end end
end end

@ -46,55 +46,59 @@ using namespace DFHack;
#include "modules/Maps.h" #include "modules/Maps.h"
#include "DataDefs.h" #include "DataDefs.h"
#include "df/world.h"
#include "df/announcement_flags.h"
#include "df/announcements.h"
#include "df/assign_trade_status.h"
#include "df/building_civzonest.h"
#include "df/building_furnacest.h"
#include "df/building_trapst.h"
#include "df/building_workshopst.h"
#include "df/game_mode.h"
#include "df/general_ref.h"
#include "df/global_objects.h" #include "df/global_objects.h"
#include "df/viewscreen_dwarfmodest.h" #include "df/graphic.h"
#include "df/viewscreen_dungeonmodest.h" #include "df/interfacest.h"
#include "df/job.h"
#include "df/layer_object_listst.h"
#include "df/occupation.h"
#include "df/plant.h"
#include "df/popup_message.h"
#include "df/report.h"
#include "df/route_stockpile_link.h"
#include "df/stop_depart_condition.h"
#include "df/ui_advmode.h"
#include "df/ui_build_selector.h"
#include "df/ui_look_list.h"
#include "df/ui_sidebar_menus.h"
#include "df/ui_unit_view_mode.h"
#include "df/unit.h"
#include "df/unit_inventory_item.h"
#include "df/viewscreen_buildinglistst.h"
#include "df/viewscreen_dungeon_monsterstatusst.h" #include "df/viewscreen_dungeon_monsterstatusst.h"
#include "df/viewscreen_jobst.h" #include "df/viewscreen_dungeonmodest.h"
#include "df/viewscreen_dwarfmodest.h"
#include "df/viewscreen_itemst.h"
#include "df/viewscreen_joblistst.h" #include "df/viewscreen_joblistst.h"
#include "df/viewscreen_jobmanagementst.h" #include "df/viewscreen_jobmanagementst.h"
#include "df/viewscreen_unitlistst.h" #include "df/viewscreen_jobst.h"
#include "df/viewscreen_buildinglistst.h"
#include "df/viewscreen_itemst.h"
#include "df/viewscreen_layer.h" #include "df/viewscreen_layer.h"
#include "df/viewscreen_layer_noblelistst.h"
#include "df/viewscreen_layer_overall_healthst.h"
#include "df/viewscreen_layer_assigntradest.h" #include "df/viewscreen_layer_assigntradest.h"
#include "df/viewscreen_layer_militaryst.h" #include "df/viewscreen_layer_militaryst.h"
#include "df/viewscreen_layer_noblelistst.h"
#include "df/viewscreen_layer_overall_healthst.h"
#include "df/viewscreen_layer_stockpilest.h" #include "df/viewscreen_layer_stockpilest.h"
#include "df/viewscreen_layer_unit_relationshipst.h"
#include "df/viewscreen_locationsst.h" #include "df/viewscreen_locationsst.h"
#include "df/viewscreen_petst.h" #include "df/viewscreen_petst.h"
#include "df/viewscreen_tradegoodsst.h"
#include "df/viewscreen_storesst.h" #include "df/viewscreen_storesst.h"
#include "df/viewscreen_textviewerst.h"
#include "df/viewscreen_tradegoodsst.h"
#include "df/viewscreen_unitlistst.h"
#include "df/viewscreen_unitst.h"
#include "df/viewscreen_workquota_conditionst.h" #include "df/viewscreen_workquota_conditionst.h"
#include "df/viewscreen_workshop_profilest.h" #include "df/viewscreen_workshop_profilest.h"
#include "df/ui_unit_view_mode.h" #include "df/world.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"
#include "df/building_furnacest.h"
#include "df/building_trapst.h"
#include "df/building_civzonest.h"
#include "df/general_ref.h"
#include "df/unit_inventory_item.h"
#include "df/report.h"
#include "df/popup_message.h"
#include "df/interfacest.h"
#include "df/graphic.h"
#include "df/layer_object_listst.h"
#include "df/assign_trade_status.h"
#include "df/announcement_flags.h"
#include "df/announcements.h"
#include "df/stop_depart_condition.h"
#include "df/route_stockpile_link.h"
#include "df/game_mode.h"
#include "df/unit.h"
#include "df/occupation.h"
#include "df/plant.h"
using namespace df::enums; using namespace df::enums;
using df::global::gview; using df::global::gview;
@ -815,6 +819,11 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top)
using df::global::ui_look_list; using df::global::ui_look_list;
using df::global::ui_selected_unit; using df::global::ui_selected_unit;
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitst, top))
{
return screen->unit;
}
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_joblistst, top)) if (VIRTUAL_CAST_VAR(screen, df::viewscreen_joblistst, top))
{ {
if (auto unit = vector_get(screen->units, screen->cursor_pos)) if (auto unit = vector_get(screen->units, screen->cursor_pos))
@ -830,6 +839,14 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top)
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_dungeon_monsterstatusst, top)) if (VIRTUAL_CAST_VAR(screen, df::viewscreen_dungeon_monsterstatusst, top))
return screen->unit; return screen->unit;
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_unit_relationshipst, top))
{
if (VIRTUAL_CAST_VAR(list, df::layer_object_listst, vector_get(screen->layer_objects, 0)))
return vector_get(screen->relation_unit, list->cursor);
return NULL;
}
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_itemst, top)) if (VIRTUAL_CAST_VAR(screen, df::viewscreen_itemst, top))
{ {
df::general_ref *ref = vector_get(screen->entry_ref, screen->cursor_pos); df::general_ref *ref = vector_get(screen->entry_ref, screen->cursor_pos);
@ -910,6 +927,13 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top)
return NULL; return NULL;
} }
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_textviewerst, top))
{
if (screen->parent)
return getAnyUnit(screen->parent);
return NULL;
}
if (auto dfscreen = dfhack_viewscreen::try_cast(top)) if (auto dfscreen = dfhack_viewscreen::try_cast(top))
return dfscreen->getSelectedUnit(); return dfscreen->getSelectedUnit();
@ -1463,8 +1487,12 @@ Gui::DwarfmodeDims getDwarfmodeViewDims_default()
auto ws = Screen::getWindowSize(); auto ws = Screen::getWindowSize();
dims.y1 = 1; dims.y1 = 1;
dims.y2 = ws.y-2; dims.y2 = ws.y-2;
dims.map_x1 = 1; dims.map_x1 = 1;
dims.map_x2 = ws.x-2; dims.map_x2 = ws.x-2;
dims.map_y1 = dims.y1;
dims.map_y2 = dims.y2;
dims.area_x1 = dims.area_x2 = dims.menu_x1 = dims.menu_x2 = -1; dims.area_x1 = dims.area_x2 = dims.menu_x1 = dims.menu_x2 = -1;
dims.menu_forced = false; dims.menu_forced = false;
@ -1544,7 +1572,7 @@ bool Gui::revealInDwarfmodeMap(df::coord pos, bool center)
auto dims = getDwarfmodeViewDims(); auto dims = getDwarfmodeViewDims();
int w = dims.map_x2 - dims.map_x1 + 1; int w = dims.map_x2 - dims.map_x1 + 1;
int h = dims.y2 - dims.y1 + 1; int h = dims.map_y2 - dims.map_y1 + 1;
*window_z = pos.z; *window_z = pos.z;

@ -166,6 +166,17 @@ bool Maps::isValidTilePos(int32_t x, int32_t y, int32_t z)
return true; return true;
} }
bool Maps::isTileVisible(int32_t x, int32_t y, int32_t z)
{
df::map_block *block = getTileBlock(x, y, z);
if (!block)
return false;
if (block->designation[x % 16][y % 16].bits.hidden)
return false;
return true;
}
df::map_block *Maps::getTileBlock (int32_t x, int32_t y, int32_t z) df::map_block *Maps::getTileBlock (int32_t x, int32_t y, int32_t z)
{ {
if (!isValidTilePos(x,y,z)) if (!isValidTilePos(x,y,z))

@ -95,8 +95,12 @@ bool Screen::inGraphicsMode()
return init && init->display.flag.is_set(init_display_flags::USE_GRAPHICS); return init && init->display.flag.is_set(init_display_flags::USE_GRAPHICS);
} }
static void doSetTile_default(const Pen &pen, int x, int y, bool map) static bool doSetTile_default(const Pen &pen, int x, int y, bool map)
{ {
auto dim = Screen::getWindowSize();
if (x < 0 || x >= dim.x || y < 0 || y >= dim.y)
return false;
int index = ((x * gps->dimy) + y); int index = ((x * gps->dimy) + y);
auto screen = gps->screen + index*4; auto screen = gps->screen + index*4;
screen[0] = uint8_t(pen.ch); screen[0] = uint8_t(pen.ch);
@ -108,30 +112,27 @@ static void doSetTile_default(const Pen &pen, int x, int y, bool map)
gps->screentexpos_grayscale[index] = (pen.tile_mode == Screen::Pen::TileColor); gps->screentexpos_grayscale[index] = (pen.tile_mode == Screen::Pen::TileColor);
gps->screentexpos_cf[index] = pen.tile_fg; gps->screentexpos_cf[index] = pen.tile_fg;
gps->screentexpos_cbr[index] = pen.tile_bg; gps->screentexpos_cbr[index] = pen.tile_bg;
return true;
} }
GUI_HOOK_DEFINE(Screen::Hooks::set_tile, doSetTile_default); GUI_HOOK_DEFINE(Screen::Hooks::set_tile, doSetTile_default);
static void doSetTile(const Pen &pen, int x, int y, bool map) static bool doSetTile(const Pen &pen, int x, int y, bool map)
{ {
GUI_HOOK_TOP(Screen::Hooks::set_tile)(pen, x, y, map); return GUI_HOOK_TOP(Screen::Hooks::set_tile)(pen, x, y, map);
} }
bool Screen::paintTile(const Pen &pen, int x, int y, bool map) bool Screen::paintTile(const Pen &pen, int x, int y, bool map)
{ {
if (!gps || !pen.valid()) return false; if (!gps || !pen.valid()) return false;
auto dim = getWindowSize();
if (x < 0 || x >= dim.x || y < 0 || y >= dim.y) return false;
doSetTile(pen, x, y, map); doSetTile(pen, x, y, map);
return true; return true;
} }
Pen Screen::readTile(int x, int y) static Pen doGetTile_default(int x, int y, bool map)
{ {
if (!gps) return Pen(0,0,0,-1); auto dim = Screen::getWindowSize();
auto dim = getWindowSize();
if (x < 0 || x >= dim.x || y < 0 || y >= dim.y) if (x < 0 || x >= dim.x || y < 0 || y >= dim.y)
return Pen(0,0,0,-1); return Pen(0,0,0,-1);
@ -162,6 +163,19 @@ Pen Screen::readTile(int x, int y)
return pen; return pen;
} }
GUI_HOOK_DEFINE(Screen::Hooks::get_tile, doGetTile_default);
static Pen doGetTile(int x, int y, bool map)
{
return GUI_HOOK_TOP(Screen::Hooks::get_tile)(x, y, map);
}
Pen Screen::readTile(int x, int y, bool map)
{
if (!gps) return Pen(0,0,0,-1);
return doGetTile(x, y, map);
}
bool Screen::paintString(const Pen &pen, int x, int y, const std::string &text, bool map) bool Screen::paintString(const Pen &pen, int x, int y, const std::string &text, bool map)
{ {
auto dim = getWindowSize(); auto dim = getWindowSize();

@ -42,6 +42,7 @@ using namespace std;
// we connect to those // we connect to those
#include "modules/Units.h" #include "modules/Units.h"
#include "modules/Items.h" #include "modules/Items.h"
#include "modules/Maps.h"
#include "modules/Materials.h" #include "modules/Materials.h"
#include "modules/Translation.h" #include "modules/Translation.h"
#include "ModuleFactory.h" #include "ModuleFactory.h"
@ -83,436 +84,48 @@ using df::global::world;
using df::global::ui; using df::global::ui;
using df::global::gamemode; using df::global::gamemode;
bool Units::isValid() int32_t Units::getNumUnits()
{
return (world->units.all.size() > 0);
}
int32_t Units::getNumCreatures()
{ {
return world->units.all.size(); return world->units.all.size();
} }
df::unit * Units::GetCreature (const int32_t index) df::unit *Units::getUnit (const int32_t index)
{ {
if (!isValid()) return NULL; return vector_get(world->units.all, index);
// read pointer from vector at position
if(size_t(index) > world->units.all.size())
return 0;
return world->units.all[index];
} }
// returns index of creature actually read or -1 if no creature can be found // returns index of creature actually read or -1 if no creature can be found
int32_t Units::GetCreatureInBox (int32_t index, df::unit ** furball, bool Units::getUnitsInBox (std::vector<df::unit*> &units,
const uint16_t x1, const uint16_t y1, const uint16_t z1, int16_t x1, int16_t y1, int16_t z1,
const uint16_t x2, const uint16_t y2, const uint16_t z2) int16_t x2, int16_t y2, int16_t z2)
{ {
if (!isValid()) if (!world)
return -1; return false;
size_t size = world->units.all.size(); if (x1 > x2) swap(x1, x2);
while (size_t(index) < size) if (y1 > y2) swap(y1, y2);
{ if (z1 > z2) swap(z1, z2);
// read pointer from vector at position
df::unit * temp = world->units.all[index];
if (temp->pos.x >= x1 && temp->pos.x < x2)
{
if (temp->pos.y >= y1 && temp->pos.y < y2)
{
if (temp->pos.z >= z1 && temp->pos.z < z2)
{
*furball = temp;
return index;
}
}
}
index++;
}
*furball = NULL;
return -1;
}
void Units::CopyCreature(df::unit * source, t_unit & furball) units.clear();
{ for (df::unit *u : world->units.all)
if(!isValid()) return;
// read pointer from vector at position
furball.origin = source;
//read creature from memory
// name
Translation::readName(furball.name, &source->name);
// basic stuff
furball.id = source->id;
furball.x = source->pos.x;
furball.y = source->pos.y;
furball.z = source->pos.z;
furball.race = source->race;
furball.civ = source->civ_id;
furball.sex = source->sex;
furball.caste = source->caste;
furball.flags1.whole = source->flags1.whole;
furball.flags2.whole = source->flags2.whole;
furball.flags3.whole = source->flags3.whole;
// custom profession
furball.custom_profession = source->custom_profession;
// profession
furball.profession = source->profession;
// happiness
furball.happiness = 100;//source->status.happiness;
// physical attributes
memcpy(&furball.strength, source->body.physical_attrs, sizeof(source->body.physical_attrs));
// mood stuff
furball.mood = source->mood;
furball.mood_skill = source->job.mood_skill; // FIXME: really? More like currently used skill anyway.
Translation::readName(furball.artifact_name, &source->status.artifact_name);
// labors
memcpy(&furball.labors, &source->status.labors, sizeof(furball.labors));
furball.birth_year = source->birth_year;
furball.birth_time = source->birth_time;
furball.pregnancy_timer = source->pregnancy_timer;
// appearance
furball.nbcolors = source->appearance.colors.size();
if(furball.nbcolors>MAX_COLORS)
furball.nbcolors = MAX_COLORS;
for(uint32_t i = 0; i < furball.nbcolors; i++)
{
furball.color[i] = source->appearance.colors[i];
}
//likes. FIXME: where do they fit in now? The soul?
/*
DfVector <uint32_t> likes(d->p, temp + offs.creature_likes_offset);
furball.numLikes = likes.getSize();
for(uint32_t i = 0;i<furball.numLikes;i++)
{ {
uint32_t temp2 = *(uint32_t *) likes[i]; if (u->pos.x >= x1 && u->pos.x <= x2)
p->read(temp2,sizeof(t_like),(uint8_t *) &furball.likes[i]);
}
*/
/*
if(d->Ft_soul)
{ {
uint32_t soul = p->readDWord(addr_cr + offs.default_soul_offset); if (u->pos.y >= y1 && u->pos.y <= y2)
furball.has_default_soul = false;
if(soul)
{ {
furball.has_default_soul = true; if (u->pos.z >= z1 && u->pos.z <= z2)
// get first soul's skills
DfVector <uint32_t> skills(soul + offs.soul_skills_vector_offset);
furball.defaultSoul.numSkills = skills.size();
for (uint32_t i = 0; i < furball.defaultSoul.numSkills;i++)
{ {
uint32_t temp2 = skills[i]; units.push_back(u);
// a byte: this gives us 256 skills maximum.
furball.defaultSoul.skills[i].id = p->readByte (temp2);
furball.defaultSoul.skills[i].rating =
p->readByte (temp2 + offsetof(t_skill, rating));
furball.defaultSoul.skills[i].experience =
p->readWord (temp2 + offsetof(t_skill, experience));
}
// mental attributes are part of the soul
p->read(soul + offs.soul_mental_offset,
sizeof(t_attrib) * NUM_CREATURE_MENTAL_ATTRIBUTES,
(uint8_t *)&furball.defaultSoul.analytical_ability);
// traits as well
p->read(soul + offs.soul_traits_offset,
sizeof (uint16_t) * NUM_CREATURE_TRAITS,
(uint8_t *) &furball.defaultSoul.traits);
} }
} }
*/
if(source->job.current_job == NULL)
{
furball.current_job.active = false;
} }
else
{
furball.current_job.active = true;
furball.current_job.jobType = source->job.current_job->job_type;
furball.current_job.jobId = source->job.current_job->id;
} }
}
int32_t Units::FindIndexById(int32_t creature_id)
{
return df::unit::binsearch_index(world->units.all, creature_id);
}
/*
bool Creatures::WriteLabors(const uint32_t index, uint8_t labors[NUM_CREATURE_LABORS])
{
if(!d->Started || !d->Ft_advanced) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->write(temp + d->creatures.labors_offset, NUM_CREATURE_LABORS, labors);
uint32_t pickup_equip;
p->readDWord(temp + d->creatures.pickup_equipment_bit, pickup_equip);
pickup_equip |= 1u;
p->writeDWord(temp + d->creatures.pickup_equipment_bit, pickup_equip);
return true; return true;
} }
bool Creatures::WriteHappiness(const uint32_t index, const uint32_t happinessValue) int32_t Units::findIndexById(int32_t creature_id)
{ {
if(!d->Started || !d->Ft_advanced) return false; return df::unit::binsearch_index(world->units.all, creature_id);
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->writeDWord (temp + d->creatures.happiness_offset, happinessValue);
return true;
}
bool Creatures::WriteFlags(const uint32_t index,
const uint32_t flags1,
const uint32_t flags2)
{
if(!d->Started || !d->Ft_basic) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->writeDWord (temp + d->creatures.flags1_offset, flags1);
p->writeDWord (temp + d->creatures.flags2_offset, flags2);
return true;
}
bool Creatures::WriteFlags(const uint32_t index,
const uint32_t flags1,
const uint32_t flags2,
const uint32_t flags3)
{
if(!d->Started || !d->Ft_basic) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->writeDWord (temp + d->creatures.flags1_offset, flags1);
p->writeDWord (temp + d->creatures.flags2_offset, flags2);
p->writeDWord (temp + d->creatures.flags3_offset, flags3);
return true;
}
bool Creatures::WriteSkills(const uint32_t index, const t_soul &soul)
{
if(!d->Started || !d->Ft_soul) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
uint32_t souloff = p->readDWord(temp + d->creatures.default_soul_offset);
if(!souloff)
{
return false;
}
DfVector<uint32_t> skills(souloff + d->creatures.soul_skills_vector_offset);
for (uint32_t i=0; i<soul.numSkills; i++)
{
uint32_t temp2 = skills[i];
p->writeByte(temp2 + offsetof(t_skill, rating), soul.skills[i].rating);
p->writeWord(temp2 + offsetof(t_skill, experience), soul.skills[i].experience);
}
return true;
}
bool Creatures::WriteAttributes(const uint32_t index, const t_creature &creature)
{
if(!d->Started || !d->Ft_advanced || !d->Ft_soul) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
uint32_t souloff = p->readDWord(temp + d->creatures.default_soul_offset);
if(!souloff)
{
return false;
}
// physical attributes
p->write(temp + d->creatures.physical_offset,
sizeof(t_attrib) * NUM_CREATURE_PHYSICAL_ATTRIBUTES,
(uint8_t *)&creature.strength);
// mental attributes are part of the soul
p->write(souloff + d->creatures.soul_mental_offset,
sizeof(t_attrib) * NUM_CREATURE_MENTAL_ATTRIBUTES,
(uint8_t *)&creature.defaultSoul.analytical_ability);
return true;
}
bool Creatures::WriteSex(const uint32_t index, const uint8_t sex)
{
if(!d->Started || !d->Ft_basic ) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->writeByte (temp + d->creatures.sex_offset, sex);
return true;
}
bool Creatures::WriteTraits(const uint32_t index, const t_soul &soul)
{
if(!d->Started || !d->Ft_soul) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
uint32_t souloff = p->readDWord(temp + d->creatures.default_soul_offset);
if(!souloff)
{
return false;
}
p->write(souloff + d->creatures.soul_traits_offset,
sizeof (uint16_t) * NUM_CREATURE_TRAITS,
(uint8_t *) &soul.traits);
return true;
}
bool Creatures::WriteMood(const uint32_t index, const uint16_t mood)
{
if(!d->Started || !d->Ft_advanced) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->writeWord(temp + d->creatures.mood_offset, mood);
return true;
}
bool Creatures::WriteMoodSkill(const uint32_t index, const uint16_t moodSkill)
{
if(!d->Started || !d->Ft_advanced) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->writeWord(temp + d->creatures.mood_skill_offset, moodSkill);
return true;
}
bool Creatures::WriteJob(const t_creature * furball, std::vector<t_material> const& mat)
{
if(!d->Inited || !d->Ft_job_materials) return false;
if(!furball->current_job.active) return false;
unsigned int i;
Process * p = d->owner;
Private::t_offsets & off = d->creatures;
DfVector <uint32_t> cmats(furball->current_job.occupationPtr + off.job_materials_vector);
for(i=0;i<cmats.size();i++)
{
p->writeWord(cmats[i] + off.job_material_itemtype_o, mat[i].itemType);
p->writeWord(cmats[i] + off.job_material_subtype_o, mat[i].itemSubtype);
p->writeWord(cmats[i] + off.job_material_subindex_o, mat[i].subIndex);
p->writeDWord(cmats[i] + off.job_material_index_o, mat[i].index);
p->writeDWord(cmats[i] + off.job_material_flags_o, mat[i].flags);
}
return true;
}
bool Creatures::WritePos(const uint32_t index, const t_creature &creature)
{
if(!d->Started) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->write (temp + d->creatures.pos_offset, 3 * sizeof (uint16_t), (uint8_t *) & (creature.x));
return true;
}
bool Creatures::WriteCiv(const uint32_t index, const int32_t civ)
{
if(!d->Started) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->writeDWord(temp + d->creatures.civ_offset, civ);
return true;
}
bool Creatures::WritePregnancy(const uint32_t index, const uint32_t pregTimer)
{
if(!d->Started) return false;
uint32_t temp = d->p_cre->at (index);
Process * p = d->owner;
p->writeDWord(temp + d->creatures.pregnancy_offset, pregTimer);
return true;
}
*/
uint32_t Units::GetDwarfRaceIndex()
{
return ui->race_id;
}
int32_t Units::GetDwarfCivId()
{
return ui->civ_id;
}
/*
bool Creatures::getCurrentCursorCreature(uint32_t & creature_index)
{
if(!d->cursorWindowInited) return false;
Process * p = d->owner;
creature_index = p->readDWord(d->current_cursor_creature_offset);
return true;
}
*/
/*
bool Creatures::ReadJob(const t_creature * furball, vector<t_material> & mat)
{
unsigned int i;
if(!d->Inited || !d->Ft_job_materials) return false;
if(!furball->current_job.active) return false;
Process * p = d->owner;
Private::t_offsets & off = d->creatures;
DfVector <uint32_t> cmats(furball->current_job.occupationPtr + off.job_materials_vector);
mat.resize(cmats.size());
for(i=0;i<cmats.size();i++)
{
mat[i].itemType = p->readWord(cmats[i] + off.job_material_itemtype_o);
mat[i].itemSubtype = p->readWord(cmats[i] + off.job_material_subtype_o);
mat[i].subIndex = p->readWord(cmats[i] + off.job_material_subindex_o);
mat[i].index = p->readDWord(cmats[i] + off.job_material_index_o);
mat[i].flags = p->readDWord(cmats[i] + off.job_material_flags_o);
}
return true;
}
*/
bool Units::ReadInventoryByIdx(const uint32_t index, std::vector<df::item *> & item)
{
if(index >= world->units.all.size()) return false;
df::unit * temp = world->units.all[index];
return ReadInventoryByPtr(temp, item);
}
bool Units::ReadInventoryByPtr(const df::unit * unit, std::vector<df::item *> & items)
{
if(!isValid()) return false;
if(!unit) return false;
items.clear();
for (size_t i = 0; i < unit->inventory.size(); i++)
items.push_back(unit->inventory[i]->item);
return true;
}
void Units::CopyNameTo(df::unit * creature, df::language_name * target)
{
Translation::copyName(&creature->name, target);
} }
df::coord Units::getPosition(df::unit *unit) df::coord Units::getPosition(df::unit *unit)
@ -914,6 +527,12 @@ bool Units::isOwnRace(df::unit* unit)
return unit->race == ui->race_id; return unit->race == ui->race_id;
} }
bool Units::isVisible(df::unit* unit)
{
CHECK_NULL_POINTER(unit);
return Maps::isTileVisible(unit->pos);
}
// get race name by id or unit pointer // get race name by id or unit pointer
string Units::getRaceNameById(int32_t id) string Units::getRaceNameById(int32_t id)
{ {

@ -14,6 +14,7 @@
// DF data structure definition headers // DF data structure definition headers
#include "DataDefs.h" #include "DataDefs.h"
#include "MiscUtils.h" #include "MiscUtils.h"
#include "TileTypes.h"
#include "df/build_req_choice_genst.h" #include "df/build_req_choice_genst.h"
#include "df/build_req_choice_specst.h" #include "df/build_req_choice_specst.h"
#include "df/construction_type.h" #include "df/construction_type.h"
@ -25,6 +26,7 @@
#include "df/job.h" #include "df/job.h"
#include "df/world.h" #include "df/world.h"
#include "df/building_constructionst.h" #include "df/building_constructionst.h"
#include "df/job_item.h"
#include "modules/Gui.h" #include "modules/Gui.h"
#include "modules/Screen.h" #include "modules/Screen.h"
@ -34,8 +36,7 @@
#include "modules/Maps.h" #include "modules/Maps.h"
#include "modules/MapCache.h" #include "modules/MapCache.h"
#include "TileTypes.h" #include "uicommon.h"
#include "df/job_item.h"
using namespace std; using namespace std;
using std::map; using std::map;
@ -79,27 +80,7 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
return CR_OK; return CR_OK;
} }
void OutputString(int8_t color, int &x, int &y, const std::string &text, bool newline = false, int left_margin = 0) void AMOutputToggleString(int &x, int &y, const char *text, const char *hotkey, bool state, bool newline = true, int left_margin = 0, int8_t color = COLOR_WHITE)
{
Screen::paintString(Screen::Pen(' ', color, 0), x, y, text);
if (newline)
{
++y;
x = left_margin;
}
else
x += text.length();
}
void OutputHotkeyString(int &x, int &y, const char *text, const char *hotkey, bool newline = false, int left_margin = 0, int8_t color = COLOR_WHITE)
{
OutputString(10, x, y, hotkey);
string display(": ");
display.append(text);
OutputString(color, x, y, display, newline, left_margin);
}
void OutputToggleString(int &x, int &y, const char *text, const char *hotkey, bool state, bool newline = true, int left_margin = 0, int8_t color = COLOR_WHITE)
{ {
OutputHotkeyString(x, y, text, hotkey); OutputHotkeyString(x, y, text, hotkey);
OutputString(COLOR_WHITE, x, y, ": "); OutputString(COLOR_WHITE, x, y, ": ");
@ -109,16 +90,7 @@ void OutputToggleString(int &x, int &y, const char *text, const char *hotkey, bo
OutputString(COLOR_GREY, x, y, "Disabled", newline, left_margin); OutputString(COLOR_GREY, x, y, "Disabled", newline, left_margin);
} }
static string int_to_string(int i)
{
return static_cast<ostringstream*>( &(ostringstream() << i))->str();
}
//START UI Functions //START UI Functions
struct coord32_t
{
int32_t x, y, z;
};
static enum t_box_select_mode {SELECT_FIRST, SELECT_SECOND, SELECT_MATERIALS, AUTOSELECT_MATERIALS} box_select_mode = SELECT_FIRST; static enum t_box_select_mode {SELECT_FIRST, SELECT_SECOND, SELECT_MATERIALS, AUTOSELECT_MATERIALS} box_select_mode = SELECT_FIRST;
static coord32_t box_first, box_second; static coord32_t box_first, box_second;
@ -668,7 +640,7 @@ struct jobutils_hook : public df::viewscreen_dwarfmodest
x = x - vport.x + 1; x = x - vport.x + 1;
y = y - vport.y + 1; y = y - vport.y + 1;
OutputString(COLOR_GREEN, x, y, "X"); OutputString(COLOR_GREEN, x, y, "X", false, 0, 0, true /* map */);
} }
else if (show_box_selection && box_select_mode == SELECT_SECOND) else if (show_box_selection && box_select_mode == SELECT_SECOND)
{ {
@ -688,7 +660,7 @@ struct jobutils_hook : public df::viewscreen_dwarfmodest
int32_t x = xB - vport.x + 1; int32_t x = xB - vport.x + 1;
int32_t y = yB - vport.y + 1; int32_t y = yB - vport.y + 1;
OutputString(color, x, y, "X"); OutputString(color, x, y, "X", false, 0, 0, true /* map */);
} }
} }
} }
@ -698,7 +670,7 @@ struct jobutils_hook : public df::viewscreen_dwarfmodest
{ {
int32_t x = it->pos.x - vport.x + 1; int32_t x = it->pos.x - vport.x + 1;
int32_t y = it->pos.y - vport.y + 1; int32_t y = it->pos.y - vport.y + 1;
OutputString(COLOR_GREEN, x, y, "X"); OutputString(COLOR_GREEN, x, y, "X", false, 0, 0, true /* map */);
} }
} }
} }
@ -1114,7 +1086,7 @@ struct jobutils_hook : public df::viewscreen_dwarfmodest
MaterialDescriptor material = get_material_in_list(ui_build_selector->sel_index); MaterialDescriptor material = get_material_in_list(ui_build_selector->sel_index);
if (material.valid) if (material.valid)
{ {
OutputToggleString(x, y, "Autoselect", "a", check_autoselect(material, false), true, left_margin); AMOutputToggleString(x, y, "Autoselect", "a", check_autoselect(material, false), true, left_margin);
if (box_select_mode == SELECT_MATERIALS) if (box_select_mode == SELECT_MATERIALS)
{ {
@ -1127,16 +1099,16 @@ struct jobutils_hook : public df::viewscreen_dwarfmodest
else if (in_placement_stage() && ui_build_selector->building_subtype < 7) else if (in_placement_stage() && ui_build_selector->building_subtype < 7)
{ {
OutputString(COLOR_BROWN, x, y, "DFHack Options", true, left_margin); OutputString(COLOR_BROWN, x, y, "DFHack Options", true, left_margin);
OutputToggleString(x, y, "Auto Mat-select", "a", auto_choose_materials, true, left_margin); AMOutputToggleString(x, y, "Auto Mat-select", "a", auto_choose_materials, true, left_margin);
OutputToggleString(x, y, "Reselect Type", "t", revert_to_last_used_type, true, left_margin); AMOutputToggleString(x, y, "Reselect Type", "t", revert_to_last_used_type, true, left_margin);
++y; ++y;
OutputToggleString(x, y, "Box Select", "b", box_select_enabled, true, left_margin); AMOutputToggleString(x, y, "Box Select", "b", box_select_enabled, true, left_margin);
if (box_select_enabled) if (box_select_enabled)
{ {
OutputToggleString(x, y, "Show Box Mask", "x", show_box_selection, true, left_margin); AMOutputToggleString(x, y, "Show Box Mask", "x", show_box_selection, true, left_margin);
OutputHotkeyString(x, y, (hollow_selection) ? "Make Solid" : "Make Hollow", "h", true, left_margin); OutputHotkeyString(x, y, (hollow_selection) ? "Make Solid" : "Make Hollow", "h", true, left_margin);
OutputToggleString(x, y, "Open Placement", "o", allow_future_placement, true, left_margin); AMOutputToggleString(x, y, "Open Placement", "o", allow_future_placement, true, left_margin);
} }
++y; ++y;
if (box_select_enabled) if (box_select_enabled)
@ -1165,7 +1137,7 @@ struct jobutils_hook : public df::viewscreen_dwarfmodest
int cx = box_first.x; int cx = box_first.x;
int cy = box_first.y; int cy = box_first.y;
OutputString(COLOR_BROWN, cx, cy, "X"); OutputString(COLOR_BROWN, cx, cy, "X", false, 0, 0, true /* map */);
} }
OutputString(COLOR_BROWN, x, ++y, "Ignore Building Restrictions", true, left_margin); OutputString(COLOR_BROWN, x, ++y, "Ignore Building Restrictions", true, left_margin);

@ -1,9 +1,11 @@
#include "buildingplan-lib.h" #include "buildingplan-lib.h"
#include "df/ui_sidebar_menus.h"
DFHACK_PLUGIN("buildingplan"); DFHACK_PLUGIN("buildingplan");
#define PLUGIN_VERSION 0.14 #define PLUGIN_VERSION 0.14
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(ui_build_selector); REQUIRE_GLOBAL(ui_build_selector);
REQUIRE_GLOBAL(ui_sidebar_menus);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
DFhackCExport command_result plugin_shutdown ( color_ostream &out ) DFhackCExport command_result plugin_shutdown ( color_ostream &out )
@ -188,6 +190,8 @@ struct buildingplan_hook : public df::viewscreen_dwarfmodest
} }
else if (isInNobleRoomQueryMode()) else if (isInNobleRoomQueryMode())
{ {
if (ui_sidebar_menus->barracks.in_rename)
return false;
auto np = getNoblePositionOfSelectedBuildingOwner(); auto np = getNoblePositionOfSelectedBuildingOwner();
df::interface_key last_token = get_string_key(input); df::interface_key last_token = get_string_key(input);
if (last_token >= interface_key::STRING_A048 && last_token <= interface_key::STRING_A058) if (last_token >= interface_key::STRING_A048 && last_token <= interface_key::STRING_A058)

@ -314,6 +314,7 @@ command_result show_prompt(color_ostream &out, std::vector <std::string> & param
if (Gui::getCurFocus() == "dfhack/commandprompt") if (Gui::getCurFocus() == "dfhack/commandprompt")
{ {
Screen::dismiss(Gui::getCurViewscreen(true)); Screen::dismiss(Gui::getCurViewscreen(true));
return CR_OK;
} }
std::string params; std::string params;
for(size_t i=0;i<parameters.size();i++) for(size_t i=0;i<parameters.size();i++)

@ -19,9 +19,9 @@ struct {
uint8_t tick; uint8_t tick;
} config; } config;
void color_text_tile(const Screen::Pen &pen, int x, int y, bool map); bool color_text_tile(const Screen::Pen &pen, int x, int y, bool map);
GUI_HOOK_CALLBACK(Screen::Hooks::set_tile, color_text_hook, color_text_tile); GUI_HOOK_CALLBACK(Screen::Hooks::set_tile, color_text_hook, color_text_tile);
void color_text_tile(const Screen::Pen &pen, int x, int y, bool map) bool color_text_tile(const Screen::Pen &pen, int x, int y, bool map)
{ {
Screen::Pen pen2 = pen; Screen::Pen pen2 = pen;
uint8_t color = config.flicker ? config.tick % 8 : config.color; uint8_t color = config.flicker ? config.tick % 8 : config.color;
@ -40,24 +40,24 @@ void color_text_tile(const Screen::Pen &pen, int x, int y, bool map)
return color_text_hook.next()(pen2, x, y, map); return color_text_hook.next()(pen2, x, y, map);
} }
void aaaaa_set_tile(const Screen::Pen &pen, int x, int y, bool map); bool aaaaa_set_tile(const Screen::Pen &pen, int x, int y, bool map);
GUI_HOOK_CALLBACK(Screen::Hooks::set_tile, aaaaa_set_tile_hook, aaaaa_set_tile); GUI_HOOK_CALLBACK(Screen::Hooks::set_tile, aaaaa_set_tile_hook, aaaaa_set_tile);
void aaaaa_set_tile(const Screen::Pen &pen, int x, int y, bool map) bool aaaaa_set_tile(const Screen::Pen &pen, int x, int y, bool map)
{ {
Screen::Pen pen2 = pen; Screen::Pen pen2 = pen;
if ((pen.ch >= 'A' && pen.ch <= 'Z') || (pen.ch >= '0' && pen.ch <= '9')) if ((pen.ch >= 'A' && pen.ch <= 'Z') || (pen.ch >= '0' && pen.ch <= '9'))
pen2.ch = 'A'; pen2.ch = 'A';
else if (pen.ch >= 'a' && pen.ch <= 'z') else if (pen.ch >= 'a' && pen.ch <= 'z')
pen2.ch = 'a'; pen2.ch = 'a';
aaaaa_set_tile_hook.next()(pen2, x, y, map); return aaaaa_set_tile_hook.next()(pen2, x, y, map);
} }
void shift_set_tile(const Screen::Pen &pen, int x, int y, bool map); bool shift_set_tile(const Screen::Pen &pen, int x, int y, bool map);
GUI_HOOK_CALLBACK(Screen::Hooks::set_tile, shift_set_tile_hook, shift_set_tile); GUI_HOOK_CALLBACK(Screen::Hooks::set_tile, shift_set_tile_hook, shift_set_tile);
void shift_set_tile(const Screen::Pen &pen, int x, int y, bool map) bool shift_set_tile(const Screen::Pen &pen, int x, int y, bool map)
{ {
x = (x + 1) % gps->dimx; x = (x + 1) % gps->dimx;
shift_set_tile_hook.next()(pen, x, y, map); return shift_set_tile_hook.next()(pen, x, y, map);
} }
DFhackCExport command_result plugin_enable (color_ostream &out, bool enable) DFhackCExport command_result plugin_enable (color_ostream &out, bool enable)

@ -65,7 +65,7 @@ static df::coord get_mouse_pos(int32_t &mx, int32_t &my)
pos.x = vx + mx - 1; pos.x = vx + mx - 1;
pos.y = vy + my - 1; pos.y = vy + my - 1;
pos.z = vz - Gui::getDepthAt(pos.x, pos.y); pos.z = vz - Gui::getDepthAt(mx, my);
return pos; return pos;
} }

@ -27,6 +27,8 @@
#include "modules/World.h" #include "modules/World.h"
#include "uicommon.h"
using std::map; using std::map;
using std::string; using std::string;
using std::vector; using std::vector;
@ -50,30 +52,6 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
return CR_OK; return CR_OK;
} }
template <class T, typename Fn>
static void for_each_(vector<T> &v, Fn func)
{
for_each(v.begin(), v.end(), func);
}
template <class T, class V, typename Fn>
static void transform_(vector<T> &src, vector<V> &dst, Fn func)
{
transform(src.begin(), src.end(), back_inserter(dst), func);
}
void OutputString(int8_t color, int &x, int &y, const std::string &text, bool newline = false, int left_margin = 0)
{
Screen::paintString(Screen::Pen(' ', color, 0), x, y, text);
if (newline)
{
++y;
x = left_margin;
}
else
x += text.length();
}
df::job *get_suspended_job(df::building *bld) df::job *get_suspended_job(df::building *bld)
{ {
if (bld->getBuildStage() != 0) if (bld->getBuildStage() != 0)
@ -147,7 +125,7 @@ void show_suspended_buildings()
auto dims = Gui::getDwarfmodeViewDims(); auto dims = Gui::getDwarfmodeViewDims();
int left_margin = vx + dims.map_x2; int left_margin = vx + dims.map_x2;
int bottom_margin = vy + dims.y2; int bottom_margin = vy + dims.map_y2 - 1;
for (auto sb = suspended_buildings.begin(); sb != suspended_buildings.end();) for (auto sb = suspended_buildings.begin(); sb != suspended_buildings.end();)
{ {
@ -168,7 +146,7 @@ void show_suspended_buildings()
else if (sb->was_resumed) else if (sb->was_resumed)
color = COLOR_RED; color = COLOR_RED;
OutputString(color, x, y, "X"); OutputString(color, x, y, "X", false, 0, 0, true /* map */);
} }
sb++; sb++;

@ -138,7 +138,7 @@ module DFHack
def cpp_new(init=nil) def cpp_new(init=nil)
ptr = DFHack.malloc(_sizeof) ptr = DFHack.malloc(_sizeof)
if _rtti_classname and vt = DFHack.rtti_getvtable(_rtti_classname) if _rtti_classname and vt = DFHack.rtti_getvtable(_rtti_classname)
DFHack.memory_write_int32(ptr, vt) DFHack.memory_write_ptr(ptr, vt)
# TODO call constructor # TODO call constructor
end end
o = new._at(ptr) o = new._at(ptr)

@ -5,9 +5,11 @@
#include "PluginManager.h" #include "PluginManager.h"
#include "VersionInfo.h" #include "VersionInfo.h"
#include "MemAccess.h" #include "MemAccess.h"
#include "DataDefs.h" #include "DataDefs.h"
#include "modules/Gui.h"
#include "df/global_objects.h" #include "df/global_objects.h"
#include "df/unit.h"
#include "tinythread.h" #include "tinythread.h"
@ -627,6 +629,12 @@ static VALUE rb_dfget_vtable_ptr(VALUE self, VALUE objptr)
return rb_uint2inum(*(uintptr_t*)rb_num2ulong(objptr)); return rb_uint2inum(*(uintptr_t*)rb_num2ulong(objptr));
} }
static VALUE rb_dfget_selected_unit_id(VALUE self)
{
df::unit *u = Gui::getAnyUnit(Core::getTopViewscreen());
return rb_int2inum(u ? u->id : -1);
}
// run a dfhack command, as if typed from the dfhack console // run a dfhack command, as if typed from the dfhack console
static VALUE rb_dfhack_run(VALUE self, VALUE cmd) static VALUE rb_dfhack_run(VALUE self, VALUE cmd)
{ {
@ -1138,6 +1146,7 @@ static void ruby_bind_dfhack(void) {
rb_define_singleton_method(rb_cDFHack, "get_vtable", RUBY_METHOD_FUNC(rb_dfget_vtable), 1); rb_define_singleton_method(rb_cDFHack, "get_vtable", RUBY_METHOD_FUNC(rb_dfget_vtable), 1);
rb_define_singleton_method(rb_cDFHack, "get_rtti_classname", RUBY_METHOD_FUNC(rb_dfget_rtti_classname), 1); rb_define_singleton_method(rb_cDFHack, "get_rtti_classname", RUBY_METHOD_FUNC(rb_dfget_rtti_classname), 1);
rb_define_singleton_method(rb_cDFHack, "get_vtable_ptr", RUBY_METHOD_FUNC(rb_dfget_vtable_ptr), 1); rb_define_singleton_method(rb_cDFHack, "get_vtable_ptr", RUBY_METHOD_FUNC(rb_dfget_vtable_ptr), 1);
rb_define_singleton_method(rb_cDFHack, "get_selected_unit_id", RUBY_METHOD_FUNC(rb_dfget_selected_unit_id), 0);
rb_define_singleton_method(rb_cDFHack, "dfhack_run", RUBY_METHOD_FUNC(rb_dfhack_run), 1); rb_define_singleton_method(rb_cDFHack, "dfhack_run", RUBY_METHOD_FUNC(rb_dfhack_run), 1);
rb_define_singleton_method(rb_cDFHack, "print_str", RUBY_METHOD_FUNC(rb_dfprint_str), 1); rb_define_singleton_method(rb_cDFHack, "print_str", RUBY_METHOD_FUNC(rb_dfprint_str), 1);
rb_define_singleton_method(rb_cDFHack, "print_color", RUBY_METHOD_FUNC(rb_dfprint_color), 2); rb_define_singleton_method(rb_cDFHack, "print_color", RUBY_METHOD_FUNC(rb_dfprint_color), 2);

@ -6,43 +6,7 @@ module DFHack
# with an argument that respond to x/y/z (eg cursor), find first unit at this position # with an argument that respond to x/y/z (eg cursor), find first unit at this position
def unit_find(what=:selected, y=nil, z=nil) def unit_find(what=:selected, y=nil, z=nil)
if what == :selected if what == :selected
case curview._rtti_classname return world.units.all.binsearch(df.get_selected_unit_id)
when :viewscreen_itemst
ref = curview.entry_ref[curview.cursor_pos]
ref.unit_tg if ref.kind_of?(GeneralRefUnit)
when :viewscreen_unitlistst
v = curview
v.units[v.page][v.cursor_pos[v.page]]
when :viewscreen_petst
v = curview
case v.mode
when :List
v.animal[v.cursor].unit if !v.is_vermin[v.cursor]
when :SelectTrainer
v.trainer_unit[v.trainer_cursor]
end
when :viewscreen_dwarfmodest
case ui.main.mode
when :ViewUnits
# nobody selected => idx == 0
v = world.units.active[ui_selected_unit]
v if v and v.pos.z == cursor.z
when :LookAround
k = ui_look_list.items[ui_look_cursor]
k.unit if k.type == :Unit
else
ui.follow_unit_tg if ui.follow_unit != -1
end
when :viewscreen_dungeonmodest
case ui_advmode.menu
when :Default
world.units.active[0]
else
unit_find(cursor) # XXX
end
when :viewscreen_dungeon_monsterstatusst
curview.unit
end
elsif what.kind_of?(Integer) elsif what.kind_of?(Integer)
# search by id # search by id
return world.units.all.binsearch(what) if not z return world.units.all.binsearch(what) if not z

@ -1121,7 +1121,7 @@ static void paintAimScreen(df::building_siegeenginest *bld, df::coord view, df::
if (is_in_range(engine->building_rect, tile_pos)) if (is_in_range(engine->building_rect, tile_pos))
continue; continue;
Pen cur_tile = Screen::readTile(ltop.x+x, ltop.y+y); Pen cur_tile = Screen::readTile(ltop.x+x, ltop.y+y, true);
if (!cur_tile.valid()) if (!cur_tile.valid())
continue; continue;
@ -1159,7 +1159,7 @@ static void paintAimScreen(df::building_siegeenginest *bld, df::coord view, df::
if (cur_tile.tile) if (cur_tile.tile)
cur_tile.tile_mode = Pen::CharColor; cur_tile.tile_mode = Pen::CharColor;
Screen::paintTile(cur_tile, ltop.x+x, ltop.y+y); Screen::paintTile(cur_tile, ltop.x+x, ltop.y+y, true);
} }
} }
} }

@ -10,7 +10,8 @@ struct hotkey_clear_hook : df::viewscreen_dwarfmodest {
INTERPOSE_NEXT(render)(); INTERPOSE_NEXT(render)();
if (ui->main.mode == df::ui_sidebar_mode::Hotkeys) if (ui->main.mode == df::ui_sidebar_mode::Hotkeys)
{ {
int x = 26, y = 19; auto dims = Gui::getDwarfmodeViewDims();
int x = dims.menu_x1 + 1, y = 19;
OutputHotkeyString(x, y, "Clear", df::interface_key::CUSTOM_C, false, 0, COLOR_WHITE, COLOR_LIGHTRED); OutputHotkeyString(x, y, "Clear", df::interface_key::CUSTOM_C, false, 0, COLOR_WHITE, COLOR_LIGHTRED);
} }
} }

@ -450,7 +450,7 @@ void unitInfo(color_ostream & out, df::unit* unit, bool verbose = false)
if(verbose) if(verbose)
{ {
out << ". Pos: ("<<unit->pos.x << "/"<< unit->pos.y << "/" << unit->pos.z << ") " << endl; out << ". Pos: ("<<unit->pos.x << "/"<< unit->pos.y << "/" << unit->pos.z << ") " << endl;
out << "index in units vector: " << FindIndexById(unit->id) << endl; out << "index in units vector: " << findIndexById(unit->id) << endl;
} }
out << endl; out << endl;