Skip to content

Commit a9e09e9

Browse files
committed
allow messengers to rescue stuck squads
1 parent afcd9c1 commit a9e09e9

File tree

3 files changed

+50
-21
lines changed

3 files changed

+50
-21
lines changed

docs/fix/stuck-squad.rst

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,29 @@ fix/stuck-squad
22
===============
33

44
.. dfhack-tool::
5-
:summary: Allow squads returning from missions to rescue lost squads.
5+
:summary: Allow squads and messengers to rescue lost squads.
66
:tags: fort bugfix military
77

88
Occasionally, squads that you send out on a mission get stuck on the world map.
99
They lose their ability to navigate and are unable to return to your fortress.
10-
This tool allows another of your squads that is (successfully) returning from a
11-
mission to rescue the lost squad along the way and bring them home.
10+
This tool allows a messenger that is returning from a holding or any other of
11+
your squads that is returning from a mission to rescue the lost squad along the
12+
way and bring them home.
1213

1314
This fix is enabled by default in the DFHack
1415
`control panel <gui/control-panel>`, or you can run it as needed. However, it
15-
is still up to you to send out another squad that can be tasked with the rescue
16-
mission. You can send the squad out on a relatively innocuous mission, like
17-
"Demand one-time tribute", to minimize risk to the squad.
16+
is still up to you to send out a messenger or squad that can be tasked with the
17+
rescue. If you have a holding that is linked to your fort, you can send out a
18+
messenger -- you don't have to actually request any workers. Otherwise, you can
19+
send a squad out on a mission with minimal risk, like "Demand one-time tribute".
1820

1921
This tool is integrated with `gui/notify`, so you will get a notification in
20-
the DFHack notification panel when a squad is stuck and there are no squads
21-
currently out traveling that can rescue them.
22+
the DFHack notification panel when a squad is stuck and there are no squads or
23+
messengers currently out traveling that can rescue them.
2224

2325
Note that there might be other reasons why your squad appears missing -- if it
2426
got wiped out in combat and nobody survived to report back, for example -- but
25-
this tool should fix the cases that are actual bugs.
27+
this tool should allow you to recover from the cases that are actual bugs.
2628

2729
Usage
2830
-----

fix/stuck-squad.lua

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,18 @@ end
1616

1717
local function is_army_valid_and_returning(army)
1818
local controller = get_top_controller(army.controller)
19-
if not controller or controller.goal ~= df.army_controller_goal_type.SITE_INVASION then
20-
return false, false
19+
if not controller then return false, false end
20+
if controller.goal == df.army_controller_goal_type.SITE_INVASION then
21+
return true, controller.data.goal_site_invasion.flag.RETURNING_HOME
22+
elseif controller.goal == df.army_controller_goal_type.MAKE_REQUEST then
23+
return true, controller.data.goal_make_request.flag.RETURNING_HOME
2124
end
22-
return true, controller.data.goal_site_invasion.flag.RETURNING_HOME
25+
return false, false
26+
end
27+
28+
local function get_hf_army(hf)
29+
if not hf then return end
30+
return df.army.find(hf.info and hf.info.whereabouts and hf.info.whereabouts.army_id or -1)
2331
end
2432

2533
-- need to check all squad positions since some members may have died
@@ -28,7 +36,7 @@ local function get_squad_army(squad)
2836
for _,sp in ipairs(squad.positions) do
2937
local hf = df.historical_figure.find(sp.occupant)
3038
if not hf then goto continue end
31-
local army = df.army.find(hf.info and hf.info.whereabouts and hf.info.whereabouts.army_id or -1)
39+
local army = get_hf_army(hf)
3240
if army then return army end
3341
::continue::
3442
end
@@ -58,6 +66,24 @@ function scan_fort_armies()
5866
end
5967
::continue::
6068
end
69+
70+
if #stuck_armies == 0 then return stuck_armies, nil, nil end
71+
72+
-- prefer returning with a messenger if one is readily available
73+
for _,messenger in ipairs(dfhack.units.getUnitsByNobleRole('Messenger')) do
74+
local army = get_hf_army(df.historical_figure.find(messenger.hist_figure_id))
75+
if not army then goto continue end
76+
local valid, returning = is_army_valid_and_returning(army)
77+
if valid then
78+
if returning then
79+
returning_army = {army=army}
80+
else
81+
outbound_army = {army=army}
82+
end
83+
end
84+
::continue::
85+
end
86+
6187
return stuck_armies, outbound_army, returning_army
6288
end
6389

@@ -67,14 +93,14 @@ local function unstick_armies()
6793
if not returning_army then
6894
local instructions = outbound_army
6995
and ('Please wait for %s to complete their objective and run this command again when they are on their way home.'):format(
70-
dfhack.df2console(dfhack.military.getSquadName(outbound_army.squad.id)))
71-
or 'Please send a squad out on a mission that will return to the fort, and'..
96+
outbound_army.squad and dfhack.df2console(dfhack.military.getSquadName(outbound_army.squad.id)) or 'the messenger')
97+
or 'Please send a squad or a messenger out on a mission that will return to the fort, and'..
7298
' run this command again when they are on the way home.'
73-
qerror(('%d stuck arm%s found, but no returning armies found to rescue them!\n%s'):format(
74-
#stuck_armies, #stuck_armies == 1 and 'y' or 'ies', instructions))
99+
qerror(('%d stuck squad%s found, but no returning squads or messengers are available to rescue them!\n%s'):format(
100+
#stuck_armies, #stuck_armies == 1 and '' or 's', instructions))
75101
return
76102
end
77-
local returning_squad_name = dfhack.df2console(dfhack.military.getSquadName(returning_army.squad.id))
103+
local returning_squad_name = returning_army.squad and dfhack.df2console(dfhack.military.getSquadName(returning_army.squad.id)) or 'the messenger'
78104
for _,stuck in ipairs(stuck_armies) do
79105
print(('fix/stuck-squad: Squad rescue operation underway! %s is rescuing %s'):format(
80106
returning_squad_name, dfhack.military.getSquadName(stuck.squad.id)))

internal/notify/notifications.lua

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,10 @@ NOTIFICATIONS_BY_IDX = {
323323
end,
324324
on_click=function()
325325
local message = 'A squad is lost on the world map and needs rescue!\n\n' ..
326-
'Please send a squad out on a mission that will return to the fort (e.g.\n' ..
327-
'a Demand one-time tribute mission, but not a Conquer and occupy mission).\n' ..
328-
'They will rescue the stuck squad on their way home.'
326+
'Please send a messenger to a holding or a squad out on a mission\n' ..
327+
'that will return to the fort (e.g. a Demand one-time tribute mission,\n' ..
328+
'but not a Conquer and occupy mission). They will rescue the stuck\n' ..
329+
'squad on their way home.'
329330
if not repeat_util.isScheduled('control-panel/fix/stuck-squad') then
330331
message = message .. '\n\n' ..
331332
'Please enable fix/stuck-squad in the DFHack control panel to enable\n'..

0 commit comments

Comments
 (0)