From c40f2efad2d9454b14019d162aa7574b41eda6fc Mon Sep 17 00:00:00 2001 From: alexpolo1 Date: Sun, 6 Sep 2026 08:18:47 +0200 Subject: [PATCH] fix(baal_xp): keep the leech alive when its own cycles keep failing - leech cycle failures no longer feed the session consecutive-fail tally (five bad joins disabled the route for the whole session and ended the game); _baal_xp_rearm keeps its own local breaker and resets the game-level counter so the controller restarts D2R and the leech retries - on_start_from_town: a leech that re-enters its own game on a corpse (died in the public game, or save-and-exit raced the death screen) gets pre_buff + /nopickup here - without it the char stays dead and the next cycle's save-and-exit has no living game to exit from --- src/bot.py | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/bot.py b/src/bot.py index 980d4a5..70e4602 100644 --- a/src/bot.py +++ b/src/bot.py @@ -455,6 +455,21 @@ class Bot: Logger.info(f"Teleport keybind is lost upon death. Rebinding teleport to '{keybind}'") self._char.remap_right_skill_hotkey("TELE_ACTIVE", Config().char["teleport"]) + # A leech cycle that died in a public game (or whose save-and-exit raced + # the death screen) re-enters its own game on a corpse. The generic + # pickup above only fires on the town-spawn path, so handle it here too - + # without this the character stays dead and the next cycle's save-and- + # exit has no living game to exit from. + if corpse_present and self._baal_xp_only(): + self._char.pre_buff() + if Config().char["enable_no_pickup"] and (not self._ran_no_pickup and not self._game_stats._nopickup_active): + self._ran_no_pickup = True + if view.enable_no_pickup(): + self._game_stats._nopickup_active = True + Logger.info("Activated /nopickup") + else: + Logger.error("Failed to detect if /nopickup command was applied or not") + # Run /nopickup command to avoid picking up stuff on accident if Config().char["enable_no_pickup"] and (not self._ran_no_pickup and not self._game_stats._nopickup_active): self._ran_no_pickup = True @@ -1291,6 +1306,13 @@ class Bot: Logger.warning(f"baal_xp: {self._baal_xp_fails} cycles failed in a row — " f"ending the game so the controller can recover") self._baal_xp_fails = 0 + # A leech cycle that failed at the join/leave/recovery stage is NOT a + # run that died in combat - it is a broken cycle that the rearm loop + # is about to retry. Counting it in the session's consecutive-fail + # tally (via _record_run_result) made five join failures disable the + # route for the whole session and end the game, so the leech could + # never self-heal. Keep the breaker local to the leech. + self._game_stats.reset_consecutive_fails() return self._do_runs["run_baal_xp"] = True # Re-arm the route in the config layer too: on_maintenance re-reads @@ -2007,7 +2029,15 @@ class Bot: # early (low HP, run over) - the XP was collected; only a broken # cycle (join/leave/recovery failure) is a failure. self._game_stats.log_run_finished("run_baal_xp", not ok, None, loot=[]) - self._record_run_result("run_baal_xp", not ok) + if ok: + self._record_run_result("run_baal_xp", False) + else: + # A failed leech cycle is a broken join/leave/recovery, not a run + # that died in combat - it must not feed the session's + # consecutive-fail tally, or five bad joins disable the route for + # the whole session and end the game. _baal_xp_rearm keeps its + # own breaker for that. + self._game_stats.reset_consecutive_fails() self._game_stats.log_exp() self._baal_xp_rearm(ok=ok) self.trigger_or_stop("end_run") @@ -2022,7 +2052,7 @@ class Bot: # Best effort: get back to our own game so the bot keeps running self._baal_xp_go_home() self._game_stats.log_run_finished("run_baal_xp", True, None, loot=[]) - self._record_run_result("run_baal_xp", True) + self._game_stats.reset_consecutive_fails() self._baal_xp_rearm(ok=False) self.trigger_or_stop("end_run") finally: