Resolve merge conflicts, keeping local Win10 specific changes
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
"VSync": 1,
|
||||
"Framerate Cap": 60,
|
||||
"Framerate Target": 0,
|
||||
"Window Mode": 0,
|
||||
"Window Mode": 1,
|
||||
"Graphic Presets": 4,
|
||||
"Texture Quality": 4,
|
||||
"Texture Anisotropy": 0,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -100,8 +100,7 @@ mana_slice=961,610,7,101
|
||||
cut_skill_bar=0,0,1280,653
|
||||
reduce_to_center=120,60,1040,540
|
||||
search_npcs=120,0,1040,620
|
||||
merc_icon=5,5,60,60
|
||||
merc_panel=0,0,450,100
|
||||
merc_icon=10,9,56,56
|
||||
loading_left_black=0,0,350,720
|
||||
death=444,198,397,71
|
||||
tp_search=353,120,547,400
|
||||
|
||||
@@ -8,19 +8,9 @@
|
||||
; bnet_pass=${BOTTY_BNET_PASS}
|
||||
; char_name=${BOTTY_CHAR_NAME}
|
||||
; difficulty: game difficulty to create ("normal", "nightmare", "hell")
|
||||
;
|
||||
; Hammerdin difficulty guide (CTA build with Conviction aura):
|
||||
; NORMAL - Very easy. 1-2h Hammer kills most packs. No CTA needed.
|
||||
; NIGHTMARE - Recommended starting point. Bosses hit ~100-200 dmg.
|
||||
; CTA + Conviction drops resists. Need decent armor (ED/HR).
|
||||
; Gear targets: ~200 AR, ~15 ED, ~30% HR, ~50% FCR on hammer.
|
||||
; HELL - Bosses hit 400-800+ dmg per swing. Conviction is mandatory.
|
||||
; Gear targets: ~350+ AR, ~20+ ED, ~50%+ HR, ~60%+ FCR,
|
||||
; ~150% IAS on weapon. Full Rejuv belt recommended.
|
||||
; If you chicken/die repeatedly, drop to Nightmare first.
|
||||
difficulty=nightmare
|
||||
difficulty=hell
|
||||
; name: bot profile name used in logs/messages and mod launch option replacement
|
||||
name=fistman
|
||||
name=fiskenersej
|
||||
; randomize_runs: 0 = run in listed order, 1 = shuffle run order
|
||||
randomize_runs=0
|
||||
; target_tz: target Terror Zone id (leave as default unless you know the mapping)
|
||||
@@ -32,7 +22,7 @@ level_max_steps=20
|
||||
|
||||
; Set to 1 to enable auto-login and auto-launch of D2R on startup.
|
||||
; Credentials below are ONLY used when auto_login=1.
|
||||
auto_login=1
|
||||
auto_login=0
|
||||
bnet_name=${BOTTY_BNET_NAME}
|
||||
bnet_pass=${BOTTY_BNET_PASS}
|
||||
|
||||
@@ -42,13 +32,13 @@ char_name=${BOTTY_CHAR_NAME}
|
||||
|
||||
; messaging
|
||||
; custom_loot_message_hook: optional separate webhook for loot notifications
|
||||
custom_loot_message_hook=${BOTTY_CUSTOM_LOOT_MESSAGE_HOOK}
|
||||
custom_loot_message_hook=https://discord.com/api/webhooks/1510992232939913297/20rbnGmpTWMKBBL6JN0JaE897jLGOmHl6zclJ1AO82o2dtD67YHfAKMD-e4G8DWvUOXV
|
||||
; custom_message_hook: main webhook for status/death/chicken messages
|
||||
custom_message_hook=${BOTTY_CUSTOM_MESSAGE_HOOK}
|
||||
custom_message_hook=https://discord.com/api/webhooks/1510992232939913297/20rbnGmpTWMKBBL6JN0JaE897jLGOmHl6zclJ1AO82o2dtD67YHfAKMD-e4G8DWvUOXV
|
||||
; discord_log_chicken: 1 = send chicken/death style notifications
|
||||
discord_log_chicken=1
|
||||
; discord_status_runs: send periodic status every X completed runs (blank/0 disables)
|
||||
discord_status_runs=10
|
||||
discord_status_runs=100
|
||||
; discord_status_count: legacy fallback, send periodic status every X games (blank/0 disables)
|
||||
discord_status_count=20
|
||||
; message_api_type: "" disables messaging, "discord" or "generic_api"
|
||||
@@ -66,14 +56,10 @@ d2r_path=C:\Program Files (x86)\Diablo II Resurrected
|
||||
; max_consecutive_fails: stop bot after this many failed runs in a row
|
||||
max_consecutive_fails=5
|
||||
; max_game_length_s: emergency timeout per run/game
|
||||
max_game_length_s=600
|
||||
; auto_downgrade_threshold: if combined chickens+deaths exceed this number within 1 hour,
|
||||
; bot automatically lowers difficulty by one tier (hell->nightmare->normal) and restarts.
|
||||
; Set to 0 to disable.
|
||||
auto_downgrade_threshold=40
|
||||
max_game_length_s=160
|
||||
|
||||
; if you set this field to 1, botty will attempt to restart d2 after a crash or failure
|
||||
restart_d2r_when_stuck=1
|
||||
restart_d2r_when_stuck=0
|
||||
; hardcore: 1 enables hardcore-safe assumptions in some routines
|
||||
hardcore=0
|
||||
|
||||
@@ -181,7 +167,7 @@ skill_mistake_chance = 0.015
|
||||
; run_countess (Act 1 Forgotten Tower)
|
||||
; run_mephisto (Act 3 Durance of Hate)
|
||||
; run_baal (Act 5 Throne of Destruction)
|
||||
order=run_pindle, run_eldritch_shenk, run_nihlathak, run_arcane, run_diablo, run_vizier, run_trav
|
||||
order=run_trav
|
||||
|
||||
[char]
|
||||
; ==========================
|
||||
@@ -194,9 +180,9 @@ type=hammerdin
|
||||
; belt_rows: in-game belt size (2/3/4)
|
||||
belt_rows=4
|
||||
; casting_frames: your char cast breakpoint (affects action timing)
|
||||
casting_frames=8
|
||||
casting_frames=11
|
||||
; cta_casting_frames: cast breakpoint on CTA swap (if used)
|
||||
cta_casting_frames=8
|
||||
cta_casting_frames=11
|
||||
; attack_frames: base attack animation timing for non-cast attacks
|
||||
attack_frames=15
|
||||
; cta_available: 1 if Call to Arms swap exists, else 0
|
||||
@@ -225,13 +211,13 @@ show_items=alt
|
||||
; stand_still cannot be the default "shift" as it would interfere with merc healing
|
||||
stand_still=capslock
|
||||
; teleport: leave empty if you can't use
|
||||
teleport=b
|
||||
town_portal=6
|
||||
teleport=f4
|
||||
town_portal=f8
|
||||
; call to arms settings:
|
||||
; weapon_switch/battle_orders/battle_command only used when cta_available=1
|
||||
weapon_switch=w
|
||||
battle_orders=7
|
||||
battle_command=8
|
||||
battle_orders=f6
|
||||
battle_command=f5
|
||||
|
||||
; ==========================
|
||||
; ==== Optional configs ====
|
||||
@@ -240,43 +226,13 @@ stash_gold=1
|
||||
use_merc=1
|
||||
|
||||
; Attack length for barbarians should be as high as 8-10 and even 10-12 for trav/shenk
|
||||
;
|
||||
; Hammerdin attack lengths (seconds of hammer spam per boss):
|
||||
; atk_len_trav = 3.0 (Council of 3 - 3 council members, easy)
|
||||
; atk_len_pindle = 8.0 (Pindle + Eldritch + Shenk - longest fight)
|
||||
; Pindle stats by difficulty:
|
||||
; Normal: 1064-1588 HP, 75% fire, 70% poison
|
||||
; Nightmare: 4773-5859 HP, 100% poison
|
||||
; Hell: 13094-16070 HP, 75% fire, 50% cold, 33% light, 100% poison
|
||||
; With Conviction (-33% res), Hell Pindle = 50% fire, 17% cold, 0% light, 67% poison
|
||||
; CTA adds +100% dmg to hammer. Need ~60%+ FCR and good IAS to kill in 8s.
|
||||
; atk_len_nihlathak = 4.0 (Nihlathak - single boss)
|
||||
; atk_len_eldritch = 3.0 (Eldritch only - single boss)
|
||||
; atk_len_shenk = 4.0 (Shenk only - single boss)
|
||||
; atk_len_arc = 2.5 (Summoner in Arcane - single boss)
|
||||
; atk_len_diablo = 10.0 (Diablo in CS - longest single boss)
|
||||
; atk_len_countess = 3.0 (Countess - single boss, easy)
|
||||
; atk_len_andariel = 4.0 (Andariel - single boss)
|
||||
; atk_len_mephisto = 12.0 (Mephisto - single boss, high HP)
|
||||
; atk_len_baal = 10.0 (Baal - single boss)
|
||||
; atk_len_baal_waves = 30.0 (Baal's spawn waves before boss)
|
||||
;
|
||||
; Chaos Sanctuary (Diablo run) individual fights:
|
||||
; atk_len_cs_trashmobs = 2.0 (Trash packs in CS)
|
||||
; atk_len_diablo_vizier = 2.0 (Vizier of Chaos - seal boss A)
|
||||
; atk_len_diablo_infector = 4.0 (Infector of Souls - seal boss C)
|
||||
; atk_len_diablo_deseis = 5.0 (Lord De Seis - seal boss B, hardest seal)
|
||||
;
|
||||
; Increase these if your hammer kills slower (low IAS/FCR).
|
||||
; Decrease if your hammer kills faster (high IAS/FCR, good gear).
|
||||
; If you die during a fight, the attack length is too long for your defense.
|
||||
atk_len_arc=2.5
|
||||
atk_len_eldritch=3.0
|
||||
atk_len_nihlathak=4.0
|
||||
atk_len_pindle=8.0
|
||||
atk_len_pindle=3.0
|
||||
atk_len_shenk=4.0
|
||||
atk_len_diablo=10.0
|
||||
atk_len_trav=3.0
|
||||
atk_len_diablo=3.0
|
||||
atk_len_trav=5.0
|
||||
|
||||
; Boss run attack lengths (per-character defaults in kill_* methods)
|
||||
; Adjust these if your build is faster/slower against these bosses
|
||||
@@ -302,14 +258,14 @@ belt_mp_columns=1
|
||||
belt_rejuv_columns=2
|
||||
|
||||
; Potion/chicken settings
|
||||
take_health_potion=0.95
|
||||
take_mana_potion=0.90
|
||||
take_rejuv_potion_health=0.80
|
||||
take_rejuv_potion_mana=0.55
|
||||
heal_merc=0.85
|
||||
heal_rejuv_merc=0.55
|
||||
chicken=0.50
|
||||
merc_chicken=0.20
|
||||
take_health_potion=0.60
|
||||
take_mana_potion=0.40
|
||||
take_rejuv_potion_health=0.40
|
||||
take_rejuv_potion_mana=0.10
|
||||
heal_merc=0.60
|
||||
heal_rejuv_merc=0.25
|
||||
chicken=0.45
|
||||
merc_chicken=0.25
|
||||
|
||||
; Misc.
|
||||
; helps reduce accidental pickups when enabled especially on walking characters
|
||||
@@ -319,24 +275,24 @@ fill_shared_stash_first=0
|
||||
; to gamble, add any/all of the following: circlet, ring, coronet, talon, amulet
|
||||
gamble_items=
|
||||
; open_chests: 1 = open clickable chests along path when possible
|
||||
open_chests=1
|
||||
open_chests=0
|
||||
; pre_buff_every_run: 1 = always recast buffs at run start
|
||||
pre_buff_every_run=0
|
||||
; runs_per_repair: visit repair vendor every X runs (blank/0 disables)
|
||||
runs_per_repair=5
|
||||
runs_per_repair=2000
|
||||
; repair_npc: preferred repair vendor strategy.
|
||||
; - a4_halbu (recommended, most stable)
|
||||
; - a5_larzuk (faster when templates are reliable)
|
||||
repair_npc=a4_halbu
|
||||
; runs_per_stash: stash/sell every X runs (blank/0 disables)
|
||||
runs_per_stash=4
|
||||
runs_per_stash=1
|
||||
; sell_junk: 1 = vendor non-keep items automatically
|
||||
sell_junk=1
|
||||
sell_junk=0
|
||||
; protect_shields_from_sell: 1 = never vendor items with "shield" in detected name (recommended safety)
|
||||
protect_shields_from_sell=1
|
||||
; pick_rares_for_gold: 1 = pick all yellow (rare) ground items; non-keep rares will be sold
|
||||
; Requires sell_junk=1 to convert extra pickups into gold.
|
||||
pick_rares_for_gold=0
|
||||
pick_rares_for_gold=1
|
||||
; pick_gold: 1 = pick up ground gold piles, 0 = ignore all ground gold
|
||||
pick_gold=1
|
||||
|
||||
@@ -347,12 +303,12 @@ stash_destination=3,2,1,0
|
||||
; chipped, flawed, standard, flawless
|
||||
transmute=flawless
|
||||
;how often we want to run transmute routine(e.g. every 100 games)
|
||||
transmute_every_x_game=2000
|
||||
transmute_every_x_game=500
|
||||
; number of stash tabs (ROTW has more than 6, adjust as needed)
|
||||
stash_tabs=6
|
||||
; potion transmute settings
|
||||
; convert_rejuv: 1 = convert regular Rejuv Potions to Full Rejuv via cube (3 -> 1)
|
||||
convert_rejuv=1
|
||||
convert_rejuv=0
|
||||
; min_rejuv_to_convert: minimum regular rejuv potions in inventory before starting conversion
|
||||
min_rejuv_to_convert=6
|
||||
|
||||
@@ -402,23 +358,22 @@ hydra=f1
|
||||
; ==== Builds: Paladin ====
|
||||
; =========================
|
||||
[paladin]
|
||||
cleansing=f9
|
||||
holy_shield=f2
|
||||
redemption=f3
|
||||
vigor=f4
|
||||
cleansing=f2
|
||||
holy_shield=f7
|
||||
redemption=
|
||||
vigor=f3
|
||||
|
||||
[fohdin]
|
||||
; foh must be left skill, hotkey required
|
||||
blessed_hammer=f1
|
||||
concentration=f8
|
||||
conviction=f5
|
||||
blessed_hammer=f9
|
||||
concentration=f1
|
||||
conviction=
|
||||
foh=f6
|
||||
holy_bolt=f7
|
||||
|
||||
[hammerdin]
|
||||
blessed_hammer=f1
|
||||
concentration=f8
|
||||
conviction=f5
|
||||
blessed_hammer=f9
|
||||
concentration=f1
|
||||
|
||||
; =========================
|
||||
; ==== Builds: Warlock ====
|
||||
@@ -576,13 +531,13 @@ buff_2=
|
||||
; select_runs_key: open run selector UI
|
||||
select_runs_key=pagedown
|
||||
; restore_settings_from_backup_key: restore backed-up D2R settings
|
||||
restore_settings_from_backup_key=insert
|
||||
restore_settings_from_backup_key=f10
|
||||
; settings_backup_key: create backup of current D2R settings
|
||||
settings_backup_key=pause
|
||||
; auto_settings_key: auto-apply required D2R settings
|
||||
auto_settings_key=pageup
|
||||
; graphic_debugger_key: toggle on-screen debug layers
|
||||
graphic_debugger_key=delete
|
||||
graphic_debugger_key=insert
|
||||
; resume_key: start/pause bot loop
|
||||
resume_key=f11
|
||||
; exit_key: hard stop bot
|
||||
@@ -606,7 +561,7 @@ message_headers=
|
||||
; ocr_during_pickit: 1 = run OCR while looting (slower, more diagnostics)
|
||||
ocr_during_pickit=0
|
||||
;use "can_teleport_natively" or "can_teleport_with_charges" if you want to force certain behavior in case autodetection isn't working properly
|
||||
override_capabilities=can_teleport_natively
|
||||
override_capabilities=
|
||||
; pathing_delay_factor: movement/click delay multiplier (1 fast .. 10 slow)
|
||||
pathing_delay_factor=2
|
||||
; If you want to control Hyper-V window from host use 0,51 here
|
||||
|
||||
BIN
debug_full_screen.png
Normal file
BIN
debug_full_screen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 MiB |
BIN
debug_merc_area.png
Normal file
BIN
debug_merc_area.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
BIN
debug_portal_search.png
Normal file
BIN
debug_portal_search.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 MiB |
BIN
debug_screen.png
Normal file
BIN
debug_screen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
BIN
debug_screen_full.png
Normal file
BIN
debug_screen_full.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
@@ -100,7 +100,7 @@ class IChar:
|
||||
return False
|
||||
else:
|
||||
mouse.move(pos[0], pos[1])
|
||||
wait(0.1, 0.12)
|
||||
wait(0.04, 0.06)
|
||||
mouse.click(button="left")
|
||||
|
||||
#Current logic only sets force_run if we previously teled.
|
||||
@@ -157,8 +157,7 @@ class IChar:
|
||||
while time.time() - check_success_start < 2:
|
||||
if success_func is None or success_func():
|
||||
return True
|
||||
elapsed = time.time() - start
|
||||
Logger.error(f"select_by_template: could not find {template_type} after {elapsed:.1f}s (timeout={timeout}s, threshold={threshold})")
|
||||
Logger.error(f"Wanted to select {template_type}, but could not find it")
|
||||
return False
|
||||
|
||||
def skill_is_charged(self, img: np.ndarray = None) -> bool:
|
||||
@@ -304,83 +303,56 @@ class IChar:
|
||||
return False
|
||||
|
||||
def _pre_buff_cta(self):
|
||||
"""Switch to CTA weapon, cast BC + BO, switch back to main.
|
||||
|
||||
Uses the BC skill-bar template to verify each weapon switch rather than
|
||||
blindly toggling — prevents the character from fighting with the wrong
|
||||
weapon after a chicken/death interrupted a previous buff cycle and saved
|
||||
the game with the CTA slot active.
|
||||
"""
|
||||
bc_hotkey = Config().char.get("battle_command")
|
||||
|
||||
if not bc_hotkey:
|
||||
# No hotkey configured → can't verify; fall back to unverified toggle
|
||||
Logger.warning("_pre_buff_cta: battle_command hotkey not set — using unverified weapon switch")
|
||||
# Check if we are already on CTA side
|
||||
if skills.is_right_skill_selected(["BC", "BO"]):
|
||||
keyboard.send(Config().char["weapon_switch"])
|
||||
wait(0.3, 0.35)
|
||||
self._select_skill(skill="battle_command", mouse_click_type="right", delay=(0.1, 0.2))
|
||||
wait(0.4, 0.45)
|
||||
|
||||
# Save current skill img
|
||||
skill_before = cut_roi(grab(), Config().ui_roi["skill_right"])
|
||||
# Try to switch weapons and select bo until we find the skill on the right skill slot
|
||||
start = time.time()
|
||||
switch_sucess = False
|
||||
while time.time() - start < 4:
|
||||
keyboard.send(Config().char["weapon_switch"])
|
||||
wait(0.4, 0.45)
|
||||
keyboard.send(Config().char["battle_command"])
|
||||
wait(0.2, 0.3)
|
||||
if skills.is_right_skill_selected(["BC", "BO"]):
|
||||
switch_sucess = True
|
||||
break
|
||||
else:
|
||||
Logger.warning("Failed to find Battle Command, swapping weapons again.")
|
||||
|
||||
if not switch_sucess:
|
||||
Logger.error("You dont have Battle Command bound, or you do not have CTA. Ending CTA buff")
|
||||
return False
|
||||
else:
|
||||
# We switched succesfully, let's pre buff
|
||||
mouse.click(button="right")
|
||||
wait(self._cta_cast_duration, self._cta_cast_duration)
|
||||
self._select_skill(skill="battle_orders", mouse_click_type="right", delay=(0.1, 0.2))
|
||||
self._select_skill(skill = "battle_orders", mouse_click_type="right", delay=(0.1, 0.2))
|
||||
mouse.click(button="right")
|
||||
wait(self._cta_cast_duration, self._cta_cast_duration)
|
||||
if Config().char["buff_with_cta"]:
|
||||
self.cast_buffs(self._cta_cast_duration)
|
||||
wait(0.08, 0.08)
|
||||
keyboard.send(Config().char["weapon_switch"])
|
||||
wait(0.3, 0.35)
|
||||
return True
|
||||
wait(0.08,0.08) #Give extra time after last cast to allow weapon switch to be available
|
||||
|
||||
# --- Step 1: ensure we start on the main weapon slot ---
|
||||
# If a previous run was interrupted mid-buff (chicken / death), D2R may have
|
||||
# saved with the CTA slot active. Detect that by pressing the BC hotkey and
|
||||
# checking if BC appears on the right skill bar.
|
||||
keyboard.send(bc_hotkey)
|
||||
wait(0.12, 0.18)
|
||||
if skills.is_right_skill_selected(["BC"]):
|
||||
Logger.warning("_pre_buff_cta: game started on CTA slot (leftover from interrupted buff) — correcting to main weapon")
|
||||
# Make sure the switch back to the original weapon is good
|
||||
start = time.time()
|
||||
switch_sucess = False
|
||||
while time.time() - start < 4:
|
||||
keyboard.send(Config().char["weapon_switch"])
|
||||
wait(0.45, 0.55)
|
||||
|
||||
# --- Step 2: switch TO CTA slot and verify ---
|
||||
keyboard.send(Config().char["weapon_switch"])
|
||||
wait(0.3, 0.35)
|
||||
keyboard.send(bc_hotkey)
|
||||
wait(0.12, 0.18)
|
||||
on_cta = skills.is_right_skill_selected(["BC"])
|
||||
if not on_cta:
|
||||
Logger.warning("_pre_buff_cta: switch to CTA slot failed — retrying")
|
||||
keyboard.send(Config().char["weapon_switch"])
|
||||
wait(0.45, 0.55)
|
||||
keyboard.send(bc_hotkey)
|
||||
wait(0.12, 0.18)
|
||||
on_cta = skills.is_right_skill_selected(["BC"])
|
||||
if not on_cta:
|
||||
Logger.error("_pre_buff_cta: could not confirm CTA slot after retry — casting Holy Shield from main and skipping CTA buffs")
|
||||
self.cast_buffs(self._cast_duration)
|
||||
return True # buffs cast from main; weapon slot is correct
|
||||
|
||||
# --- Step 3: cast BC (already selected above) then BO ---
|
||||
mouse.click(button="right")
|
||||
wait(self._cta_cast_duration, self._cta_cast_duration)
|
||||
self._select_skill(skill="battle_orders", mouse_click_type="right", delay=(0.1, 0.2))
|
||||
mouse.click(button="right")
|
||||
wait(self._cta_cast_duration, self._cta_cast_duration)
|
||||
if Config().char["buff_with_cta"]:
|
||||
self.cast_buffs(self._cta_cast_duration)
|
||||
wait(0.08, 0.08)
|
||||
|
||||
# --- Step 4: switch back to main weapon slot and verify ---
|
||||
keyboard.send(Config().char["weapon_switch"])
|
||||
wait(0.3, 0.35)
|
||||
if skills.is_right_skill_selected(["BC"]):
|
||||
Logger.warning("_pre_buff_cta: switch back to main failed — retrying")
|
||||
keyboard.send(Config().char["weapon_switch"])
|
||||
wait(0.45, 0.55)
|
||||
if skills.is_right_skill_selected(["BC"]):
|
||||
Logger.error("_pre_buff_cta: still on CTA slot after retry — CHARACTER WILL FIGHT WITH WRONG WEAPON")
|
||||
# Buffs are cast; return True so pre_buff() doesn't skip Holy Shield entirely.
|
||||
return True
|
||||
wait(0.4, 0.45)
|
||||
skill_after = cut_roi(grab(), Config().ui_roi["skill_right"])
|
||||
_, max_val, _, _ = cv2.minMaxLoc(cv2.matchTemplate(skill_after, skill_before, cv2.TM_CCOEFF_NORMED))
|
||||
if max_val > 0.8:
|
||||
switch_sucess = True
|
||||
break
|
||||
else:
|
||||
Logger.warning("Failed to switch weapon, try again")
|
||||
wait(0.5)
|
||||
return switch_sucess
|
||||
|
||||
|
||||
def vec_to_monitor(self, target):
|
||||
|
||||
@@ -14,7 +14,7 @@ class DeathManager:
|
||||
def __init__(self):
|
||||
self._died = False
|
||||
self._do_monitor = False
|
||||
self._loop_delay = 1.0
|
||||
self._loop_delay = 0.5
|
||||
self._callback = None
|
||||
self._last_death_screenshot = None
|
||||
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import cv2
|
||||
import time
|
||||
import random
|
||||
from threading import Lock
|
||||
from inventory import belt
|
||||
from pather import Location
|
||||
import cv2
|
||||
from threading import Lock
|
||||
import time
|
||||
from input_layer import keyboard
|
||||
from input_layer import mouse
|
||||
from utils.misc import wait
|
||||
from logger import Logger
|
||||
from utils.log_rotation import safe_imwrite
|
||||
from screen import grab
|
||||
import time
|
||||
from config import Config
|
||||
from inventory import common
|
||||
from ui import view, meters
|
||||
from ui_manager import ScreenObjects, is_visible
|
||||
from random import uniform
|
||||
|
||||
|
||||
class HealthManager:
|
||||
@@ -92,104 +91,99 @@ class HealthManager:
|
||||
Logger.info("Start health monitoring")
|
||||
self._do_monitor = True
|
||||
self._did_chicken = False
|
||||
start = time.time()
|
||||
|
||||
lp_hp_potion_delay = 10.24
|
||||
lp_mp_potion_delay = 5.12
|
||||
lp_mp_potion_delay = 1.0
|
||||
merc_hp_potion_delay = 10.24
|
||||
|
||||
while self._do_monitor:
|
||||
if self._did_chicken or self.get_pause_state():
|
||||
wait(1)
|
||||
wait(0.5, 0.7)
|
||||
continue
|
||||
fn_start = time.perf_counter()
|
||||
img = grab()
|
||||
if is_visible(ScreenObjects.InGame, img):
|
||||
health_percentage = meters.get_health(img)
|
||||
mana_percentage = meters.get_mana(img)
|
||||
|
||||
try:
|
||||
fn_start = time.perf_counter()
|
||||
img = grab()
|
||||
if is_visible(ScreenObjects.InGame, img):
|
||||
health_percentage = meters.get_health(img)
|
||||
mana_percentage = meters.get_mana(img)
|
||||
|
||||
# check rejuv first
|
||||
success_drink_rejuv = False
|
||||
last_drink = time.time() - self._last_rejuv
|
||||
#It seems that hit recovery can delay the use of juvs and 15 frames is max recovery time.
|
||||
#To delay two juvs being used back to back, we'll need to wait the recovery time between uses.
|
||||
#15 frames is 0.60 seconds.
|
||||
if last_drink > 0.60:
|
||||
if (health_percentage <= Config().char["take_rejuv_potion_health"]) or \
|
||||
(mana_percentage <= Config().char["take_rejuv_potion_mana"]):
|
||||
# Simulate human reaction time (100-300ms)
|
||||
wait(0.1, 0.3)
|
||||
success_drink_rejuv = belt.drink_potion("rejuv", stats=[health_percentage, mana_percentage])
|
||||
#failure to drink juv (likely out of juvs). Perform chicken
|
||||
if not success_drink_rejuv:
|
||||
Logger.warning(f"Failed to drink rejuv. Trying to chicken, player HP {(health_percentage*100):.1f}%!")
|
||||
self._do_chicken(img)
|
||||
continue
|
||||
self._last_rejuv = time.time()
|
||||
# check rejuv first
|
||||
success_drink_rejuv = False
|
||||
last_drink = time.time() - self._last_rejuv
|
||||
if last_drink > 0.60:
|
||||
if (health_percentage <= Config().char["take_rejuv_potion_health"]) or \
|
||||
(mana_percentage <= Config().char["take_rejuv_potion_mana"]):
|
||||
# Critical: Reduce delay to minimum
|
||||
wait(0.02, 0.05)
|
||||
success_drink_rejuv = belt.drink_potion("rejuv", stats=[health_percentage, mana_percentage])
|
||||
if not success_drink_rejuv:
|
||||
Logger.warning(f"Failed to drink rejuv. Trying to chicken, player HP {(health_percentage*100):.1f}%!")
|
||||
self._do_chicken(img)
|
||||
continue
|
||||
self._last_rejuv = time.time()
|
||||
|
||||
#if we drink two juvs within 8 seconds of one another AND HP is still low, may be in bad state. Perform chicken
|
||||
# Only chicken on rapid double-rejuv if HP was the actual trigger (not just mana).
|
||||
# Hammerdins spend mana fast — mana-triggered rejuvs can legitimately fire back-to-back.
|
||||
if last_drink < 8 and health_percentage <= Config().char["take_rejuv_potion_health"]:
|
||||
Logger.warning(f"Two juvs drank within {last_drink} seconds. Trying to chicken, player HP {(health_percentage*100):.1f}%!")
|
||||
self._do_chicken(img)
|
||||
continue
|
||||
if last_drink < 8:
|
||||
Logger.warning(f"Two juvs drank within {last_drink:.1f} seconds. Trying to chicken, player HP {(health_percentage*100):.1f}%!")
|
||||
self._do_chicken(img)
|
||||
continue
|
||||
|
||||
# Default chicken if health is below threshold.
|
||||
if health_percentage <= Config().char["chicken"]:
|
||||
Logger.warning(f"Trying to chicken, player HP {(health_percentage*100):.1f}%!")
|
||||
self._do_chicken(img)
|
||||
continue
|
||||
|
||||
# in case no rejuv was used, check for chicken, health pot and mana pot usage
|
||||
if not success_drink_rejuv:
|
||||
# check health
|
||||
last_drink = time.time() - self._last_health
|
||||
if health_percentage <= Config().char["take_health_potion"] and last_drink > lp_hp_potion_delay:
|
||||
wait(0.1, 0.3) # human reaction time
|
||||
belt.drink_potion("health", stats=[health_percentage, mana_percentage])
|
||||
self._last_health = time.time()
|
||||
# check mana
|
||||
last_drink = time.time() - self._last_mana
|
||||
if mana_percentage <= Config().char["take_mana_potion"] and last_drink > lp_mp_potion_delay:
|
||||
wait(0.1, 0.3) # human reaction time
|
||||
belt.drink_potion("mana", stats=[health_percentage, mana_percentage])
|
||||
self._last_mana = time.time()
|
||||
# check merc health and heal/chicken as needed
|
||||
if any([Config().char[x] for x in ["heal_rejuv_merc", "merc_chicken", "heal_merc"]]):
|
||||
merc_health = meters.get_merc_health(img)
|
||||
last_drink = time.time() - self._last_merc_heal
|
||||
# chicken if merc is too low
|
||||
if Config().char["merc_chicken"] and (merc_health < Config().char["merc_chicken"]):
|
||||
Logger.warning(f"Trying to chicken, merc HP {(merc_health*100):.1f}%!")
|
||||
if health_percentage <= Config().char["chicken"]:
|
||||
Logger.warning(f"Trying to chicken, player HP {(health_percentage*100):.1f}%!")
|
||||
self._do_chicken(img)
|
||||
continue
|
||||
# rejuv if merc is critically low
|
||||
if Config().char["heal_rejuv_merc"] and (merc_health < Config().char["heal_rejuv_merc"]) and (last_drink > 4.0):
|
||||
wait(0.1, 0.3) # human reaction time
|
||||
belt.drink_potion("rejuv", merc=True, stats=[merc_health])
|
||||
self._last_merc_heal = time.time()
|
||||
elif Config().char["heal_merc"] and (merc_health < Config().char["heal_merc"]) and (last_drink > merc_hp_potion_delay):
|
||||
wait(0.1, 0.3) # human reaction time
|
||||
belt.drink_potion("health", merc=True, stats=[merc_health])
|
||||
self._last_merc_heal = time.time()
|
||||
|
||||
if not success_drink_rejuv:
|
||||
# check health
|
||||
last_drink = time.time() - self._last_health
|
||||
if health_percentage <= Config().char["take_health_potion"] and last_drink > lp_hp_potion_delay:
|
||||
wait(0.05, 0.1)
|
||||
if belt.drink_potion("health", stats=[health_percentage, mana_percentage]):
|
||||
self._last_health = time.time()
|
||||
# check mana
|
||||
last_drink = time.time() - self._last_mana
|
||||
if mana_percentage <= Config().char["take_mana_potion"] and last_drink > lp_mp_potion_delay:
|
||||
wait(0.05, 0.1)
|
||||
if belt.drink_potion("mana", stats=[health_percentage, mana_percentage]):
|
||||
self._last_mana = time.time()
|
||||
# check merc health
|
||||
if any([Config().char[x] for x in ["heal_rejuv_merc", "merc_chicken", "heal_merc"]]):
|
||||
merc_health = meters.get_merc_health(img)
|
||||
last_drink = time.time() - self._last_merc_heal
|
||||
if Config().char["merc_chicken"] and (merc_health < Config().char["merc_chicken"]):
|
||||
Logger.warning(f"Trying to chicken, merc HP {(merc_health*100):.1f}%!")
|
||||
self._do_chicken(img)
|
||||
continue
|
||||
if Config().char["heal_rejuv_merc"] and (merc_health < Config().char["heal_rejuv_merc"]) and (last_drink > 4.0):
|
||||
wait(0.05, 0.1)
|
||||
if belt.drink_potion("rejuv", merc=True, stats=[merc_health]):
|
||||
self._last_merc_heal = time.time()
|
||||
elif Config().char["heal_merc"] and (merc_health < Config().char["heal_merc"]) and (last_drink > merc_hp_potion_delay):
|
||||
wait(0.05, 0.1)
|
||||
if belt.drink_potion("health", merc=True, stats=[merc_health]):
|
||||
self._last_merc_heal = time.time()
|
||||
|
||||
# Close any open panels that might block detection
|
||||
if not self.get_panel_check_paused() and (is_visible(ScreenObjects.LeftPanel, img) or is_visible(ScreenObjects.RightPanel, img)):
|
||||
Logger.warning(f"Found an open inventory / quest / skill / stats page. Close it.")
|
||||
self._count_panel_detects += 1
|
||||
if self._count_panel_detects >= 2:
|
||||
self._count_panel_detects = 0
|
||||
Logger.warning(f"Found an open inventory / quest / skill / stats page again. Chicken to dismiss.")
|
||||
Logger.warning(f"Found open panels (inv/quest/stats) twice. Chickening to be safe.")
|
||||
self._do_chicken(img)
|
||||
continue
|
||||
Logger.debug("Found an open panel. Closing it.")
|
||||
common.close()
|
||||
fn_end = time.perf_counter()
|
||||
# Add timing jitter to avoid perfectly regular polling pattern (anti-cheat)
|
||||
import random
|
||||
base_wait = 3/25 - (fn_end - fn_start)
|
||||
jitter = random.uniform(0.8, 1.2) # ±20% jitter
|
||||
wait_time = max(0.0, base_wait * jitter)
|
||||
if wait_time > 0:
|
||||
wait(wait_time) # wait ~3 frames before rechecking
|
||||
|
||||
fn_end = time.perf_counter()
|
||||
# Target ~15 FPS polling with anti-cheat jitter
|
||||
base_wait = 1/15 - (fn_end - fn_start)
|
||||
wait_time = max(0.01, base_wait * random.uniform(0.8, 1.2))
|
||||
wait(wait_time)
|
||||
|
||||
except Exception as e:
|
||||
Logger.error(f"HealthManager error: {e}")
|
||||
wait(0.5)
|
||||
|
||||
Logger.debug("Stop health monitoring")
|
||||
|
||||
|
||||
|
||||
@@ -260,15 +260,21 @@ class mouse:
|
||||
@staticmethod
|
||||
def click(button):
|
||||
if button != "left" or mouse._is_clicking_safe():
|
||||
try:
|
||||
from utils.stealth import apply_click_delay
|
||||
apply_click_delay()
|
||||
except Exception:
|
||||
from logger import Logger
|
||||
Logger.warning("[Stealth] apply_click_delay failed, falling back to manual delay")
|
||||
from utils.misc import wait as _wait
|
||||
_wait(0.05, 0.3)
|
||||
# DISABLED STEALTH FOR DEBUGGING
|
||||
# try:
|
||||
# from utils.stealth import apply_click_delay
|
||||
# apply_click_delay()
|
||||
# except Exception:
|
||||
# from logger import Logger
|
||||
# Logger.warning("[Stealth] apply_click_delay failed, falling back to manual delay")
|
||||
# from utils.misc import wait as _wait
|
||||
# _wait(0.05, 0.3)
|
||||
from logger import Logger
|
||||
Logger.debug(f"Executing native click: {button}")
|
||||
_native_click(button)
|
||||
else:
|
||||
from logger import Logger
|
||||
Logger.debug(f"Click blocked by safety check (button: {button})")
|
||||
|
||||
@staticmethod
|
||||
def press(button):
|
||||
|
||||
@@ -177,7 +177,7 @@ def _make_mouse_input(flags: int, dx: int = 0, dy: int = 0, data: int = 0):
|
||||
i.union.mi.dx = dx
|
||||
i.union.mi.dy = dy
|
||||
i.union.mi.mouseData = data
|
||||
i.union.mi.dwFlags = flags | MOUSEEVENTF_ABSOLUTE
|
||||
i.union.mi.dwFlags = flags
|
||||
i.union.mi.dwExtraInfo = None
|
||||
return i
|
||||
|
||||
@@ -285,8 +285,9 @@ def mouse_up(button: str = "left"):
|
||||
raise ValueError(f"Unknown button: {button}")
|
||||
|
||||
def mouse_click(button: str = "left"):
|
||||
"""Click (press + release) a mouse button."""
|
||||
"""Click (press + release) a mouse button with a reliable delay."""
|
||||
mouse_down(button)
|
||||
time.sleep(0.1) # 100ms hold time is very reliable for games
|
||||
mouse_up(button)
|
||||
|
||||
def mouse_wheel(delta: int):
|
||||
|
||||
@@ -78,7 +78,7 @@ def _potion_type(img: np.ndarray) -> str:
|
||||
roi = [int(w * 0.4), int(h * 0.3), int(w * 0.4), int(h * 0.7)]
|
||||
img = cut_roi(img, roi)
|
||||
avg_brightness = np.average(img)
|
||||
if avg_brightness < 47:
|
||||
if avg_brightness < 30:
|
||||
return "empty"
|
||||
score_list = []
|
||||
# rejuv
|
||||
@@ -92,7 +92,7 @@ def _potion_type(img: np.ndarray) -> str:
|
||||
score_list.append((float(np.sum(mask)) / mask.size) * (1/255.0))
|
||||
# find max score
|
||||
max_val = np.max(score_list)
|
||||
if max_val > 0.28:
|
||||
if max_val > 0.20:
|
||||
idx = np.argmax(score_list)
|
||||
types = ["rejuv", "health", "mana"]
|
||||
return types[idx]
|
||||
|
||||
@@ -120,9 +120,8 @@ class PickIt:
|
||||
tele_success = True
|
||||
Logger.info(f"Teled to pickup item {ground_item.Name} and now at distance {ground_item.Distance}")
|
||||
char.pick_up_item((ground_item.CenterMonitor['x'], ground_item.CenterMonitor['y']), item_name=ground_item.Name, distance=ground_item.Distance, force_run=True)
|
||||
# Wait for the pickup animation to complete before moving on
|
||||
# Issue #939: bot was teleporting away before item was actually grabbed
|
||||
wait(0.2, 0.3)
|
||||
# Wait briefly for the pickup animation to start/complete
|
||||
wait(0.08, 0.12)
|
||||
break
|
||||
if not tele_success:
|
||||
Logger.warning(f"Failed to scan item '{item.Name}' after tele. Items visible: {len(items)}")
|
||||
|
||||
@@ -272,25 +272,46 @@ def open_npc_menu(npc_key: Npc) -> bool:
|
||||
results.append({"pos": res.center_monitor, "score": res.score, "combo": min_dist / (res.score**2)})
|
||||
# sort by composite of template match score and distance to NPC pose
|
||||
results = sorted(results, key=lambda r: r["combo"])
|
||||
if not results:
|
||||
Logger.debug(f"NPC {npc_key} search - No templates matched in this frame")
|
||||
for result in results:
|
||||
Logger.debug(f"Hovering over NPC at monitor pos: {result['pos']}")
|
||||
mouse.move(*result["pos"], randomize=3, delay_factor=[0.3, 0.5])
|
||||
wait(0.2, 0.3)
|
||||
img = grab()
|
||||
img = escape_dialogue(img)
|
||||
_, filtered_inp_w = color_filter(img, Config().colors["white"])
|
||||
_, filtered_inp_g = color_filter(img, Config().colors["gold"])
|
||||
res_w = template_finder.search(npcs[npc_key]["name_tag_white"], filtered_inp_w, 0.9, roi=roi).valid
|
||||
res_g = template_finder.search(npcs[npc_key]["name_tag_gold"], filtered_inp_g, 0.9, roi=roi).valid
|
||||
if res_w:
|
||||
res_w = template_finder.search(npcs[npc_key]["name_tag_white"], filtered_inp_w, 0.5, roi=roi)
|
||||
res_g = template_finder.search(npcs[npc_key]["name_tag_gold"], filtered_inp_g, 0.5, roi=roi)
|
||||
|
||||
# fallback to grayscale if color filter is too aggressive
|
||||
if not res_w.valid:
|
||||
res_w_gray = template_finder.search(npcs[npc_key]["name_tag_white"], img, 0.5, roi=roi, use_grayscale=True)
|
||||
if res_w_gray.score > res_w.score:
|
||||
res_w = res_w_gray
|
||||
Logger.debug(f"NPC {npc_key} hover - using grayscale fallback (score: {res_w.score:.3f})")
|
||||
|
||||
Logger.debug(f"NPC {npc_key} hover - White score: {res_w.score:.3f}, Gold score: {res_g.score:.3f}")
|
||||
|
||||
if res_w.valid:
|
||||
Logger.info(f"Clicking on {npc_key} at {mouse.get_position()}")
|
||||
mouse.click(button="left")
|
||||
attempts += 1
|
||||
wait(0.7, 1.0)
|
||||
_, filtered_inp = color_filter(grab(), Config().colors["gold"])
|
||||
res = template_finder.search(npcs[npc_key]["name_tag_gold"], filtered_inp, 0.9, roi=roi).valid
|
||||
if res:
|
||||
# Wait for gold name tag to appear (indicates NPC menu opened or mouse stayed over NPC)
|
||||
wait(0.8, 1.2)
|
||||
img_after = grab()
|
||||
_, filtered_inp_g2 = color_filter(img_after, Config().colors["gold"])
|
||||
res_g2 = template_finder.search(npcs[npc_key]["name_tag_gold"], filtered_inp_g2, 0.5, roi=roi)
|
||||
if res_g2.valid:
|
||||
Logger.debug(f"NPC {npc_key} - gold name tag confirmed after click")
|
||||
return True
|
||||
elif res_g:
|
||||
else:
|
||||
Logger.warning(f"NPC {npc_key} - clicked but gold name tag not found (score: {res_g2.score:.3f})")
|
||||
elif res_g.valid:
|
||||
Logger.debug(f"NPC {npc_key} - already hovered/selected (gold tag score: {res_g.score:.3f})")
|
||||
return True
|
||||
wait(0.1) # Brief pause before next frame grab if no matches were valid
|
||||
return False
|
||||
|
||||
def press_npc_btn(npc_key: Npc, action_btn_key: str):
|
||||
|
||||
@@ -96,7 +96,7 @@ def _single_template_match(template: Template, inp_img: np.ndarray = None, roi:
|
||||
|
||||
# filter for desired color or make grayscale
|
||||
if color_match:
|
||||
template_img, = color_filter(template.img_bgr, color_match)[1],
|
||||
template_img = color_filter(template.img_bgr, color_match)[1]
|
||||
img = color_filter(img, color_match)[1]
|
||||
elif use_grayscale:
|
||||
template_img = template.img_gray
|
||||
@@ -104,25 +104,32 @@ def _single_template_match(template: Template, inp_img: np.ndarray = None, roi:
|
||||
else:
|
||||
template_img = template.img_bgr
|
||||
|
||||
if not (img.shape[0] > template_img.shape[0] and img.shape[1] > template_img.shape[1]):
|
||||
Logger.error(f"Image shape and template shape are incompatible: {template.name}. Image: {img.shape}, Template: {template_img.shape}, roi: {roi}")
|
||||
if not (img.shape[0] >= template_img.shape[0] and img.shape[1] >= template_img.shape[1]):
|
||||
from logger import Logger
|
||||
Logger.debug(f"Incompatible shapes for {template.name}: Image {img.shape}, Template {template_img.shape}, ROI {roi}")
|
||||
else:
|
||||
res = cv2.matchTemplate(img, template_img, cv2.TM_CCOEFF_NORMED, mask = template.alpha_mask)
|
||||
np.nan_to_num(res, copy=False, nan=0.0, posinf=0.0, neginf=0.0)
|
||||
_, max_val, _, max_pos = cv2.minMaxLoc(res)
|
||||
try:
|
||||
res = cv2.matchTemplate(img, template_img, cv2.TM_CCOEFF_NORMED, mask = template.alpha_mask)
|
||||
np.nan_to_num(res, copy=False, nan=0.0, posinf=0.0, neginf=0.0)
|
||||
_, max_val, _, max_pos = cv2.minMaxLoc(res)
|
||||
|
||||
# save rectangle corresponding to matched region
|
||||
rec_x = int((max_pos[0] + rx))
|
||||
rec_y = int((max_pos[1] + ry))
|
||||
rec_w = int(template_img.shape[1])
|
||||
rec_h = int(template_img.shape[0])
|
||||
template_match.region = [rec_x, rec_y, rec_w, rec_h]
|
||||
template_match.region_monitor = [*convert_screen_to_monitor((rec_x, rec_y)), rec_w, rec_h]
|
||||
template_match.center = roi_center(template_match.region)
|
||||
template_match.center_monitor = convert_screen_to_monitor(template_match.center)
|
||||
template_match.name = template.name
|
||||
template_match.score = max_val
|
||||
template_match.valid = True
|
||||
# save rectangle corresponding to matched region
|
||||
rec_x = int((max_pos[0] + rx))
|
||||
rec_y = int((max_pos[1] + ry))
|
||||
rec_w = int(template_img.shape[1])
|
||||
rec_h = int(template_img.shape[0])
|
||||
template_match.region = [rec_x, rec_y, rec_w, rec_h]
|
||||
template_match.region_monitor = [*convert_screen_to_monitor((rec_x, rec_y)), rec_w, rec_h]
|
||||
template_match.center = roi_center(template_match.region)
|
||||
template_match.center_monitor = convert_screen_to_monitor(template_match.center)
|
||||
template_match.name = template.name
|
||||
template_match.score = max_val
|
||||
template_match.valid = True
|
||||
except Exception as e:
|
||||
from logger import Logger
|
||||
Logger.error(f"Template match failed for {template.name}: {e}")
|
||||
import traceback
|
||||
Logger.debug(traceback.format_exc())
|
||||
|
||||
return template_match
|
||||
|
||||
@@ -160,7 +167,8 @@ def search(
|
||||
# Single template — no benefit to parallelize
|
||||
if len(templates) == 1:
|
||||
match = _single_template_match(templates[0], inp_img, roi, color_match, use_grayscale)
|
||||
return match if match.score >= threshold else TemplateMatch()
|
||||
match.valid = match.score >= threshold
|
||||
return match
|
||||
|
||||
# Multiple templates — parallel search
|
||||
matches = []
|
||||
@@ -171,10 +179,8 @@ def search(
|
||||
]
|
||||
for future in concurrent.futures.as_completed(futures):
|
||||
match = future.result()
|
||||
if match.score >= threshold:
|
||||
if not best_match:
|
||||
return match
|
||||
matches.append(match)
|
||||
match.valid = match.score >= threshold
|
||||
matches.append(match)
|
||||
|
||||
if matches:
|
||||
matches = sorted(matches, key=lambda obj: obj.score, reverse=True)
|
||||
|
||||
@@ -20,7 +20,7 @@ def get_mana(img: np.ndarray) -> float:
|
||||
return mana_percentage
|
||||
|
||||
def get_merc_health(img: np.ndarray) -> float:
|
||||
health_rec = [Config().ui_pos["merc_health_left"], Config().ui_pos["merc_health_top"], Config().ui_pos["merc_health_width"], 1]
|
||||
health_rec = [Config().ui_pos["merc_health_left"], Config().ui_pos["merc_health_top"], Config().ui_pos["merc_health_width"], 3]
|
||||
merc_health_img = cut_roi(img, health_rec)
|
||||
merc_health_img = cv2.cvtColor(merc_health_img, cv2.COLOR_BGR2GRAY)
|
||||
_, thresh = cv2.threshold(merc_health_img, 5, 255, cv2.THRESH_BINARY)
|
||||
|
||||
@@ -17,7 +17,7 @@ def is_left_skill_selected(template_list: list[str]) -> bool:
|
||||
"""
|
||||
skill_left_ui_roi = Config().ui_roi["skill_left"]
|
||||
for template in template_list:
|
||||
if template_finder.search(template, grab(), threshold=0.84, roi=skill_left_ui_roi).valid:
|
||||
if template_finder.search(template, grab(), threshold=0.8, roi=skill_left_ui_roi).valid:
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -73,7 +73,7 @@ def is_right_skill_selected(template_list: list[str]) -> bool:
|
||||
"""
|
||||
skill_right_ui_roi = Config().ui_roi["skill_right"]
|
||||
for template in template_list:
|
||||
if template_finder.search(template, grab(), threshold=0.84, roi=skill_right_ui_roi).valid:
|
||||
if template_finder.search(template, grab(), threshold=0.8, roi=skill_right_ui_roi).valid:
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -82,7 +82,7 @@ def wait_until_right_skill_selected(template: str, timeout: float = 1) -> bool:
|
||||
:return: Bool if skill gets selected on the right skill slot within the timeout.
|
||||
"""
|
||||
skill_right_ui_roi = Config().ui_roi["skill_right"]
|
||||
if template_finder.search_and_wait(template, roi=skill_right_ui_roi, timeout = timeout, threshold=0.84).valid:
|
||||
if template_finder.search_and_wait(template, roi=skill_right_ui_roi, timeout = timeout, threshold=0.8).valid:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -61,13 +61,7 @@ class ScreenObjects:
|
||||
MercIcon=ScreenObject(
|
||||
ref=["MERC_A2", "MERC_A2_2", "MERC_A1", "MERC_A5", "MERC_A3"],
|
||||
roi="merc_icon",
|
||||
threshold=0.85,
|
||||
use_grayscale=True
|
||||
)
|
||||
MercPanelText=ScreenObject(
|
||||
ref=["MERCENARY_SCREEN"],
|
||||
roi="merc_panel",
|
||||
threshold=0.85,
|
||||
threshold=0.75,
|
||||
use_grayscale=True
|
||||
)
|
||||
PlayBtn=ScreenObject(
|
||||
@@ -182,7 +176,7 @@ class ScreenObjects:
|
||||
YouHaveDied=ScreenObject(
|
||||
ref="YOU_HAVE_DIED",
|
||||
roi="death",
|
||||
threshold=0.9,
|
||||
threshold=0.8,
|
||||
color_match=Config().colors["red"],
|
||||
use_grayscale=True
|
||||
)
|
||||
@@ -257,8 +251,10 @@ class ScreenObjects:
|
||||
threshold=0.8,
|
||||
)
|
||||
NotEnoughGold=ScreenObject(
|
||||
ref="MISSING_GOLD",
|
||||
threshold=0.8,
|
||||
ref="NOT_ENOUGH_GOLD",
|
||||
threshold=0.9,
|
||||
color_match=Config().colors["red"],
|
||||
use_grayscale=True
|
||||
)
|
||||
QuestSkillBtn=ScreenObject(
|
||||
ref="QUEST_SKILL_BTN",
|
||||
|
||||
BIN
test_grab.png
Normal file
BIN
test_grab.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 MiB |
Reference in New Issue
Block a user