def scroll_screen(x: int, y: int, scroll_clicks: int):
        """Attempt to scroll the screen to reveal more UI elements from the provided x and y coordinates.

        Args:
            x (int): X coordinate on the screen.
            y (int): Y coordinate on the screen.
            scroll_clicks (int): How much to scroll the screen. Positive for scrolling up and negative for scrolling down.

        Returns:
            None
        """
        if Settings.debug_mode:
            MessageLog.print_message(
                f"[DEBUG] Now scrolling the screen from ({x}, {y}) by {scroll_clicks} clicks..."
            )

        MouseUtils.move_to(x, y)

        if Settings.enable_bezier_curve_mouse_movement:
            # Reset the pause delay back to 0.25, primarily for ImageUtils' methods using pyautogui.
            pyautogui.PAUSE = 0.25

        pyautogui.scroll(scroll_clicks, x=x, y=y)

        return None
    def scroll_screen_from_home_button(scroll_clicks: int):
        """Attempt to scroll the screen using the "Home" button coordinates to reveal more UI elements.

        Args:
            scroll_clicks (int): How much to scroll the screen. Positive for scrolling up and negative for scrolling down.

        Returns:
            None
        """
        x = Settings.home_button_location[0]
        y = Settings.home_button_location[1] - 50

        if Settings.debug_mode:
            MessageLog.print_message(
                f"[DEBUG] Now scrolling the screen from the \"Home\" button's coordinates at ({x}, {y}) by {scroll_clicks} clicks..."
            )

        MouseUtils.move_to(x, y)

        if Settings.enable_bezier_curve_mouse_movement:
            # Reset the pause delay back to 0.25, primarily for ImageUtils' methods using pyautogui.
            pyautogui.PAUSE = 0.25

        pyautogui.scroll(scroll_clicks, x=x, y=y)

        return None
Exemple #3
0
    def _clear_joined_raids():
        """Begin process to wait out the joined raids if there are 3 or more currently active.

        Returns:
            None
        """
        from bot.game import Game

        # If the maximum number of raids has been joined, collect any pending rewards with a interval of 30 seconds in between until the number of joined raids is below 3.
        while Raid._raids_joined >= 3:
            MessageLog.print_message(
                f"\n[RAID] Maximum raids of 3 has been joined. Waiting 30 seconds to see if any finish."
            )
            Game.wait(30)

            Game.go_back_home(confirm_location_check=True)
            Game.find_and_click_button("quest")

            if Game.check_for_pending():
                Game.find_and_click_button("quest")
                Game.wait(1)

            Game.find_and_click_button("raid")
            Game.wait(1)
            Raid._check_for_joined_raids()

        return None
    def _navigate():
        """Navigates to the specified Proving Grounds mission.

        Returns:
            None
        """
        from bot.game import Game

        # Go to the Home screen.
        Game.go_back_home(confirm_location_check=True)

        MessageLog.print_message(
            f"\n[PROVING.GROUNDS] Now navigating to Proving Grounds...")

        # Go to the Event by clicking on the "Menu" button and then click the very first banner.
        Game.find_and_click_button("home_menu")
        banner_locations = ImageUtils.find_all("event_banner",
                                               custom_confidence=0.7)
        if len(banner_locations) == 0:
            banner_locations = ImageUtils.find_all("event_banner_blue",
                                                   custom_confidence=0.7)
            if len(banner_locations) == 0:
                raise ProvingGroundsException(
                    "Failed to find the Event banner.")
        MouseUtils.move_and_click_point(banner_locations[0][0],
                                        banner_locations[0][1], "event_banner")

        Game.wait(1)

        difficulty = ""
        if Settings.mission_name == "Extreme":
            difficulty = "Extreme"
        elif Settings.mission_name == "Extreme+":
            difficulty = "Extreme+"

        # Select the difficulty.
        if ImageUtils.confirm_location("proving_grounds"):
            if Game.find_and_click_button("proving_grounds_missions"):
                difficulty_button_locations = ImageUtils.find_all(
                    "play_round_button")

                if difficulty == "Extreme":
                    MouseUtils.move_and_click_point(
                        difficulty_button_locations[1][0],
                        difficulty_button_locations[1][1], "play_round_button")
                elif difficulty == "Extreme+":
                    MouseUtils.move_and_click_point(
                        difficulty_button_locations[2][0],
                        difficulty_button_locations[2][1], "play_round_button")

                # After the difficulty has been selected, click "Play" to land the bot at the Proving Grounds' Summon Selection screen.
                Game.find_and_click_button("play")
        else:
            raise ProvingGroundsException(
                "Failed to arrive at the main screen for Proving Grounds.")

        return None
    def move_and_click_point(x: int,
                             y: int,
                             image_name: str,
                             custom_mouse_speed: float = 0.0,
                             mouse_clicks: int = 1):
        """Move the cursor to the specified point on the screen and clicks it.

        Args:
            x (int): X coordinate on the screen.
            y (int): Y coordinate on the screen.
            image_name (str): File name of the image in /images/buttons/ folder.
            custom_mouse_speed (float, optional): Time in seconds it takes for the mouse to move to the specified point. Defaults to 0.0.
            mouse_clicks (int, optional): Number of mouse clicks. Defaults to 1.

        Returns:
            None
        """
        if Settings.debug_mode:
            MessageLog.print_message(f"[DEBUG] Old coordinates: ({x}, {y})")

        new_x, new_y = MouseUtils._randomize_point(x, y, image_name)

        if Settings.debug_mode:
            MessageLog.print_message(
                f"[DEBUG] New coordinates: ({new_x}, {new_y})")

        # Move the mouse to the specified coordinates.
        if Settings.enable_bezier_curve_mouse_movement:
            # HumanClicker only accepts int as the mouse speed.
            if int(custom_mouse_speed) < 1:
                custom_mouse_speed = 1

            MouseUtils._hc.move(
                (new_x, new_y),
                duration=custom_mouse_speed,
                humanCurve=pyclick.HumanCurve(pyautogui.position(),
                                              (new_x, new_y)))
        else:
            if custom_mouse_speed <= 0.0:
                custom_mouse_speed = Settings.custom_mouse_speed

            pyautogui.moveTo(x,
                             y,
                             duration=custom_mouse_speed,
                             tween=pyautogui.easeInOutQuad)

        pyautogui.click(clicks=mouse_clicks)

        # This delay is necessary as ImageUtils will take the screenshot too fast and the bot will use the last frame before clicking to navigate.
        from bot.game import Game
        Game.wait(1)

        return None
    def stop_bot(self):
        """Stops the bot and terminates the Process.

        Returns:
            None
        """
        if self._bot_process is not None:
            MessageLog.print_message(
                "\n[STATUS] Stopping the bot and terminating its Thread.")
            self._bot_process.terminate()

        return None
    async def print_status(self):
        """Grab each message in the Queue and send it as a private DM to the user.

        Returns:
            None
        """
        if self.user is not None and not self.queue.empty():
            message: str = self.queue.get()
            if Settings.debug_mode:
                MessageLog.print_message(
                    f"\n[DEBUG] Acquired message to send via Discord DM: {message}"
                )
            await self.user.send(content=message)
