Files
my-botty/src/run/nihlathak.py
T

111 lines
5.3 KiB
Python

from char.i_char import IChar
from logger import Logger
from pather import Location, Pather
from item.pickit import PickIt
import template_finder
from town.town_manager import TownManager
from utils.misc import wait
from dataclasses import dataclass
from screen import convert_abs_to_monitor
import random
from ui import loading, waypoint
from collections import OrderedDict
class Nihlathak:
name = "run_nihlathak"
def __init__(
self,
pather: Pather,
town_manager: TownManager,
char: IChar,
pickit: PickIt,
runs: OrderedDict
):
self._pather = pather
self._town_manager = town_manager
self._char = char
self._pickit = pickit
self._runs = runs
def approach(self, start_loc: Location) -> bool | Location:
Logger.info("Run Nihlathak")
if not self._char.capabilities.can_teleport_natively:
raise ValueError("Nihlathak requires teleport")
if not self._town_manager.open_wp(start_loc):
return False
wait(0.4)
if waypoint.use_wp("Halls of Pain"): # use Halls of Pain Waypoint (5th in A5)
return Location.A5_NIHLATHAK_START
return False
def battle(self, do_pre_buff: bool) -> bool | tuple[Location, bool]:
# TODO: We might need a second template for each option as merc might run into the template and we dont find it then
# Let's check which layout ("NI1_A = bottom exit" , "NI1_B = large room", "NI1_C = small room")
template_match = template_finder.search_and_wait(["NI1_A", "NI1_B", "NI1_C"], threshold=0.65, timeout=20)
if not template_match.valid:
return False
if do_pre_buff:
if not self._char.pre_buff():
return False
# Depending on what template is found we do static pathing to the stairs on level1.
# Its xpects that the static routes defined in game.ini are named: "ni1_a", "ni1_b", "ni1_c"
self._pather.traverse_nodes_fixed(template_match.name.lower(), self._char)
found_loading_screen_func = lambda: loading.wait_for_loading_screen(2.0) or \
template_finder.search_and_wait(["NI2_SEARCH_0", "NI2_SEARCH_1"], threshold=0.8, timeout=0.5).valid
# look for stairs
if not self._char.select_by_template(["NI1_STAIRS", "NI1_STAIRS_2", "NI1_STAIRS_3", "NI1_STAIRS_4"], found_loading_screen_func, threshold=0.63, timeout=4):
# do a random tele jump and try again
pos_m = convert_abs_to_monitor((random.randint(-70, 70), random.randint(-70, 70)))
self._char.move(pos_m, force_move=True)
if not self._char.select_by_template(["NI1_STAIRS", "NI1_STAIRS_2", "NI1_STAIRS_3", "NI1_STAIRS_4"], found_loading_screen_func, threshold=0.63, timeout=4):
return False
# Wait until templates in lvl 2 entrance are found
if not template_finder.search_and_wait(["NI2_SEARCH_0", "NI2_SEARCH_1", "NI2_SEARCH_2"], threshold=0.8, timeout=20).valid:
return False
wait(1.0) # wait to make sure the red writing is gone once we check for the eye
@dataclass
class EyeCheckData:
template_name: list[str]
destination_static_path_key: str
circle_static_path_key: str
save_dist_nodes: list[int]
end_nodes: list[int]
check_arr = [
EyeCheckData(["NI2_A_1_SAFE_DIST", "NI2_A_2_SAFE_DIST", "NI2_A_1_NOATTACK", "NI2_A_2_NOATTACK"], "ni2_a_safe_dist", "ni2_circle_a", [500], [501]),
EyeCheckData(["NI2_B_1_SAFE_DIST", "NI2_B_1_NOATTACK", "NI2_B_2_NOATTACK"], "ni2_b_safe_dist", "ni2_circle_b", [505], [506]),
EyeCheckData(["NI2_C_1_SAFE_DIST", "NI2_C_1_NOATTACK"], "ni2_c_safe_dist", "ni2_circle_c", [510], [511]),
EyeCheckData(["NI2_D_1_SAFE_DIST", "NI2_D_1_NOATTACK"], "ni2_d_safe_dist", "ni2_circle_d", [515], [516, 517]),
]
end_nodes = None
for data in check_arr:
# Move to spot where eye would be visible
self._pather.traverse_nodes_fixed(data.circle_static_path_key, self._char)
# Search for eye
template_match = template_finder.search_and_wait(data.template_name, threshold=0.7, best_match=True, timeout=3)
# If it is found, move down that hallway
if template_match.valid and template_match.name.endswith("_SAFE_DIST"):
self._pather.traverse_nodes_fixed(data.destination_static_path_key, self._char)
self._pather.traverse_nodes(data.save_dist_nodes, self._char, timeout=2, do_pre_move=False)
end_nodes = data.end_nodes
break
# circle back and just assume path a if we failed to find the "eye"
if end_nodes is None:
self._pather.traverse_nodes_fixed("ni2_circle_back_to_a", self._char)
self._pather.traverse_nodes_fixed(check_arr[0].destination_static_path_key, self._char)
self._pather.traverse_nodes(check_arr[0].save_dist_nodes, self._char, timeout=2, do_pre_move=False)
end_nodes = check_arr[0].end_nodes
# Attack & Pick items
if not self._char.kill_nihlathak(end_nodes):
return False
wait(0.2, 0.3)
picked_up_items = self._pickit.pick_up_items(self._char)
return (Location.A5_NIHLATHAK_END, picked_up_items)