develop
Warmist 2012-04-28 22:21:57 +03:00
commit a56f1549a9
62 changed files with 2888 additions and 655 deletions

@ -108,7 +108,7 @@ OPTION(BUILD_PLUGINS "Build the plugins." ON)
# enable C++11 features
IF(UNIX)
add_definitions(-DLINUX_BUILD)
SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall")
SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -Wall -Wno-unused-variable")
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -m32 -march=i686 -mtune=generic -std=c++0x")
SET(CMAKE_C_FLAGS "-fvisibility=hidden -m32 -march=i686 -mtune=generic")
ENDIF()

@ -594,41 +594,44 @@ C++ function wrappers
=====================
Thin wrappers around C++ functions, similar to the ones for virtual methods.
One notable difference is that these explicit wrappers allow argument count
adjustment according to the usual lua rules, so trailing false/nil arguments
can be omitted.
* ``dfhack.TranslateName(name,in_english,only_last_name)``
* ``dfhack.TranslateName(name[,in_english,only_last_name])``
Convert a language_name or only the last name part to string.
Gui module
----------
* ``dfhack.gui.getSelectedWorkshopJob(silent)``
* ``dfhack.gui.getSelectedWorkshopJob([silent])``
When a job is selected in *'q'* mode, returns the job, else
prints error unless silent and returns *nil*.
* ``dfhack.gui.getSelectedJob(silent)``
* ``dfhack.gui.getSelectedJob([silent])``
Returns the job selected in a workshop or unit/jobs screen.
* ``dfhack.gui.getSelectedUnit(silent)``
* ``dfhack.gui.getSelectedUnit([silent])``
Returns the unit selected via *'v'*, *'k'*, unit/jobs, or
a full-screen item view of a cage or suchlike.
* ``dfhack.gui.getSelectedItem(silent)``
* ``dfhack.gui.getSelectedItem([silent])``
Returns the item selected via *'v'* ->inventory, *'k'*, *'t'*, or
a full-screen item view of a container. Note that in the
last case, the highlighted *contained item* is returned, not
the container itself.
* ``dfhack.gui.showAnnouncement(text,color,is_bright)``
* ``dfhack.gui.showAnnouncement(text,color[,is_bright])``
Adds a regular announcement with given text, color, and brightness.
The is_bright boolean actually seems to invert the brightness.
* ``dfhack.gui.showPopupAnnouncement(text,color,is_bright)``
* ``dfhack.gui.showPopupAnnouncement(text,color[,is_bright])``
Pops up a titan-style modal announcement window.
@ -688,6 +691,10 @@ Units module
Returns the language_name object visible in game, accounting for false identities.
* ``dfhack.units.getIdentity(unit)``
Returns the false identity of the unit if it has one, or *nil*.
* ``dfhack.units.getNemesis(unit)``
Returns the nemesis record of the unit if it has one, or *nil*.
@ -704,17 +711,24 @@ Units module
The unit is capable of rational action, i.e. not dead, insane or zombie.
* ``dfhack.units.clearBurrowMembers(burrow)``
* ``dfhack.units.getAge(unit[,true_age])``
Removes all units from the burrow.
Returns the age of the unit in years as a floating-point value.
If ``true_age`` is true, ignores false identities.
* ``dfhack.units.isInBurrow(unit,burrow)``
* ``dfhack.units.getNoblePositions(unit)``
Checks if the unit is in the burrow.
Returns a list of tables describing noble position assignments, or *nil*.
Every table has fields ``entity``, ``assignment`` and ``position``.
* ``dfhack.units.setInBurrow(unit,burrow,enable)``
* ``dfhack.units.getProfessionName(unit[,ignore_noble,plural])``
Adds or removes the unit from the burrow.
Retrieves the profession name using custom profession, noble assignments
or raws. The ``ignore_noble`` boolean disables the use of noble positions.
* ``dfhack.units.getCasteProfessionName(race,caste,prof_id[,plural])``
Retrieves the profession name for the given race/caste using raws.
Items module
@ -781,31 +795,57 @@ Maps module
Returns the local feature object with the given region coords and index.
* ``dfhack.maps.findBurrowByName(name)``
* ``dfhack.maps.canWalkBetween(pos1, pos2)``
Checks if a dwarf may be able to walk between the two tiles,
using a pathfinding cache maintained by the game. Note that
this cache is only updated when the game is unpaused, and thus
can get out of date if doors are forbidden or unforbidden, or
tools like liquids or tiletypes are used. It also cannot possibly
take into account anything that depends on the actual units, like
burrows, or the presence of invaders.
Burrows module
--------------
* ``dfhack.burrows.findByName(name)``
Returns the burrow pointer or *nil*.
* ``dfhack.maps.listBurrowBlocks(burrow)``
* ``dfhack.burrows.clearUnits(burrow)``
Returns a table of map block pointers.
Removes all units from the burrow.
* ``dfhack.burrows.isAssignedUnit(burrow,unit)``
Checks if the unit is in the burrow.
* ``dfhack.burrows.setAssignedUnit(burrow,unit,enable)``
* ``dfhack.maps.clearBurrowTiles(burrow)``
Adds or removes the unit from the burrow.
* ``dfhack.burrows.clearTiles(burrow)``
Removes all tiles from the burrow.
* ``dfhack.maps.isBurrowTile(burrow,tile_coord)``
* ``dfhack.burrows.listBlocks(burrow)``
Returns a table of map block pointers.
* ``dfhack.burrows.isAssignedTile(burrow,tile_coord)``
Checks if the tile is in burrow.
* ``dfhack.maps.setBurrowTile(burrow,tile_coord,enable)``
* ``dfhack.burrows.setAssignedTile(burrow,tile_coord,enable)``
Adds or removes the tile from the burrow. Returns *false* if invalid coords.
* ``dfhack.maps.isBlockBurrowTile(burrow,block,x,y)``
* ``dfhack.burrows.isAssignedBlockTile(burrow,block,x,y)``
Checks if the tile within the block is in burrow.
* ``dfhack.maps.setBlockBurrowTile(burrow,block,x,y,enable)``
* ``dfhack.burrows.setAssignedBlockTile(burrow,block,x,y,enable)``
Adds or removes the tile from the burrow. Returns *false* if invalid coords.
@ -856,3 +896,65 @@ Features:
Invokes all listeners contained in the event in an arbitrary
order using ``dfhack.safecall``.
=======
Plugins
=======
DFHack plugins may export native functions and events
to lua contexts. They are automatically imported by
``mkmodule('plugins.<name>')``; this means that a lua
module file is still necessary for ``require`` to read.
The following plugins have lua support.
burrows
=======
Implements extended burrow manipulations.
Events:
* ``onBurrowRename.foo = function(burrow)``
Emitted when a burrow might have been renamed either through
the game UI, or ``renameBurrow()``.
* ``onDigComplete.foo = function(job_type,pos,old_tiletype,new_tiletype)``
Emitted when a tile might have been dug out. Only tracked if the
auto-growing burrows feature is enabled.
Native functions:
* ``renameBurrow(burrow,name)``
Renames the burrow, emitting ``onBurrowRename`` and updating auto-grow state properly.
* ``findByName(burrow,name)``
Finds a burrow by name, using the same rules as the plugin command line interface.
Namely, trailing ``'+'`` characters marking auto-grow burrows are ignored.
* ``copyUnits(target,source,enable)``
Applies units from ``source`` burrow to ``target``. The ``enable``
parameter specifies if they are to be added or removed.
* ``copyTiles(target,source,enable)``
Applies tiles from ``source`` burrow to ``target``. The ``enable``
parameter specifies if they are to be added or removed.
* ``setTilesByKeyword(target,keyword,enable)``
Adds or removes tiles matching a predefined keyword. The keyword
set is the same as used by the command line.
The lua module file also re-exports functions from ``dfhack.burrows``.
sort
====
Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items.

@ -342,14 +342,20 @@ ul.auto-toc {
<li><a class="reference internal" href="#units-module" id="id16">Units module</a></li>
<li><a class="reference internal" href="#items-module" id="id17">Items module</a></li>
<li><a class="reference internal" href="#maps-module" id="id18">Maps module</a></li>
<li><a class="reference internal" href="#burrows-module" id="id19">Burrows module</a></li>
</ul>
</li>
<li><a class="reference internal" href="#core-interpreter-context" id="id19">Core interpreter context</a><ul>
<li><a class="reference internal" href="#event-type" id="id20">Event type</a></li>
<li><a class="reference internal" href="#core-interpreter-context" id="id20">Core interpreter context</a><ul>
<li><a class="reference internal" href="#event-type" id="id21">Event type</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#plugins" id="id22">Plugins</a><ul>
<li><a class="reference internal" href="#burrows" id="id23">burrows</a></li>
<li><a class="reference internal" href="#sort" id="id24">sort</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="df-structure-wrapper">
@ -842,37 +848,40 @@ Accept dfhack_material_category auto-assign table.</p>
</div>
<div class="section" id="c-function-wrappers">
<h2><a class="toc-backref" href="#id13">C++ function wrappers</a></h2>
<p>Thin wrappers around C++ functions, similar to the ones for virtual methods.</p>
<p>Thin wrappers around C++ functions, similar to the ones for virtual methods.
One notable difference is that these explicit wrappers allow argument count
adjustment according to the usual lua rules, so trailing false/nil arguments
can be omitted.</p>
<ul>
<li><p class="first"><tt class="docutils literal">dfhack.TranslateName(name,in_english,only_last_name)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.TranslateName(name[,in_english,only_last_name])</span></tt></p>
<p>Convert a language_name or only the last name part to string.</p>
</li>
</ul>
<div class="section" id="gui-module">
<h3><a class="toc-backref" href="#id14">Gui module</a></h3>
<ul>
<li><p class="first"><tt class="docutils literal">dfhack.gui.getSelectedWorkshopJob(silent)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedWorkshopJob([silent])</span></tt></p>
<p>When a job is selected in <em>'q'</em> mode, returns the job, else
prints error unless silent and returns <em>nil</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.getSelectedJob(silent)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedJob([silent])</span></tt></p>
<p>Returns the job selected in a workshop or unit/jobs screen.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.getSelectedUnit(silent)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedUnit([silent])</span></tt></p>
<p>Returns the unit selected via <em>'v'</em>, <em>'k'</em>, unit/jobs, or
a full-screen item view of a cage or suchlike.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.getSelectedItem(silent)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedItem([silent])</span></tt></p>
<p>Returns the item selected via <em>'v'</em> -&gt;inventory, <em>'k'</em>, <em>'t'</em>, or
a full-screen item view of a container. Note that in the
last case, the highlighted <em>contained item</em> is returned, not
the container itself.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.showAnnouncement(text,color,is_bright)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showAnnouncement(text,color[,is_bright])</span></tt></p>
<p>Adds a regular announcement with given text, color, and brightness.
The is_bright boolean actually seems to invert the brightness.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.showPopupAnnouncement(text,color,is_bright)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showPopupAnnouncement(text,color[,is_bright])</span></tt></p>
<p>Pops up a titan-style modal announcement window.</p>
</li>
</ul>
@ -923,6 +932,9 @@ a lua list containing them.</p>
<li><p class="first"><tt class="docutils literal">dfhack.units.getVisibleName(unit)</tt></p>
<p>Returns the language_name object visible in game, accounting for false identities.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.getIdentity(unit)</tt></p>
<p>Returns the false identity of the unit if it has one, or <em>nil</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.getNemesis(unit)</tt></p>
<p>Returns the nemesis record of the unit if it has one, or <em>nil</em>.</p>
</li>
@ -935,14 +947,20 @@ a lua list containing them.</p>
<li><p class="first"><tt class="docutils literal">dfhack.units.isSane(unit)</tt></p>
<p>The unit is capable of rational action, i.e. not dead, insane or zombie.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.clearBurrowMembers(burrow)</tt></p>
<p>Removes all units from the burrow.</p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.units.getAge(unit[,true_age])</span></tt></p>
<p>Returns the age of the unit in years as a floating-point value.
If <tt class="docutils literal">true_age</tt> is true, ignores false identities.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.isInBurrow(unit,burrow)</tt></p>
<p>Checks if the unit is in the burrow.</p>
<li><p class="first"><tt class="docutils literal">dfhack.units.getNoblePositions(unit)</tt></p>
<p>Returns a list of tables describing noble position assignments, or <em>nil</em>.
Every table has fields <tt class="docutils literal">entity</tt>, <tt class="docutils literal">assignment</tt> and <tt class="docutils literal">position</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.setInBurrow(unit,burrow,enable)</tt></p>
<p>Adds or removes the unit from the burrow.</p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.units.getProfessionName(unit[,ignore_noble,plural])</span></tt></p>
<p>Retrieves the profession name using custom profession, noble assignments
or raws. The <tt class="docutils literal">ignore_noble</tt> boolean disables the use of noble positions.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.units.getCasteProfessionName(race,caste,prof_id[,plural])</span></tt></p>
<p>Retrieves the profession name for the given race/caste using raws.</p>
</li>
</ul>
</div>
@ -997,32 +1015,55 @@ Returns <em>false</em> in case of error.</p>
<li><p class="first"><tt class="docutils literal">dfhack.maps.getLocalInitFeature(region_coord2d,index)</tt></p>
<p>Returns the local feature object with the given region coords and index.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.maps.findBurrowByName(name)</tt></p>
<li><p class="first"><tt class="docutils literal">dfhack.maps.canWalkBetween(pos1, pos2)</tt></p>
<p>Checks if a dwarf may be able to walk between the two tiles,
using a pathfinding cache maintained by the game. Note that
this cache is only updated when the game is unpaused, and thus
can get out of date if doors are forbidden or unforbidden, or
tools like liquids or tiletypes are used. It also cannot possibly
take into account anything that depends on the actual units, like
burrows, or the presence of invaders.</p>
</li>
</ul>
</div>
<div class="section" id="burrows-module">
<h3><a class="toc-backref" href="#id19">Burrows module</a></h3>
<ul>
<li><p class="first"><tt class="docutils literal">dfhack.burrows.findByName(name)</tt></p>
<p>Returns the burrow pointer or <em>nil</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.maps.listBurrowBlocks(burrow)</tt></p>
<p>Returns a table of map block pointers.</p>
<li><p class="first"><tt class="docutils literal">dfhack.burrows.clearUnits(burrow)</tt></p>
<p>Removes all units from the burrow.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.burrows.isAssignedUnit(burrow,unit)</tt></p>
<p>Checks if the unit is in the burrow.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.burrows.setAssignedUnit(burrow,unit,enable)</tt></p>
<p>Adds or removes the unit from the burrow.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.maps.clearBurrowTiles(burrow)</tt></p>
<li><p class="first"><tt class="docutils literal">dfhack.burrows.clearTiles(burrow)</tt></p>
<p>Removes all tiles from the burrow.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.maps.isBurrowTile(burrow,tile_coord)</tt></p>
<li><p class="first"><tt class="docutils literal">dfhack.burrows.listBlocks(burrow)</tt></p>
<p>Returns a table of map block pointers.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.burrows.isAssignedTile(burrow,tile_coord)</tt></p>
<p>Checks if the tile is in burrow.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.maps.setBurrowTile(burrow,tile_coord,enable)</tt></p>
<li><p class="first"><tt class="docutils literal">dfhack.burrows.setAssignedTile(burrow,tile_coord,enable)</tt></p>
<p>Adds or removes the tile from the burrow. Returns <em>false</em> if invalid coords.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.maps.isBlockBurrowTile(burrow,block,x,y)</tt></p>
<li><p class="first"><tt class="docutils literal">dfhack.burrows.isAssignedBlockTile(burrow,block,x,y)</tt></p>
<p>Checks if the tile within the block is in burrow.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.maps.setBlockBurrowTile(burrow,block,x,y,enable)</tt></p>
<li><p class="first"><tt class="docutils literal">dfhack.burrows.setAssignedBlockTile(burrow,block,x,y,enable)</tt></p>
<p>Adds or removes the tile from the burrow. Returns <em>false</em> if invalid coords.</p>
</li>
</ul>
</div>
</div>
<div class="section" id="core-interpreter-context">
<h2><a class="toc-backref" href="#id19">Core interpreter context</a></h2>
<h2><a class="toc-backref" href="#id20">Core interpreter context</a></h2>
<p>While plugins can create any number of interpreter instances,
there is one special context managed by dfhack core. It is the
only context that can receive events from DF and plugins.</p>
@ -1036,7 +1077,7 @@ only context that can receive events from DF and plugins.</p>
</li>
</ul>
<div class="section" id="event-type">
<h3><a class="toc-backref" href="#id20">Event type</a></h3>
<h3><a class="toc-backref" href="#id21">Event type</a></h3>
<p>An event is just a lua table with a predefined metatable that
contains a __call metamethod. When it is invoked, it loops
through the table with next and calls all contained values.
@ -1061,6 +1102,57 @@ order using <tt class="docutils literal">dfhack.safecall</tt>.</p>
</div>
</div>
</div>
<div class="section" id="plugins">
<h1><a class="toc-backref" href="#id22">Plugins</a></h1>
<p>DFHack plugins may export native functions and events
to lua contexts. They are automatically imported by
<tt class="docutils literal"><span class="pre">mkmodule('plugins.&lt;name&gt;')</span></tt>; this means that a lua
module file is still necessary for <tt class="docutils literal">require</tt> to read.</p>
<p>The following plugins have lua support.</p>
<div class="section" id="burrows">
<h2><a class="toc-backref" href="#id23">burrows</a></h2>
<p>Implements extended burrow manipulations.</p>
<p>Events:</p>
<ul>
<li><p class="first"><tt class="docutils literal">onBurrowRename.foo = function(burrow)</tt></p>
<p>Emitted when a burrow might have been renamed either through
the game UI, or <tt class="docutils literal">renameBurrow()</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">onDigComplete.foo = function(job_type,pos,old_tiletype,new_tiletype)</tt></p>
<p>Emitted when a tile might have been dug out. Only tracked if the
auto-growing burrows feature is enabled.</p>
</li>
</ul>
<p>Native functions:</p>
<ul>
<li><p class="first"><tt class="docutils literal">renameBurrow(burrow,name)</tt></p>
<p>Renames the burrow, emitting <tt class="docutils literal">onBurrowRename</tt> and updating auto-grow state properly.</p>
</li>
<li><p class="first"><tt class="docutils literal">findByName(burrow,name)</tt></p>
<p>Finds a burrow by name, using the same rules as the plugin command line interface.
Namely, trailing <tt class="docutils literal">'+'</tt> characters marking auto-grow burrows are ignored.</p>
</li>
<li><p class="first"><tt class="docutils literal">copyUnits(target,source,enable)</tt></p>
<p>Applies units from <tt class="docutils literal">source</tt> burrow to <tt class="docutils literal">target</tt>. The <tt class="docutils literal">enable</tt>
parameter specifies if they are to be added or removed.</p>
</li>
<li><p class="first"><tt class="docutils literal">copyTiles(target,source,enable)</tt></p>
<p>Applies tiles from <tt class="docutils literal">source</tt> burrow to <tt class="docutils literal">target</tt>. The <tt class="docutils literal">enable</tt>
parameter specifies if they are to be added or removed.</p>
</li>
<li><p class="first"><tt class="docutils literal">setTilesByKeyword(target,keyword,enable)</tt></p>
<p>Adds or removes tiles matching a predefined keyword. The keyword
set is the same as used by the command line.</p>
</li>
</ul>
<p>The lua module file also re-exports functions from <tt class="docutils literal">dfhack.burrows</tt>.</p>
</div>
<div class="section" id="sort">
<h2><a class="toc-backref" href="#id24">sort</a></h2>
<p>Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items.</p>
</div>
</div>
</div>
</body>
</html>

@ -57,7 +57,7 @@ IF(CMAKE_COMPILER_IS_GNUCC)
ENDIF()
IF (HAVE_HASH_MAP EQUAL 0)
MESSAGE(SEND_ERROR "Could not find a working hash map implementation. Please update GCC.")
MESSAGE(SEND_ERROR "Could not find a working hash map implementation. Please install GCC >= 4.4, and all necessary 32-bit C++ development libraries.")
ENDIF()
FIND_PACKAGE(Threads)
@ -200,6 +200,8 @@ google/protobuf/compiler/zip_writer.cc
LIST(APPEND LIBPROTOBUF_FULL_SRCS ${LIBPROTOBUF_LITE_SRCS})
SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -Wno-sign-compare")
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
SET(PROTOBUF_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS})

