@@ -11,7 +11,7 @@ use crate::{
11
11
} ;
12
12
use codegen:: { get_joined_commands, get_khajiit_script} ;
13
13
use regex:: { Regex , RegexBuilder } ;
14
- use tes3:: esp:: { Cell , Dialogue , Npc , NpcFlags , Reference , Script , TES3Object } ;
14
+ use tes3:: esp:: { Cell , Dialogue , DialogueType2 , Npc , NpcFlags , Reference , Script , TES3Object } ;
15
15
16
16
enum PositionMarkerType {
17
17
Unknown ,
@@ -39,6 +39,9 @@ pub struct ScriptValidator {
39
39
marker_id : Regex ,
40
40
mod_reputation : Regex ,
41
41
mod_facrep : Regex ,
42
+ add_topic : Regex ,
43
+ added_topics : HashMap < String , Vec < String > > ,
44
+ topics : HashSet < String > ,
42
45
}
43
46
44
47
struct ScriptInfo {
@@ -70,54 +73,64 @@ impl Handler<'_> for ScriptValidator {
70
73
if context. mode == Mode :: Vanilla {
71
74
return ;
72
75
}
73
- if let TES3Object :: Script ( script) = record {
74
- let text = & script. text ;
75
- let mut info = ScriptInfo :: new (
76
- self . npc . is_match ( text) ,
77
- self . khajiit . is_match ( text) ,
78
- self . nolore . is_match ( text) ,
79
- self . vampire . is_match ( text) ,
80
- ) ;
81
- for ( local, regex) in & self . projects {
82
- if regex. is_match ( text) {
83
- info. projects . push ( local) ;
76
+ match record {
77
+ TES3Object :: Script ( script) => {
78
+ let text = & script. text ;
79
+ let mut info = ScriptInfo :: new (
80
+ self . npc . is_match ( text) ,
81
+ self . khajiit . is_match ( text) ,
82
+ self . nolore . is_match ( text) ,
83
+ self . vampire . is_match ( text) ,
84
+ ) ;
85
+ for ( local, regex) in & self . projects {
86
+ if regex. is_match ( text) {
87
+ info. projects . push ( local) ;
88
+ }
89
+ }
90
+ if info. khajiit && !self . has_correct_khajiit_check ( script, text) {
91
+ println ! ( "Script {} contains non-standard khajiit check" , script. id) ;
92
+ }
93
+ self . scripts . insert ( script. id . to_ascii_lowercase ( ) , info) ;
94
+ if let Some ( captures) = self . commands . captures ( text) {
95
+ println ! (
96
+ "Script {} contains line {}" ,
97
+ script. id,
98
+ captures. get( 0 ) . unwrap( ) . as_str( )
99
+ ) ;
84
100
}
85
101
}
86
- if info. khajiit && !self . has_correct_khajiit_check ( script, text) {
87
- println ! ( "Script {} contains non-standard khajiit check" , script. id) ;
88
- }
89
- self . scripts . insert ( script. id . to_ascii_lowercase ( ) , info) ;
90
- if let Some ( captures) = self . commands . captures ( text) {
91
- println ! (
92
- "Script {} contains line {}" ,
93
- script. id,
94
- captures. get( 0 ) . unwrap( ) . as_str( )
95
- ) ;
102
+ TES3Object :: Npc ( npc) => {
103
+ if !npc. is_dead ( ) {
104
+ if npc. script . is_empty ( ) {
105
+ println ! ( "Npc {} does not have a script" , npc. id) ;
106
+ } else {
107
+ self . check_npc_script ( npc) ;
108
+ }
109
+ }
96
110
}
97
- } else if let TES3Object :: Npc ( npc) = record {
98
- if !npc. is_dead ( ) {
99
- if npc. script . is_empty ( ) {
100
- println ! ( "Npc {} does not have a script" , npc. id) ;
111
+ TES3Object :: Book ( book) => {
112
+ let id = book. id . to_ascii_lowercase ( ) ;
113
+ let marker = if book. mesh . eq_ignore_ascii_case ( NPC_MARKER ) {
114
+ PositionMarkerType :: NpcMarker
115
+ } else if is_marker ( book) {
116
+ PositionMarkerType :: Marker
101
117
} else {
102
- self . check_npc_script ( npc) ;
118
+ PositionMarkerType :: Book
119
+ } ;
120
+ if let Some ( ( _, marker_type, _, _) ) = self . markers . get_mut ( & id) {
121
+ * marker_type = marker;
122
+ } else if let Some ( found) = self . marker_id . find ( & book. id ) {
123
+ if found. len ( ) == book. id . len ( ) {
124
+ self . markers . insert ( id, ( String :: new ( ) , marker, false , 0 ) ) ;
125
+ }
103
126
}
104
127
}
105
- } else if let TES3Object :: Book ( book) = record {
106
- let id = book. id . to_ascii_lowercase ( ) ;
107
- let marker = if book. mesh . eq_ignore_ascii_case ( NPC_MARKER ) {
108
- PositionMarkerType :: NpcMarker
109
- } else if is_marker ( book) {
110
- PositionMarkerType :: Marker
111
- } else {
112
- PositionMarkerType :: Book
113
- } ;
114
- if let Some ( ( _, marker_type, _, _) ) = self . markers . get_mut ( & id) {
115
- * marker_type = marker;
116
- } else if let Some ( found) = self . marker_id . find ( & book. id ) {
117
- if found. len ( ) == book. id . len ( ) {
118
- self . markers . insert ( id, ( String :: new ( ) , marker, false , 0 ) ) ;
128
+ TES3Object :: Dialogue ( dial) => {
129
+ if dial. dialogue_type == DialogueType2 :: Topic {
130
+ self . topics . insert ( dial. id . to_ascii_lowercase ( ) ) ;
119
131
}
120
132
}
133
+ _ => { }
121
134
}
122
135
}
123
136
@@ -219,6 +232,28 @@ impl Handler<'_> for ScriptValidator {
219
232
}
220
233
}
221
234
}
235
+ if let Some ( captures) = self . add_topic . captures ( code) {
236
+ let mut capture = captures. get ( 3 ) ;
237
+ if capture. is_none ( ) {
238
+ capture = captures. get ( 4 ) ;
239
+ }
240
+ if let Some ( string) = capture {
241
+ let id = string. as_str ( ) . to_ascii_lowercase ( ) ;
242
+ let description = if let TES3Object :: DialogueInfo ( info) = record {
243
+ format ! ( "Info {} in topic {}" , info. id, topic. id)
244
+ } else if let TES3Object :: Script ( script) = record {
245
+ format ! ( "Script {}" , script. id)
246
+ } else {
247
+ String :: new ( )
248
+ } ;
249
+ let entry = self . added_topics . get_mut ( & id) ;
250
+ if let Some ( sources) = entry {
251
+ sources. push ( description) ;
252
+ } else {
253
+ self . added_topics . insert ( id, vec ! [ description] ) ;
254
+ }
255
+ }
256
+ }
222
257
}
223
258
224
259
fn on_cellref (
@@ -278,6 +313,17 @@ impl Handler<'_> for ScriptValidator {
278
313
) ;
279
314
}
280
315
}
316
+ for ( topic, sources) in & self . added_topics {
317
+ if self . topics . contains ( topic) {
318
+ continue ;
319
+ }
320
+ for source in sources {
321
+ println ! (
322
+ "{} adds topic {} which is not defined in this file" ,
323
+ source, topic
324
+ ) ;
325
+ }
326
+ }
281
327
}
282
328
}
283
329
@@ -337,6 +383,7 @@ impl ScriptValidator {
337
383
. build ( ) ?;
338
384
let mod_reputation = Regex :: new ( r"^[,\s]*modreputation[,\s]" ) ?;
339
385
let mod_facrep = Regex :: new ( r#"modpcfacrep[,\s]+([0-9"-]+)([,\s]+([^,\s]+))?[,\s]*$"# ) ?;
386
+ let add_topic = Regex :: new ( r#"^([,\s]*|.*?->[,\s]*)addtopic[,\s]+("([^"]+)"|([^\s"]+))"# ) ?;
340
387
Ok ( Self {
341
388
unique_heads,
342
389
scripts : HashMap :: new ( ) ,
@@ -356,6 +403,9 @@ impl ScriptValidator {
356
403
markers : HashMap :: new ( ) ,
357
404
mod_reputation,
358
405
mod_facrep,
406
+ add_topic,
407
+ added_topics : HashMap :: new ( ) ,
408
+ topics : HashSet :: new ( ) ,
359
409
} )
360
410
}
361
411
0 commit comments