Add: [CN]Dossier Beacon Attack Add: [CN]Ash Beacon OneHitMode

This commit is contained in:
zhou525 2022-08-25 13:45:53 +08:00
parent 0a568ee2b3
commit 9085ac0b8b
87 changed files with 645 additions and 361 deletions

18
alas.py
View File

@ -103,16 +103,16 @@ class AzurLaneAutoScript:
logger.critical(e)
logger.critical('This is likely to be a mistake of developers, but sometimes just random issues')
handle_notify(
self.config.Error_OnePushConfig,
title=f"Alas <{self.config_name}> crashed",
self.config.Error_OnePushConfig,
title=f"Alas <{self.config_name}> crashed",
content=f"<{self.config_name}> ScriptError",
)
exit(1)
except RequestHumanTakeover:
logger.critical('Request human takeover')
handle_notify(
self.config.Error_OnePushConfig,
title=f"Alas <{self.config_name}> crashed",
self.config.Error_OnePushConfig,
title=f"Alas <{self.config_name}> crashed",
content=f"<{self.config_name}> RequestHumanTakeover",
)
exit(1)
@ -120,8 +120,8 @@ class AzurLaneAutoScript:
logger.exception(e)
self.save_error_log()
handle_notify(
self.config.Error_OnePushConfig,
title=f"Alas <{self.config_name}> crashed",
self.config.Error_OnePushConfig,
title=f"Alas <{self.config_name}> crashed",
content=f"<{self.config_name}> Exception occured",
)
exit(1)
@ -288,9 +288,13 @@ class AzurLaneAutoScript:
MaritimeEscort(config=self.config, device=self.device).run()
def opsi_ash_assist(self):
from module.os_ash.ash import AshBeaconAssist
from module.os_ash.meta import AshBeaconAssist
AshBeaconAssist(config=self.config, device=self.device).run()
def opsi_ash_beacon(self):
from module.os_ash.meta import OpsiAshBeacon
OpsiAshBeacon(config=self.config, device=self.device).run()
def opsi_explore(self):
from module.campaign.os_run import OSCampaignRun
OSCampaignRun(config=self.config, device=self.device).opsi_explore()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

View File

