@@ -12,10 +12,27 @@ local widgets = require('gui.widgets')
1212local presets_file = json .open (" dfhack-config/mod-manager.json" )
1313local GLOBAL_KEY = ' mod-manager'
1414
15- -- get_newregion_viewscreen and get_modlist_fields are declared as global functions
16- -- so external tools can call them to get the DF mod list
17- function get_newregion_viewscreen ()
15+ local function vanilla (dir )
16+ return dir :startswith (' data/vanilla' )
17+ end
18+
19+ -- get_moddable_viewscreen(), get_any_moddable_viewscreen() and get_modlist_fields are declared
20+ -- as global functions so external tools can call them to get the DF mod list
21+ function get_moddable_viewscreen (type )
22+ local vs = nil
23+ if type == ' region' then
24+ vs = dfhack .gui .getViewscreenByType (df .viewscreen_new_regionst , 0 )
25+ elseif type == ' arena' then
26+ vs = dfhack .gui .getViewscreenByType (df .viewscreen_new_arenast , 0 )
27+ end
28+ return vs
29+ end
30+
31+ function get_any_moddable_viewscreen ()
1832 local vs = dfhack .gui .getViewscreenByType (df .viewscreen_new_regionst , 0 )
33+ if not vs then
34+ vs = dfhack .gui .getViewscreenByType (df .viewscreen_new_arenast , 0 )
35+ end
1936 return vs
2037end
2138
@@ -55,21 +72,30 @@ function get_modlist_fields(kind, viewscreen)
5572 end
5673end
5774
75+ --- @return boolean # true if the mod entry was moved; false if the mod or mod version was not found.
76+ --- @return string | nil # loaded version - DISPLAYED_VERSION from the mod's info.txt
5877local function move_mod_entry (viewscreen , to , from , mod_id , mod_version )
5978 local to_fields = get_modlist_fields (to , viewscreen )
6079 local from_fields = get_modlist_fields (from , viewscreen )
6180
6281 local mod_index = nil
82+ local loaded_version = nil
6383 for i , v in ipairs (from_fields .id ) do
6484 local version = from_fields .numeric_version [i ]
65- if v .value == mod_id and version == mod_version then
85+ local src_dir = from_fields .src_dir [i ]
86+ local displayed_version = from_fields .displayed_version [i ].value
87+ -- assumes that vanilla mods will not have multiple possible indices.
88+ if v .value == mod_id and (vanilla (src_dir ) or version == mod_version ) then
89+ if version ~= mod_version then
90+ loaded_version = displayed_version
91+ end
6692 mod_index = i
6793 break
6894 end
6995 end
7096
7197 if mod_index == nil then
72- return false
98+ return false , nil
7399 end
74100
75101 for k , v in pairs (to_fields ) do
@@ -80,17 +106,21 @@ local function move_mod_entry(viewscreen, to, from, mod_id, mod_version)
80106 end
81107 end
82108
83- for k , v in pairs (from_fields ) do
109+ for _ , v in pairs (from_fields ) do
84110 v :erase (mod_index )
85111 end
86112
87- return true
113+ return true , loaded_version
88114end
89115
116+ --- @return boolean # true if the mod entry was moved; false if the mod or mod version was not found.
117+ --- @return string | nil # loaded version - DISPLAYED_VERSION from the mod's info.txt
90118local function enable_mod (viewscreen , mod_id , mod_version )
91119 return move_mod_entry (viewscreen , " object_load_order" , " available" , mod_id , mod_version )
92120end
93121
122+ --- @return boolean # true if the mod entry was moved; false if the mod or mod version was not found.
123+ --- @return string | nil # loaded version - DISPLAYED_VERSION from the mod's info.txt
94124local function disable_mod (viewscreen , mod_id , mod_version )
95125 return move_mod_entry (viewscreen , " available" , " object_load_order" , mod_id , mod_version )
96126end
@@ -105,19 +135,25 @@ local function get_active_modlist(viewscreen)
105135 return t
106136end
107137
138+ --- @return string[]
139+ --- @return { id : string , new : string } []
108140local function swap_modlist (viewscreen , modlist )
109141 local current = get_active_modlist (viewscreen )
110142 for _ , v in ipairs (current ) do
111143 disable_mod (viewscreen , v .id , v .version )
112144 end
113145
114146 local failures = {}
147+ local changed = {}
115148 for _ , v in ipairs (modlist ) do
116- if not enable_mod (viewscreen , v .id , v .version ) then
149+ local success , version = enable_mod (viewscreen , v .id , v .version )
150+ if not success then
117151 table.insert (failures , v .id )
152+ elseif version then
153+ table.insert (changed , { id = v .id , new = version })
118154 end
119155 end
120- return failures
156+ return failures , changed
121157end
122158
123159---- ----------------
@@ -137,7 +173,7 @@ ModmanageMenu.ATTRS {
137173}
138174
139175local function save_new_preset (preset_name )
140- local viewscreen = get_newregion_viewscreen ()
176+ local viewscreen = get_any_moddable_viewscreen ()
141177 local modlist = get_active_modlist (viewscreen )
142178 table.insert (presets_file .data , { name = preset_name , modlist = modlist })
143179 presets_file :write ()
@@ -157,27 +193,17 @@ local function overwrite_preset(idx)
157193 return
158194 end
159195
160- local viewscreen = get_newregion_viewscreen ()
196+ local viewscreen = get_any_moddable_viewscreen ()
161197 local modlist = get_active_modlist (viewscreen )
162198 presets_file .data [idx ].modlist = modlist
163199 presets_file :write ()
164200end
165201
166- local function load_preset (idx , unset_default_on_failure )
167- if idx > # presets_file .data then
168- return
169- end
202+ local function prepare_warning (text , failed , changed , unset_default_on_failure )
203+ if not failed and not changed then return end
170204
171- local viewscreen = get_newregion_viewscreen ()
172- local modlist = presets_file .data [idx ].modlist
173- local failures = swap_modlist (viewscreen , modlist )
174-
175- if # failures > 0 then
176- local text = {}
205+ if failed then
177206 if unset_default_on_failure then
178- presets_file .data [idx ].default = false
179- presets_file :write ()
180-
181207 table.insert (text , {
182208 text = ' Failed to load some mods from your default preset.' ,
183209 pen = COLOR_LIGHTRED ,
@@ -193,19 +219,70 @@ local function load_preset(idx, unset_default_on_failure)
193219 pen = COLOR_LIGHTRED ,
194220 })
195221 end
222+ end
223+
224+ if failed and changed then
196225 table.insert (text , NEWLINE )
197- table.insert (text , NEWLINE )
198- table.insert (text , ' Please re-create your preset with mods you currently have installed.' )
199- table.insert (text , NEWLINE )
226+ end
227+
228+ if changed then
229+ table.insert (text , {
230+ text = ' Some vanilla mods have been updated.' ,
231+ pen = COLOR_LIGHTRED ,
232+ })
233+ end
234+ table.insert (text , NEWLINE )
235+ table.insert (text , ' Please re-create your preset with mods you currently have installed.' )
236+ table.insert (text , NEWLINE )
237+ table.insert (text , NEWLINE )
238+ end
239+
240+ local function load_preset (idx , unset_default_on_failure )
241+ if idx > # presets_file .data then
242+ return
243+ end
244+
245+ local viewscreen = get_any_moddable_viewscreen ()
246+ local modlist = presets_file .data [idx ].modlist
247+ local failures , changes = swap_modlist (viewscreen , modlist )
248+ local text = {}
249+
250+ local failed = # failures > 0
251+ local changed = # changes > 0
252+
253+ prepare_warning (text , failed , changed )
254+ if failed and unset_default_on_failure then
255+ presets_file .data [idx ].default = false
256+ presets_file :write ()
257+ end
258+
259+ if failed then
200260 table.insert (text , ' Here are the mods that failed to load:' )
201261 table.insert (text , NEWLINE )
202262 table.insert (text , NEWLINE )
203263 for _ , v in ipairs (failures ) do
204264 table.insert (text , (' - %s' ):format (v ))
205265 table.insert (text , NEWLINE )
206266 end
267+ end
268+
269+ if failed and changed then
270+ table.insert (text , NEWLINE ) -- just to separate the sections
271+ end
272+
273+ if changed then
274+ table.insert (text , ' Here are the vanilla mods that have been updated:' )
275+ table.insert (text , NEWLINE )
276+ table.insert (text , NEWLINE )
277+ for _ , v in ipairs (changes ) do
278+ table.insert (text , (' - %s to %s' ):format (v .id , v .new ))
279+ table.insert (text , NEWLINE )
280+ end
281+ end
282+
283+ if failed or changed then
207284 dialogs .showMessage (" Warning" , text )
208- end
285+ end
209286end
210287
211288local function find_preset_by_name (name )
@@ -573,7 +650,7 @@ ModmanageOverlay.ATTRS {
573650 desc = " Adds a link to the mod selection screen for accessing the mod manager." ,
574651 default_pos = { x = 5 , y =- 6 },
575652 version = 2 ,
576- viewscreens = { " new_region/Mods" },
653+ viewscreens = { " new_region/Mods" , " new_arena/Mods " },
577654 default_enabled = true ,
578655}
579656
@@ -636,7 +713,7 @@ notification_timer_fn()
636713local default_applied = false
637714dfhack .onStateChange [GLOBAL_KEY ] = function (sc )
638715 if sc == SC_VIEWSCREEN_CHANGED then
639- local vs = get_newregion_viewscreen ()
716+ local vs = get_any_moddable_viewscreen ()
640717 if vs and not default_applied then
641718 default_applied = true
642719 for i , v in ipairs (presets_file .data ) do
0 commit comments