예제 #1
0
    def testCanAddLocationToRegion(self):

        region = Region(100, 100, 1, 1)

        # Check that initialized properly
        self.assertEqual(region.getX(), 100)
        self.assertEqual(region.getY(), 100)
        self.assertEqual(region.getW(), 1)
        self.assertEqual(region.getH(), 1)

        region = region.add(Location(50, 50))

        # X,Y Should have changed to 50
        self.assertEqual(region.getX(), 50)
        self.assertEqual(region.getY(), 50)

        # W,H should have changed to 50
        self.assertEqual(region.getW(), 51)
        self.assertEqual(region.getH(), 51)

        region = region.add(Location(200, 50))

        # Width/Height should have changed to 200/200
        self.assertEqual(region.getX(), 50)
        self.assertEqual(region.getY(), 50)
        self.assertEqual(region.getW(), 150)
        self.assertEqual(region.getH(), 51)

        region = region.add(Location(200, 200))

        # Width/Height should have changed to 200/200
        self.assertEqual(region.getX(), 50)
        self.assertEqual(region.getY(), 50)
        self.assertEqual(region.getW(), 150)
        self.assertEqual(region.getH(), 150)
예제 #2
0
    def wait_and_click_and_wait(
            cls, click_region, click_target, wait_region, wait_target, time=10,
            expand=[]):
        """Method to wait for the appearance of an image match, click it,
        then wait for another subsequent image match.

        Args:
            click_region (Region): Region to conduct the initial match in
            click_target (str, Pattern): the filename of the asset or Pattern
                to search for the initial click
            wait_region (Region): Region to conduct the second match in
            wait_target (str, Pattern): the filename of the asset or Pattern
                to search for in the second wait check
            time (int, optional): max amount of time to wait for assets to
                appear
            expand (list, optional): area expansion for the click
        """
        click_region.wait(click_target, time)
        if Globals.SLEEP_MODIFIER:
            cls.kc_sleep()
        click_region.click(
            cls.generate_pattern(click_region, click_target, expand, True))
        try:
            wait_region.wait(wait_target, time)
        except FindFailed:
            # the initial click might have failed due to lag within the client;
            # rejigger the mouse and retry the click if this happens
            click_region.mouseMove(Location(1, 1))
            cls.wait_and_click_and_wait(
                click_region, click_target, wait_region, wait_target, time,
                expand)

        cls.kc_sleep()
예제 #3
0
    def click_node(self, kc_region):
        rand_x = kc_region.x + randint(self.coords[0] - 5, self.coords[0] + 5)
        rand_y = kc_region.y + randint(self.coords[1] - 5, self.coords[1] + 5)

        kc_region.mouseMove(Location(rand_x, rand_y))
        kc_region.mouseDown(Button.LEFT)
        Util.kc_sleep()
        kc_region.mouseUp(Button.LEFT)
예제 #4
0
    def testSetOffset(self):

        region = Region(100, 100, 100, 100)
        region = region.offset(Location(100, 100))

        self.assertEqual(region.getX(), 200)
        self.assertEqual(region.getY(), 200)
        self.assertEqual(region.getW(), 100)
        self.assertEqual(region.getH(), 100)
예제 #5
0
    def _pick_fleet_ship(self):
        """Method to click a fleet ship based on the fleet icons displayed next
        to the ship in the ship list.

        Returns:
            boolean: True if a fleet ship was chosen and clicked, False
                otherwise
        """
        Util.log_msg("Picking damaged ship from combat fleet(s) to repair.")
        # generate markers for fleets to repair
        fleet_markers = []
        if self.config.combat['fleet_mode'] == 'striking':
            fleet_markers = ['repairlist_fleet_3.png']
        else:
            fleet_markers = [
                'repairlist_fleet_1_flag.png', 'repairlist_fleet_1.png'
            ]
            if self.config.combat['combined_fleet']:
                fleet_markers.append('repairlist_fleet_2.png')

        # get damages to repair
        valid_damages = CombatFleet.get_damages_at_threshold(
            self.config.combat['repair_limit'])

        for fleet_marker in fleet_markers:
            fleet_id = int(fleet_marker[17])  # infer from filename
            fleet_instance = self.fleets[fleet_id]

            if fleet_instance.get_damage_counts_at_threshold(
                    self.config.combat['repair_limit']) == 0:
                # if this fleet has no longer has ships that need repair,
                # don't search for its marker
                continue

            ship_matches = Util.findAll_wrapper(
                self.regions['repair_shiplist_fleet_markers'],
                Pattern(fleet_marker).similar(0.9))
            for ship_match in ship_matches:
                target_region = ship_match.offset(Location(342, 0)).nearby(5)
                for damage in valid_damages:
                    if fleet_instance.damage_counts[damage] == 0:
                        # if no ships in this fleet are at this damage state,
                        # don't search for it
                        continue

                    damage_icon = 'repairlist_dmg_{}.png'.format(damage)
                    if Util.check_and_click(target_region, damage_icon,
                                            Globals.EXPAND['repair_list']):
                        fleet_instance.damage_counts[damage] -= 1
                        fleet_instance.damage_counts['repair'] += 1
                        return True
        return False
