address review comments

- use :: shorthand where we can
- clarify sub-alias docs
- remove note about multiple modifier keys not being supported
develop
myk002 2020-12-11 11:22:38 -08:00
parent ab815de38f
commit 45a9106e9f
No known key found for this signature in database
GPG Key ID: 8A39CA0FA0C16E78
2 changed files with 89 additions and 220 deletions

@ -6,9 +6,7 @@ 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:
::
For example, say you have the following ``#build`` and ``#place`` blueprints::
#build masonry workshop
~, ~,~,`,`,`
@ -22,18 +20,14 @@ For example, say you have the following ``#build`` and ``#place`` blueprints:
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:
::
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:
::
or you could use aliases::
#query configure stockpile with aliases
~,~,~,otherstone,`,`
@ -41,9 +35,7 @@ or you could use aliases:
~,~,~,`, `,`
If the stockpile had only a single tile, you could also replay both aliases in
a single cell:
::
a single cell::
#query configure mason with multiple aliases in one cell
~,~,~,{otherstone}{give2left},`,`
@ -59,8 +51,9 @@ 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`. The aliases in that file are
described at the `bottom of this document <quickfort-alias-library>`.
: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,
@ -71,9 +64,7 @@ library.
Alias syntax and usage
----------------------
The syntax for defining aliases is:
::
The syntax for defining aliases is::
aliasname: expansion
@ -89,9 +80,7 @@ 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:
::
two rows and uses it as part of a longer sequence in the third row::
#query apply alias 'aliasname' in three different ways
aliasname
@ -100,26 +89,20 @@ two rows and uses it as part of a longer sequence in the third row:
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:
::
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:
::
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:
::
if they are the only text in the definition::
alias1: text1
alias2: alias1
@ -140,9 +123,7 @@ 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:
::
useful for blueprints::
Up
Down
@ -168,17 +149,12 @@ 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``.
Note that DF does not handle keys that have more than a single modifier, so
sequences like ``{Ctrl}{Alt}a`` will result in an error.
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:
::
brackets::
& expands to {Enter}
@ expands to {Shift}{Enter}
@ -193,9 +169,7 @@ 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":
::
one alias built into the code for the common shorthand for "make room"::
r+ expands to r+{Enter}
@ -208,52 +182,53 @@ 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. For example:
middle of a larger alias. As a simple example, the ``givename`` alias is defined
like this::
::
givename: !n{name}&
{quantumstopfromeast name="Trash Dump"}
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::
The value of the sub-alias ``name`` is used in the middle of the definition of
``quantumstopfromeast`` to give a useful name to your quantum dump hauling
route. Without sub-aliases, we'd have to write something like:
{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::
{quantumstopfromeastprefix}Trash Dump{quantumstopfromeastsuffix}
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:
::
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:
::
enable furniture for some specific stockpile like this::
{quantum quantum_enable={enablefurniture}}
Sub-aliases must be in one of the following formats:
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:`}`:
::
repetitions goes last, right before the :kbd:`}`::
{alias subaliasname=value repetitions}
@ -271,9 +246,7 @@ 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:
::
For example, here is the standard library alias for giving a name to a zone::
namezone: ^i{givename}^q
@ -318,9 +291,7 @@ namezone name
======== ===========
``givename`` works anywhere you can hit Ctrl-n to customize a name, like when
the cursor is over buildings and stockpiles. Example:
::
the cursor is over buildings and stockpiles. Example::
#place
f(10x2)
@ -330,9 +301,7 @@ the cursor is over buildings and stockpiles. Example:
``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:
::
mode. Example::
#zone
n(2x2)
@ -426,9 +395,7 @@ 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:
::
example for how to just give names to everything::
#query message(remember to assign a minecart to the new route)
,{quantum name="armory quantum"}
@ -445,9 +412,7 @@ 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:
::
fistfight::
#query
{quantum name="furniture quantum" quantum_enable={enablefurniture}}
@ -455,9 +420,7 @@ fistfight:
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:
::
example, you can set the ``route_enable`` sub-alias::
#query
{quantumstopfromsouth name="Steel bar quantum" route_enable="{enablebars}{steelbars}"}
@ -478,9 +441,7 @@ 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:
::
move from the track stop to the feeder stockpile and back again, respectively::
#query
{quantumstop move="{Right 2}{Up}" move_back="{Down}{Left 2}"}
@ -535,9 +496,7 @@ 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:
::
connect an ``otherstone`` stockpile with a mason workshop::
#place
s,s,s,s,s
@ -558,9 +517,7 @@ connect an ``otherstone`` stockpile with a mason workshop:
otherstone
and here is a generic stone stockpile that gives to a stockpile that only
takes flux:
::
takes flux::
#place
s(10x1)
@ -575,9 +532,7 @@ 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:
::
tiles down::
#query
{give move="<{Left 9}{Down 14}"}
@ -586,9 +541,7 @@ tiles down:
``{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:
::
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}^
@ -608,9 +561,7 @@ For each stockpile item category, there are three standard aliases:
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``:
::
library definition for ``booze``::
booze: {foodprefix}b{Right}{Down 5}p{Down}p^

@ -133,9 +133,7 @@ Sheets <https://sheets.new>`__, or `LibreOffice <https://www.libreoffice.org>`__
to edit blueprint files, but any text editor will do.
The format of Quickfort-compatible blueprint files is straightforward. The first
line (or upper-left cell) of the spreadsheet should look like this:
::
line (or upper-left cell) of the spreadsheet should look like this::
#dig
@ -169,9 +167,7 @@ You can use this space for explanations, attribution, etc.
Below this line begin entering keys in each spreadsheet cell that represent what
you want designated in the corresponding game map tile. For example, we could
dig out a 4x4 room like so (spaces are used as column separators here for
readability, but a real .csv file would have commas):
::
readability, but a real .csv file would have commas)::
#dig
d d d d #
@ -185,9 +181,7 @@ These are completely optional, but can be helpful to make the row and column
positions clear.
Once the dwarves have that dug out, let's build a walled-in bedroom within our
dug-out area:
::
dug-out area::
#build
Cw Cw Cw Cw #
@ -263,9 +257,7 @@ in your DFHack folder.
Area expansion syntax
~~~~~~~~~~~~~~~~~~~~~
In Quickfort, the following blueprints are equivalent:
::
In Quickfort, the following blueprints are equivalent::
#dig a 3x3 area
d d d #
@ -280,17 +272,13 @@ In Quickfort, the following blueprints are equivalent:
# # # #
The second example uses Quickfort's "area expansion syntax", which takes the
form:
::
form::
keys(WxH)
Note that area expansion syntax can only specify rectangular areas. If you want
to create extent-based structures (e.g. farm plots or stockpiles) in different
shapes, use the first format above. For example:
::
shapes, use the first format above. For example::
#place L shaped food stockpile
f f ` ` #
@ -300,9 +288,7 @@ shapes, use the first format above. For example:
# # # # #
Area expansion syntax also sets boundaries, which can be useful if you want
adjacent, but separate, stockpiles of the same type:
::
adjacent, but separate, stockpiles of the same type::
#place Two touching but separate food stockpiles
f(4x2) #
@ -313,9 +299,7 @@ adjacent, but separate, stockpiles of the same type:
As mentioned previously, :kbd:`~` characters are ignored as comment characters
and can be used for visualizing the blueprint layout. This blueprint can be
equivalently written as:
::
equivalently written as::
#place Two touching but separate food stockpiles
f(4x2) #
@ -328,9 +312,7 @@ since the area expansion syntax of the upper stockpile prevents it from
combining with the lower, freeform syntax stockpile.
Area expansion syntax can also be used for buildings which have an adjustable
size, like bridges. The following blueprints are equivalent:
::
size, like bridges. The following blueprints are equivalent::
#build a 4x2 bridge from row 1, col 1
ga(4x2) ` #
@ -347,9 +329,7 @@ Automatic area expansion
Buildings larger than 1x1, like workshops, can be represented in any of three
ways. You can designate just their center tile with empty cells around it to
leave room for the footprint, like this:
::
leave room for the footprint, like this::
#build a mason workshop in row 2, col 2 that will occupy the 3x3 area
` ` ` #
@ -357,9 +337,7 @@ leave room for the footprint, like this:
` ` ` #
# # # #
Or you can fill out the entire footprint like this:
::
Or you can fill out the entire footprint like this::
#build a mason workshop
wm wm wm #
@ -371,9 +349,7 @@ This format may be verbose for regular workshops, but it can be very helpful for
laying out structures like screw pump towers and waterwheels, whose "center
point" can be non-obvious.
Finally, you can use area expansion syntax to represent the workshop:
::
Finally, you can use area expansion syntax to represent the workshop::
#build a mason workshop
wm(3x3) #
@ -383,9 +359,7 @@ Finally, you can use area expansion syntax to represent the workshop:
This style can be convenient for laying out multiple buildings of the same type.
If you are building a large-scale block factory, for example, this will create
20 mason workshops all in a row:
::
20 mason workshops all in a row::
#build line of 20 mason workshops
wm(60x3)
@ -423,9 +397,7 @@ Dig priorities
DF designation priorities are supported for ``#dig`` blueprints. The full syntax
is ``[letter][number][expansion]``, where if the ``letter`` is not specified,
``d`` is assumed, and if ``number`` is not specified, ``4`` is assumed (the
default priority). So each of these blueprints is equivalent:
::
default priority). So each of these blueprints is equivalent::
#dig dig the interior of the room at high priority
d d d d d #
@ -458,9 +430,7 @@ Marker mode is useful for when you want to plan out your digging, but you don't
want to dig everything just yet. In ``#dig`` mode, you can add a :kbd:`m` before
any other designation letter to indicate that the tile should be designated in
marker mode. For example, to dig out the perimeter of a room, but leave the
center of the room marked for digging later:
::
center of the room marked for digging later::
#dig
d d d d d #
@ -488,17 +458,13 @@ zones that permit more than one activity. Although it is perfectly valid to
declare a single-purpose stockpile or zone and then modify it with a ``#query``
blueprint, quickfort also supports directly declaring all the types in the
``#place`` and ``#zone`` blueprints. For example, to declare a 20x10 stockpile
that accepts both corpses and refuse, you could write:
::
that accepts both corpses and refuse, you could write::
#place refuse heap
yr(20x10)
And similarly, to declare a zone that is a pasture, a fruit picking area, and a
meeting area all at once:
::
meeting area all at once::
#zone main pasture and picnic area
nmg(10x10)
@ -515,16 +481,12 @@ by mimicking the hotkeys used to set them. Note that gather flags default to
true, so specifying them in a blueprint will turn the toggles off. If you need
to set configuration from multiple zone subscreens, separate the key sections
with :kbd:`^`. Note the special syntax for setting hospital supply levels, which
have no in-game hotkeys:
::
have no in-game hotkeys::
#zone a combination hospital and shrub (but not fruit) gathering zone
gGtf^hH{hospital buckets=5 splints=20}(10x10)
The valid hospital settings (and their maximum values) are:
::
The valid hospital settings (and their maximum values) are::
thread (1500000)
cloth (1000000)
@ -536,9 +498,7 @@ The valid hospital settings (and their maximum values) are:
To toggle the ``active`` flag for zones, add an :kbd:`a` character to the
string. For example, to create a *disabled* pond zone (that you later intend to
carefully fill with 3-depth water for a dwarven bathtub):
::
carefully fill with 3-depth water for a dwarven bathtub)::
#zone disabled pond zone
apPf(1x3)
@ -563,9 +523,7 @@ very quickly and is very difficult to read in a blueprint. Moreover, constructed
track segments don't even have keys associated with them at all!
To solve this problem, Quickfort provides the following keywords for use in
build blueprints:
::
build blueprints::
-- Track segments --
trackN
@ -625,9 +583,7 @@ build blueprints:
specified with 'trackstopaaaa'.
As an example, you can create an E-W track with stops at each end that dump to
their outside directions with the following blueprint:
::
their outside directions with the following blueprint::
#build Example track
trackstopW trackEW trackEW trackEW trackstopE
@ -645,19 +601,15 @@ Carved tracks
In the game, you carve a minecart track by specifying a beginning and ending
tile and the game "adds" the designation to the tiles in between. You cannot
designate single tiles. For example to carve two track segments that cross each
other, you might use the cursor to designate a line of three vertical tiles like
this:
::
other, you might use the cursor to designate a line of three vertical tiles
like this::
` start here ` #
` ` ` #
` end here ` #
# # # #
Then to carve the cross, you'd do a horizonal segment:
::
Then to carve the cross, you'd do a horizonal segment::
` ` ` #
start here ` end here #
@ -665,9 +617,7 @@ Then to carve the cross, you'd do a horizonal segment:
# # # #
This will result in a carved track that would be equivalent to a constructed
track of the form:
::
track of the form::
#build
` trackS ` #
@ -676,9 +626,7 @@ track of the form:
# # # #
To carve this same track with a ``#dig`` blueprint, you'd use area expansion
syntax with a height or width of 1 to indicate the segments to designate:
::
syntax with a height or width of 1 to indicate the segments to designate::
#dig
` T(1x3) ` #
@ -690,9 +638,7 @@ syntax with a height or width of 1 to indicate the segments to designate:
to the South and East? You can't put both T(1xH) and T(Wx1) in the same cell!"
This is true, but you can specify both width and height, and for tracks, QF
interprets it as an upper-left corner extending to the right W tiles and down H
tiles. For example, to carve a track in a closed ring, you'd write:
::
tiles. For example, to carve a track in a closed ring, you'd write::
#dig
T(3x3) ` T(1x3) #
@ -700,9 +646,7 @@ tiles. For example, to carve a track in a closed ring, you'd write:
T(3x1) ` ` #
# # # #
Which would result in a carved track simliar to a constructed track of the form:
::
Which would result in a carved track simliar to a constructed track of the form::
#build
trackSE trackEW trackSW #
@ -724,9 +668,7 @@ about yet. You can:
- register a message to be displayed after the blueprint is successfully
applied
The full modeline syntax, when all optional elements are specified, is:
::
The full modeline syntax, when all optional elements are specified, is::
#mode label(mylabel) start(X;Y;STARTCOMMENT) hidden() message(mymessage) comment
@ -734,9 +676,7 @@ Note that all elements are optional except for the initial ``#mode`` (though, as
mentioned in the first section, if a modeline doesn't appear at all in the first
cell of a spreadsheet, the blueprint is interpreted as a ``#dig`` blueprint with
no optional markers). Here are a few examples of modelines with optional
elements before we discuss them in more detail:
::
elements before we discuss them in more detail::
#dig start(3; 3; Center tile of a 5-tile square) Regular blueprint comment
#build label(noblebedroom) start(10;15)
@ -766,9 +706,7 @@ Start positions
Start positions specify a cursor offset for a particular blueprint, simplifying
the task of blueprint alignment. This is very helpful for blueprints that are
based on a central staircase, but it helps whenever a blueprint has an obvious
"center". For example:
::
"center". For example::
#build start(2;2;center of workshop) label(masonw) a mason workshop
wm wm wm #
@ -787,9 +725,7 @@ position is ``1;1``, you can omit the numbers and just add a comment describing
where to put the cursor. This is also useful for meta blueprints that don't
actually care where the cursor is, but that refer to other blueprints that have
fully-specified ``start()`` markers. For example, a meta blueprint that refers
to the ``masonw`` blueprint above could look like this:
::
to the ``masonw`` blueprint above could look like this::
#meta start(center of workshop) a mason workshop
/masonw
@ -814,9 +750,7 @@ A blueprint with a ``message()`` marker will display a message after the
blueprint is applied with ``quickfort run``. This is useful for reminding
players to take manual steps that cannot be automated, like assigning minecarts
to a route, or listing the next step in a series of blueprints. For long or
multi-part messages, you can embed newlines:
::
multi-part messages, you can embed newlines::
"#meta label(surface1) message(This would be a good time to start digging the industry level.
Once the area is clear, continue with /surface2.) clear the embark site and set up pastures"
@ -848,9 +782,7 @@ can concatenate them into one single file. This is especially useful when you
are sharing your blueprints with others. A single file is much easier to manage
than a directory of files.
For example, you can store multiple blueprints together like this:
::
For example, you can store multiple blueprints together like this::
#dig label(bed1)
d d d d #
@ -884,9 +816,7 @@ For example, you can store multiple blueprints together like this:
# # # # #
Of course, you could still choose to keep your blueprints in single-sheet .csv
files and just give related blueprints similar names:
::
files and just give related blueprints similar names::
bedroom.1.dig.csv
bedroom.2.build.csv
@ -939,9 +869,7 @@ files or blueprints in the same spreadsheet sheet as the ``#meta`` blueprint
that references them.
A few examples might make this clearer. Say you have a .csv file with the "bed"
blueprints in the previous section:
::
blueprints in the previous section::
#dig label(bed1)
...
@ -962,9 +890,7 @@ a problem if we're just running the blueprints individually from the
going to change over time.
So let's add a meta blueprint to this file that will combine the middle three
blueprints into one:
::
blueprints into one::
"#meta plan bedroom: combines build, place, and stockpile config blueprints"
/bed2
@ -1000,9 +926,7 @@ dig_bedrooms one #dig blueprint, no label
============= ========
We can add a sheet named "dig_all" with the following contents (we're expecting
a big fort, so we're planning for a lot of bedrooms):
::
a big fort, so we're planning for a lot of bedrooms)::
#meta dig the whole fortress (remember to set force_marker_mode to true)
dig_farming/1
@ -1059,9 +983,7 @@ useful for small, single-line messages, but a ``#notes`` blueprint is more
convenient for long messages or messages that span many lines. The lines in a
``#notes`` blueprint are output as if they were contained within one large
multi-line ``message()`` marker. For example, the following two blueprints
result in the same output:
::
result in the same output::
"#meta label(help) message(This is the help text for the blueprint set
contained in this file.
@ -1426,9 +1348,7 @@ categories:
If you have a stockpile that covers multiple tiles, it might seem natural to put
one alias per spreadsheet cell. The aliases still all get applied to the
stockpile, and with only one alias per cell, you can just type the alias name
and avoid having to use the messier-looking ``{aliasname}`` syntax:
::
and avoid having to use the messier-looking ``{aliasname}`` syntax::
#place Declare a food stockpile
f(3x3)
@ -1442,9 +1362,7 @@ stockpile to have tallow exclusively permitted, then to add dye. It could happen
that the two aliases are applied in the opposite order, though, and we'd end up
with dye being permitted, then everything being forbidden and tallow being
enabled. To make sure you always get what you want, write order-sensitive
aliases on the same line:
::
aliases on the same line::
#place Declare a food stockpile
f(3x3)