- config/params.ini: show_belt k->n matches the actual D2R keybind so
the bot can now correctly read and manage belt potion inventory.
pickit_screenshots=1 enables per-run loot scan evidence.
- blizz_sorc.py: kill_pindle() now waits 1.5-2.0s (was ~0.33s) after
the attack loop before teleporting to the loot area. Blizzard has an
~1.8s fall duration, so the old wait left enemies alive when the sorc
arrived. Also adds _cast_static() at the start to reduce pack HP
immediately.
- pickit.py: rename loop var i->ground_item (fixes potential NameError
when items list is empty) and improve tele-fail warning message.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The TELE_ACTIVE template only matches native teleport's icon. Charged
teleport (from a staff/item) shows a different icon with a blue charge
indicator, so is_right_skill_selected(["TELE_ACTIVE"]) returns False
and char.move() falls back to walking.
Walking a path calibrated for teleport drops the sorc in the wrong
game-world position, so blizzard casts land south of Pindle ("below
targets") and the sorc is exposed to the full minion pack.
Fix: for can_teleport_with_charges chars, call select_tp() once then
pass force_tp=True to each char.move() hop. force_tp bypasses the
template check and re-arms the teleport hotkey before each right-click,
so charges are actually consumed per hop. If charges deplete mid-path
char.move() right-clicks with no effect and the remaining hops degrade
to standing still rather than walking into monsters.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pindle.py: route can_teleport_with_charges chars through
traverse_nodes_fixed for the Pindle approach instead of traverse_nodes.
traverse_nodes (node-based) falls back to walking for charges chars
because pre_move does nothing for them — so the sorc was slow-walking
through the entire minion pack before the fight, arriving at near-zero HP.
pather.py: traverse_nodes_fixed now calls char.select_tp() before
pre_move when using charge-based teleport, so char.move() sees
teleport on the right-skill slot and uses charges for each step.
When charges deplete mid-path it falls back to walking gracefully.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- misc.py: catch psutil.NoSuchProcess in WindowSpec.match() — a process
can exit between EnumWindows enumerating it and us calling .name(),
which was crashing the window-detection thread and leaving
monitor_x_range/monitor_y_range as None
- screen.py: guard convert_screen_to_monitor against None ranges so
template matching doesn't throw TypeError before the D2R window is
first located; logs a warning and returns unclamped coords instead
- main.py: switch BeautifulTable to STYLE_DEFAULT (ASCII only) to avoid
UnicodeEncodeError on cp1252 terminals; add try/except fallback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The run-selector window now also shows a character section with radio
buttons for the three supported builds. Selecting a char updates
Config().char["type"] in-memory alongside the run selection; both take
effect on the next game.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-launch of D2R and bnet credential injection are now gated behind
an explicit `auto_login=0` flag in params.ini. Setting it to 1 restores
the previous behaviour. Credentials stored in bnet_name/bnet_pass are
never appended to launch options while auto_login=0.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a tkinter run-selector window accessible from the botty console via
the new select_runs_key hotkey (default F6). Users can check/uncheck any
of the 11 supported boss/farm runs; the selection updates Config in-memory
and takes effect on the next game without restarting botty.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The custom tesserocr-2.5.2 wheel was compiled on a specific machine
against DLL versions that do not match a fresh conda-forge installation.
This caused persistent ImportError: DLL load failed regardless of PATH
or LoadLibraryExW approach.
conda-forge's tesserocr package is compiled against the exact same
conda-forge tesseract/leptonica binaries, so all DLL dependencies
are automatically satisfied within the conda environment — no manual
DLL path manipulation needed.
Changes:
- environment.yml: add tesserocr + tesseract as conda-forge packages,
remove leptonica pin (no longer needed), remove custom wheel from pip
- install.bat: replace wheel force-reinstall with pip uninstall cleanup
- src/*.py: simplify DLL fix to os.add_dll_directory only
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Every approach to manually replicating conda's DLL environment from
Python code or batch PATH manipulation has failed. conda run activates
the environment exactly like "conda activate botty" — setting PATH,
running activate.d scripts, and properly resolving all transitive DLL
dependencies for tesseract51.dll.
run_botty.bat now derives conda.exe from the botty python.exe path
(two levels up: envs/botty -> envs -> miniforge3 -> Scripts/conda.exe)
and uses "conda run -n botty --no-capture-output python src/main.py".
install.bat smoke test now uses "%CONDA_EXE% run -n botty python -c ..."
which already has CONDA_EXE set from the install step.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
os.add_dll_directory alone is not enough — LOAD_LIBRARY_SEARCH_USER_DIRS
does not propagate to transitive deps of deps when loaded automatically
by the OS (e.g. tesseract51.dll's deps like mingw runtimes, leptonica).
LoadLibraryExW with LOAD_LIBRARY_SEARCH_DEFAULT_DIRS (0x1000) explicitly
propagates user DLL dir search to the entire transitive dep chain, so
leptonica, libgcc, libstdc++, zlib etc. are all found in Library\bin
and Library\mingw-w64\bin without conda activate.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ctypes.WinDLL uses LoadLibraryW which does NOT search user DLL dirs
registered via os.add_dll_directory/AddDllDirectory. It was throwing
FileNotFoundError and blocking the import before tesserocr was ever tried.
Python 3.8+ loads .pyd files with LOAD_LIBRARY_SEARCH_USER_DIRS which
DOES search user-registered dirs for the pyd and all its transitive DLL
dependencies. os.add_dll_directory(Library\bin) alone is sufficient.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
os.environ['PATH'] set from inside Python does not affect the Windows
DLL loader used by ctypes.WinDLL — the loader reads the process PATH
at load time, not from Python's env dict. Set PATH in the .bat files
before python.exe is launched so tesseract51.dll's transitive deps
(leptonica, zlib, libpng, etc.) are findable by the loader.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When ctypes.WinDLL loads tesseract51.dll by absolute path, Windows
resolves that DLL's own transitive deps using the standard search order:
app-dir → System32 → Windows → cwd → PATH. Library\bin is in none of
those (conda activate was not run), so leptonica, zlib, libpng, etc.
are invisible and the load fails even though the DLLs are all present.
Fix: prepend all conda DLL dirs to os.environ['PATH'] before the
ctypes.WinDLL call so the standard DLL search finds them. os.add_dll_directory
is still called for Python's LOAD_LIBRARY_SEARCH_USER_DIRS path.
Together the three steps guarantee the import works without conda activate:
1. os.add_dll_directory - for .pyd loading
2. os.environ PATH - for ctypes transitive dep resolution
3. ctypes.WinDLL(abs) - pre-cache tesseract so .pyd reuses it
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
os.add_dll_directory alone is not enough on Windows. When Python loads
the tesserocr .pyd via LOAD_LIBRARY_SEARCH_USER_DIRS, Windows finds
tesseract51.dll in the added directory but then resolves tesseract's own
transitive deps (leptonica, zlib, libpng etc.) using only the standard
system search path -- not the user DLL dirs. Those libs live in
Library\bin, not System32, so they're invisible and the load fails even
though every DLL is present.
Fix: call ctypes.WinDLL(absolute_path_to_tesseract51.dll) before the
tesserocr import. LoadLibraryW with a full path anchors tesseract51.dll
to Library\bin, so Windows searches that directory for its transitive
deps. The already-loaded DLL is then returned from cache when the .pyd
requests it, making the import succeed.
Applied to ocr.py (test entry point), main.py, and shopper.py.
Also updated install.bat smoke test and diagnostic to use the same fix.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The custom tesserocr wheel links against leptonica-1.78.0.dll at
compile time. Unpinned leptonica on conda-forge resolves to 1.82+
which installs leptonica-1.82.0.dll — a different filename — so
Windows DLL loader cannot find it regardless of os.add_dll_directory.
Also force-reinstall the wheel in install.bat to guarantee the
correct binary is used (not a stale cached version), and add a
diagnostic that prints which DLLs are actually present when the
smoke test fails so the root cause is visible instead of a vague
warning.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- README: add step-by-step Installation section (Miniforge → download
ZIP → install.bat → config → run_botty.bat) so a non-technical user
can follow it without reading development.md
- config/params.ini: reset personal fields (name, char_name,
saved_games_folder) to generic defaults so the downloaded zip
works out of the box for anyone
- install.bat: apply os.add_dll_directory before the tesserocr smoke
test so it stops emitting a false warning on every install
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dirname(dirname(sys.executable)) walks two levels up from the exe on
Windows, landing in the envs/ parent rather than the env root. Replace
with sys.prefix which is always the correct conda env root, and cover
Library/{bin,mingw-w64/bin,usr/bin} to handle all conda-forge layouts.
Also remove unused _dll_fix.py which had the same bug.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
install.bat:
- Add conda self-test (conda --version) before env create
- Verify botty python.exe exists after env creation
- Smoke-test key imports (cv2, tesserocr, discord, etc.)
CI (.github/workflows/ci.yml):
- Add test_setup_bat_files.py to test matrix
test/test_setup_bat_files.py (7 tests):
- All expected .bat files exist
- No hardcoded usernames (alex, alexpolo, ultimate) in run scripts
- No absolute home paths in run scripts (must use %~dp0 / %USERNAME%)
- All run_*.bat source find_python.bat (no duplicated conda detection)
- find_python.bat checks >= 6 conda locations
- install.bat has conda self-test and python verification
- Add find_python.bat shared helper to auto-detect conda env (6 locations)
- All bat scripts now resolve paths relative to script location (%~dp0)
- Fixes crash when launching from Start Menu / pinned shortcut (cwd=System32)
- Fixes hardcoded username path in run_asset_extractor.bat
Python 3.8+ no longer searches conda's Library\bin for DLLs automatically.
Add os.add_dll_directory(sys.prefix/Library/bin) before importing tesserocr
so leptonica and tesseract DLLs are found on any conda-based Windows env.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without cd /d "%~dp0", conda resolves environment.yml relative to
wherever the user launched the bat from (e.g. C:\Windows\system32).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
find_best_match was using extractOne (which maximises its scorer) with
Levenshtein distance (lower = better), so it returned the worst match
instead of the best. Switch to extract+min to correctly minimise distance.
Fixes 6 failing tests in test_text_correction.py.
CI: run pytest under `coverage run` so coverage.xml has data to report;
drop deprecated use-only-tar-bz2 flag from setup-miniconda steps.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds install.bat, run_botty.bat, run.bat, environment.yml, src/, and
dependencies/ to the build output so users can download zip → run
install.bat → run_botty.bat without needing a pre-built conda env.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>