From 2bf2c241b136086cdf6ebad366b59c3ebc4a35f9 Mon Sep 17 00:00:00 2001
From: Myk Taylor <myk002@yahoo.com>
Date: Fri, 4 Oct 2024 16:40:43 -0700
Subject: [PATCH] clear enemy status cache for makeown

and allow fix/loyaltycascade to work on non-dwarves
---
 changelog.txt               |  2 ++
 docs/fix/loyaltycascade.rst |  2 +-
 fix/loyaltycascade.lua      | 40 ++++++++++---------------------------
 makeown.lua                 | 26 ++++++++++++++++++++++++
 4 files changed, 40 insertions(+), 30 deletions(-)

diff --git a/changelog.txt b/changelog.txt
index b58d36042f..4470beb018 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -32,6 +32,8 @@ Template for new versions:
 
 ## Fixes
 - `gui/quickfort`: only print a help blueprint's text once even if the repeat setting is enabled
+- `makeown`: quell any active enemy relationships with the converted creature
+- `fix/loyaltycascade`: allow the fix to work on non-dwarven citizens
 - `control-panel`: fix setting numeric preferences from the commandline
 
 ## Misc Improvements
diff --git a/docs/fix/loyaltycascade.rst b/docs/fix/loyaltycascade.rst
index 7a1eaad620..39899aae3f 100644
--- a/docs/fix/loyaltycascade.rst
+++ b/docs/fix/loyaltycascade.rst
@@ -5,7 +5,7 @@ fix/loyaltycascade
     :summary: Halts loyalty cascades where dwarves are fighting dwarves.
     :tags: fort bugfix units
 
-This tool aborts loyalty cascades by fixing units who consider their own
+This tool neutralizes loyalty cascades by fixing units who consider their own
 civilization to be the enemy.
 
 Usage
diff --git a/fix/loyaltycascade.lua b/fix/loyaltycascade.lua
index a3b7090880..b6ae0515ef 100644
--- a/fix/loyaltycascade.lua
+++ b/fix/loyaltycascade.lua
@@ -1,5 +1,7 @@
 -- Prevents a "loyalty cascade" (intra-fort civil war) when a citizen is killed.
 
+local makeown = reqscript('makeown')
+
 -- Checks if a unit is a former member of a given entity as well as it's
 -- current enemy.
 local function getUnitRenegade(unit, entity_id)
@@ -14,9 +16,9 @@ local function getUnitRenegade(unit, entity_id)
             goto skipentity
         end
 
-        if link_type ==  df.histfig_entity_link_type.FORMER_MEMBER then
+        if link_type == df.histfig_entity_link_type.FORMER_MEMBER then
             former_index = index
-        elseif link_type ==  df.histfig_entity_link_type.ENEMY then
+        elseif link_type == df.histfig_entity_link_type.ENEMY then
             enemy_index = index
         end
 
@@ -42,11 +44,7 @@ end
 local function fixUnit(unit)
     local fixed = false
 
-    if not dfhack.units.isOwnCiv(unit) or not dfhack.units.isDwarf(unit) then
-        return fixed
-    end
-
-    local unit_name = dfhack.TranslateName(dfhack.units.getVisibleName(unit))
+    local unit_name = dfhack.units.getReadableName(unit)
     local former_civ_index, enemy_civ_index = getUnitRenegade(unit, df.global.plotinfo.civ_id)
     local former_group_index, enemy_group_index = getUnitRenegade(unit, df.global.plotinfo.group_id)
 
@@ -57,7 +55,8 @@ local function fixUnit(unit)
 
         convertUnit(unit, df.global.plotinfo.civ_id, former_civ_index, enemy_civ_index)
 
-        dfhack.gui.showAnnouncement(('loyaltycascade: %s is now a member of %s again'):format(unit_name, civ_name), COLOR_WHITE)
+        dfhack.gui.showAnnouncement(
+            ('loyaltycascade: %s is now a happy member of %s again'):format(unit_name, civ_name), COLOR_WHITE)
 
         fixed = true
     end
@@ -67,31 +66,14 @@ local function fixUnit(unit)
 
         convertUnit(unit, df.global.plotinfo.group_id, former_group_index, enemy_group_index)
 
-        dfhack.gui.showAnnouncement(('loyaltycascade: %s is now a member of %s again'):format(unit_name, group_name), COLOR_WHITE)
+        dfhack.gui.showAnnouncement(
+            ('loyaltycascade: %s is now a happy member of %s again'):format(unit_name, group_name), COLOR_WHITE)
 
         fixed = true
     end
 
-    if fixed and unit.enemy.enemy_status_slot ~= -1 then
-        local status_cache = df.global.world.enemy_status_cache
-        local status_slot = unit.enemy.enemy_status_slot
-
-        unit.enemy.enemy_status_slot = -1
-        status_cache.slot_used[status_slot] = false
-
-        for index, _ in pairs(status_cache.rel_map[status_slot]) do
-            status_cache.rel_map[status_slot][index] = -1
-        end
-
-        for index, _ in pairs(status_cache.rel_map) do
-            status_cache.rel_map[index][status_slot] = -1
-        end
-
-        -- TODO: what if there were status slots taken above status_slot?
-        -- does everything need to be moved down by one?
-        if status_cache.next_slot > status_slot then
-            status_cache.next_slot = status_slot
-        end
+    if fixed then
+        makeown.clear_enemy_status(unit)
     end
 
     return false
diff --git a/makeown.lua b/makeown.lua
index 565b7c6856..73054f6ed3 100644
--- a/makeown.lua
+++ b/makeown.lua
@@ -59,6 +59,30 @@ local function fix_clothing_ownership(unit)
     unit.uniform.uniform_drop:resize(0)
 end
 
+function clear_enemy_status(unit)
+    if unit.enemy.enemy_status_slot <= -1 then return end
+
+    local status_cache = df.global.world.enemy_status_cache
+    local status_slot = unit.enemy.enemy_status_slot
+
+    unit.enemy.enemy_status_slot = -1
+    status_cache.slot_used[status_slot] = false
+
+    for index in ipairs(status_cache.rel_map[status_slot]) do
+        status_cache.rel_map[status_slot][index] = -1
+    end
+
+    for index in ipairs(status_cache.rel_map) do
+        status_cache.rel_map[index][status_slot] = -1
+    end
+
+    -- TODO: what if there were status slots taken above status_slot?
+    -- does everything need to be moved down by one to fill the gap?
+    if status_cache.next_slot > status_slot then
+        status_cache.next_slot = status_slot
+    end
+end
+
 local function fix_unit(unit)
     unit.flags1.marauder = false;
     unit.flags1.merchant = false;
@@ -82,6 +106,8 @@ local function fix_unit(unit)
 
     if  unit.profession == df.profession.MERCHANT then  unit.profession = df.profession.TRADER end
     if unit.profession2 == df.profession.MERCHANT then unit.profession2 = df.profession.TRADER end
+
+    clear_enemy_status(unit)
 end
 
 local function add_to_entity(hf, eid)