From fbc2d85609808b69f27f5653d8898eabfbfce242 Mon Sep 17 00:00:00 2001
From: jj
Date: Mon, 1 Oct 2012 11:14:00 +0200
Subject: [PATCH 01/29] ruby: rename building_isitemfree to item_isfree, add
trader flag check
---
plugins/ruby/building.rb | 12 +-----------
plugins/ruby/item.rb | 12 ++++++++++++
2 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/plugins/ruby/building.rb b/plugins/ruby/building.rb
index 59f715515..08c12a841 100644
--- a/plugins/ruby/building.rb
+++ b/plugins/ruby/building.rb
@@ -352,23 +352,13 @@ module DFHack
job
end
- # check item flags to see if it is suitable for use as a building material
- def building_isitemfree(i)
- !i.flags.in_job and
- !i.flags.in_inventory and
- !i.flags.removed and
- !i.flags.in_building and
- !i.flags.owned and
- !i.flags.forbid
- end
-
# exemple usage
def buildbed(pos=cursor)
raise 'where to ?' if pos.x < 0
item = world.items.all.find { |i|
i.kind_of?(ItemBedst) and
- building_isitemfree(i)
+ item_isfree(i)
}
raise 'no free bed, build more !' if not item
diff --git a/plugins/ruby/item.rb b/plugins/ruby/item.rb
index fc840f7ad..9a254d9e8 100644
--- a/plugins/ruby/item.rb
+++ b/plugins/ruby/item.rb
@@ -47,5 +47,17 @@ module DFHack
raise "what what?"
end
end
+
+ # check item flags to see if it is suitable for use as a job input material
+ def item_isfree(i)
+ !i.flags.trader and
+ !i.flags.in_job and
+ !i.flags.in_inventory and
+ !i.flags.removed and
+ !i.flags.in_building and
+ !i.flags.owned and
+ !i.flags.forbid
+ end
+
end
end
From 150704f1af024143575b92429b432ae0c22aea08 Mon Sep 17 00:00:00 2001
From: jj
Date: Mon, 1 Oct 2012 16:05:07 +0200
Subject: [PATCH 02/29] ruby: raise when using unknown symbols in
viewscreen.feed
---
plugins/ruby/ruby-autogen-defs.rb | 3 +++
1 file changed, 3 insertions(+)
diff --git a/plugins/ruby/ruby-autogen-defs.rb b/plugins/ruby/ruby-autogen-defs.rb
index 64c08facb..4470c8022 100644
--- a/plugins/ruby/ruby-autogen-defs.rb
+++ b/plugins/ruby/ruby-autogen-defs.rb
@@ -785,6 +785,7 @@ module DFHack
def isset(key)
raise unless @_memaddr
key = @_enum.int(key) if _enum
+ raise "unknown key #{key.inspect}" if key.kind_of?(::Symbol)
DFHack.memory_stlset_isset(@_memaddr, key)
end
alias is_set? isset
@@ -792,12 +793,14 @@ module DFHack
def set(key)
raise unless @_memaddr
key = @_enum.int(key) if _enum
+ raise "unknown key #{key.inspect}" if key.kind_of?(::Symbol)
DFHack.memory_stlset_set(@_memaddr, key)
end
def delete(key)
raise unless @_memaddr
key = @_enum.int(key) if _enum
+ raise "unknown key #{key.inspect}" if key.kind_of?(::Symbol)
DFHack.memory_stlset_deletekey(@_memaddr, key)
end
From 7440e80e6c6af23284403db3af103a5f35358f0f Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Tue, 2 Oct 2012 13:49:31 +0400
Subject: [PATCH 03/29] Add an API function to retrieve interface key bindings
for display.
---
library/Core.cpp | 3 ++
library/LuaApi.cpp | 1 +
library/include/modules/Screen.h | 3 ++
library/modules/Screen.cpp | 48 ++++++++++++++++++++++++++++++++
library/xml | 2 +-
5 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/library/Core.cpp b/library/Core.cpp
index 1015194ad..bc90abc6b 100644
--- a/library/Core.cpp
+++ b/library/Core.cpp
@@ -821,6 +821,8 @@ std::string Core::getHackPath()
#endif
}
+void init_screen_module(Core *);
+
bool Core::Init()
{
if(started)
@@ -866,6 +868,7 @@ bool Core::Init()
// Init global object pointers
df::global::InitGlobals();
+ init_screen_module(this);
cerr << "Initializing Console.\n";
// init the console.
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 352e21ccf..aba6301d2 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -1146,6 +1146,7 @@ static const LuaWrapper::FunctionReg dfhack_screen_module[] = {
WRAPM(Screen, inGraphicsMode),
WRAPM(Screen, clear),
WRAPM(Screen, invalidate),
+ WRAPM(Screen, getKeyDisplay),
{ NULL, NULL }
};
diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h
index a2e64a515..ccd7f2f8d 100644
--- a/library/include/modules/Screen.h
+++ b/library/include/modules/Screen.h
@@ -128,6 +128,9 @@ namespace DFHack
DFHACK_EXPORT bool show(df::viewscreen *screen, df::viewscreen *before = NULL);
DFHACK_EXPORT void dismiss(df::viewscreen *screen, bool to_first = false);
DFHACK_EXPORT bool isDismissed(df::viewscreen *screen);
+
+ /// Retrieve the string representation of the bound key.
+ DFHACK_EXPORT std::string getKeyDisplay(df::interface_key key);
}
class DFHACK_EXPORT dfhack_viewscreen : public df::viewscreen {
diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp
index 0b9279d2d..29f718266 100644
--- a/library/modules/Screen.cpp
+++ b/library/modules/Screen.cpp
@@ -28,6 +28,7 @@ distribution.
#include
#include
#include
Interactive commands like 'liquids' cannot be used as hotkeys.
Most of the commands come from plugins. Those reside in 'hack/plugins/'.
+
+
+
On linux and OSX, users of patched binaries may have to find the relevant
+section in symbols.xml, and add a new line with the checksum of their
+executable:
+
+<md5-hash value='????????????????????????????????'/>
+
+
In order to find the correct value of the hash, look into stderr.log;
+DFHack prints an error there if it does not recognize the hash.
+
DFHack includes a small stand-alone utility for applying and removing
+binary patches from the game executable. Use it from the regular operating
+system console:
+
+
+binpatch check "Dwarf Fortress.exe" patch.dif
+Checks and prints if the patch is currently applied.
+
+binpatch apply "Dwarf Fortress.exe" patch.dif
+Applies the patch, unless it is already applied or in conflict.
+
+binpatch remove "Dwarf Fortress.exe" patch.dif
+Removes the patch, unless it is already removed.
+
+
+
+
The patches are expected to be encoded in text format used by IDA.
+
-
+
First, don't panic :) Second, dfhack keeps a few log files in DF's folder
- stderr.log and stdout.log. You can look at those and possibly find out what's
happening.
@@ -596,13 +627,13 @@ the issues tracker on github, contact me (
-
+
If your DF folder contains a file named dfhack.init, its contents will be run
every time you start DF. This allows setting up keybindings. An example file
is provided as dfhack.init-example - you can tweak it and rename to dfhack.init
if you want to use this functionality.
-
+
To set keybindings, use the built-in keybinding command. Like any other
command it can be used at any time from the console, but it is also meaningful
in the DFHack init file.
@@ -647,7 +678,7 @@ for context
foo/bar/baz, possible matches are
-
+
DFHack command syntax consists of a command name, followed by arguments separated
by whitespace. To include whitespace in an argument, quote it in double quotes.
To include a double quote character, use \" inside double quotes.
@@ -669,13 +700,13 @@ The following two command lines are exactly equivalent:
to retrieve further help without having to look at this document. Alternatively,
some accept a 'help'/'?' option on their command line.
-
+
-
+
Instantly kills DF without saving.
-
+
Forces DF to pause. This is useful when your FPS drops below 1 and you lose
control of the game.
@@ -686,12 +717,12 @@ control of the game.
-
+
Disables pausing (both manual and automatic) with the exception of pause forced
by 'reveal hell'. This is nice for digging under rivers.
-
+
Controls speedydwarf and teledwarf. Speedydwarf makes dwarves move quickly and perform tasks quickly. Teledwarf makes dwarves move instantaneously, but do jobs at the same speed.
@@ -706,29 +737,29 @@ by 'reveal hell'. This is nice for digging under rivers.
-
+
-
+
Makes the game view follow the currently highlighted unit after you exit from
current menu/cursor mode. Handy for watching dwarves running around. Deactivated
by moving the view manually.
-
+
Toggle between all possible positions where the idlers count can be placed.
-
+
Toggle between displaying/not displaying liquid depth as numbers.
-
+
Copies the parameters of the currently highlighted stockpile to the custom
stockpile settings and switches to custom stockpile placement mode, effectively
allowing you to copy/paste stockpiles easily.
-
+
Allows renaming various things.
Options:
@@ -762,9 +793,9 @@ siege engine or an activity zone.
-
+
-
+
This allows taking control over your followers and other creatures in adventure
mode. For example, you can make them pick up new arms and armor and equip them
properly.
@@ -777,7 +808,7 @@ properly.
-
+
-
+
Changes material of the geology layer under cursor to the specified inorganic
RAW material. Can have impact on all surrounding regions, not only your embark!
By default changing stone to soil and vice versa is not allowed. By default
@@ -877,7 +908,7 @@ You did save your game, right?
-
+
Changes material of the vein under cursor to the specified inorganic RAW
material. Only affects tiles within the current 16x16 block - for veins and
large clusters, you will need to use this command multiple times.
@@ -890,7 +921,7 @@ large clusters, you will need to use this command multiple times.
-
+
Allows changing item material and base quality. By default the item currently
selected in the UI will be changed (you can select items in the 'k' list
or inside containers/inventory). By default change is only allowed if materials
@@ -930,7 +961,7 @@ crafters/haulers.
-
+
Allows listing all the vermin colonies on the map and optionally turning them into honey bee colonies.
Options:
@@ -945,12 +976,12 @@ crafters/haulers.
-
+
Removes all ramps designated for removal from the map. This is useful for replicating the old channel digging designation.
It also removes any and all 'down ramps' that can remain after a cave-in (you don't have to designate anything for that to happen).
-
+
Enables management of map features.
- Discovering a magma feature (magma pool, volcano, magma sea, or curious
@@ -975,7 +1006,7 @@ that cavern to grow within your fortress.
-
+
Allows adding magma, water and obsidian to the game. It replaces the normal
dfhack command line and can't be used from a hotkey. Settings will be remembered
as long as dfhack runs. Intended for use in combination with the command
@@ -988,13 +1019,13 @@ temperatures (creating heat traps). You've been warned.
-
+
Run the liquid spawner with the current/last settings made in liquids (if no
settings in liquids were made it paints a point of 7/7 magma by default).
Intended to be used as keybinding. Requires an active in-game cursor.
-
+
Can be used for painting map tiles and is an interactive command, much like
liquids.
The tool works with two set of options and a brush. The brush determines which
@@ -1055,27 +1086,27 @@ up.
For more details, see the 'help' command while using this.
-
+
Runs tiletypes commands, separated by ;. This makes it possible to change
tiletypes modes from a hotkey.
-
+
Apply the current tiletypes options at the in-game cursor position, including
the brush. Can be used from a hotkey.
-
+
Apply the current tiletypes options at the in-game cursor position to a single
tile. Can be used from a hotkey.
-
+
Fills all the adamantine veins again. Veins that were empty will be filled in
too, but might still trigger a demon invasion (this is a known bug).
-
+
A tool for getting rid of trees and shrubs. By default, it only kills
a tree/shrub under the cursor. The plants are turned into ashes instantly.
Options:
@@ -1095,20 +1126,20 @@ a tree/shrub under the cursor. The plants are turned into ashes instantly.
-
+
Makes all saplings present on the map grow into trees (almost) instantly.
-
+
Very similar to extirpate, but additionally sets the plants on fire. The fires
can and will spread ;)
-
+
Regrows grass. Not much to it ;)
-
+
Prints the current weather map by default.
Also lets you change the current weather to 'clear sky', 'rainy' or 'snowing'.
Options:
@@ -1129,9 +1160,9 @@ can and
will spread ;)
-
+
-
+
Checks a single map tile or the whole map/world for cursed creatures (ghosts,
vampires, necromancers, werebeasts, zombies).
With an active in-game cursor only the selected tile will be observed.
@@ -1186,17 +1217,17 @@ of curses, for example.
-
+
A tool for checking how many tiles contain flowing liquids. If you suspect that
your magma sea leaks into HFS, you can use this tool to be sure without
revealing the map.
-
+
Can be used to determine tile properties like temperature.
-
+
Prints a big list of all the present minerals and plants. By default, only
the visible part of the map is scanned.
Options:
@@ -1215,7 +1246,7 @@ the visible part of the map is scanned.
-
+
If prospect is called during the embark selection screen, it displays an estimate of
layer stone availability.
@@ -1240,7 +1271,7 @@ that is actually present.
-
+
This reveals the map. By default, HFS will remain hidden so that the demons
don't spawn. You can use 'reveal hell' to reveal everything. With hell revealed,
you won't be able to unpause until you hide the map again. If you really want
@@ -1249,34 +1280,34 @@ to unpause with hell revealed, use 'reveal demons'.
you move. When you use it this way, you don't need to run 'unreveal'.
-
+
Reverts the effects of 'reveal'.
-
+
Switches between 'reveal' and 'unreveal'.
-
+
This command will hide the whole map and then reveal all the tiles that have
a path to the in-game cursor.
-
+
When you use reveal, it saves information about what was/wasn't visible before
revealing everything. Unreveal uses this information to hide things again.
This command throws away the information. For example, use in cases where
you abandoned with the fort revealed and no longer want the data.
-
+
Shows all items needed for the currently active strange mood.
-
+
-
+
Miscellaneous burrow control. Allows manipulating burrows and automated burrow
expansion while digging.
Options:
@@ -1324,17 +1355,17 @@ Digging 1-wide corridors with the miner inside the burrow is SLOW.
-
+
Designates a whole vein for digging. Requires an active in-game cursor placed
over a vein tile. With the 'x' option, it will traverse z-levels (putting stairs
between the same-material tiles).
-
+
A permanent alias for 'digv x'.
-
+
Designates layer stone for digging. Requires an active in-game cursor placed
over a layer stone tile. With the 'x' option, it will traverse z-levels
(putting stairs between the same-material tiles). With the 'undo' option it
@@ -1342,11 +1373,11 @@ will remove the dig designation instead (if you realize that digging out a 50
z-level deep layer was not such a good idea after all).
-
+
A permanent alias for 'digl x'.
-
+
A command for easy designation of filled and hollow circles.
It has several types of options.
Shape:
@@ -1472,7 +1503,7 @@ repeats with the last selected parameters.
-
+
For every tile on the map of the same vein type as the selected tile, this command designates it to have the same designation as the selected tile. If the selected tile has no designation, they will be dig designated.
If an argument is given, the designation of the selected tile is ignored, and all appropriate tiles are set to the specified designation.
Options:
@@ -1500,7 +1531,7 @@ If an argument is given, the designation of the selected tile is ignored, and al
-
+
Set traffic designations using flood-fill starting at the cursor.
Traffic Type Codes:
@@ -1539,7 +1570,7 @@ If an argument is given, the designation of the selected tile is ignored, and al
'filltraffic H' - When used in a room with doors, it will set traffic to HIGH in just that room.
-
+
Set traffic designations for every single tile of the map (useful for resetting traffic designations).
Traffic Type Codes:
@@ -1563,7 +1594,7 @@ If an argument is given, the designation of the selected tile is ignored, and al
'alltraffic N' - Set traffic to 'normal' for all tiles.
-
+
This tool allows plant gathering and tree cutting by RAW ID. Specify the types
of trees to cut down and/or shrubs to gather by their plant names, separated
by spaces.
@@ -1590,9 +1621,9 @@ all valid plant IDs will be listed.
-
+
-
+
Cleans all the splatter that get scattered all over the map, items and
creatures. In an old fortress, this can significantly reduce FPS lag. It can
also spoil your !!FUN!!, so think before you use it.
@@ -1626,12 +1657,12 @@ also spoil your !!FUN!!, so think before you use it.
-
+
Works like 'clean map snow mud', but only for the tile under the cursor. Ideal
if you want to keep that bloody entrance 'clean map' would clean up.
-
+
This utility lets you quickly move all items designated to be dumped.
Items are instantly moved to the cursor position, the dump flag is unset,
and the forbid flag is set, as if it had been dumped normally.
@@ -1658,17 +1689,17 @@ Be aware that any active dump item tasks still point at the item.
-
+
Destroy items marked for dumping under cursor. Identical to autodump
destroy-here, but intended for use as keybinding.
-
+
Destroy the selected item. The item may be selected in the 'k' list, or inside
a container. If called again before the game is resumed, cancels destroy.
-
+
Confiscates items owned by dwarfs. By default, owned food on the floor
and rotten items are confistacted and dumped.
Options:
@@ -1702,13 +1733,13 @@ worn items with 'X' damage and above.
-
+
-
+
This utility removes water from all buckets in your fortress, allowing them to be safely used for making lye.
-
+
Up to version 0.31.12, Elves only sent Diplomats to your fortress to propose
tree cutting quotas due to a bug; once that bug was fixed, Elves stopped caring
about excess tree cutting. This command adds a Diplomat position to all Elven
@@ -1717,19 +1748,19 @@ to violate them and potentially start wars) in case you haven't already modified
your raws accordingly.
-
+
This command adds the Guild Representative position to all Human civilizations,
allowing them to make trade agreements (just as they did back in 0.28.181.40d
and earlier) in case you haven't already modified your raws accordingly.
-
+
Removes invalid references to mineral inclusions and restores missing ones.
Use this if you broke your embark with tools like tiletypes, or if you
accidentally placed a construction on top of a valuable mineral floor.
-
+
Contains various tweaks for minor bugs.
One-shot subcommands:
@@ -1817,9 +1848,9 @@ to make them stand out more in the list.
-
+
-
+
This command allows you to mark the map as 'monster lair', preventing item
scatter on abandon. When invoked as 'lair reset', it does the opposite.
Unlike reveal, this command doesn't save the information about tiles - you
@@ -1839,7 +1870,7 @@ won't be able to restore state of real monster lairs using 'lair reset'.
-
+
This command lets you see and change the game mode directly.
Not all combinations are good for every situation and most of them will
produce undesirable results. There are a few good ones though.
@@ -1859,9 +1890,9 @@ You just created a returnable mountain home and gained an adventurer.
-
+
-
+
Export the current loaded map as a file. This will be eventually usable
with visualizers.
-
+
Export dwarves to RuneSmith-compatible XML.
-
+
-
+
Command for general job query and manipulation.
- Options:
@@ -1905,7 +1936,7 @@ in a workshop, or the unit/jobs screen.
-
+
Alter the material of the selected job.
Invoked as:
@@ -1923,7 +1954,7 @@ over the first available choice with the matching material.
-
+
- Duplicate the selected job in a workshop:
@@ -1934,7 +1965,7 @@ instantly duplicates the job.
-
+
Manage control of repeat jobs.
Usage:
@@ -1958,7 +1989,7 @@ Otherwise, enables or disables any of the following options:
-
+
When the plugin is enabled, it protects all repeat jobs from removal.
If they do disappear due to any cause, they are immediately re-added to their
workshop and suspended.
@@ -1969,7 +2000,7 @@ the amount has to drop before jobs are resumed; this is intended to reduce
the frequency of jobs being toggled.
-
+
Keep metal bolts within 900-1000, and wood/bone within 150-200.
workflow amount AMMO:ITEM_AMMO_BOLTS/METAL 1000 100
@@ -2008,15 +2039,15 @@ command.
-
+
-
+
Tool for turning cooking of seeds and plants on/off depending on how much you
have of them.
See 'seedwatch help' for detailed description.
-
+
Helps a bit with managing activity zones (pens, pastures and pits) and cages.
Options:
@@ -2115,7 +2146,7 @@ for war/hunt). Negatable.
-
+
One convenient way to use the zone tool is to bind the command 'zone assign' to
a hotkey, maybe also the command 'zone set'. Place the in-game cursor over
a pen/pasture or pit, use 'zone set' to mark it. Then you can select units
@@ -2124,7 +2155,7 @@ and use 'zone assign' to assign them to their new home. Allows pitting your
own dwarves, by the way.
-
+
All filters can be used together with the 'assign' command.
Restrictions: It's not possible to assign units who are inside built cages
or chained because in most cases that won't be desirable anyways.
@@ -2142,14 +2173,14 @@ are not properly added to your own stocks; slaughtering them should work).
Most filters can be negated (e.g. 'not grazer' -> race is not a grazer).
-
+
Using the 'nick' command you can set the same nickname for multiple units.
If used without 'assign', 'all' or 'count' it will rename all units in the
current default target zone. Combined with 'assign', 'all' or 'count' (and
further optional filters) it will rename units matching the filter conditions.
-
+
Using the 'tocages' command you can assign units to a set of cages, for example
a room next to your butcher shop(s). They will be spread evenly among available
cages to optimize hauling to and butchering from them. For this to work you need
@@ -2160,7 +2191,7 @@ would make no sense, but can be used together with 'nick' or 'remnick' and all
the usual filters.
-
+
- zone assign all own ALPACA minage 3 maxage 10
- Assign all own alpacas who are between 3 and 10 years old to the selected
@@ -2186,7 +2217,7 @@ on the current default zone.
-
+
Assigns unpastured female egg-layers to nestbox zones. Requires that you create
pen/pasture zones above nestboxes. If the pen is bigger than 1x1 the nestbox
must be in the top left corner. Only 1 unit will be assigned per pen, regardless
@@ -2215,7 +2246,7 @@ frames between runs.
-
+
Assigns lifestock for slaughter once it reaches a specific count. Requires that
you add the target race(s) to a watch list. Only tame units will be processed.
Named units will be completely ignored (to protect specific animals from
@@ -2323,7 +2354,7 @@ autobutcher.bat
-
+
Automatically manage dwarf labors.
When enabled, autolabor periodically checks your dwarves and enables or
disables labors. It tries to keep as many dwarves as possible busy but
@@ -2337,14 +2368,14 @@ while it is enabled.
-
+
-
+
Makes cats just multiply. It is not a good idea to run this more than once or
twice.
-
+
When enabled, every new negative dwarven thought will be multiplied by a factor (2 by default).
Usage:
@@ -2390,7 +2421,7 @@ twice.
-
+
Lua or ruby scripts placed in the hack/scripts/ directory are considered for
execution as if they were native DFHack commands. They are listed at the end
of the 'ls' command output.
@@ -2399,7 +2430,7 @@ only be listed by ls if called as 'ls -a'. This is intended as a way to hide
scripts that are obscure, developer-oriented, or should be used as keybindings.
Some notable scripts:
-
+
Scripts in this subdirectory fix various bugs and issues, some of them obscure.
fix/dead-units
@@ -2425,22 +2456,22 @@ caused by autodump bugs or other hacking mishaps.
-
+
Scripts that implement dialogs inserted into the main game window are put in this
directory.
-
+
If called in dwarf mode, makes DF immediately auto-save the game by setting a flag
normally used in seasonal auto-save.
-
+
Run setfps <number> to set the FPS cap at runtime, in case you want to watch
combat in slow motion or something :)
-
+
Wakes up sleeping units, cancels breaks and stops parties either everywhere,
or in the burrows given as arguments. In return, adds bad thoughts about
noise, tiredness and lack of protection. Also, the units with interrupted
@@ -2448,7 +2479,7 @@ breaks will go on break again a lot sooner. The script is intended for
emergencies, e.g. when a siege appears, and all your military is partying.
-
+
Instantly grow seeds inside farming plots.
With no argument, this command list the various seed types currently in
use in your farming plots.
@@ -2460,7 +2491,7 @@ growcrops plump 40
-
+
This script remove negative thoughts from your dwarves. Very useful against
tantrum spirals.
With a selected unit in 'v' mode, will clear this unit's mind, otherwise
@@ -2473,7 +2504,7 @@ you unpause.
it removed.
-
+
Kills any unit of a given race.
With no argument, lists the available races.
With the special argument 'him', targets only the selected creature.
@@ -2499,7 +2530,7 @@ slayrace elve magma
-
+
Create an infinite magma source on a tile.
This script registers a map tile as a magma source, and every 12 game ticks
that tile receives 1 new unit of flowing magma.
@@ -2514,7 +2545,7 @@ To remove all placed sources, call
magmasource stop
With no argument, this command shows an help message and list existing sources.
-
+
A script to designate an area for digging according to a plan in csv format.
This script, inspired from quickfort, can designate an area for digging.
Your plan should be stored in a .csv file like this:
@@ -2532,7 +2563,7 @@ To skip a row in your design, use a single
;.<
The script takes the plan filename, starting from the root df folder.
-
+
Similar to fastdwarf, per-creature.
To make any creature superfast, target it ingame using 'v' and:
@@ -2542,17 +2573,17 @@ superdwarf add
This plugin also shortens the 'sleeping' and 'on break' periods of targets.
-
+
Remove all 'aquifer' tag from the map blocks. Irreversible.
-
+
Focus a body part ingame, and this script will display the cause of death of
the creature.
-
+
These plugins, when activated via configuration UI or by detecting certain
structures in RAWs, modify the game engine behavior concerning the target
objects to add features not otherwise present.
@@ -2659,20 +2690,20 @@ technical challenge, and do not represent any long-term plans to produce more
similar modifications of the game.
-
+
The siege-engine plugin enables siege engines to be linked to stockpiles, and
aimed at an arbitrary rectangular area across Z levels, instead of the original
four directions. Also, catapults can be ordered to load arbitrary objects, not
just stones.
-
+
Siege engines are a very interesting feature, but sadly almost useless in the current state
because they haven't been updated since 2D and can only aim in four directions. This is an
attempt to bring them more up to date until Toady has time to work on it. Actual improvements,
e.g. like making siegers bring their own, are something only Toady can do.
-
+
The configuration front-end to the plugin is implemented by the gui/siege-engine
script. Bind it to a key and activate after selecting a siege engine in 'q' mode.
The main mode displays the current target, selected ammo item type, linked stockpiles and
@@ -2693,7 +2724,7 @@ menu.
-
+
The power-meter plugin implements a modified pressure plate that detects power being
supplied to gear boxes built in the four adjacent N/S/W/E tiles.
The configuration front-end is implemented by the gui/power-meter script. Bind it to a
@@ -2702,11 +2733,11 @@ key and activate after selecting Pressure Plate in the build menu.
configuration page, but configures parameters relevant to the modded power meter building.
-
+
The steam-engine plugin detects custom workshops with STEAM_ENGINE in
their token, and turns them into real steam engines.
-
+
The vanilla game contains only water wheels and windmills as sources of
power, but windmills give relatively little power, and water wheels require
flowing water, which must either be a real river and thus immovable and
@@ -2717,7 +2748,7 @@ it can be done just by combining existing features of the game engine
in a new way with some glue code and a bit of custom logic.
-
+
The workshop needs water as its input, which it takes via a
passable floor tile below it, like usual magma workshops do.
The magma version also needs magma.
@@ -2741,7 +2772,7 @@ short axles that can be built later than both of the engines.
-
+
In order to operate the engine, queue the Stoke Boiler job (optionally
on repeat). A furnace operator will come, possibly bringing a bar of fuel,
and perform it. As a result, a "boiling water" item will appear
@@ -2772,7 +2803,7 @@ decrease it by further 4%, and also decrease the whole steam
use rate by 10%.
-
+
The engine must be constructed using barrel, pipe and piston
from fire-safe, or in the magma version magma-safe metals.
During operation weak parts get gradually worn out, and
@@ -2781,7 +2812,7 @@ toppled during operation by a building destroyer, or a
tantruming dwarf.
-
+
It should be safe to load and view engine-using fortresses
from a DF version without DFHack installed, except that in such
case the engines won't work. However actually making modifications
@@ -2792,7 +2823,7 @@ being generated.
-
+
This plugin makes reactions with names starting with SPATTER_ADD_
produce contaminants on the items instead of improvements. The produced
contaminants are immune to being washed away by water or destroyed by
diff --git a/Readme.rst b/Readme.rst
index b5c0f335d..bed837f0b 100644
--- a/Readme.rst
+++ b/Readme.rst
@@ -88,6 +88,36 @@ Interactive commands like 'liquids' cannot be used as hotkeys.
Most of the commands come from plugins. Those reside in 'hack/plugins/'.
+Patched binaries
+================
+
+On linux and OSX, users of patched binaries may have to find the relevant
+section in symbols.xml, and add a new line with the checksum of their
+executable::
+
+
+
+In order to find the correct value of the hash, look into stderr.log;
+DFHack prints an error there if it does not recognize the hash.
+
+DFHack includes a small stand-alone utility for applying and removing
+binary patches from the game executable. Use it from the regular operating
+system console:
+
+ * ``binpatch check "Dwarf Fortress.exe" patch.dif``
+
+ Checks and prints if the patch is currently applied.
+
+ * ``binpatch apply "Dwarf Fortress.exe" patch.dif``
+
+ Applies the patch, unless it is already applied or in conflict.
+
+ * ``binpatch remove "Dwarf Fortress.exe" patch.dif``
+
+ Removes the patch, unless it is already removed.
+
+The patches are expected to be encoded in text format used by IDA.
+
=============================
Something doesn't work, help!
=============================
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 536f4d34d..a6ce58877 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -249,6 +249,7 @@ ADD_LIBRARY(dfhack-client SHARED RemoteClient.cpp ColorText.cpp MiscUtils.cpp ${
ADD_DEPENDENCIES(dfhack-client dfhack)
ADD_EXECUTABLE(dfhack-run dfhack-run.cpp)
+ADD_EXECUTABLE(binpatch binpatch.cpp)
IF(BUILD_EGGY)
SET_TARGET_PROPERTIES(dfhack PROPERTIES OUTPUT_NAME "egg" )
@@ -329,7 +330,7 @@ install(FILES xml/symbols.xml
install(FILES ../dfhack.init-example
DESTINATION ${DFHACK_BINARY_DESTINATION})
-install(TARGETS dfhack-run dfhack-client
+install(TARGETS dfhack-run dfhack-client binpatch
LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION}
RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION})
diff --git a/library/binpatch.cpp b/library/binpatch.cpp
new file mode 100644
index 000000000..10188db8c
--- /dev/null
+++ b/library/binpatch.cpp
@@ -0,0 +1,308 @@
+/*
+https://github.com/peterix/dfhack
+Copyright (c) 2011 Petr Mrázek
+
+A thread-safe logging console with a line editor for windows.
+
+Based on linenoise win32 port,
+copyright 2010, Jon Griffiths .
+All rights reserved.
+Based on linenoise, copyright 2010, Salvatore Sanfilippo .
+The original linenoise can be found at: http://github.com/antirez/linenoise
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Redis nor the names of its contributors may be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+using std::cout;
+using std::cerr;
+using std::endl;
+
+typedef unsigned char patch_byte;
+
+struct BinaryPatch {
+ struct Byte {
+ unsigned offset;
+ patch_byte old_val, new_val;
+ };
+ enum State {
+ Conflict = 0,
+ Unapplied = 1,
+ Applied = 2,
+ Partial = 3
+ };
+
+ std::vector entries;
+
+ bool loadDIF(std::string name);
+ State checkState(const patch_byte *ptr, size_t len);
+
+ void apply(patch_byte *ptr, size_t len, bool newv);
+};
+
+inline bool is_hex(char c)
+{
+ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
+}
+
+bool BinaryPatch::loadDIF(std::string name)
+{
+ entries.clear();
+
+ std::ifstream infile(name);
+ if(infile.bad())
+ {
+ cerr << "Cannot open file: " << name << endl;
+ return false;
+ }
+
+ std::string s;
+ while(std::getline(infile, s))
+ {
+ // Parse lines that begin with "[0-9a-f]+:"
+ size_t idx = s.find(':');
+ if (idx == std::string::npos || idx == 0 || idx > 8)
+ continue;
+
+ bool ok = true;
+ for (size_t i = 0; i < idx; i++)
+ if (!is_hex(s[i]))
+ ok = false;
+ if (!ok)
+ continue;
+
+ unsigned off, oval, nval;
+ int nchar = 0;
+ int cnt = sscanf(s.c_str(), "%x: %x %x%n", &off, &oval, &nval, &nchar);
+
+ if (cnt < 3)
+ {
+ cerr << "Could not parse: " << s << endl;
+ return false;
+ }
+
+ for (size_t i = nchar; i < s.size(); i++)
+ {
+ if (!isspace(s[i]))
+ {
+ cerr << "Garbage at end of line: " << s << endl;
+ return false;
+ }
+ }
+
+ if (oval >= 256 || nval >= 256)
+ {
+ cerr << "Invalid byte values: " << s << endl;
+ return false;
+ }
+
+ Byte bv = { off, patch_byte(oval), patch_byte(nval) };
+ entries.push_back(bv);
+ }
+
+ if (entries.empty())
+ {
+ cerr << "No lines recognized." << endl;
+ return false;
+ }
+
+ return true;
+}
+
+BinaryPatch::State BinaryPatch::checkState(const patch_byte *ptr, size_t len)
+{
+ int state = 0;
+
+ for (size_t i = 0; i < entries.size(); i++)
+ {
+ Byte &bv = entries[i];
+
+ if (bv.offset >= len)
+ {
+ cerr << "Offset out of range: 0x" << std::hex << bv.offset << std::dec << endl;
+ return Conflict;
+ }
+
+ patch_byte cv = ptr[bv.offset];
+ if (bv.old_val == cv)
+ state |= Unapplied;
+ else if (bv.new_val == cv)
+ state |= Applied;
+ else
+ {
+ cerr << std::hex << bv.offset << ": " << bv.old_val << " " << bv.new_val
+ << ", but currently " << cv << std::dec << endl;
+ return Conflict;
+ }
+ }
+
+ return State(state);
+}
+
+void BinaryPatch::apply(patch_byte *ptr, size_t len, bool newv)
+{
+ for (size_t i = 0; i < entries.size(); i++)
+ {
+ Byte &bv = entries[i];
+ assert (bv.offset < len);
+
+ ptr[bv.offset] = (newv ? bv.new_val : bv.old_val);
+ }
+}
+
+bool load_file(std::vector *pvec, std::string fname)
+{
+ FILE *f = fopen(fname.c_str(), "rb");
+ if (!f)
+ {
+ cerr << "Cannot open file: " << fname << endl;
+ return false;
+ }
+
+ fseek(f, 0, SEEK_END);
+ pvec->resize(ftell(f));
+ fseek(f, 0, SEEK_SET);
+ size_t cnt = fread(pvec->data(), 1, pvec->size(), f);
+ fclose(f);
+
+ return cnt == pvec->size();
+}
+
+bool save_file(const std::vector &pvec, std::string fname)
+{
+ FILE *f = fopen(fname.c_str(), "wb");
+ if (!f)
+ {
+ cerr << "Cannot open file: " << fname << endl;
+ return false;
+ }
+
+ size_t cnt = fwrite(pvec.data(), 1, pvec.size(), f);
+ fclose(f);
+
+ return cnt == pvec.size();
+}
+
+int main (int argc, char *argv[])
+{
+ if (argc <= 3)
+ {
+ cerr << "Usage: binpatch check|apply|remove " << endl;
+ return 2;
+ }
+
+ std::string cmd = argv[1];
+
+ if (cmd != "check" && cmd != "apply" && cmd != "remove")
+ {
+ cerr << "Invalid command: " << cmd << endl;
+ return 2;
+ }
+
+ std::string exe_file = argv[2];
+ std::vector bindata;
+ if (!load_file(&bindata, exe_file))
+ return 2;
+
+ BinaryPatch patch;
+ if (!patch.loadDIF(argv[3]))
+ return 2;
+
+ BinaryPatch::State state = patch.checkState(bindata.data(), bindata.size());
+ if (state == BinaryPatch::Conflict)
+ return 1;
+
+ if (cmd == "check")
+ {
+ switch (state)
+ {
+ case BinaryPatch::Unapplied:
+ cout << "Currently not applied." << endl;
+ break;
+ case BinaryPatch::Applied:
+ cout << "Currently applied." << endl;
+ break;
+ case BinaryPatch::Partial:
+ cout << "Currently partially applied." << endl;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+ }
+ else if (cmd == "apply")
+ {
+ if (state == BinaryPatch::Applied)
+ {
+ cout << "Already applied." << endl;
+ return 0;
+ }
+
+ patch.apply(bindata.data(), bindata.size(), true);
+ }
+ else if (cmd == "remove")
+ {
+ if (state == BinaryPatch::Unapplied)
+ {
+ cout << "Already removed." << endl;
+ return 0;
+ }
+
+ patch.apply(bindata.data(), bindata.size(), false);
+ }
+
+ std::string bak_file = exe_file + ".bak";
+ remove(bak_file.c_str());
+
+ if (rename(exe_file.c_str(), bak_file.c_str()) != 0)
+ {
+ cerr << "Could not create backup." << endl;
+ return 1;
+ }
+
+ if (!save_file(bindata, exe_file))
+ return 1;
+
+ cout << "Patched " << patch.entries.size() << " bytes." << endl;
+ return 0;
+}
From 28f0fed0aa1d339d60228969b0e6b174da27e42c Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Mon, 8 Oct 2012 16:22:35 +0400
Subject: [PATCH 21/29] Redo the way binpatch backs up, so as not to lose the
executable perms.
---
library/binpatch.cpp | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/library/binpatch.cpp b/library/binpatch.cpp
index 10188db8c..88ef2f004 100644
--- a/library/binpatch.cpp
+++ b/library/binpatch.cpp
@@ -291,10 +291,7 @@ int main (int argc, char *argv[])
patch.apply(bindata.data(), bindata.size(), false);
}
- std::string bak_file = exe_file + ".bak";
- remove(bak_file.c_str());
-
- if (rename(exe_file.c_str(), bak_file.c_str()) != 0)
+ if (!save_file(bindata, exe_file + ".bak"))
{
cerr << "Could not create backup." << endl;
return 1;
From 7224c8746aa44249d1b1c12088e6d4aeefa4ac22 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Mon, 8 Oct 2012 16:47:52 +0400
Subject: [PATCH 22/29] Print the new md5 hash after modification in binpatch.
---
depends/md5/md5wrapper.cpp | 9 +++------
depends/md5/md5wrapper.h | 6 +++++-
library/CMakeLists.txt | 2 ++
library/binpatch.cpp | 11 ++++++++++-
4 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/depends/md5/md5wrapper.cpp b/depends/md5/md5wrapper.cpp
index e12b65780..d9f857c5d 100644
--- a/depends/md5/md5wrapper.cpp
+++ b/depends/md5/md5wrapper.cpp
@@ -36,16 +36,14 @@
* internal hash function, calling
* the basic methods from md5.h
*/
-std::string md5wrapper::hashit(std::string text)
+std::string md5wrapper::hashit(unsigned char *data, size_t length)
{
MD5Context ctx;
//init md5
MD5Init(&ctx);
//update with our string
- MD5Update(&ctx,
- (unsigned char*)text.c_str(),
- text.length());
+ MD5Update(&ctx, data, length);
//create the hash
unsigned char buff[16] = "";
@@ -95,10 +93,9 @@ md5wrapper::~md5wrapper()
*/
std::string md5wrapper::getHashFromString(std::string text)
{
- return this->hashit(text);
+ return this->hashit((unsigned char*)text.data(), text.length());
}
-
/*
* creates a MD5 hash from
* a file specified in "filename" and
diff --git a/depends/md5/md5wrapper.h b/depends/md5/md5wrapper.h
index 1a41192a1..0b534b61d 100644
--- a/depends/md5/md5wrapper.h
+++ b/depends/md5/md5wrapper.h
@@ -31,7 +31,7 @@ class md5wrapper
* internal hash function, calling
* the basic methods from md5.h
*/
- std::string hashit(std::string text);
+ std::string hashit(unsigned char *data, size_t length);
/*
* converts the numeric giets to
@@ -52,6 +52,10 @@ class md5wrapper
*/
std::string getHashFromString(std::string text);
+ std::string getHashFromBytes(const unsigned char *data, size_t size) {
+ return hashit(const_cast(data),size);
+ }
+
/*
* creates a MD5 hash from
* a file specified in "filename" and
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index a6ce58877..6f33d5c8a 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -249,7 +249,9 @@ ADD_LIBRARY(dfhack-client SHARED RemoteClient.cpp ColorText.cpp MiscUtils.cpp ${
ADD_DEPENDENCIES(dfhack-client dfhack)
ADD_EXECUTABLE(dfhack-run dfhack-run.cpp)
+
ADD_EXECUTABLE(binpatch binpatch.cpp)
+TARGET_LINK_LIBRARIES(binpatch dfhack-md5)
IF(BUILD_EGGY)
SET_TARGET_PROPERTIES(dfhack PROPERTIES OUTPUT_NAME "egg" )
diff --git a/library/binpatch.cpp b/library/binpatch.cpp
index 88ef2f004..815ac5b92 100644
--- a/library/binpatch.cpp
+++ b/library/binpatch.cpp
@@ -53,6 +53,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include
+#include
+
using std::cout;
using std::cerr;
using std::endl;
@@ -222,6 +224,12 @@ bool save_file(const std::vector &pvec, std::string fname)
return cnt == pvec.size();
}
+std::string compute_hash(const std::vector &pvec)
+{
+ md5wrapper md5;
+ return md5.getHashFromBytes(pvec.data(), pvec.size());
+}
+
int main (int argc, char *argv[])
{
if (argc <= 3)
@@ -300,6 +308,7 @@ int main (int argc, char *argv[])
if (!save_file(bindata, exe_file))
return 1;
- cout << "Patched " << patch.entries.size() << " bytes." << endl;
+ cout << "Patched " << patch.entries.size()
+ << " bytes, new hash: " << compute_hash(bindata) << endl;
return 0;
}
From 5cf42fd6f8b61efe302738d20bb1585b2704a5f3 Mon Sep 17 00:00:00 2001
From: jj
Date: Wed, 10 Oct 2012 14:57:45 +0200
Subject: [PATCH 23/29] ruby: add Matinfo#===
---
plugins/ruby/material.rb | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/plugins/ruby/material.rb b/plugins/ruby/material.rb
index 4a92118d6..ca0a64779 100644
--- a/plugins/ruby/material.rb
+++ b/plugins/ruby/material.rb
@@ -189,6 +189,10 @@ module DFHack
end
def to_s ; token ; end
+
+ def ===(other)
+ other.mat_index == mat_index and other.mat_type == mat_type
+ end
end
class << self
From 7c969f774f5ea86aaf9251c02e187014c73986c6 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Wed, 10 Oct 2012 18:22:01 +0400
Subject: [PATCH 24/29] Split the liquipowder fix-dimensions hook into separate
liquid and powder.
The item_liquipowder vtable is completely optimized out by MSVC.
---
plugins/tweak.cpp | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/plugins/tweak.cpp b/plugins/tweak.cpp
index d54c4a5ec..8488ba3e8 100644
--- a/plugins/tweak.cpp
+++ b/plugins/tweak.cpp
@@ -34,7 +34,8 @@
#include "df/ui_build_selector.h"
#include "df/building_trapst.h"
#include "df/item_actual.h"
-#include "df/item_liquipowder.h"
+#include "df/item_liquid_miscst.h"
+#include "df/item_powder_miscst.h"
#include "df/item_barst.h"
#include "df/item_threadst.h"
#include "df/item_clothst.h"
@@ -402,8 +403,8 @@ static void correct_dimension(df::item_actual *self, int32_t &delta, int32_t dim
if (copy) copy->categorize(true);
}
-struct dimension_lqp_hook : df::item_liquipowder {
- typedef df::item_liquipowder interpose_base;
+struct dimension_liquid_hook : df::item_liquid_miscst {
+ typedef df::item_liquid_miscst interpose_base;
DEFINE_VMETHOD_INTERPOSE(bool, subtractDimension, (int32_t delta))
{
@@ -412,7 +413,19 @@ struct dimension_lqp_hook : df::item_liquipowder {
}
};
-IMPLEMENT_VMETHOD_INTERPOSE(dimension_lqp_hook, subtractDimension);
+IMPLEMENT_VMETHOD_INTERPOSE(dimension_liquid_hook, subtractDimension);
+
+struct dimension_powder_hook : df::item_powder_miscst {
+ typedef df::item_powder_miscst interpose_base;
+
+ DEFINE_VMETHOD_INTERPOSE(bool, subtractDimension, (int32_t delta))
+ {
+ correct_dimension(this, delta, dimension);
+ return INTERPOSE_NEXT(subtractDimension)(delta);
+ }
+};
+
+IMPLEMENT_VMETHOD_INTERPOSE(dimension_powder_hook, subtractDimension);
struct dimension_bar_hook : df::item_barst {
typedef df::item_barst interpose_base;
@@ -795,7 +808,8 @@ static command_result tweak(color_ostream &out, vector ¶meters)
}
else if (cmd == "fix-dimensions")
{
- enable_hook(out, INTERPOSE_HOOK(dimension_lqp_hook, subtractDimension), parameters);
+ enable_hook(out, INTERPOSE_HOOK(dimension_liquid_hook, subtractDimension), parameters);
+ enable_hook(out, INTERPOSE_HOOK(dimension_powder_hook, subtractDimension), parameters);
enable_hook(out, INTERPOSE_HOOK(dimension_bar_hook, subtractDimension), parameters);
enable_hook(out, INTERPOSE_HOOK(dimension_thread_hook, subtractDimension), parameters);
enable_hook(out, INTERPOSE_HOOK(dimension_cloth_hook, subtractDimension), parameters);
From 41de37a5c116d14175de54e3dfa9367454967868 Mon Sep 17 00:00:00 2001
From: Alexander Gavrilov
Date: Wed, 10 Oct 2012 18:29:59 +0400
Subject: [PATCH 25/29] Add a special workshop for add spatter reactions into
example raws.
---
plugins/raw/building_spatter.txt | 22 ++++++++++++++++++++++
plugins/raw/reaction_spatter.txt | 30 +++++++++++++++---------------
2 files changed, 37 insertions(+), 15 deletions(-)
create mode 100644 plugins/raw/building_spatter.txt
diff --git a/plugins/raw/building_spatter.txt b/plugins/raw/building_spatter.txt
new file mode 100644
index 000000000..7bde8297b
--- /dev/null
+++ b/plugins/raw/building_spatter.txt
@@ -0,0 +1,22 @@
+building_spatter
+
+[OBJECT:BUILDING]
+
+[BUILDING_WORKSHOP:GREASING_STATION]
+ [NAME:Greasing Station]
+ [NAME_COLOR:2:0:1]
+ [DIM:1:1]
+ [WORK_LOCATION:1:1]
+ [BUILD_LABOR:DYER]
+ [BUILD_KEY:CUSTOM_ALT_G]
+ [BLOCK:1:0]
+ [TILE:0:1:150]
+ [COLOR:0:1:0:0:1]
+ [TILE:1:1:150]
+ [COLOR:1:1:MAT]
+ [TILE:2:1:8]
+ [COLOR:2:1:MAT]
+ [TILE:3:1:8]
+ [COLOR:3:1:7:5:0]
+ [BUILD_ITEM:1:BUCKET:NONE:NONE:NONE][CAN_USE_ARTIFACT]
+ [BUILD_ITEM:1:NONE:NONE:NONE:NONE][BUILDMAT]
diff --git a/plugins/raw/reaction_spatter.txt b/plugins/raw/reaction_spatter.txt
index 81f9a2b62..95b9f1d33 100644
--- a/plugins/raw/reaction_spatter.txt
+++ b/plugins/raw/reaction_spatter.txt
@@ -7,7 +7,7 @@ Reaction name must start with 'SPATTER_ADD_':
[REACTION:SPATTER_ADD_OBJECT_LIQUID]
[NAME:coat object with liquid]
[ADVENTURE_MODE_ENABLED]
- [SKILL:WAX_WORKING]
+ [SKILL:DYER]
[REAGENT:extract:150:LIQUID_MISC:NONE:NONE:NONE]
[MIN_DIMENSION:150]
[DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
@@ -28,10 +28,10 @@ Reaction name must start with 'SPATTER_ADD_':
[REACTION:SPATTER_ADD_WEAPON_EXTRACT]
[NAME:coat weapon with extract]
- [BUILDING:CRAFTSMAN:NONE]
- [SKILL:WAX_WORKING]
- [REAGENT:extract:150:LIQUID_MISC:NONE:NONE:NONE]
- [MIN_DIMENSION:150]
+ [BUILDING:GREASING_STATION:CUSTOM_W]
+ [SKILL:DYER]
+ [REAGENT:extract:100:LIQUID_MISC:NONE:NONE:NONE]
+ [MIN_DIMENSION:100]
[REACTION_CLASS:CREATURE_EXTRACT]
[DOES_NOT_DETERMINE_PRODUCT_AMOUNT]
[REAGENT:extract container:1:NONE:NONE:NONE:NONE]
@@ -51,8 +51,8 @@ Reaction name must start with 'SPATTER_ADD_':
[REACTION:SPATTER_ADD_AMMO_EXTRACT]
[NAME:coat ammo with extract]
- [BUILDING:CRAFTSMAN:NONE]
- [SKILL:WAX_WORKING]
+ [BUILDING:GREASING_STATION:CUSTOM_A]
+ [SKILL:DYER]
[REAGENT:extract:50:LIQUID_MISC:NONE:NONE:NONE]
[MIN_DIMENSION:50]
[REACTION_CLASS:CREATURE_EXTRACT]
@@ -75,8 +75,8 @@ Reaction name must start with 'SPATTER_ADD_':
[REACTION:SPATTER_ADD_WEAPON_GCS]
[NAME:coat weapon with GCS venom]
- [BUILDING:CRAFTSMAN:NONE]
- [SKILL:WAX_WORKING]
+ [BUILDING:GREASING_STATION:NONE]
+ [SKILL:DYER]
[REAGENT:extract:150:LIQUID_MISC:NONE:CAVE_SPIDER_GIANT:POISON]
[MIN_DIMENSION:150]
[REACTION_CLASS:CREATURE_EXTRACT]
@@ -95,8 +95,8 @@ Reaction name must start with 'SPATTER_ADD_':
[REACTION:SPATTER_ADD_AMMO_GCS]
[NAME:coat ammo with GCS venom]
- [BUILDING:CRAFTSMAN:NONE]
- [SKILL:WAX_WORKING]
+ [BUILDING:GREASING_STATION:NONE]
+ [SKILL:DYER]
[REAGENT:extract:50:LIQUID_MISC:NONE:CAVE_SPIDER_GIANT:POISON]
[MIN_DIMENSION:50]
[REACTION_CLASS:CREATURE_EXTRACT]
@@ -115,8 +115,8 @@ Reaction name must start with 'SPATTER_ADD_':
[REACTION:SPATTER_ADD_WEAPON_GDS]
[NAME:coat weapon with GDS venom]
- [BUILDING:CRAFTSMAN:NONE]
- [SKILL:WAX_WORKING]
+ [BUILDING:GREASING_STATION:NONE]
+ [SKILL:DYER]
[REAGENT:extract:150:LIQUID_MISC:NONE:SCORPION_DESERT_GIANT:POISON]
[MIN_DIMENSION:150]
[REACTION_CLASS:CREATURE_EXTRACT]
@@ -135,8 +135,8 @@ Reaction name must start with 'SPATTER_ADD_':
[REACTION:SPATTER_ADD_AMMO_GDS]
[NAME:coat ammo with GDS venom]
- [BUILDING:CRAFTSMAN:NONE]
- [SKILL:WAX_WORKING]
+ [BUILDING:GREASING_STATION:NONE]
+ [SKILL:DYER]
[REAGENT:extract:50:LIQUID_MISC:NONE:SCORPION_DESERT_GIANT:POISON]
[MIN_DIMENSION:50]
[REACTION_CLASS:CREATURE_EXTRACT]
From 46a24a83fb660d46aed0a8304fb68d00e675c785 Mon Sep 17 00:00:00 2001
From: jj
Date: Wed, 10 Oct 2012 18:01:57 +0200
Subject: [PATCH 26/29] ruby: fix item_find(:selected) in item details screen
---
plugins/ruby/item.rb | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/plugins/ruby/item.rb b/plugins/ruby/item.rb
index 9a254d9e8..469ec7449 100644
--- a/plugins/ruby/item.rb
+++ b/plugins/ruby/item.rb
@@ -6,8 +6,12 @@ module DFHack
if what == :selected
case curview._rtti_classname
when :viewscreen_itemst
- ref = curview.entry_ref[curview.cursor_pos]
- ref.item_tg if ref.kind_of?(GeneralRefItem)
+ if ref = curview.entry_ref[curview.cursor_pos]
+ ref.item_tg if ref.kind_of?(GeneralRefItem)
+ else
+ # not a container
+ curview.item
+ end
when :viewscreen_storesst # z/stocks
if curview.in_group_mode == 0 and curview.in_right_list == 1
curview.items[curview.item_cursor]
From e3e01107b91c9b22524c1c0d1e93d3932b53f491 Mon Sep 17 00:00:00 2001
From: jj
Date: Wed, 10 Oct 2012 18:56:23 +0200
Subject: [PATCH 27/29] fix deathcause for new df-structures
---
scripts/deathcause.rb | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/scripts/deathcause.rb b/scripts/deathcause.rb
index 178ebbc87..0ed54d81a 100644
--- a/scripts/deathcause.rb
+++ b/scripts/deathcause.rb
@@ -1,15 +1,13 @@
# show death cause of a creature
-def display_event(e)
- p e if $DEBUG
-
- str = "#{e.victim_tg.name} died in year #{e.year}"
- str << " of #{e.death_cause}" if false
- str << " killed by the #{e.slayer_race_tg.name[0]} #{e.slayer_tg.name}" if e.slayer != -1
+def display_death_event(e)
+ str = "The #{e.victim_hf_tg.race_tg.name[0]} #{e.victim_hf_tg.name} died in year #{e.year}"
+ str << " (cause: #{e.death_cause.to_s.downcase}),"
+ str << " killed by the #{e.slayer_race_tg.name[0]} #{e.slayer_hf_tg.name}" if e.slayer_hf != -1
str << " using a #{df.world.raws.itemdefs.weapons[e.weapon.item_subtype].name}" if e.weapon.item_type == :WEAPON
str << ", shot by a #{df.world.raws.itemdefs.weapons[e.weapon.bow_item_subtype].name}" if e.weapon.bow_item_type == :WEAPON
- puts str + '.'
+ puts str.chomp(',') + '.'
end
item = df.item_find(:selected)
@@ -21,14 +19,15 @@ end
if !item or !item.kind_of?(DFHack::ItemBodyComponent)
puts "Please select a corpse in the loo'k' menu"
else
- hfig = item.hist_figure_id
- if hfig == -1
- puts "Not a historical figure, cannot find info"
+ hf = item.hist_figure_id
+ if hf == -1
+ # TODO try to retrieve info from the unit (u = item.unit_tg)
+ puts "Not a historical figure, cannot death find info"
else
events = df.world.history.events
(0...events.length).reverse_each { |i|
- if events[i].kind_of?(DFHack::HistoryEventHistFigureDiedst) and events[i].victim == hfig
- display_event(events[i])
+ if events[i].kind_of?(DFHack::HistoryEventHistFigureDiedst) and events[i].victim_hf == hf
+ display_death_event(events[i])
break
end
}
From b3b93f818d097f88cb2517df4de5fb64b1ac3d69 Mon Sep 17 00:00:00 2001
From: jj
Date: Wed, 10 Oct 2012 19:25:30 +0200
Subject: [PATCH 28/29] slayrace: show number of creatures per race
---
scripts/slayrace.rb | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/scripts/slayrace.rb b/scripts/slayrace.rb
index b1fc24e35..749d0189b 100644
--- a/scripts/slayrace.rb
+++ b/scripts/slayrace.rb
@@ -33,12 +33,14 @@ slayit = lambda { |u|
end
}
-all_races = df.world.units.active.map { |u|
- u.race_tg.creature_id if checkunit[u]
-}.compact.uniq.sort
+all_races = Hash.new(0)
+
+df.world.units.active.map { |u|
+ all_races[u.race_tg.creature_id] += 1 if checkunit[u]
+}
if !race
- puts all_races
+ all_races.sort_by { |race, cnt| [cnt, race] }.each{ |race, cnt| puts " #{race} #{cnt}" }
elsif race == 'him'
if him = df.unit_find
slayit[him]
@@ -46,7 +48,7 @@ elsif race == 'him'
puts "Choose target"
end
else
- raw_race = df.match_rawname(race, all_races)
+ raw_race = df.match_rawname(race, all_races.keys)
raise 'invalid race' if not raw_race
race_nr = df.world.raws.creatures.all.index { |cr| cr.creature_id == raw_race }
From b5f5d1f85b56fe0d7bd804fe881ce8a50310de10 Mon Sep 17 00:00:00 2001
From: jj
Date: Wed, 10 Oct 2012 19:42:36 +0200
Subject: [PATCH 29/29] removebadthoughts: add --dry-run option
---
NEWS | 1 +
Readme.rst | 16 +++++++------
scripts/removebadthoughts.rb | 44 ++++++++++++++++++++++++------------
3 files changed, 40 insertions(+), 21 deletions(-)
diff --git a/NEWS b/NEWS
index 65339ad64..192b93aed 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
DFHack future
Nothing yet!
+ - removebadthoughts: add --dry-run option
DFHack v0.34.11-r2
diff --git a/Readme.rst b/Readme.rst
index b5c0f335d..7ce15015a 100644
--- a/Readme.rst
+++ b/Readme.rst
@@ -1632,16 +1632,18 @@ removebadthoughts
This script remove negative thoughts from your dwarves. Very useful against
tantrum spirals.
-With a selected unit in 'v' mode, will clear this unit's mind, otherwise
-clear all your fort's units minds.
+The script can target a single creature, when used with the ``him`` argument,
+or the whole fort population, with ``all``.
+
+To show every bad thought present without actually removing them, run the
+script with the ``-n`` or ``--dry-run`` argument. This can give a quick
+hint on what bothers your dwarves the most.
Individual dwarf happiness may not increase right after this command is run,
but in the short term your dwarves will get much more joyful.
-The thoughts are set to be very old, and the game will remove them soon when
-you unpause.
-With the optional ``-v`` parameter, the script will dump the negative thoughts
-it removed.
+Internals: the thoughts are set to be very old, so that the game remove them
+quickly after you unpause.
slayrace
@@ -1650,7 +1652,7 @@ Kills any unit of a given race.
With no argument, lists the available races.
-With the special argument 'him', targets only the selected creature.
+With the special argument ``him``, targets only the selected creature.
Any non-dead non-caged unit of the specified race gets its ``blood_count``
set to 0, which means immediate death at the next game tick. For creatures
diff --git a/scripts/removebadthoughts.rb b/scripts/removebadthoughts.rb
index 99b742643..ff98f8f65 100644
--- a/scripts/removebadthoughts.rb
+++ b/scripts/removebadthoughts.rb
@@ -1,27 +1,43 @@
# remove bad thoughts for the selected unit or the whole fort
-# with removebadthoughts -v, dump the bad thoughts types we removed
-verbose = $script_args.delete('-v')
+dry_run = $script_args.delete('--dry-run') || $script_args.delete('-n')
-if u = df.unit_find(:selected)
- targets = [u]
-else
- targets = df.unit_citizens
-end
+$script_args << 'all' if dry_run and $script_args.empty?
seenbad = Hash.new(0)
-targets.each { |u|
+clear_mind = lambda { |u|
u.status.recent_events.each { |e|
next if DFHack::UnitThoughtType::Value[e.type].to_s[0, 1] != '-'
seenbad[e.type] += 1
- e.age = 0x1000_0000
+ e.age = 0x1000_0000 unless dry_run
}
}
-if verbose
- seenbad.sort_by { |k, v| v }.each { |k, v| puts " #{v} #{k}" }
-end
+summary = lambda {
+ seenbad.sort_by { |thought, cnt| cnt }.each { |thought, cnt|
+ puts " #{thought} #{cnt}"
+ }
+ count = seenbad.values.inject(0) { |sum, cnt| sum+cnt }
+ puts "Removed #{count} bad thought#{'s' if count != 1}." if count > 0 and not dry_run
+}
-count = seenbad.values.inject(0) { |s, v| s+v }
-puts "removed #{count} bad thought#{'s' if count != 1}"
+case $script_args[0]
+when 'him'
+ if u = df.unit_find
+ clear_mind[u]
+ summary[]
+ else
+ puts 'Please select a dwarf ingame'
+ end
+
+when 'all'
+ df.unit_citizens.each { |uu|
+ clear_mind[uu]
+ }
+ summary[]
+
+else
+ puts "Usage: removebadthoughts [--dry-run] "
+
+end