Files
my-botty/src/town/town_manager.py
T
2022-06-16 09:46:14 -04:00

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))