mirror of
https://github.com/LmeSzinc/StarRailCopilot.git
synced 2024-11-26 18:20:42 +00:00
Add: Logic fleet_2_rescue, Logic for chapter 3
- Fix camera outside map caused by info bar - Fix mis-detection of is_caught_by_siren - Fix grid attribute is_caught_by_siren will be kept to next attack - Fix find_current_fleet when ammo icon of another fleet is covered by the green arrow of current fleet - Fix fleet_boss_index - Fix can not predict when boss appear on fleet's face
This commit is contained in:
parent
6548677c80
commit
81f9b61ea5
Binary file not shown.
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 4.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 4.9 KiB |
@ -14,9 +14,9 @@ MAP.map_data = '''
|
|||||||
'''
|
'''
|
||||||
MAP.weight_data = '''
|
MAP.weight_data = '''
|
||||||
30 30 30 20 10 10 10
|
30 30 30 20 10 10 10
|
||||||
30 30 30 20 10 10 10
|
30 30 30 20 10 09 10
|
||||||
40 40 40 20 10 10 10
|
|
||||||
40 40 40 20 10 10 10
|
40 40 40 20 10 10 10
|
||||||
|
40 40 40 20 20 10 10
|
||||||
'''
|
'''
|
||||||
MAP.spawn_data = [
|
MAP.spawn_data = [
|
||||||
{'battle': 0, 'enemy': 2, 'mystery': 1},
|
{'battle': 0, 'enemy': 2, 'mystery': 1},
|
||||||
@ -36,6 +36,9 @@ class Config:
|
|||||||
FLEET_BOSS = 1
|
FLEET_BOSS = 1
|
||||||
|
|
||||||
MAP_MYSTERY_HAS_CARRIER = True
|
MAP_MYSTERY_HAS_CARRIER = True
|
||||||
|
|
||||||
|
INTERNAL_LINES_HOUGHLINES_THRESHOLD = 40
|
||||||
|
EDGE_LINES_HOUGHLINES_THRESHOLD = 40
|
||||||
INTERNAL_LINES_FIND_PEAKS_PARAMETERS = {
|
INTERNAL_LINES_FIND_PEAKS_PARAMETERS = {
|
||||||
'height': (120, 255 - 40),
|
'height': (120, 255 - 40),
|
||||||
'width': (1.5, 10),
|
'width': (1.5, 10),
|
||||||
@ -54,6 +57,11 @@ class Campaign(CampaignBase):
|
|||||||
MAP = MAP
|
MAP = MAP
|
||||||
|
|
||||||
def battle_0(self):
|
def battle_0(self):
|
||||||
|
self.fleet_2_push_forward()
|
||||||
|
|
||||||
|
if self.fleet_2_rescue(G2):
|
||||||
|
return True
|
||||||
|
|
||||||
self.clear_all_mystery()
|
self.clear_all_mystery()
|
||||||
|
|
||||||
return self.battle_default()
|
return self.battle_default()
|
||||||
@ -64,4 +72,4 @@ class Campaign(CampaignBase):
|
|||||||
if not self.check_accessibility(G2, fleet='boss'):
|
if not self.check_accessibility(G2, fleet='boss'):
|
||||||
return self.fleet_boss.battle_default()
|
return self.fleet_boss.battle_default()
|
||||||
|
|
||||||
return self.clear_boss()
|
return self.fleet_boss.clear_boss()
|
||||||
|
@ -15,10 +15,10 @@ MAP.map_data = '''
|
|||||||
SP ME -- -- ME MM -- ++
|
SP ME -- -- ME MM -- ++
|
||||||
'''
|
'''
|
||||||
MAP.weight_data = '''
|
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 40 40 30 20 10 10
|
||||||
50 50 50 40 40 20 20 20
|
50 50 50 40 40 50 20 20
|
||||||
50 50 50 50 35 30 30 30
|
50 50 50 50 35 50 50 50
|
||||||
'''
|
'''
|
||||||
MAP.spawn_data = [
|
MAP.spawn_data = [
|
||||||
{'battle': 0, 'enemy': 2, 'mystery': 1},
|
{'battle': 0, 'enemy': 2, 'mystery': 1},
|
||||||
@ -38,11 +38,17 @@ class Campaign(CampaignBase):
|
|||||||
MAP = MAP
|
MAP = MAP
|
||||||
|
|
||||||
def battle_0(self):
|
def battle_0(self):
|
||||||
|
self.fleet_2_push_forward()
|
||||||
|
|
||||||
|
if self.fleet_2_rescue(H1):
|
||||||
|
return True
|
||||||
|
|
||||||
self.clear_all_mystery()
|
self.clear_all_mystery()
|
||||||
|
|
||||||
return self.battle_default()
|
return self.battle_default()
|
||||||
|
|
||||||
def battle_3(self):
|
def battle_3(self):
|
||||||
|
# print(H1.__dict__)
|
||||||
self.clear_all_mystery()
|
self.clear_all_mystery()
|
||||||
|
|
||||||
if not self.check_accessibility(H1, fleet='boss'):
|
if not self.check_accessibility(H1, fleet='boss'):
|
||||||
|
@ -18,8 +18,8 @@ MAP.weight_data = '''
|
|||||||
50 50 30 30 50 50
|
50 50 30 30 50 50
|
||||||
50 50 30 30 50 50
|
50 50 30 30 50 50
|
||||||
50 50 20 30 50 50
|
50 50 20 30 50 50
|
||||||
10 10 10 20 50 50
|
09 10 11 20 50 50
|
||||||
10 10 10 50 50 50
|
10 10 11 50 50 50
|
||||||
'''
|
'''
|
||||||
MAP.spawn_data = [
|
MAP.spawn_data = [
|
||||||
{'battle': 0, 'enemy': 2, 'mystery': 1},
|
{'battle': 0, 'enemy': 2, 'mystery': 1},
|
||||||
@ -40,6 +40,11 @@ class Campaign(CampaignBase):
|
|||||||
MAP = MAP
|
MAP = MAP
|
||||||
|
|
||||||
def battle_0(self):
|
def battle_0(self):
|
||||||
|
self.fleet_2_push_forward()
|
||||||
|
|
||||||
|
if self.fleet_2_rescue(A4):
|
||||||
|
return True
|
||||||
|
|
||||||
self.clear_all_mystery()
|
self.clear_all_mystery()
|
||||||
|
|
||||||
return self.battle_default()
|
return self.battle_default()
|
||||||
|
@ -18,8 +18,8 @@ MAP.map_data = '''
|
|||||||
MAP.weight_data = '''
|
MAP.weight_data = '''
|
||||||
40 40 40 40 40 40 40 40
|
40 40 40 40 40 40 40 40
|
||||||
40 40 40 30 30 30 30 30
|
40 40 40 30 30 30 30 30
|
||||||
40 40 30 30 20 10 10 10
|
40 40 30 30 20 10 10 09
|
||||||
40 40 30 20 20 10 10 10
|
40 40 30 20 20 10 10 09
|
||||||
'''
|
'''
|
||||||
MAP.spawn_data = [
|
MAP.spawn_data = [
|
||||||
{'battle': 0, 'enemy': 2},
|
{'battle': 0, 'enemy': 2},
|
||||||
@ -38,15 +38,16 @@ A4, B4, C4, D4, E4, F4, G4, H4, \
|
|||||||
class Config(Config31):
|
class Config(Config31):
|
||||||
MAP_MYSTERY_HAS_CARRIER = False
|
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):
|
class Campaign(CampaignBase):
|
||||||
MAP = MAP
|
MAP = MAP
|
||||||
|
|
||||||
def battle_0(self):
|
def battle_0(self):
|
||||||
|
self.fleet_2_push_forward()
|
||||||
|
|
||||||
|
if self.fleet_2_rescue(H3):
|
||||||
|
return True
|
||||||
|
|
||||||
return self.battle_default()
|
return self.battle_default()
|
||||||
|
|
||||||
def battle_3(self):
|
def battle_3(self):
|
||||||
|
@ -111,7 +111,15 @@ class Camera(InfoHandler):
|
|||||||
self.grids.update(image=self.device.image)
|
self.grids.update(image=self.device.image)
|
||||||
return True
|
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
|
# Catch perspective error
|
||||||
known_exception = self.info_bar_count()
|
known_exception = self.info_bar_count()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
|
|
||||||
from module.base.timer import Timer
|
from module.base.timer import Timer
|
||||||
from module.exception import MapWalkError
|
from module.exception import MapWalkError
|
||||||
from module.handler.ambush import AmbushHandler
|
from module.handler.ambush import AmbushHandler
|
||||||
@ -58,7 +59,7 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
|||||||
@property
|
@property
|
||||||
def fleet_boss_index(self):
|
def fleet_boss_index(self):
|
||||||
if self.config.FLEET_BOSS == 2 or self.config.FLEET_2:
|
if self.config.FLEET_BOSS == 2 or self.config.FLEET_2:
|
||||||
return 1
|
return 2
|
||||||
else:
|
else:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@ -265,7 +266,12 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
|||||||
|
|
||||||
for loca in [self.fleet_1_location, self.fleet_2_location]:
|
for loca in [self.fleet_1_location, self.fleet_2_location]:
|
||||||
if len(loca) and loca in self.map:
|
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):
|
def find_all_fleets(self):
|
||||||
logger.hr('Find all fleets')
|
logger.hr('Find all fleets')
|
||||||
@ -306,7 +312,12 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
|||||||
self.fleet_1 = another.location
|
self.fleet_1 = another.location
|
||||||
self.fleet_2 = fleets[0].location
|
self.fleet_2 = fleets[0].location
|
||||||
else:
|
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:
|
elif count == 2:
|
||||||
current = self.map.select(is_current_fleet=True)
|
current = self.map.select(is_current_fleet=True)
|
||||||
if current.count == 1:
|
if current.count == 1:
|
||||||
|
@ -139,11 +139,17 @@ class GridInfo:
|
|||||||
ignore_may (bool): Ignore map_data, force update.
|
ignore_may (bool): Ignore map_data, force update.
|
||||||
ignore_cleared (bool): Ignore is_cleared property.
|
ignore_cleared (bool): Ignore is_cleared property.
|
||||||
"""
|
"""
|
||||||
|
if info.is_caught_by_siren:
|
||||||
|
self.is_caught_by_siren = True
|
||||||
|
|
||||||
for item in ['boss', 'siren']:
|
for item in ['boss', 'siren']:
|
||||||
if info.enemy_scale or self.enemy_scale:
|
if info.enemy_scale or self.enemy_scale:
|
||||||
break
|
break
|
||||||
if info.__getattribute__('is_' + item):
|
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:
|
if not ignore_may:
|
||||||
flag &= self.__getattribute__('may_' + item)
|
flag &= self.__getattribute__('may_' + item)
|
||||||
if not ignore_cleared:
|
if not ignore_cleared:
|
||||||
@ -186,8 +192,6 @@ class GridInfo:
|
|||||||
self.is_fleet = info.is_fleet
|
self.is_fleet = info.is_fleet
|
||||||
if info.is_current_fleet:
|
if info.is_current_fleet:
|
||||||
self.is_current_fleet = True
|
self.is_current_fleet = True
|
||||||
if info.is_caught_by_siren:
|
|
||||||
self.is_caught_by_siren = True
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def wipe_out(self):
|
def wipe_out(self):
|
||||||
@ -201,6 +205,7 @@ class GridInfo:
|
|||||||
self.is_boss = False
|
self.is_boss = False
|
||||||
self.is_ammo = False
|
self.is_ammo = False
|
||||||
self.is_siren = False
|
self.is_siren = False
|
||||||
|
self.is_caught_by_siren = False
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"""
|
"""
|
||||||
|
@ -267,4 +267,3 @@ class GridPredictor:
|
|||||||
return name
|
return name
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -237,7 +237,8 @@ class Map(Fleet):
|
|||||||
bool:
|
bool:
|
||||||
"""
|
"""
|
||||||
grids = self.map.select(is_boss=True, is_accessible=True)
|
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:
|
if not grids.count:
|
||||||
grids = grids.add(self.map.select(may_boss=True, is_enemy=True, is_accessible=True))
|
grids = grids.add(self.map.select(may_boss=True, is_enemy=True, is_accessible=True))
|
||||||
logger.warning('Boss not detected, using may_boss grids.')
|
logger.warning('Boss not detected, using may_boss grids.')
|
||||||
@ -277,6 +278,7 @@ class Map(Fleet):
|
|||||||
def brute_clear_boss(self):
|
def brute_clear_boss(self):
|
||||||
"""
|
"""
|
||||||
Method to clear boss, using brute-force to find roadblocks.
|
Method to clear boss, using brute-force to find roadblocks.
|
||||||
|
Note: This method will use 2 fleets.
|
||||||
"""
|
"""
|
||||||
boss = self.map.select(is_boss=True)
|
boss = self.map.select(is_boss=True)
|
||||||
if boss:
|
if boss:
|
||||||
@ -296,7 +298,7 @@ class Map(Fleet):
|
|||||||
elif self.map.select(may_boss=True, is_caught_by_siren=True):
|
elif self.map.select(may_boss=True, is_caught_by_siren=True):
|
||||||
logger.info('BOSS appear on fleet grid')
|
logger.info('BOSS appear on fleet grid')
|
||||||
self.fleet_2.switch_to()
|
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:
|
else:
|
||||||
logger.warning('BOSS not detected, trying all boss spawn point.')
|
logger.warning('BOSS not detected, trying all boss spawn point.')
|
||||||
return self.clear_potential_boss()
|
return self.clear_potential_boss()
|
||||||
@ -442,3 +444,26 @@ class Map(Fleet):
|
|||||||
self.fleet_2.goto(grids[0])
|
self.fleet_2.goto(grids[0])
|
||||||
self.fleet_1.switch_to()
|
self.fleet_1.switch_to()
|
||||||
return True
|
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
|
||||||
|
@ -392,6 +392,22 @@ class CampaignMap:
|
|||||||
|
|
||||||
return path
|
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):
|
def missing_get(self, battle_count, mystery_count=0, siren_count=0, carrier_count=0):
|
||||||
try:
|
try:
|
||||||
missing = self.spawn_data[battle_count].copy()
|
missing = self.spawn_data[battle_count].copy()
|
||||||
@ -408,15 +424,12 @@ class CampaignMap:
|
|||||||
missing[attr] -= 1
|
missing[attr] -= 1
|
||||||
|
|
||||||
for grid in self:
|
for grid in self:
|
||||||
for upper in grid.covered_grid():
|
for upper in self.grid_covered(grid):
|
||||||
upper = tuple(np.array(grid.location) + upper)
|
for attr in ['enemy', 'mystery', 'siren', 'boss']:
|
||||||
if upper in self:
|
if upper.__getattribute__('may_' + attr) and not upper.__getattribute__('is_' + attr):
|
||||||
upper = self[upper]
|
may[attr] += 1
|
||||||
for attr in ['enemy', 'mystery', 'siren', 'boss']:
|
if upper.may_carrier:
|
||||||
if upper.__getattribute__('may_' + attr) and not upper.__getattribute__('is_' + attr):
|
may['carrier'] += 1
|
||||||
may[attr] += 1
|
|
||||||
if upper.may_carrier:
|
|
||||||
may['carrier'] += 1
|
|
||||||
|
|
||||||
logger.attr('enemy_missing',
|
logger.attr('enemy_missing',
|
||||||
', '.join([f'{k[:2].upper()}:{str(v).rjust(2)}' for k, v in missing.items() if k != 'battle']))
|
', '.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
|
# predict
|
||||||
for grid in self:
|
for grid in self:
|
||||||
for upper in grid.covered_grid():
|
for upper in self.grid_covered(grid):
|
||||||
upper = tuple(np.array(grid.location) + upper)
|
for attr in ['enemy', 'mystery', 'siren', 'boss']:
|
||||||
if upper in self:
|
if upper.__getattribute__('may_' + attr) and missing[attr] > 0 and missing[attr] == may[attr]:
|
||||||
upper = self[upper]
|
logger.info('Predict %s to be %s' % (location2node(upper.location), attr))
|
||||||
for attr in ['enemy', 'mystery', 'siren', 'boss']:
|
upper.__setattr__('is_' + attr, True)
|
||||||
if upper.__getattribute__('may_' + attr) and missing[attr] > 0 and missing[attr] == may[attr]:
|
if carrier_count:
|
||||||
logger.info('Predict %s to be %s' % (location2node(upper.location), attr))
|
if upper.may_carrier and missing['carrier'] > 0 and missing['carrier'] == may['carrier']:
|
||||||
upper.__setattr__('is_' + attr, True)
|
logger.info('Predict %s to be enemy' % location2node(upper.location))
|
||||||
if carrier_count:
|
upper.__setattr__('is_enemy', True)
|
||||||
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):
|
def select(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user