@ -1467,11 +1467,25 @@
"RepairThreshold": 0.4,
"DoRandomMapEvent": true,
"AkashiShopFilter": "ActionPoint > PurpleCoins"
}
},
"OpsiAshBeacon": {
"Scheduler": {
"Enable": false,
"NextRun": "2020-01-01 00:00:00",
"Command": "OpsiAshBeacon",
"SuccessInterval": 30,
"FailureInterval": 30,
"ServerUpdate": "00:00"
},
"OpsiAshBeacon": {
"AshAttack": true,
"EnsureFullyCollected": true,
"RequestAssist": true
"OneHitMode": true,
"RequestAssist": true,
"EnsureFullyCollected": true
},
"OpsiDossierBeacon": {
"Enable": true
}
},
"OpsiAshAssist": {

View File

@ -7457,19 +7457,62 @@
"type": "textarea",
"value": "ActionPoint > PurpleCoins"
}
}
},
"OpsiAshBeacon": {
"Scheduler": {
"Enable": {
"type": "checkbox",
"value": false
},
"NextRun": {
"type": "datetime",
"value": "2020-01-01 00:00:00",
"validate": "datetime"
},
"Command": {
"type": "input",
"value": "OpsiAshBeacon",
"display": "hide"
},
"SuccessInterval": {
"type": "input",
"value": 30,
"display": "hide"
},
"FailureInterval": {
"type": "input",
"value": 30,
"display": "hide"
},
"ServerUpdate": {
"type": "input",
"value": "00:00",
"display": "hide"
}
},
"OpsiAshBeacon": {
"AshAttack": {
"type": "checkbox",
"value": true
},
"EnsureFullyCollected": {
"OneHitMode": {
"type": "checkbox",
"value": true
},
"RequestAssist": {
"type": "checkbox",
"value": true
},
"EnsureFullyCollected": {
"type": "checkbox",
"value": true
}
},
"OpsiDossierBeacon": {
"Enable": {
"type": "checkbox",
"value": true
}
}
},

View File

@ -530,8 +530,11 @@ OpsiGeneral:
ActionPoint > PurpleCoins
OpsiAshBeacon:
AshAttack: true
EnsureFullyCollected: true
OneHitMode: true
RequestAssist: true
EnsureFullyCollected: true
OpsiDossierBeacon:
Enable: true
OpsiFleetFilter:
Filter: |-
Fleet-4 > CallSubmarine > Fleet-2 > Fleet-3 > Fleet-1

View File

@ -52,6 +52,7 @@
],
"Opsi": [
"OpsiGeneral",
"OpsiAshBeacon",
"OpsiAshAssist",
"OpsiExplore",
"OpsiShop",

View File

@ -336,6 +336,11 @@ OpsiAshAssist:
SuccessInterval: 30
FailureInterval: 30
ServerUpdate: 00:00
OpsiAshBeacon:
Scheduler:
SuccessInterval: 30
FailureInterval: 30
ServerUpdate: 00:00
OpsiExplore:
Scheduler:
SuccessInterval: 0

View File

@ -235,7 +235,10 @@ WarArchives:
OpsiGeneral:
- OpsiGeneral
OpsiAshBeacon:
- Scheduler
- OpsiAshBeacon
- OpsiDossierBeacon
OpsiAshAssist:
- Scheduler
- OpsiAshAssist

View File

@ -338,8 +338,12 @@ class GeneratedConfig:
# Group `OpsiAshBeacon`
OpsiAshBeacon_AshAttack = True
OpsiAshBeacon_EnsureFullyCollected = True
OpsiAshBeacon_OneHitMode = True
OpsiAshBeacon_RequestAssist = True
OpsiAshBeacon_EnsureFullyCollected = True
# Group `OpsiDossierBeacon`
OpsiDossierBeacon_Enable = True
# Group `OpsiFleetFilter`
OpsiFleetFilter_Filter = 'Fleet-4 > CallSubmarine > Fleet-2 > Fleet-3 > Fleet-1'

View File

@ -16,9 +16,10 @@ class ManualConfig:
> Reward > MetaReward > BattlePass
> ShopFrequent > ShopOnce > Shipyard > DataKey
> OpsiExplore
> OpsiAshBeacon
> OpsiDaily > OpsiShop
> OpsiAbyssal > OpsiStronghold > OpsiObscure
> Daily > Hard > OpsiAshAssist
> Daily > Hard > OpsiAshBeacon > OpsiAshAssist
> Sos > EventSp > EventA > EventB > EventC > EventD > RaidDaily > WarArchives > MaritimeEscort
> Event > Event2 > Raid > Main > Main2 > Main3
> OpsiMeowfficerFarming

View File

@ -194,6 +194,10 @@
"name": "OpSi General",
"help": ""
},
"OpsiAshBeacon": {
"name": "Ash Beacon",
"help": ""
},
"OpsiAshAssist": {
"name": "OpSi Ash Assist",
"help": ""
@ -1922,13 +1926,27 @@
"name": "Enable Ash Attack",
"help": "When data beacon is full; attack until ash has been completed"
},
"EnsureFullyCollected": {
"name": "Ensure 200 Beacon Data Fully Collected",
"help": "Ignore AP limit setting temporarily before ash beacon fully collected. \"Meowfficer Farming\" must be enabled"
"OneHitMode": {
"name": "One Hit Mode",
"help": "Strike each beacon only once, then call for support every half hour thereafter"
},
"RequestAssist": {
"name": "Request Assists",
"help": "Before the attack, request assists from friends, guild and world"
},
"EnsureFullyCollected": {
"name": "Ensure 200 Beacon Data Fully Collected",
"help": "Ignore AP limit setting temporarily before ash beacon fully collected. \"Meowfficer Farming\" must be enabled"
}
},
"OpsiDossierBeacon": {
"_info": {
"name": "Dossier Beacon",
"help": ""
},
"Enable": {
"name": "Enable Dossier Beacon Attack",
"help": ""
}
},
"OpsiFleetFilter": {

View File

@ -194,6 +194,10 @@
"name": "Task.OpsiGeneral.name",
"help": "Task.OpsiGeneral.help"
},
"OpsiAshBeacon": {
"name": "Task.OpsiAshBeacon.name",
"help": "Task.OpsiAshBeacon.help"
},
"OpsiAshAssist": {
"name": "Task.OpsiAshAssist.name",
"help": "Task.OpsiAshAssist.help"
@ -1922,13 +1926,27 @@
"name": "OpsiAshBeacon.AshAttack.name",
"help": "OpsiAshBeacon.AshAttack.help"
},
"EnsureFullyCollected": {
"name": "OpsiAshBeacon.EnsureFullyCollected.name",
"help": "OpsiAshBeacon.EnsureFullyCollected.help"
"OneHitMode": {
"name": "OpsiAshBeacon.OneHitMode.name",
"help": "OpsiAshBeacon.OneHitMode.help"
},
"RequestAssist": {
"name": "OpsiAshBeacon.RequestAssist.name",
"help": "OpsiAshBeacon.RequestAssist.help"
},
"EnsureFullyCollected": {
"name": "OpsiAshBeacon.EnsureFullyCollected.name",
"help": "OpsiAshBeacon.EnsureFullyCollected.help"
}
},
"OpsiDossierBeacon": {
"_info": {
"name": "OpsiDossierBeacon._info.name",
"help": "OpsiDossierBeacon._info.help"
},
"Enable": {
"name": "OpsiDossierBeacon.Enable.name",
"help": "OpsiDossierBeacon.Enable.help"
}
},
"OpsiFleetFilter": {

View File

@ -194,10 +194,14 @@
"name": "通用设置",
"help": ""
},
"OpsiAshAssist": {
"OpsiAshBeacon": {
"name": "余烬信标",
"help": ""
},
"OpsiAshAssist": {
"name": "信标支援",
"help": ""
},
"OpsiExplore": {
"name": "每月开荒",
"help": ""
@ -1875,7 +1879,7 @@
},
"OpsiAshAssist": {
"_info": {
"name": "余烬信标支援",
"name": "信标支援",
"help": "打每天三次的信标支援"
},
"Tier": {
@ -1922,13 +1926,27 @@
"name": "打余烬信标",
"help": "信标数据满了之后打余烬信标,一直打直到打完"
},
"EnsureFullyCollected": {
"name": "保证收集满每日200信标数据",
"help": "在收集满为前,暂时无视保留行动力设置,需要同时开启 \"短猫相接\""
"OneHitMode": {
"name": "一击即走",
"help": "对每个信标只出击一次,之后每半个小时呼叫支援"
},
"RequestAssist": {
"name": "呼叫支援",
"help": "打信标之前,从好友、舰队、世界呼叫支援"
},
"EnsureFullyCollected": {
"name": "保证收集满每日200信标数据",
"help": "在收集满为前,暂时无视保留行动力设置,需要同时开启 \"短猫相接\""
}
},
"OpsiDossierBeacon": {
"_info": {
"name": "档案信标",
"help": ""
},
"Enable": {
"name": "打档案信标",
"help": ""
}
},
"OpsiFleetFilter": {

View File

@ -194,10 +194,14 @@
"name": "通用設定",
"help": ""
},
"OpsiAshAssist": {
"OpsiAshBeacon": {
"name": "餘燼信標",
"help": ""
},
"OpsiAshAssist": {
"name": "信標支援",
"help": ""
},
"OpsiExplore": {
"name": "每月開荒",
"help": ""
@ -1875,7 +1879,7 @@
},
"OpsiAshAssist": {
"_info": {
"name": "餘燼信標支援",
"name": "信標支援",
"help": "打每日三次的信標支援"
},
"Tier": {
@ -1922,13 +1926,27 @@
"name": "打餘燼信標",
"help": "信標數據滿了之後打餘燼信標,一直打直到打完"
},
"EnsureFullyCollected": {
"name": "保證收集滿每日200信標數據",
"help": "在收集滿為前,暫時無視保留行動力設置,需要同時開啟 \"短貓相接\""
"OneHitMode": {
"name": "一擊即走",
"help": "對每個信標只出擊一次,之後每半個小時呼叫支援"
},
"RequestAssist": {
"name": "呼叫支援",
"help": "打信標之前,從好友、艦隊、世界呼叫支援"
},
"EnsureFullyCollected": {
"name": "保證收集滿每日200信標數據",
"help": "在收集滿為前,暫時無視保留行動力設置,需要同時開啟 \"短貓相接\""
}
},
"OpsiDossierBeacon": {
"_info": {
"name": "檔案信標",
"help": ""
},
"Enable": {
"name": "打檔案信標",
"help": ""
}
},
"OpsiFleetFilter": {

View File

@ -1,15 +1,11 @@
from module.base.timer import Timer
from module.base.utils import color_bar_percentage, image_left_strip
from module.combat.combat import BATTLE_PREPARATION, GET_ITEMS_1, Combat
from module.base.utils import image_left_strip
from module.combat.combat import BATTLE_PREPARATION, Combat
from module.logger import logger
from module.ocr.ocr import Digit, DigitCounter
from module.os.assets import MAP_GOTO_GLOBE, GLOBE_GOTO_MAP
from module.ocr.ocr import DigitCounter
from module.os_ash.assets import *
from module.os_handler.assets import IN_MAP
from module.os_handler.map_event import MapEventHandler
from module.ui.assets import BACK_ARROW
from module.ui.page import page_os
from module.ui.switch import Switch
from module.ui.ui import UI
@ -20,14 +16,6 @@ class DailyDigitCounter(DigitCounter):
return image
OCR_BEACON_REMAIN = DigitCounter(BEACON_REMAIN, threshold=256, name='OCR_ASH_REMAIN')
OCR_BEACON_TIER = Digit(BEACON_TIER, name='OCR_ASH_TIER')
SWITCH_BEACON = Switch(name='Beacon', offset=(20, 20))
SWITCH_BEACON.add_status('mine', BEACON_LIST)
SWITCH_BEACON.add_status('list', BEACON_MY)
class AshBeaconFinished(Exception):
pass
@ -83,125 +71,10 @@ class AshCombat(Combat):
class OSAsh(UI, MapEventHandler):
ash_entrance_offset = (200, 5)
beacon_entrance_offset = (100, 100)
def is_in_ash(self):
return self.appear(ASH_CHECK, offset=(100, 20)) or \
self.appear(ASH_SHOWDOWN, offset=(30, 30))
def is_in_map(self):
return self.appear(IN_MAP, offset=(200, 5))
def _ash_assist_enter_from_map(self, offset=(200, 5), skip_first_screenshot=True):
"""
Args:
offset:
skip_first_screenshot:
Pages:
in: IN_MAP
out: is_in_ash
"""
confirm_timer = Timer(1, count=2).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.appear_then_click(MAP_GOTO_GLOBE, offset=offset, interval=5):
confirm_timer.reset()
continue
if self.appear_then_click(ASH_SHOWDOWN, offset=(30, 30), interval=5):
confirm_timer.reset()
continue
if self.appear_then_click(ASH_ENTRANCE, offset=offset, interval=5):
confirm_timer.reset()
continue
if self._handle_ash_beacon_reward():
confirm_timer.reset()
continue
if self.handle_popup_confirm('GOTO_GLOBE'):
# Popup: Leaving current zone will terminate meowfficer searching
confirm_timer.reset()
continue
if self.handle_map_event():
confirm_timer.reset()
continue
# End
if self.is_in_ash():
if confirm_timer.reached():
break
else:
confirm_timer.reset()
def _ash_beacon_select(self, tier=15, trial=5):
"""
Args:
tier (int): Try to find a beacon with tier greater or equal argument tier.
trial (int): If not found after several trial, attack current one.
Returns:
bool: If selected beacon satisfies input tier.
Page:
in: ASH_CHECK, beacon list
"""
# Ensure BEACON_TIER shown up
# When entering beacon list, tier number wasn't shown immediately.
for n in range(10):
if self.image_color_count(BEACON_TIER, color=(0, 0, 0), threshold=221, count=50):
break
self.device.screenshot()
if n >= 9:
logger.warning('Waiting for beacon tier timeout')
# Select beacon
for _ in range(trial):
current = OCR_BEACON_TIER.ocr(self.device.image)
if current >= tier:
return True
else:
self.device.click(BEACON_NEXT)
self.device.sleep((0.3, 0.5))
self.device.screenshot()
logger.info(f'Tier {tier} beacon not found after {trial} trial, use current beacon')
return False
def ash_beacon_assist(self):
"""
Run beacon ash assist.
Pages:
in: Any page
out: page_os
"""
# If the main story in OS is not cleared, ASH_ENTRANCE is the first button counted from bottom right.
# When main story is cleared, ASH_ENTRANCE move to the second one.
# Here use an offset to handle that.
ash_combat = AshCombat(self.config, self.device)
self.ui_ensure(page_os)
self._ash_assist_enter_from_map(offset=self.ash_entrance_offset, skip_first_screenshot=True)
for _ in range(10):
SWITCH_BEACON.set('list', main=self)
remain, _, _ = OCR_BEACON_REMAIN.ocr(self.device.image)
if remain <= 0:
logger.info('Ash beacon exhausted')
break
self._ash_beacon_select(tier=self.config.OpsiAshAssist_Tier)
ash_combat.combat(expected_end=self.is_in_ash, save_get_items=False, emotion_reduce=False)
self.device.sleep((0.5, 0.8))
self.device.screenshot()
self._ash_exit_to_globe()
return True
_ash_fully_collected = False
def ash_collect_status(self):
@ -239,179 +112,6 @@ class OSAsh(UI, MapEventHandler):
status = 0
return status
def _ash_mine_enter_from_map(self, skip_first_screenshot=True):
"""
Pages:
in: is_in_map
out: is_in_ash
"""
in_map_timeout = Timer(2, count=3)
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if in_map_timeout.reached() and self.is_in_map():
self.device.click(ASH_COLLECT_STATUS)
in_map_timeout.reset()
continue
if self.appear_then_click(ASH_ENTER_CONFIRM, offset=(30, 50), interval=2):
continue
if self.appear_then_click(ASH_SHOWDOWN, offset=(30, 30), interval=3):
continue
if self.appear_then_click(BEACON_ENTER, offset=self.beacon_entrance_offset, interval=2):
continue
if self._handle_ash_beacon_reward():
continue
if self.handle_map_event():
# Random map events, may slow to show.
continue
# End:
if self.appear(ASH_START, offset=(30, 30)):
break
def _ash_exit_to_map(self, skip_first_screenshot=True):
"""
Pages:
in: is_in_ash
out: is_in_map
"""
click_timer = Timer(3)
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if self.is_in_map():
break
if click_timer.reached() and self.is_in_ash():
self.device.click(ASH_QUIT)
click_timer.reset()
continue
if self.appear(ASH_SHOWDOWN, offset=(30, 30), interval=3):
self.device.click(ASH_QUIT)
continue
if self.appear_then_click(GLOBE_GOTO_MAP, offset=(20, 20), interval=3):
continue
if self.handle_map_event():
continue
def _ash_exit_to_globe(self, skip_first_screenshot=True):
"""
Pages:
in: is_in_ash
out: is_in_map
"""
click_timer = Timer(3)
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
# End
if self.appear(ASH_ENTRANCE, offset=self.ash_entrance_offset):
break
if click_timer.reached() and self.is_in_ash():
self.device.click(ASH_QUIT)
click_timer.reset()
continue
if self.appear(ASH_SHOWDOWN, offset=(30, 30), interval=3):
self.device.click(ASH_QUIT)
continue
if self.appear_then_click(MAP_GOTO_GLOBE, offset=(20, 20), interval=3):
continue
if self.handle_map_event():
continue
def _ash_help(self):
"""
Request help from friends, guild and world.
Pages:
in: is_in_ash
out: is_in_ash
"""
self.ui_click(click_button=HELP_ENTER, check_button=HELP_CONFIRM)
# Here use simple clicks. Dropping some clicks is acceptable, no need to confirm they are selected.
self.device.click(HELP_1)
self.device.sleep((0.1, 0.3))
self.device.click(HELP_2)
self.device.sleep((0.1, 0.3))
self.device.click(HELP_3)
self.ui_click(click_button=HELP_CONFIRM, check_button=HELP_ENTER)
def _handle_ash_beacon_reward(self):
"""
Returns:
bool: If clicked
"""
if self.appear_then_click(BEACON_REWARD, interval=2):
return True
if self.appear(GET_ITEMS_1, interval=2):
self.device.click(BEACON_REWARD)
return True
return False
def _ash_beacon_attack(self):
"""
Attack ash beacon until it's killed.
Returns:
bool: If all beacon finished
Pages:
in: is_in_ash
out: is_in_ash
"""
logger.info('Ash beacon attack')
confirm_timer = Timer(1, count=2).start()
ash_combat = AshCombat(self.config, self.device)
while 1:
self.device.screenshot()
percent = color_bar_percentage(
self.device.image, BEACON_HP_PERCENTAGE.area, prev_color=(181, 56, 57), threshold=15)
logger.attr('Ash_beacon_hp', f'{int(percent * 100)}%')
# End
if self.appear(BEACON_EMPTY, offset=(20, 20)):
if confirm_timer.reached():
logger.info('Ash beacon attack finished')
return True
elif self.appear(BEACON_ENTER, offset=self.beacon_entrance_offset):
# If previous beacon is not completed, the previous beacon is attacked in this round.
# Then found a new beacon, after attack.
if confirm_timer.reached():
logger.info('Ash beacon attack finished, but found another beacon')
return False
else:
confirm_timer.reset()
# Accident clicks
if self.appear(BATTLE_PREPARATION, offset=(30, 30), interval=2):
self.device.click(BACK_ARROW)
continue
if self.appear(HELP_CONFIRM, offset=(30, 30), interval=2):
self.device.click(BACK_ARROW)
continue
# Redirected by game
if self.appear_then_click(ASH_SHOWDOWN, offset=(30, 30), interval=2):
continue
# Combat and rewards
if self._handle_ash_beacon_reward():
continue
if self.appear(ASH_START, offset=(30, 30)):
ash_combat.combat(expected_end=self.is_in_ash, save_get_items=False, emotion_reduce=False)
continue
def handle_ash_beacon_attack(self):
"""
Returns:
@ -421,31 +121,12 @@ class OSAsh(UI, MapEventHandler):
in: is_in_map
out: is_in_map
"""
if not self.config.OpsiAshBeacon_AshAttack:
if not self.config.OpsiAshBeacon_AshAttack \
and not self.config.OpsiDossierBeacon_Enable:
return False
if self.ash_collect_status() < 100:
return False
for _ in range(3):
self._ash_mine_enter_from_map()
if self.config.OpsiAshBeacon_RequestAssist:
self._ash_help()
finish = self._ash_beacon_attack()
if finish:
break
self._ash_exit_to_map()
self.config.task_call(task='OpsiAshBeacon')
return True
class AshBeaconAssist(OSAsh):
def run(self):
"""
Run daily ash beacon assist.
Pages:
in: Any page
out: page_os
"""
self.ash_beacon_assist()
self.config.task_delay(server_update=True)

View File

@ -4,26 +4,35 @@ from module.base.template import Template
# This file was automatically generated by dev_tools/button_extract.py.
# Don't modify it manually.
ASH_CHECK = Button(area={'cn': (921, 20, 1028, 53), 'en': (922, 21, 1028, 54), 'jp': (940, 24, 1013, 45), 'tw': (921, 20, 1028, 54)}, color={'cn': (116, 87, 87), 'en': (125, 84, 83), 'jp': (166, 132, 132), 'tw': (120, 84, 84)}, button={'cn': (921, 20, 1028, 53), 'en': (922, 21, 1028, 54), 'jp': (940, 24, 1013, 45), 'tw': (921, 20, 1028, 54)}, file={'cn': './assets/cn/os_ash/ASH_CHECK.png', 'en': './assets/en/os_ash/ASH_CHECK.png', 'jp': './assets/jp/os_ash/ASH_CHECK.png', 'tw': './assets/tw/os_ash/ASH_CHECK.png'})
ASH_COLLECT_STATUS = Button(area={'cn': (640, 27, 720, 49), 'en': (640, 27, 720, 49), 'jp': (640, 27, 720, 49), 'tw': (640, 27, 720, 49)}, color={'cn': (82, 92, 99), 'en': (82, 92, 99), 'jp': (82, 92, 99), 'tw': (82, 92, 99)}, button={'cn': (640, 27, 720, 49), 'en': (640, 27, 720, 49), 'jp': (640, 27, 720, 49), 'tw': (640, 27, 720, 49)}, file={'cn': './assets/cn/os_ash/ASH_COLLECT_STATUS.png', 'en': './assets/en/os_ash/ASH_COLLECT_STATUS.png', 'jp': './assets/jp/os_ash/ASH_COLLECT_STATUS.png', 'tw': './assets/tw/os_ash/ASH_COLLECT_STATUS.png'})
ASH_DAILY_STATUS = Button(area={'cn': (637, 0, 741, 19), 'en': (637, 0, 741, 19), 'jp': (637, 0, 741, 19), 'tw': (637, 0, 741, 19)}, color={'cn': (104, 112, 121), 'en': (104, 112, 121), 'jp': (104, 112, 121), 'tw': (104, 112, 121)}, button={'cn': (637, 0, 741, 19), 'en': (637, 0, 741, 19), 'jp': (637, 0, 741, 19), 'tw': (637, 0, 741, 19)}, file={'cn': './assets/cn/os_ash/ASH_DAILY_STATUS.png', 'en': './assets/en/os_ash/ASH_DAILY_STATUS.png', 'jp': './assets/jp/os_ash/ASH_DAILY_STATUS.png', 'tw': './assets/tw/os_ash/ASH_DAILY_STATUS.png'})
ASH_ENTER_CONFIRM = Button(area={'cn': (554, 482, 726, 539), 'en': (560, 487, 720, 534), 'jp': (553, 482, 727, 539), 'tw': (554, 482, 726, 539)}, color={'cn': (109, 153, 209), 'en': (106, 151, 207), 'jp': (111, 154, 207), 'tw': (109, 153, 209)}, button={'cn': (554, 482, 726, 539), 'en': (560, 487, 720, 534), 'jp': (553, 482, 727, 539), 'tw': (554, 482, 726, 539)}, file={'cn': './assets/cn/os_ash/ASH_ENTER_CONFIRM.png', 'en': './assets/en/os_ash/ASH_ENTER_CONFIRM.png', 'jp': './assets/jp/os_ash/ASH_ENTER_CONFIRM.png', 'tw': './assets/tw/os_ash/ASH_ENTER_CONFIRM.png'})
ASH_ENTRANCE = Button(area={'cn': (935, 671, 1002, 689), 'en': (938, 676, 995, 690), 'jp': (934, 658, 1026, 689), 'tw': (934, 670, 1000, 689)}, color={'cn': (53, 57, 58), 'en': (73, 74, 75), 'jp': (50, 58, 62), 'tw': (60, 63, 65)}, button={'cn': (932, 631, 1078, 692), 'en': (932, 631, 1078, 692), 'jp': (934, 629, 1079, 693), 'tw': (930, 629, 1080, 693)}, file={'cn': './assets/cn/os_ash/ASH_ENTRANCE.png', 'en': './assets/en/os_ash/ASH_ENTRANCE.png', 'jp': './assets/jp/os_ash/ASH_ENTRANCE.png', 'tw': './assets/tw/os_ash/ASH_ENTRANCE.png'})
ASH_QUIT = Button(area={'cn': (29, 25, 59, 49), 'en': (29, 25, 59, 49), 'jp': (22, 25, 54, 48), 'tw': (29, 25, 59, 49)}, color={'cn': (115, 63, 68), 'en': (115, 63, 68), 'jp': (114, 61, 67), 'tw': (115, 63, 68)}, button={'cn': (29, 25, 59, 49), 'en': (29, 25, 59, 49), 'jp': (22, 25, 54, 48), 'tw': (29, 25, 59, 49)}, file={'cn': './assets/cn/os_ash/ASH_QUIT.png', 'en': './assets/en/os_ash/ASH_QUIT.png', 'jp': './assets/jp/os_ash/ASH_QUIT.png', 'tw': './assets/tw/os_ash/ASH_QUIT.png'})
ASH_SHOWDOWN = Button(area={'cn': (120, 14, 262, 38), 'en': (120, 16, 319, 35), 'jp': (122, 15, 246, 39), 'tw': (120, 14, 262, 38)}, color={'cn': (153, 131, 131), 'en': (130, 106, 106), 'jp': (164, 144, 145), 'tw': (153, 131, 131)}, button={'cn': (278, 167, 559, 551), 'en': (278, 167, 559, 551), 'jp': (278, 167, 559, 551), 'tw': (278, 167, 559, 551)}, file={'cn': './assets/cn/os_ash/ASH_SHOWDOWN.png', 'en': './assets/en/os_ash/ASH_SHOWDOWN.png', 'jp': './assets/jp/os_ash/ASH_SHOWDOWN.png', 'tw': './assets/cn/os_ash/ASH_SHOWDOWN.png'})
ASH_SHOWDOWN = Button(area={'cn': (120, 14, 262, 38), 'en': (120, 16, 319, 35), 'jp': (122, 15, 246, 39), 'tw': (120, 14, 262, 38)}, color={'cn': (153, 131, 131), 'en': (130, 106, 106), 'jp': (164, 144, 145), 'tw': (153, 131, 131)}, button={'cn': (120, 14, 262, 38), 'en': (120, 16, 319, 35), 'jp': (122, 15, 246, 39), 'tw': (120, 14, 262, 38)}, file={'cn': './assets/cn/os_ash/ASH_SHOWDOWN.png', 'en': './assets/en/os_ash/ASH_SHOWDOWN.png', 'jp': './assets/jp/os_ash/ASH_SHOWDOWN.png', 'tw': './assets/cn/os_ash/ASH_SHOWDOWN.png'})
ASH_START = Button(area={'cn': (1061, 635, 1259, 695), 'en': (1063, 637, 1255, 693), 'jp': (1058, 634, 1260, 697), 'tw': (1043, 637, 1242, 698)}, color={'cn': (236, 187, 115), 'en': (223, 184, 124), 'jp': (222, 185, 126), 'tw': (223, 186, 131)}, button={'cn': (1061, 635, 1259, 695), 'en': (1063, 637, 1255, 693), 'jp': (1058, 634, 1260, 697), 'tw': (1043, 637, 1242, 698)}, file={'cn': './assets/cn/os_ash/ASH_START.png', 'en': './assets/en/os_ash/ASH_START.png', 'jp': './assets/jp/os_ash/ASH_START.png', 'tw': './assets/tw/os_ash/ASH_START.png'})
BATTLE_STATUS = Button(area={'cn': (1051, 644, 1123, 675), 'en': (1022, 657, 1150, 671), 'jp': (1087, 642, 1127, 679), 'tw': (1050, 644, 1123, 675)}, color={'cn': (247, 199, 137), 'en': (243, 207, 160), 'jp': (229, 171, 91), 'tw': (243, 193, 128)}, button={'cn': (1051, 644, 1123, 675), 'en': (1022, 657, 1150, 671), 'jp': (1087, 642, 1127, 679), 'tw': (1050, 644, 1123, 675)}, file={'cn': './assets/cn/os_ash/BATTLE_STATUS.png', 'en': './assets/en/os_ash/BATTLE_STATUS.png', 'jp': './assets/jp/os_ash/BATTLE_STATUS.png', 'tw': './assets/tw/os_ash/BATTLE_STATUS.png'})
BEACON_EMPTY = Button(area={'cn': (535, 288, 647, 316), 'en': (522, 290, 775, 313), 'jp': (465, 286, 664, 318), 'tw': (534, 287, 648, 316)}, color={'cn': (126, 129, 134), 'en': (148, 150, 154), 'jp': (119, 122, 128), 'tw': (128, 130, 135)}, button={'cn': (535, 288, 647, 316), 'en': (522, 290, 775, 313), 'jp': (465, 286, 664, 318), 'tw': (534, 287, 648, 316)}, file={'cn': './assets/cn/os_ash/BEACON_EMPTY.png', 'en': './assets/en/os_ash/BEACON_EMPTY.png', 'jp': './assets/jp/os_ash/BEACON_EMPTY.png', 'tw': './assets/tw/os_ash/BEACON_EMPTY.png'})
BEACON_ENTER = Button(area={'cn': (553, 308, 669, 332), 'en': (590, 359, 705, 372), 'jp': (589, 348, 706, 371), 'tw': (650, 348, 706, 372)}, color={'cn': (90, 92, 92), 'en': (104, 105, 104), 'jp': (101, 102, 101), 'tw': (95, 97, 99)}, button={'cn': (509, 78, 713, 470), 'en': (509, 78, 713, 470), 'jp': (548, 115, 747, 502), 'tw': (509, 78, 714, 470)}, file={'cn': './assets/cn/os_ash/BEACON_ENTER.png', 'en': './assets/en/os_ash/BEACON_ENTER.png', 'jp': './assets/jp/os_ash/BEACON_ENTER.png', 'tw': './assets/tw/os_ash/BEACON_ENTER.png'})
BEACON_HP_PERCENTAGE = Button(area={'cn': (278, 609, 1239, 623), 'en': (278, 609, 1239, 623), 'jp': (278, 609, 1239, 623), 'tw': (278, 609, 1239, 623)}, color={'cn': (224, 31, 22), 'en': (224, 31, 22), 'jp': (224, 31, 22), 'tw': (224, 31, 22)}, button={'cn': (278, 609, 1239, 623), 'en': (278, 609, 1239, 623), 'jp': (278, 609, 1239, 623), 'tw': (278, 609, 1239, 623)}, file={'cn': './assets/cn/os_ash/BEACON_HP_PERCENTAGE.png', 'en': './assets/en/os_ash/BEACON_HP_PERCENTAGE.png', 'jp': './assets/jp/os_ash/BEACON_HP_PERCENTAGE.png', 'tw': './assets/tw/os_ash/BEACON_HP_PERCENTAGE.png'})
BEACON_LIST = Button(area={'cn': (26, 649, 218, 703), 'en': (25, 648, 218, 703), 'jp': (22, 645, 221, 706), 'tw': (23, 646, 221, 705)}, color={'cn': (135, 105, 122), 'en': (141, 104, 121), 'jp': (141, 107, 129), 'tw': (135, 101, 119)}, button={'cn': (26, 649, 218, 703), 'en': (25, 648, 218, 703), 'jp': (22, 645, 221, 706), 'tw': (23, 646, 221, 705)}, file={'cn': './assets/cn/os_ash/BEACON_LIST.png', 'en': './assets/en/os_ash/BEACON_LIST.png', 'jp': './assets/jp/os_ash/BEACON_LIST.png', 'tw': './assets/tw/os_ash/BEACON_LIST.png'})
BEACON_MY = Button(area={'cn': (25, 647, 218, 702), 'en': (25, 647, 218, 704), 'jp': (22, 645, 221, 706), 'tw': (22, 644, 221, 707)}, color={'cn': (106, 84, 86), 'en': (110, 85, 86), 'jp': (102, 77, 78), 'tw': (108, 82, 84)}, button={'cn': (25, 647, 218, 702), 'en': (25, 647, 218, 704), 'jp': (22, 645, 221, 706), 'tw': (22, 644, 221, 707)}, file={'cn': './assets/cn/os_ash/BEACON_MY.png', 'en': './assets/en/os_ash/BEACON_MY.png', 'jp': './assets/jp/os_ash/BEACON_MY.png', 'tw': './assets/tw/os_ash/BEACON_MY.png'})
BEACON_NEXT = Button(area={'cn': (129, 369, 440, 439), 'en': (129, 369, 440, 439), 'jp': (180, 368, 449, 440), 'tw': (129, 369, 440, 439)}, color={'cn': (51, 52, 48), 'en': (51, 52, 48), 'jp': (53, 54, 50), 'tw': (51, 52, 48)}, button={'cn': (129, 369, 440, 439), 'en': (129, 369, 440, 439), 'jp': (180, 368, 449, 440), 'tw': (129, 369, 440, 439)}, file={'cn': './assets/cn/os_ash/BEACON_NEXT.png', 'en': './assets/en/os_ash/BEACON_NEXT.png', 'jp': './assets/jp/os_ash/BEACON_NEXT.png', 'tw': './assets/tw/os_ash/BEACON_NEXT.png'})
BEACON_REMAIN = Button(area={'cn': (1014, 25, 1073, 48), 'en': (1014, 25, 1073, 48), 'jp': (1014, 25, 1073, 48), 'tw': (1014, 25, 1073, 48)}, color={'cn': (48, 51, 48), 'en': (48, 51, 48), 'jp': (48, 51, 48), 'tw': (48, 51, 48)}, button={'cn': (1014, 25, 1073, 48), 'en': (1014, 25, 1073, 48), 'jp': (1014, 25, 1073, 48), 'tw': (1014, 25, 1073, 48)}, file={'cn': './assets/cn/os_ash/BEACON_REMAIN.png', 'en': './assets/en/os_ash/BEACON_REMAIN.png', 'jp': './assets/jp/os_ash/BEACON_REMAIN.png', 'tw': './assets/tw/os_ash/BEACON_REMAIN.png'})
BEACON_REWARD = Button(area={'cn': (1049, 640, 1239, 695), 'en': (1072, 640, 1242, 695), 'jp': (1043, 637, 1242, 698), 'tw': (1049, 640, 1239, 695)}, color={'cn': (117, 164, 236), 'en': (112, 160, 237), 'jp': (108, 156, 232), 'tw': (119, 163, 228)}, button={'cn': (1049, 640, 1239, 695), 'en': (1072, 640, 1242, 695), 'jp': (1043, 637, 1242, 698), 'tw': (1049, 640, 1239, 695)}, file={'cn': './assets/cn/os_ash/BEACON_REWARD.png', 'en': './assets/en/os_ash/BEACON_REWARD.png', 'jp': './assets/jp/os_ash/BEACON_REWARD.png', 'tw': './assets/tw/os_ash/BEACON_REWARD.png'})
BEACON_TIER = Button(area={'cn': (100, 562, 200, 637), 'en': (100, 562, 200, 637), 'jp': (100, 562, 200, 637), 'tw': (100, 562, 200, 637)}, color={'cn': (82, 83, 79), 'en': (82, 83, 79), 'jp': (82, 83, 79), 'tw': (82, 83, 79)}, button={'cn': (100, 562, 200, 637), 'en': (100, 562, 200, 637), 'jp': (100, 562, 200, 637), 'tw': (100, 562, 200, 637)}, file={'cn': './assets/cn/os_ash/BEACON_TIER.png', 'en': './assets/en/os_ash/BEACON_TIER.png', 'jp': './assets/jp/os_ash/BEACON_TIER.png', 'tw': './assets/tw/os_ash/BEACON_TIER.png'})
DOSSIER_LIST = Button(area={'cn': (22, 646, 221, 706), 'en': (22, 646, 221, 706), 'jp': (22, 646, 221, 706), 'tw': (22, 646, 221, 706)}, color={'cn': (116, 89, 77), 'en': (116, 89, 77), 'jp': (116, 89, 77), 'tw': (116, 89, 77)}, button={'cn': (22, 646, 221, 706), 'en': (22, 646, 221, 706), 'jp': (22, 646, 221, 706), 'tw': (22, 646, 221, 706)}, file={'cn': './assets/cn/os_ash/DOSSIER_LIST.png', 'en': './assets/cn/os_ash/DOSSIER_LIST.png', 'jp': './assets/cn/os_ash/DOSSIER_LIST.png', 'tw': './assets/cn/os_ash/DOSSIER_LIST.png'})
HELP_1 = Button(area={'cn': (391, 270, 557, 439), 'en': (391, 270, 557, 439), 'jp': (391, 270, 557, 439), 'tw': (391, 270, 557, 439)}, color={'cn': (83, 95, 118), 'en': (83, 95, 118), 'jp': (83, 95, 118), 'tw': (83, 95, 118)}, button={'cn': (391, 270, 557, 439), 'en': (391, 270, 557, 439), 'jp': (391, 270, 557, 439), 'tw': (391, 270, 557, 439)}, file={'cn': './assets/cn/os_ash/HELP_1.png', 'en': './assets/en/os_ash/HELP_1.png', 'jp': './assets/jp/os_ash/HELP_1.png', 'tw': './assets/tw/os_ash/HELP_1.png'})
HELP_2 = Button(area={'cn': (584, 270, 750, 439), 'en': (584, 270, 750, 439), 'jp': (584, 270, 750, 439), 'tw': (584, 270, 750, 439)}, color={'cn': (82, 95, 119), 'en': (82, 95, 119), 'jp': (82, 95, 119), 'tw': (82, 95, 119)}, button={'cn': (584, 270, 750, 439), 'en': (584, 270, 750, 439), 'jp': (584, 270, 750, 439), 'tw': (584, 270, 750, 439)}, file={'cn': './assets/cn/os_ash/HELP_2.png', 'en': './assets/en/os_ash/HELP_2.png', 'jp': './assets/jp/os_ash/HELP_2.png', 'tw': './assets/tw/os_ash/HELP_2.png'})
HELP_3 = Button(area={'cn': (778, 271, 941, 438), 'en': (778, 271, 941, 438), 'jp': (778, 271, 941, 438), 'tw': (778, 271, 941, 438)}, color={'cn': (83, 96, 118), 'en': (83, 96, 118), 'jp': (83, 96, 118), 'tw': (83, 96, 118)}, button={'cn': (778, 271, 941, 438), 'en': (778, 271, 941, 438), 'jp': (778, 271, 941, 438), 'tw': (778, 271, 941, 438)}, file={'cn': './assets/cn/os_ash/HELP_3.png', 'en': './assets/en/os_ash/HELP_3.png', 'jp': './assets/jp/os_ash/HELP_3.png', 'tw': './assets/tw/os_ash/HELP_3.png'})
HELP_CONFIRM = Button(area={'cn': (742, 500, 914, 557), 'en': (748, 505, 908, 552), 'jp': (741, 500, 915, 557), 'tw': (742, 500, 914, 557)}, color={'cn': (94, 143, 203), 'en': (114, 156, 209), 'jp': (91, 139, 198), 'tw': (94, 143, 203)}, button={'cn': (742, 500, 914, 557), 'en': (748, 505, 908, 552), 'jp': (741, 500, 915, 557), 'tw': (742, 500, 914, 557)}, file={'cn': './assets/cn/os_ash/HELP_CONFIRM.png', 'en': './assets/en/os_ash/HELP_CONFIRM.png', 'jp': './assets/jp/os_ash/HELP_CONFIRM.png', 'tw': './assets/tw/os_ash/HELP_CONFIRM.png'})
HELP_ENTER = Button(area={'cn': (894, 635, 1013, 699), 'en': (875, 639, 1011, 695), 'jp': (866, 636, 1010, 697), 'tw': (894, 636, 1011, 698)}, color={'cn': (210, 130, 130), 'en': (220, 160, 160), 'jp': (207, 131, 131), 'tw': (208, 127, 127)}, button={'cn': (894, 635, 1013, 699), 'en': (875, 639, 1011, 695), 'jp': (866, 636, 1010, 697), 'tw': (894, 636, 1011, 698)}, file={'cn': './assets/cn/os_ash/HELP_ENTER.png', 'en': './assets/en/os_ash/HELP_ENTER.png', 'jp': './assets/jp/os_ash/HELP_ENTER.png', 'tw': './assets/tw/os_ash/HELP_ENTER.png'})
META_AUTO_ATTACKING = Button(area={'cn': (746, 649, 778, 680), 'en': (746, 649, 778, 680), 'jp': (746, 649, 778, 680), 'tw': (746, 649, 778, 680)}, color={'cn': (111, 95, 93), 'en': (111, 95, 93), 'jp': (111, 95, 93), 'tw': (111, 95, 93)}, button={'cn': (746, 649, 778, 680), 'en': (746, 649, 778, 680), 'jp': (746, 649, 778, 680), 'tw': (746, 649, 778, 680)}, file={'cn': './assets/cn/os_ash/META_AUTO_ATTACKING.png', 'en': './assets/en/os_ash/META_AUTO_ATTACKING.png', 'jp': './assets/jp/os_ash/META_AUTO_ATTACKING.png', 'tw': './assets/tw/os_ash/META_AUTO_ATTACKING.png'})
META_AUTO_CONFIRM = Button(area={'cn': (608, 506, 674, 535), 'en': (608, 506, 674, 535), 'jp': (608, 506, 674, 535), 'tw': (608, 506, 674, 535)}, color={'cn': (208, 148, 141), 'en': (208, 148, 141), 'jp': (208, 148, 141), 'tw': (208, 148, 141)}, button={'cn': (608, 506, 674, 535), 'en': (608, 506, 674, 535), 'jp': (608, 506, 674, 535), 'tw': (608, 506, 674, 535)}, file={'cn': './assets/cn/os_ash/META_AUTO_CONFIRM.png', 'en': './assets/cn/os_ash/META_AUTO_CONFIRM.png', 'jp': './assets/cn/os_ash/META_AUTO_CONFIRM.png', 'tw': './assets/cn/os_ash/META_AUTO_CONFIRM.png'})
META_BEACON_DATA = Button(area={'cn': (840, 22, 951, 45), 'en': (840, 22, 951, 45), 'jp': (840, 22, 951, 45), 'tw': (840, 22, 951, 45)}, color={'cn': (49, 53, 52), 'en': (49, 53, 52), 'jp': (49, 53, 52), 'tw': (49, 53, 52)}, button={'cn': (840, 22, 951, 45), 'en': (840, 22, 951, 45), 'jp': (840, 22, 951, 45), 'tw': (840, 22, 951, 45)}, file={'cn': './assets/cn/os_ash/META_BEACON_DATA.png', 'en': './assets/en/os_ash/META_BEACON_DATA.png', 'jp': './assets/jp/os_ash/META_BEACON_DATA.png', 'tw': './assets/tw/os_ash/META_BEACON_DATA.png'})
META_BEACON_FLAG = Button(area={'cn': (788, 22, 811, 45), 'en': (788, 22, 811, 45), 'jp': (788, 22, 811, 45), 'tw': (788, 22, 811, 45)}, color={'cn': (48, 111, 134), 'en': (48, 111, 134), 'jp': (48, 111, 134), 'tw': (48, 111, 134)}, button={'cn': (788, 22, 811, 45), 'en': (788, 22, 811, 45), 'jp': (788, 22, 811, 45), 'tw': (788, 22, 811, 45)}, file={'cn': './assets/cn/os_ash/META_BEACON_FLAG.png', 'en': './assets/en/os_ash/META_BEACON_FLAG.png', 'jp': './assets/jp/os_ash/META_BEACON_FLAG.png', 'tw': './assets/tw/os_ash/META_BEACON_FLAG.png'})
META_BEGIN_ENTRANCE = Button(area={'cn': (546, 115, 748, 503), 'en': (546, 115, 748, 503), 'jp': (546, 115, 748, 503), 'tw': (546, 115, 748, 503)}, color={'cn': (36, 35, 34), 'en': (36, 35, 34), 'jp': (36, 35, 34), 'tw': (36, 35, 34)}, button={'cn': (546, 115, 748, 503), 'en': (546, 115, 748, 503), 'jp': (546, 115, 748, 503), 'tw': (546, 115, 748, 503)}, file={'cn': './assets/cn/os_ash/META_BEGIN_ENTRANCE.png', 'en': './assets/en/os_ash/META_BEGIN_ENTRANCE.png', 'jp': './assets/jp/os_ash/META_BEGIN_ENTRANCE.png', 'tw': './assets/tw/os_ash/META_BEGIN_ENTRANCE.png'})
META_DAMAGE = Button(area={'cn': (1196, 380, 1276, 416), 'en': (1196, 380, 1276, 416), 'jp': (1196, 380, 1276, 416), 'tw': (1196, 380, 1276, 416)}, color={'cn': (58, 59, 58), 'en': (58, 59, 58), 'jp': (58, 59, 58), 'tw': (58, 59, 58)}, button={'cn': (1196, 380, 1276, 416), 'en': (1196, 380, 1276, 416), 'jp': (1196, 380, 1276, 416), 'tw': (1196, 380, 1276, 416)}, file={'cn': './assets/cn/os_ash/META_DAMAGE.png', 'en': './assets/en/os_ash/META_DAMAGE.png', 'jp': './assets/jp/os_ash/META_DAMAGE.png', 'tw': './assets/tw/os_ash/META_DAMAGE.png'})
META_DOSSIER_DATA = Button(area={'cn': (1050, 22, 1161, 46), 'en': (1050, 22, 1161, 46), 'jp': (1050, 22, 1161, 46), 'tw': (1050, 22, 1161, 46)}, color={'cn': (53, 56, 56), 'en': (53, 56, 56), 'jp': (53, 56, 56), 'tw': (53, 56, 56)}, button={'cn': (1050, 22, 1161, 46), 'en': (1050, 22, 1161, 46), 'jp': (1050, 22, 1161, 46), 'tw': (1050, 22, 1161, 46)}, file={'cn': './assets/cn/os_ash/META_DOSSIER_DATA.png', 'en': './assets/en/os_ash/META_DOSSIER_DATA.png', 'jp': './assets/jp/os_ash/META_DOSSIER_DATA.png', 'tw': './assets/tw/os_ash/META_DOSSIER_DATA.png'})
META_DOSSIER_FLAG = Button(area={'cn': (999, 22, 1022, 45), 'en': (999, 22, 1022, 45), 'jp': (999, 22, 1022, 45), 'tw': (999, 22, 1022, 45)}, color={'cn': (123, 70, 44), 'en': (123, 70, 44), 'jp': (123, 70, 44), 'tw': (123, 70, 44)}, button={'cn': (999, 22, 1022, 45), 'en': (999, 22, 1022, 45), 'jp': (999, 22, 1022, 45), 'tw': (999, 22, 1022, 45)}, file={'cn': './assets/cn/os_ash/META_DOSSIER_FLAG.png', 'en': './assets/en/os_ash/META_DOSSIER_FLAG.png', 'jp': './assets/jp/os_ash/META_DOSSIER_FLAG.png', 'tw': './assets/tw/os_ash/META_DOSSIER_FLAG.png'})
META_ENTRANCE = Button(area={'cn': (578, 463, 623, 493), 'en': (578, 463, 623, 493), 'jp': (578, 463, 623, 493), 'tw': (578, 463, 623, 493)}, color={'cn': (106, 134, 169), 'en': (106, 134, 169), 'jp': (106, 134, 169), 'tw': (106, 134, 169)}, button={'cn': (578, 463, 623, 493), 'en': (578, 463, 623, 493), 'jp': (578, 463, 623, 493), 'tw': (578, 463, 623, 493)}, file={'cn': './assets/cn/os_ash/META_ENTRANCE.png', 'en': './assets/en/os_ash/META_ENTRANCE.png', 'jp': './assets/jp/os_ash/META_ENTRANCE.png', 'tw': './assets/tw/os_ash/META_ENTRANCE.png'})
META_INNER_PAGE_DAMAGE = Button(area={'cn': (936, 105, 1029, 128), 'en': (936, 105, 1029, 128), 'jp': (936, 105, 1029, 128), 'tw': (936, 105, 1029, 128)}, color={'cn': (148, 105, 105), 'en': (148, 105, 105), 'jp': (148, 105, 105), 'tw': (148, 105, 105)}, button={'cn': (936, 105, 1029, 128), 'en': (936, 105, 1029, 128), 'jp': (936, 105, 1029, 128), 'tw': (936, 105, 1029, 128)}, file={'cn': './assets/cn/os_ash/META_INNER_PAGE_DAMAGE.png', 'en': './assets/cn/os_ash/META_INNER_PAGE_DAMAGE.png', 'jp': './assets/cn/os_ash/META_INNER_PAGE_DAMAGE.png', 'tw': './assets/cn/os_ash/META_INNER_PAGE_DAMAGE.png'})
META_INNER_PAGE_NOT_DAMAGE = Button(area={'cn': (936, 105, 1029, 128), 'en': (936, 105, 1029, 128), 'jp': (936, 105, 1029, 128), 'tw': (936, 105, 1029, 128)}, color={'cn': (68, 71, 72), 'en': (68, 71, 72), 'jp': (68, 71, 72), 'tw': (68, 71, 72)}, button={'cn': (936, 105, 1029, 128), 'en': (936, 105, 1029, 128), 'jp': (936, 105, 1029, 128), 'tw': (936, 105, 1029, 128)}, file={'cn': './assets/cn/os_ash/META_INNER_PAGE_NOT_DAMAGE.png', 'en': './assets/cn/os_ash/META_INNER_PAGE_NOT_DAMAGE.png', 'jp': './assets/cn/os_ash/META_INNER_PAGE_NOT_DAMAGE.png', 'tw': './assets/cn/os_ash/META_INNER_PAGE_NOT_DAMAGE.png'})
META_MAIN_BEACON_ENTRANCE = Button(area={'cn': (275, 162, 567, 557), 'en': (275, 162, 567, 557), 'jp': (275, 162, 567, 557), 'tw': (275, 162, 567, 557)}, color={'cn': (68, 56, 52), 'en': (68, 56, 52), 'jp': (68, 56, 52), 'tw': (68, 56, 52)}, button={'cn': (275, 162, 567, 557), 'en': (275, 162, 567, 557), 'jp': (275, 162, 567, 557), 'tw': (275, 162, 567, 557)}, file={'cn': './assets/cn/os_ash/META_MAIN_BEACON_ENTRANCE.png', 'en': './assets/en/os_ash/META_MAIN_BEACON_ENTRANCE.png', 'jp': './assets/jp/os_ash/META_MAIN_BEACON_ENTRANCE.png', 'tw': './assets/tw/os_ash/META_MAIN_BEACON_ENTRANCE.png'})
META_MAIN_DOSSIER_ENTRANCE = Button(area={'cn': (706, 163, 998, 557), 'en': (706, 163, 998, 557), 'jp': (706, 163, 998, 557), 'tw': (706, 163, 998, 557)}, color={'cn': (91, 82, 79), 'en': (91, 82, 79), 'jp': (91, 82, 79), 'tw': (91, 82, 79)}, button={'cn': (706, 163, 998, 557), 'en': (706, 163, 998, 557), 'jp': (706, 163, 998, 557), 'tw': (706, 163, 998, 557)}, file={'cn': './assets/cn/os_ash/META_MAIN_DOSSIER_ENTRANCE.png', 'en': './assets/en/os_ash/META_MAIN_DOSSIER_ENTRANCE.png', 'jp': './assets/jp/os_ash/META_MAIN_DOSSIER_ENTRANCE.png', 'tw': './assets/tw/os_ash/META_MAIN_DOSSIER_ENTRANCE.png'})

444
module/os_ash/meta.py Normal file
View File

@ -0,0 +1,444 @@
from enum import Enum
import module.config.server as server
from module.base.timer import Timer
from module.combat.assets import BATTLE_PREPARATION
from module.logger import logger
from module.ocr.ocr import DigitCounter, Digit
from module.os_ash.ash import AshCombat
from module.os_ash.assets import *
from module.os_handler.map_event import MapEventHandler
from module.ui.assets import BACK_ARROW
from module.ui.page import page_reward
from module.ui.ui import UI
class MetaState(Enum):
INIT = 'no meta begin'
ATTACKING = 'a meta under attack'
COMPLETE = 'reward to be collected'
UNDEFINED = 'a undefined page'
OCR_BEACON_TIER = Digit(BEACON_TIER, name='OCR_ASH_TIER')
OCR_META_DAMAGE = Digit(META_DAMAGE, name='OCR_META_DAMAGE')
class Meta(UI, MapEventHandler):
def digit_ocr_point_and_check(self, button: Button, check_number: int):
point_ocr = DigitCounter(button, letter=(235, 235, 235), threshold=160, name='POINT_OCR')
point, _, _ = point_ocr.ocr(self.device.image)
if point >= check_number:
return True
return False
def handle_map_event(self, drop=None):
if super().handle_map_event(drop):
return True
if self.appear_then_click(META_AUTO_CONFIRM, offset=(20, 20), interval=2):
logger.info('Find auto attack complete')
return True
if self.appear(HELP_CONFIRM, offset=(30, 30), interval=2):
logger.info('Accidentally click HELP_ENTER')
self.device.click(BACK_ARROW)
return True
if self.appear(BATTLE_PREPARATION, offset=(30, 30), interval=2):
logger.info('Game auto into battle preparation page')
self.device.click(BACK_ARROW)
return True
if self.handle_popup_cancel():
return True
def _server_support():
return server.server == 'cn'
class OpsiAshBeacon(Meta):
def _attack_meta(self, skip_first_screenshot=True):
"""
Handle all META attack events.
Pages:
in: in_meta
out: in_meta
"""
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.handle_map_event():
continue
state = self._get_state()
logger.info('Meta state:' + state.name)
if MetaState.UNDEFINED == state:
continue
if MetaState.INIT == state:
if self._begin_meta():
continue
else:
# Normal finish
break
if MetaState.ATTACKING == state:
if not self._pre_attack():
continue
if self._satisfy_attack_condition():
self._make_an_attack()
continue
if MetaState.COMPLETE == state:
self._handle_ash_beacon_reward()
# Check other tasks after kill a meta
self.config.check_task_switch()
continue
def _make_an_attack(self, skip_first_screenshot=True):
"""
Handle a meta combat.
Pages:
in: in_meta, ASH_START
out: in_meta, ASH_START or BEACON_REWARD
"""
logger.hr('Begin meta combat', level=2)
# Attack
combat = AshCombat(config=self.config, device=self.device)
combat.combat(expected_end=self._in_meta_page, save_get_items=False, emotion_reduce=False)
timer = Timer(1, count=2).start()
# Finish random events
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self._in_meta_page():
if timer.reached():
logger.info('Meta combat finished and in meta page')
break
else:
timer.reset()
if self.handle_map_event():
continue
def _handle_ash_beacon_reward(self, skip_first_screenshot=True):
"""
Reward meta.
Pages:
in: in_meta, BEACON_REWARD
out: in_meta
"""
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.appear_then_click(BEACON_REWARD, offset=(30, 30), interval=2):
logger.info('Reap meta rewards')
continue
if self._in_meta_page():
break
# Finish random events
if self.handle_map_event():
continue
def _satisfy_attack_condition(self):
"""
Check whether this meta can be attacked.
In beacon:
when enable OneHitMode and has attacked, not allow attack.
In Dossier:
when enable autoAttack, not allow attack
"""
if self.appear(BEACON_LIST, offset=(20, 20)):
# Enable OneHitMode and had attack this meta
if _server_support() and self.config.OpsiAshBeacon_OneHitMode:
damage = self._get_meta_damage()
if damage > 0:
logger.info('Enable OneHitMode and meta damage is ' + str(damage) + ', check after 30 minutes')
self.config.task_delay(minute=30)
self.config.task_stop()
if self.appear(DOSSIER_LIST, offset=(20, 20)):
# Meta is Auto Attacking
if self.appear(META_AUTO_ATTACKING, offset=(20, 20)):
logger.info('This meta is auto attacking, check after 15 minutes')
self.config.task_delay(minute=15)
self.config.task_stop()
return True
def _get_meta_damage(self):
"""
Get the damage the from current meta
"""
self._ensure_meta_inner_page_damage()
return OCR_META_DAMAGE.ocr(self.device.image)
def _ensure_meta_inner_page_damage(self, skip_first_screenshot=True):
"""
Switch inner page ensure in damage, not information.
Pages:
in: in_meta, ASH_START
out: in_meta, META_INNER_PAGE_DAMAGE, ASH_START
"""
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.appear(META_INNER_PAGE_DAMAGE, offset=(20, 20)) \
and META_INNER_PAGE_DAMAGE.match_appear_on(self.device.image):
logger.info('Already in meta damage page')
break
if self.appear(META_INNER_PAGE_NOT_DAMAGE, offset=(20, 20)) \
and META_INNER_PAGE_NOT_DAMAGE.match_appear_on(self.device.image):
logger.info('In meta details page, should switch to damage page')
self.appear_then_click(META_INNER_PAGE_NOT_DAMAGE, offset=(20, 20), interval=2)
continue
def _pre_attack(self):
"""
Some pre_attack preparations.
In beacon:
ask for help if needed
In dossier:
do nothing this version
"""
# Page beacon or dossier
if self.appear(BEACON_LIST, offset=(20, 20)):
if self.config.OpsiAshBeacon_OneHitMode or self.config.OpsiAshBeacon_RequestAssist:
self._ask_for_help()
return True
if self.appear(DOSSIER_LIST, offset=(20, 20)):
return True
return False
def _ask_for_help(self):
"""
Request help from friends, guild and world.
Pages:
in: is_in_meta
out: is_in_meta
"""
self.ui_click(click_button=HELP_ENTER, check_button=HELP_CONFIRM)
# Here use simple clicks. Dropping some clicks is acceptable, no need to confirm they are selected.
self.device.click(HELP_1)
self.device.sleep((0.1, 0.3))
self.device.click(HELP_2)
self.device.sleep((0.1, 0.3))
self.device.click(HELP_3)
self.ui_click(click_button=HELP_CONFIRM, check_button=HELP_ENTER)
def _begin_meta(self):
"""
No matter which meta page you are in, start or select a meta.
In meta main:
select beacon or dossier entrance into if needed, or end task
In beacon or dossier:
begin a new meta if needed, or back to meta main page
"""
# Page meta main
if self.appear(ASH_SHOWDOWN, offset=(30, 30), interval=2):
if self.config.OpsiAshBeacon_AshAttack \
and self._check_beacon_point():
self.device.click(META_MAIN_BEACON_ENTRANCE)
logger.info('Select beacon entrance into')
return True
if _server_support() \
and self.config.OpsiDossierBeacon_Enable \
and self._check_dossier_point():
self.device.click(META_MAIN_DOSSIER_ENTRANCE)
logger.info('Select dossier entrance into')
return True
return False
# Page beacon
elif self.appear(BEACON_LIST, offset=(20, 20), interval=2):
if self.config.OpsiAshBeacon_AshAttack \
and self._check_beacon_point():
self.device.click(META_BEGIN_ENTRANCE)
logger.info('Begin a beacon')
else:
self.appear_then_click(ASH_QUIT, offset=(10, 10), interval=2)
return True
# Page dossier
elif _server_support() \
and self.appear(DOSSIER_LIST, offset=(20, 20), interval=2):
if self.config.OpsiDossierBeacon_Enable \
and self._check_dossier_point():
self.device.click(META_BEGIN_ENTRANCE)
logger.info('Begin a dossier')
else:
self.appear_then_click(ASH_QUIT, offset=(10, 10), interval=2)
return True
# UnKnown Page
else:
return True
def _check_beacon_point(self) -> bool:
if self.appear(META_BEACON_FLAG, offset=(180, 20)):
META_BEACON_DATA.load_offset(META_BEACON_FLAG)
return self.digit_ocr_point_and_check(META_BEACON_DATA.button, 100)
return False
def _check_dossier_point(self) -> bool:
if self.appear(META_DOSSIER_FLAG, offset=(180, 20)):
META_DOSSIER_DATA.load_offset(META_DOSSIER_FLAG)
return self.digit_ocr_point_and_check(META_DOSSIER_DATA.button, 100)
return False
def _get_state(self):
# Page UnKnown
if not self._in_meta_page():
return MetaState.UNDEFINED
# Page beacon or dossier
elif self.appear(BEACON_LIST, offset=(20, 20)) \
or self.appear(DOSSIER_LIST, offset=(20, 20)):
if self.appear(HELP_ENTER, offset=(30, 30)):
return MetaState.ATTACKING
elif self.appear(BEACON_REWARD, offset=(20, 20)):
return MetaState.COMPLETE
return MetaState.INIT
elif self.appear(ASH_SHOWDOWN, offset=(30, 30)):
return MetaState.INIT
return MetaState.UNDEFINED
def _in_meta_page(self):
return self.appear(ASH_SHOWDOWN, offset=(30, 30)) \
or self.appear(BEACON_LIST, offset=(20, 20)) \
or self.appear(DOSSIER_LIST, offset=(20, 20))
def _ensure_meta_page(self, skip_first_screenshot=True):
logger.info('Ensure beacon attack page')
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self._in_meta_page():
logger.info('In meta page')
return True
if self.handle_map_event():
continue
if self.appear_then_click(META_ENTRANCE, offset=(10, 10), interval=2):
continue
def _begin_beacon(self):
logger.hr('Meta Beacon Attack')
if not _server_support():
logger.info("Server not support dossier beacon and OneHitMode, please contact the developer.")
self._ensure_meta_page()
self._attack_meta()
def run(self):
self.ui_ensure(page_reward)
self._begin_beacon()
self.config.task_delay(server_update=True)
class AshBeaconAssist(Meta):
finished = False
def _attack_meta(self, skip_first_screenshot=True):
combat = AshCombat(config=self.config, device=self.device)
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.handle_map_event():
continue
if self._satisfy_attack_condition():
self._ensure_meta_level()
combat.combat(expected_end=self._in_meta_assist_page, save_get_items=False, emotion_reduce=False)
continue
else:
break
def _satisfy_attack_condition(self):
remain_times = self.digit_ocr_point_and_check(BEACON_REMAIN, 1)
if not remain_times:
logger.info('No enough assist times, complete')
self.finished = True
return False
if self.appear(ASH_START, offset=(20, 20)):
return True
else:
logger.info('Can not find a meta to attack, check after 30 minutes')
self.config.task_delay(minute=30)
self.config.task_stop()
def _ensure_meta_level(self):
"""
Select an meta whose level satisfies
"""
# Ensure BEACON_TIER shown up
# When entering beacon list, tier number wasn't shown immediately.
tier = self.config.OpsiAshAssist_Tier
logger.info('Begin find a level ' + str(tier) + ' meta')
for n in range(10):
if self.image_color_count(BEACON_TIER, color=(0, 0, 0), threshold=221, count=50):
break
self.device.screenshot()
if n >= 9:
logger.warning('Waiting for beacon tier timeout')
# Select beacon
current = -1
for _ in range(5):
current = OCR_BEACON_TIER.ocr(self.device.image)
if current >= tier:
break
else:
self.device.click(BEACON_NEXT)
self.device.sleep((0.3, 0.5))
self.device.screenshot()
if current < tier:
logger.info(f'Tier {tier} beacon not found after 5 trial, use current beacon')
logger.info('Find a beacon in level:' + str(current))
def _in_meta_assist_page(self):
return self.appear(BEACON_MY, offset=(20, 20))
def _ensure_meta_assist_page(self, skip_first_screenshot=True):
logger.info('Ensure beacon assist page')
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self._in_meta_assist_page():
logger.info('In beacon assist page')
return True
if self.handle_map_event():
continue
if self.appear_then_click(META_ENTRANCE, offset=(10, 10), interval=2):
continue
if self.appear(ASH_SHOWDOWN, offset=(20, 20)):
self.device.click(META_MAIN_BEACON_ENTRANCE)
logger.info('In meta page main')
continue
if self.appear_then_click(BEACON_LIST, offset=(300, 20), interval=2):
continue
if self.appear_then_click(DOSSIER_LIST, offset=(20, 20), interval=2):
logger.info('In meta page dossier')
continue
def _begin_meta_assist(self):
logger.hr('Meta Beacon Assist')
self._ensure_meta_assist_page()
return self._attack_meta(skip_first_screenshot=False)
def run(self):
self.ui_ensure(page_reward)
self._begin_meta_assist()
self.config.task_delay(server_update=True)