Exemple #8
0
    def start(first_run: bool) -> int:
        """Starts the process to complete a run for Raid Farming Mode and returns the number of items detected.

        Args:
            first_run (bool): Flag that determines whether or not to run the navigation process again. Should be False if the Farming Mode supports the "Play Again" feature for repeated runs.

        Returns:
            (int): Number of items detected.
        """
        from bot.game import Game

        number_of_items_dropped: int = 0

        # Start the navigation process.
        if first_run:
            Raid._navigate()
        else:
            # Check for Pending Battles and then perform navigation again.
            Game.check_for_pending()
            Raid._navigate()

        # Check for EP.
        Game.check_for_ep()

        # Check if the bot is at the Summon Selection screen.
        if ImageUtils.confirm_location("select_a_summon", tries=30):
            summon_check = Game.select_summon(Settings.summon_list,
                                              Settings.summon_element_list)

            if summon_check:
                # Select the Party.
                if Game.find_party_and_start_mission(Settings.group_number,
                                                     Settings.party_number):
                    # Handle the rare case where joining the Raid after selecting the Summon and Party led the bot to the Quest Results screen with no loot to collect.
                    if ImageUtils.confirm_location("no_loot", tries=2):
                        MessageLog.print_message(
                            "\n[RAID] Seems that the Raid just ended. Moving back to the Home screen and joining another Raid..."
                        )
                    elif CombatMode.start_combat_mode():
                        number_of_items_dropped = Game.collect_loot(
                            is_completed=True)
                else:
                    MessageLog.print_message(
                        "\n[RAID] Seems that the Raid ended before the bot was able to join. Now looking for another Raid to join..."
                    )
        else:
            raise RaidException(
                "Failed to arrive at the Summon Selection screen.")

        return number_of_items_dropped
Exemple #9
0
    def start() -> int:
        """Starts the process of completing a generic setup that supports the 'Play Again' logic.

        Returns:
            (int): Number of runs completed.
        """
        from bot.game import Game

        runs_completed = 0

        MessageLog.print_message(
            f"\n[GENERIC] Now checking for run eligibility...")

        # Bot can start either at the Combat screen with the "Attack" button visible or the Loot Collection screen with the "Play Again" button visible.
        if ImageUtils.find_button("attack", tries=5):
            MessageLog.print_message(
                f"[GENERIC] Bot is at the Combat screen. Starting Combat Mode now..."
            )
            if CombatMode.start_combat_mode():
                runs_completed = Game.collect_loot(is_completed=True)
        else:
            MessageLog.print_message(
                f"[GENERIC] Bot is not at the Combat screen. Checking for the Loot Collection screen now..."
            )

            # Press the "Play Again" button if necessary, otherwise start Combat Mode.
            if Game.find_and_click_button("play_again"):
                Game.check_for_popups()
            else:
                raise GenericException(
                    "Failed to detect the 'Play Again' button. Bot can start either at the Combat screen with the 'Attack' button visible or the Loot Collection screen with the 'Play Again' button visible.."
                )

            # Check for AP.
            Game.check_for_ap()

            # Check if the bot is at the Summon Selection screen.
            if ImageUtils.confirm_location("select_a_summon", tries=30):
                summon_check = Game.select_summon(Settings.summon_list,
                                                  Settings.summon_element_list)
                if summon_check:
                    # Do not select party and just commence the mission.
                    MessageLog.print_message(
                        f"[GENERIC] Skipping party selection and immediately commencing mission..."
                    )
                    if Game.find_and_click_button("ok", tries=10):
                        # Now start Combat Mode and detect any item drops.
                        if CombatMode.start_combat_mode():
                            runs_completed = Game.collect_loot(
                                is_completed=True)
                    else:
                        raise GenericException(
                            "Failed to skip party selection.")
            else:
                raise GenericException(
                    "Failed to arrive at the Summon Selection screen.")

        return runs_completed
Exemple #10
0
    def get_room_code():
        """Clean the tweets from the listener and parse out a valid room code from them.

        Returns:
            (str): A single room code that has not been visited.
        """
        if len(TwitterRoomFinder._listener.tweets) == 0:
            MessageLog.print_message(
                f"[TWITTER] There are no recent or detected tweets available for the given raid."
            )
            return ""

        MessageLog.print_message(
            f"[TWITTER] Now cleaning up the tweets and parsing for room codes..."
        )

        while len(TwitterRoomFinder._listener.tweets) > 0:
            tweet = TwitterRoomFinder._listener.tweets.pop()

            if re.search(
                    rf"\b{Settings.mission_name}\b", tweet.text
            ) or re.search(
                    rf"\b{TwitterRoomFinder._list_of_raids[Settings.mission_name]}\b",
                    tweet.text):
                # Split up the tweet's text by whitespaces.
                split_text = tweet.text.split(" ")

                # Parse the room code and if it has not been visited yet, append it to the list.
                for i, identifier in enumerate(split_text):
                    if (":Battle" in identifier) or (":参戦ID" in identifier):
                        parsed_code = split_text[i - 1]
                        if parsed_code not in TwitterRoomFinder._already_visited_codes:
                            MessageLog.print_message(
                                f"[TWITTER] Found {parsed_code} created at {tweet.created_at}"
                            )
                            TwitterRoomFinder._already_visited_codes.append(
                                parsed_code)
                            return parsed_code
                        else:
                            MessageLog.print_message(
                                f"[TWITTER] Already visited {parsed_code} before in this session. Skipping this code..."
                            )
            else:
                MessageLog.print_message(
                    f"[TWITTER] Skipping tweet as it is for a different raid.")

        return ""
    def start_bot(self):
        """Starts the bot's Game class on a new Thread.

        Returns:
            None
        """
        # Create a new Process whose target is the MainDriver's run_bot() method.
        self._bot_process = multiprocessing.Process(target=self._run_bot)

        MessageLog.print_message(
            "[STATUS] Starting bot process on a new thread now...")

        # Now start the new Process on a new Thread.
        self._bot_process.start()
        self._bot_process.is_alive()

        return None
    def _check_for_boss() -> bool:
        """Checks for the existence of 3-3, 6-3 or 9-3 boss if user settings enabled it.

        Returns:
            (bool): Flag on whether or not a Boss was detected.
        """
        if Settings.enable_stop_on_arcarum_boss:
            MessageLog.print_message(
                f"\n[ARCARUM] Checking if boss is available...")

            if ImageUtils.find_button("arcarum_boss",
                                      tries=1) or ImageUtils.find_button(
                                          "arcarum_boss2", tries=1):
                return True
            else:
                return False
        else:
            return False
