Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
BIN
assets/share/combat/stamina/status/ICON_SEARCH.png
Normal file
After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 6.8 KiB |
BIN
assets/share/combat/stamina/status/RESERVED_OCR.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
BIN
assets/share/combat/stamina/status/STAMINA_OCR.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
assets/share/dungeon/ui_rogue/SURVIVAL_INDEX_OE_LOADED.2.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.1 KiB |
@ -107,6 +107,7 @@
|
||||
},
|
||||
"DungeonStorage": {
|
||||
"TrailblazePower": {},
|
||||
"Reserved": {},
|
||||
"Immersifier": {},
|
||||
"DungeonDouble": {},
|
||||
"EchoOfWar": {},
|
||||
|
@ -715,6 +715,12 @@
|
||||
"order": 1,
|
||||
"color": "#eb8efe"
|
||||
},
|
||||
"Reserved": {
|
||||
"type": "stored",
|
||||
"value": {},
|
||||
"display": "hide",
|
||||
"stored": "StoredResersed"
|
||||
},
|
||||
"Immersifier": {
|
||||
"type": "stored",
|
||||
"value": {},
|
||||
|
@ -120,6 +120,8 @@ DungeonStorage:
|
||||
stored: StoredTrailblazePower
|
||||
order: 1
|
||||
color: "#eb8efe"
|
||||
Reserved:
|
||||
stored: StoredResersed
|
||||
Immersifier:
|
||||
stored: StoredImmersifier
|
||||
DungeonDouble:
|
||||
|
@ -662,6 +662,19 @@
|
||||
"order": 0,
|
||||
"color": "#777777"
|
||||
},
|
||||
"Reserved": {
|
||||
"name": "Reserved",
|
||||
"path": "Dungeon.DungeonStorage.Reserved",
|
||||
"i18n": "DungeonStorage.Reserved.name",
|
||||
"stored": "StoredResersed",
|
||||
"attrs": {
|
||||
"time": "2020-01-01 00:00:00",
|
||||
"total": 8,
|
||||
"value": 0
|
||||
},
|
||||
"order": 0,
|
||||
"color": "#777777"
|
||||
},
|
||||
"Immersifier": {
|
||||
"name": "Immersifier",
|
||||
"path": "Dungeon.DungeonStorage.Immersifier",
|
||||
|
@ -57,6 +57,7 @@ class GeneratedConfig:
|
||||
|
||||
# Group `DungeonStorage`
|
||||
DungeonStorage_TrailblazePower = {}
|
||||
DungeonStorage_Reserved = {}
|
||||
DungeonStorage_Immersifier = {}
|
||||
DungeonStorage_DungeonDouble = {}
|
||||
DungeonStorage_EchoOfWar = {}
|
||||
|
@ -445,6 +445,10 @@
|
||||
"name": "Power",
|
||||
"help": ""
|
||||
},
|
||||
"Reserved": {
|
||||
"name": "Reserved Trailblaze Power",
|
||||
"help": ""
|
||||
},
|
||||
"Immersifier": {
|
||||
"name": "Immersifier",
|
||||
"help": ""
|
||||
|
@ -445,6 +445,10 @@
|
||||
"name": "Poder",
|
||||
"help": ""
|
||||
},
|
||||
"Reserved": {
|
||||
"name": "Trailblaze Poder Reservada",
|
||||
"help": ""
|
||||
},
|
||||
"Immersifier": {
|
||||
"name": "Inmersor",
|
||||
"help": ""
|
||||
|
@ -445,6 +445,10 @@
|
||||
"name": "DungeonStorage.TrailblazePower.name",
|
||||
"help": "DungeonStorage.TrailblazePower.help"
|
||||
},
|
||||
"Reserved": {
|
||||
"name": "DungeonStorage.Reserved.name",
|
||||
"help": "DungeonStorage.Reserved.help"
|
||||
},
|
||||
"Immersifier": {
|
||||
"name": "DungeonStorage.Immersifier.name",
|
||||
"help": "DungeonStorage.Immersifier.help"
|
||||
|
@ -445,6 +445,10 @@
|
||||
"name": "开拓力",
|
||||
"help": ""
|
||||
},
|
||||
"Reserved": {
|
||||
"name": "后备开拓力",
|
||||
"help": ""
|
||||
},
|
||||
"Immersifier": {
|
||||
"name": "沉浸器",
|
||||
"help": ""
|
||||
|
@ -445,6 +445,10 @@
|
||||
"name": "開拓力",
|
||||
"help": ""
|
||||
},
|
||||
"Reserved": {
|
||||
"name": "后备開拓力",
|
||||
"help": ""
|
||||
},
|
||||
"Immersifier": {
|
||||
"name": "沉浸器",
|
||||
"help": ""
|
||||
|
@ -206,6 +206,10 @@ class StoredTrailblazePower(StoredCounter):
|
||||
return value
|
||||
|
||||
|
||||
class StoredResersed(StoredCounter):
|
||||
FIXED_TOTAL = 2400
|
||||
|
||||
|
||||
class StoredImmersifier(StoredCounter):
|
||||
FIXED_TOTAL = 8
|
||||
|
||||
|
@ -22,6 +22,7 @@ from module.config.stored.classes import (
|
||||
StoredInt,
|
||||
StoredPlanner,
|
||||
StoredPlannerOverall,
|
||||
StoredResersed,
|
||||
StoredSimulatedUniverse,
|
||||
StoredSimulatedUniverseElite,
|
||||
StoredTrailblazePower,
|
||||
@ -85,6 +86,7 @@ class StoredGenerated:
|
||||
Item_Dream_Making_Engine = StoredPlanner("Dungeon.Planner.Item_Dream_Making_Engine")
|
||||
Item_Shards_of_Desires = StoredPlanner("Dungeon.Planner.Item_Shards_of_Desires")
|
||||
TrailblazePower = StoredTrailblazePower("Dungeon.DungeonStorage.TrailblazePower")
|
||||
Reserved = StoredResersed("Dungeon.DungeonStorage.Reserved")
|
||||
Immersifier = StoredImmersifier("Dungeon.DungeonStorage.Immersifier")
|
||||
DungeonDouble = StoredDungeonDouble("Dungeon.DungeonStorage.DungeonDouble")
|
||||
EchoOfWar = StoredEchoOfWar("Dungeon.DungeonStorage.EchoOfWar")
|
||||
|
@ -271,6 +271,7 @@ class Connection(ConnectionAttr):
|
||||
return self.adb_shell(['getprop', name]).strip()
|
||||
|
||||
@cached_property
|
||||
@retry
|
||||
def cpu_abi(self) -> str:
|
||||
"""
|
||||
Returns:
|
||||
@ -282,6 +283,7 @@ class Connection(ConnectionAttr):
|
||||
return abi
|
||||
|
||||
@cached_property
|
||||
@retry
|
||||
def sdk_ver(self) -> int:
|
||||
"""
|
||||
Android SDK/API levels, see https://apilevels.com/
|
||||
@ -295,6 +297,7 @@ class Connection(ConnectionAttr):
|
||||
return 0
|
||||
|
||||
@cached_property
|
||||
@retry
|
||||
def is_avd(self):
|
||||
if get_serial_pair(self.serial)[0] is None:
|
||||
return False
|
||||
@ -305,12 +308,35 @@ class Connection(ConnectionAttr):
|
||||
return False
|
||||
|
||||
@cached_property
|
||||
@retry
|
||||
def is_waydroid(self):
|
||||
res = self.adb_getprop('ro.product.brand')
|
||||
logger.attr('ro.product.brand', res)
|
||||
return 'waydroid' in res.lower()
|
||||
|
||||
@cached_property
|
||||
@retry
|
||||
def nemud_app_keep_alive(self) -> str:
|
||||
res = self.adb_getprop('nemud.app_keep_alive')
|
||||
logger.attr('nemud.app_keep_alive', res)
|
||||
return res
|
||||
|
||||
@cached_property
|
||||
@retry
|
||||
def nemud_player_version(self) -> str:
|
||||
# [nemud.player_product_version]: [3.8.27.2950]
|
||||
res = self.adb_getprop('nemud.player_version')
|
||||
logger.attr('nemud.player_version', res)
|
||||
return res
|
||||
|
||||
@cached_property
|
||||
@retry
|
||||
def nemud_player_engine(self) -> str:
|
||||
# NEMUX or MACPRO
|
||||
res = self.adb_getprop('nemud.player_engine')
|
||||
logger.attr('nemud.player_engine', res)
|
||||
return res
|
||||
|
||||
def check_mumu_app_keep_alive(self):
|
||||
if not self.is_mumu_family:
|
||||
return False
|
||||
@ -340,12 +366,13 @@ class Connection(ConnectionAttr):
|
||||
"""
|
||||
if not self.is_mumu_family:
|
||||
return False
|
||||
# >= 4.0 has no info in getprop
|
||||
if self.nemud_player_version == '':
|
||||
return True
|
||||
if self.nemud_app_keep_alive != '':
|
||||
return True
|
||||
if IS_MACINTOSH:
|
||||
res = self.adb_getprop('nemud.player_engine')
|
||||
logger.attr('nemud.player_engine', res)
|
||||
if 'MACPRO' in res:
|
||||
if 'MACPRO' in self.nemud_player_engine:
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -665,13 +692,9 @@ class Connection(ConnectionAttr):
|
||||
# Brute force connect nearby ports to handle serial switches
|
||||
if self.is_mumu12_family:
|
||||
before = self.serial
|
||||
for port_offset in [1, -1, 2, -2]:
|
||||
port = self.port + port_offset
|
||||
serial = self.serial.replace(str(self.port), str(port))
|
||||
msg = self.adb_client.connect(serial)
|
||||
logger.info(msg)
|
||||
if 'connected' in msg:
|
||||
break
|
||||
serial_list = [self.serial.replace(str(self.port), str(self.port + offset))
|
||||
for offset in [1, -1, 2, -2]]
|
||||
self.adb_brute_force_connect(serial_list)
|
||||
self.detect_device()
|
||||
if self.serial != before:
|
||||
return True
|
||||
@ -684,6 +707,25 @@ class Connection(ConnectionAttr):
|
||||
self.detect_device()
|
||||
return False
|
||||
|
||||
def adb_brute_force_connect(self, serial_list):
|
||||
"""
|
||||
Args:
|
||||
serial_list (list[str]):
|
||||
"""
|
||||
import asyncio
|
||||
ev = asyncio.new_event_loop()
|
||||
|
||||
def _connect(serial):
|
||||
msg = self.adb_client.connect(serial)
|
||||
logger.info(msg)
|
||||
return msg
|
||||
|
||||
async def connect():
|
||||
tasks = [ev.run_in_executor(None, _connect, serial) for serial in serial_list]
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
ev.run_until_complete(connect())
|
||||
|
||||
@Config.when(DEVICE_OVER_HTTP=True)
|
||||
def adb_connect(self):
|
||||
# No adb connect if over http
|
||||
|
@ -163,6 +163,10 @@ class ConnectionAttr:
|
||||
def is_network_device(self):
|
||||
return bool(re.match(r'\d+\.\d+\.\d+\.\d+:\d+', self.serial))
|
||||
|
||||
@cached_property
|
||||
def is_local_network_device(self):
|
||||
return bool(re.match(r'192\.168\.\d+\.\d+:\d+', self.serial))
|
||||
|
||||
@cached_property
|
||||
def is_over_http(self):
|
||||
return bool(re.match(r"^https?://", self.serial))
|
||||
|
@ -303,8 +303,11 @@ class Adb(Connection):
|
||||
logger.error(result)
|
||||
raise PackageNotInstalled(package_name)
|
||||
|
||||
ret = self.adb_shell(['am', 'start', '-a', 'android.intent.action.MAIN', '-c',
|
||||
'android.intent.category.LAUNCHER', '-n', f'{package_name}/{activity_name}'])
|
||||
cmd = ['am', 'start', '-a', 'android.intent.action.MAIN', '-c',
|
||||
'android.intent.category.LAUNCHER', '-n', f'{package_name}/{activity_name}']
|
||||
if self.is_local_network_device and self.is_waydroid:
|
||||
cmd += ['--windowingMode', '4']
|
||||
ret = self.adb_shell(cmd)
|
||||
# Invalid activity
|
||||
# Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=... }
|
||||
# Error type 3
|
||||
@ -320,6 +323,24 @@ class Adb(Connection):
|
||||
if 'Warning: Activity not started' in ret:
|
||||
logger.info('App activity is already started')
|
||||
return True
|
||||
# Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.YoStarEN.AzurLane/com.manjuu.azurlane.MainActivity }
|
||||
# java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.YoStarEN.AzurLane/com.manjuu.azurlane.MainActivity } from null (pid=5140, uid=2000) not exported from uid 10064
|
||||
# at android.os.Parcel.readException(Parcel.java:1692)
|
||||
# at android.os.Parcel.readException(Parcel.java:1645)
|
||||
# at android.app.ActivityManagerProxy.startActivityAsUser(ActivityManagerNative.java:3152)
|
||||
# at com.android.commands.am.Am.runStart(Am.java:643)
|
||||
# at com.android.commands.am.Am.onRun(Am.java:394)
|
||||
# at com.android.internal.os.BaseCommand.run(BaseCommand.java:51)
|
||||
# at com.android.commands.am.Am.main(Am.java:124)
|
||||
# at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
|
||||
# at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:290)
|
||||
if 'Permission Denial' in ret:
|
||||
if allow_failure:
|
||||
return False
|
||||
else:
|
||||
logger.error(ret)
|
||||
logger.error('Permission Denial while starting app, probably because activity invalid')
|
||||
return False
|
||||
# Success
|
||||
# Starting: Intent...
|
||||
return True
|
||||
|
@ -486,6 +486,9 @@ class NemuIpc(Platform):
|
||||
def nemu_ipc_available(self) -> bool:
|
||||
if not self.is_mumu_family:
|
||||
return False
|
||||
# >= 4.0 has no info in getprop
|
||||
if self.nemud_player_version == '':
|
||||
return True
|
||||
if self.nemud_app_keep_alive == '':
|
||||
return False
|
||||
try:
|
||||
|
@ -224,28 +224,147 @@ class Uiautomator2(Connection):
|
||||
return result['package']
|
||||
|
||||
@retry
|
||||
def app_start_uiautomator2(self, package_name=None, activity_name=None):
|
||||
def _app_start_u2_monkey(self, package_name=None, allow_failure=False):
|
||||
"""
|
||||
Args:
|
||||
package_name (str):
|
||||
allow_failure (bool):
|
||||
|
||||
Returns:
|
||||
bool: If success to start
|
||||
|
||||
Raises:
|
||||
PackageNotInstalled:
|
||||
"""
|
||||
if not package_name:
|
||||
package_name = self.package
|
||||
result = self.u2.shell([
|
||||
'monkey', '-p', package_name, '-c',
|
||||
'android.intent.category.LAUNCHER', '--pct-syskeys', '0', '1'
|
||||
])
|
||||
if 'No activities found' in result.output:
|
||||
# ** No activities found to run, monkey aborted.
|
||||
if allow_failure:
|
||||
return False
|
||||
else:
|
||||
logger.error(result)
|
||||
raise PackageNotInstalled(package_name)
|
||||
elif 'inaccessible' in result:
|
||||
# /system/bin/sh: monkey: inaccessible or not found
|
||||
return False
|
||||
else:
|
||||
# Events injected: 1
|
||||
# ## Network stats: elapsed time=4ms (0ms mobile, 0ms wifi, 4ms not connected)
|
||||
return True
|
||||
|
||||
@retry
|
||||
def _app_start_u2_am(self, package_name=None, activity_name=None, allow_failure=False):
|
||||
"""
|
||||
Args:
|
||||
package_name (str):
|
||||
activity_name (str):
|
||||
allow_failure (bool):
|
||||
|
||||
Returns:
|
||||
bool: If success to start
|
||||
|
||||
Raises:
|
||||
PackageNotInstalled:
|
||||
"""
|
||||
if not package_name:
|
||||
package_name = self.package
|
||||
if not activity_name:
|
||||
try:
|
||||
info = self.u2.app_info(package_name)
|
||||
except u2.BaseError as e:
|
||||
if allow_failure:
|
||||
return False
|
||||
# BaseError('package "111" not found')
|
||||
elif 'not found' in str(e):
|
||||
logger.error(e)
|
||||
raise PackageNotInstalled(package_name)
|
||||
# Unknown error
|
||||
else:
|
||||
raise
|
||||
activity_name = info['mainActivity']
|
||||
|
||||
cmd = ['am', 'start', '-a', 'android.intent.action.MAIN', '-c',
|
||||
'android.intent.category.LAUNCHER', '-n', f'{package_name}/{activity_name}']
|
||||
if self.is_local_network_device and self.is_waydroid:
|
||||
cmd += ['--windowingMode', '4']
|
||||
ret = self.u2.shell(cmd)
|
||||
# Invalid activity
|
||||
# Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=... }
|
||||
# Error type 3
|
||||
# Error: Activity class {.../...} does not exist.
|
||||
if 'Error: Activity class' in ret.output:
|
||||
if allow_failure:
|
||||
return False
|
||||
else:
|
||||
logger.error(ret)
|
||||
return False
|
||||
# Already running
|
||||
# Warning: Activity not started, intent has been delivered to currently running top-most instance.
|
||||
if 'Warning: Activity not started' in ret.output:
|
||||
logger.info('App activity is already started')
|
||||
return True
|
||||
# Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.YoStarEN.AzurLane/com.manjuu.azurlane.MainActivity }
|
||||
# java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.YoStarEN.AzurLane/com.manjuu.azurlane.MainActivity } from null (pid=5140, uid=2000) not exported from uid 10064
|
||||
# at android.os.Parcel.readException(Parcel.java:1692)
|
||||
# at android.os.Parcel.readException(Parcel.java:1645)
|
||||
# at android.app.ActivityManagerProxy.startActivityAsUser(ActivityManagerNative.java:3152)
|
||||
# at com.android.commands.am.Am.runStart(Am.java:643)
|
||||
# at com.android.commands.am.Am.onRun(Am.java:394)
|
||||
# at com.android.internal.os.BaseCommand.run(BaseCommand.java:51)
|
||||
# at com.android.commands.am.Am.main(Am.java:124)
|
||||
# at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
|
||||
# at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:290)
|
||||
if 'Permission Denial' in ret.output:
|
||||
if allow_failure:
|
||||
return False
|
||||
else:
|
||||
logger.error(ret)
|
||||
logger.error('Permission Denial while starting app, probably because activity invalid')
|
||||
return False
|
||||
# Success
|
||||
# Starting: Intent...
|
||||
return True
|
||||
|
||||
# No @retry decorator since _app_start_adb_am and _app_start_adb_monkey have @retry already
|
||||
# @retry
|
||||
def app_start_uiautomator2(self, package_name=None, activity_name=None, allow_failure=False):
|
||||
"""
|
||||
Args:
|
||||
package_name (str):
|
||||
If None, to get from config
|
||||
activity_name (str):
|
||||
If None, to get from DICT_PACKAGE_TO_ACTIVITY
|
||||
If still None, launch from monkey
|
||||
If monkey failed, fetch activity name and launch from am
|
||||
allow_failure (bool):
|
||||
True for no PackageNotInstalled raising, just return False
|
||||
|
||||
Returns:
|
||||
bool: If success to start
|
||||
|
||||
Raises:
|
||||
PackageNotInstalled:
|
||||
"""
|
||||
if not package_name:
|
||||
package_name = self.package
|
||||
if not activity_name:
|
||||
activity_name = DICT_PACKAGE_TO_ACTIVITY.get(package_name)
|
||||
|
||||
try:
|
||||
self.u2.app_start(package_name, activity_name)
|
||||
except u2.exceptions.BaseError as e:
|
||||
# BaseError: package "com.bilibili.azurlane" not found
|
||||
logger.error(e)
|
||||
raise PackageNotInstalled(package_name)
|
||||
if activity_name:
|
||||
if self._app_start_u2_am(package_name, activity_name, allow_failure):
|
||||
return True
|
||||
if self._app_start_u2_monkey(package_name, allow_failure):
|
||||
return True
|
||||
if self._app_start_u2_am(package_name, activity_name, allow_failure):
|
||||
return True
|
||||
|
||||
logger.error('app_start_uiautomator2: All trials failed')
|
||||
return False
|
||||
|
||||
@retry
|
||||
def app_stop_uiautomator2(self, package_name=None):
|
||||
|
@ -23,3 +23,13 @@ ROGUE_LEAVE_FOR_NOW = ButtonWrapper(
|
||||
button=(729, 475, 765, 519),
|
||||
),
|
||||
)
|
||||
ROGUE_LEAVE_FOR_NOW_OE = ButtonWrapper(
|
||||
name='ROGUE_LEAVE_FOR_NOW_OE',
|
||||
share=Button(
|
||||
file='./assets/share/base/main_page/ROGUE_LEAVE_FOR_NOW_OE.png',
|
||||
area=(730, 551, 760, 587),
|
||||
search=(710, 531, 780, 607),
|
||||
color=(63, 52, 40),
|
||||
button=(730, 551, 760, 587),
|
||||
),
|
||||
)
|
||||
|
@ -297,6 +297,16 @@ MAP_EXIT = ButtonWrapper(
|
||||
),
|
||||
],
|
||||
)
|
||||
MAP_EXIT_OE = ButtonWrapper(
|
||||
name='MAP_EXIT_OE',
|
||||
share=Button(
|
||||
file='./assets/share/base/page/MAP_EXIT_OE.png',
|
||||
area=(51, 55, 68, 84),
|
||||
search=(31, 35, 88, 104),
|
||||
color=(141, 140, 141),
|
||||
button=(51, 55, 68, 84),
|
||||
),
|
||||
)
|
||||
MAP_GOTO_WORLD = ButtonWrapper(
|
||||
name='MAP_GOTO_WORLD',
|
||||
share=Button(
|
||||
|
@ -4,8 +4,8 @@ from module.base.timer import Timer
|
||||
from module.exception import GameNotRunningError, GamePageUnknownError
|
||||
from module.logger import logger
|
||||
from module.ocr.ocr import Ocr
|
||||
from tasks.base.assets.assets_base_main_page import ROGUE_LEAVE_FOR_NOW
|
||||
from tasks.base.assets.assets_base_page import CLOSE, MAIN_GOTO_CHARACTER, MAP_EXIT
|
||||
from tasks.base.assets.assets_base_main_page import ROGUE_LEAVE_FOR_NOW, ROGUE_LEAVE_FOR_NOW_OE
|
||||
from tasks.base.assets.assets_base_page import CLOSE, MAIN_GOTO_CHARACTER, MAP_EXIT, MAP_EXIT_OE
|
||||
from tasks.base.main_page import MainPage
|
||||
from tasks.base.page import Page, page_gacha, page_main
|
||||
from tasks.combat.assets.assets_combat_finish import COMBAT_EXIT
|
||||
@ -344,7 +344,6 @@ class UI(MainPage):
|
||||
|
||||
return appear
|
||||
|
||||
|
||||
def is_in_map_exit(self, interval=0):
|
||||
self.device.stuck_record_add(MAP_EXIT)
|
||||
|
||||
@ -355,6 +354,9 @@ class UI(MainPage):
|
||||
if MAP_EXIT.match_template_luma(self.device.image):
|
||||
if self.image_color_count(MAP_EXIT, color=(235, 235, 235), threshold=221, count=50):
|
||||
appear = True
|
||||
if MAP_EXIT_OE.match_template_luma(self.device.image):
|
||||
if self.image_color_count(MAP_EXIT_OE, color=(235, 235, 235), threshold=221, count=50):
|
||||
appear = True
|
||||
|
||||
if appear and interval:
|
||||
self.interval_reset(MAP_EXIT, interval=interval)
|
||||
@ -482,3 +484,6 @@ class UI(MainPage):
|
||||
if self.appear_then_click(ROGUE_LEAVE_FOR_NOW, interval=2):
|
||||
clicked = True
|
||||
continue
|
||||
if self.appear_then_click(ROGUE_LEAVE_FOR_NOW_OE, interval=2):
|
||||
clicked = True
|
||||
continue
|
||||
|
@ -1,165 +0,0 @@
|
||||
from module.base.button import Button, ButtonWrapper
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.button_extract ```
|
||||
|
||||
EXTRACT_RESERVED_TRAILBLAZE_POWER = ButtonWrapper(
|
||||
name='EXTRACT_RESERVED_TRAILBLAZE_POWER',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/EXTRACT_RESERVED_TRAILBLAZE_POWER.png',
|
||||
area=(909, 506, 929, 526),
|
||||
search=(889, 486, 949, 546),
|
||||
color=(91, 91, 91),
|
||||
button=(909, 506, 929, 526),
|
||||
),
|
||||
)
|
||||
FUEL = ButtonWrapper(
|
||||
name='FUEL',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/FUEL.png',
|
||||
area=(592, 276, 688, 366),
|
||||
search=(474, 271, 811, 396),
|
||||
color=(123, 96, 134),
|
||||
button=(592, 276, 688, 366),
|
||||
),
|
||||
)
|
||||
FUEL_ENTRANCE = ButtonWrapper(
|
||||
name='FUEL_ENTRANCE',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/FUEL_ENTRANCE.png',
|
||||
area=(1035, 26, 1056, 48),
|
||||
search=(1015, 6, 1076, 68),
|
||||
color=(188, 180, 226),
|
||||
button=(1035, 26, 1056, 48),
|
||||
),
|
||||
)
|
||||
FUEL_MINUS = ButtonWrapper(
|
||||
name='FUEL_MINUS',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/FUEL_MINUS.png',
|
||||
area=(472, 425, 510, 450),
|
||||
search=(452, 405, 530, 470),
|
||||
color=(236, 236, 236),
|
||||
button=(472, 425, 510, 450),
|
||||
),
|
||||
)
|
||||
FUEL_PLUS = ButtonWrapper(
|
||||
name='FUEL_PLUS',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/FUEL_PLUS.png',
|
||||
area=(967, 426, 1005, 449),
|
||||
search=(947, 406, 1025, 469),
|
||||
color=(232, 232, 232),
|
||||
button=(967, 426, 1005, 449),
|
||||
),
|
||||
)
|
||||
FUEL_SELECTED = ButtonWrapper(
|
||||
name='FUEL_SELECTED',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/FUEL_SELECTED.png',
|
||||
area=(587, 271, 692, 368),
|
||||
search=(474, 271, 811, 396),
|
||||
color=(136, 112, 144),
|
||||
button=(587, 271, 692, 368),
|
||||
),
|
||||
)
|
||||
FUEL_SLIDER = ButtonWrapper(
|
||||
name='FUEL_SLIDER',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/FUEL_SLIDER.png',
|
||||
area=(561, 434, 916, 441),
|
||||
search=(541, 414, 936, 461),
|
||||
color=(215, 185, 154),
|
||||
button=(561, 434, 916, 441),
|
||||
),
|
||||
)
|
||||
OCR_EXTRACT_RESERVED_TRAILBLAZE_POWER_COUNT = ButtonWrapper(
|
||||
name='OCR_EXTRACT_RESERVED_TRAILBLAZE_POWER_COUNT',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/OCR_EXTRACT_RESERVED_TRAILBLAZE_POWER_COUNT.png',
|
||||
area=(425, 415, 688, 436),
|
||||
search=(405, 395, 708, 456),
|
||||
color=(192, 192, 192),
|
||||
button=(425, 415, 688, 436),
|
||||
),
|
||||
)
|
||||
OCR_FUEL = ButtonWrapper(
|
||||
name='OCR_FUEL',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/OCR_FUEL.png',
|
||||
area=(605, 369, 678, 386),
|
||||
search=(585, 349, 698, 406),
|
||||
color=(66, 66, 66),
|
||||
button=(605, 369, 678, 386),
|
||||
),
|
||||
)
|
||||
OCR_FUEL_COUNT = ButtonWrapper(
|
||||
name='OCR_FUEL_COUNT',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/OCR_FUEL_COUNT.png',
|
||||
area=(686, 409, 881, 425),
|
||||
search=(666, 389, 901, 445),
|
||||
color=(205, 205, 205),
|
||||
button=(686, 409, 881, 425),
|
||||
),
|
||||
)
|
||||
OCR_RESERVED_TRAILBLAZE_POWER = ButtonWrapper(
|
||||
name='OCR_RESERVED_TRAILBLAZE_POWER',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/OCR_RESERVED_TRAILBLAZE_POWER.png',
|
||||
area=(883, 29, 992, 44),
|
||||
search=(863, 9, 1012, 64),
|
||||
color=(51, 65, 65),
|
||||
button=(883, 29, 992, 44),
|
||||
),
|
||||
)
|
||||
RESERVED_MINUS = ButtonWrapper(
|
||||
name='RESERVED_MINUS',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/RESERVED_MINUS.png',
|
||||
area=(248, 474, 281, 498),
|
||||
search=(228, 454, 301, 518),
|
||||
color=(238, 238, 238),
|
||||
button=(248, 474, 281, 498),
|
||||
),
|
||||
)
|
||||
RESERVED_PLUS = ButtonWrapper(
|
||||
name='RESERVED_PLUS',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/RESERVED_PLUS.png',
|
||||
area=(938, 475, 974, 498),
|
||||
search=(918, 455, 994, 518),
|
||||
color=(232, 232, 232),
|
||||
button=(938, 475, 974, 498),
|
||||
),
|
||||
)
|
||||
RESERVED_SLIDER = ButtonWrapper(
|
||||
name='RESERVED_SLIDER',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/RESERVED_SLIDER.png',
|
||||
area=(334, 483, 873, 489),
|
||||
search=(314, 463, 893, 509),
|
||||
color=(212, 173, 130),
|
||||
button=(334, 483, 873, 489),
|
||||
),
|
||||
)
|
||||
RESERVED_TRAILBLAZE_POWER_ENTRANCE = ButtonWrapper(
|
||||
name='RESERVED_TRAILBLAZE_POWER_ENTRANCE',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/RESERVED_TRAILBLAZE_POWER_ENTRANCE.png',
|
||||
area=(895, 26, 916, 48),
|
||||
search=(875, 6, 936, 68),
|
||||
color=(154, 213, 214),
|
||||
button=(895, 26, 916, 48),
|
||||
),
|
||||
)
|
||||
USING_FUEL = ButtonWrapper(
|
||||
name='USING_FUEL',
|
||||
share=Button(
|
||||
file='./assets/share/combat/fuel/USING_FUEL.png',
|
||||
area=(263, 265, 363, 365),
|
||||
search=(243, 245, 383, 385),
|
||||
color=(161, 116, 129),
|
||||
button=(263, 265, 363, 365),
|
||||
),
|
||||
)
|
@ -20,16 +20,6 @@ COMBAT_PREPARE = ButtonWrapper(
|
||||
button=(956, 640, 1225, 676),
|
||||
),
|
||||
)
|
||||
OCR_TRAILBLAZE_POWER = ButtonWrapper(
|
||||
name='OCR_TRAILBLAZE_POWER',
|
||||
share=Button(
|
||||
file='./assets/share/combat/prepare/OCR_TRAILBLAZE_POWER.png',
|
||||
area=(998, 26, 1130, 48),
|
||||
search=(978, 6, 1150, 68),
|
||||
color=(77, 76, 87),
|
||||
button=(998, 26, 1130, 48),
|
||||
),
|
||||
)
|
||||
OCR_WAVE_COST = ButtonWrapper(
|
||||
name='OCR_WAVE_COST',
|
||||
share=Button(
|
||||
|
85
tasks/combat/assets/assets_combat_stamina_fuel.py
Normal file
@ -0,0 +1,85 @@
|
||||
from module.base.button import Button, ButtonWrapper
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.button_extract ```
|
||||
|
||||
FUEL = ButtonWrapper(
|
||||
name='FUEL',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/fuel/FUEL.png',
|
||||
area=(592, 276, 688, 366),
|
||||
search=(474, 271, 811, 396),
|
||||
color=(123, 96, 134),
|
||||
button=(592, 276, 688, 366),
|
||||
),
|
||||
)
|
||||
FUEL_MINUS = ButtonWrapper(
|
||||
name='FUEL_MINUS',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/fuel/FUEL_MINUS.png',
|
||||
area=(472, 425, 510, 450),
|
||||
search=(452, 405, 530, 470),
|
||||
color=(236, 236, 236),
|
||||
button=(472, 425, 510, 450),
|
||||
),
|
||||
)
|
||||
FUEL_PLUS = ButtonWrapper(
|
||||
name='FUEL_PLUS',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/fuel/FUEL_PLUS.png',
|
||||
area=(967, 426, 1005, 449),
|
||||
search=(947, 406, 1025, 469),
|
||||
color=(232, 232, 232),
|
||||
button=(967, 426, 1005, 449),
|
||||
),
|
||||
)
|
||||
FUEL_SELECTED = ButtonWrapper(
|
||||
name='FUEL_SELECTED',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/fuel/FUEL_SELECTED.png',
|
||||
area=(587, 271, 692, 368),
|
||||
search=(474, 271, 811, 396),
|
||||
color=(136, 112, 144),
|
||||
button=(587, 271, 692, 368),
|
||||
),
|
||||
)
|
||||
FUEL_SLIDER = ButtonWrapper(
|
||||
name='FUEL_SLIDER',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/fuel/FUEL_SLIDER.png',
|
||||
area=(561, 434, 916, 441),
|
||||
search=(541, 414, 936, 461),
|
||||
color=(215, 185, 154),
|
||||
button=(561, 434, 916, 441),
|
||||
),
|
||||
)
|
||||
OCR_FUEL = ButtonWrapper(
|
||||
name='OCR_FUEL',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/fuel/OCR_FUEL.png',
|
||||
area=(605, 369, 678, 386),
|
||||
search=(585, 349, 698, 406),
|
||||
color=(66, 66, 66),
|
||||
button=(605, 369, 678, 386),
|
||||
),
|
||||
)
|
||||
OCR_FUEL_COUNT = ButtonWrapper(
|
||||
name='OCR_FUEL_COUNT',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/fuel/OCR_FUEL_COUNT.png',
|
||||
area=(686, 409, 881, 425),
|
||||
search=(666, 389, 901, 445),
|
||||
color=(205, 205, 205),
|
||||
button=(686, 409, 881, 425),
|
||||
),
|
||||
)
|
||||
USING_FUEL = ButtonWrapper(
|
||||
name='USING_FUEL',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/fuel/USING_FUEL.png',
|
||||
area=(263, 265, 363, 365),
|
||||
search=(243, 245, 383, 385),
|
||||
color=(161, 116, 129),
|
||||
button=(263, 265, 363, 365),
|
||||
),
|
||||
)
|
55
tasks/combat/assets/assets_combat_stamina_reserved.py
Normal file
@ -0,0 +1,55 @@
|
||||
from module.base.button import Button, ButtonWrapper
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.button_extract ```
|
||||
|
||||
EXTRACT_RESERVED_TRAILBLAZE_POWER = ButtonWrapper(
|
||||
name='EXTRACT_RESERVED_TRAILBLAZE_POWER',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/reserved/EXTRACT_RESERVED_TRAILBLAZE_POWER.png',
|
||||
area=(909, 506, 929, 526),
|
||||
search=(889, 486, 949, 546),
|
||||
color=(91, 91, 91),
|
||||
button=(909, 506, 929, 526),
|
||||
),
|
||||
)
|
||||
OCR_EXTRACT_RESERVED_TRAILBLAZE_POWER_COUNT = ButtonWrapper(
|
||||
name='OCR_EXTRACT_RESERVED_TRAILBLAZE_POWER_COUNT',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/reserved/OCR_EXTRACT_RESERVED_TRAILBLAZE_POWER_COUNT.png',
|
||||
area=(425, 415, 688, 436),
|
||||
search=(405, 395, 708, 456),
|
||||
color=(192, 192, 192),
|
||||
button=(425, 415, 688, 436),
|
||||
),
|
||||
)
|
||||
RESERVED_MINUS = ButtonWrapper(
|
||||
name='RESERVED_MINUS',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/reserved/RESERVED_MINUS.png',
|
||||
area=(248, 474, 281, 498),
|
||||
search=(228, 454, 301, 518),
|
||||
color=(238, 238, 238),
|
||||
button=(248, 474, 281, 498),
|
||||
),
|
||||
)
|
||||
RESERVED_PLUS = ButtonWrapper(
|
||||
name='RESERVED_PLUS',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/reserved/RESERVED_PLUS.png',
|
||||
area=(938, 475, 974, 498),
|
||||
search=(918, 455, 994, 518),
|
||||
color=(232, 232, 232),
|
||||
button=(938, 475, 974, 498),
|
||||
),
|
||||
)
|
||||
RESERVED_SLIDER = ButtonWrapper(
|
||||
name='RESERVED_SLIDER',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/reserved/RESERVED_SLIDER.png',
|
||||
area=(334, 483, 873, 489),
|
||||
search=(314, 463, 893, 509),
|
||||
color=(212, 173, 130),
|
||||
button=(334, 483, 873, 489),
|
||||
),
|
||||
)
|
75
tasks/combat/assets/assets_combat_stamina_status.py
Normal file
@ -0,0 +1,75 @@
|
||||
from module.base.button import Button, ButtonWrapper
|
||||
|
||||
# This file was auto-generated, do not modify it manually. To generate:
|
||||
# ``` python -m dev_tools.button_extract ```
|
||||
|
||||
ICON_SEARCH = ButtonWrapper(
|
||||
name='ICON_SEARCH',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/status/ICON_SEARCH.png',
|
||||
area=(568, 8, 1265, 66),
|
||||
search=(548, 0, 1280, 86),
|
||||
color=(71, 70, 100),
|
||||
button=(568, 8, 1265, 66),
|
||||
),
|
||||
)
|
||||
IMMERSIFIER_ICON = ButtonWrapper(
|
||||
name='IMMERSIFIER_ICON',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/status/IMMERSIFIER_ICON.png',
|
||||
area=(1047, 26, 1066, 49),
|
||||
search=(1027, 6, 1086, 69),
|
||||
color=(138, 127, 117),
|
||||
button=(1047, 26, 1066, 49),
|
||||
),
|
||||
)
|
||||
IMMERSIFIER_OCR = ButtonWrapper(
|
||||
name='IMMERSIFIER_OCR',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/status/IMMERSIFIER_OCR.png',
|
||||
area=(1049, 26, 1151, 48),
|
||||
search=(1029, 6, 1171, 68),
|
||||
color=(64, 61, 61),
|
||||
button=(1049, 26, 1151, 48),
|
||||
),
|
||||
)
|
||||
RESERVED_ICON = ButtonWrapper(
|
||||
name='RESERVED_ICON',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/status/RESERVED_ICON.png',
|
||||
area=(895, 26, 916, 48),
|
||||
search=(875, 6, 936, 68),
|
||||
color=(155, 212, 215),
|
||||
button=(895, 26, 916, 48),
|
||||
),
|
||||
)
|
||||
RESERVED_OCR = ButtonWrapper(
|
||||
name='RESERVED_OCR',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/status/RESERVED_OCR.png',
|
||||
area=(895, 26, 999, 48),
|
||||
search=(875, 6, 1019, 68),
|
||||
color=(50, 69, 83),
|
||||
button=(895, 26, 999, 48),
|
||||
),
|
||||
)
|
||||
STAMINA_ICON = ButtonWrapper(
|
||||
name='STAMINA_ICON',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/status/STAMINA_ICON.png',
|
||||
area=(873, 26, 894, 48),
|
||||
search=(853, 6, 914, 68),
|
||||
color=(188, 180, 226),
|
||||
button=(873, 26, 894, 48),
|
||||
),
|
||||
)
|
||||
STAMINA_OCR = ButtonWrapper(
|
||||
name='STAMINA_OCR',
|
||||
share=Button(
|
||||
file='./assets/share/combat/stamina/status/STAMINA_OCR.png',
|
||||
area=(873, 26, 1013, 48),
|
||||
search=(853, 6, 1033, 68),
|
||||
color=(66, 64, 88),
|
||||
button=(873, 26, 1013, 48),
|
||||
),
|
||||
)
|
@ -54,7 +54,7 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo
|
||||
|
||||
# Check limits
|
||||
if self.config.stored.TrailblazePower.value < self.combat_wave_cost:
|
||||
return self._try_get_more_trablaize_power(self.config.stored.TrailblazePower.value, self.combat_wave_cost)
|
||||
return self._try_get_more_trablaize_power(self.combat_wave_cost)
|
||||
if self.combat_waves <= 0:
|
||||
logger.info('Combat wave limited, cannot continue combat')
|
||||
return False
|
||||
@ -163,6 +163,8 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo
|
||||
skip_first_screenshot = True
|
||||
is_executing = True
|
||||
self.combat_state_reset()
|
||||
self.device.stuck_record_clear()
|
||||
self.device.click_record_clear()
|
||||
self.device.screenshot_interval_set('combat')
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
@ -196,6 +198,8 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo
|
||||
if self.handle_battle_pass_notification():
|
||||
continue
|
||||
|
||||
self.device.stuck_record_clear()
|
||||
self.device.click_record_clear()
|
||||
self.device.screenshot_interval_set()
|
||||
|
||||
def _combat_can_again(self) -> bool:
|
||||
@ -221,7 +225,7 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo
|
||||
logger.info(f'Current has {current}, combat costs {self.combat_wave_cost}, can run again')
|
||||
return True
|
||||
else:
|
||||
return self._try_get_more_trablaize_power(current, self.combat_wave_cost * self.combat_waves)
|
||||
return self._try_get_more_trablaize_power(self.combat_wave_cost * self.combat_waves)
|
||||
elif self.combat_wave_cost <= 0:
|
||||
logger.info(f'Free combat, combat costs {self.combat_wave_cost}, can not run again')
|
||||
return False
|
||||
@ -230,20 +234,15 @@ class Combat(CombatInteract, CombatPrepare, CombatState, CombatTeam, CombatSuppo
|
||||
logger.info(f'Current has {current}, combat costs {self.combat_wave_cost}, can run again')
|
||||
return True
|
||||
else:
|
||||
return self._try_get_more_trablaize_power(current, self.combat_wave_cost * self.combat_waves)
|
||||
|
||||
def _try_get_more_trablaize_power(self, current, cost):
|
||||
if self.config.TrailblazePower_ExtractReservedTrailblazePower:
|
||||
logger.info('Extract reserved trailblaze power to get more trailblaze power')
|
||||
if self.extract_reserved_trailblaze_power(current):
|
||||
self.combat_get_trailblaze_power()
|
||||
self.get_interval_timer(COMBAT_EXIT).wait()
|
||||
if self.config.TrailblazePower_UseFuel:
|
||||
logger.info('Use fuel to get more trailblaze power')
|
||||
if self.use_fuel(current):
|
||||
self.combat_get_trailblaze_power()
|
||||
self.get_interval_timer(COMBAT_AGAIN).wait()
|
||||
return self._try_get_more_trablaize_power(self.combat_wave_cost * self.combat_waves)
|
||||
|
||||
def _try_get_more_trablaize_power(self, cost):
|
||||
self.extract_stamina(
|
||||
update=False,
|
||||
use_reserved=self.config.TrailblazePower_ExtractReservedTrailblazePower,
|
||||
use_fuel=self.config.TrailblazePower_UseFuel
|
||||
)
|
||||
current = self.config.stored.TrailblazePower.value
|
||||
if current >= cost:
|
||||
return True
|
||||
else:
|
||||
|
@ -4,14 +4,16 @@ from module.base.utils import area_offset, crop
|
||||
from module.logger import logger
|
||||
from module.ocr.ocr import Digit
|
||||
from tasks.base.assets.assets_base_popup import GET_REWARD, POPUP_CANCEL, POPUP_CONFIRM
|
||||
from tasks.base.ui import UI
|
||||
from tasks.combat.assets.assets_combat_finish import COMBAT_AGAIN, COMBAT_EXIT
|
||||
from tasks.combat.assets.assets_combat_fuel import *
|
||||
from tasks.combat.assets.assets_combat_prepare import COMBAT_PREPARE
|
||||
from tasks.combat.assets.assets_combat_stamina_fuel import *
|
||||
from tasks.combat.assets.assets_combat_stamina_reserved import *
|
||||
from tasks.combat.assets.assets_combat_stamina_status import *
|
||||
from tasks.combat.stamina_status import StaminaStatus
|
||||
from tasks.item.slider import Slider
|
||||
|
||||
|
||||
class Fuel(UI):
|
||||
class Fuel(StaminaStatus):
|
||||
fuel_trailblaze_power = 60
|
||||
|
||||
def _use_fuel_finish(self):
|
||||
@ -26,7 +28,7 @@ class Fuel(UI):
|
||||
return True
|
||||
if self.appear(COMBAT_PREPARE):
|
||||
if self.image_color_count(COMBAT_PREPARE.button, color=(230, 230, 230), threshold=240, count=400):
|
||||
logger.info(f'Use fuel finished at COMBAT_AGAIN')
|
||||
logger.info(f'Use fuel finished at COMBAT_PREPARE')
|
||||
return True
|
||||
return False
|
||||
|
||||
@ -87,7 +89,7 @@ class Fuel(UI):
|
||||
timer = self.get_interval_timer(COMBAT_EXIT, interval=5, renew=True)
|
||||
timer.set_current(4.4)
|
||||
|
||||
def extract_reserved_trailblaze_power(self, current, skip_first_screenshot=True):
|
||||
def extract_reserved_trailblaze_power(self, skip_first_screenshot=True):
|
||||
"""
|
||||
Extract reserved trailblaze power from previous combat.
|
||||
|
||||
@ -95,11 +97,8 @@ class Fuel(UI):
|
||||
bool: If extracted
|
||||
"""
|
||||
logger.info('Extract reserved trailblaze power')
|
||||
reserved = Digit(OCR_RESERVED_TRAILBLAZE_POWER).ocr_single_line(self.device.image)
|
||||
if reserved <= 0:
|
||||
logger.info('No reserved trailblaze power')
|
||||
return False
|
||||
|
||||
RESERVED_ICON.load_search(ICON_SEARCH.area)
|
||||
self.interval_clear([POPUP_CONFIRM, POPUP_CANCEL, GET_REWARD])
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
@ -111,12 +110,14 @@ class Fuel(UI):
|
||||
break
|
||||
if self.appear_then_click(EXTRACT_RESERVED_TRAILBLAZE_POWER):
|
||||
continue
|
||||
if self.appear_then_click(RESERVED_TRAILBLAZE_POWER_ENTRANCE):
|
||||
if self.appear_then_click(RESERVED_ICON):
|
||||
continue
|
||||
|
||||
count = min(reserved, self.config.stored.TrailblazePower.FIXED_TOTAL - current)
|
||||
logger.info(f'Having {reserved} reserved, going to use {count}')
|
||||
self.set_reserved_trailblaze_power(count, total=reserved)
|
||||
# No need, amount will be set by game client
|
||||
# count = min(reserved, self.config.stored.TrailblazePower.FIXED_TOTAL - current)
|
||||
# logger.info(f'Having {reserved} reserved, going to use {count}')
|
||||
# self.set_reserved_trailblaze_power(count, total=reserved)
|
||||
|
||||
self._fuel_confirm()
|
||||
return True
|
||||
|
||||
@ -160,6 +161,7 @@ class Fuel(UI):
|
||||
|
||||
logger.info("Use Fuel")
|
||||
|
||||
STAMINA_ICON.load_search(ICON_SEARCH.area)
|
||||
timeout = Timer(1, count=3)
|
||||
has_fuel = False
|
||||
while 1:
|
||||
@ -182,7 +184,7 @@ class Fuel(UI):
|
||||
if self.appear_then_click(FUEL):
|
||||
has_fuel = True
|
||||
continue
|
||||
if not self.appear(POPUP_CONFIRM) and self.appear_then_click(FUEL_ENTRANCE):
|
||||
if not self.appear(POPUP_CONFIRM) and self.appear_then_click(STAMINA_ICON):
|
||||
continue
|
||||
|
||||
offset = FUEL_SELECTED.button_offset
|
||||
@ -215,3 +217,39 @@ class Fuel(UI):
|
||||
self.set_fuel_count(use)
|
||||
self._fuel_confirm()
|
||||
return True
|
||||
|
||||
def extract_stamina(self, update=True, use_reserved=True, use_fuel=False):
|
||||
"""
|
||||
Args:
|
||||
update:
|
||||
use_reserved:
|
||||
use_fuel:
|
||||
|
||||
Returns:
|
||||
bool: If used
|
||||
"""
|
||||
if not use_reserved and not use_fuel:
|
||||
return False
|
||||
|
||||
logger.hr('Extract stamina', level=2)
|
||||
logger.info(f'Extract stamina, reserved={use_reserved}, fuel={use_fuel}')
|
||||
if update:
|
||||
self.update_stamina_status()
|
||||
used = False
|
||||
|
||||
if use_reserved:
|
||||
if self.config.stored.Reserved.value <= 0:
|
||||
logger.info('No reserved stamina')
|
||||
else:
|
||||
self.extract_reserved_trailblaze_power()
|
||||
used = True
|
||||
self.update_stamina_status()
|
||||
self.get_interval_timer(COMBAT_AGAIN).wait()
|
||||
|
||||
if use_fuel:
|
||||
self.use_fuel(current=self.config.stored.TrailblazePower.value)
|
||||
used = True
|
||||
self.update_stamina_status()
|
||||
self.get_interval_timer(COMBAT_AGAIN).wait()
|
||||
|
||||
return used
|
||||
|
@ -1,35 +1,20 @@
|
||||
import re
|
||||
|
||||
import module.config.server as server
|
||||
from module.base.timer import Timer
|
||||
from module.base.utils import color_similar, get_color
|
||||
from module.logger import logger
|
||||
from module.ocr.ocr import Digit, DigitCounter
|
||||
from tasks.base.ui import UI
|
||||
from module.ocr.ocr import Digit
|
||||
from tasks.combat.assets.assets_combat_prepare import (
|
||||
OCR_TRAILBLAZE_POWER,
|
||||
OCR_WAVE_COST,
|
||||
OCR_WAVE_COUNT,
|
||||
WAVE_MINUS,
|
||||
WAVE_PLUS, WAVE_SLIDER
|
||||
WAVE_PLUS,
|
||||
WAVE_SLIDER
|
||||
)
|
||||
from tasks.combat.stamina_status import StaminaStatus
|
||||
from tasks.item.slider import Slider
|
||||
|
||||
|
||||
class TrailblazePowerOcr(DigitCounter):
|
||||
def after_process(self, result):
|
||||
result = super().after_process(result)
|
||||
# The trailblaze power icon is recognized as 买
|
||||
# OCR_TRAILBLAZE_POWER includes the icon because the length varies by value
|
||||
result = re.sub(r'[买米装:()]', '', result)
|
||||
# 61240 -> 6/240
|
||||
result = re.sub(r'1240$', '/240', result)
|
||||
# 0*0/24 -> 0/240
|
||||
result = re.sub(r'24$', '240', result)
|
||||
return result
|
||||
|
||||
|
||||
class CombatPrepare(UI):
|
||||
class CombatPrepare(StaminaStatus):
|
||||
# Current combat waves,
|
||||
combat_waves = 1
|
||||
# Limit combat runs, 0 means no limit.
|
||||
@ -78,20 +63,20 @@ class CombatPrepare(UI):
|
||||
else:
|
||||
self.device.screenshot()
|
||||
|
||||
current, _, total = TrailblazePowerOcr(OCR_TRAILBLAZE_POWER).ocr_single_line(self.device.image)
|
||||
# Empty result
|
||||
if total == 0:
|
||||
data = self.update_stamina_status(image=self.device.image)
|
||||
if data.stamina is None:
|
||||
continue
|
||||
# Confirm if it is > 240, sometimes just OCR errors
|
||||
if current > 240 and timeout.reached():
|
||||
# if current > 240 and timeout.reached():
|
||||
# break
|
||||
if expect_reduce and timeout.reached():
|
||||
break
|
||||
if expect_reduce and current >= before:
|
||||
if expect_reduce and data.stamina >= before:
|
||||
continue
|
||||
if current <= 240:
|
||||
if data.stamina <= 240:
|
||||
break
|
||||
|
||||
self.config.stored.TrailblazePower.value = current
|
||||
return current
|
||||
return data.stamina
|
||||
|
||||
def combat_get_wave_cost(self, skip_first_screenshot=True):
|
||||
"""
|
||||
|
161
tasks/combat/stamina_status.py
Normal file
@ -0,0 +1,161 @@
|
||||
import re
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from module.base.timer import Timer
|
||||
from module.base.utils import crop
|
||||
from module.logger import logger
|
||||
from module.ocr.ocr import Digit, DigitCounter
|
||||
from tasks.base.ui import UI
|
||||
from tasks.combat.assets.assets_combat_stamina_status import *
|
||||
|
||||
|
||||
class StaminaOcr(DigitCounter):
|
||||
def after_process(self, result):
|
||||
result = super().after_process(result)
|
||||
# The trailblaze power icon is recognized as 买
|
||||
# OCR_TRAILBLAZE_POWER includes the icon because the length varies by value
|
||||
result = re.sub(r'[买米装来:()]', '', result)
|
||||
# 61240 -> 6/240
|
||||
result = re.sub(r'1240$', '/240', result)
|
||||
# 0*0/24 -> 0/240
|
||||
result = re.sub(r'24$', '240', result)
|
||||
return result
|
||||
|
||||
|
||||
class ReservedOcr(Digit):
|
||||
pass
|
||||
|
||||
|
||||
class ImmersifierOcr(DigitCounter):
|
||||
pass
|
||||
|
||||
|
||||
class DataStaminaStatus(BaseModel):
|
||||
stamina: int | None
|
||||
reserved: int | None
|
||||
immersifier: int | None
|
||||
|
||||
|
||||
class StaminaStatus(UI):
|
||||
@staticmethod
|
||||
def get_stamina_status(image) -> DataStaminaStatus:
|
||||
"""
|
||||
Update trailblaze power, stored trailblaze power, immersifier
|
||||
|
||||
Returns:
|
||||
int: Stamina, or None if stamina not displayed or error on OCR
|
||||
int: Reserved stamina
|
||||
int: Immersifier
|
||||
"""
|
||||
for button in [STAMINA_ICON, RESERVED_ICON, IMMERSIFIER_ICON]:
|
||||
button.load_search(ICON_SEARCH.area)
|
||||
|
||||
stamina = None
|
||||
if STAMINA_ICON.match_template(image):
|
||||
STAMINA_OCR.load_offset(STAMINA_ICON)
|
||||
im = crop(image, STAMINA_OCR.button, copy=False)
|
||||
stamina, _, total = StaminaOcr(STAMINA_OCR).ocr_single_line(im, direct_ocr=True)
|
||||
if total > 240 or total == 0:
|
||||
logger.warning(f'Unexpected stamina total: {total}')
|
||||
stamina = None
|
||||
|
||||
reserved = None
|
||||
if RESERVED_ICON.match_template(image):
|
||||
RESERVED_OCR.load_offset(RESERVED_ICON)
|
||||
im = crop(image, RESERVED_OCR.button, copy=False)
|
||||
reserved = ReservedOcr(RESERVED_OCR).ocr_single_line(im, direct_ocr=True)
|
||||
if reserved > 2400:
|
||||
logger.warning(f'Unexpected reserved value: {reserved}')
|
||||
reserved = None
|
||||
|
||||
immersifier = None
|
||||
if IMMERSIFIER_ICON.match_template(image):
|
||||
IMMERSIFIER_OCR.load_offset(IMMERSIFIER_ICON)
|
||||
im = crop(image, IMMERSIFIER_OCR.button, copy=False)
|
||||
immersifier, _, total = StaminaOcr(IMMERSIFIER_OCR).ocr_single_line(im, direct_ocr=True)
|
||||
if total != 8:
|
||||
logger.warning(f'Unexpected immersifier total: {total}')
|
||||
immersifier = None
|
||||
|
||||
return DataStaminaStatus(
|
||||
stamina=stamina,
|
||||
reserved=reserved,
|
||||
immersifier=immersifier,
|
||||
)
|
||||
|
||||
def update_stamina_status(
|
||||
self,
|
||||
image=None,
|
||||
skip_first_screenshot=True,
|
||||
expect_stamina=False,
|
||||
expect_reserved=False,
|
||||
expect_immersifier=False,
|
||||
) -> DataStaminaStatus:
|
||||
"""
|
||||
Update stamina status with retry
|
||||
|
||||
Args:
|
||||
image: Detect given image only, no new screenshot will be taken
|
||||
and all expect_* are considered False
|
||||
skip_first_screenshot:
|
||||
expect_stamina:
|
||||
True to expect stamina exists, retry detect if it wasn't
|
||||
expect_reserved:
|
||||
expect_immersifier:
|
||||
|
||||
Pages:
|
||||
in: page_guild, Survival_Index, Simulated_Universe
|
||||
or page_rogue, LEVEL_CONFIRM
|
||||
or rogue, REWARD_CLOSE
|
||||
"""
|
||||
timeout = Timer(1, count=2).start()
|
||||
if image is None:
|
||||
image = self.device.image
|
||||
use_cached_image = False
|
||||
else:
|
||||
skip_first_screenshot = True
|
||||
use_cached_image = True
|
||||
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
image = self.device.image
|
||||
|
||||
# Timeout
|
||||
if timeout.reached():
|
||||
logger.warning('dungeon_update_stamina() timeout')
|
||||
return DataStaminaStatus(
|
||||
stamina=None,
|
||||
reserved=None,
|
||||
immersifier=None,
|
||||
)
|
||||
|
||||
# Ocr
|
||||
status = self.get_stamina_status(image)
|
||||
valid = True
|
||||
if expect_stamina and status.stamina is None:
|
||||
valid = False
|
||||
if expect_reserved and status.reserved is None:
|
||||
valid = False
|
||||
if expect_immersifier and status.immersifier is None:
|
||||
valid = False
|
||||
if status.stamina is None and status.reserved is None and status.immersifier is None:
|
||||
logger.warning('update_stamina_status: No icon detected')
|
||||
valid = False
|
||||
|
||||
# Write config
|
||||
with self.config.multi_set():
|
||||
if status.stamina is not None:
|
||||
self.config.stored.TrailblazePower.value = status.stamina
|
||||
if status.reserved is not None:
|
||||
self.config.stored.Reserved.value = status.reserved
|
||||
if status.immersifier is not None:
|
||||
self.config.stored.Immersifier.value = status.reserved
|
||||
|
||||
if use_cached_image or valid:
|
||||
return status
|
||||
else:
|
||||
continue
|
@ -203,6 +203,7 @@ class CombatSupport(UI):
|
||||
scroll.set_bottom(main=self)
|
||||
scroll.drag_threshold = backup
|
||||
scroll.set_top(main=self)
|
||||
self.device.click_record_clear()
|
||||
|
||||
logger.info("Searching support")
|
||||
skip_first_screenshot = True
|
||||
@ -216,9 +217,11 @@ class CombatSupport(UI):
|
||||
if character:
|
||||
logger.info("Support found")
|
||||
if self._select_support(character):
|
||||
self.device.click_record_clear()
|
||||
return True
|
||||
else:
|
||||
logger.warning("Support not selected")
|
||||
self.device.click_record_clear()
|
||||
return False
|
||||
|
||||
if not scroll.at_bottom(main=self):
|
||||
@ -226,6 +229,7 @@ class CombatSupport(UI):
|
||||
continue
|
||||
else:
|
||||
logger.info("Support not found")
|
||||
self.device.click_record_clear()
|
||||
return False
|
||||
|
||||
def _select_support(self, character: SupportCharacter):
|
||||
|
@ -41,16 +41,6 @@ AMOUNT_PLUS = ButtonWrapper(
|
||||
),
|
||||
],
|
||||
)
|
||||
ENTER_IMMERSIFIER = ButtonWrapper(
|
||||
name='ENTER_IMMERSIFIER',
|
||||
share=Button(
|
||||
file='./assets/share/dungeon/stamina/ENTER_IMMERSIFIER.png',
|
||||
area=(1047, 26, 1066, 49),
|
||||
search=(1027, 6, 1086, 69),
|
||||
color=(138, 127, 117),
|
||||
button=(1049, 26, 1151, 48),
|
||||
),
|
||||
)
|
||||
IMMERSIFIER_CHECK = ButtonWrapper(
|
||||
name='IMMERSIFIER_CHECK',
|
||||
share=Button(
|
||||
|
@ -45,13 +45,22 @@ SIMULATED_UNIVERSE_LOADED_CLASSIC = ButtonWrapper(
|
||||
)
|
||||
SURVIVAL_INDEX_OE_LOADED = ButtonWrapper(
|
||||
name='SURVIVAL_INDEX_OE_LOADED',
|
||||
share=Button(
|
||||
file='./assets/share/dungeon/ui_rogue/SURVIVAL_INDEX_OE_LOADED.png',
|
||||
area=(455, 208, 485, 338),
|
||||
search=(460, 238, 480, 268),
|
||||
color=(130, 116, 91),
|
||||
button=(455, 208, 485, 338),
|
||||
),
|
||||
share=[
|
||||
Button(
|
||||
file='./assets/share/dungeon/ui_rogue/SURVIVAL_INDEX_OE_LOADED.png',
|
||||
area=(460, 238, 480, 268),
|
||||
search=(455, 208, 485, 338),
|
||||
color=(221, 192, 131),
|
||||
button=(460, 238, 480, 268),
|
||||
),
|
||||
Button(
|
||||
file='./assets/share/dungeon/ui_rogue/SURVIVAL_INDEX_OE_LOADED.2.png',
|
||||
area=(460, 238, 480, 268),
|
||||
search=(455, 208, 485, 338),
|
||||
color=(198, 161, 100),
|
||||
button=(460, 238, 480, 268),
|
||||
),
|
||||
],
|
||||
)
|
||||
SURVIVAL_INDEX_SU_LOADED = ButtonWrapper(
|
||||
name='SURVIVAL_INDEX_SU_LOADED',
|
||||
|
@ -3,6 +3,7 @@ from module.base.timer import Timer
|
||||
from module.logger import logger
|
||||
from module.ocr.ocr import Digit
|
||||
from tasks.base.page import page_guide
|
||||
from tasks.combat.assets.assets_combat_stamina_status import ICON_SEARCH, IMMERSIFIER_ICON
|
||||
from tasks.dungeon.assets.assets_dungeon_stamina import *
|
||||
from tasks.dungeon.keywords import KEYWORDS_DUNGEON_TAB
|
||||
from tasks.dungeon.ui import DungeonUI
|
||||
@ -16,6 +17,7 @@ class DungeonStamina(DungeonUI):
|
||||
out: IMMERSIFIER_CHECK
|
||||
"""
|
||||
logger.info('Enter immersifier')
|
||||
IMMERSIFIER_ICON.load_search(ICON_SEARCH.area)
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
@ -24,7 +26,7 @@ class DungeonStamina(DungeonUI):
|
||||
|
||||
if self.appear(IMMERSIFIER_CHECK):
|
||||
break
|
||||
if self.appear_then_click(ENTER_IMMERSIFIER, interval=2):
|
||||
if self.appear_then_click(IMMERSIFIER_ICON, interval=2):
|
||||
continue
|
||||
|
||||
def _immersifier_exit(self, skip_first_screenshot=True):
|
||||
@ -140,7 +142,7 @@ class DungeonStamina(DungeonUI):
|
||||
logger.hr('Immersifier store', level=2)
|
||||
logger.info(f'Max store: {max_store}')
|
||||
self.dungeon_tab_goto(KEYWORDS_DUNGEON_TAB.Survival_Index)
|
||||
self.dungeon_update_stamina()
|
||||
self.update_stamina_status()
|
||||
before = self.config.stored.Immersifier.value
|
||||
|
||||
if self.config.stored.Immersifier.is_full():
|
||||
@ -159,7 +161,7 @@ class DungeonStamina(DungeonUI):
|
||||
self._immersifier_enter()
|
||||
self._item_amount_set(amount, ocr_button=OCR_IMMERSIFIER_AMOUNT)
|
||||
self._item_confirm()
|
||||
self.dungeon_update_stamina()
|
||||
self.update_stamina_status()
|
||||
diff = self.config.stored.Immersifier.value - before
|
||||
logger.info(f'Stored {diff} immersifiers')
|
||||
return diff
|
||||
|
@ -1,14 +1,13 @@
|
||||
from datetime import timedelta
|
||||
|
||||
from module.base.base import ModuleBase
|
||||
from module.base.timer import Timer
|
||||
from module.base.utils import crop
|
||||
from module.config.stored.classes import now
|
||||
from module.config.utils import DEFAULT_TIME, get_server_next_monday_update, get_server_next_update
|
||||
from module.logger import logger
|
||||
from module.ocr.ocr import DigitCounter
|
||||
from tasks.base.ui import UI
|
||||
from tasks.dungeon.assets.assets_dungeon_state import OCR_SIMUNI_POINT, OCR_SIMUNI_POINT_OFFSET, OCR_STAMINA
|
||||
from tasks.combat.stamina_status import StaminaStatus
|
||||
from tasks.dungeon.assets.assets_dungeon_state import OCR_SIMUNI_POINT, OCR_SIMUNI_POINT_OFFSET
|
||||
from tasks.dungeon.keywords import DungeonList
|
||||
|
||||
|
||||
@ -19,7 +18,7 @@ class OcrSimUniPoint(DigitCounter):
|
||||
return result
|
||||
|
||||
|
||||
class DungeonState(UI):
|
||||
class DungeonState(StaminaStatus):
|
||||
def dungeon_get_simuni_point(self, image=None) -> int:
|
||||
"""
|
||||
Page:
|
||||
@ -48,67 +47,6 @@ class DungeonState(UI):
|
||||
logger.warning(f'Invalid SimulatedUniverse points: {value}/{total}')
|
||||
return 0
|
||||
|
||||
def dungeon_update_stamina(self, image=None, skip_first_screenshot=True):
|
||||
"""
|
||||
Returns:
|
||||
bool: If success
|
||||
|
||||
Pages:
|
||||
in: page_guild, Survival_Index, Simulated_Universe
|
||||
or page_rogue, LEVEL_CONFIRM
|
||||
or rogue, REWARD_CLOSE
|
||||
"""
|
||||
ocr = DigitCounter(OCR_STAMINA)
|
||||
timeout = Timer(1, count=2).start()
|
||||
if image is None:
|
||||
image = self.device.image
|
||||
use_cached_image = False
|
||||
else:
|
||||
skip_first_screenshot = True
|
||||
use_cached_image = True
|
||||
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
else:
|
||||
self.device.screenshot()
|
||||
image = self.device.image
|
||||
|
||||
stamina = (0, 0, 0)
|
||||
immersifier = (0, 0, 0)
|
||||
|
||||
if timeout.reached():
|
||||
logger.warning('dungeon_update_stamina() timeout')
|
||||
return False
|
||||
|
||||
for row in ocr.detect_and_ocr(image):
|
||||
if row.ocr_text.isdigit():
|
||||
continue
|
||||
if row.ocr_text == '+':
|
||||
continue
|
||||
if not ocr.is_format_matched(row.ocr_text):
|
||||
continue
|
||||
data = ocr.format_result(row.ocr_text)
|
||||
if data[2] == self.config.stored.TrailblazePower.FIXED_TOTAL:
|
||||
stamina = data
|
||||
if data[2] == self.config.stored.Immersifier.FIXED_TOTAL:
|
||||
immersifier = data
|
||||
|
||||
if stamina[2] > 0 and immersifier[2] > 0:
|
||||
break
|
||||
if use_cached_image:
|
||||
logger.info('dungeon_update_stamina() ended')
|
||||
return
|
||||
|
||||
stamina = stamina[0]
|
||||
immersifier = immersifier[0]
|
||||
logger.attr('TrailblazePower', stamina)
|
||||
logger.attr('Imersifier', immersifier)
|
||||
with self.config.multi_set():
|
||||
self.config.stored.TrailblazePower.value = stamina
|
||||
self.config.stored.Immersifier.value = immersifier
|
||||
return True
|
||||
|
||||
def dungeon_update_simuni(self):
|
||||
"""
|
||||
Update rogue weekly points, stamina, immersifier
|
||||
@ -122,8 +60,8 @@ class DungeonState(UI):
|
||||
def func(image):
|
||||
logger.info('Update thread start')
|
||||
with self.config.multi_set():
|
||||
self.dungeon_get_simuni_point(image)
|
||||
self.dungeon_update_stamina(image)
|
||||
# self.dungeon_get_simuni_point(image)
|
||||
self.update_stamina_status(image)
|
||||
|
||||
ModuleBase.worker.submit(func, self.device.image)
|
||||
|
||||
|
@ -578,6 +578,7 @@ class DungeonUI(DungeonState):
|
||||
DUNGEON_LIST.use_plane = bool(dungeon.is_Calyx_Crimson)
|
||||
# Insight dungeon
|
||||
DUNGEON_LIST.insight_row(dungeon, main=self)
|
||||
self.device.click_record_clear()
|
||||
# Check if dungeon unlocked
|
||||
for entrance in DUNGEON_LIST.navigates:
|
||||
entrance: OcrResultButton = entrance
|
||||
@ -596,6 +597,7 @@ class DungeonUI(DungeonState):
|
||||
DUNGEON_LIST.drag_vector = (0.2, 0.4)
|
||||
DUNGEON_LIST.limit_entrance = True
|
||||
DUNGEON_LIST.insight_row(dungeon, main=self)
|
||||
self.device.click_record_clear()
|
||||
DUNGEON_LIST.drag_vector = DraggableList.drag_vector
|
||||
DUNGEON_LIST.limit_entrance = False
|
||||
DUNGEON_LIST.load_rows(main=self)
|
||||
|
@ -130,7 +130,7 @@ class OrnamentCombat(Dungeon, RouteLoader, DungeonState):
|
||||
|
||||
after = before
|
||||
for _ in range(3):
|
||||
self.dungeon_update_stamina()
|
||||
self.update_stamina_status()
|
||||
after = self.get_equivalent_stamina()
|
||||
if expect_reduce:
|
||||
if before > after:
|
||||
|
@ -261,7 +261,7 @@ class RogueEntry(RouteBase, RogueRewardHandler, RoguePathHandler, DungeonRogueUI
|
||||
if not self.image_color_count(LEVEL_CONFIRM, color=(223, 223, 225), threshold=240, count=50):
|
||||
self.interval_clear(LEVEL_CONFIRM)
|
||||
continue
|
||||
self.dungeon_update_stamina()
|
||||
self.update_stamina_status()
|
||||
self.check_stop_condition()
|
||||
self.device.click(LEVEL_CONFIRM)
|
||||
continue
|
||||
|
@ -54,7 +54,7 @@ class RogueReward(RogueUI, CombatInteract, DungeonState):
|
||||
confirm.reset()
|
||||
continue
|
||||
if self.appear(REWARD_CLOSE, interval=2):
|
||||
self.dungeon_update_stamina()
|
||||
self.update_stamina_status()
|
||||
if not init:
|
||||
initial_stamina = self.config.stored.TrailblazePower.value
|
||||
initial_immersifier = self.config.stored.Immersifier.value
|
||||
|