Skip to content
This repository has been archived by the owner on Jul 1, 2022. It is now read-only.

Fixes and fail saves #44

Merged
merged 2 commits into from
Nov 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ run_shenk=0
--------------------------------|---------------------------------------------
monitor | Select on which monitor D2R is running in case multiple are available
res | Resolution settings can be any of [1920_1080, 1280_720]
offset_top | Your D2R window should always be in the top left corner. If you are on windowed mode you might have a window bar on top. Measure the pixel height of the bar and set the offset here.
offset_top | Your D2R windows offset from top of the screen (including the window bar). For fullscreen leave at 0.
offset_left | Your D2R window offset from left of screen. For fullscreen leave at 0.
min_game_length_s | Games must have at least this length, will wait in hero selection for if game is too quick (to avoid server connection issues)
exit_key | Pressing this key (anywhere), will force botty to shut down
resume_key | After starting the exe botty will wait for this keypress to atually start botting away
color_checker_key | Pressing this key will start a debug mode to check if the color filtering works with your settings. It also includes the item search and marks items it would pick up with red circles
logger_lvl | Can be any of [info, debug] and determines how much output you see on the command line
randomize_runs | If 0, the order will always be pindle -> eldritch/shenk. If 1 the order will be random.
difficulty | Set to `normal` `nightmare` or `hell` for game difficulty
send_drops_to_discord | If 1 sends your drops to the discord channel "drop-log"
custom_discord_hook | Add your own discord hook here to get messages about drops and in case botty got stuck and can not resume
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
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...
Expand Down
2 changes: 1 addition & 1 deletion params.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
monitor=0
res=1920_1080
offset_top=0
offset_left=0
min_game_length_s=65
resume_key=f11
exit_key=f12
Expand All @@ -10,7 +11,6 @@ color_checker_key=f10
logg_lvl=info
randomize_runs=0
difficulty=hell
send_drops_to_discord=1
custom_discord_hook=
info_screenshots=1
loot_screenshots=0
Expand Down
10 changes: 9 additions & 1 deletion src/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ def draw_graph(self):
def start(self):
self.trigger('create_game')

def current_game_length(self):
if self._timer is None:
return 0
return time.time() - self._timer

def shuffle_runs(self):
tmp = list(self._do_runs.items())
random.shuffle(tmp)
Expand All @@ -97,7 +102,10 @@ def is_last_run(self):
def _shut_down(self):
Logger.error("Something went wrong here, bot is unsure about current location. Closing down bot.")
if self._config.general["custom_discord_hook"] != "":
send_discord_thread = threading.Thread(target=send_discord, args=("Botty got stuck and can not resume", self._config.general["custom_discord_hook"]))
send_discord_thread = threading.Thread(
target=send_discord,
args=("Botty got stuck and can not resume", self._config.general["custom_discord_hook"])
)
send_discord_thread.daemon = True
send_discord_thread.start()
self._ui_manager.save_and_exit()
Expand Down
3 changes: 2 additions & 1 deletion src/char/i_char.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ def tp_town(self):
keyboard.send(self._char_config["tp"])
wait(0.05, 0.1)
mouse.click(button="right")
mouse.move(120, 450, randomize=150, delay_factor=[0.8, 1.4])
# TODO: Add hardcoded coordinates to ini file
mouse.move(int(120 * self._config.scale), int(450 * self._config.scale), randomize=150, delay_factor=[0.8, 1.4])
wait(0.8, 1.3) # takes quite a while for tp to be visible
roi = self._config.ui_roi["tp_search"]
start = time.time()
Expand Down
37 changes: 18 additions & 19 deletions src/char/sorceress.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,25 @@ def pre_buff(self):
if self._char_config["cta_available"]:
self._pre_buff_cta()