Exemple #13
0
    def _navigate():
        """Navigates to the specified Raid.

        Returns:
            None
        """
        from bot.game import Game

        MessageLog.print_message(
            f"\n[RAID] Beginning process to navigate to the raid: {Settings.mission_name}..."
        )

        # Head to the Home screen.
        Game.go_back_home(confirm_location_check=True)

        # Then navigate 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=1):
            Game.find_and_click_button("ok")

        # Check for any Pending Battles popup.
        if Game.check_for_pending():
            Game.find_and_click_button("quest")

        # Now navigate to the Raid screen.
        Game.find_and_click_button("raid")

        if ImageUtils.confirm_location("raid"):
            # Check for any joined raids and if the max number of raids joined was reached, clear them.
            Raid._check_for_joined_raids()
            Raid._clear_joined_raids()

            # Click on the "Enter ID" button and then start the process to join a raid.
            MessageLog.print_message(
                f"\n[RAID] Now moving to the \"Enter ID\" screen.")
            if Game.find_and_click_button("enter_id"):
                Raid._join_raid()
        else:
            raise RaidException("Failed to reach the Backup Requests screen.")
Exemple #14
0
    def _check_for_joined_raids():
        """Check and update the number of raids currently joined.

        Returns:
            None
        """
        from bot.game import Game

        # Find out the number of currently joined raids.
        Game.wait(1)
        joined_locations = ImageUtils.find_all("joined")

        if joined_locations is not None:
            Raid._raids_joined = len(joined_locations)
            MessageLog.print_message(
                f"\n[RAID] There are currently {Raid._raids_joined} raids joined."
            )

        return None
def start_now(token: str, user_id: int, queue: multiprocessing.Queue):
    """Initialize the Client object and begin the process to connect to the Discord API.

    Args:
        token (str): Discord Token for use with Discord's API.
        user_id (int): The user's Discord user ID.
        queue (multiprocessing.Queue): The Queue holding messages to be sent to the user over Discord.

    Returns:
        None
    """
    client = discord.Client()
    MyClient(client, user_id, queue)
    try:
        client.run(token)
    except LoginFailure:
        MessageLog.print_message(
            "\n[DISCORD] Failed to connect to Discord API. Please double check your token.\n"
        )
Exemple #16
0
    def _take_screenshot():
        """Takes a screenshot of the Quest Results screen when called in find_farmed_items().

        Returns:
            None
        """
        MessageLog.print_message(
            f"[INFO] Taking a screenshot of the Quest Results screen...")

        # Construct the image file and folder name from the current date, time, and image number.
        current_time = datetime.datetime.now().strftime("%H-%M-%S")
        current_date = date.today()
        new_file_name = f"{current_date} {current_time} #{ImageUtils._image_number}"
        ImageUtils._image_number += 1
        if ImageUtils._new_folder_name is None:
            ImageUtils._new_folder_name = f"{current_date} {current_time}"

        # Take a screenshot using the calibrated window dimensions.
        new_image: PIL.Image.Image = pyautogui.screenshot(
            region=(Settings.window_left, Settings.window_top,
                    Settings.window_width, Settings.window_height))

        # Create the /results/ directory if it does not already exist.
        current_dir = os.getcwd()
        results_dir = os.path.join(current_dir, r"results")
        if not os.path.exists(results_dir):
            os.makedirs(results_dir)

        # Then create a new folder to hold this session's screenshots in.
        new_dir = os.path.join(current_dir, r"results",
                               ImageUtils._new_folder_name)
        if not os.path.exists(new_dir):
            os.makedirs(new_dir)

        # Finally, save the new image into the results directory with its new file name.
        new_image.save(
            f"{ImageUtils._current_dir}/results/{ImageUtils._new_folder_name}/{new_file_name}.jpg"
        )
        MessageLog.print_message(
            f"[INFO] Results image saved as \"{new_file_name}.jpg\" in \"{ImageUtils._new_folder_name}\" folder..."
        )
        return None
Exemple #17
0
    def wait_vanish(image_name: str,
                    timeout: int = 10,
                    suppress_error: bool = False) -> bool:
        """Check if the provided image vanishes from the screen after a certain amount of time.

        Args:
            image_name (str): Name of the image file in the /images/buttons/ folder.
            timeout (int, optional): Timeout in tries. Defaults to 10.
            suppress_error (bool, optional): Suppresses template matching error if True. Defaults to False.

        Returns:
            (bool): True if the image vanishes from the screen within the allotted time or False if timeout was reached.
        """
        MessageLog.print_message(
            f"\n[INFO] Now waiting for {image_name} to vanish from screen...")

        template: numpy.ndarray = cv2.imread(
            f"{ImageUtils._current_dir}/images/buttons/{image_name.lower()}.jpg",
            0)

        for _ in range(timeout):
            if ImageUtils._match(template) is False:
                MessageLog.print_message(
                    f"[SUCCESS] Image successfully vanished from screen...")
                return True

        if suppress_error is False:
            MessageLog.print_message(
                f"[WARNING] Image did not vanish from screen...")

        return False
Exemple #18
0
    def connect():
        if Settings.farming_mode == "Raid":
            MessageLog.print_message(
                f"\n[TWITTER] Authenticating provided consumer keys and tokens with the Twitter API..."
            )
            _auth = tweepy.OAuthHandler(Settings.twitter_keys_tokens[0],
                                        Settings.twitter_keys_tokens[1])
            _auth.set_access_token(Settings.twitter_keys_tokens[2],
                                   Settings.twitter_keys_tokens[3])
            _api = tweepy.API(_auth)

            # Check to see if connection to Twitter's API was successful.
            if not _api.verify_credentials():
                raise (ConnectionError(
                    f"[ERROR] Failed to connect to the Twitter API. Check your keys and tokens."
                ))

            MessageLog.print_message(
                f"[TWITTER] Successfully connected to the Twitter API.")

            # Create the listener and stream objects. for the Twitter Stream API.
            TwitterRoomFinder._stream = tweepy.Stream(
                auth=_api.auth, listener=TwitterRoomFinder._listener)

            # Start asynchronous process of listening to tweets for the specified raid.
            MessageLog.print_message(
                f"\n[TWITTER] Now listening onto the Stream API for the newest tweets for {Settings.mission_name}."
            )
            TwitterRoomFinder._stream.filter(track=[
                Settings.mission_name,
                TwitterRoomFinder._list_of_raids[Settings.mission_name]
            ],
                                             is_async=True,
                                             filter_level="none")
