mirror of
https://github.com/LmeSzinc/AzurLaneAutoScript.git
synced 2025-01-09 09:37:41 +08:00
Add: OpSi abyssal and handle battle status C/D in auto search
This commit is contained in:
parent
f848fd068d
commit
dfd334736f
BIN
assets/cn/os/STRONGHOLD_PERCENTAGE.png
Normal file
BIN
assets/cn/os/STRONGHOLD_PERCENTAGE.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
BIN
assets/en/os/STRONGHOLD_PERCENTAGE.png
Normal file
BIN
assets/en/os/STRONGHOLD_PERCENTAGE.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
BIN
assets/jp/os/STRONGHOLD_PERCENTAGE.png
Normal file
BIN
assets/jp/os/STRONGHOLD_PERCENTAGE.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
BIN
assets/tw/os/STRONGHOLD_PERCENTAGE.png
Normal file
BIN
assets/tw/os/STRONGHOLD_PERCENTAGE.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
@ -21,6 +21,7 @@ SELECT_DANGEROUS = Button(area={'cn': (89, 318, 167, 336), 'en': (82, 254, 173,
|
||||
SELECT_OBSCURE = Button(area={'cn': (89, 251, 167, 269), 'en': (98, 252, 158, 268), 'jp': (89, 251, 167, 269), 'tw': (88, 250, 167, 270)}, color={'cn': (109, 111, 114), 'en': (96, 97, 101), 'jp': (110, 112, 115), 'tw': (102, 104, 107)}, button={'cn': (89, 251, 167, 269), 'en': (98, 252, 158, 268), 'jp': (89, 251, 167, 269), 'tw': (88, 250, 167, 270)}, file={'cn': './assets/cn/os/SELECT_OBSCURE.png', 'en': './assets/en/os/SELECT_OBSCURE.png', 'jp': './assets/jp/os/SELECT_OBSCURE.png', 'tw': './assets/tw/os/SELECT_OBSCURE.png'})
|
||||
SELECT_SAFE = Button(area={'cn': (89, 251, 167, 269), 'en': (92, 253, 164, 268), 'jp': (89, 251, 167, 269), 'tw': (88, 250, 167, 270)}, color={'cn': (89, 94, 94), 'en': (103, 109, 108), 'jp': (118, 121, 121), 'tw': (103, 109, 107)}, button={'cn': (89, 251, 167, 269), 'en': (92, 253, 164, 268), 'jp': (89, 251, 167, 269), 'tw': (88, 250, 167, 270)}, file={'cn': './assets/cn/os/SELECT_SAFE.png', 'en': './assets/en/os/SELECT_SAFE.png', 'jp': './assets/jp/os/SELECT_SAFE.png', 'tw': './assets/tw/os/SELECT_SAFE.png'})
|
||||
SELECT_STRONGHOLD = Button(area={'cn': (89, 251, 166, 269), 'en': (81, 252, 175, 272), 'jp': (89, 251, 167, 269), 'tw': (88, 250, 167, 270)}, color={'cn': (113, 114, 118), 'en': (81, 83, 87), 'jp': (115, 116, 119), 'tw': (103, 105, 108)}, button={'cn': (89, 251, 166, 269), 'en': (81, 252, 175, 272), 'jp': (89, 251, 167, 269), 'tw': (88, 250, 167, 270)}, file={'cn': './assets/cn/os/SELECT_STRONGHOLD.png', 'en': './assets/en/os/SELECT_STRONGHOLD.png', 'jp': './assets/jp/os/SELECT_STRONGHOLD.png', 'tw': './assets/tw/os/SELECT_STRONGHOLD.png'})
|
||||
STRONGHOLD_PERCENTAGE = Button(area={'cn': (293, 125, 340, 143), 'en': (293, 125, 340, 143), 'jp': (293, 125, 340, 143), 'tw': (293, 125, 340, 143)}, color={'cn': (132, 135, 146), 'en': (132, 135, 146), 'jp': (132, 135, 146), 'tw': (132, 135, 146)}, button={'cn': (293, 125, 340, 143), 'en': (293, 125, 340, 143), 'jp': (293, 125, 340, 143), 'tw': (293, 125, 340, 143)}, file={'cn': './assets/cn/os/STRONGHOLD_PERCENTAGE.png', 'en': './assets/en/os/STRONGHOLD_PERCENTAGE.png', 'jp': './assets/jp/os/STRONGHOLD_PERCENTAGE.png', 'tw': './assets/tw/os/STRONGHOLD_PERCENTAGE.png'})
|
||||
TEMPLATE_EMPTY_HP = Template(file={'cn': './assets/cn/os/TEMPLATE_EMPTY_HP.png', 'en': './assets/en/os/TEMPLATE_EMPTY_HP.png', 'jp': './assets/jp/os/TEMPLATE_EMPTY_HP.png', 'tw': './assets/tw/os/TEMPLATE_EMPTY_HP.png'})
|
||||
ZONE_ABYSSAL = Button(area={'cn': (85, 302, 171, 322), 'en': (86, 302, 168, 319), 'jp': (84, 301, 171, 322), 'tw': (84, 301, 172, 322)}, color={'cn': (171, 143, 147), 'en': (176, 136, 138), 'jp': (160, 123, 127), 'tw': (168, 134, 139)}, button={'cn': (85, 302, 171, 322), 'en': (86, 302, 168, 319), 'jp': (84, 301, 171, 322), 'tw': (84, 301, 172, 322)}, file={'cn': './assets/cn/os/ZONE_ABYSSAL.png', 'en': './assets/en/os/ZONE_ABYSSAL.png', 'jp': './assets/jp/os/ZONE_ABYSSAL.png', 'tw': './assets/tw/os/ZONE_ABYSSAL.png'})
|
||||
ZONE_DANGEROUS = Button(area={'cn': (87, 310, 171, 322), 'en': (71, 310, 184, 319), 'jp': (84, 311, 172, 322), 'tw': (84, 310, 172, 322)}, color={'cn': (153, 177, 197), 'en': (181, 191, 204), 'jp': (139, 167, 189), 'tw': (153, 176, 195)}, button={'cn': (87, 310, 171, 322), 'en': (71, 310, 184, 319), 'jp': (84, 311, 172, 322), 'tw': (84, 310, 172, 322)}, file={'cn': './assets/cn/os/ZONE_DANGEROUS.png', 'en': './assets/en/os/ZONE_DANGEROUS.png', 'jp': './assets/jp/os/ZONE_DANGEROUS.png', 'tw': './assets/tw/os/ZONE_DANGEROUS.png'})
|
||||
|
@ -10,7 +10,8 @@ from module.map.fleet import Fleet
|
||||
from module.map.map_grids import SelectedGrids
|
||||
from module.map.utils import location_ensure
|
||||
from module.map_detection.utils import *
|
||||
from module.os.assets import TEMPLATE_EMPTY_HP
|
||||
from module.ocr.ocr import Ocr
|
||||
from module.os.assets import *
|
||||
from module.os.camera import OSCamera
|
||||
from module.os.map_base import OSCampaignMap
|
||||
from module.os_ash.ash import OSAsh
|
||||
@ -38,6 +39,17 @@ class BossFleet:
|
||||
__repr__ = __str__
|
||||
|
||||
|
||||
class PercentageOcr(Ocr):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['lang'] = 'azur_lane'
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def pre_process(self, image):
|
||||
image = super().pre_process(image)
|
||||
image = np.pad(image, ((2, 2), (0, 0)), mode='constant', constant_values=255)
|
||||
return image
|
||||
|
||||
|
||||
class OSFleet(OSCamera, Combat, Fleet, OSAsh):
|
||||
def _goto(self, location, expected=''):
|
||||
super()._goto(location, expected)
|
||||
@ -143,6 +155,8 @@ class OSFleet(OSCamera, Combat, Fleet, OSAsh):
|
||||
def hp_retreat_triggered(self):
|
||||
return False
|
||||
|
||||
need_repair = [False, False, False, False, False, False]
|
||||
|
||||
def hp_get(self):
|
||||
"""
|
||||
Calculate current HP, also detects the wrench (Ship died, need to repair)
|
||||
@ -150,6 +164,7 @@ class OSFleet(OSCamera, Combat, Fleet, OSAsh):
|
||||
super().hp_get()
|
||||
ship_icon = self._hp_grid().crop((0, -67, 67, 0))
|
||||
need_repair = [TEMPLATE_EMPTY_HP.match(self.image_area(button)) for button in ship_icon.buttons]
|
||||
self.need_repair = need_repair
|
||||
logger.attr('Repair icon', need_repair)
|
||||
|
||||
if any(need_repair):
|
||||
@ -533,3 +548,22 @@ class OSFleet(OSCamera, Combat, Fleet, OSAsh):
|
||||
self.question_goto(has_fleet_step=True)
|
||||
result = self.boss_clear(has_fleet_step=True)
|
||||
return result
|
||||
|
||||
def get_stronghold_percentage(self):
|
||||
"""
|
||||
Get the clear status in siren stronghold.
|
||||
|
||||
Returns:
|
||||
str: Usually in ['100', '80', '60', '40', '20', '0']
|
||||
"""
|
||||
ocr = PercentageOcr(STRONGHOLD_PERCENTAGE, letter=(255, 255, 255), threshold=128, name='STRONGHOLD_PERCENTAGE')
|
||||
result = ocr.ocr(self.device.image)
|
||||
result = result.rstrip('7Kk')
|
||||
for starter in ['100', '80', '60', '40', '20', '0']:
|
||||
if result.startswith(starter):
|
||||
result = starter
|
||||
logger.attr('STRONGHOLD_PERCENTAGE', result)
|
||||
return result
|
||||
|
||||
logger.warning(f'Unexpected STRONGHOLD_PERCENTAGE: {result}')
|
||||
return result
|
||||
|
@ -178,7 +178,10 @@ class OSMap(OSFleet, Map, GlobeCamera):
|
||||
if self.combat_appear():
|
||||
self._auto_search_battle_count += 1
|
||||
logger.attr('battle_count', self._auto_search_battle_count)
|
||||
self.auto_search_combat()
|
||||
result = self.auto_search_combat()
|
||||
if not result:
|
||||
logger.warning('Fleet died, stop auto search')
|
||||
break
|
||||
if self.handle_map_event():
|
||||
# Auto search can not handle siren searching device.
|
||||
continue
|
||||
|
@ -3,6 +3,7 @@ import numpy as np
|
||||
from module.exception import MapWalkError, ScriptError, RequestHumanTakeover
|
||||
from module.logger import logger
|
||||
from module.map.map_grids import SelectedGrids
|
||||
from module.os.fleet import BossFleet
|
||||
from module.os.map import OSMap
|
||||
from module.reward.reward import Reward
|
||||
from module.ui.ui import page_os
|
||||
@ -447,7 +448,10 @@ class OperationSiren(Reward, OSMap):
|
||||
self.config.task_delay(server_update=True)
|
||||
self.config.task_stop()
|
||||
|
||||
raise NotImplementedError
|
||||
self.globe_enter(zone)
|
||||
self.zone_init()
|
||||
self.os_order_execute(recon_scan=True, submarine_call=False)
|
||||
self.run_stronghold()
|
||||
|
||||
self.fleet_repair(revert=False)
|
||||
|
||||
@ -456,6 +460,74 @@ class OperationSiren(Reward, OSMap):
|
||||
self.clear_stronghold()
|
||||
self.config.check_task_switch()
|
||||
|
||||
def run_stronghold_one_fleet(self, fleet):
|
||||
"""
|
||||
Args
|
||||
fleet (BossFleet):
|
||||
|
||||
Returns:
|
||||
bool: If all cleared.
|
||||
"""
|
||||
self.config.override(
|
||||
OpsiGeneral_BuyAkashiShop=False,
|
||||
OpsiGeneral_RepairThreshold=0
|
||||
)
|
||||
# Try 3 times, because fleet may stuck in fog.
|
||||
for _ in range(3):
|
||||
# Attack
|
||||
self.fleet_set(fleet.fleet_index)
|
||||
self.run_auto_search()
|
||||
self.hp_reset()
|
||||
self.hp_get()
|
||||
|
||||
# End
|
||||
if self.get_stronghold_percentage() == '0':
|
||||
logger.info('BOSS clear')
|
||||
return True
|
||||
elif any(self.need_repair):
|
||||
logger.info('Auto search stopped, because fleet died')
|
||||
# Re-enter to reset fleet position
|
||||
prev = self.zone
|
||||
self.globe_goto(self.zone_nearest_azur_port(self.zone))
|
||||
self.globe_goto(prev, types='STRONGHOLD')
|
||||
return False
|
||||
else:
|
||||
logger.info('Auto search stopped, because fleet stuck')
|
||||
# Re-enter to reset fleet position
|
||||
prev = self.zone
|
||||
self.globe_goto(self.zone_nearest_azur_port(self.zone))
|
||||
self.globe_goto(prev, types='STRONGHOLD')
|
||||
continue
|
||||
|
||||
def run_stronghold(self):
|
||||
"""
|
||||
All fleets take turns in attacking siren stronghold.
|
||||
|
||||
Returns:
|
||||
bool: If success to clear.
|
||||
|
||||
Pages:
|
||||
in: Siren logger (abyssal), boss appeared.
|
||||
out: If success, dangerous or safe zone.
|
||||
If failed, still in abyssal.
|
||||
"""
|
||||
logger.hr(f'Stronghold clear', level=1)
|
||||
fleets = self.parse_fleet_filter()
|
||||
for fleet in fleets:
|
||||
logger.hr(f'Turn: {fleet}', level=2)
|
||||
if not isinstance(fleet, BossFleet):
|
||||
self.os_order_execute(recon_scan=False, submarine_call=True)
|
||||
continue
|
||||
|
||||
result = self.run_stronghold_one_fleet(fleet)
|
||||
if result:
|
||||
return True
|
||||
else:
|
||||
continue
|
||||
|
||||
logger.critical('Unable to clear boss, fleets exhausted')
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
self = OperationSiren('alas', task='OpsiObscure')
|
||||
@ -464,4 +536,4 @@ if __name__ == '__main__':
|
||||
self.config = self.config.merge(OSConfig())
|
||||
self.device.screenshot()
|
||||
self.os_init()
|
||||
self.clear_abyssal()
|
||||
self.clear_stronghold()
|
||||
|
@ -152,8 +152,43 @@ class Combat(Combat_, MapEventHandler):
|
||||
logger.info('Continuous combat detected')
|
||||
continue
|
||||
|
||||
def handle_auto_search_battle_status(self, drop=None):
|
||||
if self.appear(BATTLE_STATUS_C, interval=self.battle_status_click_interval):
|
||||
logger.warning('Battle Status C')
|
||||
# raise GameStuckError('Battle status C')
|
||||
if drop:
|
||||
drop.handle_add(self)
|
||||
else:
|
||||
self.device.sleep((0.25, 0.5))
|
||||
self.device.click(BATTLE_STATUS_C)
|
||||
return True
|
||||
if self.appear(BATTLE_STATUS_D, interval=self.battle_status_click_interval):
|
||||
logger.warning('Battle Status D')
|
||||
# raise GameStuckError('Battle Status D')
|
||||
if drop:
|
||||
drop.handle_add(self)
|
||||
else:
|
||||
self.device.sleep((0.25, 0.5))
|
||||
self.device.click(BATTLE_STATUS_D)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def handle_auto_search_exp_info(self):
|
||||
if self.appear_then_click(EXP_INFO_C):
|
||||
self.device.sleep((0.25, 0.5))
|
||||
return True
|
||||
if self.appear_then_click(EXP_INFO_D):
|
||||
self.device.sleep((0.25, 0.5))
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def auto_search_combat(self):
|
||||
"""
|
||||
Returns:
|
||||
bool: True if enemy cleared, False if fleet died.
|
||||
|
||||
Pages:
|
||||
in: is_combat_loading()
|
||||
out: combat status
|
||||
@ -180,17 +215,24 @@ class Combat(Combat_, MapEventHandler):
|
||||
if self.config.Submarine_Fleet:
|
||||
submarine_mode = self.config.Submarine_Mode
|
||||
|
||||
success = True
|
||||
while 1:
|
||||
self.device.screenshot()
|
||||
|
||||
if self.handle_submarine_call(submarine_mode):
|
||||
continue
|
||||
if self.handle_os_auto_search_map_option():
|
||||
if success and self.handle_os_auto_search_map_option():
|
||||
continue
|
||||
|
||||
# End
|
||||
if self.is_combat_executing():
|
||||
continue
|
||||
if self.handle_auto_search_battle_status():
|
||||
success = False
|
||||
continue
|
||||
if self.handle_auto_search_exp_info():
|
||||
success = False
|
||||
continue
|
||||
if self.handle_map_event():
|
||||
continue
|
||||
if self.is_in_map():
|
||||
@ -198,3 +240,4 @@ class Combat(Combat_, MapEventHandler):
|
||||
break
|
||||
|
||||
logger.info('Combat end.')
|
||||
return success
|
||||
|
Loading…
Reference in New Issue
Block a user