From f1391b63e2beae0bc0ec13d44f0a42557fc681b3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 3 Sep 2015 15:02:08 -0400 Subject: [PATCH] dfstatus: Allow sections and metal bars to be customized --- NEWS | 1 + Readme.rst | 1 + dfhack-config/dfstatus.lua | 28 +++++ scripts/gui/dfstatus.lua | 244 +++++++++++++++++++++++++++---------- 4 files changed, 207 insertions(+), 67 deletions(-) create mode 100644 dfhack-config/dfstatus.lua diff --git a/NEWS b/NEWS index be8be21cd..dd2acc430 100644 --- a/NEWS +++ b/NEWS @@ -67,6 +67,7 @@ DFHack Future - widgets' positions, formats, etc. are now customizable (see Readme) - weather display now separated from the date display - New mouse cursor widget + dfstatus: Can enable/disable individual categories and customize metal bar list full-heal: "-r" option removes corpses gui/gm-editor - Pointers can now be displaced diff --git a/Readme.rst b/Readme.rst index bb8e2bf7f..dea56d40e 100644 --- a/Readme.rst +++ b/Readme.rst @@ -2365,6 +2365,7 @@ directory. * 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``. * gui/stockpiles diff --git a/dfhack-config/dfstatus.lua b/dfhack-config/dfstatus.lua new file mode 100644 index 000000000..f1e087d2f --- /dev/null +++ b/dfhack-config/dfstatus.lua @@ -0,0 +1,28 @@ +-- dfstatus config +-- the dfstatus script can be found in hack/scripts/gui/ +--[[ +The following variables can be set to true/false to enable/disable categories (all true by default) +* drink +* wood +* fuel +* prepared_meals +* tanned_hides +* cloth +* metals + +Example: +drink = false +fuel = true + +To add metals: +* metal 'IRON' +* metals "GOLD" 'SILVER' +* metal('COPPER') +* metals("BRONZE", 'HORN_SILVER') +Use '-' for a blank line: +* metal '-' +]] + +metals 'IRON' 'PIG_IRON' 'STEEL' +metals '-' +metals 'GOLD' 'SILVER' 'COPPER' diff --git a/scripts/gui/dfstatus.lua b/scripts/gui/dfstatus.lua index 8d7ceeb27..32758cfbf 100644 --- a/scripts/gui/dfstatus.lua +++ b/scripts/gui/dfstatus.lua @@ -1,8 +1,87 @@ --- dfstatus 1.5 - a quick access status screen. --- originally written by enjia2000@gmail.com +-- a quick access status screen +-- originally written by enjia2000@gmail.com (stolencatkarma) 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, @@ -13,95 +92,126 @@ dfstatus.ATTRS = { focus_path = 'dfstatus', } -function dfstatus:onRenderBody(dc) +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 meat = 0 - --local raw_fish = 0 - --local plants = 0 - local prepared_meals = 0 - local fuel = 0 - local pigiron = 0 - local iron = 0 - local steel = 0 - - local silver = 0 - local copper = 0 - local gold = 0 - local tannedhides = 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 tannedhides = tannedhides + item:getStackSize() - elseif (item:getType() == df.item_type.CLOTH) then cloth = cloth + item:getStackSize() - --elseif (item:getType() == df.item_type.MEAT) then meat = meat + item:getStackSize() - --elseif (item:getType() == df.item_type.FISH_RAW) then raw_fish = raw_fish + item:getStackSize() - --elseif (item:getType() == df.item_type.PLANT) then plants = plants + item:getStackSize() - elseif (item:getType() == df.item_type.FOOD) then prepared_meals = prepared_meals + item:getStackSize() - elseif (item:getType() == df.item_type.BAR) then - for token in string.gmatch(dfhack.items.getDescription(item,0),"[^%s]+") do - if (token == "silver") then silver = silver + item:getStackSize() - elseif (token == "charcoal" or token == "coke") then fuel = fuel + item:getStackSize() - elseif (token == "iron") then iron = iron + item:getStackSize() - elseif (token == "pig") then pigiron = pigiron + item:getStackSize() - elseif (token == "copper") then copper = copper + item:getStackSize() - elseif (token == "gold") then gold = gold + item:getStackSize() - elseif (token == "steel") then steel = steel + item:getStackSize() + 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 - break -- only need to look at the 1st token of each item. 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) - dc:string("Drinks: " .. drink) - dc:newline(0) - dc:string("Meals: " .. prepared_meals) - dc:newline(0) - dc:newline(0) - dc:string("Wood: " .. wood) - dc:newline(0) - dc:newline(0) - dc:string("Hides: " .. tannedhides) - dc:newline(0) - dc:string("Cloth: " .. cloth) - dc:newline(0) - -- dc:string("Raw Fish: ".. raw_fish) - -- dc:newline(0) - -- dc:string("Plants: ".. plants) - -- dc:newline(0) - dc:newline(0) - dc:string("Bars:") - dc:newline(1) - dc:string("Fuel: " .. fuel) - dc:newline(1) - dc:string("Pig Iron: " .. pigiron) - dc:newline(1) - dc:string("Steel: " .. steel) - dc:newline(1) - dc:string("Iron: " .. iron) - dc:newline(1) - dc:newline(1) - dc:string("Copper: " .. copper) - dc:newline(1) - dc:string("Silver: " .. silver) - dc:newline(1) - dc:string("Gold: " .. gold) + 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