@ -100,6 +100,7 @@ Process-linux.cpp
SET(MODULE_HEADERS
include/modules/Buildings.h
include/modules/Burrows.h
include/modules/Constructions.h
include/modules/Units.h
include/modules/Engravings.h
@ -120,6 +121,7 @@ include/modules/Graphic.h
SET( MODULE_SOURCES
modules/Buildings.cpp
modules/Burrows.cpp
modules/Constructions.cpp
modules/Units.cpp
modules/Engravings.cpp

@ -163,6 +163,7 @@ namespace DFHack
return false;
return true;
}
return false;
}
public:
@ -489,7 +490,7 @@ namespace DFHack
{
right_arrow:
/* right arrow */
if (raw_cursor != raw_buffer.size())
if (size_t(raw_cursor) != raw_buffer.size())
{
raw_cursor++;
prompt_refresh();
@ -510,7 +511,7 @@ namespace DFHack
history_index = 0;
break;
}
else if (history_index >= history.size())
else if (size_t(history_index) >= history.size())
{
history_index = history.size()-1;
break;
@ -545,7 +546,7 @@ namespace DFHack
if (seq[1] == '3' && seq2 == '~' )
{
// delete
if (raw_buffer.size() > 0 && raw_cursor < raw_buffer.size())
if (raw_buffer.size() > 0 && size_t(raw_cursor) < raw_buffer.size())
{
raw_buffer.erase(raw_cursor,1);
prompt_refresh();
@ -555,11 +556,11 @@ namespace DFHack
}
break;
default:
if (raw_buffer.size() == raw_cursor)
if (raw_buffer.size() == size_t(raw_cursor))
{
raw_buffer.append(1,c);
raw_cursor++;
if (plen+raw_buffer.size() < get_columns())
if (plen+raw_buffer.size() < size_t(get_columns()))
{
/* Avoid a full update of the line in the
* trivial case. */

@ -42,13 +42,14 @@ using namespace DFHack;
void *type_identity::do_allocate_pod() {
void *p = malloc(size);
memset(p, 0, size);
size_t sz = byte_size();
void *p = malloc(sz);
memset(p, 0, sz);
return p;
}
void type_identity::do_copy_pod(void *tgt, const void *src) {
memmove(tgt, src, size);
memmove(tgt, src, byte_size());
};
bool type_identity::do_destroy_pod(void *obj) {
@ -81,8 +82,9 @@ bool type_identity::destroy(void *obj) {
}
void *enum_identity::do_allocate() {
void *p = malloc(byte_size());
memcpy(p, &first_item_value, std::min(byte_size(), sizeof(int64_t)));
size_t sz = byte_size();
void *p = malloc(sz);
memcpy(p, &first_item_value, std::min(sz, sizeof(int64_t)));
return p;
}
@ -96,7 +98,7 @@ std::vector<compound_identity*> compound_identity::top_scope;
compound_identity::compound_identity(size_t size, TAllocateFn alloc,
compound_identity *scope_parent, const char *dfhack_name)
: constructed_identity(size, alloc), scope_parent(scope_parent), dfhack_name(dfhack_name)
: constructed_identity(size, alloc), dfhack_name(dfhack_name), scope_parent(scope_parent)
{
next = list; list = this;
}
@ -144,8 +146,8 @@ enum_identity::enum_identity(size_t size,
const char *const *keys,
const void *attrs, struct_identity *attr_type)
: compound_identity(size, NULL, scope_parent, dfhack_name),
first_item_value(first_item_value), last_item_value(last_item_value),
keys(keys), base_type(base_type), attrs(attrs), attr_type(attr_type)
keys(keys), first_item_value(first_item_value), last_item_value(last_item_value),
base_type(base_type), attrs(attrs), attr_type(attr_type)
{
}
@ -380,7 +382,7 @@ int DFHack::findEnumItem(const std::string &name, int size, const char *const *i
void DFHack::flagarrayToString(std::vector<std::string> *pvec, const void *p,
int bytes, int base, int size, const char *const *items)
{
for (unsigned i = 0; i < bytes*8; i++) {
for (int i = 0; i < bytes*8; i++) {
int value = getBitfieldField(p, i, 1);
if (value)

@ -28,6 +28,7 @@ namespace df {
NUMBER_IDENTITY_TRAITS(int64_t);
NUMBER_IDENTITY_TRAITS(uint64_t);
NUMBER_IDENTITY_TRAITS(float);
NUMBER_IDENTITY_TRAITS(double);
bool_identity identity_traits<bool>::identity;
stl_string_identity identity_traits<std::string>::identity;

@ -46,6 +46,7 @@ distribution.
#include "modules/Materials.h"
#include "modules/Maps.h"
#include "modules/MapCache.h"
#include "modules/Burrows.h"
#include "LuaWrapper.h"
#include "LuaTools.h"
@ -58,8 +59,13 @@ distribution.
#include "df/unit.h"
#include "df/item.h"
#include "df/material.h"
#include "df/assumed_identity.h"
#include "df/nemesis_record.h"
#include "df/historical_figure.h"
#include "df/historical_entity.h"
#include "df/entity_position.h"
#include "df/entity_position_assignment.h"
#include "df/histfig_entity_link_positionst.h"
#include "df/plant_raw.h"
#include "df/creature_raw.h"
#include "df/inorganic_raw.h"
@ -74,6 +80,17 @@ distribution.
using namespace DFHack;
using namespace DFHack::LuaWrapper;
void Lua::Push(lua_State *state, const Units::NoblePosition &pos)
{
lua_createtable(state, 0, 3);
Lua::PushDFObject(state, pos.entity);
lua_setfield(state, -2, "entity");
Lua::PushDFObject(state, pos.assignment);
lua_setfield(state, -2, "assignment");
Lua::PushDFObject(state, pos.position);
lua_setfield(state, -2, "position");
}
int Lua::PushPosXYZ(lua_State *state, df::coord pos)
{
if (!pos.isValid())
@ -353,6 +370,7 @@ static void push_matinfo(lua_State *state, MaterialInfo &info)
case MaterialInfo::Plant: id = "plant"; break;
case MaterialInfo::Creature: id = "creature"; break;
case MaterialInfo::Inorganic: id = "inorganic"; break;
default: break;
}
lua_pushstring(state, id);
@ -551,11 +569,15 @@ static void OpenModule(lua_State *state, const char *mname,
#define WRAP(function) { #function, df::wrap_function(function,true) }
#define WRAPN(name, function) { #name, df::wrap_function(function,true) }
/***** Translation module *****/
static const LuaWrapper::FunctionReg dfhack_module[] = {
WRAPM(Translation, TranslateName),
{ NULL, NULL }
};
/***** Gui module *****/
static const LuaWrapper::FunctionReg dfhack_gui_module[] = {
WRAPM(Gui, getSelectedWorkshopJob),
WRAPM(Gui, getSelectedJob),
@ -566,6 +588,8 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = {
{ NULL, NULL }
};
/***** Job module *****/
static bool jobEqual(df::job *job1, df::job *job2) { return *job1 == *job2; }
static bool jobItemEqual(df::job_item *job1, df::job_item *job2) { return *job1 == *job2; }
@ -602,18 +626,20 @@ static const luaL_Reg dfhack_job_funcs[] = {
{ NULL, NULL }
};
/***** Units module *****/
static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, getContainer),
WRAPM(Units, setNickname),
WRAPM(Units, getVisibleName),
WRAPM(Units, getIdentity),
WRAPM(Units, getNemesis),
WRAPM(Units, isDead),
WRAPM(Units, isAlive),
WRAPM(Units, isSane),
WRAPM(Units, clearBurrowMembers),
WRAPM(Units, isInBurrow),
WRAPM(Units, setInBurrow),
WRAPM(Units, getAge),
WRAPM(Units, getProfessionName),
WRAPM(Units, getCasteProfessionName),
{ NULL, NULL }
};
@ -622,11 +648,26 @@ static int units_getPosition(lua_State *state)
return Lua::PushPosXYZ(state, Units::getPosition(Lua::CheckDFObject<df::unit>(state,1)));
}
static int units_getNoblePositions(lua_State *state)
{
std::vector<Units::NoblePosition> np;
if (Units::getNoblePositions(&np, Lua::CheckDFObject<df::unit>(state,1)))
Lua::PushVector(state, np);
else
lua_pushnil(state);
return 1;
}
static const luaL_Reg dfhack_units_funcs[] = {
{ "getPosition", units_getPosition },
{ "getNoblePositions", units_getNoblePositions },
{ NULL, NULL }
};
/***** Items module *****/
static bool items_moveToGround(df::item *item, df::coord pos)
{
MapExtras::MapCache mc;
@ -667,16 +708,7 @@ static const luaL_Reg dfhack_items_funcs[] = {
{ NULL, NULL }
};
static bool maps_isBlockBurrowTile(df::burrow *burrow, df::map_block *block, int x, int y)
{
return Maps::isBlockBurrowTile(burrow, block, df::coord2d(x,y));
}
static bool maps_setBlockBurrowTile(df::burrow *burrow, df::map_block *block, int x, int y, bool enable)
{
return Maps::setBlockBurrowTile(burrow, block, df::coord2d(x,y), enable);
}
/***** Maps module *****/
static const LuaWrapper::FunctionReg dfhack_maps_module[] = {
WRAPN(getBlock, (df::map_block* (*)(int32_t,int32_t,int32_t))Maps::getBlock),
@ -684,25 +716,49 @@ static const LuaWrapper::FunctionReg dfhack_maps_module[] = {
WRAPM(Maps, getRegionBiome),
WRAPM(Maps, getGlobalInitFeature),
WRAPM(Maps, getLocalInitFeature),
WRAPM(Maps, findBurrowByName),
WRAPM(Maps, clearBurrowTiles),
WRAPN(isBlockBurrowTile, maps_isBlockBurrowTile),
WRAPN(setBlockBurrowTile, maps_setBlockBurrowTile),
WRAPM(Maps, isBurrowTile),
WRAPM(Maps, setBurrowTile),
WRAPM(Maps, canWalkBetween),
{ NULL, NULL }
};
static const luaL_Reg dfhack_maps_funcs[] = {
{ NULL, NULL }
};
/***** Burrows module *****/
static bool burrows_isAssignedBlockTile(df::burrow *burrow, df::map_block *block, int x, int y)
{
return Burrows::isAssignedBlockTile(burrow, block, df::coord2d(x,y));
}
static bool burrows_setAssignedBlockTile(df::burrow *burrow, df::map_block *block, int x, int y, bool enable)
{
return Burrows::setAssignedBlockTile(burrow, block, df::coord2d(x,y), enable);
}
static const LuaWrapper::FunctionReg dfhack_burrows_module[] = {
WRAPM(Burrows, findByName),
WRAPM(Burrows, clearUnits),
WRAPM(Burrows, isAssignedUnit),
WRAPM(Burrows, setAssignedUnit),
WRAPM(Burrows, clearTiles),
WRAPN(isAssignedBlockTile, burrows_isAssignedBlockTile),
WRAPN(setAssignedBlockTile, burrows_setAssignedBlockTile),
WRAPM(Burrows, isAssignedTile),
WRAPM(Burrows, setAssignedTile),
{ NULL, NULL }
};
static int maps_listBurrowBlocks(lua_State *state)
static int burrows_listBlocks(lua_State *state)
{
std::vector<df::map_block*> pvec;
Maps::listBurrowBlocks(&pvec, Lua::CheckDFObject<df::burrow>(state,1));
Burrows::listBlocks(&pvec, Lua::CheckDFObject<df::burrow>(state,1));
Lua::PushVector(state, pvec);
return 1;
}
static const luaL_Reg dfhack_maps_funcs[] = {
{ "listBurrowBlocks", maps_listBurrowBlocks },
static const luaL_Reg dfhack_burrows_funcs[] = {
{ "listBlocks", burrows_listBlocks },
{ NULL, NULL }
};
@ -722,4 +778,5 @@ void OpenDFHackApi(lua_State *state)
OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs);
OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs);
OpenModule(state, "maps", dfhack_maps_module, dfhack_maps_funcs);
OpenModule(state, "burrows", dfhack_burrows_module, dfhack_burrows_funcs);
}

@ -162,11 +162,13 @@ static Console *get_console(lua_State *state)
return static_cast<Console*>(pstream);
}
static int DFHACK_TOSTRING_TOKEN = 0;
static std::string lua_print_fmt(lua_State *L)
{
/* Copied from lua source to fully replicate builtin print */
int n = lua_gettop(L); /* number of arguments */
lua_getglobal(L, "tostring");
lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_TOSTRING_TOKEN);
std::stringstream ss;
@ -319,7 +321,7 @@ static int DFHACK_EXCEPTION_META_TOKEN = 0;
static void error_tostring(lua_State *L, bool keep_old = false)
{
lua_getglobal(L, "tostring");
lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_TOSTRING_TOKEN);
if (keep_old)
lua_pushvalue(L, -2);
else
@ -682,6 +684,9 @@ int DFHack::Lua::SafeResume(color_ostream &out, lua_State *from, int nargs, int
*/
static int DFHACK_LOADED_TOKEN = 0;
static int DFHACK_DFHACK_TOKEN = 0;
static int DFHACK_BASE_G_TOKEN = 0;
static int DFHACK_REQUIRE_TOKEN = 0;
bool DFHack::Lua::PushModule(color_ostream &out, lua_State *state, const char *module)
{
@ -699,7 +704,7 @@ bool DFHack::Lua::PushModule(color_ostream &out, lua_State *state, const char *m
}
lua_pop(state, 2);
lua_getglobal(state, "require");
lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_REQUIRE_TOKEN);
lua_pushstring(state, module);
return Lua::SafeCall(out, state, 1, 1);
@ -730,7 +735,11 @@ bool DFHack::Lua::Require(color_ostream &out, lua_State *state,
return false;
if (setglobal)
lua_setglobal(state, module.c_str());
{
lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_BASE_G_TOKEN);
lua_swap(state);
lua_setfield(state, -2, module.c_str());
}
else
lua_pop(state, 1);
@ -900,7 +909,7 @@ namespace {
static bool init_interpreter(color_ostream &out, lua_State *state, void *info)
{
auto args = (InterpreterArgs*)info;
lua_getglobal(state, "dfhack");
lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_DFHACK_TOKEN);
lua_getfield(state, -1, "interpreter");
lua_remove(state, -2);
lua_pushstring(state, args->prompt);
@ -1252,9 +1261,22 @@ lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
lua_pushcfunction(state, lua_dfhack_println);
lua_setglobal(state, "print");
lua_getglobal(state, "require");
lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_REQUIRE_TOKEN);
lua_getglobal(state, "tostring");
lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_TOSTRING_TOKEN);
// Create the dfhack global
lua_newtable(state);
lua_dup(state);
lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_DFHACK_TOKEN);
lua_rawgeti(state, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
lua_dup(state);
lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_BASE_G_TOKEN);
lua_setfield(state, -2, "BASE_G");
lua_pushboolean(state, IsCoreContext(state));
lua_setfield(state, -2, "is_core_context");
@ -1295,6 +1317,17 @@ lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state)
luaL_setfuncs(state, dfhack_coro_funcs, 0);
lua_pop(state, 1);
// split the global environment
lua_newtable(state);
lua_newtable(state);
lua_rawgeti(state, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
lua_setfield(state, -2, "__index");
lua_setmetatable(state, -2);
lua_dup(state);
lua_setglobal(state, "_G");
lua_dup(state);
lua_rawseti(state, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
// load dfhack.lua
Require(out, state, "dfhack");
@ -1322,7 +1355,7 @@ void DFHack::Lua::Core::Init(color_ostream &out)
Lua::Open(out, State);
// Register events
lua_getglobal(State, "dfhack");
lua_rawgetp(State, LUA_REGISTRYINDEX, &DFHACK_DFHACK_TOKEN);
MakeEvent(State, (void*)onStateChange);
lua_setfield(State, -2, "onStateChange");

@ -576,35 +576,6 @@ static void write_field(lua_State *state, const struct_field_info *field, void *
}
}
/**
* Metamethod: represent a type node as string.
*/
static int meta_type_tostring(lua_State *state)
{
if (!lua_getmetatable(state, 1))
return 0;
lua_getfield(state, -1, "__metatable");
const char *cname = lua_tostring(state, -1);
lua_pushstring(state, stl_sprintf("<type: %s>", cname).c_str());
return 1;
}
/**
* Metamethod: represent a DF object reference as string.
*/
static int meta_ptr_tostring(lua_State *state)
{
uint8_t *ptr = get_object_addr(state, 1, 0, "access");
lua_getfield(state, UPVAL_METATABLE, "__metatable");
const char *cname = lua_tostring(state, -1);
lua_pushstring(state, stl_sprintf("<%s: 0x%08x>", cname, (unsigned)ptr).c_str());
return 1;
}
/**
* Metamethod: __index for structures.
*/

@ -542,10 +542,23 @@ static int meta_sizeof(lua_State *state)
return 2;
}
type_identity *id = get_object_identity(state, 1, "df.sizeof()", true);
type_identity *id = get_object_identity(state, 1, "df.sizeof()", true, true);
lua_pushinteger(state, id->byte_size());
// Static arrays need special handling
if (id->type() == IDTYPE_BUFFER)
{
auto buf = (df::buffer_container_identity*)id;
type_identity *item = buf->getItemType();
int count = buf->getSize();
fetch_container_details(state, lua_gettop(state), &item, &count);
lua_pushinteger(state, item->byte_size() * count);
}
else
lua_pushinteger(state, id->byte_size());
// Add the address
if (lua_isuserdata(state, 1))
{
lua_pushnumber(state, (size_t)get_object_ref(state, 1));

@ -216,6 +216,9 @@ void DFHack::describeMaterial(BasicMaterialInfo *info, const MaterialInfo &mat,
case MaterialInfo::Plant:
info->set_plant_id(mat.index);
break;
default:
break;
}
}
@ -298,7 +301,7 @@ void DFHack::describeUnit(BasicUnitInfo *info, df::unit *unit,
if (mask && mask->labors())
{
for (int i = 0; i < sizeof(unit->status.labors)/sizeof(bool); i++)
for (size_t i = 0; i < sizeof(unit->status.labors)/sizeof(bool); i++)
if (unit->status.labors[i])
info->add_labors(i);
}
@ -399,7 +402,7 @@ static command_result GetWorldInfo(color_ostream &stream,
case GAMETYPE_ADVENTURE_MAIN:
out->set_mode(GetWorldInfoOut::MODE_ADVENTURE);
if (auto unit = vector_get(world->units.other[0], 0))
if (auto unit = vector_get(world->units.active, 0))
out->set_player_unit_id(unit->id);
if (!ui_advmode)
@ -630,7 +633,7 @@ static command_result ListSquads(color_ostream &stream,
static command_result SetUnitLabors(color_ostream &stream, const SetUnitLaborsIn *in)
{
for (size_t i = 0; i < in->change_size(); i++)
for (int i = 0; i < in->change_size(); i++)
{
auto change = in->change(i);
auto unit = df::unit::find(change.unit_id());

@ -68,6 +68,8 @@ namespace DFHack
return tiletype::LavaPillar;
case tiletype_material::STONE:
return tiletype::StonePillar;
default:
break;
}
}

@ -83,7 +83,7 @@ namespace DFHack
public:
virtual ~type_identity() {}
size_t byte_size() { return size; }
virtual size_t byte_size() { return size; }
virtual identity_type type() = 0;
@ -372,14 +372,14 @@ namespace DFHack
template<class T>
int linear_index(const DFHack::enum_list_attr<T> &lst, T val) {
for (int i = 0; i < lst.size; i++)
for (size_t i = 0; i < lst.size; i++)
if (lst.items[i] == val)
return i;
return -1;
}
inline int linear_index(const DFHack::enum_list_attr<const char*> &lst, const std::string &val) {
for (int i = 0; i < lst.size; i++)
for (size_t i = 0; i < lst.size; i++)
if (lst.items[i] == val)
return i;
return -1;

@ -289,9 +289,11 @@ namespace df
{}
buffer_container_identity(int size, type_identity *item, enum_identity *ienum = NULL)
: container_identity(item->byte_size()*size, NULL, item, ienum), size(size)
: container_identity(0, NULL, item, ienum), size(size)
{}
size_t byte_size() { return getItemType()->byte_size()*size; }
std::string getFullName(type_identity *item);
int getSize() { return size; }
@ -445,6 +447,7 @@ namespace df
NUMBER_IDENTITY_TRAITS(int64_t);
NUMBER_IDENTITY_TRAITS(uint64_t);
NUMBER_IDENTITY_TRAITS(float);
NUMBER_IDENTITY_TRAITS(double);
template<> struct DFHACK_EXPORT identity_traits<bool> {
static bool_identity identity;

@ -36,6 +36,10 @@ distribution.
namespace DFHack {
class function_identity_base;
namespace Units {
struct NoblePosition;
}
}
namespace DFHack {namespace Lua {
@ -243,14 +247,21 @@ namespace DFHack {namespace Lua {
}
inline void Push(lua_State *state, df::coord &obj) { PushDFObject(state, &obj); }
inline void Push(lua_State *state, df::coord2d &obj) { PushDFObject(state, &obj); }
void Push(lua_State *state, const Units::NoblePosition &pos);
template<class T> inline void Push(lua_State *state, T *ptr) {
PushDFObject(state, ptr);
}
template<class T>
void PushVector(lua_State *state, const T &pvec)
void PushVector(lua_State *state, const T &pvec, bool addn = false)
{
lua_createtable(state,pvec.size(),0);
lua_createtable(state,pvec.size(), addn?1:0);
if (addn)
{
lua_pushinteger(state, pvec.size());
lua_setfield(state, -2, "n");
}
for (size_t i = 0; i < pvec.size(); i++)
{
@ -267,6 +278,26 @@ namespace DFHack {namespace Lua {
DFHACK_EXPORT void MakeEvent(lua_State *state, void *key);
DFHACK_EXPORT void InvokeEvent(color_ostream &out, lua_State *state, void *key, int num_args);
class StackUnwinder {
lua_State *state;
int top;
public:
StackUnwinder(lua_State *state, int bias = 0) : state(state), top(0) {
if (state) top = lua_gettop(state) - bias;
}
~StackUnwinder() {
if (state) lua_settop(state, top);
}
operator int () { return top; }
int operator+ (int v) { return top + v; }
int operator- (int v) { return top + v; }
int operator[] (int v) { return top + v; }
StackUnwinder &operator += (int v) { top += v; return *this; }
StackUnwinder &operator -= (int v) { top += v; return *this; }
StackUnwinder &operator ++ () { top++; return *this; }
StackUnwinder &operator -- () { top--; return *this; }
};
/**
* Namespace for the common lua interpreter state.
* All accesses must be done under CoreSuspender.

@ -73,7 +73,7 @@ namespace DFHack
*/
template<class T>
void flagarray_to_ints(RepeatedField<google::protobuf::int32> *pf, const BitArray<T> &val) {
for (int i = 0; i < val.size*8; i++)
for (size_t i = 0; i < val.size*8; i++)
if (val.is_set(T(i)))
pf->Add(i);
}

@ -1,26 +1,21 @@
inline bool getassignment( const df::coord2d &xy )
{
return getassignment(xy.x,xy.y);
return tile_bitmask.getassignment(xy);
}
inline bool getassignment( int x, int y )
{
return (tile_bitmask[y] & (1 << x));
return tile_bitmask.getassignment(x,y);
}
inline void setassignment( const df::coord2d &xy, bool bit )
{
return setassignment(xy.x,xy.y, bit);
return tile_bitmask.setassignment(xy, bit);
}
inline void setassignment( int x, int y, bool bit )
{
if(bit)
tile_bitmask[y] |= (1 << x);
else
tile_bitmask[y] &= ~(1 << x);
return tile_bitmask.setassignment(x, y, bit);
}
bool has_assignments()
{
for (int i = 0; i < 16; i++)
if (tile_bitmask[i])
return true;
return false;
return tile_bitmask.has_assignments();
}

@ -1,26 +1,20 @@
inline bool getassignment( const df::coord2d &xy )
{
return getassignment(xy.x,xy.y);
return tile_bitmask.getassignment(xy);
}
inline bool getassignment( int x, int y )
{
return (tile_bitmask[y] & (1 << x));
return tile_bitmask.getassignment(x,y);
}
inline void setassignment( const df::coord2d &xy, bool bit )
{
return setassignment(xy.x,xy.y, bit);
return tile_bitmask.setassignment(xy, bit);
}
inline void setassignment( int x, int y, bool bit )
{
if(bit)
tile_bitmask[y] |= (1 << x);
else
tile_bitmask[y] &= ~(1 << x);
return tile_bitmask.setassignment(x, y, bit);
}
bool has_assignments()
{
for (int i = 0; i < 16; i++)
if (tile_bitmask[i])
return true;
return false;
return tile_bitmask.has_assignments();
}

@ -0,0 +1,38 @@
inline uint16_t &operator[] (int y)
{
return bits[y];
}
void clear()
{
memset(bits,0,sizeof(bits));
}
void set_all()
{
memset(bits,0xFF,sizeof(bits));
}
inline bool getassignment( const df::coord2d &xy )
{
return getassignment(xy.x,xy.y);
}
inline bool getassignment( int x, int y )
{
return (bits[y] & (1 << x));
}
inline void setassignment( const df::coord2d &xy, bool bit )
{
return setassignment(xy.x,xy.y, bit);
}
inline void setassignment( int x, int y, bool bit )
{
if(bit)
bits[y] |= (1 << x);
else
bits[y] &= ~(1 << x);
}
bool has_assignments()
{
for (int i = 0; i < 16; i++)
if (bits[i])
return true;
return false;
}

@ -0,0 +1,78 @@
/*
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 "DataDefs.h"
#include "modules/Maps.h"
#include <vector>
/**
* \defgroup grp_burrows Burrows module and its types
* @ingroup grp_modules
*/
namespace df
{
struct unit;
struct burrow;
struct block_burrow;
}
namespace DFHack
{
namespace Burrows
{
DFHACK_EXPORT df::burrow *findByName(std::string name);
// Units
DFHACK_EXPORT void clearUnits(df::burrow *burrow);
DFHACK_EXPORT bool isAssignedUnit(df::burrow *burrow, df::unit *unit);
DFHACK_EXPORT void setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable);
// Tiles
DFHACK_EXPORT void clearTiles(df::burrow *burrow);
DFHACK_EXPORT void listBlocks(std::vector<df::map_block*> *pvec, df::burrow *burrow);
DFHACK_EXPORT bool isAssignedBlockTile(df::burrow *burrow, df::map_block *block, df::coord2d tile);
DFHACK_EXPORT bool setAssignedBlockTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable);
inline bool isAssignedTile(df::burrow *burrow, df::coord tile) {
return isAssignedBlockTile(burrow, Maps::getTileBlock(tile), tile);
}
inline bool setAssignedTile(df::burrow *burrow, df::coord tile, bool enable) {
return setAssignedBlockTile(burrow, Maps::getTileBlock(tile), tile, enable);
}
DFHACK_EXPORT df::block_burrow *getBlockMask(df::burrow *burrow, df::map_block *block, bool create = false);
DFHACK_EXPORT bool deleteBlockMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask);
inline bool deleteBlockMask(df::burrow *burrow, df::map_block *block) {
return deleteBlockMask(burrow, block, getBlockMask(burrow, block));
}
}
}

@ -31,12 +31,17 @@ distribution.
#include <stdint.h>
#include <cstring>
#include "df/map_block.h"
#include "df/tile_bitmask.h"
#include "df/block_square_event_mineralst.h"
#include "df/construction.h"
#include "df/item.h"
using namespace DFHack;
namespace df {
struct world_region_details;
}
namespace MapExtras
{
@ -50,6 +55,38 @@ inline bool is_valid_tile_coord(df::coord2d p) {
return (p.x & ~15) == 0 && (p.y & ~15) == 0;
}
class Block;
class BlockInfo
{
Block *mblock;
MapCache *parent;
df::map_block *block;
public:
t_blockmaterials veinmats;
t_blockmaterials basemats;
t_blockmaterials grass;
std::map<df::coord,df::plant*> plants;
df::feature_init *global_feature;
df::feature_init *local_feature;
BlockInfo()
: mblock(NULL), parent(NULL), block(NULL),
global_feature(NULL), local_feature(NULL) {}
void prepare(Block *mblock);
t_matpair getBaseMaterial(df::tiletype tt, df::coord2d pos);
static void SquashVeins(df::map_block *mb, t_blockmaterials & materials);
static void SquashFrozenLiquids (df::map_block *mb, tiletypes40d & frozen);
static void SquashRocks (df::map_block *mb, t_blockmaterials & materials,
std::vector< std::vector <int16_t> > * layerassign);
static void SquashGrass(df::map_block *mb, t_blockmaterials &materials);
};
class DFHACK_EXPORT Block
{
public:
@ -62,39 +99,81 @@ public:
//Arbitrary tag field for flood fills etc.
int16_t &tag(df::coord2d p) {
if (!tags) init_tags();
return index_tile<int16_t&>(tags, p);
}
// Base layer
df::tiletype baseTiletypeAt(df::coord2d p)
{
if (!tiles) init_tiles();
return index_tile<df::tiletype>(tiles->base_tiles,p);
}
t_matpair baseMaterialAt(df::coord2d p)
{
if (!basemats) init_tiles(true);
return t_matpair(
index_tile<int16_t>(basemats->mattype,p),
index_tile<int16_t>(basemats->matindex,p)
);
}
bool isVeinAt(df::coord2d p)
{
using namespace df::enums::tiletype_material;
auto tm = tileMaterial(baseTiletypeAt(p));
return tm == MINERAL;
}
bool isLayerAt(df::coord2d p)
{
using namespace df::enums::tiletype_material;
auto tm = tileMaterial(baseTiletypeAt(p));
return tm == STONE || tm == SOIL;
}
int16_t veinMaterialAt(df::coord2d p)
{
return index_tile<int16_t>(veinmats,p);
return isVeinAt(p) ? baseMaterialAt(p).mat_index : -1;
}
int16_t baseMaterialAt(df::coord2d p)
int16_t layerMaterialAt(df::coord2d p)
{
return index_tile<int16_t>(basemats,p);
if (!basemats) init_tiles(true);
return index_tile<int16_t>(basemats->layermat,p);
}
df::tiletype BaseTileTypeAt(df::coord2d p)
// Static layer (base + constructions)
df::tiletype staticTiletypeAt(df::coord2d p)
{
auto tt = index_tile<df::tiletype>(contiles,p);
if (tt != tiletype::Void) return tt;
tt = index_tile<df::tiletype>(icetiles,p);
if (tt != tiletype::Void) return tt;
return index_tile<df::tiletype>(rawtiles,p);
if (!tiles) init_tiles();
if (tiles->con_info)
return index_tile<df::tiletype>(tiles->con_info->tiles,p);
return baseTiletypeAt(p);
}
df::tiletype TileTypeAt(df::coord2d p)
t_matpair staticMaterialAt(df::coord2d p)
{
return index_tile<df::tiletype>(rawtiles,p);
if (!basemats) init_tiles(true);
if (tiles->con_info)
return t_matpair(
index_tile<int16_t>(tiles->con_info->mattype,p),
index_tile<int16_t>(tiles->con_info->matindex,p)
);
return baseMaterialAt(p);
}
bool setTiletypeAt(df::coord2d p, df::tiletype tiletype)
bool hasConstructionAt(df::coord2d p)
{
if(!valid) return false;
dirty_tiletypes = true;
//printf("setting block %d/%d/%d , %d %d\n",x,y,z, p.x, p.y);
index_tile<df::tiletype&>(rawtiles,p) = tiletype;
return true;
if (!tiles) init_tiles();
return tiles->con_info &&
tiles->con_info->constructed.getassignment(p);
}
df::tiletype tiletypeAt(df::coord2d p)
{
if (!block) return tiletype::Void;
if (tiles)
return index_tile<df::tiletype>(tiles->raw_tiles,p);
return index_tile<df::tiletype>(block->tiletype,p);
}
bool setTiletypeAt(df::coord2d, df::tiletype tt, bool force = false);
uint16_t temperature1At(df::coord2d p)
{
return index_tile<uint16_t>(temp1,p);
@ -179,29 +258,32 @@ public:
bool is_valid() { return valid; }
df::map_block *getRaw() { return block; }
MapCache *getParent() { return parent; }
private:
friend class MapCache;
friend class BlockInfo;
MapCache *parent;
df::map_block *block;
static void SquashVeins(df::map_block *mb, t_blockmaterials & materials);
static void SquashFrozenLiquids (df::map_block *mb, tiletypes40d & frozen);
static void SquashConstructions (df::map_block *mb, tiletypes40d & constructions);
static void SquashRocks (df::map_block *mb, t_blockmaterials & materials,
std::vector< std::vector <int16_t> > * layerassign);
int biomeIndexAt(df::coord2d p);
bool valid;
bool dirty_designations:1;
bool dirty_tiletypes:1;
bool dirty_tiles:1;
bool dirty_temperatures:1;
bool dirty_blockflags:1;
bool dirty_occupancies:1;
DFCoord bcoord;
int16_t tags[16][16];
// Custom tags for floodfill
typedef int16_t T_tags[16];
T_tags *tags;
void init_tags();
// On-ground item count info
typedef int T_item_counts[16];
T_item_counts *item_counts;
void init_item_counts();
@ -209,30 +291,53 @@ private:
bool addItemOnGround(df::item *item);
bool removeItemOnGround(df::item *item);
tiletypes40d rawtiles;
struct ConInfo {
df::tile_bitmask constructed;
df::tiletype tiles[16][16];
t_blockmaterials mattype;
t_blockmaterials matindex;
};
struct TileInfo {
df::tile_bitmask frozen;
df::tile_bitmask dirty_raw;
df::tiletype raw_tiles[16][16];
ConInfo *con_info;
df::tile_bitmask dirty_base;
df::tiletype base_tiles[16][16];
TileInfo();
~TileInfo();
void init_coninfo();
};
struct BasematInfo {
df::tile_bitmask dirty;
t_blockmaterials mattype;
t_blockmaterials matindex;
t_blockmaterials layermat;
BasematInfo();
};
TileInfo *tiles;
BasematInfo *basemats;
void init_tiles(bool basemat = false);
void ParseTiles(TileInfo *tiles);
void ParseBasemats(TileInfo *tiles, BasematInfo *bmats);
designations40d designation;
occupancies40d occupancy;
t_blockflags blockflags;
t_blockmaterials veinmats;
t_blockmaterials basemats;
t_temperatures temp1;
t_temperatures temp2;
tiletypes40d contiles; // what's underneath constructions
tiletypes40d icetiles; // what's underneath ice
};
class DFHACK_EXPORT MapCache
{
public:
MapCache()
{
valid = 0;
Maps::getSize(x_bmax, y_bmax, z_max);
x_tmax = x_bmax*16; y_tmax = y_bmax*16;
validgeo = Maps::ReadGeology(&layer_mats, &geoidx);
valid = true;
};
MapCache();
~MapCache()
{
trash();
@ -251,19 +356,60 @@ class DFHACK_EXPORT MapCache
df::tiletype baseTiletypeAt (DFCoord tilecoord)
{
Block * b= BlockAtTile(tilecoord);
return b ? b->BaseTileTypeAt(tilecoord) : tiletype::Void;
Block *b = BlockAtTile(tilecoord);
return b ? b->baseTiletypeAt(tilecoord) : tiletype::Void;
}
t_matpair baseMaterialAt (DFCoord tilecoord)
{
Block *b = BlockAtTile(tilecoord);
return b ? b->baseMaterialAt(tilecoord) : t_matpair();
}
int16_t veinMaterialAt (DFCoord tilecoord)
{
Block *b = BlockAtTile(tilecoord);
return b ? b->veinMaterialAt(tilecoord) : -1;
}
int16_t layerMaterialAt (DFCoord tilecoord)
{
Block *b = BlockAtTile(tilecoord);
return b ? b->layerMaterialAt(tilecoord) : -1;
}
bool isVeinAt (DFCoord tilecoord)
{
Block *b = BlockAtTile(tilecoord);
return b && b->isVeinAt(tilecoord);
}
bool isLayerAt (DFCoord tilecoord)
{
Block *b = BlockAtTile(tilecoord);
return b && b->isLayerAt(tilecoord);
}
df::tiletype staticTiletypeAt (DFCoord tilecoord)
{
Block *b = BlockAtTile(tilecoord);
return b ? b->staticTiletypeAt(tilecoord) : tiletype::Void;
}
t_matpair staticMaterialAt (DFCoord tilecoord)
{
Block *b = BlockAtTile(tilecoord);
return b ? b->staticMaterialAt(tilecoord) : t_matpair();
}
bool hasConstructionAt (DFCoord tilecoord)
{
Block *b = BlockAtTile(tilecoord);
return b && b->hasConstructionAt(tilecoord);
}
df::tiletype tiletypeAt (DFCoord tilecoord)
{
Block * b= BlockAtTile(tilecoord);
return b ? b->TileTypeAt(tilecoord) : tiletype::Void;
Block *b = BlockAtTile(tilecoord);
return b ? b->tiletypeAt(tilecoord) : tiletype::Void;
}
bool setTiletypeAt(DFCoord tilecoord, df::tiletype tiletype)
bool setTiletypeAt (DFCoord tilecoord, df::tiletype tt, bool force = false)
{
if (Block * b= BlockAtTile(tilecoord))
return b->setTiletypeAt(tilecoord, tiletype);
return false;
Block *b = BlockAtTile(tilecoord);
return b && b->setTiletypeAt(tilecoord, tt, force);
}
uint16_t temperature1At (DFCoord tilecoord)
@ -290,17 +436,6 @@ class DFHACK_EXPORT MapCache
return false;
}
int16_t veinMaterialAt (DFCoord tilecoord)
{
Block * b= BlockAtTile(tilecoord);
return b ? b->veinMaterialAt(tilecoord) : -1;
}
int16_t baseMaterialAt (DFCoord tilecoord)
{
Block * b= BlockAtTile(tilecoord);
return b ? b->baseMaterialAt(tilecoord) : -1;
}
int16_t tagAt(DFCoord tilecoord)
{
Block * b= BlockAtTile(tilecoord);
@ -311,6 +446,7 @@ class DFHACK_EXPORT MapCache
Block * b= BlockAtTile(tilecoord);
if (b) b->tag(tilecoord) = val;
}
void resetTags();
df::tile_designation designationAt (DFCoord tilecoord)
{
@ -378,6 +514,7 @@ class DFHACK_EXPORT MapCache
private:
friend class Block;
friend class BlockInfo;
bool valid;
bool validgeo;
@ -387,7 +524,10 @@ private:
uint32_t y_tmax;
uint32_t z_max;
std::vector<df::coord2d> geoidx;
std::vector<int> default_soil;
std::vector<int> default_stone;
std::vector< std::vector <int16_t> > layer_mats;
std::map<df::coord2d, df::world_region_details*> region_details;
std::map<DFCoord, Block *> blocks;
};
}

@ -256,34 +256,7 @@ extern DFHACK_EXPORT bool SortBlockEvents(df::map_block *block,
/// remove a block event from the block by address
extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, df::block_square_event * which );
/*
* BURROWS
*/
DFHACK_EXPORT df::burrow *findBurrowByName(std::string name);
DFHACK_EXPORT void listBurrowBlocks(std::vector<df::map_block*> *pvec, df::burrow *burrow);
DFHACK_EXPORT void clearBurrowTiles(df::burrow *burrow);
DFHACK_EXPORT df::block_burrow *getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create = false);
DFHACK_EXPORT bool deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask);
inline bool deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block)
{
return deleteBlockBurrowMask(burrow, block, getBlockBurrowMask(burrow, block));
}
DFHACK_EXPORT bool isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile);
DFHACK_EXPORT bool setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable);
inline bool isBurrowTile(df::burrow *burrow, df::coord tile) {
return isBlockBurrowTile(burrow, getTileBlock(tile), tile);
}
inline bool setBurrowTile(df::burrow *burrow, df::coord tile, bool enable) {
return setBlockBurrowTile(burrow, getTileBlock(tile), tile, enable);
}
DFHACK_EXPORT bool canWalkBetween(df::coord pos1, df::coord pos2);
}
}
#endif

@ -60,6 +60,14 @@ namespace df
namespace DFHack
{
struct t_matpair {
int16_t mat_type;
int32_t mat_index;
t_matpair(int16_t type = -1, int32_t index = -1)
: mat_type(type), mat_index(index) {}
};
struct DFHACK_EXPORT MaterialInfo {
static const int NUM_BUILTIN = 19;
static const int GROUP_SIZE = 200;
@ -91,6 +99,7 @@ namespace DFHack
public:
MaterialInfo(int16_t type = -1, int32_t index = -1) { decode(type, index); }
MaterialInfo(const t_matpair &mp) { decode(mp.mat_type, mp.mat_index); }
template<class T> MaterialInfo(T *ptr) { decode(ptr); }
bool isValid() const { return material != NULL; }
@ -107,6 +116,7 @@ namespace DFHack
bool decode(int16_t type, int32_t index = -1);
bool decode(df::item *item);
bool decode(const df::material_vec_ref &vr, int idx);
bool decode(const t_matpair &mp) { return decode(mp.mat_type, mp.mat_index); }
template<class T> bool decode(T *ptr) {
// Assume and exploit a certain naming convention

@ -52,6 +52,8 @@ DFHACK_EXPORT bool copyName(df::language_name * address, df::language_name * tar
DFHACK_EXPORT void setNickname(df::language_name *name, std::string nick);
DFHACK_EXPORT std::string capitalize(const std::string &str, bool all_words = false);
// translate a name using the loaded dictionaries
DFHACK_EXPORT std::string TranslateName (const df::language_name * name, bool inEnglish = true,
bool onlyLastPart = false);

@ -37,6 +37,10 @@ namespace df
{
struct nemesis_record;
struct burrow;
struct assumed_identity;
struct historical_entity;
struct entity_position_assignment;
struct entity_position;
}
/**
@ -201,6 +205,7 @@ DFHACK_EXPORT df::item *getContainer(df::unit *unit);
DFHACK_EXPORT void setNickname(df::unit *unit, std::string nick);
DFHACK_EXPORT df::language_name *getVisibleName(df::unit *unit);
DFHACK_EXPORT df::assumed_identity *getIdentity(df::unit *unit);
DFHACK_EXPORT df::nemesis_record *getNemesis(df::unit *unit);
DFHACK_EXPORT bool isDead(df::unit *unit);
@ -209,11 +214,18 @@ DFHACK_EXPORT bool isSane(df::unit *unit);
DFHACK_EXPORT bool isCitizen(df::unit *unit);
DFHACK_EXPORT bool isDwarf(df::unit *unit);
DFHACK_EXPORT void clearBurrowMembers(df::burrow *burrow);
DFHACK_EXPORT double getAge(df::unit *unit, bool true_age = false);
DFHACK_EXPORT bool isInBurrow(df::unit *unit, df::burrow *burrow);
DFHACK_EXPORT void setInBurrow(df::unit *unit, df::burrow *burrow, bool enable);
struct NoblePosition {
df::historical_entity *entity;
df::entity_position_assignment *assignment;
df::entity_position *position;
};
DFHACK_EXPORT bool getNoblePositions(std::vector<NoblePosition> *pvec, df::unit *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);
}
}
#endif

@ -117,11 +117,11 @@ namespace Windows
for ( auto iter = str.begin(); iter != str.end(); iter++)
{
auto elem = *iter;
if(cursor_y >= height)
if(cursor_y >= (int)height)
break;
if(wrap)
{
if(cursor_x >= width)
if(cursor_x >= (int)width)
cursor_x = wrap_column;
}
df_screentile & tile = buffer[cursor_x * height + cursor_y];
@ -224,12 +224,12 @@ namespace Windows
virtual void blit_to_parent ()
{
df_tilebuf par = parent->getBuffer();
for(int xi = 0; xi < width; xi++)
for(unsigned xi = 0; xi < width; xi++)
{
for(int yi = 0; yi < height; yi++)
for(unsigned yi = 0; yi < height; yi++)
{
int parx = left + xi;
int pary = top + yi;
unsigned parx = left + xi;
unsigned pary = top + yi;
if(pary >= par.height) continue;
if(parx >= par.width) continue;
par.data[parx * par.height + pary] = buffer[xi * height + yi];

@ -1,6 +1,15 @@
-- Common startup file for all dfhack plugins with lua support
-- The global dfhack table is already created by C++ init code.
-- Setup the global environment.
-- BASE_G is the original lua global environment,
-- preserved as a common denominator for all modules.
-- This file uses it instead of the new default one.
local dfhack = dfhack
local base_env = dfhack.BASE_G
local _ENV = base_env
-- Console color constants
COLOR_RESET = -1
@ -70,7 +79,7 @@ function mkmodule(module,env)
if plugname then
dfhack.open_plugin(pkg,plugname)
end
setmetatable(pkg, { __index = (env or _G) })
setmetatable(pkg, { __index = (env or base_env) })
return pkg
end
@ -116,6 +125,31 @@ function xyz2pos(x,y,z)
end
end
function rawset_default(target,source)
for k,v in pairs(source) do
if rawget(target,k) == nil then
rawset(target,k,v)
end
end
end
function safe_index(obj,idx,...)
if obj == nil or idx == nil then
return nil
end
if type(idx) == 'number' and (idx < 0 or idx >= #obj) then
return nil
end
obj = obj[idx]
if select('#',...) > 0 then
return safe_index(obj,...)
else
return obj
end
end
-- String conversions
function dfhack.event:__tostring()
return "<event>"
end
@ -159,12 +193,14 @@ function dfhack.interpreter(prompt,hfile,env)
end
local prompt_str = "["..(prompt or 'lua').."]# "
local prompt_cont = string.rep(' ',#prompt_str-4)..">>> "
local prompt_env = {}
local t_prompt
local cmdlinelist = {}
local t_prompt = nil
local vcnt = 1
setmetatable(prompt_env, { __index = env or _G })
local cmdlinelist={}
while true do
local cmdline = dfhack.lineedit(t_prompt or prompt_str, hfile)
@ -173,26 +209,29 @@ function dfhack.interpreter(prompt,hfile,env)
elseif cmdline ~= '' then
local pfix = string.sub(cmdline,1,1)
if pfix == '!' or pfix == '=' then
if not t_prompt and (pfix == '!' or pfix == '=') then
cmdline = 'return '..string.sub(cmdline,2)
else
pfix = nil
end
table.insert(cmdlinelist,cmdline)
local code,err = load(table.concat(cmdlinelist,'\n'), '=(interactive)', 't', prompt_env)
table.insert(cmdlinelist,cmdline)
cmdline = table.concat(cmdlinelist,'\n')
local code,err = load(cmdline, '=(interactive)', 't', prompt_env)
if code == nil then
if err:sub(-5)=="<eof>" then
t_prompt="[cont]"
else
dfhack.printerr(err)
cmdlinelist={}
t_prompt=nil
end
if not pfix and err:sub(-5)=="<eof>" then
t_prompt=prompt_cont
else
dfhack.printerr(err)
cmdlinelist={}
t_prompt=nil
end
else
cmdlinelist={}
t_prompt=nil
cmdlinelist={}
t_prompt=nil
local data = table.pack(safecall(code))
if data[1] and data.n > 1 then

@ -0,0 +1,114 @@
local _ENV = mkmodule('utils')
-- Comparator function
function compare(a,b)
if a < b then
return -1
elseif a > b then
return 1
else
return 0
end
end
-- Sort strings; compare empty last
function compare_name(a,b)
if a == '' then
if b == '' then
return 0
else
return 1
end
elseif b == '' then
return -1
else
return compare(a,b)
end
end
--[[
Sort items in data according to ordering.
Each ordering spec is a table with possible fields:
* key = function(value)
Computes comparison key from a data value. Not called on nil.
* key_table = function(data)
Computes a key table from the data table in one go.
* compare = function(a,b)
Comparison function. Defaults to compare above.
Called on non-nil keys; nil sorts last.
* nil_first
If true, nil keys are sorted first instead of last.
* reverse
If true, sort non-nil keys in descending order.
Returns a table of integer indices into data.
--]]
function make_sort_order(data,ordering)
-- Compute sort keys and comparators
local keys = {}
local cmps = {}
local size = data.n or #data
for i=1,#ordering do
local order = ordering[i]
if order.key_table then
keys[i] = order.key_table(data)
elseif order.key then
local kt = {}
local kf = order.key
for j=1,size do
if data[j] == nil then
kt[j] = nil
else
kt[j] = kf(data[j])
end
end
keys[i] = kt
else
keys[i] = data
end
cmps[i] = order.compare or compare
end
-- Make an order table
local index = {}
for i=1,size do
index[i] = i
end
-- Sort the ordering table
table.sort(index, function(ia,ib)
for i=1,#keys do
local ka = keys[i][ia]
local kb = keys[i][ib]
-- Sort nil keys to the end
if ka == nil then
if kb ~= nil then
return ordering[i].nil_first
end
elseif kb == nil then
return not ordering[i].nil_first
else
local cmpv = cmps[i](ka,kb)
if ordering[i].reverse then
cmpv = -cmpv
end
if cmpv < 0 then
return true
elseif cmpv > 0 then
return false
end
end
end
return ia < ib -- this should ensure stable sort
end)
return index
end
return _ENV

@ -0,0 +1,278 @@
/*
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.
*/
#include "Internal.h"
#include <vector>
#include <cstdlib>
using namespace std;
#include "Error.h"
#include "Core.h"
#include "modules/Burrows.h"
#include "modules/Maps.h"
#include "modules/Units.h"
#include "MiscUtils.h"
#include "DataDefs.h"
#include "df/ui.h"
#include "df/burrow.h"
#include "df/block_burrow.h"
#include "df/block_burrow_link.h"
using namespace DFHack;
using namespace df::enums;
using df::global::world;
using df::global::ui;
df::burrow *Burrows::findByName(std::string name)
{
auto &vec = df::burrow::get_vector();
for (size_t i = 0; i < vec.size(); i++)
if (vec[i]->name == name)
return vec[i];
return NULL;
}
void Burrows::clearUnits(df::burrow *burrow)
{
CHECK_NULL_POINTER(burrow);
for (size_t i = 0; i < burrow->units.size(); i++)
{
auto unit = df::unit::find(burrow->units[i]);
if (unit)
erase_from_vector(unit->burrows, burrow->id);
}
burrow->units.clear();
// Sync ui if active
if (ui && ui->main.mode == ui_sidebar_mode::Burrows &&
ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id)
{
auto &sel = ui->burrows.sel_units;
for (size_t i = 0; i < sel.size(); i++)
sel[i] = false;
}
}
bool Burrows::isAssignedUnit(df::burrow *burrow, df::unit *unit)
{
CHECK_NULL_POINTER(unit);
CHECK_NULL_POINTER(burrow);
return binsearch_index(unit->burrows, burrow->id) >= 0;
}
void Burrows::setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable)
{
using df::global::ui;
CHECK_NULL_POINTER(unit);
CHECK_NULL_POINTER(burrow);
if (enable)
{
insert_into_vector(unit->burrows, burrow->id);
insert_into_vector(burrow->units, unit->id);
}
else
{
erase_from_vector(unit->burrows, burrow->id);
erase_from_vector(burrow->units, unit->id);
}
// Sync ui if active
if (ui && ui->main.mode == ui_sidebar_mode::Burrows &&
ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id)
{
int idx = linear_index(ui->burrows.list_units, unit);
if (idx >= 0)
ui->burrows.sel_units[idx] = enable;
}
}
void Burrows::listBlocks(std::vector<df::map_block*> *pvec, df::burrow *burrow)
{
CHECK_NULL_POINTER(burrow);
pvec->clear();
pvec->reserve(burrow->block_x.size());
df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z);
for (size_t i = 0; i < burrow->block_x.size(); i++)
{
df::coord pos(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]);
auto block = Maps::getBlock(pos - base);
if (block)
pvec->push_back(block);
}
}
static void destroyBurrowMask(df::block_burrow *mask)
{
if (!mask) return;
auto link = mask->link;
link->prev->next = link->next;
if (link->next)
link->next->prev = link->prev;
delete link;
delete mask;
}
void Burrows::clearTiles(df::burrow *burrow)
{
CHECK_NULL_POINTER(burrow);
df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z);
for (size_t i = 0; i < burrow->block_x.size(); i++)
{
df::coord pos(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]);
auto block = Maps::getBlock(pos - base);
if (!block)
continue;
destroyBurrowMask(getBlockMask(burrow, block));
}
burrow->block_x.clear();
burrow->block_y.clear();
burrow->block_z.clear();
}
df::block_burrow *Burrows::getBlockMask(df::burrow *burrow, df::map_block *block, bool create)
{
CHECK_NULL_POINTER(burrow);
CHECK_NULL_POINTER(block);
int32_t id = burrow->id;
df::block_burrow_link *prev = &block->block_burrows;
df::block_burrow_link *link = prev->next;
for (; link; prev = link, link = link->next)
if (link->item->id == id)
return link->item;
if (create)
{
link = new df::block_burrow_link;
link->item = new df::block_burrow;
link->item->id = burrow->id;
link->item->tile_bitmask.clear();
link->item->link = link;
link->next = NULL;
link->prev = prev;
prev->next = link;
df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z);
df::coord pos = base + block->map_pos/16;
burrow->block_x.push_back(pos.x);
burrow->block_y.push_back(pos.y);
burrow->block_z.push_back(pos.z);
return link->item;
}
return NULL;
}
bool Burrows::deleteBlockMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask)
{
CHECK_NULL_POINTER(burrow);
CHECK_NULL_POINTER(block);
if (!mask)
return false;
df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z);
df::coord pos = base + block->map_pos/16;
destroyBurrowMask(mask);
for (size_t i = 0; i < burrow->block_x.size(); i++)
{
df::coord cur(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]);
if (cur == pos)
{
vector_erase_at(burrow->block_x, i);
vector_erase_at(burrow->block_y, i);
vector_erase_at(burrow->block_z, i);
break;
}
}
return true;
}
bool Burrows::isAssignedBlockTile(df::burrow *burrow, df::map_block *block, df::coord2d tile)
{
CHECK_NULL_POINTER(burrow);
if (!block) return false;
auto mask = getBlockMask(burrow, block);
return mask ? mask->getassignment(tile & 15) : false;
}
bool Burrows::setAssignedBlockTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable)
{
CHECK_NULL_POINTER(burrow);
if (!block) return false;
auto mask = getBlockMask(burrow, block, enable);
if (mask)
{
mask->setassignment(tile & 15, enable);
if (!enable && !mask->has_assignments())
deleteBlockMask(burrow, block, mask);
}
return true;
}

@ -52,14 +52,14 @@ uint32_t Constructions::getCount()
df::construction * Constructions::getConstruction(const int32_t index)
{
if (index < 0 || index >= getCount())
if (uint32_t(index) >= getCount())
return NULL;
return world->constructions[index];
}
bool Constructions::copyConstruction(const int32_t index, t_construction &out)
{
if (index < 0 || index >= getCount())
if (uint32_t(index) >= getCount())
return false;
out.origin = world->constructions[index];

@ -53,14 +53,14 @@ uint32_t Engravings::getCount()
df::engraving * Engravings::getEngraving(int index)
{
if (index < 0 || index >= getCount())
if (uint32_t(index) >= getCount())
return NULL;
return world->engravings[index];
}
bool Engravings::copyEngraving(const int32_t index, t_engraving &out)
{
if (index < 0 || index >= getCount())
if (uint32_t(index) >= getCount())
return false;
out.origin = world->engravings[index];

@ -50,6 +50,11 @@ using namespace DFHack;
#include "df/viewscreen_joblistst.h"
#include "df/viewscreen_unitlistst.h"
#include "df/viewscreen_itemst.h"
#include "df/viewscreen_layerst.h"
#include "df/viewscreen_layer_workshop_profilest.h"
#include "df/viewscreen_layer_noblelistst.h"
#include "df/viewscreen_layer_overall_healthst.h"
#include "df/viewscreen_petst.h"
#include "df/ui_unit_view_mode.h"
#include "df/ui_sidebar_menus.h"
#include "df/ui_look_list.h"
@ -63,12 +68,18 @@ using namespace DFHack;
#include "df/popup_message.h"
#include "df/interfacest.h"
#include "df/graphic.h"
#include "df/layer_object_listst.h"
using namespace df::enums;
using df::global::gview;
using df::global::init;
using df::global::gps;
static df::layer_object_listst *getLayerList(df::viewscreen_layerst *layer, int idx)
{
return virtual_cast<df::layer_object_listst>(vector_get(layer->layer_objects,idx));
}
// Predefined common guard functions
bool Gui::default_hotkey(df::viewscreen *top)
@ -194,7 +205,7 @@ bool Gui::view_unit_hotkey(df::viewscreen *top)
if (!ui_selected_unit) // allow missing
return false;
return vector_get(world->units.other[0], *ui_selected_unit) != NULL;
return vector_get(world->units.active, *ui_selected_unit) != NULL;
}
bool Gui::unit_inventory_hotkey(df::viewscreen *top)
@ -223,7 +234,7 @@ df::job *Gui::getSelectedWorkshopJob(color_ostream &out, bool quiet)
df::building *selected = world->selected_building;
int idx = *ui_workshop_job_cursor;
if (idx < 0 || idx >= selected->jobs.size())
if (size_t(idx) >= selected->jobs.size())
{
out.printerr("Invalid job cursor index: %d\n", idx);
return NULL;
@ -294,6 +305,62 @@ static df::unit *getAnyUnit(df::viewscreen *top)
return ref ? ref->getUnit() : NULL;
}
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_workshop_profilest, top))
{
if (auto list1 = getLayerList(screen, 0))
return vector_get(screen->workers, list1->cursor);
return NULL;
}
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_noblelistst, top))
{
switch (screen->mode)
{
case df::viewscreen_layer_noblelistst::List:
if (auto list1 = getLayerList(screen, 0))
{
if (auto info = vector_get(screen->info, list1->cursor))
return info->unit;
}
return NULL;
case df::viewscreen_layer_noblelistst::Appoint:
if (auto list2 = getLayerList(screen, 1))
{
if (auto info = vector_get(screen->candidates, list2->cursor))
return info->unit;
}
return NULL;
default:
return NULL;
}
}
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_petst, top))
{
switch (screen->mode)
{
case df::viewscreen_petst::List:
if (!vector_get(screen->is_vermin, screen->cursor))
return (df::unit*)vector_get(screen->animal, screen->cursor);
return NULL;
case df::viewscreen_petst::SelectTrainer:
return vector_get(screen->trainer_unit, screen->trainer_cursor);
default:
return NULL;
}
}
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_overall_healthst, top))
{
if (auto list1 = getLayerList(screen, 0))
return vector_get(screen->unit, list1->cursor);
return NULL;
}
if (!Gui::dwarfmode_hotkey(top))
return NULL;
@ -303,7 +370,7 @@ static df::unit *getAnyUnit(df::viewscreen *top)
if (!ui_selected_unit)
return NULL;
return vector_get(world->units.other[0], *ui_selected_unit);
return vector_get(world->units.active, *ui_selected_unit);
}
case LookAround:
{

@ -536,6 +536,9 @@ df::coord Items::getPosition(df::item *item)
if (auto bld = ref->getBuilding())
return df::coord(bld->centerx, bld->centery, bld->z);
break;
default:
break;
}
}
}