예제 #6
0
    def testSetClickOffset(self):

        region = Region(100, 100, 100, 100)
        region.setClickOffset(Location(10, 10))

        # Check that it is set right
        location = region.getClickOffset()
        self.assertEqual(location.getX(), 10)
        self.assertEqual(location.getY(), 10)

        location = region.getClickLocation()
        self.assertEqual(location.getX(), 160.0)
        self.assertEqual(location.getY(), 160.0)
예제 #7
0
    def click_coords(cls, region, x, y):
        """Method to move the mouse to the specified x,y coordinates and
        simulate clicking the mouse on the location.

        Args:
            region (Region): sikuli Region instance containing the last known
                location of the Kantai Collection game screen
            x (int): x-coords in pixels, relative to upper-left corner of game
            y (int): y-coords in pixels, relative to upper-left corner of game
        """
        # offset x,y coords relative to upper-left corner of game to upper-left
        # corner of screen
        offset_x = region.x + x
        offset_y = region.y + y
        # move the mouse to offset location
        region.mouseMove(Location(offset_x, offset_y))
        cls.click_mouse(region)
예제 #8
0
    def rejigger_mouse(cls, regions, preset):
        """Method to move the mouse to a random X,Y coordinate in the specified
        preset region.

        Args:
            regions (dict): dict of pre-defined kcauto regions
            preset (str): name of preset-area to move the mouse to
        """
        # preset areas are designated as (X_start, X_end, Y_start, Y_end)
        presets = {
            'game': (0, Globals.GAME_WIDTH, 0, Globals.GAME_HEIGHT),
            'center': (225, 975, 180, 540),
            'top': (400, 1200, 12, 42),
            'quest_menu': (790, 895, 50, 95),
            'shipgirl': (700, 1100, 130, 550),
            'lbas': (500, 700, 5, 50),
            'lbas_mode_switch_button': (1150, 1175, 210, 265),
            '7th_next': (386, 413, 400, 427)  # NU
        }

        if isinstance(preset, str):
            x1, x2, y1, y2 = presets[preset]
            # max bounds
            temp_screen = Screen().getBounds()
            max_x = temp_screen.width
            max_y = temp_screen.height

            rand_x = regions['game'].x + cls.random_coord(x1, x2)
            rand_y = regions['game'].y + cls.random_coord(y1, y2)

            rand_x = max_x - 1 if rand_x > max_x else rand_x
            rand_y = max_y - 1 if rand_y > max_y else rand_y
        elif (isinstance(preset, Region) or isinstance(preset, JRegion)
              or isinstance(preset, Match) or isinstance(preset, JMatch)):
            rand_x = cls.random_coord(preset.x, preset.x + preset.w)
            rand_y = cls.random_coord(preset.y, preset.y + preset.h)

        regions['game'].mouseMove(Location(rand_x, rand_y))
예제 #9
0
    def rejigger_mouse(cls, regions, preset):
        """Method to move the mouse to a random X,Y coordinate in the specified
        preset region.

        Args:
            regions (dict): dict of pre-defined kcauto-kai regions
            preset (str): name of preset-area to move the mouse to
        """
        # preset areas are designated as (X_start, X_end, Y_start, Y_end)
        presets = {
            'game': (0, 800, 0, 480),
            'center': (150, 650, 130, 350),
            'top': (120, 780, 5, 25),
            'shipgirl': (370, 780, 100, 420),
            'lbas': (350, 450, 5, 50),
            'lbas_mode_switch_button': (763, 788, 137, 179),
            '7th_next': (386, 413, 400, 427)
        }

        if isinstance(preset, str):
            x1, x2, y1, y2 = presets[preset]
            # max bounds
            temp_screen = Screen().getBounds()
            max_x = temp_screen.width
            max_y = temp_screen.height

            rand_x = regions['game'].x + cls.randint_gauss(x1, x2)
            rand_y = regions['game'].y + cls.randint_gauss(y1, y2)

            rand_x = max_x - 1 if rand_x > max_x else rand_x
            rand_y = max_y - 1 if rand_y > max_y else rand_y
        elif (isinstance(preset, Region) or isinstance(preset, JRegion)
                or isinstance(preset, Match) or isinstance(preset, JMatch)):
            rand_x = cls.randint_gauss(preset.x, preset.x + preset.w)
            rand_y = cls.randint_gauss(preset.y, preset.y + preset.h)

        regions['game'].mouseMove(Location(rand_x, rand_y))
