Skip to content

Commit d3459f7

Browse files
authored
Merge branch 'DFHack:master' into door-toggle
2 parents 3242c73 + 1b9f8c6 commit d3459f7

File tree

4 files changed

+102
-40
lines changed

4 files changed

+102
-40
lines changed

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ repos:
2020
args: ['--fix=lf']
2121
- id: trailing-whitespace
2222
- repo: https://github.com/python-jsonschema/check-jsonschema
23-
rev: 0.36.0
23+
rev: 0.36.1
2424
hooks:
2525
- id: check-github-workflows
2626
- repo: https://github.com/Lucas-C/pre-commit-hooks
27-
rev: v1.5.5
27+
rev: v1.5.6
2828
hooks:
2929
- id: forbid-tabs
3030
exclude_types:

changelog.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Template for new versions:
1818

1919
## Fixes
2020

21+
- `prioritize`: Fix the overlay appearing where it should not when following a unit
22+
2123
## Misc Improvements
2224

2325
## Removed
@@ -33,6 +35,7 @@ Template for new versions:
3335
## Fixes
3436

3537
## Misc Improvements
38+
- `gui/notify`: reduced severity of the missing nemesis records warning if no units on the map are affected. clarified wording.
3639

3740
## Removed
3841

internal/notify/notifications.lua

Lines changed: 73 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -335,24 +335,25 @@ local function save_popup()
335335
end
336336
end
337337

338-
---@return string[]
339-
local function get_active_units_with_missing_nemesis_records()
340-
local namelist = {}
341-
for _, unit in ipairs(df.global.world.units.active) do
338+
---@return df.unit.id[]
339+
local function _get_active_unit_ids_with_missing_nemesis_records()
340+
local list = {}
341+
for _, unit in ipairs(units.active) do
342342
local ref = dfhack.units.getGeneralRef(unit, df.general_ref_type.IS_NEMESIS)
343343
if ref then
344344
local nrec = ref:getNemesis()
345345
if nrec == nil then
346-
table.insert(namelist, dfhack.units.getReadableName(unit))
346+
table.insert(list, unit.id)
347347
end
348348
end
349349
end
350-
return namelist
350+
return list
351351
end
352352

353-
---@param vector any[] # a df vector or array, or a Lua list.
353+
---@generic T
354+
---@param vector `T`[] # a df vector or array, or a Lua list (not tested yet).
354355
---@param field string? # nil, or the field name to sort on.
355-
---@param comparator fun(a:any, b:any):integer|nil
356+
---@param comparator fun(a:T, b:T):integer|nil
356357
--- # an optional comparator that returns -1,0,1 per utils.compare_* .
357358
--- # nil falls back to utils.compare or utils.compare_field.
358359
--- # if a comparator is given, the field parameter is ignored.
@@ -378,17 +379,46 @@ local function verify_vector_is_sorted(vector, field, comparator)
378379
return sorted
379380
end
380381

381-
local cache_nemesis_all_is_sorted = {}
382-
---only verifies if the vector length has changed.
383-
---@return boolean
384-
local function verify_nemesis_all_is_sorted()
385-
local vector = df.global.world.nemesis.all
386-
if #vector == cache_nemesis_all_is_sorted.length then
387-
return cache_nemesis_all_is_sorted.sorted
382+
local Cache_nemesis_all = defclass(Cache_nemesis_all, nil) -- singleton, don't need to instantiate.
383+
Cache_nemesis_all.ATTRS{}
384+
385+
function Cache_nemesis_all:invalidate()
386+
self.ATTRS.cached_on_year = -1
387+
end
388+
389+
---@param force boolean? # true to force updating the cached data
390+
function Cache_nemesis_all:populate(force)
391+
local recheck_after = (self.ATTRS.cached_on_tick or 0) + 1200
392+
if force ~= true
393+
and dfhack.world.ReadCurrentYear() == self.ATTRS.cached_on_year
394+
and dfhack.world.ReadCurrentTick() < recheck_after
395+
and self.ATTRS.nemesis_all_length == #df.global.world.nemesis.all
396+
and self.ATTRS.units_active_length == #df.global.world.units.active
397+
then
398+
return
388399
end
389-
cache_nemesis_all_is_sorted.length = #vector
390-
cache_nemesis_all_is_sorted.sorted = verify_vector_is_sorted(vector, 'id')
391-
return cache_nemesis_all_is_sorted.sorted
400+
self.ATTRS.cached_on_year = dfhack.world.ReadCurrentYear()
401+
self.ATTRS.cached_on_tick = dfhack.world.ReadCurrentTick()
402+
self.ATTRS.nemesis_all_length = #df.global.world.nemesis.all
403+
self.ATTRS.units_active_length = #df.global.world.units.active
404+
self.ATTRS.nemesis_all_is_sorted = verify_vector_is_sorted(df.global.world.nemesis.all, 'id')
405+
self.ATTRS.affected_unit_ids = _get_active_unit_ids_with_missing_nemesis_records()
406+
end
407+
408+
function Cache_nemesis_all:init()
409+
self:invalidate()
410+
end
411+
412+
---@return boolean
413+
function Cache_nemesis_all:is_sorted()
414+
self:populate()
415+
return self.ATTRS.nemesis_all_is_sorted
416+
end
417+
418+
---@return df.unit[]
419+
function Cache_nemesis_all:get_affected_unit_ids()
420+
self:populate()
421+
return self.ATTRS.affected_unit_ids
392422
end
393423

