1
0
mirror of https://github.com/TheFunny/ArisuAutoSweeper synced 2025-12-16 19:55:12 +00:00

Compare commits

...

6 Commits

11 changed files with 132 additions and 42 deletions

View File

@ -12,7 +12,7 @@
The script is still under active development. The following features have been implemented:
- [x] **Cafe** Claim rewards / Interact / Second floor
- [x] **Cafe** Claim rewards / Interact / Invitation / Second floor
- [x] **Club** Claim AP
- [x] **Mailbox** Claim rewards
- [x] **Bounty** Auto sweep

View File

@ -12,7 +12,7 @@
当前脚本还在活跃开发中,已经实现的功能有:
- [x] **咖啡厅** 领取奖励 / 互动 / 第二咖啡厅
- [x] **咖啡厅** 领取奖励 / 互动 / 邀请 / 第二咖啡厅
- [x] **公会** 领取体力
- [x] **邮箱** 领取奖励
- [x] **悬赏通缉** 自动扫荡

View File

@ -81,15 +81,15 @@
"OnError": "skip"
},
"Highway": {
"Stage": 1,
"Stage": 0,
"Count": 2
},
"DesertRailroad": {
"Stage": 1,
"Stage": 0,
"Count": 2
},
"Schoolhouse": {
"Stage": 1,
"Stage": 0,
"Count": 2
}
},
@ -104,15 +104,15 @@
"OnError": "skip"
},
"Trinity": {
"Stage": 1,
"Stage": 0,
"Count": 2
},
"Gehenna": {
"Stage": 1,
"Stage": 0,
"Count": 2
},
"Millennium": {
"Stage": 1,
"Stage": 0,
"Count": 2
}
},

View File

@ -332,8 +332,9 @@
"Highway": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,
@ -353,8 +354,9 @@
"DesertRailroad": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,
@ -374,8 +376,9 @@
"Schoolhouse": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,
@ -432,8 +435,9 @@
"Trinity": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,
@ -448,8 +452,9 @@
"Gehenna": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,
@ -464,8 +469,9 @@
"Millennium": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,

View File