Exemple #19
0
    def find_button(image_name: str,
                    custom_confidence: float = 0.8,
                    tries: int = 5,
                    suppress_error: bool = False):
        """Find the location of the specified button.

        Args:
            image_name (str): Name of the button image file in the /images/buttons/ folder.
            custom_confidence (float, optional): Accuracy threshold for matching. Defaults to 0.8.
            tries (int, optional): Number of tries before failing. Defaults to 5.
            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 button is located if image matching was successful. Otherwise, return None.
        """
        if Settings.debug_mode:
            MessageLog.print_message(
                f"\n[DEBUG] Starting process to find the {image_name.upper()} button image..."
            )

        template: numpy.ndarray = cv2.imread(
            f"{ImageUtils._current_dir}/images/buttons/{image_name.lower()}.jpg",
            0)

        while tries > 0:
            result_flag: bool = ImageUtils._match(template, custom_confidence)

            if result_flag is False:
                tries -= 1
                if tries <= 0:
                    if not suppress_error:
                        MessageLog.print_message(
                            f"[WARNING] Failed to find the {image_name.upper()} button."
                        )
                    return None
            else:
                return ImageUtils._match_location

        return None
Exemple #20
0
    def confirm_location(image_name: str,
                         custom_confidence: float = 0.8,
                         tries: int = 5,
                         suppress_error: bool = False):
        """Confirm the position of the bot by searching for the header image.

        Args:
            image_name (str): Name of the header image file in the /images/headers/ folder.
            custom_confidence (float, optional): Accuracy threshold for matching. Defaults to 0.8.
            tries (int, optional): Number of tries before failing. Defaults to 5.
            suppress_error (bool, optional): Suppresses template matching error if True. Defaults to False.

        Returns:
            (bool): True if current location is confirmed. Otherwise, False.
        """
        if Settings.debug_mode:
            MessageLog.print_message(
                f"\n[DEBUG] Starting process to find the {image_name.upper()} button image..."
            )

        template: numpy.ndarray = cv2.imread(
            f"{ImageUtils._current_dir}/images/headers/{image_name.lower()}_header.jpg",
            0)

        while tries > 0:
            result_flag: bool = ImageUtils._match(template, custom_confidence)

            if result_flag is False:
                tries -= 1
                if tries <= 0:
                    if not suppress_error:
                        MessageLog.print_message(
                            f"[WARNING] Failed to confirm the bot's location at {image_name.upper()}."
                        )
                    return False
            else:
                return True

        return False
    async def before_print_status(self):
        """Determine when the bot has successfully connected to the Discord API and found the user.

        Returns:
            None
        """
        MessageLog.print_message(
            "[DISCORD] Waiting for connection to Discord API...")
        await self.bot.wait_until_ready()
        MessageLog.print_message(
            "[DISCORD] Successful connection to Discord API")
        self.queue.put(
            f"```diff\n+ Successful connection to Discord API for Granblue Automation\n```"
        )

        try:
            self.user = await self.bot.fetch_user(self.user_id)
            MessageLog.print_message(f"[DISCORD] Found user: {self.user.name}")
        except discord.errors.NotFound:
            MessageLog.print_message("[DISCORD] Failed to find user.\n")
    def _navigate():
        """Navigates to the specified Xeno Clash mission.

        Returns:
            None
        """
        from bot.game import Game

        # Go to the Home screen.
        Game.go_back_home(confirm_location_check = True)

        MessageLog.print_message(f"\n[XENO.CLASH] Now navigating to Xeno Clash...")

        # Go to the Event by clicking on the "Menu" button and then click the very first banner.
        Game.find_and_click_button("home_menu")
        event_banner_locations = ImageUtils.find_all("event_banner", custom_confidence = 0.7)
        if len(event_banner_locations) == 0:
            event_banner_locations = ImageUtils.find_all("event_banner_blue", custom_confidence = 0.7)
        MouseUtils.move_and_click_point(event_banner_locations[0][0], event_banner_locations[0][1], "event_banner")

        Game.wait(2.0)

        if Game.find_and_click_button("xeno_special", tries = 30):
            # Check to see if the user already has a Nightmare available.
            nightmare_is_available = 0
            if ImageUtils.find_button("event_nightmare", tries = 1) is not None:
                nightmare_is_available = 1

            # Find all the "Select" buttons.
            select_button_locations = ImageUtils.find_all("select")

            if Settings.mission_name == "Xeno Clash Extreme":
                MessageLog.print_message(f"[XENO.CLASH] Now hosting Xeno Clash Extreme...")
                MouseUtils.move_and_click_point(select_button_locations[1 + nightmare_is_available][0], select_button_locations[1 + nightmare_is_available][1], "select")

                difficulty_button_locations = ImageUtils.find_all("play_round_button")
                MouseUtils.move_and_click_point(difficulty_button_locations[0][0], difficulty_button_locations[0][1], "play_round_button")
            elif Settings.mission_name == "Xeno Clash Raid":
                MessageLog.print_message(f"[XENO.CLASH] Now hosting Xeno Clash Raid...")
                MouseUtils.move_and_click_point(select_button_locations[2 + nightmare_is_available][0], select_button_locations[2 + nightmare_is_available][1], "select")

                Game.wait(2.0)

                Game.find_and_click_button("play")
        else:
            raise(XenoClashException("Failed to open the Xeno Special tab."))

        return None
    def _navigate():
        """Navigates to the specified Event mission.

        Returns:
            None
        """
        from bot.game import Game

        # Switch over to the navigation logic for Event (Token Drawboxes) if needed.
        if Settings.farming_mode == "Event (Token Drawboxes)":
            Event._navigate_token_drawboxes()
        else:
            MessageLog.print_message(
                f"[EVENT] Now beginning process to navigate to the mission: {Settings.mission_name}..."
            )

            # Go to the Home screen.
            Game.go_back_home(confirm_location_check=True)

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

            # Go to the Special screen.
            Game.find_and_click_button("special")
            Game.wait(3.0)

            Game.find_and_click_button("special_event")

            # Remove the difficulty prefix from the mission name.
            difficulty = ""
            formatted_mission_name = ""
            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:]
            elif Settings.mission_name.find("EX+ ") == 0:
                difficulty = "Extreme+"
                formatted_mission_name = Settings.mission_name[4:]

            if ImageUtils.confirm_location("special"):
                # Check to see if the user already has a Nightmare available.
                nightmare_is_available = 0
                if ImageUtils.find_button("event_nightmare",
                                          tries=1) is not None:
                    nightmare_is_available = 1

                # Find all the "Select" buttons.
                select_button_locations = ImageUtils.find_all("select")
                if Settings.enable_event_location_incrementation_by_one:
                    position = 1
                else:
                    position = 0

                # Select the Event Quest or Event Raid. Additionally, offset the locations by 1 if there is a Nightmare available.
                try:
                    if formatted_mission_name == "Event Quest":
                        MessageLog.print_message(
                            f"[EVENT] Now hosting Event Quest...")
                        MouseUtils.move_and_click_point(
                            select_button_locations[position +
                                                    nightmare_is_available][0],
                            select_button_locations[position +
                                                    nightmare_is_available][1],
                            "select")
                    elif formatted_mission_name == "Event Raid":
                        MessageLog.print_message(
                            f"[EVENT] Now hosting Event Raid...")
                        MouseUtils.move_and_click_point(
                            select_button_locations[(position + 1) +
                                                    nightmare_is_available][0],
                            select_button_locations[(position + 1) +
                                                    nightmare_is_available][1],
                            "play_round_button")
                except IndexError as e:
                    MessageLog.print_message(
                        f"\n[ERROR] Turn on/off the 'Enable Incrementation of Location by 1' and try again."
                    )
                    raise IndexError(e)

                Game.wait(1)

                # Find all the round "Play" buttons.
                round_play_button_locations = ImageUtils.find_all(
                    "play_round_button")

                # If Extreme+ was selected and only 3 locations were found for the play_round_button, that means Extreme+ is not available.
                if len(round_play_button_locations
                       ) == 3 and difficulty == "Extreme+":
                    MessageLog.print_message(
                        f"[EVENT] Extreme+ was selected but it seems it is not available. Defaulting to Extreme difficulty..."
                    )
                    difficulty = "Extreme"

                # Now select the chosen difficulty.
                if difficulty == "Very Hard":
                    MouseUtils.move_and_click_point(
                        round_play_button_locations[0][0],
                        round_play_button_locations[0][1], "play_round_button")
                elif difficulty == "Extreme":
                    MouseUtils.move_and_click_point(
                        round_play_button_locations[1][0],
                        round_play_button_locations[1][1], "play_round_button")
                elif difficulty == "Extreme+":
                    MouseUtils.move_and_click_point(
                        round_play_button_locations[2][0],
                        round_play_button_locations[2][1], "play_round_button")
            else:
                raise EventException(
                    "Failed to arrive at the Special Quest screen.")

        return None
    def check_for_event_nightmare():
        """Checks for Event Nightmare and if it appears and the user enabled it in user settings, start it.

        Returns:
            (bool): Return True if Event Nightmare was detected and successfully completed. Otherwise, return False.
        """
        from bot.game import Game

        if Settings.enable_nightmare and ImageUtils.confirm_location(
                "limited_time_quests", tries=1):
            # First check if the Event Nightmare is skippable.
            event_claim_loot_location = ImageUtils.find_button(
                "event_claim_loot", tries=1, suppress_error=True)
            if event_claim_loot_location is not None:
                MessageLog.print_message(
                    "\n[EVENT] Skippable Event Nightmare detected. Claiming it now..."
                )
                MouseUtils.move_and_click_point(event_claim_loot_location[0],
                                                event_claim_loot_location[1],
                                                "event_claim_loot")
                Game.collect_loot(is_completed=False, is_event_nightmare=True)
                return True
            else:
                MessageLog.print_message(
                    "\n[EVENT] Detected Event Nightmare. Starting it now...")

                MessageLog.print_message(
                    "\n********************************************************************************"
                )
                MessageLog.print_message(
                    "********************************************************************************"
                )
                MessageLog.print_message(f"[EVENT] Event Nightmare")
                MessageLog.print_message(
                    f"[EVENT] Event Nightmare Summon Elements: {Settings.nightmare_summon_elements_list}"
                )
                MessageLog.print_message(
                    f"[EVENT] Event Nightmare Summons: {Settings.nightmare_summon_list}"
                )
                MessageLog.print_message(
                    f"[EVENT] Event Nightmare Group Number: {Settings.nightmare_group_number}"
                )
                MessageLog.print_message(
                    f"[EVENT] Event Nightmare Party Number: {Settings.nightmare_party_number}"
                )
                MessageLog.print_message(
                    f"[EVENT] Event Nightmare Combat Script: {Settings.nightmare_combat_script_name}"
                )
                MessageLog.print_message(
                    "********************************************************************************"
                )
                MessageLog.print_message(
                    "********************************************************************************\n"
                )

                # Click the "Play Next" button to head to the Summon Selection screen.
                Game.find_and_click_button("play_next")

                Game.wait(1)

                # Once the bot is at the Summon Selection screen, select your Summon and Party and start the mission.
                if ImageUtils.confirm_location("select_a_summon"):
                    Game.select_summon(Settings.nightmare_summon_list,
                                       Settings.nightmare_summon_elements_list)
                    start_check = Game.find_party_and_start_mission(
                        int(Settings.nightmare_group_number),
                        int(Settings.nightmare_party_number))

                    # Once preparations are completed, start Combat Mode.
                    if start_check and CombatMode.start_combat_mode(
                            is_nightmare=True):
                        Game.collect_loot(is_completed=False,
                                          is_event_nightmare=True)
                        return True

        elif not Settings.enable_nightmare and ImageUtils.confirm_location(
                "limited_time_quests", tries=1):
            # First check if the Event Nightmare is skippable.
            event_claim_loot_location = ImageUtils.find_button(
                "event_claim_loot", tries=1, suppress_error=True)
            if event_claim_loot_location is not None:
                MessageLog.print_message(
                    "\n[EVENT] Skippable Event Nightmare detected but user opted to not run it. Claiming it regardless..."
                )
                MouseUtils.move_and_click_point(event_claim_loot_location[0],
                                                event_claim_loot_location[1],
                                                "event_claim_loot")
                Game.collect_loot(is_completed=False, is_event_nightmare=True)
                return True
            else:
                MessageLog.print_message(
                    "\n[EVENT] Event Nightmare detected but user opted to not run it. Moving on..."
                )
                Game.find_and_click_button("close")
        else:
            MessageLog.print_message(
                "\n[EVENT] No Event Nightmare detected. Moving on...")

        return False
    def _navigate_token_drawboxes():
        """Navigates to the specified Event (Token Drawboxes) mission.

        Returns:
            None
        """
        from bot.game import Game

        MessageLog.print_message(
            f"[EVENT.TOKEN.DRAWBOXES] Now 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 Event by clicking on the "Menu" button and then click the very first banner.
        Game.find_and_click_button("home_menu")
        banner_locations = ImageUtils.find_all("event_banner",
                                               custom_confidence=0.7)
        if len(banner_locations) == 0:
            banner_locations = ImageUtils.find_all("event_banner_blue",
                                                   custom_confidence=0.7)
            if len(banner_locations) == 0:
                raise EventException("Failed to find the Event banner.")
        MouseUtils.move_and_click_point(banner_locations[0][0],
                                        banner_locations[0][1], "event_banner")

        Game.wait(1)

        # Check and click away the "Daily Missions" popup.
        if ImageUtils.confirm_location("event_daily_missions", tries=1):
            MessageLog.print_message(
                f"\n[EVENT.TOKEN.DRAWBOXES] Detected \"Daily Missions\" popup. Clicking it away..."
            )
            Game.find_and_click_button("close")

        # Remove the difficulty prefix from the mission name.
        difficulty = ""
        formatted_mission_name = ""
        if 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:]
        elif Settings.mission_name.find("EX+ ") == 0:
            difficulty = "Extreme+"
            formatted_mission_name = Settings.mission_name[4:]
        elif Settings.mission_name.find("IM ") == 0:
            difficulty = "Impossible"
            formatted_mission_name = Settings.mission_name[3:]

        # Scroll down the screen a little bit for this UI layout that has Token Drawboxes.
        MouseUtils.scroll_screen_from_home_button(-200)

        if formatted_mission_name == "Event Quest":
            MessageLog.print_message(
                f"[EVENT.TOKEN.DRAWBOXES] Now hosting Event Quest...")
            Game.find_and_click_button("event_quests")

            Game.wait(1)

            # Find all the round "Play" buttons.
            quest_play_locations = ImageUtils.find_all("play_round_button")

            # Only Extreme and Extreme+ difficulty is supported for farming efficiency.
            if difficulty == "Extreme":
                MouseUtils.move_and_click_point(quest_play_locations[3][0],
                                                quest_play_locations[3][1],
                                                "play_round_button")
            elif difficulty == "Extreme+":
                MouseUtils.move_and_click_point(quest_play_locations[4][0],
                                                quest_play_locations[4][1],
                                                "play_round_button")
        elif formatted_mission_name == "Event Raid":
            # Bring up the "Raid Battle" popup. Then scroll down the screen a bit for screens less than 1440p to see the entire popup.
            MessageLog.print_message(
                f"[EVENT.TOKEN.DRAWBOXES] Now hosting Event Raid...")
            if not Game.find_and_click_button("event_raid_battle"):
                ImageUtils.generate_alert(
                    "Failed to detect Token Drawbox layout for this Event. Are you sure this Event has Token Drawboxes? If not, switch to \"Event\" Farming Mode."
                )
                raise EventException(
                    "Failed to detect Token Drawbox layout for this Event. Are you sure this Event has Token Drawboxes? If not, switch to \"Event\" Farming Mode."
                )
            MouseUtils.scroll_screen_from_home_button(-200)

            Game.wait(1)

            ap_locations = ImageUtils.find_all("ap")

            if difficulty == "Very Hard":
                MouseUtils.move_and_click_point(ap_locations[0][0],
                                                ap_locations[0][1], "ap")
                if not ImageUtils.wait_vanish("close", timeout=10):
                    MouseUtils.move_and_click_point(ap_locations[0][0],
                                                    ap_locations[0][1], "ap")
                else:
                    return None
            elif difficulty == "Extreme":
                MouseUtils.move_and_click_point(ap_locations[1][0],
                                                ap_locations[1][1], "ap")
                if not ImageUtils.wait_vanish("close", timeout=10):
                    MouseUtils.move_and_click_point(ap_locations[1][0],
                                                    ap_locations[1][1], "ap")
                else:
                    return None
            elif difficulty == "Impossible":
                MouseUtils.move_and_click_point(ap_locations[2][0],
                                                ap_locations[2][1], "ap")
                if not ImageUtils.wait_vanish("close", timeout=10):
                    MouseUtils.move_and_click_point(ap_locations[2][0],
                                                    ap_locations[2][1], "ap")
                else:
                    return None

            # If the user does not have enough Treasures to host a Extreme or an Impossible Raid, host a Very Hard Raid instead.
            MessageLog.print_message(
                f"[EVENT.TOKEN.DRAWBOXES] Not enough materials to host {difficulty}. Hosting Very Hard instead..."
            )
            MouseUtils.move_and_click_point(ap_locations[0][0],
                                            ap_locations[0][1], "ap")
            if not ImageUtils.wait_vanish("close", timeout=10):
                MouseUtils.move_and_click_point(ap_locations[0][0],
                                                ap_locations[0][1], "ap")

        return None
