19
19
import colorama
20
20
21
21
22
- VERSION = "v2.1"
22
+ VERSION = "v2.1.1 "
23
23
follow_mode = False # False -> analyze mode
24
24
25
25
dt_dict = {
@@ -90,7 +90,7 @@ def __init__(self,
90
90
nickname : str ,
91
91
pt_found : float ,
92
92
phase_durations : dict [int , float ],
93
- shields : dict [int , list [tuple [str , float ]]],
93
+ shields : dict [float , list [tuple [str , float ]]],
94
94
legs : dict [int , list [float ]],
95
95
body_dur : dict [int , float ],
96
96
pylon_dur : dict [int , float ]):
@@ -152,6 +152,10 @@ def pretty_print_phase(self, phase: int):
152
152
153
153
if phase in self .pylon_dur :
154
154
print (f'{ fg .white } Pylons:\t { fg .li_green } { self .pylon_dur [phase ]:7.3f} s' )
155
+
156
+ if phase == 3 and self .shields [3.5 ]: # Print phase 3.5
157
+ print (f'{ fg .white } Extra shields:\t \t { fg .li_yellow } '
158
+ f'{ " | " .join ((shield for shield , _ in self .shields [3.5 ]))} ' )
155
159
print ('' ) # to print an enter
156
160
157
161
def pretty_print_sum_of_parts (self ):
@@ -184,7 +188,7 @@ def __init__(self, run_nr: int):
184
188
self .nickname = ''
185
189
self .heist_start = 0.0
186
190
self .pt_found = 0.0
187
- self .shields : dict [int , list [tuple [str , float ]]] = defaultdict (list ) # phase -> list((type, absolute time))
191
+ self .shields : dict [float , list [tuple [str , float ]]] = defaultdict (list ) # phase -> list((type, absolute time))
188
192
self .legs : dict [int , list [float ]] = defaultdict (list ) # phase -> list(absolute time)
189
193
self .body_vuln : dict [int , float ] = {} # phase -> vuln-time
190
194
self .body_kill : dict [int , float ] = {} # phase -> kill-time
@@ -194,6 +198,12 @@ def __init__(self, run_nr: int):
194
198
def __str__ (self ):
195
199
return '\n ' .join ((f'{ key } : { val } ' for key , val in vars (self ).items ()))
196
200
201
+ def post_process (self ):
202
+ # Take the final shield from shield phase 3.5 and prepend it to phase 4.
203
+ self .shields [4 ] = [self .shields [3.5 ].pop ()] + self .shields [4 ]
204
+ # Remove the extra shield from phase 4.
205
+ self .shields [4 ].pop ()
206
+
197
207
def to_rel (self ) -> RelRun :
198
208
pt_found = self .pt_found - self .heist_start
199
209
phase_durations = {}
@@ -225,6 +235,9 @@ def to_rel(self) -> RelRun:
225
235
# Set phase duration
226
236
phase_durations [phase ] = previous_value - self .heist_start
227
237
238
+ # Set phase 3.5 shields
239
+ shields [3.5 ] = [(shield , nan ) for shield , _ in self .shields [3.5 ]]
240
+
228
241
return RelRun (self .run_nr , self .nickname , pt_found , phase_durations , shields , legs , body_dur , pylon_dur )
229
242
230
243
@@ -262,7 +275,10 @@ def register_phase(log: Iterator[str], run: AbsRun, phase: int):
262
275
lambda line : Constants .HEIST_START in line , # Functions as abort as well
263
276
lambda line : Constants .HOST_MIGRATION in line ])
264
277
if match == 0 : # Shield switch
265
- run .shields [phase ].append (shield_from_line (line ))
278
+ # Shield_phase '3.5' is for when shields swap during the pylon phase in phase 3.
279
+ shield_phase = 3.5 if phase == 3 and 3 in run .pylon_start else phase
280
+ run .shields [shield_phase ].append (shield_from_line (line ))
281
+
266
282
if follow_mode and len (run .shields [1 ]) == 1 : # The first shield can help determine whether to abort.
267
283
print (f'{ fg .white } First shield: { fg .li_cyan } { run .shields [phase ][0 ][0 ]} ' )
268
284
elif match == 1 : # Leg kill
@@ -272,7 +288,6 @@ def register_phase(log: Iterator[str], run: AbsRun, phase: int):
272
288
run .body_vuln [phase ] = time_from_line (line )
273
289
kill_sequence += 1 # 3x BODY_VULNERABLE in one phase means PT dies.
274
290
if kill_sequence == 3 : # PT dies.
275
- run .shields [phase ].pop () # We get a random extra shield we don't need.
276
291
run .body_kill [phase ] = time_from_line (line )
277
292
return
278
293
elif match == 3 : # Generic state change
@@ -288,8 +303,6 @@ def register_phase(log: Iterator[str], run: AbsRun, phase: int):
288
303
elif match == 6 : # Phase endings (excludes phase 4)
289
304
if phase in [1 , 3 ]: # Ignore phase 2 as it already matches body_kill.
290
305
run .pylon_end [phase ] = time_from_line (line )
291
- if phase == 3 : # Put the final shield from phase 3 as the first of phase 4.
292
- run .shields [phase + 1 ].append (run .shields [phase ].pop ())
293
306
return
294
307
elif match == 7 : # Nickname
295
308
run .nickname = line .replace (',' , '' ).split ()[- 2 ]
@@ -319,6 +332,7 @@ def read_run(log: Iterator[str], run_nr: int, require_heist_start=False) -> AbsR
319
332
320
333
for phase in [1 , 2 , 3 , 4 ]:
321
334
register_phase (log , run , phase ) # Adds information to run, including the start time
335
+ run .post_process () # Apply shield phase corrections
322
336
323
337
return run
324
338
0 commit comments