diff --git a/README.md b/README.md
index 538e507..ff35e54 100644
--- a/README.md
+++ b/README.md
@@ -12,8 +12,8 @@ And please. I urge you to actually read that README! It will make your life a lo
Botty only supports English language! Botty is currently working in 1080p or 720p and will try to adjust the D2R settings accordingly depending on your monitor res and your botty setting for "res" in the [general] section.
### 1) Graphics and Gameplay Settings
-All settings will automatically be set when you execute `run.exe` and press the hotkey for "Adjust D2R settings" (default f9). Note that D2R should not run during this process, or if it does you will have to restart afterwards. 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. Also, there are sample screenshots of how graphics should look like: Example 1, Example 2
-**Note**: There have been issues reported with image sharpening being truned on via the graphic card settings itself outside of D2R. Try turning it off when running botty.
+All settings will automatically be set when you execute `run.exe` and press the hotkey for "Adjust D2R settings" (default f9). Note that D2R should not run during this process, or if it does you will have to restart afterwards. 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**: There have been issues reported with image sharpening being truned on via the graphic card settings itself outside of D2R. Try turning it off when running botty. Also HDR should be truned off.
### 2) Supported builds
@@ -115,11 +115,12 @@ thunder_storm | Optional Hotkey for thunder storm
[hammerdin] | Descriptions
--------------------------------|---------------------------------------------
-teleport | Required Hotkey for teleport
+teleport | Optional Hotkey for teleport. If left empty hammerdin will run instead of teleport.
concentration | Required Hotkey for Concentration
-redemption | Optional Hotkey for redemption
holy_shield | Hotkey for Holy Shield
blessed_hammer | Hotkey for Blessed Hammer
+redemption | Optional Hotkey for redemption
+vigor | Optional Hotkey for vigor
[advanced_options] | Descriptions
--------------------------------|---------------------------------------------
diff --git a/assets/docs/sample_graphics.png b/assets/docs/sample_graphics.png
deleted file mode 100644
index 184dffc..0000000
Binary files a/assets/docs/sample_graphics.png and /dev/null differ
diff --git a/assets/docs/sample_graphics_2.png b/assets/docs/sample_graphics_2.png
deleted file mode 100644
index fac4601..0000000
Binary files a/assets/docs/sample_graphics_2.png and /dev/null differ
diff --git a/assets/templates/vigor.png b/assets/templates/vigor.png
new file mode 100644
index 0000000..23f9d91
Binary files /dev/null and b/assets/templates/vigor.png differ
diff --git a/assets/templates_1280_720/vigor.png b/assets/templates_1280_720/vigor.png
new file mode 100644
index 0000000..3b93554
Binary files /dev/null and b/assets/templates_1280_720/vigor.png differ
diff --git a/game.ini b/game.ini
index d2fcc64..e22d6bd 100644
--- a/game.ini
+++ b/game.ini
@@ -91,6 +91,8 @@ item_height_min=9
item_width_min=30
; pather
reached_node_dist=150
+min_walk_dist=38
+max_walk_dist=190
[ui_roi_1920_1080]
; all rois are in [left, top, width, height] format
diff --git a/params.ini b/params.ini
index 7748e02..8e89841 100644
--- a/params.ini
+++ b/params.ini
@@ -69,9 +69,10 @@ telekinesis=
[hammerdin]
teleport=f1
concentration=f2
-redemption=
holy_shield=f4
blessed_hammer=f5
+vigor=
+redemption=
[advanced_options]
;===== don't touch unless you know what you're doing =====
diff --git a/src/char/hammerdin.py b/src/char/hammerdin.py
index 04058f5..3c5308a 100644
--- a/src/char/hammerdin.py
+++ b/src/char/hammerdin.py
@@ -16,6 +16,11 @@ class Hammerdin(IChar):
Logger.info("Setting up Hammerdin")
super().__init__(skill_hotkeys, char_config, screen, template_finder, ui_manager)
self._pather = pather
+ self._do_pre_move = True
+ # In case we have a running pala, we want to switch to concentration when moving to the boss
+ # ass most likely we will click on some mobs and already cast hammers
+ if not self._skill_hotkeys["teleport"]:
+ self._do_pre_move = False
def pre_buff(self):
if self._char_config["cta_available"]:
@@ -30,7 +35,8 @@ class Hammerdin(IChar):
wait(0.05, 0.15)
keyboard.send(self._char_config["stand_still"], do_release=False)
wait(0.05, 0.15)
- keyboard.send(self._skill_hotkeys["blessed_hammer"])
+ if self._skill_hotkeys["blessed_hammer"]:
+ keyboard.send(self._skill_hotkeys["blessed_hammer"])
wait(0.05, 0.15)
mouse.press(button="left")
start = time.time()
@@ -56,7 +62,10 @@ class Hammerdin(IChar):
if self._config.char["static_path_pindle"]:
self._pather.traverse_nodes_fixed("pindle_end", self)
else:
- self._pather.traverse_nodes(Location.PINDLE_SAVE_DIST, Location.PINDLE_END, self, time_out=0.5)
+ if not self._do_pre_move:
+ keyboard.send(self._skill_hotkeys["concentration"])
+ wait(0.05, 0.15)
+ self._pather.traverse_nodes(Location.PINDLE_SAVE_DIST, Location.PINDLE_END, self, time_out=1.0, do_pre_move=self._do_pre_move)
self._cast_hammers(1)
# pindle sometimes knocks back, get back in
self._pather.traverse_nodes(Location.PINDLE_SAVE_DIST, Location.PINDLE_END, self, time_out=0.1)
@@ -69,7 +78,10 @@ class Hammerdin(IChar):
if self._config.char["static_path_eldritch"]:
self._pather.traverse_nodes_fixed("eldritch_end", self)
else:
- self._pather.traverse_nodes(Location.ELDRITCH_SAVE_DIST, Location.ELDRITCH_END, self, time_out=0.5)
+ if not self._do_pre_move:
+ keyboard.send(self._skill_hotkeys["concentration"])
+ wait(0.05, 0.15)
+ self._pather.traverse_nodes(Location.ELDRITCH_SAVE_DIST, Location.ELDRITCH_END, self, time_out=1.0, do_pre_move=self._do_pre_move)
wait(0.05, 0.1)
self._cast_hammers(self._char_config["atk_len_eldritch"])
wait(0.05, 0.15)
@@ -77,13 +89,26 @@ class Hammerdin(IChar):
return True
def kill_shenk(self):
- self._pather.traverse_nodes(Location.SHENK_SAVE_DIST, Location.SHENK_END, self, time_out=0.2)
+ if not self._do_pre_move:
+ keyboard.send(self._skill_hotkeys["concentration"])
+ wait(0.05, 0.15)
+ self._pather.traverse_nodes(Location.SHENK_SAVE_DIST, Location.SHENK_END, self, time_out=1.0, do_pre_move=self._do_pre_move)
wait(0.05, 0.1)
self._cast_hammers(self._char_config["atk_len_shenk"])
wait(0.05, 0.15)
self._do_redemption()
return True
+ def pre_move(self):
+ # select teleport if available
+ super().pre_move()
+ # in case teleport hotkey is not set or teleport can not be used, use vigor if set
+ should_cast_vigor = self._skill_hotkeys["vigor"] and not self._ui_manager.is_right_skill_selected(["VIGOR"])
+ can_teleport = self._skill_hotkeys["teleport"] and self._ui_manager.is_right_skill_active()
+ if should_cast_vigor and not can_teleport:
+ keyboard.send(self._skill_hotkeys["vigor"])
+ wait(0.15, 0.25)
+
if __name__ == "__main__":
import os
@@ -98,10 +123,6 @@ if __name__ == "__main__":
pather = Pather(screen, t_finder)
ui_manager = UiManager(screen, t_finder)
char = Hammerdin(config.hammerdin, config.char, screen, t_finder, ui_manager, pather)
- # for i in range(20):
- # char.pre_buff()
- # time.sleep(1.5)
- # char.tp_town()
- char.select_by_template("A5_WP")
- wait(1.0)
- ui_manager.use_wp(4, 1)
+ char.pre_buff()
+ pather.traverse_nodes(Location.ELDRITCH_START, Location.ELDRITCH_SAVE_DIST, char)
+ char.kill_eldritch()
diff --git a/src/char/i_char.py b/src/char/i_char.py
index 8649306..e5f03bd 100644
--- a/src/char/i_char.py
+++ b/src/char/i_char.py
@@ -11,6 +11,7 @@ from logger import Logger
import time
from typing import Dict, Tuple, Union, List
from config import Config
+import random
def abstract(f):
@@ -55,12 +56,15 @@ class IChar:
return True
return False
- def move(self, pos_monitor: Tuple[float, float], force_tp: bool = False):
- if force_tp or not self._ui_manager.is_teleport_selected():
+ def pre_move(self):
+ # if teleport hotkey is set and if teleport is not already selected
+ if self._skill_hotkeys["teleport"] and not self._ui_manager.is_right_skill_selected(["TELE_ACTIVE", "TELE_INACTIVE"]):
keyboard.send(self._skill_hotkeys["teleport"])
wait(0.15, 0.25)
+
+ def move(self, pos_monitor: Tuple[float, float], force_tp: bool = False):
factor = self._config.advanced_options["pathing_delay_factor"]
- if force_tp or self._ui_manager.can_teleport():
+ if self._skill_hotkeys["teleport"] and (force_tp or self._ui_manager.is_right_skill_active()):
mouse.move(pos_monitor[0], pos_monitor[1], randomize=3, delay_factor=[factor*0.1, factor*0.14])
wait(0.012, 0.02)
mouse.click(button="right")
@@ -70,7 +74,12 @@ class IChar:
pos_screen = self._screen.convert_monitor_to_screen(pos_monitor)
pos_abs = self._screen.convert_screen_to_abs(pos_screen)
dist = math.dist(pos_abs, (0, 0))
- adjust_factor = (dist - 50) / dist
+ min_wd = self._config.ui_pos["min_walk_dist"]
+ if self._config.char["slow_walk"]:
+ max_wd = dist
+ else:
+ max_wd = random.randint(int(self._config.ui_pos["max_walk_dist"] * 0.65), self._config.ui_pos["max_walk_dist"])
+ adjust_factor = max(max_wd, min(min_wd, dist - 50)) / dist
pos_abs = [int(pos_abs[0] * adjust_factor), int(pos_abs[1] * adjust_factor)]
x, y = self._screen.convert_abs_to_monitor(pos_abs)
mouse.move(x, y, randomize=5, delay_factor=[factor*0.1, factor*0.14])
diff --git a/src/config.py b/src/config.py
index 8740a69..2b2d734 100644
--- a/src/config.py
+++ b/src/config.py
@@ -91,6 +91,9 @@ class Config:
self.hammerdin = self._config["hammerdin"]
if "hammerdin" in self._custom:
self.hammerdin.update(self._custom["hammerdin"])
+ if not self.hammerdin["teleport"]:
+ self.char["static_path_pindle"] = False
+ self.char["static_path_eldritch"] = False
self.advanced_options = {
"pathing_delay_factor": min(max(int(self._select_val("advanced_options", "pathing_delay_factor")),1),10),
diff --git a/src/pather.py b/src/pather.py
index 1f121da..9a304a6 100644
--- a/src/pather.py
+++ b/src/pather.py
@@ -77,7 +77,7 @@ class Pather:
120: {"ELDRITCH_0": (439, 36), "ELDRITCH_1": (-461, 114)},
121: {"ELDRITCH_1": (-493, -155), "ELDRITCH_2": (616, 257), "ELDRITCH_3": (-137, 297)},
122: {"ELDRITCH_2": (530, -218), "ELDRITCH_3": (-223, -178)},
- 123: {"ELDRITCH_3": (-148, -498), "ELDRITCH_2": (604, -538), "ELDRITCH_4": (-163, -283)},
+ 123: {"ELDRITCH_3": (-148, -498+120), "ELDRITCH_2": (604, -538+120), "ELDRITCH_4": (-163+70, -283+120)},
# Shenk
140: {"SHENK_0": (-224, -340), "SHENK_17": (-750, 353), "SHENK_15": (120, 20), "SHENK_1": (667, -242)},
141: {"SHENK_0": (-194, 66), "SHENK_17": (-780, 792), "SHENK_15": (116, 440), "SHENK_1": (696, 161), "SHENK_2": (-251, -51)},
@@ -88,8 +88,7 @@ class Pather:
146: {"SHENK_12": (408, 166), "SHENK_9": (-497, -216), "SHENK_8": (-108, 387)},
147: {"SHENK_16": (290, -150), "SHENK_9": (-100, 208), "SHENK_10": (-646, 100)},
148: {"SHENK_16": (967, 95), "SHENK_9": (451, 395), "SHENK_10": (-97, 282), "SHENK_11": (-459, 208)},
- 149: {"SHENK_11": (532, 602), "SHENK_10": (882, 682), "SHENK_13": (730, 36)},
-
+ 149: {"SHENK_11": (532-140, 642-50), "SHENK_10": (882-140, 682-50), "SHENK_13": (730-140, 36-50)},
}
self._paths = {
# A5 Town
@@ -161,7 +160,8 @@ class Pather:
def _convert_rel_to_abs(rel_loc: Tuple[float, float], pos_abs: Tuple[float, float]) -> Tuple[float, float]:
return (rel_loc[0] + pos_abs[0], rel_loc[1] + pos_abs[1])
- def traverse_nodes_fixed(self, key: str, char):
+ def traverse_nodes_fixed(self, key: str, char: IChar):
+ char.pre_move()
path = self._config.path[key]
for pos in path:
x_m, y_m = self._screen.convert_screen_to_monitor(pos)
@@ -212,7 +212,7 @@ class Pather:
return node_pos_abs
return None
- def traverse_nodes(self, start_location: Location, end_location: Location, char: IChar, time_out: float = 7, force_tp: bool = False) -> bool:
+ def traverse_nodes(self, start_location: Location, end_location: Location, char: IChar, time_out: float = 7, force_tp: bool = False, do_pre_move: bool = True) -> bool:
"""
Traverse from one location to another
:param start_location: Location the char is starting at
@@ -223,6 +223,8 @@ class Pather:
"""
Logger.debug(f"Traverse from {start_location} to {end_location}")
path = self._paths[(start_location, end_location)]
+ if do_pre_move:
+ char.pre_move()
for i, node_idx in enumerate(path):
continue_to_next_node = False
last_move = time.time()
@@ -264,13 +266,14 @@ if __name__ == "__main__":
keyboard.wait("f11")
from config import Config
from char.sorceress import Sorceress
+ from char.hammerdin import Hammerdin
from ui_manager import UiManager
config = Config()
screen = Screen(config.general["monitor"])
t_finder = TemplateFinder(screen)
pather = Pather(screen, t_finder)
ui_manager = UiManager(screen, t_finder)
- char = Sorceress(config.sorceress, config.char, screen, t_finder, ui_manager, pather)
+ char = Hammerdin(config.hammerdin, config.char, screen, t_finder, ui_manager, pather)
# pather.traverse_nodes_fixed("pindle_save_dist", char)
- # pather.traverse_nodes(Location.SHENK_START, Location.SHENK_SAVE_DIST, char)
- pather._display_all_nodes_debug(filter="SHENK_17")
+ # pather.traverse_nodes(Location.A5_TOWN_START, Location.NIHLATHAK_PORTAL, char)
+ pather._display_all_nodes_debug(filter="SHENK")
diff --git a/src/pickit.py b/src/pickit.py
index b8a45e9..e0cbe00 100644
--- a/src/pickit.py
+++ b/src/pickit.py
@@ -40,6 +40,7 @@ class PickIt:
start = prev_cast_start = time.time()
time_out = False
picked_up_items = []
+ char.pre_move()
while not time_out:
if (time.time() - start) > 24:
time_out = True
diff --git a/src/template_finder.py b/src/template_finder.py
index cf90dbd..f8e8d6e 100644
--- a/src/template_finder.py
+++ b/src/template_finder.py
@@ -92,6 +92,7 @@ class TemplateFinder:
"MERC": [load_template(f"assets/templates{res_str}/merc.png", 1.0), 1.0],
"TELE_ACTIVE": [load_template(f"assets/templates{res_str}/tele_active.png", 1.0), 1.0],
"TELE_INACTIVE": [load_template(f"assets/templates{res_str}/tele_inactive.png", 1.0), 1.0],
+ "VIGOR": [load_template(f"assets/templates{res_str}/vigor.png", 1.0), 1.0],
"REPAIR_BTN": [load_template(f"assets/templates{res_str}/repair_btn.png", 1.0), 1.0],
"TP_TOMB": [load_template(f"assets/templates{res_str}/tp_tomb.png", 1.0), 1.0],
"SUPER_HEALING_POTION": [load_template(f"assets/templates{res_str}/super_healing_potion.png", 1.0), 1.0],
diff --git a/src/ui_manager.py b/src/ui_manager.py
index 3b52f45..663c3e7 100644
--- a/src/ui_manager.py
+++ b/src/ui_manager.py
@@ -12,6 +12,7 @@ from logger import Logger
from utils.misc import wait, cut_roi, color_filter, send_discord
from config import Config
from item_finder import ItemFinder
+from typing import List
class UiManager():
@@ -41,9 +42,9 @@ class UiManager():
wait(0.4, 0.5)
mouse.click(button="left")
- def can_teleport(self) -> bool:
+ def is_right_skill_active(self) -> bool:
"""
- :return: Bool if teleport is red/available or not. Teleport skill must be selected on right skill slot when calling the function.
+ :return: Bool if skill is red/available or not. Skill must be selected on right skill slot when calling the function.
"""
roi = [
self._config.ui_pos["skill_right_x"] - (self._config.ui_pos["skill_width"] // 2),
@@ -55,9 +56,9 @@ class UiManager():
avg = np.average(img)
return avg > 75.0
- def is_teleport_selected(self) -> bool:
+ def is_right_skill_selected(self, template_list: List[str]) -> bool:
"""
- :return: Bool if teleport is currently the selected skill on the right skill slot.
+ :return: Bool if skill is currently the selected skill on the right skill slot.
"""
roi = [
self._config.ui_pos["skill_right_x"] - (self._config.ui_pos["skill_width"] // 2),
@@ -65,10 +66,9 @@ class UiManager():
self._config.ui_pos["skill_width"],
self._config.ui_pos["skill_height"]
]
- if self._template_finder.search("TELE_ACTIVE", self._screen.grab(), threshold=0.94, roi=roi)[0]:
- return True
- if self._template_finder.search("TELE_INACTIVE", self._screen.grab(), threshold=0.94, roi=roi)[0]:
- return True
+ for template in template_list:
+ if self._template_finder.search(template, self._screen.grab(), threshold=0.94, roi=roi)[0]:
+ return True
return False
def is_overburdened(self) -> bool: