Skip to content

Commit 1b9f8c6

Browse files
authored
Merge pull request #1537 from SilasD/notify-nemesis2
Update notification case: missing nemesis records
2 parents ca71e41 + 8ab8891 commit 1b9f8c6

2 files changed

Lines changed: 74 additions & 31 deletions

File tree

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Template for new versions:
3535
## Fixes
3636

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

3940
## Removed
4041

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

0 commit comments

Comments
 (0)