Skip to content

Commit 6cd5936

Browse files
authored
Merge pull request #1505 from amade-w/archery-practice-rework
Archery practice rework
2 parents c6e4e62 + a43f339 commit 6cd5936

File tree

4 files changed

+156
-60
lines changed

4 files changed

+156
-60
lines changed

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Template for new versions:
3131
## New Features
3232

3333
## Fixes
34+
- `fix/archery-practice`: now splits instead of combining ammo items in quivers, and moves quivers to end of unit's inventory list
3435

3536
## Misc Improvements
3637

docs/fix/archery-practice.rst

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,63 +2,66 @@ fix/archery-practice
22
====================
33

44
.. dfhack-tool::
5-
:summary: Consolidate and remove extra ammo items to fix 'Soldier (no item)' issue.
5+
:summary: Fix quivers and training ammo items to allow archery practice to take place.
66
:tags: fort bugfix items
77

8-
Combine ammo items inside quivers that are assigned for training to allow
8+
Make quivers the last item in the inventory of every ranged unit currently
9+
training and split stacks of ammo items assigned for training inside the
10+
quivers to ensure each training unit can have more than one stack to allow
911
archery practice to take place.
1012

1113
Usage
1214
-----
1315

1416
``fix/archery-practice``
15-
Combine ammo items inside quivers that are assigned for training.
17+
Move quivers to the end of units' inventory list and split stacks of
18+
training ammo items inside the quivers.
1619

1720
``fix/archery-practice -q``, ``fix/archery-practice --quiet``
18-
Combine ammo items inside quivers that are assigned for training.
19-
Do not print to console.
21+
Move quivers to the end of units' inventory list and split stacks of
22+
training ammo items inside the quivers. Do not print to console.
2023

21-
This tool will combine ammo items inside the quivers of units in squads
22-
that are currently set to train with the objective of ensuring that each
23-
unit hold only one combined stack of ammo item assigned for training in
24-
their quiver. Any ammo items left over after the combining operation
25-
will be dropped on the ground.
24+
This tool will set quivers as the last item in the inventory of units in
25+
squads that are currently set to train as well as split ammo items inside
26+
their quivers into multiple stacks if a quiver contains only ammo item
27+
with a stack size of 25 or larger assigned for training. The original
28+
training ammo item with a reduced stack size will remain in the quiver
29+
while new ammo items split from it will be placed on the ground where
30+
the unit is located to be picked up later.
2631

27-
The 'Soldier (no item)' issue
28-
-----------------------------
32+
Why are archers not practicing archery?
33+
---------------------------------------
2934

3035
Due to a bug in the game, a unit that is scheduled to train will not be
3136
able to practice archery at the archery range when their quiver contains
32-
more than one stack of ammo item that is assigned to them for training.
33-
This is indicated on the unit by the 'Soldier (no item)' status.
37+
only one stack of ammo item assigned for training. This is sometimes
38+
indicated on the unit by the 'Soldier (no item)' status.
3439

35-
The issue occurs when the game assigns an ammo item with a stack size of
36-
less than 25 to the unit, prompting the game to assign additional stacks
37-
of ammo items to make up for the deficit.
40+
During versions 52.03 and 52.04, the issue was the complete reverse;
41+
units would not practice when their quivers contained more than one
42+
stack of ammo items assigned for training.
3843

39-
The workaround to this issue is to ensure the squad ammo assignments
40-
for use in training contain as few ammo items with stack sizes smaller
41-
than 25 as possible. Since training bolts are often made from wood or
42-
bone which are created in stacks of 5, the use of the ``combine`` tool on
43-
ammo stockpiles is recommended to reduce the frequency of this issue
44-
occurring, while "incomplete" stacks of ammo items that are already
45-
picked up by training units can be managed by this tool.
44+
Another issue in 52.05 is that units will not practice archery if their
45+
quiver is not the last item in their inventory.
4646

47-
Any other stacks of ammo items inside the quiver that are not assigned
48-
for training will not affect the unit's ability to practice archery.
49-
50-
As of DF version 52.05, this bug should already be fixed.
47+
This tool provides an interim remedy by moving quivers to the end of
48+
every training unit's inventory list and splitting stacks of ammo items
49+
inside their quivers to prompt the game to give them multiple stacks
50+
of training ammo items.
5151

5252
Limitations
5353
-----------
5454

55-
Due to the very limited number of ammo items a unit's quiver might contain,
56-
the material, quality, and maker of the items are ignored when performing
57-
the combining operation on them. Only ammo items assigned for training will
58-
be combined, while ammo items inside the quiver that are assigned for combat
59-
will not be affected.
55+
The game has a tendency to reshuffle the squad's ammo/unit pairings if
56+
the newly split ammo items are force paired to the units holding the
57+
original ammo item. As a compromise, the new items are placed on the
58+
ground instead and added to the squad's training ammo assignment pool,
59+
so that the game can distribute the items normally without causing the
60+
pairing for ammo items already in quivers to be reshuffled.
6061

