Skip to content

Commit

Permalink
Merge pull request #1354 from myk002/myk_stuck_squad_messenger
Browse files Browse the repository at this point in the history
[fix/stuck-squad] allow messengers to rescue stuck squads
  • Loading branch information
myk002 authored Dec 25, 2024
2 parents afcd9c1 + a9e09e9 commit b0f8d4a
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 21 deletions.
20 changes: 11 additions & 9 deletions docs/fix/stuck-squad.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,29 @@ fix/stuck-squad
===============

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

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

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

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

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

Usage
-----
Expand Down
44 changes: 35 additions & 9 deletions fix/stuck-squad.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,18 @@ end

local function is_army_valid_and_returning(army)
local controller = get_top_controller(army.controller)
if not controller or controller.goal ~= df.army_controller_goal_type.SITE_INVASION then
return false, false
if not controller then return false, false end
if controller.goal == df.army_controller_goal_type.SITE_INVASION then
return true, controller.data.goal_site_invasion.flag.RETURNING_HOME
elseif controller.goal == df.army_controller_goal_type.MAKE_REQUEST then
return true, controller.data.goal_make_request.flag.RETURNING_HOME
end
return true, controller.data.goal_site_invasion.flag.RETURNING_HOME
return false, false
end

local function get_hf_army(hf)
if not hf then return end
return df.army.find(hf.info and hf.info.whereabouts and hf.info.whereabouts.army_id or -1)
end

-- need to check all squad positions since some members may have died
Expand All @@ -28,7 +36,7 @@ local function get_squad_army(squad)
for _,sp in ipairs(squad.positions) do
local hf = df.historical_figure.find(sp.occupant)
if not hf then goto continue end
local army = df.army.find(hf.info and hf.info.whereabouts and hf.info.whereabouts.army_id or -1)
local army = get_hf_army(hf)
if army then return army end
::continue::
end
Expand Down Expand Up @@ -58,6 +66,24 @@ function scan_fort_armies()
end
::continue::
end

if #stuck_armies == 0 then return stuck_armies, nil, nil end

-- prefer returning with a messenger if one is readily available
for _,messenger in ipairs(dfhack.units.getUnitsByNobleRole('Messenger')) do
local army = get_hf_army(df.historical_figure.find(messenger.hist_figure_id))
if not army then goto continue end
local valid, returning = is_army_valid_and_returning(army)
if valid then
if returning then
returning_army = {army=army}
else
outbound_army = {army=army}
end
end
::continue::
end

return stuck_armies, outbound_army, returning_army
end

Expand All @@ -67,14 +93,14 @@ local function unstick_armies()
if not returning_army then
local instructions = outbound_army
and ('Please wait for %s to complete their objective and run this command again when they are on their way home.'):format(
dfhack.df2console(dfhack.military.getSquadName(outbound_army.squad.id)))
or 'Please send a squad out on a mission that will return to the fort, and'..
outbound_army.squad and dfhack.df2console(dfhack.military.getSquadName(outbound_army.squad.id)) or 'the messenger')
or 'Please send a squad or a messenger out on a mission that will return to the fort, and'..
' run this command again when they are on the way home.'
qerror(('%d stuck arm%s found, but no returning armies found to rescue them!\n%s'):format(
#stuck_armies, #stuck_armies == 1 and 'y' or 'ies', instructions))
qerror(('%d stuck squad%s found, but no returning squads or messengers are available to rescue them!\n%s'):format(
#stuck_armies, #stuck_armies == 1 and '' or 's', instructions))
return
end
local returning_squad_name = dfhack.df2console(dfhack.military.getSquadName(returning_army.squad.id))
local returning_squad_name = returning_army.squad and dfhack.df2console(dfhack.military.getSquadName(returning_army.squad.id)) or 'the messenger'
for _,stuck in ipairs(stuck_armies) do
print(('fix/stuck-squad: Squad rescue operation underway! %s is rescuing %s'):format(
returning_squad_name, dfhack.military.getSquadName(stuck.squad.id)))
Expand Down
7 changes: 4 additions & 3 deletions internal/notify/notifications.lua
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,10 @@ NOTIFICATIONS_BY_IDX = {
end,
on_click=function()
local message = 'A squad is lost on the world map and needs rescue!\n\n' ..
'Please send a squad out on a mission that will return to the fort (e.g.\n' ..
'a Demand one-time tribute mission, but not a Conquer and occupy mission).\n' ..
'They will rescue the stuck squad on their way home.'
'Please send a messenger to a holding or a squad out on a mission\n' ..
'that will return to the fort (e.g. a Demand one-time tribute mission,\n' ..
'but not a Conquer and occupy mission). They will rescue the stuck\n' ..
'squad on their way home.'
if not repeat_util.isScheduled('control-panel/fix/stuck-squad') then
message = message .. '\n\n' ..
'Please enable fix/stuck-squad in the DFHack control panel to enable\n'..
Expand Down

0 comments on commit b0f8d4a

Please sign in to comment.