Skip to content

Commit

Permalink
support melting masterworks in logistics
Browse files Browse the repository at this point in the history
  • Loading branch information
myk002 committed Oct 7, 2023
1 parent beaba19 commit 25600e4
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 20 deletions.
1 change: 1 addition & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Template for new versions:
- `preserve-tombs`: tracks tomb assignments to living units and ensures that the tomb stays assigned to them when they die.

## New Features
- `logistics`: ``automelt`` now optionally supports melting masterworks; feature accessible from `stockpiles` overlay

## Fixes

Expand Down
4 changes: 4 additions & 0 deletions docs/plugins/logistics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,7 @@ Options
Causes the command to act upon stockpiles with the given names or numbers
instead of the stockpile that is currently selected in the UI. Note that
the numbers are the stockpile numbers, not the building ids.
``-m``, ``--melt-masterworks``
If specified with a ``logistics add melt`` command, will configure the
stockpile to allow melting of masterworks. By default, masterworks are not
marked for melting, even if they are in an automelt stockpile.
8 changes: 7 additions & 1 deletion docs/plugins/stockpiles.rst
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,13 @@ Overlay

This plugin provides a panel that appears when you select a stockpile via an
`overlay` widget. You can use it to easily toggle `logistics` plugin features
like autotrade, automelt, or autotrain.
like autotrade, automelt, or autotrain. There are also buttons along the top frame for:

- minimizing the panel (if it is in the way of the vanilla stockpile
configuration widgets)
- showing help for the overlay widget in `gui/launcher` (this page)
- configuring advanced settings for the stockpile, such as whether automelt
will melt masterworks

.. _stockpiles-library:

Expand Down
29 changes: 21 additions & 8 deletions plugins/logistics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ enum StockpileConfigValues {
STOCKPILE_CONFIG_TRADE = 2,
STOCKPILE_CONFIG_DUMP = 3,
STOCKPILE_CONFIG_TRAIN = 4,
STOCKPILE_CONFIG_MELT_MASTERWORKS = 5,
};