def _left_attack(self, cast_pos: Tuple[float, float], delay: float, spray: int = 10):
def _left_attack(self, cast_pos_abs: Tuple[float, float], delay: float, spray: int = 10):
keyboard.send(self._char_config["stand_still"], do_release=False)
mouse.move(cast_pos[0], cast_pos[1])
keyboard.send(self._skill_hotkeys["skill_left"])
if self._skill_hotkeys["skill_left"]:
keyboard.send(self._skill_hotkeys["skill_left"])
for _ in range(6):
x = cast_pos[0] + (random.random() * 2*spray - spray)
y = cast_pos[1] + (random.random() * 2*spray - spray)
mouse.move(x, y)
x = cast_pos_abs[0] + (random.random() * 2*spray - spray)
y = cast_pos_abs[1] + (random.random() * 2*spray - spray)
cast_pos_monitor = self._screen.convert_abs_to_monitor((x, y))
mouse.move(*cast_pos_monitor)
mouse.click(button="left")
wait(delay[0], delay[1])
keyboard.send(self._char_config["stand_still"], do_press=False)

def _main_attack(self, cast_pos: Tuple[float, float], delay: float, spray: float = 10):
def _main_attack(self, cast_pos_abs: Tuple[float, float], delay: float, spray: float = 10):
keyboard.send(self._skill_hotkeys["skill_right"])
x = cast_pos[0] + (random.random() * 2*spray - spray)
y = cast_pos[1] + (random.random() * 2*spray - spray)
mouse.move(x, y)
x = cast_pos_abs[0] + (random.random() * 2*spray - spray)
y = cast_pos_abs[1] + (random.random() * 2*spray - spray)
cast_pos_monitor = self._screen.convert_abs_to_monitor((x, y))
mouse.move(*cast_pos_monitor)
mouse.click(button="right")
wait(delay[0], delay[1])

Expand All @@ -65,10 +67,9 @@ def kill_pindle(self) -> bool:
pindle_pos_abs = self._pather.find_abs_node_pos(104, self._screen.grab())
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)
for _ in range(int(self._char_config["atk_len_pindle"])):
self._main_attack(cast_pos_monitor, delay, 15)
self._left_attack(cast_pos_monitor, delay, 15)
self._main_attack(cast_pos_abs, delay, 15)
self._left_attack(cast_pos_abs, delay, 15)
wait(0.1, 0.15)
# Move to items
if self._config.char["static_path_pindle"]:
Expand All @@ -83,10 +84,9 @@ def kill_eldritch(self) -> bool:
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)
for _ in range(int(self._char_config["atk_len_eldritch"])):
self._main_attack(cast_pos_monitor, delay, 90)
self._left_attack(cast_pos_monitor, delay, 90)
self._main_attack(cast_pos_abs, delay, 90)
self._left_attack(cast_pos_abs, delay, 90)
wait(0.2, 0.3)
# Move to items
if self._config.char["static_path_eldritch"]:
Expand All @@ -100,10 +100,9 @@ def kill_shenk(self):
delay = [0.2, 0.3]
pos_abs = self._pather.find_abs_node_pos(149, self._screen.grab())
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)
for _ in range(int(self._char_config["atk_len_shenk"])):
self._main_attack(cast_pos_monitor, delay, 90)
self._left_attack(cast_pos_monitor, delay, 90)
self._main_attack(cast_pos_abs, delay, 90)
self._left_attack(cast_pos_abs, delay, 90)
wait(0.2, 0.3)
# Move to items
self._pather.traverse_nodes(Location.SHENK_SAVE_DIST, Location.SHENK_END, self, time_out=2.0, force_tp=True)
Expand Down
2 changes: 1 addition & 1 deletion src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def __init__(self, print_warnings: bool = False):
"monitor": int(self._select_val("general", "monitor")),
"res": self._select_val("general", "res"),
"offset_top": int(self._select_val("general", "offset_top")),
"offset_left": int(self._select_val("general", "offset_left")),
"min_game_length_s": float(self._select_val("general", "min_game_length_s")),
"exit_key": self._select_val("general", "exit_key"),
"resume_key": self._select_val("general", "resume_key"),
Expand All @@ -36,7 +37,6 @@ def __init__(self, print_warnings: bool = False):
"logg_lvl": self._select_val("general", "logg_lvl"),
"randomize_runs": bool(int(self._select_val("general", "randomize_runs"))),
"difficulty": self._select_val("general", "difficulty"),
"send_drops_to_discord": bool(int(self._select_val("general", "send_drops_to_discord"))),
"custom_discord_hook": self._select_val("general", "custom_discord_hook"),
"info_screenshots": bool(int(self._select_val("general", "info_screenshots"))),
"loot_screenshots": bool(int(self._select_val("general", "loot_screenshots"))),
Expand Down
5 changes: 3 additions & 2 deletions src/health_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import cv2
import time
import keyboard
from utils.misc import kill_thread, cut_roi, color_filter
from utils.misc import kill_thread, cut_roi, color_filter, wait
from logger import Logger
from screen import Screen
import numpy as np
Expand Down Expand Up @@ -78,15 +78,16 @@ def get_merc_health(self, img: np.ndarray) -> float:
return merc_health_percentage

