Add: 适配复刻苍红的回响AB图
- 开荒模式移动至出击设置 - 增加开荒模式自动启用, 无脑开就完事了 - 将透视识别参数放到了config里, 这样就可以用地图config覆盖了 - 适配小地图模式, 参数抄A1就行了 - 修复了章节名OCR的识别位置 - 修复了开荒会把BOSS当作精英打问题 - 增加战斗中的剧情跳过 - 注释掉了截图和点击的retry - 增加了捕捉目标点超出移动范围
BIN
assets/handler/MAP_WALK_OUT_OF_STEP.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
BIN
assets/map/MAP_PREPARATION_CANCEL.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
assets/template/TEMPLATE_MAP_WALK_OUT_OF_STEP.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
59
campaign/event_20200423_cn/a1.py
Normal file
@ -0,0 +1,59 @@
|
||||
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.camera_sight = (-4, -2, 5, 3)
|
||||
MAP.map_data = '''
|
||||
-- -- -- -- -- -- -- -- --
|
||||
-- -- -- -- -- -- -- -- --
|
||||
-- -- -- ++ ++ -- ++ -- --
|
||||
-- -- -- ++ ++ -- -- -- --
|
||||
SP -- -- -- -- -- -- ++ --
|
||||
SP SP -- -- -- -- -- ++ --
|
||||
'''
|
||||
|
||||
|
||||
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_GRID_CENTER_TOLERANCE = 0.3
|
||||
MAP_SIREN_COUNT = 2
|
||||
|
||||
INTERNAL_LINES_HOUGHLINES_THRESHOLD = 50
|
||||
EDGE_LINES_HOUGHLINES_THRESHOLD = 50
|
||||
CAMERA_SWIPE_MULTIPLY_X = 200 * 0.7
|
||||
CAMERA_SWIPE_MULTIPLY_Y = 140 * 0.7
|
||||
COINCIDENT_POINT_ENCOURAGE_DISTANCE = 1.
|
||||
MID_DIFF_RANGE_H = (45, 70)
|
||||
MID_DIFF_RANGE_V = (97 - 3, 97 + 3)
|
||||
TRUST_EDGE_LINES = True
|
||||
|
||||
VANISH_POINT_RANGE = ((540, 740), (-4000, -2000))
|
||||
DISTANCE_POINT_X_RANGE = ((-2000, -1000),)
|
||||
INTERNAL_LINES_FIND_PEAKS_PARAMETERS = {
|
||||
'height': (80, 255 - 40),
|
||||
'width': (0.9, 10),
|
||||
'prominence': 10,
|
||||
'distance': 35,
|
||||
'wlen': 100,
|
||||
}
|
||||
EDGE_LINES_FIND_PEAKS_PARAMETERS = {
|
||||
'height': (255 - 40, 255),
|
||||
'prominence': 10,
|
||||
'distance': 50,
|
||||
'wlen': 1000
|
||||
}
|
||||
|
||||
|
||||
class Campaign(CampaignBase):
|
||||
MAP = MAP
|
21
campaign/event_20200423_cn/a2.py
Normal 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_20200423_cn.a1 import Config
|
||||
|
||||
MAP = CampaignMap()
|
||||
MAP.camera_sight = (-4, -2, 5, 3)
|
||||
MAP.map_data = '''
|
||||
-- -- -- -- -- -- --
|
||||
-- -- -- ++ ++ ++ --
|
||||
-- -- -- -- -- -- --
|
||||
-- -- ++ -- -- -- --
|
||||
-- -- -- -- -- -- --
|
||||
SP -- -- -- -- ++ --
|
||||
SP SP -- -- -- ++ --
|
||||
'''
|
||||
|
||||
|
||||
class Campaign(CampaignBase):
|
||||
MAP = MAP
|
21
campaign/event_20200423_cn/a3.py
Normal 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_20200423_cn.a1 import Config
|
||||
|
||||
MAP = CampaignMap()
|
||||
MAP.camera_sight = (-4, -2, 5, 3)
|
||||
MAP.map_data = '''
|
||||
SP SP -- -- -- -- -- -- --
|
||||
SP -- -- -- ++ ++ ++ -- --
|
||||
-- -- -- -- -- -- -- -- --
|
||||
-- ++ -- -- -- -- -- -- --
|
||||
-- ++ -- -- ++ ++ -- -- --
|
||||
-- -- -- -- -- -- -- ++ ++
|
||||
-- -- -- -- -- -- -- ++ ++
|
||||
'''
|
||||
|
||||
|
||||
class Campaign(CampaignBase):
|
||||
MAP = MAP
|
58
campaign/event_20200423_cn/b1.py
Normal file
@ -0,0 +1,58 @@
|
||||
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.camera_sight = (-4, -2, 5, 3)
|
||||
MAP.map_data = '''
|
||||
-- -- -- -- -- -- -- -- --
|
||||
-- ++ ++ -- -- -- -- ++ --
|
||||
-- -- -- -- -- -- -- -- --
|
||||
-- -- ++ ++ ++ -- -- -- --
|
||||
-- -- -- -- -- -- -- -- --
|
||||
++ ++ -- -- -- -- ++ -- --
|
||||
++ ++ SP SP -- -- ++ -- --
|
||||
'''
|
||||
|
||||
|
||||
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_GRID_CENTER_TOLERANCE = 0.3
|
||||
MAP_SIREN_COUNT = 2
|
||||
|
||||
INTERNAL_LINES_HOUGHLINES_THRESHOLD = 50
|
||||
EDGE_LINES_HOUGHLINES_THRESHOLD = 50
|
||||
CAMERA_SWIPE_MULTIPLY_X = 200 * 0.7
|
||||
CAMERA_SWIPE_MULTIPLY_Y = 140 * 0.7
|
||||
COINCIDENT_POINT_ENCOURAGE_DISTANCE = 1.
|
||||
MID_DIFF_RANGE_H = (45, 70)
|
||||
MID_DIFF_RANGE_V = (97 - 3, 97 + 3)
|
||||
TRUST_EDGE_LINES = True
|
||||
|
||||
VANISH_POINT_RANGE = ((540, 740), (-4000, -2000))
|
||||
DISTANCE_POINT_X_RANGE = ((-2000, -1000),)
|
||||
INTERNAL_LINES_FIND_PEAKS_PARAMETERS = {
|
||||
'height': (80, 255 - 40),
|
||||
'width': (0.9, 10),
|
||||
'prominence': 10,
|
||||
'distance': 35,
|
||||
'wlen': 100,
|
||||
}
|
||||
EDGE_LINES_FIND_PEAKS_PARAMETERS = {
|
||||
'height': (255 - 40, 255),
|
||||
'prominence': 10,
|
||||
'distance': 50,
|
||||
'wlen': 1000
|
||||
}
|
||||
|
||||
|
||||
class Campaign(CampaignBase):
|
||||
MAP = MAP
|
25
campaign/event_20200423_cn/b2.py
Normal 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_20200423_cn.b1 import Config as ConfigBase
|
||||
|
||||
MAP = CampaignMap()
|
||||
MAP.camera_sight = (-4, -2, 5, 3)
|
||||
MAP.map_data = '''
|
||||
-- -- -- -- SP SP -- -- ++ ++
|
||||
-- -- -- -- -- -- -- -- ++ ++
|
||||
++ ++ ++ -- -- -- -- -- -- --
|
||||
-- -- -- -- ++ ++ -- -- -- --
|
||||
-- -- -- -- -- -- -- -- -- --
|
||||
-- ++ -- -- -- -- ++ -- -- --
|
||||
-- ++ -- -- -- -- -- -- -- --
|
||||
'''
|
||||
|
||||
|
||||
class Config(ConfigBase):
|
||||
FLEET_BOSS = 2
|
||||
|
||||
|
||||
class Campaign(CampaignBase):
|
||||
MAP = MAP
|
25
campaign/event_20200423_cn/b3.py
Normal 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_20200423_cn.b1 import Config as ConfigBase
|
||||
|
||||
MAP = CampaignMap()
|
||||
MAP.camera_sight = (-4, -2, 5, 3)
|
||||
MAP.map_data = '''
|
||||
-- -- -- -- -- -- -- -- --
|
||||
-- -- -- -- -- -- -- ++ ++
|
||||
++ ++ -- -- ++ ++ -- -- --
|
||||
-- -- -- -- ++ ++ -- -- SP
|
||||
++ ++ -- -- -- -- -- -- SP
|
||||
-- -- -- -- -- -- -- ++ --
|
||||
-- -- ++ ++ ++ -- -- -- --
|
||||
'''
|
||||
|
||||
|
||||
class Config(ConfigBase):
|
||||
FLEET_BOSS = 2
|
||||
|
||||
|
||||
class Campaign(CampaignBase):
|
||||
MAP = MAP
|
@ -47,6 +47,9 @@ retire_sr = no
|
||||
retire_ssr = no
|
||||
enable_drop_screenshot = no
|
||||
drop_screenshot_folder =
|
||||
enable_map_clear_mode = yes
|
||||
clear_mode_stop_condition = map_green
|
||||
map_star_clear_all = index_3
|
||||
command = setting
|
||||
|
||||
[Reward]
|
||||
@ -110,9 +113,6 @@ command = daily
|
||||
[Main]
|
||||
command = main
|
||||
main_stage = 7-2
|
||||
enable_map_clear_mode = no
|
||||
clear_mode_stop_condition = map_green
|
||||
map_star_clear_all = index_3
|
||||
|
||||
[Event]
|
||||
command = event
|
||||
|
@ -48,7 +48,7 @@ class Ocr:
|
||||
self.mid_process_height = mid_process_height
|
||||
self.threshold = threshold
|
||||
self.additional_preprocess = additional_preprocess
|
||||
self.use_binary=use_binary
|
||||
self.use_binary = use_binary
|
||||
self.length = (length, length) if isinstance(length, int) else length
|
||||
self.white_list = white_list
|
||||
self.buttons = buttons if isinstance(buttons, list) else [buttons]
|
||||
|
@ -39,6 +39,8 @@ class CampaignBase(Map):
|
||||
if self.brute_clear_boss():
|
||||
return True
|
||||
else:
|
||||
if self.clear_siren():
|
||||
return True
|
||||
return self.clear_enemy()
|
||||
|
||||
logger.warning('No battle executed.')
|
||||
@ -53,7 +55,11 @@ class CampaignBase(Map):
|
||||
if self.battle_count >= 3:
|
||||
self.pick_up_ammo()
|
||||
|
||||
if self.map.select(is_enemy=True, is_boss=False).count > 0:
|
||||
remain = self.map.select(is_enemy=True, is_boss=False)
|
||||
logger.info('Enemy remain: {}')
|
||||
if remain.count > 0:
|
||||
if self.clear_siren():
|
||||
return True
|
||||
return self.battle_default()
|
||||
else:
|
||||
return self.battle_boss()
|
||||
@ -91,4 +97,7 @@ class CampaignBase(Map):
|
||||
self.execute_a_battle()
|
||||
except CampaignEnd:
|
||||
logger.hr('Campaign end')
|
||||
break
|
||||
return True
|
||||
|
||||
logger.warning('Battle function exhausted.')
|
||||
raise ScriptError('Battle function exhausted.')
|
||||
|
@ -72,7 +72,7 @@ class CampaignOcr:
|
||||
digits.append(Button(area=area_offset(stage, point), color=stage_clear_color, button=button, name='stage'))
|
||||
|
||||
result = TEMPLATE_STAGE_PERCENT.match_multi(image, similarity=0.95)
|
||||
name_offset = (50, 0)
|
||||
name_offset = (48, 0)
|
||||
for point in result:
|
||||
point = point[::-1]
|
||||
button = tuple(np.append(point, point + TEMPLATE_STAGE_PERCENT.image.shape[:2][::-1]))
|
||||
|
@ -115,7 +115,7 @@ class CampaignRun(CampaignUI, Reward, LoginHandler):
|
||||
start_date = datetime.now().date()
|
||||
while 1:
|
||||
if datetime.now().date() != start_date:
|
||||
start_date.replace(day=datetime.now().day)
|
||||
start_date = datetime.now().date()
|
||||
self.app_restart()
|
||||
self.campaign.fleet_checked_reset()
|
||||
if self.handle_reward():
|
||||
|
@ -10,16 +10,16 @@ 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.story import StoryHandler
|
||||
from module.handler.urgent_commission import UrgentCommissionHandler
|
||||
from module.logger import logger
|
||||
from module.map.assets import MAP_OFFENSIVE
|
||||
from module.map.exception import CampaignEnd
|
||||
from module.retire.retirement import Retirement
|
||||
from module.ui.assets import BACK_ARROW
|
||||
|
||||
|
||||
class Combat(HPBalancer, UrgentCommissionHandler, EnemySearchingHandler, Retirement, SubmarineCall, LowEmotionHandler,
|
||||
CombatAuto, CombatManual):
|
||||
CombatAuto, CombatManual, StoryHandler):
|
||||
_automation_set_timer = Timer(1)
|
||||
_emotion: Emotion
|
||||
battle_status_click_interval = 0
|
||||
@ -189,6 +189,8 @@ class Combat(HPBalancer, UrgentCommissionHandler, EnemySearchingHandler, Retirem
|
||||
if not confirm_timer.reached() and self.appear_then_click(AUTOMATION_CONFIRM, offset=True):
|
||||
continue
|
||||
|
||||
if self.handle_story_skip():
|
||||
continue
|
||||
if self.handle_combat_auto():
|
||||
continue
|
||||
if self.handle_combat_manual():
|
||||
@ -298,6 +300,8 @@ class Combat(HPBalancer, UrgentCommissionHandler, EnemySearchingHandler, Retirem
|
||||
continue
|
||||
if self.handle_urgent_commission(save_get_items=save_get_items):
|
||||
continue
|
||||
if self.handle_story_skip():
|
||||
continue
|
||||
|
||||
# End
|
||||
if expected_end is None:
|
||||
|
@ -163,6 +163,11 @@ def main(ini_name=''):
|
||||
drop.add_argument('--启用掉落记录', default=default('--启用掉落记录'), choices=['是', '否'])
|
||||
drop.add_argument('--掉落保存目录', default=default('--掉落保存目录'))
|
||||
|
||||
clear = setting_parser.add_argument_group('开荒模式', '未开荒地图会在完成后停止, 已开荒的地图会忽略选项, 无脑开就完事了')
|
||||
clear.add_argument('--启用开荒', default=default('--启用开荒'), choices=['是', '否'])
|
||||
clear.add_argument('--开荒停止条件', default=default('--开荒停止条件'), choices=['地图通关', '地图三星', '地图绿海'])
|
||||
clear.add_argument('--地图全清星星', default=default('--地图全清星星'), choices=['第一个', '第二个', '第三个', '不使用'], help='第几颗星星是击破所有敌舰')
|
||||
|
||||
# ==========收菜设置==========
|
||||
reward_parser = subs.add_parser('收菜设置')
|
||||
reward_condition = reward_parser.add_argument_group('触发条件', '需要运行一次来保存选项, 运行时会执行一次收菜')
|
||||
@ -264,17 +269,12 @@ def main(ini_name=''):
|
||||
stage = main_parser.add_argument_group('选择关卡', '主线图出击, 目前仅支持前六章和7-2')
|
||||
stage.add_argument('--主线地图出击', default=default('--主线地图出击'), help='例如 7-2')
|
||||
|
||||
clear = stage.add_argument_group('主线开荒', '')
|
||||
clear.add_argument('--启用主线开荒', default=default('--启用主线开荒'), choices=['是', '否'])
|
||||
clear.add_argument('--主线开荒停止条件', default=default('--主线开荒停止条件'), choices=['地图通关', '地图三星', '地图绿海'])
|
||||
clear.add_argument('--主线全清星星', default=default('--主线全清星星'), choices=['第一个', '第二个', '第三个', '不使用'], help='第几颗星星是击破所有敌舰')
|
||||
|
||||
# ==========活动图==========
|
||||
event_parser = subs.add_parser('活动图')
|
||||
|
||||
event = event_parser.add_argument_group('选择关卡', '')
|
||||
event.add_argument('--活动地图', default=default('--活动地图'),
|
||||
choices=['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3', 'd1', 'd2', 'd3'][::-1],
|
||||
choices=['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3', 'd1', 'd2', 'd3'],
|
||||
help='例如 d3')
|
||||
event.add_argument('--sp地图', default=default('--sp地图'),
|
||||
choices=['sp3', 'sp2', 'sp1'],
|
||||
|
@ -195,9 +195,18 @@ class AzurLaneConfig:
|
||||
"""
|
||||
MAP_HAS_AMBUSH = True
|
||||
MAP_HAS_FLEET_STEP = False
|
||||
MAP_HAS_MOVABLE_ENEMY = False
|
||||
MAP_HAS_SIREN = False
|
||||
MAP_HAS_DYNAMIC_RED_BORDER = False
|
||||
MAP_SIREN_MOVE_WAIT = 1.8 # The enemy moving takes about 1.5 ~ 1.8s.
|
||||
MAP_SIREN_COUNT = 0
|
||||
MAP_MYSTERY_HAS_CARRIER = False
|
||||
MAP_GRID_CENTER_TOLERANCE = 0.1
|
||||
|
||||
POOR_MAP_DATA = False
|
||||
FLEET_BOSS = 2
|
||||
CAMERA_SWIPE_MULTIPLY_X = 200
|
||||
CAMERA_SWIPE_MULTIPLY_Y = 140
|
||||
|
||||
"""
|
||||
module.retire
|
||||
@ -246,20 +255,15 @@ class AzurLaneConfig:
|
||||
# Parameters for lines pre-cleansing
|
||||
HORIZONTAL_LINES_THETA_THRESHOLD = 0.005
|
||||
VERTICAL_LINES_THETA_THRESHOLD = 18
|
||||
TRUST_EDGE_LINES = True # For map fog in event_20200326_cn.
|
||||
# Parameters for perspective calculating
|
||||
VANISH_POINT_RANGE = ((540, 740), (-3000, -1000))
|
||||
DISTANCE_POINT_X_RANGE = ((-3200, -1600),)
|
||||
# Parameters for line cleansing
|
||||
COINCIDENT_POINT_ENCOURAGE_DISTANCE = 3
|
||||
ERROR_LINES_TOLERANCE = (-10, 10)
|
||||
MID_DIFF_RANGE = (129 - 3, 129 + 3)
|
||||
COINCIDENT_POINT_RANGE = (
|
||||
(
|
||||
-abs(ERROR_LINES_TOLERANCE[0]) * MID_DIFF_RANGE[1],
|
||||
# SCREEN_SIZE[0] + ERROR_LINES_TOLERANCE[1] * MID_DIFF_RANGE[1]
|
||||
200
|
||||
),
|
||||
MID_DIFF_RANGE
|
||||
)
|
||||
MID_DIFF_RANGE_H = (129 - 3, 129 + 3)
|
||||
MID_DIFF_RANGE_V = (129 - 3, 129 + 3)
|
||||
|
||||
"""
|
||||
module.daemon
|
||||
@ -405,6 +409,11 @@ class AzurLaneConfig:
|
||||
self.RETIRE_MODE = option['retire_mode'].split('_')[1]
|
||||
for r in ['n', 'r', 'sr', 'ssr']:
|
||||
self.__setattr__(f'RETIRE_{r.upper()}', to_bool(option[f'retire_{r}']))
|
||||
# Clear mode
|
||||
self.ENABLE_MAP_CLEAR_MODE = to_bool(option['enable_map_clear_mode'])
|
||||
self.CLEAR_MODE_STOP_CONDITION = option['clear_mode_stop_condition']
|
||||
star = option['map_star_clear_all']
|
||||
self.MAP_STAR_CLEAR_ALL = int(star.split('_')[1]) if star.startswith('index_') else 0
|
||||
|
||||
# Reward
|
||||
option = config['Reward']
|
||||
@ -418,10 +427,6 @@ class AzurLaneConfig:
|
||||
option = config['Main']
|
||||
self.CAMPAIGN_NAME = option['main_stage']
|
||||
self.CAMPAIGN_NAME = 'campaign_' + self.CAMPAIGN_NAME.replace('-', '_')
|
||||
self.ENABLE_MAP_CLEAR_MODE = to_bool(option['enable_map_clear_mode'])
|
||||
self.CLEAR_MODE_STOP_CONDITION = option['clear_mode_stop_condition']
|
||||
star = option['map_star_clear_all']
|
||||
self.MAP_STAR_CLEAR_ALL = int(star.split('_')[1]) if star.startswith('index_') else 0
|
||||
|
||||
option = config['Daily']
|
||||
for n in ['daily_mission', 'hard_campaign', 'exercise']:
|
||||
|
@ -81,6 +81,9 @@ dic_chi_to_eng = {
|
||||
'退役金皮': 'retire_ssr',
|
||||
'启用掉落记录': 'enable_drop_screenshot',
|
||||
'掉落保存目录': 'drop_screenshot_folder',
|
||||
'启用开荒': 'enable_map_clear_mode',
|
||||
'开荒停止条件': 'clear_mode_stop_condition',
|
||||
'地图全清星星': 'map_star_clear_all',
|
||||
'启用收获': 'enable_reward',
|
||||
'收菜间隔': 'reward_interval',
|
||||
'启用石油收获': 'enable_oil_reward',
|
||||
@ -131,9 +134,6 @@ dic_chi_to_eng = {
|
||||
'演习低血量确认时长': 'exercise_low_hp_confirm',
|
||||
'演习快速换装': 'exercise_equipment',
|
||||
'主线地图出击': 'main_stage',
|
||||
'启用主线开荒': 'enable_map_clear_mode',
|
||||
'主线开荒停止条件': 'clear_mode_stop_condition',
|
||||
'主线全清星星': 'map_star_clear_all',
|
||||
'活动地图': 'event_stage',
|
||||
'sp地图': 'sp_stage',
|
||||
'活动名称': 'event_name',
|
||||
|
@ -10,7 +10,4 @@ FLEET_PREPARATION = Button(area=(981, 575, 1180, 636), color=(235, 185, 114), bu
|
||||
GET_EMERGENCY_REPAIR = Button(area=(645, 352, 666, 360), color=(255, 255, 255), button=(645, 352, 666, 360), file='./assets/daemon/GET_EMERGENCY_REPAIR.png')
|
||||
GET_ITEMS = Button(area=(538, 217, 741, 253), color=(160, 192, 248), button=(1120, 643, 1146, 666), file='./assets/daemon/GET_ITEMS.png')
|
||||
MAP_PREPARATION = Button(area=(853, 488, 1053, 549), color=(235, 186, 114), button=(853, 488, 1053, 549), file='./assets/daemon/MAP_PREPARATION.png')
|
||||
STORY_CHOOCE = Button(area=(902, 344, 959, 357), color=(98, 122, 156), button=(902, 344, 959, 357), file='./assets/daemon/STORY_CHOOCE.png')
|
||||
STORY_CHOOCE_2 = Button(area=(903, 388, 959, 399), color=(98, 121, 156), button=(903, 388, 959, 399), file='./assets/daemon/STORY_CHOOCE_2.png')
|
||||
STORY_SKIP = Button(area=(1216, 676, 1258, 708), color=(148, 159, 178), button=(1180, 30, 1256, 49), file='./assets/daemon/STORY_SKIP.png')
|
||||
STRATEGY_OPEN = Button(area=(1102, 480, 1178, 482), color=(255, 223, 74), button=(1064, 405, 1093, 483), file='./assets/daemon/STRATEGY_OPEN.png')
|
||||
|
@ -2,13 +2,13 @@ from module.combat.combat import Combat
|
||||
from module.daemon.assets import *
|
||||
from module.handler.ambush import MAP_AMBUSH_EVADE
|
||||
from module.handler.mystery import MysteryHandler
|
||||
from module.handler.popup import PopupHandler
|
||||
from module.handler.story import StoryHandler
|
||||
from module.handler.urgent_commission import UrgentCommissionHandler
|
||||
from module.map.map_fleet_preparation import FleetPreparation
|
||||
|
||||
|
||||
class AzurLaneDaemon(FleetPreparation, Combat, UrgentCommissionHandler, MysteryHandler,
|
||||
PopupHandler):
|
||||
StoryHandler):
|
||||
def daemon(self):
|
||||
|
||||
while 1:
|
||||
@ -54,14 +54,7 @@ class AzurLaneDaemon(FleetPreparation, Combat, UrgentCommissionHandler, MysteryH
|
||||
|
||||
# Story
|
||||
if self.config.ENABLE_SEMI_STORY_SKIP:
|
||||
if self.appear_then_click(STORY_SKIP, offset=True, interval=2):
|
||||
continue
|
||||
if self.handle_popup_confirm():
|
||||
continue
|
||||
if self.appear_then_click(STORY_CHOOCE, offset=True, interval=2):
|
||||
continue
|
||||
if self.appear_then_click(STORY_CHOOCE_2, offset=True, interval=2):
|
||||
continue
|
||||
self.story_skip()
|
||||
|
||||
# End
|
||||
# No end condition, stop it manually.
|
||||
|
@ -64,11 +64,11 @@ class Control(Connection):
|
||||
self._click_uiautomator2(x, y)
|
||||
self.sleep(self.config.SLEEP_AFTER_CLICK)
|
||||
|
||||
@retry()
|
||||
# @retry()
|
||||
def _click_uiautomator2(self, x, y):
|
||||
self.device.click(x, y)
|
||||
|
||||
@retry()
|
||||
# @retry()
|
||||
def _click_adb(self, x, y):
|
||||
self.adb_shell(['input', 'tap', str(x), str(y)], serial=self.serial)
|
||||
|
||||
|
@ -47,7 +47,7 @@ class Screenshot(Connection):
|
||||
screenshot = self.adb_shell(['screencap', '-p'], serial=self.serial)
|
||||
return self._process_screenshot(screenshot)
|
||||
|
||||
@retry()
|
||||
# @retry()
|
||||
# @timer
|
||||
def screenshot(self):
|
||||
"""
|
||||
|
@ -5,7 +5,7 @@ from module.base.utils import red_overlay_transparency, get_color
|
||||
from module.combat.combat import Combat
|
||||
from module.handler.assets import *
|
||||
from module.logger import logger
|
||||
from module.template.assets import TEMPLATE_AMBUSH_EVADE_SUCCESS, TEMPLATE_AMBUSH_EVADE_FAILED
|
||||
from module.template.assets import *
|
||||
|
||||
|
||||
def ambush_letter_preprocess(image):
|
||||
@ -26,6 +26,7 @@ def ambush_letter_preprocess(image):
|
||||
|
||||
TEMPLATE_AMBUSH_EVADE_SUCCESS.image = ambush_letter_preprocess(TEMPLATE_AMBUSH_EVADE_SUCCESS.image)
|
||||
TEMPLATE_AMBUSH_EVADE_FAILED.image = ambush_letter_preprocess(TEMPLATE_AMBUSH_EVADE_FAILED.image)
|
||||
TEMPLATE_MAP_WALK_OUT_OF_STEP.image = ambush_letter_preprocess(TEMPLATE_MAP_WALK_OUT_OF_STEP.image)
|
||||
|
||||
|
||||
class AmbushHandler(Combat):
|
||||
@ -98,3 +99,17 @@ class AmbushHandler(Combat):
|
||||
self._handle_ambush()
|
||||
|
||||
return False
|
||||
|
||||
def handle_walk_out_of_step(self):
|
||||
if not self.config.MAP_HAS_FLEET_STEP:
|
||||
return False
|
||||
if not self.appear(INFO_BAR_1):
|
||||
return False
|
||||
|
||||
image = ambush_letter_preprocess(np.array(self.device.image.crop(MAP_WALK_OUT_OF_STEP.area)))
|
||||
if TEMPLATE_MAP_WALK_OUT_OF_STEP.match(image):
|
||||
logger.warning('Map walk out of step.')
|
||||
self.handle_info_bar()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
@ -35,9 +35,13 @@ MAP_GREEN = Button(area=(195, 260, 349, 292), color=(125, 190, 84), button=(195,
|
||||
MAP_STAR_1 = Button(area=(245, 377, 254, 384), color=(251, 233, 143), button=(245, 377, 254, 384), file='./assets/handler/MAP_STAR_1.png')
|
||||
MAP_STAR_2 = Button(area=(532, 377, 540, 384), color=(251, 233, 144), button=(532, 377, 540, 384), file='./assets/handler/MAP_STAR_2.png')
|
||||
MAP_STAR_3 = Button(area=(818, 377, 827, 384), color=(251, 233, 143), button=(818, 377, 827, 384), file='./assets/handler/MAP_STAR_3.png')
|
||||
MAP_WALK_OUT_OF_STEP = Button(area=(654, 312, 704, 335), color=(109, 113, 120), button=(654, 312, 704, 335), file='./assets/handler/MAP_WALK_OUT_OF_STEP.png')
|
||||
MYSTERY_ITEM = Button(area=(589, 294, 691, 427), color=(144, 127, 83), button=(589, 294, 691, 427), file='./assets/handler/MYSTERY_ITEM.png')
|
||||
POPUP_CANCEL = Button(area=(404, 493, 576, 550), color=(166, 169, 172), button=(404, 493, 576, 550), file='./assets/handler/POPUP_CANCEL.png')
|
||||
POPUP_CONFIRM = Button(area=(704, 493, 876, 550), color=(94, 144, 204), button=(704, 493, 876, 550), file='./assets/handler/POPUP_CONFIRM.png')
|
||||
STORY_CHOOCE = Button(area=(902, 344, 959, 357), color=(98, 122, 156), button=(902, 344, 959, 357), file='./assets/handler/STORY_CHOOCE.png')
|
||||
STORY_CHOOCE_2 = Button(area=(903, 388, 959, 399), color=(98, 121, 156), button=(903, 388, 959, 399), file='./assets/handler/STORY_CHOOCE_2.png')
|
||||
STORY_SKIP = Button(area=(1216, 676, 1258, 708), color=(148, 159, 178), button=(1180, 30, 1256, 49), file='./assets/handler/STORY_SKIP.png')
|
||||
STRATEGY_OPEN = Button(area=(1198, 411, 1269, 471), color=(81, 85, 101), button=(1198, 411, 1269, 471), file='./assets/handler/STRATEGY_OPEN.png')
|
||||
STRATEGY_OPENED = Button(area=(1176, 366, 1275, 393), color=(128, 155, 218), button=(1060, 406, 1092, 485), file='./assets/handler/STRATEGY_OPENED.png')
|
||||
SUBMARINE_HUNT_OFF = Button(area=(1200, 415, 1262, 477), color=(125, 127, 132), button=(1200, 415, 1262, 477), file='./assets/handler/SUBMARINE_HUNT_OFF.png')
|
||||
|
@ -22,14 +22,17 @@ class EnemySearchingHandler(InfoBarHandler):
|
||||
self.device.sleep(1.2)
|
||||
|
||||
def handle_in_stage(self):
|
||||
if self.appear(IN_STAGE_RED) or self.appear(IN_STAGE_BLUE):
|
||||
if self.is_in_stage():
|
||||
logger.info('In stage.')
|
||||
# self.device.sleep(0.5)
|
||||
self.ensure_no_info_bar(timeout=0.6)
|
||||
raise CampaignEnd('In map.')
|
||||
self.ensure_no_info_bar(timeout=1.2)
|
||||
raise CampaignEnd('In stage.')
|
||||
else:
|
||||
return False
|
||||
|
||||
def is_in_stage(self):
|
||||
return self.appear(IN_STAGE_RED) or self.appear(IN_STAGE_BLUE)
|
||||
|
||||
def is_in_map(self):
|
||||
return self.appear(IN_MAP)
|
||||
|
||||
|
@ -3,7 +3,6 @@ from module.base.switch import Switch
|
||||
from module.base.utils import color_bar_percentage
|
||||
from module.handler.assets import *
|
||||
from module.logger import logger
|
||||
from module.map.exception import ScriptEnd
|
||||
|
||||
fast_forward = Switch('Fast_Forward')
|
||||
fast_forward.add_status('on', check_button=FAST_FORWARD_ON)
|
||||
@ -14,6 +13,8 @@ fleet_lock.add_status('off', check_button=FLEET_UNLOCKED)
|
||||
|
||||
|
||||
class FastForwardHandler(ModuleBase):
|
||||
map_clear_record = None
|
||||
|
||||
def handle_fast_forward(self):
|
||||
if not self.appear(MAP_STAR_1) or not self.appear(MAP_STAR_2) or not self.appear(MAP_STAR_3):
|
||||
logger.info('Campaign is not 3-star cleared.')
|
||||
@ -30,6 +31,7 @@ class FastForwardHandler(ModuleBase):
|
||||
|
||||
logger.info('Set fast forward.')
|
||||
self.config.MAP_HAS_FLEET_STEP = False
|
||||
self.config.MAP_HAS_MOVABLE_ENEMY = False
|
||||
if self.config.ENABLE_FAST_FORWARD:
|
||||
self.config.MAP_HAS_AMBUSH = False
|
||||
status = 'on'
|
||||
@ -51,7 +53,7 @@ class FastForwardHandler(ModuleBase):
|
||||
changed = fleet_lock.set(status=status, main=self)
|
||||
return changed
|
||||
|
||||
def handle_map_clear_mode_stop(self):
|
||||
def triggered_map_clear_mode_stop(self):
|
||||
if not self.config.ENABLE_MAP_CLEAR_MODE:
|
||||
return False
|
||||
|
||||
@ -59,11 +61,11 @@ class FastForwardHandler(ModuleBase):
|
||||
logger.attr('Map_clear', f'{int(percent * 100)}%')
|
||||
if self.config.CLEAR_MODE_STOP_CONDITION == 'map_100':
|
||||
if percent > 0.95:
|
||||
raise ScriptEnd(f'Reach condition: {self.config.CLEAR_MODE_STOP_CONDITION}')
|
||||
return True
|
||||
|
||||
if self.config.CLEAR_MODE_STOP_CONDITION == 'map_3_star':
|
||||
if self.appear(MAP_STAR_1) and self.appear(MAP_STAR_2) and self.appear(MAP_STAR_3):
|
||||
raise ScriptEnd(f'Reach condition: {self.config.CLEAR_MODE_STOP_CONDITION}')
|
||||
if self.appear(MAP_STAR_1) and self.appear(MAP_STAR_2) and self.appear(MAP_STAR_3) and percent > 0.95:
|
||||
return True
|
||||
|
||||
if self.config.CLEAR_MODE_STOP_CONDITION in ['map_3_star', 'map_green'] and self.config.MAP_STAR_CLEAR_ALL:
|
||||
button = [MAP_STAR_1, MAP_STAR_2, MAP_STAR_3][self.config.MAP_STAR_CLEAR_ALL - 1]
|
||||
@ -72,4 +74,18 @@ class FastForwardHandler(ModuleBase):
|
||||
|
||||
if self.config.CLEAR_MODE_STOP_CONDITION == 'map_green':
|
||||
if self.appear(MAP_GREEN):
|
||||
raise ScriptEnd(f'Reach condition: {self.config.CLEAR_MODE_STOP_CONDITION}')
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def handle_map_clear_mode_stop(self):
|
||||
if self.map_clear_record is True:
|
||||
return False
|
||||
|
||||
flag = self.triggered_map_clear_mode_stop()
|
||||
if self.map_clear_record is None:
|
||||
self.map_clear_record = flag
|
||||
elif self.map_clear_record is False and flag:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
22
module/handler/story.py
Normal file
@ -0,0 +1,22 @@
|
||||
from module.handler.assets import *
|
||||
from module.handler.popup import PopupHandler
|
||||
|
||||
|
||||
class StoryHandler(PopupHandler):
|
||||
def story_skip(self):
|
||||
if self.appear_then_click(STORY_SKIP, offset=True, interval=2):
|
||||
return True
|
||||
if self.handle_popup_confirm():
|
||||
return True
|
||||
if self.appear_then_click(STORY_CHOOCE, offset=True, interval=2):
|
||||
return True
|
||||
if self.appear_then_click(STORY_CHOOCE_2, offset=True, interval=2):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def handle_story_skip(self):
|
||||
if not self.config.ENABLE_MAP_CLEAR_MODE:
|
||||
return False
|
||||
|
||||
return self.story_skip()
|
@ -18,6 +18,7 @@ FLEET_PREPARATION_HARD_2 = Button(area=(201, 393, 1001, 394), color=(255, 219, 0
|
||||
MAP_CAT_ATTACK = Button(area=(1241, 106, 1271, 115), color=(255, 231, 123), button=(1148, 653, 1262, 705), file='./assets/map/MAP_CAT_ATTACK.png')
|
||||
MAP_OFFENSIVE = Button(area=(1148, 653, 1262, 705), color=(234, 180, 108), button=(1148, 653, 1262, 705), file='./assets/map/MAP_OFFENSIVE.png')
|
||||
MAP_PREPARATION = Button(area=(854, 488, 1052, 548), color=(236, 186, 115), button=(854, 488, 1052, 548), file='./assets/map/MAP_PREPARATION.png')
|
||||
MAP_PREPARATION_CANCEL = Button(area=(234, 12, 278, 47), color=(45, 46, 69), button=(234, 12, 278, 47), file='./assets/map/MAP_PREPARATION_CANCEL.png')
|
||||
SUBMARINE_BAR = Button(area=(1015, 525, 1186, 602), color=(193, 177, 144), button=(1015, 525, 1186, 602), file='./assets/map/SUBMARINE_BAR.png')
|
||||
SUBMARINE_CHOOSE = Button(area=(1026, 447, 1090, 505), color=(208, 164, 103), button=(1026, 447, 1090, 505), file='./assets/map/SUBMARINE_CHOOSE.png')
|
||||
SUBMARINE_CLEAR = Button(area=(1108, 447, 1172, 505), color=(152, 153, 154), button=(1108, 447, 1172, 505), file='./assets/map/SUBMARINE_CLEAR.png')
|
||||
|
@ -47,10 +47,20 @@ class Camera(InfoBarHandler):
|
||||
# Linear fit
|
||||
# x = x * 200
|
||||
# y = y * 140
|
||||
# Function fit
|
||||
x, y = swipe_multiply_2d(x, y)
|
||||
if self.config.CAMERA_SWIPE_MULTIPLY_X is not None and self.config.CAMERA_SWIPE_MULTIPLY_Y is not None:
|
||||
if callable(self.config.CAMERA_SWIPE_MULTIPLY_X):
|
||||
x = self.config.CAMERA_SWIPE_MULTIPLY_X(x)
|
||||
else:
|
||||
x = x * self.config.CAMERA_SWIPE_MULTIPLY_X
|
||||
if callable(self.config.CAMERA_SWIPE_MULTIPLY_Y):
|
||||
y = self.config.CAMERA_SWIPE_MULTIPLY_X(y)
|
||||
else:
|
||||
y = y * self.config.CAMERA_SWIPE_MULTIPLY_Y
|
||||
else:
|
||||
# Function fit
|
||||
x, y = swipe_multiply_2d(x, y)
|
||||
|
||||
vector = (-x, -y)
|
||||
vector = (-int(x), -int(y))
|
||||
self.device.swipe(vector)
|
||||
self.device.sleep(0.3)
|
||||
self.update()
|
||||
@ -71,7 +81,10 @@ class Camera(InfoBarHandler):
|
||||
vector = np.array(vector)
|
||||
self.camera = tuple(vector + self.camera)
|
||||
vector = np.array([0.5, 0.5]) - np.array(self.grids.center_offset) + vector
|
||||
self._map_swipe(vector)
|
||||
try:
|
||||
self._map_swipe(vector)
|
||||
except PerspectiveError as e:
|
||||
self.handle_camera_outside_map(e)
|
||||
|
||||
def focus_to_grid_center(self):
|
||||
"""
|
||||
@ -80,7 +93,7 @@ class Camera(InfoBarHandler):
|
||||
Returns:
|
||||
bool: Map swiped.
|
||||
"""
|
||||
if np.any(np.abs(self.grids.center_offset - 0.5) > 0.1):
|
||||
if np.any(np.abs(self.grids.center_offset - 0.5) > self.config.MAP_GRID_CENTER_TOLERANCE):
|
||||
logger.info('Re-focus to grid center.')
|
||||
self.map_swipe((0, 0))
|
||||
return True
|
||||
@ -176,10 +189,7 @@ class Camera(InfoBarHandler):
|
||||
self.map_swipe((x, y))
|
||||
|
||||
except PerspectiveError as e:
|
||||
msg = str(e).split(':')[1].strip()
|
||||
logger.info(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])
|
||||
self.handle_camera_outside_map(e)
|
||||
continue
|
||||
|
||||
record.append((x, y))
|
||||
@ -196,6 +206,12 @@ class Camera(InfoBarHandler):
|
||||
|
||||
return record
|
||||
|
||||
def handle_camera_outside_map(self, e):
|
||||
msg = str(e).split(':')[1].strip()
|
||||
logger.info(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])
|
||||
|
||||
def focus_to(self, location, swipe_limit=(3, 2)):
|
||||
"""Focus camera on a grid
|
||||
|
||||
@ -248,15 +264,17 @@ class Camera(InfoBarHandler):
|
||||
carrier_count=carrier_count)
|
||||
self.map.show()
|
||||
|
||||
def in_sight(self, location, sight=(-3, -1, 3, 2)):
|
||||
def in_sight(self, location, sight=None):
|
||||
"""Make sure location in camera sight
|
||||
|
||||
Args:
|
||||
location:
|
||||
sight:
|
||||
sight (tuple): Such as (-3, -1, 3, 2).
|
||||
"""
|
||||
location = location_ensure(location)
|
||||
logger.info('In sight: %s' % location2node(location))
|
||||
if sight is None:
|
||||
sight = self.map.camera_sight
|
||||
|
||||
diff = np.array(location) - self.camera
|
||||
if diff[1] > sight[3]:
|
||||
|
@ -6,6 +6,10 @@ class PerspectiveError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MapWalkError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ScriptError(Exception):
|
||||
pass
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
import itertools
|
||||
|
||||
from module.base.timer import Timer
|
||||
from module.handler.ambush import AmbushHandler
|
||||
from module.logger import logger
|
||||
from module.map.camera import Camera
|
||||
import itertools
|
||||
|
||||
from module.map.exception import MapWalkError
|
||||
from module.map.grids import Grids
|
||||
from module.map.map_base import SelectedGrids
|
||||
from module.map.map_base import location2node, location_ensure
|
||||
from module.map.map_operation import MapOperation
|
||||
@ -82,12 +84,14 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
||||
location (tuple, str, GridInfo): Destination.
|
||||
"""
|
||||
location = location_ensure(location)
|
||||
self.in_sight(location, sight=(-3, 0, 3, 2))
|
||||
self.focus_to_grid_center()
|
||||
grid = self.convert_map_to_grid(location)
|
||||
result_mystery = ''
|
||||
|
||||
while 1:
|
||||
sight = self.map.camera_sight
|
||||
self.in_sight(location, sight=(sight[0], 0, sight[2], sight[3]))
|
||||
self.focus_to_grid_center()
|
||||
grid = self.convert_map_to_grid(location)
|
||||
|
||||
self.ambush_color_initial()
|
||||
self.enemy_searching_color_initial()
|
||||
grid.__str__ = location
|
||||
@ -95,8 +99,10 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
||||
self.device.click(grid)
|
||||
arrived = False
|
||||
# Wait to confirm fleet arrived. It does't appear immediately if fleet in combat .
|
||||
arrive_timer = Timer(0.3)
|
||||
arrive_unexpected_timer = Timer(1.5)
|
||||
add = self.config.MAP_SIREN_MOVE_WAIT * self.config.MAP_SIREN_COUNT \
|
||||
if not self.config.ENABLE_FAST_FORWARD else 0
|
||||
arrive_timer = Timer(0.3 + add)
|
||||
arrive_unexpected_timer = Timer(1.5 + add)
|
||||
# Wait after ambushed.
|
||||
ambushed_retry = Timer(0.5)
|
||||
# If nothing happens, click again.
|
||||
@ -124,7 +130,7 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
||||
self.hp_get()
|
||||
if self.hp_withdraw_triggered():
|
||||
self.withdraw()
|
||||
arrived = True
|
||||
arrived = True if not self.config.MAP_HAS_MOVABLE_ENEMY else False
|
||||
result = 'combat'
|
||||
self.battle_count += 1
|
||||
self.fleet_ammo -= 1
|
||||
@ -141,6 +147,9 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
||||
if self.handle_map_cat_attack():
|
||||
continue
|
||||
|
||||
if self.handle_walk_out_of_step():
|
||||
raise MapWalkError('walk_out_of_step')
|
||||
|
||||
# Arrive
|
||||
if self.is_in_map() and grid.predict_fleet():
|
||||
arrive_timer.start()
|
||||
@ -176,19 +185,27 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
||||
self.__setattr__('fleet_%s_location' % self.fleet_current_index, location)
|
||||
if result_mystery == 'get_carrier':
|
||||
prev_enemy = self.map.select(is_enemy=True)
|
||||
self.full_scan(battle_count=self.battle_count, mystery_count=self.mystery_count,
|
||||
siren_count=self.siren_count, carrier_count=self.carrier_count, is_carrier_scan=True)
|
||||
self.full_scan(is_carrier_scan=True)
|
||||
diff = self.map.select(is_enemy=True).delete(prev_enemy)
|
||||
logger.info(f'Carrier spawn: {diff}')
|
||||
elif self.config.POOR_MAP_DATA:
|
||||
for grid in self.map:
|
||||
grid.wipe_out()
|
||||
self.full_scan()
|
||||
self.find_path_initial()
|
||||
|
||||
def goto(self, location, optimize=True, expected=''):
|
||||
# self.device.sleep(1000)
|
||||
location = location_ensure(location)
|
||||
if self.config.MAP_HAS_AMBUSH and optimize:
|
||||
if (self.config.MAP_HAS_AMBUSH or self.config.MAP_HAS_FLEET_STEP) and optimize:
|
||||
nodes = self.map.find_path(location, step=self.fleet_step)
|
||||
for node in nodes:
|
||||
self._goto(node, expected=expected if node == nodes[-1] else '')
|
||||
try:
|
||||
self._goto(node, expected=expected if node == nodes[-1] else '')
|
||||
except MapWalkError:
|
||||
nodes_ = self.map.find_path(node, step=1)
|
||||
for node_ in nodes_:
|
||||
self._goto(node_, expected=expected if node == nodes[-1] else '')
|
||||
else:
|
||||
self._goto(location, expected=expected)
|
||||
|
||||
@ -206,6 +223,16 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
||||
fleets.append(text)
|
||||
logger.info(' '.join(fleets))
|
||||
|
||||
def full_scan(self, is_carrier_scan=False):
|
||||
super().full_scan(battle_count=self.battle_count, mystery_count=self.mystery_count,
|
||||
siren_count=self.siren_count, carrier_count=self.carrier_count,
|
||||
is_carrier_scan=is_carrier_scan)
|
||||
if self.config.FLEET_2 and not self.fleet_2_location:
|
||||
fleets = self.map.select(is_fleet=True, is_current_fleet=False)
|
||||
if fleets.count:
|
||||
logger.info(f'Predict fleet_2 to be {fleets[0]}')
|
||||
self.fleet_2_location = fleets[0].location
|
||||
|
||||
def find_all_fleets(self):
|
||||
logger.hr('Find all fleets')
|
||||
queue = self.map.select(is_spawn_point=True)
|
||||
@ -232,25 +259,36 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
||||
self.fleet_1 = fleets[0].location
|
||||
else:
|
||||
logger.info('Fleet_2 not detected.')
|
||||
self.find_all_fleets()
|
||||
elif count == 2:
|
||||
fleets = fleets.sort_by_camera_distance(self.camera)
|
||||
self.in_sight(fleets[0], sight=(-1, 0, 1, 2))
|
||||
if self.convert_map_to_grid(fleets[0]).predict_current_fleet():
|
||||
self.fleet_1 = fleets[0].location
|
||||
self.fleet_2 = fleets[1].location
|
||||
else:
|
||||
self.in_sight(fleets[1], sight=(-1, 0, 1, 2))
|
||||
if self.convert_map_to_grid(fleets[1]).predict_current_fleet():
|
||||
self.fleet_1 = fleets[1].location
|
||||
self.fleet_2 = fleets[0].location
|
||||
if self.config.POOR_MAP_DATA and self.map.select(is_spawn_point=True):
|
||||
self.fleet_1 = fleets[0].location
|
||||
else:
|
||||
logger.warning('Current fleet not found')
|
||||
self.find_all_fleets()
|
||||
elif count == 2:
|
||||
current = self.map.select(is_current_fleet=True)
|
||||
if current.count == 1:
|
||||
self.fleet_1 = current[0].location
|
||||
self.fleet_2 = fleets.delete(current)[0].location
|
||||
else:
|
||||
fleets = fleets.sort_by_camera_distance(self.camera)
|
||||
self.in_sight(fleets[0], sight=(-1, 0, 1, 2))
|
||||
if self.convert_map_to_grid(fleets[0]).predict_current_fleet():
|
||||
self.fleet_1 = fleets[0].location
|
||||
self.fleet_2 = fleets[1].location
|
||||
else:
|
||||
self.in_sight(fleets[1], sight=(-1, 0, 1, 2))
|
||||
if self.convert_map_to_grid(fleets[1]).predict_current_fleet():
|
||||
self.fleet_1 = fleets[1].location
|
||||
self.fleet_2 = fleets[0].location
|
||||
else:
|
||||
logger.warning('Current fleet not found')
|
||||
self.fleet_1 = fleets[0].location
|
||||
self.fleet_2 = fleets[1].location
|
||||
else:
|
||||
if count == 0:
|
||||
logger.warning('No fleets detected.')
|
||||
fleets = self.map.select(is_current_fleet=True)
|
||||
if fleets.count:
|
||||
self.fleet_1 = fleets[0].location
|
||||
if count > 2:
|
||||
logger.warning('Too many fleets: %s.' % str(fleets))
|
||||
self.find_all_fleets()
|
||||
@ -275,8 +313,7 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
||||
self.hp_init()
|
||||
self.handle_strategy(index=self.fleet_current_index)
|
||||
self.ensure_edge_insight(preset=self.map.in_map_swipe_preset_data)
|
||||
self.full_scan(battle_count=self.battle_count, mystery_count=self.mystery_count, siren_count=self.siren_count,
|
||||
carrier_count=self.carrier_count)
|
||||
self.full_scan()
|
||||
self.find_current_fleet()
|
||||
self.find_path_initial()
|
||||
self.map.show_cost()
|
||||
@ -386,6 +423,18 @@ class Fleet(Camera, MapOperation, AmbushHandler):
|
||||
if data.get('battle') == self.battle_count and data.get('boss', 0):
|
||||
appear = True
|
||||
|
||||
if self.config.POOR_MAP_DATA:
|
||||
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
|
||||
for grid in self.map:
|
||||
grid.wipe_out()
|
||||
break
|
||||
|
||||
if appear:
|
||||
logger.info('Catch camera re-positioning after boss appear')
|
||||
camera = self.camera
|
||||
|
@ -93,6 +93,9 @@ class Grids(Perspective):
|
||||
def predict(self):
|
||||
for grid in self:
|
||||
grid.predict()
|
||||
if not self.config.MAP_HAS_DYNAMIC_RED_BORDER:
|
||||
for grid in self:
|
||||
grid.is_siren = False
|
||||
|
||||
def update(self, image):
|
||||
self.image = image
|
||||
|
@ -18,11 +18,9 @@ class Map(Fleet):
|
||||
self.emotion.wait(fleet=self.fleet_current_index)
|
||||
self.goto(grid, expected=expected)
|
||||
|
||||
if self.config.POOR_MAP_DATA:
|
||||
self.ensure_edge_insight()
|
||||
self.full_scan(battle_count=self.battle_count, mystery_count=self.mystery_count, siren_count=self.siren_count,
|
||||
carrier_count=self.carrier_count)
|
||||
self.find_path_initial()
|
||||
if not self.config.POOR_MAP_DATA:
|
||||
self.full_scan()
|
||||
self.find_path_initial()
|
||||
self.map.show_cost()
|
||||
|
||||
def clear_chosen_mystery(self, grid):
|
||||
@ -287,7 +285,7 @@ class Map(Fleet):
|
||||
"""
|
||||
Method to clear roadblocks between fleets, using brute-force to find roadblocks.
|
||||
"""
|
||||
if not self.config.FLEET_2:
|
||||
if not self.config.FLEET_2 or not self.fleet_2_location:
|
||||
return False
|
||||
grids = self.brute_find_roadblocks(self.map[self.fleet_2_location], fleet=1)
|
||||
if grids:
|
||||
@ -304,11 +302,18 @@ class Map(Fleet):
|
||||
Returns:
|
||||
bool: True if clear an enemy.
|
||||
"""
|
||||
if not self.config.MAP_HAS_SIREN:
|
||||
return False
|
||||
|
||||
grids = self.map.select(may_siren=True, is_enemy=True)
|
||||
grids = grids.add(self.map.select(may_siren=True, is_siren=True))
|
||||
grids = grids.add(self.map.select(is_siren=True))
|
||||
grids = grids.add(self.map.select(is_enemy=True, enemy_scale=0))
|
||||
grids = grids.delete(self.map.select(is_boss=True))
|
||||
logger.info('May siren: %s' % self.map.select(may_siren=True))
|
||||
logger.info('May siren and is enemy: %s' % self.map.select(may_siren=True, is_enemy=True))
|
||||
logger.info('Is siren: %s' % self.map.select(is_siren=True))
|
||||
logger.info('Is 0 scale enemy: %s' % self.map.select(is_enemy=True, enemy_scale=0))
|
||||
logger.info('Delete is boss: %s' % self.map.select(is_boss=True))
|
||||
|
||||
grids = self.select_grids(grids, **kwargs)
|
||||
|
||||
|
@ -46,6 +46,7 @@ class CampaignMap:
|
||||
self._camera_data = []
|
||||
self.in_map_swipe_preset_data = None
|
||||
self.poor_map_data = False
|
||||
self.camera_sight = (-3, -1, 3, 2)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.grids.values())
|
||||
@ -85,7 +86,7 @@ class CampaignMap:
|
||||
self.grids[(x, y)] = grid
|
||||
|
||||
# camera_data can be generate automatically, but it's better to set it manually.
|
||||
self.camera_data = [location2node(loca) for loca in camera_2d(self._shape, sight=(-3, -1, 3, 2))]
|
||||
self.camera_data = [location2node(loca) for loca in camera_2d(self._shape, sight=self.camera_sight)]
|
||||
|
||||
# weight_data set to 10.
|
||||
for grid in self:
|
||||
|
@ -2,16 +2,18 @@ from module.base.timer import Timer
|
||||
from module.handler.fast_forward import FastForwardHandler
|
||||
from module.handler.low_emotion import LowEmotionHandler
|
||||
from module.handler.mystery import MysteryHandler
|
||||
from module.handler.story import StoryHandler
|
||||
from module.handler.urgent_commission import UrgentCommissionHandler
|
||||
from module.logger import logger
|
||||
from module.map.assets import *
|
||||
from module.map.exception import CampaignEnd
|
||||
from module.map.exception import ScriptEnd
|
||||
from module.map.map_fleet_preparation import FleetPreparation
|
||||
from module.retire.retirement import Retirement
|
||||
|
||||
|
||||
class MapOperation(UrgentCommissionHandler, MysteryHandler, FleetPreparation, Retirement, FastForwardHandler,
|
||||
LowEmotionHandler):
|
||||
LowEmotionHandler, StoryHandler):
|
||||
def fleet_switch_click(self):
|
||||
"""
|
||||
Switch fleet.
|
||||
@ -55,7 +57,9 @@ class MapOperation(UrgentCommissionHandler, MysteryHandler, FleetPreparation, Re
|
||||
if map_timer.reached() and self.appear(MAP_PREPARATION):
|
||||
self.device.sleep(0.3) # Wait for map information.
|
||||
self.device.screenshot()
|
||||
self.handle_map_clear_mode_stop()
|
||||
if self.handle_map_clear_mode_stop():
|
||||
self.enter_map_cancel()
|
||||
raise ScriptEnd(f'Reach condition: {self.config.CLEAR_MODE_STOP_CONDITION}')
|
||||
self.handle_fast_forward()
|
||||
self.device.click(MAP_PREPARATION)
|
||||
map_timer.reset()
|
||||
@ -84,12 +88,33 @@ class MapOperation(UrgentCommissionHandler, MysteryHandler, FleetPreparation, Re
|
||||
if self.handle_urgent_commission():
|
||||
continue
|
||||
|
||||
# Story skip
|
||||
if self.handle_story_skip():
|
||||
continue
|
||||
|
||||
# End
|
||||
if self.handle_in_map_with_enemy_searching():
|
||||
break
|
||||
|
||||
return True
|
||||
|
||||
def enter_map_cancel(self, skip_first_screenshot=True):
|
||||
logger.hr('Enter map cancel')
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
if self.appear(MAP_PREPARATION) or self.appear(FLEET_PREPARATION):
|
||||
self.device.click(MAP_PREPARATION_CANCEL)
|
||||
continue
|
||||
|
||||
if self.is_in_stage():
|
||||
break
|
||||
|
||||
return True
|
||||
|
||||
def withdraw(self):
|
||||
"""
|
||||
Withdraw campaign.
|
||||
|
@ -69,8 +69,11 @@ class Perspective:
|
||||
# edge_v = edge_v.group()
|
||||
horizontal = inner_h.add(edge_h).group()
|
||||
vertical = inner_v.add(edge_v).group()
|
||||
edge_h = edge_h.group().delete(inner_h) # Experimental, reduce edge lines.
|
||||
edge_v = edge_v.group().delete(inner_v)
|
||||
edge_h = edge_h.group()
|
||||
edge_v = edge_v.group()
|
||||
if not self.config.TRUST_EDGE_LINES:
|
||||
edge_h = edge_h.delete(inner_h) # Experimental, reduce edge lines.
|
||||
edge_v = edge_v.delete(inner_v)
|
||||
self.horizontal = horizontal
|
||||
self.vertical = vertical
|
||||
|
||||
@ -261,6 +264,7 @@ class Perspective:
|
||||
793.1379371 922.2605459 1051.38315469 1180.50576349 1309.62837229]
|
||||
"""
|
||||
right_distant_point = (self.vanish_point[0] * 2 - self.distant_point[0], self.distant_point[1])
|
||||
encourage = self.config.COINCIDENT_POINT_ENCOURAGE_DISTANCE ** 2
|
||||
|
||||
def convert_to_x(ys):
|
||||
return Points([[self.config.SCREEN_CENTER[0], y] for y in ys], config=self.config) \
|
||||
@ -285,7 +289,7 @@ class Perspective:
|
||||
|
||||
# Activation function
|
||||
# distance = 1 / (1 + np.exp(16 / distance - distance))
|
||||
distance = 1 / (1 + np.exp(9 / distance) / distance)
|
||||
distance = 1 / (1 + np.exp(encourage / distance) / distance)
|
||||
distance = np.sum(distance)
|
||||
return distance
|
||||
|
||||
@ -302,16 +306,18 @@ class Perspective:
|
||||
# Fitting mid
|
||||
coincident = Lines(np.vstack(lines), is_horizontal=False, config=self.config)
|
||||
# print(np.round(np.sort(coincident.get_x(128))).astype(int))
|
||||
coincident_point = optimize.brute(coincident_point_value, self.config.COINCIDENT_POINT_RANGE)
|
||||
mid_diff_range = self.config.MID_DIFF_RANGE_H if is_horizontal else self.config.MID_DIFF_RANGE_V
|
||||
coincident_point_range = ((-abs(self.config.ERROR_LINES_TOLERANCE[0]) * mid_diff_range[1], 200), mid_diff_range)
|
||||
coincident_point = optimize.brute(coincident_point_value, coincident_point_range)
|
||||
# print(coincident_point, is_horizontal)
|
||||
|
||||
diff = abs(coincident_point[1] - 129)
|
||||
if diff > 3:
|
||||
diff = np.max([mid_diff_range[0] - coincident_point[1], coincident_point[1] - mid_diff_range[1]])
|
||||
if diff > 0:
|
||||
self.correct = False
|
||||
logger.info('%s coincident point unexpected: %s' % (
|
||||
'Horizontal' if is_horizontal else 'Vertical',
|
||||
str(coincident_point)))
|
||||
if diff > 6:
|
||||
if diff > 3:
|
||||
self.save_error_image()
|
||||
|
||||
# The limits of detecting area
|
||||
@ -329,6 +335,7 @@ class Perspective:
|
||||
|
||||
left, right = border
|
||||
# print(mids)
|
||||
# print(np.diff(mids))
|
||||
# Filling mid
|
||||
mids = np.arange(-25, 25) * coincident_point[1] + coincident_point[0]
|
||||
mids = mids[(mids > left - threshold) & (mids < right + threshold)]
|
||||
|
@ -119,6 +119,7 @@ class Reward(RewardCommission):
|
||||
for button in [GET_ITEMS_1, GET_ITEMS_2]:
|
||||
if self.appear_then_click(button, offset=(30, 30), interval=1):
|
||||
exit_timer.reset()
|
||||
timeout.reset()
|
||||
reward = True
|
||||
continue
|
||||
|
||||
@ -128,12 +129,14 @@ class Reward(RewardCommission):
|
||||
if self.appear_then_click(button, interval=1):
|
||||
exit_timer.reset()
|
||||
click_timer.reset()
|
||||
timeout.reset()
|
||||
continue
|
||||
|
||||
if not self.appear(MISSION_CHECK):
|
||||
if self.appear_then_click(GET_SHIP, interval=1):
|
||||
click_timer.reset()
|
||||
exit_timer.reset()
|
||||
timeout.reset()
|
||||
continue
|
||||
|
||||
# End
|
||||
|
@ -14,5 +14,6 @@ TEMPLATE_FLEET_AMMO = Template(file='./assets/template/TEMPLATE_FLEET_AMMO.png')
|
||||
TEMPLATE_FORMATION_1 = Template(file='./assets/template/TEMPLATE_FORMATION_1.png')
|
||||
TEMPLATE_FORMATION_2 = Template(file='./assets/template/TEMPLATE_FORMATION_2.png')
|
||||
TEMPLATE_FORMATION_3 = Template(file='./assets/template/TEMPLATE_FORMATION_3.png')
|
||||
TEMPLATE_MAP_WALK_OUT_OF_STEP = Template(file='./assets/template/TEMPLATE_MAP_WALK_OUT_OF_STEP.png')
|
||||
TEMPLATE_STAGE_CLEAR = Template(file='./assets/template/TEMPLATE_STAGE_CLEAR.png')
|
||||
TEMPLATE_STAGE_PERCENT = Template(file='./assets/template/TEMPLATE_STAGE_PERCENT.png')
|
||||
|