예제 #10
0
    def recover(kcauto_kai, e):
        """Attempts very basic recovery actions on a FindFailed exception. WIP
        and does not integrate with the config.

        Args:
            kcauto_kai (KCAutoKai): KCAutoKai instance
            e (Exception): Exception

        Returns:
            bool: True on successful recovery, otherwise raises an error
        """
        kc_region = kcauto_kai.kc_region
        regions = kcauto_kai.regions
        recovery_method = 'kc3'

        Util.log_warning(
            "FindFailed error occurred; attempting basic recovery.")

        App.focus(kcauto_kai.config.program)
        kc_region.mouseMove(Location(1, 1))

        # basic recovery attempt
        type(Key.ESC)
        sleep(1)
        if kc_region.exists(Pattern('kc_reference_point.png').exact()):
            # reference point exists, so we are in-game
            Util.log_success("Recovery successful.")
            kcauto_kai.stats.increment_recoveries()
            return True
        elif kc_region.exists('next.png'):
            # crashed at some results screen; try to click it away until we see
            # the main game screen
            while (kc_region.exists('next.png') and not kc_region.exists(
                    Pattern('kc_reference_point.png').exact())):
                Util.click_screen(regions, 'center')
                sleep(2)
            if kc_region.exists(Pattern('kc_reference_point.png').exact()):
                # reference point exists, so we are back in-game
                Util.log_success("Recovery successful.")
                kcauto_kai.stats.increment_recoveries()
                return True

        # catbomb recovery
        if kc_region.exists('catbomb.png') and recovery_method != 'None':
            if recovery_method == 'browser':
                Region.type(Key.F5)
            elif recovery_method == 'kc3':
                Region.type(Key.F5)
                sleep(1)
                Region.type(Key.SPACE)
                sleep(1)
                Region.type(Key.TAB)
                sleep(1)
                Region.type(Key.SPACE)
            elif recovery_method == 'kcv':
                Region.type(Key.F5)
            elif recovery_method == 'kct':
                Region.type(Key.ALT)
                sleep(1)
                Region.type(Key.DOWN)
                sleep(1)
                Region.type(Key.DOWN)
                sleep(1)
                Region.type(Key.ENTER)
            elif recovery_method == 'eo':
                Region.type(Key.F5)
                sleep(1)
                Region.type(Key.TAB)
                sleep(1)
                Region.type(Key.SPACE)
            sleep(3)
            kc_region.mouseMove(Location(0, 0))
            sleep(3)
            Util.wait_and_click(kc_region,
                                Pattern('game_start.png').similar(0.999), 60)
            sleep(5)
            Util.log_success("Recovery successful.")
            kcauto_kai.stats.increment_recoveries()
            return True

        # recovery failed
        Util.log_error("Irrecoverable crash")
        print(e)
        raise
예제 #11
0
    def recover(kcauto_kai, config, e):
        """Attempts very basic recovery actions on a FindFailed exception. WIP
        and does not integrate with the config.

        Args:
            kcauto_kai (KCAutoKai): KCAutoKai instance
            config (Config): Config instance
            e (Exception): Exception

        Returns:
            bool: True on successful recovery, otherwise raises an error
        """
        kc_region = (kcauto_kai.kc_region
                     if kcauto_kai.kc_region else Util.focus_kc(config))
        kc_region = kcauto_kai.kc_region
        regions = kcauto_kai.regions

        Util.log_warning(e)
        Util.log_warning(
            "** FindFailed error occurred; attempting basic recovery. **")

        App.focus(kcauto_kai.config.program)
        kc_region.mouseMove(Location(1, 1))

        # basic recovery attempt
        Region.type(kc_region, Key.ESC)
        sleep(1)
        Region.type(kc_region, Key.SPACE)
        if kc_region.exists(Pattern('kc_reference_point.png').exact()):
            # reference point exists, so we are in-game
            Util.log_success("Recovery successful.")
            kcauto_kai.stats.increment_recoveries()
            return True
        elif kc_region.exists('next.png'):
            # crashed at some results screen; try to click it away until we see
            # the main game screen
            while (kc_region.exists('next.png') and not kc_region.exists(
                    Pattern('kc_reference_point.png').exact())):
                Util.click_preset_region(regions, 'center')
                sleep(2)
            if kc_region.exists(Pattern('kc_reference_point.png').exact()):
                # reference point exists, so we are back in-game
                Util.log_success("Recovery successful.")
                kcauto_kai.stats.increment_recoveries()
                return True

        # catbomb recovery
        if kc_region.exists('catbomb.png', 10):
            Util.log_warning("** Catbomb detected. **")
            catbombed = True
            catbomb_n = 0
            while catbombed and catbomb_n < 7:
                # generic f5-space-tab-space keystrokes to mimick refresh
                # attempt
                Region.type(kc_region, Key.F5)
                sleep(1)
                Region.type(kc_region, Key.SPACE)
                sleep(1)
                Region.type(kc_region, Key.TAB)
                sleep(1)
                Region.type(kc_region, Key.SPACE)
                sleep(3)
                # clear mouse
                kc_region.mouseMove(Location(1, 1))
                if kc_region.exists('catbomb.png'):
                    sleep_len = pow(2, catbomb_n + 4)
                    Util.log_warning(
                        "Catbomb recovery attempt {} failed; trying again in "
                        "{} seconds!".format(catbomb_n + 1, sleep_len))
                    sleep(sleep_len)
                    catbomb_n += 1
                else:
                    catbombed = False
            sleep(3)
            Util.wait_and_click(kc_region,
                                Pattern('game_start.png').similar(0.999), 60)
            sleep(5)
            Util.log_success("Catbomb recovery successful.")
            kcauto_kai.stats.increment_recoveries()
            return True

        # recovery failed
        Util.log_error("** Irrecoverable crash. **")
        print(e)
        raise