394424
-- the order of this list controls the order the notifications will appear in the overlay
@@ -398,7 +428,7 @@ NOTIFICATIONS_BY_IDX = {
398428
desc='Reports missing nemesis records, indicating savegame corruption.',
399429
default=true,
400430
fn = function()
401-
if not verify_nemesis_all_is_sorted() then
431+
if not Cache_nemesis_all:is_sorted() then
402432
return { {
403433
pen = COLOR_LIGHTRED,
404434
text = 'nemesis vector not sorted'
@@ -407,12 +437,13 @@ NOTIFICATIONS_BY_IDX = {
407437
local count = df.global.nemesis_next_id - #df.global.world.nemesis.all
408438
if count == 0 then return end
409439
return { {
410-
pen = COLOR_LIGHTRED,
440+
pen = #Cache_nemesis_all:get_affected_unit_ids() > 0
441+
and COLOR_LIGHTRED or COLOR_YELLOW,
411442
text = ('missing %d nemesis record%s'):format(count, count == 1 and '' or 's')
412443
} }
413444
end,
414445
on_click=function()
415-
if not verify_nemesis_all_is_sorted() then
446+
if not Cache_nemesis_all:is_sorted() then
416447
local message =
417448
'This save game is corrupt.\n\nThe world.nemesis.global vector\n' ..
418449
'of this savegame is not sorted.\n\nSome attempts to lookup the\n' ..
@@ -421,6 +452,7 @@ NOTIFICATIONS_BY_IDX = {
421452
dlg.showMessage('nemesis vector not sorted', message, COLOR_RED)
422453
return
423454
end
455+
local list = Cache_nemesis_all:get_affected_unit_ids()
424456
local message = {
425457
{ pen = COLOR_RED, text = 'This save game may be corrupt.' }, NEWLINE,
426458
NEWLINE,
@@ -431,23 +463,31 @@ NOTIFICATIONS_BY_IDX = {
431463
{ pen = COLOR_WHITE, text = 'crashes during game save and when retiring forts.' }, NEWLINE,
432464
NEWLINE,
433465
{ pen = COLOR_WHITE, text = 'Units with missing nemesis records will' }, NEWLINE,
434-
{ pen = COLOR_RED, text = 'permanently disappear' },
466+
{ pen = #list > 0 and COLOR_RED or COLOR_WHITE,
467+
text = 'permanently disappear' },
435468
{ pen = COLOR_WHITE, text = ' if they leave the map or' }, NEWLINE,
436469
{ pen = COLOR_WHITE, text = 'if the fort is retired.' }, NEWLINE,
437470
NEWLINE,
438471
}
439-
local redtext = get_active_units_with_missing_nemesis_records()
440-
if #redtext > 0 then
472+
if #list > 0 then
441473
table.insert(message, { pen = COLOR_RED,
442-
text = 'These active units are missing their nemesis records:' })
474+
text = 'These units on the map are missing their nemesis records:' })
443475
table.insert(message, NEWLINE)
444-
for _, line in ipairs(redtext) do
445-
table.insert(message, { pen = COLOR_LIGHTRED, text = ' ' .. line })
476+
for _, unit_id in ipairs(list) do
477+
local unit = df.unit.find(unit_id)
478+
local text = unit and dfhack.units.getReadableName(unit)
479+
or "missing unit for unit id " .. unit_id
480+
if #text > 55 then text = dfhack.units.getReadableName(unit, true); end
481+
table.insert(message, { pen = COLOR_LIGHTRED, text = text })
446482
table.insert(message, NEWLINE)
447483
end
484+
else
485+
table.insert(message, { pen = COLOR_YELLOW,
486+
text = 'No units on the map are missing their nemesis records.' })
487+
table.insert(message, NEWLINE)
448488
end
449-
dlg.showMessage((#redtext > 0 and 'Active units are' or 'This world is')
450-
.. ' missing nemesis records',message, COLOR_WHITE)
489+
dlg.showMessage((#list > 0 and 'Units on the map are' or 'This world is')
490+
.. ' missing nemesis records', message, COLOR_WHITE)
451491
end,
452492
},
453493
{
@@ -728,7 +768,9 @@ end
728768
config = get_config()
729769

730770
dfhack.onStateChange['internal/notify/notifications'] = function(event)
731-
if event == SC_WORLD_LOADED or event == SC_WORLD_UNLOADED then
732-
cache_nemesis_all_is_sorted = {}
771+
if event == SC_WORLD_LOADED or event == SC_WORLD_UNLOADED
772+
or event == SC_MAP_LOADED or event == SC_MAP_UNLOADED
773+
then
774+
Cache_nemesis_all:invalidate()
733775
end
734776
end

prioritize.lua

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -658,11 +658,28 @@ end
658658
-- EnRouteOverlay
659659
--
660660

661+
--- Return the selected active construction or destruction job
662+
local function getSelectedActiveBuildingJob()
663+
-- This is not relying on dfhack.gui.getSelectedJob() because we don't want
664+
-- the job of a selected or followed unit, only of a selected building
665+
local building = dfhack.gui.getSelectedBuilding(true)
666+
if not building then
667+
return nil
668+
end
669+
670+
-- Find if the building is being constructed
671+
for _, job in ipairs(building.jobs) do
672+
if not job.flags.suspend and (job.job_type == df.job_type.ConstructBuilding or job.job_type == df.job_type.ConstructBuilding) then
673+
return job
674+
end
675+
end
676+
677+
return nil
678+
end
679+
680+
661681
local function is_visible()
662-
local job = dfhack.gui.getSelectedJob(true)
663-
return job and not job.flags.suspend and
664-
(job.job_type == df.job_type.DestroyBuilding or
665-
job.job_type == df.job_type.ConstructBuilding)
682+
return getSelectedActiveBuildingJob() ~= nil
666683
end
667684

668685
EnRouteOverlay = defclass(EnRouteOverlay, overlay.OverlayWidget)
@@ -693,7 +710,7 @@ function EnRouteOverlay:init()
693710
label='Make top priority:',
694711
key='CUSTOM_CTRL_T',
695712
on_change=function(val)
696-
local job = dfhack.gui.getSelectedJob(true)
713+
local job = getSelectedActiveBuildingJob()
697714
if not job then return end
698715
job.flags.do_now = val
699716
end,
@@ -712,7 +729,7 @@ function EnRouteOverlay:get_builder_name_pen()
712729
end
713730

714731
function EnRouteOverlay:zoom_to_builder()
715-
local job = dfhack.gui.getSelectedJob(true)
732+
local job = getSelectedActiveBuildingJob()
716733
if not job then return end
717734
local builder = dfhack.job.getWorker(job)
718735
if builder then
@@ -721,7 +738,7 @@ function EnRouteOverlay:zoom_to_builder()
721738
end
722739

723740
function EnRouteOverlay:render(dc)
724-
local job = dfhack.gui.getSelectedJob(true)
741+
local job = getSelectedActiveBuildingJob()
725742
self.builder = dfhack.job.getWorker(job)
726743
self.subviews.do_now:setOption(job.flags.do_now)
727744
EnRouteOverlay.super.render(self, dc)

0 commit comments

Comments
 (0)