def _do_chicken(self, img, run_thread):
kill_thread(run_thread)
if self._config.general["info_screenshots"]:
cv2.imwrite("./info_screenshots/info_debug_chicken_" + time.strftime("%Y%m%d_%H%M%S") + ".png", img)
# clean up key presses that might be pressed in the run_thread
keyboard.release(self._config.char["stand_still"])
wait(0.02, 0.05)
keyboard.release(self._config.char["show_items"])
time.sleep(0.01)
self._ui_manager.save_and_exit(does_chicken=True)
self._did_chicken = True
kill_thread(run_thread)
self._do_monitor = False

def start_monitor(self, run_thread: Thread):
Expand Down
9 changes: 4 additions & 5 deletions src/pickit.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,11 @@ def pick_up_items(self, char: IChar) -> bool:
else:
# send log to discord
if found_items and self._config.items[closest_item.name] == 2 and closest_item.name not in picked_up_items:
if self._config.general["send_drops_to_discord"]:
send_discord_thread = threading.Thread(target=send_discord, args=(f"Botty just found: {closest_item.name}",))
send_discord_thread.daemon = True
send_discord_thread.start()
if self._config.general["custom_discord_hook"] != "":
send_discord_thread = threading.Thread(target=send_discord, args=(f"Botty just found: {closest_item.name}", self._config.general["custom_discord_hook"]))
send_discord_thread = threading.Thread(
target=send_discord,
args=(f"Botty just found: {closest_item.name}", self._config.general["custom_discord_hook"])
)
send_discord_thread.daemon = True
send_discord_thread.start()
picked_up_items.append(closest_item.name)
Expand Down
9 changes: 5 additions & 4 deletions src/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
import logging


def start_bot():
def start_bot(bot):
try:
bot = Bot()
bot.start()
except KeyboardInterrupt:
Logger.info('Exit (ctrl+c)') or exit()
Expand Down Expand Up @@ -45,14 +44,16 @@ def start_bot():

while 1:
if keyboard.is_pressed(config.general['resume_key']):
start_bot()
break
bot = Bot()
bot_thread = threading.Thread(target=start_bot, args=(bot,))
bot_thread.start()
if keyboard.is_pressed(config.general['auto_settings_key']):
adjust_settings()
elif keyboard.is_pressed(config.general['color_checker_key']):
run_color_checker()
break
time.sleep(0.02)

bot_thread.join()
print("Press Enter to exit ...")
input()
5 changes: 3 additions & 2 deletions src/screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ def __init__(self, monitor: int = 0):
self._monitor_roi = self._sct.monitors[monitor_idx]
# For windowed screens it is expected to always have them at the top left edge and adjust offset_top then
self._monitor_roi["top"] += config.general["offset_top"]
self._monitor_roi["left"] += config.general["offset_left"]
self._monitor_roi["width"] = config.ui_pos["screen_width"]
self._monitor_roi["height"] = config.ui_pos["screen_height"]
self._monitor_x_range = (self._monitor_roi["left"] + 2, self._monitor_roi["left"] + self._monitor_roi["width"] - 2)
self._monitor_y_range = (self._monitor_roi["top"] + 2, self._monitor_roi["top"] + self._monitor_roi["height"] - 2)
self._monitor_x_range = (self._monitor_roi["left"] + 10, self._monitor_roi["left"] + self._monitor_roi["width"] - 10)
self._monitor_y_range = (self._monitor_roi["top"] + 10, self._monitor_roi["top"] + self._monitor_roi["height"] - 10)

