dfhack/scripts/gui/dfstatus.lua

230 lines
6.2 KiB
Lua

-- a quick access status screen
-- originally written by enjia2000@gmail.com (stolencatkarma)
--[[=begin
gui/dfstatus
============
Show a quick overview of critical stock quantities, including food, drinks, wood, and various bars.
Sections can be enabled/disabled/configured by editing ``dfhack-config/dfstatus.lua``.
=end]]
local gui = require 'gui'
function warn(msg)
dfhack.color(COLOR_LIGHTRED)
print(msg)
dfhack.color(nil)
end
config = {
flags = {
drink = true,
wood = true,
fuel = true,
prepared_meals = true,
tanned_hides = true,
cloth = true,
metals = true,
},
metal_ids = {},
}
function parse_config()
local metal_map = {}
for id, raw in pairs(df.global.world.raws.inorganics) do
if raw.material.flags.IS_METAL then
metal_map[raw.id:upper()] = id
metal_map[id] = raw.id:upper()
end
end
local function add_metal(...)
for _, m in pairs({...}) do
id = metal_map[tostring(m):upper()]
if id ~= nil then
table.insert(config.metal_ids, id)
elseif m == '-' then
table.insert(config.metal_ids, '-')
else
warn('Invalid metal: ' .. tostring(m))
end
end
return add_metal
end
local env = {}
setmetatable(env, {
__index = function(_, k)
if k == 'metal' or k == 'metals' then
return add_metal
elseif k == 'flags' then
return config.flags
else
error('unknown name: ' .. k, 2)
end
end,
__newindex = function(_, k, v)
if config.flags[k] ~= nil then
if v ~= nil then
config.flags[k] = v
else
config.flags[k] = false
end
else
error('unknown flag: ' .. k, 2)
end
end,
})
local f, err = loadfile('dfhack-config/dfstatus.lua', 't', env)
if not f then
qerror('error loading config: ' .. err)
end
local ok, err = pcall(f)
if not ok then
qerror('error parsing config: ' .. err)
end
end
function getInorganicName(id)
return (df.inorganic_raw.find(id).material.state_name.Solid:gsub('^[a-z]', string.upper))
end
dfstatus = defclass(dfstatus, gui.FramedScreen)
dfstatus.ATTRS = {
frame_style = gui.GREY_LINE_FRAME,
frame_title = 'dfstatus',
frame_width = 16,
frame_height = 17,
frame_inset = 1,
focus_path = 'dfstatus',
}
function dfstatus:init()
self.text = {}
self.start = 1
local function write(line)
table.insert(self.text, line)
-- ensure that the window is wide enough for this line plus a scroll arrow
if #line + 1 > self.frame_width then
self.frame_width = #line + 1
end
end
local function newline() write('') end
local f = config.flags
local drink = 0
local wood = 0
local fuel = 0
local prepared_meals = 0
local tanned_hides = 0
local cloth = 0
local metals = {}
for _, id in pairs(config.metal_ids) do
metals[id] = 0
end
for _, item in ipairs(df.global.world.items.all) do
if not item.flags.rotten and not item.flags.dump and not item.flags.forbid then
if item:getType() == df.item_type.WOOD then
wood = wood + item:getStackSize()
elseif item:getType() == df.item_type.DRINK then
drink = drink + item:getStackSize()
elseif item:getType() == df.item_type.SKIN_TANNED then
tanned_hides = tanned_hides + item:getStackSize()
elseif item:getType() == df.item_type.CLOTH then
cloth = cloth + item:getStackSize()
elseif item:getType() == df.item_type.FOOD then
prepared_meals = prepared_meals + item:getStackSize()
elseif item:getType() == df.item_type.BAR then
if item:getMaterial() == df.builtin_mats.COAL then
fuel = fuel + item:getStackSize()
elseif item:getMaterial() == df.builtin_mats.INORGANIC then
local mat_idx = item:getMaterialIndex()
if metals[mat_idx] ~= nil then
metals[mat_idx] = metals[mat_idx] + item:getStackSize()
end
end
end
end
end
if f.drink then
write("Drinks: " .. drink)
end
if f.prepared_meals then
write("Meals: " .. prepared_meals)
end
if f.drink or f.prepared_meals then
newline()
end
if f.wood then
write("Wood: " .. wood)
end
if f.fuel then
write("Fuel: " .. fuel)
end
if f.wood or f.fuel then
newline()
end
if f.tanned_hides then
write("Hides: " .. tanned_hides)
end
if f.cloth then
write("Cloth: " .. cloth)
end
if f.tanned_hides or f.cloth then
newline()
end
if f.metals then
write("Metal bars:")
for _, id in pairs(config.metal_ids) do
if id == '-' then
newline()
else
write(' ' .. ('%-10s'):format(getInorganicName(id) .. ': ') .. metals[id])
end
end
end
self.start_min = 1
self.start_max = #self.text - self.frame_height + 1
end
function dfstatus:onRenderBody(dc)
dc:pen(COLOR_LIGHTGREEN)
for id, line in pairs(self.text) do
if id >= self.start then
dc:string(line):newline()
end
end
dc:pen(COLOR_LIGHTCYAN)
if self.start > self.start_min then
dc:seek(self.frame_width - 1, 0):char(24)
end
if self.start < self.start_max then
dc:seek(self.frame_width - 1, self.frame_height - 1):char(25)
end
end
function dfstatus:onInput(keys)
if keys.LEAVESCREEN or keys.SELECT then
self:dismiss()
scr = nil
elseif keys.STANDARDSCROLL_UP then
self.start = math.max(self.start - 1, self.start_min)
elseif keys.STANDARDSCROLL_DOWN then
self.start = math.min(self.start + 1, self.start_max)
end
end
if not scr then
parse_config()
scr = dfstatus()
scr:show()
else
scr:dismiss()
scr = nil
end