v50 Steam/Premium information for editors
- v50 information can now be added to pages in the main namespace. v0.47 information can still be found in the DF2014 namespace. See here for more details on the new versioning policy.
- Use this page to report any issues related to the migration.
This notice may be cached—the current version can be found here.
User:Fleeting Frames/listobituary
Jump to navigation
Jump to search
Requires gui/indicator-screen, run when viewing dead units list, outputs deadcounts.csv into the folder that sorts number of deaths by category and date
--Death listing shower
--[===[
listobituary
============
Displays the death date and cause in unitlist/Dead
]===]
local saveToFileEnabled = false
local indipresent, indi = pcall(function() return dfhack.script_environment('gui/indicator_screen') end)
if not indipresent then qerror("this script required gui/indicator_screen") end
function categorizeUnit(unit)
if(df.global.world.raws.creatures.all[unit.race].flags.GENERATED) then return "Procedurals" end
--in case of procedural invaders
if(unit.flags1.invader_origin or unit.flags1.invades) then return "Invaders" end
if(dfhack.units.isMerchant(unit) or (unit.flags3.unk31 and unit.flags2.visitor) ) then return "Visitors" end
--unk31 is "guest" toggle.
if(dfhack.units.isOwnCiv(unit) and
( (unit.profession>74 and unit.profession<98) or
unit.profession == 110
or unit.profession == 65)) then return "Military" end
--Profession is military profession or Mercenary or Administrator; not ideal but what is better?
if(dfhack.units.isOwnCiv(unit) and (dfhack.units.isTamable(unit) or dfhack.units.isDomesticated(unit))) then return "Livestock" end
--higher specific matches above less specific ones
if(dfhack.units.isOwnCiv(unit)) then return "Fort" end
--For covering both workers and residents here.
if( (dfhack.units.isTamable(unit) or not df.global.world.raws.creatures.all[unit.race].caste[unit.caste].flags.CAN_LEARN)) then return "Animals" end
--Not learning but not tamable: Unicorns, some evil and cavern creatures.
if(df.global.world.raws.creatures.all[unit.race].flags.CASTE_CAN_LEARN) then return "Savages" end
--Covers animalmen, gremlins, current resident cave people and camp goblins
end
function saveToFile(deadlist, deathdates, cumulative)
if saveToFileEnabled then
local file, err = io.open((dfhack.getDFPath() .. "/deadcounts.csv"), "wb")
local outT,outTi = {}
outTb = {Date =0, in_years =0, Total =0, Fort =0, Military =0, Livestock =0, Animals =0, Procedurals =0, Invaders =0, Visitors =0, Savages=0}
outTi = copyall(outTb)
for index = 0, #deadlist-1 do
if index == 0 or outTi["Date"] ~= deathdates[index+1].text then
if index ~= 0 then table.insert(outT,outTi)
outTi = cumulative and copyall(outTi) or copyall(outTb) end
outTi["Date"] = deathdates[index+1].text
outTi["in_years"] = outTi["Date"]:find("Unknown") and "Unknown" or (outTi["Date"]:sub(1,4)+(outTi["Date"]:sub(6,7)-1)/12+(outTi["Date"]:sub(9,10)/(12*28)))
end
outTi["Total"] = outTi["Total"] + 1
if categorizeUnit(deadlist[index]) then
outTi[categorizeUnit(deadlist[index])] = outTi[categorizeUnit(deadlist[index])] + 1
else
print("No category for " .. df.global.world.raws.creatures.all[unit.race].creature_id .. " " .. dfhack.TranslateName(unit.name,true) " id " .. unit.id)
end
end
table.insert(outT,outTi) --last element
file:write("Date;in years;Total;Fort;Military;Livestock;Animals;Procedurals;Invaders;Visitors;Savages")
file:write(NEWLINE)
local optionorder= {}
table.insert(optionorder,"Date")
table.insert(optionorder,"in_years")
table.insert(optionorder,"Total")
table.insert(optionorder,"Fort")
table.insert(optionorder,"Military")
table.insert(optionorder,"Livestock")
table.insert(optionorder,"Animals")
table.insert(optionorder,"Procedurals")
table.insert(optionorder,"Invaders")
table.insert(optionorder,"Visitors")
table.insert(optionorder,"Savages")
for index = 1, #outT do
for oindex=1,#optionorder do
file:write((tostring(outT[index][optionorder[oindex]]) .. ";"))
end
file:write(NEWLINE)
end
file:flush()
file:close()
end
end
function getBottomMostViewscreenWithFocus(text, targetscreeni)
--Finds and returns the screen closest to root screen whose path includes text
local targetscreen = targetscreeni or df.global.gview.view.child
--if the target screen wasn't included, starts looking from the bottom
if targetscreen and
dfhack.gui.getFocusString(targetscreen):find(text) then
return targetscreen
elseif targetscreen and targetscreen.child then --Attempting to call nil.child will crash this
return getBottomMostViewscreenWithFocus(text, targetscreen.child)
end
-- if there's no child, it didn't find a screen with text in focus and returns nil
end
orbituarylist = orbituarylist or {}
local unitscreen = getBottomMostViewscreenWithFocus("unitlist/Dead")
if not unitscreen then
qerror("This script requires you to view dead units list")
else
print(#unitscreen.units.Dead)
local pagelength = df.global.gps.dimy - 9
local list_rect = {x = 86, y = 4, width = 13, height = pagelength}
local currentpage = math.floor(unitscreen.cursor_pos.Dead / pagelength)
orbituarylist.color=6
if #orbituarylist<#unitscreen.units.Dead then --refreshing things
for index=#orbituarylist, #unitscreen.units.Dead-1 do
table.insert(orbituarylist,{text = dfhack.run_command_silent("deathcause " .. unitscreen.units.Dead[index].id):sub(4,16):match('%d+-%d+-%d+') or "Unknown"})
dfhack.println(index, orbituarylist[index].text)
--[[if(categorizeUnit(unitscreen.units.Dead[index])) then
print("unit's category is " .. categorizeUnit(unitscreen.units.Dead[index]))
else
print("No category for " .. df.global.world.raws.creatures.all[unitscreen.units.Dead[index].race].creature_id .. " " .. dfhack.TranslateName(unitscreen.units.Dead[index].name,true) .. " id " .. unitscreen.units.Dead[index].id)
end--]]
end
end
saveToFile(unitscreen.units.Dead, orbituarylist, false)
local newscreen = indi.getScreen(orbituarylist, list_rect, nil)
local baseonInput = newscreen.onInput
newscreen.onInput = function(self, keys)
baseonInput(self,keys)
if ((keys._MOUSE_L or keys._MOUSE_L_DOWN) or
(keys._MOUSE_R or keys._MOUSE_R_DOWN)) then
df.global.gview.view.child.child.cursor_pos = (df.global.gps.mouse_y-2+currentpage*pagelength)
end
if currentpage ~= math.floor(df.global.gview.view.child.child.cursor_pos.Dead / pagelength) then
currentpage = math.floor(df.global.gview.view.child.child.cursor_pos.Dead / pagelength)
self.frame_body.y1 = 4-currentpage*pagelength --Hacky, but directly setting rect won't work due rollover. Might want to update indicator-screen for map scrolling.
end
end
local baseOnResize = newscreen.onResize
newscreen.onResize = function(self)
baseOnResize(self)
if pagelength ~= (df.global.gps.dimy - 7) then
--If window length changed, better refresh the data.
pagelength = df.global.gps.dimy - 7
self:adjustDims(true,list_rect.x, list_rect.y,(df.global.gps.dimx-4), pagelength)
--Not adjusting height here would result in situation where making screen shorter works, but taller not.
self.frame_body.y1 = 4-currentpage*pagelength
end
end
newscreen:show()
end