def convert_monitor_to_screen(self, screen_coord: Tuple[float, float]) -> Tuple[float, float]:
return (screen_coord[0] - self._monitor_roi["left"], screen_coord[1] - self._monitor_roi["top"])
Expand Down
13 changes: 7 additions & 6 deletions src/ui_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import os
import numpy as np
from logger import Logger
from utils.misc import wait, cut_roi, color_filter, send_discord
from utils.misc import wait, cut_roi, color_filter
from config import Config

class UiManager():
Expand Down Expand Up @@ -135,21 +135,22 @@ def save_and_exit(self, does_chicken: bool = False) -> bool:
wait(0.1)
exit_btn_pos = (self._config.ui_pos["save_and_exit_x"], self._config.ui_pos["save_and_exit_y"])
x_m, y_m = self._screen.convert_screen_to_monitor(exit_btn_pos)
away_x_m, away_y_m = self._screen.convert_screen_to_monitor((200, 450))
# TODO: Add hardcoded coordinates to ini file
away_x_m, away_y_m = self._screen.convert_screen_to_monitor((int(170 * self._config.scale), int(400 * self._config.scale)))
templates = ["SAVE_AND_EXIT_NO_HIGHLIGHT","SAVE_AND_EXIT_HIGHLIGHT"]
while self._template_finder.search_and_wait(templates, roi=self._config.ui_roi["save_and_exit"], time_out=1.5, take_ss=False)[0]:
delay = [0.9, 1.1]
if does_chicken:
delay = [0.3, 0.4]
mouse.move(x_m, y_m, randomize=[60, 10], delay_factor=delay)
mouse.move(x_m, y_m, randomize=[38, 7], delay_factor=delay)
wait(0.03, 0.06)
mouse.click(button="left")
if does_chicken:
# lets just try again just in case
wait(0.05, 0.08)
mouse.click(button="left")
wait(0.1, 0.2)
mouse.move(away_x_m, away_y_m, randomize=100, delay_factor=[0.6, 0.9])
mouse.move(away_x_m, away_y_m, randomize=60, delay_factor=[0.6, 0.9])
wait(0.1, 0.5)
return True
return False
Expand Down Expand Up @@ -177,7 +178,7 @@ def start_game(self) -> bool:
Logger.debug(f"Found Play Btn ({mode_info}) -> clicking it")
if mode_info == "online":
Logger.warning("You are creating a game in online mode!")
mouse.move(x, y, randomize=[50, 15], delay_factor=[1.0, 1.8])
mouse.move(x, y, randomize=[50, 9], delay_factor=[1.0, 1.8])
wait(0.1, 0.15)
mouse.click(button="left")
break
Expand All @@ -200,7 +201,7 @@ def start_game(self) -> bool:

x, y = self._screen.convert_screen_to_monitor((self._config.ui_pos[f"{difficulty}_x"], self._config.ui_pos[f"{difficulty}_y"]))
Logger.debug(f"Found {difficulty} Btn -> clicking it")
mouse.move(x, y, randomize=[50, 15], delay_factor=[1.0, 1.8])
mouse.move(x, y, randomize=[50, 9], delay_factor=[1.0, 1.8])
wait(0.15, 0.2)
mouse.click(button="left")
break
Expand Down
6 changes: 3 additions & 3 deletions src/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
from version import __version__


def send_discord(msg, url:str = None):
if url is None:
url = "https://discord.com/api/webhooks/908071105372250213/puaS6gIYqYxTE-TBLAIs6_Qb6ZUwuygSeQfTQkpuXrSag5DPeV2gk0SctOjPy5qMHGeh"
def send_discord(msg, url: str):
if not url:
return
data = {"content": f"{msg} (v{__version__})"}
requests.post(url, json=data)

Expand Down
2 changes: 1 addition & 1 deletion src/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.2.2'
__version__ = '0.2.2-dev'