- win_input.py: detect OS build via platform.win32_ver(), use
MOUSEEVENTF_ABSOLUTE only on Win10 (build < 22000)
- install.bat: detect and display Windows version on install
personal.open_inventory() returns None when the inventory cannot be opened
(e.g. after a failed vendor interaction leaves the UI in a bad state). The
previous code passed that None straight into common.get_slot_pos_and_img()
which tried to index it, crashing the bot thread with:
TypeError: 'NoneType' object is not subscriptable
Also wraps the shift-click loop in try/finally so keyboard.release("shift")
is guaranteed even if an exception fires mid-loop (prevents stuck Shift key).
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- i_char.py: rewrite _pre_buff_cta() to verify each weapon switch via BC
skill-bar template; detects wrong slot on game start (leftover from
interrupted buff cycle), retries failed switches once, logs clearly
when stuck on CTA slot to prevent dying with wrong weapon in combat
- personal.py: protect needed consumables from sell/drop in inspect_items;
check get_needs() before marking a pot for discard — if the belt needs
that pot type, skip it so fill_up_belt_from_inventory can restock later
- bot.py: add fill_up_belt_from_inventory + update_pot_needs after
buy_consumables so inventory pots reach the belt even when out of gold;
add town-heal loop at start of on_maintenance to drink health/rejuv pots
until HP >= 95% before the next run (health manager is paused in town)
- game_stats.py: add rolling 10-game pickup health check; warns in log and
sends Discord alert when zero item pickups occur across 10 games while
chickens or merc deaths are present
- params.ini: fix show_belt=n -> show_belt=k (belt key was wrong, causing
1.5s wasted recovery attempt every first game in a session)
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- Updated bot behavior to end the game when no TP charges are left, instead of attempting to walk back to town.
- Refined item processing logic in `processing_helpers.py` to use identity checks for item comparisons and improved item removal methods.
- Enhanced game stats logging to include failure reasons and send Discord notifications for failed games.
- Improved health management logic to trigger chicken behavior based on health percentage after rapid rejuvination.
- Added error handling for item pickup failures in `pickit.py` to blacklist items that cannot be picked up.
- Introduced walking fallback nodes for Countess, Andariel, Mephisto, and Baal runs in `pather.py`.
- Implemented path data validation in run scripts for Countess, Andariel, Mephisto, and Baal to ensure paths are correctly defined.
- Enhanced item identification and stash processes in `diablo.py` with retry logic for failures.
- Updated town management to handle identification failures gracefully and log appropriate warnings.
- Improved character selection logic to provide clearer logging messages.
- Modified game restart logic to launch the game via PowerShell for better session handling.
- Added documentation for recording paths for the Countess run and created a PowerShell script for scheduled task management.
- BC and BO cast with left-click (targets self) instead of right-click
- Swap-back loop simplified to 2 attempts with match score logging
- Added full test route order: trav, pindle, eldritch_shenk, nihlathak, arcane, diablo, vizier
Removed the visual skill check (is_right_skill_selected BC/BO) that always
failed because the BC.png/BO.png templates do not match D2R icons. New flow:
switch weapon, cast BC, cast BO, buff, switch back. Only verifies swap-back
by matching the original skill icon via template matching.
- game_controller: set reason on max_game_length, chicken, force_stop
- bot.py on_end_game: set default reason when failed=True has no reason yet
- bot.py save_and_exit failure: set reason before stop()
- bot.py restart_or_exit: capture error message as failure reason
- All retry paths (stash, buy_consumables, heal, repair) now use known-good
location constants instead of corrupted self._curr_loc (False)
- Guard gamble->stash chain against False location
- Guard wait_for_tp against False location
- Add run_trav to route order (travincal then pindle)
- Fix merc icon detection: expanded ROI from 40x40 to 60x60 (matchTemplate requires search area > template)
- Add MercPanelText screen object using mercenary_screen.png for reliable merc alive check
- Bot merc check now uses MercPanelText instead of generic LeftPanel
- Diablo: wait for boss to spawn before attacking (up to 15s), use conviction aura
- Diablo/Pindle attack lengths increased (diablo 3->10s, pindle 3->8s)
- Aura key switch delay increased from 50-100ms to 200-300ms for reliable activation
- Add conviction hotkey (F5) to hammerdin config
- Move Pindle CTA pre-buff from town to after entering red portal
- More aggressive healing thresholds (health potion at 98%, rejuv at 85%)
- Max game length increased from 160s to 600s for full Diablo runs
- Crop A5_RED_PORTAL template to remove empty space (center now aligns with portal)
- Fix merc_icon ROI from 10,9,50,50 to 15,14,40,40 (matches 40x40 merc templates)
- Lower MercIcon threshold from 0.9 to 0.85, add MERC_A2_2 variant
- Add merc panel confirmation with 'O' key before resurrect (prevents false resurrect when icon detection fails)
- Override capabilities to can_teleport_natively
- src/inventory/vendor.py: Log screenshots when NotEnoughGold detected
during gambling, purchasing, and repairing
- src/ui_manager.py: Update NotEnoughGold to use new MISSING_GOLD template
from assets/npc/missing_gold/ (full dialog match instead of color-based)
- assets/npc/missing_gold/missing_gold.png: New template for the popup
- src/utils/misc.py: move_d2r_window now calculates outer window position
to place client area at target coords (was incorrectly setting outer
window to target, shifting client area unpredictably)
- src/bot.py: Call move_d2r_window(5,98) at game start to restore original
working client area position and prevent 13px offset drift
- src/screen.py: Add force param to find_and_set_window_position/set_window_position
to bypass early-return guard and skip wait when called programmatically
- src/run/pindle.py: Force window re-detection before each traverse_nodes and
select_by_template call to handle offset drift between runs
- src/pather.py: Add fallback full-image search with lower threshold (0.55) when
cropped ROI search fails in find_abs_node_pos
- src/bot.py: Move D2R window to stable position (0,0) at game start via
move_d2r_window; skip merc resurrect after first failure (no gold)
- src/game_stats.py: Add _merc_resurrect_failed flag (reset each game)
- src/utils/misc.py: Add move_d2r_window() function
- config/params.ini: Updated teleport=b, show_belt=k, override_capabilities,
restore_settings_from_backup_key=insert, graphic_debugger_key=delete
- health_manager.py: read actual merc health for heal/chicken/rejuv decisions
instead of timer-only logic; pass merc_health to belt.drink_potion stats
- processing.py: remove stale TODO comment (traceback import is used)
- Restore test/assets/ from commit 5127417^ (was moved to bottytools/botty-test-assets which is now 404)
- Remove 'Download test assets' step from CI workflow (assets are now in-repo)
- Make download_test_assets.py a no-op for backward compatibility
- Fix import: from pipes import Template -> from template_finder import Template
- Remove test/assets/ from .gitignore
- Add utils/log_rotation.py: safe_imwrite() auto-rotates screenshot dirs
when they exceed configured file count or size limits
- Add [log_rotation] config section in params.ini (pickit/info/items
max_files, max_mb, discord_notify_rotation)
- Replace 40 cv2.imwrite() calls with safe_imwrite() across 13 files
- Add failure reason tracking: bot.py catches run exceptions, stores
reason in game_stats, Discord message includes the error
- Add Discord notification when log rotation deletes old files
- Prevents disk-full crashes that stopped botty on May 30