Add: 适配第一章, 修复大量bug

- 修复处理夜间委托时, 出现递归调用的问题
- 增加红脸出击确认的功能
- 增加了透视识别错误图片保存的开关
- 修复了地图太小时, 透视识别报错的问题
- 修复了相机位于地图外时, 透视识别出错的问题
- 修复了离开退役时, 会连击的问题
- 修复了同时出现低心情和船坞已满弹窗时, 卡住的问题
- 更新了一键退役实装后的安全点击的位置
- 修复了换装滑动失败时, 卡住的问题
- 修复了关闭自动收获后, 出现委托完成的提示是, 进图卡住的问题
- 修复了, 无正在跑的委托时, 报错的问题
This commit is contained in:
LmeSzinc 2020-04-11 15:23:51 +08:00
parent f1c2d182db
commit be00742c3c
29 changed files with 246 additions and 42 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -0,0 +1,37 @@
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.shape = 'G1'
MAP.map_data = '''
SP -- -- -- -- ME MB
'''
MAP.spawn_data = [
{'battle': 0, 'enemy': 1},
{'battle': 1, 'boss': 1},
]
A1, B1, C1, D1, E1, F1, G1, \
= MAP.flatten()
class Config:
FLEET_2 = 0
INTERNAL_LINES_FIND_PEAKS_PARAMETERS = {
'height': (120, 255 - 40),
'width': (1.5, 10),
'prominence': 10,
'distance': 35,
}
INTERNAL_LINES_HOUGHLINES_THRESHOLD = 40
EDGE_LINES_HOUGHLINES_THRESHOLD = 40
class Campaign(CampaignBase):
MAP = MAP
def battle_0(self):
return self.battle_default()
def battle_1(self):
return self.clear_boss()

View File

@ -0,0 +1,36 @@
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.campaign_main.campaign_1_1 import Config
MAP = CampaignMap()
MAP.shape = 'E3'
MAP.map_data = '''
SP -- ME ME MB
-- ++ -- -- ++
-- -- ME MM ++
'''
MAP.spawn_data = [
{'battle': 0, 'enemy': 1, 'mystery': 1},
{'battle': 1, 'enemy': 1},
{'battle': 2, 'boss': 1},
]
A1, B1, C1, D1, E1, \
A2, B2, C2, D2, E2, \
A3, B3, C3, D3, E3, \
= MAP.flatten()
class Campaign(CampaignBase):
MAP = MAP
def battle_0(self):
self.clear_all_mystery()
return self.battle_default()
def battle_2(self):
self.clear_all_mystery()
return self.clear_boss()

View File

@ -0,0 +1,36 @@
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.campaign_main.campaign_1_1 import Config
MAP = CampaignMap()
MAP.shape = 'F3'
MAP.map_data = '''
++ ++ ++ -- MB --
-- ME -- ME -- --
SP -- ++ -- -- MM
'''
MAP.spawn_data = [
{'battle': 0, 'enemy': 1, 'mystery': 1},
{'battle': 1, 'enemy': 1},
{'battle': 2, 'boss': 1},
]
A1, B1, C1, D1, E1, F1, \
A2, B2, C2, D2, E2, F2, \
A3, B3, C3, D3, E3, F3, \
= MAP.flatten()
class Campaign(CampaignBase):
MAP = MAP
def battle_0(self):
self.clear_all_mystery()
return self.battle_default()
def battle_2(self):
self.clear_all_mystery()
return self.clear_boss()

View File

@ -0,0 +1,35 @@
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.campaign_main.campaign_1_1 import Config
MAP = CampaignMap()
MAP.shape = 'G3'
MAP.map_data = '''
SP -- ME -- ++ ++ ++
++ ++ ME -- MA ++ ++
++ ++ ++ ME -- ME MB
'''
MAP.spawn_data = [
{'battle': 0, 'enemy': 2},
{'battle': 1, 'enemy': 1},
{'battle': 2},
{'battle': 3, 'boss': 1},
]
A1, B1, C1, D1, E1, F1, G1, \
A2, B2, C2, D2, E2, F2, G2, \
A3, B3, C3, D3, E3, F3, G3, \
= MAP.flatten()
class Campaign(CampaignBase):
MAP = MAP
def battle_0(self):
return self.battle_default()
def battle_3(self):
return self.clear_boss()

View File

