diff --git a/docs/changelog.txt b/docs/changelog.txt index b2cd693a5..1df3e567f 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -70,6 +70,7 @@ Template for new versions: - `sort`: allow searching by profession on the squad assignment page - `sort`: add search for work animal assignment screen; allow filtering by miltary/squad/civilian/burrow - `sort`: on the squad assignment screen, make effectiveness and potential ratings use the same scale so effectiveness is always less than or equal to potential for a unit and so you can tell when units are approaching their maximum potential +- `sort`: new overlay on the animal assignment screen that shows how many work animals each visible unit already has assigned to them - `dreamfort`: Inside+ and Clearcutting burrows now automatically created and managed ## Documentation @@ -77,6 +78,8 @@ Template for new versions: ## API - ``Gui::revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target - ``Maps::getWalkableGroup``: get the walkability group of a tile +- ``Units::getReadableName``: now returns the *untranslated* name +- ``Burrows::setAssignedUnit``: now properly handles inactive burrows ## Lua - ``dfhack.gui.revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 95033d949..eb3e20663 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -105,6 +105,13 @@ can search for that text as well. This is often a job name or a status, like "caged". The work animal assignment page can also filter by squad or burrow membership. +Work animals overlay +-------------------- + +In addition to the search and filter widgets provided by the Info tabs overlay, +the work animal assignment screen has an additional overlay that annotates each +visible unit with the number of work animals that unit already has. + Interrogation overlay --------------------- diff --git a/library/modules/Burrows.cpp b/library/modules/Burrows.cpp index 9e63c0dbc..afd6ac9e3 100644 --- a/library/modules/Burrows.cpp +++ b/library/modules/Burrows.cpp @@ -78,8 +78,10 @@ void Burrows::clearUnits(df::burrow *burrow) { auto unit = df::unit::find(burrow->units[i]); - if (unit) + if (unit) { erase_from_vector(unit->burrows, burrow->id); + erase_from_vector(unit->inactive_burrows, burrow->id); + } } burrow->units.clear(); @@ -90,7 +92,8 @@ bool Burrows::isAssignedUnit(df::burrow *burrow, df::unit *unit) CHECK_NULL_POINTER(unit); CHECK_NULL_POINTER(burrow); - return binsearch_index(unit->burrows, burrow->id) >= 0; + return binsearch_index(unit->burrows, burrow->id) >= 0 || + binsearch_index(unit->inactive_burrows, burrow->id) >= 0; } void Burrows::setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable) @@ -100,14 +103,15 @@ void Burrows::setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable) CHECK_NULL_POINTER(unit); CHECK_NULL_POINTER(burrow); - if (enable) - { - insert_into_vector(unit->burrows, burrow->id); + if (enable) { + if (burrow->limit_workshops & 2) // inactive flag + insert_into_vector(unit->inactive_burrows, burrow->id); + else + insert_into_vector(unit->burrows, burrow->id); insert_into_vector(burrow->units, unit->id); - } - else - { + } else { erase_from_vector(unit->burrows, burrow->id); + erase_from_vector(unit->inactive_burrows, burrow->id); erase_from_vector(burrow->units, unit->id); } } diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index a6a28239d..4fba833d9 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -252,6 +252,8 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) newFocusString += "/ActivityDetails"; else if (game->main_interface.info.creatures.adding_trainer) newFocusString += "/AddingTrainer"; + else if (game->main_interface.info.creatures.assign_work_animal) + newFocusString += "/AssignWorkAnimal"; else newFocusString += '/' + enum_item_key(game->main_interface.info.creatures.current_mode); break; diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index a9d361706..ff36481b7 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -1282,7 +1282,7 @@ string Units::getReadableName(df::unit* unit) { race_name = "hunter " + race_name; if (isWar(unit)) race_name = "war " + race_name; - string name = Translation::TranslateName(getVisibleName(unit)); + string name = Translation::TranslateName(getVisibleName(unit), false); if (name.empty()) { name = race_name; } else { diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index bc2991891..6b9c963bd 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1289,6 +1289,7 @@ OVERLAY_WIDGETS = { squad_assignment=SquadAssignmentOverlay, squad_annotation=SquadAnnotationOverlay, info=require('plugins.sort.info').InfoOverlay, + workanimals=require('plugins.sort.info').WorkAnimalOverlay, candidates=require('plugins.sort.info').CandidatesOverlay, interrogation=require('plugins.sort.info').InterrogationOverlay, location_selector=require('plugins.sort.locationselector').LocationSelectorOverlay, diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index 9110ec825..8d4a0a802 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -1,6 +1,7 @@ local _ENV = mkmodule('plugins.sort.info') local gui = require('gui') +local overlay = require('plugins.overlay') local sortoverlay = require('plugins.sort.sortoverlay') local widgets = require('gui.widgets') local utils = require('utils') @@ -179,7 +180,10 @@ local function get_squad_options() end local function get_burrow_options() - local options = {{label='Any', value='all', pen=COLOR_GREEN}} + local options = { + {label='Any', value='all', pen=COLOR_GREEN}, + {label='Unburrowed', value='none', pen=COLOR_LIGHTRED}, + } for _, burrow in ipairs(df.global.plotinfo.burrows.list) do table.insert(options, { label=#burrow.name > 0 and burrow.name or ('Burrow %d'):format(burrow.id + 1), @@ -409,8 +413,9 @@ function InfoOverlay:matches_filters(unit) return target_id == squad_id elseif subset == 'burrow' then local target_id = self.subviews.burrow:getOptionValue() - if target_id == 'all' then return true end - return utils.binsearch(unit.burrows, target_id) + if target_id == 'all' then return #unit.burrows + #unit.inactive_burrows > 0 end + if target_id == 'none' then return #unit.burrows + #unit.inactive_burrows == 0 end + return utils.binsearch(unit.burrows, target_id) or utils.binsearch(unit.inactive_burrows, target_id) end return true end @@ -469,6 +474,73 @@ function CandidatesOverlay:onRenderBody(dc) end end +-- ---------------------- +-- WorkAnimalOverlay +-- + +WorkAnimalOverlay = defclass(WorkAnimalOverlay, overlay.OverlayWidget) +WorkAnimalOverlay.ATTRS{ + default_pos={x=-33, y=12}, + viewscreens='dwarfmode/Info/CREATURES/AssignWorkAnimal', + default_enabled=true, + frame={w=29, h=1}, +} + +function WorkAnimalOverlay:init() + self:addviews{ + widgets.Label{ + view_id='annotations', + frame={t=0, l=0}, + text='', + } + } +end + +local function get_work_animal_counts() + local counts = {} + for _,unit in ipairs(df.global.world.units.active) do + if not dfhack.units.isOwnCiv(unit) or + (not dfhack.units.isWar(unit) and not dfhack.units.isHunter(unit)) + then + goto continue + end + local owner_id = unit.relationship_ids.Pet + if owner_id == -1 then goto continue end + counts[owner_id] = (counts[owner_id] or 0) + 1 + ::continue:: + end + return counts +end + +function WorkAnimalOverlay:onRenderFrame(dc, rect) + local _, sh = dfhack.screen.getWindowSize() + local _, t = get_panel_offsets() + local list_height = sh - (17 + t) + local num_elems = list_height // 3 + local max_elem = math.min(#creatures.work_animal_recipient-1, + creatures.scroll_position_work_animal+num_elems-1) + + local annotations = {} + local counts = get_work_animal_counts() + for idx=creatures.scroll_position_work_animal,max_elem do + table.insert(annotations, NEWLINE) + table.insert(annotations, NEWLINE) + local animal_count = counts[creatures.work_animal_recipient[idx].id] + if animal_count and animal_count > 0 then + table.insert(annotations, {text='[', pen=COLOR_RED}) + table.insert(annotations, ('Assigned work animals: %d'):format(animal_count)) + table.insert(annotations, {text=']', pen=COLOR_RED}) + end + table.insert(annotations, NEWLINE) + end + + self.subviews.annotations.frame.t = t + self.subviews.annotations:setText(annotations) + self.frame.h = list_height + t + + WorkAnimalOverlay.super.onRenderFrame(self, dc, rect) +end + -- ---------------------- -- InterrogationOverlay --