Skip to content

make deathcause an api for getting the cause of death #1434

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Template for new versions:
## New Tools

## New Features
- `deathcause`: added functionality to this script to fetch cause of death programatically

## Fixes

Expand Down
38 changes: 22 additions & 16 deletions deathcause.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
-- show death cause of a creature
--@ module = true

local DEATH_TYPES = reqscript('gui/unit-info-viewer').DEATH_TYPES

-- Gets the first corpse item at the given location
function getItemAtPosition(pos)
local function getItemAtPosition(pos)
for _, item in ipairs(df.global.world.items.other.ANY_CORPSE) do
if item.pos.x == pos.x and item.pos.y == pos.y and item.pos.z == pos.z then
Copy link
Contributor

@Bumber64 Bumber64 Jun 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not important, but this check can be if same_xyz(pos, item.pos) then.

print("Automatically chose first corpse at the selected location.")
Expand All @@ -12,25 +13,25 @@ function getItemAtPosition(pos)
end
end

function getRaceNameSingular(race_id)
local function getRaceNameSingular(race_id)
return df.creature_raw.find(race_id).name[0]
end

function getDeathStringFromCause(cause)
local function getDeathStringFromCause(cause)
if cause == -1 then
return "died"
else
return DEATH_TYPES[cause]:trim()
end
end

function displayDeathUnit(unit)
-- Returns a cause of death given a unit
function getDeathCauseFromUnit(unit)
local str = unit.name.has_name and '' or 'The '
str = str .. dfhack.units.getReadableName(unit)

if not dfhack.units.isDead(unit) then
print(dfhack.df2console(str) .. " is not dead yet!")
return
return str .. " is not dead yet!"
end

str = str .. (" %s"):format(getDeathStringFromCause(unit.counters.death_cause))
Expand All @@ -50,20 +51,20 @@ function displayDeathUnit(unit)
end
end

print(dfhack.df2console(str) .. '.')
return str .. '.'
end

-- returns the item description if the item still exists; otherwise
-- returns the weapon name
function getWeaponName(item_id, subtype)
local function getWeaponName(item_id, subtype)
local item = df.item.find(item_id)
if not item then
return df.global.world.raws.itemdefs.weapons[subtype].name
end
return dfhack.items.getDescription(item, 0, false)
end

function displayDeathEventHistFigUnit(histfig_unit, event)
local function getDeathEventHistFigUnit(histfig_unit, event)
local str = ("The %s %s %s in year %d"):format(
getRaceNameSingular(histfig_unit.race),
dfhack.translation.translateName(dfhack.units.getVisibleName(histfig_unit)),
Expand All @@ -87,11 +88,11 @@ function displayDeathEventHistFigUnit(histfig_unit, event)
end
end

print(dfhack.df2console(str) .. '.')
return str .. '.'
end

-- Returns the death event for the given histfig or nil if not found
function getDeathEventForHistFig(histfig_id)
local function getDeathEventForHistFig(histfig_id)
for i = #df.global.world.history.events - 1, 0, -1 do
local event = df.global.world.history.events[i]
if event:getType() == df.history_event_type.HIST_FIGURE_DIED then
Expand All @@ -102,17 +103,18 @@ function getDeathEventForHistFig(histfig_id)
end
end

function displayDeathHistFig(histfig)
-- Returns the cause of death given a histfig
function getDeathCauseFromHistFig(histfig)
local histfig_unit = df.unit.find(histfig.unit_id)
if not histfig_unit then
qerror("Cause of death not available")
end

if not dfhack.units.isDead(histfig_unit) then
print(("%s is not dead yet!"):format(dfhack.df2console(dfhack.units.getReadableName(histfig_unit))))
return ("%s is not dead yet!"):format(dfhack.units.getReadableName(histfig_unit))
else
local death_event = getDeathEventForHistFig(histfig.id)
displayDeathEventHistFigUnit(histfig_unit, death_event)
return getDeathEventHistFigUnit(histfig_unit, death_event)
end
end

Expand Down Expand Up @@ -147,6 +149,10 @@ local function get_target()
return selected_item.hist_figure_id, df.unit.find(selected_item.unit_id)
end

if dfhack_flags.module then
return
end

local hist_figure_id, selected_unit = get_target()

if not hist_figure_id then
Expand All @@ -155,7 +161,7 @@ elseif hist_figure_id == -1 then
if not selected_unit then
qerror("Cause of death not available")
end
displayDeathUnit(selected_unit)
print(dfhack.df2console(getDeathCauseFromUnit(selected_unit)))
else
displayDeathHistFig(df.historical_figure.find(hist_figure_id))
print(dfhack.df2console(getDeathCauseFromHistFig(df.historical_figure.find(hist_figure_id))))
end
26 changes: 26 additions & 0 deletions docs/deathcause.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,29 @@ Usage
::

deathcause

API
---

The ``deathcause`` script can be called programmatically by other scripts, either via the
commandline interface with ``dfhack.run_script()`` or via the API functions
defined in :source-scripts:`deathcause.lua`, available from the return value of
``reqscript('deathcause')``:

* ``getDeathCauseFromHistFig(histfig)``

Returns a string with the historical figure's cause of death, sometimes with more information
than with a unit.

* ``getDeathCauseFromUnit(unit)``

Returns a string with the unit's cause of death.

API usage example::

local dc = reqscript('deathcause')

-- Note: this is an arguably bad example because this is the same as running deathcause
-- from the launcher, but this would theoretically still work.
local deathReason = dc.getDeathCauseFromUnit(dfhack.gui.getSelectedUnit())
print(deathReason)