@@ -4,17 +4,18 @@ use super::Context;
4
4
use crate :: {
5
5
context:: Mode ,
6
6
handlers:: Handler ,
7
- util:: { ci_starts_with, Actor } ,
7
+ util:: { ci_ends_with , ci_starts_with, is_correct_vampire_head , Actor } ,
8
8
} ;
9
9
use codegen:: { get_joined_commands, get_khajiit_script} ;
10
10
use regex:: { Regex , RegexBuilder } ;
11
- use tes3:: esp:: { Dialogue , Npc , Script , TES3Object } ;
11
+ use tes3:: esp:: { Dialogue , Npc , NpcFlags , Script , TES3Object } ;
12
12
13
13
pub struct ScriptValidator {
14
14
scripts : HashMap < String , ScriptInfo > ,
15
15
npc : Regex ,
16
16
khajiit : Regex ,
17
17
nolore : Regex ,
18
+ vampire : Regex ,
18
19
commands : Regex ,
19
20
khajiit_script : Regex ,
20
21
projects : Vec < ( & ' static str , Regex ) > ,
@@ -29,17 +30,19 @@ struct ScriptInfo {
29
30
npc : bool ,
30
31
khajiit : bool ,
31
32
nolore : bool ,
33
+ vampire : bool ,
32
34
projects : Vec < & ' static str > ,
33
35
}
34
36
35
37
impl ScriptInfo {
36
- fn new ( npc : bool , khajiit : bool , nolore : bool ) -> Self {
38
+ fn new ( npc : bool , khajiit : bool , nolore : bool , vampire : bool ) -> Self {
37
39
Self {
38
40
used : false ,
39
41
used_by_khajiit : false ,
40
42
npc,
41
43
khajiit,
42
44
nolore,
45
+ vampire,
43
46
projects : Vec :: new ( ) ,
44
47
}
45
48
}
@@ -56,6 +59,7 @@ impl Handler<'_> for ScriptValidator {
56
59
self . npc . is_match ( text) ,
57
60
self . khajiit . is_match ( text) ,
58
61
self . nolore . is_match ( text) ,
62
+ self . vampire . is_match ( text) ,
59
63
) ;
60
64
for ( local, regex) in & self . projects {
61
65
if regex. is_match ( text) {
@@ -75,12 +79,11 @@ impl Handler<'_> for ScriptValidator {
75
79
}
76
80
} else if let TES3Object :: Npc ( npc) = record {
77
81
if !npc. is_dead ( ) {
78
- if ! npc. script . is_empty ( ) {
79
- let id = npc. script . to_ascii_lowercase ( ) ;
80
- self . check_npc_script ( npc , id ) ;
81
- return ;
82
+ if npc. script . is_empty ( ) {
83
+ println ! ( "Npc {} does not have a script" , npc. id ) ;
84
+ } else {
85
+ self . check_npc_script ( npc ) ;
82
86
}
83
- println ! ( "Npc {} does not have a script" , npc. id) ;
84
87
}
85
88
}
86
89
}
@@ -133,6 +136,7 @@ impl ScriptValidator {
133
136
let npc = get_variable ( "T_Local_NPC" , "short" ) ?;
134
137
let khajiit = get_variable ( "T_Local_Khajiit" , "short" ) ?;
135
138
let nolore = get_variable ( "NoLore" , "short" ) ?;
139
+ let vampire = get_variable ( "T_Local_Vampire" , "short" ) ?;
136
140
let commands = get_variable ( get_joined_commands ! ( ) , "(short|long|float)" ) ?;
137
141
let khajiit_script = RegexBuilder :: new ( get_khajiit_script ! ( ) )
138
142
. case_insensitive ( true )
@@ -157,6 +161,7 @@ impl ScriptValidator {
157
161
npc,
158
162
khajiit,
159
163
nolore,
164
+ vampire,
160
165
commands,
161
166
khajiit_script,
162
167
projects,
@@ -166,19 +171,21 @@ impl ScriptValidator {
166
171
} )
167
172
}
168
173
169
- fn check_npc_script ( & mut self , npc : & Npc , id : String ) {
170
- if let Some ( script) = self . scripts . get_mut ( & id) {
174
+ fn check_npc_script ( & mut self , npc : & Npc ) {
175
+ let vampire;
176
+ if let Some ( script) = self . scripts . get_mut ( & npc. script . to_ascii_lowercase ( ) ) {
171
177
script. used = true ;
178
+ vampire = script. vampire ;
172
179
if !script. npc {
173
180
println ! (
174
181
"Npc {} uses script {} which does not define T_Local_NPC" ,
175
- npc. id, id
182
+ npc. id, npc . script
176
183
) ;
177
184
}
178
185
if !script. nolore {
179
186
println ! (
180
187
"Npc {} uses script {} which does not define NoLore" ,
181
- npc. id, id
188
+ npc. id, npc . script
182
189
) ;
183
190
}
184
191
let race = & npc. race ;
@@ -187,17 +194,17 @@ impl ScriptValidator {
187
194
if !script. khajiit {
188
195
println ! (
189
196
"Npc {} uses script {} which does not define T_Local_Khajiit" ,
190
- npc. id, id
197
+ npc. id, npc . script
191
198
) ;
192
199
}
193
200
}
194
201
if script. projects . is_empty ( ) {
195
- println ! ( "Npc {} uses script {} which does not define any province specific local variables" , npc. id, id ) ;
202
+ println ! ( "Npc {} uses script {} which does not define any province specific local variables" , npc. id, npc . script ) ;
196
203
} else if script. projects . len ( ) > 1 {
197
204
println ! (
198
205
"Npc {} uses script {} which defines {}" ,
199
206
npc. id,
200
- id ,
207
+ npc . script ,
201
208
script
202
209
. projects
203
210
. iter( )
@@ -206,8 +213,25 @@ impl ScriptValidator {
206
213
. join( ", " )
207
214
) ;
208
215
}
209
- } else if !ci_starts_with ( & id, "t_scnpc_" ) {
210
- println ! ( "Npc {} uses unknown script {}" , npc. id, id) ;
216
+ } else if ci_starts_with ( & npc. script , "t_scvamp_" ) && ci_ends_with ( & npc. script , "_npc" ) {
217
+ vampire = true ;
218
+ } else if !ci_starts_with ( & npc. script , "t_scnpc_" ) {
219
+ println ! ( "Npc {} uses unknown script {}" , npc. id, npc. script) ;
220
+ return ;
221
+ } else {
222
+ vampire = npc. script . contains ( "Vamp" ) ;
223
+ }
224
+ if vampire {
225
+ let has_vampire_head = is_correct_vampire_head (
226
+ & npc. head ,
227
+ & npc. race ,
228
+ npc. npc_flags . contains ( NpcFlags :: FEMALE ) ,
229
+ ) ;
230
+ let is_sneaky = npc. faction . eq_ignore_ascii_case ( "T_Cyr_VampirumOrder" )
231
+ || ci_starts_with ( & npc. script , "T_ScNpc_Cyr_" ) ;
232
+ if !has_vampire_head && !is_sneaky {
233
+ println ! ( "Npc {} is a vampire but uses head {}" , npc. id, npc. head) ;
234
+ }
211
235
}
212
236
}
213
237
0 commit comments