diff --git a/changelog.txt b/changelog.txt index 81eff7583..90278e713 100644 --- a/changelog.txt +++ b/changelog.txt @@ -34,6 +34,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 7a1eaad62..39899aae3 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 a3b709088..b6ae0515e 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 565b7c685..73054f6ed 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)