Merge branch 'develop' into lua-runcommand

develop
lethosor 2021-01-08 20:45:23 -05:00
commit 614ea739d0
No known key found for this signature in database
GPG Key ID: 76A269552F4F58C1
34 changed files with 1563 additions and 703 deletions

@ -185,7 +185,7 @@ endif()
# set up versioning. # set up versioning.
set(DF_VERSION "0.47.04") set(DF_VERSION "0.47.04")
set(DFHACK_RELEASE "r3") set(DFHACK_RELEASE "r4")
set(DFHACK_PRERELEASE FALSE) set(DFHACK_PRERELEASE FALSE)
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")

@ -1,4 +1,5 @@
This folder contains blueprints used by the `quickfort` script. For more information, see: This folder contains blueprints that can be applied by the `quickfort` script. For more information, see:
* [Quickfort command reference](https://docs.dfhack.org/en/stable/docs/_auto/base.html#quickfort) * [Quickfort command reference](https://docs.dfhack.org/en/stable/docs/_auto/base.html#quickfort)
* [Quickfort user guide](https://docs.dfhack.org/en/stable/docs/guides/quickfort-user-guide.html) * [Quickfort blueprint guide](https://docs.dfhack.org/en/stable/docs/guides/quickfort-user-guide.html)
* [Quickfort library guide](https://docs.dfhack.org/en/stable/docs/guides/quickfort-library-guide.html)

@ -1,32 +1,63 @@
# Common baseline for aliases for quickfort query mode blueprints. # Standard library of aliases for quickfort query mode blueprints.
# #
# Please DO NOT EDIT this file directly. It will get overwritten when DFHack # Please DO NOT EDIT this file directly. It will get overwritten when DFHack
# is updated. Instead, custom aliases should be added to # is updated. Instead, custom aliases should be added to
# dfhack-config/quickfort/aliases.txt. See that file for syntax documentation. # dfhack-config/quickfort/aliases.txt
# Custom alias definitions will take precedence over aliases in this file.
# #
# The aliases in this file were tested in DF 0.47.04 on 2020 Jul 18. # Please see
# # https://docs.dfhack.org/en/latest/docs/guides/quickfort-alias-guide.html
# The aliases are generally split into three categories: # or
# 1) The aliases that name a type disable everything else for that stockpile # hack/docs/docs/guides/quickfort-alias-guide.html
# category and enable only that type. For example, "preparedfood" enables # in your DF installation directory for alias syntax documentation and
# prepared food and disables all other types of food. # documentation for the aliases in this file.
# 2) The aliases that start with "forbid" only forbid (or toggle) the named type
# and leave the rest of the stockpile untouched. ##################################
# 3) The aliases that start with "permit" only permit (or toggle) the named type # naming aliases
# and leave the rest of the stockpile untouched. ##################################
#
# Aliases that don't fit into those two categories have comments explaining name: {Right}
# their usage. givename: !n{name}&
namezone: ^i{givename}^q
##################################
# quantum stockpile aliases
##################################
# Allows the standard stockpile config aliases to also be used to configure
# hauling routes.
enter_sp_config: {enter_sp_config_default}
enter_sp_config_default: s
enter_sp_config_hauling: &
quantum_enable: {enableanimals}{enablefood}{enablefurniture}{enablestone}{enableammo}{enablecoins}{enablebars}{enablegems}{enablefinishedgoods}{enableleather}{enablecloth}{enablewood}{enableweapons}{enablearmor}{enablesheet}
quantum: {linksonly}{nocontainers}{quantum_enable}{givename}
stop_name: {Right}
route_enable: {quantum_enable}{enablecorpses}{enablerefuse}
quantumstop: ^hrn{name}&sn{stop_name}&&xxx{route_enable enter_sp_config={enter_sp_config_hauling}}s{move}p^{move_back}^q
quantumstopfromeast: {quantumstop move={Right} move_back={Left}}
quantumstopfromsouth: {quantumstop move={Down} move_back={Up}}
quantumstopfromwest: {quantumstop move={Left} move_back={Right}}
quantumstopfromnorth: {quantumstop move={Up} move_back={Down}}
##################################
# farm plots
##################################
growlastcropall: a/&b/&c/&d/&
growfirstcropall: a&b&c&d&
######################################## ########################################
# general purpose stockpile adjustments # stockpile utility aliases
######################################## ########################################
linksonly: a linksonly: a
nocontainers: CE nocontainers: CE
# for configuring stockpiles to give to other nearby stockpiles/workshops
give: g{move}& give: g{move}&
give2up: {give move={Up 2}} give2up: {give move={Up 2}}
give2down: {give move={Down 2}} give2down: {give move={Down 2}}
@ -37,69 +68,15 @@ give10down: {give move={Down 10}}
give10left: {give move={Left 10}} give10left: {give move={Left 10}}
give10right: {give move={Right 10}} give10right: {give move={Right 10}}
# Keep in mind that building, stockpile, and zone names have a maximum length
# of 20 characters. usage example: {givename name="myname"}
givename: {Ctrl}n{name}&
# use to toggle a sequence of stockpile options. for example: {togglesequence 5}
togglesequence: &{Down} togglesequence: &{Down}
togglesequence2: &{Down 2} togglesequence2: &{Down 2}
enablesequence: e{Down}
# Enables everything but corpses and refuse. Refuse is excluded since otherwise
# clothes and armor in this quantum stockpile will rot away. If you want bones
# in your quantum stockpile, apply this alias to a refuse stockpile (but don't
# put useful clothes or armor in there!)
# Optionally set a name for the stockpile by specifying the 'name' parameter,
# for example: {quantum name="my name"}
quantum: {linksonly}{nocontainers}{enableanimals}{enablefood}{enablefurniture}{enablestone}{enableammo}{enablecoins}{enablebars}{enablegems}{enablefinishedgoods}{enableleather}{enablecloth}{enablewood}{enableweapons}{enablearmor}{enablesheet}{givename}
##################################
# hauling aliases
##################################
# Run one of the quantumstopfrom* aliases over a track stop that is set to dump
# into a quantum stockpile. The alias will set up the stop to accept all types
# (the actual types stored in the quantum stockpile should be controlled by the
# feeder stockpile) and link the indicated adjacent feeder stockpile. For
# example, the quantumstopfromsouth alias should be used over a track stop set
# to dump to the North and take items from a feeder stockpile one tile to the
# South. All you need to do afterwards is assign a vehicle to the stop. The
# track stop does not need to be constructed yet, but the feeder stockpile needs
# to exist so we can link to it.
#
# Be sure to define the optional 'name' parameter if you want to give your
# quantum hauling routes custom names. Keep in mind that names have a maximum
# length of 22 characters. For example:
# {quantumstopfromsouth name="Trash Dump"}
#
# For several examples of these aliases, see
# https://docs.google.com/spreadsheets/d/1gvTJxxRxZ5V4vXkqwhL-qlr_lXCNt8176TK14m4kSOU
namelastrouteprefix: ^h--n
namelastroutesuffix: &^q
namelastroute: {namelastrouteprefix}{name}{namelastroutesuffix}
quantumstopprefix: ^hrs&xxx&{enablesequence 17}^
quantumstopsuffix: ^q{namelastroute}
quantumstopfromeast: {quantumstopprefix}s{Right}p^{Left}{quantumstopsuffix}
quantumstopfromsouth: {quantumstopprefix}s{Down}p^{Up}{quantumstopsuffix}
quantumstopfromwest: {quantumstopprefix}s{Left}p^{Right}{quantumstopsuffix}
quantumstopfromnorth: {quantumstopprefix}s{Up}p^{Down}{quantumstopsuffix}
##################################
# zone aliases
##################################
# usage example: {namezone name="my zone name"}
namezone: ^i{givename}^q
################################## ##################################
# animal stockpile adjustments # animal stockpile adjustments
################################## ##################################
animalsprefix: s animalsprefix: {enter_sp_config}
enableanimals: {animalsprefix}e^ enableanimals: {animalsprefix}e^
disableanimals: {animalsprefix}d^ disableanimals: {animalsprefix}d^
@ -117,7 +94,7 @@ permittraps: {forbidtraps}
# food stockpile adjustments # food stockpile adjustments
################################## ##################################
foodprefix: s{Down} foodprefix: {enter_sp_config}{Down}
enablefood: {foodprefix}e^ enablefood: {foodprefix}e^
disablefood: {foodprefix}d^ disablefood: {foodprefix}d^
@ -148,9 +125,10 @@ permitdye: {forbiddye}
permittallow: {forbidtallow} permittallow: {forbidtallow}
permitmiscliquid: {foodprefix}{Right}{Down 18}p^ permitmiscliquid: {foodprefix}{Right}{Down 18}p^
# the next two aliases are for compatibility with previous implementations of
# Quickfort and are not documented.
# enables everything but seeds # enables everything but seeds
noseeds: {disablefood}{enablefood}{forbidseeds} noseeds: {disablefood}{enablefood}{forbidseeds}
# enables all food except for the types listed above # enables all food except for the types listed above
food: {noseeds}{forbidpreparedfood}{forbidunpreparedfish}{forbidplants}{forbidbooze}{forbiddye}{forbidtallow}{forbidmiscliquid} food: {noseeds}{forbidpreparedfood}{forbidunpreparedfish}{forbidplants}{forbidbooze}{forbiddye}{forbidtallow}{forbidmiscliquid}
@ -159,7 +137,7 @@ food: {noseeds}{forbidpreparedfood}{forbidunpreparedfish}{forbidplants}{forbidbo
# furniture stockpile adjustments # furniture stockpile adjustments
################################## ##################################
furnitureprefix: s{Down 2} furnitureprefix: {enter_sp_config}{Down 2}
enablefurniture: {furnitureprefix}e^ enablefurniture: {furnitureprefix}e^
disablefurniture: {furnitureprefix}d^ disablefurniture: {furnitureprefix}d^
@ -173,11 +151,11 @@ sand: {furnitureprefix}de{Right}f{Right}{Up}&^
# corpses and refuse stockpile adjustments # corpses and refuse stockpile adjustments
########################################### ###########################################
corpsesprefix: s{Down 3} corpsesprefix: {enter_sp_config}{Down 3}
enablecorpses: {corpsesprefix}e^ enablecorpses: {corpsesprefix}e^
disablecorpses: {corpsesprefix}d{Up}d^ disablecorpses: {corpsesprefix}d{Up}d^
refuseprefix: s{Down 4} refuseprefix: {enter_sp_config}{Down 4}
enablerefuse: {refuseprefix}e^ enablerefuse: {refuseprefix}e^
disablerefuse: {refuseprefix}d^ disablerefuse: {refuseprefix}d^
@ -220,7 +198,7 @@ permitcraftrefuse: {permitskulls}{permitbones}{permitshells}{permitteeth}{permit
# stone stockpile adjustments # stone stockpile adjustments
################################## ##################################
stoneprefix: s{Down 5} stoneprefix: {enter_sp_config}{Down 5}
enablestone: {stoneprefix}e^ enablestone: {stoneprefix}e^
disablestone: {stoneprefix}d^ disablestone: {stoneprefix}d^
@ -259,7 +237,7 @@ permitclay: {stoneprefix}{Right}{Down 3}p^
# ammo stockpile adjustments # ammo stockpile adjustments
################################## ##################################
ammoprefix: s{Down 6} ammoprefix: {enter_sp_config}{Down 6}
enableammo: {ammoprefix}e^ enableammo: {ammoprefix}e^
disableammo: {ammoprefix}d^ disableammo: {ammoprefix}d^
@ -274,7 +252,7 @@ forbidbonebolts: {ammoprefix}{Right}{Down 2}{Right}{Down}&^
# bar stockpile adjustments # bar stockpile adjustments
################################## ##################################
barsprefix: s{Down 8} barsprefix: {enter_sp_config}{Down 8}
enablebars: {barsprefix}e^ enablebars: {barsprefix}e^
disablebars: {barsprefix}d^ disablebars: {barsprefix}d^
@ -309,7 +287,7 @@ forbidblocks: {barsprefix}{Down 2}f{Down}f{Down}f^
# gem stockpile adjustments # gem stockpile adjustments
################################## ##################################
gemsprefix: s{Down 9} gemsprefix: {enter_sp_config}{Down 9}
enablegems: {gemsprefix}e^ enablegems: {gemsprefix}e^
disablegems: {gemsprefix}d^ disablegems: {gemsprefix}d^
@ -330,7 +308,7 @@ forbidcutstone: {gemsprefix}{Right}{Down 4}f^
# finished goods stockpile adjustments # finished goods stockpile adjustments
####################################### #######################################
finishedgoodsprefix: s{Down 10} finishedgoodsprefix: {enter_sp_config}{Down 10}
enablefinishedgoods: {finishedgoodsprefix}e^ enablefinishedgoods: {finishedgoodsprefix}e^
disablefinishedgoods: {finishedgoodsprefix}d^ disablefinishedgoods: {finishedgoodsprefix}d^
@ -341,7 +319,7 @@ jugs: {finishedgoodsprefix}{Right}f{Right}{Up 2}&{Left}{Down 2}f{Down}f{Down}f^
# cloth # cloth
################################## ##################################
clothprefix: s{Down 12} clothprefix: {enter_sp_config}{Down 12}
enablecloth: {clothprefix}e^ enablecloth: {clothprefix}e^
disablecloth: {clothprefix}d^ disablecloth: {clothprefix}d^
@ -355,7 +333,7 @@ adamantinecloth: {clothprefix}b{Right}{Up}p^
# weapon stockpile adjustments # weapon stockpile adjustments
################################## ##################################
weaponsprefix: s{Down 14} weaponsprefix: {enter_sp_config}{Down 14}
enableweapons: {weaponsprefix}e^ enableweapons: {weaponsprefix}e^
disableweapons: {weaponsprefix}d^ disableweapons: {weaponsprefix}d^
@ -396,7 +374,7 @@ permitartifactweapons: {forbidartifactweapons}
# armor stockpile adjustments # armor stockpile adjustments
################################## ##################################
armorprefix: s{Down 15} armorprefix: {enter_sp_config}{Down 15}
enablearmor: {armorprefix}e^ enablearmor: {armorprefix}e^
disablearmor: {armorprefix}d^ disablearmor: {armorprefix}d^
@ -432,32 +410,18 @@ permitartifactarmor: {forbidartifactarmor}
# others # others
################################## ##################################
coinsprefix: s{Down 7} coinsprefix: {enter_sp_config}{Down 7}
enablecoins: {coinsprefix}e^ enablecoins: {coinsprefix}e^
disablecoins: {coinsprefix}d^ disablecoins: {coinsprefix}d^
leatherprefix: s{Down 11} leatherprefix: {enter_sp_config}{Down 11}
enableleather: {leatherprefix}e^ enableleather: {leatherprefix}e^
disableleather: {leatherprefix}d^ disableleather: {leatherprefix}d^
woodprefix: s{Down 13} woodprefix: {enter_sp_config}{Down 13}
enablewood: {woodprefix}e^ enablewood: {woodprefix}e^
disablewood: {woodprefix}d^ disablewood: {woodprefix}d^
sheetprefix: s{Down 16} sheetprefix: {enter_sp_config}{Down 16}
enablesheet: {sheetprefix}e^ enablesheet: {sheetprefix}e^
disablesheet: {sheetprefix}d^ disablesheet: {sheetprefix}d^
##################################
# farm plots
##################################
# Sets a farm plot to grow the LAST type of seed in the list of available seeds
# for all 4 seasons. The last seed is used because it's usually Plump helmet
# spawn, suitable for post-embark. If you only have 1 seed type, that'll be
# grown.
growlastcropall: a/&b/&c/&d/&
# Like growlastcropall but grows the first one in the list instead.
growfirstcropall: a&b&c&d&

@ -12,6 +12,9 @@ add_subdirectory(tthread)
option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" OFF) option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" OFF)
option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" OFF) option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" OFF)
add_subdirectory(jsoncpp-sub EXCLUDE_FROM_ALL) add_subdirectory(jsoncpp-sub EXCLUDE_FROM_ALL)
if(UNIX)
set_target_properties(jsoncpp_lib_static PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations")
endif()
# build clsocket static and only as a dependency. Setting those options here overrides its own default settings. # build clsocket static and only as a dependency. Setting those options here overrides its own default settings.
option(CLSOCKET_SHARED "Build clsocket lib as shared." OFF) option(CLSOCKET_SHARED "Build clsocket lib as shared." OFF)
option(CLSOCKET_DEP_ONLY "Build for use inside other CMake projects as dependency." ON) option(CLSOCKET_DEP_ONLY "Build for use inside other CMake projects as dependency." ON)

@ -1 +1 @@
Subproject commit be76fa5086bfe6b1a5e83c9855e39f98edc1f066 Subproject commit da0d18ae59ef2699013316b703cdc93809414c93

@ -100,6 +100,7 @@ if(MSVC)
target_compile_options(lua PRIVATE "/FIdfhack_llimits.h") target_compile_options(lua PRIVATE "/FIdfhack_llimits.h")
else() else()
target_compile_options(lua PRIVATE -include dfhack_llimits.h) target_compile_options(lua PRIVATE -include dfhack_llimits.h)
set_source_files_properties(src/lstring.c PROPERTIES COMPILE_FLAGS "-Wno-stringop-overflow")
endif() endif()
install(TARGETS lua install(TARGETS lua

@ -1,106 +1,17 @@
# Aliases for quickfort #query mode blueprints # Custom aliases for quickfort query mode blueprints
# #
# This file defines custom keycode shortcuts for #query mode blueprints. # This file defines custom key sequence shortcuts for query mode blueprints.
# Definitions in this file take precedence over any definitions in the baseline # Definitions in this file take precedence over any definitions in the
# aliases configuration file at hack/data/quickfort/aliases-common.txt. See that # baseline aliases configuration file in
# file for the many useful aliases that are already defined. # hack/data/quickfort/aliases-common.txt
# #
# If possible, build on the baseline aliases when defining your own aliases. If # Please see
# the DF UI screens change, updated baseline aliases may allow your aliases to # https://docs.dfhack.org/en/latest/docs/guides/quickfort-alias-guide.html
# automatically adapt to the new UI. For example, if you create an alias to # or
# modify particular furniture stockpile settings, start your alias with # hack/docs/docs/guides/quickfort-alias-guide.html
# "{furnitureprefix}" instead of manually writing "s{Down 2}". Then, if the # in your DF installation directory for alias syntax documentation and an
# location of the furniture setting changes, your alias will automatically # overview of the DFHack alias standard library.
# inherit the updated position when DFHack is updated.
# #
# Aliases simplify repetitive tasks, such as configuring workshop profiles or
# adjusting a food stockpile to accept only seeds. Making new aliases is just a
# matter of mimicking the keys used to navigate through the menus and select
# options. Use the aliases in your blueprint spreadsheets by writing an alias by
# itself in a cell, like "nocontainers", or reference an alias in a larger
# sequence by enclosing it in curly brackets, like "{nocontainers}{linksonly}"
# #
# For example, say you have the following build and place blueprints: # Add your custom aliases here. Example:
# # food_stash: {foodprefix}b{Right}{Down 11}p^{permitplants}
# #build masonry workshop
# ~, ~,~,`,`,`
# ~,wm,~,`,`,`
# ~, ~,~,`,`,`
#
# #place stockpile for mason
# ~,~,~,s,s,s
# ~,~,~,s,s,s
# ~,~,~,s,s,s
#
# and you want to configure the stockpile to hold only non-economic ("other")
# stone and to give to the adjacent mason workshop. You could write the
# keystrokes directly:
#
# #query start(4;1;upper left corner of stockpile) configure mason
# ~,~,~,s{Down 5}deb{Right}{Down 2}p^,`,`
# ~,~,~,g{Left 2}&, `,`
# ~,~,~,`, `,`
#
# or you could use alias names:
#
# #query start(4;1;upper left corner of stockpile) configure mason
# ~,~,~,otherstone,`,`
# ~,~,~,give2left, `,`
# ~,~,~,`, `,`
#
# you can combine the two aliases above into a single cell as well, if desired:
#
# #query start(4;1;upper left corner of stockpile) configure mason
# ~,~,~,{otherstone}{give2left},`,`
# ~,~,~,`, `,`
# ~,~,~,`, `,`
#
# The syntax for defining aliases is:
# aliasname: keystrokes
#
# Where aliasname is at least two letters or digits long (including dashes and
# underscores) and keystrokes are whatever you would type into the DF UI. A
# keystroke can also be a named keycode from the DF interface definition file
# (data/init/interface.txt), enclosed in curly brackets like an alias, like:
# "{Right}" or "{Enter}". In # order to avoid naming conflicts between aliases
# and keycodes, the convention is to start aliases with a lowercase letter.
#
# Anything enclosed within curly brackets can also have a number after it,
# indicating how many times that alias or keycode should be repeated. For
# example: "{togglesequence 9}" or "{Down 5}".
#
# Finally, you can specify sub-aliases that will only be defined while the
# current alias is being resolved by adding them after the alias name (but
# before the repetition number, if it is specified), for example:
# {quantumstopfromeast name="Trash Dump"}
# The value of the sub-alias 'name' is used by quantumstopfromeast (or one of
# the aliases it calls) to give a useful name to your quantum dump hauling
# route. You can also use this format to temporarily override the value of an
# existing regularly-defined alias.
#
# Sub-aliases must be in one of the following formats:
# subaliasname=valwithnospaces
# subaliasname="val with spaces"
# subaliasname={someotheralias repetitions}
#
# Ctrl, Alt, and Shift modifiers can be specified for the next keycode by adding
# them into the key sequence. For example, Alt-h is written as "{Alt}h".
#
# Some frequently-used keystrokes are assigned shorthand characters. Think of
# them as single-character aliases that don't need to be surrounded in curly
# brackets:
# & expands to {Enter}
# @ expands to {Shift}{Enter}
# ~ expands to {Alt}
# ! expands to {Ctrl}
# ^ expands to {ESC}
#
# There is also a non-standard alias built into the code for the common
# shorthand for "make room":
# r+ expands to r+&
#
# If you need literal verisons of the shorthand characters, surround them in
# curly brackets, for example: "{!}"
#
#
# Add your custom aliases here:

@ -55,6 +55,9 @@ keybinding add Alt-S@dwarfmode/Default gui/settings-manager
# change quantity of manager orders # change quantity of manager orders
keybinding add Alt-Q@jobmanagement/Main gui/manager-quantity keybinding add Alt-Q@jobmanagement/Main gui/manager-quantity
# re-check manager orders
keybinding add Alt-R@jobmanagement/Main workorder-recheck
# view combat reports for the selected unit/corpse/spatter # view combat reports for the selected unit/corpse/spatter
keybinding add Ctrl-Shift-R view-unit-reports keybinding add Ctrl-Shift-R view-unit-reports

@ -119,15 +119,13 @@ Add link targets if you need them, but otherwise plain headings are preferred.
Scripts have link targets created automatically. Scripts have link targets created automatically.
Building the documentation Required dependencies
========================== =====================
.. highlight:: shell .. highlight:: shell
Required dependencies
---------------------
In order to build the documentation, you must have Python with Sphinx In order to build the documentation, you must have Python with Sphinx
version |sphinx_min_version| or later. Both Python 2.x and 3.x are supported. version |sphinx_min_version| or later. Python 3 is recommended.
When installing Sphinx from OS package managers, be aware that there is When installing Sphinx from OS package managers, be aware that there is
another program called Sphinx, completely unrelated to documentation management. another program called Sphinx, completely unrelated to documentation management.
@ -146,7 +144,7 @@ For more detailed platform-specific instructions, see the sections below:
Linux Linux
~~~~~ -----
Most Linux distributions will include Python by default. If not, start by Most Linux distributions will include Python by default. If not, start by
installing Python (preferably Python 3). On Debian-based distros:: installing Python (preferably Python 3). On Debian-based distros::
@ -172,7 +170,7 @@ system-wide by running pip with ``sudo``. In any case, you will need the folder
containing ``sphinx-build`` to be in your ``$PATH``. containing ``sphinx-build`` to be in your ``$PATH``.
macOS macOS
~~~~~ -----
macOS has Python 2.7 installed by default, but it does not have the pip package manager. macOS has Python 2.7 installed by default, but it does not have the pip package manager.
You can install Homebrew's Python 3, which includes pip, and then install the You can install Homebrew's Python 3, which includes pip, and then install the
@ -193,7 +191,7 @@ If not, just installing sphinx-doc for macOS's system Python 2.7 is fine.
Windows Windows
~~~~~~~ -------
Python for Windows can be downloaded `from python.org <https://www.python.org/downloads/>`_. Python for Windows can be downloaded `from python.org <https://www.python.org/downloads/>`_.
The latest version of Python 3 is recommended, as it includes pip already. The latest version of Python 3 is recommended, as it includes pip already.
@ -210,6 +208,11 @@ Once you have pip available, you can install Sphinx with the following command::
Note that this may require opening a new (admin) command prompt if you just Note that this may require opening a new (admin) command prompt if you just
installed pip from the same command prompt. installed pip from the same command prompt.
Building the documentation
==========================
Once the required dependencies are installed, there are multiple ways to run
Sphinx to build the docs:
Using CMake Using CMake
----------- -----------
@ -230,7 +233,7 @@ ways to do this:
* You can edit the ``BUILD_DOCS`` setting in CMakeCache.txt directly * You can edit the ``BUILD_DOCS`` setting in CMakeCache.txt directly
* You can use the CMake GUI to change ``BUILD_DOCS`` * You can use the CMake GUI or ``ccmake`` to change the ``BUILD_DOCS`` setting
* On Windows, if you prefer to use the batch scripts, you can run * On Windows, if you prefer to use the batch scripts, you can run
``generate-msvc-gui.bat`` and set ``BUILD_DOCS`` through the GUI. If you are ``generate-msvc-gui.bat`` and set ``BUILD_DOCS`` through the GUI. If you are
@ -238,19 +241,28 @@ ways to do this:
it to add the flag. You can also run ``cmake`` on the command line, similar to it to add the flag. You can also run ``cmake`` on the command line, similar to
other platforms. other platforms.
The generated documentation will be stored in ``docs/html`` in the root DFHack
folder, and will be installed to ``hack/docs`` when you next install DFHack in a
DF folder.
Running Sphinx manually Running Sphinx manually
----------------------- -----------------------
You can also build the documentation without going through CMake, which may be You can also build the documentation without running CMake - this is faster if
faster. There is a ``docs/build.sh`` script provided for Linux and macOS that you only want to rebuild the documentation regardless of any code changes. There
will run essentially the same command that CMake runs - see the script for is a ``docs/build.sh`` script provided for Linux and macOS that will run
additional options. essentially the same command that CMake runs when building the docs - see the
script for additional options.
To build the documentation with default options, run the following command from To build the documentation with default options, run the following command from
the root DFHack folder:: the root DFHack folder::
sphinx-build . docs/html sphinx-build . docs/html
The resulting documentation will be stored in ``docs/html`` (you can specify
a different path when running ``sphinx-build`` manually, but be warned that
Sphinx may overwrite existing files in this folder).
Sphinx has many options to enable clean builds, parallel builds, logging, and Sphinx has many options to enable clean builds, parallel builds, logging, and
more - run ``sphinx-build --help`` for details. more - run ``sphinx-build --help`` for details.
@ -263,7 +275,7 @@ want to build a PDF version locally, you will need ``pdflatex``, which is part
of a TeX distribution. The following command will then build a PDF, located in of a TeX distribution. The following command will then build a PDF, located in
``docs/pdf/latex/DFHack.pdf``, with default options:: ``docs/pdf/latex/DFHack.pdf``, with default options::
sphinx-build -M latexpdf . ./docs/pdf sphinx-build -M latexpdf . docs/pdf
There is a ``docs/build-pdf.sh`` script provided for Linux and macOS that runs There is a ``docs/build-pdf.sh`` script provided for Linux and macOS that runs
this command for convenience - see the script for additional options. this command for convenience - see the script for additional options.
@ -272,10 +284,11 @@ this command for convenience - see the script for additional options.
Building the changelogs Building the changelogs
======================= =======================
If you have Python installed, but do not want to build all of the documentation, If you have Python installed, you can build just the changelogs without building
you can build the changelogs with the ``docs/gen_changelog.py`` script. This the rest of the documentation by running the ``docs/gen_changelog.py`` script.
script provides additional options, including one to build individual changelogs This script provides additional options, including one to build individual
for all DFHack versions - run ``python docs/gen_changelog.py --help`` for details. changelogs for all DFHack versions - run ``python docs/gen_changelog.py --help``
for details.
Changelog entries are obtained from ``changelog.txt`` files in multiple repos. Changelog entries are obtained from ``changelog.txt`` files in multiple repos.
This allows changes to be listed in the same repo where they were made. These This allows changes to be listed in the same repo where they were made. These
@ -302,3 +315,30 @@ Changelog syntax
.. include:: /docs/changelog.txt .. include:: /docs/changelog.txt
:start-after: ===help :start-after: ===help
:end-before: ===end :end-before: ===end
.. _docs-ci:
GitHub Actions
==============
Documentation is built automatically with GitHub Actions (a GitHub-provided
continuous integration service) for all pull requests and commits in the
"dfhack" and "scripts" repositories. These builds run with strict settings, i.e.
warnings are treated as errors. If a build fails, you will see a red "x" next to
the relevant commit or pull request. You can view detailed output from Sphinx in
a few ways:
* Click on the red "x" (or green checkmark), then click "Details" next to
the "Build / docs" entry
* For pull requests only: navigate to the "Checks" tab, then click on "Build" in
the sidebar to expand it, then "docs" under it
Sphinx output will be visible under the step named "Build docs". If a different
step failed, or you aren't sure how to interpret the output, leave a comment
on the pull request (or commit).
You can also download the "docs" artifact from the summary page (typically
accessible by clicking "Build") if the build succeeded. This is a way to
visually inspect what the documentation looks like when built without installing
Sphinx locally, although we recommend installing Sphinx if you are planning to
do any significant work on the documentation.

@ -1704,7 +1704,11 @@ Low-level building creation functions:
Returns *false* if the building cannot be placed, or *true, width, Returns *false* if the building cannot be placed, or *true, width,
height, rect_area, true_area*. Returned width and height are the height, rect_area, true_area*. Returned width and height are the
final values used by the building; true_area is less than rect_area final values used by the building; true_area is less than rect_area
if any tiles were removed from designation. if any tiles were removed from designation. You can specify a non-rectangular
designation for building types that support extents by setting the
``room.extents`` bitmap before calling this function. The extents will be
reset, however, if the size returned by this function doesn't match the
input size parameter.
* ``dfhack.buildings.constructAbstract(building)`` * ``dfhack.buildings.constructAbstract(building)``
@ -1793,7 +1797,9 @@ Among them are:
- ``fields = { ... }`` - ``fields = { ... }``
Initializes fields of the building object after creation with ``df.assign``. Initializes fields of the building object after creation with
``df.assign``. If ``room.extents`` is assigned this way and this function
returns with error, the memory allocated for the extents is freed.
- ``width = ..., height = ..., direction = ...`` - ``width = ..., height = ..., direction = ...``

@ -33,31 +33,44 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
# Future # Future
## Fixes
- `embark-assistant`: fixed order of factors when calculating min temperature
# 0.47.04-r4
## Fixes ## Fixes
- Fixed an issue on some Linux systems where DFHack installed through a package manager would attempt to write files to a non-writable folder (notably when running `exportlegends` or `gui/autogems`) - Fixed an issue on some Linux systems where DFHack installed through a package manager would attempt to write files to a non-writable folder (notably when running `exportlegends` or `gui/autogems`)
- `buildingplan`: artifacts are now successfully matched when max quality is set to ``artifacts`` - `buildingplan`: fixed an issue preventing artifacts from being matched when the maximum item quality is set to ``artifacts``
- `buildingplan`: no longer erroneously matches items to buildings while the game is paused - `buildingplan`: stopped erroneously matching items to buildings while the game is paused
- `buildingplan`: fixed a crash when pressing 0 while having a noble room selected - `buildingplan`: fixed a crash when pressing 0 while having a noble room selected
- `dwarfvet`: fixed a crash that could occur when discharging patients - `dwarfvet`: fixed a crash that could occur when discharging patients
- `dwarfmonitor`: fixed a crash when opening the ``prefs`` screen if units have vague preferences - `dwarfmonitor`: fixed a crash when opening the ``prefs`` screen if units have vague preferences
- `embark-assistant`: fixed an issue causing incursion resource matching (e.g. sand/clay) to skip some tiles if those resources were provided only through incursions - `embark-assistant`: fixed an issue causing incursion resource matching (e.g. sand/clay) to skip some tiles if those resources were provided only through incursions
- `embark-assistant`: corrected river size determination by performing it at the MLT level rather than the world tile one - `embark-assistant`: corrected river size determination by performing it at the MLT level rather than the world tile level
- `search`: fixed an issue where search options might not display if screens were destroyed and recreated programmatically (e.g. with `quickfort`)
- `workflow`: fixed an error when creating constraints on "mill plants" jobs and some other plant-related jobs
- `zone`: fixed an issue causing the ``enumnick`` subcommand to run when attempting to run ``assign``, ``unassign``, or ``slaughter`` - `zone`: fixed an issue causing the ``enumnick`` subcommand to run when attempting to run ``assign``, ``unassign``, or ``slaughter``
## Misc Improvements ## Misc Improvements
- `buildingplan`: all buildings, furniture, and constructions are now supported (except for instruments) - `buildingplan`: added support for all buildings, furniture, and constructions (except for instruments)
- `buildingplan`: now respects building job_item filters when matching items, so you can set your own programmatic filters for buildings before submitting them to buildingplan - `buildingplan`: added support for respecting building job_item filters when matching items, so you can set your own programmatic filters for buildings before submitting them to buildingplan
- `buildingplan`: default filter setting for max quality changed from ``artifact`` to ``masterwork`` - `buildingplan`: changed default filter setting for max quality from ``artifact`` to ``masterwork``
- `buildingplan`: min quality adjustment hotkeys changed from 'qw' to 'QW' to avoid conflict with existing hotkeys for setting roller speed. max quality adjustment hotkeys changed from 'QW' to 'AS' to make room for the min quality hotkey changes. - `buildingplan`: changed min quality adjustment hotkeys from 'qw' to 'QW' to avoid conflict with existing hotkeys for setting roller speed - also changed max quality adjustment hotkeys from 'QW' to 'AS' to make room for the min quality hotkey changes
- `buildingplan`: new global settings page accessible via ``G`` hotkey when on any building build screen; ``Quickfort Mode`` toggle for legacy Python Quickfort has been moved to this page - `buildingplan`: added a new global settings page accessible via the ``G`` hotkey when on any building build screen; ``Quickfort Mode`` toggle for legacy Python Quickfort has been moved to this page
- `buildingplan`: new global settings for whether generic building materials should match blocks, boulders, logs, and/or bars. defaults are everything but bars. - `buildingplan`: added new global settings for whether generic building materials should match blocks, boulders, logs, and/or bars - defaults are everything but bars
- `quickfort`: The Dreamfort sample blueprints now have complete walkthroughs for each fort level and importable orders that automate basic fort stock management
- `quickfort`: More blueprints have been added to the blueprints library: several bedroom layouts, the Saracen Crypts, and the complete fortress example from Python Quickfort: TheQuickFortress
- `embark-assistant`: split the lair types displayed on the local map into mound, burrow, and lair - `embark-assistant`: split the lair types displayed on the local map into mound, burrow, and lair
- `probe`: added more output for designations and tile occupancy
- `quickfort`: The Dreamfort sample blueprints now have complete walkthroughs for each fort level and importable orders that automate basic fort stock management
- `quickfort`: added more blueprints to the blueprints library: several bedroom layouts, the Saracen Crypts, and the complete fortress example from Python Quickfort: TheQuickFortress
## Documentation
- `quickfort-alias-guide`: alias syntax and alias standard library documentation for `quickfort` blueprints
- `quickfort-library-guide`: overview of the quickfort blueprint library
## API ## API
- `buildingplan`: added Lua interface API - `buildingplan`: added Lua interface API
- add item type param to dfhack.job.isSuitableMaterial() so the non_economic flag can be properly handled (it was being matched for all item types instead of just boulders) - ``dfhack.job.isSuitableMaterial()``: added an item type parameter so the ``non_economic`` flag can be properly handled (it was being matched for all item types instead of just boulders)
- ``Buildings::setSize()``: changed to reuse existing extents when possible
## Lua ## Lua
- ``utils.addressof()``: fixed for raw userdata - ``utils.addressof()``: fixed for raw userdata

@ -0,0 +1,801 @@
.. _quickfort-alias-guide:
Quickfort Alias Guide
=====================
Aliases allow you to use simple words to represent complicated key sequences
when configuring buildings and stockpiles in quickfort ``#query`` blueprints.
For example, say you have the following ``#build`` and ``#place`` blueprints::
#build masonry workshop
~, ~,~,`,`,`
~,wm,~,`,`,`
~, ~,~,`,`,`
#place stockpile for mason
~,~,~,s,s,s
~,~,~,s,s,s
~,~,~,s,s,s
and you want to configure the stockpile to hold only non-economic ("other")
stone and to give to the adjacent mason workshop. You could write the
key sequences directly::
#query configure stockpile with expanded key sequences
~,~,~,s{Down 5}deb{Right}{Down 2}p^,`,`
~,~,~,g{Left 2}&, `,`
~,~,~,`, `,`
or you could use aliases::
#query configure stockpile with aliases
~,~,~,otherstone,`,`
~,~,~,give2left, `,`
~,~,~,`, `,`
If the stockpile had only a single tile, you could also replay both aliases in
a single cell::
#query configure mason with multiple aliases in one cell
~,~,~,{otherstone}{give2left},`,`
~,~,~,`, `,`
~,~,~,`, `,`
With aliases, blueprints are much easier to read and understand. They also
save you from having to copy the same long key sequences everywhere.
Alias definition files
----------------------
DFHack comes with a library of aliases for you to use that are always
available when you run a ``#query`` blueprint. Many blueprints can be built
with just those aliases. This "standard alias library" is stored in
:source:`data/quickfort/aliases-common.txt` (installed under the ``hack`` folder
in your DFHack installation). The aliases in that file are described at the
`bottom of this document <quickfort-alias-library>`.
Please do not edit the aliases in the standard library directly. The file will
get overwritten when DFHack is updated and you'll lose your changes. Instead,
add your custom aliases to :source:`dfhack-config/quickfort/aliases.txt`.
Definitions in this file take precedence over any definitions in the standard
library.
Alias syntax and usage
----------------------
The syntax for defining aliases is::
aliasname: expansion
Where ``aliasname`` is at least two letters or digits long (dashes and
underscores are also allowed) and ``expansion`` is whatever you would type
into the DF UI.
You use an alias by typing its name into a ``#query`` blueprint cell where you
want it to be applied. You can use an alias by itself or as part of a larger
sequence, potentially with other aliases. If the alias is the only text in the
cell, the alias name is matched and its expansion is used. If the alias has
other keys before or after it, the alias name must be surrounded in curly
brackets (:kbd:`{` and :kbd:`}`). An alias can be surrounded in curly brackets
even if it is the only text in the cell, it just isn't necesary. For example,
the following blueprint uses the ``aliasname`` alias by itself in the first
two rows and uses it as part of a longer sequence in the third row::
#query apply alias 'aliasname' in three different ways
aliasname
{aliasname}
literaltext{aliasname}literaltext
For a more concrete example of an alias definition, a simple alias that
configures a stockpile to have no bins (:kbd:`C`) and no barrels (:kbd:`E`)
assigned to it would look like this::
nocontainers: CE
The alias definition can also contain references to other aliases by including
the alias names in curly brackets. For example, ``nocontainers`` could be
equivalently defined like this::
nobins: C
nobarrels: E
nocontainers: {nobins}{nobarrels}
Aliases used in alias definitions *must* be surrounded by curly brackets, even
if they are the only text in the definition::
alias1: text1
alias2: alias1
alias3: {alias1}
Here, ``alias1`` and ``alias3`` expand to ``text1``, but ``alias2`` expands to
the literal text ``alias1``.
Keycodes
~~~~~~~~
Non-printable characters, like the arrow keys, are represented by their
keycode name and are also surrounded by curly brackets, like ``{Right}`` or
``{Enter}``. Keycodes are used exactly like aliases -- they just have special
expansions that you wouldn't be able to write yourself. In order to avoid
naming conflicts between aliases and keycodes, the convention is to start
aliases with a lowercase letter.
Any keycode name from the DF interface definition file
(data/init/interface.txt) is valid, but only a few keycodes are actually
useful for blueprints::
Up
Down
Left
Right
Enter
ESC
Backspace
Space
Tab
Repetitions
~~~~~~~~~~~
Anything enclosed within curly brackets can also have a number, indicating how
many times that alias or keycode should be repeated. For example:
``{togglesequence 9}`` or ``{Down 5}`` will repeat the ``togglesequence``
alias nine times and the ``Down`` keycode five times, respectively.
Modifier keys
~~~~~~~~~~~~~
Ctrl, Alt, and Shift modifiers can be specified for the next key by adding
them into the key sequence. For example, Alt-h is written as ``{Alt}h``.
Shorthand characters
~~~~~~~~~~~~~~~~~~~~
Some frequently-used keycodes are assigned shorthand characters. Think of them
as single-character aliases that don't need to be surrounded in curly
brackets::
& expands to {Enter}
@ expands to {Shift}{Enter}
~ expands to {Alt}
! expands to {Ctrl}
^ expands to {ESC}
If you need literal versions of the shorthand characters, surround them in
curly brackets, for example: use ``{!}`` for a literal exclamation point.
Built-in aliases
~~~~~~~~~~~~~~~~
Most aliases that come with DFHack are in ``aliases-common.txt``, but there is
one alias built into the code for the common shorthand for "make room"::
r+ expands to r+{Enter}
This needs special code support since ``+`` can't normally be used in alias
names. You can use it just like any other alias, either by itself in a cell
(``r+``) or surrounded in curly brackets (``{r+}``).
Sub-aliases
~~~~~~~~~~~
You can specify sub-aliases that will only be defined while the current alias
is being resolved. This is useful for "injecting" custom behavior into the
middle of a larger alias. As a simple example, the ``givename`` alias is defined
like this::
givename: !n{name}&
Note the use of the ``name`` alias inside of the ``givename`` expansion. In your
``#query`` blueprint, you could write something like this, say, while over your
main drawbridge::
{givename name="Front Gate"}
The value that you give the sub-alias ``name`` will be used when the
``givename`` alias is expanded. Without sub-aliases, we'd have to define ``givename`` like this::
givenameprefix: !n
givenamesuffix: &
and use it like this::
{givenameprefix}Front Gate{givenamesuffix}
which is more difficult to write and more difficult to understand.
A handy technique is to define an alias with some sort of default
behavior and then use sub-aliases to override that behavior as necessary. For
example, here is a simplified version of the standard ``quantum`` alias that
sets up quantum stockpiles::
quantum_enable: {enableanimals}{enablefood}{enablefurniture}...
quantum: {linksonly}{nocontainers}{quantum_enable}
You can use the default behavior of ``quantum_enable`` by just using the
``quantum`` alias by itself. But you can override ``quantum_enable`` to just
enable furniture for some specific stockpile like this::
{quantum quantum_enable={enablefurniture}}
If an alias uses a sub-alias in its expansion, but the sub-alias is not defined when the alias is used, quickfort will halt the ``#query`` blueprint with an error. If you want your aliases to work regardless of whether sub-aliases are defined, then you must define them with default values like ``quantum_enable`` above.
Sub-aliases must be in one of the following formats::
subaliasname=keyswithnospaces
subaliasname="keys with spaces or {aliases}"
subaliasname={singlealias}
If you specify both a sub-alias and a number of repetitions, the number for
repetitions goes last, right before the :kbd:`}`::
{alias subaliasname=value repetitions}
Beyond query mode
-----------------
``#query`` blueprints normally do things in DF :kbd:`q`\uery mode, but nobody
said that we have to *stay* in query mode. ``#query`` blueprints send
arbitrary key sequences to Dwarf Fortress. Anything you can do by typing keys
into DF, you can do in a ``#query`` blueprint. It is absolutely fine to
temporarily exit out of query mode, go into, say, hauling or zone or hotkey
mode, and do whatever needs to be done.
You just have to make certain to exit out of that alternate mode and get back
into :kbd:`q`\uery mode at the end of the key sequence. That way quickfort can
continue on configuring the next tile -- a tile configuration that assumes the
game is still in query mode.
For example, here is the standard library alias for giving a name to a zone::
namezone: ^i{givename}^q
The first :kbd:`\^` exits out of query mode. Then :kbd:`i` enters zones mode.
We then reuse the standard alias for giving something a name. Finally, we exit
out of zones mode with another :kbd:`\^` and return to :kbd:`q`\uery mode.
.. _quickfort-alias-library:
The DFHack standard alias library
---------------------------------
DFHack comes with many useful aliases for you to use in your blueprints. Many
blueprints can be built with just these aliases alone, with no custom aliases
required.
This section goes through all aliases provided by the DFHack standard alias
library, discussing their intended usage and detailing sub-aliases that you
can define to customize their behavior.
If you do define your own custom aliases in
``dfhack-config/quickfort/aliases.txt``, try to build on the library aliases.
For example, if you create an alias to modify particular furniture stockpile
settings, start your alias with ``{furnitureprefix}`` instead of
``s{Down 2}``. Using library prefixes will allow sub-aliases to work with your
aliases just like they do with library aliases. In this case, using
``{furnitureprefix}`` will allow your stockpile customization alias to work
with both stockpiles and hauling routes.
Naming aliases
~~~~~~~~~~~~~~
These aliases give descriptive names to workshops, levers, stockpiles, zones,
etc. Dwarf Fortress building, stockpile, and zone names have a maximum length
of 20 characters.
======== ===========
Alias Sub-aliases
======== ===========
givename name
namezone name
======== ===========
``givename`` works anywhere you can hit Ctrl-n to customize a name, like when
the cursor is over buildings and stockpiles. Example::
#place
f(10x2)
#query
{booze}{givename name=booze}
``namezone`` is intended to be used when over an activity zone. It includes
commands to get into zones mode, set the zone name, and get back to query
mode. Example::
#zone
n(2x2)
#query
{namezone name="guard dog pen"}
Quantum stockpile aliases
~~~~~~~~~~~~~~~~~~~~~~~~~
These aliases make it easy to create :wiki:`minecart stop-based quantum stockpiles <Quantum_stockpile#The_Minecart_Stop>`.
+----------------------+------------------+
| Alias | Sub-aliases |
+======================+==================+
| quantum | | name |
| | | quantum_enable |
+----------------------+------------------+
| quantumstopfromnorth | | name |
+----------------------+ | stop_name |
| quantumstopfromsouth | | route_enable |
+----------------------+ |
| quantumstopfromeast | |
+----------------------+ |
| quantumstopfromwest | |
+----------------------+------------------+
| quantumstop | | name |
| | | stop_name |
| | | route_enable |
| | | move |
| | | move_back |
+----------------------+------------------+
The idea is to use a minecart on a track stop to dump an infinite number of
items into a receiving "quantum" stockpile, which significantly simplifies
stockpile management. These aliases configure the quantum stockpile and
hauling route that make it all work. Here is a complete example for quantum
stockpiling weapons, armor, and ammunition. It has a 3x1 feeder stockpile on
the bottom (South), the trackstop in the center, and the quantum stockpile on
the top (North). Note that the feeder stockpile is the only stockpile that
needs to be configured to control which types of items end up in the quantum
stockpile. By default, the hauling route and quantum stockpile itself simply
accept whatever is put into them.
::
#place
,c
,
pdz(3x1)
#build
,
,trackstopN
#query message(remember to assign a minecart to the new route)
,quantum
,quantumstopfromsouth
nocontainers
The ``quantum`` alias configures a 1x1 stockpile to be a quantum stockpile. It
bans all containers and prevents the stockpile from being manually filled. By
default, it also enables storage of all item categories (except corpses and
refuse), so it doesn't really matter what letter you use to place the
stockpile. :wiki:`Refuse` is excluded by default since otherwise clothes and
armor in the quantum stockpile would rot away. If you want corpses or bones in
your quantum stockpile, use :kbd:`y` and/or :kbd:`r` to place the stockpile
and the ``quantum`` alias will just enable the remaining types. If you *do*
enable refuse in your quantum stockpile, be sure you avoid putting useful
clothes or armor in there!
The ``quantumstopfromsouth`` alias is run over the track stop and configures
the hauling route, again, allowing all item categories into the minecart by
default so any item that can go into the feeder stockpile can then be placed
in the minecart. It also links the hauling route with the feeder stockpile to
the South.The track stop does not need to be fully constructed before the
``#query`` blueprint is run, but the feeder stockpile needs to exist so we can
link to it. This means that the three blueprints above can be run one right
after another, without any dwarven labor in between them, and the quantum
stockpile will work properly.
Finally, the ``nocontainers`` alias simply configures the feeder stockpile to
not have any containers (which would just get in the way here). If we wanted
to be more specific about what item types we want in the quantum stockpile, we
could configure the feeder stockpile further, for example with standard
`stockpile adjustment aliases <quickfort-stockpile-aliases>`.
After the blueprints are run, the last step is to manually assign a minecart
to the newly-defined hauling route.
You can define sub-aliases to customize how these aliases work, for example to
have fine-grained control over what item types are enabled for the route and
quantum stockpile. We'll go over those options below, but first, here is an
example for how to just give names to everything::
#query message(remember to assign a minecart to the new route)
,{quantum name="armory quantum"}
,{quantumstopfromsouth name="Armory quantum" stop_name="Armory quantum stop"}{givename name="armory dumper"}
{givename name="armory feeder"}
All ``name`` sub-aliases are completely optional, of course. Keep in mind that
hauling route names have a maximum length of 22 characters, hauling route stop
names have a maximum length of 21 characters, and all other names have a
maximum length of 20 characters.
If you want to be absolutely certain that nothing ends up in your quantum
stockpile other than what you've configured in the feeder stockpile, you can
set the ``quantum_enable`` sub-alias for the ``quantum`` alias. This can
prevent, for example, somebody's knocked-out tooth from being considered part
of your furniture quantum stockpile when it happened to land on it during a
fistfight::
#query
{quantum name="furniture quantum" quantum_enable={enablefurniture}}
You can have similar control over the hauling route if you need to be more
selective about what item types are allowed into the minecart. If you have
multiple specialized quantum stockpiles that use a common feeder pile, for
example, you can set the ``route_enable`` sub-alias::
#query
{quantumstopfromsouth name="Steel bar quantum" route_enable="{enablebars}{steelbars}"}
Any of the `stockpile configuration aliases <quickfort-stockpile-aliases>` can
be used for either the ``quantum_enable`` or ``route_enable`` sub-aliases.
Experienced Dwarf Fortress players may be wondering how the same aliases can
work in both contexts since the keys for entering the configuration screen
differ. Fear not! There is some sub-alias magic at work here. If you define
your own stockpile configuraiton aliases, you can use the magic yourself by
building your aliases on the ``*prefix`` aliases described later in this
guide.
Finally, the ``quantumstop`` alias is a more general version of the
``quantumstopfrom*`` aliases. The ``quantumstopfrom*`` aliases assume that the
feeder stockpile is orthogonally adjacent to your track stop (which is how
most people set them up). If your feeder stockpile is somewhere further away,
you can use the ``quantumstop`` alias directly. In addition to the
``quantumstopfrom*`` sub-aliases, you can also define the ``move`` and
``move_back`` sub-aliases, which let you specify the cursor keys required to
move from the track stop to the feeder stockpile and back again, respectively::
#query
{quantumstop move="{Right 2}{Up}" move_back="{Down}{Left 2}"}
Farm plots
~~~~~~~~~~
Sets a farm plot to grow the first or last type of seed in the list of
available seeds for all four seasons. The last seed is usually Plump helmet
spawn, suitable for post-embark. But if you only have one seed type, that'll
be grown instead.
+------------------+
| Alias |
+==================+
| growlastcropall |
+------------------+
| growfirstcropall |
+------------------+
Instead of these aliases, though, it might be more useful to use the DFHack
`autofarm` plugin.
Stockpile configuration utility aliases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
=============== ===========
Alias Sub-aliases
=============== ===========
linksonly
nocontainers
give2up
give2down
give2left
give2right
give10up
give10down
give10left
give10right
give move
togglesequence
togglesequence2
=============== ===========
``linksonly`` and ``nocontainers`` set the named basic properties on
stockpiles. ``nocontainers`` sets bins and barrels to 0, but does not affect
wheelbarrows since the hotkeys for changing the number of wheelbarrows depend
on whether you have the DFHack `stockpiles` plugin active. It is better to set
the number of wheelbarrows via the `quickfort` ``stockpiles_max_wheelbarrows``
setting. It is set to ``0`` by default.
The ``give*`` aliases set a stockpile to give to a workshop or another
stockpile located at the indicated number of tiles in the indicated direction
from the current tile. For example, here we use the ``give2down`` alias to
connect an ``otherstone`` stockpile with a mason workshop::
#place
s,s,s,s,s
s, , , ,s
s, , , ,s
s, , , ,s
s,s,s,s,s
#build
`,`,`,`,`
`, , , ,`
`, ,wm,,`
`, , , ,`
`,`,`,`,`
#query
, ,give2down
otherstone
and here is a generic stone stockpile that gives to a stockpile that only
takes flux::
#place
s(10x1)
s(10x10)
#query
flux
,
give2up
If you want to give to some other tile that is not already covered by the
``give2*`` or ``give10*`` aliases, you can use the generic ``give`` alias and
specify the movement keys yourself in the ``move`` sub-alias. Here is how to
give to a stockpile or workshop one z-level above, 9 tiles to the left, and 14
tiles down::
#query
{give move="<{Left 9}{Down 14}"}
``togglesequence`` and ``togglesequence2`` send ``{Down}{Enter}`` or
``{Down 2}{Enter}`` to toggle adjacent (or alternating) items in a list. This
is useful when toggling a bunch of related item types in the stockpile config.
For example, the ``dye`` and ``tallow`` aliases in the standard alias library
need to select specific items from long lists::
dye: {foodprefix}b{Right}{Down 11}{Right}{Down 28}{togglesequence 4}^
tallow: {foodprefix}b{Right}{Down 13}{Right}{Down}{togglesequence2 811}^
.. _quickfort-stockpile-aliases:
Stockpile adjustment aliases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For each stockpile item category, there are three standard aliases:
* ``*prefix`` aliases enter the stockpile configuration screen and position
the cursor at a particular item category in the left-most column, ready for
further keys that configure the elements within that category. All other
stockpile adjustment aliases are built on these prefixes. You can use them
yourself to create stockpile adjustment aliases that aren't already covered
by the standard library aliases. Using the library prefix instead of
creating your own also allows your stockpile configuration aliases to be
used for both stockpiles and hauling routes. For example, here is the
library definition for ``booze``::
booze: {foodprefix}b{Right}{Down 5}p{Down}p^
* ``enable*`` aliases enter the stockpile configuration screen, enable all
subtypes of the named category, and exit the stockpile configuration screen
* ``disable*`` aliases enter the stockpile configuration screen, disable all
subtypes of the named category, and exit the stockpile configuration screen
==================== ==================== =====================
Prefix Enable Disable
==================== ==================== =====================
animalsprefix enableanimals disableanimals
foodprefix enablefood disablefood
furnitureprefix enablefurniture disablefurniture
corpsesprefix enablecorpses disablecorpses
refuseprefix enablerefuse disablerefuse
stoneprefix enablestone disablestone
ammoprefix enableammo disableammo
coinsprefix enablecoins disablecoins
barsprefix enablebars disablebars
gemsprefix enablegems disablegems
finishedgoodsprefix enablefinishedgoods disablefinishedgoods
leatherprefix enableleather disableleather
clothprefix enablecloth disablecloth
woodprefix enablewood disablewood
weaponsprefix enableweapons disableweapons
armorprefix enablearmor disablearmor
sheetprefix enablesheet disablesheet
==================== ==================== =====================
Then, for each item category, there are aliases that manipulate interesting
subsets of that category:
* Exclusive aliases forbid everthing within a category and then enable only
the named item type (or named class of items)
* ``forbid*`` aliases forbid the named type and leave the rest of the
stockpile untouched.
* ``permit*`` aliases permit the named type and leave the rest of the
stockpile untouched.
Note that for specific item types (items in the third stockpile configuration
column), you can only toggle the item type on and off. Aliases can't know
whether sending the ``{Enter}`` key will enable or disable the type. The
``forbid*`` aliases that affect these item types assume the item type was
enabled and toggle it off. Likewise, the ``permit*`` aliases assume the item
type was disabled and toggle it on. If the item type is not in the expected
enabled/disabled state when the alias is run, the aliases will not behave
properly.
Animal stockpile adjustments
````````````````````````````
=========== =========== ============
Exclusive Forbid Permit
=========== =========== ============
cages forbidcages permitcages
traps forbidtraps permittraps
=========== =========== ============
Food stockpile adjustments
``````````````````````````
=============== ==================== ====================
Exclusive Forbid Permit
=============== ==================== ====================
preparedfood forbidpreparedfood permitpreparedfood
unpreparedfish forbidunpreparedfish permitunpreparedfish
plants forbidplants permitplants
booze forbidbooze permitbooze
seeds forbidseeds permitseeds
dye forbiddye permitdye
tallow forbidtallow permittallow
miscliquid forbidmiscliquid permitmiscliquid
=============== ==================== ====================
Furniture stockpile adjustments
```````````````````````````````
+-----------+
| Exclusive |
+===========+
| pots |
+-----------+
| bags |
+-----------+
| buckets |
+-----------+
| sand |
+-----------+
Notes:
* Because of the limitations of Dwarf Fortress, ``bags`` cannot distinguish
between empty and filled bags
Refuse stockpile adjustments
````````````````````````````
=========== ================== ==================
Exclusive Forbid Permit
=========== ================== ==================
bodyparts forbidbodyparts permitbodyparts
rawhides forbidrawhides permitrawhides
tannedhides forbidtannedhides permittannedhides
skulls forbidskulls permitskulls
bones forbidbones permitbones
shells forbidshells permitshells
teeth forbidteeth permitteeth
horns forbidhorns permithorns
hair forbidhair permithair
craftrefuse forbidcraftrefuse permitcraftrefuse
=========== ================== ==================
Notes:
* ``bodyparts`` includes remains/corpses and rotten rawhdes.
* ``craftrefuse`` includes everything a craftsdwarf can use: skulls, bones,
shells, teeth, horns, and hair.
Stone stockpile adjustments
```````````````````````````
============= ==================== ====================
Exclusive Forbid Permit
============= ==================== ====================
metal forbidmetal permitmetal
iron forbidiron permitiron
economic forbideconomic permiteconomic
flux forbidflux permitflux
plaster forbidplaster permitplaster
coalproducing forbidcoalproducing permitcoalproducing
otherstone forbidotherstone permitotherstone
bauxite forbidbauxite permitbauxite
clay forbidclay permitclay
============= ==================== ====================
Ammo stockpile adjustments
``````````````````````````
=============== ====================
Exclusive Forbid
=============== ====================
bolts
\ forbidmetalbolts
\ forbidwoodenbolts
\ forbidbonebolts
=============== ====================
Bar stockpile adjustments
`````````````````````````
=========== ==================
Exclusive Forbid
=========== ==================
bars forbidbars
metalbars forbidmetalbars
ironbars forbidironbars
steelbars forbidsteelbars
pigironbars forbidpigironbars
otherbars forbidotherbars
coal forbidcoal
potash forbidpotash
ash forbidash
pearlash forbidpearlash
soap forbidsoap
blocks forbidblocks
=========== ==================
Gem stockpile adjustments
`````````````````````````
=========== ================
Exclusive Forbid
=========== ================
roughgems forbidroughgems
roughglass forbidroughglass
cutgems forbidcutgems
cutglass forbidcutglass
cutstone forbidcutstone
=========== ================
Finished goods stockpile adjustments
````````````````````````````````````
+-----------+
| Exclusive |
+===========+
| jugs |
+-----------+
Cloth stockpile adjustments
```````````````````````````
+------------------+
| Exclusive |
+==================+
| thread |
+------------------+
| adamantinethread |
+------------------+
| cloth |
+------------------+
| adamantinecloth |
+------------------+
Weapon stockpile adjustments
````````````````````````````
================= ======================== ====================
Exclusive Forbid Permit
================= ======================== ====================
\ forbidweapons permitweapons
\ forbidtrapcomponents permittrapcomponents
metalweapons forbidmetalweapons permitmetalweapons
\ forbidstoneweapons permitstoneweapons
\ forbidotherweapons permitotherweapons
ironweapons forbidironweapons permitironweapons
copperweapons forbidcopperweapons permitcopperweapons
steelweapons forbidsteelweapons permitsteelweapons
masterworkweapons forbidmasterworkweapons permitmasterworkweapons
artifactweapons forbidartifactweapons permitartifactweapons
================= ======================== ====================
Armor stockpile adjustments
```````````````````````````
=============== ====================== ====================
Exclusive Forbid Permit
=============== ====================== ====================
metalarmor forbidmetalarmor permitmetalarmor
otherarmor forbidotherarmor permitotherarmor
ironarmor forbidironarmor permitironarmor
copperarmor forbidcopperarmor permitcopperarmor
steelarmor forbidsteelarmor permitsteelarmor
masterworkarmor forbidmasterworkarmor permitmasterworkarmor
artifactarmor forbidartifactarmor permitartifactarmor
=============== ====================== ====================

@ -0,0 +1,106 @@
.. _quickfort-library-guide:
Quickfort Library Guide
=======================
This guide contains a high-level overview of the blueprints available in the
:source:`quickfort blueprint library <data/blueprints/library>`. You can list
library blueprints by running ``quickfort list --library`` or by hitting
:kbd:`Alt`:kbd:`l` in the ``quickfort gui`` interactive dialog.
Each file is hyperlinked to its online version so you can see exactly what the
blueprints do.
Whole fort blueprint sets
-------------------------
These files contain the plans for entire fortresses. Each file has one or more
help sections that walk you through how to build the fort, step by step.
- :source:`library/dreamfort.csv <data/blueprints/library/dreamfort.csv>`
- :source:`library/quickfortress.csv <data/blueprints/library/quickfortress.csv>`
Dreamfort
~~~~~~~~~
Dreamfort is a fully functional, self-sustaining fortress with defenses,
farming, a complete set of workshops, self-managing quantum stockpiles, a grand
dining hall, hospital, jail, fresh water well system, guildhalls, and bedrooms
for hundreds of dwarves. It also comes with manager work orders to automate
basic fort needs, such as food and booze production. It can function by itself
or as the core of a larger, more ambitious fortress. Read the high-level
walkthrough by running ``quickfort run library/dreamfort.csv`` and list the
walkthroughs for the individual levels by running ``quickfort list dreamfort -l
-m notes`` or by opening the ``quickfort gui`` dialog, enabling the library
with :kbd:`Alt`:kbd:`l`, and setting the filter to ``dreamfort notes``.
Dreamfort blueprints are also available for easy viewing and copying `online
<https://drive.google.com/drive/folders/1iS90EEVqUkxTeZiiukVj1pLloZqabKuP>`__.
The Quick Fortresses
~~~~~~~~~~~~~~~~~~~~
The Quick Fortress is an updated version of the example fortress that came with
`Python Quickfort 2.0 <https://github.com/joelpt/quickfort>`__ (the program
DFHack quickfort was inspired by). While it is not a complete fortress by
itself, it is much simpler than Dreamfort and is good for a first introduction
to `quickfort` blueprints. Read its walkthrough with ``quickfort run
library/quickfortress.csv``.
Layout helpers
--------------
These files simply draw diagonal marker-mode lines starting from the cursor.
They are especially useful for finding the center of the map when you are
planning your fortress. Once you are done using them for alignment, use
``quickfort undo`` at the same cursor position to make them disappear. Since
these ``#dig`` blueprints can only mark undug wall tiles for mining, they are
best used underground. They won't do much on the surface, where there aren't
many walls.
- :source:`library/layout-helpers/mark_up_left.csv <data/blueprints/library/layout-helpers/mark_up_left.csv>`
- :source:`library/layout-helpers/mark_up_right.csv <data/blueprints/library/layout-helpers/mark_up_right.csv>`
- :source:`library/layout-helpers/mark_down_right.csv <data/blueprints/library/layout-helpers/mark_down_right.csv>`
- :source:`library/layout-helpers/mark_down_left.csv <data/blueprints/library/layout-helpers/mark_down_left.csv>`
Bedrooms
--------
These are popular bedroom layouts from the :wiki:`Bedroom design` page on the
wiki. Each file has ``#dig``, ``#build``, and ``#query`` blueprints to dig the
rooms, build the furniture, and configure the beds as bedrooms, respectively.
- :source:`library/bedrooms/48-4-Raynard_Whirlpool_Housing.csv <data/blueprints/library/bedrooms/48-4-Raynard_Whirlpool_Housing.csv>`
- :source:`library/bedrooms/95-9-Hactar1_3_Branch_Tree.csv <data/blueprints/library/bedrooms/95-9-Hactar1_3_Branch_Tree.csv>`
- :source:`library/bedrooms/28-3-Modified_Windmill_Villas.csv <data/blueprints/library/bedrooms/28-3-Modified_Windmill_Villas.csv>`
Tombs
-----
These blueprints have burial plot layouts for fortress that expect a lot of
casualties.
- :source:`library/tombs/Mini_Saracen.csv <data/blueprints/library/tombs/Mini_Saracen.csv>`
- :source:`library/tombs/The_Saracen_Crypts.csv <data/blueprints/library/tombs/The_Saracen_Crypts.csv>`
Exploratory mining
------------------
Several mining patterns to choose from when searching for gems or ores. The
patterns can be repeated up or down z-levels for exploring through the depths.
- :source:`library/exploratory-mining/tunnels.csv <data/blueprints/library/exploratory-mining/tunnels.csv>`
- :source:`library/exploratory-mining/vertical-mineshafts.csv <data/blueprints/library/exploratory-mining/vertical-mineshafts.csv>`
- :source:`library/exploratory-mining/connected-mineshafts.csv <data/blueprints/library/exploratory-mining/connected-mineshafts.csv>`
Miscellaneous
-------------
Extra blueprints that are useful in specific situations.
- :source:`library/embark.csv <data/blueprints/library/embark.csv>`
The embark blueprints are useful directly after embark. It contains a ``#build``
blueprint that builds important starting workshops (mason, carpenter, mechanic,
and craftsdwarf) and a ``#place`` blueprint that lays down a pattern of useful
starting stockpiles.

File diff suppressed because it is too large Load Diff

@ -156,9 +156,6 @@ def parse_changelog():
def consolidate_changelog(all_entries): def consolidate_changelog(all_entries):
for sections in all_entries.values(): for sections in all_entries.values():
for section, entries in sections.items(): for section, entries in sections.items():
# sort() is stable, so reverse entries so that older entries for the
# same feature are on top
entries.reverse()
entries.sort(key=lambda entry: entry.sort_key) entries.sort(key=lambda entry: entry.sort_key)
new_entries = [] new_entries = []
for feature, group in itertools.groupby(entries, for feature, group in itertools.groupby(entries,

@ -485,3 +485,5 @@ if(BUILD_DEVEL)
DESTINATION ${DFHACK_INCLUDES_DESTINATION} DESTINATION ${DFHACK_INCLUDES_DESTINATION}
FILES_MATCHING PATTERN "*.h" PATTERN "*.inc" ) FILES_MATCHING PATTERN "*.h" PATTERN "*.inc" )
endif() endif()
add_subdirectory(xml)

@ -24,6 +24,7 @@ distribution.
#define DFhackCExport extern "C" __declspec(dllexport) #define DFhackCExport extern "C" __declspec(dllexport)
#define NOMINMAX
#include <windows.h> #include <windows.h>
#include <stdint.h> #include <stdint.h>
#include <vector> #include <vector>
@ -35,6 +36,7 @@ distribution.
#include "tinythread.h" #include "tinythread.h"
#include "modules/Graphic.h" #include "modules/Graphic.h"
#include "../plugins/uicommon.h"
/* /*
* Plugin loading functions * Plugin loading functions
@ -44,7 +46,22 @@ namespace DFHack
DFLibrary* GLOBAL_NAMES = (DFLibrary*)GetModuleHandle(nullptr); DFLibrary* GLOBAL_NAMES = (DFLibrary*)GetModuleHandle(nullptr);
DFLibrary * OpenPlugin (const char * filename) DFLibrary * OpenPlugin (const char * filename)
{ {
return (DFLibrary *) LoadLibrary(filename); DFLibrary *ret = (DFLibrary *) LoadLibrary(filename);
if (!ret) {
DWORD error = GetLastError();
LPSTR buf = NULL;
DWORD len = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
if (len > 0) {
std::string message = buf;
std::cerr << "LoadLibrary " << filename << ": " << rtrim(message) << " (" << error << ")" << std::endl;
LocalFree(buf);
}
else {
std::cerr << "LoadLibrary " << filename << ": unknown error " << error << std::endl;
}
}
return ret;
} }
void * LookupPlugin (DFLibrary * plugin ,const char * function) void * LookupPlugin (DFLibrary * plugin ,const char * function)
{ {

@ -162,6 +162,8 @@ DFHACK_EXPORT bool hasSupport(df::coord pos, df::coord2d size);
/** /**
* Sets the size of the building, using size and direction as guidance. * Sets the size of the building, using size and direction as guidance.
* Any custom extents set for the building will be cleared if the size passed in
* as guidance cannot be applied to the building.
* Returns true if the building can be created at its position, using that size. * Returns true if the building can be created at its position, using that size.
*/ */
DFHACK_EXPORT bool setSize(df::building *bld, df::coord2d size, int direction = 0); DFHACK_EXPORT bool setSize(df::building *bld, df::coord2d size, int direction = 0);

@ -485,6 +485,11 @@ function buildings.constructBuilding(info)
local to_delete = instance local to_delete = instance
return dfhack.with_finalize( return dfhack.with_finalize(
function() function()
-- ensure we don't leak extents created by Buildings::checkFreeTiles
if to_delete and to_delete.room.extents then
df.delete(to_delete.room.extents)
to_delete.room.extents = nil
end
df.delete(to_delete) df.delete(to_delete)
end, end,
function() function()

@ -758,18 +758,19 @@ bool Buildings::setSize(df::building *bld, df::coord2d size, int direction)
CHECK_NULL_POINTER(bld); CHECK_NULL_POINTER(bld);
CHECK_INVALID_ARGUMENT(bld->id == -1); CHECK_INVALID_ARGUMENT(bld->id == -1);
// Delete old extents
if (bld->room.extents)
{
delete[] bld->room.extents;
bld->room.extents = NULL;
}
// Compute correct size and apply it // Compute correct size and apply it
df::coord2d old_size = size;
df::coord2d center; df::coord2d center;
getCorrectSize(size, center, bld->getType(), bld->getSubtype(), getCorrectSize(size, center, bld->getType(), bld->getSubtype(),
bld->getCustomType(), direction); bld->getCustomType(), direction);
// Delete old extents if size has changed.
if (old_size != size && bld->room.extents)
{
delete[] bld->room.extents;
bld->room.extents = NULL;
}
bld->x2 = bld->x1 + size.x - 1; bld->x2 = bld->x1 + size.x - 1;
bld->y2 = bld->y1 + size.y - 1; bld->y2 = bld->y1 + size.y - 1;
bld->centerx = bld->x1 + center.x; bld->centerx = bld->x1 + center.x;

@ -1 +1 @@
Subproject commit 403722a6cbdcb65256359ceab03b203d65489c3e Subproject commit 4b3b0f0046af33749bf3e5e61f1374c4c461d332

@ -59,7 +59,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <Plug
" digFlood 1\n" " digFlood 1\n"
" enable plugin\n" " enable plugin\n"
" digFlood 0 MICROCLINE COAL_BITUMINOUS 1\n" " digFlood 0 MICROCLINE COAL_BITUMINOUS 1\n"
" disable plugin and remove microcline and bituminous coal from being monitored, then re-enable plugin" " disable plugin and remove microcline and bituminous coal from being monitored, then re-enable plugin\n"
" digFlood 1 MICROCLINE 0 COAL_BITUMINOUS 1\n" " digFlood 1 MICROCLINE 0 COAL_BITUMINOUS 1\n"
" do monitor microcline, don't monitor COAL_BITUMINOUS, then enable plugin\n" " do monitor microcline, don't monitor COAL_BITUMINOUS, then enable plugin\n"
" digFlood CLEAR\n" " digFlood CLEAR\n"

@ -498,7 +498,7 @@ namespace embark_assist {
else { else {
process_embark_incursion(result, process_embark_incursion(result,
survey_results, survey_results,
&survey_results->at(fetch_x).at(fetch_y).south_row[i], &survey_results->at(fetch_x).at(fetch_y).south_row[fetch_i],
finder, finder,
mlt->at(i).at(k).elevation, mlt->at(i).at(k).elevation,
fetch_x, fetch_x,
@ -530,7 +530,7 @@ namespace embark_assist {
else { else {
process_embark_incursion(result, process_embark_incursion(result,
survey_results, survey_results,
&survey_results->at(fetch_x).at(fetch_y).north_row[i], &survey_results->at(fetch_x).at(fetch_y).north_row[fetch_i],
finder, finder,
mlt->at(i).at(k).elevation, mlt->at(i).at(k).elevation,
fetch_x, fetch_x,
@ -542,7 +542,7 @@ namespace embark_assist {
if (fetch_i < 0) { if (fetch_i < 0) {
process_embark_incursion(result, process_embark_incursion(result,
survey_results, survey_results,
&survey_results->at(fetch_x).at(fetch_y).east_column[k], &survey_results->at(fetch_x).at(fetch_y).east_column[fetch_k],
finder, finder,
mlt->at(i).at(k).elevation, mlt->at(i).at(k).elevation,
fetch_x, fetch_x,
@ -552,7 +552,7 @@ namespace embark_assist {
else if (fetch_i > 15) { else if (fetch_i > 15) {
process_embark_incursion(result, process_embark_incursion(result,
survey_results, survey_results,
&survey_results->at(fetch_x).at(fetch_y).west_column[k], &survey_results->at(fetch_x).at(fetch_y).west_column[fetch_k],
finder, finder,
mlt->at(i).at(k).elevation, mlt->at(i).at(k).elevation,
fetch_x, fetch_x,

@ -432,17 +432,17 @@ namespace embark_assist {
} }
if (world->world_data->world_height == 17) { if (world->world_data->world_height == 17) {
divisor = (57 / steps * lat + 0.4); divisor = ((lat * 57) / steps + 0.4);
} }
else if (world->world_data->world_height == 33) { else if (world->world_data->world_height == 33) {
divisor = (61 / steps * lat + 0.1); divisor = ((lat * 61) / steps + 0.1);
} }
else if (world->world_data->world_height == 65) { else if (world->world_data->world_height == 65) {
divisor = (63 / steps * lat); divisor = ((lat * 63) / steps);
} }
else if (world->world_data->world_height == 129 || else if (world->world_data->world_height == 129 ||
world->world_data->world_height == 257) { world->world_data->world_height == 257) {
divisor = (64 / steps * lat); divisor = ((lat * 64) / steps);
} }
else { else {
return max_temperature; // Not any standard world height. No formula available return max_temperature; // Not any standard world height. No formula available
@ -601,7 +601,7 @@ namespace embark_assist {
else { else {
process_embark_incursion(site_info, process_embark_incursion(site_info,
survey_results, survey_results,
&survey_results->at(fetch_x).at(fetch_y).south_row[i], &survey_results->at(fetch_x).at(fetch_y).south_row[fetch_i],
mlt->at(i).at(k).elevation, mlt->at(i).at(k).elevation,
fetch_x, fetch_x,
fetch_y); fetch_y);
@ -627,7 +627,7 @@ namespace embark_assist {
else { else {
process_embark_incursion(site_info, process_embark_incursion(site_info,
survey_results, survey_results,
&survey_results->at(fetch_x).at(fetch_y).north_row[i], &survey_results->at(fetch_x).at(fetch_y).north_row[fetch_i],
mlt->at(i).at(k).elevation, mlt->at(i).at(k).elevation,
fetch_x, fetch_x,
fetch_y); fetch_y);
@ -637,7 +637,7 @@ namespace embark_assist {
if (fetch_i < 0) { if (fetch_i < 0) {
process_embark_incursion(site_info, process_embark_incursion(site_info,
survey_results, survey_results,
&survey_results->at(fetch_x).at(fetch_y).east_column[k], &survey_results->at(fetch_x).at(fetch_y).east_column[fetch_k],
mlt->at(i).at(k).elevation, mlt->at(i).at(k).elevation,
fetch_x, fetch_x,
fetch_y); fetch_y);
@ -645,7 +645,7 @@ namespace embark_assist {
else if (fetch_i > 15) { else if (fetch_i > 15) {
process_embark_incursion(site_info, process_embark_incursion(site_info,
survey_results, survey_results,
&survey_results->at(fetch_x).at(fetch_y).west_column[k], &survey_results->at(fetch_x).at(fetch_y).west_column[fetch_k],
mlt->at(i).at(k).elevation, mlt->at(i).at(k).elevation,
fetch_x, fetch_x,
fetch_y); fetch_y);
@ -1663,8 +1663,8 @@ uint8_t embark_assist::survey::translate_corner(embark_assist::defs::world_tile
return embark_assist::defs::directions::Center; return embark_assist::defs::directions::Center;
} }
nw_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i - 1, effective_k - 1); nw_region_type = embark_assist::survey::region_type_of(survey_results, effective_x, effective_y, effective_i - 1, effective_k - 1);
w_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i - 1, effective_k); w_region_type = embark_assist::survey::region_type_of(survey_results, effective_x, effective_y, effective_i - 1, effective_k);
if (nw_region_type == df::world_region_type::Lake || if (nw_region_type == df::world_region_type::Lake ||
nw_region_type == df::world_region_type::Ocean) { nw_region_type == df::world_region_type::Ocean) {
@ -1705,8 +1705,8 @@ uint8_t embark_assist::survey::translate_corner(embark_assist::defs::world_tile
} }
} }
else if (effective_y == world_data->world_height) { else if (effective_y == world_data->world_height) {
nw_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i - 1, effective_k - 1); nw_region_type = embark_assist::survey::region_type_of(survey_results, effective_x, effective_y, effective_i - 1, effective_k - 1);
n_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i, effective_k - 1); n_region_type = embark_assist::survey::region_type_of(survey_results, effective_x, effective_y, effective_i, effective_k - 1);
if (nw_region_type == df::world_region_type::Lake || if (nw_region_type == df::world_region_type::Lake ||
nw_region_type == df::world_region_type::Ocean) { nw_region_type == df::world_region_type::Ocean) {
@ -1756,10 +1756,10 @@ uint8_t embark_assist::survey::translate_corner(embark_assist::defs::world_tile
effective_corner = survey_results->at(effective_x).at(effective_y).west_corner_selection[effective_k]; effective_corner = survey_results->at(effective_x).at(effective_y).west_corner_selection[effective_k];
} }
nw_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i - 1, effective_k - 1); nw_region_type = embark_assist::survey::region_type_of(survey_results, effective_x, effective_y, effective_i - 1, effective_k - 1);
n_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i, effective_k - 1); n_region_type = embark_assist::survey::region_type_of(survey_results, effective_x, effective_y, effective_i, effective_k - 1);
w_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i - 1, effective_k); w_region_type = embark_assist::survey::region_type_of(survey_results, effective_x, effective_y, effective_i - 1, effective_k);
home_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i, effective_k); home_region_type = embark_assist::survey::region_type_of(survey_results, effective_x, effective_y, effective_i, effective_k);
if (nw_region_type == df::world_region_type::Lake || if (nw_region_type == df::world_region_type::Lake ||
nw_region_type == df::world_region_type::Ocean) { nw_region_type == df::world_region_type::Ocean) {

@ -196,27 +196,24 @@ function job_outputs.MakeCrafts(callback, job)
end end
local plant_products = { local plant_products = {
BrewDrink = 'DRINK',
MillPlants = 'MILL', MillPlants = 'MILL',
ProcessPlants = 'THREAD', ProcessPlants = 'THREAD',
ProcessPlantsBag = 'LEAVES',
ProcessPlantsBarrel = 'EXTRACT_BARREL', ProcessPlantsBarrel = 'EXTRACT_BARREL',
ProcessPlantsVial = 'EXTRACT_VIAL', ProcessPlantsVial = 'EXTRACT_VIAL',
ExtractFromPlants = 'EXTRACT_STILL_VIAL', ExtractFromPlants = 'EXTRACT_STILL_VIAL',
} }
for job,flag in pairs(plant_products) do for job,flag in pairs(plant_products) do
local ttag = 'type_'..string.lower(flag) local tag = string.lower(flag)
local itag = 'idx_'..string.lower(flag)
job_outputs[job] = function(callback, job) job_outputs[job] = function(callback, job)
local mat_type, mat_index = -1, -1 local mat_type, mat_index = -1, -1
local seed_type, seed_index = -1, -1 local seed_type, seed_index = -1, -1
local mat = dfhack.matinfo.decode(job.job_items[0]) local mat = dfhack.matinfo.decode(job.job_items[0])
if mat and mat.plant and mat.plant.flags[flag] then if mat and mat.plant and mat.plant.flags[flag] then
mat_type = mat.plant.material_defs[ttag] mat_type = mat.plant.material_defs.type[tag]
mat_index = mat.plant.material_defs[itag] mat_index = mat.plant.material_defs.idx[tag]
seed_type = mat.plant.material_defs['type_seed'] seed_type = mat.plant.material_defs.type.seed
seed_index = mat.plant.material_defs['idx_seed'] seed_index = mat.plant.material_defs.idx.seed
end end
local mat_mask = { } local mat_mask = { }
if flag ~= 'LEAVES' then if flag ~= 'LEAVES' then
@ -358,4 +355,10 @@ function listWeakenedConstraints(outputs)
return variants return variants
end end
if dfhack.internal.IN_TEST then
test_data = {
job_outputs = job_outputs,
}
end
return _ENV return _ENV

@ -309,10 +309,17 @@ command_result df_probe (color_ostream &out, vector <string> & parameters)
if(des.bits.water_stagnant) if(des.bits.water_stagnant)
out << "stagnant" << endl; out << "stagnant" << endl;
out.print("%-16s= %s\n", "dig", ENUM_KEY_STR(tile_dig_designation, des.bits.dig).c_str());
out.print("%-16s= %s\n", "traffic", ENUM_KEY_STR(tile_traffic, des.bits.traffic).c_str());
#define PRINT_FLAG( FIELD, BIT ) out.print("%-16s= %c\n", #BIT , ( FIELD.bits.BIT ? 'Y' : ' ' ) ) #define PRINT_FLAG( FIELD, BIT ) out.print("%-16s= %c\n", #BIT , ( FIELD.bits.BIT ? 'Y' : ' ' ) )
out.print("%-16s= %s\n", "dig", enum_item_key(des.bits.dig).c_str());
PRINT_FLAG(occ, dig_marked);
PRINT_FLAG(occ, dig_auto);
out.print("%-16s= %s\n", "traffic", enum_item_key(des.bits.traffic).c_str());
PRINT_FLAG(occ, carve_track_north);
PRINT_FLAG(occ, carve_track_south);
PRINT_FLAG(occ, carve_track_east);
PRINT_FLAG(occ, carve_track_west);
PRINT_FLAG( des, hidden ); PRINT_FLAG( des, hidden );
PRINT_FLAG( des, light ); PRINT_FLAG( des, light );
PRINT_FLAG( des, outside ); PRINT_FLAG( des, outside );
@ -344,12 +351,19 @@ command_result df_probe (color_ostream &out, vector <string> & parameters)
out.print(" (%2d)", global.type); out.print(" (%2d)", global.type);
out.print(" %s\n", sa_feature(global.type)); out.print(" %s\n", sa_feature(global.type));
} }
#undef PRINT_FLAG
out << "local feature idx: " << block.local_feature out << "local feature idx: " << block.local_feature
<< endl; << endl;
out << "global feature idx: " << block.global_feature out << "global feature idx: " << block.global_feature
<< endl; << endl;
out << std::endl; out << endl;
out << "Occupancy:" << endl;
out.print("%-16s= %s\n", "building", enum_item_key(occ.bits.building).c_str());
PRINT_FLAG(occ, unit);
PRINT_FLAG(occ, unit_grounded);
PRINT_FLAG(occ, item);
PRINT_FLAG(occ, moss);
out << endl;
if(block.occupancy[tileX][tileY].bits.no_grow) if(block.occupancy[tileX][tileY].bits.no_grow)
out << "no grow" << endl; out << "no grow" << endl;
@ -382,7 +396,7 @@ command_result df_probe (color_ostream &out, vector <string> & parameters)
} }
} }
#undef PRINT_FLAG
return CR_OK; return CR_OK;
} }

@ -1081,7 +1081,7 @@ void CopyDesignation(df::map_block * DfBlock, RemoteFortressReader::MapBlock * N
if (gamemode && (*gamemode == game_mode::ADVENTURE)) if (gamemode && (*gamemode == game_mode::ADVENTURE))
{ {
auto fog_of_war = DfBlock->fog_of_war[xx][yy]; auto fog_of_war = DfBlock->fog_of_war[xx][yy];
NetBlock->add_hidden(designation.bits.dig == TileDigDesignation::NO_DIG || designation.bits.hidden); NetBlock->add_hidden((TileDigDesignation)designation.bits.dig == TileDigDesignation::NO_DIG || designation.bits.hidden);
NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG);
NetBlock->add_tile_dig_designation_marker(false); NetBlock->add_tile_dig_designation_marker(false);
NetBlock->add_tile_dig_designation_auto(false); NetBlock->add_tile_dig_designation_auto(false);

@ -97,7 +97,7 @@ void make_text_dim(int x1, int x2, int y)
static bool is_live_screen(const df::viewscreen *screen) static bool is_live_screen(const df::viewscreen *screen)
{ {
for (df::viewscreen *cur = &gview->view; cur; cur = cur->child) for (df::viewscreen *cur = &gview->view; cur; cur = cur->child)
if (cur == screen) if (cur == screen && cur->breakdown_level == interface_breakdown_types::NONE)
return true; return true;
return false; return false;
} }

@ -1 +1 @@
Subproject commit 2c8b19167268c4aee7976f67c93c510b30b115e1 Subproject commit 9911d54b02aa514004b95034ce8b5091e316a007

@ -104,6 +104,16 @@ function delay(frames)
script.sleep(frames, 'frames') script.sleep(frames, 'frames')
end end
function clean_require(module)
-- wrapper around require() - forces a clean load of every module to ensure
-- that modules checking for dfhack.internal.IN_TEST at load time behave
-- properly
if package.loaded[module] then
reload(module)
end
return require(module)
end
function ensure_title_screen() function ensure_title_screen()
if df.viewscreen_titlest:is_instance(dfhack.gui.getCurViewscreen()) then if df.viewscreen_titlest:is_instance(dfhack.gui.getCurViewscreen()) then
return return
@ -153,6 +163,7 @@ function build_test_env()
}, },
expect = {}, expect = {},
delay = delay, delay = delay,
require = clean_require,
} }
local private = { local private = {
checks = 0, checks = 0,
@ -206,6 +217,7 @@ function save_test_status(status)
end end
function finish_tests() function finish_tests()
dfhack.internal.IN_TEST = false
if done_command then if done_command then
dfhack.run_command(done_command) dfhack.run_command(done_command)
end end
@ -220,7 +232,9 @@ function load_tests(file, tests)
dfhack.printerr('Failed to load file: ' .. tostring(err)) dfhack.printerr('Failed to load file: ' .. tostring(err))
return false return false
else else
dfhack.internal.IN_TEST = true
local ok, err = pcall(code) local ok, err = pcall(code)
dfhack.internal.IN_TEST = false
if not ok then if not ok then
dfhack.printerr('Error when running file: ' .. tostring(err)) dfhack.printerr('Error when running file: ' .. tostring(err))
return false return false
@ -260,7 +274,9 @@ function run_test(test, status, counts)
test.private.checks = 0 test.private.checks = 0
test.private.checks_ok = 0 test.private.checks_ok = 0
counts.tests = counts.tests + 1 counts.tests = counts.tests + 1
dfhack.internal.IN_TEST = true
local ok, err = pcall(test.func) local ok, err = pcall(test.func)
dfhack.internal.IN_TEST = false
local passed = false local passed = false
if not ok then if not ok then
dfhack.printerr('test errored: ' .. test.name .. ': ' .. tostring(err)) dfhack.printerr('test errored: ' .. test.name .. ': ' .. tostring(err))

@ -0,0 +1,7 @@
local workflow = require('plugins.workflow')
function test.job_outputs()
for job_type in pairs(workflow.test_data.job_outputs) do
expect.ne(df.job_type[job_type], nil, "Found unrecognized job type: " .. tostring(job_type))
end
end

@ -0,0 +1,3 @@
function test.internal_in_test()
expect.true_(dfhack.internal.IN_TEST)
end

@ -128,21 +128,17 @@ def main():
lines[i] = line.decode('utf-8') lines[i] = line.decode('utf-8')
except UnicodeDecodeError: except UnicodeDecodeError:
msg_params = (rel_path, i + 1, 'Invalid UTF-8 (other errors will be ignored)') msg_params = (rel_path, i + 1, 'Invalid UTF-8 (other errors will be ignored)')
error('%s:%i: %s' % msg_params)
if is_github_actions: if is_github_actions:
error()
print('::error file=%s,line=%i::%s' % msg_params) print('::error file=%s,line=%i::%s' % msg_params)
else:
error('%s:%i: %s' % msg_params)
lines[i] = '' lines[i] = ''
for linter in linters: for linter in linters:
try: try:
linter.check(lines) linter.check(lines)
except LinterError as e: except LinterError as e:
error('%s: %s' % (rel_path, e))
if is_github_actions: if is_github_actions:
error()
print(e.github_actions_workflow_command(rel_path)) print(e.github_actions_workflow_command(rel_path))
else:
error('%s: %s' % (rel_path, e))
if fix: if fix:
linter.fix(lines) linter.fix(lines)
contents = '\n'.join(lines) contents = '\n'.join(lines)

@ -11,6 +11,7 @@ def print_stderr(stderr, args):
return return
for line in stderr.split('\n'): for line in stderr.split('\n'):
print(line)
parts = list(map(str.strip, line.split(':'))) parts = list(map(str.strip, line.split(':')))
# e.g. luac prints "luac:" in front of messages, so find the first part # e.g. luac prints "luac:" in front of messages, so find the first part
# containing the actual filename # containing the actual filename
@ -18,7 +19,6 @@ def print_stderr(stderr, args):
if parts[i].endswith('.' + args.ext) and parts[i + 1].isdigit(): if parts[i].endswith('.' + args.ext) and parts[i + 1].isdigit():
print('::error file=%s,line=%s::%s' % (parts[i], parts[i + 1], ':'.join(parts[i + 2:]))) print('::error file=%s,line=%s::%s' % (parts[i], parts[i + 1], ':'.join(parts[i + 2:])))
break break
print(line)
def main(args): def main(args):