Exemple #26
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
Exemple #27
0
    def check_for_dimensional_halo():
        """Checks for Dimensional Halo and if it appears and the user enabled it in user settings, start it.

        Returns:
            (bool): Return True if Dimensional Halo was detected and successfully completed. Otherwise, return False.
        """
        from bot.game import Game

        if Settings.enable_nightmare and ImageUtils.confirm_location(
                "limited_time_quests", tries=1):
            MessageLog.print_message(
                "\n[D.HALO] Detected Dimensional Halo. Starting it now...")
            Special._dimensional_halo_amount += 1

            MessageLog.print_message(
                "\n********************************************************************************"
            )
            MessageLog.print_message(
                "********************************************************************************"
            )
            MessageLog.print_message(f"[D.HALO] Dimensional Halo")
            MessageLog.print_message(
                f"[D.HALO] Dimensional Halo Summon Elements: {Settings.nightmare_summon_elements_list}"
            )
            MessageLog.print_message(
                f"[D.HALO] Dimensional Halo Summons: {Settings.nightmare_summon_list}"
            )
            MessageLog.print_message(
                f"[D.HALO] Dimensional Halo Group Number: {Settings.nightmare_group_number}"
            )
            MessageLog.print_message(
                f"[D.HALO] Dimensional Halo Party Number: {Settings.nightmare_party_number}"
            )
            MessageLog.print_message(
                f"[D.HALO] Dimensional Halo Combat Script: {Settings.nightmare_combat_script_name}"
            )
            MessageLog.print_message(
                "********************************************************************************"
            )
            MessageLog.print_message(
                "********************************************************************************\n"
            )

            # Click the "Play Next" button to head to the Summon Selection screen.
            Game.find_and_click_button("play_next")

            Game.wait(1)

            # Once the bot is at the Summon Selection screen, select your Summon and Party and start the mission.
            if ImageUtils.confirm_location("select_a_summon"):
                Game.select_summon(Settings.nightmare_summon_list,
                                   Settings.nightmare_summon_elements_list)
                start_check = Game.find_party_and_start_mission(
                    int(Settings.nightmare_group_number),
                    int(Settings.nightmare_party_number))

                # Once preparations are completed, start Combat Mode.
                if start_check and CombatMode.start_combat_mode(
                        is_nightmare=True):
                    Game.collect_loot(is_completed=False,
                                      is_event_nightmare=True)
                    return True

        elif not Settings.enable_nightmare and ImageUtils.confirm_location(
                "limited_time_quests", tries=1):
            MessageLog.print_message(
                "\n[D.HALO] Dimensional Halo detected but user opted to not run it. Moving on..."
            )
            Game.find_and_click_button("close")
        else:
            MessageLog.print_message(
                "\n[D.HALO] No Dimensional Halo detected. Moving on...")

        return False
    def _navigate():
        """Navigates to the specified Rise of the Beasts mission.

        Returns:
            None
        """
        from bot.game import Game

        # Go to the Home screen.
        Game.go_back_home(confirm_location_check=True)

        MessageLog.print_message(
            f"\n[ROTB] Now navigating to Rise of the Beasts...")

        # Go to the Event by clicking on the "Menu" button and then click the very first banner.
        Game.find_and_click_button("home_menu")
        banner_locations = ImageUtils.find_all("event_banner",
                                               custom_confidence=0.7)
        if len(banner_locations) == 0:
            banner_locations = ImageUtils.find_all("event_banner_blue",
                                                   custom_confidence=0.7)
        MouseUtils.move_and_click_point(banner_locations[0][0],
                                        banner_locations[0][1], "event_banner")

        Game.wait(1)

        if ImageUtils.confirm_location("rotb"):
            # Remove the difficulty prefix from the mission name.
            difficulty = ""
            temp_mission_name = ""
            if Settings.mission_name.find("VH ") == 0:
                difficulty = "Very Hard"
                temp_mission_name = Settings.mission_name[3:]
            elif Settings.mission_name.find("EX ") == 0:
                difficulty = "Extreme"
                temp_mission_name = Settings.mission_name[3:]

            # Only Raids are marked with Extreme difficulty.
            if difficulty == "Extreme":
                # Click on the Raid banner.
                MessageLog.print_message(
                    f"[ROTB] Now hosting {temp_mission_name} Raid...")
                Game.find_and_click_button("rotb_extreme")

                if ImageUtils.confirm_location("rotb_battle_the_beasts",
                                               tries=30):
                    if temp_mission_name == "Zhuque":
                        MessageLog.print_message(
                            f"[ROTB] Now starting EX Zhuque Raid...")
                        Game.find_and_click_button("rotb_raid_zhuque")
                    elif temp_mission_name == "Xuanwu":
                        MessageLog.print_message(
                            f"[ROTB] Now starting EX Xuanwu Raid...")
                        Game.find_and_click_button("rotb_raid_xuanwu")
                    elif temp_mission_name == "Baihu":
                        MessageLog.print_message(
                            f"[ROTB] Now starting EX Baihu Raid...")
                        Game.find_and_click_button("rotb_raid_baihu")
                    elif temp_mission_name == "Qinglong":
                        MessageLog.print_message(
                            f"[ROTB] Now starting EX Qinglong Raid...")
                        Game.find_and_click_button("rotb_raid_qinglong")
                else:
                    raise (RiseOfTheBeastsException(
                        "Failed to open the ROTB Battle the Beasts popup."))

            elif Settings.mission_name == "Lvl 100 Shenxian":
                # Click on Shenxian to host.
                MessageLog.print_message(
                    f"[ROTB] Now hosting Shenxian Raid...")
                Game.find_and_click_button("rotb_shenxian_host")

                if ImageUtils.wait_vanish("rotb_shenxian_host",
                                          timeout=10) is False:
                    MessageLog.print_message(
                        f"[ROTB] There are no more Shenxian hosts left. Alerting user..."
                    )
                    raise RiseOfTheBeastsException(
                        "There are no more Shenxian hosts left.")

            else:
                MessageLog.print_message(
                    f"[ROTB] Now hosting {temp_mission_name} Quest...")

                # Scroll the screen down to make way for smaller screens.
                MouseUtils.scroll_screen_from_home_button(-400)

                # Find all instances of the "Select" button on the screen and click on the first instance.
                select_button_locations = ImageUtils.find_all("select")
                MouseUtils.move_and_click_point(select_button_locations[0][0],
                                                select_button_locations[0][1],
                                                "select")

                if ImageUtils.confirm_location("rotb_rising_beasts_showdown",
                                               tries=30):
                    # Find all the round "Play" buttons.
                    round_play_button_locations = ImageUtils.find_all(
                        "play_round_button")

                    if temp_mission_name == "Zhuque":
                        MouseUtils.move_and_click_point(
                            round_play_button_locations[0][0],
                            round_play_button_locations[0][1],
                            "play_round_button")
                    elif temp_mission_name == "Xuanwu":
                        MouseUtils.move_and_click_point(
                            round_play_button_locations[1][0],
                            round_play_button_locations[1][1],
                            "play_round_button")
                    elif temp_mission_name == "Baihu":
                        MouseUtils.move_and_click_point(
                            round_play_button_locations[2][0],
                            round_play_button_locations[2][1],
                            "play_round_button")
                    elif temp_mission_name == "Qinglong":
                        MouseUtils.move_and_click_point(
                            round_play_button_locations[3][0],
                            round_play_button_locations[3][1],
                            "play_round_button")

                    Game.wait(2.0)

                    # Find all the round "Play" buttons again.
                    round_play_button_locations = ImageUtils.find_all(
                        "play_round_button")

                    # Only Very Hard difficulty will be supported for farming efficiency
                    MouseUtils.move_and_click_point(
                        round_play_button_locations[2][0],
                        round_play_button_locations[2][1], "play_round_button")
                else:
                    raise (RiseOfTheBeastsException(
                        "Failed to open the ROTB Rising Beasts Showdown popup."
                    ))

        return None
    def check_for_rotb_extreme_plus():
        """Checks for Extreme+ for Rise of the Beasts and if it appears and the user enabled it in user settings, start it.

        Returns:
            (bool): Return True if Extreme+ was detected and successfully completed. Otherwise, return False.
        """
        from bot.game import Game

        if Settings.enable_nightmare and ImageUtils.confirm_location(
                "rotb_extreme_plus", tries=1):
            MessageLog.print_message(
                "\n[ROTB] Detected Extreme+. Starting it now...")

            MessageLog.print_message(
                "\n********************************************************************************"
            )
            MessageLog.print_message(
                "********************************************************************************"
            )
            MessageLog.print_message(f"[ROTB] Rise of the Beasts Extreme+")
            MessageLog.print_message(
                f"[ROTB] Rise of the Beasts Extreme+ Summon Elements: {Settings.nightmare_summon_elements_list}"
            )
            MessageLog.print_message(
                f"[ROTB] Rise of the Beasts Extreme+ Summons: {Settings.nightmare_summon_list}"
            )
            MessageLog.print_message(
                f"[ROTB] Rise of the Beasts Extreme+ Group Number: {Settings.nightmare_group_number}"
            )
            MessageLog.print_message(
                f"[ROTB] Rise of the Beasts Extreme+ Party Number: {Settings.nightmare_party_number}"
            )
            MessageLog.print_message(
                f"[ROTB] Rise of the Beasts Extreme+ Combat Script: {Settings.nightmare_combat_script_name}"
            )
            MessageLog.print_message(
                "********************************************************************************"
            )
            MessageLog.print_message(
                "********************************************************************************\n"
            )

            # Click the "Play Next" button to head to the Summon Selection screen.
            Game.find_and_click_button("play_next")

            Game.wait(1)

            # Once the bot is at the Summon Selection screen, select your Summon and Party and start the mission.
            if ImageUtils.confirm_location("select_a_summon"):
                Game.select_summon(Settings.nightmare_summon_list,
                                   Settings.nightmare_summon_elements_list)
                start_check = Game.find_party_and_start_mission(
                    int(Settings.nightmare_group_number),
                    int(Settings.nightmare_party_number))

                # Once preparations are completed, start Combat mode.
                if start_check and CombatMode.start_combat_mode(
                        is_nightmare=True):
                    Game.collect_loot(is_completed=False,
                                      is_event_nightmare=True)
                    return True

        elif not Settings.enable_nightmare and ImageUtils.confirm_location(
                "rotb_extreme_plus", tries=2):
            MessageLog.print_message(
                "\n[ROTB] Rise of the Beasts Extreme+ detected but user opted to not run it. Moving on..."
            )
            Game.find_and_click_button("close")
        else:
            MessageLog.print_message(
                "\n[ROTB] No Rise of the Beasts Extreme+ detected. Moving on..."
            )

        return False
