diff --git a/changelog.txt b/changelog.txt index e06cd30e55..a65987dcb3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -36,7 +36,7 @@ Template for new versions: ## New Features - `uniform-unstick`: add overlay to the squad equipment screen to show a equipment conflict report and give you a one-click button to fix -- `gui/settings-manager`: save and load (optionally automatically) embark difficulty settings +- `gui/settings-manager`: save and load (optionally automatically) embark difficulty settings and standing orders ## Fixes - `source`: water and magma sources now persist with fort across saves and loads diff --git a/control-panel.lua b/control-panel.lua index eea72bc5b4..c013712197 100644 --- a/control-panel.lua +++ b/control-panel.lua @@ -55,6 +55,30 @@ dfhack.onStateChange[GLOBAL_KEY] = function(sc) end end +local function get_command_data(name_or_idx) + if type(name_or_idx) == 'number' then + return registry.COMMANDS_BY_IDX[name_or_idx] + end + return registry.COMMANDS_BY_NAME[name_or_idx] +end + +local function get_autostart_internal(data) + local default_value = not not data.default + local current_value = safe_index(common.config.data.commands, data.command, 'autostart') + if current_value == nil then + current_value = default_value + end + return current_value, default_value +end + +-- API + +-- returns current, default +function get_autostart(command) + local data = get_command_data(command) + if not data then return end + return get_autostart_internal(data) +end -- CLI @@ -85,12 +109,7 @@ local function list_command_group(group, filter_strs, enabled_map) if #desc > 0 then print((' %s'):format(desc)) end - local default_value = not not data.default - local current_value = safe_index(common.config.data.commands, data.command, 'autostart') - if current_value == nil then - current_value = default_value - end - print((' autostart enabled: %s (default: %s)'):format(current_value, default_value)) + print((' autostart enabled: %s (default: %s)'):format(get_autostart_internal(data))) if enabled_map[data.command] ~= nil then print((' currently enabled: %s'):format(enabled_map[data.command])) end @@ -130,13 +149,6 @@ local function do_list(filter_strs) list_preferences(filter_strs) end -local function get_command_data(name_or_idx) - if type(name_or_idx) == 'number' then - return registry.COMMANDS_BY_IDX[name_or_idx] - end - return registry.COMMANDS_BY_NAME[name_or_idx] -end - local function do_enable_disable(which, entries) local enabled_map =common.get_enabled_map() for _, entry in ipairs(entries) do diff --git a/docs/control-panel.rst b/docs/control-panel.rst index 5d73663ff9..275a68db94 100644 --- a/docs/control-panel.rst +++ b/docs/control-panel.rst @@ -67,3 +67,12 @@ Examples this will also remove some entries from the ``control-panel list`` output. Run ``control-panel list`` to see all preference options and their descriptions. + +API +--- + +Other scripts can query whether a command is set for autostart via the script +API:: + + local control_panel = reqscript('control-panel') + local enabled, default = control_panel.get_autostart(command) diff --git a/docs/gui/settings-manager.rst b/docs/gui/settings-manager.rst index a53cc1a1f3..a9f3254643 100644 --- a/docs/gui/settings-manager.rst +++ b/docs/gui/settings-manager.rst @@ -2,15 +2,40 @@ gui/settings-manager ==================== .. dfhack-tool:: - :summary: Save, load, and modify DF settings. + :summary: Import and export DF settings. :tags: embark interface -This tool provides overlays that allow you to save and load DF settings. +This tool allows you to save and load DF settings. + +Usage +----- + +:: + + gui/settings-manager save-difficulty + gui/settings-manager load-difficulty + gui/settings-manager save-standing-orders + gui/settings-manager load-standing-orders + +Difficulty can be saved and loaded on the embark "preparation" screen or in an +active fort. Standing orders can only be saved and loaded in an active fort. + +If auto-restoring of difficulty settings is turned on, it happens when the +embark "preparation" screen is loaded. If auto-restoring of standing orders +settings is turned on, it happens when the fort is loaded for the first time +(just like all other Autostart commands configured in `gui/control-panel`). Overlays -------- -When embarking, if you click on the ``Custom settings`` button for game -difficulty, you will see a new panel at the top. You can save the current -difficulty settings and load the saved settings back. You can also toggle an -option to automatically load the saved settings for new embarks. +When embarking or when a fort is loaded, if you click on the +``Custom settings`` button for game difficulty, you will see a new panel at the +top. You can save the current difficulty settings and load the saved settings +back. You can also toggle an option to automatically load the saved settings +for new embarks. + +When a fort is loaded, you can also go to the Labor -> Standing Orders page. +You will see a new panel that allows you to save and restore your settings for +standing orders. You can also toggle whether the saved standing orders are +automatically restored when you embark on a new fort. This will toggle the +relevant command in `gui/control-panel` on the Automation -> Autostart page. diff --git a/gui/settings-manager.lua b/gui/settings-manager.lua index a03aa8b1ab..67cacda932 100644 --- a/gui/settings-manager.lua +++ b/gui/settings-manager.lua @@ -1,5 +1,7 @@ --@ module = true +local argparse = require('argparse') +local control_panel = reqscript('control-panel') local gui = require('gui') local json = require('json') local overlay = require('plugins.overlay') @@ -224,16 +226,233 @@ function DifficultySettingsOverlay:get_df_struct() return df.global.game.main_interface.settings end +------------------------------ +-- StandingOrdersOverlay +-- + +StandingOrdersOverlay = defclass(StandingOrdersOverlay, overlay.OverlayWidget) +StandingOrdersOverlay.ATTRS { + desc='Adds buttons to the standing orders screen for saving and restoring settings.', + default_pos={x=6, y=-5}, + viewscreens='dwarfmode/Info/LABOR/STANDING_ORDERS/AUTOMATED_WORKSHOPS', + default_enabled=true, + frame={w=78, h=5}, + frame_style=gui.MEDIUM_FRAME, + frame_background=gui.CLEAR_PEN, +} + +local li = df.global.plotinfo.labor_info + +local function save_standing_orders() + local standing_orders = {} + for name, val in pairs(df.global) do + if name:startswith('standing_orders_') then + standing_orders[name] = val + end + end + config.data.standing_orders = standing_orders + local chores = {} + chores.enabled = li.flags.children_do_chores + chores.labors = utils.clone(li.chores) + config.data.chores = chores + config:write() +end + +local function load_standing_orders() + for name, val in pairs(config.data.standing_orders or {}) do + df.global[name] = val + end + li.flags.children_do_chores = not not safe_index(config.data.chores, 'enabled') + for i, val in ipairs(safe_index(config.data.chores, 'labors') or {}) do + li.chores[i-1] = val + end +end + +function StandingOrdersOverlay:init() + self:addviews{ + widgets.HotkeyLabel{ + view_id='save', + frame={l=0, t=0, w=39}, + key='CUSTOM_CTRL_E', + label='Save standing orders (all tabs)', + on_activate=self:callback('do_save'), + }, + widgets.Label{ + view_id='save_flash', + frame={l=18, t=0}, + text='Saved', + text_pen=COLOR_GREEN, + visible=false, + }, + widgets.HotkeyLabel{ + view_id='load', + frame={l=42, t=0, w=34}, + key='CUSTOM_CTRL_I', + label='Load saved standing orders', + on_activate=self:callback('do_load'), + enabled=function() return next(config.data.standing_orders or {}) end, + }, + widgets.Label{ + view_id='load_flash', + frame={l=51, t=0}, + text='Loaded', + text_pen=COLOR_GREEN, + visible=false, + }, + widgets.ToggleHotkeyLabel{ + view_id='auto', + frame={l=0, t=2}, + key='CUSTOM_CTRL_A', + label='Apply saved settings for new embarks:', + on_change=self:callback('do_auto'), + enabled=function() return next(config.data.standing_orders or {}) end, + }, + } +end + +function StandingOrdersOverlay:do_save() + flash(self, 'save') + save_standing_orders() +end + +function StandingOrdersOverlay:do_load() + flash(self, 'load') + load_standing_orders() +end + +local autostart_command = 'gui/settings-manager load-standing-orders' + +SOMessage = defclass(SOMessage, widgets.Window) +SOMessage.ATTRS { + frame={w=61, h=9}, + enabled=DEFAULT_NIL, +} + +function SOMessage:init() + self:addviews{ + widgets.Label{ + view_id='label', + frame={t=0, l=0}, + text={ + 'The "', autostart_command, '" command', NEWLINE, + 'has been ', + {text=self.enabled and 'enabled' or 'disabled', pen=self.enabled and COLOR_GREEN or COLOR_LIGHTRED}, + ' in the ', + {text='Automation', pen=COLOR_YELLOW}, ' -> ', + {text='Autostart', pen=COLOR_YELLOW}, ' tab of ', NEWLINE, + {text='.', gap=25}, + }, + }, + widgets.HotkeyLabel{ + frame={t=2, l=0}, + label='gui/control-panel', + key='CUSTOM_CTRL_G', + auto_width=true, + on_activate=function() + self.parent_view:dismiss() + dfhack.run_script('gui/control-panel') + end, + }, + widgets.HotkeyLabel{ + frame={b=0, l=0, r=0}, + label='Ok', + key='SELECT', + auto_width=true, + on_activate=function() self.parent_view:dismiss() end, + }, + } +end + +SOMessageScreen = defclass(SOMessageScreen, gui.ZScreenModal) +SOMessageScreen.ATTRS { + focus_path='settings-manager/prompt', + enabled=DEFAULT_NIL, +} + +function SOMessageScreen:init() + self:addviews{ + SOMessage{ + frame_title=(self.enabled and 'Enabled' or 'Disabled')..' auto-restore', + enabled=self.enabled + }, + } +end + +function StandingOrdersOverlay:do_auto(val) + dfhack.run_script('control-panel', (val and '' or 'no') .. 'autostart', autostart_command) + SOMessageScreen{enabled=val}:show() +end + +function StandingOrdersOverlay:onRenderFrame(dc, rect) + StandingOrdersOverlay.super.onRenderFrame(self, dc, rect) + local enabled = control_panel.get_autostart(autostart_command) + self.subviews.auto:setOption(enabled) +end + OVERLAY_WIDGETS = { embark_difficulty=DifficultyEmbarkOverlay, embark_notification=DifficultyEmbarkNotificationOverlay, settings_difficulty=DifficultySettingsOverlay, + standing_orders=StandingOrdersOverlay, } if dfhack_flags.module then return end +------------------------------ +-- CLI processing +-- + +local help = false + +local positionals = argparse.processArgsGetopt({...}, { + {'h', 'help', handler=function() help = true end}, + }) + +local command = (positionals or {})[1] + +if help then + print(dfhack.script_help()) + return +end + +local scr = dfhack.gui.getDFViewscreen(true) +local is_embark = df.viewscreen_setupdwarfgamest:is_instance(scr) +local is_fort = df.viewscreen_dwarfmodest:is_instance(scr) + +if command == 'save-difficulty' then + if is_embark then save_difficulty(scr.difficulty) + elseif is_fort then + save_difficulty(df.global.game.main_interface.settings.difficulty) + else + qerror('must be on the embark preparation screen or in a loaded fort') + end +elseif command == 'load-difficulty' then + if is_embark then + load_difficulty(scr.difficulty) + show_notification = true + elseif is_fort then + load_difficulty(df.global.game.main_interface.settings.difficulty) + else + qerror('must be on the embark preparation screen or in a loaded fort') + end +elseif command == 'save-standing-orders' then + if is_fort then save_standing_orders() + else + qerror('must be in a loaded fort') + end +elseif command == 'load-standing-orders' then + if is_fort then load_standing_orders() + else + qerror('must be in a loaded fort') + end +else + print(dfhack.script_help()) +end + +return + --[[ TODO: reinstate color editor diff --git a/internal/control-panel/registry.lua b/internal/control-panel/registry.lua index fd8bd3f208..0ab101a327 100644 --- a/internal/control-panel/registry.lua +++ b/internal/control-panel/registry.lua @@ -38,6 +38,8 @@ COMMANDS_BY_IDX = { {command='cleanowned', group='automation', mode='repeat', desc='Encourage dwarves to drop tattered clothing and grab new ones.', params={'--time', '1', '--timeUnits', 'months', '--command', '[', 'cleanowned', 'X', ']'}}, + {command='gui/settings-manager load-standing-orders', group='automation', mode='run', + desc='Go to the Standing Orders tab in the Labor screen to save your current settings.'}, {command='nestboxes', group='automation', mode='enable'}, {command='orders-sort', help_command='orders', group='automation', mode='repeat', desc='Sort manager orders by repeat frequency so one-time orders can be completed.',