From be6e3a267dfe210ad35f4b77a750ec177ca26b40 Mon Sep 17 00:00:00 2001
From: Legit <96157236+D2RLegit@users.noreply.github.com>
Date: Thu, 30 Jun 2022 01:59:57 -0500
Subject: [PATCH 1/5] Poisonmancer Overhaul with mob detect
Fixed poisonmancer by doing a complete overhaul with mob detection
---
src/char/poison_necro.py | 803 +++++++++++++++++++++------------------
1 file changed, 435 insertions(+), 368 deletions(-)
diff --git a/src/char/poison_necro.py b/src/char/poison_necro.py
index 72ae64cac..cf950dfc0 100644
--- a/src/char/poison_necro.py
+++ b/src/char/poison_necro.py
@@ -14,6 +14,8 @@
import time
import os
from ui_manager import get_closest_non_hud_pixel
+from screen import convert_abs_to_monitor, convert_screen_to_abs, grab
+from target_detect import get_visible_green_targets, get_visible_targets, get_visible_blue_targets
class Poison_Necro(IChar):
def __init__(self, skill_hotkeys: dict, pather: Pather):
@@ -41,56 +43,6 @@ def __init__(self, skill_hotkeys: dict, pather: Pather):
self._golem_count="none"
self._revive_count=0
-
- def _check_shenk_death(self):
- ''' make sure shenk is dead checking for fireballs so we can exit combat sooner '''
-
- roi = [640,0,640,720]
- img = grab()
-
- template_match = template_finder.search(
- ['SHENK_DEATH_1','SHENK_DEATH_2','SHENK_DEATH_3','SHENK_DEATH_4'],
- img,
- threshold=0.6,
- roi=roi,
- use_grayscale = False
- )
- if template_match.valid:
- self._shenk_dead=1
- Logger.info('\33[31m'+"Shenks Dead, looting..."+'\033[0m')
- else:
- return True
-
- def _count_revives(self):
- roi = [15,14,400,45]
- img = grab()
- max_rev = 13
-
- template_match = template_finder.search(
- ['REV_BASE'],
- img,
- threshold=0.6,
- roi=roi
- )
- if template_match.valid:
- self._revive_count=max_rev
- else:
- self._revive_count=0
- return True
-
- for count in range(1,max_rev):
- rev_num = "REV_"+str(count)
- template_match = template_finder.search(
- [rev_num],
- img,
- threshold=0.66,
- roi=roi,
- use_grayscale = False
- )
- if template_match.valid:
- self._revive_count=count
-
-
def poison_nova(self, time_in_s: float):
if not self._skill_hotkeys["poison_nova"]:
raise ValueError("You did not set poison nova hotkey!")
@@ -102,148 +54,7 @@ def poison_nova(self, time_in_s: float):
mouse.press(button="right")
wait(0.12, 0.2)
mouse.release(button="right")
-
- def _count_skeletons(self):
- roi = [15,14,400,45]
- img = grab()
- max_skeles = 13
-
- template_match = template_finder.search(
- ['SKELE_BASE'],
- img,
- threshold=0.6,
- roi=roi
- )
- if template_match.valid:
- self._skeletons_count=max_skeles
- else:
- self._skeletons_count=0
- return True
-
- for count in range(1,max_skeles):
- skele_num = "SKELE_"+str(count)
- template_match = template_finder.search(
- [skele_num],
- img,
- threshold=0.66,
- roi=roi,
- use_grayscale = False
- )
- if template_match.valid:
- self._skeletons_count=count
-
- def _count_gol(self):
- roi = [15,14,400,45]
- img = grab()
-
- template_match = template_finder.search(
- ['CLAY'],
- img,
- threshold=0.6,
- roi=roi
- )
- if template_match.valid:
- self._golem_count="clay gol"
- else:
- self._golem_count="none"
- return True
-
- def _summon_count(self):
- ''' see how many summons and which golem are out '''
-
- self._count_skeletons()
- self._count_revives()
- self._count_gol()
- def _summon_stat(self):
- ''' print counts for summons '''
- Logger.info('\33[31m'+"Summon status | "+str(self._skeletons_count)+"skele | "+str(self._revive_count)+" rev | "+self._golem_count+" |"+'\033[0m')
-
- def _revive(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=12):
- Logger.info('\033[94m'+"raise revive"+'\033[0m')
- keyboard.send(Config().char["stand_still"], do_release=False)
- for _ in range(cast_count):
- if self._skill_hotkeys["raise_revive"]:
- keyboard.send(self._skill_hotkeys["raise_revive"])
- #Logger.info("revive -> cast")
- x = cast_pos_abs[0] + (random.random() * 2*spray - spray)
- y = cast_pos_abs[1] + (random.random() * 2*spray - spray)
- cast_pos_monitor = screen.convert_abs_to_monitor((x, y))
-
- nx = cast_pos_monitor[0]
- ny = cast_pos_monitor[1]
- if(nx>1280):
- nx=1275
- if(ny>720):
- ny=715
- if(nx<0):
- nx=0
- if(ny<0):
- ny=0
- clamp = [nx,ny]
-
- mouse.move(*clamp)
- mouse.press(button="right")
- wait(0.075, 0.1)
- mouse.release(button="right")
- keyboard.send(Config().char["stand_still"], do_press=False)
-
- def _raise_skeleton(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=16):
- Logger.info('\033[94m'+"raise skeleton"+'\033[0m')
- keyboard.send(Config().char["stand_still"], do_release=False)
- for _ in range(cast_count):
- if self._skill_hotkeys["raise_skeleton"]:
- keyboard.send(self._skill_hotkeys["raise_skeleton"])
- #Logger.info("raise skeleton -> cast")
- x = cast_pos_abs[0] + (random.random() * 2*spray - spray)
- y = cast_pos_abs[1] + (random.random() * 2*spray - spray)
- cast_pos_monitor = screen.convert_abs_to_monitor((x, y))
-
- nx = cast_pos_monitor[0]
- ny = cast_pos_monitor[1]
- if(nx>1280):
- nx=1279
- if(ny>720):
- ny=719
- if(nx<0):
- nx=0
- if(ny<0):
- ny=0
- clamp = [nx,ny]
-
- mouse.move(*clamp)
- mouse.press(button="right")
- wait(0.02, 0.05)
- mouse.release(button="right")
- keyboard.send(Config().char["stand_still"], do_press=False)
-
- def _raise_mage(self, cast_pos_abs: tuple[float, float], spray: int = 10, cast_count: int=16):
- Logger.info('\033[94m'+"raise mage"+'\033[0m')
- keyboard.send(Config().char["stand_still"], do_release=False)
- for _ in range(cast_count):
- if self._skill_hotkeys["raise_mage"]:
- keyboard.send(self._skill_hotkeys["raise_mage"])
- #Logger.info("raise skeleton -> cast")
- x = cast_pos_abs[0] + (random.random() * 2*spray - spray)
- y = cast_pos_abs[1] + (random.random() * 2*spray - spray)
- cast_pos_monitor = screen.convert_abs_to_monitor((x, y))
-
- nx = cast_pos_monitor[0]
- ny = cast_pos_monitor[1]
- if(nx>1280):
- nx=1279
- if(ny>720):
- ny=719
- if(nx<0):
- nx=0
- if(ny<0):
- ny=0
- clamp = [nx,ny]
-
- mouse.move(*clamp)
- mouse.press(button="right")
- wait(0.02, 0.05)
mouse.release(button="right")
- keyboard.send(Config().char["stand_still"], do_press=False)
def pre_buff(self):
@@ -270,6 +81,17 @@ def _clay_golem(self):
mouse.click(button="right")
wait(self._cast_duration)
+ def amp_dmg(self, hork_time: int):
+ wait(0.5)
+ if self._skill_hotkeys["amp_dmg"]:
+ keyboard.send(self._skill_hotkeys["amp_dmg"])
+ wait(0.5, 0.15)
+ pos_m = convert_abs_to_monitor((0, -20))
+ mouse.move(*pos_m)
+ wait(0.5, 0.15)
+ mouse.press(button="right")
+ wait(hork_time)
+ mouse.release(button="right")
def bone_armor(self):
if self._skill_hotkeys["bone_armor"]:
@@ -322,223 +144,468 @@ def _left_attack_single(self, cast_pos_abs: tuple[float, float], spray: int = 10
keyboard.send(Config().char["stand_still"], do_press=False)
- def _amp_dmg(self, cast_pos_abs: tuple[float, float], spray: float = 10):
- if self._skill_hotkeys["amp_dmg"]:
- keyboard.send(self._skill_hotkeys["amp_dmg"])
-
- x = cast_pos_abs[0] + (random.random() * 2*spray - spray)
- y = cast_pos_abs[1] + (random.random() * 2*spray - spray)
- cast_pos_monitor = screen.convert_abs_to_monitor((x, y))
- mouse.move(*cast_pos_monitor)
+ def _do_curse(self, hork_time: int):
+ wait(0.5)
+ if self._skill_hotkeys["curse"]:
+ keyboard.send(self._skill_hotkeys["curse"])
+ wait(0.05, 0.15)
+ pos_m = convert_abs_to_monitor((0, -20))
+ mouse.move(*pos_m)
+ wait(0.05, 0.15)
mouse.press(button="right")
- wait(0.25, 0.35)
- mouse.release(button="right")
-
- def _lower_res(self, cast_pos_abs: tuple[float, float], spray: float = 10):
- if self._skill_hotkeys["lower_res"]:
- keyboard.send(self._skill_hotkeys["lower_res"])
-
- x = cast_pos_abs[0] + (random.random() * 2*spray - spray)
- y = cast_pos_abs[1] + (random.random() * 2*spray - spray)
- cast_pos_monitor = screen.convert_abs_to_monitor((x, y))
+ wait(hork_time)
+ mouse.release(button="right")
+
+ def _force_teleport(self, cast_pos_abs: tuple[float, float], spray: float = 10):
+ if not self._skill_hotkeys["force_teleport"]:
+ raise ValueError("You did not set a hotkey for force_teleport!")
+ keyboard.send(self._skill_hotkeys["force_teleport"])
+ x = cast_pos_abs[0] + (random.random() * 2 * spray - spray)
+ y = cast_pos_abs[1] + (random.random() * 2 * spray - spray)
+ cast_pos_monitor = convert_abs_to_monitor((x, y))
mouse.move(*cast_pos_monitor)
- mouse.press(button="right")
- wait(0.25, 0.35)
- mouse.release(button="right")
-
- def _corpse_explosion(self, cast_pos_abs: tuple[float, float], spray: int = 10,cast_count: int = 8):
- keyboard.send(Config().char["stand_still"], do_release=False)
- Logger.info('\033[93m'+"corpse explosion~> random cast"+'\033[0m')
- for _ in range(cast_count):
- if self._skill_hotkeys["corpse_explosion"]:
- keyboard.send(self._skill_hotkeys["corpse_explosion"])
- x = cast_pos_abs[0] + (random.random() * 2*spray - spray)
- y = cast_pos_abs[1] + (random.random() * 2*spray - spray)
- cast_pos_monitor = screen.convert_abs_to_monitor((x, y))
- mouse.move(*cast_pos_monitor)
- mouse.press(button="right")
- wait(0.075, 0.1)
- mouse.release(button="right")
- keyboard.send(Config().char["stand_still"], do_press=False)
+ click_tries = random.randint(2, 4)
+ for _ in range(click_tries):
+ mouse.press(button="right")
+ wait(0.09, 0.12)
+ mouse.release(button="right")
+
+ def _raise_skeleton(self, cast_pos_abs: tuple[float, float], spray: float = 10):
+ if not self._skill_hotkeys["raise_skeleton"]:
+ raise ValueError("You did not set a hotkey for raise_skeleton!")
+ keyboard.send(self._skill_hotkeys["raise_skeleton"])
+ x = cast_pos_abs[0] + (random.random() * 2 * spray - spray)
+ y = cast_pos_abs[1] + (random.random() * 2 * spray - spray)
+ cast_pos_monitor = convert_abs_to_monitor((x, y))
+ mouse.move(*cast_pos_monitor)
+ click_tries = random.randint(2, 4)
+ for _ in range(click_tries):
+ mouse.press(button="right")
+ wait(0.09, 0.12)
+ mouse.release(button="right")
- def _cast_circle(self, cast_dir: tuple[float,float],cast_start_angle: float=0.0, cast_end_angle: float=90.0,cast_div: int = 10,cast_v_div: int=4,cast_spell: str='raise_skeleton',delay: float=1.0,offset: float=1.0):
- Logger.info('\033[93m'+"circle cast ~>"+cast_spell+'\033[0m')
- keyboard.send(Config().char["stand_still"], do_release=False)
- keyboard.send(self._skill_hotkeys[cast_spell])
- mouse.press(button="right")
+ def corpse_explosion(self, cast_pos_abs: tuple[float, float], spray: float = 10):
+ if not self._skill_hotkeys["corpse_explosion"]:
+ raise ValueError("You did not set a hotkey for corpse_explosion!")
+ keyboard.send(self._skill_hotkeys["corpse_explosion"])
+ x = cast_pos_abs[0] + (random.random() * 2 * spray - spray)
+ y = cast_pos_abs[1] + (random.random() * 2 * spray - spray)
+ cast_pos_monitor = convert_abs_to_monitor((x, y))
+ mouse.move(*cast_pos_monitor)
+ click_tries = random.randint(2, 4)
+ for _ in range(click_tries):
+ mouse.press(button="right")
+ wait(0.09, 0.12)
+ mouse.release(button="right")
+
+ def _raise_mage(self, cast_pos_abs: tuple[float, float], delay: tuple[float, float] = (0.2, 0.3), spray: float = 10):
+ if not self._skill_hotkeys["raise_mage"]:
+ raise ValueError("You did not set raise_mage hotkey!")
+ keyboard.send(self._skill_hotkeys["raise_mage"])
+ 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 = convert_abs_to_monitor((x, y))
+ mouse.move(*cast_pos_monitor, delay_factor=[0.3, 0.6])
+ mouse.press(button="right")
+ wait(delay[0], delay[1])
+ mouse.release(button="right")
- for i in range(cast_div):
- angle = self._lerp(cast_start_angle,cast_end_angle,float(i)/cast_div)
- target = unit_vector(rotate_vec(cast_dir, angle))
- #Logger.info("current angle ~> "+str(angle))
- for j in range(cast_v_div):
- circle_pos_abs = get_closest_non_hud_pixel(pos = ((target*120.0*float(j+1.0))*offset), pos_type="abs")
- circle_pos_monitor = screen.convert_abs_to_monitor(circle_pos_abs)
- mouse.move(*circle_pos_monitor,delay_factor=[0.3*delay, .6*delay])
+ def _raise_revive(self, cast_pos_abs: tuple[float, float], spray: float = 10):
+ if not self._skill_hotkeys["raise_revive"]:
+ raise ValueError("You did not set a hotkey for raise_revive!")
+ keyboard.send(self._skill_hotkeys["raise_revive"])
+ x = cast_pos_abs[0] + (random.random() * 2 * spray - spray)
+ y = cast_pos_abs[1] + (random.random() * 2 * spray - spray)
+ cast_pos_monitor = convert_abs_to_monitor((x, y))
+ mouse.move(*cast_pos_monitor)
+ click_tries = random.randint(2, 4)
+ for _ in range(click_tries):
+ mouse.press(button="right")
+ wait(0.09, 0.12)
+ mouse.release(button="right")
+
+ def _pn_attack_sequence(
+ self,
+ default_target_abs: tuple[int, int] = (-50, -50),
+ min_duration: float = 0,
+ max_duration: float = 15,
+ blizz_to_ice_blast_ratio: int = 3,
+ target_detect: bool = True,
+ default_spray: int = 20,
+ #aura: str = ""
+ ) -> bool:
+ start = time.time()
+ target_check_count = 1
+ #foh_aura = aura if aura else "conviction"
+ #holy_bolt_aura = aura if aura else "concentration"
+ while (elapsed := (time.time() - start)) <= max_duration:
+ cast_pos_abs = default_target_abs
+ spray = default_spray
+ atk_len = Config().char["atk_len_cs_trashmobs"] * .50
+ # if targets are detected, switch to targeting with reduced spread rather than present default cast position and default spread
+ if target_detect and (targets := get_visible_green_targets()):
+ # log_targets(targets)
+ spray = 5
+ cast_pos_abs = targets[0].center_abs
+ target_check_count += 1
+ closest_target_position_monitor = targets[0].center_monitor
+
+
+
+ # if time > minimum and either targets aren't set or targets don't exist, exit loop
+ if elapsed > min_duration and (not target_detect or not targets):
+ break
+
+ targets = get_visible_green_targets()
+ if targets and len(targets) > 0:
+ # TODO: add delay between FOH casts--doesn't properly cast each FOH in sequence
+ # cast foh to holy bolt with preset ratio (e.g. 3 foh followed by 1 holy bolt if foh_to_holy_bolt_ratio = 3)
+ Logger.info("Mob detected, Attacking mobs!")
+ self.poison_nova(atk_len)
+ self._raise_skeleton(cast_pos_abs, spray=spray)
+ #self._raise_mage(cast_pos_abs, spray=spray)
+ self._raise_revive(cast_pos_abs, spray=spray)
+ targets = get_visible_green_targets()
+ if targets:
+ closest_target_position_monitor = targets[0].center_monitor
+ self.pre_move()
+ self.move(closest_target_position_monitor, force_move=True)
+ pos_m = screen.convert_abs_to_monitor((50, 0))
+ self.walk(pos_m, force_move=True)
+ self.poison_nova(atk_len)
+ targets = get_visible_green_targets()
+ self._raise_revive(cast_pos_abs, spray=spray)
+ self._raise_mage(cast_pos_abs, spray=spray)
+ self._raise_skeleton(cast_pos_abs, spray=spray)
+
+ else:
+ Logger.info("No minions detected yet, Default attack sequence")
+ targets = get_visible_green_targets()
+ self.poison_nova(atk_len)
+ targets = get_visible_green_targets()
+ self._raise_skeleton((-25, -75), spray=50)
+ pos_m = screen.convert_abs_to_monitor((0, 30))
+ self.walk(pos_m, force_move=True)
+ self._raise_revive((-35, -50), spray=50)
+ self._raise_mage((0, -100), spray=50)
+ self._raise_skeleton(cast_pos_abs, spray=spray)
+
+
+ target_check_count += 1
+ return True
- #Logger.info("circle move")
- mouse.release(button="right")
- keyboard.send(Config().char["stand_still"], do_press=False)
-
+ def _trav_attack(
+ self,
+ default_target_abs: tuple[int, int] = (-50, -50),
+ min_duration: float = 0,
+ max_duration: float = 15,
+ blizz_to_ice_blast_ratio: int = 3,
+ target_detect: bool = True,
+ default_spray: int = 20,
+ #aura: str = ""
+ ) -> bool:
+ start = time.time()
+ target_check_count = 1
+ #foh_aura = aura if aura else "conviction"
+ #holy_bolt_aura = aura if aura else "concentration"
+ while (elapsed := (time.time() - start)) <= max_duration:
+ cast_pos_abs = default_target_abs
+ spray = default_spray
+ atk_len = Config().char["atk_len_cs_trashmobs"] * .50
+ # if targets are detected, switch to targeting with reduced spread rather than present default cast position and default spread
+ if target_detect and (targets := get_visible_targets()):
+ # log_targets(targets)
+ spray = 5
+ cast_pos_abs = targets[0].center_abs
+ target_check_count += 1
+ closest_target_position_monitor = targets[0].center_monitor
+
+
+
+ # if time > minimum and either targets aren't set or targets don't exist, exit loop
+ if elapsed > min_duration and (not target_detect or not targets):
+ break
+
+ targets = get_visible_targets()
+ if targets and len(targets) > 0:
+ # TODO: add delay between FOH casts--doesn't properly cast each FOH in sequence
+ # cast foh to holy bolt with preset ratio (e.g. 3 foh followed by 1 holy bolt if foh_to_holy_bolt_ratio = 3)
+ Logger.info("Mob detected, Attacking mobs!")
+ self.poison_nova(atk_len)
+ #self._raise_revive(cast_pos_abs, spray=spray)
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ targets = get_visible_targets()
+ if targets:
+ Logger.info("Teleporting to mob!")
+ closest_target_position_monitor = targets[0].center_monitor
+ self.pre_move()
+ self.move(closest_target_position_monitor, force_move=True)
+ pos_m = screen.convert_abs_to_monitor((50, 0))
+ self.walk(pos_m, force_move=True)
+ self.poison_nova(atk_len)
+ targets = get_visible_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ if targets:
+ closest_target_position_monitor = targets[0].center_monitor
+ self.pre_move()
+ self.move(closest_target_position_monitor, force_move=True)
+ pos_m = screen.convert_abs_to_monitor((-50, 0))
+ self.walk(pos_m, force_move=True)
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ self._raise_revive(cast_pos_abs, spray=spray)
+ #self._raise_mage(cast_pos_abs, spray=spray)
+ self._raise_skeleton(cast_pos_abs, spray=spray)
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+
+ else:
+ Logger.info("No minions detected yet, Default attack sequence")
+ targets = get_visible_targets()
+ self.poison_nova(atk_len)
+ targets = get_visible_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ #self._raise_revive(cast_pos_abs, spray=spray)
+ self._raise_mage(cast_pos_abs, spray=spray)
+ self._raise_skeleton(cast_pos_abs, spray=spray)
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+
+ target_check_count += 1
+ return True
+
+ def _nihl_attack(
+ self,
+ default_target_abs: tuple[int, int] = (-50, -50),
+ min_duration: float = 0,
+ max_duration: float = 15,
+ blizz_to_ice_blast_ratio: int = 3,
+ target_detect: bool = True,
+ default_spray: int = 20,
+ #aura: str = ""
+ ) -> bool:
+ start = time.time()
+ target_check_count = 1
+ #foh_aura = aura if aura else "conviction"
+ #holy_bolt_aura = aura if aura else "concentration"
+ while (elapsed := (time.time() - start)) <= max_duration:
+ cast_pos_abs = default_target_abs
+ spray = default_spray
+ atk_len = Config().char["atk_len_nihlathak"] * .50
+ # if targets are detected, switch to targeting with reduced spread rather than present default cast position and default spread
+ if target_detect and (targets := get_visible_targets()):
+ # log_targets(targets)
+ spray = 5
+ cast_pos_abs = targets[0].center_abs
+ target_check_count += 1
+ closest_target_position_monitor = targets[0].center_monitor
+
+
+
+ # if time > minimum and either targets aren't set or targets don't exist, exit loop
+ if elapsed > min_duration and (not target_detect or not targets):
+ break
+
+ targets = get_visible_targets()
+ if targets and len(targets) > 0:
+ # TODO: add delay between FOH casts--doesn't properly cast each FOH in sequence
+ # cast foh to holy bolt with preset ratio (e.g. 3 foh followed by 1 holy bolt if foh_to_holy_bolt_ratio = 3)
+ Logger.info("Mob detected, Attacking mobs!")
+ self.poison_nova(1.5)
+ #self._raise_revive(cast_pos_abs, spray=spray)
+ targets = get_visible_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ targets = get_visible_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ targets = get_visible_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ if targets:
+ Logger.info("Teleporting to mob!")
+ closest_target_position_monitor = targets[0].center_monitor
+ self.pre_move()
+ self.move(closest_target_position_monitor, force_move=True)
+ self.poison_nova(1.5)
+ targets = get_visible_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ targets = get_visible_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ else:
+ Logger.info("No minions detected yet, Default attack sequence")
+ targets = get_visible_targets()
+ self.poison_nova(1.5)
+ targets = get_visible_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ targets = get_visible_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ targets = get_visible_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ targets = get_visible_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+
+ target_check_count += 1
+ return True
+
+ def _pindle_attack(
+ self,
+ default_target_abs: tuple[int, int] = (-50, -50),
+ min_duration: float = 0,
+ max_duration: float = 15,
+ blizz_to_ice_blast_ratio: int = 3,
+ target_detect: bool = True,
+ default_spray: int = 20,
+ #aura: str = ""
+ ) -> bool:
+ start = time.time()
+ target_check_count = 1
+ #foh_aura = aura if aura else "conviction"
+ #holy_bolt_aura = aura if aura else "concentration"
+ while (elapsed := (time.time() - start)) <= max_duration:
+ cast_pos_abs = default_target_abs
+ spray = default_spray
+ atk_len = Config().char["atk_len_nihlathak"] * .50
+ # if targets are detected, switch to targeting with reduced spread rather than present default cast position and default spread
+ if target_detect and (targets := get_visible_blue_targets()):
+ # log_targets(targets)
+ spray = 5
+ cast_pos_abs = targets[0].center_abs
+ target_check_count += 1
+ closest_target_position_monitor = targets[0].center_monitor
+
+
+
+ # if time > minimum and either targets aren't set or targets don't exist, exit loop
+ if elapsed > min_duration and (not target_detect or not targets):
+ break
+
+ targets = get_visible_blue_targets()
+ if targets and len(targets) > 0:
+ # TODO: add delay between FOH casts--doesn't properly cast each FOH in sequence
+ # cast foh to holy bolt with preset ratio (e.g. 3 foh followed by 1 holy bolt if foh_to_holy_bolt_ratio = 3)
+ Logger.info("Mob detected, Attacking mobs!")
+ self.poison_nova(atk_len)
+ #self._raise_revive(cast_pos_abs, spray=spray)
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ targets = get_visible_blue_targets()
+ if targets:
+ closest_target_position_monitor = targets[0].center_monitor
+ self.pre_move()
+ self.move(closest_target_position_monitor, force_move=True)
+ pos_m = screen.convert_abs_to_monitor((-50, 0))
+ self.walk(pos_m, force_move=True)
+ self.poison_nova(atk_len)
+ self._raise_revive(cast_pos_abs, spray=spray)
+ self._raise_mage(cast_pos_abs, spray=spray)
+ self._raise_skeleton(cast_pos_abs, spray=spray)
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+
+ else:
+ Logger.info("No minions detected yet, Default attack sequence")
+ targets = get_visible_blue_targets()
+ self.poison_nova(atk_len)
+ targets = get_visible_blue_targets()
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+ self._raise_revive(cast_pos_abs, spray=spray)
+ self._raise_mage(cast_pos_abs, spray=spray)
+ self._raise_skeleton(cast_pos_abs, spray=spray)
+ self.corpse_explosion(cast_pos_abs, spray=spray)
+
+ target_check_count += 1
+ return True
+
+ def _attack_sequence(self, min_duration: float = Config().char["atk_len_cs_trashmobs"], max_duration: float = Config().char["atk_len_cs_trashmobs"] * 2):
+ self._pn_attack_sequence(default_target_abs=(20,20), min_duration = min_duration, max_duration = max_duration, default_spray=10, blizz_to_ice_blast_ratio=2)
+
+ def _trav_attack_sequence(self, min_duration: float = Config().char["atk_len_trav"], max_duration: float = Config().char["atk_len_trav"] * 4):
+ self._trav_attack(default_target_abs=(20,20), min_duration = min_duration, max_duration = max_duration, default_spray=10, blizz_to_ice_blast_ratio=2)
+
+ def _nihl_attack_sequence(self, min_duration: float = Config().char["atk_len_nihlathak"], max_duration: float = Config().char["atk_len_nihlathak"] * 4):
+ self._nihl_attack(default_target_abs=(20,20), min_duration = min_duration, max_duration = max_duration, default_spray=10, blizz_to_ice_blast_ratio=2)
+
+ def _pindle_attack_sequence(self, min_duration: float = Config().char["atk_len_nihlathak"], max_duration: float = Config().char["atk_len_nihlathak"] * 4):
+ self._pindle_attack(default_target_abs=(20,20), min_duration = min_duration, max_duration = max_duration, default_spray=10, blizz_to_ice_blast_ratio=2)
def kill_pindle(self) -> bool:
- pos_m = screen.convert_abs_to_monitor((0, 30))
- self.walk(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0)
- self.poison_nova(3.0)
- pos_m = screen.convert_abs_to_monitor((0, -50))
- self.pre_move()
- self.move(pos_m, force_move=True)
- pos_m = screen.convert_abs_to_monitor((50, 0))
- self.walk(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=5,cast_v_div=2,cast_spell='corpse_explosion',delay=1.1,offset=1.8)
- self.poison_nova(3.0)
+ self.bone_armor()
+ self._do_curse(.5)
+ self._pindle_attack_sequence()
+ self._pindle_attack_sequence()
+ self._pindle_attack_sequence()
+ # Move to items
+ self._pather.traverse_nodes_fixed("pindle_end", self)
return True
def kill_eldritch(self) -> bool:
- pos_m = screen.convert_abs_to_monitor((0, -100))
+ pos_m = screen.convert_abs_to_monitor((0, -60))
self.pre_move()
self.move(pos_m, force_move=True)
self.bone_armor()
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0)
- self.poison_nova(2.0)
- self._summon_stat()
+ self._do_curse(.5)
+ self._attack_sequence()
+ self._attack_sequence()
# move a bit back
- pos_m = screen.convert_abs_to_monitor((0, 50))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self.poison_nova(2.0)
- self._pather.traverse_nodes((Location.A5_ELDRITCH_SAFE_DIST, Location.A5_ELDRITCH_END), self, timeout=0.6, force_tp=True)
- pos_m = screen.convert_abs_to_monitor((0, 170))
- self.pre_move()
- self.move(pos_m, force_move=True)
- #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=8,cast_v_div=4,cast_spell='raise_revive',delay=1.2,offset=.8)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=8,cast_v_div=4,cast_spell='raise_skeleton',delay=1.1,offset=.8)
- pos_m = screen.convert_abs_to_monitor((0, -50))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=8,cast_v_div=4,cast_spell='raise_mage',delay=1.1,offset=1.0)
- pos_m = screen.convert_abs_to_monitor((-75, 0))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=8,cast_v_div=4,cast_spell='raise_skeleton',delay=1.1,offset=.5)
- self._summon_count()
- self._summon_stat()
-
self._pather.traverse_nodes((Location.A5_ELDRITCH_SAFE_DIST, Location.A5_ELDRITCH_END), self, timeout=0.6, force_tp=True)
return True
def kill_shenk(self) -> bool:
self._pather.traverse_nodes((Location.A5_SHENK_SAFE_DIST, Location.A5_SHENK_END), self, timeout=1.0)
- #pos_m = self._screen.convert_abs_to_monitor((50, 0))
- #self.walk(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0)
- self.poison_nova(3.0)
- pos_m = screen.convert_abs_to_monitor((0, -50))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=10,cast_v_div=4,cast_spell='raise_mage',delay=1.1,offset=.8)
pos_m = screen.convert_abs_to_monitor((50, 0))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=720,cast_div=10,cast_v_div=4,cast_spell='raise_revive',delay=1.1,offset=.8)
- pos_m = screen.convert_abs_to_monitor((-20, -20))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell='raise_skeleton',delay=1.1,offset=.8)
- self._summon_count()
+ self.walk(pos_m, force_move=True)
+ self._do_curse(.5)
+ self._attack_sequence()
+ self._attack_sequence()
#self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=2,cast_v_div=1,cast_spell='corpse_explosion',delay=3.0,offset=1.8)
return True
def kill_council(self) -> bool:
- pos_m = screen.convert_abs_to_monitor((0, -200))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._pather.traverse_nodes([229], self, timeout=2.5, force_tp=True, use_tp_charge=True)
- pos_m = screen.convert_abs_to_monitor((50, 0))
- self.walk(pos_m, force_move=True)
- #self._lower_res((-50, 0), spray=10)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0)
- self.poison_nova(2.0)
- #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=9,cast_v_div=3,cast_spell='raise_skeleton',delay=1.2,offset=.8)
- pos_m = screen.convert_abs_to_monitor((200, 50))
- self.pre_move()
- self.move(pos_m, force_move=True)
- pos_m = screen.convert_abs_to_monitor((30, -50))
+ self.bone_armor()
+ # Check out the node screenshot in assets/templates/trav/nodes to see where each node is at
+ atk_len = Config().char["atk_len_trav"]
+ # Go inside and hammer a bit
+ self._pather.traverse_nodes([228, 229], self, timeout=2.2, do_pre_move=False, force_tp=True, use_tp_charge=True)
+ pos_m = screen.convert_abs_to_monitor((50, 50))
self.walk(pos_m, force_move=True)
- self.poison_nova(2.0)
- #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=2,cast_v_div=1,cast_spell='corpse_explosion',delay=3.0,offset=1.8)
- #wait(self._cast_duration, self._cast_duration +.2)
- pos_m = screen.convert_abs_to_monitor((-200, 200))
- self.pre_move()
- self.move(pos_m, force_move=True)
- pos_m = screen.convert_abs_to_monitor((-100, 200))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._pather.traverse_nodes([226], self, timeout=2.5, force_tp=True, use_tp_charge=True)
- pos_m = screen.convert_abs_to_monitor((0, 30))
+ # Move a bit back and another round
+ self._do_curse(.5)
+ self._trav_attack_sequence()
+ self._pather.traverse_nodes([229], self, timeout=2.2, do_pre_move=False, force_tp=True, use_tp_charge=True)
+ # Here we have two different attack sequences depending if tele is available or not
+ # Back to center stairs and more hammers
+ #self._pather.traverse_nodes([228], self, timeout=2.2, do_pre_move=False, force_tp=True, use_tp_charge=True)
+ self._pather.traverse_nodes([300], self, timeout=2.2, do_pre_move=False, force_tp=True, use_tp_charge=True)
+ pos_m = screen.convert_abs_to_monitor((50, -50))
self.walk(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0)
- wait(0.5)
- self.poison_nova(4.0)
- #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=2,cast_v_div=1,cast_spell='corpse_explosion',delay=3.0,offset=1.8)
- #wait(self._cast_duration, self._cast_duration +.2)
- #self.poison_nova(2.0)
- pos_m = screen.convert_abs_to_monitor((50, 0))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=5,cast_v_div=2,cast_spell='corpse_explosion',delay=0.5,offset=1.8)
- #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=9,cast_v_div=3,cast_spell='raise_skeleton',delay=1.2,offset=.8)
- #self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=9,cast_v_div=3,cast_spell='raise_mage',delay=1.2,offset=.8)
- pos_m = screen.convert_abs_to_monitor((-200, -200))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._pather.traverse_nodes([229], self, timeout=2.5, force_tp=True, use_tp_charge=True)
- pos_m = screen.convert_abs_to_monitor((20, -50))
+ self._do_curse(.5)
+ self._trav_attack_sequence()
+ self._pather.traverse_nodes([300], self, timeout=2.2, do_pre_move=False, force_tp=True, use_tp_charge=True)
+ #self._pather.traverse_nodes([228], self, timeout=2.2, do_pre_move=False, force_tp=True, use_tp_charge=True)
+ self._pather.traverse_nodes([228], self, timeout=2.2, do_pre_move=False, force_tp=True, use_tp_charge=True)
+ self._pather.traverse_nodes([226], self, timeout=2.2, do_pre_move=False, force_tp=True, use_tp_charge=True)
+ pos_m = screen.convert_abs_to_monitor((50, -50))
self.walk(pos_m, force_move=True)
- self.poison_nova(2.0)
- pos_m = screen.convert_abs_to_monitor((50, 0))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=120,cast_div=5,cast_v_div=2,cast_spell='corpse_explosion',delay=3.0,offset=1.8)
- pos_m = screen.convert_abs_to_monitor((-30, -20))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell='raise_skeleton',delay=1.2,offset=.8)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell='raise_mage',delay=1.2,offset=.8)
+ self._do_curse(.5)
+ self._trav_attack_sequence()
+ # move a bit to the top
+
return True
def kill_nihlathak(self, end_nodes: list[int]) -> bool:
+ self.bone_armor()
# Move close to nihlathak
self._pather.traverse_nodes(end_nodes, self, timeout=0.8, do_pre_move=True)
- pos_m = screen.convert_abs_to_monitor((20, 20))
- self.walk(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0)
- self.poison_nova(3.0)
- pos_m = screen.convert_abs_to_monitor((50, 0))
- self.pre_move()
- self.move(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=7200,cast_div=2,cast_v_div=2,cast_spell='corpse_explosion',delay=3.0,offset=1.8)
- wait(self._cast_duration, self._cast_duration +.2)
- self.poison_nova(3.0)
+ self._do_curse(.5)
+ self._nihl_attack_sequence()
return True
def kill_summoner(self) -> bool:
# Attack
- pos_m = screen.convert_abs_to_monitor((0, 30))
- self.walk(pos_m, force_move=True)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=4,cast_v_div=3,cast_spell='lower_res',delay=1.0)
- wait(0.5)
- self.poison_nova(3.0)
- pos_m = screen.convert_abs_to_monitor((50, 0))
- self.pre_move()
- self.move(pos_m, force_move=True)
- wait(self._cast_duration, self._cast_duration + 0.2)
- self._cast_circle(cast_dir=[-1,1],cast_start_angle=0,cast_end_angle=360,cast_div=10,cast_v_div=4,cast_spell='raise_mage',delay=1.2,offset=.8)
+ pos_m = convert_abs_to_monitor((0, 20))
+ mouse.move(*pos_m, randomize=80, delay_factor=[0.5, 0.7])
+ # Attack
+ self._do_curse(.5)
+ self.poison_nova(Config().char["atk_len_arc"])
+ # Move a bit back and another round
return True
From 119e05990ae92bd3dae19797489cdaa31da17cfe Mon Sep 17 00:00:00 2001
From: Legit <96157236+D2RLegit@users.noreply.github.com>
Date: Thu, 30 Jun 2022 02:01:38 -0500
Subject: [PATCH 2/5] option for only poison or only cold mob detect
added optional only poison or only cold mob detect
---
src/target_detect.py | 81 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 81 insertions(+)
diff --git a/src/target_detect.py b/src/target_detect.py
index 914bd7143..78573eb77 100644
--- a/src/target_detect.py
+++ b/src/target_detect.py
@@ -14,6 +14,14 @@
{"erode": 1, "blur": 3, "lh": 110, "ls": 169, "lv": 50, "uh": 120, "us": 255, "uv": 255} # frozen
]
+FILTER_GREEN_RANGES=[
+ {"erode": 1, "blur": 3, "lh": 38, "ls": 169, "lv": 50, "uh": 70, "us": 255, "uv": 255}, # poison
+]
+
+FILTER_BLUE_RANGES=[
+ {"erode": 1, "blur": 3, "lh": 110, "ls": 169, "lv": 50, "uh": 120, "us": 255, "uv": 255} # frozen
+]
+
@dataclass
class TargetInfo:
roi: tuple = None
@@ -69,6 +77,79 @@ def get_visible_targets(
targets = sorted(targets, key=lambda obj: obj.distance)
return targets
+def get_visible_green_targets(
+ img: np.ndarray = None,
+ radius_min: int = 150,
+ radius_max: int = 1280,
+ ignore_roi: list[int] = [600, 300, (1280/2 - 600)*2, (720/2 - 300)*2],
+ use_radius: bool = False
+) -> list[TargetInfo]:
+ """
+ :param img: The image to find targets in
+ :param radius_min: The minimum radius of the target [Default: 150, Integer 0 - 1280]
+ :param radius_max: The maximum radius of the target [Default: 1280, Integer 0 - 1280]
+ :param ignore_roi: The region of interest to ignore [Default: [600, 300, (1280/2 - 600)*2, (720/2 - 300)*2]]
+ :param use_radius: Whether to use the radius of the target (True) or the ignore_roi parameter (False)
+ Returns a list of TargetInfo objects
+ """
+ img = grab() if img is None else img
+ targets = []
+ for filter in FILTER_GREEN_RANGES:
+ filterimage, threshz = _process_image(img, mask_char=True, mask_hud=True, **filter) # HSV Filter for BLUE Only (Holy Freeze)
+ filterimage, rectangles, positions = _add_markers(filterimage, threshz, rect_min_size=100, rect_max_size=200, marker=True) # rather large rectangles
+ if positions:
+ for cnt, position in enumerate(positions):
+ distance = _dist_to_center(position)
+ condition = (radius_min <= distance <= radius_max) if use_radius else (not is_in_roi(ignore_roi, position))
+ if condition:
+ targets.append(TargetInfo(
+ roi = rectangles[cnt],
+ center = position,
+ center_monitor = convert_screen_to_monitor(position),
+ center_abs = convert_screen_to_abs(position),
+ distance = distance
+ ))
+ if targets:
+ targets = sorted(targets, key=lambda obj: obj.distance)
+ return targets
+
+def get_visible_blue_targets(
+ img: np.ndarray = None,
+ radius_min: int = 150,
+ radius_max: int = 1280,
+ ignore_roi: list[int] = [600, 300, (1280/2 - 600)*2, (720/2 - 300)*2],
+ use_radius: bool = False
+) -> list[TargetInfo]:
+ """
+ :param img: The image to find targets in
+ :param radius_min: The minimum radius of the target [Default: 150, Integer 0 - 1280]
+ :param radius_max: The maximum radius of the target [Default: 1280, Integer 0 - 1280]
+ :param ignore_roi: The region of interest to ignore [Default: [600, 300, (1280/2 - 600)*2, (720/2 - 300)*2]]
+ :param use_radius: Whether to use the radius of the target (True) or the ignore_roi parameter (False)
+ Returns a list of TargetInfo objects
+ """
+ img = grab() if img is None else img
+ targets = []
+ for filter in FILTER_BLUE_RANGES:
+ filterimage, threshz = _process_image(img, mask_char=True, mask_hud=True, **filter) # HSV Filter for BLUE Only (Holy Freeze)
+ filterimage, rectangles, positions = _add_markers(filterimage, threshz, rect_min_size=100, rect_max_size=200, marker=True) # rather large rectangles
+ if positions:
+ for cnt, position in enumerate(positions):
+ distance = _dist_to_center(position)
+ condition = (radius_min <= distance <= radius_max) if use_radius else (not is_in_roi(ignore_roi, position))
+ if condition:
+ targets.append(TargetInfo(
+ roi = rectangles[cnt],
+ center = position,
+ center_monitor = convert_screen_to_monitor(position),
+ center_abs = convert_screen_to_abs(position),
+ distance = distance
+ ))
+ if targets:
+ targets = sorted(targets, key=lambda obj: obj.distance)
+ return targets
+
+
def _bright_contrast(img: np.ndarray, brightness: int = 255, contrast: int = 127):
"""
:param img: The image to which filters should be applied
From db940fa18d9fc6b4959e44d1c531015a5d975d9a Mon Sep 17 00:00:00 2001
From: Legit <96157236+D2RLegit@users.noreply.github.com>
Date: Thu, 30 Jun 2022 02:07:57 -0500
Subject: [PATCH 3/5] cleanup of uneeded skills
---
src/char/poison_necro.py | 29 +----------------------------
1 file changed, 1 insertion(+), 28 deletions(-)
diff --git a/src/char/poison_necro.py b/src/char/poison_necro.py
index cf950dfc0..3ae587896 100644
--- a/src/char/poison_necro.py
+++ b/src/char/poison_necro.py
@@ -81,18 +81,6 @@ def _clay_golem(self):
mouse.click(button="right")
wait(self._cast_duration)
- def amp_dmg(self, hork_time: int):
- wait(0.5)
- if self._skill_hotkeys["amp_dmg"]:
- keyboard.send(self._skill_hotkeys["amp_dmg"])
- wait(0.5, 0.15)
- pos_m = convert_abs_to_monitor((0, -20))
- mouse.move(*pos_m)
- wait(0.5, 0.15)
- mouse.press(button="right")
- wait(hork_time)
- mouse.release(button="right")
-
def bone_armor(self):
if self._skill_hotkeys["bone_armor"]:
keyboard.send(self._skill_hotkeys["bone_armor"])
@@ -113,7 +101,6 @@ def _bone_armor(self):
wait(self._cast_duration)
-
def _left_attack(self, cast_pos_abs: tuple[float, float], spray: int = 10):
keyboard.send(Config().char["stand_still"], do_release=False)
if self._skill_hotkeys["skill_left"]:
@@ -154,21 +141,7 @@ def _do_curse(self, hork_time: int):
wait(0.05, 0.15)
mouse.press(button="right")
wait(hork_time)
- mouse.release(button="right")
-
- def _force_teleport(self, cast_pos_abs: tuple[float, float], spray: float = 10):
- if not self._skill_hotkeys["force_teleport"]:
- raise ValueError("You did not set a hotkey for force_teleport!")
- keyboard.send(self._skill_hotkeys["force_teleport"])
- x = cast_pos_abs[0] + (random.random() * 2 * spray - spray)
- y = cast_pos_abs[1] + (random.random() * 2 * spray - spray)
- cast_pos_monitor = convert_abs_to_monitor((x, y))
- mouse.move(*cast_pos_monitor)
- click_tries = random.randint(2, 4)
- for _ in range(click_tries):
- mouse.press(button="right")
- wait(0.09, 0.12)
- mouse.release(button="right")
+ mouse.release(button="right")
def _raise_skeleton(self, cast_pos_abs: tuple[float, float], spray: float = 10):
if not self._skill_hotkeys["raise_skeleton"]:
From aef8190e655ef4ecfed60f2851b263787bc962f0 Mon Sep 17 00:00:00 2001
From: Legit <96157236+D2RLegit@users.noreply.github.com>
Date: Thu, 30 Jun 2022 02:09:40 -0500
Subject: [PATCH 4/5] Renamed lower_res to curse
---
config/params.ini | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/config/params.ini b/config/params.ini
index 21d5949ee..fbaa5f01c 100644
--- a/config/params.ini
+++ b/config/params.ini
@@ -249,8 +249,8 @@ clay_golem=
clear_pindle_pack=
corpse_explosion=
heart_of_wolverine=
-# Can Use any curse
-lower_res=
+# Can Use any curse but will likely want Lower resist
+curse=
poison_nova=
raise_mage=
raise_revive=
From 3b693281b7bbc0388ab28388d943e9c4ecad3778 Mon Sep 17 00:00:00 2001
From: Legit <96157236+D2RLegit@users.noreply.github.com>
Date: Thu, 30 Jun 2022 12:03:15 -0500
Subject: [PATCH 5/5] Add files via upload
---
assets/hud_mask.png | Bin 9552 -> 13450 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/assets/hud_mask.png b/assets/hud_mask.png
index 36d9c912dbd8172506a928cfb9a8164ce1e5d6d7..b6adcb563febfd624cd094b829718e2f49ca9f74 100644
GIT binary patch
literal 13450
zcmeHOc|6ql|NoGR6n3lan`{kj(Q3xr7ZW9m3WcaGH0D5I#>}`CU90WTp;8oTmG5+r
za_6k=SaRlAD@QqE3MEJ6_`N=qZ{PiW_gjzOciZppkLDpWX5OFo`*l2Duh;YS`b
f(Vc<>}_jGu?QrB39r$&^|UZ!OC;M^
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
AivR!s
literal 9552
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