"Basic" classes (#352)
* Start of "Basic" classes will left attack unless right attack is available. * Update basic_ranged.py * Update basic.py
This commit is contained in:
@@ -150,6 +150,35 @@ shout=f3
|
||||
war_cry=f5
|
||||
find_item=f4
|
||||
|
||||
; ===========================
|
||||
; ==== Builds: Basic ====
|
||||
; ===========================
|
||||
; Supported runs: UNTESTED (this is your job!)
|
||||
; this will basically continuously left attack, unless right attack is available.
|
||||
;if the buffs are not set they are not used (they are part of the prebuff setup)
|
||||
|
||||
[basic]
|
||||
teleport=
|
||||
left_attack=f5
|
||||
right_attack=f2
|
||||
buff_1=f8
|
||||
buff_2=f3
|
||||
|
||||
|
||||
; ===========================
|
||||
; ==== Builds: Basic Ranged====
|
||||
; ===========================
|
||||
; Supported runs: UNTESTED (this is your job!)
|
||||
; this will basically continuously left attack, unless right attack is available.
|
||||
;if the buffs are not set they are not used (they are part of the prebuff setup)
|
||||
|
||||
[basic_ranged]
|
||||
teleport=
|
||||
left_attack=f5
|
||||
right_attack=f2
|
||||
buff_1=f8
|
||||
buff_2=f3
|
||||
|
||||
|
||||
[dclone]
|
||||
; Normally have known region IP (that we didn't block) for ip hunting
|
||||
|
||||
@@ -28,6 +28,8 @@ from char.sorceress import LightSorc, BlizzSorc, NovaSorc
|
||||
from char.trapsin import Trapsin
|
||||
from char.hammerdin import Hammerdin
|
||||
from char.barbarian import Barbarian
|
||||
from char.basic import Basic
|
||||
from char.basic_ranged import Basic_Ranged
|
||||
from run import Pindle, ShenkEld, Trav, Nihlatak, Arcane
|
||||
from town import TownManager, A1, A2, A3, A4, A5
|
||||
|
||||
@@ -61,6 +63,10 @@ class Bot:
|
||||
self._char: IChar = Trapsin(self._config.trapsin, self._config.char, self._screen, self._template_finder, self._ui_manager, self._pather)
|
||||
elif self._config.char["type"] == "barbarian":
|
||||
self._char: IChar = Barbarian(self._config.barbarian, self._config.char, self._screen, self._template_finder, self._ui_manager, self._pather)
|
||||
elif self._config.char["type"] == "basic":
|
||||
self._char: IChar = Basic(self._config.basic, self._config.char, self._screen, self._template_finder, self._ui_manager, self._pather)
|
||||
elif self._config.char["type"] == "basic_ranged":
|
||||
self._char: IChar = Basic_Ranged(self._config.basic, 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)
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import keyboard
|
||||
from utils.custom_mouse import mouse
|
||||
from char import IChar
|
||||
from template_finder import TemplateFinder
|
||||
from ui import UiManager
|
||||
from pather import Pather
|
||||
from logger import Logger
|
||||
from screen import Screen
|
||||
from utils.misc import wait, cut_roi
|
||||
import time
|
||||
from pather import Pather, Location
|
||||
|
||||
|
||||
class Basic(IChar):
|
||||
def __init__(self, skill_hotkeys, char_config, screen: Screen, template_finder: TemplateFinder, ui_manager: UiManager, pather: Pather):
|
||||
Logger.info("Setting up Basic Character")
|
||||
super().__init__(skill_hotkeys, char_config, screen, template_finder, ui_manager)
|
||||
self._pather = pather
|
||||
self._do_pre_move = True
|
||||
# offset shenk final position further to the right and bottom
|
||||
if self._skill_hotkeys["teleport"]:
|
||||
self._pather.offset_node(149, [120, 70])
|
||||
|
||||
def _cast_attack_pattern(self, time_in_s: float):
|
||||
keyboard.send(self._char_config["stand_still"], do_release=False)
|
||||
wait(0.05, 0.1)
|
||||
keyboard.send(self._skill_hotkeys["left_attack"])
|
||||
wait(0.05, 0.1)
|
||||
keyboard.send(self._skill_hotkeys["right_attack"])
|
||||
wait(0.05, 0.1)
|
||||
start = time.time()
|
||||
while (time.time() - start) < time_in_s:
|
||||
if self._ui_manager.is_right_skill_active():
|
||||
wait(0.05, 0.1)
|
||||
mouse.click(button="right")
|
||||
else:
|
||||
wait(0.05, 0.1)
|
||||
mouse.click(button="left")
|
||||
wait(0.01, 0.05)
|
||||
keyboard.send(self._char_config["stand_still"], do_press=False)
|
||||
|
||||
def pre_buff(self):
|
||||
if self._skill_hotkeys["buff_1"]:
|
||||
keyboard.send(self._skill_hotkeys["buff_1"])
|
||||
wait(0.5, 0.15)
|
||||
mouse.click(button="right")
|
||||
wait(0.5, 0.15)
|
||||
if self._skill_hotkeys["buff_2"]:
|
||||
keyboard.send(self._skill_hotkeys["buff_2"])
|
||||
wait(0.5, 0.15)
|
||||
mouse.click(button="right")
|
||||
wait(0.5, 0.15)
|
||||
|
||||
def pre_move(self):
|
||||
# select teleport if available
|
||||
super().pre_move()
|
||||
|
||||
|
||||
def _move_and_attack(self, abs_move: tuple[int, int], atk_len: float):
|
||||
pos_m = self._screen.convert_abs_to_monitor(abs_move)
|
||||
self.pre_move()
|
||||
self.move(pos_m, force_move=True)
|
||||
self._cast_attack_pattern(atk_len)
|
||||
|
||||
|
||||
|
||||
#this is where we kill bosses
|
||||
|
||||
def kill_pindle(self) -> bool:
|
||||
wait(0.1, 0.15)
|
||||
if self.can_teleport():
|
||||
self._pather.traverse_nodes_fixed("pindle_end", self)
|
||||
else:
|
||||
if not self._do_pre_move:
|
||||
# keyboard.send(self._skill_hotkeys["concentration"])
|
||||
# wait(0.05, 0.15)
|
||||
self._pather.traverse_nodes((Location.A5_PINDLE_SAFE_DIST, Location.A5_PINDLE_END), self, time_out=1.0, do_pre_move=self._do_pre_move)
|
||||
self._pather.traverse_nodes((Location.A5_PINDLE_SAFE_DIST, Location.A5_PINDLE_END), self, time_out=0.1)
|
||||
self._cast_attack_pattern(self._char_config["atk_len_pindle"])
|
||||
wait(0.1, 0.15)
|
||||
return True
|
||||
|
||||
def kill_eldritch(self) -> bool:
|
||||
if self.can_teleport():
|
||||
self._pather.traverse_nodes_fixed("eldritch_end", self)
|
||||
else:
|
||||
if not self._do_pre_move:
|
||||
# keyboard.send(self._skill_hotkeys["concentration"])
|
||||
# wait(0.05, 0.15)
|
||||
self._pather.traverse_nodes((Location.A5_ELDRITCH_SAFE_DIST, Location.A5_ELDRITCH_END), self, time_out=1.0, do_pre_move=self._do_pre_move)
|
||||
wait(0.05, 0.1)
|
||||
self._cast_attack_pattern(self._char_config["atk_len_eldritch"])
|
||||
return True
|
||||
|
||||
def kill_shenk(self):
|
||||
# if not self._do_pre_move:
|
||||
# keyboard.send(self._skill_hotkeys["concentration"])
|
||||
# wait(0.05, 0.15)
|
||||
self._pather.traverse_nodes((Location.A5_SHENK_SAFE_DIST, Location.A5_SHENK_END), self, time_out=1.0, do_pre_move=self._do_pre_move)
|
||||
wait(0.05, 0.1)
|
||||
self._cast_attack_pattern(self._char_config["atk_len_shenk"])
|
||||
wait(0.1, 0.15)
|
||||
return True
|
||||
|
||||
def kill_council(self) -> bool:
|
||||
# Check out the node screenshot in assets/templates/trav/nodes to see where each node is at
|
||||
atk_len = self._char_config["atk_len_trav"]
|
||||
# Go inside and war cry a bit
|
||||
self._pather.traverse_nodes([228, 229], self, time_out=2.5, force_tp=True)
|
||||
self._cast_attack_pattern(atk_len)
|
||||
# Move a bit back and another round
|
||||
self._move_and_attack((40, 20), atk_len)
|
||||
# Here we have two different attack sequences depending if tele is available or not
|
||||
if self.can_teleport():
|
||||
# Back to center stairs and more war cry
|
||||
self._pather.traverse_nodes([226], self, time_out=2.5, force_tp=True)
|
||||
self._cast_attack_pattern(atk_len)
|
||||
# move a bit to the top
|
||||
self._move_and_attack((65, -30), atk_len)
|
||||
else:
|
||||
# Stay inside and cast war cry again moving forward
|
||||
self._move_and_attack((40, 10), atk_len)
|
||||
self._move_and_attack((-40, -20), atk_len)
|
||||
return True
|
||||
|
||||
def kill_nihlatak(self, end_nodes: list[int]) -> bool:
|
||||
# Move close to nilathak
|
||||
self._pather.traverse_nodes(end_nodes, self, time_out=0.8, do_pre_move=False)
|
||||
# move mouse to center (leftover from hammerdin)
|
||||
pos_m = self._screen.convert_abs_to_monitor((0, 0))
|
||||
mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7])
|
||||
self._cast_attack_pattern(self._char_config["atk_len_nihlatak"] * 0.4)
|
||||
self._cast_attack_pattern(0.8)
|
||||
self._move_and_attack((30, 15), self._char_config["atk_len_nihlatak"] * 0.3)
|
||||
self._cast_attack_pattern(0.8)
|
||||
self._move_and_attack((-30, -15), self._char_config["atk_len_nihlatak"] * 0.4)
|
||||
wait(0.1, 0.15)
|
||||
self._cast_attack_pattern(1.2)
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
import keyboard
|
||||
keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or os._exit(1))
|
||||
keyboard.wait("f11")
|
||||
from config import Config
|
||||
from ui.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 = Basic(config.basic, config.char, screen, t_finder, ui_manager, pather)
|
||||
char.kill_council()
|
||||
@@ -0,0 +1,212 @@
|
||||
import keyboard
|
||||
from utils.custom_mouse import mouse
|
||||
from char import IChar
|
||||
from template_finder import TemplateFinder
|
||||
from ui import UiManager
|
||||
from pather import Pather
|
||||
from logger import Logger
|
||||
from screen import Screen
|
||||
from utils.misc import wait, cut_roi
|
||||
import time
|
||||
import random
|
||||
import numpy as np
|
||||
from pather import Pather, Location
|
||||
|
||||
|
||||
class Basic_Ranged(IChar):
|
||||
def __init__(self, skill_hotkeys, char_config, screen: Screen, template_finder: TemplateFinder, ui_manager: UiManager, pather: Pather):
|
||||
Logger.info("Setting up Basic Ranged Character")
|
||||
super().__init__(skill_hotkeys, char_config, screen, template_finder, ui_manager)
|
||||
self._pather = pather
|
||||
self._do_pre_move = True
|
||||
|
||||
def _left_attack(self, cast_pos_abs: tuple[float, float], delay: tuple[float, float] = (0.2, 0.3), spray: int = 10):
|
||||
if self._skill_hotkeys["left_attack"]:
|
||||
keyboard.send(self._skill_hotkeys["left_attack"])
|
||||
for _ in range(4):
|
||||
x = cast_pos_abs[0] + (random.random() * 2 * spray - spray)
|
||||
y = cast_pos_abs[1] + (random.random() * 2 * spray - spray)
|
||||
pos_m = self._screen.convert_abs_to_monitor((x, y))
|
||||
mouse.move(*pos_m)
|
||||
mouse.click(button="left")
|
||||
|
||||
def _right_attack(self, cast_pos_abs: tuple[float, float], delay: tuple[float, float] = (0.2, 0.3), spray: float = 10):
|
||||
if not self._skill_hotkeys["right_attack"]:
|
||||
raise ValueError("You did not set right attack hotkey!")
|
||||
keyboard.send(self._skill_hotkeys["right_attack"])
|
||||
for _ in range(3):
|
||||
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")
|
||||
|
||||
def pre_buff(self):
|
||||
if self._skill_hotkeys["buff_1"]:
|
||||
keyboard.send(self._skill_hotkeys["buff_1"])
|
||||
wait(0.5, 0.15)
|
||||
mouse.click(button="right")
|
||||
wait(0.5, 0.15)
|
||||
if self._skill_hotkeys["buff_2"]:
|
||||
keyboard.send(self._skill_hotkeys["buff_2"])
|
||||
wait(0.5, 0.15)
|
||||
mouse.click(button="right")
|
||||
wait(0.5, 0.15)
|
||||
|
||||
|
||||
#bosses
|
||||
|
||||
def kill_pindle(self) -> bool:
|
||||
pindle_pos_abs = self._screen.convert_screen_to_abs(self._config.path["pindle_end"][0])
|
||||
cast_pos_abs = [pindle_pos_abs[0] * 0.9, pindle_pos_abs[1] * 0.9]
|
||||
start = time.time()
|
||||
keyboard.send(self._char_config["stand_still"], do_release=False)
|
||||
while (time.time() - start) < self._char_config["atk_len_pindle"]:
|
||||
if self._ui_manager.is_right_skill_active():
|
||||
wait(0.05, 0.1)
|
||||
self._right_attack(cast_pos_abs, spray=11)
|
||||
else:
|
||||
wait(0.05, 0.1)
|
||||
self._left_attack(cast_pos_abs, spray=11)
|
||||
keyboard.send(self._char_config["stand_still"], do_press=False)
|
||||
wait(self._cast_duration, self._cast_duration + 0.2)
|
||||
# Move to items
|
||||
self._pather.traverse_nodes((Location.A5_PINDLE_SAFE_DIST, Location.A5_PINDLE_END), self, time_out=1.4, force_tp=True)
|
||||
return True
|
||||
|
||||
|
||||
def kill_eldritch(self) -> bool:
|
||||
eld_pos_abs = self._screen.convert_screen_to_abs(self._config.path["eldritch_end"][0])
|
||||
cast_pos_abs = [eld_pos_abs[0] * 0.9, eld_pos_abs[1] * 0.9]
|
||||
start = time.time()
|
||||
keyboard.send(self._char_config["stand_still"], do_release=False)
|
||||
while (time.time() - start) < self._char_config["atk_len_eldritch"]:
|
||||
if self._ui_manager.is_right_skill_active():
|
||||
wait(0.05, 0.1)
|
||||
self._right_attack(cast_pos_abs, spray=11)
|
||||
else:
|
||||
wait(0.05, 0.1)
|
||||
self._left_attack(cast_pos_abs, spray=11)
|
||||
keyboard.send(self._char_config["stand_still"], do_press=False)
|
||||
wait(self._cast_duration, self._cast_duration + 0.2)
|
||||
# Move to items
|
||||
self._pather.traverse_nodes((Location.A5_ELDRITCH_SAFE_DIST, Location.A5_ELDRITCH_END), self, time_out=1.4, force_tp=True)
|
||||
return True
|
||||
|
||||
def kill_shenk(self) -> bool:
|
||||
shenk_pos_abs = self._pather.find_abs_node_pos(149, self._screen.grab())
|
||||
if shenk_pos_abs is None:
|
||||
shenk_pos_abs = self._screen.convert_screen_to_abs(self._config.path["shenk_end"][0])
|
||||
cast_pos_abs = [shenk_pos_abs[0] * 0.9, shenk_pos_abs[1] * 0.9]
|
||||
start = time.time()
|
||||
keyboard.send(self._char_config["stand_still"], do_release=False)
|
||||
while (time.time() - start) < self._char_config["atk_len_shenk"]:
|
||||
if self._ui_manager.is_right_skill_active():
|
||||
wait(0.05, 0.1)
|
||||
self._right_attack(cast_pos_abs, spray=11)
|
||||
else:
|
||||
wait(0.05, 0.1)
|
||||
self._left_attack(cast_pos_abs, spray=11)
|
||||
keyboard.send(self._char_config["stand_still"], do_press=False)
|
||||
wait(self._cast_duration, self._cast_duration + 0.2)
|
||||
# Move to items
|
||||
self._pather.traverse_nodes((Location.A5_SHENK_SAFE_DIST, Location.A5_SHENK_END), self, time_out=1.4, force_tp=True)
|
||||
return True
|
||||
|
||||
def kill_council(self) -> bool:
|
||||
atk_len_trav_2 = int(self._char_config["atk_len_trav"] / 2)
|
||||
# Check out the node screenshot in assets/templates/trav/nodes to see where each node is at
|
||||
# Go inside cast stuff in general direction
|
||||
self._pather.offset_node(229, [250, 130])
|
||||
self._pather.traverse_nodes([228, 229], self, time_out=2.5, force_tp=True)
|
||||
self._pather.offset_node(229, [-250, -130])
|
||||
atk_pos_abs = self._pather.find_abs_node_pos(230, self._screen.grab())
|
||||
if atk_pos_abs is None:
|
||||
Logger.debug("Could not find node [230]. Using static attack coordinates instead.")
|
||||
atk_pos_abs = [-300, -200]
|
||||
else:
|
||||
atk_pos_abs = [atk_pos_abs[0], atk_pos_abs[1] + 70]
|
||||
cast_pos_abs = np.array([atk_pos_abs[0] * 0.9, atk_pos_abs[1] * 0.9])
|
||||
self._left_attack(cast_pos_abs, spray=80)
|
||||
for _ in range(atk_len_trav_2):
|
||||
if self._ui_manager.is_right_skill_active():
|
||||
self._right_attack(cast_pos_abs, spray=11)
|
||||
else:
|
||||
self._left_attack(cast_pos_abs, spray=11)
|
||||
# move a bit back
|
||||
pos_m = self._screen.convert_abs_to_monitor((160, 30))
|
||||
self.pre_move()
|
||||
self.move(pos_m, force_move=True)
|
||||
atk_pos_abs = self._pather.find_abs_node_pos(229, self._screen.grab())
|
||||
if atk_pos_abs is None:
|
||||
Logger.debug("Could not find node [229]. Using static attack coordinates instead.")
|
||||
atk_pos_abs = [-200, -80]
|
||||
for _ in range(atk_len_trav_2):
|
||||
if self._ui_manager.is_right_skill_active():
|
||||
self._right_attack(cast_pos_abs, spray=11)
|
||||
else:
|
||||
self._left_attack(cast_pos_abs, spray=11)
|
||||
# Move outside
|
||||
# Move a bit back and another round
|
||||
self._pather.traverse_nodes([226], self, time_out=2.5, force_tp=True)
|
||||
cast_pos_abs = np.array([-300, -100])
|
||||
for _ in range(atk_len_trav_2):
|
||||
if self._ui_manager.is_right_skill_active():
|
||||
self._right_attack(cast_pos_abs, spray=11)
|
||||
else:
|
||||
self._left_attack(cast_pos_abs, spray=11)
|
||||
# move a bit back
|
||||
pos_m = self._screen.convert_abs_to_monitor((100, 0))
|
||||
cast_pos_abs = self._pather.find_abs_node_pos(229, self._screen.grab())
|
||||
if cast_pos_abs is not None:
|
||||
self.pre_move()
|
||||
self.move(pos_m, force_move=True)
|
||||
for _ in range(atk_len_trav_2):
|
||||
if self._ui_manager.is_right_skill_active():
|
||||
self._right_attack(cast_pos_abs, spray=11)
|
||||
else:
|
||||
self._left_attack(cast_pos_abs, spray=11)
|
||||
return True
|
||||
|
||||
def kill_nihlatak(self, end_nodes: list[int]) -> bool:
|
||||
# Find nilhlatak position
|
||||
delay = [0.2, 0.3]
|
||||
atk_len = int(self._char_config["atk_len_nihlatak"])
|
||||
for i in range(atk_len):
|
||||
nihlatak_pos_abs = self._pather.find_abs_node_pos(end_nodes[-1], self._screen.grab())
|
||||
if nihlatak_pos_abs is None:
|
||||
return False
|
||||
cast_pos_abs = np.array([nihlatak_pos_abs[0] * 0.9, nihlatak_pos_abs[1] * 0.9])
|
||||
self._left_attack(cast_pos_abs, delay, 90)
|
||||
# Do some tele "dancing" after each sequence
|
||||
if i < atk_len - 1:
|
||||
rot_deg = random.randint(-10, 10) if i % 2 == 0 else random.randint(170, 190)
|
||||
tele_pos_abs = unit_vector(rotate_vec(cast_pos_abs, rot_deg)) * 100
|
||||
pos_m = self._screen.convert_abs_to_monitor(tele_pos_abs)
|
||||
self.pre_move()
|
||||
self.move(pos_m)
|
||||
else:
|
||||
self._right_attack(cast_pos_abs, spray=60)
|
||||
# Move to items
|
||||
wait(self._cast_duration, self._cast_duration + 0.2)
|
||||
self._pather.traverse_nodes(end_nodes, self, time_out=0.8)
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
import keyboard
|
||||
from screen import Screen
|
||||
from template_finder import TemplateFinder
|
||||
from pather import Pather
|
||||
keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or os._exit(1))
|
||||
keyboard.wait("f11")
|
||||
from config import Config
|
||||
from ui 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 = LightSorc(config.light_sorc, config.char, screen, t_finder, ui_manager, pather)
|
||||
char.kill_council()
|
||||
@@ -156,6 +156,16 @@ class Config:
|
||||
self.barbarian = self._config["barbarian"]
|
||||
if "barbarian" in self._custom:
|
||||
self.barbarian.update(self._custom["barbarian"])
|
||||
|
||||
# Basic config
|
||||
self.basic = self._config["basic"]
|
||||
if "basic" in self._custom:
|
||||
self.basic.update(self._custom["basic"])
|
||||
|
||||
# Basic Ranged config
|
||||
self.basic = self._config["basic_ranged"]
|
||||
if "basic_ranged" in self._custom:
|
||||
self.basic_ranged.update(self._custom["basic_ranged"])
|
||||
|
||||
self.advanced_options = {
|
||||
"pathing_delay_factor": min(max(int(self._select_val("advanced_options", "pathing_delay_factor")), 1), 10),
|
||||
|
||||
Reference in New Issue
Block a user