static int get_config_val(PersistentDataItem& c, int index) {
Expand Down Expand Up @@ -81,6 +82,7 @@ static PersistentDataItem& ensure_stockpile_config(color_ostream& out, int stock
set_config_bool(c, STOCKPILE_CONFIG_TRADE, false);
set_config_bool(c, STOCKPILE_CONFIG_DUMP, false);
set_config_bool(c, STOCKPILE_CONFIG_TRAIN, false);
set_config_bool(c, STOCKPILE_CONFIG_MELT_MASTERWORKS, false);
return c;
}

Expand Down Expand Up @@ -259,8 +261,8 @@ class StockProcessor {

class MeltStockProcessor : public StockProcessor {
public:
MeltStockProcessor(int32_t stockpile_number, bool enabled, ProcessorStats &stats)
: StockProcessor("melt", stockpile_number, enabled, stats) { }
MeltStockProcessor(int32_t stockpile_number, bool enabled, ProcessorStats &stats, bool melt_masterworks)
: StockProcessor("melt", stockpile_number, enabled, stats), melt_masterworks(melt_masterworks) { }

bool is_designated(color_ostream &out, df::item *item) override {
return item->flags.bits.melt;
Expand Down Expand Up @@ -294,7 +296,9 @@ class MeltStockProcessor : public StockProcessor {
}
}

if (item->getQuality() >= df::item_quality::Masterful)
if (!melt_masterworks && item->getQuality() >= df::item_quality::Masterful)
return false;
if (item->flags.bits.artifact)
return false;

return true;
Expand All @@ -305,6 +309,9 @@ class MeltStockProcessor : public StockProcessor {
item->flags.bits.melt = 1;
return true;
}

private:
const bool melt_masterworks;
};

class TradeStockProcessor: public StockProcessor {
Expand Down Expand Up @@ -519,11 +526,12 @@ static void do_cycle(color_ostream& out, int32_t& melt_count, int32_t& trade_cou
int32_t stockpile_number = bld->stockpile_number;

bool melt = get_config_bool(c, STOCKPILE_CONFIG_MELT);
bool melt_masterworks = get_config_bool(c, STOCKPILE_CONFIG_MELT_MASTERWORKS);
bool trade = get_config_bool(c, STOCKPILE_CONFIG_TRADE);
bool dump = get_config_bool(c, STOCKPILE_CONFIG_DUMP);
bool train = get_config_bool(c, STOCKPILE_CONFIG_TRAIN);

MeltStockProcessor melt_stock_processor(stockpile_number, melt, melt_stats);
MeltStockProcessor melt_stock_processor(stockpile_number, melt, melt_stats, melt_masterworks);
TradeStockProcessor trade_stock_processor(stockpile_number, trade, trade_stats);
DumpStockProcessor dump_stock_processor(stockpile_number, dump, dump_stats);
TrainStockProcessor train_stock_processor(stockpile_number, train, train_stats);
Expand Down Expand Up @@ -555,7 +563,7 @@ static int logistics_getStockpileData(lua_State *L) {

for (auto bld : df::global::world->buildings.other.STOCKPILE) {
int32_t stockpile_number = bld->stockpile_number;
MeltStockProcessor melt_stock_processor(stockpile_number, false, melt_stats);
MeltStockProcessor melt_stock_processor(stockpile_number, false, melt_stats, false);
TradeStockProcessor trade_stock_processor(stockpile_number, false, trade_stats);
DumpStockProcessor dump_stock_processor(stockpile_number, false, dump_stats);
TrainStockProcessor train_stock_processor(stockpile_number, false, train_stats);
Expand All @@ -581,12 +589,14 @@ static int logistics_getStockpileData(lua_State *L) {
PersistentDataItem &c = entry.second;

bool melt = get_config_bool(c, STOCKPILE_CONFIG_MELT);
bool melt_masterworks = get_config_bool(c, STOCKPILE_CONFIG_MELT_MASTERWORKS);
bool trade = get_config_bool(c, STOCKPILE_CONFIG_TRADE);
bool dump = get_config_bool(c, STOCKPILE_CONFIG_DUMP);
bool train = get_config_bool(c, STOCKPILE_CONFIG_TRAIN);

unordered_map<string, string> config;
config.emplace("melt", melt ? "true" : "false");
config.emplace("melt_masterworks", melt_masterworks ? "true" : "false");
config.emplace("trade", trade ? "true" : "false");
config.emplace("dump", dump ? "true" : "false");
config.emplace("train", train ? "true" : "false");
Expand Down Expand Up @@ -633,11 +643,13 @@ static unordered_map<string, int> get_stockpile_config(int32_t stockpile_number)
if (watched_stockpiles.count(stockpile_number)) {
PersistentDataItem &c = watched_stockpiles[stockpile_number];
stockpile_config.emplace("melt", get_config_bool(c, STOCKPILE_CONFIG_MELT));
stockpile_config.emplace("melt_masterworks", get_config_bool(c, STOCKPILE_CONFIG_MELT_MASTERWORKS));
stockpile_config.emplace("trade", get_config_bool(c, STOCKPILE_CONFIG_TRADE));
stockpile_config.emplace("dump", get_config_bool(c, STOCKPILE_CONFIG_DUMP));
stockpile_config.emplace("train", get_config_bool(c, STOCKPILE_CONFIG_TRAIN));
} else {
stockpile_config.emplace("melt", false);
stockpile_config.emplace("melt_masterworks", false);
stockpile_config.emplace("trade", false);
stockpile_config.emplace("dump", false);
stockpile_config.emplace("train", false);
Expand Down Expand Up @@ -666,9 +678,9 @@ static int logistics_getStockpileConfigs(lua_State *L) {
return 1;
}

static void logistics_setStockpileConfig(color_ostream& out, int stockpile_number, bool melt, bool trade, bool dump, bool train) {
DEBUG(status, out).print("entering logistics_setStockpileConfig stockpile_number=%d, melt=%d, trade=%d, dump=%d, train=%d\n",
stockpile_number, melt, trade, dump, train);
static void logistics_setStockpileConfig(color_ostream& out, int stockpile_number, bool melt, bool trade, bool dump, bool train, bool melt_masterworks) {
DEBUG(status, out).print("entering logistics_setStockpileConfig stockpile_number=%d, melt=%d, trade=%d, dump=%d, train=%d, melt_masterworks=%d\n",
stockpile_number, melt, trade, dump, train, melt_masterworks);

if (!find_stockpile(stockpile_number)) {
out.printerr("invalid stockpile number: %d\n", stockpile_number);
Expand All @@ -677,6 +689,7 @@ static void logistics_setStockpileConfig(color_ostream& out, int stockpile_numbe

auto &c = ensure_stockpile_config(out, stockpile_number);
set_config_bool(c, STOCKPILE_CONFIG_MELT, melt);
set_config_bool(c, STOCKPILE_CONFIG_MELT_MASTERWORKS, melt_masterworks);
set_config_bool(c, STOCKPILE_CONFIG_TRADE, trade);
set_config_bool(c, STOCKPILE_CONFIG_DUMP, dump);
set_config_bool(c, STOCKPILE_CONFIG_TRAIN, train);
Expand Down
17 changes: 14 additions & 3 deletions plugins/lua/logistics.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function getStockpileData()
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)
Expand All @@ -41,16 +42,24 @@ local function print_stockpile_data(data)
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) return ('[%s]'):format(stats.enabled and 'x' or ' ') end
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
print(fmt:format(sp.stockpile_number, sp.name, get_enab(sp.melt), 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)))
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

Expand Down Expand Up @@ -101,7 +110,8 @@ local function do_add_stockpile_config(features, opts)
features.melt or config.melt == 1,
features.trade or config.trade == 1,
features.dump or config.dump == 1,
features.train or config.train == 1)
features.train or config.train == 1,
not not opts.melt_masterworks)
end
end
end)
Expand All @@ -125,6 +135,7 @@ local function process_args(opts, args)

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
Expand Down
89 changes: 81 additions & 8 deletions plugins/lua/stockpiles.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ local argparse = require('argparse')
local gui = require('gui')
local logistics = require('plugins.logistics')
local overlay = require('plugins.overlay')
local textures = require('gui.textures')
local widgets = require('gui.widgets')

local STOCKPILES_DIR = 'dfhack-config/stockpiles'
Expand Down Expand Up @@ -262,6 +263,45 @@ local function do_export()
export_view = export_view and export_view:raise() or StockpilesExportScreen{}:show()
end

--------------------
-- ConfigModal
--------------------

ConfigModal = defclass(ConfigModal, gui.ZScreenModal)
ConfigModal.ATTRS{
focus_path='stockpiles_config',
on_close=DEFAULT_NIL,
}

function ConfigModal:init()
local sp = dfhack.gui.getSelectedStockpile(true)
local cur_setting = false
if sp then
local config = logistics.logistics_getStockpileConfigs(sp.stockpile_number)[1]
cur_setting = config.melt_masterworks == 1
end

self:addviews{
widgets.Window{
frame={w=35, h=10},
frame_title='Advanced logistics settings',
subviews={
widgets.ToggleHotkeyLabel{
view_id='melt_masterworks',
frame={l=0, t=0},
key='CUSTOM_M',
label='Melt masterworks',
initial_option=cur_setting,
},
},
},
}
end

function ConfigModal:onDismiss()
self.on_close{melt_masterworks=self.subviews.melt_masterworks:getOptionValue()}
end

--------------------
-- MinimizeButton
--------------------
Expand Down Expand Up @@ -368,9 +408,7 @@ function StockpilesOverlay:init()
view_id='main',
frame_style=gui.MEDIUM_FRAME,
frame_background=gui.CLEAR_PEN,
visible=function()
return not self.minimized
end,
visible=function() return not self.minimized end,
subviews={
-- widgets.HotkeyLabel{
-- frame={t=0, l=0},
Expand Down Expand Up @@ -439,14 +477,40 @@ function StockpilesOverlay:init()
},
}

local button_pen_left = dfhack.pen.parse{fg=COLOR_CYAN,
tile=curry(textures.tp_control_panel, 7) or nil, ch=string.byte('[')}
local button_pen_right = dfhack.pen.parse{fg=COLOR_CYAN,
tile=curry(textures.tp_control_panel, 8) or nil, ch=string.byte(']')}
local help_pen_center = dfhack.pen.parse{
tile=curry(textures.tp_control_panel, 9) or nil, ch=string.byte('?')}
local configure_pen_center = dfhack.pen.parse{
tile=curry(textures.tp_control_panel, 10) or nil, ch=15} -- gear/masterwork symbol

self:addviews{
main_panel, MinimizeButton{
main_panel,
MinimizeButton{
frame={t=0, r=9},
get_minimized_fn=function()
return self.minimized
end,
get_minimized_fn=function() return self.minimized end,
on_click=self:callback('toggleMinimized'),
},
widgets.Label{
frame={t=0, r=5, w=3},
text={
{tile=button_pen_left},
{tile=configure_pen_center},
{tile=button_pen_right},
},
on_click=function() ConfigModal{on_close=self:callback('on_custom_config')}:show() end,
},
widgets.Label{
frame={t=0, r=1, w=3},
text={
{tile=button_pen_left},
{tile=help_pen_center},
{tile=button_pen_right},
},
on_click=function() dfhack.run_command('gui/launcher', 'stockpiles ') end,
},
}
end

Expand Down Expand Up @@ -475,7 +539,16 @@ function StockpilesOverlay:toggleLogisticsFeature(feature)
-- logical xor
logistics.logistics_setStockpileConfig(config.stockpile_number,
(feature == 'melt') ~= (config.melt == 1), (feature == 'trade') ~= (config.trade == 1),
(feature == 'dump') ~= (config.dump == 1), (feature == 'train') ~= (config.train == 1))
(feature == 'dump') ~= (config.dump == 1), (feature == 'train') ~= (config.train == 1),
config.melt_masterworks == 1)
end

function StockpilesOverlay:on_custom_config(custom)
local sp = dfhack.gui.getSelectedStockpile(true)
if not sp then return end
local config = logistics.logistics_getStockpileConfigs(sp.stockpile_number)[1]
logistics.logistics_setStockpileConfig(config.stockpile_number,
config.melt == 1, config.trade == 1, config.dump == 1, config.train == 1, custom.melt_masterworks)
end

function StockpilesOverlay:toggleMinimized()
Expand Down

0 comments on commit 25600e4

Please sign in to comment.