@ -51,6 +51,9 @@ using namespace std;
#include "df/burrow.h"
#include "df/block_burrow.h"
#include "df/block_burrow_link.h"
#include "df/world_region_details.h"
#include "df/builtin_mats.h"
#include "df/block_square_event_grassst.h"
using namespace DFHack;
using namespace df::enums;
@ -158,7 +161,7 @@ df::world_data::T_region_map *Maps::getRegionBiome(df::coord2d rgn_pos)
df::feature_init *Maps::getGlobalInitFeature(int32_t index)
{
auto data = world->world_data;
if (!data)
if (!data || index < 0)
return NULL;
auto rgn = vector_get(data->underground_regions, index);
@ -186,7 +189,7 @@ bool Maps::GetGlobalFeature(t_feature &feature, int32_t index)
df::feature_init *Maps::getLocalInitFeature(df::coord2d rgn_pos, int32_t index)
{
auto data = world->world_data;
if (!data)
if (!data || index < 0)
return NULL;
if (rgn_pos.x < 0 || rgn_pos.x >= data->world_width ||
@ -353,7 +356,7 @@ bool Maps::ReadGeology(vector<vector<int16_t> > *layer_mats, vector<df::coord2d>
int bioRX = world->map.region_x / 16 + ((i % 3) - 1);
int bioRY = world->map.region_y / 16 + ((i / 3) - 1);
df::coord2d rgn_pos(clip_range(bioRX,0,world_width-1),clip_range(bioRX,0,world_height-1));
df::coord2d rgn_pos(clip_range(bioRX,0,world_width-1),clip_range(bioRY,0,world_height-1));
(*geoidx)[i] = rgn_pos;
@ -384,12 +387,26 @@ bool Maps::ReadGeology(vector<vector<int16_t> > *layer_mats, vector<df::coord2d>
return true;
}
bool Maps::canWalkBetween(df::coord pos1, df::coord pos2)
{
auto block1 = getTileBlock(pos1);
auto block2 = getTileBlock(pos2);
if (!block1 || !block2)
return false;
auto tile1 = MapExtras::index_tile<uint16_t>(block1->walkable, pos1);
auto tile2 = MapExtras::index_tile<uint16_t>(block2->walkable, pos2);
return tile1 && tile1 == tile2;
}
#define COPY(a,b) memcpy(&a,&b,sizeof(a))
MapExtras::Block::Block(MapCache *parent, DFCoord _bcoord) : parent(parent)
{
dirty_designations = false;
dirty_tiletypes = false;
dirty_tiles = false;
dirty_temperatures = false;
dirty_blockflags = false;
dirty_occupancies = false;
@ -397,12 +414,12 @@ MapExtras::Block::Block(MapCache *parent, DFCoord _bcoord) : parent(parent)
bcoord = _bcoord;
block = Maps::getBlock(bcoord);
item_counts = NULL;
memset(tags,0,sizeof(tags));
tags = NULL;
tiles = NULL;
basemats = NULL;
if(block)
{
COPY(rawtiles, block->tiletype);
COPY(designation, block->designation);
COPY(occupancy, block->occupancy);
blockflags = block->flags;
@ -410,33 +427,189 @@ MapExtras::Block::Block(MapCache *parent, DFCoord _bcoord) : parent(parent)
COPY(temp1, block->temperature_1);
COPY(temp2, block->temperature_2);
SquashVeins(block,veinmats);
SquashConstructions(block, contiles);
SquashFrozenLiquids(block, icetiles);
if(parent->validgeo)
SquashRocks(block,basemats,&parent->layer_mats);
else
memset(basemats,-1,sizeof(basemats));
valid = true;
}
else
{
blockflags.whole = 0;
memset(rawtiles,0,sizeof(rawtiles));
memset(designation,0,sizeof(designation));
memset(occupancy,0,sizeof(occupancy));
memset(temp1,0,sizeof(temp1));
memset(temp2,0,sizeof(temp2));
memset(veinmats,-1,sizeof(veinmats));
memset(contiles,0,sizeof(contiles));
memset(icetiles,0,sizeof(icetiles));
memset(basemats,-1,sizeof(basemats));
}
}
MapExtras::Block::~Block()
{
delete[] item_counts;
delete[] tags;
delete tiles;
delete basemats;
}
void MapExtras::Block::init_tags()
{
if (!tags)
tags = new T_tags[16];
memset(tags,0,sizeof(T_tags)*16);
}
void MapExtras::Block::init_tiles(bool basemat)
{
if (!tiles)
{
tiles = new TileInfo();
if (block)
ParseTiles(tiles);
}
if (basemat && !basemats)
{
basemats = new BasematInfo();
if (block)
ParseBasemats(tiles, basemats);
}
}
MapExtras::Block::TileInfo::TileInfo()
{
frozen.clear();
dirty_raw.clear();
memset(raw_tiles,0,sizeof(raw_tiles));
con_info = NULL;
dirty_base.clear();
memset(base_tiles,0,sizeof(base_tiles));
}
MapExtras::Block::TileInfo::~TileInfo()
{
delete con_info;
}
void MapExtras::Block::TileInfo::init_coninfo()
{
if (con_info)
return;
con_info = new ConInfo();
con_info->constructed.clear();
COPY(con_info->tiles, base_tiles);
memset(con_info->mattype, -1, sizeof(con_info->mattype));
memset(con_info->matindex, -1, sizeof(con_info->matindex));
}
MapExtras::Block::BasematInfo::BasematInfo()
{
dirty.clear();
memset(mattype,0,sizeof(mattype));
memset(matindex,-1,sizeof(matindex));
memset(layermat,-1,sizeof(layermat));
}
bool MapExtras::Block::setTiletypeAt(df::coord2d pos, df::tiletype tt, bool force)
{
if (!block)
return false;
if (!basemats)
init_tiles(true);
pos = pos & 15;
dirty_tiles = true;
tiles->raw_tiles[pos.x][pos.y] = tt;
tiles->dirty_raw.setassignment(pos, true);
return true;
}
void MapExtras::Block::ParseTiles(TileInfo *tiles)
{
tiletypes40d icetiles;
BlockInfo::SquashFrozenLiquids(block, icetiles);
COPY(tiles->raw_tiles, block->tiletype);
for (int x = 0; x < 16; x++)
{
for (int y = 0; y < 16; y++)
{
using namespace df::enums::tiletype_material;
df::tiletype tt = tiles->raw_tiles[x][y];
df::coord coord = block->map_pos + df::coord(x,y,0);
// Frozen liquid comes topmost
if (tileMaterial(tt) == FROZEN_LIQUID)
{
tiles->frozen.setassignment(x,y,true);
if (icetiles[x][y] != tiletype::Void)
{
tt = icetiles[x][y];
}
}
// The next layer may be construction
bool is_con = false;
if (tileMaterial(tt) == CONSTRUCTION)
{
df::construction *con = df::construction::find(coord);
if (con)
{
if (!tiles->con_info)
tiles->init_coninfo();
is_con = true;
tiles->con_info->constructed.setassignment(x,y,true);
tiles->con_info->tiles[x][y] = tt;
tiles->con_info->mattype[x][y] = con->mat_type;
tiles->con_info->matindex[x][y] = con->mat_index;
tt = con->original_tile;
}
}
// Finally, base material
tiles->base_tiles[x][y] = tt;
// Copy base info back to construction layer
if (tiles->con_info && !is_con)
tiles->con_info->tiles[x][y] = tt;
}
}
}
void MapExtras::Block::ParseBasemats(TileInfo *tiles, BasematInfo *bmats)
{
BlockInfo info;
info.prepare(this);
COPY(bmats->layermat, info.basemats);
for (int x = 0; x < 16; x++)
{
for (int y = 0; y < 16; y++)
{
using namespace df::enums::tiletype_material;
auto tt = tiles->base_tiles[x][y];
auto mat = info.getBaseMaterial(tt, df::coord2d(x,y));
bmats->mattype[x][y] = mat.mat_type;
bmats->matindex[x][y] = mat.mat_index;
// Copy base info back to construction layer
if (tiles->con_info && !tiles->con_info->constructed.getassignment(x,y))
{
tiles->con_info->mattype[x][y] = mat.mat_type;
tiles->con_info->matindex[x][y] = mat.mat_index;
}
}
}
}
bool MapExtras::Block::Write ()
@ -454,10 +627,21 @@ bool MapExtras::Block::Write ()
block->flags.bits.designated = true;
dirty_designations = false;
}
if(dirty_tiletypes)
if(dirty_tiles && tiles)
{
COPY(block->tiletype, rawtiles);
dirty_tiletypes = false;
dirty_tiles = false;
for (int x = 0; x < 16; x++)
{
for (int y = 0; y < 16; y++)
{
if (tiles->dirty_raw.getassignment(x,y))
block->tiletype[x][y] = tiles->raw_tiles[x][y];
}
}
delete tiles; tiles = NULL;
delete basemats; basemats = NULL;
}
if(dirty_temperatures)
{
@ -473,65 +657,187 @@ bool MapExtras::Block::Write ()
return true;
}
void MapExtras::Block::SquashVeins(df::map_block *mb, t_blockmaterials & materials)
void MapExtras::BlockInfo::prepare(Block *mblock)
{
memset(materials,-1,sizeof(materials));
std::vector <df::block_square_event_mineralst *> veins;
Maps::SortBlockEvents(mb,&veins);
for (uint32_t x = 0;x<16;x++) for (uint32_t y = 0; y< 16;y++)
this->mblock = mblock;
block = mblock->getRaw();
parent = mblock->getParent();
SquashVeins(block,veinmats);
SquashGrass(block, grass);
if (parent->validgeo)
SquashRocks(block,basemats,&parent->layer_mats);
else
memset(basemats,-1,sizeof(basemats));
for (size_t i = 0; i < block->plants.size(); i++)
{
auto pp = block->plants[i];
plants[pp->pos] = pp;
}
global_feature = Maps::getGlobalInitFeature(block->global_feature);
local_feature = Maps::getLocalInitFeature(block->region_pos, block->local_feature);
}
t_matpair MapExtras::BlockInfo::getBaseMaterial(df::tiletype tt, df::coord2d pos)
{
using namespace df::enums::tiletype_material;
t_matpair rv(0,-1);
int x = pos.x, y = pos.y;
switch (tileMaterial(tt)) {
case NONE:
case AIR:
rv.mat_type = -1;
break;
case DRIFTWOOD:
case SOIL:
{
rv.mat_index = basemats[x][y];
if (auto raw = df::inorganic_raw::find(rv.mat_index))
{
if (raw->flags.is_set(inorganic_flags::SOIL_ANY))
break;
int biome = mblock->biomeIndexAt(pos);
int idx = vector_get(parent->default_soil, biome, -1);
if (idx >= 0)
rv.mat_index = idx;
}
break;
}
case STONE:
{
df::tiletype tt = mb->tiletype[x][y];
if (tileMaterial(tt) == tiletype_material::MINERAL)
rv.mat_index = basemats[x][y];
if (auto raw = df::inorganic_raw::find(rv.mat_index))
{
for (size_t i = 0; i < veins.size(); i++)
if (!raw->flags.is_set(inorganic_flags::SOIL_ANY))
break;
int biome = mblock->biomeIndexAt(pos);
int idx = vector_get(parent->default_stone, biome, -1);
if (idx >= 0)
rv.mat_index = idx;
}
break;
}
case MINERAL:
rv.mat_index = veinmats[x][y];
break;
case LAVA_STONE:
if (auto details = parent->region_details[mblock->biomeRegionAt(pos)])
rv.mat_index = details->lava_stone;
break;
case PLANT:
rv.mat_type = MaterialInfo::PLANT_BASE;
if (auto plant = plants[block->map_pos + df::coord(x,y,0)])
{
if (auto raw = df::plant_raw::find(plant->material))
{
if (veins[i]->getassignment(x,y))
materials[x][y] = veins[i]->inorganic_mat;
rv.mat_type = raw->material_defs.type_basic_mat;
rv.mat_index = raw->material_defs.idx_basic_mat;
}
}
break;
case GRASS_LIGHT:
case GRASS_DARK:
case GRASS_DRY:
case GRASS_DEAD:
rv.mat_type = MaterialInfo::PLANT_BASE;
if (auto raw = df::plant_raw::find(grass[x][y]))
{
rv.mat_type = raw->material_defs.type_basic_mat;
rv.mat_index = raw->material_defs.idx_basic_mat;
}
break;
case FEATURE:
{
auto dsgn = block->designation[x][y];
if (dsgn.bits.feature_local && local_feature)
local_feature->getMaterial(&rv.mat_type, &rv.mat_index);
else if (dsgn.bits.feature_global && global_feature)
global_feature->getMaterial(&rv.mat_type, &rv.mat_index);
break;
}
case CONSTRUCTION: // just a fallback
case MAGMA:
case HFS:
// use generic 'rock'
break;
case FROZEN_LIQUID:
rv.mat_type = builtin_mats::WATER;
break;
case POOL:
case BROOK:
case RIVER:
rv.mat_index = basemats[x][y];
break;
case ASHES:
case FIRE:
case CAMPFIRE:
rv.mat_type = builtin_mats::ASH;
break;
}
return rv;
}
void MapExtras::Block::SquashFrozenLiquids(df::map_block *mb, tiletypes40d & frozen)
void MapExtras::BlockInfo::SquashVeins(df::map_block *mb, t_blockmaterials & materials)
{
std::vector <df::block_square_event_frozen_liquidst *> ices;
Maps::SortBlockEvents(mb,NULL,&ices);
for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++)
std::vector <df::block_square_event_mineralst *> veins;
Maps::SortBlockEvents(mb,&veins);
memset(materials,-1,sizeof(materials));
for (uint32_t x = 0;x<16;x++) for (uint32_t y = 0; y< 16;y++)
{
df::tiletype tt = mb->tiletype[x][y];
frozen[x][y] = tiletype::Void;
if (tileMaterial(tt) == tiletype_material::FROZEN_LIQUID)
for (size_t i = 0; i < veins.size(); i++)
{
for (size_t i = 0; i < ices.size(); i++)
{
df::tiletype tt2 = ices[i]->tiles[x][y];
if (tt2 != tiletype::Void)
{
frozen[x][y] = tt2;
break;
}
}
if (veins[i]->getassignment(x,y))
materials[x][y] = veins[i]->inorganic_mat;
}
}
}
void MapExtras::Block::SquashConstructions (df::map_block *mb, tiletypes40d & constructions)
void MapExtras::BlockInfo::SquashFrozenLiquids(df::map_block *mb, tiletypes40d & frozen)
{
std::vector <df::block_square_event_frozen_liquidst *> ices;
Maps::SortBlockEvents(mb,NULL,&ices);
memset(frozen,0,sizeof(frozen));
for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++)
{
df::tiletype tt = mb->tiletype[x][y];
constructions[x][y] = tiletype::Void;
if (tileMaterial(tt) == tiletype_material::CONSTRUCTION)
for (size_t i = 0; i < ices.size(); i++)
{
DFCoord coord = mb->map_pos + df::coord(x,y,0);
df::construction *con = df::construction::find(coord);
if (con)
constructions[x][y] = con->original_tile;
df::tiletype tt2 = ices[i]->tiles[x][y];
if (tt2 != tiletype::Void)
{
frozen[x][y] = tt2;
break;
}
}
}
}
void MapExtras::Block::SquashRocks (df::map_block *mb, t_blockmaterials & materials,
void MapExtras::BlockInfo::SquashRocks (df::map_block *mb, t_blockmaterials & materials,
std::vector< std::vector <int16_t> > * layerassign)
{
// get the layer materials
@ -547,18 +853,49 @@ void MapExtras::Block::SquashRocks (df::map_block *mb, t_blockmaterials & materi
}
}
df::coord2d MapExtras::Block::biomeRegionAt(df::coord2d p)
void MapExtras::BlockInfo::SquashGrass(df::map_block *mb, t_blockmaterials &materials)
{
std::vector<df::block_square_event_grassst*> grasses;
Maps::SortBlockEvents(mb, NULL, NULL, NULL, &grasses);
memset(materials,-1,sizeof(materials));
for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++)
{
int amount = 0;
for (size_t i = 0; i < grasses.size(); i++)
{
if (grasses[i]->amount[x][y] >= amount)
{
amount = grasses[i]->amount[x][y];
materials[x][y] = grasses[i]->plant_index;
}
}
}
}
int MapExtras::Block::biomeIndexAt(df::coord2d p)
{
if (!block)
return df::coord2d(-30000,-30000);
return -1;
auto des = index_tile<df::tile_designation>(designation,p);
uint8_t idx = des.bits.biome;
if (idx >= 9)
return block->region_pos;
return -1;
idx = block->region_offset[idx];
if (idx >= parent->geoidx.size())
return -1;
return idx;
}
df::coord2d MapExtras::Block::biomeRegionAt(df::coord2d p)
{
if (!block)
return df::coord2d(-30000,-30000);
int idx = biomeIndexAt(p);
if (idx < 0)
return block->region_pos;
return parent->geoidx[idx];
}
@ -662,191 +999,74 @@ bool MapExtras::Block::removeItemOnGround(df::item *item)
return true;
}
MapExtras::Block *MapExtras::MapCache::BlockAt(DFCoord blockcoord)
MapExtras::MapCache::MapCache()
{
if(!valid)
return 0;
std::map <DFCoord, Block*>::iterator iter = blocks.find(blockcoord);
if(iter != blocks.end())
{
return (*iter).second;
}
else
valid = 0;
Maps::getSize(x_bmax, y_bmax, z_max);
x_tmax = x_bmax*16; y_tmax = y_bmax*16;
validgeo = Maps::ReadGeology(&layer_mats, &geoidx);
valid = true;
if (auto data = df::global::world->world_data)
{
if(blockcoord.x >= 0 && blockcoord.x < x_bmax &&
blockcoord.y >= 0 && blockcoord.y < y_bmax &&
blockcoord.z >= 0 && blockcoord.z < z_max)
for (size_t i = 0; i < data->region_details.size(); i++)
{
Block * nblo = new Block(this, blockcoord);
blocks[blockcoord] = nblo;
return nblo;
auto info = data->region_details[i];
region_details[info->pos] = info;
}
return 0;
}
}
df::burrow *Maps::findBurrowByName(std::string name)
{
auto &vec = df::burrow::get_vector();
for (size_t i = 0; i < vec.size(); i++)
if (vec[i]->name == name)
return vec[i];
return NULL;
}
void Maps::listBurrowBlocks(std::vector<df::map_block*> *pvec, df::burrow *burrow)
{
CHECK_NULL_POINTER(burrow);
pvec->clear();
pvec->reserve(burrow->block_x.size());
df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z);
for (size_t i = 0; i < burrow->block_x.size(); i++)
{
df::coord pos(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]);
auto block = getBlock(pos - base);
if (block)
pvec->push_back(block);
}
}
static void destroyBurrowMask(df::block_burrow *mask)
{
if (!mask) return;
auto link = mask->link;
link->prev->next = link->next;
if (link->next)
link->next->prev = link->prev;
delete link;
delete mask;
}
void Maps::clearBurrowTiles(df::burrow *burrow)
{
CHECK_NULL_POINTER(burrow);
df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z);
default_soil.resize(layer_mats.size());
default_stone.resize(layer_mats.size());
for (size_t i = 0; i < burrow->block_x.size(); i++)
for (size_t i = 0; i < layer_mats.size(); i++)
{
df::coord pos(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]);
default_soil[i] = -1;
default_stone[i] = -1;
auto block = getBlock(pos - base);
if (!block)
continue;
destroyBurrowMask(getBlockBurrowMask(burrow, block));
for (size_t j = 0; j < layer_mats[i].size(); j++)
{
auto raw = df::inorganic_raw::find(layer_mats[i][j]);
if (!raw)
continue;
bool is_soil = raw->flags.is_set(inorganic_flags::SOIL_ANY);
if (is_soil)
default_soil[i] = layer_mats[i][j];
else if (default_stone[i] == -1)
default_stone[i] = layer_mats[i][j];
}
}
burrow->block_x.clear();
burrow->block_y.clear();
burrow->block_z.clear();
}
df::block_burrow *Maps::getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create)
MapExtras::Block *MapExtras::MapCache::BlockAt(DFCoord blockcoord)
{
CHECK_NULL_POINTER(burrow);
CHECK_NULL_POINTER(block);
int32_t id = burrow->id;
df::block_burrow_link *prev = &block->block_burrows;
df::block_burrow_link *link = prev->next;
for (; link; prev = link, link = link->next)
if (link->item->id == id)
return link->item;
if (create)
if(!valid)
return 0;
std::map <DFCoord, Block*>::iterator iter = blocks.find(blockcoord);
if(iter != blocks.end())
{
link = new df::block_burrow_link;
link->item = new df::block_burrow;
link->item->id = burrow->id;
memset(link->item->tile_bitmask,0,sizeof(link->item->tile_bitmask));
link->item->link = link;
link->next = NULL;
link->prev = prev;
prev->next = link;
df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z);
df::coord pos = base + block->map_pos/16;
burrow->block_x.push_back(pos.x);
burrow->block_y.push_back(pos.y);
burrow->block_z.push_back(pos.z);
return link->item;
return (*iter).second;
}
return NULL;
}
bool Maps::deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask)
{
CHECK_NULL_POINTER(burrow);
CHECK_NULL_POINTER(block);
if (!mask)
return false;
df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z);
df::coord pos = base + block->map_pos/16;
destroyBurrowMask(mask);
for (size_t i = 0; i < burrow->block_x.size(); i++)
else
{
df::coord cur(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]);
if (cur == pos)
if(unsigned(blockcoord.x) < x_bmax &&
unsigned(blockcoord.y) < y_bmax &&
unsigned(blockcoord.z) < z_max)
{
vector_erase_at(burrow->block_x, i);
vector_erase_at(burrow->block_y, i);
vector_erase_at(burrow->block_z, i);
break;
Block * nblo = new Block(this, blockcoord);
blocks[blockcoord] = nblo;
return nblo;
}
return 0;
}
return true;
}
bool Maps::isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile)
void MapExtras::MapCache::resetTags()
{
CHECK_NULL_POINTER(burrow);
if (!block) return false;
auto mask = getBlockBurrowMask(burrow, block);
return mask ? mask->getassignment(tile & 15) : false;
}
bool Maps::setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable)
{
CHECK_NULL_POINTER(burrow);
if (!block) return false;
auto mask = getBlockBurrowMask(burrow, block, enable);
if (mask)
for (auto it = blocks.begin(); it != blocks.end(); ++it)
{
mask->setassignment(tile & 15, enable);
if (!enable && !mask->has_assignments())
deleteBlockBurrowMask(burrow, block, mask);
delete[] it->second->tags;
it->second->tags = NULL;
}
return true;
}

