From 2cf676758967a63db2845fb9f31f73a8412e5475 Mon Sep 17 00:00:00 2001 From: myk002 Date: Wed, 2 Nov 2022 12:40:18 -0700 Subject: [PATCH 1/5] migrate dwarfmonitor widgets to overlay v2 --- dfhack-config/dwarfmonitor.json | 20 +- .../overlay/widgets/dwarfmonitor_cursor.json | 12 + .../overlay/widgets/dwarfmonitor_date.json | 11 + .../overlay/widgets/dwarfmonitor_misery.json | 11 + .../overlay/widgets/dwarfmonitor_weather.json | 11 + plugins/dwarfmonitor.cpp | 376 +++--------------- plugins/lua/dwarfmonitor.lua | 227 +++++------ 7 files changed, 201 insertions(+), 467 deletions(-) create mode 100644 dfhack-config/overlay/widgets/dwarfmonitor_cursor.json create mode 100644 dfhack-config/overlay/widgets/dwarfmonitor_date.json create mode 100644 dfhack-config/overlay/widgets/dwarfmonitor_misery.json create mode 100644 dfhack-config/overlay/widgets/dwarfmonitor_weather.json diff --git a/dfhack-config/dwarfmonitor.json b/dfhack-config/dwarfmonitor.json index 007dad020..9bd3b1f76 100644 --- a/dfhack-config/dwarfmonitor.json +++ b/dfhack-config/dwarfmonitor.json @@ -1,21 +1,3 @@ { - "widgets": [ - { - "type": "weather", - "x": 22, - "y": -1 - }, - { - "type": "date", - "x": -30, - "y": 0, - "format": "Y-M-D" - }, - { - "type": "misery", - "x": -2, - "y": -1, - "anchor": "right" - } - ] + "date_format": "Y-M-D" } diff --git a/dfhack-config/overlay/widgets/dwarfmonitor_cursor.json b/dfhack-config/overlay/widgets/dwarfmonitor_cursor.json new file mode 100644 index 000000000..cc2db582b --- /dev/null +++ b/dfhack-config/overlay/widgets/dwarfmonitor_cursor.json @@ -0,0 +1,12 @@ +{ + "pos": { + "x": 2, + "y": 2 + }, + "provider": "dwarfmonitor", + "class": "Widget_cursor", + "viewscreens": [ + "dungeonmode", + "dwarfmode" + ] +} diff --git a/dfhack-config/overlay/widgets/dwarfmonitor_date.json b/dfhack-config/overlay/widgets/dwarfmonitor_date.json new file mode 100644 index 000000000..6c868d419 --- /dev/null +++ b/dfhack-config/overlay/widgets/dwarfmonitor_date.json @@ -0,0 +1,11 @@ +{ + "pos": { + "x": -16, + "y": 1 + }, + "provider": "dwarfmonitor", + "class": "Widget_date", + "viewscreens": [ + "dwarfmode" + ] +} diff --git a/dfhack-config/overlay/widgets/dwarfmonitor_misery.json b/dfhack-config/overlay/widgets/dwarfmonitor_misery.json new file mode 100644 index 000000000..5ef741823 --- /dev/null +++ b/dfhack-config/overlay/widgets/dwarfmonitor_misery.json @@ -0,0 +1,11 @@ +{ + "pos": { + "x": -2, + "y": -1 + }, + "provider": "dwarfmonitor", + "class": "Widget_misery", + "viewscreens": [ + "dwarfmode" + ] +} diff --git a/dfhack-config/overlay/widgets/dwarfmonitor_weather.json b/dfhack-config/overlay/widgets/dwarfmonitor_weather.json new file mode 100644 index 000000000..8a6130af0 --- /dev/null +++ b/dfhack-config/overlay/widgets/dwarfmonitor_weather.json @@ -0,0 +1,11 @@ +{ + "pos": { + "x": 15, + "y": -1 + }, + "provider": "dwarfmonitor", + "class": "Widget_weather", + "viewscreens": [ + "dwarfmode" + ] +} diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 1a453e0d5..4355104a7 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -52,7 +52,6 @@ using std::deque; DFHACK_PLUGIN("dwarfmonitor"); DFHACK_PLUGIN_IS_ENABLED(is_enabled); -REQUIRE_GLOBAL(current_weather); REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(ui); @@ -74,20 +73,8 @@ struct less_second { } }; -struct dwarfmonitor_configst { - std::string date_format; -}; -static dwarfmonitor_configst dwarfmonitor_config; - -static bool monitor_jobs = false; -static bool monitor_misery = true; -static bool monitor_date = true; -static bool monitor_weather = true; static map> work_history; -static int misery[] = { 0, 0, 0, 0, 0, 0, 0 }; -static bool misery_upto_date = false; - static color_value monitor_colors[] = { COLOR_LIGHTRED, @@ -151,102 +138,18 @@ static void move_cursor(df::coord &pos) static void open_stats_screen(); -namespace dm_lua { - static color_ostream_proxy *out; - static lua_State *state; - typedef int(*initializer)(lua_State*); - int no_args (lua_State *L) { return 0; } - void cleanup() - { - if (out) - { - delete out; - out = NULL; - } - } - bool init_call (const char *func) - { - if (!out) - out = new color_ostream_proxy(Core::getInstance().getConsole()); - return Lua::PushModulePublic(*out, state, "plugins.dwarfmonitor", func); - } - bool safe_call (int nargs) - { - return Lua::SafeCall(*out, state, nargs, 0); - } - - bool call (const char *func, initializer init = no_args) - { - Lua::StackUnwinder top(state); - if (!init_call(func)) - return false; - int nargs = init(state); - return safe_call(nargs); - } - - namespace api { - int monitor_state (lua_State *L) - { - std::string type = luaL_checkstring(L, 1); - if (type == "weather") - lua_pushboolean(L, monitor_weather); - else if (type == "misery") - lua_pushboolean(L, monitor_misery); - else if (type == "date") - lua_pushboolean(L, monitor_date); - else - lua_pushnil(L); - return 1; - } - int get_weather_counts (lua_State *L) - { - #define WEATHER_TYPES WTYPE(clear, None); WTYPE(rain, Rain); WTYPE(snow, Snow); - #define WTYPE(type, name) int type = 0; - WEATHER_TYPES - #undef WTYPE - int i, j; - for (i = 0; i < 5; ++i) - { - for (j = 0; j < 5; ++j) - { - switch ((*current_weather)[i][j]) - { - #define WTYPE(type, name) case weather_type::name: type++; break; - WEATHER_TYPES - #undef WTYPE - } - } - } - lua_newtable(L); - #define WTYPE(type, name) Lua::TableInsert(L, #type, type); - WEATHER_TYPES - #undef WTYPE - #undef WEATHER_TYPES - return 1; - } - int get_misery_data (lua_State *L) - { - lua_newtable(L); - for (int i = 0; i < 7; i++) - { - Lua::Push(L, i); - lua_newtable(L); - Lua::TableInsert(L, "value", misery[i]); - Lua::TableInsert(L, "color", monitor_colors[i]); - Lua::TableInsert(L, "last", (i == 6)); - lua_settable(L, -3); - } - return 1; - } +static int getStressCategoryColors(lua_State *L) { + const size_t n = sizeof(monitor_colors)/sizeof(color_value); + lua_createtable(L, n, 0); + for (size_t i = 0; i < n; ++i) { + Lua::Push(L, monitor_colors[i]); + lua_rawseti(L, -2, i+1); } + return 1; } -#define DM_LUA_FUNC(name) { #name, df::wrap_function(dm_lua::api::name, true) } -#define DM_LUA_CMD(name) { #name, dm_lua::api::name } DFHACK_PLUGIN_LUA_COMMANDS { - DM_LUA_CMD(monitor_state), - DM_LUA_CMD(get_weather_counts), - DM_LUA_CMD(get_misery_data), + DFHACK_LUA_COMMAND(getStressCategoryColors), DFHACK_LUA_END }; @@ -1648,8 +1551,7 @@ public: return (selected_column == 1) ? dwarf_column.getFirstSelectedElem() : nullptr; } - void feed(set *input) - { + void feed(set *input) override { bool key_processed = false; switch (selected_column) { @@ -1723,8 +1625,7 @@ public: } } - void render() - { + void render() override { using namespace df::enums::interface_key; if (Screen::isDismissed(this)) @@ -1751,7 +1652,7 @@ public: getSelectedUnit() ? COLOR_WHITE : COLOR_DARKGREY); } - std::string getFocusString() { return "dwarfmonitor_preferences"; } + std::string getFocusString() override { return "dwarfmonitor_preferences"; } private: ListColumn preferences_column; @@ -1762,13 +1663,11 @@ private: vector preferences_store; - void validateColumn() - { + void validateColumn() { set_to_limit(selected_column, 1); } - void resize(int32_t x, int32_t y) - { + void resize(int32_t x, int32_t y) override { dfhack_viewscreen::resize(x, y); preferences_column.resize(); dwarf_column.resize(); @@ -1776,15 +1675,12 @@ private: }; -static void open_stats_screen() -{ +static void open_stats_screen() { Screen::show(dts::make_unique(), plugin_self); } -static void add_work_history(df::unit *unit, activity_type type) -{ - if (work_history.find(unit) == work_history.end()) - { +static void add_work_history(df::unit *unit, activity_type type) { + if (work_history.find(unit) == work_history.end()) { auto max_history = get_max_history(); for (int i = 0; i < max_history; i++) work_history[unit].push_back(JOB_UNKNOWN); @@ -1794,8 +1690,7 @@ static void add_work_history(df::unit *unit, activity_type type) work_history[unit].pop_front(); } -static bool is_at_leisure(df::unit *unit) -{ +static bool is_at_leisure(df::unit *unit) { if (Units::getMiscTrait(unit, misc_trait_type::Migrant)) return true; @@ -1805,32 +1700,17 @@ static bool is_at_leisure(df::unit *unit) return false; } -static void reset() -{ +static void reset() { work_history.clear(); - - for (int i = 0; i < 7; i++) - misery[i] = 0; - - misery_upto_date = false; } static void update_dwarf_stats(bool is_paused) { - if (monitor_misery) - { - for (int i = 0; i < 7; i++) - misery[i] = 0; - } - - for (auto iter = world->units.active.begin(); iter != world->units.active.end(); iter++) - { - df::unit* unit = *iter; + for (auto unit : world->units.active) { if (!Units::isCitizen(unit)) continue; - if (!DFHack::Units::isActive(unit)) - { + if (!DFHack::Units::isActive(unit)) { auto it = work_history.find(unit); if (it != work_history.end()) work_history.erase(it); @@ -1838,35 +1718,25 @@ static void update_dwarf_stats(bool is_paused) continue; } - if (monitor_misery) - { - misery[get_happiness_cat(unit)]++; - } - - if (!monitor_jobs || is_paused) + if (is_paused) continue; if (Units::isBaby(unit) || - Units::isChild(unit) || - unit->profession == profession::DRUNK) - { + Units::isChild(unit) || + unit->profession == profession::DRUNK) continue; - } - if (ENUM_ATTR(profession, military, unit->profession)) - { + if (ENUM_ATTR(profession, military, unit->profession)) { add_work_history(unit, JOB_MILITARY); continue; } - if (!unit->job.current_job) - { + if (!unit->job.current_job) { add_work_history(unit, JOB_IDLE); continue; } - if (is_at_leisure(unit)) - { + if (is_at_leisure(unit)) { add_work_history(unit, JOB_LEISURE); continue; } @@ -1876,107 +1746,21 @@ static void update_dwarf_stats(bool is_paused) } -DFhackCExport command_result plugin_onupdate (color_ostream &out) -{ - if (!monitor_jobs && !monitor_misery) - return CR_OK; - - if(!Maps::IsValid()) +DFhackCExport command_result plugin_onupdate (color_ostream &out) { + if (!is_enabled | !Maps::IsValid()) return CR_OK; bool is_paused = DFHack::World::ReadPauseState(); - if (is_paused) - { - if (monitor_misery && !misery_upto_date) - misery_upto_date = true; - else - return CR_OK; - } - else - { - if (world->frame_counter % DELTA_TICKS != 0) - return CR_OK; - } + if (!is_paused && world->frame_counter % DELTA_TICKS != 0) + return CR_OK; update_dwarf_stats(is_paused); return CR_OK; } -struct dwarf_monitor_hook : public df::viewscreen_dwarfmodest -{ - typedef df::viewscreen_dwarfmodest interpose_base; - - DEFINE_VMETHOD_INTERPOSE(void, render, ()) - { - INTERPOSE_NEXT(render)(); - - CoreSuspendClaimer suspend; - if (Maps::IsValid()) - { - dm_lua::call("render_all"); - } - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(dwarf_monitor_hook, render); - -static bool set_monitoring_mode(const string &mode, const bool &state) -{ - bool mode_recognized = false; - - if (!is_enabled) - return false; - /* - NOTE: although we are not touching DF directly but there might be - code running that uses these values. So this could use another mutex - or just suspend the core while we edit our values. - */ - CoreSuspender guard; - - if (mode == "work" || mode == "all") - { - mode_recognized = true; - monitor_jobs = state; - if (!monitor_jobs) - reset(); - } - if (mode == "misery" || mode == "all") - { - mode_recognized = true; - monitor_misery = state; - } - if (mode == "date" || mode == "all") - { - mode_recognized = true; - monitor_date = state; - } - if (mode == "weather" || mode == "all") - { - mode_recognized = true; - monitor_weather = state; - } - - return mode_recognized; -} - -static bool load_config() -{ - return dm_lua::call("load_config"); -} - -DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) -{ - if (enable) - { - CoreSuspender guard; - load_config(); - } - if (is_enabled != enable) - { - if (!INTERPOSE_HOOK(dwarf_monitor_hook, render).apply(enable)) - return CR_FAILURE; - +DFhackCExport command_result plugin_enable(color_ostream &, bool enable) { + if (is_enabled != enable) { reset(); is_enabled = enable; } @@ -1984,76 +1768,28 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) return CR_OK; } -static command_result dwarfmonitor_cmd(color_ostream &out, vector & parameters) -{ - bool show_help = false; +static command_result dwarfmonitor_cmd(color_ostream &, vector & parameters) { if (parameters.empty()) - { - show_help = true; - } - else - { - auto cmd = parameters[0][0]; - string mode; - - if (parameters.size() > 1) - mode = toLower(parameters[1]); - - if (cmd == 'v' || cmd == 'V') - { - out << "DwarfMonitor" << endl << "Version: " << PLUGIN_VERSION << endl; - } - else if ((cmd == 'e' || cmd == 'E') && !mode.empty()) - { - if (!is_enabled) - plugin_enable(out, true); + return CR_WRONG_USAGE; - if (set_monitoring_mode(mode, true)) - { - out << "Monitoring enabled: " << mode << endl; - } - else - { - show_help = true; - } - } - else if ((cmd == 'd' || cmd == 'D') && !mode.empty()) - { - if (set_monitoring_mode(mode, false)) - out << "Monitoring disabled: " << mode << endl; - else - show_help = true; - } - else if (cmd == 's' || cmd == 'S') - { - CoreSuspender guard; - if(Maps::IsValid()) - Screen::show(dts::make_unique(), plugin_self); - } - else if (cmd == 'p' || cmd == 'P') - { - CoreSuspender guard; - if(Maps::IsValid()) - Screen::show(dts::make_unique(), plugin_self); - } - else if (cmd == 'r' || cmd == 'R') - { - CoreSuspender guard; - load_config(); - } - else - { - show_help = true; - } + auto cmd = parameters[0][0]; + if (cmd == 's' || cmd == 'S') { + CoreSuspender guard; + if(Maps::IsValid()) + Screen::show(dts::make_unique(), plugin_self); } - - if (show_help) + else if (cmd == 'p' || cmd == 'P') { + CoreSuspender guard; + if(Maps::IsValid()) + Screen::show(dts::make_unique(), plugin_self); + } + else return CR_WRONG_USAGE; return CR_OK; } -DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) +DFhackCExport command_result plugin_init(color_ostream &, std::vector &commands) { activity_labels[JOB_IDLE] = "Idle"; activity_labels[JOB_MILITARY] = "Military Duty"; @@ -2079,27 +1815,13 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector = 0 and self.opts.x or gps.dimx + self.opts.x - local y = self.opts.y >= 0 and self.opts.y or gps.dimy + self.opts.y - if self.opts.anchor == 'right' then - x = x - (self:get_width() or 0) + 1 - end - return x, y -end -function Widget:render() - if monitor_state(self.opts.type) == false then - return - end - self:update() - local x, y = self:get_pos() - local p = gui.Painter.new_xy(x, y, gps.dimx - 1, y) - self:render_body(p) -end -function Widget:update() end -function Widget:get_width() end -function Widget:render_body() end +-- -------------- +-- Widget_weather +-- -------------- -Widget_weather = defclass(Widget_weather, Widget) +Widget_weather = defclass(Widget_weather, overlay.OverlayWidget) -function Widget_weather:update() - self.counts = get_weather_counts() +function Widget_weather:init() + self.rain = false + self.snow = false end -function Widget_weather:get_width() - if self.counts.rain > 0 then - if self.counts.snow > 0 then - return 9 +function Widget_weather:overlay_onupdate() + local rain, snow = false, false + local cw = df.global.current_weather + for i=0,4 do + for j=0,4 do + weather = cw[i][j] + if weather == df.weather_type.Rain then self.rain = true end + if weather == df.weather_type.Snow then self.snow = true end end - return 4 - elseif self.counts.snow > 0 then - return 4 end - return 0 + self.frame.w = (rain and 4 or 0) + (snow and 4 or 0) + + ((snow and rain) and 1 or 0) + self.rain, self.snow = rain, snow end -function Widget_weather:render_body(p) - if self.counts.rain > 0 then - p:string('Rain', COLOR_LIGHTBLUE):advance(1) - end - if self.counts.snow > 0 then - p:string('Snow', COLOR_WHITE) - end +function Widget_weather:onRenderBody(dc) + if self.rain then dc:string('Rain', COLOR_LIGHTBLUE):advance(1) end + if self.snow then dc:string('Snow', COLOR_WHITE) end end -Widget_date = defclass(Widget_date, Widget) -Widget_date.ATTRS = { - output = '' -} +-- ----------- +-- Widget_date +-- ----------- -function Widget_date:update() - if not self.opts.format then - self.opts.format = 'Y-M-D' +local function get_date_format() + local ok, config = pcall(json.decode_file, DWARFMONITOR_CONFIG_FILE) + if not ok or not config.date_format then + return 'Y-M-D' end + return config.date_format +end + +Widget_date = defclass(Widget_date, overlay.OverlayWidget) + +function Widget_date:init() + self.datestr = '' + self.fmt = get_date_format() +end + +function Widget_date:overlay_onupdate() local year = dfhack.world.ReadCurrentYear() local month = dfhack.world.ReadCurrentMonth() + 1 local day = dfhack.world.ReadCurrentDay() - self.output = 'Date:' - for i = 1, #self.opts.format do - local c = self.opts.format:sub(i, i) + + local fmt = self.fmt + local datestr = 'Date:' + for i=1,#fmt do + local c = fmt:sub(i, i) if c == 'y' or c == 'Y' then - self.output = self.output .. year + datestr = datestr .. year elseif c == 'm' or c == 'M' then if c == 'M' and month < 10 then - self.output = self.output .. '0' + datestr = datestr .. '0' end - self.output = self.output .. month + datestr = datestr .. month elseif c == 'd' or c == 'D' then if c == 'D' and day < 10 then - self.output = self.output .. '0' + datestr = datestr .. '0' end - self.output = self.output .. day + datestr = datestr .. day else - self.output = self.output .. c + datestr = datestr .. c end end -end -function Widget_date:get_width() - return #self.output + self.frame.w = #datestr + self.datestr = datestr end -function Widget_date:render_body(p) - p:string(self.output, COLOR_GREY) +function Widget_date:onRenderBody(dc) + dc:string(self.datestr, COLOR_GREY) end -Widget_misery = defclass(Widget_misery, Widget) +-- ------------- +-- Widget_misery +-- ------------- + +Widget_misery = defclass(Widget_misery, overlay.OverlayWidget) -function Widget_misery:update() - self.data = get_misery_data() +function Widget_misery:init() + self.colors = getStressCategoryColors() + self.stress_category_counts = {} end -function Widget_misery:get_width() - local w = 2 + 6 - for k, v in pairs(self.data) do - w = w + #tostring(v.value) +function Widget_misery:overlay_onupdate() + local counts, num_colors = {}, #self.colors + for _,unit in ipairs(df.global.world.units.active) do + local stress_category = math.min(num_colors, + dfhack.units.getStressCategory(unit)) + counts[stress_category] = (counts[stress_category] or 0) + 1 end - return w -end -function Widget_misery:render_body(p) - p:string("H:", COLOR_WHITE) - for i = 0, 6 do - local v = self.data[i] - p:string(tostring(v.value), v.color) - if not v.last then - p:string("/", COLOR_WHITE) - end + local width = 2 + num_colors - 1 -- 'H:' plus the slashes + for i=1,num_colors do + width = width + #tostring(counts[i] or 0) end -end -Widget_cursor = defclass(Widget_cursor, Widget) + self.stress_category_counts = counts + self.frame.w = width +end -function Widget_cursor:update() - if gps.mouse_x == -1 and not self.opts.show_invalid then - self.output = '' - return +function Widget_misery:onRenderBody(dc) + dc:string('H:', COLOR_WHITE) + local counts = self.stress_category_counts + for i,color in ipairs(self.colors) do + dc:string(tostring(counts[i] or 0), color) + if i < #self.colors then dc:string('/', COLOR_WHITE) end end - self.output = (self.opts.format or '(x,y)'):gsub('[xX]', gps.mouse_x):gsub('[yY]', gps.mouse_y) end -function Widget_cursor:get_width() - return #self.output -end +-- ------------- +-- Widget_cursor +-- ------------- -function Widget_cursor:render_body(p) - p:string(self.output) -end +Widget_cursor = defclass(Widget_cursor, overlay.OverlayWidget) -function render_all() - for _, w in pairs(widgets) do - w:render() - end -end +function Widget_cursor:onRenderBody(dc) + local screenx, screeny = dfhack.screen.getMousePos() + local mouse_map = dfhack.gui.getMousePos() + local keyboard_map = guidm.getCursorPos() -function load_config() - config = require('json').decode_file('dfhack-config/dwarfmonitor.json') - if not config.widgets then - dmerror('No widgets enabled') + local text = {} + table.insert(text, ('mouse UI grid (%d,%d)'):format(screenx, screeny)) + if mouse_map then + table.insert(text, ('mouse map coord (%d,%d,%d)') + :format(mouse_map.x, mouse_map.y, mouse_map.z)) end - if type(config.widgets) ~= 'table' then - dmerror('"widgets" is not a table') + if keyboard_map then + table.insert(text, ('kbd cursor coord (%d,%d,%d)') + :format(keyboard_map.x, keyboard_map.y, keyboard_map.z)) end - widgets = {} - for _, opts in pairs(config.widgets) do - if type(opts) ~= 'table' then dmerror('"widgets" is not an array') end - if not opts.type then dmerror('Widget missing type field') end - local cls = _ENV['Widget_' .. opts.type] - if not cls then - dmerror('Invalid widget type: ' .. opts.type) - end - table.insert(widgets, cls(opts)) + local width = 0 + for i,line in ipairs(text) do + dc:seek(0, i-1):string(line) + width = math.max(width, #line) end + self.frame.w = width + self.frame.h = #text end return _ENV From 9ce9d2001c7214be18197e4c4183326c50b73b82 Mon Sep 17 00:00:00 2001 From: myk002 Date: Fri, 4 Nov 2022 10:29:09 -0700 Subject: [PATCH 2/5] adapt dwarfmonitor widgets to new API --- .../overlay/widgets/dwarfmonitor_cursor.json | 12 --- .../overlay/widgets/dwarfmonitor_date.json | 11 --- .../overlay/widgets/dwarfmonitor_misery.json | 11 --- .../overlay/widgets/dwarfmonitor_weather.json | 11 --- plugins/lua/dwarfmonitor.lua | 76 ++++++++++++------- 5 files changed, 50 insertions(+), 71 deletions(-) delete mode 100644 dfhack-config/overlay/widgets/dwarfmonitor_cursor.json delete mode 100644 dfhack-config/overlay/widgets/dwarfmonitor_date.json delete mode 100644 dfhack-config/overlay/widgets/dwarfmonitor_misery.json delete mode 100644 dfhack-config/overlay/widgets/dwarfmonitor_weather.json diff --git a/dfhack-config/overlay/widgets/dwarfmonitor_cursor.json b/dfhack-config/overlay/widgets/dwarfmonitor_cursor.json deleted file mode 100644 index cc2db582b..000000000 --- a/dfhack-config/overlay/widgets/dwarfmonitor_cursor.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "pos": { - "x": 2, - "y": 2 - }, - "provider": "dwarfmonitor", - "class": "Widget_cursor", - "viewscreens": [ - "dungeonmode", - "dwarfmode" - ] -} diff --git a/dfhack-config/overlay/widgets/dwarfmonitor_date.json b/dfhack-config/overlay/widgets/dwarfmonitor_date.json deleted file mode 100644 index 6c868d419..000000000 --- a/dfhack-config/overlay/widgets/dwarfmonitor_date.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "pos": { - "x": -16, - "y": 1 - }, - "provider": "dwarfmonitor", - "class": "Widget_date", - "viewscreens": [ - "dwarfmode" - ] -} diff --git a/dfhack-config/overlay/widgets/dwarfmonitor_misery.json b/dfhack-config/overlay/widgets/dwarfmonitor_misery.json deleted file mode 100644 index 5ef741823..000000000 --- a/dfhack-config/overlay/widgets/dwarfmonitor_misery.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "pos": { - "x": -2, - "y": -1 - }, - "provider": "dwarfmonitor", - "class": "Widget_misery", - "viewscreens": [ - "dwarfmode" - ] -} diff --git a/dfhack-config/overlay/widgets/dwarfmonitor_weather.json b/dfhack-config/overlay/widgets/dwarfmonitor_weather.json deleted file mode 100644 index 8a6130af0..000000000 --- a/dfhack-config/overlay/widgets/dwarfmonitor_weather.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "pos": { - "x": 15, - "y": -1 - }, - "provider": "dwarfmonitor", - "class": "Widget_weather", - "viewscreens": [ - "dwarfmode" - ] -} diff --git a/plugins/lua/dwarfmonitor.lua b/plugins/lua/dwarfmonitor.lua index 27d43cd5b..866aa609a 100644 --- a/plugins/lua/dwarfmonitor.lua +++ b/plugins/lua/dwarfmonitor.lua @@ -6,18 +6,22 @@ local overlay = require('plugins.overlay') local DWARFMONITOR_CONFIG_FILE = 'dfhack-config/dwarfmonitor.json' --- -------------- --- Widget_weather --- -------------- +-- ------------- -- +-- WeatherWidget -- +-- ------------- -- -Widget_weather = defclass(Widget_weather, overlay.OverlayWidget) +WeatherWidget = defclass(WeatherWidget, overlay.OverlayWidget) +WeatherWidget.ATTRS{ + default_pos={x=15,y=-1}, + viewscreens={'dungeonmode', 'dwarfmode'}, +} -function Widget_weather:init() +function WeatherWidget:init() self.rain = false self.snow = false end -function Widget_weather:overlay_onupdate() +function WeatherWidget:overlay_onupdate() local rain, snow = false, false local cw = df.global.current_weather for i=0,4 do @@ -32,14 +36,14 @@ function Widget_weather:overlay_onupdate() self.rain, self.snow = rain, snow end -function Widget_weather:onRenderBody(dc) +function WeatherWidget:onRenderBody(dc) if self.rain then dc:string('Rain', COLOR_LIGHTBLUE):advance(1) end if self.snow then dc:string('Snow', COLOR_WHITE) end end --- ----------- --- Widget_date --- ----------- +-- ---------- -- +-- DateWidget -- +-- ---------- -- local function get_date_format() local ok, config = pcall(json.decode_file, DWARFMONITOR_CONFIG_FILE) @@ -49,14 +53,18 @@ local function get_date_format() return config.date_format end -Widget_date = defclass(Widget_date, overlay.OverlayWidget) +DateWidget = defclass(DateWidget, overlay.OverlayWidget) +DateWidget.ATTRS{ + default_pos={x=-16,y=1}, + viewscreens={'dungeonmode', 'dwarfmode'}, +} -function Widget_date:init() +function DateWidget:init() self.datestr = '' self.fmt = get_date_format() end -function Widget_date:overlay_onupdate() +function DateWidget:overlay_onupdate() local year = dfhack.world.ReadCurrentYear() local month = dfhack.world.ReadCurrentMonth() + 1 local day = dfhack.world.ReadCurrentDay() @@ -86,22 +94,26 @@ function Widget_date:overlay_onupdate() self.datestr = datestr end -function Widget_date:onRenderBody(dc) +function DateWidget:onRenderBody(dc) dc:string(self.datestr, COLOR_GREY) end --- ------------- --- Widget_misery --- ------------- +-- ------------ -- +-- MiseryWidget -- +-- ------------ -- -Widget_misery = defclass(Widget_misery, overlay.OverlayWidget) +MiseryWidget = defclass(MiseryWidget, overlay.OverlayWidget) +MiseryWidget.ATTRS{ + default_pos={x=-2,y=-1}, + viewscreens={'dwarfmode'}, +} -function Widget_misery:init() +function MiseryWidget:init() self.colors = getStressCategoryColors() self.stress_category_counts = {} end -function Widget_misery:overlay_onupdate() +function MiseryWidget:overlay_onupdate() local counts, num_colors = {}, #self.colors for _,unit in ipairs(df.global.world.units.active) do local stress_category = math.min(num_colors, @@ -118,7 +130,7 @@ function Widget_misery:overlay_onupdate() self.frame.w = width end -function Widget_misery:onRenderBody(dc) +function MiseryWidget:onRenderBody(dc) dc:string('H:', COLOR_WHITE) local counts = self.stress_category_counts for i,color in ipairs(self.colors) do @@ -127,13 +139,17 @@ function Widget_misery:onRenderBody(dc) end end --- ------------- --- Widget_cursor --- ------------- +-- ------------ -- +-- CursorWidget -- +-- ------------ -- -Widget_cursor = defclass(Widget_cursor, overlay.OverlayWidget) +CursorWidget = defclass(CursorWidget, overlay.OverlayWidget) +CursorWidget.ATTRS{ + default_pos={x=2,y=-4}, + viewscreens={'dungeonmode', 'dwarfmode'}, +} -function Widget_cursor:onRenderBody(dc) +function CursorWidget:onRenderBody(dc) local screenx, screeny = dfhack.screen.getMousePos() local mouse_map = dfhack.gui.getMousePos() local keyboard_map = guidm.getCursorPos() @@ -157,4 +173,12 @@ function Widget_cursor:onRenderBody(dc) self.frame.h = #text end +-- register our widgets with the overlay +OVERLAY_WIDGETS = { + cursor=CursorWidget, + date=DateWidget, + misery=MiseryWidget, + weather=WeatherWidget, +} + return _ENV From 722f70437ccf59aa68f5c1a608f4e6213d42d2d7 Mon Sep 17 00:00:00 2001 From: myk002 Date: Fri, 11 Nov 2022 17:42:18 -0800 Subject: [PATCH 3/5] update dwarfmonitor docs --- docs/plugins/dwarfmonitor.rst | 91 +++++++++-------------------------- 1 file changed, 23 insertions(+), 68 deletions(-) diff --git a/docs/plugins/dwarfmonitor.rst b/docs/plugins/dwarfmonitor.rst index 79472ae58..75e261171 100644 --- a/docs/plugins/dwarfmonitor.rst +++ b/docs/plugins/dwarfmonitor.rst @@ -2,7 +2,7 @@ dwarfmonitor ============ .. dfhack-tool:: - :summary: Measure fort happiness and efficiency. + :summary: Report on dwarf preferences and efficiency. :tags: fort inspection jobs units It can also show heads-up display widgets with live fort statistics. @@ -11,84 +11,39 @@ Usage ----- ``enable dwarfmonitor`` - Enable the plugin. -``dwarfmonitor enable `` - Start tracking a specific facet of fortress life. The ``mode`` can be - "work", "misery", "date", "weather", or "all". This will show the - corresponding on-screen widgets, if applicable. -``dwarfmonitor disable `` - Stop monitoring ``mode`` and disable corresponding widgets. + Enable tracking of job efficiency for display on the ``dwarfmonitor stats`` + screen. ``dwarfmonitor stats`` - Show statistics summary. + Show statistics and efficiency summary. ``dwarfmonitor prefs`` - Show summary of dwarf preferences. -``dwarfmonitor reload`` - Reload the widget configuration file (``dfhack-config/dwarfmonitor.json``). + Show a summary of preferences for dwarves in your fort. Widget configuration -------------------- -The following types of widgets (defined in -:file:`hack/lua/plugins/dwarfmonitor.lua`) can be displayed on the main fortress -mode screen: +The following widgets are registered for display on the main fortress mode +screen with the `overlay` framework: -``misery`` - Show overall happiness levels of all dwarves. -``date`` +``dwarfmonitor.cursor`` + Show the current keyboard and mouse cursor positions. +``dwarfmonitor.date`` Show the in-game date. -``weather`` +``dwarfmonitor.misery`` + Show overall happiness levels of all dwarves. +``dwarfmonitor.weather`` Show current weather (e.g. rain/snow). -``cursor`` - Show the current mouse cursor position. - -The file :file:`dfhack-config/dwarfmonitor.json` can be edited to control the -positions and settings of all widgets. This file should contain a JSON object -with the key ``widgets`` containing an array of objects: - -.. code-block:: lua - - { - "widgets": [ - { - "type": "widget type (weather, misery, etc.)", - "x": X coordinate, - "y": Y coordinate - <...additional options...> - } - ] - } - -X and Y coordinates begin at zero (in the upper left corner of the screen). -Negative coordinates will be treated as distances from the lower right corner, -beginning at 1 - e.g. an x coordinate of 0 is the leftmost column, while an x -coordinate of -1 is the rightmost column. - -By default, the x and y coordinates given correspond to the leftmost tile of -the widget. Including an ``anchor`` option set to ``right`` will cause the -rightmost tile of the widget to be located at this position instead. - -Some widgets support additional options: - -* ``date`` widget: - - * ``format``: specifies the format of the date. The following characters - are replaced (all others, such as punctuation, are not modified) - * ``Y`` or ``y``: The current year - * ``M``: The current month, zero-padded if necessary - * ``m``: The current month, *not* zero-padded - * ``D``: The current day, zero-padded if necessary - * ``d``: The current day, *not* zero-padded +They can be enabled or disable via the `overlay` command. - The default date format is ``Y-M-D``, per the ISO8601_ standard. +The :file:`dfhack-config/dwarfmonitor.json` file can be edited to specify the +format for the ``dwarfmonitor.date`` widget: - .. _ISO8601: https://en.wikipedia.org/wiki/ISO_8601 +* ``Y`` or ``y``: The current year +* ``M``: The current month, zero-padded if necessary +* ``m``: The current month, *not* zero-padded +* ``D``: The current day, zero-padded if necessary +* ``d``: The current day, *not* zero-padded -* ``cursor`` widget: +The default date format is ``Y-M-D``, per the ISO8601_ standard. - * ``format``: Specifies the format. ``X``, ``x``, ``Y``, and ``y`` are - replaced with the corresponding cursor coordinates, while all other - characters are unmodified. - * ``show_invalid``: If set to ``true``, the mouse coordinates will both be - displayed as ``-1`` when the cursor is outside of the DF window; otherwise, - nothing will be displayed. +.. _ISO8601: https://en.wikipedia.org/wiki/ISO_8601 From 52e850917e9b44e0f723c3ccf2de2969afe86dcc Mon Sep 17 00:00:00 2001 From: myk002 Date: Fri, 11 Nov 2022 17:43:35 -0800 Subject: [PATCH 4/5] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 4465a0f12..9c6940cd0 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -53,6 +53,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `blueprint`: generate meta blueprints to reduce the number of blueprints you have to apply - `blueprint`: support splitting the output file into phases grouped by when they can be applied - `blueprint`: when splitting output files, number them so they sort into the order you should apply them in +- `dwarfmonitor`: widgets have been ported to the overlay framework and can be enabled and configured via the overlay command - `ls`: indent tag listings and wrap them in the right column for better readability - `ls`: new ``--exclude`` option for hiding matched scripts from the output. this can be especially useful for modders who don't want their mod scripts to be included in ``ls`` output. - `digtype`: new ``-z`` option for digtype to restrict designations to the current z-level and down From e3498f275fca456fb8d33f27b6ed809cb2bebb22 Mon Sep 17 00:00:00 2001 From: myk002 Date: Mon, 14 Nov 2022 15:23:30 -0800 Subject: [PATCH 5/5] fix dwarfmonitor weather widget --- plugins/lua/dwarfmonitor.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/lua/dwarfmonitor.lua b/plugins/lua/dwarfmonitor.lua index 866aa609a..e8c07cac6 100644 --- a/plugins/lua/dwarfmonitor.lua +++ b/plugins/lua/dwarfmonitor.lua @@ -27,8 +27,8 @@ function WeatherWidget:overlay_onupdate() for i=0,4 do for j=0,4 do weather = cw[i][j] - if weather == df.weather_type.Rain then self.rain = true end - if weather == df.weather_type.Snow then self.snow = true end + if weather == df.weather_type.Rain then rain = true end + if weather == df.weather_type.Snow then snow = true end end end self.frame.w = (rain and 4 or 0) + (snow and 4 or 0) +