Skip to content

Commit 21fef5f

Browse files
authored
Merge pull request #5665 from ChrisJohnsen/cj/search-siege-engines
search widget support for DF siege engines subtab
2 parents e51be42 + e8b7cd3 commit 21fef5f

File tree

3 files changed

+121
-7
lines changed

3 files changed

+121
-7
lines changed

docs/changelog.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,11 @@ Template for new versions:
5858
- ``edgescroll``: Introduced plugin to pan the view automatically when the mouse reaches the screen border.
5959

6060
## New Features
61+
- `sort`: Places search widget can search "Siege engines" subtab by name, loaded status, and operator status
6162

6263
## Fixes
64+
- `sort`: Using the squad unit selector will no longer cause Dwarf Fortress to crash on exit
65+
- `sort`: Places search widget moved to account for DF's new "Siege engines" subtab
6366

6467
## Misc Improvements
6568
- `createitem`: created items can now be placed onto/into tables, nests, bookcases, display cases, and altars

plugins/lua/sort/info.lua

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,8 @@ function InfoOverlay:get_key()
278278
end
279279

280280
function resize_overlay(self)
281-
local sw = dfhack.screen.getWindowSize()
282-
local overlay_width = math.min(40, sw-(self.frame_rect.x1 + 30))
281+
local iw = gui.get_interface_rect().width
282+
local overlay_width = math.min(40, iw - (self.frame_rect.x1 + 30))
283283
if overlay_width ~= self.frame.w then
284284
self.frame.w = overlay_width
285285
return true
@@ -292,15 +292,13 @@ end
292292

293293
function get_panel_offsets()
294294
local tabs_in_two_rows = is_tabs_in_two_rows()
295-
local shift_right = info.current_mode == df.info_interface_mode_type.ARTIFACTS or
296-
info.current_mode == df.info_interface_mode_type.LABOR
295+
local shift_right = info.current_mode == df.info_interface_mode_type.ARTIFACTS
297296
local l_offset = (not tabs_in_two_rows and shift_right) and 4 or 0
298297
local t_offset = 1
299298
if tabs_in_two_rows then
300299
t_offset = shift_right and 0 or 3
301300
end
302-
if info.current_mode == df.info_interface_mode_type.JOBS or
303-
info.current_mode == df.info_interface_mode_type.BUILDINGS then
301+
if info.current_mode == df.info_interface_mode_type.JOBS then
304302
t_offset = t_offset - 1
305303
end
306304
return l_offset, t_offset

plugins/lua/sort/places.lua

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,14 +170,126 @@ local function get_farmplot_search_key(farmplot)
170170
return table.concat(result, ' ')
171171
end
172172