@ -80,7 +80,7 @@ bool MaterialInfo::decode(df::item *item)
bool MaterialInfo::decode(const df::material_vec_ref &vr, int idx)
{
if (idx < 0 || idx >= vr.mat_type.size() || idx >= vr.mat_index.size())
if (size_t(idx) >= vr.mat_type.size() || size_t(idx) >= vr.mat_index.size())
return decode(-1);
else
return decode(vr.mat_type[idx], vr.mat_index[idx]);
@ -103,7 +103,7 @@ bool MaterialInfo::decode(int16_t type, int32_t index)
df::world_raws &raws = world->raws;
if (type >= sizeof(raws.mat_table.builtin)/sizeof(void*))
if (size_t(type) >= sizeof(raws.mat_table.builtin)/sizeof(void*))
return false;
if (index < 0)
@ -127,7 +127,7 @@ bool MaterialInfo::decode(int16_t type, int32_t index)
mode = Creature;
subtype = type-CREATURE_BASE;
creature = df::creature_raw::find(index);
if (!creature || subtype >= creature->material.size())
if (!creature || size_t(subtype) >= creature->material.size())
return false;
material = creature->material[subtype];
}
@ -139,7 +139,7 @@ bool MaterialInfo::decode(int16_t type, int32_t index)
if (!figure)
return false;
creature = df::creature_raw::find(figure->race);
if (!creature || subtype >= creature->material.size())
if (!creature || size_t(subtype) >= creature->material.size())
return false;
material = creature->material[subtype];
}
@ -148,7 +148,7 @@ bool MaterialInfo::decode(int16_t type, int32_t index)
mode = Plant;
subtype = type-PLANT_BASE;
plant = df::plant_raw::find(index);
if (!plant || subtype >= plant->material.size())
if (!plant || size_t(subtype) >= plant->material.size())
return false;
material = plant->material[subtype];
}

