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
33local argparse = require (" argparse" )
44local 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
4141end
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
4346local 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
141144end
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
143220local 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
173265end
0 commit comments