@ -76,6 +76,7 @@ urgent_ship = 155
command = emulator
serial = 127.0.0.1:62001
package_name = com.bilibili.azurlane
enable_perspective_error_image_save = no
[Daily]
enable_daily_mission = yes

View File

@ -133,7 +133,7 @@ class CampaignRun(CampaignUI, Reward):
self.ensure_campaign_ui(name=self.stage)
self.campaign.ENTRANCE = self.campaign_get_entrance(name=self.stage)
if self.commission_notice_show_at_campaign():
self.reward()
if self.reward():
continue
# End

View File

@ -13,6 +13,7 @@ BATTLE_PREPARATION = Button(area=(1043, 607, 1241, 667), color=(234, 179, 97), b
BATTLE_PREPARATION_WITH_OVERLAY = Button(area=(1058, 622, 1226, 652), color=(96, 74, 39), button=(1058, 622, 1226, 652), file='./assets/combat/BATTLE_PREPARATION_WITH_OVERLAY.png')
BATTLE_STATUS_A = Button(area=(622, 266, 732, 288), color=(235, 227, 111), button=(1000, 631, 1055, 689), file='./assets/combat/BATTLE_STATUS_A.png')
BATTLE_STATUS_S = Button(area=(633, 297, 722, 320), color=(233, 241, 127), button=(1000, 631, 1055, 689), file='./assets/combat/BATTLE_STATUS_S.png')
COMBAT_AUTO = Button(area=(110, 32, 139, 61), color=(162, 186, 228), button=(18, 38, 96, 56), file='./assets/combat/COMBAT_AUTO.png')
EXP_INFO_A = Button(area=(389, 100, 444, 116), color=(236, 231, 116), button=(1000, 631, 1055, 689), file='./assets/combat/EXP_INFO_A.png')
EXP_INFO_S = Button(area=(396, 122, 457, 137), color=(233, 241, 127), button=(1000, 631, 1055, 689), file='./assets/combat/EXP_INFO_S.png')
GET_ITEMS_1 = Button(area=(538, 217, 741, 253), color=(160, 192, 248), button=(1000, 631, 1055, 689), file='./assets/combat/GET_ITEMS_1.png')

View File

@ -5,6 +5,7 @@ from module.combat.emotion import Emotion
from module.combat.hp_balancer import HPBalancer
from module.combat.submarine import SubmarineCall
from module.handler.enemy_searching import EnemySearchingHandler
from module.handler.low_emotion import LowEmotionHandler
from module.handler.urgent_commission import UrgentCommissionHandler
from module.logger import logger
from module.map.assets import MAP_OFFENSIVE
@ -13,7 +14,7 @@ from module.retire.retirement import Retirement
from module.ui.assets import BACK_ARROW
class Combat(HPBalancer, UrgentCommissionHandler, EnemySearchingHandler, Retirement, SubmarineCall):
class Combat(HPBalancer, UrgentCommissionHandler, EnemySearchingHandler, Retirement, SubmarineCall, LowEmotionHandler):
_automation_set_timer = Timer(1)
_emotion: Emotion
@ -33,7 +34,9 @@ class Combat(HPBalancer, UrgentCommissionHandler, EnemySearchingHandler, Retirem
return True
if self.handle_retirement():
self.map_offensive()
return True
return False
if self.handle_combat_low_emotion():
return False
if self.appear(BATTLE_PREPARATION):
return True
@ -110,6 +113,11 @@ class Combat(HPBalancer, UrgentCommissionHandler, EnemySearchingHandler, Retirem
if self.handle_retirement():
continue
# Emotion
if not self.config.ENABLE_MAP_FLEET_LOCK:
if self.handle_combat_low_emotion():
continue
# Combat start
if self.appear_then_click(BATTLE_PREPARATION):
continue

View File

@ -205,6 +205,9 @@ def main(ini_name=''):
emulator.add_argument('--设备', default=default('--设备'), help='例如 127.0.0.1:62001')
emulator.add_argument('--包名', default=default('--包名'), help='如果不是Biliibli国服, 或者使用了非官方客户端, 需修改')
debug = emulator_parser.add_argument_group('调试', '')
debug.add_argument('--保存透视识别出错的图像', default=default('--保存透视识别错误的图像'))
# ==========每日任务==========
daily_parser = subs.add_parser('每日任务困难演习')

View File

@ -235,6 +235,7 @@ class AzurLaneConfig:
),
MID_DIFF_RANGE
)
ENABLE_PERSPECTIVE_ERROR_IMAGE_SAVE = False
"""
module.daemon
"""
@ -329,6 +330,7 @@ class AzurLaneConfig:
option = config['Emulator']
self.SERIAL = option['serial']
self.PACKAGE_NAME = option['package_name'].strip()
self.ENABLE_PERSPECTIVE_ERROR_IMAGE_SAVE = to_bool(option['enable_perspective_error_image_save'])
option = config['Setting']
# Stop condition

View File

@ -103,6 +103,7 @@ dic_chi_to_eng = {
'观舰类紧急委托': 'urgent_ship',
'设备': 'serial',
'包名': 'package_name',
'保存透视识别出错的图像': 'enable_perspective_error_image_save',
'打每日': 'enable_daily_mission',
'打困难': 'enable_hard_campaign',
'打演习': 'enable_exercise',

View File

@ -32,7 +32,7 @@ class Device(Screenshot, Control, AppControl):
super().screenshot()
if GET_MISSION.appear_on(self.image):
self.click(GET_MISSION)
super().click(GET_MISSION)
if wait.reached():
break

View File

@ -16,14 +16,13 @@ class Equipment(InfoBarHandler):
SWIPE_CHECK.load_color(self.device.image)
self.device.swipe(vector=(distance, 0), box=SWIPE_AREA.area, random_range=SWIPE_RANDOM_RANGE,
padding=0, duration=(0.1, 0.12))
while 1:
self.device.sleep(0.3)
self.device.screenshot()
if SWIPE_CHECK.match(self.device.image):
continue
if self.appear(EQUIPMENT_OPEN):
break
if not SWIPE_CHECK.match(self.device.image):
if self.appear(EQUIPMENT_OPEN) and not SWIPE_CHECK.match(self.device.image):
break
def _view_next(self):

View File

@ -23,6 +23,8 @@ IN_STAGE_BLUE = Button(area=(20, 641, 148, 702), color=(154, 177, 226), button=(
IN_STAGE_RED = Button(area=(22, 643, 150, 704), color=(229, 159, 159), button=(22, 643, 150, 704), file='./assets/handler/IN_STAGE_RED.png')
LOGIN_ANNOUNCE = Button(area=(1160, 45, 1227, 90), color=(174, 61, 56), button=(1160, 45, 1227, 90), file='./assets/handler/LOGIN_ANNOUNCE.png')
LOGIN_CHECK = Button(area=(77, 655, 154, 711), color=(33, 36, 33), button=(940, 394, 1107, 513), file='./assets/handler/LOGIN_CHECK.png')
LOW_EMOTION_CANCEL = Button(area=(404, 493, 576, 550), color=(166, 169, 172), button=(404, 493, 576, 550), file='./assets/handler/LOW_EMOTION_CANCEL.png')
LOW_EMOTION_CONFIRM = Button(area=(704, 493, 876, 550), color=(94, 144, 204), button=(704, 493, 876, 550), file='./assets/handler/LOW_EMOTION_CONFIRM.png')
MAP_AIR_RAID = Button(area=(350, 447, 1280, 472), color=(154, 43, 46), button=(350, 447, 1280, 472), file='./assets/handler/MAP_AIR_RAID.png')
MAP_AMBUSH = Button(area=(261, 433, 1280, 449), color=(161, 41, 43), button=(261, 433, 1280, 449), file='./assets/handler/MAP_AMBUSH.png')
MAP_AMBUSH_EVADE = Button(area=(325, 393, 1280, 395), color=(255, 255, 255), button=(979, 444, 1152, 502), file='./assets/handler/MAP_AMBUSH_EVADE.png')

View File

@ -17,7 +17,7 @@ class LoginHandler(Combat):
continue
if self.handle_get_ship():
continue
if self.appear_then_click(LOGIN_ANNOUNCE, interval=1):
if self.appear_then_click(LOGIN_ANNOUNCE, offset=(30, 30), interval=1):
continue
if self.appear(EVENT_LIST_CHECK):
self.ui_back(check_button=MAIN_CHECK, appear_button=EVENT_LIST_CHECK, skip_first_screenshot=True)

View File

@ -0,0 +1,15 @@
from module.base.base import ModuleBase
from module.handler.assets import LOW_EMOTION_CONFIRM, LOW_EMOTION_CANCEL
class LowEmotionHandler(ModuleBase):
def handle_combat_low_emotion(self):
if not self.config.IGNORE_LOW_EMOTION_WARN:
return False
if self.appear(LOW_EMOTION_CANCEL, offset=30)\
and self.appear(LOW_EMOTION_CONFIRM, offset=30, interval=1):
self.device.click(LOW_EMOTION_CONFIRM)
return True
else:
return False

View File

@ -2,6 +2,7 @@ import numpy as np
from module.handler.info_bar import InfoBarHandler
from module.logger import logger
from module.map.exception import PerspectiveError
from module.map.grids import Grids, Grid
from module.map.map_base import CampaignMap, location2node, location_ensure
@ -144,19 +145,29 @@ class Camera(InfoBarHandler):
"""
logger.info('Ensure edge in sight.')
record = []
self.update()
while 1:
try:
if len(record) == 0:
self.update()
if preset is not None:
self.map_swipe(preset)
record.append(preset)
self.update()
while 1:
x = 0 if self.grids.left_edge or self.grids.right_edge else 3
y = 0 if self.grids.lower_edge or self.grids.upper_edge else 2
if len(record) > 0:
# Swipe even if two edges insight, this will avoid some embarrassing camera position.
self.map_swipe((x, y))
except PerspectiveError as e:
msg = str(e).split(':')[1].strip()
logger.warning(f'Camera outside map: {msg}')
dic = {'to the left': (2, 0), 'to the right': (-2, 0), 'to the lower': (0, 2), 'to the upper': (0, -2)}
self._map_swipe(dic[msg])
continue
record.append((x, y))
if x == 0 and y == 0:

View File

@ -1,2 +1,6 @@
class CampaignEnd(Exception):
pass
class PerspectiveError(Exception):
pass

View File

@ -308,7 +308,10 @@ class CampaignMap:
return path
def missing_get(self, battle_count, mystery_count=0, siren_count=0):
try:
missing = self.spawn_data[battle_count].copy()
except IndexError:
missing = self.spawn_data[-1].copy()
may = {'enemy': 0, 'mystery': 0, 'siren': 0, 'boss': 0}
missing['enemy'] -= battle_count
missing['mystery'] -= mystery_count

View File

@ -1,6 +1,7 @@
from module.base.timer import Timer
from module.handler.enemy_searching import EnemySearchingHandler
from module.handler.fast_forward import FastForwardHandler
from module.handler.low_emotion import LowEmotionHandler
from module.handler.strategy import StrategyHandler
from module.handler.urgent_commission import UrgentCommissionHandler
from module.logger import logger
@ -11,7 +12,7 @@ from module.retire.retirement import Retirement
class MapOperation(UrgentCommissionHandler, EnemySearchingHandler, FleetPreparation, Retirement, FastForwardHandler,
StrategyHandler):
StrategyHandler, LowEmotionHandler):
def fleet_switch_click(self):
"""
Switch fleet.
@ -74,7 +75,8 @@ class MapOperation(UrgentCommissionHandler, EnemySearchingHandler, FleetPreparat
continue
# Emotion
pass
if self.handle_combat_low_emotion():
continue
# Urgent commission
if self.handle_urgent_commission():

View File

@ -9,6 +9,7 @@ from scipy import signal, optimize
from module.config.config import AzurLaneConfig
from module.logger import logger
from module.map.exception import PerspectiveError
from module.map.perspective_items import Points, Lines
warnings.filterwarnings("ignore")
@ -362,6 +363,16 @@ class Perspective:
lower = lower[0] if len(lower) else None
upper = upper[-1] if len(upper) else None
# If camera outside map
if lower is not None:
correct, incorrect = np.sum(inner - lower > -threshold), np.sum(inner - lower < threshold)
if incorrect >= 2 and incorrect > correct:
raise PerspectiveError('Camera outside map: to the %s' % ('upper' if lines.is_horizontal else 'right'))
if upper is not None:
correct, incorrect = np.sum(upper - inner > -threshold), np.sum(upper - inner < threshold)
if incorrect >= 2 and incorrect > correct:
raise PerspectiveError('Camera outside map: to the %s' % ('lower' if lines.is_horizontal else 'left'))
# crop mid
if lower:
clean = clean[clean > lower - threshold]
@ -387,6 +398,9 @@ class Perspective:
return lines, lower, upper
def save_error_image(self):
if not self.config.ENABLE_PERSPECTIVE_ERROR_IMAGE_SAVE:
return False
file = '%s.%s' % (int(time.time() * 1000), 'png')
file = os.path.join(self.config.ERROR_LOG_FOLDER, file)
self.image.save(file)

View File

@ -111,6 +111,8 @@ class Lines:
def add(self, other):
if not other:
return self
if not self:
return other
lines = np.append(self.lines, other.lines, axis=0)
return Lines(lines, is_horizontal=self.is_horizontal, config=self.config)

View File

@ -8,7 +8,7 @@ COMMON_SHIP_FILTER_DISABLE = Button(area=(666, 6, 802, 48), color=(71, 88, 125),
COMMON_SHIP_FILTER_ENABLE = Button(area=(666, 6, 802, 48), color=(182, 145, 96), button=(666, 6, 802, 48), file='./assets/retire/COMMON_SHIP_FILTER_ENABLE.png')
EQUIP_CONFIRM = Button(area=(871, 516, 1044, 573), color=(95, 143, 203), button=(871, 516, 1044, 573), file='./assets/retire/EQUIP_CONFIRM.png')
EQUIP_CONFIRM_2 = Button(area=(720, 541, 893, 598), color=(94, 142, 202), button=(720, 541, 893, 598), file='./assets/retire/EQUIP_CONFIRM_2.png')
GET_ITEMS_1_RETIREMENT_SAVE = Button(area=(951, 654, 987, 687), color=(64, 62, 69), button=(951, 654, 987, 687), file='./assets/retire/GET_ITEMS_1_RETIREMENT_SAVE.png')
GET_ITEMS_1_RETIREMENT_SAVE = Button(area=(1031, 656, 1063, 688), color=(49, 44, 54), button=(1031, 656, 1063, 688), file='./assets/retire/GET_ITEMS_1_RETIREMENT_SAVE.png')
IN_RETIREMENT_CHECK = Button(area=(854, 641, 1027, 698), color=(184, 99, 89), button=(854, 641, 1027, 698), file='./assets/retire/IN_RETIREMENT_CHECK.png')
RETIRE_APPEAR_1 = Button(area=(353, 492, 527, 550), color=(96, 144, 204), button=(353, 492, 527, 550), file='./assets/retire/RETIRE_APPEAR_1.png')
RETIRE_APPEAR_2 = Button(area=(553, 492, 727, 550), color=(94, 143, 204), button=(553, 492, 727, 550), file='./assets/retire/RETIRE_APPEAR_2.png')

View File

@ -4,7 +4,7 @@ from module.combat.assets import GET_ITEMS_1
from module.handler.info_bar import InfoBarHandler
from module.logger import logger
from module.retire.assets import *
from module.ui.ui import UI, BACK_ARROW
from module.ui.ui import UI
CARD_GRIDS = ButtonGrid(origin=(93, 76), delta=(164 + 2 / 3, 227), button_shape=(138, 204), grid_shape=(7, 2), name='CARD')
CARD_RARITY_GRIDS = ButtonGrid(origin=(93, 76), delta=(164 + 2 / 3, 227), button_shape=(138, 5), grid_shape=(7, 2), name='RARITY')
@ -141,20 +141,11 @@ class Retirement(UI, InfoBarHandler):
and self.appear(RETIRE_APPEAR_2, offset=30) \
and self.appear(RETIRE_APPEAR_3, offset=30)
def _retirement_quit_check_func(self):
return not self.appear(IN_RETIREMENT_CHECK)
def _retirement_quit(self):
skip = True
while 1:
if skip:
skip = False
else:
self.device.screenshot()
# End
if not self.appear(IN_RETIREMENT_CHECK):
break
if self.appear_then_click(BACK_ARROW, offset=(20, 20)):
continue
self.ui_back(check_button=self._retirement_quit_check_func, skip_first_screenshot=True)
@property
def _retire_amount(self):

View File

@ -221,7 +221,7 @@ def commission_choose(daily, urgent, priority, time_limit=None):
"""
# Count Commission
commission = daily.commission + urgent.commission
running_count = np.sum([1 for c in commission if c.status == 'running'])
running_count = int(np.sum([1 for c in commission if c.status == 'running']))
logger.attr('Running', running_count)
if running_count >= 4:
return [], []

View File

@ -68,6 +68,7 @@ class Reward(RewardCommission):
for button in [EXP_INFO_S_REWARD, GET_ITEMS_1, GET_ITEMS_2, GET_SHIP]:
if self.appear(button, interval=1):
REWARD_SAVE_CLICK.name = button.name
self.device.click(REWARD_SAVE_CLICK)
click_timer.reset()
exit_timer.reset()