예제 #12
0
 def test_moveTo(self):
     r = Rectangle(0, 10, 20, 30)
     r.moveTo(Location(5, 15))
     self.assertEqual((r.x, r.y, r.w, r.h), (5, 15, 20, 30))
예제 #13
0
 def test_getCenter(self):
     r = Rectangle(0, 10, 20, 30)
     self.assertEqual(r.getCenter(), Location(10, 25))
예제 #14
0
    def _pick_fleet_ship(self):
        """Method to click a fleet ship based on the fleet icons displayed next
        to the ship in the ship list.

        Returns:
            boolean: True if a fleet ship was chosen and clicked, False
                otherwise
        """
        Util.log_msg("Picking damaged ship from combat fleet(s) to repair.")
        # generate markers for fleets to repair
        fleet_markers = []
        if self.config.combat['fleet_mode'] == 'striking':
            fleet_markers = ['repairlist_fleet_3.png']
        else:
            fleet_markers = [
                'repairlist_fleet_1_flag.png', 'repairlist_fleet_1.png'
            ]
            if self.config.combat['combined_fleet']:
                fleet_markers.append('repairlist_fleet_2.png')

        # get damages to repair
        valid_damages = CombatFleet.get_damages_at_threshold(
            self.config.combat['repair_limit'])

        while self.current_shiplist_page <= self.ship_page_count:
            for fleet_marker in fleet_markers:
                fleet_id = int(fleet_marker[17])  # infer from filename
                fleet_instance = self.fleets[fleet_id]

                if fleet_instance.get_damage_counts_at_threshold(
                        self.config.combat['repair_limit']) == 0:
                    # if this fleet has no longer has ships that need repair,
                    # don't search for its marker
                    continue

                ship_matches = Util.findAll_wrapper(
                    self.module_regions['repair_shiplist_fleet_markers'],
                    Pattern(fleet_marker).similar(0.9))
                for ship_match in ship_matches:
                    target_region = ship_match.offset(Location(525,
                                                               0)).nearby(10)
                    for damage in valid_damages:
                        if fleet_instance.damage_counts[damage] == 0:
                            # if no ships in this fleet are at this damage
                            # state, don't search for it
                            continue

                        damage_icon = 'repairlist_dmg_{}.png'.format(damage)
                        if Util.check_and_click(target_region, damage_icon,
                                                Globals.EXPAND['repair_list']):
                            fleet_instance.damage_counts[damage] -= 1
                            fleet_instance.damage_counts['repair'] += 1
                            return True
            if self.current_shiplist_page < self.ship_page_count:
                # check if there were even any damaged ships on the page
                damage_exists = False
                for damage in valid_damages:
                    damage_icon = 'repairlist_dmg_{}.png'.format(damage)
                    if self.regions['right'].exists(damage_icon):
                        damage_exists = True
                        break
                if damage_exists:
                    # did not select a ship but damaged ships exist; go to next
                    # page
                    self._navigate_to_shiplist_page(
                        self.current_shiplist_page + 1)
                else:
                    # no more ships of valid damage state exists in list;
                    # return to the first page
                    self._navigate_to_shiplist_page(1)
                    return False
        return False