DFHack / dfhack

Memory hacking library for Dwarf Fortress and a set of tools that use it
Other
1.86k stars 471 forks source link

Proper Burial of Reanimated Dwarf Corpses #3806

Open Halifay opened 1 year ago

Halifay commented 1 year ago

Description: Reanimated dwarf corpses cannot be appropriately buried because their body parts are placed on top of coffins rather than inside them. This results in repeated hauling of these parts between refuse stockpiles and the tomb. The root of this issue lies in the is_dead_dwarf flag, which is incorrectly set to false after reanimation. My tests have shown that iterating over the list of all corpse parts and assigning the is_dead_dwarf flag to parts of dwarves resolves this problem, enabling the proper burial of reanimated dwarf corpses.

Suggestion: Consider implementing a plugin that periodically resets the is_dead_dwarf flag, ensuring that corpses are buried as intended, either at regular intervals or when a dwarf passes away.

Halifay commented 1 year ago

I came up with the following script to set is_dead_dwarf flag for dwarves and pets to true. I am not sure if it works well with siege animals that have names but I presume they have no owner. It also doesn't include non-dwarf citizens (all dwarves regardless affiliation have flag set to true as well).

local utils = require 'utils'

print("Invoking fix_dead_dwarves")
for _, corpses in ipairs(df.global.world.items.other.ANY_CORPSE) do
    unit_id = corpses.unit_id
    local unit = df.unit.find(unit_id)
    if unit then
        -- Only check those that are not marked
        if corpses.flags.dead_dwarf == false then
            local hf_id = unit.hist_figure_id
            local hf = df.historical_figure.find(hf_id) -- get the historical figure object
            if not hf then
                hf_id = unit.hist_figure_id2
                hf = df.historical_figure.find(hf_id)
            end

            -- check if the historical figure exists
            if hf ~= nil then

                local player_civ_id = df.global.world.world_data.active_site[0].civ_id
                local hf_civ_id = hf.civ_id

                -- Check if was/is a citizen
                -- Currenlty just selecting dwarves. Problem distinguishing between named enemies and citizens
                -- if hf_civ_id == player_civ_id and dfhack.units.isDwarf(unit) then
                if dfhack.units.isDwarf(unit) then
                    corpses.flags.dead_dwarf = true
                    print('dead_dwarf flag of a citizen '..dfhack.TranslateName(hf.name)..' was set to true.')
                else
                    -- loop through the relations
                    -- Check if was/is a pet
                    for i, link in ipairs(hf.histfig_links) do
                        -- get the type of the relation
                        local link_type = link:getType()
                        -- presuming that 13 is relation of pet to its owner
                        if link_type == 13 then
                            corpses.flags.dead_dwarf = true
                            print('dead_dwarf flag of a pet '..dfhack.TranslateName(hf.name)..' was set to true.')
                            break
                        end
                    end
                end
            end
        end
    end
end
myk002 commented 12 months ago

Could you open a PR for this script so we can discuss?