61-
Although this tool will consolidate ammo items inside quivers and discard
62-
any surplus items, the training units may not immediately go for archery
63-
practice, especially if they are still trying to collect more ammo items
64-
that the game have assigned to them.
62+
Although this tool would allow units to practice archery, the activity
63+
will still be aborted once they have only one stack of training ammo
64+
item remaining in their quivers. Practicing units will gain skill from
65+
practice, but not the positive thought they would have gained from
66+
having completed the activity. Once the game assigns more training
67+
ammo items to them, they can continue practicing archery.

fix/archery-practice.lua

Lines changed: 113 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- Consolidate and remove extra ammo items to fix 'Soldier (no item)' issue.
1+
-- Fix quivers and training ammo items to allow archery practice to take place.
22

33
local argparse = require("argparse")
44
local utils = require('utils')
@@ -8,7 +8,7 @@ local function GetTrainingSquads()
88
for _, squad in ipairs(df.global.world.squads.all) do
99
if squad.entity_id == df.global.plotinfo.group_id then
1010
if #squad.ammo.ammunition > 0 and squad.activity ~= -1 then
11-
trainingSquads[#trainingSquads + 1] = squad
11+
table.insert(trainingSquads, squad)
1212
end
1313
end
1414
end
@@ -33,13 +33,16 @@ local function GetTrainingAmmo(quiver, squad)
3333
local containedAmmo = generalRef
3434
local ammoItem = containedAmmo and df.item.find(containedAmmo.item_id)
3535
if isTrainingAmmo(ammoItem, squad) then
36-
trainingAmmo[#trainingAmmo + 1] = ammoItem
36+
table.insert(trainingAmmo, ammoItem)
3737
end
3838
end
3939
end
4040
return trainingAmmo
4141
end
4242

43+
--[[ The following functions are commented out because the nature
44+
-- of the bug has changed, requiring a different solution.
45+
-- More info: https://discord.com/channels/793331351645323264/873014631315148840/1423311023254933576
4346
local function UnassignAmmo(trainingAmmo, itemToKeep, itemsToRemove, squad, unit)
4447
local plotEqAssignedAmmo = df.global.plotinfo.equipment.items_assigned.AMMO
4548
local plotEqUnassignedAmmo = df.global.plotinfo.equipment.items_unassigned.AMMO
@@ -139,35 +142,124 @@ local function ConsolidateAmmo(trainingAmmo, squad, unit)
139142
end
140143
end
141144
end
145+
-- End of commented out functions ]]
146+
147+
-- Currently, only assignment to squad is practical, as pairing ammo items with
148+
-- units directly has a tendency to cause the game to reshuffle the pairings.
149+
local function AssignAmmoToSquad(newItems, item, squad)
150+
local plotEqAssignedAmmo = df.global.plotinfo.equipment.items_assigned.AMMO
151+
local assignedAmmo
152+
for _, ammoSpec in ipairs(squad.ammo.ammunition) do
153+
if utils.linear_index(ammoSpec.assigned, item.id) then
154+
assignedAmmo = ammoSpec
155+
break
156+
end
157+
end
158+
for _, newItem in ipairs(newItems) do
159+
assignedAmmo.assigned:insert('#', newItem.id)
160+
utils.sort_vector(assignedAmmo.assigned)
161+
plotEqAssignedAmmo:insert('#', newItem.id)
162+
utils.sort_vector(plotEqAssignedAmmo)
163+
end
164+
end
165+
166+
local function SplitAmmo(item, squad, unit)
167+
local newItems = {}
168+
repeat
169+
local items = dfhack.items.createItem(
170+
unit,
171+
dfhack.items.findType('AMMO'),
172+
item.subtype.subtype,
173+
item.mat_type,
174+
item.mat_index
175+
)
176+
if items then
177+
for _, newItem in ipairs(items) do
178+
newItem:setStackSize(5)
179+
newItem.maker_race = item.maker_race
180+
newItem:setQuality(item.quality)
181+
newItem.skill_rating = item.skill_rating
182+
newItem.maker = item.maker
183+
newItem.masterpiece_event = item.masterpiece_event
184+
table.insert(newItems, newItem)
185+
end
186+
end
187+
item:setStackSize(item.stack_size - 5)
188+
until item.stack_size <= 5
189+
AssignAmmoToSquad(newItems, item, squad)
190+
end
191+
192+
local function RemoveQuiverFromInv(unit, quiver)
193+
local equippedQuiver
194+
for i, v in ipairs (unit.inventory) do
195+
-- Remove quiver only if it's not the last item in the inventory.
196+
if v.item == quiver and i ~= (#unit.inventory - 1) then
197+
equippedQuiver = v
198+
end
199+
end
200+
if equippedQuiver then
201+
local idx = utils.linear_index(unit.inventory, equippedQuiver)
202+
unit.inventory:erase(idx)
203+
return true
204+
end
205+
return false
206+
end
207+
208+
local function MoveQuiverToEnd(unit, quiver)
209+
local caste = dfhack.units.getCasteRaw(unit)
210+
local bodyPart
211+
for i, v in ipairs(caste.body_info.body_parts) do
212+
if v.category == 'BODY_UPPER' then
213+
bodyPart = i
214+
break
215+
end
216+
end
217+
if bodyPart then dfhack.items.moveToInventory(quiver, unit, df.inv_item_role_type.Worn, bodyPart) end
218+
end
142219

143220
local function FixTrainingUnits(trainingSquads, options)
144-
local totalTrainingAmmo = 0
145-
local consolidateCount = 0
221+
local splitAmmoCount = 0
222+
local fixQuiverCount = 0
146223
for _, squad in ipairs(trainingSquads) do
147224
for _, position in ipairs(squad.positions) do
148-
if position.occupant == -1 then goto nextPosition end
149-
local unit = df.unit.find(df.historical_figure.find(position.occupant).unit_id)
150-
local quiver = unit and df.item.find(position.equipment.quiver)
151-
if quiver then
152-
local trainingAmmo = GetTrainingAmmo(quiver, squad)
153-
if #trainingAmmo > 1 then
154-
if not options.quiet then
155-
local unitName = unit and dfhack.units.getReadableName(unit)
156-
print(('Consolidating training ammo for %s...'):format(unitName))
225+
if position.occupant ~= -1 then
226+
local unit = df.unit.find(df.historical_figure.find(position.occupant).unit_id)
227+
local quiver = unit and df.item.find(position.equipment.quiver)
228+
if quiver then
229+
local trainingAmmo = GetTrainingAmmo(quiver, squad)
230+
local unitName = unit and dfhack.units.getReadableName(unit)
231+
if #trainingAmmo == 1 then
232+
local item = trainingAmmo[1]
233+
-- Split ammo if it's the only training ammo item and its stack size is 25 or larger.
234+
if item.stack_size >= 25 then
235+
if not options.quiet then
236+
print(('Splitting training ammo for %s...'):format(unitName))
237+
end
238+
SplitAmmo(item, squad, unit)
239+
splitAmmoCount = splitAmmoCount + 1
240+
end
241+
end
242+
if RemoveQuiverFromInv(unit, quiver) then
243+
if not options.quiet then
244+
print(('Moving quiver to the end for %s...'):format(unitName))
245+
end
246+
MoveQuiverToEnd(unit, quiver)
247+
fixQuiverCount = fixQuiverCount + 1
157248
end
158-
totalTrainingAmmo = totalTrainingAmmo + #trainingAmmo
159-
ConsolidateAmmo(trainingAmmo, squad, unit)
160-
consolidateCount = consolidateCount + 1
161249
end
162250
end
163-
::nextPosition::
164251
end
165252
end
166253
if not options.quiet then
167-
if consolidateCount > 0 then
168-
print(('%d stacks of ammo items in %d quiver(s) consolidated.'):format(totalTrainingAmmo, consolidateCount))
254+
if splitAmmoCount > 0 then
255+
print(('%d stack(s) of ammo item(s) split into stacks of 5.'):format(splitAmmoCount))
256+
else
257+
print('No ammo items require splitting.')
258+
end
259+
if fixQuiverCount > 0 then
260+
print(('%d quiver(s) moved to the end of each unit\'s inventory list.'):format(fixQuiverCount))
169261
else
170-
print('No stacks of ammo items require consolidation.')
262+
print('No inventories require sorting.')
171263
end
172264
end
173265
end

internal/control-panel/registry.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ COMMANDS_BY_IDX = {
7474
-- can be restored here once we solve issue #4292
7575
-- {command='craft-age-wear', help_command='tweak', group='bugfix', mode='tweak', default=true,
7676
-- desc='Allows items crafted from organic materials to wear out over time.'},
77-
{command='fix/archery-practice', group='bugfix', mode='repeat',
78-
desc='Consolidate ammo items inside quivers to allow archery practice to take place.',
77+
{command='fix/archery-practice', group='bugfix', mode='repeat', default=true,
78+
desc='Fix quivers and training ammo items to allow archery practice to take place.',
7979
params={'--time', '449', '--timeUnits', 'ticks', '--command', '[', 'fix/archery-practice', '-q', ']'}},
8080
{command='fix/blood-del', group='bugfix', mode='run', default=true},
8181
{command='fix/dead-units', group='bugfix', mode='repeat', default=true,

0 commit comments

Comments
 (0)