Skip to content

Commit f861e8c

Browse files
committed
Add new tool resize-armor
1 parent 80d61d1 commit f861e8c

File tree

3 files changed

+164
-0
lines changed

3 files changed

+164
-0
lines changed

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Template for new versions:
2727
# Future
2828

2929
## New Tools
30+
- `resize-armor`: resize armor or clothing item to any creature size.
3031

3132
## New Features
3233

docs/resize-armor.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
resize-armor
2+
============
3+
4+
.. dfhack-tool::
5+
:summary: Resize armor and clothing.
6+
:tags: adventure fort armok gameplay items
7+
8+
Resize any armor or clothing item to suit any creature size.
9+
10+
Usage
11+
-----
12+
13+
``resize-armor [<option>]``
14+
15+
Select an armor or clothing item while in either adventure or fortress mode and
16+
run this tool to resize the item. A stockpile can be selected while in fortress
17+
mode to perform the resize operation on armor or clothing items contained in
18+
the stockpile. If race ID is not specified, the items will be resized to suit
19+
the race of the current adventurer while in adventure mode, or to suit the race
20+
of the current site's civilization while in fortress mode.
21+
22+
Options
23+
-------
24+
25+
``-r``, ``--race <id>``
26+
Specify the race ID of the target race to resize the item to.

resize-armor.lua

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
-- Resize armor and clothing.
2+
3+
local argparse = require('argparse')
4+
local utils = require('utils')
5+
6+
local function isValidItem(item)
7+
local itemTypes = {
8+
df.item_type.ARMOR,
9+
df.item_type.SHOES,
10+
df.item_type.GLOVES,
11+
df.item_type.HELM,
12+
df.item_type.PANTS,
13+
}
14+
if not utils.linear_index(itemTypes, item:getType()) or
15+
item.flags.in_job or
16+
item.flags.hostile or
17+
item.flags.removed or
18+
item.flags.dead_dwarf or
19+
item.flags.rotten or
20+
item.flags.spider_web or
21+
item.flags.construction or
22+
item.flags.encased or
23+
item.flags.trader or
24+
item.flags.garbage_collect or
25+
item.flags.forbid or
26+
item.flags.dump or
27+
item.flags.on_fire or
28+
item.flags.melt
29+
then
30+
return false
31+
end
32+
return true
33+
end
34+
35+
local function GetStockpileItems(stockpile)
36+
local stockPileItems = dfhack.buildings.getStockpileContents(stockpile)
37+
local items = {}
38+
for _, stockPileItem in ipairs(stockPileItems) do
39+
if #stockPileItems > 0 and isValidItem(stockPileItem) then
40+
table.insert(items, stockPileItem)
41+
end
42+
end
43+
return items
44+
end
45+
46+
local function GetRace()
47+
local race
48+
if dfhack.world.isAdventureMode() then
49+
race = dfhack.world.getAdventurer().race
50+
elseif dfhack.world.isFortressMode() then
51+
local site = dfhack.world.getCurrentSite()
52+
for _, entityLink in ipairs(site.entity_links) do
53+
local entity = df.historical_entity.find(entityLink.entity_id)
54+
if entity and entity.type == df.historical_entity_type.Civilization then
55+
race = entity.race
56+
break
57+
end
58+
end
59+
end
60+
return race
61+
end
62+
63+
local function ResizeItems(items, race)
64+
local raceName = race and dfhack.units.getRaceNamePluralById(race)
65+
local resizeCount = 0
66+
for _, item in ipairs(items) do
67+
local itemName = item and dfhack.items.getReadableDescription(item)
68+
if item:getMakerRace() ~= race then
69+
item:setMakerRace(race)
70+
item:calculateWeight()
71+
resizeCount = resizeCount + 1
72+
if #items == 1 then print(('%s resized for %s.'):format(itemName, raceName)) end
73+
elseif #items == 1 then print(('%s is already sized for %s.'):format(itemName, raceName)) end
74+
end
75+
if resizeCount > 1 then
76+
print(('%d items resized for %s.'):format(resizeCount, raceName))
77+
elseif resizeCount == 0 and #items > 1 then
78+
print(('All items are already sized for %s'):format(raceName))
79+
end
80+
end
81+
82+
local function ParseCommandLine(args)
83+
local options = {
84+
help = false,
85+
race = nil,
86+
}
87+
local positionals = argparse.processArgsGetopt(args, {
88+
{'h', 'help', handler = function() options.help = true end},
89+
{'r', 'race', hasArg = true, handler = function(arg) options.race = argparse.nonnegativeInt(arg, 'race') end},
90+
})
91+
return options
92+
end
93+
94+
local function Main(args)
95+
local options = ParseCommandLine(args)
96+
if args[1] == 'help' or options.help then
97+
print(dfhack.script_help())
98+
return
99+
end
100+
local items = {}
101+
local item = dfhack.gui.getSelectedItem(true)
102+
if item then
103+
if isValidItem(item) then
104+
table.insert(items, item)
105+
else
106+
qerror('Selected item cannot be resized.')
107+
end
108+
elseif dfhack.world.isFortressMode() then
109+
local stockpile = dfhack.gui.getSelectedStockpile(true)
110+
if stockpile and df.building_stockpilest:is_instance(stockpile) then
111+
items = GetStockpileItems(stockpile)
112+
if #items < 1 then qerror('Selected stockpile contains no items that can be resized.') end
113+
end
114+
end
115+
if #items > 0 then
116+
local race = options.race or GetRace()
117+
if not race then
118+
qerror('Unable to obtain race ID. Please specify race ID manually.')
119+
end
120+
ResizeItems(items, race)
121+
else
122+
if dfhack.world.isAdventureMode() then
123+
qerror('No item selected.')
124+
elseif dfhack.world.isFortressMode() then
125+
qerror('No item or stockpile selected.')
126+
end
127+
end
128+
end
129+
130+
if not dfhack.isMapLoaded() or (
131+
not dfhack.world.isAdventureMode() and not dfhack.world.isFortressMode()
132+
)
133+
then
134+
qerror('This script requires the game to be in adventure or fortress mode.')
135+
end
136+
137+
Main({...})

0 commit comments

Comments
 (0)