173+
---@param siege_engine df.building_siegeenginest
174+
---@return string
175+
local function siege_engine_type(siege_engine)
176+
if siege_engine.type == df.siegeengine_type.BoltThrower then
177+
return 'Bolt Thrower'
178+
end
179+
return df.siegeengine_type[siege_engine.type]
180+
end
181+
182+
---@param siege_engine df.building_siegeenginest
183+
---@return string
184+
local function siege_engine_status(siege_engine)
185+
-- portions of return value with with underscores are to allow easier
186+
-- word-anchored matching even when the DFHack full-text search mode is
187+
-- enabled; e.g.
188+
-- - "loaded" would match "Loaded" and "Unloaded",
189+
-- - but "_loaded" would only match "_Loaded"
190+
local count = 0
191+
local count_all = siege_engine.type == df.siegeengine_type.BoltThrower
192+
for _, building_item in ipairs(siege_engine.contained_items) do
193+
if building_item.use_mode == df.building_item_role_type.TEMP then
194+
if not count_all then
195+
return 'Loaded _Loaded'
196+
end
197+
count = count + building_item.item:getStackSize()
198+
end
199+
end
200+
if count_all and count > 0 then
201+
return ('%d bolts _%d_bolts'):format(count, count)
202+
end
203+
return 'Unloaded'
204+
end
205+
206+
---@param siege_engine df.building_siegeenginest
207+
---@return string
208+
local function siege_engine_job_status(siege_engine)
209+
for _, job in ipairs(siege_engine.jobs) do
210+
if job.job_type == df.job_type.LoadCatapult
211+
or job.job_type == df.job_type.LoadBallista
212+
or job.job_type == df.job_type.LoadBoltThrower
213+
then
214+
if dfhack.job.getWorker(job) ~= nil then
215+
return 'Loading'
216+
else
217+
return 'Inactive load task'
218+
end
219+
end
220+
local firing_bolt_thrower = job.job_type == df.job_type.FireBoltThrower
221+
local firing = job.job_type == df.job_type.FireCatapult
222+
or job.job_type == df.job_type.FireBallista
223+
or firing_bolt_thrower
224+
if firing then
225+
local unit = dfhack.job.getWorker(job)
226+
if unit == nil then
227+
return 'No operator'
228+
else
229+
---@type integer?, integer?, integer?
230+
local x, y, z = dfhack.units.getPosition(unit)
231+
-- DF shows "present" when the unit is inside the building's
232+
-- footprint (or, for bolt throwers, next to it); the unit does
233+
-- not need to be at the exact firing position tile (which
234+
-- varies based on siege engine type and direction)
235+
if x ~= nil and z == siege_engine.z then
236+
---@cast y integer
237+
if firing_bolt_thrower then
238+
if siege_engine.x1 - 1 <= x and x <= siege_engine.x2 + 1
239+
and siege_engine.y1 - 1 <= y and y <= siege_engine.y2 + 1
240+
then
241+
return 'Operator present'
242+
end
243+
elseif dfhack.buildings.containsTile(siege_engine, x, y) then
244+
return 'Operator present'
245+
end
246+
end
247+
return 'Operator assigned'
248+
end
249+
end
250+
end
251+
return ''
252+
end
253+
254+
---@param siege_engine df.building_siegeenginest
255+
---@return string
256+
local function get_siege_engine_search_key(siege_engine)
257+
-- DF 53.05 Info window, Places tab, Siege Engines subtab shows this info:
258+
-- name: assigned name or siege engine type name
259+
-- status: "Unloaded", "Loaded", "<N> bolts"
260+
-- job status:
261+
-- - "Inactive load task" (load job unassigned),
262+
-- - "Loading" (load job assigned),
263+
-- - "No operator" (fire job unassigned),
264+
-- - "Operator present" (fire job assigned),
265+
-- - "Operator assigned" (fire job assigned, but not in position),
266+
-- - blank
267+
-- action: (icons) fire-at-will, practice, prepare-to-fire, keep-loaded, not-in-use
268+
-- These have associated text blurbs that are shown in the
269+
-- building info window, but those texts are not discoverable
270+
-- from the Info > Places > Siege engine list view.
271+
local result = {}
272+
273+
if #siege_engine.name ~= 0 then table.insert(result, siege_engine.name) end
274+
275+
table.insert(result, siege_engine_type(siege_engine))
276+
277+
table.insert(result, siege_engine_status(siege_engine))
278+
279+
table.insert(result, siege_engine_job_status(siege_engine))
280+
281+
return table.concat(result, ' ')
282+
end
283+
173284
-- ----------------------
174285
-- PlacesOverlay
175286
--
176287

177288
PlacesOverlay = defclass(PlacesOverlay, sortoverlay.SortOverlay)
178289
PlacesOverlay.ATTRS{
179290
desc='Adds search functionality to the places overview screens.',
180-
default_pos={x=71, y=9},
291+
default_pos={x=52, y=9},
292+
version=2,
181293
viewscreens='dwarfmode/Info',
182294
frame={w=40, h=6}
183295
}
@@ -205,6 +317,7 @@ function PlacesOverlay:init()
205317
self:register_handler('STOCKPILES', buildings.list[df.buildings_mode_type.STOCKPILES], curry(sortoverlay.single_vector_search, {get_search_key_fn=get_stockpile_search_key}))
206318
self:register_handler('WORKSHOPS', buildings.list[df.buildings_mode_type.WORKSHOPS], curry(sortoverlay.single_vector_search, {get_search_key_fn=get_workshop_search_key}))
207319
self:register_handler('FARMPLOTS', buildings.list[df.buildings_mode_type.FARMPLOTS], curry(sortoverlay.single_vector_search, {get_search_key_fn=get_farmplot_search_key}))
320+
self:register_handler('SIEGE_ENGINES', buildings.list[df.buildings_mode_type.SIEGE_ENGINES], curry(sortoverlay.single_vector_search, {get_search_key_fn=get_siege_engine_search_key}))
208321
end
209322

210323
function PlacesOverlay:get_key()

0 commit comments

Comments
 (0)