def find_summon(summon_list: List[str], summon_element_list: List[str], home_button_x: int, home_button_y: int, custom_confidence: float = 0.8, suppress_error: bool = False): """Find the location of the specified Summon. Will attempt to scroll the screen down to see more Summons if the initial screen position yielded no matches. Args: summon_list (List[str]): List of names of the Summon image's file name in /images/summons/ folder. summon_element_list (List[str]): List of names of the Summon element image file in the /images/buttons/ folder. home_button_x (int): X coordinate of where the center of the Home Button is. home_button_y (int): Y coordinate of where the center of the Home Button is. custom_confidence (float, optional): Accuracy threshold for matching. Defaults to 0.8. suppress_error (bool, optional): Suppresses template matching error if True. Defaults to False. Returns: (Tuple[int, int]): Tuple of coordinates of where the center of the Summon is located if image matching was successful. Otherwise, return None. """ from bot.game import Game if Settings.debug_mode: MessageLog.print_message( f"[DEBUG] Received the following list of Summons to search for: {str(summon_list)}" ) MessageLog.print_message( f"[DEBUG] Received the following list of Elements: {str(summon_element_list)}" ) last_summon_element = "" summon_index = 0 # Make sure that the bot is at the Summon Selection screen. tries = 10 while not ImageUtils.confirm_location("select_a_summon"): Game.find_and_click_button('reload') tries -= 1 if tries <= 0 and ImageUtils.confirm_location("select_a_summon", tries=1) is False: raise Exception("Could not reach the Summon Selection screen.") # Determine if all the summon elements are the same or not. This will influence whether or not the bot needs to change elements in repeated runs. ImageUtils._summon_selection_same_element = all( element == summon_element_list[0] for element in summon_element_list) while True: # Perform first time setup by selecting the correct summon element. if ImageUtils._summon_selection_first_run or ImageUtils._summon_selection_same_element is False: current_summon_element: str = summon_element_list[summon_index] if current_summon_element != last_summon_element: Game.find_and_click_button( f"summon_{current_summon_element}") last_summon_element = current_summon_element ImageUtils._summon_selection_first_run = False summon_index = 0 while summon_index < len(summon_list): # Now try and find the Summon at the current index. template: numpy.ndarray = cv2.imread( f"{ImageUtils._current_dir}/images/summons/{summon_list[summon_index]}.jpg", 0) # Crop the summon template image so that plus marks would not potentially obscure any match. height, width = template.shape template = template[0:height, 0:width - 40] result_flag: bool = ImageUtils._match(template, custom_confidence) if result_flag: if Settings.debug_mode: MessageLog.print_message( f"[SUCCESS] Found {summon_list[summon_index].upper()} Summon at {ImageUtils._match_location}." ) return ImageUtils._match_location else: if suppress_error is False: MessageLog.print_message( f"[WARNING] Could not locate {summon_list[summon_index].upper()} Summon." ) summon_index += 1 # If the bot reached the bottom of the page, scroll back up to the top and start searching for the next Summon. if ImageUtils.find_button("bottom_of_summon_selection", tries=1) is not None: MessageLog.print_message( f"[WARNING] Bot has reached the bottom of the page and found no suitable Summons. Resetting Summons now..." ) return None # If matching failed, scroll the screen down to see more Summons. from utils.mouse_utils import MouseUtils MouseUtils.scroll_screen(home_button_x, home_button_y - 50, -700) Game.wait(1.0)
def _navigate(): """Navigates to the specified Special mission. Returns: None """ from bot.game import Game MessageLog.print_message( f"\n[SPECIAL] Beginning process to navigate to the mission: {Settings.mission_name}..." ) # Go to the Home screen. Game.go_back_home(confirm_location_check=True) # Go to the Quest screen. Game.find_and_click_button("quest", suppress_error=True) # Check for the "You retreated from the raid battle" popup. Game.wait(1) if ImageUtils.confirm_location("you_retreated_from_the_raid_battle", tries=1): Game.find_and_click_button("ok") if ImageUtils.confirm_location("quest"): # Go to the Special screen. Game.find_and_click_button("special") # Remove the difficulty prefix from the mission name. difficulty = "" if Settings.mission_name.find("N ") == 0: difficulty = "Normal" formatted_mission_name = Settings.mission_name[2:] elif Settings.mission_name.find("H ") == 0: difficulty = "Hard" formatted_mission_name = Settings.mission_name[2:] elif Settings.mission_name.find("VH ") == 0: difficulty = "Very Hard" formatted_mission_name = Settings.mission_name[3:] elif Settings.mission_name.find("EX ") == 0: difficulty = "Extreme" formatted_mission_name = Settings.mission_name[3:] else: formatted_mission_name = Settings.mission_name if ImageUtils.confirm_location("special"): tries = 2 # Try to select the specified Special mission for a number of tries. while tries != 0: # Scroll the screen down if its any of the Special Quests that are more towards the bottom of the page to alleviate problems for smaller screens. if Settings.map_name != "Campaign-Exclusive Quest" and Settings.map_name != "Basic Treasure Quests" and Settings.map_name != "Shiny Slime Search!" and Settings.map_name != "Six Dragon Trial": MouseUtils.scroll_screen_from_home_button(-500) mission_select_button = ImageUtils.find_button( Settings.map_name.lower().replace(" ", "_").replace( "-", "_")) if mission_select_button is not None: MessageLog.print_message( f"[SPECIAL] Navigating to {Settings.map_name}...") # Move to the specified Special by clicking its "Select" button. special_quest_select_button = ( mission_select_button[0] + 145, mission_select_button[1] + 75) MouseUtils.move_and_click_point( special_quest_select_button[0], special_quest_select_button[1], "select") Game.wait(1) if Settings.map_name == "Basic Treasure Quests": locations = ImageUtils.find_all( "play_round_button") if formatted_mission_name == "Scarlet Trial": # Navigate to Scarlet Trial. MessageLog.print_message( f"[SPECIAL] Selecting Scarlet Trial...") MouseUtils.move_and_click_point( locations[0][0], locations[0][1], "play_round_button") elif formatted_mission_name == "Cerulean Trial": # Navigate to Cerulean Trial. MessageLog.print_message( f"[SPECIAL] Selecting Cerulean Trial...") MouseUtils.move_and_click_point( locations[1][0], locations[1][1], "play_round_button") elif formatted_mission_name == "Violet Trial": # Navigate to Violet Trial. MessageLog.print_message( f"[SPECIAL] Selecting Violet Trial...") MouseUtils.move_and_click_point( locations[2][0], locations[2][1], "play_round_button") Game.wait(1) # Now start the Trial with the specified difficulty. MessageLog.print_message( f"[SPECIAL] Now navigating to {difficulty}...") locations = ImageUtils.find_all( "play_round_button") if difficulty == "Normal": MouseUtils.move_and_click_point( locations[0][0], locations[0][1], "play_round_button") elif difficulty == "Hard": MouseUtils.move_and_click_point( locations[1][0], locations[1][1], "play_round_button") elif difficulty == "Very Hard": MouseUtils.move_and_click_point( locations[2][0], locations[2][1], "play_round_button") elif Settings.map_name == "Shiny Slime Search!": # Start up the Shiny Slime Search! mission by selecting its difficulty. MessageLog.print_message( f"[SPECIAL] Selecting {difficulty} Shiny Slime Search!..." ) locations = ImageUtils.find_all( "play_round_button") if difficulty == "Normal": MouseUtils.move_and_click_point( locations[0][0], locations[0][1], "play_round_button") elif difficulty == "Hard": MouseUtils.move_and_click_point( locations[1][0], locations[1][1], "play_round_button") elif difficulty == "Very Hard": MouseUtils.move_and_click_point( locations[2][0], locations[2][1], "play_round_button") elif Settings.map_name == "Six Dragon Trial": # Start up the Six Dragon Trial mission by selecting its difficulty. MessageLog.print_message( f"[SPECIAL] Selecting {difficulty} Six Dragon Trial..." ) locations = ImageUtils.find_all( "play_round_button") if difficulty == "Normal": MouseUtils.move_and_click_point( locations[0][0], locations[0][1], "play_round_button") elif difficulty == "Hard": MouseUtils.move_and_click_point( locations[1][0], locations[1][1], "play_round_button") elif difficulty == "Very Hard": MouseUtils.move_and_click_point( locations[2][0], locations[2][1], "play_round_button") elif Settings.map_name == "Elemental Treasure Quests": # Start up the specified Elemental Treasure Quest mission. MessageLog.print_message( f"[SPECIAL] Selecting {Settings.mission_name}..." ) locations = ImageUtils.find_all( "play_round_button") if formatted_mission_name == "The Hellfire Trial": MouseUtils.move_and_click_point( locations[0][0], locations[0][1], "play_round_button") elif formatted_mission_name == "The Deluge Trial": MouseUtils.move_and_click_point( locations[1][0], locations[1][1], "play_round_button") elif formatted_mission_name == "The Wasteland Trial": MouseUtils.move_and_click_point( locations[2][0], locations[2][1], "play_round_button") elif formatted_mission_name == "The Typhoon Trial": MouseUtils.move_and_click_point( locations[3][0], locations[3][1], "play_round_button") elif formatted_mission_name == "The Aurora Trial": MouseUtils.move_and_click_point( locations[4][0], locations[4][1], "play_round_button") elif formatted_mission_name == "The Oblivion Trial": MouseUtils.move_and_click_point( locations[5][0], locations[5][1], "play_round_button") elif Settings.map_name == "Showdowns": locations = ImageUtils.find_all( "play_round_button") if formatted_mission_name == "Ifrit Showdown": # Navigate to Ifrit Showdown. MessageLog.print_message( f"[SPECIAL] Selecting Ifrit Showdown...") MouseUtils.move_and_click_point( locations[0][0], locations[0][1], "play_round_button") elif formatted_mission_name == "Cocytus Showdown": # Navigate to Cocytus Showdown. MessageLog.print_message( f"[SPECIAL] Selecting Cocytus Showdown...") MouseUtils.move_and_click_point( locations[1][0], locations[1][1], "play_round_button") elif formatted_mission_name == "Vohu Manah Showdown": # Navigate to Vohu Manah Showdown. MessageLog.print_message( f"[SPECIAL] Selecting Vohu Manah Showdown..." ) MouseUtils.move_and_click_point( locations[2][0], locations[2][1], "play_round_button") elif formatted_mission_name == "Sagittarius Showdown": # Navigate to Sagittarius Showdown. MessageLog.print_message( f"[SPECIAL] Selecting Sagittarius Showdown..." ) MouseUtils.move_and_click_point( locations[3][0], locations[3][1], "play_round_button") elif formatted_mission_name == "Corow Showdown": # Navigate to Corow Showdown. MessageLog.print_message( f"[SPECIAL] Selecting Corow Showdown...") MouseUtils.move_and_click_point( locations[4][0], locations[4][1], "play_round_button") elif formatted_mission_name == "Diablo Showdown": # Navigate to Diablo Showdown. MessageLog.print_message( f"[SPECIAL] Selecting Diablo Showdown...") MouseUtils.move_and_click_point( locations[5][0], locations[5][1], "play_round_button") # Now start the Showdown with the specified difficulty. Game.wait(1) MessageLog.print_message( f"[SPECIAL] Now navigating to {difficulty}...") locations = ImageUtils.find_all( "play_round_button") if difficulty == "Hard": MouseUtils.move_and_click_point( locations[0][0], locations[0][1], "play_round_button") elif difficulty == "Very Hard": MouseUtils.move_and_click_point( locations[1][0], locations[1][1], "play_round_button") elif difficulty == "Extreme": MouseUtils.move_and_click_point( locations[2][0], locations[2][1], "play_round_button") elif Settings.map_name == "Campaign-Exclusive Quest": MessageLog.print_message( f"[SPECIAL] Selecting Campaign-Exclusive Quest..." ) locations = ImageUtils.find_all( "play_round_button") # There is only one round "Play" button for this time-limited quest. MouseUtils.move_and_click_point( locations[0][0], locations[0][1], "play_round_button") else: # Start up the Angel Halo mission by selecting its difficulty. MessageLog.print_message( f"[SPECIAL] Selecting {difficulty} Angel Halo..." ) locations = ImageUtils.find_all( "play_round_button") if difficulty == "Normal": MouseUtils.move_and_click_point( locations[0][0], locations[0][1], "play_round_button") elif difficulty == "Hard": MouseUtils.move_and_click_point( locations[1][0], locations[1][1], "play_round_button") elif difficulty == "Very Hard": MouseUtils.move_and_click_point( locations[2][0], locations[2][1], "play_round_button") break else: # Scroll the screen down more if on a smaller screen and it obscures the targeted mission. MouseUtils.scroll_screen( Settings.home_button_location[0], Settings.home_button_location[1] - 50, -500) tries -= 1 return None
def _navigate(): """Navigates to the specified Quest mission. Returns: None """ from bot.game import Game MessageLog.print_message( f"\n[QUEST] Beginning process to navigate to the mission: {Settings.mission_name}..." ) # Go to the Home screen. Game.go_back_home(confirm_location_check=True) current_location = "" formatted_map_name = Settings.map_name.lower().replace(" ", "_").replace( "-", "_") # Check which island the bot is at. if ImageUtils.confirm_location(f"map_{formatted_map_name}", tries=3): MessageLog.print_message( f"[QUEST] Bot is currently on the correct island.") check_location = True else: MessageLog.print_message( f"[QUEST] Bot is currently not on the correct island.") check_location = False location_list = [ "Zinkenstill", "Port Breeze Archipelago", "Valtz Duchy", "Auguste Isles", "Lumacie Archipelago", "Albion Citadel", "Mist-Shrouded Isle", "Golonzo Island", "Amalthea Island", "Former Capital Mephorash", "Agastia" ] while len(location_list) > 0: temp_map_location = location_list.pop(0) temp_formatted_map_location = temp_map_location.lower( ).replace(" ", "_").replace("-", "_") if ImageUtils.confirm_location( f"map_{temp_formatted_map_location}", tries=1): MessageLog.print_message( f"[QUEST] Bot's current location is at {temp_map_location}. Now moving to {Settings.map_name}..." ) current_location = temp_map_location break # Once the bot has determined where it is, go to the Quest screen. Game.find_and_click_button("quest") Game.wait(1) # Check for the "You retreated from the raid battle" popup. if ImageUtils.confirm_location("you_retreated_from_the_raid_battle", tries=3): Game.find_and_click_button("ok") if ImageUtils.confirm_location("quest"): # If the bot is currently not at the correct island, move to it. if not check_location: # Click the "World" button. Game.find_and_click_button("world") # On the World screen, click the specified coordinates on the window to move to the island. If the island is on a different world page, switch pages as necessary. Quest._navigate_to_map(Settings.map_name, current_location) # Click "Go" on the popup after clicking on the map node. Game.find_and_click_button("go") # Grab the location of the "World" button. world_location = ImageUtils.find_button("world", tries=5) if world_location is None: world_location = ImageUtils.find_button("world2", tries=5) # Now that the bot is on the correct island and is at the Quest screen, click the correct chapter node. if Settings.mission_name == "Scattered Cargo": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 1 (115) node at ({world_location[0] + 97}, {world_location[1] + 97})..." ) MouseUtils.move_and_click_point(world_location[0] + 97, world_location[1] + 97, "template_node") elif Settings.mission_name == "Lucky Charm Hunt": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 6 (122) node...") MouseUtils.move_and_click_point(world_location[0] + 332, world_location[1] + 16, "template_node") elif Settings.mission_name == "Special Op's Request": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 8 node...") MouseUtils.move_and_click_point(world_location[0] + 258, world_location[1] + 151, "template_node") elif Settings.mission_name == "Threat to the Fisheries": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 9 node...") MouseUtils.move_and_click_point(world_location[0] + 216, world_location[1] + 113, "template_node") elif Settings.mission_name == "The Fruit of Lumacie" or Settings.mission_name == "Whiff of Danger": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 13 (39/52) node...") MouseUtils.move_and_click_point(world_location[0] + 78, world_location[1] + 92, "template_node") elif Settings.mission_name == "I Challenge You!": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 17 node...") MouseUtils.move_and_click_point(world_location[0] + 119, world_location[1] + 121, "template_node") elif Settings.mission_name == "For Whom the Bell Tolls": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 22 node...") MouseUtils.move_and_click_point(world_location[0] + 178, world_location[1] + 33, "template_node") elif Settings.mission_name == "Golonzo's Battles of Old": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 25 node...") MouseUtils.move_and_click_point(world_location[0] + 196, world_location[1] + 5, "template_node") elif Settings.mission_name == "The Dungeon Diet": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 30 (44/65) node...") MouseUtils.move_and_click_point(world_location[0] + 242, world_location[1] + 24, "template_node") elif Settings.mission_name == "Trust Busting Dustup": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 36 (123) node...") MouseUtils.move_and_click_point(world_location[0] + 319, world_location[1] + 13, "template_node") elif Settings.mission_name == "Erste Kingdom Episode 4": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 70 node...") MouseUtils.move_and_click_point(world_location[0] + 253, world_location[1] + 136, "template_node") elif Settings.mission_name == "Imperial Wanderer's Soul": MessageLog.print_message( f"\n[QUEST] Moving to Chapter 55 node...") MouseUtils.move_and_click_point(world_location[0] + 162, world_location[1] + 143, "template_node") # After being on the correct chapter node, scroll down the screen as far as possible and then click the mission to start. MouseUtils.scroll_screen(Settings.home_button_location[0], Settings.home_button_location[1] - 50, -1000) Game.find_and_click_button(Settings.mission_name.replace(" ", "_")) # Apply special navigation for mission "Ch. 70 - Erste Kingdom". if Settings.mission_name == "Erste Kingdom Episode 4": Game.find_and_click_button("episode_4") Game.find_and_click_button("ok") return None