diff --git a/assets/templates/eldritch/eldritch_0.png b/assets/templates/eldritch/eldritch_0.png new file mode 100644 index 0000000..a53a529 Binary files /dev/null and b/assets/templates/eldritch/eldritch_0.png differ diff --git a/assets/templates/eldritch/eldritch_1.png b/assets/templates/eldritch/eldritch_1.png new file mode 100644 index 0000000..cb0a33f Binary files /dev/null and b/assets/templates/eldritch/eldritch_1.png differ diff --git a/assets/templates/eldritch/eldritch_2.png b/assets/templates/eldritch/eldritch_2.png new file mode 100644 index 0000000..ab7d338 Binary files /dev/null and b/assets/templates/eldritch/eldritch_2.png differ diff --git a/assets/templates/eldritch/eldritch_3.png b/assets/templates/eldritch/eldritch_3.png new file mode 100644 index 0000000..5d85fc9 Binary files /dev/null and b/assets/templates/eldritch/eldritch_3.png differ diff --git a/assets/templates/eldritch/eldritch_4.png b/assets/templates/eldritch/eldritch_4.png new file mode 100644 index 0000000..d5921a9 Binary files /dev/null and b/assets/templates/eldritch/eldritch_4.png differ diff --git a/assets/templates/eldritch/nodes/eldritch_0.png b/assets/templates/eldritch/nodes/eldritch_0.png new file mode 100644 index 0000000..7fde73c Binary files /dev/null and b/assets/templates/eldritch/nodes/eldritch_0.png differ diff --git a/assets/templates/eldritch/nodes/eldritch_1.png b/assets/templates/eldritch/nodes/eldritch_1.png new file mode 100644 index 0000000..8079a58 Binary files /dev/null and b/assets/templates/eldritch/nodes/eldritch_1.png differ diff --git a/assets/templates/eldritch/nodes/eldritch_2.png b/assets/templates/eldritch/nodes/eldritch_2.png new file mode 100644 index 0000000..13bfb2e Binary files /dev/null and b/assets/templates/eldritch/nodes/eldritch_2.png differ diff --git a/assets/templates/shenk_flame.png b/assets/templates/shenk_flame.png deleted file mode 100644 index d172b57..0000000 Binary files a/assets/templates/shenk_flame.png and /dev/null differ diff --git a/src/bot.py b/src/bot.py index 929051a..e03dade 100644 --- a/src/bot.py +++ b/src/bot.py @@ -235,13 +235,13 @@ class Bot: bot._char.select_by_template("A5_WP") wait(1.0) bot._ui_manager.use_wp(4, 1) - self.success = bot._template_finder.search_and_wait("SHENK_FLAME", time_out=20)[0] + self.success = bot._template_finder.search_and_wait("ELDRITCH_0", time_out=20)[0] if not self.success: return bot._char.pre_buff() # eldritch - bot._pather.traverse_nodes_fixed("ELDRITCH", bot._char) - bot._char.kill_eldritch(bot._pather.get_fixed_path("ELDRITCH")[1]) + bot._pather.traverse_nodes(Location.ELDRITCH_START, Location.ELDRITCH_SAVE_DIST, bot._char) + bot._char.kill_eldritch() wait(0.5) bot._picked_up_items = bot._pickit.pick_up_items(bot._char) # shenk diff --git a/src/char/hammerdin.py b/src/char/hammerdin.py index 422ebbe..9eb6c86 100644 --- a/src/char/hammerdin.py +++ b/src/char/hammerdin.py @@ -57,15 +57,18 @@ class Hammerdin(IChar): keyboard.send(self._skill_hotkeys["redemption"]) wait(1.5, 2.0) - def kill_pindle(self): + def kill_pindle(self) -> bool: wait(0.1, 0.15) - self._pather.traverse_nodes(Location.PINDLE_SAVE_DIST, Location.PINDLE_END, self) + if not self._pather.traverse_nodes(Location.PINDLE_SAVE_DIST, Location.PINDLE_END, self): + return False self._cast_hammers(1) # pindle sometimes knocks back, get back in - self._pather.traverse_nodes(Location.PINDLE_SAVE_DIST, Location.PINDLE_END, self) + if not self._pather.traverse_nodes(Location.PINDLE_SAVE_DIST, Location.PINDLE_END, self): + return False self._cast_hammers(6) wait(0.1, 0.15) self._do_redemption() + return True def kill_shenk(self, shenk_pos_screen: Tuple[float, float]): pos_monitor = self._screen.convert_screen_to_monitor(shenk_pos_screen) @@ -79,12 +82,11 @@ class Hammerdin(IChar): wait(0.1, 0.15) self._do_redemption() - def kill_eldritch(self, eldritch_pos_screen: Tuple[float, float]): - pos_monitor = self._screen.convert_screen_to_monitor(eldritch_pos_screen) - keyboard.send(self._skill_hotkeys["teleport"]) - custom_mouse.move(pos_monitor[0], pos_monitor[1], duration=(random.random() * 0.05 + 0.15)) - mouse.click(button="right") + def kill_eldritch(self) -> bool: + if not self._pather.traverse_nodes(Location.ELDRITCH_SAVE_DIST, Location.ELDRITCH_END, self): + return False wait(0.1, 0.15) self._cast_hammers(6) wait(0.1, 0.15) self._do_redemption() + return True diff --git a/src/char/i_char.py b/src/char/i_char.py index 9af3ea7..b540127 100644 --- a/src/char/i_char.py +++ b/src/char/i_char.py @@ -93,7 +93,7 @@ class IChar: pass @abstract - def kill_pindle(self): + def kill_pindle(self) -> bool: pass @abstract @@ -101,5 +101,5 @@ class IChar: pass @abstract - def kill_eldritch(self, eldritch_pos_screen): + def kill_eldritch(self) -> bool: pass diff --git a/src/char/sorceress.py b/src/char/sorceress.py index 42aa859..c09c5bf 100644 --- a/src/char/sorceress.py +++ b/src/char/sorceress.py @@ -59,21 +59,24 @@ class Sorceress(IChar): mouse.click(button="right") wait(delay[0], delay[1]) - def kill_pindle(self): + def kill_pindle(self) -> bool: delay = [0.2, 0.3] pindle_pos_abs = self._pather.find_abs_node_pos(104, self._screen.grab()) - cast_pos_abs = [pindle_pos_abs[0] * 0.9, pindle_pos_abs[1] * 0.9] - cast_pos_monitor = self._screen.convert_abs_to_monitor(cast_pos_abs) - self._main_attack(cast_pos_monitor, delay) - self._left_attack(cast_pos_monitor, delay) - self._main_attack(cast_pos_monitor, delay) - self._left_attack(cast_pos_monitor, delay) - wait(0.1, 0.15) - # Move to items - self._pather.traverse_nodes(Location.PINDLE_SAVE_DIST, Location.PINDLE_END, self) - wait(0.1, 0.15) - blizzard_cast_pos = self._screen.convert_abs_to_monitor([0, 0]) - self._main_attack(blizzard_cast_pos, delay) + if pindle_pos_abs is not None: + cast_pos_abs = [pindle_pos_abs[0] * 0.9, pindle_pos_abs[1] * 0.9] + cast_pos_monitor = self._screen.convert_abs_to_monitor(cast_pos_abs) + self._main_attack(cast_pos_monitor, delay) + self._left_attack(cast_pos_monitor, delay) + self._main_attack(cast_pos_monitor, delay) + self._left_attack(cast_pos_monitor, delay) + wait(0.1, 0.15) + # Move to items + self._pather.traverse_nodes(Location.PINDLE_SAVE_DIST, Location.PINDLE_END, self) + wait(0.1, 0.15) + blizzard_cast_pos = self._screen.convert_abs_to_monitor([0, 0]) + self._main_attack(blizzard_cast_pos, delay) + return True + return False def kill_shenk(self, shenk_pos_screen: Tuple[float, float]): delay = [0.2, 0.3] @@ -95,22 +98,22 @@ class Sorceress(IChar): custom_mouse.move(pos_monitor[0], pos_monitor[1], duration=(random.random() * 0.05 + 0.15)) mouse.click(button="right") - def kill_eldritch(self, eldritch_pos_screen: Tuple[float, float]): + def kill_eldritch(self) -> bool: delay = [0.2, 0.3] - pos_abs = self._screen.convert_screen_to_abs(eldritch_pos_screen) - cast_pos_abs = [pos_abs[0] * 0.9, pos_abs[1] * 0.9] - cast_pos_monitor = self._screen.convert_abs_to_monitor(cast_pos_abs) - pos_monitor = self._screen.convert_screen_to_monitor(eldritch_pos_screen) - self._main_attack(cast_pos_monitor, delay, 90) - self._left_attack(cast_pos_monitor, delay, 90) - self._main_attack(cast_pos_monitor, delay, 90) - self._main_attack(cast_pos_monitor, delay, 90) - self._left_attack(cast_pos_monitor, delay, 90) - wait(0.2, 0.3) - # Move to items - keyboard.send(self._skill_hotkeys["teleport"]) - custom_mouse.move(pos_monitor[0], pos_monitor[1], duration=(random.random() * 0.05 + 0.15)) - mouse.click(button="right") + pos_abs = self._pather.find_abs_node_pos(123, self._screen.grab()) + if pos_abs is not None: + cast_pos_abs = [pos_abs[0] * 0.9, pos_abs[1] * 0.9] + cast_pos_monitor = self._screen.convert_abs_to_monitor(cast_pos_abs) + self._main_attack(cast_pos_monitor, delay, 90) + self._left_attack(cast_pos_monitor, delay, 90) + self._main_attack(cast_pos_monitor, delay, 90) + self._main_attack(cast_pos_monitor, delay, 90) + self._left_attack(cast_pos_monitor, delay, 90) + wait(0.2, 0.3) + # Move to items + self._pather.traverse_nodes(Location.ELDRITCH_SAVE_DIST, Location.ELDRITCH_END, self) + return True + return False if __name__ == "__main__": diff --git a/src/pather.py b/src/pather.py index d968615..da30ef1 100644 --- a/src/pather.py +++ b/src/pather.py @@ -24,9 +24,13 @@ class Location: MALAH = "malah" NIHLATHAK_PORTAL = "nihlathak_portal" # Pindle - PINDLE_START = "PINDLE_START" - PINDLE_SAVE_DIST = "PINDLE_SAVE_DIST" - PINDLE_END = "PINDLE_END" + PINDLE_START = "pindle_aster" + PINDLE_SAVE_DIST = "pindle_save_dist" + PINDLE_END = "pindle_end" + # Eldritch + ELDRITCH_START = "eldritch_start" + ELDRITCH_SAVE_DIST = "eldritch_save_dist" + ELDRITCH_END = "eldritch_end" class Pather: @@ -64,6 +68,11 @@ class Pather: 102: {"PINDLE_3": (334, 132), "PINDLE_4": (142, 323)}, 103: {"PINDLE_3": (593, -113), "PINDLE_4": (401, 78)}, 104: {"PINDLE_4": (1076, -176), "PINDLE_3": (1264, -366), "PINDLE_5": (-280, 356), "PINDLE_6": (-700, 133)}, + # Eldritch + 120: {"ELDRITCH_0": (439, 236), "ELDRITCH_1": (-461, 314)}, + 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)} } self._paths = { # A5 Town @@ -81,12 +90,13 @@ class Pather: # Pindle (Location.PINDLE_START, Location.PINDLE_SAVE_DIST): [100, 101, 102, 103], (Location.PINDLE_SAVE_DIST, Location.PINDLE_END): [104], + # Eldritch + (Location.ELDRITCH_START, Location.ELDRITCH_SAVE_DIST): [120, 121, 122], + (Location.ELDRITCH_SAVE_DIST, Location.ELDRITCH_END): [123], } self._fixed_tele_path = { # 0: path to boss, 1: location of boss - "PINDLE": ([(1382, 53), (1685, 105), (1429, 122)], (1533, 327)), - "PINDLE_END": ([(600, 40)], None), - "ELDRITCH": ([(978, 95), (845, 109)], (1012, 42)), + "PINDLE_END": ([(600, 40)], None), # to move away from items "SHENK": ([(798, 869), (1112, 882), (1220, 860), (1330, 869), (1502, 836), (1247, 887), (1258, 901), (1463, 814), (1351, 778)], [1815, 772]) } @@ -94,24 +104,25 @@ class Pather: def get_fixed_path(self, key: str): return self._fixed_tele_path[key] - def _display_all_nodes_debug(self): + def _display_all_nodes_debug(self, filter: str = None): while 1: img = self._screen.grab() for node_idx in self._nodes: for template_type in self._nodes[node_idx]: - success, ref_pos_screen = self._template_finder.search(template_type, img) - if success: - # Get reference position of template in abs coordinates - ref_pos_abs = self._screen.convert_screen_to_abs(ref_pos_screen) - # Calc the abs node position with the relative coordinates (relative to ref) - node_pos_rel = self._nodes[node_idx][template_type] - node_pos_abs = self._convert_rel_to_abs(node_pos_rel, ref_pos_abs) - node_pos_abs = self._adjust_abs_range_to_screen(node_pos_abs) - x, y = self._screen.convert_abs_to_screen(node_pos_abs) - cv2.circle(img, (x, y), 5, (255, 0, 0), 3) - cv2.putText(img, str(node_idx), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2, cv2.LINE_AA) - x, y = self._screen.convert_abs_to_monitor(ref_pos_abs) - cv2.circle(img, (x, y), 5, (0, 255, 0), 3) + if filter is None or filter in template_type: + success, ref_pos_screen = self._template_finder.search(template_type, img) + if success: + # Get reference position of template in abs coordinates + ref_pos_abs = self._screen.convert_screen_to_abs(ref_pos_screen) + # Calc the abs node position with the relative coordinates (relative to ref) + node_pos_rel = self._nodes[node_idx][template_type] + node_pos_abs = self._convert_rel_to_abs(node_pos_rel, ref_pos_abs) + node_pos_abs = self._adjust_abs_range_to_screen(node_pos_abs) + x, y = self._screen.convert_abs_to_screen(node_pos_abs) + cv2.circle(img, (x, y), 5, (255, 0, 0), 3) + cv2.putText(img, str(node_idx), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2, cv2.LINE_AA) + x, y = self._screen.convert_abs_to_monitor(ref_pos_abs) + cv2.circle(img, (x, y), 5, (0, 255, 0), 3) img = cv2.resize(img, None, fx=0.5, fy=0.5) cv2.imshow("debug", img) cv2.waitKey(1) @@ -226,7 +237,7 @@ if __name__ == "__main__": 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) + char = Sorceress(config.sorceress, config.char, screen, t_finder, ui_manager, pather) # pather.traverse_nodes_fixed("PINDLE", char) - pather.traverse_nodes(Location.A5_TOWN_START, Location.MALAH, char, debug=True) - # pather._display_all_nodes() + # pather.traverse_nodes(Location.A5_TOWN_START, Location.MALAH, char, debug=True) + pather._display_all_nodes_debug(filter="ELDRITCH") diff --git a/src/template_finder.py b/src/template_finder.py index 4ac8dac..59960cf 100644 --- a/src/template_finder.py +++ b/src/template_finder.py @@ -44,8 +44,12 @@ class TemplateFinder: "PINDLE_4": [load_template("assets/templates/pindle/pindle_4.png", self._scale_factor), self._scale_factor], "PINDLE_5": [load_template("assets/templates/pindle/pindle_5.png", self._scale_factor), self._scale_factor], "PINDLE_6": [load_template("assets/templates/pindle/pindle_6.png", self._scale_factor), self._scale_factor], - # Template Shenk area (currently only used to check if we are at shenk at wp, the walking is done statically) - "SHENK_FLAME": [load_template("assets/templates/shenk_flame.png", self._scale_factor), self._scale_factor], + # Teplates for nodes to Eldritch + "ELDRITCH_0": [load_template("assets/templates/eldritch/eldritch_0.png", self._scale_factor), self._scale_factor], + "ELDRITCH_1": [load_template("assets/templates/eldritch/eldritch_1.png", self._scale_factor), self._scale_factor], + "ELDRITCH_2": [load_template("assets/templates/eldritch/eldritch_2.png", self._scale_factor), self._scale_factor], + "ELDRITCH_3": [load_template("assets/templates/eldritch/eldritch_3.png", self._scale_factor), self._scale_factor], + "ELDRITCH_4": [load_template("assets/templates/eldritch/eldritch_4.png", self._scale_factor), self._scale_factor], # Template Selectables "A5_STASH": [load_template("assets/templates/a5_stash.png", self._scale_factor), self._scale_factor], "A5_WP": [load_template("assets/templates/a5_wp.png", self._scale_factor), self._scale_factor],