Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
86e636f
Add entomb.lua and docs/entomb.rst
amade-w Jul 15, 2025
f684542
Update changelog.txt to add new tool: entomb
amade-w Jul 15, 2025
07594b5
Apply revisions to entomb.lua according to PR comments
amade-w Jul 16, 2025
0f75b56
Apply 2nd revision to entomb.lua: improve PutInCoffin()
amade-w Jul 16, 2025
36b7771
entomb.lua Implement a function that creates a job to haul an item to…
SilasD Jul 18, 2025
b359cba
entomb.lua Very Important Bugfix completely assign unit to tomb.
SilasD Jul 19, 2025
6a185fd
entomb.lua Update the unit's owned buildings with the newly-assigned …
SilasD Jul 20, 2025
a2f4548
Undo commit b359cbaa4c7ea3b62da9ccea24ca3fdf6e025581
SilasD Jul 23, 2025
3c62cda
Merge pull request #1 from SilasD/entomb
SilasD Jul 23, 2025
25714bf
Add function to validate moving items, separate job removal into own …
amade-w Jul 25, 2025
7952e13
Assign new name to unnamed tombs during assignment
amade-w Jul 25, 2025
f484912
Move logic to call HaulToCoffin() and TeleportToCoffin() into new fun…
amade-w Jul 25, 2025
ba5e5d1
Implement add-item option, revise Main() logic, switch to use argpars…
amade-w Jul 28, 2025
e11d968
Disable teleport function, update documentation
amade-w Jul 28, 2025
8f4feca
Fix argparse short-form conflict
amade-w Jul 29, 2025
785741b
Fix documentation
amade-w Jul 29, 2025
062ef18
Assign only active tomb zones and make it unavailable for auto assigm…
amade-w Aug 13, 2025
5f1c7b7
Remove duplicated code in IterateTombZones()
amade-w Aug 13, 2025
c343176
Merge branch 'master' into entomb
amade-w Aug 17, 2025
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
61 changes: 61 additions & 0 deletions docs/entomb.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
entomb
======

.. dfhack-tool::
:summary: Entomb any corpse into tomb zones.
:tags: fort items buildings

Assign any corpse regardless of citizenship, residency, pet status,
or affiliation to an unassigned tomb zone for burial.

Usage
-----

``entomb [<options>]``

This script must be executed with either a unit's corpse or body part
selected or with a unit ID specified. An unassigned tomb zone will then
be assigned to the unit for burial and all its corpse and/or body parts
will become valid items for interment.

Optionally, the zone ID may also be specified to assign a specific tomb
zone to the unit.

A non-citizen, non-resident, or non-pet unit that is still alive may
even be assigned a tomb zone if they have lost any body part that can
be placed inside a tomb, e.g. teeth or severed limbs. New corpse items
after a tomb has already been assigned will not be properly interred
until the script is executed again on either the unit, its corpse, or
any of its body parts.

If executed on slaughtered animals, all its butchering returns will
become valid burial items and no longer usable for cooking or crafting.

Examples
--------

``entomb unit <id>``
Assign an unassigned tomb zone to the unit with the specified ID.

``entomb tomb <id>``
Assign a tomb zone with the specified ID to the selected corpse
item's unit.

``entomb unit <id> tomb <id> now``
Assign a tomb zone with the specified ID to the unit with the
specified ID and teleport its corpse and/or body parts into the
coffin in the tomb zone.

Options
-------

``unit <id>``
Specify the ID of the unit to be assigned to a tomb zone.

``tomb <id>``
Specify the ID of the zone into which a unit will be interred.

``now``
Instantly teleport the unit's corpse and/or body parts into the
coffin of its assigned tomb zone. This option can be called on
corpse items or units that are already assigned a tomb zone.
193 changes: 193 additions & 0 deletions entomb.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
-- Entomb corpse items of any dead unit.
Comment thread
amade-w marked this conversation as resolved.
--@module = true

local utils = require('utils')

local unit_id
Comment thread
amade-w marked this conversation as resolved.
Outdated
local unit
local building_id
local tomb
local forceBurial

local args = {...}

-- Get unit from selected corpse or corpse piece item.
local function GetUnitFromCorpse()
Comment thread
amade-w marked this conversation as resolved.
Outdated
local item = dfhack.gui.getSelectedItem(true)
if item then
if df.item_corpsest:is_instance(item) or df.item_corpsepiecest:is_instance(item) then
unit_id = item.unit_id
Comment thread
amade-w marked this conversation as resolved.
Outdated
unit = df.unit.find(unit_id)
else
qerror('Selected item is not a corpse or body part.')
end
else
qerror('No item selected or unit specified.')
end
end
Comment thread
amade-w marked this conversation as resolved.

-- Validate tomb zone assignment.
local function CheckTombZone(building, id)
Comment thread
amade-w marked this conversation as resolved.
Outdated
if df.building_civzonest:is_instance(building) then
if building.type == 97 then
Comment thread
amade-w marked this conversation as resolved.
Outdated
if building.assigned_unit_id == id then
return true
end
end
end
end
Comment thread
amade-w marked this conversation as resolved.

-- Iterate through all available tomb zones.
local function IterateTombZone(id)
Comment thread
amade-w marked this conversation as resolved.
Outdated
for _, building in pairs(df.global.world.buildings.all) do
Comment thread
amade-w marked this conversation as resolved.
Outdated
if CheckTombZone(building, id) then return building end
end
end
Comment thread
amade-w marked this conversation as resolved.

