Compare commits
15 Commits
v0.1.2
...
v0.1.3-rc0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a91a91dc7c | ||
|
|
648d89ff28 | ||
|
|
489cc4ec36 | ||
|
|
fddd72c3a5 | ||
|
|
5abe2fb33e | ||
|
|
df12dbd57c | ||
|
|
9a3b054248 | ||
|
|
26246f141b | ||
|
|
8d1f84062d | ||
|
|
a7d31775f1 | ||
|
|
7c52b05d10 | ||
|
|
a7d7a96268 | ||
|
|
8e48dfe3d0 | ||
|
|
c89b35ff33 | ||
|
|
0d6ab59277 |
BIN
assets/templates/eldritch/eldritch_0.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
assets/templates/eldritch/eldritch_1.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
assets/templates/eldritch/eldritch_2.png
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
assets/templates/eldritch/eldritch_3.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
assets/templates/eldritch/eldritch_4.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
assets/templates/eldritch/nodes/eldritch_0.png
Normal file
|
After Width: | Height: | Size: 910 KiB |
BIN
assets/templates/eldritch/nodes/eldritch_1.png
Normal file
|
After Width: | Height: | Size: 919 KiB |
BIN
assets/templates/eldritch/nodes/eldritch_2.png
Normal file
|
After Width: | Height: | Size: 920 KiB |
BIN
assets/templates/pindle/nodes/pindle_0.png
Normal file
|
After Width: | Height: | Size: 865 KiB |
BIN
assets/templates/pindle/nodes/pindle_1.png
Normal file
|
After Width: | Height: | Size: 884 KiB |
BIN
assets/templates/pindle/nodes/pindle_2.png
Normal file
|
After Width: | Height: | Size: 899 KiB |
BIN
assets/templates/pindle/nodes/pindle_3.png
Normal file
|
After Width: | Height: | Size: 890 KiB |
BIN
assets/templates/pindle/nodes/pindle_4.png
Normal file
|
After Width: | Height: | Size: 859 KiB |
BIN
assets/templates/pindle/pindle_0.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
assets/templates/pindle/pindle_1.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
assets/templates/pindle/pindle_2.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
assets/templates/pindle/pindle_3.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
assets/templates/pindle/pindle_4.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
assets/templates/pindle/pindle_5.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
assets/templates/pindle/pindle_6.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 59 KiB |
BIN
assets/templates/shenk/nodes/shenk_0.png
Normal file
|
After Width: | Height: | Size: 935 KiB |
BIN
assets/templates/shenk/nodes/shenk_1.png
Normal file
|
After Width: | Height: | Size: 933 KiB |
BIN
assets/templates/shenk/nodes/shenk_2.png
Normal file
|
After Width: | Height: | Size: 921 KiB |
BIN
assets/templates/shenk/nodes/shenk_3.png
Normal file
|
After Width: | Height: | Size: 909 KiB |
BIN
assets/templates/shenk/nodes/shenk_4.png
Normal file
|
After Width: | Height: | Size: 940 KiB |
BIN
assets/templates/shenk/nodes/shenk_5.png
Normal file
|
After Width: | Height: | Size: 954 KiB |
BIN
assets/templates/shenk/nodes/shenk_6.png
Normal file
|
After Width: | Height: | Size: 949 KiB |
BIN
assets/templates/shenk/nodes/shenk_7.png
Normal file
|
After Width: | Height: | Size: 907 KiB |
BIN
assets/templates/shenk/nodes/shenk_8.png
Normal file
|
After Width: | Height: | Size: 885 KiB |
BIN
assets/templates/shenk/nodes/shenk_9.png
Normal file
|
After Width: | Height: | Size: 921 KiB |
BIN
assets/templates/shenk/shenk_0.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
assets/templates/shenk/shenk_1.png
Normal file
|
After Width: | Height: | Size: 61 KiB |
BIN
assets/templates/shenk/shenk_10.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
assets/templates/shenk/shenk_11.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
assets/templates/shenk/shenk_12.png
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
assets/templates/shenk/shenk_13.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
assets/templates/shenk/shenk_14.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
assets/templates/shenk/shenk_2.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
assets/templates/shenk/shenk_3.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
assets/templates/shenk/shenk_4.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
assets/templates/shenk/shenk_5.png
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
assets/templates/shenk/shenk_6.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
assets/templates/shenk/shenk_7.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
assets/templates/shenk/shenk_8.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
assets/templates/shenk/shenk_9.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 129 KiB |
@@ -14,8 +14,12 @@ python src/run.py
|
||||
```
|
||||
|
||||
## Building from source
|
||||
If you want to build a .exe from source you will have to first add the cv2 path to your PYTHONPATH:</br>
|
||||
Edit System environment variables -> Enfironment Vriables... -> PYTHONPATH -> C:\Users\\$USER\miniconda3\envs\botty\lib\site-packages\cv2
|
||||
If you want to build a .exe from source you will have to first add the cv2 path to your PYTHONPATH in System variables or User variables for current user:</br>
|
||||
Edit the system environment variables -> Environment Variables... -> New... </br>
|
||||
Variable name: PYTHONPATH </br>
|
||||
Variable value: %USERPROFILE%\miniconda3\envs\botty\Lib\site-packages\cv2 </br>
|
||||
|
||||
If you installed your miniconda in another location you will of course have ot change it for that one.
|
||||
```python
|
||||
# building .exe and bundeling all needed resource into one folder
|
||||
python release.py
|
||||
|
||||
@@ -14,3 +14,4 @@ dependencies:
|
||||
- keyboard
|
||||
- graphviz
|
||||
- beautifultable
|
||||
- zstandard
|
||||
|
||||
30
src/bot.py
@@ -34,9 +34,9 @@ class Bot:
|
||||
self._npc_manager = NpcManager(self._screen, self._template_finder)
|
||||
self._pickit = PickIt(self._screen, self._item_finder, self._ui_manager)
|
||||
if self._config.char["type"] == "sorceress":
|
||||
self._char: IChar = Sorceress(self._config.sorceress, self._config.char, self._screen, self._template_finder, self._ui_manager)
|
||||
self._char: IChar = Sorceress(self._config.sorceress, self._config.char, self._screen, self._template_finder, self._ui_manager, self._pather)
|
||||
elif self._config.char["type"] == "hammerdin":
|
||||
self._char: IChar = Hammerdin(self._config.hammerdin, self._config.char, self._screen, self._template_finder, self._ui_manager)
|
||||
self._char: IChar = Hammerdin(self._config.hammerdin, self._config.char, self._screen, self._template_finder, self._ui_manager, self._pather)
|
||||
else:
|
||||
Logger.error(f'{self._config.char["type"]} is not supported! Closing down bot.')
|
||||
os._exit(1)
|
||||
@@ -101,7 +101,9 @@ class Bot:
|
||||
self._template_finder.search_and_wait("A5_TOWN_1")
|
||||
self._tp_is_up = False
|
||||
self._curr_location = Location.A5_TOWN_START
|
||||
keyboard.send(self._config.char["stand_still"]) # just in case the key is still locked
|
||||
# Make sure these keys are released
|
||||
keyboard.release(self._config.char["stand_still"])
|
||||
keyboard.release(self._config.char["show_items"])
|
||||
self.trigger("maintenance")
|
||||
|
||||
def on_maintenance(self):
|
||||
@@ -203,13 +205,13 @@ class Bot:
|
||||
bot._curr_location = Location.NIHLATHAK_PORTAL
|
||||
wait(0.2, 0.4)
|
||||
self.success &= bot._char.select_by_template("A5_RED_PORTAL")
|
||||
self.success &= bot._template_finder.search_and_wait("PINDLE_STONE", time_out=20)[0]
|
||||
self.success &= bot._template_finder.search_and_wait("PINDLE_0", time_out=20)[0]
|
||||
if not self.success:
|
||||
return
|
||||
bot._char.pre_buff()
|
||||
wait(0.2, 0.4)
|
||||
bot._pather.traverse_nodes_fixed("PINDLE", bot._char)
|
||||
bot._char.kill_pindle(bot._pather.get_fixed_path("PINDLE")[1])
|
||||
bot._pather.traverse_nodes(Location.PINDLE_START, Location.PINDLE_SAVE_DIST, bot._char)
|
||||
bot._char.kill_pindle()
|
||||
wait(1.5, 1.8)
|
||||
bot._picked_up_items = bot._pickit.pick_up_items(bot._char)
|
||||
# in order to move away for items and such to have a clear tp, move to the end of the hall
|
||||
@@ -233,20 +235,20 @@ 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
|
||||
if bot._route_config["run_shenk"]:
|
||||
bot._pather.traverse_nodes_fixed("SHENK", bot._char)
|
||||
bot._pather.traverse_nodes(Location.SHENK_START, Location.SHENK_SAVE_DIST, bot._char)
|
||||
wait(0.15, 0.2)
|
||||
bot._char.kill_shenk(bot._pather.get_fixed_path("SHENK")[1])
|
||||
bot._char.kill_shenk()
|
||||
wait(0.5)
|
||||
bot._picked_up_items |= bot._pickit.pick_up_items(bot._char)
|
||||
self.success = True
|
||||
@@ -279,8 +281,10 @@ class Bot:
|
||||
if self._timer is not None:
|
||||
elapsed_time = time.time() - self._timer
|
||||
Logger.info(f"End game. Elapsed time: {elapsed_time:.2f}s")
|
||||
for key in self._do_runs:
|
||||
self._do_runs[key] = self._route_config[key]
|
||||
self._do_runs = {
|
||||
"run_pindle": self._route_config["run_pindle"],
|
||||
"run_shenk": self._route_config["run_shenk"] or self._route_config["run_eldritch"]
|
||||
}
|
||||
wait(0.2, 0.5)
|
||||
self.trigger("create_game")
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import mouse
|
||||
from utils import custom_mouse
|
||||
from char.i_char import IChar
|
||||
from template_finder import TemplateFinder
|
||||
from item_finder import ItemFinder
|
||||
from ui_manager import UiManager
|
||||
from pather import Pather
|
||||
from logger import Logger
|
||||
@@ -12,12 +11,14 @@ from utils.misc import wait
|
||||
import random
|
||||
import time
|
||||
from typing import Tuple
|
||||
from pather import Pather, Location
|
||||
|
||||
|
||||
class Hammerdin(IChar):
|
||||
def __init__(self, skill_hotkeys, char_config, screen: Screen, template_finder: TemplateFinder, ui_manager: UiManager):
|
||||
def __init__(self, skill_hotkeys, char_config, screen: Screen, template_finder: TemplateFinder, ui_manager: UiManager, pather: Pather):
|
||||
Logger.info("Setting up Hammerdin")
|
||||
super().__init__(skill_hotkeys, char_config, screen, template_finder, ui_manager)
|
||||
self._pather = pather
|
||||
|
||||
def pre_buff(self):
|
||||
keyboard.send(self._skill_hotkeys["holy_shield"])
|
||||
@@ -48,7 +49,7 @@ class Hammerdin(IChar):
|
||||
mouse.press(button="left")
|
||||
start = time.time()
|
||||
while (time.time() - start) < time_in_s:
|
||||
time.sleep(0.05)
|
||||
time.sleep(0.02)
|
||||
mouse.release(button="left")
|
||||
keyboard.send(self._char_config["stand_still"], do_press=False)
|
||||
|
||||
@@ -56,33 +57,27 @@ class Hammerdin(IChar):
|
||||
keyboard.send(self._skill_hotkeys["redemption"])
|
||||
wait(1.5, 2.0)
|
||||
|
||||
def kill_pindle(self, pindle_pos_screen: Tuple[float, float]):
|
||||
pos_monitor = self._screen.convert_screen_to_monitor(pindle_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_pindle(self) -> bool:
|
||||
wait(0.1, 0.15)
|
||||
self._cast_hammers(7)
|
||||
self._pather.traverse_nodes(Location.PINDLE_SAVE_DIST, Location.PINDLE_END, self, time_out=0.5)
|
||||
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.2)
|
||||
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)
|
||||
keyboard.send(self._skill_hotkeys["teleport"])
|
||||
wait(0.05)
|
||||
custom_mouse.move(pos_monitor[0], pos_monitor[1], duration=(random.random() * 0.05 + 0.15))
|
||||
wait(0.02)
|
||||
mouse.click(button="right")
|
||||
def kill_eldritch(self) -> bool:
|
||||
self._pather.traverse_nodes(Location.ELDRITCH_SAVE_DIST, Location.ELDRITCH_END, self, time_out=0.2)
|
||||
wait(0.1, 0.15)
|
||||
self._cast_hammers(6)
|
||||
wait(0.1, 0.15)
|
||||
self._do_redemption()
|
||||
return True
|
||||
|
||||
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_shenk(self):
|
||||
self._pather.traverse_nodes(Location.SHENK_SAVE_DIST, Location.SHENK_END, self, time_out=0.2)
|
||||
wait(0.1, 0.15)
|
||||
self._cast_hammers(6)
|
||||
wait(0.1, 0.15)
|
||||
|
||||
@@ -3,7 +3,6 @@ from cv2 import threshold
|
||||
import mouse
|
||||
from utils import custom_mouse
|
||||
from template_finder import TemplateFinder
|
||||
from item_finder import ItemFinder
|
||||
from ui_manager import UiManager
|
||||
from screen import Screen
|
||||
from utils.misc import wait
|
||||
@@ -94,13 +93,13 @@ class IChar:
|
||||
pass
|
||||
|
||||
@abstract
|
||||
def kill_pindle(self, pindle_pos_screen):
|
||||
def kill_pindle(self) -> bool:
|
||||
pass
|
||||
|
||||
@abstract
|
||||
def kill_shenk(self, shenk_pos_screen):
|
||||
def kill_shenk(self) -> bool:
|
||||
pass
|
||||
|
||||
@abstract
|
||||
def kill_eldritch(self, eldritch_pos_screen):
|
||||
def kill_eldritch(self) -> bool:
|
||||
pass
|
||||
|
||||
@@ -11,12 +11,14 @@ from screen import Screen
|
||||
from utils.misc import wait
|
||||
import random
|
||||
from typing import Tuple
|
||||
from pather import Location, Pather
|
||||
|
||||
|
||||
class Sorceress(IChar):
|
||||
def __init__(self, skill_hotkeys, char_config, screen: Screen, template_finder: TemplateFinder, ui_manager: UiManager):
|
||||
def __init__(self, skill_hotkeys, char_config, screen: Screen, template_finder: TemplateFinder, ui_manager: UiManager, pather: Pather):
|
||||
Logger.info("Setting up Sorceress")
|
||||
super().__init__(skill_hotkeys, char_config, screen, template_finder, ui_manager)
|
||||
self._pather = pather
|
||||
|
||||
def pre_buff(self):
|
||||
keyboard.send(self._skill_hotkeys["frozen_armor"])
|
||||
@@ -57,31 +59,30 @@ class Sorceress(IChar):
|
||||
mouse.click(button="right")
|
||||
wait(delay[0], delay[1])
|
||||
|
||||
def kill_pindle(self, pindle_pos_screen: Tuple[float, float]):
|
||||
def kill_pindle(self) -> bool:
|
||||
delay = [0.2, 0.3]
|
||||
pindle_pos_abs = self._screen.convert_screen_to_abs(pindle_pos_screen)
|
||||
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)
|
||||
pindle_pos_monitor = self._screen.convert_screen_to_monitor(pindle_pos_screen)
|
||||
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
|
||||
keyboard.send(self._skill_hotkeys["teleport"])
|
||||
custom_mouse.move(pindle_pos_monitor[0], pindle_pos_monitor[1], duration=(random.random() * 0.05 + 0.15))
|
||||
mouse.click(button="right")
|
||||
wait(0.1, 0.15)
|
||||
blizzard_cast_pos = self._screen.convert_abs_to_monitor([0, 0])
|
||||
self._main_attack(blizzard_cast_pos, delay)
|
||||
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)
|
||||
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]):
|
||||
def kill_shenk(self):
|
||||
delay = [0.2, 0.3]
|
||||
pos_abs = self._screen.convert_screen_to_abs(shenk_pos_screen)
|
||||
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)
|
||||
pos_monitor = self._screen.convert_screen_to_monitor(shenk_pos_screen)
|
||||
# TODO: Not sure if we need so much attacks... maybe add a "number_attack_sequenze" to the param.ini
|
||||
self._main_attack(cast_pos_monitor, delay, 90)
|
||||
self._left_attack(cast_pos_monitor, delay, 90)
|
||||
@@ -92,26 +93,24 @@ class Sorceress(IChar):
|
||||
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")
|
||||
self._pather.traverse_nodes(Location.SHENK_SAVE_DIST, Location.SHENK_END, self, time_out=2.0)
|
||||
|
||||
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, time_out=2.0)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -46,6 +46,9 @@ class DeathManager:
|
||||
Logger.warning("You have died! Waiting 30 sec to make sure chicken does not do any funny during with this logic.")
|
||||
# first wait a bit to make sure health manager is done with its chicken stuff which obviously failed
|
||||
kill_thread(run_thread)
|
||||
# clean up key presses that might be pressed in the run_thread
|
||||
keyboard.release(self._config.char["stand_still"])
|
||||
keyboard.release(self._config.char["show_items"])
|
||||
time.sleep(30)
|
||||
self._died = True
|
||||
if self._template_finder.search("D2_LOGO_HS", self._screen.grab())[0]:
|
||||
|
||||
@@ -100,6 +100,9 @@ class HealthManager:
|
||||
self._ui_manager.save_and_exit()
|
||||
self._did_chicken = True
|
||||
kill_thread(run_thread)
|
||||
# clean up key presses that might be pressed in the run_thread
|
||||
keyboard.release(self._config.char["stand_still"])
|
||||
keyboard.release(self._config.char["show_items"])
|
||||
self._do_monitor = False
|
||||
break
|
||||
# check mana
|
||||
|
||||
173
src/pather.py
@@ -1,3 +1,4 @@
|
||||
from char.i_char import IChar
|
||||
from screen import Screen
|
||||
from template_finder import TemplateFinder
|
||||
from logger import Logger
|
||||
@@ -15,12 +16,25 @@ import numpy as np
|
||||
|
||||
|
||||
class Location:
|
||||
# A5 Town
|
||||
A5_TOWN_START = "a5_town_start"
|
||||
A5_STASH = "a5_stash"
|
||||
A5_WP = "a5_wp"
|
||||
QUAL_KEHK = "qual_kehk"
|
||||
MALAH = "malah"
|
||||
NIHLATHAK_PORTAL = "nihlathak_portal"
|
||||
# Pindle
|
||||
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"
|
||||
# Shenk
|
||||
SHENK_START = "shenk_start"
|
||||
SHENK_SAVE_DIST = "shenk_save_dist"
|
||||
SHENK_END = "shenk_end"
|
||||
|
||||
|
||||
class Pather:
|
||||
@@ -35,7 +49,7 @@ class Pather:
|
||||
self._screen = screen
|
||||
self._template_finder = template_finder
|
||||
self._range_x = [-self._config.ui_pos["center_x"] + 10, self._config.ui_pos["center_x"] - 10]
|
||||
self._range_y = [-self._config.ui_pos["center_y"] + 10, self._config.ui_pos["center_y"] - self._config.ui_pos["skill_bar_height"] - 10]
|
||||
self._range_y = [-self._config.ui_pos["center_y"] + 10, self._config.ui_pos["center_y"] - self._config.ui_pos["skill_bar_height"] - 50]
|
||||
self._nodes = {
|
||||
# A5 town
|
||||
0: {"A5_TOWN_0": (110-70, 373), "A5_TOWN_1": (-68-70, -205)},
|
||||
@@ -52,8 +66,32 @@ class Pather:
|
||||
12: {"A5_TOWN_8": (-209, -294), "A5_TOWN_9": (-248, 130)},
|
||||
13: {"A5_TOWN_3": (262, 210)},
|
||||
14: {"A5_TOWN_3": (694, 282)},
|
||||
# Pindle
|
||||
100: {"PINDLE_0": (-146, -60), "PINDLE_1": (-19, 335), "PINDLE_2": (-549, 127)},
|
||||
101: {"PINDLE_1": (557, -68), "PINDLE_2": (27, -276), "PINDLE_3": (-185, 391)},
|
||||
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)},
|
||||
# Shenk
|
||||
140: {"SHENK_0": (-224, -340), "SHENK_1": (667, -242)},
|
||||
141: {"SHENK_0": (-194, 66), "SHENK_1": (696, 161), "SHENK_2": (-251, -51)},
|
||||
142: {"SHENK_1": (876, 564), "SHENK_2": (-78, 352), "SHENK_3": (535, -194), "SHENK_4": (-665, -155)},
|
||||
143: {"SHENK_2": (212, 758),"SHENK_3": (823, 209), "SHENK_4": (-377, 248), "SHENK_6": (-508, -103)},
|
||||
144: {"SHENK_6": (-162, 185), "SHENK_7": (721, 226)},
|
||||
145: {"SHENK_12": (146, -200), "SHENK_7": (1204, 558), "SHENK_6": (314, 520), "SHENK_8": (-367, 27)},
|
||||
146: {"SHENK_12": (408, 166), "SHENK_9": (-497, -216), "SHENK_8": (-108, 387)},
|
||||
147: {"SHENK_9": (-100, 208), "SHENK_10": (-646, 100)},
|
||||
148: {"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), "SHENK_14": (510, 343)},
|
||||
|
||||
}
|
||||
self._paths = {
|
||||
# A5 Town
|
||||
(Location.A5_TOWN_START, Location.NIHLATHAK_PORTAL): [3, 4, 5, 6, 8, 9],
|
||||
(Location.A5_TOWN_START, Location.A5_STASH): [3, 4, 5],
|
||||
(Location.A5_TOWN_START, Location.A5_WP): [3, 4],
|
||||
@@ -65,49 +103,44 @@ class Pather:
|
||||
(Location.A5_STASH, Location.A5_WP): [],
|
||||
(Location.QUAL_KEHK, Location.NIHLATHAK_PORTAL): [12, 11, 10, 6, 8, 9],
|
||||
(Location.QUAL_KEHK, Location.A5_WP): [12, 11, 10, 6],
|
||||
# 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],
|
||||
# Shenk
|
||||
(Location.SHENK_START, Location.SHENK_SAVE_DIST): [140, 141, 142, 143, 144, 145, 146, 147, 148],
|
||||
(Location.SHENK_SAVE_DIST, Location.SHENK_END): [149],
|
||||
}
|
||||
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)),
|
||||
"SHENK": ([(798, 869), (1112, 882), (1220, 860), (1330, 869), (1502, 836), (1247, 887), (1258, 901), (1463, 814), (1351, 778)], [1815, 772])
|
||||
"PINDLE_END": ([(600, 40)], None), # to move away from items
|
||||
}
|
||||
|
||||
def get_fixed_path(self, key: str):
|
||||
return self._fixed_tele_path[key]
|
||||
|
||||
def _draw_debug(self, img: np.ndarray, node_pos_abs_list: List, ref_pos_abs_list: List):
|
||||
for node_pos_abs in node_pos_abs_list:
|
||||
pos_screen = self._screen.convert_abs_to_screen(node_pos_abs)
|
||||
cv2.circle(img, pos_screen, 10, (255, 0, 0), 10)
|
||||
for ref_pos_screen in ref_pos_abs_list:
|
||||
pos_screen = self._screen.convert_abs_to_screen(ref_pos_screen)
|
||||
cv2.circle(img, pos_screen, 10, (0, 255, 0), 10)
|
||||
img = cv2.resize(img, None, fx=0.5, fy=0.5)
|
||||
cv2.namedWindow("x")
|
||||
cv2.moveWindow("x", 2000, 30)
|
||||
cv2.imshow("x", img)
|
||||
cv2.waitKey(1)
|
||||
|
||||
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)
|
||||
if self._check_abs_range_to_screen(node_pos_abs):
|
||||
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)
|
||||
cv2.putText(img, template_type, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2, cv2.LINE_AA)
|
||||
img = cv2.resize(img, None, fx=0.5, fy=0.5)
|
||||
cv2.imshow("debug", img)
|
||||
cv2.waitKey(1)
|
||||
@@ -116,7 +149,7 @@ 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: IChar):
|
||||
def traverse_nodes_fixed(self, key: str, char):
|
||||
path = self._fixed_tele_path[key][0]
|
||||
for pos in path:
|
||||
x_m, y_m = self._screen.convert_screen_to_monitor(pos)
|
||||
@@ -136,29 +169,44 @@ class Pather:
|
||||
f = min(f, abs(self._range_x[1] / float(abs_pos[0])))
|
||||
elif abs_pos[0] < self._range_x[0]:
|
||||
f = min(f, abs(self._range_x[0] / float(abs_pos[0])))
|
||||
# Check top y-range
|
||||
# Check y-range
|
||||
if abs_pos[1] > self._range_y[1]:
|
||||
f = min(f, abs(self._range_y[1] / float(abs_pos[1])))
|
||||
if abs_pos[1] < self._range_y[0]:
|
||||
f = min(f, abs(self._range_y[0] / float(abs_pos[1])))
|
||||
# check bottom y-range + globe roi which will also not allow a movement
|
||||
range_y_bottom = self._range_y[1]
|
||||
screen_pos = self._screen.convert_abs_to_screen(abs_pos)
|
||||
if is_in_roi(self._config.ui_roi["mana_globe"], screen_pos) or is_in_roi(self._config.ui_roi["health_globe"], screen_pos):
|
||||
# convert any of health or mana roi top coordinate to abs (x-coordinate is just a dummy 0 value)
|
||||
range_y_bottom = self._screen.convert_screen_to_abs((0, self._config.ui_roi["mana_globe"][1]))[1]
|
||||
if abs_pos[1] > range_y_bottom:
|
||||
f = min(f, abs(range_y_bottom / float(abs_pos[1])))
|
||||
# Scale the position by the factor f
|
||||
if f < 1.0:
|
||||
abs_pos = (int(abs_pos[0] * f), int(abs_pos[1] * f))
|
||||
# Check if adjusted position is "inside globe"
|
||||
screen_pos = self._screen.convert_abs_to_screen(abs_pos)
|
||||
if is_in_roi(self._config.ui_roi["mana_globe"], screen_pos) or is_in_roi(self._config.ui_roi["health_globe"], screen_pos):
|
||||
# convert any of health or mana roi top coordinate to abs (x-coordinate is just a dummy 0 value)
|
||||
new_range_y_bottom = self._screen.convert_screen_to_abs((0, self._config.ui_roi["mana_globe"][1]))[1]
|
||||
f = abs(new_range_y_bottom / float(abs_pos[1]))
|
||||
abs_pos = (int(abs_pos[0] * f), int(abs_pos[1] * f))
|
||||
return abs_pos
|
||||
|
||||
def traverse_nodes(self, start_location: Location, end_location: Location, char: IChar, debug: bool = False) -> bool:
|
||||
def find_abs_node_pos(self, node_idx: int, img: np.ndarray) -> Tuple[float, float]:
|
||||
node = self._nodes[node_idx]
|
||||
for template_type in node:
|
||||
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 = node[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)
|
||||
return node_pos_abs
|
||||
return None
|
||||
|
||||
def traverse_nodes(self, start_location: Location, end_location: Location, char: IChar, time_out: float = 7) -> bool:
|
||||
"""
|
||||
Traverse from one location to another
|
||||
:param start_location: Location the char is starting at
|
||||
:param end_location: Location the char is supposed to end up
|
||||
:param char: Char that is traversing the nodes
|
||||
:param debug: Debug mode will display some images and stuff
|
||||
:param time_out: Timeout in second. If no more move was found in that time it will cancel traverse
|
||||
:return: Bool if traversed succesfull or False if it got stuck
|
||||
"""
|
||||
Logger.debug(f"Traverse from {start_location} to {end_location}")
|
||||
@@ -168,7 +216,7 @@ class Pather:
|
||||
last_move = time.time()
|
||||
while not continue_to_next_node:
|
||||
img = self._screen.grab()
|
||||
if (time.time() - last_move) > 7:
|
||||
if (time.time() - last_move) > time_out:
|
||||
success, _ = self._template_finder.search("WAYPOINT_MENU", img)
|
||||
if success:
|
||||
# sometimes bot opens waypoint menu, close it to find templates again
|
||||
@@ -179,33 +227,18 @@ class Pather:
|
||||
cv2.imwrite("info_pather_got_stuck.png", img)
|
||||
Logger.error("Got stuck exit pather")
|
||||
return False
|
||||
_debug_node_pos_abs_list = []
|
||||
_debug_ref_pos_abs_list = []
|
||||
node = self._nodes[node_idx]
|
||||
for template_type in node:
|
||||
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)
|
||||
_debug_ref_pos_abs_list.append(ref_pos_abs)
|
||||
# Calc the abs node position with the relative coordinates (relative to ref)
|
||||
node_pos_rel = node[template_type]
|
||||
node_pos_abs = self._convert_rel_to_abs(node_pos_rel, ref_pos_abs)
|
||||
_debug_node_pos_abs_list.append(node_pos_abs)
|
||||
if debug:
|
||||
self._draw_debug(img, _debug_node_pos_abs_list, _debug_ref_pos_abs_list)
|
||||
node_pos_abs = self._adjust_abs_range_to_screen(node_pos_abs)
|
||||
dist = math.dist(node_pos_abs, (0, 0))
|
||||
if dist < self._config.ui_pos["reached_node_dist"]:
|
||||
continue_to_next_node = True
|
||||
else:
|
||||
# Move the char
|
||||
x_m, y_m = self._screen.convert_abs_to_monitor(node_pos_abs)
|
||||
char.move((x_m, y_m))
|
||||
last_move = time.time()
|
||||
if self._config.char["slow_walk"]:
|
||||
wait(1.2, 1.4)
|
||||
break
|
||||
node_pos_abs = self.find_abs_node_pos(node_idx, img)
|
||||
if node_pos_abs is not None:
|
||||
dist = math.dist(node_pos_abs, (0, 0))
|
||||
if dist < self._config.ui_pos["reached_node_dist"]:
|
||||
continue_to_next_node = True
|
||||
else:
|
||||
# Move the char
|
||||
x_m, y_m = self._screen.convert_abs_to_monitor(node_pos_abs)
|
||||
char.move((x_m, y_m))
|
||||
last_move = time.time()
|
||||
if self._config.char["slow_walk"]:
|
||||
wait(1.2, 1.4)
|
||||
return True
|
||||
|
||||
|
||||
@@ -222,7 +255,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="SHENK")
|
||||
|
||||
@@ -19,7 +19,7 @@ class TemplateFinder:
|
||||
:param screen: Screen object
|
||||
:param scale_factor: Scale factor that is used for templates. Note: UI and NPC templates will always have scale of 1.0
|
||||
"""
|
||||
self.debug_last_score = -1.0
|
||||
self.last_score = -1.0
|
||||
self._screen = screen
|
||||
self._scale_factor = scale_factor
|
||||
self._config = Config()
|
||||
@@ -36,10 +36,35 @@ class TemplateFinder:
|
||||
"A5_TOWN_7": [load_template("assets/templates/a5_town/a5_town_7.png", self._scale_factor), self._scale_factor],
|
||||
"A5_TOWN_8": [load_template("assets/templates/a5_town/a5_town_8.png", self._scale_factor), self._scale_factor],
|
||||
"A5_TOWN_9": [load_template("assets/templates/a5_town/a5_town_9.png", self._scale_factor), self._scale_factor],
|
||||
# Template Pindle area (currently only used to check if we are at pindle, the walking is done statically)
|
||||
"PINDLE_STONE": [load_template("assets/templates/pindle_stone.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],
|
||||
# Templates for nod at Pindle
|
||||
"PINDLE_0": [load_template("assets/templates/pindle/pindle_0.png", self._scale_factor), self._scale_factor],
|
||||
"PINDLE_1": [load_template("assets/templates/pindle/pindle_1.png", self._scale_factor), self._scale_factor],
|
||||
"PINDLE_2": [load_template("assets/templates/pindle/pindle_2.png", self._scale_factor), self._scale_factor],
|
||||
"PINDLE_3": [load_template("assets/templates/pindle/pindle_3.png", self._scale_factor), self._scale_factor],
|
||||
"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],
|
||||
# Templates 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],
|
||||
# Templates for nodes to Shenk (from Eldritch)
|
||||
"SHENK_0": [load_template("assets/templates/shenk/shenk_0.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_1": [load_template("assets/templates/shenk/shenk_1.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_2": [load_template("assets/templates/shenk/shenk_2.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_3": [load_template("assets/templates/shenk/shenk_3.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_4": [load_template("assets/templates/shenk/shenk_4.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_6": [load_template("assets/templates/shenk/shenk_6.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_7": [load_template("assets/templates/shenk/shenk_7.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_8": [load_template("assets/templates/shenk/shenk_8.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_9": [load_template("assets/templates/shenk/shenk_9.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_10": [load_template("assets/templates/shenk/shenk_10.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_11": [load_template("assets/templates/shenk/shenk_11.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_12": [load_template("assets/templates/shenk/shenk_12.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_13": [load_template("assets/templates/shenk/shenk_13.png", self._scale_factor), self._scale_factor],
|
||||
"SHENK_14": [load_template("assets/templates/shenk/shenk_14.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],
|
||||
@@ -116,7 +141,7 @@ class TemplateFinder:
|
||||
if img.shape[0] > template.shape[0] and img.shape[1] > template.shape[1]:
|
||||
res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)
|
||||
_, max_val, _, max_pos = cv2.minMaxLoc(res)
|
||||
self.debug_last_score = max_val
|
||||
self.last_score = max_val
|
||||
if max_val > threshold:
|
||||
ref_point = (max_pos[0] + int(template.shape[1] * 0.5) + rx, max_pos[1] + int(template.shape[0] * 0.5) + ry)
|
||||
ref_point = (int(ref_point[0] * (1.0 / scale)), int(ref_point[1] * (1.0 / scale)))
|
||||
@@ -153,7 +178,7 @@ if __name__ == "__main__":
|
||||
while 1:
|
||||
img = screen.grab()
|
||||
success, pos = template_finder.search("BLUE_PORTAL", img, threshold=0.67)
|
||||
print(template_finder.debug_last_score)
|
||||
print(template_finder.last_score)
|
||||
if success:
|
||||
cv2.circle(img, pos, 7, (255, 0, 0), thickness=5)
|
||||
img = cv2.resize(img, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_NEAREST)
|
||||
|
||||
@@ -151,46 +151,41 @@ class UiManager():
|
||||
Starting a game in hell mode. Will wait and retry on server connection issue.
|
||||
:return: Bool if action was successful
|
||||
"""
|
||||
while self._template_finder.search("PLAY_BTN_GRAY", self._screen.grab(), roi=self._config.ui_roi["play_btn"], threshold=0.95)[0]:
|
||||
time.sleep(2)
|
||||
|
||||
Logger.debug(f"Searching for Play Btn...")
|
||||
found, pos = self._template_finder.search_and_wait("PLAY_BTN", roi=self._config.ui_roi["play_btn"], time_out=8)
|
||||
if not found:
|
||||
return False
|
||||
# sanity x, y check and determine if offline or online
|
||||
x_range_offline = [self._config.ui_pos["play_x_offline"] - 50, self._config.ui_pos["play_x_offline"] + 50]
|
||||
x_range_online = [self._config.ui_pos["play_x_online"] - 50, self._config.ui_pos["play_x_online"] + 50]
|
||||
y_range = [self._config.ui_pos["play_y"] - 50, self._config.ui_pos["play_y"] + 50]
|
||||
in_offline_range = x_range_offline[0] < pos[0] < x_range_offline[1]
|
||||
in_online_range = x_range_online[0] < pos[0] < x_range_online[1]
|
||||
mode_info = "online mode" if in_online_range else "offline mode"
|
||||
if (in_offline_range or in_online_range) and y_range[0] < pos[1] < y_range[1]:
|
||||
pos = [pos[0], self._config.ui_pos["play_y"]]
|
||||
x, y = self._screen.convert_screen_to_monitor(pos)
|
||||
Logger.debug(f"Found Play Btn ({mode_info}) -> clicking it")
|
||||
if mode_info == "online mode":
|
||||
Logger.warning("You are creating a game in online mode!")
|
||||
custom_mouse.move(x, y, duration=(random.random() * 0.2 + 0.5), randomize=5)
|
||||
mouse.click(button="left")
|
||||
else:
|
||||
Logger.debug("Sanity position check on play btn failed")
|
||||
return False
|
||||
while 1:
|
||||
img = self._screen.grab()
|
||||
# search offline btn
|
||||
found_off, _ = self._template_finder.search("PLAY_BTN", img, roi=self._config.ui_roi["play_btn_offline"], threshold=0.8)
|
||||
# search online btn with enabled and disabled version
|
||||
found_on, _ = self._template_finder.search("PLAY_BTN", img, roi=self._config.ui_roi["play_btn_online"], threshold=0.8)
|
||||
score_enabled = self._template_finder.last_score
|
||||
self._template_finder.search("PLAY_BTN_GRAY", img, roi=self._config.ui_roi["play_btn_online"], threshold=0.8)
|
||||
score_disabled = self._template_finder.last_score
|
||||
found_on = found_on and score_enabled > score_disabled
|
||||
if found_off or found_on:
|
||||
x_s = self._config.ui_pos["play_x_offline"] if found_off else self._config.ui_pos["play_x_online"]
|
||||
pos = [x_s, self._config.ui_pos["play_y"]]
|
||||
x, y = self._screen.convert_screen_to_monitor(pos)
|
||||
mode_info = "offline" if found_off else "online"
|
||||
Logger.debug(f"Found Play Btn ({mode_info}) -> clicking it")
|
||||
if mode_info == "online":
|
||||
Logger.warning("You are creating a game in online mode!")
|
||||
custom_mouse.move(x, y, duration=(random.random() * 0.2 + 0.4), randomize=5)
|
||||
mouse.click(button="left")
|
||||
break
|
||||
time.sleep(3.0)
|
||||
|
||||
Logger.debug("Searching for Hell Btn...")
|
||||
found, pos = self._template_finder.search_and_wait("HELL_BTN", roi=self._config.ui_roi["hell_btn"], time_out=8)
|
||||
if not found:
|
||||
return False
|
||||
# sanity x y check. Note: not checking y range as it often detects nightmare button as hell btn, not sure why
|
||||
x_range = [self._config.ui_pos["hell_x"] - 50, self._config.ui_pos["hell_x"] + 50]
|
||||
if x_range[0] < pos[0] < x_range[1]:
|
||||
while 1:
|
||||
found, pos = self._template_finder.search_and_wait("HELL_BTN", roi=self._config.ui_roi["hell_btn"], time_out=8)
|
||||
if not found:
|
||||
Logger.debug("Could not find hell btn, try from start again")
|
||||
return self.start_hell_game()
|
||||
# sanity x y check. Note: not checking y range as it often detects nightmare button as hell btn, not sure why
|
||||
x, y = self._screen.convert_screen_to_monitor((self._config.ui_pos["hell_x"], self._config.ui_pos["hell_y"]))
|
||||
Logger.debug("Found Hell Btn -> clicking it")
|
||||
custom_mouse.move(x, y, duration=(random.random() * 0.2 + 1.0), randomize=5)
|
||||
custom_mouse.move(x, y, duration=(random.random() * 0.1 + 0.4), randomize=5)
|
||||
mouse.click(button="left")
|
||||
else:
|
||||
Logger.debug("Sanity position check on hell btn failed")
|
||||
return False
|
||||
break
|
||||
|
||||
# check for server issue
|
||||
wait(2.0)
|
||||
@@ -198,7 +193,7 @@ class UiManager():
|
||||
if server_issue:
|
||||
Logger.warning("Server connection issue. waiting 20s")
|
||||
x, y = self._screen.convert_screen_to_monitor((self._config.ui_pos["issue_occured_ok_x"], self._config.ui_pos["issue_occured_ok_y"]))
|
||||
custom_mouse.move(x, y, duration=(random.random() * 0.4 + 1.0), randomize=5)
|
||||
custom_mouse.move(x, y, duration=(random.random() * 0.1 + 0.4), randomize=5)
|
||||
mouse.click(button="left")
|
||||
wait(1, 2)
|
||||
keyboard.send("esc")
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = '0.1.1'
|
||||
__version__ = '0.1.2'
|
||||
|
||||
7
ui.ini
@@ -85,8 +85,9 @@ reached_node_dist=150
|
||||
; all rois are in [left, top, width, height] format
|
||||
is_overburdened=17,765,470,90
|
||||
save_and_exit=750,350,410,260
|
||||
play_btn=390,760,1150,300
|
||||
hell_btn=550,100,1000,800
|
||||
play_btn_online=640,920,320,100
|
||||
play_btn_offline=800,940,320,100
|
||||
hell_btn=840,550,245,70
|
||||
gold_btn=1390,736,400,150
|
||||
health_globe=260,890,320,190
|
||||
mana_globe=1350,890,320,190
|
||||
@@ -94,4 +95,4 @@ cut_skill_bar=0,0,1920,980
|
||||
merc_icon=0,0,150,150
|
||||
loading_left_black=0,0,500,1080
|
||||
death=770,290,380,75
|
||||
tp_search=530,180,820,600
|
||||
tp_search=530,180,820,600
|
||||
|
||||