diff --git a/Readme.html b/Readme.html index 737963372..b7ca94964 100644 --- a/Readme.html +++ b/Readme.html @@ -501,38 +501,40 @@ access DF memory and allow for easier development of new tools.
Enables a fix for storage of squad equipment in barracks.
-Specifically, it prevents your haulers from moving that equipment +
Specifically, it prevents your haulers from moving squad equipment to stockpiles, and instead queues jobs to store it on weapon racks, armor stands, and in containers.
In order to actually be used, weapon racks have to be patched and manually assigned to a squad. See documentation for gui/assign-rack below.
-Also, the default capacity of armor stands is way too low, so check out +
Also, the default capacity of armor stands is way too low, so you +may want to also apply the armorstand-capacity patch. Check out http://www.bay12games.com/dwarves/mantisbt/view.php?id=1445 -for a patch addressing that too.
+for more information about the bugs.Note that the buildings in the armory are used as follows:
This is the DFusion lua plugin system by warmist/darius, running as a DFHack plugin.
-See the bay12 thread for details: http://www.bay12forums.com/smf/index.php?topic=69682.15
-Confirmed working DFusion plugins:
-simple_embark: | allows changing the number of dwarves available on embark. | +
---|---|
Friendship: | a binary plugin that allows multi race forts (to use make a script that imports plugins.dfusion.friendship and use Friendship:install{table} table should contain list of race names.) | +
Embark: | a binary plugin that allows multi race embark (to use make a script that imports plugins.dfusion.embark and use Embark:install{table} table should contain list of race names or list of pairs (race-name, caste_id)). |
See the bay12 thread for details: http://www.bay12forums.com/smf/index.php?topic=93317.0
Note
Focus a body part ingame, and this script will display the cause of death of the creature.
+Allows to embark anywhere. Currently windows only.
+These tools work by displaying dialogs or overlays in the game window, and are mostly implemented by lua scripts.
Implemented by the manipulator plugin. To activate, open the unit screen and press 'l'.
This tool implements a Dwarf Therapist-like interface within the game UI. The @@ -2775,7 +2797,7 @@ cursor onto that cell instead of toggling it. directly to the main dwarf mode screen.
The search plugin adds search to the Stocks, Trading and Unit List screens.
Searching works the same way as the search option in "Move to Depot" does. You will see the Search option displayed on screen with a hotkey (usually 's'). @@ -2794,13 +2816,13 @@ 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.
To use, bind to a key and activate in the 'k' mode.
While active, use the suggested keys to switch the usual liquids parameters, and Enter to select the target area and apply changes.
To use, bind to a key and activate in the 'q' mode.
Lists mechanisms connected to the building, and their links. Navigating the list centers the view on the relevant linked buildings.
@@ -2809,7 +2831,7 @@ focus on the current one. Shift-Enter has an effect equivalent to pressing Enter re-entering the mechanisms ui.Backed by the rename plugin, this script allows entering the desired name via a simple dialog in the game ui.
The building or unit options are automatically assumed when in relevant ui state.
To use, bind to a key and activate in the 'q' mode, either immediately or after opening the assign owner page.
The script lists other rooms owned by the same owner, or by the unit selected in the assign list, and allows unassigning them.
Bind to a key, 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 @@ -2842,13 +2864,13 @@ only that entry, and does it even if it is not 'individual choice'.
and may lead to inappropriate weapons being selected.Bind to a key, and activate in the Hauling menu with the cursor over a Guide order.
The script displays the cached path that will be used by the order; the game computes it when the order is executed for the first time.
Bind to a key, and activate with a job selected in a workshop in the 'q' mode.
The script shows a list of the input reagents of the selected job, and allows changing them like the job item-type and job item-material commands.
@@ -2876,7 +2898,7 @@ and then try to change the input item type, now it won't let you select plan you have to unset the material first.Bind to a key, and activate with a job selected in a workshop in the 'q' mode.
This script provides a simple interface to constraints managed by the workflow plugin. When active, it displays a list of all constraints applicable to the @@ -2898,7 +2920,7 @@ as described in workflow documentation above. can be used for troubleshooting jobs that don't match the right constraints.
Bind to a key, and activate when viewing a weapon rack in the 'q' mode.
This script is part of a group of related fixes to make the armory storage work again. The existing issues are:
@@ -2907,7 +2929,9 @@ work again. The existing issues are: beds/boxes/armor stands and individual squad members, but nothing in the game does this. This issue is what this script addresses.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.
@@ -2929,20 +2953,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 @@ -2963,7 +2987,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 @@ -2972,11 +2996,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 @@ -2987,7 +3011,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.
@@ -3011,7 +3035,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 @@ -3042,7 +3066,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 @@ -3051,7 +3075,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 @@ -3062,7 +3086,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 66f4017c7..ed2fe3ee8 100644 --- a/Readme.rst +++ b/Readme.rst @@ -1103,7 +1103,7 @@ fix-armory Enables a fix for storage of squad equipment in barracks. -Specifically, it prevents your haulers from moving that equipment +Specifically, it prevents your haulers from moving squad equipment to stockpiles, and instead queues jobs to store it on weapon racks, armor stands, and in containers. @@ -1113,9 +1113,10 @@ armor stands, and in containers. manually assigned to a squad. See documentation for ``gui/assign-rack`` below. - Also, the default capacity of armor stands is way too low, so check out + Also, the default capacity of armor stands is way too low, so you + may want to also apply the ``armorstand-capacity`` patch. Check out http://www.bay12games.com/dwarves/mantisbt/view.php?id=1445 - for a patch addressing that too. + for more information about the bugs. Note that the buildings in the armory are used as follows: @@ -2165,7 +2166,9 @@ work again. The existing issues are: the game does this. This issue is what this script addresses. * Even if assigned by the script, **the game will unassign the racks again without a binary patch**. - Check the comments for this bug to get it: + This patch is called ``weaponrack-unassign``, and can be applied via + the binpatch program, or the matching script. See this for more info + about the bug: http://www.bay12games.com/dwarves/mantisbt/view.php?id=1445 * Haulers still take equpment stored in the armory away to the stockpiles, diff --git a/library/lua/binpatch.lua b/library/lua/binpatch.lua new file mode 100644 index 000000000..e957148f7 --- /dev/null +++ b/library/lua/binpatch.lua @@ -0,0 +1,121 @@ +-- Simple binary patch with IDA dif file support. + +local function load_patch(name) + local filename = name + if not string.match(filename, '[./\\]') then + filename = dfhack.getHackPath()..'/patches/'..dfhack.getDFVersion()..'/'..name..'.dif' + end + + local file, err = io.open(filename, 'r') + if not file then + if string.match(err, ': No such file or directory') then + return nil, 'patch not found' + end + end + + local old_bytes = {} + local new_bytes = {} + + for line in file:lines() do + if string.match(line, '^%x+:') then + local offset, oldv, newv = string.match(line, '^(%x+):%s*(%x+)%s+(%x+)%s*$') + if not offset then + file:close() + return nil, 'could not parse: '..line + end + + offset, oldv, newv = tonumber(offset,16), tonumber(oldv,16), tonumber(newv,16) + if oldv > 255 or newv > 255 then + file:close() + return nil, 'invalid byte values: '..line + end + + old_bytes[offset] = oldv + new_bytes[offset] = newv + end + end + + return { name = name, old_bytes = old_bytes, new_bytes = new_bytes } +end + +local function rebase_table(input) + local output = {} + local base = dfhack.internal.getImageBase() + for k,v in pairs(input) do + local offset = dfhack.internal.adjustOffset(k) + if not offset then + return nil, string.format('invalid offset: %x', k) + end + output[base + offset] = v + end + return output +end + +local function rebase_patch(patch) + local nold, err = rebase_table(patch.old_bytes) + if not nold then return nil, err end + local nnew, err = rebase_table(patch.new_bytes) + if not nnew then return nil, err end + return { name = patch.name, old_bytes = nold, new_bytes = nnew } +end + +BinaryPatch = defclass(BinaryPatch) + +BinaryPatch.ATTRS { + name = DEFAULT_NIL, + old_bytes = DEFAULT_NIL, + new_bytes = DEFAULT_NIL, +} + +function load_dif_file(name) + local patch, err = load_patch(name) + if not patch then return nil, err end + + local rpatch, err = rebase_patch(patch) + if not rpatch then return nil, err end + + return BinaryPatch(rpatch) +end + +function BinaryPatch:status() + local old_ok, err, addr = dfhack.internal.patchBytes({}, self.old_bytes) + if old_ok then + return 'removed' + elseif dfhack.internal.patchBytes({}, self.new_bytes) then + return 'applied' + else + return 'conflict', addr + end +end + +function BinaryPatch:isApplied() + return dfhack.internal.patchBytes({}, self.new_bytes) +end + +function BinaryPatch:apply() + local ok, err, addr = dfhack.internal.patchBytes(self.new_bytes, self.old_bytes) + if ok then + return true, 'applied the patch' + elseif dfhack.internal.patchBytes({}, self.new_bytes) then + return true, 'patch is already applied' + else + return false, string.format('conflict at address %x', addr) + end +end + +function BinaryPatch:isRemoved() + return dfhack.internal.patchBytes({}, self.old_bytes) +end + +function BinaryPatch:remove() + local ok, err, addr = dfhack.internal.patchBytes(self.old_bytes, self.new_bytes) + if ok then + return true, 'removed the patch' + elseif dfhack.internal.patchBytes({}, self.old_bytes) then + return true, 'patch is already removed' + else + return false, string.format('conflict at address %x', addr) + end +end + +return _ENV diff --git a/scripts/binpatch.lua b/scripts/binpatch.lua index f0f14e929..b9a4cf0b1 100644 --- a/scripts/binpatch.lua +++ b/scripts/binpatch.lua @@ -1,109 +1,36 @@ -- Apply or remove binary patches at runtime. -local utils = require('utils') - -function load_patch(name) - local filename = name - local auto = false - if not string.match(filename, '[./\\]') then - auto = true - filename = dfhack.getHackPath()..'/patches/'..dfhack.getDFVersion()..'/'..name..'.dif' - end - - local file, err = io.open(filename, 'r') - if not file then - if auto and string.match(err, ': No such file or directory') then - return nil, 'no patch '..name..' for '..dfhack.getDFVersion() - else - return nil, err - end - end - - local old_bytes = {} - local new_bytes = {} - - for line in file:lines() do - if string.match(line, '^%x+:') then - local offset, oldv, newv = string.match(line, '^(%x+):%s*(%x+)%s+(%x+)%s*$') - if not offset then - file:close() - return nil, 'Could not parse: '..line - end - - offset, oldv, newv = tonumber(offset,16), tonumber(oldv,16), tonumber(newv,16) - if oldv > 255 or newv > 255 then - file:close() - return nil, 'Invalid byte values: '..line - end - - old_bytes[offset] = oldv - new_bytes[offset] = newv - end - end - - return { name = name, old_bytes = old_bytes, new_bytes = new_bytes } -end - -function rebase_table(input) - local output = {} - local base = dfhack.internal.getImageBase() - for k,v in pairs(input) do - local offset = dfhack.internal.adjustOffset(k) - if not offset then - return nil, string.format('invalid offset: %x', k) - end - output[base + offset] = v - end - return output -end - -function rebase_patch(patch) - local nold, err = rebase_table(patch.old_bytes) - if not nold then return nil, err end - local nnew, err = rebase_table(patch.new_bytes) - if not nnew then return nil, err end - return { name = patch.name, old_bytes = nold, new_bytes = nnew } -end +local bp = require('binpatch') function run_command(cmd,name) - local patch, err = load_patch(name) - if not patch then - dfhack.printerr('Could not load: '..err) - return - end + local pfix = name..': ' - local rpatch, err = rebase_patch(patch) - if not rpatch then - dfhack.printerr(name..': '..err) + local patch, err = bp.load_dif_file(name) + if not patch then + dfhack.printerr(pfix..err) return end if cmd == 'check' then - local old_ok, err, addr = dfhack.internal.patchBytes({}, rpatch.old_bytes) - if old_ok then - print(name..': patch is not applied.') - elseif dfhack.internal.patchBytes({}, rpatch.new_bytes) then - print(name..': patch is applied.') + local status, addr = patch:status() + if status == 'conflict' then + dfhack.printerr(string.format('%sconflict at address %x', pfix, addr)) else - dfhack.printerr(string.format('%s: conflict at address %x', name, addr)) + print(pfix..'patch is '..status) end elseif cmd == 'apply' then - local ok, err, addr = dfhack.internal.patchBytes(rpatch.new_bytes, rpatch.old_bytes) + local ok, msg = patch:apply() if ok then - print(name..': applied the patch.') - elseif dfhack.internal.patchBytes({}, rpatch.new_bytes) then - print(name..': patch is already applied.') + print(pfix..msg) else - dfhack.printerr(string.format('%s: conflict at address %x', name, addr)) + dfhack.printerr(pfix..msg) end elseif cmd == 'remove' then - local ok, err, addr = dfhack.internal.patchBytes(rpatch.old_bytes, rpatch.new_bytes) + local ok, msg = patch:remove() if ok then - print(name..': removed the patch.') - elseif dfhack.internal.patchBytes({}, rpatch.old_bytes) then - print(name..': patch is already removed.') + print(pfix..msg) else - dfhack.printerr(string.format('%s: conflict at address %x', name, addr)) + dfhack.printerr(pfix..msg) end else qerror('Invalid command: '..cmd) diff --git a/scripts/gui/assign-rack.lua b/scripts/gui/assign-rack.lua index d358dfff1..92535d793 100644 --- a/scripts/gui/assign-rack.lua +++ b/scripts/gui/assign-rack.lua @@ -1,19 +1,13 @@ --- Assign weapon racks to squads. Requires patch from bug 1445. +-- Assign weapon racks to squads. Requires the weaponrack-unassign patch. ---[[ - - Required patches: - - v0.34.11 linux: http://pastebin.com/mt5EUgFZ - v0.34.11 windows: http://pastebin.com/09nRCybe - -]] +-- See bug 1445 for more info about the patches. local utils = require 'utils' local gui = require 'gui' local guidm = require 'gui.dwarfmode' local widgets = require 'gui.widgets' local dlg = require 'gui.dialogs' +local bp = require 'binpatch' AssignRack = defclass(AssignRack, guidm.MenuOverlay) @@ -190,12 +184,18 @@ end AssignRack{ building = dfhack.gui.getSelectedBuilding() }:show() -if not already_warned then - already_warned = true +if not already_patched then + local patch = bp.load_dif_file('weaponrack-unassign') + if patch and patch:isApplied() then + already_patched = true + end +end + +if not already_patched then dlg.showMessage( 'BUG ALERT', - { 'This script requires a binary patch from', NEWLINE, - 'bug 1445 on the tracker. Otherwise the game', NEWLINE, + { 'This script requires applying the binary patch', NEWLINE, + 'named weaponrack-unassign. Otherwise the game', NEWLINE, 'will lose your settings due to a bug.' }, COLOR_YELLOW )