Add: claim immersifier rewards

This commit is contained in:
LmeSzinc 2023-10-20 17:48:22 +08:00
parent fe39645e59
commit 9a113a7b9b
21 changed files with 255 additions and 22 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -58,6 +58,7 @@
}, },
"DungeonStorage": { "DungeonStorage": {
"TrailblazePower": {}, "TrailblazePower": {},
"Immersifier": {},
"DungeonDouble": {}, "DungeonDouble": {},
"EchoOfWar": {}, "EchoOfWar": {},
"SimulatedUniverse": {} "SimulatedUniverse": {}

View File

@ -390,6 +390,12 @@
"order": 1, "order": 1,
"color": "#eb8efe" "color": "#eb8efe"
}, },
"Immersifier": {
"type": "stored",
"value": {},
"display": "hide",
"stored": "StoredImmersifier"
},
"DungeonDouble": { "DungeonDouble": {
"type": "stored", "type": "stored",
"value": {}, "value": {},

View File

@ -116,6 +116,8 @@ DungeonStorage:
stored: StoredTrailblazePower stored: StoredTrailblazePower
order: 1 order: 1
color: "#eb8efe" color: "#eb8efe"
Immersifier:
stored: StoredImmersifier
DungeonDouble: DungeonDouble:
stored: StoredDungeonDouble stored: StoredDungeonDouble
EchoOfWar: EchoOfWar:

View File

@ -101,6 +101,19 @@
"order": 8, "order": 8,
"color": "#fc8f8b" "color": "#fc8f8b"
}, },
"Immersifier": {
"name": "Immersifier",
"path": "Dungeon.DungeonStorage.Immersifier",
"i18n": "DungeonStorage.Immersifier.name",
"stored": "StoredImmersifier",
"attrs": {
"time": "2020-01-01 00:00:00",
"total": 8,
"value": 0
},
"order": 0,
"color": "#777777"
},
"DungeonDouble": { "DungeonDouble": {
"name": "DungeonDouble", "name": "DungeonDouble",
"path": "Dungeon.DungeonStorage.DungeonDouble", "path": "Dungeon.DungeonStorage.DungeonDouble",

View File

@ -57,6 +57,7 @@ class GeneratedConfig:
# Group `DungeonStorage` # Group `DungeonStorage`
DungeonStorage_TrailblazePower = {} DungeonStorage_TrailblazePower = {}
DungeonStorage_Immersifier = {}
DungeonStorage_DungeonDouble = {} DungeonStorage_DungeonDouble = {}
DungeonStorage_EchoOfWar = {} DungeonStorage_EchoOfWar = {}
DungeonStorage_SimulatedUniverse = {} DungeonStorage_SimulatedUniverse = {}

View File

@ -401,6 +401,10 @@
"name": "Power", "name": "Power",
"help": "" "help": ""
}, },
"Immersifier": {
"name": "Immersifier",
"help": ""
},
"DungeonDouble": { "DungeonDouble": {
"name": "Dungeon Double", "name": "Dungeon Double",
"help": "" "help": ""

View File

@ -401,6 +401,10 @@
"name": "Poder", "name": "Poder",
"help": "" "help": ""
}, },
"Immersifier": {
"name": "Inmersor",
"help": ""
},
"DungeonDouble": { "DungeonDouble": {
"name": "Mazmorra x2", "name": "Mazmorra x2",
"help": "" "help": ""

View File

@ -401,6 +401,10 @@
"name": "DungeonStorage.TrailblazePower.name", "name": "DungeonStorage.TrailblazePower.name",
"help": "DungeonStorage.TrailblazePower.help" "help": "DungeonStorage.TrailblazePower.help"
}, },
"Immersifier": {
"name": "DungeonStorage.Immersifier.name",
"help": "DungeonStorage.Immersifier.help"
},
"DungeonDouble": { "DungeonDouble": {
"name": "DungeonStorage.DungeonDouble.name", "name": "DungeonStorage.DungeonDouble.name",
"help": "DungeonStorage.DungeonDouble.help" "help": "DungeonStorage.DungeonDouble.help"

View File

@ -401,6 +401,10 @@
"name": "开拓力", "name": "开拓力",
"help": "" "help": ""
}, },
"Immersifier": {
"name": "沉浸器",
"help": ""
},
"DungeonDouble": { "DungeonDouble": {
"name": "副本双倍", "name": "副本双倍",
"help": "" "help": ""

View File

@ -401,6 +401,10 @@
"name": "開拓力", "name": "開拓力",
"help": "" "help": ""
}, },
"Immersifier": {
"name": "沉浸器",
"help": ""
},
"DungeonDouble": { "DungeonDouble": {
"name": "副本雙倍", "name": "副本雙倍",
"help": "" "help": ""
@ -806,20 +810,20 @@
"combat": "偏好戰鬥", "combat": "偏好戰鬥",
"occurrence": "偏好事件" "occurrence": "偏好事件"
}, },
"ImmersionReward": { "ImmersionReward": {
"name": "领取浸器奖励", "name": "領取浸器獎勵",
"help": "注意:选择 \"使用沉浸器和开拓力领取\" 时,每日副本任务不再打本,所有开拓力将优先被用于领取浸器奖励,双倍活动时除外", "help": "注意:選擇 \"使用沉浸器和開拓力領取\" 時,每日副本任務不再打本,所有開拓力將優先被用於領取浸器獎勵,雙倍活動時除外",
"do_not_claim": "不领取", "do_not_claim": "不領取",
"immersifier": "仅使用沉浸器领取", "immersifier": "只使用沉浸器領取",
"immersifier_trailblaze_power": "使用沉浸器和开拓力领取" "immersifier_trailblaze_power": "使用沉浸器和開拓力領取"
}, },
"StopCondition": { "StopCondition": {
"name": "停止条件", "name": "停止條件",
"help": "注意:\"每周100精英怪掉落奖励达到上限\" 时,模拟宇宙任务将运行数小时", "help": "注意:\"每週100精英怪掉落獎勵達到上限\" 時,模擬宇宙任務將運行數小時",
"weekly_point_reward": "每周点数奖励达到上限", "weekly_point_reward": "每週點數獎勵達到上限",
"100_elite_boss": "每周100精英怪掉落奖励达到上限", "100_elite_boss": "每週100精英怪掉落獎勵達到上限",
"non_stop": "不停止 (仅用于除錯)" "non_stop": "不停止 (只用於除錯)"
} }
}, },
"RoguePath": { "RoguePath": {
"_info": { "_info": {

View File

@ -177,6 +177,29 @@ class StoredDailyActivity(StoredCounter, StoredExpiredAt0400):
class StoredTrailblazePower(StoredCounter): class StoredTrailblazePower(StoredCounter):
FIXED_TOTAL = 240 FIXED_TOTAL = 240
def predict_current(self) -> int:
"""
Predict current stamina from records
"""
# Overflowed
value = self.value
if value >= self.FIXED_TOTAL:
return value
# Invalid time, record in the future
record = self.time
now = datetime.now()
if record >= now:
return value
# Calculate
# Recover 1 trailbaze power each 6 minutes
diff = (now - record).total_seconds()
value += int(diff // 360)
return value
class StoredImmersifier(StoredCounter):
FIXED_TOTAL = 8
class StoredSimulatedUniverse(StoredCounter, StoredExpiredAtMonday0400): class StoredSimulatedUniverse(StoredCounter, StoredExpiredAtMonday0400):
pass pass

View File

@ -10,6 +10,7 @@ from module.config.stored.classes import (
StoredEchoOfWar, StoredEchoOfWar,
StoredExpiredAt0400, StoredExpiredAt0400,
StoredExpiredAtMonday0400, StoredExpiredAtMonday0400,
StoredImmersifier,
StoredInt, StoredInt,
StoredSimulatedUniverse, StoredSimulatedUniverse,
StoredTrailblazePower, StoredTrailblazePower,
@ -21,6 +22,7 @@ from module.config.stored.classes import (
class StoredGenerated: class StoredGenerated:
TrailblazePower = StoredTrailblazePower("Dungeon.DungeonStorage.TrailblazePower") TrailblazePower = StoredTrailblazePower("Dungeon.DungeonStorage.TrailblazePower")
Immersifier = StoredImmersifier("Dungeon.DungeonStorage.Immersifier")
DungeonDouble = StoredDungeonDouble("Dungeon.DungeonStorage.DungeonDouble") DungeonDouble = StoredDungeonDouble("Dungeon.DungeonStorage.DungeonDouble")
EchoOfWar = StoredEchoOfWar("Dungeon.DungeonStorage.EchoOfWar") EchoOfWar = StoredEchoOfWar("Dungeon.DungeonStorage.EchoOfWar")
SimulatedUniverse = StoredSimulatedUniverse("Dungeon.DungeonStorage.SimulatedUniverse") SimulatedUniverse = StoredSimulatedUniverse("Dungeon.DungeonStorage.SimulatedUniverse")

View File

@ -0,0 +1,45 @@
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 ```
OCR_REMAIN = ButtonWrapper(
name='OCR_REMAIN',
share=Button(
file='./assets/share/rogue/reward/OCR_REMAIN.png',
area=(675, 11, 1181, 64),
search=(655, 0, 1201, 84),
color=(75, 89, 125),
button=(675, 11, 1181, 64),
),
)
REWARD_CLOSE = ButtonWrapper(
name='REWARD_CLOSE',
share=Button(
file='./assets/share/rogue/reward/REWARD_CLOSE.png',
area=(1043, 194, 1073, 224),
search=(1023, 174, 1093, 244),
color=(174, 175, 178),
button=(1043, 194, 1073, 224),
),
)
USE_IMMERSIFIER = ButtonWrapper(
name='USE_IMMERSIFIER',
share=Button(
file='./assets/share/rogue/reward/USE_IMMERSIFIER.png',
area=(713, 509, 737, 523),
search=(693, 489, 757, 543),
color=(189, 189, 189),
button=(684, 499, 963, 535),
),
)
USE_STAMINA = ButtonWrapper(
name='USE_STAMINA',
share=Button(
file='./assets/share/rogue/reward/USE_STAMINA.png',
area=(345, 509, 378, 524),
search=(325, 489, 398, 544),
color=(172, 172, 172),
button=(319, 499, 595, 535),
),
)

117
tasks/rogue/event/reward.py Normal file
View File

@ -0,0 +1,117 @@
from module.base.timer import Timer
from module.logger import logger
from module.ocr.ocr import DigitCounter
from tasks.base.assets.assets_base_popup import GET_REWARD
from tasks.combat.interact import CombatInteract
from tasks.rogue.assets.assets_rogue_reward import OCR_REMAIN, REWARD_CLOSE, USE_IMMERSIFIER, USE_STAMINA
from tasks.rogue.bleesing.ui import RogueUI
class RogueReward(RogueUI, CombatInteract):
def _reward_update_stamina(self, skip_first_screenshot=True):
ocr = DigitCounter(OCR_REMAIN)
timeout = Timer(1, count=2).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
stamina = (0, 0, 0)
immersifier = (0, 0, 0)
if timeout.reached():
logger.warning('_reward_update_stamina() timeout')
break
for row in ocr.detect_and_ocr(self.device.image):
if row.ocr_text.isdigit():
continue
if 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
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
def claim_domain_reward(
self,
use_trailblaze_power=False,
use_immersifier=True,
skip_first_screenshot=True
):
"""
Pages:
in: page_main, DUNGEON_COMBAT_INTERACT, near immersifier
"""
logger.hr('Claim domain reward', level=2)
logger.info(f'use_trailblaze_power={use_trailblaze_power}, use_immersifier={use_immersifier}')
if not use_trailblaze_power and not use_immersifier:
return
confirm = Timer(0.6, count=2).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
self.device.screenshot()
if self.is_in_main():
if confirm.reached():
break
else:
confirm.reset()
if self.handle_combat_interact():
self.interval_clear(USE_STAMINA)
confirm.reset()
continue
if self.handle_reward():
self.interval_clear(USE_STAMINA)
confirm.reset()
continue
if self.appear(REWARD_CLOSE, interval=2):
self._reward_update_stamina()
if use_immersifier and self.config.stored.Immersifier.value > 0:
self.device.click(USE_IMMERSIFIER)
self.interval_reset(USE_STAMINA)
self.interval_clear(GET_REWARD)
confirm.reset()
continue
elif use_trailblaze_power and self.config.stored.TrailblazePower.value >= 40:
self.device.click(USE_STAMINA)
self.interval_reset(USE_STAMINA)
self.interval_clear(GET_REWARD)
confirm.reset()
continue
else:
logger.info('Cannot claim more rewards')
self.device.click(REWARD_CLOSE)
self.interval_reset(USE_STAMINA)
confirm.reset()
continue
def can_claim_domain_reward(
self,
use_trailblaze_power=False,
use_immersifier=True
):
if not use_trailblaze_power and not use_immersifier:
return False
if use_immersifier and self.config.stored.Immersifier.value >= 0:
return True
if use_trailblaze_power and self.config.stored.TrailblazePower.predict_current() >= 40:
return True
return False

View File

@ -11,10 +11,11 @@ from tasks.rogue.bleesing.blessing import RogueBlessingSelector
from tasks.rogue.bleesing.bonus import RogueBonusSelector from tasks.rogue.bleesing.bonus import RogueBonusSelector
from tasks.rogue.bleesing.curio import RogueCurioSelector from tasks.rogue.bleesing.curio import RogueCurioSelector
from tasks.rogue.event.event import RogueEvent from tasks.rogue.event.event import RogueEvent
from tasks.rogue.event.reward import RogueReward
from tasks.rogue.route.exit import RogueExit from tasks.rogue.route.exit import RogueExit
class RouteBase(RouteBase_, RogueExit, RogueEvent): class RouteBase(RouteBase_, RogueExit, RogueEvent, RogueReward):
registered_domain_exit = None registered_domain_exit = None
def combat_expected_end(self): def combat_expected_end(self):
@ -174,14 +175,16 @@ class RouteBase(RouteBase_, RogueExit, RogueEvent):
Get reward of the DomainElite and DomainBoss Get reward of the DomainElite and DomainBoss
""" """
logger.hr('Clear reward', level=1) logger.hr('Clear reward', level=1)
use_trailblaze_power = 'trailblaze' in self.config.RogueWorld_ImmersionReward
use_immersifier = 'immersifier' in self.config.RogueWorld_ImmersionReward
# TODO: Skip if user don't want rewards or stamina exhausted if self.can_claim_domain_reward(use_trailblaze_power=use_trailblaze_power, use_immersifier=use_immersifier):
return [] logger.info('Can claim domain reward')
result = self.goto(*waypoints)
result = self.goto(*waypoints) self.claim_domain_reward(use_trailblaze_power=use_trailblaze_power, use_immersifier=use_immersifier)
else:
# TODO: Get reward logger.info('Cannot claim more rewards')
pass result = []
return result return result