@@ -12,10 +12,27 @@ local widgets = require('gui.widgets')
12
12
local presets_file = json .open (" dfhack-config/mod-manager.json" )
13
13
local GLOBAL_KEY = ' mod-manager'
14
14
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 ()
18
32
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
19
36
return vs
20
37
end
21
38
@@ -55,21 +72,30 @@ function get_modlist_fields(kind, viewscreen)
55
72
end
56
73
end
57
74
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
58
77
local function move_mod_entry (viewscreen , to , from , mod_id , mod_version )
59
78
local to_fields = get_modlist_fields (to , viewscreen )
60
79
local from_fields = get_modlist_fields (from , viewscreen )
61
80
62
81
local mod_index = nil
82
+ local loaded_version = nil
63
83
for i , v in ipairs (from_fields .id ) do
64
84
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
66
92
mod_index = i
67
93
break
68
94
end
69
95
end
70
96
71
97
if mod_index == nil then
72
- return false
98
+ return false , nil
73
99
end
74
100
75
101
for k , v in pairs (to_fields ) do
@@ -80,17 +106,21 @@ local function move_mod_entry(viewscreen, to, from, mod_id, mod_version)
80
106
end
81
107
end
82
108
83
- for k , v in pairs (from_fields ) do
109
+ for _ , v in pairs (from_fields ) do
84
110
v :erase (mod_index )
85
111
end
86
112
87
- return true
113
+ return true , loaded_version
88
114
end
89
115
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
90
118
local function enable_mod (viewscreen , mod_id , mod_version )
91
119
return move_mod_entry (viewscreen , " object_load_order" , " available" , mod_id , mod_version )
92
120
end
93
121
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
94
124
local function disable_mod (viewscreen , mod_id , mod_version )
95
125
return move_mod_entry (viewscreen , " available" , " object_load_order" , mod_id , mod_version )
96
126
end
@@ -105,19 +135,25 @@ local function get_active_modlist(viewscreen)
105
135
return t
106
136
end
107
137
138
+ --- @return string[]
139
+ --- @return { id : string , new : string } []
108
140
local function swap_modlist (viewscreen , modlist )
109
141
local current = get_active_modlist (viewscreen )
110
142
for _ , v in ipairs (current ) do
111
143
disable_mod (viewscreen , v .id , v .version )
112
144
end
113
145
114
146
local failures = {}
147
+ local changed = {}
115
148
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
117
151
table.insert (failures , v .id )
152
+ elseif version then
153
+ table.insert (changed , { id = v .id , new = version })
118
154
end
119
155
end
120
- return failures
156
+ return failures , changed
121
157
end
122
158
123
159
---- ----------------
@@ -137,7 +173,7 @@ ModmanageMenu.ATTRS {
137
173
}
138
174
139
175
local function save_new_preset (preset_name )
140
- local viewscreen = get_newregion_viewscreen ()
176
+ local viewscreen = get_any_moddable_viewscreen ()
141
177
local modlist = get_active_modlist (viewscreen )
142
178
table.insert (presets_file .data , { name = preset_name , modlist = modlist })
143
179
presets_file :write ()
@@ -157,27 +193,17 @@ local function overwrite_preset(idx)
157
193
return
158
194
end
159
195
160
- local viewscreen = get_newregion_viewscreen ()
196
+ local viewscreen = get_any_moddable_viewscreen ()
161
197
local modlist = get_active_modlist (viewscreen )
162
198
presets_file .data [idx ].modlist = modlist
163
199
presets_file :write ()
164
200
end
165
201
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
170
204
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
177
206
if unset_default_on_failure then
178
- presets_file .data [idx ].default = false
179
- presets_file :write ()
180
-
181
207
table.insert (text , {
182
208
text = ' Failed to load some mods from your default preset.' ,
183
209
pen = COLOR_LIGHTRED ,
@@ -193,19 +219,70 @@ local function load_preset(idx, unset_default_on_failure)
193
219
pen = COLOR_LIGHTRED ,
194
220
})
195
221
end
222
+ end
223
+
224
+ if failed and changed then
196
225
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
200
260
table.insert (text , ' Here are the mods that failed to load:' )
201
261
table.insert (text , NEWLINE )
202
262
table.insert (text , NEWLINE )
203
263
for _ , v in ipairs (failures ) do
204
264
table.insert (text , (' - %s' ):format (v ))
205
265
table.insert (text , NEWLINE )
206
266
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
207
284
dialogs .showMessage (" Warning" , text )
208
- end
285
+ end
209
286
end
210
287
211
288
local function find_preset_by_name (name )
@@ -573,7 +650,7 @@ ModmanageOverlay.ATTRS {
573
650
desc = " Adds a link to the mod selection screen for accessing the mod manager." ,
574
651
default_pos = { x = 5 , y =- 6 },
575
652
version = 2 ,
576
- viewscreens = { " new_region/Mods" },
653
+ viewscreens = { " new_region/Mods" , " new_arena/Mods " },
577
654
default_enabled = true ,
578
655
}
579
656
@@ -636,7 +713,7 @@ notification_timer_fn()
636
713
local default_applied = false
637
714
dfhack .onStateChange [GLOBAL_KEY ] = function (sc )
638
715
if sc == SC_VIEWSCREEN_CHANGED then
639
- local vs = get_newregion_viewscreen ()
716
+ local vs = get_any_moddable_viewscreen ()
640
717
if vs and not default_applied then
641
718
default_applied = true
642
719
for i , v in ipairs (presets_file .data ) do
0 commit comments