mirror of
https://github.com/LmeSzinc/AzurLaneAutoScript.git
synced 2025-01-08 13:27:45 +08:00
commit
aa8d990fc8
BIN
assets/cn/os_handler/CURRENT_AP_CHECK.png
Normal file
BIN
assets/cn/os_handler/CURRENT_AP_CHECK.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
BIN
assets/en/os_handler/CURRENT_AP_CHECK.png
Normal file
BIN
assets/en/os_handler/CURRENT_AP_CHECK.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
BIN
assets/jp/os_handler/CURRENT_AP_CHECK.png
Normal file
BIN
assets/jp/os_handler/CURRENT_AP_CHECK.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
BIN
assets/tw/os_handler/CURRENT_AP_CHECK.png
Normal file
BIN
assets/tw/os_handler/CURRENT_AP_CHECK.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
@ -12,7 +12,7 @@ class Config:
|
||||
# Disabled because having errors
|
||||
MAP_SWIPE_PREDICT_WITH_SEA_GRIDS = False
|
||||
# Ambushes can be avoid by having more DDs.
|
||||
MAP_WALK_OPTIMIZE = False
|
||||
MAP_WALK_TURNING_OPTIMIZE = False
|
||||
|
||||
|
||||
class CampaignBase(CampaignBase_):
|
||||
|
@ -13,7 +13,7 @@ MASK_MAP_UI_W15 = Mask(file='./assets/mask/MASK_MAP_UI_W15.png')
|
||||
|
||||
class Config:
|
||||
# Ambushes can be avoid by having more DDs.
|
||||
MAP_WALK_OPTIMIZE = False
|
||||
MAP_WALK_TURNING_OPTIMIZE = False
|
||||
MAP_HAS_MYSTERY = False
|
||||
MAP_ENEMY_TEMPLATE = ['Light', 'Main', 'Carrier', 'CarrierSpecial']
|
||||
INTERNAL_LINES_FIND_PEAKS_PARAMETERS = {
|
||||
|
@ -81,6 +81,7 @@ class Config:
|
||||
}
|
||||
HOMO_EDGE_COLOR_RANGE = (0, 33)
|
||||
HOMO_EDGE_HOUGHLINES_THRESHOLD = 300
|
||||
MAP_ENSURE_EDGE_INSIGHT_CORNER = 'bottom'
|
||||
MAP_IS_ONE_TIME_STAGE = True
|
||||
MAP_SWIPE_MULTIPLY = (1.063, 1.083)
|
||||
MAP_SWIPE_MULTIPLY_MINITOUCH = (1.028, 1.047)
|
||||
|
@ -331,28 +331,33 @@ class CampaignOcr(ModuleBase):
|
||||
logger.warning(f'get_chapter_index: WITHDRAW appears')
|
||||
raise CampaignNameError
|
||||
|
||||
def get_chapter_index(self, image):
|
||||
def get_chapter_index(self, skip_first_screenshot=True):
|
||||
"""
|
||||
A tricky method for ui_ensure_index
|
||||
|
||||
Args:
|
||||
image: Screenshot
|
||||
skip_first_screenshot:
|
||||
|
||||
Returns:
|
||||
int: Chapter index.
|
||||
"""
|
||||
timeout = Timer(2, count=4).start()
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if timeout.reached():
|
||||
raise CampaignNameError
|
||||
if self.handle_get_chapter_additional():
|
||||
continue
|
||||
image = self.device.image
|
||||
try:
|
||||
self._get_stage_name(image)
|
||||
break
|
||||
except (IndexError, CampaignNameError):
|
||||
self.device.screenshot()
|
||||
image = self.device.image
|
||||
pass
|
||||
|
||||
if self.handle_get_chapter_additional():
|
||||
continue
|
||||
|
||||
return self._campaign_get_chapter_index(self.campaign_chapter)
|
||||
|
@ -49,7 +49,7 @@ class CampaignUI(MapOperation, CampaignEvent, CampaignOcr):
|
||||
if self.handle_chapter_additional():
|
||||
continue
|
||||
|
||||
current = self.get_chapter_index(self.device.image)
|
||||
current = self.get_chapter_index()
|
||||
|
||||
logger.attr("Index", current)
|
||||
diff = index - current
|
||||
@ -227,19 +227,35 @@ class CampaignUI(MapOperation, CampaignEvent, CampaignOcr):
|
||||
return True
|
||||
return False
|
||||
|
||||
def ensure_campaign_ui(self, name, mode='normal'):
|
||||
for n in range(20):
|
||||
def ensure_campaign_ui(self, name, mode='normal', skip_first_screenshot=True):
|
||||
"""
|
||||
Args:
|
||||
name (str): Campaign name, such as '7-2', 'd3', 'sp3'.
|
||||
mode (str): 'normal' or 'hard'.
|
||||
skip_first_screenshot:
|
||||
|
||||
Raises:
|
||||
ScriptEnd: If failed to switch after retries
|
||||
"""
|
||||
timeout = Timer(5, count=20).start()
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if timeout.reached():
|
||||
break
|
||||
try:
|
||||
self.campaign_set_chapter(name, mode)
|
||||
self.ENTRANCE = self.campaign_get_entrance(name=name)
|
||||
return True
|
||||
except CampaignNameError:
|
||||
pass
|
||||
|
||||
if self.handle_campaign_ui_additional():
|
||||
continue
|
||||
|
||||
self.device.screenshot()
|
||||
|
||||
logger.warning('Campaign name error')
|
||||
raise ScriptEnd('Campaign name error')
|
||||
|
||||
|
@ -182,7 +182,7 @@ class ManualConfig:
|
||||
# Use the green arrow on current fleet to decide if fleet arrived a certain grid
|
||||
MAP_WALK_USE_CURRENT_FLEET = False
|
||||
# Optimize walk path, reducing ambushes
|
||||
MAP_WALK_OPTIMIZE = True
|
||||
MAP_WALK_TURNING_OPTIMIZE = True
|
||||
# Optimize swipe path, reducing swipes turn info clicks.
|
||||
MAP_SWIPE_OPTIMIZE = True
|
||||
# Swipe after boss appear. Could avoid map detection error when camera is on edge.
|
||||
|
@ -299,10 +299,18 @@ class Emulator(EmulatorBase):
|
||||
for folder in self.list_folder('../vms', is_dir=True):
|
||||
for file in iter_folder(folder, ext='.nemu'):
|
||||
serial = Emulator.vbox_file_to_serial(file)
|
||||
name = os.path.basename(folder)
|
||||
if serial:
|
||||
yield EmulatorInstance(
|
||||
serial=serial,
|
||||
name=os.path.basename(folder),
|
||||
name=name,
|
||||
path=self.path,
|
||||
)
|
||||
# Fix for MuMu12 v4.0.4, default instance of which has no forward record in vbox config
|
||||
elif name == 'MuMuPlayer-12.0-0':
|
||||
yield EmulatorInstance(
|
||||
serial='127.0.0.1:16384',
|
||||
name=name,
|
||||
path=self.path,
|
||||
)
|
||||
elif self == Emulator.MEmuPlayer:
|
||||
|
@ -467,23 +467,27 @@ class Fleet(Camera, AmbushHandler):
|
||||
if result == 'nothing' and expected == 'combat':
|
||||
raise MapEnemyMoved
|
||||
|
||||
def goto(self, location, optimize=None, expected=''):
|
||||
def goto(self, location, expected='', step_optimize=None, turning_optimize=None):
|
||||
"""
|
||||
Args:
|
||||
location (tuple, str, GridInfo): Destination.
|
||||
optimize (bool): Optimize walk path, reducing ambushes.
|
||||
If None, loads MAP_WALK_OPTIMIZE
|
||||
expected (str): Expected result on destination grid, such as 'combat', 'combat_siren', 'mystery'.
|
||||
Will give a waring if arrive with unexpected result.
|
||||
step_optimize (bool): True to walk in fleet step
|
||||
turning_optimize (bool): True to optimize route to reduce ambushes
|
||||
"""
|
||||
location = location_ensure(location)
|
||||
if optimize is None:
|
||||
optimize = self.config.MAP_WALK_OPTIMIZE
|
||||
if step_optimize is None:
|
||||
step_optimize = self.config.MAP_HAS_FLEET_STEP
|
||||
if self.config.MAP_HAS_PORTAL or self.config.MAP_HAS_MAZE:
|
||||
step_optimize = True
|
||||
if turning_optimize is None:
|
||||
turning_optimize = self.config.MAP_HAS_AMBUSH
|
||||
|
||||
# self.device.sleep(1000)
|
||||
if optimize and (self.config.MAP_HAS_AMBUSH or self.config.MAP_HAS_FLEET_STEP or self.config.MAP_HAS_PORTAL
|
||||
or self.config.MAP_HAS_MAZE):
|
||||
nodes = self.map.find_path(location, step=self.fleet_step)
|
||||
if step_optimize or turning_optimize:
|
||||
step = self.fleet_step if step_optimize else 0
|
||||
nodes = self.map.find_path(location, step=step, turning_optimize=turning_optimize)
|
||||
for node in nodes:
|
||||
if self.maze_active_on(node):
|
||||
logger.info(f'Maze is active on {location2node(node)}, bouncing to wait')
|
||||
@ -499,7 +503,7 @@ class Fleet(Camera, AmbushHandler):
|
||||
logger.warning('Map walk error.')
|
||||
self.predict()
|
||||
self.ensure_edge_insight()
|
||||
nodes_ = self.map.find_path(node, step=1)
|
||||
nodes_ = self.map.find_path(node, step=1, turning_optimize=False)
|
||||
for node_ in nodes_:
|
||||
self._goto(node_, expected=expected if node == nodes[-1] else '')
|
||||
else:
|
||||
|
@ -653,8 +653,8 @@ class Map(Fleet):
|
||||
|
||||
def clear_filter_enemy(self, string, preserve=0):
|
||||
"""
|
||||
if EnemyPriority_EnemyScaleBalanceWeight != default_mode
|
||||
Filter will be covered
|
||||
If EnemyPriority_EnemyScaleBalanceWeight != default_mode, enemy filter is ignored
|
||||
If MAP_HAS_MOVABLE_NORMAL_ENEMY, enemy filter is ignored
|
||||
|
||||
Args:
|
||||
string (str): Filter to select enemies, from easy to hard
|
||||
@ -664,6 +664,11 @@ class Map(Fleet):
|
||||
Returns:
|
||||
bool: If clear an enemy.
|
||||
"""
|
||||
if self.config.MAP_HAS_MOVABLE_NORMAL_ENEMY:
|
||||
if self.clear_any_enemy(sort=('cost_2',)):
|
||||
return True
|
||||
return False
|
||||
|
||||
if self.config.EnemyPriority_EnemyScaleBalanceWeight == 'S3_enemy_first':
|
||||
string = '3L > 3M > 3E > 3C > 2L > 2M > 2E > 2C > 1L > 1M > 1E > 1C'
|
||||
preserve = 0
|
||||
|
@ -604,11 +604,12 @@ class CampaignMap:
|
||||
|
||||
return res
|
||||
|
||||
def _find_route_node(self, route, step=0):
|
||||
def _find_route_node(self, route, step=0, turning_optimize=False):
|
||||
"""
|
||||
Args:
|
||||
route (list[tuple]): list of grids.
|
||||
step (int): Fleet step in event map. Default to 0.
|
||||
turning_optimize: (bool): True to optimize route to reduce ambushes
|
||||
|
||||
Returns:
|
||||
list[tuple]: list of walking node.
|
||||
@ -617,23 +618,30 @@ class CampaignMap:
|
||||
MAP_7_2._find_route_node([(2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (6, 1), (7, 1)])
|
||||
[(6, 2), (7, 1)]
|
||||
"""
|
||||
res = []
|
||||
diff = np.abs(np.diff(route, axis=0))
|
||||
turning = np.diff(diff, axis=0)[:, 0]
|
||||
indexes = np.where(turning == -1)[0] + 1
|
||||
for index in indexes:
|
||||
if not self[route[index]].is_fleet:
|
||||
res.append(index)
|
||||
else:
|
||||
logger.info(f'Path_node_avoid: {self[route[index]]}')
|
||||
if (index > 1) and (index - 1 not in indexes):
|
||||
res.append(index - 1)
|
||||
if (index < len(route) - 2) and (index + 1 not in indexes):
|
||||
res.append(index + 1)
|
||||
res.append(len(route) - 1)
|
||||
# res = [6, 8]
|
||||
if step == 0:
|
||||
return [route[index] for index in res]
|
||||
if turning_optimize:
|
||||
res = []
|
||||
diff = np.abs(np.diff(route, axis=0))
|
||||
turning = np.diff(diff, axis=0)[:, 0]
|
||||
indexes = np.where(turning == -1)[0] + 1
|
||||
for index in indexes:
|
||||
if not self[route[index]].is_fleet:
|
||||
res.append(index)
|
||||
else:
|
||||
logger.info(f'Path_node_avoid: {self[route[index]]}')
|
||||
if (index > 1) and (index - 1 not in indexes):
|
||||
res.append(index - 1)
|
||||
if (index < len(route) - 2) and (index + 1 not in indexes):
|
||||
res.append(index + 1)
|
||||
res.append(len(route) - 1)
|
||||
# res = [4, 6]
|
||||
if step == 0:
|
||||
return [route[index] for index in res]
|
||||
else:
|
||||
if step == 0:
|
||||
return [route[-1]]
|
||||
# Index of the last node
|
||||
# res = [6]
|
||||
res = [max(len(route) - 1, 0)]
|
||||
|
||||
res.insert(0, 0)
|
||||
inserted = []
|
||||
@ -653,7 +661,7 @@ class CampaignMap:
|
||||
# res = [3, 6, 8]
|
||||
return [route[index] for index in res]
|
||||
|
||||
def find_path(self, location, step=0):
|
||||
def find_path(self, location, step=0, turning_optimize=False):
|
||||
location = location_ensure(location)
|
||||
|
||||
path = self._find_path(location)
|
||||
@ -676,7 +684,7 @@ class CampaignMap:
|
||||
if end - start == 1 and self[path[start]].is_portal and self[path[start]].portal_link == path[end]:
|
||||
continue
|
||||
local_path = path[start:end + 1]
|
||||
local_path = self._find_route_node(local_path, step=step)
|
||||
local_path = self._find_route_node(local_path, step=step, turning_optimize=turning_optimize)
|
||||
portal_path += local_path
|
||||
logger.info('Path: %s' % '[' + ', ' .join([location2node(grid) for grid in local_path]) + ']')
|
||||
path = portal_path
|
||||
|
@ -105,6 +105,10 @@ class ActionPointHandler(UI, MapEventHandler):
|
||||
def _is_in_action_point(self):
|
||||
return self.appear(ACTION_POINT_USE, offset=(20, 20))
|
||||
|
||||
def is_current_ap_visible(self):
|
||||
return self.appear(CURRENT_AP_CHECK, offset=(40, 5)) \
|
||||
and CURRENT_AP_CHECK.match_appear_on(self.device.image, threshold=15)
|
||||
|
||||
def action_point_use(self, skip_first_screenshot=True):
|
||||
prev = self._action_point_current
|
||||
self.interval_clear(ACTION_POINT_USE)
|
||||
@ -144,6 +148,20 @@ class ActionPointHandler(UI, MapEventHandler):
|
||||
self._action_point_total = total
|
||||
|
||||
def action_point_safe_get(self, skip_first_screenshot=True):
|
||||
timeout = Timer(3, count=6).start()
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if self.is_current_ap_visible():
|
||||
break
|
||||
if timeout.reached():
|
||||
logger.warning('Get action points timeout, wait is_current_ap_visible timeout')
|
||||
break
|
||||
|
||||
skip_first_screenshot = True
|
||||
timeout = Timer(1, count=2).start()
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
@ -155,10 +173,6 @@ class ActionPointHandler(UI, MapEventHandler):
|
||||
logger.warning('Get action points timeout')
|
||||
break
|
||||
|
||||
if self.info_bar_count() >= 2:
|
||||
timeout.reset()
|
||||
continue
|
||||
|
||||
self.action_point_update()
|
||||
|
||||
# Having too many current AP, probably an OCR error
|
||||
|
@ -15,6 +15,7 @@ AUTO_SEARCH_OS_MAP_OPTION_OFF_DISABLED = Button(area={'cn': (1205, 531, 1275, 54
|
||||
AUTO_SEARCH_OS_MAP_OPTION_ON = Button(area={'cn': (1205, 549, 1275, 566), 'en': (1203, 534, 1274, 544), 'jp': (1205, 573, 1275, 592), 'tw': (1206, 573, 1275, 591)}, color={'cn': (149, 176, 193), 'en': (110, 131, 152), 'jp': (145, 172, 190), 'tw': (123, 148, 169)}, button={'cn': (1205, 549, 1275, 566), 'en': (1203, 534, 1274, 544), 'jp': (1205, 573, 1275, 592), 'tw': (1206, 573, 1275, 591)}, file={'cn': './assets/cn/os_handler/AUTO_SEARCH_OS_MAP_OPTION_ON.png', 'en': './assets/en/os_handler/AUTO_SEARCH_OS_MAP_OPTION_ON.png', 'jp': './assets/jp/os_handler/AUTO_SEARCH_OS_MAP_OPTION_ON.png', 'tw': './assets/tw/os_handler/AUTO_SEARCH_OS_MAP_OPTION_ON.png'})
|
||||
AUTO_SEARCH_REWARD = Button(area={'cn': (575, 598, 721, 646), 'en': (574, 597, 722, 648), 'jp': (577, 597, 722, 645), 'tw': (576, 598, 720, 647)}, color={'cn': (169, 168, 170), 'en': (168, 171, 174), 'jp': (165, 170, 175), 'tw': (171, 174, 179)}, button={'cn': (575, 598, 721, 646), 'en': (574, 597, 722, 648), 'jp': (577, 597, 722, 645), 'tw': (576, 598, 720, 647)}, file={'cn': './assets/cn/os_handler/AUTO_SEARCH_REWARD.png', 'en': './assets/en/os_handler/AUTO_SEARCH_REWARD.png', 'jp': './assets/jp/os_handler/AUTO_SEARCH_REWARD.png', 'tw': './assets/tw/os_handler/AUTO_SEARCH_REWARD.png'})
|
||||
CLICK_SAFE_AREA = Button(area={'cn': (1104, 169, 1214, 284), 'en': (1104, 169, 1214, 284), 'jp': (1104, 169, 1214, 284), 'tw': (1104, 169, 1214, 284)}, color={'cn': (96, 114, 142), 'en': (96, 114, 142), 'jp': (96, 114, 142), 'tw': (96, 114, 142)}, button={'cn': (1104, 169, 1214, 284), 'en': (1104, 169, 1214, 284), 'jp': (1104, 169, 1214, 284), 'tw': (1104, 169, 1214, 284)}, file={'cn': './assets/cn/os_handler/CLICK_SAFE_AREA.png', 'en': './assets/en/os_handler/CLICK_SAFE_AREA.png', 'jp': './assets/jp/os_handler/CLICK_SAFE_AREA.png', 'tw': './assets/tw/os_handler/CLICK_SAFE_AREA.png'})
|
||||
CURRENT_AP_CHECK = Button(area={'cn': (837, 228, 867, 252), 'en': (837, 228, 867, 252), 'jp': (837, 228, 867, 252), 'tw': (837, 228, 867, 252)}, color={'cn': (165, 124, 73), 'en': (165, 124, 73), 'jp': (165, 124, 73), 'tw': (165, 124, 73)}, button={'cn': (837, 228, 867, 252), 'en': (837, 228, 867, 252), 'jp': (837, 228, 867, 252), 'tw': (837, 228, 867, 252)}, file={'cn': './assets/cn/os_handler/CURRENT_AP_CHECK.png', 'en': './assets/en/os_handler/CURRENT_AP_CHECK.png', 'jp': './assets/jp/os_handler/CURRENT_AP_CHECK.png', 'tw': './assets/tw/os_handler/CURRENT_AP_CHECK.png'})
|
||||
EXCHANGE_CHECK = Button(area={'cn': (144, 17, 249, 41), 'en': (143, 16, 240, 37), 'jp': (141, 16, 250, 42), 'tw': (142, 15, 250, 44)}, color={'cn': (153, 170, 209), 'en': (117, 133, 171), 'jp': (86, 98, 127), 'tw': (135, 151, 189)}, button={'cn': (144, 17, 249, 41), 'en': (143, 16, 240, 37), 'jp': (141, 16, 250, 42), 'tw': (142, 15, 250, 44)}, file={'cn': './assets/cn/os_handler/EXCHANGE_CHECK.png', 'en': './assets/en/os_handler/EXCHANGE_CHECK.png', 'jp': './assets/jp/os_handler/EXCHANGE_CHECK.png', 'tw': './assets/tw/os_handler/EXCHANGE_CHECK.png'})
|
||||
EXCHANGE_ENTER = Button(area={'cn': (195, 629, 344, 693), 'en': (202, 640, 332, 690), 'jp': (195, 629, 345, 693), 'tw': (195, 629, 344, 693)}, color={'cn': (58, 54, 52), 'en': (64, 61, 59), 'jp': (53, 50, 48), 'tw': (59, 55, 54)}, button={'cn': (195, 629, 344, 693), 'en': (202, 640, 332, 690), 'jp': (195, 629, 345, 693), 'tw': (195, 629, 344, 693)}, file={'cn': './assets/cn/os_handler/EXCHANGE_ENTER.png', 'en': './assets/en/os_handler/EXCHANGE_ENTER.png', 'jp': './assets/jp/os_handler/EXCHANGE_ENTER.png', 'tw': './assets/tw/os_handler/EXCHANGE_ENTER.png'})
|
||||
GET_ADAPTABILITY = Button(area={'cn': (538, 191, 742, 227), 'en': (527, 194, 659, 215), 'jp': (538, 191, 743, 227), 'tw': (539, 191, 741, 227)}, color={'cn': (166, 195, 246), 'en': (198, 207, 230), 'jp': (158, 190, 245), 'tw': (164, 195, 246)}, button={'cn': (538, 191, 742, 227), 'en': (527, 194, 659, 215), 'jp': (538, 191, 743, 227), 'tw': (539, 191, 741, 227)}, file={'cn': './assets/cn/os_handler/GET_ADAPTABILITY.png', 'en': './assets/en/os_handler/GET_ADAPTABILITY.png', 'jp': './assets/jp/os_handler/GET_ADAPTABILITY.png', 'tw': './assets/tw/os_handler/GET_ADAPTABILITY.png'})
|
||||
|
Loading…
Reference in New Issue
Block a user