@ -81,15 +81,32 @@ bool Translation::copyName(df::language_name * source, df::language_name * targe
return true;
}
std::string Translation::capitalize(const std::string &str, bool all_words)
{
string upper = str;
if (!upper.empty())
{
upper[0] = toupper(upper[0]);
if (all_words)
{
for (size_t i = 1; i < upper.size(); i++)
if (isspace(upper[i-1]))
upper[i] = toupper(upper[i]);
}
}
return upper;
}
void addNameWord (string &out, const string &word)
{
if (word.empty())
return;
string upper = word;
upper[0] = toupper(upper[0]);
if (out.length() > 0)
out.append(" ");
out.append(upper);
out.append(Translation::capitalize(word));
}
void Translation::setNickname(df::language_name *name, std::string nick)

@ -55,8 +55,13 @@ using namespace std;
#include "df/historical_entity.h"
#include "df/historical_figure.h"
#include "df/historical_figure_info.h"
#include "df/entity_position.h"
#include "df/entity_position_assignment.h"
#include "df/histfig_entity_link_positionst.h"
#include "df/assumed_identity.h"
#include "df/burrow.h"
#include "df/creature_raw.h"
#include "df/caste_raw.h"
using namespace DFHack;
using namespace df::enums;
@ -78,7 +83,7 @@ df::unit * Units::GetCreature (const int32_t index)
if (!isValid()) return NULL;
// read pointer from vector at position
if(index > world->units.all.size())
if(size_t(index) > world->units.all.size())
return 0;
return world->units.all[index];
}
@ -529,6 +534,23 @@ df::item *Units::getContainer(df::unit *unit)
return NULL;
}
static df::assumed_identity *getFigureIdentity(df::historical_figure *figure)
{
if (figure && figure->info && figure->info->reputation)
return df::assumed_identity::find(figure->info->reputation->cur_identity);
return NULL;
}
df::assumed_identity *Units::getIdentity(df::unit *unit)
{
CHECK_NULL_POINTER(unit);
df::historical_figure *figure = df::historical_figure::find(unit->hist_figure_id);
return getFigureIdentity(figure);
}
void Units::setNickname(df::unit *unit, std::string nick)
{
CHECK_NULL_POINTER(unit);
@ -547,25 +569,19 @@ void Units::setNickname(df::unit *unit, std::string nick)
{
Translation::setNickname(&figure->name, nick);
// v0.34.01: added the vampire's assumed identity
if (figure->info && figure->info->reputation)
if (auto identity = getFigureIdentity(figure))
{
auto identity = df::assumed_identity::find(figure->info->reputation->cur_identity);
auto id_hfig = df::historical_figure::find(identity->histfig_id);
if (identity)
if (id_hfig)
{
auto id_hfig = df::historical_figure::find(identity->histfig_id);
if (id_hfig)
{
// Even DF doesn't do this bit, because it's apparently
// only used for demons masquerading as gods, so you
// can't ever change their nickname in-game.
Translation::setNickname(&id_hfig->name, nick);
}
else
Translation::setNickname(&identity->name, nick);
// Even DF doesn't do this bit, because it's apparently
// only used for demons masquerading as gods, so you
// can't ever change their nickname in-game.
Translation::setNickname(&id_hfig->name, nick);
}
else
Translation::setNickname(&identity->name, nick);
}
}
}
@ -574,25 +590,14 @@ 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)
if (auto identity = getIdentity(unit))
{
// v0.34.01: added the vampire's assumed identity
if (figure->info && figure->info->reputation)
{
auto identity = df::assumed_identity::find(figure->info->reputation->cur_identity);
auto id_hfig = df::historical_figure::find(identity->histfig_id);
if (identity)
{
auto id_hfig = df::historical_figure::find(identity->histfig_id);
if (id_hfig)
return &id_hfig->name;
if (id_hfig)
return &id_hfig->name;
return &identity->name;
}
}
return &identity->name;
}
return &unit->name;
@ -672,65 +677,224 @@ bool DFHack::Units::isDwarf(df::unit *unit)
return unit->race == ui->race_id;
}
void DFHack::Units::clearBurrowMembers(df::burrow *burrow)
double DFHack::Units::getAge(df::unit *unit, bool true_age)
{
CHECK_NULL_POINTER(burrow);
using df::global::cur_year;
using df::global::cur_year_tick;
for (size_t i = 0; i < burrow->units.size(); i++)
{
auto unit = df::unit::find(burrow->units[i]);
CHECK_NULL_POINTER(unit);
if (unit)
erase_from_vector(unit->burrows, burrow->id);
}
if (!cur_year || !cur_year_tick)
return -1;
burrow->units.clear();
double year_ticks = 403200.0;
double birth_time = unit->relations.birth_year + unit->relations.birth_time/year_ticks;
double cur_time = *cur_year + *cur_year_tick / year_ticks;
// Sync ui if active
if (ui && ui->main.mode == ui_sidebar_mode::Burrows &&
ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id)
if (!true_age && unit->relations.curse_year >= 0)
{
auto &sel = ui->burrows.sel_units;
for (size_t i = 0; i < sel.size(); i++)
sel[i] = false;
if (auto identity = getIdentity(unit))
{
if (identity->histfig_id < 0)
birth_time = identity->birth_year + identity->birth_second/year_ticks;
}
}
return cur_time - birth_time;
}
static bool noble_pos_compare(const Units::NoblePosition &a, const Units::NoblePosition &b)
{
if (a.position->precedence < b.position->precedence)
return true;
if (a.position->precedence > b.position->precedence)
return false;
return a.position->id < b.position->id;
}
bool DFHack::Units::isInBurrow(df::unit *unit, df::burrow *burrow)
bool DFHack::Units::getNoblePositions(std::vector<NoblePosition> *pvec, df::unit *unit)
{
CHECK_NULL_POINTER(unit);
CHECK_NULL_POINTER(burrow);
return binsearch_index(unit->burrows, burrow->id) >= 0;
pvec->clear();
auto histfig = df::historical_figure::find(unit->hist_figure_id);
if (!histfig)
return false;
for (size_t i = 0; i < histfig->entity_links.size(); i++)
{
auto link = histfig->entity_links[i];
auto epos = strict_virtual_cast<df::histfig_entity_link_positionst>(link);
if (!epos)
continue;
NoblePosition pos;
pos.entity = df::historical_entity::find(epos->entity_id);
if (!pos.entity)
continue;
pos.assignment = binsearch_in_vector(pos.entity->positions.assignments, epos->assignment_id);
if (!pos.assignment)
continue;
pos.position = binsearch_in_vector(pos.entity->positions.own, pos.assignment->position_id);
if (!pos.position)
continue;
pvec->push_back(pos);
}
if (pvec->empty())
return false;
std::sort(pvec->begin(), pvec->end(), noble_pos_compare);
return true;
}
void DFHack::Units::setInBurrow(df::unit *unit, df::burrow *burrow, bool enable)
std::string DFHack::Units::getProfessionName(df::unit *unit, bool ignore_noble, bool plural)
{
using df::global::ui;
std::string prof = unit->custom_profession;
if (!prof.empty())
return prof;
CHECK_NULL_POINTER(unit);
CHECK_NULL_POINTER(burrow);
std::vector<NoblePosition> np;
if (enable)
if (!ignore_noble && getNoblePositions(&np, unit))
{
insert_into_vector(unit->burrows, burrow->id);
insert_into_vector(burrow->units, unit->id);
switch (unit->sex)
{
case 0:
prof = np[0].position->name_female[plural ? 1 : 0];
break;
case 1:
prof = np[0].position->name_male[plural ? 1 : 0];
break;
default:
break;
}
if (prof.empty())
prof = np[0].position->name[plural ? 1 : 0];
if (!prof.empty())
return prof;
}
else
return getCasteProfessionName(unit->race, unit->caste, unit->profession, plural);
}
std::string DFHack::Units::getCasteProfessionName(int race, int casteid, df::profession pid, bool plural)
{
std::string prof, race_prefix;
if (pid < 0 || !is_valid_enum_item(pid))
return "";
bool use_race_prefix = (race >= 0 && race != df::global::ui->race_id);
if (auto creature = df::creature_raw::find(race))
{
if (auto caste = vector_get(creature->caste, casteid))
{
race_prefix = caste->caste_name[0];
if (plural)
prof = caste->caste_profession_name.plural[pid];
else
prof = caste->caste_profession_name.singular[pid];
if (prof.empty())
{
switch (pid)
{
case profession::CHILD:
prof = caste->child_name[plural ? 1 : 0];
if (!prof.empty())
use_race_prefix = false;
break;
case profession::BABY:
prof = caste->baby_name[plural ? 1 : 0];
if (!prof.empty())
use_race_prefix = false;
break;
default:
break;
}
}
}
if (race_prefix.empty())
race_prefix = creature->name[0];
if (prof.empty())
{
if (plural)
prof = creature->profession_name.plural[pid];
else
prof = creature->profession_name.singular[pid];
if (prof.empty())
{
switch (pid)
{
case profession::CHILD:
prof = creature->general_child_name[plural ? 1 : 0];
if (!prof.empty())
use_race_prefix = false;
break;
case profession::BABY:
prof = creature->general_baby_name[plural ? 1 : 0];
if (!prof.empty())
use_race_prefix = false;
break;
default:
break;
}
}
}
}
if (race_prefix.empty())
race_prefix = "Animal";
if (prof.empty())
{
erase_from_vector(unit->burrows, burrow->id);
erase_from_vector(burrow->units, unit->id);
switch (pid)
{
case profession::TRAINED_WAR:
prof = "War " + (use_race_prefix ? race_prefix : "Peasant");
use_race_prefix = false;
break;
case profession::TRAINED_HUNTER:
prof = "Hunting " + (use_race_prefix ? race_prefix : "Peasant");
use_race_prefix = false;
break;
case profession::STANDARD:
if (!use_race_prefix)
prof = "Peasant";
break;
default:
if (auto caption = ENUM_ATTR(profession, caption, pid))
prof = caption;
else
prof = ENUM_KEY_STR(profession, pid);
}
}
// Sync ui if active
if (ui && ui->main.mode == ui_sidebar_mode::Burrows &&
ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id)
if (use_race_prefix)
{
int idx = linear_index(ui->burrows.list_units, unit);
if (idx >= 0)
ui->burrows.sel_units[idx] = enable;
if (!prof.empty())
race_prefix += " ";
prof = race_prefix + prof;
}
}
return Translation::capitalize(prof, true);
}

