Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 7.9 KiB |
BIN
assets/cn/base/page/ASSIGNMENT_CHECK.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
assets/en/base/page/ASSIGNMENT_CHECK.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
BIN
assets/share/freebies/support_reward/REWARD_POPUP.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
assets/share/rogue/path/PATH_LOADED_CHECK.png
Normal file
After Width: | Height: | Size: 13 KiB |
@ -34,6 +34,23 @@ class Button(Resource):
|
||||
def clear_offset(self):
|
||||
self._button_offset = (0, 0)
|
||||
|
||||
def is_offset_in(self, x=0, y=0):
|
||||
"""
|
||||
Args:
|
||||
x:
|
||||
y:
|
||||
|
||||
Returns:
|
||||
bool: If _button_offset is in (-x, -y, x, y)
|
||||
"""
|
||||
if x:
|
||||
if self._button_offset[0] < -x or self._button_offset[0] > x:
|
||||
return False
|
||||
if y:
|
||||
if self._button_offset[1] < -y or self._button_offset[1] > y:
|
||||
return False
|
||||
return True
|
||||
|
||||
@cached_property
|
||||
def image(self):
|
||||
return load_image(self.file, self.area)
|
||||
@ -295,6 +312,17 @@ class ButtonWrapper(Resource):
|
||||
for b in self.iter_buttons():
|
||||
b.clear_offset()
|
||||
|
||||
def is_offset_in(self, x=0, y=0):
|
||||
"""
|
||||
Args:
|
||||
x:
|
||||
y:
|
||||
|
||||
Returns:
|
||||
bool: If _button_offset is in (-x, -y, x, y)
|
||||
"""
|
||||
return self.matched_button.is_offset_in(x=x, y=y)
|
||||
|
||||
def load_search(self, area):
|
||||
"""
|
||||
Set `search` attribute.
|
||||
|
@ -105,6 +105,51 @@ class Route(RouteBase):
|
||||
if self.minimap.position_diff(enemy3.position) > 25:
|
||||
self.clear_enemy(enemy3)
|
||||
|
||||
def Luofu_ArtisanshipCommission_F1_X481Y920(self):
|
||||
"""
|
||||
| Waypoint | Position | Direction | Rotation |
|
||||
| ----------- | ------------------------- | --------- | -------- |
|
||||
| spawn | Waypoint((473.5, 920.9)), | 4.5 | 4 |
|
||||
| enemy1left | Waypoint((475.0, 848.4)), | 4.4 | 4 |
|
||||
| enemy2right | Waypoint((493.5, 807.4)), | 157.1 | 48 |
|
||||
| enemy3 | Waypoint((528.9, 782.9)), | 198.5 | 91 |
|
||||
| exit_ | Waypoint((528.9, 782.9)), | 198.5 | 91 |
|
||||
| exit1 | Waypoint((537.0, 773.2)), | 99.0 | 89 |
|
||||
| exit2 | Waypoint((537.5, 790.6)), | 101.1 | 91 |
|
||||
"""
|
||||
self.map_init(plane=Luofu_ArtisanshipCommission, floor="F1", position=(481.5, 920.9))
|
||||
self.register_domain_exit(
|
||||
Waypoint((528.9, 782.9)), end_rotation=91,
|
||||
left_door=Waypoint((537.0, 773.2)), right_door=Waypoint((537.5, 790.6)))
|
||||
enemy1left = Waypoint((475.0, 848.4))
|
||||
enemy2right = Waypoint((493.5, 807.4))
|
||||
enemy3 = Waypoint((528.9, 782.9))
|
||||
# ===== End of generated waypoints =====
|
||||
|
||||
self.rotation_set(30)
|
||||
self.clear_enemy(
|
||||
enemy1left,
|
||||
enemy2right,
|
||||
)
|
||||
self.clear_enemy(enemy3)
|
||||
if self.minimap.position_diff(enemy3.position) > 25:
|
||||
self.clear_enemy(enemy3)
|
||||
|
||||
"""
|
||||
Notes
|
||||
Luofu_ArtisanshipCommission_F1_X481Y920 is the same as Luofu_ArtisanshipCommission_F1_X473Y920
|
||||
but for wrong spawn point detected
|
||||
"""
|
||||
# Best 3 predictions: [
|
||||
# ('Combat_Luofu_ArtisanshipCommission_F1_X473Y920', 0.168, (481.0, 920.9)),
|
||||
# ('Combat_Luofu_ArtisanshipCommission_F1_X41Y640', 0.163, (40.8, 664.0)),
|
||||
# ('Combat_Luofu_ArtisanshipCommission_F1_X667Y189', 0.14, (705.0, 193.3))
|
||||
# ]
|
||||
# Best 3 nearby predictions: [
|
||||
# ('Combat_Herta_SupplyZone_F2_X45Y369', 0.128, (47.6, 369.4)),
|
||||
# ('Combat_Herta_SupplyZone_F2Rogue_X219Y112', 0.093, (219.6, 108.7))
|
||||
# ]
|
||||
|
||||
def Luofu_ArtisanshipCommission_F1_X543Y269(self):
|
||||
"""
|
||||
| Waypoint | Position | Direction | Rotation |
|
||||
|
@ -769,6 +769,17 @@
|
||||
],
|
||||
"domain": "Combat"
|
||||
},
|
||||
{
|
||||
"name": "Combat_Luofu_ArtisanshipCommission_F1_X481Y920",
|
||||
"route": "route.rogue.Combat.Luofu_ArtisanshipCommission_F1:Luofu_ArtisanshipCommission_F1_X481Y920",
|
||||
"plane": "Luofu_ArtisanshipCommission",
|
||||
"floor": "F1",
|
||||
"position": [
|
||||
481.5,
|
||||
920.9
|
||||
],
|
||||
"domain": "Combat"
|
||||
},
|
||||
{
|
||||
"name": "Combat_Luofu_ArtisanshipCommission_F1_X543Y269",
|
||||
"route": "route.rogue.Combat.Luofu_ArtisanshipCommission_F1:Luofu_ArtisanshipCommission_F1_X543Y269",
|
||||
|
@ -7,10 +7,10 @@ CHARACTER_MATERIALS_CHECK = ButtonWrapper(
|
||||
name='CHARACTER_MATERIALS_CHECK',
|
||||
cn=Button(
|
||||
file='./assets/cn/assignment/ui/CHARACTER_MATERIALS_CHECK.png',
|
||||
area=(346, 97, 421, 117),
|
||||
search=(326, 77, 441, 137),
|
||||
color=(177, 176, 173),
|
||||
button=(346, 97, 421, 117),
|
||||
area=(190, 98, 265, 120),
|
||||
search=(170, 78, 285, 140),
|
||||
color=(195, 194, 191),
|
||||
button=(190, 98, 265, 120),
|
||||
),
|
||||
en=[
|
||||
Button(
|
||||
@ -33,10 +33,10 @@ CHARACTER_MATERIALS_CLICK = ButtonWrapper(
|
||||
name='CHARACTER_MATERIALS_CLICK',
|
||||
cn=Button(
|
||||
file='./assets/cn/assignment/ui/CHARACTER_MATERIALS_CLICK.png',
|
||||
area=(347, 97, 421, 117),
|
||||
search=(327, 77, 441, 137),
|
||||
color=(60, 60, 60),
|
||||
button=(347, 97, 421, 117),
|
||||
area=(190, 98, 265, 119),
|
||||
search=(170, 78, 285, 139),
|
||||
color=(64, 63, 61),
|
||||
button=(190, 98, 265, 119),
|
||||
),
|
||||
en=[
|
||||
Button(
|
||||
@ -86,10 +86,10 @@ EXP_MATERIALS_CREDITS_CHECK = ButtonWrapper(
|
||||
name='EXP_MATERIALS_CREDITS_CHECK',
|
||||
cn=Button(
|
||||
file='./assets/cn/assignment/ui/EXP_MATERIALS_CREDITS_CHECK.png',
|
||||
area=(514, 97, 614, 117),
|
||||
search=(494, 77, 634, 137),
|
||||
color=(178, 177, 174),
|
||||
button=(514, 97, 614, 117),
|
||||
area=(420, 100, 518, 118),
|
||||
search=(400, 80, 538, 138),
|
||||
color=(170, 169, 166),
|
||||
button=(420, 100, 518, 118),
|
||||
),
|
||||
en=[
|
||||
Button(
|
||||
@ -112,10 +112,10 @@ EXP_MATERIALS_CREDITS_CLICK = ButtonWrapper(
|
||||
name='EXP_MATERIALS_CREDITS_CLICK',
|
||||
cn=Button(
|
||||
file='./assets/cn/assignment/ui/EXP_MATERIALS_CREDITS_CLICK.png',
|
||||
area=(514, 97, 614, 117),
|
||||
search=(494, 77, 634, 137),
|
||||
color=(61, 60, 60),
|
||||
button=(514, 97, 614, 117),
|
||||
area=(420, 100, 518, 118),
|
||||
search=(400, 80, 538, 138),
|
||||
color=(64, 65, 64),
|
||||
button=(420, 100, 518, 118),
|
||||
),
|
||||
en=[
|
||||
Button(
|
||||
@ -229,10 +229,10 @@ SYNTHESIS_MATERIALS_CHECK = ButtonWrapper(
|
||||
name='SYNTHESIS_MATERIALS_CHECK',
|
||||
cn=Button(
|
||||
file='./assets/cn/assignment/ui/SYNTHESIS_MATERIALS_CHECK.png',
|
||||
area=(708, 97, 783, 117),
|
||||
search=(688, 77, 803, 137),
|
||||
color=(180, 179, 176),
|
||||
button=(708, 97, 783, 117),
|
||||
area=(676, 98, 749, 119),
|
||||
search=(656, 78, 769, 139),
|
||||
color=(182, 181, 178),
|
||||
button=(676, 98, 749, 119),
|
||||
),
|
||||
en=[
|
||||
Button(
|
||||
@ -255,10 +255,10 @@ SYNTHESIS_MATERIALS_CLICK = ButtonWrapper(
|
||||
name='SYNTHESIS_MATERIALS_CLICK',
|
||||
cn=Button(
|
||||
file='./assets/cn/assignment/ui/SYNTHESIS_MATERIALS_CLICK.png',
|
||||
area=(709, 97, 783, 117),
|
||||
search=(689, 77, 803, 137),
|
||||
color=(68, 66, 65),
|
||||
button=(709, 97, 783, 117),
|
||||
area=(676, 99, 749, 119),
|
||||
search=(656, 79, 769, 139),
|
||||
color=(57, 58, 57),
|
||||
button=(676, 99, 749, 119),
|
||||
),
|
||||
en=[
|
||||
Button(
|
||||
|
@ -19,6 +19,16 @@ class AssignmentEntry(Keyword):
|
||||
def __hash__(self) -> int:
|
||||
return super().__hash__()
|
||||
|
||||
@classmethod
|
||||
def _compare(cls, name, keyword):
|
||||
# 2024.05.08 Assignment names are omitted in EN
|
||||
if name == keyword:
|
||||
return True
|
||||
# namelesslandnameless.. Nameless Land, Nameless People
|
||||
if name[:17] == keyword[:17]:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class AssignmentEntryDetailed(Keyword):
|
||||
|
@ -5,12 +5,19 @@ from module.base.button import Button, ButtonWrapper
|
||||
|
||||
ASSIGNMENT_CHECK = ButtonWrapper(
|
||||
name='ASSIGNMENT_CHECK',
|
||||
share=Button(
|
||||
file='./assets/share/base/page/ASSIGNMENT_CHECK.png',
|
||||
area=(45, 21, 70, 53),
|
||||
search=(25, 1, 90, 73),
|
||||
color=(162, 145, 112),
|
||||
button=(45, 21, 70, 53),
|
||||
cn=Button(
|
||||
file='./assets/cn/base/page/ASSIGNMENT_CHECK.png',
|
||||
area=(535, 165, 587, 181),
|
||||
search=(515, 145, 607, 201),
|
||||
color=(207, 199, 181),
|
||||
button=(535, 165, 587, 181),
|
||||
),
|
||||
en=Button(
|
||||
file='./assets/en/base/page/ASSIGNMENT_CHECK.png',
|
||||
area=(535, 165, 581, 180),
|
||||
search=(515, 145, 601, 200),
|
||||
color=(204, 195, 176),
|
||||
button=(535, 165, 581, 180),
|
||||
),
|
||||
)
|
||||
BACK = ButtonWrapper(
|
||||
|
@ -9,6 +9,7 @@ DICT_SORTED_RANGES = {
|
||||
RuanMei,
|
||||
DanHengImbibitorLunae,
|
||||
Welt,
|
||||
Aventurine,
|
||||
FuXuan,
|
||||
# Longer precast
|
||||
BlackSwan,
|
||||
|
@ -32,6 +32,7 @@ class CharacterSwitch(UI):
|
||||
characters: list[CharacterList] = []
|
||||
character_current: CharacterList | None = None
|
||||
character_buttons: list[OcrResultButton] = []
|
||||
character_is_ranged: t.Optional[bool] = None
|
||||
|
||||
def character_update(self, skip_first_screenshot=True) -> list[CharacterList]:
|
||||
"""
|
||||
@ -187,7 +188,7 @@ class CharacterSwitch(UI):
|
||||
skip_first_screenshot:
|
||||
|
||||
Returns:
|
||||
bool: If chose
|
||||
bool: If chose success
|
||||
"""
|
||||
logger.info(f'Character choose: {character}')
|
||||
if isinstance(character, int):
|
||||
@ -220,8 +221,12 @@ class CharacterSwitch(UI):
|
||||
# End
|
||||
selected = self._update_current_character()
|
||||
if index in selected:
|
||||
logger.info('Character chose')
|
||||
return True
|
||||
if len(selected) > 1:
|
||||
logger.warning('Multiple selected characters found, cannot guarantee character selected')
|
||||
return False
|
||||
else:
|
||||
logger.info('Character chose')
|
||||
return True
|
||||
if count > 3:
|
||||
logger.warning('Failed to choose character, assume chose')
|
||||
return False
|
||||
@ -255,22 +260,35 @@ class CharacterSwitch(UI):
|
||||
logger.info('No ranged characters in team')
|
||||
return False
|
||||
|
||||
def character_switch_to_ranged(self, update=True) -> bool:
|
||||
def character_switch_to_ranged(self, update=True) -> bool | None:
|
||||
"""
|
||||
Args:
|
||||
update: If update characters before switching
|
||||
|
||||
Returns:
|
||||
bool: If using a ranged character now
|
||||
or None if failed to switch
|
||||
"""
|
||||
if self.character_is_ranged is not None:
|
||||
return self.character_is_ranged
|
||||
|
||||
logger.hr('Character switch to ranged')
|
||||
if update:
|
||||
self.character_update()
|
||||
|
||||
character = self._get_ranged_character()
|
||||
if character is True:
|
||||
self.character_is_ranged = True
|
||||
return True
|
||||
elif character is False:
|
||||
self.character_is_ranged = False
|
||||
return False
|
||||
|
||||
success = self.character_switch(character)
|
||||
if success:
|
||||
self.character_is_ranged = True
|
||||
return True
|
||||
else:
|
||||
return self.character_switch(character)
|
||||
# Cannot switch, keep None to retry at next call
|
||||
self.character_is_ranged = None
|
||||
return None
|
||||
|
@ -7,20 +7,20 @@ CAN_GET_REWARD = ButtonWrapper(
|
||||
name='CAN_GET_REWARD',
|
||||
share=Button(
|
||||
file='./assets/share/freebies/support_reward/CAN_GET_REWARD.png',
|
||||
area=(1066, 121, 1097, 144),
|
||||
search=(1046, 101, 1117, 164),
|
||||
color=(245, 225, 170),
|
||||
button=(1066, 121, 1097, 144),
|
||||
area=(1092, 181, 1123, 204),
|
||||
search=(1072, 161, 1143, 224),
|
||||
color=(246, 227, 173),
|
||||
button=(1092, 181, 1123, 204),
|
||||
),
|
||||
)
|
||||
IN_PROFILE = ButtonWrapper(
|
||||
name='IN_PROFILE',
|
||||
share=Button(
|
||||
file='./assets/share/freebies/support_reward/IN_PROFILE.png',
|
||||
area=(647, 128, 673, 146),
|
||||
search=(627, 108, 693, 166),
|
||||
area=(640, 155, 666, 173),
|
||||
search=(620, 135, 686, 193),
|
||||
color=(109, 97, 83),
|
||||
button=(647, 128, 673, 146),
|
||||
button=(640, 155, 666, 173),
|
||||
),
|
||||
)
|
||||
MENU_TO_PROFILE = ButtonWrapper(
|
||||
@ -50,3 +50,13 @@ PROFILE = ButtonWrapper(
|
||||
button=(907, 102, 1092, 132),
|
||||
),
|
||||
)
|
||||
REWARD_POPUP = ButtonWrapper(
|
||||
name='REWARD_POPUP',
|
||||
share=Button(
|
||||
file='./assets/share/freebies/support_reward/REWARD_POPUP.png',
|
||||
area=(883, 552, 914, 580),
|
||||
search=(863, 532, 934, 600),
|
||||
color=(88, 89, 114),
|
||||
button=(883, 552, 914, 580),
|
||||
),
|
||||
)
|
||||
|
@ -1,13 +1,14 @@
|
||||
from module.base.timer import Timer
|
||||
from module.logger import logger
|
||||
from tasks.base.assets.assets_base_page import MENU_CHECK
|
||||
from tasks.base.assets.assets_base_page import CLOSE, MENU_CHECK
|
||||
from tasks.base.page import page_menu
|
||||
from tasks.base.ui import UI
|
||||
from tasks.freebies.assets.assets_freebies_support_reward import (
|
||||
CAN_GET_REWARD,
|
||||
IN_PROFILE,
|
||||
MENU_TO_PROFILE,
|
||||
PROFILE
|
||||
PROFILE,
|
||||
REWARD_POPUP,
|
||||
)
|
||||
|
||||
|
||||
@ -70,6 +71,9 @@ class SupportReward(UI):
|
||||
if self.reward_appear():
|
||||
logger.info('Got reward')
|
||||
break
|
||||
if self.appear(REWARD_POPUP):
|
||||
logger.info('Got reward popup')
|
||||
break
|
||||
if timeout.reached():
|
||||
logger.warning('Get support reward timeout')
|
||||
break
|
||||
@ -96,10 +100,14 @@ class SupportReward(UI):
|
||||
if self.appear(MENU_CHECK):
|
||||
return True
|
||||
|
||||
if self.appear_then_click(REWARD_POPUP, interval=2):
|
||||
logger.info(f'{REWARD_POPUP} - {CLOSE}')
|
||||
self.device.click(CLOSE)
|
||||
continue
|
||||
if self.handle_ui_close(IN_PROFILE, interval=2):
|
||||
continue
|
||||
if self.handle_reward(click_button=CAN_GET_REWARD):
|
||||
# # Avoid clicking on some other buttons
|
||||
# Avoid clicking on some other buttons
|
||||
continue
|
||||
|
||||
|
||||
|
@ -238,3 +238,13 @@ PAGE_ROGUE_PATH = ButtonWrapper(
|
||||
button=(606, 89, 656, 108),
|
||||
),
|
||||
)
|
||||
PATH_LOADED_CHECK = ButtonWrapper(
|
||||
name='PATH_LOADED_CHECK',
|
||||
share=Button(
|
||||
file='./assets/share/rogue/path/PATH_LOADED_CHECK.png',
|
||||
area=(989, 18, 1175, 59),
|
||||
search=(969, 0, 1195, 79),
|
||||
color=(45, 45, 47),
|
||||
button=(989, 18, 1175, 59),
|
||||
),
|
||||
)
|
||||
|
@ -4,8 +4,8 @@ from module.base.utils import area_offset
|
||||
from module.logger import logger
|
||||
from module.ocr.ocr import Digit, Ocr, OcrResultButton
|
||||
from tasks.base.ui import UI
|
||||
from tasks.rogue.assets.assets_rogue_weekly import REWARD_ENTER
|
||||
from tasks.rogue.assets.assets_rogue_ui import *
|
||||
from tasks.rogue.assets.assets_rogue_weekly import REWARD_ENTER
|
||||
from tasks.rogue.keywords import RoguePath
|
||||
|
||||
|
||||
|
@ -250,6 +250,9 @@ class RogueEntry(RouteBase, RogueRewardHandler, RoguePathHandler, DungeonUI):
|
||||
self.interval_reset(REWARD_ENTER, interval=2)
|
||||
continue
|
||||
if self.match_template_color(LEVEL_CONFIRM, interval=2):
|
||||
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.check_stop_condition()
|
||||
self.device.click(LEVEL_CONFIRM)
|
||||
|
@ -206,6 +206,9 @@ class RoguePathHandler(RogueUI):
|
||||
break
|
||||
|
||||
if self.match_template_color(ROGUE_LAUNCH, interval=2):
|
||||
if not self.image_color_count(ROGUE_LAUNCH, color=(223, 223, 225), threshold=240, count=50):
|
||||
self.interval_clear(ROGUE_LAUNCH)
|
||||
continue
|
||||
if not self._is_team_prepared():
|
||||
raise RogueTeamNotPrepared
|
||||
self.device.click(ROGUE_LAUNCH)
|
||||
@ -216,11 +219,19 @@ class RoguePathHandler(RogueUI):
|
||||
continue
|
||||
# Select path
|
||||
if self.interval_is_reached(entry, interval=2) and self._is_page_rogue_path():
|
||||
if self.appear_then_click(entry, interval=2):
|
||||
if not self.image_color_count(PATH_LOADED_CHECK, color=(246, 246, 246), threshold=240, count=50):
|
||||
self.interval_clear(entry)
|
||||
continue
|
||||
if self.appear(entry):
|
||||
self.device.click(entry)
|
||||
self.interval_reset(entry, interval=2)
|
||||
continue
|
||||
# Confirm path
|
||||
if self.appear(CONFIRM_PATH, interval=2):
|
||||
if not self.image_color_count(CONFIRM_PATH, color=(223, 223, 225), threshold=240, count=50):
|
||||
self.interval_clear(CONFIRM_PATH)
|
||||
continue
|
||||
if self._change_confirm_path(path):
|
||||
self.device.click(CONFIRM_PATH)
|
||||
self.interval_reset(CONFIRM_PATH)
|
||||
continue
|
||||
|
@ -285,6 +285,7 @@ class RouteLoader(RogueUI, MinimapWrapper, RouteLoader_, CharacterSwitch):
|
||||
"""
|
||||
base = RouteBase(config=self.config, device=self.device, task=self.config.task.command)
|
||||
count = 1
|
||||
self.character_is_ranged = None
|
||||
while 1:
|
||||
if skip_first_screenshot:
|
||||
skip_first_screenshot = False
|
||||
@ -293,8 +294,7 @@ class RouteLoader(RogueUI, MinimapWrapper, RouteLoader_, CharacterSwitch):
|
||||
|
||||
logger.hr(f'Route run: {count}', level=1)
|
||||
base.clear_blessing()
|
||||
if count == 1:
|
||||
self.character_switch_to_ranged(update=True)
|
||||
self.character_switch_to_ranged(update=True)
|
||||
|
||||
self.route_run()
|
||||
# if not success:
|
||||
|