dfhack/plugins/lua/logistics.lua

168 lines
6.0 KiB
Lua

local _ENV = mkmodule('plugins.logistics')
local argparse = require('argparse')
local utils = require('utils')
local function make_stat(name, stockpile_number, stats, configs)
return {
enabled=configs[stockpile_number] and configs[stockpile_number][name] == 'true',
designated=stats[name..'_designated'][stockpile_number] or 0,
can_designate=stats[name..'_can_designate'][stockpile_number] or 0,
}
end
function getStockpileData()
local stats, configs = logistics_getStockpileData()
local data = {}
for _,bld in ipairs(df.global.world.buildings.other.STOCKPILE) do
local stockpile_number, name = bld.stockpile_number, bld.name
local sort_key = tostring(name):lower()
if #name == 0 then
name = ('Stockpile #%d'):format(bld.stockpile_number)
sort_key = ('stockpile #%09d'):format(bld.stockpile_number)
end
table.insert(data, {
stockpile_number=stockpile_number,
name=name,
sort_key=sort_key,
melt=make_stat('melt', stockpile_number, stats, configs),
trade=make_stat('trade', stockpile_number, stats, configs),
dump=make_stat('dump', stockpile_number, stats, configs),
train=make_stat('train', stockpile_number, stats, configs),
melt_masterworks=configs[stockpile_number] and configs[stockpile_number].melt_masterworks == 'true',
})
end
table.sort(data, function(a, b) return a.sort_key < b.sort_key end)
return data
end
local function print_stockpile_data(data)
local name_len = 4
for _,sp in ipairs(data) do
name_len = math.min(40, math.max(name_len, #sp.name))
end
local has_melt_mastworks = false
print('Designated/designatable items in stockpiles:')
print()
local fmt = '%6s %-' .. name_len .. 's %4s %10s %5s %11s %4s %10s %5s %11s';
print(fmt:format('number', 'name', 'melt', 'melt items', 'trade', 'trade items', 'dump', 'dump items', 'train', 'train items'))
local function uline(len) return ('-'):rep(len) end
print(fmt:format(uline(6), uline(name_len), uline(4), uline(10), uline(5), uline(11), uline(4), uline(10), uline(5), uline(11)))
local function get_enab(stats, ch) return ('[%s]'):format(stats.enabled and (ch or 'x') or ' ') end
local function get_dstat(stats) return ('%d/%d'):format(stats.designated, stats.designated + stats.can_designate) end
for _,sp in ipairs(data) do
has_melt_mastworks = has_melt_mastworks or sp.melt_masterworks
print(fmt:format(sp.stockpile_number, sp.name, get_enab(sp.melt, sp.melt_masterworks and 'X'), get_dstat(sp.melt),
get_enab(sp.trade), get_dstat(sp.trade), get_enab(sp.dump), get_dstat(sp.dump), get_enab(sp.train), get_dstat(sp.train)))
end
if has_melt_mastworks then
print()
print('An "X" in the "melt" column indicates that masterworks in the stockpile will be melted.')
end
end
local function print_status()
print(('logistics is %sactively monitoring stockpiles and marking items')
:format(isEnabled() and '' or 'not '))
if df.global.gamemode ~= df.game_mode.DWARF or not dfhack.isMapLoaded() then
return
end
local data = getStockpileData()
print()
if not data[1] then
print 'No stockpiles defined -- go make some!'
else
print_stockpile_data(data)
end
local global_stats = logistics_getGlobalCounts()
print()
print(('Total items marked for melting: %5d'):format(global_stats.total_melt))
print(('Total items marked for trading: %5d'):format(global_stats.total_trade))
print(('Total items marked for dumping: %5d'):format(global_stats.total_dump))
print(('Total animals marked for training: %2d'):format(global_stats.total_train))
end
local function for_stockpiles(opts, fn)
if not opts.sp then
local selected_sp = dfhack.gui.getSelectedStockpile()
if not selected_sp then qerror('please specify or select a stockpile') end
fn(selected_sp.stockpile_number)
return
end
for _,sp in ipairs(argparse.stringList(opts.sp)) do
fn(sp)
end
end
local function do_add_stockpile_config(features, opts)
for_stockpiles(opts, function(sp)
local configs = logistics_getStockpileConfigs(tonumber(sp) or sp)
if not configs then
dfhack.printerr('invalid stockpile: '..sp)
else
for _,config in ipairs(configs) do
logistics_setStockpileConfig(config.stockpile_number,
features.melt or config.melt == 1,
features.trade or config.trade == 1,
features.dump or config.dump == 1,
features.train or config.train == 1,
not not opts.melt_masterworks)
end
end
end)
end
local function do_clear_stockpile_config(all, opts)
if all then
logistics_clearAllStockpileConfigs()
return
end
for_stockpiles(opts, function(sp)
logistics_clearStockpileConfig(tonumber(sp) or sp)
end)
end
local function process_args(opts, args)
if args[1] == 'help' then
opts.help = true
return
end
return argparse.processArgsGetopt(args, {
{'h', 'help', handler=function() opts.help = true end},
{'m', 'melt-masterworks', handler=function() opts.melt_masterworks = true end},
{'s', 'stockpile', hasArg=true, handler=function(arg) opts.sp = arg end},
})
end
function parse_commandline(args)
local opts = {}
local positionals = process_args(opts, args)
if opts.help or not positionals then
return false
end
local command = table.remove(positionals, 1)
if not command or command == 'status' then
print_status()
elseif command == 'now' then
logistics_cycle()
elseif command == 'add' then
do_add_stockpile_config(utils.invert(positionals), opts)
elseif command == 'clear' then
do_clear_stockpile_config(utils.invert(positionals).all, opts)
else
return false
end
return true
end
return _ENV