-
+
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 4488490dd..a214a6ecb 100644
--- a/Readme.rst
+++ b/Readme.rst
@@ -144,6 +144,16 @@ system console:
The patches are expected to be encoded in text format used by IDA.
+
+Live patching
+-------------
+
+As an alternative, you can use the ``binpatch`` dfhack command to apply/remove
+patches live in memory during a DF session.
+
+In this case, updating symbols.xml is not necessary.
+
+
=============================
Something doesn't work, help!
=============================
@@ -1077,6 +1087,9 @@ Subcommands that persist until disabled or DF quit:
:patrol-duty: Makes Train orders not count as patrol duty to stop unhappy thoughts.
Does NOT fix the problem when soldiers go off-duty (i.e. civilian).
:readable-build-plate: Fixes rendering of creature weight limits in pressure plate build menu.
+
+ .. image:: images/tweak-plate.png
+
:stable-temp: Fixes performance bug 6012 by squashing jitter in temperature updates.
In very item-heavy forts with big stockpiles this can improve FPS by 50-100%
:fast-heat: Further improves temperature update performance by ensuring that 1 degree
@@ -1095,9 +1108,16 @@ Subcommands that persist until disabled or DF quit:
:military-stable-assign: Preserve list order and cursor position when assigning to squad,
i.e. stop the rightmost list of the Positions page of the military
screen from constantly resetting to the top.
-:military-color-assigned: Color squad candidates already assigned to other squads in brown/green
+:military-color-assigned: Color squad candidates already assigned to other squads in yellow/green
to make them stand out more in the list.
+ .. image:: images/tweak-mil-color.png
+
+:military-training: Speeds up melee squad training by removing an almost certainly
+ unintended inverse dependency of training speed on unit count
+ (i.e. the more units you have, the slower it becomes), and making
+ the units spar more.
+
fix-armory
----------
@@ -1946,6 +1966,41 @@ embark
======
Allows to embark anywhere. Currently windows only.
+lever
+=====
+Allow manipulation of in-game levers from the dfhack console.
+
+Can list levers, including state and links, with::
+
+ lever list
+
+To queue a job so that a dwarf will pull the lever 42, use ``lever pull 42``.
+This is the same as 'q'uerying the building and queue a 'P'ull request.
+
+To magically toggle the lever immediately, use::
+
+ lever pull 42 --now
+
+stripcaged
+==========
+For dumping items inside cages. Will mark selected items for dumping, then
+a dwarf may come and actually dump it. See also ``autodump``.
+
+With the ``items`` argument, only dumps items laying in the cage, excluding
+stuff worn by caged creatures. ``weapons`` will dump worn weapons, ``armor``
+will dump everything worn by caged creatures (including armor and clothing),
+and ``all`` will dump everything, on a creature or not.
+
+``stripcaged list`` will display on the dfhack console the list of all cages
+and their item content.
+
+Without further arguments, all commands work on all cages and animal traps on
+the map. With the ``here`` argument, considers only the in-game selected cage
+(or the cage under the game cursor). To target only specific cages, you can
+alternatively pass cage IDs as arguments::
+
+ stripcaged weapons 25321 34228
+
=======================
In-game interface tools
=======================
@@ -1958,6 +2013,9 @@ are mostly implemented by lua scripts.
In order to avoid user confusion, as a matter of policy all these tools
display the word "DFHack" on the screen somewhere while active.
+ When that is not appropriate because they merely add keybinding hints to
+ existing DF screens, they deliberately use red instead of green for the key.
+
As an exception, the tweak plugin described above does not follow this
guideline because it arguably just fixes small usability bugs in the game UI.
@@ -1974,8 +2032,12 @@ This tool implements a Dwarf Therapist-like interface within the game UI. The
far left column displays the unit's Happiness (color-coded based on its
value), and the right half of the screen displays each dwarf's labor settings
and skill levels (0-9 for Dabbling thru Professional, A-E for Great thru Grand
-Master, and U-Z for Legendary thru Legendary+5). Cells with red backgrounds
-denote skills not controlled by labors.
+Master, and U-Z for Legendary thru Legendary+5).
+
+Cells with teal backgrounds denote skills not controlled by labors, e.g.
+military and social skills.
+
+.. image:: images/manipulator2.png
Use the arrow keys or number pad to move the cursor around, holding Shift to
move 10 tiles at a time.
@@ -2036,10 +2098,46 @@ Value numbers displayed by the screen. Because of this, pressing the 't'
key while search is active clears the search instead of executing the trade.
+AutoMaterial
+============
+
+The automaterial plugin makes building constructions (walls, floors, fortifications,
+etc) a little bit easier by saving you from having to trawl through long lists of
+materials each time you place one.
+
+Firstly, it moves the last used material for a given construction type to the top of
+the list, if there are any left. So if you build a wall with chalk blocks, the next
+time you place a wall the chalk blocks will be at the top of the list, regardless of
+distance (it only does this in "grouped" mode, as individual item lists could be huge).
+This should mean you can place most constructions without having to search for your
+preferred material type.
+
+.. image:: images/automaterial-mat.png
+
+Pressing 'a' while highlighting any material will enable that material for "auto select"
+for this construction type. You can enable multiple materials as autoselect. Now the next
+time you place this type of construction, the plugin will automatically choose materials
+for you from the kinds you enabled. If there is enough to satisfy the whole placement,
+you won't be prompted with the material screen - the construction will be placed and you
+will be back in the construction menu as if you did it manually.
+
+When choosing the construction placement, you will see a couple of options:
+
+.. image:: images/automaterial-pos.png
+
+Use 'a' here to temporarily disable the material autoselection, e.g. if you need
+to go to the material selection screen so you can toggle some materials on or off.
+
+The other option (auto type selection, off by default) can be toggled on with 't'. If you
+toggle this option on, instead of returning you to the main construction menu after selecting
+materials, it returns you back to this screen. If you use this along with several autoselect
+enabled materials, you should be able to place complex constructions more conveniently.
+
+
gui/liquids
===========
-To use, bind to a key and activate in the 'k' mode.
+To use, bind to a key (the example config uses Alt-L) and activate in the 'k' mode.
.. image:: images/liquids.png
@@ -2050,7 +2148,7 @@ to select the target area and apply changes.
gui/mechanisms
==============
-To use, bind to a key and activate in the 'q' mode.
+To use, bind to a key (the example config uses Ctrl-M) and activate in the 'q' mode.
.. image:: images/mechanisms.png
@@ -2088,12 +2186,15 @@ via a simple dialog in the game ui.
The ``building`` or ``unit`` options are automatically assumed when in relevant ui state.
+The example config binds building/unit rename to Ctrl-Shift-N, and
+unit profession change to Ctrl-Shift-T.
+
gui/room-list
=============
-To use, bind to a key and activate in the 'q' mode, either immediately or after opening
-the assign owner page.
+To use, bind to a key (the example config uses Alt-R) and activate in the 'q' mode,
+either immediately or after opening the assign owner page.
.. image:: images/room-list.png
@@ -2104,7 +2205,8 @@ list, and allows unassigning them.
gui/choose-weapons
==================
-Bind to a key, and activate in the Equip->View/Customize page of the military screen.
+Bind to a key (the example config uses Ctrl-W), and activate in the Equip->View/Customize
+page of the military screen.
Depending on the cursor location, it rewrites all 'individual choice weapon' entries
in the selected squad or position to use a specific weapon type matching the assigned
@@ -2118,7 +2220,8 @@ and may lead to inappropriate weapons being selected.
gui/guide-path
==============
-Bind to a key, and activate in the Hauling menu with the cursor over a Guide order.
+Bind to a key (the example config uses Alt-P), and activate in the Hauling menu with
+the cursor over a Guide order.
.. image:: images/guide-path.png
@@ -2129,7 +2232,8 @@ computes it when the order is executed for the first time.
gui/workshop-job
================
-Bind to a key, and activate with a job selected in a workshop in the 'q' mode.
+Bind to a key (the example config uses Alt-A), and activate with a job selected in
+a workshop in the 'q' mode.
.. image:: images/workshop-job.png
@@ -2176,7 +2280,8 @@ you have to unset the material first.
gui/workflow
============
-Bind to a key, and activate with a job selected in a workshop in the 'q' mode.
+Bind to a key (the example config uses Alt-W), and activate with a job selected
+in a workshop in the 'q' mode.
.. image:: images/workflow.png
@@ -2204,20 +2309,19 @@ can be used for troubleshooting jobs that don't match the right constraints.
.. image:: images/workflow-new1.png
-After selecting one of the presented outputs, the interface proceeds to the
+If you select one of the outputs with Enter, the matching constraint is simply
+added to the list. If you use Shift-Enter, the interface proceeds to the
next dialog, which allows you to edit the suggested constraint parameters to
suit your need, and set the item count range.
.. image:: images/workflow-new2.png
-If you don't need advanced settings, you can just press 'y' to confirm creation.
-
-
gui/assign-rack
===============
-Bind to a key, and activate when viewing a weapon rack in the 'q' mode.
+Bind to a key (the example config uses P), and activate when viewing a weapon
+rack in the 'q' mode.
.. image:: images/assign-rack.png
@@ -2278,7 +2382,8 @@ Configuration UI
----------------
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.
+script. Bind it to a key (the example config uses Alt-A) and activate after selecting
+a siege engine in 'q' mode.
.. image:: images/siege-engine.png
@@ -2310,7 +2415,8 @@ The power-meter plugin implements a modified pressure plate that detects power b
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
-key and activate after selecting Pressure Plate in the build menu.
+key (the example config uses Ctrl-Shift-M) and activate after selecting Pressure Plate
+in the build menu.
.. image:: images/power-meter.png
diff --git a/images/assign-rack.png b/images/assign-rack.png
index c0acb5802..4ebcbf590 100644
Binary files a/images/assign-rack.png and b/images/assign-rack.png differ
diff --git a/images/automaterial-mat.png b/images/automaterial-mat.png
new file mode 100644
index 000000000..5517bbc6d
Binary files /dev/null and b/images/automaterial-mat.png differ
diff --git a/images/automaterial-pos.png b/images/automaterial-pos.png
new file mode 100644
index 000000000..959573643
Binary files /dev/null and b/images/automaterial-pos.png differ
diff --git a/images/guide-path.png b/images/guide-path.png
index 0a3e967a3..afb6511fa 100644
Binary files a/images/guide-path.png and b/images/guide-path.png differ
diff --git a/images/liquids.png b/images/liquids.png
index f2058695d..da70a058b 100644
Binary files a/images/liquids.png and b/images/liquids.png differ
diff --git a/images/manipulator.png b/images/manipulator.png
index de61e30fc..1f452549f 100644
Binary files a/images/manipulator.png and b/images/manipulator.png differ
diff --git a/images/manipulator2.png b/images/manipulator2.png
new file mode 100644
index 000000000..38c6c3cfb
Binary files /dev/null and b/images/manipulator2.png differ
diff --git a/images/mechanisms.png b/images/mechanisms.png
index c46868449..062d126cd 100644
Binary files a/images/mechanisms.png and b/images/mechanisms.png differ
diff --git a/images/power-meter.png b/images/power-meter.png
index 4d84f3761..b1a4b6229 100644
Binary files a/images/power-meter.png and b/images/power-meter.png differ
diff --git a/images/rename-bld.png b/images/rename-bld.png
index e1fa8ef31..0028a87a5 100644
Binary files a/images/rename-bld.png and b/images/rename-bld.png differ
diff --git a/images/rename-prof.png b/images/rename-prof.png
index 789f6fe6f..5f2cfc453 100644
Binary files a/images/rename-prof.png and b/images/rename-prof.png differ
diff --git a/images/room-list.png b/images/room-list.png
index 34c93591a..5a60398f8 100644
Binary files a/images/room-list.png and b/images/room-list.png differ
diff --git a/images/search.png b/images/search.png
index f299622fc..384c3c533 100644
Binary files a/images/search.png and b/images/search.png differ
diff --git a/images/siege-engine.png b/images/siege-engine.png
index 509b26046..032e265dc 100644
Binary files a/images/siege-engine.png and b/images/siege-engine.png differ
diff --git a/images/tweak-mil-color.png b/images/tweak-mil-color.png
new file mode 100644
index 000000000..b4a012cab
Binary files /dev/null and b/images/tweak-mil-color.png differ
diff --git a/images/tweak-plate.png b/images/tweak-plate.png
new file mode 100644
index 000000000..b7ba2c88d
Binary files /dev/null and b/images/tweak-plate.png differ
diff --git a/images/workflow-new1.png b/images/workflow-new1.png
index ccc0e5fcc..50d0e1f42 100644
Binary files a/images/workflow-new1.png and b/images/workflow-new1.png differ
diff --git a/images/workflow-new2.png b/images/workflow-new2.png
index 944563316..74a4922be 100644
Binary files a/images/workflow-new2.png and b/images/workflow-new2.png differ
diff --git a/images/workflow.png b/images/workflow.png
index 70b41f29b..a0a0d4216 100644
Binary files a/images/workflow.png and b/images/workflow.png differ
diff --git a/images/workshop-job-item.png b/images/workshop-job-item.png
index 952f19ae0..cef691918 100644
Binary files a/images/workshop-job-item.png and b/images/workshop-job-item.png differ
diff --git a/images/workshop-job-material.png b/images/workshop-job-material.png
index 2ad69eaf4..d75797766 100644
Binary files a/images/workshop-job-material.png and b/images/workshop-job-material.png differ
diff --git a/images/workshop-job.png b/images/workshop-job.png
index 25ecff0b2..938b84374 100644
Binary files a/images/workshop-job.png and b/images/workshop-job.png differ
diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h
index 2c245ae4c..bfc393734 100644
--- a/library/include/modules/Screen.h
+++ b/library/include/modules/Screen.h
@@ -28,7 +28,9 @@ distribution.
#include "BitArray.h"
#include "ColorText.h"
#include "Types.h"
+
#include
+#include
#include "DataDefs.h"
#include "df/graphic.h"
@@ -51,6 +53,8 @@ namespace DFHack
{
class Core;
+ typedef std::set interface_key_set;
+
/**
* The Screen module
* \ingroup grp_modules
diff --git a/library/include/modules/World.h b/library/include/modules/World.h
index a945c4e72..f1fea52a1 100644
--- a/library/include/modules/World.h
+++ b/library/include/modules/World.h
@@ -81,6 +81,55 @@ namespace DFHack
int &ival(int i) { return int_values[i]; }
int ival(int i) const { return int_values[i]; }
+ // Pack binary data into string field.
+ // Since DF serialization chokes on NUL bytes,
+ // use bit magic to ensure none of the bytes is 0.
+ // Choose the lowest bit for padding so that
+ // sign-extend can be used normally.
+
+ size_t data_size() const { return str_value->size(); }
+
+ bool check_data(size_t off, size_t sz = 1) {
+ return (str_value->size() >= off+sz);
+ }
+ void ensure_data(size_t off, size_t sz = 0) {
+ if (str_value->size() < off+sz) str_value->resize(off+sz, '\x01');
+ }
+ uint8_t *pdata(size_t off) { return (uint8_t*)&(*str_value)[off]; }
+
+ static const size_t int7_size = 1;
+ uint8_t get_uint7(size_t off) {
+ uint8_t *p = pdata(off);
+ return p[0]>>1;
+ }
+ int8_t get_int7(size_t off) {
+ uint8_t *p = pdata(off);
+ return int8_t(p[0])>>1;
+ }
+ void set_uint7(size_t off, uint8_t val) {
+ uint8_t *p = pdata(off);
+ p[0] = uint8_t((val<<1) | 1);
+ }
+ void set_int7(size_t off, int8_t val) { set_uint7(off, val); }
+
+ static const size_t int28_size = 4;
+ uint32_t get_uint28(size_t off) {
+ uint8_t *p = pdata(off);
+ return (p[0]>>1) | ((p[1]&~1U)<<6) | ((p[2]&~1U)<<13) | ((p[3]&~1U)<<20);
+ }
+ int32_t get_int28(size_t off) {
+ uint8_t *p = pdata(off);
+ return (p[0]>>1) | ((p[1]&~1U)<<6) | ((p[2]&~1U)<<13) | ((int8_t(p[3])&~1)<<20);
+ }
+ void set_uint28(size_t off, uint32_t val) {
+ uint8_t *p = pdata(off);
+ p[0] = uint8_t((val<<1) | 1);
+ p[1] = uint8_t((val>>6) | 1);
+ p[2] = uint8_t((val>>13) | 1);
+ p[3] = uint8_t((val>>20) | 1);
+ }
+ void set_int28(size_t off, int32_t val) { set_uint28(off, val); }
+
PersistentDataItem() : id(0), str_value(0), int_values(0) {}
PersistentDataItem(int id, const std::string &key, std::string *sv, int *iv)
: id(id), key_value(key), str_value(sv), int_values(iv) {}
diff --git a/library/lua/gui.lua b/library/lua/gui.lua
index cfb058f9d..99bf9263c 100644
--- a/library/lua/gui.lua
+++ b/library/lua/gui.lua
@@ -10,13 +10,19 @@ local to_pen = dfhack.pen.parse
CLEAR_PEN = to_pen{ch=32,fg=0,bg=0}
+local FAKE_INPUT_KEYS = {
+ _MOUSE_L = true,
+ _MOUSE_R = true,
+ _STRING = true,
+}
+
function simulateInput(screen,...)
local keys = {}
local function push_key(arg)
local kv = arg
if type(arg) == 'string' then
kv = df.interface_key[arg]
- if kv == nil then
+ if kv == nil and not FAKE_INPUT_KEYS[arg] then
error('Invalid keycode: '..arg)
end
end
@@ -106,10 +112,14 @@ function inset_frame(rect, inset, gap)
return mkdims_xy(rect.x1+l+gap, rect.y1+t+gap, rect.x2-r-gap, rect.y2-b-gap)
end
-function compute_frame_body(wavail, havail, spec, inset, gap)
+function compute_frame_body(wavail, havail, spec, inset, gap, inner_frame)
gap = gap or 0
local l,t,r,b = parse_inset(inset)
- local rect = compute_frame_rect(wavail, havail, spec, gap*2+l+r, gap*2+t+b)
+ local xgap,ygap = 0,0
+ if inner_frame then
+ xgap,ygap = gap*2+l+r, gap*2+t+b
+ end
+ local rect = compute_frame_rect(wavail, havail, spec, xgap, ygap)
local body = mkdims_xy(rect.x1+l+gap, rect.y1+t+gap, rect.x2-r-gap, rect.y2-b-gap)
return rect, body
end
@@ -617,7 +627,7 @@ end
function FramedScreen:computeFrame(parent_rect)
local sw, sh = parent_rect.width, parent_rect.height
local fw, fh = self:getWantedFrameSize(parent_rect)
- return compute_frame_body(sw, sh, { w = fw, h = fh }, self.frame_inset, 1)
+ return compute_frame_body(sw, sh, { w = fw, h = fh }, self.frame_inset, 1, true)
end
function FramedScreen:onRenderFrame(dc, rect)
diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua
index 0a79b4c3e..fb9b8fd63 100644
--- a/library/lua/gui/dialogs.lua
+++ b/library/lua/gui/dialogs.lua
@@ -152,7 +152,9 @@ ListBox.ATTRS{
with_filter = false,
cursor_pen = DEFAULT_NIL,
select_pen = DEFAULT_NIL,
- on_select = DEFAULT_NIL
+ on_select = DEFAULT_NIL,
+ on_select2 = DEFAULT_NIL,
+ select2_hint = DEFAULT_NIL,
}
function ListBox:preinit(info)
@@ -168,6 +170,16 @@ function ListBox:init(info)
list_widget = widgets.FilteredList
end
+ local on_submit2
+ if self.select2_hint or self.on_select2 then
+ on_submit2 = function(sel, obj)
+ self:dismiss()
+ if self.on_select2 then self.on_select2(sel, obj) end
+ local cb = obj.on_select2
+ if cb then cb(obj, sel) end
+ end
+ end
+
self:addviews{
list_widget{
view_id = 'list',
@@ -182,11 +194,19 @@ function ListBox:init(info)
local cb = obj.on_select or obj[2]
if cb then cb(obj, sel) end
end,
+ on_submit2 = on_submit2,
frame = { l = 0, r = 0 },
}
}
end
+function ListBox:onRenderFrame(dc,rect)
+ ListBox.super.onRenderFrame(self,dc,rect)
+ if self.select2_hint then
+ dc:seek(rect.x1+2,rect.y2):key('SEC_SELECT'):string(': '..self.select2_hint,COLOR_DARKGREY)
+ end
+end
+
function ListBox:getWantedFrameSize()
local mw, mh = InputBox.super.getWantedFrameSize(self)
local list = self.subviews.list
diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua
index 67090e114..ebbffbbbd 100644
--- a/library/lua/gui/widgets.lua
+++ b/library/lua/gui/widgets.lua
@@ -60,6 +60,7 @@ Panel = defclass(Panel, Widget)
Panel.ATTRS {
on_render = DEFAULT_NIL,
+ on_layout = DEFAULT_NIL,
}
function Panel:init(args)
@@ -70,6 +71,10 @@ function Panel:onRenderBody(dc)
if self.on_render then self.on_render(dc) end
end
+function Panel:postComputeFrame(body)
+ if self.on_layout then self.on_layout(body) end
+end
+
-----------
-- Pages --
-----------
@@ -242,7 +247,7 @@ function render_text(obj,dc,x0,y0,pen,dpen,disabled)
end
if token.text or token.key then
- local text = getval(token.text) or ''
+ local text = ''..(getval(token.text) or '')
local keypen
if dc then
@@ -256,7 +261,23 @@ function render_text(obj,dc,x0,y0,pen,dpen,disabled)
end
end
- x = x + #text
+ local width = getval(token.width)
+ local padstr
+ if width then
+ x = x + width
+ if #text > width then
+ text = string.sub(text,1,width)
+ else
+ if token.pad_char then
+ padstr = string.rep(token.pad_char,width-#text)
+ end
+ if dc and token.rjustify then
+ if padstr then dc:string(padstr) else dc:advance(width-#text) end
+ end
+ end
+ else
+ x = x + #text
+ end
if token.key then
local keystr = gui.getKeyDisplay(token.key)
@@ -281,6 +302,10 @@ function render_text(obj,dc,x0,y0,pen,dpen,disabled)
dc:string(text)
end
end
+
+ if width and dc and not token.rjustify then
+ if padstr then dc:string(padstr) else dc:advance(width-#text) end
+ end
end
token.x2 = x
@@ -384,6 +409,7 @@ List.ATTRS{
inactive_pen = DEFAULT_NIL,
on_select = DEFAULT_NIL,
on_submit = DEFAULT_NIL,
+ on_submit2 = DEFAULT_NIL,
row_height = 1,
scroll_keys = STANDARDSCROLL,
icon_width = DEFAULT_NIL,
@@ -542,10 +568,19 @@ function List:submit()
end
end
+function List:submit2()
+ if self.on_submit2 and #self.choices > 0 then
+ self.on_submit2(self:getSelected())
+ end
+end
+
function List:onInput(keys)
if self.on_submit and keys.SELECT then
self:submit()
return true
+ elseif self.on_submit2 and keys.SEC_SELECT then
+ self:submit2()
+ return true
else
for k,v in pairs(self.scroll_keys) do
if keys[k] then
@@ -581,10 +616,14 @@ end
FilteredList = defclass(FilteredList, Widget)
+FilteredList.ATTRS {
+ edit_below = false,
+}
+
function FilteredList:init(info)
self.edit = EditField{
text_pen = info.edit_pen or info.cursor_pen,
- frame = { l = info.icon_width, t = 0 },
+ frame = { l = info.icon_width, t = 0, h = 1 },
on_change = self:callback('onFilterChange'),
on_char = self:callback('onFilterChar'),
}
@@ -598,6 +637,10 @@ function FilteredList:init(info)
scroll_keys = info.scroll_keys,
icon_width = info.icon_width,
}
+ if self.edit_below then
+ self.edit.frame = { l = info.icon_width, b = 0, h = 1 }
+ self.list.frame = { t = 0, b = 2 }
+ end
if info.on_select then
self.list.on_select = function()
return info.on_select(self:getSelected())
@@ -608,11 +651,16 @@ function FilteredList:init(info)
return info.on_submit(self:getSelected())
end
end
+ if info.on_submit2 then
+ self.list.on_submit2 = function()
+ return info.on_submit2(self:getSelected())
+ end
+ end
self.not_found = Label{
visible = false,
text = info.not_found_label or 'No matches',
text_pen = COLOR_LIGHTRED,
- frame = { l = info.icon_width, t = 2 },
+ frame = { l = info.icon_width, t = self.list.frame.t },
}
self:addviews{ self.edit, self.list, self.not_found }
self:setChoices(info.choices, info.selected)
@@ -634,6 +682,10 @@ function FilteredList:submit()
return self.list:submit()
end
+function FilteredList:submit2()
+ return self.list:submit2()
+end
+
function FilteredList:canSubmit()
return not self.not_found.visible
end
diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp
index f2d1f2d5d..cd20bc25e 100644
--- a/library/modules/Screen.cpp
+++ b/library/modules/Screen.cpp
@@ -110,10 +110,10 @@ bool Screen::paintTile(const Pen &pen, int x, int y)
{
if (!gps || !pen.valid()) return false;
- int dimx = gps->dimx, dimy = gps->dimy;
- if (x < 0 || x >= dimx || y < 0 || y >= dimy) return false;
+ auto dim = getWindowSize();
+ if (x < 0 || x >= dim.x || y < 0 || y >= dim.y) return false;
- doSetTile(pen, x*dimy + y);
+ doSetTile(pen, x*dim.y + y);
return true;
}
@@ -121,11 +121,11 @@ Pen Screen::readTile(int x, int y)
{
if (!gps) return Pen(0,0,0,-1);
- int dimx = gps->dimx, dimy = gps->dimy;
- if (x < 0 || x >= dimx || y < 0 || y >= dimy)
+ auto dim = getWindowSize();
+ if (x < 0 || x >= dim.x || y < 0 || y >= dim.y)
return Pen(0,0,0,-1);
- int index = x*dimy + y;
+ int index = x*dim.y + y;
auto screen = gps->screen + index*4;
if (screen[3] & 0x80)
return Pen(0,0,0,-1);
@@ -154,14 +154,15 @@ Pen Screen::readTile(int x, int y)
bool Screen::paintString(const Pen &pen, int x, int y, const std::string &text)
{
- if (!gps || y < 0 || y >= gps->dimy) return false;
+ auto dim = getWindowSize();
+ if (!gps || y < 0 || y >= dim.y) return false;
Pen tmp(pen);
bool ok = false;
for (size_t i = -std::min(0,x); i < text.size(); i++)
{
- if (x + i >= size_t(gps->dimx))
+ if (x + i >= size_t(dim.x))
break;
tmp.ch = text[i];
@@ -175,17 +176,18 @@ bool Screen::paintString(const Pen &pen, int x, int y, const std::string &text)
bool Screen::fillRect(const Pen &pen, int x1, int y1, int x2, int y2)
{
+ auto dim = getWindowSize();
if (!gps || !pen.valid()) return false;
if (x1 < 0) x1 = 0;
if (y1 < 0) y1 = 0;
- if (x2 >= gps->dimx) x2 = gps->dimx-1;
- if (y2 >= gps->dimy) y2 = gps->dimy-1;
+ if (x2 >= dim.x) x2 = dim.x-1;
+ if (y2 >= dim.y) y2 = dim.y-1;
if (x1 > x2 || y1 > y2) return false;
for (int x = x1; x <= x2; x++)
{
- int index = x*gps->dimy;
+ int index = x*dim.y;
for (int y = y1; y <= y2; y++)
doSetTile(pen, index+y);
@@ -198,32 +200,33 @@ bool Screen::drawBorder(const std::string &title)
{
if (!gps) return false;
- int dimx = gps->dimx, dimy = gps->dimy;
+ auto dim = getWindowSize();
Pen border('\xDB', 8);
Pen text(0, 0, 7);
Pen signature(0, 0, 8);
- for (int x = 0; x < dimx; x++)
+ for (int x = 0; x < dim.x; x++)
{
- doSetTile(border, x * dimy + 0);
- doSetTile(border, x * dimy + dimy - 1);
+ doSetTile(border, x * dim.y + 0);
+ doSetTile(border, x * dim.y + dim.y - 1);
}
- for (int y = 0; y < dimy; y++)
+ for (int y = 0; y < dim.y; y++)
{
- doSetTile(border, 0 * dimy + y);
- doSetTile(border, (dimx - 1) * dimy + y);
+ doSetTile(border, 0 * dim.y + y);
+ doSetTile(border, (dim.x - 1) * dim.y + y);
}
- paintString(signature, dimx-8, dimy-1, "DFHack");
+ paintString(signature, dim.x-8, dim.y-1, "DFHack");
- return paintString(text, (dimx - title.length()) / 2, 0, title);
+ return paintString(text, (dim.x - title.length()) / 2, 0, title);
}
bool Screen::clear()
{
if (!gps) return false;
- return fillRect(Pen(' ',0,0,false), 0, 0, gps->dimx-1, gps->dimy-1);
+ auto dim = getWindowSize();
+ return fillRect(Pen(' ',0,0,false), 0, 0, dim.x-1, dim.y-1);
}
bool Screen::invalidate()
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index 29b1d3d79..1c89d9ab7 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -118,6 +118,7 @@ if (BUILD_SUPPORTED)
DFHACK_PLUGIN(forceequip forceequip.cpp)
DFHACK_PLUGIN(manipulator manipulator.cpp)
DFHACK_PLUGIN(search search.cpp)
+ DFHACK_PLUGIN(automaterial automaterial.cpp)
# this one exports functions to lua
DFHACK_PLUGIN(burrows burrows.cpp LINK_LIBRARIES lua)
DFHACK_PLUGIN(sort sort.cpp LINK_LIBRARIES lua)
diff --git a/plugins/autodump.cpp b/plugins/autodump.cpp
index 5eb25964e..5b4804647 100644
--- a/plugins/autodump.cpp
+++ b/plugins/autodump.cpp
@@ -161,7 +161,7 @@ static command_result autodump_main(color_ostream &out, vector & parame
|| itm->flags.bits.in_building
|| itm->flags.bits.in_chest
// || itm->flags.bits.in_inventory
- || itm->flags.bits.artifact1
+ || itm->flags.bits.artifact
)
continue;
@@ -271,7 +271,7 @@ command_result df_autodump_destroy_item(color_ostream &out, vector & pa
if (item->flags.bits.construction ||
item->flags.bits.in_building ||
- item->flags.bits.artifact1)
+ item->flags.bits.artifact)
{
out.printerr("Choosing not to destroy buildings, constructions and artifacts.\n");
return CR_FAILURE;
diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp
index 83718bd09..e5047b434 100644
--- a/plugins/autolabor.cpp
+++ b/plugins/autolabor.cpp
@@ -1556,7 +1556,7 @@ static int stockcheck(color_ostream &out, vector & parameters)
#define F(x) bad_flags.bits.x = true;
F(dump); F(forbid); F(garbage_collect);
F(hostile); F(on_fire); F(rotten); F(trader);
- F(in_building); F(construction); F(artifact1);
+ F(in_building); F(construction); F(artifact);
F(spider_web); F(owned); F(in_job);
#undef F
diff --git a/plugins/automaterial.cpp b/plugins/automaterial.cpp
new file mode 100644
index 000000000..9f383b935
--- /dev/null
+++ b/plugins/automaterial.cpp
@@ -0,0 +1,378 @@
+// Auto Material Select
+
+#include