@ -54,14 +54,14 @@ uint32_t Vegetation::getCount()
df::plant * Vegetation::getPlant(const int32_t index)
{
if (index < 0 || index >= getCount())
if (uint32_t(index) >= getCount())
return NULL;
return world->plants.all[index];
}
bool Vegetation::copyPlant(const int32_t index, t_plant &out)
{
if (index < 0 || index >= getCount())
if (uint32_t(index) >= getCount())
return false;
out.origin = world->plants.all[index];

@ -41,7 +41,7 @@ Windows::df_screentile *Windows::getScreenBuffer()
}
Windows::df_window::df_window(int x, int y, unsigned int width, unsigned int height)
:buffer(0), parent(0), left(x), top(y), width(width), height(height), current_painter(NULL)
:buffer(0), width(width), height(height), parent(0), left(x), top(y), current_painter(NULL)
{
buffer = 0;
};

@ -1 +1 @@
Subproject commit e8036d3f13c6be0141899baae90f605ad11d5385
Subproject commit f649d31001e6023a9df5fe83c7971c17afe0d87d

@ -106,6 +106,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(regrass regrass.cpp)
# this one exports functions to lua
DFHACK_PLUGIN(burrows burrows.cpp LINK_LIBRARIES lua)
DFHACK_PLUGIN(sort sort.cpp LINK_LIBRARIES lua)
# not yet. busy with other crud again...
#DFHACK_PLUGIN(versionosd versionosd.cpp)
endif()

