* fix: raise maintenance budget for cross-act routes; document Trav findings Travincal leaves the character in Act 3, but maintenance relocates it to Act 4 (stash at a4_tyrael_stash, repair at a4_halbu) and the next run then needs the A3 waypoint again -- two cross-act waypoint trips per game. That travel is not attributed to any timed step, so a FAIL> trail can show ~38s of work inside a 250s maintenance window. The 240s budget (tuned when Pindle kept all town business in one act) was tripped 5 times in one session, each costing a whole game. Raised to 420s. Also documents, in HANDOVER.md: - The open_wp failures are NOT a stale template. Scored a5_wp.png against all three real failure frames: 0.96-0.98 full-frame, but that match is the belt/mana-orb HUD false positive the a5.py comment already documents. Inside the real cut_skill_bar ROI it scores 0.436-0.480 against a 0.55 threshold at scattered positions -- noise. The waypoint is genuinely not on screen; the character never reaches it. Recapturing would fix nothing. Scoring a template without the ROI the code actually uses produces a confident wrong answer. - PR #39's pather abort is merged, live, and finally firing (1 abort in 21 games, after being 0-for-152 while it looked correct). - Keeping Trav town business in Act 3 is the real fix for both the timeouts and the waypoint failures. a3.py already reports can_buy_pots/can_heal/ can_stash as True, so the Act 4 trip is not a missing capability. - FoH vs hammerdin on the council, and the [fohdin]/[paladin] section trap: concentration and redemption lived in [fohdin], which hammerdin does not read, so both would have gone silently unbound after a respec. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: post-mortem for the hell Travincal / hammerdin session Narrative write-up of 29 Aug 2026: run_trav on hell, FoHdin -> hammerdin. Outcome: health chickens 3-in-8 -> 0-in-11, battle 64-68s -> 41-60s, failure rate 12% -> 9%, zero deaths throughout. The document covers the four times the obvious answer was wrong: 1. Battle time did not move after the respec, which looked like failure. hammerdin.kill_council casts for a FIXED duration with no kill detection, so the clock cannot report damage -- loot proved the respec worked. 2. a5_wp.png scored 0.96-0.98 full-frame on every failure frame, which reads as "template fine, search broken". That match is the belt/mana-orb HUD false positive the a5.py comment already documents. Inside the real cut_skill_bar ROI it scores 0.436-0.480 against a 0.55 threshold at wandering positions -- noise. The waypoint was never on screen. 3. Ormus: not masked (4-channel but fully opaque, so no mask is passed), and not a threshold problem (in-ROI best 0.342, background level -- lowering the bar would recreate the Bug 4 false-positive clicks). A3 town has frames with ZERO pather landmarks over threshold, so the character never arrives. One cause, three symptoms. 4. Reverses this session's own earlier recommendation to move Trav town business into Act 3. That was reasoned from a3.py reporting can_buy_pots/ can_heal/can_stash as True -- a capability check, not evidence about pathing. A3 is the worst-supported town in the project. Also documents three settings that were live but inert: binds under [fohdin] which hammerdin never reads, casting_frames=8 (unreachable -- a paladin's fastest cast is 10 frames, so every cast was cut short), and repair_npc= a5_larzuk, which Bug 12 set to keep repair in-act for Pindle but which forces a cross-act trip on Trav (35.8s vs 9.0s). And a caution on the key auto-detector: it reported the wrong stand_still bind both before and after a live remap, consistent with a stale .keyo read. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: correct stale hammerdin migration notes in HANDOVER (Codex review) Addresses Codex feedback on PR #40: the handover still described the character as needing conversion to hammerdin with both skills blank, while the same commit verified type=hammerdin and concentration='f6' loading live. The conflict was worse than reported. The stale "Two things only you can do" section instructed the operator to rebind F7 -> Concentration, but F7 is Battle Orders (CTA). Following it would have overwritten the CTA bind and cost a large share of the life pool -- the exact problem this session was fixing. - Replaces the migration paragraph with the verified end state, and records that Blessed Hammer lives on LEFT-CLICK, not an F-key (_cast_hammers puts the aura on the right slot, so a hammer hotkey would replace it). - Notes that concentration/redemption had to move into [paladin]; under [fohdin] a hammerdin never reads them and both would be silently unbound. - Adds the full verified bind map so F7 cannot be reassigned by mistake. - Rewrites the operator TODOs: fire resist is superseded (Zaka + Mara took chickens 3-in-8 -> 0-in-11); the live items are lightning/poison resist and the 75% FCR breakpoint, with the casting_frames mapping (75%=11, 60%=12, <48%=13) so cast timing tracks any gear change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * feat: baal_xp farm — game browser join, hide-and-wait state, config - src/ui/game_browser.py: retry-wrapped join flow (Play -> Join Game tab -> OCR game list -> click row -> loading/InGame confirm), wait_for_in_game - src/bot.py: 'baal_xp' state + run_baal_xp/end_run transitions; on_run_baal_xp: fast_save_and_exit -> hero select -> join public game -> corpse/nopickup/pre_buff -> walk to hide spot -> wait loop (XP every 30s, HP check, death recovery, InGame-miss re-anchor) -> leave -> recover to own game; on_end_run short-circuit straight to maintenance - src/config.py: [baal_xp] section (enabled, game_name_filter, max_wait_s, xp_threshold, min_hp_pct, hide_x/y, join_timeout_s) with profile overrides - config/params.ini: [baal_xp] section, order=run_baal_xp, run_trav - profile paladalla: order=run_baal_xp, run_trav (profile routes override base config — without this the route never activates) - stealth: daily budget cap (persisted, restart-proof), buy at A4 Jamella from A3 too (Ormus measured unreliable), session budget 20h * fix: import mouse in bot.py (baal_xp hide-spot click) * feat(stealth): hard per-day runtime cap that survives restarts, and quit D2R session_budget_h is per PROCESS. Every restart re-rolls it, so a bot that gets restarted -- by the user, or by the restart-on-crash path -- can run all day and never trip it. That is exactly the signal a runtime cap is meant to remove. It also silently failed in practice: params.ini still carried the temporary levelling value session_budget_h = 20, which rolls 13-27h, so the live config could not stop the bot within a day at all. Restored to 8. Adds daily_budget_h, keyed on the CALENDAR DATE and persisted to log/.daily_runtime.json, so restarts cannot hand out a fresh allowance. Design points that matter: - The rolled target is stored WITH the date. Re-rolling per process would make restarting a way to draw a bigger budget; once a day's target is chosen it is fixed until the date changes. - Jitter subtracts ONLY. daily_budget_h is a ceiling, not an average: a two-sided roll on 8h could hand out 9h, which is not what "cap it at 8 hours" means. 8 with 0.12 jitter now runs 7.0-8.0h and never more. Verified over 300 rolls: min 7.04h, max exactly 8.00h. - Time before the first tick in a process is not counted, so a crash under-counts rather than over-counts -- the safe direction for a cap. Also closes D2R when the cap trips (daily_budget_close_game, default on). The check runs in on_end_game AFTER save-and-exit, so the character is at the menu with nothing in progress and nothing is lost -- this is not the mid-game force kill that leaves D2R unenterable. A bot parked at character select for 16h is itself the pattern the cap exists to remove; a real player quits the game. The stealth manifest reports daily_budget by checking the CALL SITE in bot.py, not just the config value -- the lesson from chicken_variance and the AFK break that was 0-for-225 while the manifest said "wired". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: alexpolo1 <alex@alexpolo1.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Pixelbot for Diablo 2 Resurrected. This project is for informational and educational purposes only.
Installation (first time)
Step 1 — Install Miniforge (only needed once, skip if you already have conda/Miniconda)
Download and run the installer from: https://github.com/conda-forge/miniforge/releases/latest
Pick the Windows x86_64 .exe. Keep defaults; tick "Add to PATH" if asked.
Step 2 — Download Botty
Click the green Code button on this GitHub page → Download ZIP. Extract the ZIP anywhere (e.g. C:\botty).
Step 3 — Install dependencies
Double-click install.bat inside the extracted folder. It will create the botty conda environment and install everything. This takes a few minutes the first time.
install.bat detects Windows 10 vs Windows 11 automatically:
- Windows 10 uses
environment-win10.yml,requirements-win10.txt, and absolute mouse input. - Windows 11 uses
environment-win11.yml,requirements-win11.txt, and relative mouse input.
Botty also runs OS detection at startup and logs the selected requirements profile and mouse mode.
Step 4 — Configure
Open config\params.ini in Notepad and set at minimum:
[char] type=— your build (sorceress,hammerdin,paladin,trapsin, …)[routes] order=— which bosses to farm (e.g.run_pindle)- Hotkeys under your build's section to match your D2R keybinds
Step 5 — Start
Double-click run_botty.bat. Switch to D2R, go to the hero selection screen, then press F11 to start. Press F12 to stop.
D2R must be in English and running at 720p window mode.
Optional personal setup:
- Copy
.env.exampleto.envin the repo root and set personal values there. .envis git-ignored so multiple testers can use different local values without git conflicts.
Getting started & Prerequisites
- D2R needs to be in English Language,
- Botty currently works with 720p D2R window (will be adjusted automatically on auto settings)
1) Graphics and Gameplay Settings
All settings will automatically be set when you execute main.exe and press the hotkey for "Adjust D2R settings" (default ctrl+f9). It is not a 100% thing, in rare cases you might still have to fiddle around with your brightness. I suggest using the "Graphic Debugger" to verify your settings.
Note: Make sure that no other external programs adapt your graphics settings (HDR, Geforce Experience, etc.)
2) Supported builds
Check the documentation for params.ini further down. Different Sorc builds, Hammerdin, Barb, Trapsin are already implemented to different extents. It is quite straightforward to implement new classes. Give it a go if you like!
3) Start Location
Open up D2R and wait till you are at the hero selection screen. Make sure the char you running with is selected and will be in any of Act 3, 4 or 5 in the respective difficulty you set in the params.ini once the bot starts the game.
4) Start Botty
- Quick start: Double-click
run_botty.bat(auto-detects your conda env) - Manual:
conda activate bottythenpython src\main.py
After starting, focus your D2R window and press the start key (default f11). You can always force stop botty with f12. Note: Botty will use the /nopickup command in the first game to avoid pickup up trash while traversing. This command will only allow item pickup when "show items" is active.
Stability and safety updates
- XP OCR parsing now tolerates common OCR mistakes (
I/l/| -> 1,O/o -> 0, mixed-case "experience"). - XP status math no longer throws on early-session edge cases; unavailable projections show as
n/a. - Routine repair is best-effort for native-teleport builds to reduce fail spirals when NPC detection is flaky.
- Repair fallback from A5 now attempts A4 from Larzuk location for better path reliability.
- Discord message sending now guards invalid embed payloads and has a plain-text fallback.
- Selling now logs item names (not just positions) and shields are protected by default.
Development
Check out the development.md docu for infos on how to build from source and details of the project structure and code.
BNIP Pickit
Botty NIP (BNIP) is an extended version of Njaguar's Item Parser (NIP). BNIP is compatible with NIP (with some minor exceptions as discussed below).
There is a default nip file that comes with botty called "default.nip" inside config folder, you can add your own nip files by putting them inside config/nip with a file extension of .nip. Creating your own nip file also turns off the default.nip.
We suggest you read the NIP guide if you are unfamiliar with NIP https://github.com/blizzhackers/pickits/blob/master/NipGuide.md
New features in BNIP
Poison damage is no longer calculated, but is now read as it's raw value. Example: Adds 5-10 poison damage over 1 seconds can be picked with [poisonmindam] == 5 && [poisonmaxdam] == 10. "313 Poison Damage over 5 seconds" can be picked with [poisonmindam] == 313 or [poisonmaxdam] == 313.
[allres] is a thing now. example: [type] == amulet && [quality] == unique # [allres] == 30 will pick up Mara's
[idname] can now be used for unique / set items. For example, [idname] == thestoneofjordan will pick up SoJ. Keep in mind, however, this forces the item to be ID'd so be careful if you want to keep unid items.
[maxquantity] is not supported (yet). You can leave those tags in but they'll do nothing.
If you have the discord webhook hooked up to alert you when the bot keeps items, you can suppress these alerts by adding a "@" in front of your expression.
@[type] == ring = no notification [type] == ring = notification
Graphic Debugger
To check if you graphic settings are good and if the bot would pick up items there is a Graphic Debugger Mode. Start botty and press F10 (Default key). This will open up a (mostly black) window. Start a game in D2R and go to A5. You should see some templates with blue circles detected and scores printed out to the console. To check item finding, throw some items of different types on the ground. The debug window should show the item names with black background. If you throw an item on the ground that should be picked up, it will have a red circle. The console will print out the scores for each item that would be picked up. Scores should be well above 0.9 for these items.

