mirror of
https://github.com/TheFunny/ArisuAutoSweeper
synced 2026-06-09 20:04:52 +00:00
Added Tasks, Shop, MomoTalk (#11)
* feat: tasks Added module tasks for EN * refactor: gui added tree view Farm and Reward. * feat: shop * feat: momotalk --------- Co-authored-by: YoursFunny <admin@yoursfunny.top>
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
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 ```
|
||||
|
||||
CONFIRM_PURCHASE = ButtonWrapper(
|
||||
name='CONFIRM_PURCHASE',
|
||||
jp=None,
|
||||
en=Button(
|
||||
file='./assets/en/shop/CONFIRM_PURCHASE.png',
|
||||
area=(467, 231, 807, 309),
|
||||
search=(447, 211, 827, 329),
|
||||
color=(217, 218, 219),
|
||||
button=(668, 458, 865, 514),
|
||||
),
|
||||
)
|
||||
CONFIRM_REFRESH = ButtonWrapper(
|
||||
name='CONFIRM_REFRESH',
|
||||
jp=None,
|
||||
en=Button(
|
||||
file='./assets/en/shop/CONFIRM_REFRESH.png',
|
||||
area=(474, 271, 806, 306),
|
||||
search=(454, 251, 826, 326),
|
||||
color=(202, 203, 204),
|
||||
button=(675, 434, 863, 500),
|
||||
),
|
||||
)
|
||||
ITEM_LIST = ButtonWrapper(
|
||||
name='ITEM_LIST',
|
||||
jp=None,
|
||||
en=Button(
|
||||
file='./assets/en/shop/ITEM_LIST.png',
|
||||
area=(625, 127, 1244, 610),
|
||||
search=(605, 107, 1264, 630),
|
||||
color=(193, 206, 213),
|
||||
button=(625, 127, 1244, 610),
|
||||
),
|
||||
)
|
||||
NORMAL_OFF = ButtonWrapper(
|
||||
name='NORMAL_OFF',
|
||||
jp=None,
|
||||
en=Button(
|
||||
file='./assets/en/shop/NORMAL_OFF.png',
|
||||
area=(4, 111, 213, 167),
|
||||
search=(0, 91, 233, 187),
|
||||
color=(248, 248, 245),
|
||||
button=(4, 111, 213, 167),
|
||||
),
|
||||
)
|
||||
NORMAL_ON = ButtonWrapper(
|
||||
name='NORMAL_ON',
|
||||
jp=None,
|
||||
en=Button(
|
||||
file='./assets/en/shop/NORMAL_ON.png',
|
||||
area=(4, 109, 212, 170),
|
||||
search=(0, 89, 232, 190),
|
||||
color=(57, 78, 96),
|
||||
button=(4, 109, 212, 170),
|
||||
),
|
||||
)
|
||||
OCR_REFRESH = ButtonWrapper(
|
||||
name='OCR_REFRESH',
|
||||
jp=None,
|
||||
en=Button(
|
||||
file='./assets/en/shop/OCR_REFRESH.png',
|
||||
area=(712, 302, 762, 344),
|
||||
search=(692, 282, 782, 364),
|
||||
color=(225, 225, 226),
|
||||
button=(712, 302, 762, 344),
|
||||
),
|
||||
)
|
||||
PURCHASE = ButtonWrapper(
|
||||
name='PURCHASE',
|
||||
jp=None,
|
||||
en=Button(
|
||||
file='./assets/en/shop/PURCHASE.png',
|
||||
area=(1102, 640, 1227, 684),
|
||||
search=(1082, 620, 1247, 704),
|
||||
color=(226, 206, 65),
|
||||
button=(1102, 640, 1227, 684),
|
||||
),
|
||||
)
|
||||
REFRESH = ButtonWrapper(
|
||||
name='REFRESH',
|
||||
jp=None,
|
||||
en=Button(
|
||||
file='./assets/en/shop/REFRESH.png',
|
||||
area=(1098, 643, 1223, 682),
|
||||
search=(1078, 623, 1243, 702),
|
||||
color=(231, 234, 237),
|
||||
button=(1098, 643, 1223, 682),
|
||||
),
|
||||
)
|
||||
TC_OFF = ButtonWrapper(
|
||||
name='TC_OFF',
|
||||
jp=None,
|
||||
en=Button(
|
||||
file='./assets/en/shop/TC_OFF.png',
|
||||
area=(2, 503, 209, 558),
|
||||
search=(0, 483, 229, 578),
|
||||
color=(239, 242, 244),
|
||||
button=(2, 503, 209, 558),
|
||||
),
|
||||
)
|
||||
TC_ON = ButtonWrapper(
|
||||
name='TC_ON',
|
||||
jp=None,
|
||||
en=Button(
|
||||
file='./assets/en/shop/TC_ON.png',
|
||||
area=(3, 493, 208, 548),
|
||||
search=(0, 473, 228, 568),
|
||||
color=(62, 84, 99),
|
||||
button=(3, 493, 208, 548),
|
||||
),
|
||||
)
|
||||
@@ -0,0 +1,118 @@
|
||||
from enum import Flag
|
||||
|
||||
from module.base.timer import Timer
|
||||
from module.exception import RequestHumanTakeover
|
||||
from module.logger import logger
|
||||
from module.ui.switch import Switch
|
||||
from tasks.base.assets.assets_base_page import BACK
|
||||
from tasks.base.page import page_main, page_shop
|
||||
from tasks.shop.assets.assets_shop import *
|
||||
from tasks.shop.ui import ShopUI
|
||||
|
||||
|
||||
class ShopStatus(Flag):
|
||||
SELECT_SHOP = 0
|
||||
SELECT_ITEMS = 1
|
||||
PURCHASE = 2
|
||||
REFRESH = 3
|
||||
END = 4
|
||||
FINISH = -1
|
||||
|
||||
class Shop(ShopUI):
|
||||
@property
|
||||
def shop_info(self):
|
||||
"""Similiar to bounty_info and scrimmage_info.
|
||||
Returns a list with elements the select button, check button, how many times do make purchases and the list of items"""
|
||||
info = []
|
||||
if self.config.NormalShop_Enable:
|
||||
normal_config = self.config.cross_get(["Shop", "NormalShop"])
|
||||
normal_items = [num for num in range(1, 21) if normal_config[str(num)]]
|
||||
if normal_items:
|
||||
SWITCH_NORMAL = Switch('NormalShop_Switch')
|
||||
SWITCH_NORMAL.add_state('on', NORMAL_ON)
|
||||
SWITCH_NORMAL.add_state('off', NORMAL_OFF)
|
||||
info.append([SWITCH_NORMAL, self.config.NormalShop_Purchases, normal_items])
|
||||
|
||||
if self.config.TacticalChallengeShop_Enable:
|
||||
tc_config = self.config.cross_get(["Shop", "TacticalChallengeShop"])
|
||||
tc_items = [num for num in range(1, 16) if tc_config[str(num)]]
|
||||
if tc_items:
|
||||
SWITCH_TC = Switch('TacticalChallengeShop_Switch')
|
||||
SWITCH_TC.add_state('on', TC_ON)
|
||||
SWITCH_TC.add_state('off', TC_OFF)
|
||||
info.append([SWITCH_TC, self.config.TacticalChallengeShop_Purchases, tc_items])
|
||||
|
||||
return info
|
||||
|
||||
@property
|
||||
def valid_task(self) -> list:
|
||||
task = self.shop_info
|
||||
if not task:
|
||||
logger.warning('Shop enabled but no task set')
|
||||
return task
|
||||
|
||||
@property
|
||||
def current_shop(self):
|
||||
return self.task[0][0]
|
||||
|
||||
@property
|
||||
def current_purchase_count(self):
|
||||
return self.task[0][1]
|
||||
|
||||
@property
|
||||
def current_item_list(self):
|
||||
return self.task[0][2]
|
||||
|
||||
def handle_shop(self, status):
|
||||
match status:
|
||||
case ShopStatus.SELECT_SHOP:
|
||||
if not self.task:
|
||||
return ShopStatus.FINISH
|
||||
if self.select_shop(self.current_shop):
|
||||
self.reset_swipe_flags()
|
||||
return ShopStatus.SELECT_ITEMS
|
||||
case ShopStatus.SELECT_ITEMS:
|
||||
self.select_items(self.current_item_list)
|
||||
return ShopStatus.PURCHASE
|
||||
case ShopStatus.PURCHASE:
|
||||
if self.make_purchase():
|
||||
return ShopStatus.REFRESH
|
||||
return ShopStatus.END
|
||||
case ShopStatus.REFRESH:
|
||||
if self.refresh_shop(self.current_purchase_count):
|
||||
return ShopStatus.SELECT_SHOP
|
||||
return ShopStatus.END
|
||||
case ShopStatus.END:
|
||||
if self.appear(page_shop.check_button):
|
||||
self.task.pop(0)
|
||||
return ShopStatus.SELECT_SHOP
|
||||
self.click_with_interval(BACK, interval=2)
|
||||
case ShopStatus.FINISH:
|
||||
return status
|
||||
case _:
|
||||
logger.warning(f'Invalid status: {status}')
|
||||
return status
|
||||
|
||||
def run(self):
|
||||
"""Reset the shop and items position by going main and then shop"""
|
||||
self.ui_ensure(page_main)
|
||||
self.ui_ensure(page_shop)
|
||||
|
||||
self.task = self.valid_task
|
||||
action_timer = Timer(0.5, 1)
|
||||
status = ShopStatus.SELECT_SHOP
|
||||
|
||||
while 1:
|
||||
self.device.screenshot()
|
||||
|
||||
if self.ui_additional():
|
||||
continue
|
||||
|
||||
if action_timer.reached_and_reset():
|
||||
logger.attr('Status', status)
|
||||
status = self.handle_shop(status)
|
||||
|
||||
if status == ShopStatus.FINISH:
|
||||
break
|
||||
|
||||
self.config.task_delay(server_update=True)
|
||||
@@ -0,0 +1,138 @@
|
||||
import numpy as np
|
||||
|
||||
from module.base.timer import Timer
|
||||
from module.base.base import ModuleBase
|
||||
from module.base.utils import area_size
|
||||
from module.logger import logger
|
||||
from module.ocr.ocr import DigitCounter
|
||||
from tasks.base.ui import UI
|
||||
from tasks.shop.assets.assets_shop import *
|
||||
|
||||
ITEM_POSITIONS = {
|
||||
1: (650, 200), 2: (805, 200), 3: (960, 200), 4: (1110, 200),
|
||||
5: (650, 460), 6: (805, 460), 7: (960, 460), 8: (1110, 460),
|
||||
9: (650, 200), 10: (805, 200), 11: (960, 200), 12: (1110, 200),
|
||||
13: (650, 460), 14: (805, 460), 15: (960, 460), 16: (1110, 460),
|
||||
17: (650, 460), 18: (805, 460), 19: (960, 460), 20: (1110, 460),
|
||||
}
|
||||
|
||||
class ShopUI(UI):
|
||||
def __init__(self, config, device):
|
||||
super().__init__(config, device)
|
||||
|
||||
self.click_coords = self.device.click_methods.get(self.config.Emulator_ControlMethod, self.device.click_adb)
|
||||
self.swipe_vector_range = (0.85, 0.9)
|
||||
self.swipe_flags = {8:False, 16: False}
|
||||
self.list = ITEM_LIST
|
||||
|
||||
def swipe_page(self, direction: str, main: ModuleBase, vector_range=None, reverse=False):
|
||||
"""
|
||||
Args:
|
||||
direction: up, down
|
||||
main:
|
||||
vector_range (tuple[float, float]):
|
||||
reverse (bool):
|
||||
"""
|
||||
if vector_range is None:
|
||||
vector_range = self.swipe_vector_range
|
||||
vector = np.random.uniform(*vector_range)
|
||||
width, height = area_size(self.list.button)
|
||||
if direction == 'up':
|
||||
vector = (0, vector * height)
|
||||
elif direction == 'down':
|
||||
vector = (0, -vector * height)
|
||||
else:
|
||||
logger.warning(f'Unknown swipe direction: {direction}')
|
||||
return
|
||||
|
||||
if reverse:
|
||||
vector = (-vector[0], -vector[1])
|
||||
main.device.swipe_vector(vector, self.list.button)
|
||||
|
||||
def select_then_check(self, dest_enter: ButtonWrapper, dest_check: ButtonWrapper):
|
||||
timer = Timer(5, 10).start()
|
||||
while 1:
|
||||
self.device.screenshot()
|
||||
self.appear_then_click(dest_enter, interval=1)
|
||||
if self.appear(dest_check):
|
||||
return True
|
||||
if timer.reached():
|
||||
return False
|
||||
|
||||
def select_shop(self, shop_switch):
|
||||
"""
|
||||
Set skip switch to on
|
||||
Returns:
|
||||
True if switch is set, False if switch not found
|
||||
"""
|
||||
if not shop_switch.appear(main=self):
|
||||
logger.info(f'{shop_switch.name} not found')
|
||||
return False
|
||||
shop_switch.set('on', main=self)
|
||||
|
||||
return True
|
||||
|
||||
def select_items(self, item_list):
|
||||
"""
|
||||
Select items in the item list checking if swipe is required each time.
|
||||
However, swipes are inaccurate and clicks too fast.
|
||||
"""
|
||||
timer = Timer(1).start()
|
||||
for item in item_list:
|
||||
if self.should_swipe(item):
|
||||
self.swipe_page('down', self)
|
||||
|
||||
self.wait_until_stable(
|
||||
self.list.button,
|
||||
timer=Timer(3, 0),
|
||||
timeout=Timer(1.5, 5)
|
||||
)
|
||||
while not timer.reached_and_reset():
|
||||
pass
|
||||
self.click_coords(*ITEM_POSITIONS[item])
|
||||
|
||||
def should_swipe(self, item):
|
||||
"""
|
||||
Return True based on two checkpoints:
|
||||
one at 8 and the other at 16.
|
||||
Only once for each checkpoint.
|
||||
"""
|
||||
if (8 < item < 16) and not self.swipe_flags[8]:
|
||||
self.swipe_flags[8] = True
|
||||
return True
|
||||
elif item > 16 and not self.swipe_flags[16]:
|
||||
self.swipe_flags[16] = True
|
||||
return True
|
||||
return False
|
||||
|
||||
def reset_swipe_flags(self):
|
||||
self.swipe_flags[8], self.swipe_flags[16] = False, False
|
||||
|
||||
def make_purchase(self):
|
||||
if self.select_then_check(PURCHASE, CONFIRM_PURCHASE) and self.appear_then_click(CONFIRM_PURCHASE):
|
||||
return True
|
||||
logger.warning("No items were selected. Unable to purchase.")
|
||||
return False
|
||||
|
||||
def refresh_shop(self, need_count):
|
||||
"""
|
||||
Refresh the shop
|
||||
"""
|
||||
refresh_count = self.get_refresh_count()
|
||||
if refresh_count:
|
||||
purchased_count = 4 - refresh_count
|
||||
if need_count > purchased_count and self.appear_then_click(CONFIRM_REFRESH):
|
||||
logger.info("Refreshed the shop")
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_refresh_count(self):
|
||||
if not self.select_then_check(REFRESH, CONFIRM_REFRESH):
|
||||
logger.warning('OCR failed due to invalid page')
|
||||
return False
|
||||
count, _, total = DigitCounter(OCR_REFRESH).ocr_single_line(self.device.image)
|
||||
if total == 0:
|
||||
logger.warning('Invalid count')
|
||||
return False
|
||||
return count
|
||||
|
||||
Reference in New Issue
Block a user