Add: 适配穹顶下的圣咏曲AC图

- 修复UI导致的动态边缘识别出错
- 修复只识别出一队时的处理逻辑
- 修复处理战斗结束后跳出的剧情
- 修复辅助点击报CampaignEnd
- 修复游戏出现白屏bug时, 连续点击使用紧急维修
- 增加地图全清时, 使用二队打BOSS, 忽略FLEET_BOSS
- 增加被精英抓住的识别, 暂时还用不到
This commit is contained in:
LmeSzinc 2020-05-22 21:48:56 +08:00
parent bd8090dff5
commit 8ec5099b58
20 changed files with 261 additions and 15 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -0,0 +1,48 @@
from module.campaign.campaign_base import CampaignBase
from module.map.map_base import CampaignMap
from module.map.map_grids import SelectedGrids, RoadGrids
from module.logger import logger
MAP = CampaignMap()
MAP.map_data = '''
-- -- ++ -- -- -- ++ ++
-- -- -- -- -- -- -- --
++ -- -- ++ -- -- -- --
++ -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- ++ ++ ++ -- -- ++
'''
class Config:
SUBMARINE = 0
FLEET_BOSS = 1
POOR_MAP_DATA = True
MAP_HAS_AMBUSH = False
MAP_HAS_FLEET_STEP = True
MAP_HAS_MOVABLE_ENEMY = True
MAP_HAS_SIREN = True
MAP_HAS_DYNAMIC_RED_BORDER = True
MAP_HAS_MAP_STORY = True
MAP_SIREN_COUNT = 2
TRUST_EDGE_LINES = False
COINCIDENT_POINT_ENCOURAGE_DISTANCE = 1.5
INTERNAL_LINES_FIND_PEAKS_PARAMETERS = {
'height': (100, 235),
'width': 1,
'prominence': 10,
'distance': 35,
}
EDGE_LINES_FIND_PEAKS_PARAMETERS = {
'height': (255 - 80, 255),
'prominence': 2,
'distance': 50,
'wlen': 1000
}
class Campaign(CampaignBase):
MAP = MAP

View File

@ -0,0 +1,21 @@
from module.campaign.campaign_base import CampaignBase
from module.map.map_base import CampaignMap
from module.map.map_grids import SelectedGrids, RoadGrids
from module.logger import logger
from campaign.event_20200521_cn.a1 import Config
MAP = CampaignMap()
MAP.map_data = '''
-- -- -- -- -- -- -- -- ++
-- -- -- ++ ++ -- -- -- ++
++ -- -- -- -- -- -- -- --
++ -- ++ -- -- -- -- -- --
-- -- -- -- ++ ++ -- -- --
-- -- -- -- ++ ++ -- -- --
'''
MAP.camera_data = ['D1', 'D4', 'F2', 'F4']
class Campaign(CampaignBase):
MAP = MAP

View File

@ -0,0 +1,25 @@
from module.campaign.campaign_base import CampaignBase
from module.map.map_base import CampaignMap
from module.map.map_grids import SelectedGrids, RoadGrids
from module.logger import logger
from campaign.event_20200521_cn.a1 import Config as ConfigBase
MAP = CampaignMap()
MAP.map_data = '''
-- -- -- ++ ++ -- -- --
-- -- -- -- -- -- -- --
++ ++ -- -- -- -- ++ ++
-- -- -- ++ -- -- ++ ++
-- -- -- ++ -- -- -- --
-- -- -- -- -- -- -- ++
-- -- -- ++ -- -- -- --
'''
class Config(ConfigBase):
MAP_HAS_DYNAMIC_RED_BORDER = False
class Campaign(CampaignBase):
MAP = MAP

View File