@ -121,10 +121,26 @@ command_result lua_run_file (color_ostream &out, std::vector <std::string> &para
}
command_result lua_run (color_ostream &out, std::vector <std::string> &parameters)
{
if (!parameters.empty() && parameters[0] == "--core-context")
if (!parameters.empty())
{
Lua::InterpreterLoop(out, Lua::Core::State, "core lua");
return CR_OK;
if (parameters[0] == "--core-context")
{
Lua::InterpreterLoop(out, Lua::Core::State, "core lua");
return CR_OK;
}
else if (parameters[0] == "--core-reload")
{
CoreSuspender suspend;
for (size_t i = 1; i < parameters.size(); i++)
{
lua_getglobal(Lua::Core::State, "reload");
lua_pushstring(Lua::Core::State, parameters[i].c_str());
Lua::SafeCall(out, Lua::Core::State, 1, 0);
}
return CR_OK;
}
}
mymutex->lock();

@ -5,7 +5,7 @@ function adv_tools.reincarnate(swap_soul) --only for adventurer i guess
if swap_soul==nil then
swap_soul=true
end
local adv=df.global.world.units.other[0][0]
local adv=df.global.world.units.active[0]
if adv.flags1.dead==false then
error("You are not dead (yet)!")
end

@ -478,8 +478,8 @@ function getSelectedUnit()
return nil
end
local unit_indx=df.global.ui_selected_unit
if unit_indx<#df.global.world.units.other[0]-1 then
return df.global.world.units.other[0][unit_indx]
if unit_indx<#df.global.world.units.active-1 then
return df.global.world.units.active[unit_indx]
else
return nil
end

@ -113,7 +113,7 @@ function tools.change_adv(unit,nemesis)
if unit==nil then
error("Invalid unit!")
end
local other=df.global.world.units.other[0]
local other=df.global.world.units.active
local unit_indx
for k,v in pairs(other) do
if v==unit then
@ -157,7 +157,7 @@ function tools.MakeFollow(unit,trgunit)
error("Invalid creature")
end
if trgunit==nil then
trgunit=df.global.world.units.other[0][0]
trgunit=df.global.world.units.active[0]
end
unit.relations.group_leader_id=trgunit.id
local u_nem=getNemesis(unit)

@ -169,7 +169,7 @@ bool bodySwap(color_ostream &out, df::unit *player)
return false;
}
auto &vec = world->units.other[0];
auto &vec = world->units.active;
int idx = linear_index(vec, player);
if (idx < 0)
@ -195,7 +195,7 @@ df::nemesis_record *getPlayerNemesis(color_ostream &out, bool restore_swap)
if (restore_swap)
{
df::unit *ctl = world->units.other[0][0];
df::unit *ctl = world->units.active[0];
auto ctl_nemesis = Units::getNemesis(ctl);
if (ctl_nemesis != real_nemesis)

@ -13,6 +13,7 @@
#include "modules/MapCache.h"
#include "modules/World.h"
#include "modules/Units.h"
#include "modules/Burrows.h"
#include "TileTypes.h"
#include "DataDefs.h"
@ -345,7 +346,7 @@ static void handle_burrow_rename(color_ostream &out, df::burrow *burrow)
static void add_to_burrows(std::vector<df::burrow*> &burrows, df::coord pos)
{
for (size_t i = 0; i < burrows.size(); i++)
Maps::setBurrowTile(burrows[i], pos, true);
Burrows::setAssignedTile(burrows[i], pos, true);
}
static void add_walls_to_burrows(color_ostream &out, std::vector<df::burrow*> &burrows,
@ -379,7 +380,7 @@ static void handle_dig_complete(color_ostream &out, df::job_type job, df::coord
for (size_t i = 0; i < grow_burrows.size(); i++)
{
auto b = df::burrow::find(grow_burrows[i]);
if (b && Maps::isBurrowTile(b, pos))
if (b && Burrows::isAssignedTile(b, pos))
to_grow.push_back(b);
}
@ -446,7 +447,7 @@ static void copyUnits(df::burrow *target, df::burrow *source, bool enable)
if (source == target)
{
if (!enable)
Units::clearBurrowMembers(target);
Burrows::clearUnits(target);
return;
}
@ -456,7 +457,7 @@ static void copyUnits(df::burrow *target, df::burrow *source, bool enable)
auto unit = df::unit::find(source->units[i]);
if (unit)
Units::setInBurrow(unit, target, enable);
Burrows::setAssignedUnit(target, unit, enable);
}
}
@ -468,22 +469,22 @@ static void copyTiles(df::burrow *target, df::burrow *source, bool enable)
if (source == target)
{
if (!enable)
Maps::clearBurrowTiles(target);
Burrows::clearTiles(target);
return;
}
std::vector<df::map_block*> pvec;
Maps::listBurrowBlocks(&pvec, source);
Burrows::listBlocks(&pvec, source);
for (size_t i = 0; i < pvec.size(); i++)
{
auto block = pvec[i];
auto smask = Maps::getBlockBurrowMask(source, block);
auto smask = Burrows::getBlockMask(source, block);
if (!smask)
continue;
auto tmask = Maps::getBlockBurrowMask(target, block, enable);
auto tmask = Burrows::getBlockMask(target, block, enable);
if (!tmask)
continue;
@ -498,7 +499,7 @@ static void copyTiles(df::burrow *target, df::burrow *source, bool enable)
tmask->tile_bitmask[j] &= ~smask->tile_bitmask[j];
if (!tmask->has_assignments())
Maps::deleteBlockBurrowMask(target, block, tmask);
Burrows::deleteBlockMask(target, block, tmask);
}
}
}
@ -523,7 +524,7 @@ static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mas
continue;
if (!mask)
mask = Maps::getBlockBurrowMask(target, block, enable);
mask = Burrows::getBlockMask(target, block, enable);
if (!mask)
goto next_block;
@ -532,7 +533,7 @@ static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mas
}
if (mask && !enable && !mask->has_assignments())
Maps::deleteBlockBurrowMask(target, block, mask);
Burrows::deleteBlockMask(target, block, mask);
next_block:;
}
@ -604,7 +605,7 @@ static command_result burrow(color_ostream &out, vector <string> &parameters)
bool state = (cmd == "enable");
for (int i = 1; i < parameters.size(); i++)
for (size_t i = 1; i < parameters.size(); i++)
{
string &option = parameters[i];
@ -619,13 +620,13 @@ static command_result burrow(color_ostream &out, vector <string> &parameters)
if (parameters.size() < 2)
return CR_WRONG_USAGE;
for (int i = 1; i < parameters.size(); i++)
for (size_t i = 1; i < parameters.size(); i++)
{
auto target = findByName(out, parameters[i]);
if (!target)
return CR_WRONG_USAGE;
Units::clearBurrowMembers(target);
Burrows::clearUnits(target);
}
}
else if (cmd == "set-units" || cmd == "add-units" || cmd == "remove-units")
@ -638,11 +639,11 @@ static command_result burrow(color_ostream &out, vector <string> &parameters)
return CR_WRONG_USAGE;
if (cmd == "set-units")
Units::clearBurrowMembers(target);
Burrows::clearUnits(target);
bool enable = (cmd != "remove-units");
for (int i = 2; i < parameters.size(); i++)
for (size_t i = 2; i < parameters.size(); i++)
{
auto source = findByName(out, parameters[i]);
if (!source)
@ -656,13 +657,13 @@ static command_result burrow(color_ostream &out, vector <string> &parameters)
if (parameters.size() < 2)
return CR_WRONG_USAGE;
for (int i = 1; i < parameters.size(); i++)
for (size_t i = 1; i < parameters.size(); i++)
{
auto target = findByName(out, parameters[i]);
if (!target)
return CR_WRONG_USAGE;
Maps::clearBurrowTiles(target);
Burrows::clearTiles(target);
}
}
else if (cmd == "set-tiles" || cmd == "add-tiles" || cmd == "remove-tiles")
@ -675,11 +676,11 @@ static command_result burrow(color_ostream &out, vector <string> &parameters)
return CR_WRONG_USAGE;
if (cmd == "set-tiles")
Maps::clearBurrowTiles(target);
Burrows::clearTiles(target);
bool enable = (cmd != "remove-tiles");
for (int i = 2; i < parameters.size(); i++)
for (size_t i = 2; i < parameters.size(); i++)
{
if (setTilesByKeyword(target, parameters[i], enable))
continue;

@ -119,7 +119,7 @@ command_result writeFlag (color_ostream &out, vector <string> & parameters)
MapExtras::MapCache * MCache = new MapExtras::MapCache();
t_occupancy oc = MCache->occupancyAt(cursor);
oc.bits.building = value;
oc.bits.building = df::tile_building_occ(value);
MCache->setOccupancyAt(cursor, oc);
MCache->WriteAll();

@ -1196,7 +1196,7 @@ command_result digl (color_ostream &out, vector <string> & parameters)
df::tile_designation des = MCache->designationAt(xy);
df::tiletype tt = MCache->tiletypeAt(xy);
int16_t veinmat = MCache->veinMaterialAt(xy);
int16_t basemat = MCache->baseMaterialAt(xy);
int16_t basemat = MCache->layerMaterialAt(xy);
if( veinmat != -1 )
{
con.printerr("This is a vein. Use vdig instead!\n");
@ -1215,7 +1215,7 @@ command_result digl (color_ostream &out, vector <string> & parameters)
if (MCache->tagAt(current))
continue;
int16_t vmat2 = MCache->veinMaterialAt(current);
int16_t bmat2 = MCache->baseMaterialAt(current);
int16_t bmat2 = MCache->layerMaterialAt(current);
tt = MCache->tiletypeAt(current);
if(!DFHack::isWallTerrain(tt))
@ -1282,7 +1282,7 @@ command_result digl (color_ostream &out, vector <string> & parameters)
//below = 1;
des_minus = MCache->designationAt(current-1);
vmat_minus = MCache->veinMaterialAt(current-1);
bmat_minus = MCache->baseMaterialAt(current-1);
bmat_minus = MCache->layerMaterialAt(current-1);
tt_minus = MCache->tiletypeAt(current-1);
if ( tileMaterial(tt_minus)==tiletype_material::STONE
|| tileMaterial(tt_minus)==tiletype_material::SOIL)
@ -1293,7 +1293,7 @@ command_result digl (color_ostream &out, vector <string> & parameters)
//above = 1;
des_plus = MCache->designationAt(current+1);
vmat_plus = MCache->veinMaterialAt(current+1);
bmat_plus = MCache->baseMaterialAt(current+1);
bmat_plus = MCache->layerMaterialAt(current+1);
tt_plus = MCache->tiletypeAt(current+1);
if ( tileMaterial(tt_plus)==tiletype_material::STONE
|| tileMaterial(tt_plus)==tiletype_material::SOIL)

@ -193,7 +193,7 @@ static bool build_choice_matches(df::ui_build_item_req *req, df::build_req_choic
{
if (gen->mat_type == new_mat.type &&
gen->mat_index == new_mat.index &&
(ignore_select || gen->used_count < gen->candidates.size()))
(ignore_select || size_t(gen->used_count) < gen->candidates.size()))
{
return true;
}
@ -305,7 +305,7 @@ static df::job_item *getJobItem(color_ostream &out, df::job *job, std::string id
return NULL;
int v = atoi(idx.c_str());
if (v < 1 || v > job->job_items.size()) {
if (v < 1 || size_t(v) > job->job_items.size()) {
out.printerr("Invalid item index.\n");
return NULL;
}

@ -374,6 +374,10 @@ command_result df_liquids_execute(color_ostream &out)
DFHack::DFCoord cursor(x,y,z);
coord_vec all_tiles = brush->points(mcache,cursor);
out << "working..." << endl;
// Force the game to recompute its walkability cache
df::global::world->reindex_pathfinding = true;
if(mode == "obsidian")
{
coord_vec::iterator iter = all_tiles.begin();
@ -384,6 +388,7 @@ command_result df_liquids_execute(color_ostream &out)
mcache.setTemp2At(*iter,10015);
df::tile_designation des = mcache.designationAt(*iter);
des.bits.flow_size = 0;
des.bits.flow_forbid = false;
mcache.setDesignationAt(*iter, des);
iter ++;
}
@ -490,6 +495,9 @@ command_result df_liquids_execute(color_ostream &out)
mcache.setTemp1At(current,10015);
mcache.setTemp2At(current,10015);
}
// mark the tile passable or impassable like the game does
des.bits.flow_forbid = des.bits.flow_size &&
(des.bits.liquid_type == tile_liquid::Magma || des.bits.flow_size > 3);
mcache.setDesignationAt(current,des);
}
seen_blocks.insert(mcache.BlockAt(current / 16));

@ -2,6 +2,11 @@ local _ENV = mkmodule('plugins.burrows')
--[[
Native events:
* onBurrowRename(burrow)
* onDigComplete(job_type,pos,old_tiletype,new_tiletype)
Native functions:
* findByName(name) -> burrow
@ -13,21 +18,6 @@ local _ENV = mkmodule('plugins.burrows')
--]]
clearUnits = dfhack.units.clearBurrowMembers
function isBurrowUnit(burrow,unit)
return dfhack.units.isInBurrow(unit,burrow)
end
function setBurrowUnit(burrow,unit,enable)
return dfhack.units.setInBurrow(unit,burrow,enable)
end
clearTiles = dfhack.maps.clearBurrowTiles
listBlocks = dfhack.maps.listBurrowBlocks
isBurrowTile = dfhack.maps.isBurrowTile
setBurrowTile = dfhack.maps.setBurrowTile
isBlockBurrowTile = dfhack.maps.isBlockBurrowTile
setBlockBurrowTile = dfhack.maps.setBlockBurrowTile
rawset_default(_ENV, dfhack.burrows)
return _ENV

@ -0,0 +1,53 @@
local _ENV = mkmodule('plugins.sort')
local utils = require('utils')
local units = require('plugins.sort.units')
orders = orders or {}
orders.units = units.orders
function parse_ordering_spec(type,...)
local group = orders[type]
if group == nil then
dfhack.printerr('Invalid ordering class: '..tostring(type))
return nil
end
local specs = table.pack(...)
local rv = { }
for _,spec in ipairs(specs) do
local nil_first = false
if string.sub(spec,1,1) == '<' then
nil_first = true
spec = string.sub(spec,2)
end
local reverse = false
if string.sub(spec,1,1) == '>' then
reverse = true
spec = string.sub(spec,2)
end
local cm = group[spec]
if cm == nil then
dfhack.printerr('Unknown order for '..type..': '..tostring(spec))
return nil
end
if nil_first or reverse then
cm = copyall(cm)
cm.nil_first = nil_first
cm.reverse = reverse
end
rv[#rv+1] = cm
end
return rv
end
make_sort_order = utils.make_sort_order
return _ENV

@ -0,0 +1,112 @@
local _ENV = mkmodule('plugins.sort.units')
local utils = require('utils')
orders = orders or {}
-- Relies on NULL being auto-translated to NULL, and then sorted
orders.exists = {
key = function(unit)
return 1
end
}
orders.name = {
key = function(unit)
local name = dfhack.units.getVisibleName(unit)
if name and name.has_name then
return dfhack.TranslateName(name)
end
end,
compare = utils.compare_name
}
orders.age = {
key = function(unit)
return dfhack.units.getAge(unit)
end
}
-- This assumes that units are added to active in arrival order
orders.arrival = {
key_table = function(units)
local size = units.n or #units
local lookup={}
for i=1,size do
if units[i] then
lookup[units[i].id] = i
end
end
local idx={}
for i,v in ipairs(df.global.world.units.active) do
if lookup[v.id] then
idx[lookup[v.id]] = i
end
end
return idx
end
}
local function findRaceCaste(unit)
local rraw = df.creature_raw.find(unit.race)
return rraw, safe_index(rraw, 'caste', unit.caste)
end
orders.noble = {
key = function(unit)
local info = dfhack.units.getNoblePositions(unit)
if info then
return info[1].position.precedence
end
end
}
orders.profession = {
key = function(unit)
local cp = dfhack.units.getProfessionName(unit)
if cp and cp ~= '' then
return string.lower(cp)
end
end
}
orders.profession_class = {
key = function(unit)
local pid = unit.profession
local parent = df.profession.attrs[pid].parent
if parent >= 0 then
return parent
else
return pid
end
end
}
orders.race = {
key = function(unit)
local rraw = findRaceCaste(unit)
if rraw then
return rraw.name[0]
end
end
}
orders.squad = {
key = function(unit)
local sidx = unit.military.squad_index
if sidx >= 0 then
return sidx
end
end
}
orders.squad_position = {
key = function(unit)
local sidx = unit.military.squad_index
if sidx >= 0 then
return sidx * 1000 + unit.military.squad_position
end
end
}
return _ENV

@ -39,6 +39,46 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
return CR_OK;
}
static dfproto::Tile::TileMaterialType toProto(df::tiletype_material mat)
{
/*
* This is surely ugly, but casting enums without officially
* defined numerical values to protobuf enums is against the
* way protobufs are supposed to be used, because it defeats
* the backward compatible nature of the protocols.
*/
switch (mat)
{
#define CONVERT(name) case tiletype_material::name: return dfproto::Tile::name;
case tiletype_material::NONE:
CONVERT(AIR)
case tiletype_material::PLANT:
CONVERT(SOIL)
CONVERT(STONE)
CONVERT(FEATURE)
CONVERT(LAVA_STONE)
CONVERT(MINERAL)
CONVERT(FROZEN_LIQUID)
CONVERT(CONSTRUCTION)
CONVERT(GRASS_LIGHT)
CONVERT(GRASS_DARK)
CONVERT(GRASS_DRY)
CONVERT(GRASS_DEAD)
CONVERT(HFS)
CONVERT(CAMPFIRE)
CONVERT(FIRE)
CONVERT(ASHES)
case tiletype_material::MAGMA:
return dfproto::Tile::MAGMA_TYPE;
CONVERT(DRIFTWOOD)
CONVERT(POOL)
CONVERT(BROOK)
CONVERT(RIVER)
#undef CONVERT
}
return dfproto::Tile::AIR;
}
command_result mapexport (color_ostream &out, std::vector <std::string> & parameters)
{
bool showHidden = false;
@ -193,9 +233,9 @@ command_result mapexport (color_ostream &out, std::vector <std::string> & parame
prototile->set_flow_size(des.bits.flow_size);
}
df::tiletype type = b->TileTypeAt(coord);
df::tiletype type = b->tiletypeAt(coord);
prototile->set_type((dfproto::Tile::TileType)tileShape(type));
prototile->set_tile_material((dfproto::Tile::TileMaterialType)tileMaterial(type));
prototile->set_tile_material(toProto(tileMaterial(type)));
df::coord map_pos = df::coord(b_x*16+x,b_y*16+y,z);
@ -204,7 +244,7 @@ command_result mapexport (color_ostream &out, std::vector <std::string> & parame
case tiletype_material::SOIL:
case tiletype_material::STONE:
prototile->set_material_type(0);
prototile->set_material_index(b->baseMaterialAt(coord));
prototile->set_material_index(b->layerMaterialAt(coord));
break;
case tiletype_material::MINERAL:
prototile->set_material_type(0);

@ -103,6 +103,30 @@ command_result df_cprobe (color_ostream &out, vector <string> & parameters)
return CR_OK;
}
void describeTile(color_ostream &out, df::tiletype tiletype)
{
out.print("%d", tiletype);
if(tileName(tiletype))
out.print(" = %s",tileName(tiletype));
out.print("\n");
df::tiletype_shape shape = tileShape(tiletype);
df::tiletype_material material = tileMaterial(tiletype);
df::tiletype_special special = tileSpecial(tiletype);
df::tiletype_variant variant = tileVariant(tiletype);
out.print("%-10s: %4d %s\n","Class" ,shape,
ENUM_KEY_STR(tiletype_shape, shape).c_str());
out.print("%-10s: %4d %s\n","Material" ,
material, ENUM_KEY_STR(tiletype_material, material).c_str());
out.print("%-10s: %4d %s\n","Special" ,
special, ENUM_KEY_STR(tiletype_special, special).c_str());
out.print("%-10s: %4d %s\n" ,"Variant" ,
variant, ENUM_KEY_STR(tiletype_variant, variant).c_str());
out.print("%-10s: %s\n" ,"Direction",
tileDirection(tiletype).getStr());
out.print("\n");
}
command_result df_probe (color_ostream &out, vector <string> & parameters)
{
//bool showBlock, showDesig, showOccup, showTile, showMisc;
@ -186,26 +210,12 @@ command_result df_probe (color_ostream &out, vector <string> & parameters)
*/
// tiletype
out.print("tiletype: %d", tiletype);
if(tileName(tiletype))
out.print(" = %s",tileName(tiletype));
out.print("\n");
df::tiletype_shape shape = tileShape(tiletype);
df::tiletype_material material = tileMaterial(tiletype);
df::tiletype_special special = tileSpecial(tiletype);
df::tiletype_variant variant = tileVariant(tiletype);
out.print("%-10s: %4d %s\n","Class" ,shape,
ENUM_KEY_STR(tiletype_shape, shape).c_str());
out.print("%-10s: %4d %s\n","Material" ,
material, ENUM_KEY_STR(tiletype_material, material).c_str());
out.print("%-10s: %4d %s\n","Special" ,
special, ENUM_KEY_STR(tiletype_special, special).c_str());
out.print("%-10s: %4d %s\n" ,"Variant" ,
variant, ENUM_KEY_STR(tiletype_variant, variant).c_str());
out.print("%-10s: %s\n" ,"Direction",
tileDirection(tiletype).getStr());
out.print("\n");
out.print("tiletype: ");
describeTile(out, tiletype);
out.print("static: ");
describeTile(out, mc.staticTiletypeAt(cursor));
out.print("base: ");
describeTile(out, mc.baseTiletypeAt(cursor));
out.print("temperature1: %d U\n",mc.temperature1At(cursor));
out.print("temperature2: %d U\n",mc.temperature2At(cursor));
@ -214,7 +224,7 @@ command_result df_probe (color_ostream &out, vector <string> & parameters)
out << "biome: " << des.bits.biome << std::endl;
out << "geolayer: " << des.bits.geolayer_index
<< std::endl;
int16_t base_rock = mc.baseMaterialAt(cursor);
int16_t base_rock = mc.layerMaterialAt(cursor);
if(base_rock != -1)
{
out << "Layer material: " << dec << base_rock;
@ -238,6 +248,12 @@ command_result df_probe (color_ostream &out, vector <string> & parameters)
else
out << endl;
}
MaterialInfo minfo(mc.baseMaterialAt(cursor));
if (minfo.isValid())
out << "Base material: " << minfo.getToken() << " / " << minfo.toString() << endl;
minfo.decode(mc.staticMaterialAt(cursor));
if (minfo.isValid())
out << "Static material: " << minfo.getToken() << " / " << minfo.toString() << endl;
// liquids
if(des.bits.flow_size)
{

@ -474,7 +474,7 @@ command_result prospector (color_ostream &con, vector <string> & parameters)
liquidWater.add(global_z);
}
df::tiletype type = b->TileTypeAt(coord);
df::tiletype type = b->tiletypeAt(coord);
df::tiletype_shape tileshape = tileShape(type);
df::tiletype_material tilemat = tileMaterial(type);
@ -506,7 +506,7 @@ command_result prospector (color_ostream &con, vector <string> & parameters)
{
case tiletype_material::SOIL:
case tiletype_material::STONE:
layerMats[b->baseMaterialAt(coord)].add(global_z);
layerMats[b->layerMaterialAt(coord)].add(global_z);
break;
case tiletype_material::MINERAL:
veinMats[b->veinMaterialAt(coord)].add(global_z);

@ -0,0 +1,528 @@
#include "Core.h"
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "modules/Gui.h"
#include "modules/Translation.h"
#include "modules/Units.h"
#include "LuaTools.h"
#include "DataDefs.h"
#include "df/ui.h"
#include "df/world.h"
#include "df/viewscreen_joblistst.h"
#include "df/viewscreen_unitlistst.h"
#include "df/viewscreen_layer_militaryst.h"
#include "df/viewscreen_layer_workshop_profilest.h"
#include "df/viewscreen_layer_noblelistst.h"
#include "df/viewscreen_layer_overall_healthst.h"
#include "df/viewscreen_dwarfmodest.h"
#include "df/viewscreen_petst.h"
#include "df/layer_object_listst.h"
#include "MiscUtils.h"
#include <stdlib.h>
using std::vector;
using std::string;
using std::endl;
using namespace DFHack;
using namespace df::enums;
using df::global::ui;
using df::global::world;
using df::global::ui_building_in_assign;
using df::global::ui_building_item_cursor;
using df::global::ui_building_assign_type;
using df::global::ui_building_assign_is_marked;
using df::global::ui_building_assign_units;
using df::global::ui_building_assign_items;
static bool unit_list_hotkey(df::viewscreen *top);
static command_result sort_units(color_ostream &out, vector <string> & parameters);
DFHACK_PLUGIN("sort");
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands)
{
commands.push_back(PluginCommand(
"sort-units", "Sort the visible unit list.", sort_units, unit_list_hotkey,
" sort-units order [order...]\n"
" Sort the unit list using the given sequence of comparisons.\n"
" The '<' prefix for an order makes undefined values sort first.\n"
" The '>' prefix reverses the sort order for defined values.\n"
" Unit order examples:\n"
" name, age, arrival, squad, squad_position, profession\n"
"The orderings are defined in hack/lua/plugins/sort/*.lua\n"
));
return CR_OK;
}
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
{
return CR_OK;
}
template<class T>
void reorder_vector(std::vector<T> *pvec, const std::vector<unsigned> &order)
{
assert(pvec->size() == order.size());
std::vector<T> tmp(*pvec);
for (size_t i = 0; i < order.size(); i++)
(*pvec)[i] = tmp[order[i]];
}
template<class T>
void reorder_cursor(T *cursor, const std::vector<unsigned> &order)
{
if (*cursor == 0)
return;
for (size_t i = 0; i < order.size(); i++)
{
if (unsigned(*cursor) == order[i])
{
*cursor = T(i);
break;
}
}
}
bool parse_ordering_spec(color_ostream &out, lua_State *L, std::string type, const std::vector<std::string> &params)
{
if (!lua_checkstack(L, params.size() + 2))
return false;
if (!Lua::PushModulePublic(out, L, "plugins.sort", "parse_ordering_spec"))
return false;
Lua::Push(L, type);
for (size_t i = 0; i < params.size(); i++)
Lua::Push(L, params[i]);
if (!Lua::SafeCall(out, L, params.size()+1, 1))
return false;
if (!lua_istable(L, -1))
{
lua_pop(L, 1);
return false;
}
return true;
}
bool read_order(color_ostream &out, lua_State *L, std::vector<unsigned> *order, size_t size)
{
std::vector<char> found;
Lua::StackUnwinder frame(L, 1);
if (!lua_istable(L, -1))
{
out.printerr("Not a table returned as ordering.\n");
return false;
}
if (lua_rawlen(L, -1) != size)
{
out.printerr("Invalid ordering size: expected %d, actual %d\n", size, lua_rawlen(L, -1));
return false;
}
order->clear();
order->resize(size);
found.resize(size);
for (size_t i = 1; i <= size; i++)
{
lua_rawgeti(L, frame[1], i);
int v = lua_tointeger(L, -1);
lua_pop(L, 1);
if (v < 1 || size_t(v) > size)
{
out.printerr("Order value out of range: %d\n", v);
return false;
}
if (found[v-1])
{
out.printerr("Duplicate order value: %d\n", v);
return false;
}
found[v-1] = 1;
(*order)[i-1] = v-1;
}
return true;
}
template<class T>
bool compute_order(color_ostream &out, lua_State *L, int base, std::vector<unsigned> *order, const std::vector<T> &key)
{
lua_pushvalue(L, base+1);
Lua::PushVector(L, key, true);
lua_pushvalue(L, base+2);
if (!Lua::SafeCall(out, L, 2, 1))
return false;
return read_order(out, L, order, key.size());
}
static bool ParseSpec(color_ostream &out, lua_State *L, const char *type, vector<string> &params)
{
if (!parse_ordering_spec(out, L, "units", params))
{
out.printerr("Invalid ordering specification for %s.\n", type);
return false;
}
return true;
}
#define PARSE_SPEC(type, params) \
if (!ParseSpec(*pout, L, type, params)) return false;
static void sort_null_first(vector<string> &parameters)
{
vector_insert_at(parameters, 0, std::string("<exists"));
}
static df::layer_object_listst *getLayerList(df::viewscreen_layerst *layer, int idx)
{
return virtual_cast<df::layer_object_listst>(vector_get(layer->layer_objects,idx));
}
static bool maybe_sort_units(color_ostream *pout, lua_State *L,
df::viewscreen *screen, vector<string> &parameters)
{
Lua::StackUnwinder top(L);
if (L)
{
if (!Lua::PushModulePublic(*pout, L, "plugins.sort", "make_sort_order"))
{
pout->printerr("Cannot access the sorter function.\n");
return false;
}
}
std::vector<unsigned> order;
if (auto units = strict_virtual_cast<df::viewscreen_unitlistst>(screen))
{
if (!L) return true;
/*
* Sort units in the 'u'nit list screen.
*/
PARSE_SPEC("units", parameters);
int page = units->page;
if (compute_order(*pout, L, top, &order, units->units[page]))
{
reorder_cursor(&units->cursor_pos[page], order);
reorder_vector(&units->units[page], order);
reorder_vector(&units->jobs[page], order);
}
return true;
}
else if (auto jobs = strict_virtual_cast<df::viewscreen_joblistst>(screen))
{
if (!L) return true;
/*
* Sort units in the 'j'ob list screen.
*/
PARSE_SPEC("units", parameters);
if (compute_order(*pout, L, top, &order, jobs->units))
{
reorder_cursor(&jobs->cursor_pos, order);
reorder_vector(&jobs->units, order);
reorder_vector(&jobs->jobs, order);
}
return true;
}
else if (auto military = strict_virtual_cast<df::viewscreen_layer_militaryst>(screen))
{
switch (military->page)
{
case df::viewscreen_layer_militaryst::Positions:
{
auto &candidates = military->positions.candidates;
auto list3 = getLayerList(military, 2);
/*
* Sort candidate units in the 'p'osition page of the 'm'ilitary screen.
*/
if (list3 && !candidates.empty() && list3->bright)
{
if (!L) return true;
PARSE_SPEC("units", parameters);
if (compute_order(*pout, L, top, &order, candidates))
{
reorder_cursor(&list3->cursor, order);
reorder_vector(&candidates, order);
}
return true;
}
return false;
}
default:
return false;
}
}
else if (auto profile = strict_virtual_cast<df::viewscreen_layer_workshop_profilest>(screen))
{
auto list1 = getLayerList(profile, 0);
if (!list1) return false;
if (!L) return true;
/*
* Sort units in the workshop 'q'uery 'P'rofile modification screen.
*/
PARSE_SPEC("units", parameters);
if (compute_order(*pout, L, top, &order, profile->workers))
{
reorder_cursor(&list1->cursor, order);
reorder_vector(&profile->workers, order);
}
return true;
}
else if (auto nobles = strict_virtual_cast<df::viewscreen_layer_noblelistst>(screen))
{
switch (nobles->mode)
{
case df::viewscreen_layer_noblelistst::Appoint:
{
auto list2 = getLayerList(nobles, 1);
/*
* Sort units in the appointment candidate list of the 'n'obles screen.
*/
if (list2)
{
if (!L) return true;
sort_null_first(parameters);
PARSE_SPEC("units", parameters);
std::vector<df::unit*> units;
for (size_t i = 0; i < nobles->candidates.size(); i++)
units.push_back(nobles->candidates[i]->unit);
if (compute_order(*pout, L, top, &order, units))
{
reorder_cursor(&list2->cursor, order);
reorder_vector(&nobles->candidates, order);
}
return true;
}
return false;
}
default:
return false;
}
}
else if (auto animals = strict_virtual_cast<df::viewscreen_petst>(screen))
{
switch (animals->mode)
{
case df::viewscreen_petst::List:
{
if (!L) return true;
/*
* Sort animal units in the Animal page of the 'z' status screen.
*/
PARSE_SPEC("units", parameters);
std::vector<df::unit*> units;
for (size_t i = 0; i < animals->animal.size(); i++)
units.push_back(animals->is_vermin[i] ? NULL : (df::unit*)animals->animal[i]);
if (compute_order(*pout, L, top, &order, units))
{
reorder_cursor(&animals->cursor, order);
reorder_vector(&animals->animal, order);
reorder_vector(&animals->is_vermin, order);
reorder_vector(&animals->pet_info, order);
reorder_vector(&animals->is_tame, order);
reorder_vector(&animals->is_adopting, order);
}
return true;
}
case df::viewscreen_petst::SelectTrainer:
{
if (!L) return true;
/*
* Sort candidate trainers in the Animal page of the 'z' status screen.
*/
sort_null_first(parameters);
PARSE_SPEC("units", parameters);
if (compute_order(*pout, L, top, &order, animals->trainer_unit))
{
reorder_cursor(&animals->trainer_cursor, order);
reorder_vector(&animals->trainer_unit, order);
reorder_vector(&animals->trainer_mode, order);
}
return true;
}
default:
return false;
}
}
else if (auto health = strict_virtual_cast<df::viewscreen_layer_overall_healthst>(screen))
{
auto list1 = getLayerList(health, 0);
if (!list1) return false;
if (!L) return true;
/*
* Sort units in the Health page of the 'z' status screen.
*/
PARSE_SPEC("units", parameters);
if (compute_order(*pout, L, top, &order, health->unit))
{
reorder_cursor(&list1->cursor, order);
reorder_vector(&health->unit, order);
reorder_vector(&health->bits1, order);
reorder_vector(&health->bits2, order);
reorder_vector(&health->bits3, order);
}
return true;
}
else if (strict_virtual_cast<df::viewscreen_dwarfmodest>(screen))
{
switch (ui->main.mode)
{
case ui_sidebar_mode::Burrows:
if (!L) return true;
/*
* Sort burrow member candidate units in the 'w' sidebar mode.
*/
PARSE_SPEC("units", parameters);
if (compute_order(*pout, L, top, &order, ui->burrows.list_units))
{
reorder_cursor(&ui->burrows.unit_cursor_pos, order);
reorder_vector(&ui->burrows.list_units, order);
reorder_vector(&ui->burrows.sel_units, order);
}
return true;
case ui_sidebar_mode::QueryBuilding:
if (!ui_building_in_assign || !*ui_building_in_assign)
return false;
// fall through for building owner / chain assign animal
case ui_sidebar_mode::ZonesPenInfo:
if (ui_building_item_cursor &&
ui_building_assign_type &&
ui_building_assign_is_marked &&
ui_building_assign_units &&
ui_building_assign_items &&
ui_building_assign_type->size() == ui_building_assign_units->size() &&
!ui_building_assign_type->empty())
{
if (!L) return true;
/*
* Sort building owner candidate units in the 'q' sidebar mode,
* or pen assignment candidate units in 'z'->'N', or cage assignment.
*/
// TODO: better way
bool is_assign_owner = ((*ui_building_assign_type)[0] == -1);
if (is_assign_owner)
sort_null_first(parameters);
PARSE_SPEC("units", parameters);
if (compute_order(*pout, L, top, &order, *ui_building_assign_units))
{
reorder_cursor(ui_building_item_cursor, order);
reorder_vector(ui_building_assign_type, order);
reorder_vector(ui_building_assign_units, order);
if (ui_building_assign_units->size() == ui_building_assign_items->size())
reorder_vector(ui_building_assign_items, order);
if (ui_building_assign_units->size() == ui_building_assign_is_marked->size())
reorder_vector(ui_building_assign_is_marked, order);
}
return true;
}
return false;
default:
return false;
}
}
else
return false;
}
static bool unit_list_hotkey(df::viewscreen *screen)
{
vector<string> dummy;
return maybe_sort_units(NULL, NULL, screen, dummy);
}
static command_result sort_units(color_ostream &out, vector <string> &parameters)
{
if (parameters.empty())
return CR_WRONG_USAGE;
auto L = Lua::Core::State;
auto screen = Core::getInstance().getTopViewscreen();
if (!maybe_sort_units(&out, L, screen, parameters))
return CR_WRONG_USAGE;
return CR_OK;
}

@ -614,6 +614,9 @@ command_result executePaintJob(color_ostream &out)
coord_vec all_tiles = brush->points(map, cursor);
out.print("working...\n");
// Force the game to recompute its walkability cache
df::global::world->reindex_pathfinding = true;
for (coord_vec::iterator iter = all_tiles.begin(); iter != all_tiles.end(); ++iter)
{
const df::tiletype source = map.tiletypeAt(*iter);

@ -892,6 +892,9 @@ static void guess_job_material(df::job *job, MaterialInfo &mat, df::dfhack_mater
case item_type::WOOD:
mat_mask.bits.wood = mat_mask.bits.wood2 = true;
break;
default:
break;
}
}
}
@ -1148,6 +1151,9 @@ static void map_job_items(color_ostream &out)
if (item->getTotalDimension() < 10000)
is_invalid = true;
break;
default:
break;
}
if (item->flags.bits.melt && !item->flags.bits.owned && !itemBusy(item))