@ -100,18 +100,18 @@ Bounty:
Highway:
Stage:
value: 1
option: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
value: 0
option: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Count: 2
DesertRailroad:
Stage:
value: 1
option: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
value: 0
option: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Count: 2
Schoolhouse:
Stage:
value: 1
option: [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
value: 0
option: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Count: 2
Scrimmage:
@ -121,18 +121,18 @@ Scrimmage:
Trinity:
Stage:
value: 1
option: [ 1, 2, 3, 4 ]
value: 0
option: [ 0, 1, 2, 3, 4 ]
Count: 2
Gehenna:
Stage:
value: 1
option: [ 1, 2, 3, 4 ]
value: 0
option: [ 0, 1, 2, 3, 4 ]
Count: 2
Millennium:
Stage:
value: 1
option: [ 1, 2, 3, 4 ]
value: 0
option: [ 0, 1, 2, 3, 4 ]
Count: 2
TacticalChallenge:

View File

@ -56,30 +56,30 @@ class GeneratedConfig:
Bounty_OnError = 'skip' # stop, skip
# Group `Highway`
Highway_Stage = 1 # 1, 2, 3, 4, 5, 6, 7, 8, 9
Highway_Stage = 0 # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Highway_Count = 2
# Group `DesertRailroad`
DesertRailroad_Stage = 1 # 1, 2, 3, 4, 5, 6, 7, 8, 9
DesertRailroad_Stage = 0 # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
DesertRailroad_Count = 2
# Group `Schoolhouse`
Schoolhouse_Stage = 1 # 1, 2, 3, 4, 5, 6, 7, 8, 9
Schoolhouse_Stage = 0 # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Schoolhouse_Count = 2
# Group `Scrimmage`
Scrimmage_OnError = 'skip' # stop, skip
# Group `Trinity`
Trinity_Stage = 1 # 1, 2, 3, 4
Trinity_Stage = 0 # 0, 1, 2, 3, 4
Trinity_Count = 2
# Group `Gehenna`
Gehenna_Stage = 1 # 1, 2, 3, 4
Gehenna_Stage = 0 # 0, 1, 2, 3, 4
Gehenna_Count = 2
# Group `Millennium`
Millennium_Stage = 1 # 1, 2, 3, 4
Millennium_Stage = 0 # 0, 1, 2, 3, 4
Millennium_Count = 2
# Group `TacticalChallenge`

View File

@ -273,6 +273,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Overpass A",
"2": "02 - Overpass B",
"3": "03 - Overpass C",
@ -296,6 +297,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Abandoned Train A",
"2": "02 - Abandoned Train B",
"3": "03 - Abandoned Train C",
@ -319,6 +321,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Besieged Classroom A",
"2": "02 - Besieged Classroom B",
"3": "03 - Besieged Classroom C",
@ -354,6 +357,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Trinity A",
"2": "02 - Trinity B",
"3": "03 - Trinity C",
@ -372,6 +376,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Gehenna A",
"2": "02 - Gehenna B",
"3": "03 - Gehenna C",
@ -390,6 +395,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Millennium A",
"2": "02 - Millennium B",
"3": "03 - Millennium C",

View File

@ -273,6 +273,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 高架公路 A",
"2": "02 - 高架公路 B",
"3": "03 - 高架公路 C",
@ -296,6 +297,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 被遗弃的列车 A",
"2": "02 - 被遗弃的列车 B",
"3": "03 - 被遗弃的列车 C",
@ -319,6 +321,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 被袭击的教室 A",
"2": "02 - 被袭击的教室 B",
"3": "03 - 被袭击的教室 C",
@ -354,6 +357,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 三一 A",
"2": "02 - 三一 B",
"3": "03 - 三一 C",
@ -372,6 +376,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 格黑娜 A",
"2": "02 - 格黑娜 B",
"3": "03 - 格黑娜 C",
@ -390,6 +395,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 千年 A",
"2": "02 - 千年 B",
"3": "03 - 千年 C",

View File

@ -22,6 +22,8 @@ class BountyUI(UI):
return False
def enter_stage(self, index: int) -> bool:
if not index:
index = BOUNTY_LIST.insight_max_sweepable_index(self)
if BOUNTY_LIST.select_index_enter(self, index):
return True
return False

View File

@ -22,6 +22,8 @@ class ScrimmageUI(UI):
return False
def enter_stage(self, index: int) -> bool:
if not index:
index = SCRIMMAGE_LIST.insight_max_sweepable_index(self)
if SCRIMMAGE_LIST.select_index_enter(self, index, insight=False):
return True
return False

View File

@ -1,3 +1,5 @@
import re
import numpy as np
from module.base.base import ModuleBase
@ -31,7 +33,7 @@ class StageList:
self.current_index_min = 1
self.current_index_max = 1
self.current_indexes = []
self.current_indexes: list[tuple[str, tuple]] = []
def __str__(self):
return f'StageList({self.name})'
@ -46,11 +48,14 @@ class StageList:
@property
def _indexes(self) -> list[int]:
return list(map(lambda x: int(x.ocr_text), self.current_indexes))
return [int(x[0]) for x in self.current_indexes]
def load_stage_indexes(self, main: ModuleBase):
self.current_indexes = list(
filter(lambda x: x.ocr_text.isdigit(), self.index_ocr.detect_and_ocr(main.device.image))
filter(
lambda x: re.match(r'^\d{1,2}-?\d?$', x[0]),
map(lambda x: (x.ocr_text, x.box), self.index_ocr.detect_and_ocr(main.device.image))
)
)
if not self.current_indexes:
logger.warning(f'No valid index in {self.index_ocr.name}')
@ -126,13 +131,79 @@ class StageList:
timeout=Timer(1.5, 5)
)
def insight_max_sweepable_index(self, main: ModuleBase, skip_first_screenshot=True) -> int:
"""
Args:
main:
skip_first_screenshot:
Returns:
Index of max sweepable stage
"""
logger.info('Insight sweepable index')
max_sweepable_index = 0
last_max_sweepable_index = 0
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
main.device.screenshot()
self.load_stage_indexes(main=main)
sweepable_index = next(
filter(
lambda x: not self.is_sweepable(main, self.search_box(x[-1][:2])),
self.current_indexes
), None
)
# all sweepable
if sweepable_index is None:
logger.info('All sweepable')
max_sweepable_index = self.current_index_max
self.swipe_page(self.swipe_direction, main)
if max_sweepable_index == last_max_sweepable_index:
logger.info(f'Max sweepable index: {max_sweepable_index}')
return max_sweepable_index
last_max_sweepable_index = max_sweepable_index
# all not sweepable
elif int(sweepable_index[0]) == self.current_index_min:
logger.info('All not sweepable')
if int(sweepable_index[0]) == 1:
logger.warning('No sweepable index')
return 0
self.swipe_page(self.swipe_direction, main, reverse=True)
else:
logger.info(f'Sweepable index: {int(sweepable_index[0]) - 1}')
return int(sweepable_index[0]) - 1
main.wait_until_stable(
self.stage.button,
timer=Timer(0, 0),
timeout=Timer(1.5, 5)
)
def is_sweepable(self, main: ModuleBase, search_box) -> bool:
self.sweepable.load_search(search_box)
return main.appear(self.sweepable, similarity=0.8)
def search_box(
self,
index_cord: tuple[int, int],
padding: tuple[int, int] = (-20, -15)
) -> tuple[int, int, int, int]:
stage_item_box = area_pad((*padding, *area_size(self.stage_item)))
return area_offset(stage_item_box, index_cord)
def select_index_enter(
self,
main: ModuleBase,
index: int,
insight: bool = True,
sweepable: bool = True,
offset: tuple[int, int] = (-20, -15),
padding: tuple[int, int] = (-20, -15),
skip_first_screenshot: bool = True,
interval: int = 1.5
) -> bool:
@ -154,17 +225,14 @@ class StageList:
self.load_stage_indexes(main=main)
# find box of index
index_box = next(filter(lambda x: int(x.ocr_text) == index, self.current_indexes), None)
index_box = next(filter(lambda x: int(x[0]) == index, self.current_indexes), None)
if index_box is None:
logger.warning(f'No index {index} in {self.index_ocr.name}')
continue
stage_item_box = area_pad((*offset, *area_size(self.stage_item)))
search_box = area_offset(stage_item_box, index_box.box[:2])
self.sweepable.load_search(search_box)
if sweepable and not main.appear(self.sweepable):
search_box = self.search_box(index_box[-1][:2], padding)
if sweepable and not self.is_sweepable(main, search_box):
logger.warning(f'Index {index} is not sweepable')
return False