@ -0,0 +1,48 @@
from module.campaign.campaign_base import CampaignBase
from module.map.map_base import CampaignMap
from module.map.map_grids import SelectedGrids, RoadGrids
from module.logger import logger
MAP = CampaignMap()
MAP.map_data = '''
-- -- ++ -- -- -- ++ ++
-- -- -- -- -- -- -- --
++ -- -- ++ -- -- -- --
++ -- -- -- -- -- -- --
-- -- -- -- -- -- -- --
-- -- ++ ++ ++ -- -- ++
'''
class Config:
SUBMARINE = 0
FLEET_BOSS = 1
POOR_MAP_DATA = True
MAP_HAS_AMBUSH = False
MAP_HAS_FLEET_STEP = True
MAP_HAS_MOVABLE_ENEMY = True
MAP_HAS_SIREN = True
MAP_HAS_DYNAMIC_RED_BORDER = True
MAP_HAS_MAP_STORY = True
MAP_SIREN_COUNT = 2
TRUST_EDGE_LINES = False
COINCIDENT_POINT_ENCOURAGE_DISTANCE = 1.5
INTERNAL_LINES_FIND_PEAKS_PARAMETERS = {
'height': (100, 235),
'width': 1,
'prominence': 10,
'distance': 35,
}
EDGE_LINES_FIND_PEAKS_PARAMETERS = {
'height': (255 - 80, 255),
'prominence': 2,
'distance': 50,
'wlen': 1000
}
class Campaign(CampaignBase):
MAP = MAP

View File

@ -0,0 +1,21 @@
from module.campaign.campaign_base import CampaignBase
from module.map.map_base import CampaignMap
from module.map.map_grids import SelectedGrids, RoadGrids
from module.logger import logger
from campaign.event_20200521_cn.c1 import Config
MAP = CampaignMap()
MAP.map_data = '''
-- -- -- -- -- -- -- -- ++
-- -- -- ++ ++ -- -- -- ++
++ -- -- -- -- -- -- -- --
++ -- ++ -- -- -- -- -- --
-- -- -- -- ++ ++ -- -- --
-- -- -- -- ++ ++ -- -- --
'''
MAP.camera_data = ['D1', 'D4', 'F2', 'F4']
class Campaign(CampaignBase):
MAP = MAP

View File

@ -0,0 +1,25 @@
from module.campaign.campaign_base import CampaignBase
from module.map.map_base import CampaignMap
from module.map.map_grids import SelectedGrids, RoadGrids
from module.logger import logger
from campaign.event_20200521_cn.c1 import Config as ConfigBase
MAP = CampaignMap()
MAP.map_data = '''
-- -- -- ++ ++ -- -- --
-- -- -- -- -- -- -- --
++ ++ -- -- -- -- ++ ++
-- -- -- ++ -- -- ++ ++
-- -- -- ++ -- -- -- --
-- -- -- -- -- -- -- ++
-- -- -- ++ -- -- -- --
'''
class Config(ConfigBase):
FLEET_BOSS = 2
class Campaign(CampaignBase):
MAP = MAP

View File

@ -62,7 +62,12 @@ class CampaignBase(Map):
return True
return self.battle_default()
else:
return self.battle_boss()
backup = self.config.FLEET_BOSS
if self.config.FLEET_2 != 0:
self.config.FLEET_BOSS = 2
result = self.battle_boss()
self.config.FLEET_BOSS = backup
return result
@Config.when(MAP_CLEAR_ALL_THIS_TIME=False, POOR_MAP_DATA=False)
def execute_a_battle(self):

View File

