@@ -127,23 +127,27 @@ def update_chart():
127127 ax .set_yticks ([0 , 20 , 40 , 60 , 80 , 100 ])
128128 ax .set_yticklabels (['0%' , '20%' , '40%' , '60%' , '80%' , '100%' ])
129129
130+ # 1. Background layer: Very faint vertical lines at 24h intervals up to 144h
131+ for hour in [24 , 48 , 72 , 96 , 120 , 144 ]:
132+ ax .axvline (x = hour , color = '#FDF4A9' , linestyle = '-' , linewidth = 1 , zorder = 1 )
133+
130134 current_live_dps = 0.0
131135 try :
132136 current_live_dps = float (strip_non_numeric (dps_entry .get ()))
133137 except :
134138 pass
135139
136- # 1. Draw the main progress line (Green)
140+ # 2. Foreground Data Layers
137141 if history :
138142 x_vals = [p [0 ] for p in history ]
139143 y_vals = [p [1 ] for p in history ]
140- ax .plot (x_vals , y_vals , 'g-o' )
144+ ax .plot (x_vals , y_vals , 'g-o' , zorder = 3 )
141145
142146 try :
143147 tier_val = int (strip_non_numeric (tier_entry .get ()))
144148 total_hp = TIER_DATA [tier_val ]["health" ]
145149
146- # 2. Draw historical points' projections (lighter, dotted) for ALL points
150+ # Historical points' projections (lighter, dotted) for ALL points
147151 for i in range (len (history )):
148152 pt_x = history [i ][0 ]
149153 pt_y = history [i ][1 ]
@@ -157,9 +161,9 @@ def update_chart():
157161 remaining_hp_at_point = (pt_y / 100.0 ) * total_hp
158162 hours_to_kill = (remaining_hp_at_point / pt_dps ) / 3600.0
159163 proj_x = pt_x + hours_to_kill
160- ax .plot ([pt_x , proj_x ], [pt_y , 0 ], 'r:' , linewidth = 1 , alpha = 0.5 )
164+ ax .plot ([pt_x , proj_x ], [pt_y , 0 ], 'r:' , linewidth = 1 , alpha = 0.5 , zorder = 2 )
161165
162- # 3. Draw the latest point's projection using its SAVED snapshot DPS (darker, dashed)
166+ # Latest point's projection using its SAVED snapshot DPS (darker, dashed)
163167 last_x = history [- 1 ][0 ]
164168 last_y = history [- 1 ][1 ]
165169
@@ -172,7 +176,27 @@ def update_chart():
172176 remaining_hp = (last_y / 100.0 ) * total_hp
173177 hours_to_kill = (remaining_hp / last_dps ) / 3600.0
174178 proj_x = last_x + hours_to_kill
175- ax .plot ([last_x , proj_x ], [last_y , 0 ], 'r--' , linewidth = 1.5 , alpha = 0.9 )
179+ ax .plot ([last_x , proj_x ], [last_y , 0 ], 'r--' , linewidth = 1.5 , alpha = 0.9 , zorder = 2 )
180+
181+ # 3. Dynamic Real-Time Crosshair Indicators (Riding the dark red line)
182+ if start_time and last_dps > 0 :
183+ elapsed_seconds = (datetime .now () - start_time ).total_seconds ()
184+ # Find exactly where we are on the overall 168-hour timeline right now
185+ live_x_hours = 168 - ((total_seconds_at_start - elapsed_seconds ) / 3600.0 )
186+
187+ if 0 <= live_x_hours <= 168 :
188+ # Calculate position strictly along the red projection line from the last saved node
189+ hours_since_last_saved = live_x_hours - last_x
190+ remaining_hp_at_last_saved = (last_y / 100.0 ) * total_hp
191+
192+ projected_hp_now = remaining_hp_at_last_saved - (last_dps * hours_since_last_saved * 3600.0 )
193+ live_y_percent = (projected_hp_now / total_hp ) * 100.0
194+ live_y_percent = max (0.0 , min (100.0 , live_y_percent ))
195+
196+ # Render crosshairs riding perfectly along that path
197+ ax .axhline (y = live_y_percent , color = '#AEAEAE' , linestyle = '-' , linewidth = 0.8 , alpha = 0.7 , zorder = 1 )
198+ ax .axvline (x = live_x_hours , color = '#AEAEAE' , linestyle = '-' , linewidth = 0.8 , alpha = 0.7 , zorder = 1 )
199+
176200 except Exception :
177201 pass
178202
@@ -182,22 +206,20 @@ def update_chart():
182206 ui_x , ui_y , ui_dps , total_hp = ui_coords
183207 last_pt = history [- 1 ]
184208
185- # Check tolerance parameters to verify if inputs match the last green node
186209 is_matching_x = abs (ui_x - last_pt [0 ]) < 0.001
187210 is_matching_y = abs (ui_y - last_pt [1 ]) < 0.001
188211
189212 is_matching_dps = True
190213 if len (last_pt ) > 2 :
191214 is_matching_dps = abs (ui_dps - last_pt [2 ]) < 0.001
192215
193- # If data deviates from the last point, paint the temporary staging assets
194216 if not (is_matching_x and is_matching_y and is_matching_dps ):
195- ax .plot (ui_x , ui_y , 'bo' , alpha = pulse_alpha , markersize = 8 )
217+ ax .plot (ui_x , ui_y , 'bo' , alpha = pulse_alpha , markersize = 8 , zorder = 4 )
196218 if ui_dps > 0 and ui_y > 0 :
197219 rem_hp_staging = (ui_y / 100.0 ) * total_hp
198220 h_to_kill_staging = (rem_hp_staging / ui_dps ) / 3600.0
199221 staging_proj_x = ui_x + h_to_kill_staging
200- ax .plot ([ui_x , staging_proj_x ], [ui_y , 0 ], 'b:' , linewidth = 1.5 , alpha = 0.6 )
222+ ax .plot ([ui_x , staging_proj_x ], [ui_y , 0 ], 'b:' , linewidth = 1.5 , alpha = 0.6 , zorder = 2 )
201223
202224 ax .set_xlim (0 , 168 )
203225 ax .set_ylim (0 , 100 )
@@ -263,6 +285,8 @@ def run_update():
263285
264286 status_label .config (text = f"Projected to FAIL.\n Need { needed_dps :,.0f} additional DPS.\n Late by: { format_time_delta (delay )} " , fg = "red" )
265287
288+ # Periodic update loop automatically re-triggers crosshair updates alongside text variables
289+ update_chart ()
266290 tracking_id = root .after (1000 , run_update )
267291 except :
268292 pass
@@ -271,7 +295,6 @@ def animate_pulse():
271295 """Oscillates opacity bounds smoothly to control blue staging canvas points."""
272296 global pulse_alpha , pulse_direction , pulse_id
273297
274- # Range bound step logic
275298 if pulse_direction == 1 :
276299 pulse_alpha += 0.04
277300 if pulse_alpha >= 0.95 :
@@ -283,7 +306,6 @@ def animate_pulse():
283306 pulse_alpha = 0.35
284307 pulse_direction = 1
285308
286- # Redraw chart if staging assets are actively visible
287309 ui_coords = get_current_ui_coordinates ()
288310 if ui_coords and history :
289311 ui_x , ui_y , ui_dps , _ = ui_coords
@@ -416,5 +438,5 @@ def block_trace_handlers(should_block):
416438progress_label .place (relx = 0.98 , rely = 0.5 , anchor = "e" )
417439
418440load_all ()
419- animate_pulse () # Start running the slow opacity oscillation system loop
441+ animate_pulse ()
420442root .mainloop ()
0 commit comments