Merge remote-tracking branch 'origin/develop' into plugin-globals

develop
lethosor 2014-12-06 17:32:44 -05:00
commit 5de3e6110a
17 changed files with 792 additions and 82 deletions

@ -59,7 +59,7 @@ endif()
# set up versioning. # set up versioning.
set(DF_VERSION "0.40.19") set(DF_VERSION "0.40.19")
SET(DFHACK_RELEASE "r0" CACHE STRING "Current release revision.") SET(DFHACK_RELEASE "r1" CACHE STRING "Current release revision.")
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")
add_definitions(-DDFHACK_VERSION="${DFHACK_VERSION}") add_definitions(-DDFHACK_VERSION="${DFHACK_VERSION}")

@ -3,13 +3,13 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.8.1: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils 0.12: http://docutils.sourceforge.net/" />
<title>Building DFHACK</title> <title>Building DFHACK</title>
<style type="text/css"> <style type="text/css">
/* /*
:Author: David Goodger (goodger@python.org) :Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7056 2011-06-17 10:50:48Z milde $ :Id: $Id: html4css1.css 7614 2013-02-21 15:55:51Z milde $
:Copyright: This stylesheet has been placed in the public domain. :Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils. Default cascading style sheet for the HTML output of Docutils.
@ -77,7 +77,7 @@ div.tip p.admonition-title {
div.attention p.admonition-title, div.caution p.admonition-title, div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title, div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title { div.warning p.admonition-title, .code .error {
color: red ; color: red ;
font-weight: bold ; font-weight: bold ;
font-family: sans-serif } font-family: sans-serif }
@ -249,10 +249,19 @@ pre.address {
margin-top: 0 ; margin-top: 0 ;
font: inherit } font: inherit }
pre.literal-block, pre.doctest-block, pre.math { pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ; margin-left: 2em ;
margin-right: 2em } margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier { span.classifier {
font-family: sans-serif ; font-family: sans-serif ;
font-style: oblique } font-style: oblique }
@ -304,6 +313,21 @@ table.docutils th.field-name, table.docinfo th.docinfo-name {
white-space: nowrap ; white-space: nowrap ;
padding-left: 0 } padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% } font-size: 100% }

@ -3,7 +3,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.11: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils 0.12: http://docutils.sourceforge.net/" />
<title>Contributors</title> <title>Contributors</title>
<style type="text/css"> <style type="text/css">
@ -402,6 +402,7 @@ ul.auto-toc {
<li>Antalia &lt;<a class="reference external" href="mailto:tamarakorr&#64;gmail.com">tamarakorr&#64;gmail.com</a>&gt;</li> <li>Antalia &lt;<a class="reference external" href="mailto:tamarakorr&#64;gmail.com">tamarakorr&#64;gmail.com</a>&gt;</li>
<li>Angus Mezick &lt;<a class="reference external" href="mailto:amezick&#64;gmail.com">amezick&#64;gmail.com</a>&gt;</li> <li>Angus Mezick &lt;<a class="reference external" href="mailto:amezick&#64;gmail.com">amezick&#64;gmail.com</a>&gt;</li>
<li>PeridexisErrant &lt;<a class="reference external" href="mailto:PeridexisErrant&#64;gmail.com">PeridexisErrant&#64;gmail.com</a>&gt;</li> <li>PeridexisErrant &lt;<a class="reference external" href="mailto:PeridexisErrant&#64;gmail.com">PeridexisErrant&#64;gmail.com</a>&gt;</li>
<li>Putnam</li>
</ul> </ul>
<p>And those are the cool people who made <strong>stonesense</strong>.</p> <p>And those are the cool people who made <strong>stonesense</strong>.</p>
<ul class="simple"> <ul class="simple">

@ -3,13 +3,13 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.8.1: http://docutils.sourceforge.net/" /> <meta name="generator" content="Docutils 0.12: http://docutils.sourceforge.net/" />
<title>DFHack Lua API</title> <title>DFHack Lua API</title>
<style type="text/css"> <style type="text/css">
/* /*
:Author: David Goodger (goodger@python.org) :Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7056 2011-06-17 10:50:48Z milde $ :Id: $Id: html4css1.css 7614 2013-02-21 15:55:51Z milde $
:Copyright: This stylesheet has been placed in the public domain. :Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils. Default cascading style sheet for the HTML output of Docutils.
@ -77,7 +77,7 @@ div.tip p.admonition-title {
div.attention p.admonition-title, div.caution p.admonition-title, div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title, div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title { div.warning p.admonition-title, .code .error {
color: red ; color: red ;
font-weight: bold ; font-weight: bold ;
font-family: sans-serif } font-family: sans-serif }
@ -249,10 +249,19 @@ pre.address {
margin-top: 0 ; margin-top: 0 ;
font: inherit } font: inherit }
pre.literal-block, pre.doctest-block, pre.math { pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ; margin-left: 2em ;
margin-right: 2em } margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier { span.classifier {
font-family: sans-serif ; font-family: sans-serif ;
font-style: oblique } font-style: oblique }
@ -304,6 +313,21 @@ table.docutils th.field-name, table.docinfo th.docinfo-name {
white-space: nowrap ; white-space: nowrap ;
padding-left: 0 } padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% } font-size: 100% }
@ -1222,6 +1246,11 @@ Returns <em>true</em> on success.</p>
<li><p class="first"><tt class="docutils literal">dfhack.job.is_item_equal(job_item1,job_item2)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.job.is_item_equal(job_item1,job_item2)</tt></p>
<p>Compares important fields in the job item structures.</p> <p>Compares important fields in the job item structures.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">dfhack.job.linkIntoWorld(job,new_id)</tt></p>
<p>Adds job into <tt class="docutils literal">df.global.job_list</tt>, and if new_id
is true, then also sets it's id and increases
<tt class="docutils literal">df.global.job_next_id</tt></p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.job.listNewlyCreated(first_id)</tt></p> <li><p class="first"><tt class="docutils literal">dfhack.job.listNewlyCreated(first_id)</tt></p>
<p>Returns the current value of <tt class="docutils literal">df.global.job_next_id</tt>, and <p>Returns the current value of <tt class="docutils literal">df.global.job_next_id</tt>, and
if there are any jobs with <tt class="docutils literal">first_id &lt;= id &lt; job_next_id</tt>, if there are any jobs with <tt class="docutils literal">first_id &lt;= id &lt; job_next_id</tt>,
@ -3249,7 +3278,8 @@ tweaking (e.g. adding custom reactions)</p>
<p>Enable event checking for EventManager events. For event types use <tt class="docutils literal">eventType</tt> table. Note that different types of events require different frequencies to be effective. The frequency is how many ticks EventManager will wait before checking if that type of event has happened. If multiple scripts or plugins use the same event type, the smallest frequency is the one that is used, so you might get events triggered more often than the frequency you use here.</p> <p>Enable event checking for EventManager events. For event types use <tt class="docutils literal">eventType</tt> table. Note that different types of events require different frequencies to be effective. The frequency is how many ticks EventManager will wait before checking if that type of event has happened. If multiple scripts or plugins use the same event type, the smallest frequency is the one that is used, so you might get events triggered more often than the frequency you use here.</p>
</li> </li>
<li><p class="first"><tt class="docutils literal">registerSidebar(shop_name,callback)</tt></p> <li><p class="first"><tt class="docutils literal">registerSidebar(shop_name,callback)</tt></p>
<p>Enable callback when sidebar for <tt class="docutils literal">shop_name</tt> is drawn. Usefull for custom workshop views e.g. using gui.dwarfmode lib.</p> <p>Enable callback when sidebar for <tt class="docutils literal">shop_name</tt> is drawn. Usefull for custom workshop views e.g. using gui.dwarfmode lib. Also accepts a <tt class="docutils literal">class</tt> instead of function
as callback. Best used with <tt class="docutils literal">gui.dwarfmode</tt> class <tt class="docutils literal">WorkshopOverlay</tt>.</p>
</li> </li>
</ol> </ol>
</div> </div>
@ -3310,6 +3340,7 @@ plugin export a function it's recommended to use lua decorated function.</p>
<li><tt class="docutils literal"><span class="pre">{x=&lt;number&gt;</span> <span class="pre">y=&lt;number&gt;</span> + 4 numbers like in first case}</tt>, this generates full frame useful for animations that change little (1-2 tiles)</li> <li><tt class="docutils literal"><span class="pre">{x=&lt;number&gt;</span> <span class="pre">y=&lt;number&gt;</span> + 4 numbers like in first case}</tt>, this generates full frame useful for animations that change little (1-2 tiles)</li>
</ol> </ol>
</li> </li>
<li>canBeRoomSubset -- a flag if this building can be counted in room. 1 means it can, 0 means it can't and -1 default building behaviour</li>
</ol> </ol>
</dd> </dd>
<dt>Animate table also might contain:</dt> <dt>Animate table also might contain:</dt>

10
NEWS

@ -1,4 +1,11 @@
DFHack Future DFHack Future
Internals
Fixes
New Plugins
New Scripts
Misc Improvements
DFHack 0.40.19-r1
Internals: Internals:
Fixes: Fixes:
typo fix in modtools/reaction-trigger typo fix in modtools/reaction-trigger
@ -12,6 +19,7 @@ DFHack Future
this script replaces removebadthoughts.rb this script replaces removebadthoughts.rb
Misc improvements: Misc improvements:
cmd-prompt can now access selected items, units, and buildings cmd-prompt can now access selected items, units, and buildings
autolabor plugin: add an optional talent pool parameter
DFHack 0.40.16-r1 DFHack 0.40.16-r1
Internals: Internals:
@ -273,7 +281,7 @@ DFHack v0.34.11-r5
- rendermax: replace the renderer with something else. Most interesting is "rendermax light"- a lighting engine for df. - rendermax: replace the renderer with something else. Most interesting is "rendermax light"- a lighting engine for df.
- automelt: allows marking stockpiles for automelt (i.e. any items placed in stocpile will be designated for melting) - automelt: allows marking stockpiles for automelt (i.e. any items placed in stocpile will be designated for melting)
- embark-tools: implementations of Embark Anywhere, Nano Embark, and a few other embark-related utilities - embark-tools: implementations of Embark Anywhere, Nano Embark, and a few other embark-related utilities
- building-hacks: Allows to add custom functionality and/or animations to buildings. - building-hacks: Allows to add custom functionality and/or animations to buildings.
- petcapRemover: triggers pregnancies in creatures so that you can effectively raise the default pet population cap from the default 50 - petcapRemover: triggers pregnancies in creatures so that you can effectively raise the default pet population cap from the default 50
Misc improvements: Misc improvements:

@ -2803,6 +2803,9 @@ if labors change mid-job, are handled slightly differently to minimise churn.</p
<tr class="field"><th class="field-name" colspan="2"><cite>autolabor CUT_GEM 1 1</cite>:</th></tr> <tr class="field"><th class="field-name" colspan="2"><cite>autolabor CUT_GEM 1 1</cite>:</th></tr>
<tr class="field"><td>&nbsp;</td><td class="field-body">Keep exactly 1 dwarf with gemcutting enabled.</td> <tr class="field"><td>&nbsp;</td><td class="field-body">Keep exactly 1 dwarf with gemcutting enabled.</td>
</tr> </tr>
<tr class="field"><th class="field-name" colspan="2"><cite>autolabor COOK 1 1 3</cite>:</th></tr>
<tr class="field"><td>&nbsp;</td><td class="field-body">Keep 1 dwarf with cooking enabled, selected only from the top 3.</td>
</tr>
<tr class="field"><th class="field-name" colspan="2"><cite>autolabor FEED_WATER_CIVILIANS haulers</cite>:</th></tr> <tr class="field"><th class="field-name" colspan="2"><cite>autolabor FEED_WATER_CIVILIANS haulers</cite>:</th></tr>
<tr class="field"><td>&nbsp;</td><td class="field-body">Have haulers feed and water wounded dwarves.</td> <tr class="field"><td>&nbsp;</td><td class="field-body">Have haulers feed and water wounded dwarves.</td>
</tr> </tr>

@ -378,8 +378,8 @@ Options:
command-prompt command-prompt
-------------- --------------
A one line command prompt in df. Same as entering command into dfhack console. Best A one line command prompt in df. Same as entering command into dfhack console. Best
used as a keybinding. Can be called with optional "entry" that will start prompt with used as a keybinding. Can be called with optional "entry" that will start prompt with
that pre-filled. that pre-filled.
.. image:: images/command-prompt.png .. image:: images/command-prompt.png
@ -640,7 +640,7 @@ dfhack command line and can't be used from a hotkey. Settings will be remembered
as long as dfhack runs. Intended for use in combination with the command as long as dfhack runs. Intended for use in combination with the command
liquids-here (which can be bound to a hotkey). liquids-here (which can be bound to a hotkey).
For more information, refer to the command's internal help. For more information, refer to the command's internal help.
.. note:: .. note::
@ -828,7 +828,7 @@ out if you have any of them running around in your fort. Dead and passive
creatures (ghosts who were put to rest, killed vampires, ...) are ignored. creatures (ghosts who were put to rest, killed vampires, ...) are ignored.
Undead skeletons, corpses, bodyparts and the like are all thrown into the curse Undead skeletons, corpses, bodyparts and the like are all thrown into the curse
category "zombie". Anonymous zombies and resurrected body parts will show category "zombie". Anonymous zombies and resurrected body parts will show
as "unnamed creature". as "unnamed creature".
Options: Options:
@ -1419,12 +1419,12 @@ produce undesirable results. There are a few good ones though.
You are in fort game mode, managing your fortress and paused. You are in fort game mode, managing your fortress and paused.
You switch to the arena game mode, *assume control of a creature* and then You switch to the arena game mode, *assume control of a creature* and then
switch to adventure game mode(1). switch to adventure game mode(1).
You just lost a fortress and gained an adventurer. You just lost a fortress and gained an adventurer.
You could also do this. You could also do this.
You are in fort game mode, managing your fortress and paused at the esc menu. You are in fort game mode, managing your fortress and paused at the esc menu.
You switch to the adventure game mode, then use Dfusion to *assume control of a creature* and then You switch to the adventure game mode, then use Dfusion to *assume control of a creature* and then
save or retire. save or retire.
You just created a returnable mountain home and gained an adventurer. You just created a returnable mountain home and gained an adventurer.
@ -1462,7 +1462,7 @@ Export dwarves to RuneSmith-compatible XML.
exportlegends exportlegends
------------- -------------
Controls legends mode to export data - especially useful to set-and-forget large Controls legends mode to export data - especially useful to set-and-forget large
worlds, or when you want a map of every site when there are several hundred. worlds, or when you want a map of every site when there are several hundred.
Options: Options:
@ -1623,17 +1623,17 @@ Constraint examples
~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~
Keep metal bolts within 900-1000, and wood/bone within 150-200:: Keep metal bolts within 900-1000, and wood/bone within 150-200::
workflow amount AMMO:ITEM_AMMO_BOLTS/METAL 1000 100 workflow amount AMMO:ITEM_AMMO_BOLTS/METAL 1000 100
workflow amount AMMO:ITEM_AMMO_BOLTS/WOOD,BONE 200 50 workflow amount AMMO:ITEM_AMMO_BOLTS/WOOD,BONE 200 50
Keep the number of prepared food & drink stacks between 90 and 120:: Keep the number of prepared food & drink stacks between 90 and 120::
workflow count FOOD 120 30 workflow count FOOD 120 30
workflow count DRINK 120 30 workflow count DRINK 120 30
Make sure there are always 25-30 empty bins/barrels/bags:: Make sure there are always 25-30 empty bins/barrels/bags::
workflow count BIN 30 workflow count BIN 30
workflow count BARREL 30 workflow count BARREL 30
workflow count BOX/CLOTH,SILK,YARN 30 workflow count BOX/CLOTH,SILK,YARN 30
@ -1648,12 +1648,12 @@ Produce 15-20 gold crafts::
workflow count CRAFTS//GOLD 20 workflow count CRAFTS//GOLD 20
Collect 15-20 sand bags and clay boulders:: Collect 15-20 sand bags and clay boulders::
workflow count POWDER_MISC/SAND 20 workflow count POWDER_MISC/SAND 20
workflow count BOULDER/CLAY 20 workflow count BOULDER/CLAY 20
Make sure there are always 80-100 units of dimple dye:: Make sure there are always 80-100 units of dimple dye::
workflow amount POWDER_MISC//MUSHROOM_CUP_DIMPLE:MILL 100 20 workflow amount POWDER_MISC//MUSHROOM_CUP_DIMPLE:MILL 100 20
.. note:: .. note::
@ -1791,7 +1791,7 @@ Mass-renaming
Using the 'nick' command you can set the same nickname for multiple units. Using the 'nick' command you can set the same nickname for multiple units.
If used without 'assign', 'all' or 'count' it will rename all units in the If used without 'assign', 'all' or 'count' it will rename all units in the
current default target zone. Combined with 'assign', 'all' or 'count' (and current default target zone. Combined with 'assign', 'all' or 'count' (and
further optional filters) it will rename units matching the filter conditions. further optional filters) it will rename units matching the filter conditions.
Cage zones Cage zones
~~~~~~~~~~ ~~~~~~~~~~
@ -1828,7 +1828,7 @@ Examples
``zone tocages count 50 own tame male not grazer`` ``zone tocages count 50 own tame male not grazer``
Stuff up to 50 owned tame male animals who are not grazers into cages built Stuff up to 50 owned tame male animals who are not grazers into cages built
on the current default zone. on the current default zone.
autonestbox autonestbox
----------- -----------
Assigns unpastured female egg-layers to nestbox zones. Requires that you create Assigns unpastured female egg-layers to nestbox zones. Requires that you create
@ -1909,17 +1909,17 @@ You want to keep max 7 kids (4 female, 3 male) and max 3 adults (2 female,
slaughtered. Excess kids will get slaughtered starting with the youngest slaughtered. Excess kids will get slaughtered starting with the youngest
to allow that the older ones grow into adults. Any unnamed cats will to allow that the older ones grow into adults. Any unnamed cats will
be slaughtered as soon as possible. be slaughtered as soon as possible.
:: ::
autobutcher target 4 3 2 1 ALPACA BIRD_TURKEY autobutcher target 4 3 2 1 ALPACA BIRD_TURKEY
autobutcher target 0 0 0 0 CAT autobutcher target 0 0 0 0 CAT
autobutcher watch ALPACA BIRD_TURKEY CAT autobutcher watch ALPACA BIRD_TURKEY CAT
autobutcher start autobutcher start
Automatically put all new races onto the watchlist and mark unnamed tame units Automatically put all new races onto the watchlist and mark unnamed tame units
for slaughter as soon as they arrive in your fort. Settings already made for slaughter as soon as they arrive in your fort. Settings already made
for specific races will be left untouched. for specific races will be left untouched.
:: ::
autobutcher target 0 0 0 0 new autobutcher target 0 0 0 0 new
autobutcher autowatch autobutcher autowatch
@ -1931,16 +1931,16 @@ values again. Note: 'autobutcher unwatch all' works, but only makes sense
if you want to keep the plugin running with the 'autowatch' feature or manually if you want to keep the plugin running with the 'autowatch' feature or manually
add some new races with 'watch'. If you simply want to stop it completely use add some new races with 'watch'. If you simply want to stop it completely use
'autobutcher stop' instead. 'autobutcher stop' instead.
:: ::
autobutcher unwatch ALPACA CAT autobutcher unwatch ALPACA CAT
**Note:** **Note:**
Settings and watchlist are stored in the savegame, so that you can have Settings and watchlist are stored in the savegame, so that you can have
different settings for each world. If you want to copy your watchlist to different settings for each world. If you want to copy your watchlist to
another savegame you can use the command list_export: another savegame you can use the command list_export:
:: ::
Load savegame where you made the settings. Load savegame where you made the settings.
Start a CMD shell and navigate to the df directory. Type the following into the shell: Start a CMD shell and navigate to the df directory. Type the following into the shell:
@ -1966,21 +1966,21 @@ If you add
:: ::
enable getplants enable getplants
to your dfhack.init there will be a hotkey to open the dashboard from the chop designation to your dfhack.init there will be a hotkey to open the dashboard from the chop designation
menu. menu.
autolabor autolabor
--------- ---------
Automatically manage dwarf labors to efficiently complete jobs. Automatically manage dwarf labors to efficiently complete jobs.
Autolabor tries to keep as many dwarves as possible busy but Autolabor tries to keep as many dwarves as possible busy but
also tries to have dwarves specialize in specific skills. also tries to have dwarves specialize in specific skills.
The key is that, for almost all labors, once a dwarf begins a job it will finish that The key is that, for almost all labors, once a dwarf begins a job it will finish that
job even if the associated labor is removed. Autolabor therefore frequently checks job even if the associated labor is removed. Autolabor therefore frequently checks
which dwarf or dwarves should take new jobs for that labor, and sets labors accordingly. which dwarf or dwarves should take new jobs for that labor, and sets labors accordingly.
Labors with equiptment (mining, hunting, and woodcutting), which are abandoned Labors with equiptment (mining, hunting, and woodcutting), which are abandoned
if labors change mid-job, are handled slightly differently to minimise churn. if labors change mid-job, are handled slightly differently to minimise churn.
*Warning: autolabor will override any manual changes you make to labors* *Warning: autolabor will override any manual changes you make to labors*
@ -2007,22 +2007,23 @@ Advanced usage:
:`autolabor MINE 5`: Keep at least 5 dwarves with mining enabled. :`autolabor MINE 5`: Keep at least 5 dwarves with mining enabled.
:`autolabor CUT_GEM 1 1`: Keep exactly 1 dwarf with gemcutting enabled. :`autolabor CUT_GEM 1 1`: Keep exactly 1 dwarf with gemcutting enabled.
:`autolabor COOK 1 1 3`: Keep 1 dwarf with cooking enabled, selected only from the top 3.
:`autolabor FEED_WATER_CIVILIANS haulers`: Have haulers feed and water wounded dwarves. :`autolabor FEED_WATER_CIVILIANS haulers`: Have haulers feed and water wounded dwarves.
:`autolabor CUTWOOD disable`: Turn off autolabor for wood cutting. :`autolabor CUTWOOD disable`: Turn off autolabor for wood cutting.
By default, each labor is assigned to between 1 and 200 dwarves (2-200 for mining). By default, each labor is assigned to between 1 and 200 dwarves (2-200 for mining).
By default 33% of the workforce become haulers, who handle all hauling jobs as well By default 33% of the workforce become haulers, who handle all hauling jobs as well
as cleaning, pulling levers, recovering wounded, removing constructions, and filling ponds. as cleaning, pulling levers, recovering wounded, removing constructions, and filling ponds.
Other jobs are automatically assigned as described above. Each of these settings can be adjusted. Other jobs are automatically assigned as described above. Each of these settings can be adjusted.
Jobs are rarely assigned to nobles with responsibilities for meeting diplomats or merchants, Jobs are rarely assigned to nobles with responsibilities for meeting diplomats or merchants,
never to the chief medical dwarf, and less often to the bookeeper and manager. never to the chief medical dwarf, and less often to the bookeeper and manager.
Hunting is never assigned without a butchery, and fishing is nver assigned without a fishery. Hunting is never assigned without a butchery, and fishing is nver assigned without a fishery.
For each labor a preference order is calculated based on skill, biased against masters of other For each labor a preference order is calculated based on skill, biased against masters of other
trades and excluding those who can't do the job. The labor is then added to the best <minimum> trades and excluding those who can't do the job. The labor is then added to the best <minimum>
dwarves for that labor. We assign at least the minimum number of dwarfs, in order of preference, dwarves for that labor. We assign at least the minimum number of dwarfs, in order of preference,
and then assign additional dwarfs that meet any of these conditions: and then assign additional dwarfs that meet any of these conditions:
* The dwarf is idle and there are no idle dwarves assigned to this labor * The dwarf is idle and there are no idle dwarves assigned to this labor
@ -2112,7 +2113,7 @@ Known limitations: if the selected unit is currently performing a job, the mood
log-region log-region
---------- ----------
When enabled in dfhack.init, each time a fort is loaded identifying information will be written to the gamelog. Assists in parsing the file if you switch between forts, and adds information for story-building. When enabled in dfhack.init, each time a fort is loaded identifying information will be written to the gamelog. Assists in parsing the file if you switch between forts, and adds information for story-building.
======= =======
@ -2239,7 +2240,7 @@ A script to designate an area for digging according to a plan in csv format.
This script, inspired from quickfort, can designate an area for digging. This script, inspired from quickfort, can designate an area for digging.
Your plan should be stored in a .csv file like this:: Your plan should be stored in a .csv file like this::
# this is a comment # this is a comment
d;d;u;d;d;skip this tile;d d;d;u;d;d;skip this tile;d
d;d;d;i d;d;d;i
@ -2270,7 +2271,7 @@ Also works when selecting units from the 'u'nitlist viewscreen.
dfstatus dfstatus
======== ========
Show a quick overview of critical stock quantities, including food, dirnks, wood, and various bars. Show a quick overview of critical stock quantities, including food, dirnks, wood, and various bars.
embark embark
====== ======
@ -2614,8 +2615,8 @@ To activate, open the unit screen and press 'l'.
This tool implements a Dwarf Therapist-like interface within the game UI. The This tool implements a Dwarf Therapist-like interface within the game UI. The
far left column displays the unit's Happiness (color-coded based on its far left column displays the unit's Happiness (color-coded based on its
value), Name, Profession/Squad, and the right half of the screen displays each value), Name, Profession/Squad, and the right half of the screen displays each
dwarf's labor settings and skill levels (0-9 for Dabbling thru Professional, A-E for dwarf's labor settings and skill levels (0-9 for Dabbling thru Professional, A-E for
Great thru Grand Master, and U-Z for Legendary thru Legendary+5). Great thru Grand Master, and U-Z for Legendary thru Legendary+5).
Cells with teal backgrounds denote skills not controlled by labors, e.g. Cells with teal backgrounds denote skills not controlled by labors, e.g.
@ -2638,7 +2639,7 @@ Press Enter to toggle the selected labor for the selected unit, or Shift+Enter
to toggle all labors within the selected category. to toggle all labors within the selected category.
Press the ``+-`` keys to sort the unit list according to the currently selected Press the ``+-`` keys to sort the unit list according to the currently selected
skill/labor, and press the ``*/`` keys to sort the unit list by Name, Profession/Squad, skill/labor, and press the ``*/`` keys to sort the unit list by Name, Profession/Squad,
Happiness, or Arrival order (using Tab to select which sort method to use here). Happiness, or Arrival order (using Tab to select which sort method to use here).
With a unit selected, you can press the "v" key to view its properties (and With a unit selected, you can press the "v" key to view its properties (and
@ -2767,7 +2768,7 @@ gui/advfort
=========== ===========
This script allows to perform jobs in adventure mode. For more complete help This script allows to perform jobs in adventure mode. For more complete help
press '?' while script is running. It's most confortable to use this as a press '?' while script is running. It's most confortable to use this as a
keybinding. (e.g. keybinding set Ctrl-T gui/advfort). Possible arguments: keybinding. (e.g. keybinding set Ctrl-T gui/advfort). Possible arguments:
* -a or --nodfassign - uses different method to assign items. * -a or --nodfassign - uses different method to assign items.
@ -2776,7 +2777,7 @@ keybinding. (e.g. keybinding set Ctrl-T gui/advfort). Possible arguments:
* -c or --cheat - relaxes item requirements for buildings (e.g. walls from bones). * -c or --cheat - relaxes item requirements for buildings (e.g. walls from bones).
implies -a implies -a
* job - selects that job (e.g. Dig or FellTree) * job - selects that job (e.g. Dig or FellTree)
An example of player digging in adventure mode: An example of player digging in adventure mode:
@ -2842,7 +2843,7 @@ and selects the newly created copy.
gui/companion-order gui/companion-order
=================== ===================
A script to issue orders for companions. Select companions with lower case chars, issue orders with upper A script to issue orders for companions. Select companions with lower case chars, issue orders with upper
case. Must be in look or talk mode to issue command on tile. case. Must be in look or talk mode to issue command on tile.
.. image:: images/companion-order.png .. image:: images/companion-order.png
@ -2866,13 +2867,13 @@ There are three ways to open this editor:
* using gui/gm-editor <lua command> - executes lua command and opens editor on * using gui/gm-editor <lua command> - executes lua command and opens editor on
its results (e.g. gui/gm-editor "df.global.world.items.all" shows all items) its results (e.g. gui/gm-editor "df.global.world.items.all" shows all items)
* using gui/gm-editor dialog - shows an in game dialog to input lua command. Works * using gui/gm-editor dialog - shows an in game dialog to input lua command. Works
the same as version above. the same as version above.
.. image:: images/gm-editor.png .. image:: images/gm-editor.png
This editor allows to change and modify almost anything in df. Press '?' for an This editor allows to change and modify almost anything in df. Press '?' for an
in-game help. in-game help.
Hotkeys Hotkeys
@ -2898,13 +2899,13 @@ Type ``hotkeys`` into the DFHack console to open the screen, or bind the command
globally active hotkey in dfhack.init, e.g.: globally active hotkey in dfhack.init, e.g.:
``keybinding add Ctrl-F1 hotkeys`` ``keybinding add Ctrl-F1 hotkeys``
Stockpile Automation Stockpile Automation
==================== ====================
Enable the autodump plugin in your dfhack.init with Enable the autodump plugin in your dfhack.init with
``enable autodump`` ``enable autodump``
When querying a stockpile an option will appear to toggle autodump for this stockpile. When querying a stockpile an option will appear to toggle autodump for this stockpile.
Any items placed in this stockpile will be designated to be dumped. Any items placed in this stockpile will be designated to be dumped.

@ -4,6 +4,7 @@
# show all current key bindings # show all current key bindings
keybinding add Ctrl-F1 hotkeys keybinding add Ctrl-F1 hotkeys
keybinding add Alt-F1 hotkeys
# toggle the display of water level as 1-7 tiles # toggle the display of water level as 1-7 tiles
keybinding add Ctrl-W twaterlvl keybinding add Ctrl-W twaterlvl

@ -1,11 +1,30 @@
#!/bin/bash #!/bin/bash
# regenerate documentation after editing the .rst files. Requires python and docutils. # regenerate documentation after editing the .rst files. Requires python and docutils.
rst2html=$(which rst2html || which rst2html.py)
if [[ -z "$rst2html" ]]; then
echo "Docutils not found: See http://docutils.sourceforge.net/"
exit 1
fi
rst2html_version=$("$rst2html" --version | cut -d' ' -f3)
if [[ $(echo $rst2html_version | cut -d. -f2) -lt 12 ]]; then
echo "You are using docutils $rst2html_version. Docutils 0.12+ is recommended
to build these documents."
read -r -n1 -p "Continue? [y/N] " reply
echo
if [[ ! $reply =~ ^[Yy]$ ]]; then
exit
fi
fi
cd `dirname $0` cd `dirname $0`
function process() { function process() {
if [ "$1" -nt "$2" ]; then if [ "$1" -nt "$2" ]; then
rst2html --no-generator --no-datestamp "$1" "$2" echo -n "Updating $2... "
"$rst2html" --no-generator --no-datestamp "$1" "$2"
echo "Done"
else else
echo "$2 - up to date." echo "$2 - up to date."
fi fi

@ -1 +1 @@
Subproject commit a39ef9656e5eb257bf4c262eab3a7e7fd8b672c9 Subproject commit 55b60e3aa99aece7e9a239b041dc4f95a58dcef3

@ -359,7 +359,8 @@ static const dwarf_state dwarf_states[] = {
BUSY /* CarveTrack */, BUSY /* CarveTrack */,
BUSY /* PushTrackVehicle */, BUSY /* PushTrackVehicle */,
BUSY /* PlaceTrackVehicle */, BUSY /* PlaceTrackVehicle */,
BUSY /* StoreItemInVehicle */ BUSY /* StoreItemInVehicle */,
BUSY /* GeldAnimal */
}; };
struct labor_info struct labor_info
@ -378,6 +379,8 @@ struct labor_info
int maximum_dwarfs() { return config.ival(2); } int maximum_dwarfs() { return config.ival(2); }
void set_maximum_dwarfs(int maximum_dwarfs) { config.ival(2) = maximum_dwarfs; } void set_maximum_dwarfs(int maximum_dwarfs) { config.ival(2) = maximum_dwarfs; }
int talent_pool() { return config.ival(3); }
void set_talent_pool(int talent_pool) { config.ival(3) = talent_pool; }
}; };
struct labor_default struct labor_default
@ -471,7 +474,8 @@ static const struct labor_default default_labor_infos[] = {
/* HAUL_TRADE */ {HAULERS, false, 1, 200, 0}, /* HAUL_TRADE */ {HAULERS, false, 1, 200, 0},
/* PULL_LEVER */ {HAULERS, false, 1, 200, 0}, /* PULL_LEVER */ {HAULERS, false, 1, 200, 0},
/* REMOVE_CONSTRUCTION */ {HAULERS, false, 1, 200, 0}, /* REMOVE_CONSTRUCTION */ {HAULERS, false, 1, 200, 0},
/* HAUL_WATER */ {HAULERS, false, 1, 200, 0} /* HAUL_WATER */ {HAULERS, false, 1, 200, 0},
/* GELD */ {AUTOMATIC, false, 1, 200, 0}
}; };
static const int responsibility_penalties[] = { static const int responsibility_penalties[] = {
@ -543,6 +547,7 @@ static void reset_labor(df::unit_labor labor)
{ {
labor_infos[labor].set_minimum_dwarfs(default_labor_infos[labor].minimum_dwarfs); labor_infos[labor].set_minimum_dwarfs(default_labor_infos[labor].minimum_dwarfs);
labor_infos[labor].set_maximum_dwarfs(default_labor_infos[labor].maximum_dwarfs); labor_infos[labor].set_maximum_dwarfs(default_labor_infos[labor].maximum_dwarfs);
labor_infos[labor].set_talent_pool(200);
labor_infos[labor].set_mode(default_labor_infos[labor].mode); labor_infos[labor].set_mode(default_labor_infos[labor].mode);
} }
@ -650,7 +655,10 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
{ {
// initialize labor infos table from default table // initialize labor infos table from default table
if(ARRAY_COUNT(default_labor_infos) != ENUM_LAST_ITEM(unit_labor) + 1) if(ARRAY_COUNT(default_labor_infos) != ENUM_LAST_ITEM(unit_labor) + 1)
{
out.printerr("autolabor: labor size mismatch\n");
return CR_FAILURE; return CR_FAILURE;
}
// Fill the command list with your commands. // Fill the command list with your commands.
commands.push_back(PluginCommand( commands.push_back(PluginCommand(
@ -660,7 +668,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
" autolabor enable\n" " autolabor enable\n"
" autolabor disable\n" " autolabor disable\n"
" Enables or disables the plugin.\n" " Enables or disables the plugin.\n"
" autolabor <labor> <minimum> [<maximum>]\n" " autolabor <labor> <minimum> [<maximum>] [<talent pool>]\n"
" Set number of dwarves assigned to a labor.\n" " Set number of dwarves assigned to a labor.\n"
" autolabor <labor> haulers\n" " autolabor <labor> haulers\n"
" Set a labor to be handled by hauler dwarves.\n" " Set a labor to be handled by hauler dwarves.\n"
@ -682,11 +690,15 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
" while it is enabled.\n" " while it is enabled.\n"
" To prevent particular dwarves from being managed by autolabor, put them\n" " To prevent particular dwarves from being managed by autolabor, put them\n"
" in any burrow.\n" " in any burrow.\n"
" To restrict the assignment of a labor to only the top <n> most skilled\n"
" dwarves, add a talent pool number <n>.\n"
"Examples:\n" "Examples:\n"
" autolabor MINE 2\n" " autolabor MINE 2\n"
" Keep at least 2 dwarves with mining enabled.\n" " Keep at least 2 dwarves with mining enabled.\n"
" autolabor CUT_GEM 1 1\n" " autolabor CUT_GEM 1 1\n"
" Keep exactly 1 dwarf with gemcutting enabled.\n" " Keep exactly 1 dwarf with gemcutting enabled.\n"
" autolabor COOK 1 1 3\n"
" Keep 1 dwarf with cooking enabled, selected only from the top 3.\n"
" autolabor FEED_WATER_CIVILIANS haulers\n" " autolabor FEED_WATER_CIVILIANS haulers\n"
" Have haulers feed and water wounded dwarves.\n" " Have haulers feed and water wounded dwarves.\n"
" autolabor CUTWOOD disable\n" " autolabor CUTWOOD disable\n"
@ -758,6 +770,7 @@ static void assign_labor(unit_labor::unit_labor labor,
std::vector<int> values(n_dwarfs); std::vector<int> values(n_dwarfs);
std::vector<int> candidates; std::vector<int> candidates;
std::map<int, int> dwarf_skill; std::map<int, int> dwarf_skill;
std::map<int, int> dwarf_skillxp;
std::vector<bool> previously_enabled(n_dwarfs); std::vector<bool> previously_enabled(n_dwarfs);
auto mode = labor_infos[labor].mode(); auto mode = labor_infos[labor].mode();
@ -795,6 +808,7 @@ static void assign_labor(unit_labor::unit_labor labor,
} }
dwarf_skill[dwarf] = skill_level; dwarf_skill[dwarf] = skill_level;
dwarf_skillxp[dwarf] = skill_experience;
value += skill_level * 100; value += skill_level * 100;
value += skill_experience / 20; value += skill_experience / 20;
@ -825,6 +839,32 @@ static void assign_labor(unit_labor::unit_labor labor,
} }
int pool = labor_infos[labor].talent_pool();
if (pool < 200 && candidates.size() > 1 && pool < candidates.size())
{
// Sort in descending order
std::sort(candidates.begin(), candidates.end(), [&](const int lhs, const int rhs) -> bool {
if (dwarf_skill[lhs] == dwarf_skill[rhs])
return dwarf_skillxp[lhs] > dwarf_skillxp[rhs];
else
return dwarf_skill[lhs] > dwarf_skill[rhs];
});
// Check if all dwarves have equivalent skills, usually zero
int first_dwarf = candidates[0];
int last_dwarf = candidates[candidates.size() - 1];
if (dwarf_skill[first_dwarf] == dwarf_skill[last_dwarf] &&
dwarf_skillxp[first_dwarf] == dwarf_skillxp[last_dwarf])
{
// There's no difference in skill, so change nothing
}
else
{
// Trim down to our top talents
candidates.resize(pool);
}
}
// Sort candidates by preference value // Sort candidates by preference value
values_sorter ivs(values); values_sorter ivs(values);
std::sort(candidates.begin(), candidates.end(), ivs); std::sort(candidates.begin(), candidates.end(), ivs);
@ -1294,7 +1334,8 @@ void print_labor (df::unit_labor labor, color_ostream &out)
if (labor_infos[labor].mode() == HAULERS) if (labor_infos[labor].mode() == HAULERS)
out << "haulers"; out << "haulers";
else else
out << "minimum " << labor_infos[labor].minimum_dwarfs() << ", maximum " << labor_infos[labor].maximum_dwarfs(); out << "minimum " << labor_infos[labor].minimum_dwarfs() << ", maximum " << labor_infos[labor].maximum_dwarfs()
<< ", pool " << labor_infos[labor].talent_pool();
out << ", currently " << labor_infos[labor].active_dwarfs << " dwarfs" << endl; out << ", currently " << labor_infos[labor].active_dwarfs << " dwarfs" << endl;
} }
} }
@ -1350,7 +1391,7 @@ command_result autolabor (color_ostream &out, std::vector <std::string> & parame
hauler_pct = pct; hauler_pct = pct;
return CR_OK; return CR_OK;
} }
else if (parameters.size() == 2 || parameters.size() == 3) else if (parameters.size() >= 2 && parameters.size() <= 4)
{ {
if (!enable_autolabor) if (!enable_autolabor)
{ {
@ -1393,17 +1434,22 @@ command_result autolabor (color_ostream &out, std::vector <std::string> & parame
int minimum = atoi (parameters[1].c_str()); int minimum = atoi (parameters[1].c_str());
int maximum = 200; int maximum = 200;
if (parameters.size() == 3) int pool = 200;
if (parameters.size() >= 3)
maximum = atoi (parameters[2].c_str()); maximum = atoi (parameters[2].c_str());
if (parameters.size() == 4)
pool = std::stoi(parameters[3]);
if (maximum < minimum || maximum < 0 || minimum < 0) if (maximum < minimum || maximum < 0 || minimum < 0 || pool < 0)
{ {
out.printerr("Syntax: autolabor <labor> <minimum> [<maximum>]\n", maximum, minimum); out.printerr("Syntax: autolabor <labor> <minimum> [<maximum>] [<talent pool>]\n", maximum, minimum);
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
} }
labor_infos[labor].set_minimum_dwarfs(minimum); labor_infos[labor].set_minimum_dwarfs(minimum);
labor_infos[labor].set_maximum_dwarfs(maximum); labor_infos[labor].set_maximum_dwarfs(maximum);
labor_infos[labor].set_talent_pool(pool);
labor_infos[labor].set_mode(AUTOMATIC); labor_infos[labor].set_mode(AUTOMATIC);
print_labor(labor, out); print_labor(labor, out);

@ -141,6 +141,7 @@ const SkillColumn columns[] = {
{5, 6, profession::COOK, unit_labor::COOK, job_skill::COOK, "Co"}, {5, 6, profession::COOK, unit_labor::COOK, job_skill::COOK, "Co"},
{5, 6, profession::PRESSER, unit_labor::PRESSING, job_skill::PRESSING, "Pr"}, {5, 6, profession::PRESSER, unit_labor::PRESSING, job_skill::PRESSING, "Pr"},
{5, 6, profession::BEEKEEPER, unit_labor::BEEKEEPING, job_skill::BEEKEEPING, "Be"}, {5, 6, profession::BEEKEEPER, unit_labor::BEEKEEPING, job_skill::BEEKEEPING, "Be"},
{5, 6, profession::GELDER, unit_labor::GELD, job_skill::GELD, "Ge"},
// Fishing/Related // Fishing/Related
{6, 1, profession::FISHERMAN, unit_labor::FISH, job_skill::FISH, "Fi"}, {6, 1, profession::FISHERMAN, unit_labor::FISH, job_skill::FISH, "Fi"},
{6, 1, profession::FISH_CLEANER, unit_labor::CLEAN_FISH, job_skill::PROCESSFISH, "Cl"}, {6, 1, profession::FISH_CLEANER, unit_labor::CLEAN_FISH, job_skill::PROCESSFISH, "Cl"},

@ -655,6 +655,13 @@ public:
void feed(set<df::interface_key> *input) void feed(set<df::interface_key> *input)
{ {
if (input->count(interface_key::LEAVESCREEN))
{
input->clear();
Screen::dismiss(this);
return;
}
bool key_processed = false; bool key_processed = false;
switch (selected_column) switch (selected_column)
{ {
@ -666,13 +673,6 @@ public:
if (key_processed) if (key_processed)
return; return;
if (input->count(interface_key::LEAVESCREEN))
{
input->clear();
Screen::dismiss(this);
return;
}
if (input->count(interface_key::CUSTOM_CTRL_J)) if (input->count(interface_key::CUSTOM_CTRL_J))
{ {
hide_flags.bits.in_job = !hide_flags.bits.in_job; hide_flags.bits.in_job = !hide_flags.bits.in_job;

@ -0,0 +1,69 @@
-- Executes an autolabor command for each labor where skill level influences output quality.
local artisan_labors = {
"CARPENTER",
"DETAIL",
"MASON",
"ARCHITECT",
"ANIMALTRAIN",
"LEATHER",
"BREWER",
"WEAVER",
"CLOTHESMAKER",
"COOK",
"FORGE_WEAPON",
"FORGE_ARMOR",
"FORGE_FURNITURE",
"METAL_CRAFT",
"CUT_GEM",
"ENCRUST_GEM",
"WOOD_CRAFT",
"STONE_CRAFT",
"BONE_CARVE",
"GLASSMAKER",
"SIEGECRAFT",
"BOWYER",
"MECHANIC",
"DYER",
"POTTERY",
"WAX_WORKING",
}
local args = {...}
function make_cmd(labor)
local cmd = string.format("autolabor %s", labor)
for i, arg in ipairs(args) do
cmd = cmd .. " " .. arg
end
return cmd
end
function run()
if #args == 0 or args[1] == "help" then
print('Applies an autolabor command to all labors with quality-based output.')
print('')
print('Examples:')
print(' autolabor-artisans 0 2 3')
print(' autolabor-artisans disable')
return false
end
dfhack.run_command("autolabor enable")
-- Test with one to make sure the arguments are valid.
local cmd = make_cmd(artisan_labors[1])
local output, status = dfhack.run_command_silent(cmd)
if status ~= CR_OK then
qerror("Invalid arguments.", status)
return false
end
for i, labor in ipairs(artisan_labors) do
dfhack.run_command(make_cmd(labor))
end
return true
end
run()

@ -201,6 +201,11 @@ address('id',df.history_event,'id')
address('killed_hist_id',df.history_event_hist_figure_diedst,'victim_hf') address('killed_hist_id',df.history_event_hist_figure_diedst,'victim_hf')
header('item_offsets') header('item_offsets')
if os_type == 'darwin' then
value('item_type',0x4)
else
value('item_type',0x1)
end
address('item_def',df.item_ammost,'subtype') --currently same for all address('item_def',df.item_ammost,'subtype') --currently same for all
address('id',df.item,'id') address('id',df.item,'id')
address('general_refs',df.item,'general_refs') address('general_refs',df.item,'general_refs')
@ -306,13 +311,12 @@ address('turn_count',df.unit,'curse','time_on_site')
address('souls',df.unit,'status','souls') address('souls',df.unit,'status','souls')
address('states',df.unit,'status','misc_traits') address('states',df.unit,'status','misc_traits')
address('labors',df.unit,'status','labors') address('labors',df.unit,'status','labors')
--address('thoughts',df.unit,'status','recent_events')
--address('happiness',df.unit,'status','happiness')
address('hist_id',df.unit,'hist_figure_id') address('hist_id',df.unit,'hist_figure_id')
address('artifact_name',df.unit,'status','artifact_name') address('artifact_name',df.unit,'status','artifact_name')
address('active_syndrome_vector',df.unit,'syndromes','active') address('active_syndrome_vector',df.unit,'syndromes','active')
address('syn_sick_flag',df.unit_syndrome,'flags') address('syn_sick_flag',df.unit_syndrome,'flags')
address('unit_health_info',df.unit,'health') address('unit_health_info',df.unit,'health')
address('temp_mood',df.unit,'counters','soldier_mood')
address('counters1',df.unit,'counters','winded') address('counters1',df.unit,'counters','winded')
address('counters2',df.unit, 'counters','pain') address('counters2',df.unit, 'counters','pain')
address('counters3',df.unit, 'counters2','paralysis') address('counters3',df.unit, 'counters2','paralysis')
@ -358,9 +362,20 @@ address('skills',df.unit_soul,'skills')
address('preferences',df.unit_soul,'preferences') address('preferences',df.unit_soul,'preferences')
address('personality',df.unit_soul,'personality') address('personality',df.unit_soul,'personality')
address('beliefs',df.unit_personality,'values') address('beliefs',df.unit_personality,'values')
address('emotions',df.unit_personality,'emotions')
address('goals',df.unit_personality,'dreams') address('goals',df.unit_personality,'dreams')
address('goal_realized',df.unit_personality.T_dreams,'unk8') address('goal_realized',df.unit_personality.T_dreams,'unk8')
address('traits',df.unit_personality,'traits') address('traits',df.unit_personality,'traits')
address('stress_level',df.unit_personality,'stress_level')
header('emotion_offsets')
address('emotion_type',df.unit_personality.T_emotions,'type')
address('strength',df.unit_personality.T_emotions,'strength')
address('thought_id',df.unit_personality.T_emotions,'thought')
address('sub_id',df.unit_personality.T_emotions,'subthought')
address('level',df.unit_personality.T_emotions,'severity')
address('year',df.unit_personality.T_emotions,'year')
address('year_tick',df.unit_personality.T_emotions,'year_tick')
header('job_details') header('job_details')
address('id',df.job,'job_type') address('id',df.job,'job_type')
@ -426,8 +441,8 @@ size=10
5\value=0x00020000 5\value=0x00020000
6\name=an invader or hostile 6\name=an invader or hostile
6\value=0x00080000 6\value=0x00080000
7\name=an invader or hostile 7\name=resident, invader or ambusher
7\value=0x000C0000 7\value=0x00600000
8\name=part of a merchant caravan 8\name=part of a merchant caravan
8\value=0x00000080 8\value=0x00000080
9\name="Dead, Jim." 9\name="Dead, Jim."
@ -443,7 +458,7 @@ size=5
2\value=0x00040000 2\value=0x00040000
3\name=resident 3\name=resident
3\value=0x00080000 3\value=0x00080000
4\name=visitor_uninvited 4\name=uninvited visitor
4\value=0x00400000 4\value=0x00400000
5\name=visitor 5\name=visitor
5\value=0x00800000 5\value=0x00800000
@ -454,4 +469,4 @@ size=1
1\value=0x00001000 1\value=0x00001000
]] ]]
out:close() out:close()

@ -0,0 +1,492 @@
#!/usr/bin/perl
use strict;
use warnings;
my ($version, $timestamp, $hash);
open FH, 'version.lisp' or die "Cannot open version";
while (<FH>) {
if (/df-version-str.*\"(.*)\"/) {
$version = $1;
} elsif (/windows-timestamp.*#x([0-9a-f]+)/) {
$timestamp = $1;
} elsif (/linux-hash.*\"(.*)\"/) {
$hash = $1;
}
}
close FH;
sub load_csv(\%$) {
my ($rhash, $fname) = @_;
open FH, $fname or die "Cannot open $fname";
while (<FH>) {
next unless /^\"([^\"]*)\",\"(\d+)\",\"(?:0x([0-9a-fA-F]+))?\",\"[^\"]*\",\"([^\"]*)\",\"([^\"]*)\",\"([^\"]*)\"/;
my ($top, $level, $addr, $type, $name, $target) = ($1,$2,$3,$4,$5,$6);
next if defined $rhash->{$top}{$name};
$rhash->{$top}{$name} = ($type eq 'enum-item' ? $target : hex $addr);
}
close FH;
}
our $complete;
sub lookup_addr(\%$$;$) {
my ($rhash, $top, $name, $bias) = @_;
my $val = $rhash->{$top}{$name};
unless (defined $val) {
$complete = 0;
return 0;
}
return $val + ($bias||0);
}
our @lines;
sub emit_header($) {
my ($name) = @_;
push @lines, '' if @lines;
push @lines, "[$name]";
}
sub emit_addr($\%$$;$) {
my ($name, $rhash, $top, $var, $bias) = @_;
my $val = $rhash->{$top}{$var};
if (defined $val) {
$val += ($bias||0);
if ($val < 0x10000) {
push @lines, sprintf('%s=0x%04x', $name, $val);
} else {
push @lines, sprintf('%s=0x%08x', $name, $val);
}
} else {
$complete = 0;
push @lines, "$name=0x0";
}
}
sub generate_dt_ini($$$$) {
my ($subdir, $version, $checksum, $ssize) = @_;
my %globals;
load_csv %globals, "$subdir/globals.csv";
my %all;
load_csv %all, "$subdir/all.csv";
local $complete = 1;
local @lines;
emit_header 'addresses';
emit_addr 'translation_vector',%globals,'world','world.raws.language.translations';
emit_addr 'language_vector',%globals,'world','world.raws.language.words';
emit_addr 'creature_vector',%globals,'world','world.units.all';
emit_addr 'active_creature_vector',%globals,'world','world.units.active';
emit_addr 'dwarf_race_index',%globals,'ui','ui.race_id';
emit_addr 'squad_vector',%globals,'world','world.squads.all';
emit_addr 'current_year',%globals,'cur_year','cur_year';
emit_addr 'cur_year_tick',%globals,'cur_year_tick','cur_year_tick';
emit_addr 'dwarf_civ_index',%globals,'ui','ui.civ_id';
emit_addr 'races_vector',%globals,'world','world.raws.creatures.all';
emit_addr 'reactions_vector',%globals,'world','world.raws.reactions';
emit_addr 'events_vector',%globals,'world','world.history.events';
emit_addr 'historical_figures_vector',%globals,'world','world.history.figures';
emit_addr 'fake_identities_vector',%globals,'world','world.identities.all';
emit_addr 'fortress_entity',%globals,'ui','ui.main.fortress_entity';
emit_addr 'historical_entities_vector',%globals,'world','world.entities.all';
emit_addr 'itemdef_weapons_vector',%globals,'world','world.raws.itemdefs.weapons';
emit_addr 'itemdef_trap_vector',%globals,'world','world.raws.itemdefs.trapcomps';
emit_addr 'itemdef_toy_vector',%globals,'world','world.raws.itemdefs.toys';
emit_addr 'itemdef_tool_vector',%globals,'world','world.raws.itemdefs.tools';
emit_addr 'itemdef_instrument_vector',%globals,'world','world.raws.itemdefs.instruments';
emit_addr 'itemdef_armor_vector',%globals,'world','world.raws.itemdefs.armor';
emit_addr 'itemdef_ammo_vector',%globals,'world','world.raws.itemdefs.ammo';
emit_addr 'itemdef_siegeammo_vector',%globals,'world','world.raws.itemdefs.siege_ammo';
emit_addr 'itemdef_glove_vector',%globals,'world','world.raws.itemdefs.gloves';
emit_addr 'itemdef_shoe_vector',%globals,'world','world.raws.itemdefs.shoes';
emit_addr 'itemdef_shield_vector',%globals,'world','world.raws.itemdefs.shields';
emit_addr 'itemdef_helm_vector',%globals,'world','world.raws.itemdefs.helms';
emit_addr 'itemdef_pant_vector',%globals,'world','world.raws.itemdefs.pants';
emit_addr 'itemdef_food_vector',%globals,'world','world.raws.itemdefs.food';
emit_addr 'colors_vector',%globals,'world','world.raws.language.colors';
emit_addr 'shapes_vector',%globals,'world','world.raws.language.shapes';
emit_addr 'base_materials',%globals,'world','world.raws.mat_table.builtin';
emit_addr 'inorganics_vector',%globals,'world','world.raws.inorganics';
emit_addr 'plants_vector',%globals,'world','world.raws.plants.all';
emit_addr 'material_templates_vector',%globals,'world','world.raws.material_templates';
emit_addr 'all_syndromes_vector',%globals,'world','world.raws.syndromes.all';
emit_addr 'world_data',%globals,'world','world.world_data';
emit_addr 'active_sites_vector',%all,'world_data','active_site';
emit_addr 'world_site_type',%all,'world_site','type';
emit_addr 'weapons_vector',%globals,'world','world.items.other[WEAPON]';
emit_addr 'shields_vector',%globals,'world','world.items.other[SHIELD]';
emit_addr 'quivers_vector',%globals,'world','world.items.other[QUIVER]';
emit_addr 'crutches_vector',%globals,'world','world.items.other[CRUTCH]';
emit_addr 'backpacks_vector',%globals,'world','world.items.other[BACKPACK]';
emit_addr 'ammo_vector',%globals,'world','world.items.other[AMMO]';
emit_addr 'flasks_vector',%globals,'world','world.items.other[FLASK]';
emit_addr 'pants_vector',%globals,'world','world.items.other[PANTS]';
emit_addr 'armor_vector',%globals,'world','world.items.other[ARMOR]';
emit_addr 'shoes_vector',%globals,'world','world.items.other[SHOES]';
emit_addr 'helms_vector',%globals,'world','world.items.other[HELM]';
emit_addr 'gloves_vector',%globals,'world','world.items.other[GLOVES]';
emit_addr 'artifacts_vector',%globals,'world','world.artifacts.all';
emit_header 'offsets';
emit_addr 'word_table',%all,'language_translation','words';
push @lines, 'string_buffer_offset=0x0000';
emit_header 'word_offsets';
emit_addr 'base',%all,'language_word','word';
emit_addr 'noun_singular',%all,'language_word','forms[Noun]';
emit_addr 'noun_plural',%all,'language_word','forms[NounPlural]';
emit_addr 'adjective',%all,'language_word','forms[Adjective]';
emit_addr 'verb',%all,'language_word','forms[Verb]';
emit_addr 'present_simple_verb',%all,'language_word','forms[Verb3rdPerson]';
emit_addr 'past_simple_verb',%all,'language_word','forms[VerbPast]';
emit_addr 'past_participle_verb',%all,'language_word','forms[VerbPassive]';
emit_addr 'present_participle_verb',%all,'language_word','forms[VerbGerund]';
emit_addr 'words',%all,'language_name','words';
emit_addr 'word_type',%all,'language_name','parts_of_speech';
emit_addr 'language_id',%all,'language_name','language';
emit_header 'general_ref_offsets';
emit_addr 'ref_type',%all,'general_ref::vtable','getType';
emit_addr 'artifact_id',%all,'general_ref_artifact','artifact_id';
emit_addr 'item_id',%all,'general_ref_item','item_id';
emit_header 'race_offsets';
emit_addr 'name_singular',%all,'creature_raw','name';
emit_addr 'name_plural',%all,'creature_raw','name',$ssize;
emit_addr 'adjective',%all,'creature_raw','name',$ssize*2;
emit_addr 'baby_name_singular',%all,'creature_raw','general_baby_name';
emit_addr 'baby_name_plural',%all,'creature_raw','general_baby_name',$ssize;
emit_addr 'child_name_singular',%all,'creature_raw','general_child_name';
emit_addr 'child_name_plural',%all,'creature_raw','general_child_name',$ssize;
emit_addr 'pref_string_vector',%all,'creature_raw','prefstring';
emit_addr 'castes_vector',%all,'creature_raw','caste';
emit_addr 'pop_ratio_vector',%all,'creature_raw','pop_ratio';
emit_addr 'materials_vector',%all,'creature_raw','material';
emit_addr 'flags',%all,'creature_raw','flags';
emit_addr 'tissues_vector',%all,'creature_raw','tissue';
emit_header 'caste_offsets';
emit_addr 'caste_name',%all,'caste_raw','caste_name';
emit_addr 'caste_descr',%all,'caste_raw','description';
emit_addr 'caste_trait_ranges',%all,'caste_raw','personality.a';
emit_addr 'caste_phys_att_ranges',%all,'caste_raw','attributes.phys_att_range';
emit_addr 'baby_age',%all,'caste_raw','misc.baby_age';
emit_addr 'child_age',%all,'caste_raw','misc.child_age';
emit_addr 'adult_size',%all,'caste_raw','misc.adult_size';
emit_addr 'flags',%all,'caste_raw','flags';
emit_addr 'body_info',%all,'caste_raw','body_info';
emit_addr 'skill_rates',%all,'caste_raw','skill_rates';
emit_addr 'caste_att_rates',%all,'caste_raw','attributes.phys_att_rates';
emit_addr 'caste_att_caps',%all,'caste_raw','attributes.phys_att_cap_perc';
emit_addr 'shearable_tissues_vector',%all,'caste_raw','shearable_tissue_layer';
emit_addr 'extracts',%all,'caste_raw','extracts.extract_matidx';
emit_header 'hist_entity_offsets';
emit_addr 'beliefs',%all,'historical_entity','resources.values';
emit_addr 'squads',%all,'historical_entity','squads';
emit_addr 'positions',%all,'historical_entity','positions.own';
emit_addr 'assignments',%all,'historical_entity','positions.assignments';
emit_addr 'assign_hist_id',%all,'entity_position_assignment','histfig';
emit_addr 'assign_position_id',%all,'entity_position_assignment','position_id';
emit_addr 'position_id',%all,'entity_position','id';
emit_addr 'position_name',%all,'entity_position','name';
emit_addr 'position_female_name',%all,'entity_position','name_female';
emit_addr 'position_male_name',%all,'entity_position','name_male';
emit_header 'hist_figure_offsets';
emit_addr 'hist_race',%all,'historical_figure','race';
emit_addr 'hist_name',%all,'historical_figure','name';
emit_addr 'id',%all,'historical_figure','id';
emit_addr 'hist_fig_info',%all,'historical_figure','info';
emit_addr 'reputation',%all,'historical_figure_info','reputation';
emit_addr 'current_ident',%all,'historical_figure_info::anon13','cur_identity';
emit_addr 'fake_name',%all,'identity','name';
emit_addr 'fake_birth_year',%all,'identity','birth_year';
emit_addr 'fake_birth_time',%all,'identity','birth_second';
emit_addr 'kills',%all,'historical_figure_info','kills';
emit_addr 'killed_race_vector',%all,'historical_kills','killed_race';
emit_addr 'killed_undead_vector',%all,'historical_kills','killed_undead';
emit_addr 'killed_counts_vector',%all,'historical_kills','killed_count';
emit_header 'hist_event_offsets';
emit_addr 'event_year',%all,'history_event','year';
emit_addr 'id',%all,'history_event','id';
emit_addr 'killed_hist_id',%all,'history_event_hist_figure_diedst','victim_hf';
emit_header 'item_offsets';
if ($subdir eq 'osx') {
push @lines, 'item_type=0x0004';
} else {
push @lines, 'item_type=0x0001';
}
emit_addr 'item_def',%all,'item_ammost','subtype'; #currently same for all
emit_addr 'id',%all,'item','id';
emit_addr 'general_refs',%all,'item','general_refs';
emit_addr 'stack_size',%all,'item_actual','stack_size';
emit_addr 'wear',%all,'item_actual','wear';
emit_addr 'mat_type',%all,'item_crafted','mat_type';
emit_addr 'mat_index',%all,'item_crafted','mat_index';
emit_addr 'quality',%all,'item_crafted','quality';
emit_header 'item_subtype_offsets';
emit_addr 'sub_type',%all,'itemdef','subtype';
emit_addr 'name',%all,'itemdef_armorst','name';
emit_addr 'name_plural',%all,'itemdef_armorst','name_plural';
emit_addr 'adjective',%all,'itemdef_armorst','name_preplural';
emit_header 'item_filter_offsets';
emit_addr 'item_subtype',%all,'item_filter_spec','item_subtype';
emit_addr 'mat_class',%all,'item_filter_spec','material_class';
emit_addr 'mat_type',%all,'item_filter_spec','mattype';
emit_addr 'mat_index',%all,'item_filter_spec','matindex';
emit_header 'weapon_subtype_offsets';
emit_addr 'single_size',%all,'itemdef_weaponst','two_handed';
emit_addr 'multi_size',%all,'itemdef_weaponst','minimum_size';
emit_addr 'ammo',%all,'itemdef_weaponst','ranged_ammo';
emit_addr 'melee_skill',%all,'itemdef_weaponst','skill_melee';
emit_addr 'ranged_skill',%all,'itemdef_weaponst','skill_ranged';
emit_header 'armor_subtype_offsets';
emit_addr 'layer',%all,'armor_properties','layer';
emit_addr 'mat_name',%all,'itemdef_armorst','material_placeholder';
emit_addr 'other_armor_level',%all,'itemdef_helmst','armorlevel';
emit_addr 'armor_adjective',%all,'itemdef_armorst','adjective';
emit_addr 'armor_level',%all,'itemdef_armorst','armorlevel';
emit_addr 'chest_armor_properties',%all,'itemdef_armorst','props';
emit_addr 'pants_armor_properties',%all,'itemdef_pantsst','props';
emit_addr 'other_armor_properties',%all,'itemdef_helmst','props';
emit_header 'material_offsets';
emit_addr 'solid_name',%all,'material_common','state_name[Solid]';
emit_addr 'liquid_name',%all,'material_common','state_name[Liquid]';
emit_addr 'gas_name',%all,'material_common','state_name[Gas]';
emit_addr 'powder_name',%all,'material_common','state_name[Powder]';
emit_addr 'paste_name',%all,'material_common','state_name[Paste]';
emit_addr 'pressed_name',%all,'material_common','state_name[Pressed]';
emit_addr 'flags',%all,'material_common','flags';
emit_addr 'inorganic_materials_vector',%all,'inorganic_raw','material';
emit_addr 'inorganic_flags',%all,'inorganic_raw','flags';
emit_header 'plant_offsets';
emit_addr 'name',%all,'plant_raw','name';
emit_addr 'name_plural',%all,'plant_raw','name_plural';
emit_addr 'name_leaf_plural',%all,'plant_raw','leaves_plural';
emit_addr 'name_seed_plural',%all,'plant_raw','seed_plural';
emit_addr 'materials_vector',%all,'plant_raw','material';
emit_addr 'flags',%all,'plant_raw','flags';
emit_header 'descriptor_offsets';
emit_addr 'color_name',%all,'descriptor_color','name';
emit_addr 'shape_name_plural',%all,'descriptor_shape','name_plural';
emit_header 'health_offsets';
emit_addr 'parent_id',%all,'body_part_raw','con_part_id';
emit_addr 'layers_vector',%all,'body_part_raw','layers';
emit_addr 'number',%all,'body_part_raw','number';
emit_addr 'names_vector',%all,'body_part_raw','name_singular';
emit_addr 'names_plural_vector',%all,'body_part_raw','name_plural';
emit_addr 'layer_tissue',%all,'body_part_layer_raw','tissue_id';
emit_addr 'layer_global_id',%all,'body_part_layer_raw','layer_id';
emit_addr 'tissue_name',%all,'tissue_template','tissue_name_singular';
emit_addr 'tissue_flags',%all,'tissue_template','flags';
emit_header 'dwarf_offsets';
emit_addr 'first_name',%all,'unit','name',lookup_addr(%all,'language_name','first_name');
emit_addr 'nick_name',%all,'unit','name',lookup_addr(%all,'language_name','nickname');
emit_addr 'last_name',%all,'unit','name',lookup_addr(%all,'language_name','words');
emit_addr 'custom_profession',%all,'unit','custom_profession';
emit_addr 'profession',%all,'unit','profession';
emit_addr 'race',%all,'unit','race';
emit_addr 'flags1',%all,'unit','flags1';
emit_addr 'flags2',%all,'unit','flags2';
emit_addr 'flags3',%all,'unit','flags3';
emit_addr 'caste',%all,'unit','caste';
emit_addr 'sex',%all,'unit','sex';
emit_addr 'id',%all,'unit','id';
emit_addr 'animal_type',%all,'unit','training_level';
emit_addr 'civ',%all,'unit','civ_id';
emit_addr 'specific_refs',%all,'unit','specific_refs';
emit_addr 'squad_id',%all,'unit','military.squad_id';
emit_addr 'squad_position',%all,'unit','military.squad_position';
emit_addr 'recheck_equipment',%all,'unit','military.pickup_flags';
emit_addr 'mood',%all,'unit','mood';
emit_addr 'birth_year',%all,'unit','relations.birth_year';
emit_addr 'birth_time',%all,'unit','relations.birth_time';
emit_addr 'pet_owner_id',%all,'unit','relations.pet_owner_id';
emit_addr 'current_job',%all,'unit','job.current_job';
emit_addr 'physical_attrs',%all,'unit','body.physical_attrs';
emit_addr 'body_size',%all,'unit','appearance.body_modifiers';
emit_addr 'size_info',%all,'unit','body.size_info';
emit_addr 'curse',%all,'unit','curse.name';
emit_addr 'curse_add_flags1',%all,'unit','curse.add_tags1';
emit_addr 'turn_count',%all,'unit','curse.time_on_site';
emit_addr 'souls',%all,'unit','status.souls';
emit_addr 'states',%all,'unit','status.misc_traits';
emit_addr 'labors',%all,'unit','status.labors';
emit_addr 'hist_id',%all,'unit','hist_figure_id';
emit_addr 'artifact_name',%all,'unit','status.artifact_name';
emit_addr 'active_syndrome_vector',%all,'unit','syndromes.active';
emit_addr 'syn_sick_flag',%all,'unit_syndrome','flags.is_sick';
emit_addr 'unit_health_info',%all,'unit','health';
emit_addr 'temp_mood',%all,'unit','counters.soldier_mood';
emit_addr 'counters1',%all,'unit','counters.winded';
emit_addr 'counters2',%all,'unit','counters.pain';
emit_addr 'counters3',%all,'unit','counters2.paralysis';
emit_addr 'limb_counters',%all,'unit','status2.limbs_stand_max';
emit_addr 'blood',%all,'unit','body.blood_max';
emit_addr 'body_component_info',%all,'unit','body.components';
emit_addr 'layer_status_vector',%all,'body_component_info','layer_status';
emit_addr 'wounds_vector',%all,'unit','body.wounds';
emit_addr 'mood_skill',%all,'unit','job.mood_skill';
emit_addr 'used_items_vector',%all,'unit','used_items';
emit_addr 'affection_level',%all,'unit_item_use','affection_level';
emit_addr 'inventory',%all,'unit','inventory';
emit_addr 'inventory_item_mode',%all,'unit_inventory_item','mode';
emit_addr 'inventory_item_bodypart',%all,'unit_inventory_item','body_part_id';
emit_header 'syndrome_offsets';
emit_addr 'cie_effects',%all,'syndrome','ce';
emit_addr 'cie_end',%all,'creature_interaction_effect','end';
emit_addr 'cie_first_perc',%all,'creature_interaction_effect_phys_att_changest','phys_att_perc'; #same for mental
emit_addr 'cie_phys',%all,'creature_interaction_effect_phys_att_changest','phys_att_add';
emit_addr 'cie_ment',%all,'creature_interaction_effect_ment_att_changest','ment_att_add';
emit_addr 'syn_classes_vector',%all,'syndrome','syn_class';
emit_addr 'trans_race_id',%all,'creature_interaction_effect_body_transformationst','race';
emit_header 'unit_wound_offsets';
emit_addr 'parts',%all,'unit_wound','parts';
emit_addr 'id',%all,'unit_wound::anon2','body_part_id';
emit_addr 'layer',%all,'unit_wound::anon2','layer_idx';
emit_addr 'general_flags',%all,'unit_wound','flags';
emit_addr 'flags1',%all,'unit_wound::anon2','flags1';
emit_addr 'flags2',%all,'unit_wound::anon2','flags2';
emit_addr 'effects_vector',%all,'unit_wound::anon2','effect_type';
emit_addr 'bleeding',%all,'unit_wound::anon2','bleeding';
emit_addr 'pain',%all,'unit_wound::anon2','pain';
emit_addr 'cur_pen',%all,'unit_wound::anon2','cur_penetration_perc';
emit_addr 'max_pen',%all,'unit_wound::anon2','max_penetration_perc';
emit_header 'soul_details';
emit_addr 'name',%all,'unit_soul','name';
emit_addr 'orientation',%all,'unit_soul','orientation_flags';
emit_addr 'mental_attrs',%all,'unit_soul','mental_attrs';
emit_addr 'skills',%all,'unit_soul','skills';
emit_addr 'preferences',%all,'unit_soul','preferences';
emit_addr 'personality',%all,'unit_soul','personality';
emit_addr 'beliefs',%all,'unit_personality','values';
emit_addr 'emotions',%all,'unit_personality','emotions';
emit_addr 'goals',%all,'unit_personality','dreams';
emit_addr 'goal_realized',%all,'unit_personality::anon5','unk8';
emit_addr 'traits',%all,'unit_personality','traits';
emit_addr 'stress_level',%all,'unit_personality','stress_level';
emit_header 'emotion_offsets';
emit_addr 'emotion_type',%all,'unit_personality::anon4','type';
emit_addr 'strength',%all,'unit_personality::anon4','strength';
emit_addr 'thought_id',%all,'unit_personality::anon4','thought';
emit_addr 'sub_id',%all,'unit_personality::anon4','subthought';
emit_addr 'level',%all,'unit_personality::anon4','severity';
emit_addr 'year',%all,'unit_personality::anon4','year';
emit_addr 'year_tick',%all,'unit_personality::anon4','year_tick';
emit_header 'job_details';
emit_addr 'id',%all,'job','job_type';
emit_addr 'mat_type',%all,'job','mat_type';
emit_addr 'mat_index',%all,'job','mat_index';
emit_addr 'mat_category',%all,'job','material_category';
emit_addr 'on_break_flag',%all,'misc_trait_type','OnBreak';
emit_addr 'sub_job_id',%all,'job','reaction_name';
emit_addr 'reaction',%all,'reaction','name';
emit_addr 'reaction_skill',%all,'reaction','skill';
emit_header 'squad_offsets';
emit_addr 'id',%all,'squad','id';
emit_addr 'name',%all,'squad','name';
emit_addr 'alias',%all,'squad','alias';
emit_addr 'members',%all,'squad','positions';
emit_addr 'carry_food',%all,'squad','carry_food';
emit_addr 'carry_water',%all,'squad','carry_water';
emit_addr 'ammunition',%all,'squad','ammunition';
emit_addr 'quiver',%all,'squad_position','quiver';
emit_addr 'backpack',%all,'squad_position','backpack';
emit_addr 'flask',%all,'squad_position','flask';
emit_addr 'armor_vector',%all,'squad_position','uniform[body]';
emit_addr 'helm_vector',%all,'squad_position','uniform[head]';
emit_addr 'pants_vector',%all,'squad_position','uniform[pants]';
emit_addr 'gloves_vector',%all,'squad_position','uniform[gloves]';
emit_addr 'shoes_vector',%all,'squad_position','uniform[shoes]';
emit_addr 'shield_vector',%all,'squad_position','uniform[shield]';
emit_addr 'weapon_vector',%all,'squad_position','uniform[weapon]';
emit_addr 'uniform_item_filter',%all,'squad_uniform_spec','item_filter';
emit_addr 'uniform_indiv_choice',%all,'squad_uniform_spec','indiv_choice';
my $body_str = join("\n",@lines);
my $complete_str = ($complete ? 'true' : 'false');
open OUT, ">$subdir/therapist.ini" or die "Cannot open output file";
print OUT <<__END__;
[info]
checksum=0x$checksum
version_name=$version
complete=$complete_str
$body_str
[valid_flags_2]
size=0
[invalid_flags_1]
size=10
1\\name=a zombie
1\\value=0x00001000
2\\name=a skeleton
2\\value=0x00002000
3\\name=a merchant
3\\value=0x00000040
4\\name=outpost liason or diplomat
4\\value=0x00000800
5\\name=an invader or hostile
5\\value=0x00020000
6\\name=an invader or hostile
6\\value=0x00080000
7\\name=resident, invader or ambusher
7\\value=0x00600000
8\\name=part of a merchant caravan
8\\value=0x00000080
9\\name="Dead, Jim."
9\\value=0x00000002
10\\name=marauder
10\\value=0x00000010
[invalid_flags_2]
size=5
1\\name="killed, Jim."
1\\value=0x00000080
2\\name=from the Underworld. SPOOKY!
2\\value=0x00040000
3\\name=resident
3\\value=0x00080000
4\\name=uninvited visitor
4\\value=0x00400000
5\\name=visitor
5\\value=0x00800000
[invalid_flags_3]
size=1
1\\name=a ghost
1\\value=0x00001000
__END__
close OUT;
}
generate_dt_ini 'linux', $version, substr($hash,0,8), 4;
generate_dt_ini 'windows', $version.' (graphics)', $timestamp, 0x1C;
generate_dt_ini 'osx', $version, substr($hash,0,8), 4;

@ -35,9 +35,8 @@ if args.showunitid or args.showpos then
printall(df.global.cursor) printall(df.global.cursor)
end end
else else
local teleportSettings=getArgsTogether(args)
local unit = args.unit and df.unit.find(args.unit) or dfhack.gui.getSelectedUnit(true) local unit = args.unit and df.unit.find(args.unit) or dfhack.gui.getSelectedUnit(true)
local pos = not(not args.x or not args.y or not args.z) and {x=args.x,y=args.y,z=args.z} or df.global.cursor local pos = not(not args.x or not args.y or not args.z) and {x=args.x,y=args.y,z=args.z} or df.global.cursor
teleport(unit,pos) teleport(unit,pos)
end end