Exemple #30
0
    def _navigate():
        """Navigates to the specified Dread Barrage mission.

        Returns:
            None
        """
        from bot.game import Game

        # Go to the Home screen.
        Game.go_back_home(confirm_location_check = True)

        # Scroll down the screen a little bit and then click the Dread Barrage banner.
        MessageLog.print_message(f"\n[DREAD.BARRAGE] Now navigating to Dread Barrage...")
        MouseUtils.scroll_screen_from_home_button(-400)
        Game.find_and_click_button("dread_barrage")

        Game.wait(2)

        if ImageUtils.confirm_location("dread_barrage"):
            # Check if there is already a hosted Dread Barrage mission.
            if ImageUtils.confirm_location("resume_quests", tries = 1):
                MessageLog.print_message(f"\n[WARNING] Detected that there is already a hosted Dread Barrage mission.")
                expiry_time_in_seconds = 0

                while ImageUtils.confirm_location("resume_quests", tries = 1):
                    # If there is already a hosted Dread Barrage mission, the bot will wait for a total of 1 hour and 30 minutes
                    # for either the raid to expire or for anyone in the room to clear it.
                    MessageLog.print_message(f"\n[WARNING] The bot will now either wait for the expiry time of 1 hour and 30 minutes or for someone else in the room to clear it.")
                    MessageLog.print_message(f"[WARNING] The bot will now refresh the page every 30 seconds to check if it is still there before proceeding.")
                    MessageLog.print_message(f"[WARNING] User can either wait it out, revive and fight it to completion, or retreat from the mission manually.")
                    Game.wait(30)

                    Game.find_and_click_button("reload")
                    Game.wait(2)

                    expiry_time_in_seconds += 30
                    if expiry_time_in_seconds >= 5400:
                        break

                MessageLog.print_message(f"\n[SUCCESS] Hosted Dread Barrage mission is now gone either because of timeout or someone else in the room killed it. Moving on...\n")

            # Find all the "Play" buttons at the top of the window.
            dread_barrage_play_button_locations = ImageUtils.find_all("dread_barrage_play")

            difficulty = ""
            if Settings.mission_name.find("1 Star") == 0:
                difficulty = "1 Star"
            elif Settings.mission_name.find("2 Star") == 0:
                difficulty = "2 Star"
            elif Settings.mission_name.find("3 Star") == 0:
                difficulty = "3 Star"
            elif Settings.mission_name.find("4 Star") == 0:
                difficulty = "4 Star"
            elif Settings.mission_name.find("5 Star") == 0:
                difficulty = "5 Star"

            # Navigate to the specified difficulty.
            if difficulty == "1 Star":
                MessageLog.print_message(f"[DREAD.BARRAGE] Now starting 1 Star Dread Barrage Raid...")
                MouseUtils.move_and_click_point(dread_barrage_play_button_locations[0][0], dread_barrage_play_button_locations[0][1], "dread_barrage_play")
            elif difficulty == "2 Star":
                MessageLog.print_message(f"[DREAD.BARRAGE] Now starting 2 Star Dread Barrage Raid...")
                MouseUtils.move_and_click_point(dread_barrage_play_button_locations[1][0], dread_barrage_play_button_locations[1][1], "dread_barrage_play")
            elif difficulty == "3 Star":
                MessageLog.print_message(f"[DREAD.BARRAGE] Now starting 3 Star Dread Barrage Raid...")
                MouseUtils.move_and_click_point(dread_barrage_play_button_locations[2][0], dread_barrage_play_button_locations[2][1], "dread_barrage_play")
            elif difficulty == "4 Star":
                MessageLog.print_message(f"[DREAD.BARRAGE] Now starting 4 Star Dread Barrage Raid...")
                MouseUtils.move_and_click_point(dread_barrage_play_button_locations[3][0], dread_barrage_play_button_locations[3][1], "dread_barrage_play")
            elif difficulty == "5 Star":
                MessageLog.print_message(f"[DREAD.BARRAGE] Now starting 5 Star Dread Barrage Raid...")
                MouseUtils.move_and_click_point(dread_barrage_play_button_locations[4][0], dread_barrage_play_button_locations[4][1], "dread_barrage_play")

            Game.wait(2)