params.ini
All botty configuration files are located in the config folder. To ease the switch to new botty versions, you can also overwrite any of the .ini fields in a custom.ini file. When a new version of botty is released you just copy the file to the new version without having to port all your params.ini changes to the new version. Example:
; custom.ini - overwrites 2 params in the params.ini
[general]
name=MyCustomName
[routes]
order=run_pindle, run_eldritch
| [general] | Descriptions |
|---|---|
| difficulty | Set to normal nightmare or hell for game difficulty. |
| name | Name used in terminal and discord messages. |
| randomize_runs | Randomize the order of [routes] specified in params.ini. |
| saved_games_folder | [Optional] Defaults to ~\Saved Games\Diablo II Resurrected. Used to store configuration settings for f9 / auto settings. |
| custom_loot_message_hook | Add your message hook here (such as Discord channel) to get info about loot |
| custom_message_hook | Add your message hook here (such as Discord channel) to get info about botty status updates, discord webhook is default. |
| discord_log_chicken | Set to 1 to enable messages about bot chickens, 0 to disable. |
| discord_status_count | Number of games between discord status messages being sent. Leave empty for no status reports. |
| message_api_type | Which api to use to send botty messages. Supports "generic_api" (basic discord), or "discord" (discord embeds with images). |
| break_length_m | Break for break_length_m minutes every max_runtime_before_break_m minutes |
| max_runtime_before_break_m | ^ |
| d2r_path | [Optional] Path to d2r.exe. If not set, it will default to C:\Program Files (x86)\Diablo II Resurrected\D2R.exe when attempting to restart. |
| max_consecutive_fails | Botty will stop making games if the number of consecutive fails reaches this max value. |
| max_game_length_s | Max game length in seconds. Botty will attempt to stop whatever it's doing and try to restart a new game at specified interval. If this fails, botty will attempt to shut down D2R and Bnet. |
| restart_d2r_when_stuck | Set to 1 and botty will attempt to restart d2r in the case that botty is unable to recover its state (e.g: game crash). |
| info_screenshots | If 1, the bot takes a screenshot with timestamp on every stuck / chicken / timeout / inventory full event. This is 1 by Default, so remember to clean up the folder every once in a while. |
| pickit_screenshots | If 1, the bot takes a screenshot with timestamp on every ground loot snapshot taken during pickit routine, can be useful for debugging. |
| loot_screenshots | If 1, the bot takes a screenshot with timestamp everytime he presses show_items button and saves it to loot_screenshots folder. Remember to clear them once in a while... |
| [routes] | Descriptions |
|---|---|
| order | Comma-delimited run list. If randomize_runs=0, Botty executes left-to-right. If randomize_runs=1, enabled runs are shuffled each game. Possible runs: run_trav, run_pindle, run_eldritch, run_eldritch_shenk, run_nihlathak (teleport strongly recommended), run_arcane (teleport strongly recommended), run_diablo (teleport recommended), run_vizier, run_andariel, run_countess, run_mephisto, run_baal |
Hammerdin keyrun example (stable-first):
order=run_countess, run_arcane, run_nihlathak
| [char] | Descriptions |
|---|---|
| type | Build type. Currently only "sorceress" or "hammerdin" is supported |
| belt_rows | Integer value of how many rows the char's belt has |
| casting_frames | Depending on your char and fcr you will have a specific casting frame count. Check it here: https://diablo2.diablowiki.net/Breakpoints and fill in the right number. Determines how much delay there is after each teleport for example. If your system has some delay e.g. on vms, you might have to increase this value above the suggest value in the table! |
| cta_available | 0: no cta available, 1: cta is available and should be used during prebuff |
| safer_routines | Set to 1 to enable optional defensive maneuvers/etc during combat/runs at the cost of increased runtime (ex. hardcore players) |
| num_loot_columns | Number of columns in inventory used for loot (from left!). Remaining space can be used for charms |
| force_move | Hotkey for "force move" |
| inventory_screen | Hotkey to open inventory |
| potion1 | Hotkey to take potion in slot 1 |
| potion2 | Hotkey to take potion in slot 2 |
| potion3 | Hotkey to take potion in slot 3 |
| potion4 | Hotkey to take potion in slot 4 |
| show_belt | Hotkey for "show belt" |
| show_items | Hotkey for "show items" |
| stand_still | Hotkey for "stand still". Note this can not be the default shift key as it would interfere with the merc healing routine |
| teleport | Hotkey for teleport (set blank if your character can't teleport) |
| town_portal | Hotkey for town portal |
| weapon_switch | Hotkey for "weapon switch" (only needed if cta_available=1) |
| battle_order | Hotkey for battle orders from cta (only needed if cta_available=1) |
| battle_command | Hotkey for battle command from cta (only needed if cta_available=1) |
| stash_gold | Bool value to stash gold each time when stashing items |
| use_merc | Set to 1 for using merc. Set to 0 for not using merc (will not revive merc when dead), default = 1 |
| atk_len_arc | Attack length for hdin/sorc fighting arcane |
| atk_len_eldritch | Attack length for hdin or number of attack sequences for sorc when fighting eldritch |
| atk_len_nihlathak | Attack length for hdin or number of attack sequences for sorc when fighting nihlathak |
| atk_len_pindle | Attack length for hdin or number of attack sequences for sorc when fighting pindle |
| atk_len_shenk | Attack length for hdin or number of attack sequences for sorc when fighting shenk |
| atk_len_trav | Attack length for hdin fighting trav (note this atk length will be applied in 4 different spots each) |
| atk_len_cs_trashmobs | Attack length for hdin or number of attack sequences when fighting Trash Mobs in Chaos Sanctuary (Diablo) |
| atk_len_diablo_deseis | Attack length for hdin or number of attack sequences when fighting Sealboss B "Lord De Seis" in Chaos Sanctuary (Diablo) |
| atk_len_diablo_infector | Attack length for hdin or number of attack sequences when fighting Sealboss C "Infector of Souls" in Chaos Sanctuary (Diablo) |
| atk_len_diablo_vizier | Attack length for hdin or number of attack sequences when fighting Sealboss A "Vizier of Chaos" in Chaos Sanctuary (Diablo) |
| atk_len_diablo | Attack length for hdin or number of attack sequences when fighting Diablo in Chaos Sanctuary |
| cs_mob_detect | If 1, it will attempt to use holy freeze from merc / conviction aura / poison to detect nearby mobs to help speed-up CS run. |
| cs_town_visits | CURRENTLY BROKEN, LEAVE AT 0 FOR NOW |
| kill_cs_trash | If 1, most Trash mob packs from Chaos Sancturay Entrance to Pentagram are cleared. If 0, the run starts at Pentagram and just kills Sealbosses & Diablo (default) |
| belt_hp_columns | Number of belt columns for healing potions |
| belt_mp_columns | Number of belt columns for mana potions |
| belt_rejuv_columns | Number of belt columns for rejuv potions |
| take_health_potion | Health percentage when healing potion will be used. e.g. 0.6 = 60% helath |
| take_mana_potion | Mana percentage when mana potion will be used |
| take_rejuv_potion_health | Health percentag when rejuv potion will be used |
| take_rejuv_potion_mana | Mana percentag when rejuv potion will be used |
| heal_merc | Merc health percentage when giving healing potion to merc |
| heal_rejuv_merc | Merc health percentage when giving rejuv potion to merc |
| chicken | Will chicken (leave game) when player health percentage drops below set value, range 0 to 1. Set to 0 to not chicken. |
| merc_chicken | Will chicken (leave game) when merc health percentage drops below set value, range 0 to 1. Set to 0 to not chicken. |
| enable_no_pickup | When enabled, will type /nopickup into chat at game start, which can help reduce accidental pickups especially for walking characters. |
| fill_shared_stash_first | Fill stash tabs starting from right to left, filling personal stash last |
| gamble_items | List of items to gamble when stash fills with gold. Leave blank to disable. Supported items currently include circlet, ring, coronet, talon, amulet |
| open_chests | Open up chests in some places. E.g. on dead ends of arcane. |
| pre_buff_every_run | 0: Will only prebuff on first run, 1: Will prebuff after each run/boss |
| runs_per_repair | Force repair after runs_per_repair of runs. Set to 0 to repair only when needed. |
| runs_per_stash | 0: Will only stash after intentional item pickup, 1+: Will force stash after # of runs set here (recommend at least 4 in case of accidental pickups) |
| sell_junk | 0: Discard unwanted items by dropping them on ground. 1: Discard items by selling them at vendor. |
| [transmute] | Descriptions |
|---|---|
| stash_destination | Stash tabs by priority to place the results of the transmute. Default: 3,2,1,0. (It means the result will be first placed in stash 3 untils it's full, then to stash 2, etc. 0 - personal tab) |
| transmute | Add any or all of chipped, flawed, standard, flawless to trasmute gems of these types |
| transmute_every_x_game | How often to run transmute routine (currently transmutes flawless gems into perfect gems). Transmute routine depends on stashing routine it will only start after items stashing is done. E.g. so it could take more than X games to perform transmutes if there were no items to stash at the time. Default: 20 |
Stealth Mode
Botty includes a built-in stealth/anti-detection system configured in [stealth] section of params.ini. All features aim to make bot behaviour look more human.
|| [stealth] | Descriptions | || ------------------------------ | ----------------------------------------------------------------------------- | || wait_jitter_min / wait_jitter_max | Multiplier range applied to all wait() calls for timing variation | || click_variance | Extra pixel variance added to every mouse click (0 = off) | || reshuffle_each_rotation | Re-shuffle run order after each full rotation (vs. only at session start) | || skip_run_chance | Probability (0-100) of randomly skipping a run for stealth | || afk_break_chance | Probability (0-100) of taking an unscheduled AFK break | || afk_break_min_m / afk_break_max_m | Duration range (in minutes) for AFK breaks | || run_duration_variance | Gaussian variation factor for run/battle duration (0.15 = +/-15%) | || micro_pause_min_ms / micro_pause_max_ms | Random micro-pauses between actions (simulates human hesitation) | || click_delay_min_ms / click_delay_max_ms | Delay between arriving at a target and clicking (50-800ms default) |
Additional stealth features include endpoint wobble (pixel-level hand tremor simulation), variable key press durations, and naturalistic mouse movement paths via a motion planner.
Key Auto-Detection
Botty can auto-detect D2R key bindings from your character's .key / .keyo file in ~\Saved Games\Diablo II Resurrected. Run python tools/test_key_detector.py to test parsing. The key detector reads the binary key file format and populates config.char values (inventory, potions, teleport, skills, etc.) so you don't need to set them manually in params.ini.
Click Recorder
A click recording and playback tool is included for debugging and path testing:
python tools/click_recorder.py record # F11=start/stop, F12=exit
python tools/click_recorder.py playback # replay with human-like timing
Records mouse clicks with timestamps and replays them with configurable speed and repeat count.
Asset Manager
A comprehensive tool for managing bot assets (templates). It helps with inventorying, auditing, searching, and optimizing template images.
python asset_manager.py inventory # List all templates
python asset_manager.py audit # Check for missing/low-quality templates
python asset_manager.py search <name> # Search for a specific template
python asset_manager.py quality # Analyze template quality (SNR, contrast)
python asset_manager.py batch resize 64x64 # Batch process templates
Features include similarity checking (to find duplicates), automatic cropping, and validation of template paths.
Asset Extractor
A workflow tool for capturing and cropping new templates from D2R screenshots. Designed to work alongside an AI agent for rapid asset generation.
python asset_extractor.py
- F1: Capture D2R screen to
screenshots/debug/latest.png. - F2: Crop entities using an AI-generated
latest_annotations.jsonfile. - F3: List all currently extracted assets.
Builds
|| [sorceress] | Descriptions | || ------------- | ----------------------------------------------------------------------------- | || frozen_armor | Optional Hotkey for frozen armor (or any of the other armors) | || energy_shield | Optional Hotkey for energy shield | || thunder_storm | Optional Hotkey for thunder storm | || static_field | Optional Hotkey for static field | || telekinesis | Optional Hotkey for telekinesis |
|| [light_sorc] | Descriptions | || ------------- | ----------------------------------------------------------------------------- | || chain_lightning | Optional Hotkey for chain_lightning (must be bound to left skill) | || lightning | Required Hotkey for lightning (must be bound to right skill) | || frozen_orb | Optional Hotkey for frozen orb (must be bound to right skill) |
|| [blizz_sorc] | Descriptions | || ------------- | ----------------------------------------------------------------------------- | || blizzard | Required Hotkey for Blizzard (must be bound to right skill) | || ice_blast | Optional Hotkey for ice_blast (must be bound to left skill) |
|| [nova_sorc] | Descriptions | || ------------- | ----------------------------------------------------------------------------- | || nova | Required Hotkey for Nova (must be bound to right skill) |
|| [hydra_sorc] | Descriptions | || ------------- | ----------------------------------------------------------------------------- | || alt_attack | Required Hotkey for any alternate attacking skill. Fireball,Lightning,Frozen Orb, etc. (must be bound to right skill) | || hydra | Required Hotkey for Hydra (must be bound to right skill) |
|| [paladin] | Descriptions | || -------------- | ----------------------------------------------------------------------------------- | || cleansing | Optional Hotkey for Cleansing | || holy_shield | Required Hotkey for Holy Shield | || redemption | Optional Hotkey for Redemption | || vigor | Optional Hotkey for Vigor |
|| [fohdin] | Descriptions | || -------------- | ----------------------------------------------------------------------------------- | || blessed_hammer | Hotkey for Blessed Hammer. (Optional. Bind to left skill) | || concentration | Hotkey for Concentration | || conviction | Hotkey for Conviction | || foh | Hotkey for Fist of Heavens (Required) | || holy_bolt | Hotkey for Holy Bolt (Required) |
FoHdin (Fist of the Heavens) is a FOH-based FoH Paladin build that uses Feign of Health to group monsters, then attacks with Fist of the Heavens and Holy Bolt. Works well for Hell difficulty farming runs.
|| [hammerdin] | Descriptions | || -------------- | ----------------------------------------------------------------------------------- | || concentration | Required Hotkey for Concentration | || blessed_hammer | Required Hotkey for Blessed Hammer. (must be bound to left skill!) |
|| [trapsin] | Descriptions | || -------------- | ----------------------------------------------------------------------------------- | || burst_of_speed | Optional Hotkey for Burst of Speed | || death_sentry | Required Hotkey for Death Sentry | || fade | Optional Hotkey for Fade | || lightning_sentry | Required Hotkey for Lightning Sentry | || shadow_warrior | Optional Hotkey for Shadow Warrior | || skill_left | Optional Hotkey for Left Skill |
|| [barbarian] | Descriptions | || -------------- | ----------------------------------------------------------------------------------- | || cry_frequency | Time in seconds between each cast of war_cry. Set to 0.0 if max fcr should be used | || find_item | Optional Hotkey for Find Item | || leap | Required Hotkey for Leap | || shout | Required Hotkey for Shout | || war_cry | Required Hotkey for War Cry |
|| [Necro] | Descriptions | || -------------- | ----------------------------------------------------------------------------------- | || skill_left | Required Hotkey for attack (bonespear/teeth) | || bone_armor | Required Hotkey for Bone Armor | || clay_golem | Required Hotkey for Clay Golem | || raise_skeleton | Required Hotkey for Raise Skeleton | || amp_dmg | Required Hotkey for Amplify Damage | || corpse_explosion | Required Hotkey Corpse Explosion | || raise_revive | Required Hotkey revive | || damage_scaling | Adjusts time spent casting attack skills. Ex: 2 will cast twice as long | || clear_pindle_packs | Clears mobs before pindle |
|| [advanced_options] | Descriptions | || -------------------- | --------------------------------------------------------------------- |
Tooling
New route scaffolding
A CLI tool is provided to scaffold new farming routes in one step:
python3 tools/new_route.py --name <name> --display "<Display Name>" --act <1-5>
This creates src/run/<name>.py from a template and mutates src/bot.py and
src/run/__init__.py to wire the new route into the bot's state machine.
Options:
| Option | Description |
|---|---|
--name |
Snake-case run name (e.g. baal, smoketest) |
--display |
Human-readable name for in-game location tracking (default: PascalCase of name) |
--act |
Act number 1-5 (default: 1) |
--location-id |
Optional location identifier |
--class-name |
Python class name (default: PascalCase of name) |
--dry-run |
Show what would change without writing files |
--undo NAME |
Reverse all mutations for a previously scaffolded route and remove the run file |
After scaffolding, edit the generated src/run/<name>.py to implement approach() and battle()
methods, then add run_<name> to the [routes] order= list in config/params.ini.
