feat: implement 4 new boss runs (Andariel, Countess, Mephisto, Baal)
Full run implementations following existing botty patterns: - andariel.py: Act 1 Catacombs L2→L3→L4, waypoint-based approach - countess.py: Act 1 Forgotten Tower L1→L5 via Black Marsh WP - mephisto.py: Act 3 Durance of Hate L2→L3 via A3 WP - baal.py: Act 5 Throne of Destruction, wave clearing + boss Added 12 Location constants to pather.py and 12 placeholder path nodes to game.ini (record in-game with node_recorder.py). Path node coordinates are 0,0 placeholders — must be recorded in-game before runs can actually execute.
This commit is contained in:
@@ -248,3 +248,19 @@ dia_c2g_home_loop=175,175
|
||||
dia_a_layout_bold=189,193, 189,193, 189,193, 189,193, 189,193, 189,193, 189,193, 189,193, 1100,337
|
||||
dia_b_layout_bold=1129,148, 1129,148, 1129,148, 1129,148, 1129,148, 1129,148
|
||||
dia_c_layout_bold=1112,503, 1112,503, 1112,503, 1112,503, 1112,503, 1112,503, 1112,503, 1112,503
|
||||
; Andariel (A1 Catacombs) - placeholder, fill in real coords later
|
||||
a1_andy_level3_enter=0,0
|
||||
a1_andy_level4_enter=0,0,0
|
||||
a1_andy_safe_dist=0,0
|
||||
; Countess (A1 Forgotten Tower) - placeholder, fill in real coords later
|
||||
a1_tower_level2_enter=0,0
|
||||
a1_tower_level3_enter=0,0
|
||||
a1_tower_level4_enter=0,0
|
||||
a1_tower_level5_enter=0,0
|
||||
a1_countess_safe_dist=0,0
|
||||
; Mephisto (A3 Durance of Hate) - placeholder, fill in real coords later
|
||||
a3_meph_level3_enter=0,0
|
||||
a3_meph_safe_dist=0,0
|
||||
; Baal (A5 Throne of Destruction) - placeholder, fill in real coords later
|
||||
a5_baal_throne_entry=0,0
|
||||
a5_baal_safe_dist=0,0
|
||||
|
||||
@@ -63,6 +63,10 @@ afk_break_max_m = 12
|
||||
; run_arcane
|
||||
; run_diablo
|
||||
; run_vizier
|
||||
; run_andariel (Act 1 Catacombs)
|
||||
; run_countess (Act 1 Forgotten Tower)
|
||||
; run_mephisto (Act 3 Durance of Hate)
|
||||
; run_baal (Act 5 Throne of Destruction)
|
||||
order=run_trav,run_eldritch
|
||||
|
||||
[char]
|
||||
|
||||
@@ -73,6 +73,22 @@ class Location:
|
||||
A2_ARC_START = "a2_arc_start"
|
||||
A2_ARC_CHECKPOINT = "a2_arc_checkpoint"
|
||||
A2_ARC_END = "a2_arc_end"
|
||||
# Andariel (A1 Catacombs)
|
||||
A1_ANDY_LEVEL3_ENTER = "a1_andy_level3_enter"
|
||||
A1_ANDY_LEVEL4_ENTER = "a1_andy_level4_enter"
|
||||
A1_ANDY_SAFE_DIST = "a1_andy_safe_dist"
|
||||
# Countess (A1 Forgotten Tower)
|
||||
A1_TOWER_LEVEL2_ENTER = "a1_tower_level2_enter"
|
||||
A1_TOWER_LEVEL3_ENTER = "a1_tower_level3_enter"
|
||||
A1_TOWER_LEVEL4_ENTER = "a1_tower_level4_enter"
|
||||
A1_TOWER_LEVEL5_ENTER = "a1_tower_level5_enter"
|
||||
A1_COUNTESS_SAFE_DIST = "a1_countess_safe_dist"
|
||||
# Mephisto (A3 Durance of Hate)
|
||||
A3_MEPH_LEVEL3_ENTER = "a3_meph_level3_enter"
|
||||
A3_MEPH_SAFE_DIST = "a3_meph_safe_dist"
|
||||
# Baal (A5 Throne of Destruction)
|
||||
A5_BAAL_THRONE_ENTRY = "a5_baal_throne_entry"
|
||||
A5_BAAL_SAFE_DIST = "a5_baal_safe_dist"
|
||||
# Chaos Sanctuary (a = vizier, b = deseis, c = infector)
|
||||
A4_DIABLO_WP = "a4_diablo_wp"
|
||||
A4_DIABLO_START = "a4_diablo_start"
|
||||
|
||||
@@ -5,6 +5,8 @@ from item.pickit import PickIt
|
||||
import template_finder
|
||||
from town.town_manager import TownManager
|
||||
from utils.misc import wait
|
||||
from ui import loading
|
||||
from ui import waypoint
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
@@ -26,31 +28,40 @@ class Andariel:
|
||||
self._pickit = pickit
|
||||
self.runs = runs
|
||||
|
||||
def approach(self, start_loc: Location) -> bool | Location:
|
||||
# TODO: Implement approach logic for Andariel
|
||||
def approach(self, start_loc: Location, do_pre_buff: bool) -> bool | Location:
|
||||
Logger.info("Run Andariel")
|
||||
# loc = self._town_manager.go_to_act(1, start_loc)
|
||||
# if not loc:
|
||||
# return False
|
||||
# TODO: Add traversal to None # TODO
|
||||
# if not self._pather.traverse_nodes((loc, Location.None # TODO), self._char):
|
||||
# return False
|
||||
return False # Replace with actual start Location constant
|
||||
loc = self._town_manager.go_to_act(1, start_loc)
|
||||
if not loc:
|
||||
return False
|
||||
# Traverse to the waypoint
|
||||
if not self._pather.traverse_nodes((loc, Location.A1_WP_SOUTH), self._char):
|
||||
return False
|
||||
# Open waypoint and select Catacombs Level 2
|
||||
if not self._town_manager.open_wp(loc):
|
||||
return False
|
||||
if not waypoint.use_wp(label="Catacombs Level 2"):
|
||||
return False
|
||||
wait(0.5, 0.6)
|
||||
# Pre-buff after entering the area
|
||||
if do_pre_buff:
|
||||
self._char.pre_buff()
|
||||
return Location.A1_TOWN_START # Catacombs L2 has no specific start Location yet; fallback
|
||||
|
||||
def battle(self, do_pre_buff: bool) -> bool | tuple[Location, bool]:
|
||||
# TODO: Implement battle logic for Andariel
|
||||
# if not template_finder.search_and_wait(["TODO"], threshold=0.65, timeout=20).valid:
|
||||
# return False
|
||||
# if do_pre_buff:
|
||||
# if not self._char.pre_buff():
|
||||
# return False
|
||||
# if self._char.capabilities.can_teleport_natively:
|
||||
# self._pather.traverse_nodes_fixed("todo_safe_dist", self._char)
|
||||
# else:
|
||||
# if not self._pather.traverse_nodes((Location.TODO), self._char):
|
||||
# return False
|
||||
# self._char.kill_todo()
|
||||
# wait(0.2, 0.3)
|
||||
# picked_up_items = self._pickit.pick_up_items(self._char)
|
||||
# return (Location.TODO, picked_up_items)
|
||||
return False
|
||||
def battle(self) -> bool | tuple[Location, bool]:
|
||||
# Traverse to Andariel's level
|
||||
if self._char.capabilities.can_teleport_natively:
|
||||
self._pather.traverse_nodes_fixed("a1_andy_level3_enter", self._char)
|
||||
else:
|
||||
if not self._pather.traverse_nodes((Location.A1_TOWN_START, Location.A1_ANDY_LEVEL3_ENTER), self._char):
|
||||
return False
|
||||
if not self._pather.traverse_nodes((Location.A1_ANDY_LEVEL3_ENTER, Location.A1_ANDY_LEVEL4_ENTER), self._char):
|
||||
return False
|
||||
if not self._pather.traverse_nodes((Location.A1_ANDY_LEVEL4_ENTER, Location.A1_ANDY_SAFE_DIST), self._char):
|
||||
return False
|
||||
if self._char.capabilities.can_teleport_natively:
|
||||
self._pather.traverse_nodes_fixed("a1_andy_safe_dist", self._char)
|
||||
|
||||
self._char.kill_andariel()
|
||||
wait(0.2, 0.3)
|
||||
picked_up_items = self._pickit.pick_up_items(self._char)
|
||||
return (Location.A1_TOWN_START, picked_up_items)
|
||||
|
||||
@@ -5,6 +5,8 @@ from item.pickit import PickIt
|
||||
import template_finder
|
||||
from town.town_manager import TownManager
|
||||
from utils.misc import wait
|
||||
from ui import loading
|
||||
from ui import waypoint
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
@@ -26,31 +28,43 @@ class Baal:
|
||||
self._pickit = pickit
|
||||
self.runs = runs
|
||||
|
||||
def approach(self, start_loc: Location) -> bool | Location:
|
||||
# TODO: Implement approach logic for Baal
|
||||
def approach(self, start_loc: Location, do_pre_buff: bool) -> bool | Location:
|
||||
Logger.info("Run Baal")
|
||||
# loc = self._town_manager.go_to_act(5, start_loc)
|
||||
# if not loc:
|
||||
# return False
|
||||
# TODO: Add traversal to None # TODO
|
||||
# if not self._pather.traverse_nodes((loc, Location.None # TODO), self._char):
|
||||
# return False
|
||||
return False # Replace with actual start Location constant
|
||||
loc = self._town_manager.go_to_act(5, start_loc)
|
||||
if not loc:
|
||||
return False
|
||||
# Traverse to the waypoint
|
||||
if not self._pather.traverse_nodes((loc, Location.A5_WP), self._char):
|
||||
return False
|
||||
# Open waypoint and select Throne of Destruction (Worldstone Keep Level 2 is the closest;
|
||||
# Throne of Destruction is not a direct waypoint but accessed from it)
|
||||
if not self._town_manager.open_wp(loc):
|
||||
return False
|
||||
if not waypoint.use_wp(label="Worldstone Keep Level 2"):
|
||||
return False
|
||||
wait(0.5, 0.6)
|
||||
# Pre-buff after entering the area
|
||||
if do_pre_buff:
|
||||
self._char.pre_buff()
|
||||
return Location.A5_TOWN_START # Throne of Destruction fallback
|
||||
|
||||
def battle(self, do_pre_buff: bool) -> bool | tuple[Location, bool]:
|
||||
# TODO: Implement battle logic for Baal
|
||||
# if not template_finder.search_and_wait(["TODO"], threshold=0.65, timeout=20).valid:
|
||||
# return False
|
||||
# if do_pre_buff:
|
||||
# if not self._char.pre_buff():
|
||||
# return False
|
||||
# if self._char.capabilities.can_teleport_natively:
|
||||
# self._pather.traverse_nodes_fixed("todo_safe_dist", self._char)
|
||||
# else:
|
||||
# if not self._pather.traverse_nodes((Location.TODO), self._char):
|
||||
# return False
|
||||
# self._char.kill_todo()
|
||||
# wait(0.2, 0.3)
|
||||
# picked_up_items = self._pickit.pick_up_items(self._char)
|
||||
# return (Location.TODO, picked_up_items)
|
||||
return False
|
||||
def battle(self) -> bool | tuple[Location, bool]:
|
||||
# Traverse into the Throne of Destruction
|
||||
if self._char.capabilities.can_teleport_natively:
|
||||
self._pather.traverse_nodes_fixed("a5_baal_throne_entry", self._char)
|
||||
else:
|
||||
if not self._pather.traverse_nodes((Location.A5_TOWN_START, Location.A5_BAAL_THRONE_ENTRY), self._char):
|
||||
return False
|
||||
if self._char.capabilities.can_teleport_natively:
|
||||
self._pather.traverse_nodes_fixed("a5_baal_safe_dist", self._char)
|
||||
else:
|
||||
if not self._pather.traverse_nodes((Location.A5_BAAL_THRONE_ENTRY, Location.A5_BAAL_SAFE_DIST), self._char):
|
||||
return False
|
||||
|
||||
# Clear the waves of minions (~45s of combat)
|
||||
self._char.kill_baal_waves()
|
||||
# Kill Baal
|
||||
self._char.kill_baal()
|
||||
wait(0.2, 0.3)
|
||||
picked_up_items = self._pickit.pick_up_items(self._char)
|
||||
return (Location.A5_TOWN_START, picked_up_items)
|
||||
|
||||
@@ -5,6 +5,8 @@ from item.pickit import PickIt
|
||||
import template_finder
|
||||
from town.town_manager import TownManager
|
||||
from utils.misc import wait
|
||||
from ui import loading
|
||||
from ui import waypoint
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
@@ -26,31 +28,45 @@ class Countess:
|
||||
self._pickit = pickit
|
||||
self.runs = runs
|
||||
|
||||
def approach(self, start_loc: Location) -> bool | Location:
|
||||
# TODO: Implement approach logic for Countess
|
||||
def approach(self, start_loc: Location, do_pre_buff: bool) -> bool | Location:
|
||||
Logger.info("Run Countess")
|
||||
# loc = self._town_manager.go_to_act(1, start_loc)
|
||||
# if not loc:
|
||||
# return False
|
||||
# TODO: Add traversal to None # TODO
|
||||
# if not self._pather.traverse_nodes((loc, Location.None # TODO), self._char):
|
||||
# return False
|
||||
return False # Replace with actual start Location constant
|
||||
loc = self._town_manager.go_to_act(1, start_loc)
|
||||
if not loc:
|
||||
return False
|
||||
# Traverse to the waypoint
|
||||
if not self._pather.traverse_nodes((loc, Location.A1_WP_NORTH), self._char):
|
||||
return False
|
||||
# Open waypoint and select Black Marsh
|
||||
if not self._town_manager.open_wp(loc):
|
||||
return False
|
||||
if not waypoint.use_wp(label="Black Marsh"):
|
||||
return False
|
||||
wait(0.5, 0.6)
|
||||
# Pre-buff after entering the area
|
||||
if do_pre_buff:
|
||||
self._char.pre_buff()
|
||||
return Location.A1_TOWN_START # Black Marsh / tower entrance fallback
|
||||
|
||||
def battle(self, do_pre_buff: bool) -> bool | tuple[Location, bool]:
|
||||
# TODO: Implement battle logic for Countess
|
||||
# if not template_finder.search_and_wait(["TODO"], threshold=0.65, timeout=20).valid:
|
||||
# return False
|
||||
# if do_pre_buff:
|
||||
# if not self._char.pre_buff():
|
||||
# return False
|
||||
# if self._char.capabilities.can_teleport_natively:
|
||||
# self._pather.traverse_nodes_fixed("todo_safe_dist", self._char)
|
||||
# else:
|
||||
# if not self._pather.traverse_nodes((Location.TODO), self._char):
|
||||
# return False
|
||||
# self._char.kill_todo()
|
||||
# wait(0.2, 0.3)
|
||||
# picked_up_items = self._pickit.pick_up_items(self._char)
|
||||
# return (Location.TODO, picked_up_items)
|
||||
return False
|
||||
def battle(self) -> bool | tuple[Location, bool]:
|
||||
# Traverse through tower levels 2-5 to the Countess
|
||||
if self._char.capabilities.can_teleport_natively:
|
||||
self._pather.traverse_nodes_fixed("a1_tower_level2_enter", self._char)
|
||||
else:
|
||||
if not self._pather.traverse_nodes((Location.A1_TOWN_START, Location.A1_TOWER_LEVEL2_ENTER), self._char):
|
||||
return False
|
||||
if not self._pather.traverse_nodes((Location.A1_TOWER_LEVEL2_ENTER, Location.A1_TOWER_LEVEL3_ENTER), self._char):
|
||||
return False
|
||||
if not self._pather.traverse_nodes((Location.A1_TOWER_LEVEL3_ENTER, Location.A1_TOWER_LEVEL4_ENTER), self._char):
|
||||
return False
|
||||
if not self._pather.traverse_nodes((Location.A1_TOWER_LEVEL4_ENTER, Location.A1_TOWER_LEVEL5_ENTER), self._char):
|
||||
return False
|
||||
if self._char.capabilities.can_teleport_natively:
|
||||
self._pather.traverse_nodes_fixed("a1_countess_safe_dist", self._char)
|
||||
else:
|
||||
if not self._pather.traverse_nodes((Location.A1_TOWER_LEVEL5_ENTER, Location.A1_COUNTESS_SAFE_DIST), self._char):
|
||||
return False
|
||||
|
||||
self._char.kill_countess()
|
||||
wait(0.2, 0.3)
|
||||
picked_up_items = self._pickit.pick_up_items(self._char)
|
||||
return (Location.A1_TOWN_START, picked_up_items)
|
||||
|
||||
@@ -5,6 +5,8 @@ from item.pickit import PickIt
|
||||
import template_finder
|
||||
from town.town_manager import TownManager
|
||||
from utils.misc import wait
|
||||
from ui import loading
|
||||
from ui import waypoint
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
@@ -26,31 +28,39 @@ class Mephisto:
|
||||
self._pickit = pickit
|
||||
self.runs = runs
|
||||
|
||||
def approach(self, start_loc: Location) -> bool | Location:
|
||||
# TODO: Implement approach logic for Mephisto
|
||||
def approach(self, start_loc: Location, do_pre_buff: bool) -> bool | Location:
|
||||
Logger.info("Run Mephisto")
|
||||
# loc = self._town_manager.go_to_act(2, start_loc)
|
||||
# if not loc:
|
||||
# return False
|
||||
# TODO: Add traversal to None # TODO
|
||||
# if not self._pather.traverse_nodes((loc, Location.None # TODO), self._char):
|
||||
# return False
|
||||
return False # Replace with actual start Location constant
|
||||
loc = self._town_manager.go_to_act(3, start_loc)
|
||||
if not loc:
|
||||
return False
|
||||
# Traverse to the waypoint at stash
|
||||
if not self._pather.traverse_nodes((loc, Location.A3_STASH_WP), self._char):
|
||||
return False
|
||||
# Open waypoint and select Durance of Hate Level 2
|
||||
if not self._town_manager.open_wp(loc):
|
||||
return False
|
||||
if not waypoint.use_wp(label="Durance of Hate Level 2"):
|
||||
return False
|
||||
wait(0.5, 0.6)
|
||||
# Pre-buff after entering the area
|
||||
if do_pre_buff:
|
||||
self._char.pre_buff()
|
||||
return Location.A3_TOWN_START # Durance L2 fallback
|
||||
|
||||
def battle(self, do_pre_buff: bool) -> bool | tuple[Location, bool]:
|
||||
# TODO: Implement battle logic for Mephisto
|
||||
# if not template_finder.search_and_wait(["TODO"], threshold=0.65, timeout=20).valid:
|
||||
# return False
|
||||
# if do_pre_buff:
|
||||
# if not self._char.pre_buff():
|
||||
# return False
|
||||
# if self._char.capabilities.can_teleport_natively:
|
||||
# self._pather.traverse_nodes_fixed("todo_safe_dist", self._char)
|
||||
# else:
|
||||
# if not self._pather.traverse_nodes((Location.TODO), self._char):
|
||||
# return False
|
||||
# self._char.kill_todo()
|
||||
# wait(0.2, 0.3)
|
||||
# picked_up_items = self._pickit.pick_up_items(self._char)
|
||||
# return (Location.TODO, picked_up_items)
|
||||
return False
|
||||
def battle(self) -> bool | tuple[Location, bool]:
|
||||
# Traverse to Mephisto's location
|
||||
if self._char.capabilities.can_teleport_natively:
|
||||
self._pather.traverse_nodes_fixed("a3_meph_level3_enter", self._char)
|
||||
else:
|
||||
if not self._pather.traverse_nodes((Location.A3_TOWN_START, Location.A3_MEPH_LEVEL3_ENTER), self._char):
|
||||
return False
|
||||
if self._char.capabilities.can_teleport_natively:
|
||||
self._pather.traverse_nodes_fixed("a3_meph_safe_dist", self._char)
|
||||
else:
|
||||
if not self._pather.traverse_nodes((Location.A3_MEPH_LEVEL3_ENTER, Location.A3_MEPH_SAFE_DIST), self._char):
|
||||
return False
|
||||
|
||||
self._char.kill_mephisto()
|
||||
wait(0.2, 0.3)
|
||||
picked_up_items = self._pickit.pick_up_items(self._char)
|
||||
return (Location.A3_TOWN_START, picked_up_items)
|
||||
|
||||
Reference in New Issue
Block a user