-- Check if any of the unit's corpse items are still not in a coffin.
local function isNotBuried()
Comment thread
amade-w marked this conversation as resolved.
Outdated
for _, item_id in pairs(unit.corpse_parts) do
local item = df.item.find(item_id)
if item then
local inCoffin = dfhack.items.getGeneralRef(item, df.general_ref_type.BUILDING_HOLDER)
local coffinBuilding_id = inCoffin and inCoffin.building_id or nil
Comment thread
amade-w marked this conversation as resolved.
Outdated
local coffin = coffinBuilding_id and df.building.find(coffinBuilding_id) or nil
local isCoffin = coffin and df.building_coffinst:is_instance(coffin) or nil
Comment thread
amade-w marked this conversation as resolved.
Outdated
-- Return TRUE if even one item is not interred.
if not isCoffin then
return true
end
end
end
end
Comment thread
amade-w marked this conversation as resolved.

local function GetEmptyTombZone()
Comment thread
amade-w marked this conversation as resolved.
Outdated
-- Check if unit is already assigned to a tomb zone.
local isAlreadyAssigned = IterateTombZone(unit_id)
if isAlreadyAssigned then
if isNotBuried() or forceBurial then
tomb = isAlreadyAssigned
print('Unit is already assigned to a tomb zone but may still have uninterred corpse or body part(s).')
else
qerror('Unit is already interred in a tomb zone.')
Comment thread
amade-w marked this conversation as resolved.
Outdated
end
else
-- Find an unassigned tomb zone.
tomb = IterateTombZone(-1)
end
if not tomb then
qerror('No unassigned tomb zones are available.')
end
end
Comment thread
amade-w marked this conversation as resolved.

-- Set corpse items to be valid for burial.
local function FlagForBurial(corpseParts)
Comment thread
amade-w marked this conversation as resolved.
Outdated
-- Undead units have empty corpse_parts vector.
if unit.enemy.undead then
for _, item in pairs(df.global.world.items.other.IN_PLAY) do
Comment thread
amade-w marked this conversation as resolved.
Outdated
if df.item_corpsest:is_instance(item) or df.item_corpsepiecest:is_instance(item) then
if item.unit_id == unit_id then
corpseParts:insert(#corpseParts, item.id)
Comment thread
amade-w marked this conversation as resolved.
Outdated
end
end
end
utils.sort_vector(corpseParts)
Comment thread
amade-w marked this conversation as resolved.
Outdated
end
local burialItemCount = 0
for _, item_id in pairs(corpseParts) do
local item = df.item.find(item_id)
if item then
item.flags.dead_dwarf = true
-- Some corpse items may be lost/destroyed before burial.
burialItemCount = burialItemCount + 1
end
end
if burialItemCount == 0 then
qerror('Unit has no corpse or body parts available for burial.')
end
tomb.assigned_unit_id = unit_id
return burialItemCount
end

local function PutInCoffin(corpseParts)
Comment thread
amade-w marked this conversation as resolved.
Outdated
local coffin
for _, building in pairs(tomb.contained_buildings) do
if df.building_coffinst:is_instance(building) then coffin = building end
end
if coffin then
-- Set df.building_item_role_type.PERM first before changing
-- it to TEMP to turn it into an interred corpse item.
for _, item_id in pairs(corpseParts) do
local item = df.item.find(item_id)
if item then
dfhack.items.moveToBuilding(item, coffin, 2)
Comment thread
amade-w marked this conversation as resolved.
Outdated
end
end
for _, buildingItem in pairs(coffin.contained_items) do
local item = buildingItem.item
if not df.item_coffinst:is_instance(item) then
buildingItem.use_mode = 0
Comment thread
amade-w marked this conversation as resolved.
Outdated
end
end
print('Corpse items have been teleported into a coffin.')
else
print('No coffin in the assigned tomb zone.\nCorpse items will not be teleported into the tomb zone.')
end
end

local function AssignToTomb()
Comment thread
amade-w marked this conversation as resolved.
Outdated
local corpseParts = unit.corpse_parts
local strBurial = '%s assigned to a tomb zone for burial.'
local strCorpseItems = '(%d corpse or body part%s)'
local strUnitName = unit and dfhack.units.getReadableName(unit)
local strPlural = ''
local incident_id = unit.counters.death_id
if incident_id ~= -1 then
local incident = df.incident.find(incident_id)
-- Corpse will not be interred if not yet discovered.
incident.flags.discovered = true
end
local burialItemCount = FlagForBurial(corpseParts)
print(string.format(strBurial, strUnitName))
if forceBurial then PutInCoffin(corpseParts) end
if burialItemCount > 1 then strPlural = 's' end
print(string.format(strCorpseItems, burialItemCount, strPlural))
end

local function parseArgs()
Comment thread
amade-w marked this conversation as resolved.
Outdated
local building
if #args > 0 then
for i, v in ipairs(args) do
if v == 'unit' then
unit_id = tonumber(args[i+1]) or nil
unit = unit_id and df.unit.find(unit_id)
if not unit then qerror('Invalid unit ID.') end
end
if v == 'tomb' then
building_id = tonumber(args[i+1]) or nil
Comment thread
amade-w marked this conversation as resolved.
Outdated
building = building_id and df.building.find(building_id)
if not building then qerror('Invalid zone ID.') end
-- Check if tomb zone is unassigned.
if CheckTombZone(building, -1) then
tomb = building
else
qerror('Specified zone ID does not point to an unassigned tomb zone.')
end
end
if v == 'now' then forceBurial = true end
end
end
end

local function Main()
Comment thread
amade-w marked this conversation as resolved.
Outdated
parseArgs()
Comment thread
amade-w marked this conversation as resolved.
Outdated
if not unit then GetUnitFromCorpse() end
if unit then
if not tomb then GetEmptyTombZone() end
if tomb then AssignToTomb() end
end
end

if not dfhack_flags.module then
Main()
Comment thread
amade-w marked this conversation as resolved.
Outdated
end