diff --git a/assets/cn/template/TEMPLATE_CAUGHT_BY_SIREN.png b/assets/cn/template/TEMPLATE_CAUGHT_BY_SIREN.png index 25542f881..4bb61ddb4 100644 Binary files a/assets/cn/template/TEMPLATE_CAUGHT_BY_SIREN.png and b/assets/cn/template/TEMPLATE_CAUGHT_BY_SIREN.png differ diff --git a/assets/en/template/TEMPLATE_CAUGHT_BY_SIREN.png b/assets/en/template/TEMPLATE_CAUGHT_BY_SIREN.png index 25542f881..4bb61ddb4 100644 Binary files a/assets/en/template/TEMPLATE_CAUGHT_BY_SIREN.png and b/assets/en/template/TEMPLATE_CAUGHT_BY_SIREN.png differ diff --git a/campaign/campaign_main/campaign_3_1.py b/campaign/campaign_main/campaign_3_1.py index 29980b8b1..b87a7025d 100644 --- a/campaign/campaign_main/campaign_3_1.py +++ b/campaign/campaign_main/campaign_3_1.py @@ -14,9 +14,9 @@ MAP.map_data = ''' ''' MAP.weight_data = ''' 30 30 30 20 10 10 10 - 30 30 30 20 10 10 10 - 40 40 40 20 10 10 10 + 30 30 30 20 10 09 10 40 40 40 20 10 10 10 + 40 40 40 20 20 10 10 ''' MAP.spawn_data = [ {'battle': 0, 'enemy': 2, 'mystery': 1}, @@ -36,6 +36,9 @@ class Config: FLEET_BOSS = 1 MAP_MYSTERY_HAS_CARRIER = True + + INTERNAL_LINES_HOUGHLINES_THRESHOLD = 40 + EDGE_LINES_HOUGHLINES_THRESHOLD = 40 INTERNAL_LINES_FIND_PEAKS_PARAMETERS = { 'height': (120, 255 - 40), 'width': (1.5, 10), @@ -54,6 +57,11 @@ class Campaign(CampaignBase): MAP = MAP def battle_0(self): + self.fleet_2_push_forward() + + if self.fleet_2_rescue(G2): + return True + self.clear_all_mystery() return self.battle_default() @@ -64,4 +72,4 @@ class Campaign(CampaignBase): if not self.check_accessibility(G2, fleet='boss'): return self.fleet_boss.battle_default() - return self.clear_boss() + return self.fleet_boss.clear_boss() diff --git a/campaign/campaign_main/campaign_3_2.py b/campaign/campaign_main/campaign_3_2.py index 7d35d6e33..e0e833019 100644 --- a/campaign/campaign_main/campaign_3_2.py +++ b/campaign/campaign_main/campaign_3_2.py @@ -15,10 +15,10 @@ MAP.map_data = ''' SP ME -- -- ME MM -- ++ ''' MAP.weight_data = ''' - 50 50 50 30 30 20 10 10 + 50 50 50 30 30 20 10 09 50 50 40 40 30 20 10 10 - 50 50 50 40 40 20 20 20 - 50 50 50 50 35 30 30 30 + 50 50 50 40 40 50 20 20 + 50 50 50 50 35 50 50 50 ''' MAP.spawn_data = [ {'battle': 0, 'enemy': 2, 'mystery': 1}, @@ -38,11 +38,17 @@ class Campaign(CampaignBase): MAP = MAP def battle_0(self): + self.fleet_2_push_forward() + + if self.fleet_2_rescue(H1): + return True + self.clear_all_mystery() return self.battle_default() def battle_3(self): + # print(H1.__dict__) self.clear_all_mystery() if not self.check_accessibility(H1, fleet='boss'): diff --git a/campaign/campaign_main/campaign_3_3.py b/campaign/campaign_main/campaign_3_3.py index dbddd0c7f..6f068df4c 100644 --- a/campaign/campaign_main/campaign_3_3.py +++ b/campaign/campaign_main/campaign_3_3.py @@ -18,8 +18,8 @@ MAP.weight_data = ''' 50 50 30 30 50 50 50 50 30 30 50 50 50 50 20 30 50 50 - 10 10 10 20 50 50 - 10 10 10 50 50 50 + 09 10 11 20 50 50 + 10 10 11 50 50 50 ''' MAP.spawn_data = [ {'battle': 0, 'enemy': 2, 'mystery': 1}, @@ -40,6 +40,11 @@ class Campaign(CampaignBase): MAP = MAP def battle_0(self): + self.fleet_2_push_forward() + + if self.fleet_2_rescue(A4): + return True + self.clear_all_mystery() return self.battle_default() diff --git a/campaign/campaign_main/campaign_3_4.py b/campaign/campaign_main/campaign_3_4.py index d1348f4a9..bd20900d9 100644 --- a/campaign/campaign_main/campaign_3_4.py +++ b/campaign/campaign_main/campaign_3_4.py @@ -18,8 +18,8 @@ MAP.map_data = ''' MAP.weight_data = ''' 40 40 40 40 40 40 40 40 40 40 40 30 30 30 30 30 - 40 40 30 30 20 10 10 10 - 40 40 30 20 20 10 10 10 + 40 40 30 30 20 10 10 09 + 40 40 30 20 20 10 10 09 ''' MAP.spawn_data = [ {'battle': 0, 'enemy': 2}, @@ -38,15 +38,16 @@ A4, B4, C4, D4, E4, F4, G4, H4, \ class Config(Config31): MAP_MYSTERY_HAS_CARRIER = False - # Map 3-4 is relatively small for the density of enemies. - INTERNAL_LINES_HOUGHLINES_THRESHOLD = 40 - EDGE_LINES_HOUGHLINES_THRESHOLD = 40 - class Campaign(CampaignBase): MAP = MAP def battle_0(self): + self.fleet_2_push_forward() + + if self.fleet_2_rescue(H3): + return True + return self.battle_default() def battle_3(self): diff --git a/module/map/camera.py b/module/map/camera.py index 1b2038ff2..4900257fe 100644 --- a/module/map/camera.py +++ b/module/map/camera.py @@ -111,7 +111,15 @@ class Camera(InfoHandler): self.grids.update(image=self.device.image) return True - self.grids = Grids(self.device.image, config=self.config) + try: + self.grids = Grids(self.device.image, config=self.config) + except PerspectiveError as e: + if self.info_bar_count(): + logger.info('Perspective error cause by info bar. Waiting.') + self.handle_info_bar() + return self.update(camera=camera) + else: + raise e # Catch perspective error known_exception = self.info_bar_count() diff --git a/module/map/fleet.py b/module/map/fleet.py index 421cca48b..34179a78a 100644 --- a/module/map/fleet.py +++ b/module/map/fleet.py @@ -1,5 +1,6 @@ import itertools + from module.base.timer import Timer from module.exception import MapWalkError from module.handler.ambush import AmbushHandler @@ -58,7 +59,7 @@ class Fleet(Camera, MapOperation, AmbushHandler): @property def fleet_boss_index(self): if self.config.FLEET_BOSS == 2 or self.config.FLEET_2: - return 1 + return 2 else: return 1 @@ -265,7 +266,12 @@ class Fleet(Camera, MapOperation, AmbushHandler): for loca in [self.fleet_1_location, self.fleet_2_location]: if len(loca) and loca in self.map: - self.map[loca].wipe_out() + grid = self.map[loca] + if grid.may_boss and grid.is_caught_by_siren: + # Only boss appears on fleet's face + pass + else: + self.map[loca].wipe_out() def find_all_fleets(self): logger.hr('Find all fleets') @@ -306,7 +312,12 @@ class Fleet(Camera, MapOperation, AmbushHandler): self.fleet_1 = another.location self.fleet_2 = fleets[0].location else: - self.find_all_fleets() + cover = self.map.grid_covered(fleets[0], location=[(0, -1)]) + if fleets[0].is_current_fleet and len(cover) and cover[0].is_spawn_point: + self.fleet_1 = fleets[0].location + self.fleet_2 = cover[0].location + else: + self.find_all_fleets() elif count == 2: current = self.map.select(is_current_fleet=True) if current.count == 1: diff --git a/module/map/grid_info.py b/module/map/grid_info.py index 31a0c88d0..ec6987fbf 100644 --- a/module/map/grid_info.py +++ b/module/map/grid_info.py @@ -139,11 +139,17 @@ class GridInfo: ignore_may (bool): Ignore map_data, force update. ignore_cleared (bool): Ignore is_cleared property. """ + if info.is_caught_by_siren: + self.is_caught_by_siren = True + for item in ['boss', 'siren']: if info.enemy_scale or self.enemy_scale: break if info.__getattribute__('is_' + item): - flag = not info.is_fleet and not self.is_fleet + if item == 'boss': + flag = not info.is_fleet + else: + flag = not info.is_fleet and not self.is_fleet if not ignore_may: flag &= self.__getattribute__('may_' + item) if not ignore_cleared: @@ -186,8 +192,6 @@ class GridInfo: self.is_fleet = info.is_fleet if info.is_current_fleet: self.is_current_fleet = True - if info.is_caught_by_siren: - self.is_caught_by_siren = True return False def wipe_out(self): @@ -201,6 +205,7 @@ class GridInfo: self.is_boss = False self.is_ammo = False self.is_siren = False + self.is_caught_by_siren = False def reset(self): """ diff --git a/module/map/grid_predictor.py b/module/map/grid_predictor.py index c685f0e8d..005c1b4c0 100644 --- a/module/map/grid_predictor.py +++ b/module/map/grid_predictor.py @@ -267,4 +267,3 @@ class GridPredictor: return name return None - diff --git a/module/map/map.py b/module/map/map.py index 9b812c76f..de99d18a0 100644 --- a/module/map/map.py +++ b/module/map/map.py @@ -237,7 +237,8 @@ class Map(Fleet): bool: """ grids = self.map.select(is_boss=True, is_accessible=True) - logger.info('Is boss: %s' % self.map.select(is_boss=True)) + grids = grids.add(self.map.select(may_boss=True, is_caught_by_siren=True)) + logger.info('Is boss: %s' % grids) if not grids.count: grids = grids.add(self.map.select(may_boss=True, is_enemy=True, is_accessible=True)) logger.warning('Boss not detected, using may_boss grids.') @@ -277,6 +278,7 @@ class Map(Fleet): def brute_clear_boss(self): """ Method to clear boss, using brute-force to find roadblocks. + Note: This method will use 2 fleets. """ boss = self.map.select(is_boss=True) if boss: @@ -296,7 +298,7 @@ class Map(Fleet): elif self.map.select(may_boss=True, is_caught_by_siren=True): logger.info('BOSS appear on fleet grid') self.fleet_2.switch_to() - self.clear_chosen_enemy(self.map.select(may_boss=True, is_caught_by_siren=True)[0]) + return self.clear_chosen_enemy(self.map.select(may_boss=True, is_caught_by_siren=True)[0]) else: logger.warning('BOSS not detected, trying all boss spawn point.') return self.clear_potential_boss() @@ -442,3 +444,26 @@ class Map(Fleet): self.fleet_2.goto(grids[0]) self.fleet_1.switch_to() return True + + def fleet_2_rescue(self, grid): + """Use mob fleet to rescue boss fleet. + + Args: + grid (GridInfo): Destination. Usually to be boss spawn grid. + + Returns: + bool: If clear an enemy. + """ + if not self.config.FLEET_2: + return False + + grids = self.brute_find_roadblocks(grid, fleet=2) + if not grids: + return False + logger.info('Fleet_2 rescue') + grids = self.select_grids(grids) + if not grids: + return False + + self.clear_chosen_enemy(grids[0]) + return True diff --git a/module/map/map_base.py b/module/map/map_base.py index bb303b49f..5b8829040 100644 --- a/module/map/map_base.py +++ b/module/map/map_base.py @@ -392,6 +392,22 @@ class CampaignMap: return path + def grid_covered(self, grid, location=None): + """ + Args: + grid (GridInfo) + location (list[tuple[int]]): Relative coordinate of the covered grid. + + Returns: + list[GridInfo]: + """ + if location is None: + covered = [tuple(np.array(grid.location) + upper) for upper in grid.covered_grid()] + else: + covered = [tuple(np.array(grid.location) + upper) for upper in location] + covered = [self[upper] for upper in covered if upper in self] + return covered + def missing_get(self, battle_count, mystery_count=0, siren_count=0, carrier_count=0): try: missing = self.spawn_data[battle_count].copy() @@ -408,15 +424,12 @@ class CampaignMap: missing[attr] -= 1 for grid in self: - for upper in grid.covered_grid(): - upper = tuple(np.array(grid.location) + upper) - if upper in self: - upper = self[upper] - for attr in ['enemy', 'mystery', 'siren', 'boss']: - if upper.__getattribute__('may_' + attr) and not upper.__getattribute__('is_' + attr): - may[attr] += 1 - if upper.may_carrier: - may['carrier'] += 1 + for upper in self.grid_covered(grid): + for attr in ['enemy', 'mystery', 'siren', 'boss']: + if upper.__getattribute__('may_' + attr) and not upper.__getattribute__('is_' + attr): + may[attr] += 1 + if upper.may_carrier: + may['carrier'] += 1 logger.attr('enemy_missing', ', '.join([f'{k[:2].upper()}:{str(v).rjust(2)}' for k, v in missing.items() if k != 'battle'])) @@ -444,18 +457,15 @@ class CampaignMap: # predict for grid in self: - for upper in grid.covered_grid(): - upper = tuple(np.array(grid.location) + upper) - if upper in self: - upper = self[upper] - for attr in ['enemy', 'mystery', 'siren', 'boss']: - if upper.__getattribute__('may_' + attr) and missing[attr] > 0 and missing[attr] == may[attr]: - logger.info('Predict %s to be %s' % (location2node(upper.location), attr)) - upper.__setattr__('is_' + attr, True) - if carrier_count: - if upper.may_carrier and missing['carrier'] > 0 and missing['carrier'] == may['carrier']: - logger.info('Predict %s to be enemy' % location2node(upper.location)) - upper.__setattr__('is_enemy', True) + for upper in self.grid_covered(grid): + for attr in ['enemy', 'mystery', 'siren', 'boss']: + if upper.__getattribute__('may_' + attr) and missing[attr] > 0 and missing[attr] == may[attr]: + logger.info('Predict %s to be %s' % (location2node(upper.location), attr)) + upper.__setattr__('is_' + attr, True) + if carrier_count: + if upper.may_carrier and missing['carrier'] > 0 and missing['carrier'] == may['carrier']: + logger.info('Predict %s to be enemy' % location2node(upper.location)) + upper.__setattr__('is_enemy', True) def select(self, **kwargs): """