Saw that NPC armies can make cloth camps, and player can't. Unfair! This script fixes that.
local args = {...}
local function getLen(data)
-- Can't # an userdata value, must use function to get length.
local len = 0
for i, val in pairs(data) do
len = len +1
end
return len
end
local displacedRequirs = df.global.ui_build_selector.requirements [0]:_displace(1,dfhack.VERSION=="0.43.03-r1" and 4 or 0) --somehow 4 is appropriate size for moving it 2 ints south?
if args[1] and (args[1] == "help" or args[1] == "?" or args[1] == "-help" or args[1] "-?") then
local helptext = [====[
constructwithcloth
==================
Enables player to build cloth walls in fort mode like AI does in camps.
To use, call ``constructwithcloth`` in wall placement or material(x to F5) menu.
If that leaves you with inaccessible materials: expand, call, contract.
For ease of use, call with keybinding from dfhack.init. Suggestions:
# Press c to Construct with Cloth
# Alternatively, could call c to enable other keybindings below
keybinding add C@dwarfmode/Build/Position/Construction constructwithcloth
# Construct With Cloth on multi-tile constructions
keybinding add U@dwarfmode/Build/Position/Construction constructwithcloth
keybinding add K@dwarfmode/Build/Position/Construction constructwithcloth
# Construct with Cloth when entering Construction - Wall menu
# Script rejects workshop, furnace, machinery and weapon trap menus
# Helpful for dotted 1-tile walls with automaterial (Auto-mat select)
# Could also use Enter, if that's your preference
keybinding add W@dwarfmode/Build/Type constructwithcloth
# Construct with Cloth in build material menu with x to remove walled-off cloth
keybinding add X@dwarfmode/Build/Material/Groups constructwithcloth
Known issues:
With automaterial (Auto-Mat select), box select will return you to
normal material menu after using up autoselected materials.
]====]
dfhack.print(helptext)
elseif df.global.ui_sidebar_menus.building.category_id == 5 and --Construction Menu, Track uses 7
#displacedRequirs.candidates > 0 and -- Do we have anything to build with?
not (57 == displacedRequirs.candidates [#displacedRequirs.candidates-1]:getType() )
--Has it been run already? If not, then...
then
-- Can't just add to the end of list, throws a nil error. Must create own arrays and then replace the native ones.
-- They're added to choices on their own, which are populated each time choices list is displayed.
local candidates = {}
-- <vector>[] of pointers to items.
local candidate_selected = {}
-- Has an item been picked already? Used when you've partially selected options for multi-tile walls.
local unk_a0 = {}
-- This seems to be mostly-default value per fort, seen values ranging from 0 to 1753. Non-default seem to not change anything.
local candidate_enabled = {}
-- Toggles if thing is visible. DF uses it to remove inaccessible/inappropriate but existing materials from the list.
-- choices is stickier than list of candidates, so one could use it to apply it to clothes if called multiple times.
local addedcloths = 0
--
local initlength = #displacedRequirs.candidates
local last_unk_a0 = displacedRequirs.unk_a0 [(initlength-1)]
for index, material in pairs(df.global.world.items.other.CLOTH) do
-- This for loop populates cloth materials
if 57 == material:getType() and
not material.flags.in_job and
-- not material.flags.in_inventory and --Both cloth bins and someone's hand. Latter case is almost always covered by in_job, so better not check this.
not material.flags.construction and
not material.flags.encased and
not material.flags.forbid and
not material.flags.trader and
not material.flags.garbage_collect and
not material.flags.in_chest and
not material.flags.dump and
not material.flags.on_fire then
-- DF would give those candidate_enabled 0. I'd rather not add in the first place.
candidates[initlength+addedcloths] = material
candidate_selected [initlength+addedcloths] = 0
unk_a0 [initlength+addedcloths] = last_unk_a0
candidate_enabled [initlength+addedcloths] = 1
addedcloths = addedcloths + 1
end
end
for i=0, (initlength-1), 1 do
-- This for loop adds initial values, so one can still build with rigid materials.
candidates [i] = displacedRequirs.candidates [i]
candidate_selected [i] = 0
-- Unless using auto-material, candidates are not pre-selected.
unk_a0 [i] = displacedRequirs.unk_a0 [i]
candidate_enabled [i] = displacedRequirs.candidate_enabled [i]
end
displacedRequirs.candidates = candidates
displacedRequirs.candidate_selected = candidate_selected
displacedRequirs.unk_a0 = unk_a0
displacedRequirs.candidate_enabled = candidate_enabled
elseif df.global.ui_sidebar_menus.building.category_id == 5 and
#displacedRequirs.candidates > 0 and
(57 == displacedRequirs.candidates [#displacedRequirs.candidates-1]:getType() ) and
3 == getLen(df.global.ui_build_selector.choices[0]) and -- Expanded choices menu
57 == df.global.ui_build_selector.choices[#df.global.ui_build_selector.choices-1].candidate:getType() --last choice is cloth
then
--Already populated list. Now perhaps could check choices for walled-off candidates.
for index, choice in pairs(df.global.ui_build_selector.choices) do
if 57 == choice.candidate:getType() and --only apply to cloth
choice.distance < 0 --choice is inaccessible
then
displacedRequirs.candidate_enabled [choice.candidate_id] = 0
end
end
end
Basically, it takes the native construction material list, grabs all unused cloth in the fortress, and gives back new material list that is both combined.
It may happen that some cloth in fortress is behind walls and you get things like dist -12500 for some pieces.
To fix that there's secondary function to remove such cloth in expanded view (contract to refresh).
Will do nothing if you're not in Construction menu or don't have any normal materials to build with, unless you call it with help/?/-help/-? (which gets usage instructions).
To use, you would save the above code as constructwithcloth.lua in hack/scripts,
then call constructwithcloth with dfhack as you're sizing the wall or picking it's materials (need to expand/contract to update).
Now, why use this?
Aesthetics. Cloth walls as inside separators look nice.
There's
two one known issue
s:
1) Box select will, after using up automated material, return you to normal material menu. To fix, call it again and expand/contract to refresh the list.
2) Doesn't work with 43.03 (linux) dfhack (fails silently, unless you remove the safeties, in which case it crashes), as that version lacks the appropriate memory addresses. (But does work with 43.05 AND 42.06). Don't know how to fix this =( Fixed =)
# Press c to Construct with Cloth
keybinding add C@dwarfmode/Build/Position/Construction constructwithcloth
# Construct With Cloth on multi-tile constructions
keybinding add U@dwarfmode/Build/Position/Construction constructwithcloth
keybinding add K@dwarfmode/Build/Position/Construction constructwithcloth
# Construct with Cloth when entering Construction - Wall menu with "w". Use Enter if you prefer Enter key.
keybinding add W@dwarfmode/Build/Type constructwithcloth
# Construct with Cloth in build material menu with x (native expand/contract material list)
keybinding add X@dwarfmode/Build/Material/Groups constructwithcloth
# Alternatively, use c to enable those four cloth construction hotkeys above
keybinding add C@dwarfmode/Build/Position/Construction "multicmd keybinding add U@dwarfmode/Build/Position/Construction constructwithcloth ; keybinding add K@dwarfmode/Build/Position/Construction constructwithcloth ; keybinding add W@dwarfmode/Build/Type constructwithcloth ; keybinding add X@dwarfmode/Build/Material/Groups constructwithcloth "
# And use Shift-c to disable them.
keybinding add Shift-C@dwarfmode/Build/Position/Construction "multicmd keybinding clear U@dwarfmode/Build/Position/Construction constructwithcloth ; keybinding clear K@dwarfmode/Build/Position/Construction constructwithcloth ; keybinding clear W@dwarfmode/Build/Type constructwithcloth ; keybinding clear X@dwarfmode/Build/Material/Groups constructwithcloth "
# Might want to create single-line .lua script(s) consisting of dfhack.gui.showAnnouncement("DFHack: Enabled/Disabled Cloth Construction",4,1) and add ; them at the end of those multicmd commands to give bright red message at the bottom of screen that you've disabled or enabled those hotkeys.