269 lines
12 KiB
Python
269 lines
12 KiB
Python
from item import consumables
|
|
import keyboard
|
|
import template_finder
|
|
from config import Config
|
|
from pather import Location
|
|
from logger import Logger
|
|
from town import IAct, A1, A2, A3, A4, A5
|
|
from utils.misc import wait
|
|
from screen import grab
|
|
from ui import waypoint, view
|
|
from inventory import personal, vendor, common
|
|
|
|
TOWN_MARKERS = [
|
|
"A5_TOWN_0", "A5_TOWN_1",
|
|
"A4_TOWN_4", "A4_TOWN_5",
|
|
"A3_TOWN_0", "A3_TOWN_1",
|
|
"A2_TOWN_0", "A2_TOWN_1", "A2_TOWN_10",
|
|
"A1_TOWN_1", "A1_TOWN_3"
|
|
]
|
|
|
|
class TownManager:
|
|
|
|
def __init__(self, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5):
|
|
self._acts: dict[Location, IAct] = {
|
|
Location.A1_TOWN_START: a1,
|
|
Location.A2_TOWN_START: a2,
|
|
Location.A3_TOWN_START: a3,
|
|
Location.A4_TOWN_START: a4,
|
|
Location.A5_TOWN_START: a5
|
|
}
|
|
|
|
@staticmethod
|
|
def get_act_from_location(loc: Location) -> Location:
|
|
location = None
|
|
if loc.upper().startswith("A5_"):
|
|
location = Location.A5_TOWN_START
|
|
elif loc.upper().startswith("A4_"):
|
|
location = Location.A4_TOWN_START
|
|
elif loc.upper().startswith("A3_"):
|
|
location = Location.A3_TOWN_START
|
|
elif loc.upper().startswith("A2_"):
|
|
location = Location.A2_TOWN_START
|
|
elif loc.upper().startswith("A1_"):
|
|
location = Location.A1_TOWN_START
|
|
return location
|
|
|
|
def wait_for_town_spawn(self, timeout: float = 30) -> Location:
|
|
"""Wait for the char to spawn in town after starting a new game
|
|
:param timeout: Optional float value for time out in seconds, defaults to None
|
|
:return: Location of the town (e.g. Location.A4_TOWN_START) or None if nothing was found within timeout time
|
|
"""
|
|
template_match = template_finder.search_and_wait(TOWN_MARKERS, best_match=True, timeout=timeout)
|
|
if template_match.valid:
|
|
return TownManager.get_act_from_location(template_match.name)
|
|
return None
|
|
|
|
def wait_for_tp(self, curr_loc: Location):
|
|
curr_act = TownManager.get_act_from_location(curr_loc)
|
|
if curr_act is None: return False
|
|
return self._acts[curr_act].wait_for_tp()
|
|
|
|
def open_wp(self, curr_loc: Location):
|
|
curr_act = TownManager.get_act_from_location(curr_loc)
|
|
if curr_act is None: return False
|
|
return self._acts[curr_act].open_wp(curr_loc)
|
|
|
|
def go_to_act(self, act_idx: int, curr_loc: Location) -> Location | bool:
|
|
curr_act = TownManager.get_act_from_location(curr_loc)
|
|
if curr_act is None: return False
|
|
# check if we already are in the desired act
|
|
if act_idx == 1: act = Location.A1_TOWN_START
|
|
elif act_idx == 2: act = Location.A2_TOWN_START
|
|
elif act_idx == 3: act = Location.A3_TOWN_START
|
|
elif act_idx == 4: act = Location.A4_TOWN_START
|
|
elif act_idx == 5: act = Location.A5_TOWN_START
|
|
else:
|
|
Logger.error(f"Act {act_idx} is not supported")
|
|
return False
|
|
if curr_act == act:
|
|
return curr_loc
|
|
# if not, move to the desired act via waypoint
|
|
if not self._acts[curr_act].open_wp(curr_loc): return False
|
|
waypoint.use_wp(act = act_idx, idx = 0)
|
|
return self._acts[act].get_wp_location()
|
|
|
|
def heal(self, curr_loc: Location) -> Location | bool:
|
|
curr_act = TownManager.get_act_from_location(curr_loc)
|
|
if curr_act is None: return False
|
|
# check if we can heal in current act
|
|
if self._acts[curr_act].can_heal():
|
|
return self._acts[curr_act].heal(curr_loc)
|
|
Logger.warning(f"Could not heal in {curr_act}. Continue without healing")
|
|
return curr_loc
|
|
|
|
def buy_consumables(self, curr_loc: Location, items: list = None):
|
|
curr_act = TownManager.get_act_from_location(curr_loc)
|
|
if curr_act is None: return False, items
|
|
# check if we can buy pots in current act
|
|
if self._acts[curr_act].can_buy_pots():
|
|
new_loc = self._acts[curr_act].open_trade_menu(curr_loc)
|
|
if not (new_loc and common.wait_for_left_inventory()): return False, items
|
|
common.select_tab(3)
|
|
img=grab()
|
|
# Buy HP pots
|
|
if consumables.get_needs("health") > 0:
|
|
can_shift_click = not sum([ x > 0 for x in [consumables.get_needs("health"), consumables.get_needs("mana"), consumables.get_needs("rejuv")]]) > 1
|
|
if vendor.buy_item(template_name = "SUPER_HEALING_POTION", quantity = consumables.get_needs("health"), shift_click = can_shift_click, img=img):
|
|
consumables.set_needs("health", 0)
|
|
else:
|
|
if vendor.buy_item(template_name="GREATER_HEALING_POTION", quantity = consumables.get_needs("health"), shift_click = can_shift_click, img=img):
|
|
consumables.set_needs("health", 0)
|
|
else:
|
|
Logger.error("buy_consumables: Error purchasing health potions")
|
|
# Buy mana pots
|
|
if consumables.get_needs("mana") > 0:
|
|
can_shift_click = not sum([ x > 0 for x in [consumables.get_needs("health"), consumables.get_needs("mana"), consumables.get_needs("rejuv")]]) > 1
|
|
if vendor.buy_item(template_name="SUPER_MANA_POTION", quantity = consumables.get_needs("mana"), shift_click = can_shift_click, img=img):
|
|
consumables.set_needs("mana", 0)
|
|
else:
|
|
if vendor.buy_item(template_name="GREATER_MANA_POTION", quantity = consumables.get_needs("mana"), shift_click = can_shift_click, img=img):
|
|
consumables.set_needs("mana", 0)
|
|
else:
|
|
Logger.error("buy_consumables: Error purchasing mana potions")
|
|
# Buy TP scrolls
|
|
if consumables.get_needs("tp") > 0:
|
|
if vendor.buy_item(template_name="INV_SCROLL_TP", shift_click = True, img=img):
|
|
consumables.set_needs("tp", 0)
|
|
else:
|
|
Logger.error("buy_consumables: Error purchasing teleport scrolls")
|
|
# Buy ID scrolls
|
|
if consumables.get_needs("id") > 0:
|
|
if vendor.buy_item(template_name="INV_SCROLL_ID", shift_click = True, img=img):
|
|
consumables.set_needs("id", 0)
|
|
else:
|
|
Logger.error("buy_consumables: Error purchasing ID scrolls")
|
|
# Buy keys
|
|
if consumables.get_needs("key") > 0:
|
|
if vendor.buy_item(template_name="INV_KEY", shift_click = True, img=img):
|
|
consumables.set_needs("key", 0)
|
|
else:
|
|
Logger.error("buy_consumables: Error purchasing keys")
|
|
# Sell items, if any
|
|
if items:
|
|
items = personal.transfer_items(items, action = "sell")
|
|
common.close()
|
|
return new_loc, items
|
|
Logger.warning(f"Could not buy consumables in {curr_act}. Continue.")
|
|
return curr_loc, items
|
|
|
|
def resurrect(self, curr_loc: Location) -> Location | bool:
|
|
curr_act = TownManager.get_act_from_location(curr_loc)
|
|
if curr_act is None: return False
|
|
# check if we can resurrect in current act
|
|
if self._acts[curr_act].can_resurrect():
|
|
return self._acts[curr_act].resurrect(curr_loc)
|
|
new_loc = self.go_to_act(4, curr_loc)
|
|
if not new_loc: return False
|
|
return self._acts[Location.A4_TOWN_START].resurrect(new_loc)
|
|
|
|
def identify(self, curr_loc: Location) -> Location | bool:
|
|
curr_act = TownManager.get_act_from_location(curr_loc)
|
|
if curr_act is None: return False
|
|
# check if we can Identify in current act
|
|
if self._acts[curr_act].can_identify():
|
|
success = self._acts[curr_act].identify(curr_loc)
|
|
if success:
|
|
wait(0.2)
|
|
# close cain dialog so inventory key is not blocked
|
|
keyboard.send("esc")
|
|
else:
|
|
view.return_to_play()
|
|
return success
|
|
new_loc = self.go_to_act(5, curr_loc)
|
|
if not new_loc: return False
|
|
success = self._acts[Location.A5_TOWN_START].identify(new_loc)
|
|
if success:
|
|
wait(0.2)
|
|
# close cain dialog so inventory key is not blocked
|
|
keyboard.send("esc")
|
|
else:
|
|
view.return_to_play()
|
|
return success
|
|
|
|
def open_stash(self, curr_loc: Location) -> Location | bool:
|
|
curr_act = TownManager.get_act_from_location(curr_loc)
|
|
new_loc = curr_loc
|
|
|
|
if not self._acts[curr_act].can_stash():
|
|
new_loc = self.go_to_act(5, curr_loc)
|
|
if not new_loc: return False
|
|
curr_act = Location.A5_TOWN_START
|
|
|
|
new_loc = self._acts[curr_act].open_stash(new_loc)
|
|
if not new_loc: return False
|
|
return new_loc
|
|
|
|
def gamble(self, curr_loc: Location) -> Location | bool:
|
|
curr_act = TownManager.get_act_from_location(curr_loc)
|
|
if curr_act is None: return False
|
|
# check if we can Identify in current act
|
|
if self._acts[curr_act].can_gamble():
|
|
return self._acts[curr_act].gamble(curr_loc)
|
|
new_loc = self.go_to_act(4, curr_loc)
|
|
if not new_loc: return False
|
|
return self._acts[Location.A4_TOWN_START].gamble(new_loc)
|
|
|
|
def stash(self, curr_loc: Location, items: list = None):
|
|
curr_act = TownManager.get_act_from_location(curr_loc)
|
|
if curr_act is None: return False, False
|
|
# check if we can stash in current act
|
|
if self._acts[curr_act].can_stash():
|
|
new_loc = self._acts[curr_act].open_stash(curr_loc)
|
|
if not new_loc: return False, False
|
|
wait(1.0)
|
|
items = personal.stash_all_items(items)
|
|
return new_loc, items
|
|
new_loc = self.go_to_act(5, curr_loc)
|
|
if not new_loc: return False, False
|
|
new_loc = self._acts[Location.A5_TOWN_START].open_stash(new_loc)
|
|
if not new_loc: return False, False
|
|
wait(1.0)
|
|
items = personal.stash_all_items(items)
|
|
return new_loc, items
|
|
|
|
def repair(self, curr_loc: Location, items: list = None):
|
|
curr_act = TownManager.get_act_from_location(curr_loc)
|
|
if curr_act is None: return False, False
|
|
# check if we can rapair in current act
|
|
if self._acts[curr_act].can_trade_and_repair():
|
|
new_loc = self._acts[curr_act].open_trade_and_repair_menu(curr_loc)
|
|
if not new_loc: return False, False
|
|
if items:
|
|
items = personal.transfer_items(items, "sell")
|
|
vendor.repair()
|
|
wait(0.1, 0.2)
|
|
common.close()
|
|
return new_loc, items
|
|
new_loc = self.go_to_act(5, curr_loc)
|
|
if not new_loc: return False, False
|
|
new_loc = self._acts[Location.A5_TOWN_START].open_trade_and_repair_menu(new_loc)
|
|
if not new_loc: return False, False
|
|
if items:
|
|
items = personal.transfer_items(items, "sell")
|
|
vendor.repair()
|
|
wait(0.1, 0.2)
|
|
common.close()
|
|
return new_loc, items
|
|
|
|
# Test: Move to desired location in d2r and run any town action you want to test from there
|
|
if __name__ == "__main__":
|
|
import keyboard
|
|
import os
|
|
from screen import start_detecting_window
|
|
start_detecting_window()
|
|
keyboard.add_hotkey('f12', lambda: Logger.info('Force Exit (f12)') or os._exit(1))
|
|
print("Move to d2r window and press f11")
|
|
keyboard.wait("f11")
|
|
from char.paladin.hammerdin import Hammerdin
|
|
from pather import Pather
|
|
pather = Pather()
|
|
char = Hammerdin(Config().hammerdin, Config().char, pather)
|
|
a5 = A5(pather, char)
|
|
a4 = A4(pather, char)
|
|
a3 = A3(pather, char)
|
|
a2 = A2(pather, char)
|
|
a1 = A1(pather, char)
|
|
town_manager = TownManager(a1, a2, a3, a4, a5)
|
|
print(town_manager.identify(Location.A3_TOWN_START))
|