Skip to content
Merged
Changes from 8 commits
Commits
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
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
Comment thread
realSquidCoder marked this conversation as resolved.

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
Comment thread
realSquidCoder marked this conversation as resolved.
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!"
Comment thread
realSquidCoder marked this conversation as resolved.
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
Comment thread
realSquidCoder marked this conversation as resolved.
-- 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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is a very big loop. >750000 entries in my current fort's world, year 515.

Since a histfig has a .died_year field, you might be able to early-out with not-found ( nil, probably?) when you reach an event that occurred in the previous year.

You might even be able to get really clever and use a binary search to narrow down to the proper year's range.

This assumes that world.history.events is sorted by event date, which I believe but have not verified.

Speaking of that loop, this code implicitly returns nil when no matching event is found. The caller doesn't check for that.

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")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't like that an API function can deliberately crash.

Consider returning this string instead of calling qerror().

end

if not dfhack.units.isDead(histfig_unit) then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actually I would suggest not finding the unit at all, and testing histfig.died_year == -1 instead of not dfhack.units.isDead().

You would want to fold in the string formatting that is in getDeathEventHistFigUnit().

dfhack.units.getReadableName() accepts histfigs as well as units.

The only other use you have for a unit is to get the race, which is also in a histfig.

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