; There is detailed documentation for each parameter in the README.md [general] ; Personal values can reference env keys from repo-root .env: ; Example syntax: ; custom_message_hook=${BOTTY_CUSTOM_MESSAGE_HOOK} ; custom_loot_message_hook=${ENV:BOTTY_CUSTOM_LOOT_MESSAGE_HOOK} ; bnet_name=${BOTTY_BNET_NAME} ; bnet_pass=${BOTTY_BNET_PASS} ; char_name=${BOTTY_CHAR_NAME} ; difficulty: game difficulty to create ("normal", "nightmare", "hell") ; ; Hammerdin difficulty guide (CTA build with Conviction aura): ; NORMAL - Very easy. 1-2h Hammer kills most packs. No CTA needed. ; NIGHTMARE - Recommended starting point. Bosses hit ~100-200 dmg. ; CTA + Conviction drops resists. Need decent armor (ED/HR). ; Gear targets: ~200 AR, ~15 ED, ~30% HR, ~50% FCR on hammer. ; HELL - Bosses hit 400-800+ dmg per swing. Conviction is mandatory. ; Gear targets: ~350+ AR, ~20+ ED, ~50%+ HR, ~60%+ FCR, ; ~150% IAS on weapon. Full Rejuv belt recommended. ; If you chicken/die repeatedly, drop to Nightmare first. difficulty=hell ; name: bot profile name used in logs/messages and mod launch option replacement name=fistman ; randomize_runs: 0 = run in listed order, 1 = shuffle run order randomize_runs=0 ; target_tz: target Terror Zone id (leave as default unless you know the mapping) target_tz=1 ; saved_games_folder: optional override path to D2R Saved Games folder (blank = auto) saved_games_folder= ; level_max_steps: max pathing steps for leveling-style routines level_max_steps=20 ; Set to 1 to enable auto-login and auto-launch of D2R on startup. ; Credentials below are ONLY used when auto_login=1. auto_login=0 bnet_name=${BOTTY_BNET_NAME} bnet_pass=${BOTTY_BNET_PASS} ; Character name to auto-select from the character selection screen ; If empty, bot relies on the saved character template from previous sessions char_name=${BOTTY_CHAR_NAME} ; messaging ; custom_loot_message_hook: optional separate webhook for loot notifications custom_loot_message_hook=${BOTTY_CUSTOM_LOOT_MESSAGE_HOOK} ; custom_message_hook: main webhook for status/death/chicken messages custom_message_hook=${BOTTY_CUSTOM_MESSAGE_HOOK} ; discord_log_chicken: 1 = send chicken/death style notifications discord_log_chicken=1 ; discord_log_errors: 1 = send a Discord message + error screenshot every time a ; run fails (approach/battle/exception). Set to 0 to keep error screenshots on ; disk only. Can also be toggled via [discord_events] error=0. discord_log_errors=1 ; discord_status_runs: send periodic status every X completed runs (blank/0 disables) discord_status_runs=10 ; discord_status_count: legacy fallback, send periodic status every X games (blank/0 disables) discord_status_count=20 ; message_api_type: "" disables messaging, "discord" or "generic_api" message_api_type=discord ; breaks ; break_length_m: scheduled break duration in minutes (0 = disabled) break_length_m=0 ; max_runtime_before_break_m: runtime before taking scheduled break (0 = disabled) max_runtime_before_break_m=0 ; timers / fail handling ; d2r_path: Diablo II: Resurrected install path d2r_path=C:\Program Files (x86)\Diablo II Resurrected ; max_consecutive_fails: stop bot after this many failed runs in a row max_consecutive_fails=5 ; max_game_length_s: emergency timeout per run/game ; 900: a full Chaos Sanctuary clear (3 seals + bosses + loot) takes ~10 min; ; 600 force-quit a game while literally waiting for Diablo to spawn (2026-06-10). ; Genuinely stuck games are caught much earlier by max_maintenance_time_s and ; approach step timeouts. max_game_length_s=900 ; max_maintenance_time_s: if the town maintenance loop (heal/buy/stash/repair) takes ; longer than this many seconds, save-and-exit and rejoin a fresh game. ; Prevents the bot staying stuck in A5 town forever when NPCs or pathing fail. max_maintenance_time_s=240 ; auto_downgrade_threshold: if combined chickens+deaths exceed this number within 1 hour, ; bot automatically lowers difficulty by one tier (hell->nightmare->normal) and restarts. ; Set to 0 to disable. (NOTE: feature is parsed but not yet active in bot logic) auto_downgrade_threshold=0 restart_d2r_when_stuck=1 ; hardcore: 1 enables hardcore-safe assumptions in some routines hardcore=0 ; screenshots ; info_screenshots: save screenshots for info/chicken/death events info_screenshots=1 ; error_screenshots: save a screenshot to log/screenshots/error/ every time a run ; fails (approach failure, battle failure, or an exception) so logs and visuals can ; be reviewed side by side. Falls back to info_screenshots if unset. error_screenshots=1 ; loot_screenshots: save screenshots for picked loot loot_screenshots=0 ; pickit_screenshots: save screenshots for pickit debugging pickit_screenshots=1 ; recovery ; disable_run_after_failures: after this many CONSECUTIVE failures of the same run ; (e.g. run_vizier), the bot disables just that run for the rest of the session and ; keeps doing the other runs instead of stopping. A single success resets the count. ; If every run gets disabled the bot stops for investigation. Set high to effectively ; disable this behaviour. disable_run_after_failures=5 [discord_events] ; Fine-grained Discord event toggles (1=send, 0=disable) ; status: periodic status + generic bot messages (breaks, shop notifications, etc.) status=1 ; item_keep: send kept item notifications (loot webhooks/embeds) item_keep=1 ; death: send death notifications death=1 ; chicken: send chicken (emergency leave) notifications chicken=1 ; stash_full: send stash full notifications stash_full=1 ; gold_full: send gold full notifications gold_full=1 ; error: send run-failure notifications (message + error screenshot) error=1 [stealth] ; Multiplies all wait() calls by a random value in this range each call ; 1.0 = no change. Set range wider for more human-like timing variation. wait_jitter_min = 0.85 wait_jitter_max = 1.20 ; Extra pixel variance added to every mouse click (on top of existing randomize=5) ; 0 = off, 10 = +/-10px extra random offset per click click_variance = 8 ; Re-shuffle run order after completing a full rotation (vs only at session start) ; 0: keep [pindle, diablo] fixed so every game ENDS in A4 town (Diablo run TPs ; there) — the next game then spawns at A4 where Jamella/Cain/Tyrael work, ; avoiding the A5 Malah vendor entirely (stale templates in current patch). reshuffle_each_rotation = 0 ; Probability (0-100) of randomly skipping a run each game ; 0 = never skip, 20 = skip ~1 in 5 runs skip_run_chance = 10 ; Probability (0-100) of taking an unscheduled AFK break after any given run afk_break_chance = 5 ; Break duration range in minutes afk_break_min_m = 2 afk_break_max_m = 12 ; Vary run/battle duration by a Gaussian factor (default +/-15%) ; 0.0 = no variation, 0.3 = up to +/-30% variation run_duration_variance = 0.15 ; Micro-pause between actions (simulates human hesitation in milliseconds) micro_pause_min_ms = 20 micro_pause_max_ms = 120 ; Vary kill time to avoid perfectly consistent boss fight durations vary_kill_time = 1 ; Human mouse curve complexity (1.0 = default, 0.5 = more direct, 1.5 = more winding) human_curve_complexity = 1.0 ; Arrival-to-click delay: human-like pause between mouse arriving and clicking (milliseconds) ; 50-800ms range simulates "is this the right thing?" hesitation click_delay_min_ms = 50 click_delay_max_ms = 800 ; Key press duration variance: how long a key is held (milliseconds) ; Most presses are short (20-100ms), some linger (up to 200ms) key_press_min_ms = 20 key_press_max_ms = 200 ; Skill rotation hesitation: pause before casting a skill (milliseconds) ; Prevents machine-speed skill spam skill_hesitation_min_ms = 80 skill_hesitation_max_ms = 300 ; Wrong waypoint chance: 2-3% of selecting wrong TP portal then correcting ; Humans occasionally misclick waypoint targets wrong_waypoint_chance = 0.025 ; Skill mistake chance: 1-2% chance of miscasting and correcting ; Simulates human error during combat skill_mistake_chance = 0.015 [routes] ; Controls which farm runs Botty performs each game. ; "order" is a comma-delimited list and runs left-to-right when randomize_runs=0. ; If randomize_runs=1 (in [general]), Botty shuffles enabled runs each game. ; ; Hammerdin keyrun recommendation (stable-first): ; order=run_countess, run_arcane, run_nihlathak ; ; Route quick notes: ; run_trav (Act 3 Travincal council farm; short/high-density run) ; run_pindle (Act 5 Nihlathak temple red portal boss farm) ; run_eldritch (Act 5 Frigid Highlands Eldritch-only run) ; run_eldritch_shenk (Act 5 Eldritch then Shenk in same game) ; run_nihlathak (Act 5 Halls of Vaught, teleport strongly recommended) ; run_arcane (Act 2 Arcane Sanctuary / Summoner, teleport strongly recommended) ; run_diablo (Act 4 Chaos Sanctuary, teleport recommended) ; run_vizier (Act 4 Chaos Vizier-only route; lighter/faster than full Diablo run) ; run_andariel (Act 1 Catacombs) ; run_countess (Act 1 Forgotten Tower) ; run_mephisto (Act 3 Durance of Hate) ; run_baal (Act 5 Throne of Destruction) order=run_pindle, run_diablo [char] ; ========================== ; ==== Mandatory Fields ==== ; ========================== ; These configs have to be alligned with your d2r settings and char build ; type: character build profile to use (must match one section below) ; examples: blizz_sorc, hammerdin, fohdin type=hammerdin ; belt_rows: in-game belt size (2/3/4) belt_rows=4 ; casting_frames: your char cast breakpoint (affects action timing) casting_frames=8 ; cta_casting_frames: cast breakpoint on CTA swap (if used) cta_casting_frames=8 ; attack_frames: base attack animation timing for non-cast attacks attack_frames=15 ; cta_available: 1 if Call to Arms swap exists, else 0 cta_available=1 ;Do we want to cast non-cta buffs (ex energy shield) with cta buff_with_cta=1 ; safer_routines: enable for optional defensive maneuvers/etc during combat/runs at the cost of increased runtime (ex. hardcore players) safer_routines=1 ; num_loot_columns: Number of empty columns from left to right of inventory to be used for looting. ; Store charms, etc. to the right of the inventory. num_loot_columns=4 ; game hotkeys: ; NOTE: each key must match your in-game binding exactly force_move=e inventory_screen=i potion1=1 potion2=2 potion3=3 potion4=4 ; show_belt is different from the default hotkey as "~" is for many keyboards not reachable without also pressing altgr show_belt=k show_items=alt ; stand_still cannot be the default "shift" as it would interfere with merc healing stand_still=capslock ; teleport: leave empty if you can't use teleport=b town_portal=6 ; call to arms settings: ; weapon_switch/battle_orders/battle_command only used when cta_available=1 weapon_switch=w battle_orders=7 battle_command=8 ; ========================== ; ==== Optional configs ==== ; ========================== stash_gold=1 use_merc=1 ; Attack length for barbarians should be as high as 8-10 and even 10-12 for trav/shenk ; ; Hammerdin attack lengths (seconds of hammer spam per boss): ; atk_len_trav = 4.0 (Council of 3 - 3 council members, easy) ; atk_len_pindle = 8.0 (Pindle — Hell: 13094-16070 HP, 75% fire, 100% poison) ; Pindle stats by difficulty: ; Normal: 1064-1588 HP, 75% fire, 70% poison ; Nightmare: 4773-5859 HP, 100% poison ; Hell: 13094-16070 HP, 75% fire, 50% cold, 33% light, 100% poison ; With Conviction (-33% res), Hell Pindle = 50% fire, 17% cold, 0% light, 67% poison ; CTA adds +100% dmg to hammer. Need ~60%+ FCR and good IAS to kill in 8s. ; atk_len_nihlathak = 4.0 (Nihlathak - single boss) ; atk_len_eldritch = 3.0 (Eldritch only - single boss) ; atk_len_shenk = 4.0 (Shenk only - single boss) ; atk_len_arc = 2.5 (Summoner in Arcane - single boss) ; atk_len_diablo = 10.0 (Diablo in CS - longest single boss) ; atk_len_countess = 3.0 (Countess - single boss, easy) ; atk_len_andariel = 4.0 (Andariel - single boss) ; atk_len_mephisto = 12.0 (Mephisto - single boss, high HP) ; atk_len_baal = 10.0 (Baal - single boss) ; atk_len_baal_waves = 30.0 (Baal's spawn waves before boss) ; ; Chaos Sanctuary (Diablo run) individual fights: ; atk_len_cs_trashmobs = 2.0 (Trash packs in CS) ; atk_len_diablo_vizier = 2.0 (Vizier of Chaos - seal boss A) ; atk_len_diablo_infector = 4.0 (Infector of Souls - seal boss C) ; atk_len_diablo_deseis = 5.0 (Lord De Seis - seal boss B, hardest seal) ; ; Increase these if your hammer kills slower (low IAS/FCR). ; Decrease if your hammer kills faster (high IAS/FCR, good gear). ; If you die during a fight, the attack length is too long for your defense. atk_len_arc=2.5 atk_len_eldritch=3.0 atk_len_nihlathak=4.0 atk_len_pindle=8.0 atk_len_shenk=4.0 atk_len_diablo=3.0 atk_len_trav=4.0 ; Boss run attack lengths (per-character defaults in kill_* methods) ; Adjust these if your build is faster/slower against these bosses atk_len_andariel=4.0 atk_len_countess=3.0 atk_len_mephisto=12.0 atk_len_baal=10.0 atk_len_baal_waves=30.0 ; Chaos Sanctuary settings atk_len_cs_trashmobs=2.0 atk_len_diablo_deseis=5.0 atk_len_diablo_infector=4.0 atk_len_diablo_vizier=2.0 cs_mob_detect=0 ; cs_town_visits is currently broken, ignore for now cs_town_visits=0 kill_cs_trash=1 ; Belt settings belt_hp_columns=1 belt_mp_columns=1 belt_rejuv_columns=2 ; Potion/chicken settings take_health_potion=0.60 take_mana_potion=0.40 take_rejuv_potion_health=0.45 take_rejuv_potion_mana=0.10 heal_merc=0.60 heal_rejuv_merc=0.25 chicken=0.40 merc_chicken=0.20 ; Misc. ; helps reduce accidental pickups when enabled especially on walking characters enable_no_pickup=0 ; fill_shared_stash_first: 1 = prefer shared stash tabs before personal stash fill_shared_stash_first=0 ; to gamble, add any/all of the following: circlet, ring, coronet, talon, amulet gamble_items= ; open_chests: 1 = open clickable chests along path when possible open_chests=1 ; pre_buff_every_run: 1 = always recast buffs at run start pre_buff_every_run=1 ; runs_per_repair: visit repair vendor every X runs (blank/0 disables) runs_per_repair=5 ; repair_npc: preferred repair vendor strategy. ; - a5_larzuk (recommended: stays in A5, no cross-act trip; falls back to Halbu) ; - a4_halbu (requires WP trip to A4 every repair — act desync risk if it fails) ; 2026-06-10: switched to a5_larzuk — session logs showed Halbu detection failing ; 100% (body score ~0.39) and each failed A4 trip desynced the bot's act state. repair_npc=a5_larzuk ; runs_per_stash: stash/sell every X runs (blank/0 disables) runs_per_stash=4 ; sell_junk: 1 = vendor non-keep items automatically sell_junk=1 ; protect_shields_from_sell: 1 = never vendor items with "shield" in detected name (recommended safety) protect_shields_from_sell=1 ; pick_rares_for_gold: 1 = pick all yellow (rare) ground items; non-keep rares will be sold ; Requires sell_junk=1 to convert extra pickups into gold. pick_rares_for_gold=0 ; pick_gold: 1 = pick up ground gold piles, 0 = ignore all ground gold pick_gold=1 [transmute] ;stash tabs by priority where to put transmuted gems stash_destination=0,1,2,3 ; Add these possible gems to "transmute" to transmute them: ; chipped, flawed, standard, flawless transmute=flawless ;how often we want to run transmute routine(e.g. every 100 games) transmute_every_x_game=60 ; number of stash tabs (ROTW has more than 6, adjust as needed) stash_tabs=6 ; potion transmute settings ; convert_rejuv: 1 = convert regular Rejuv Potions to Full Rejuv via cube (3 -> 1) convert_rejuv=1 ; min_rejuv_to_convert: minimum regular rejuv potions in inventory before starting conversion min_rejuv_to_convert=6 ; =========================== ; ==== Builds: Sorceress ==== ; =========================== [sorceress] energy_shield=f4 frozen_armor=f7 static_field=f5 telekinesis=f6 thunder_storm= [light_sorc] ; chain_lightning must be bound to left skill (hotkey optional as it shouldnt change) chain_lightning= ; lightning must be right skill, hotkey required lightning= ; frozen orb must be right skill, hotkey recommended to increase safty for you and merc at trav! frozen_orb= [blizz_sorc] ; blizzard must be right skill, hotkey required blizzard=f1 ; ice_blast must be left skill (hotkey optional as it shouldnt change) ice_blast=f2 [blizzorb_sorc] ; frozen orb must be left skill and preselected (no hotkey required) ;All others must be right skill and hotkey required! blizzard=f1 glacial_spike=f7 [nova_sorc] ; nova must be right skill, hotkey required nova=f1 [hydra_sorc] ; only supports Pindle and Eldritch currently ; alt_attack is any alternate attacking right skill. Fireball,Lightning,Frozen Orb, hotkey required alt_attack=f7 ; hydra must be right skill, hotkey required hydra=f1 ; ========================= ; ==== Builds: Paladin ==== ; ========================= [paladin] cleansing=f9 holy_shield=f2 redemption=f3 vigor=f4 [fohdin] ; foh must be left skill, hotkey required blessed_hammer=f1 concentration=f8 conviction=f5 foh=f6 holy_bolt=f7 [hammerdin] blessed_hammer=f1 concentration=f8 conviction=f5 ; ========================= ; ==== Builds: Warlock ==== ; ========================= [warlock] ; All skills should be on right-click unless otherwise specified deathmark=f3 lethargy=f4 ;Set summon_demon to one of the three demons of your choice. summon_demon=f5 ;If you are summoning a 2nd demon set hotkey here. Can be same as above summon_demon2= psychic_ward= [fire_lock] ; Supported runs: Pindle ;flame_wave must be assigned to left-click and doesn't require hotkey ring_of_fire=f1 apocalypse=f2 [abyss_lock] ; Supported runs: Pindle ;miasma_bolt must be assigned to left-click and doesn't require hotkey miasma_chain=f1 abyss=f2 [echo_lock] ; Supported runs: Trav (tele only) echo_strike=f1 eldritch_blast=f2 hex_bane=f3 ;Set ring of fire if you want to stun before echo blast ring_of_fire= ; ========================== ; ==== Builds: Assassin ==== ; ========================== ; Currently no Trav implementaiton! [trapsin] ; We assume fire blast or shock web is left-click skill which is optional hotkey if pre-assigned. skill_left= ; Assume all other skills are right-click and hotkey required! burst_of_speed=f1 death_sentry=f2 fade= lightning_sentry=f3 shadow_warrior=f4 mind_blast=f5 ; =========================== ; ==== Builds: Barbarian ==== ; =========================== ; Supported runs: Trav, Pindle, Eld, Shenk, Nihlathak (tele only) ; Make sure leap hotkey is set if you do not have Enigma ; Ensure Battle Order/Command hotkeys are set above in the [char] section [barbarian] cry_frequency=0.7 find_item= leap= shout= war_cry= ; =========================== ; ==== Builds: Amazon ==== ; =========================== ; Supported runs: Trav, Pindle, Eld, Shenk, Nihlathak (tele only) ; Make sure leap hotkey is set if you do not have Enigma ; Ensure Battle Order/Command hotkeys are set above in the [char] section [amazon] ;all must be right-click skill valkyrie=f1 [javazon] ; charged strike must be left-click skill and preselected, no hotkey required ;all others must be right-click lightning_fury=f2 ; ========================== ; ==== Builds: Necro ==== ; ========================== ; Pindle+eld+shenk+trav (walking only!) ; needs all of these skills ;skill_left is just some ranged damage spell (spear,teeth, nova,etc) ;leave teleport blank for now this build currently is walking only ;tested with something like this https://d2.maxroll.gg/d2planner/3x01067c ;recomended to set skeleton mage to same as revive hot hey ;skeleton mages cause pathing issues not ideal to use yet [necro] amp_dmg= bone_armor= clay_golem= clear_pindle_pack= corpse_explosion= heart_of_wolverine= raise_mage= raise_revive= raise_skeleton= skill_left= [poison_necro] bone_armor= # Can use any golem clay_golem= clear_pindle_pack= corpse_explosion= heart_of_wolverine= # Can Use any curse lower_res= poison_nova= raise_mage= raise_revive= raise_skeleton= # Not Required skill_left= [bone_necro] bone_armor= bone_spear= bone_spirit= bone_wall= clay_golem= teeth= ; Damage scaling. One setting to adjust kill speed to account for better/worse gear. ; ex: 2 will cast all attack skills twice a long, .5 half as long. Currently only used by bone necro damage_scaling=1 ; ==== Builds: Basic ==== ; Supported runs: UNTESTED (this is your job!) ; this will basically continuously left attack, unless right attack is available. ; if the buffs are not set they are not used (they are part of the prebuff setup) [basic] left_attack=1 right_attack= buff_1= buff_2= ; ==== Builds: Basic Ranged==== ; Supported runs: UNTESTED (this is your job!) ; this will basically continuously left attack, unless right attack is available. ; if the buffs are not set they are not used (they are part of the prebuff setup) [basic_ranged] left_attack= right_attack= buff_1= buff_2= [advanced_options] ; startup hotkeys ; select_runs_key: open run selector UI select_runs_key=pagedown ; restore_settings_from_backup_key: restore backed-up D2R settings restore_settings_from_backup_key=insert ; settings_backup_key: create backup of current D2R settings settings_backup_key=pause ; auto_settings_key: auto-apply required D2R settings auto_settings_key=pageup ; graphic_debugger_key: toggle on-screen debug layers graphic_debugger_key=delete ; resume_key: start/pause bot loop resume_key=f11 ; exit_key: hard stop bot exit_key=f12 ; etc. ; graphic_debugger_layer_creator: 1 = enable interactive layer creator tooling graphic_debugger_layer_creator=0 ; hwnd_window_process: process regex used to locate D2R window handle hwnd_window_process=D2R\.exe ; hwnd_window_title: optional title regex override for window lookup hwnd_window_title= ; launch_options: will replace with setting for [general] "name" above launch_options=-mod -txt ; logg_lvl: logging verbosity (debug/info/warning/error) logg_lvl=debug ; message_body_template: payload template for generic_api mode message_body_template={{"content": "{msg}"}} ; message_headers: optional JSON headers for generic_api mode message_headers= ; ocr_during_pickit: 1 = run OCR while looting (slower, more diagnostics) ocr_during_pickit=0 ;use "can_teleport_natively" or "can_teleport_with_charges" if you want to force certain behavior in case autodetection isn't working properly override_capabilities=can_teleport_natively ; pathing_delay_factor: movement/click delay multiplier (1 fast .. 10 slow) pathing_delay_factor=2 ; If you want to control Hyper-V window from host use 0,51 here ; window_client_area_offset: x,y pixel offset for captured game client area window_client_area_offset=0,0 [log_rotation] ; Log rotation prevents screenshot directories from filling the disk. ; Each managed directory has a max file count and max total size. ; When limits are exceeded, oldest files are deleted automatically. ; Checked every 60 seconds (to avoid I/O overhead during runs). ; pickit directory (log/screenshots/pickit/): ; Can grow very fast — every item scan writes a PNG + JSON. ; pickit_max_files=500 ; max files before rotation kicks in ; pickit_max_mb=500 ; max total size in MB pickit_max_files=300 pickit_max_mb=200 ; info directory (log/screenshots/info/): ; Debug screenshots for deaths, chickens, errors, etc. ; info_max_files=200 ; max files before rotation kicks in ; info_max_mb=500 ; max total size in MB info_max_files=100 info_max_mb=200 ; items directory (log/screenshots/items/): ; Loot screenshots sent to Discord. ; items_max_files=100 ; items_max_mb=100 items_max_files=50 items_max_mb=50 ; discord_notify_rotation: 1 = send Discord message when log rotation deletes files discord_notify_rotation=0