@ -160,7 +160,7 @@ class Combat(HPBalancer, EnemySearchingHandler, Retirement, SubmarineCall, Comba
if self.appear_then_click(EMERGENCY_REPAIR_CONFIRM, offset=True):
self.device.sleep(0.5) # Animation: hp increase and emergency_repair amount decrease.
return True
if self.appear(EMERGENCY_REPAIR_AVAILABLE):
if self.appear(BATTLE_PREPARATION) and self.appear(EMERGENCY_REPAIR_AVAILABLE):
logger.info('EMERGENCY_REPAIR_AVAILABLE')
if np.min(np.array(self.hp)[np.array(self.hp) > 0.001]) < self.config.EMERGENCY_REPAIR_SINGLE_THRESHOLD \
or np.max(self.hp[:3]) < self.config.EMERGENCY_REPAIR_HOLE_THRESHOLD \
@ -346,3 +346,4 @@ class Combat(HPBalancer, EnemySearchingHandler, Retirement, SubmarineCall, Comba
func=func, call_submarine_at_boss=call_submarine_at_boss, save_get_items=save_get_items)
self.combat_status(
save_get_items=save_get_items, expected_end=expected_end)
self.handle_map_after_combat_story()

View File

@ -201,6 +201,7 @@ class AzurLaneConfig:
MAP_HAS_MOVABLE_ENEMY = False
MAP_HAS_SIREN = False
MAP_HAS_DYNAMIC_RED_BORDER = False
MAP_HAS_MAP_STORY = False # event_20200521_cn(穹顶下的圣咏曲) adds after-combat story.
MAP_SIREN_MOVE_WAIT = 1.5 # The enemy moving takes about 1.2 ~ 1.5s.
MAP_SIREN_COUNT = 0
MAP_MYSTERY_HAS_CARRIER = False
@ -233,7 +234,8 @@ class AzurLaneConfig:
MID_Y = SCREEN_CENTER[1]
# UI mask
UI_MASK_FILE = './module/map/ui_mask.png'
UI_MASK = np.array(Image.open(UI_MASK_FILE).convert('L'))
UI_MASK_PIL = Image.open(UI_MASK_FILE).convert('L')
UI_MASK = np.array(UI_MASK_PIL)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
UI_MASK_STROKE = cv2.erode(UI_MASK, kernel).astype('uint8')

View File

@ -200,6 +200,7 @@ dic_chi_to_eng = {
'微层混合': 'event_20200326_cn',
'复刻苍红的回响': 'event_20200423_cn',
'夜幕下的归途': 'event_20200507_cn',
'穹顶下的圣咏曲': 'event_20200521_cn',
}
dic_eng_to_chi = {v: k for k, v in dic_chi_to_eng.items()}

View File

@ -3,11 +3,11 @@ from module.daemon.assets import *
from module.handler.ambush import MAP_AMBUSH_EVADE
from module.handler.mystery import MysteryHandler
from module.map.map_fleet_preparation import FleetPreparation
from module.exception import *
class AzurLaneDaemon(FleetPreparation, Combat, MysteryHandler):
def daemon(self):
while 1:
self.device.screenshot()
@ -21,8 +21,11 @@ class AzurLaneDaemon(FleetPreparation, Combat, MysteryHandler):
# continue
# self.device.click(BATTLE_PREPARATION)
self.combat_preparation()
if self.handle_battle_status(save_get_items=False):
self.combat_status(save_get_items=False, expected_end='no_searching')
try:
if self.handle_battle_status(save_get_items=False):
self.combat_status(save_get_items=False, expected_end='no_searching')
continue
except CampaignEnd:
continue
# Map operation

View File

@ -55,8 +55,11 @@ class EnemySearchingHandler(InfoHandler):
if self.handle_in_stage():
return True
if self.handle_story_skip():
self.ensure_no_story()
timeout.limit = 10
timeout.reset()
# End
if self.enemy_searching_appear():
appeared = True
else:
@ -66,9 +69,7 @@ class EnemySearchingHandler(InfoHandler):
logger.info('In map.')
break
self.enemy_searching_color_initial()
if timeout.reached():
# logger.warning('Enemy searching timeout.')
logger.info('Enemy searching timeout.')
break

View File

@ -17,6 +17,9 @@ class FastForwardHandler(ModuleBase):
is_map_green = False
def handle_fast_forward(self):
if self.config.MAP_HAS_MAP_STORY:
if self.appear(MAP_STAR_1):
self.config.MAP_HAS_MAP_STORY = False
if not self.appear(MAP_STAR_1) or not self.appear(MAP_STAR_2) or not self.appear(MAP_STAR_3):
self.config.ENABLE_FAST_FORWARD = False
logger.info('Campaign is not 3-star cleared.')

View File

@ -107,3 +107,25 @@ class InfoHandler(ModuleBase):
return False
return self.story_skip()
def ensure_no_story(self, skip_first_screenshot=True):
logger.info('Ensure no story')
story_timer = Timer(5, count=4)
story_timer.start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.story_skip():
story_timer.reset()
if story_timer.reached():
break
def handle_map_after_combat_story(self):
if not self.config.MAP_HAS_MAP_STORY:
return False
self.ensure_no_story()

View File

@ -49,6 +49,6 @@ def attr(name, text):
logger.hr = hr
logger.attr = attr
logger.screenshot_deque = deque(maxlen=30)
logger.screenshot_deque = deque(maxlen=60)
logger.hr('Start', level=0)

View File

@ -242,6 +242,10 @@ class Fleet(Camera, MapOperation, AmbushHandler):
logger.info(f'Predict fleet_2 to be {fleets[0]}')
self.fleet_2_location = fleets[0].location
for loca in [self.fleet_1_location, self.fleet_2_location]:
if len(loca) and loca in self.map:
self.map[loca].wipe_out()
def find_all_fleets(self):
logger.hr('Find all fleets')
queue = self.map.select(is_spawn_point=True)
@ -269,7 +273,7 @@ class Fleet(Camera, MapOperation, AmbushHandler):
self.fleet_1 = fleets[0].location
else:
logger.info('Fleet_2 not detected.')
if self.config.POOR_MAP_DATA and self.map.select(is_spawn_point=True):
if self.config.POOR_MAP_DATA and not self.map.select(is_spawn_point=True):
self.fleet_1 = fleets[0].location
else:
self.find_all_fleets()
@ -450,22 +454,24 @@ class Fleet(Camera, MapOperation, AmbushHandler):
appear = False
for data in self.map.spawn_data:
if data.get('battle') == self.battle_count and data.get('boss', 0):
logger.info('Catch camera re-positioning after boss appear')
appear = True
if self.config.POOR_MAP_DATA:
appear = True
self.device.screenshot()
grids = Grids(self.device.image, config=self.config)
grids.predict()
grids.show()
for grid in grids:
if grid.is_boss:
appear = True
logger.info('Catch camera re-positioning after boss appear')
for g in self.map:
g.wipe_out()
break
if appear:
logger.info('Catch camera re-positioning after boss appear')
camera = self.camera
self.ensure_edge_insight()
logger.info('Refocus to previous camera position.')

View File

@ -13,7 +13,6 @@ class GridPredictor:
def __init__(self, location, image, corner):
"""
Args:
location:
image:
@ -55,6 +54,7 @@ class GridPredictor:
if self.is_fleet:
self.is_current_fleet = self.predict_current_fleet()
self.is_boss = self.predict_boss()
# self.caught_by_siren = self.predict_siren_caught()
# self.image_perspective = color_similarity_2d(
# self.image.transform(self.ENEMY_PERSPECTIVE_IMAGE_SIZE, Image.PERSPECTIVE, self._perspective)
# , color=(255, 36, 82)
@ -220,3 +220,7 @@ class GridPredictor:
return True
return False
def predict_siren_caught(self):
image = self.get_relative_image((-1, -1.5, 1, 0.5), output_shape=(120, 120))
return TEMPLATE_CAUGHT_BY_SIREN.match(image, similarity=0.6)

View File

@ -1,4 +1,5 @@
import numpy as np
from PIL import Image
from module.base.utils import area_in_area
from module.config.config import AzurLaneConfig
@ -14,10 +15,9 @@ class Grids(Perspective):
image:
config(AzurLaneConfig):
"""
self.image = image
self.config = config
# try:
super().__init__(image, config)
self.image = self._image_clear_ui(image)
self.grids = {}
for grid in self._gen():
@ -104,6 +104,15 @@ class Grids(Perspective):
# break
def update(self, image):
image = self._image_clear_ui(image)
self.image = image
for grid in self:
grid.image = image
def _image_clear_ui(self, image):
if not self.config.MAP_HAS_DYNAMIC_RED_BORDER:
return image
new = Image.new('RGB', self.config.SCREEN_SIZE, (0, 0, 0))
new.paste(image.crop(self.config.DETECTING_AREA), box=self.config.DETECTING_AREA, mask=self.config.UI_MASK_PIL)
return new

View File

@ -6,6 +6,7 @@ from module.base.template import Template
TEMPLATE_AMBUSH_EVADE_FAILED = Template(file='./assets/template/TEMPLATE_AMBUSH_EVADE_FAILED.png')
TEMPLATE_AMBUSH_EVADE_SUCCESS = Template(file='./assets/template/TEMPLATE_AMBUSH_EVADE_SUCCESS.png')
TEMPLATE_CAUGHT_BY_SIREN = Template(file='./assets/template/TEMPLATE_CAUGHT_BY_SIREN.png')
TEMPLATE_ENEMY_BOSS = Template(file='./assets/template/TEMPLATE_ENEMY_BOSS.png')
TEMPLATE_ENEMY_L = Template(file='./assets/template/TEMPLATE_ENEMY_L.png')
TEMPLATE_ENEMY_M = Template(file='./assets/template/TEMPLATE_ENEMY_M.png')