From d739d9c1ef85ef9f8afcede8e8b2ac9ca08bda70 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Oct 2023 14:33:22 -0700 Subject: [PATCH] add search support for noble candidates --- docs/changelog.txt | 2 +- docs/plugins/sort.rst | 9 +++++ plugins/lua/sort.lua | 1 + plugins/lua/sort/info.lua | 83 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 90 insertions(+), 5 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 2163305cf..5d83dc4cf 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,7 +57,7 @@ Template for new versions: ## New Features - `logistics`: ``automelt`` now optionally supports melting masterworks; click on gear icon on `stockpiles` overlay frame -- `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", and the "Work details" subtab under "Labor" +- `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", candidate assignment on the "Noble" subtab, and the "Work details" subtab under "Labor" - `sort`: new search and filter widgets for the "Interrogate" and "Convict" screens under "Justice" - `sort`: new search widgets for location selection screen (when you're choosing what kind of guildhall or temple to dedicate) - `sort`: new search widgets for burrow assignment screen and other unit assignment dialogs diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 0ffe5118b..4350a4cb0 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -115,6 +115,15 @@ necromancers, necromancer experiments, and intelligent undead. On the interrogations screen, you can also filter units by whether they have already been interrogated. +Candidates overlay +------------------ + +When you select the button to choose a candidate to assign to a noble role on +the nobles screen, you can search for units by name, profession, or any of the +skills in which they have achieved at least "novice" level. For example, when +assigning a broker, you can search for "appraisal" to find candidates that have +at least some appraisal skill. + Location selection overlay -------------------------- diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 2a98ff42c..58974a357 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1286,6 +1286,7 @@ OVERLAY_WIDGETS = { squad_assignment=SquadAssignmentOverlay, squad_annotation=SquadAnnotationOverlay, info=require('plugins.sort.info').InfoOverlay, + candidates=require('plugins.sort.info').CandidatesOverlay, interrogation=require('plugins.sort.info').InterrogationOverlay, location_selector=require('plugins.sort.locationselector').LocationSelectorOverlay, unit_selector=require('plugins.sort.unitselector').UnitSelectorOverlay, diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index 90a4e2348..1f15d643b 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -6,6 +6,7 @@ local widgets = require('gui.widgets') local utils = require('utils') local info = df.global.game.main_interface.info +local administrators = info.administrators local creatures = info.creatures local justice = info.justice local objects = info.artifacts @@ -135,7 +136,7 @@ local function work_details_search(vec, data, text, incremental) vec, data, text, incremental) end -local function cleanup_cri_unit(vec, data) +local function restore_allocated_data(vec, data) if not data.saved_visible or not data.saved_original then return end for _,elem in ipairs(data.saved_original) do if not utils.linear_index(data.saved_visible, elem) then @@ -144,6 +145,26 @@ local function cleanup_cri_unit(vec, data) end end +local function serialize_skills(unit) + if not unit or not unit.status or not unit.status.current_soul then + return '' + end + local skills = {} + for _, skill in ipairs(unit.status.current_soul.skills) do + if skill.rating > 0 then -- ignore dabbling + table.insert(skills, df.job_skill[skill.id]) + end + end + return table.concat(skills, ' ') +end + +local function get_candidate_search_key(cand) + if not cand.un then return end + return ('%s %s'):format( + get_unit_search_key(cand.un), + serialize_skills(cand.un)) +end + -- ---------------------- -- InfoOverlay -- @@ -186,12 +207,12 @@ function InfoOverlay:init() get_search_key_fn=get_cri_unit_search_key, get_sort_fn=get_sort }), - curry(cleanup_cri_unit, vec)) + curry(restore_allocated_data, vec)) end self:register_handler('JOBS', tasks.cri_job, curry(sortoverlay.single_vector_search, {get_search_key_fn=get_cri_unit_search_key}), - curry(cleanup_cri_unit, vec)) + curry(restore_allocated_data, tasks.cri_job)) self:register_handler('PET_OT', creatures.atk_index, curry(sortoverlay.single_vector_search, {get_search_key_fn=get_race_name})) self:register_handler('PET_AT', creatures.trainer, @@ -259,7 +280,7 @@ function InfoOverlay:updateFrames() local ret = resize_overlay(self) local l, t = get_panel_offsets() local frame = self.subviews.panel.frame - if (frame.l == l and frame.t == t) then return ret end + if frame.l == l and frame.t == t then return ret end frame.l, frame.t = l, t return true end @@ -282,6 +303,60 @@ function InfoOverlay:onInput(keys) return InfoOverlay.super.onInput(self, keys) end +-- ---------------------- +-- CandidatesOverlay +-- + +CandidatesOverlay = defclass(CandidatesOverlay, sortoverlay.SortOverlay) +CandidatesOverlay.ATTRS{ + default_pos={x=54, y=8}, + viewscreens='dwarfmode/Info/ADMINISTRATORS/Candidates', + frame={w=27, h=3}, +} + +function CandidatesOverlay:init() + self:addviews{ + widgets.BannerPanel{ + view_id='panel', + frame={l=0, t=0, r=0, h=1}, + subviews={ + widgets.EditField{ + view_id='search', + frame={l=1, t=0, r=1}, + label_text="Search: ", + key='CUSTOM_ALT_S', + on_change=function(text) self:do_search(text) end, + }, + }, + }, + } + + self:register_handler('CANDIDATE', administrators.candidate, + curry(sortoverlay.single_vector_search, {get_search_key_fn=get_candidate_search_key}), + curry(restore_allocated_data, administrators.candidate)) +end + +function CandidatesOverlay:get_key() + if administrators.choosing_candidate then + return 'CANDIDATE' + end +end + +function CandidatesOverlay:updateFrames() + local t = is_tabs_in_two_rows() and 2 or 0 + local frame = self.subviews.panel.frame + if frame.t == t then return end + frame.t = t + return true +end + +function CandidatesOverlay:onRenderBody(dc) + CandidatesOverlay.super.onRenderBody(self, dc) + if self:updateFrames() then + self:updateLayout() + end +end + -- ---------------------- -- InterrogationOverlay --