Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ Template for new versions:
## Fixes

## Misc Improvements
- `fix/loyaltycascade`: now also breaks up brawls and other intra-fort conflicts that *look* like loyalty cascades
- `makeown`: remove selected unit from any current conflicts so they don't just start attacking other citizens when you make them a citizen of your fort

## Removed

Expand Down
4 changes: 3 additions & 1 deletion docs/fix/loyaltycascade.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ fix/loyaltycascade
:tags: fort bugfix units

This tool neutralizes loyalty cascades by fixing units who consider their own
civilization to be the enemy.
civilization to be the enemy. It will also halt all fighting on the map that
involves your citizens, though "real" enemies will re-engage in combat after a
short delay.

Usage
-----
Expand Down
3 changes: 2 additions & 1 deletion docs/makeown.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ makeown
:tags: fort armok units

Select a unit in the UI and run this tool to converts that unit to be a fortress
citizen (if sentient). It also removes their foreign affiliation, if any.
citizen (if sentient). It also removes their foreign affiliation, if any, and
removes the unit from any current conflict they are engaged in.

This tool also fixes :bug:`10921`, where you request workers from your
holdings, but they come with the "Merchant" profession and are unable to
Expand Down
5 changes: 3 additions & 2 deletions fix/loyaltycascade.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
-- Prevents a "loyalty cascade" (intra-fort civil war) when a citizen is killed.
-- Also breaks up brawls and other conflicts.

local makeown = reqscript('makeown')

Expand Down Expand Up @@ -76,7 +77,7 @@ local function fixUnit(unit)
makeown.clear_enemy_status(unit)
end

return false
return makeown.remove_from_conflict(unit) or fixed
end

local count = 0
Expand All @@ -87,7 +88,7 @@ for _, unit in pairs(dfhack.units.getCitizens()) do
end

if count > 0 then
print(('Fixed %s units from a loyalty cascade.'):format(count))
print(('Fixed %s units with loyalty issues.'):format(count))
else
print('No loyalty cascade found.')
end
31 changes: 30 additions & 1 deletion makeown.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,35 @@ function clear_enemy_status(unit)
if status_cache.next_slot > status_slot then
status_cache.next_slot = status_slot
end

return true
end

function remove_from_conflict(unit)
-- Remove the unit from any conflict activity
-- They will prompty re-engage if there is an actual enemy around
local to_remove = {}
for act_idx,act_id in ipairs(unit.activities) do
local act = df.activity_entry.find(act_id)
if not act or act.type ~= df.activity_entry_type.Conflict then goto continue end
for _,ev in ipairs(act.events) do
if ev:getType() ~= df.activity_event_type.Conflict then goto next_ev end
for _,side in ipairs(ev.sides) do
utils.erase_sorted(side.histfig_ids, unit.hist_figure_id)
utils.erase_sorted(side.unit_ids, unit.id)
end
::next_ev::
end
table.insert(to_remove, 1, act_idx)
::continue::
end

for _,act_idx in ipairs(to_remove) do
unit.activities:erase(act_idx)
end

-- return whether we removed unit from any conflicts
return #to_remove > 0
end

local prof_map = {
Expand Down Expand Up @@ -162,7 +191,7 @@ local function fix_unit(unit)
end

clear_enemy_status(unit)

remove_from_conflict(unit)
cancel_hostile_jobs(unit.job.current_job)
end

Expand Down