mirror of
https://github.com/TheFunny/ArisuAutoSweeper
synced 2026-06-24 03:04:51 +00:00
refactor: auto-mission
This commit is contained in:
@@ -274,64 +274,32 @@
|
||||
},
|
||||
"Formation": {
|
||||
"burst1": {
|
||||
"type": "select",
|
||||
"value": 1,
|
||||
"option": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
"type": "input",
|
||||
"value": "1-1"
|
||||
},
|
||||
"burst2": {
|
||||
"type": "select",
|
||||
"value": 4,
|
||||
"option": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
"type": "input",
|
||||
"value": "1-2"
|
||||
},
|
||||
"pierce1": {
|
||||
"type": "select",
|
||||
"value": 2,
|
||||
"option": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
"type": "input",
|
||||
"value": "1-3"
|
||||
},
|
||||
"pierce2": {
|
||||
"type": "select",
|
||||
"value": 4,
|
||||
"option": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
"type": "input",
|
||||
"value": "1-4"
|
||||
},
|
||||
"mystic1": {
|
||||
"type": "select",
|
||||
"value": 3,
|
||||
"option": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
"type": "input",
|
||||
"value": "1-5"
|
||||
},
|
||||
"mystic2": {
|
||||
"type": "select",
|
||||
"value": 4,
|
||||
"option": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
]
|
||||
"type": "input",
|
||||
"value": "2-1"
|
||||
},
|
||||
"Substitute": {
|
||||
"type": "checkbox",
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
"ManualBoss": {
|
||||
@@ -346,8 +314,8 @@
|
||||
"value": false
|
||||
},
|
||||
"Area": {
|
||||
"type": "input",
|
||||
"value": 4
|
||||
"type": "textarea",
|
||||
"value": null
|
||||
},
|
||||
"Completion": {
|
||||
"type": "select",
|
||||
@@ -364,8 +332,8 @@
|
||||
"value": false
|
||||
},
|
||||
"Area": {
|
||||
"type": "input",
|
||||
"value": 6
|
||||
"type": "textarea",
|
||||
"value": null
|
||||
},
|
||||
"Completion": {
|
||||
"type": "select",
|
||||
|
||||
@@ -243,38 +243,31 @@ TacticalChallengeShop:
|
||||
"15": false
|
||||
|
||||
Formation:
|
||||
burst1:
|
||||
value: 1
|
||||
option: [ 1, 2, 3, 4 ]
|
||||
burst2:
|
||||
value: 4
|
||||
option: [ 1, 2, 3, 4 ]
|
||||
pierce1:
|
||||
value: 2
|
||||
option: [ 1, 2, 3, 4 ]
|
||||
pierce2:
|
||||
value: 4
|
||||
option: [ 1, 2, 3, 4 ]
|
||||
mystic1:
|
||||
value: 3
|
||||
option: [ 1, 2, 3, 4 ]
|
||||
mystic2:
|
||||
value: 4
|
||||
option: [ 1, 2, 3, 4 ]
|
||||
burst1: 1-1
|
||||
burst2: 1-2
|
||||
pierce1: 1-3
|
||||
pierce2: 1-4
|
||||
mystic1: 1-5
|
||||
mystic2: 2-1
|
||||
Substitute: false
|
||||
|
||||
ManualBoss:
|
||||
Enable: false
|
||||
|
||||
Normal:
|
||||
Enable: false
|
||||
Area: 4
|
||||
Area:
|
||||
value: null
|
||||
type: textarea
|
||||
Completion:
|
||||
value: clear
|
||||
option: [ clear, three_stars]
|
||||
|
||||
Hard:
|
||||
Enable: false
|
||||
Area: 6
|
||||
Area:
|
||||
value: null
|
||||
type: textarea
|
||||
Completion:
|
||||
value: clear
|
||||
option: [ clear, three_stars, three_stars_chest]
|
||||
|
||||
@@ -160,24 +160,25 @@ class GeneratedConfig:
|
||||
TacticalChallengeShop_15 = False
|
||||
|
||||
# Group `Formation`
|
||||
Formation_burst1 = 1 # 1, 2, 3, 4
|
||||
Formation_burst2 = 4 # 1, 2, 3, 4
|
||||
Formation_pierce1 = 2 # 1, 2, 3, 4
|
||||
Formation_pierce2 = 4 # 1, 2, 3, 4
|
||||
Formation_mystic1 = 3 # 1, 2, 3, 4
|
||||
Formation_mystic2 = 4 # 1, 2, 3, 4
|
||||
Formation_burst1 = '1-1'
|
||||
Formation_burst2 = '1-2'
|
||||
Formation_pierce1 = '1-3'
|
||||
Formation_pierce2 = '1-4'
|
||||
Formation_mystic1 = '1-5'
|
||||
Formation_mystic2 = '2-1'
|
||||
Formation_Substitute = False
|
||||
|
||||
# Group `ManualBoss`
|
||||
ManualBoss_Enable = False
|
||||
|
||||
# Group `Normal`
|
||||
Normal_Enable = False
|
||||
Normal_Area = 4
|
||||
Normal_Area = None
|
||||
Normal_Completion = 'clear' # clear, three_stars
|
||||
|
||||
# Group `Hard`
|
||||
Hard_Enable = False
|
||||
Hard_Area = 6
|
||||
Hard_Area = None
|
||||
Hard_Completion = 'clear' # clear, three_stars, three_stars_chest
|
||||
|
||||
# Group `ItemStorage`
|
||||
|
||||
@@ -827,55 +827,35 @@
|
||||
"Formation": {
|
||||
"_info": {
|
||||
"name": "Formation",
|
||||
"help": "Select the unit for each type"
|
||||
"help": "AAS will choose the unit from the Preset List in the Layout after entering the Unit Formation Page. The format is preset-row, for example 1-1 means choose preset 1 row 1. Please make sure the presets are set to their original names (1,2,3,4). It is highly recommended that you set them up to be unique."
|
||||
},
|
||||
"burst1": {
|
||||
"name": "Explosive 1",
|
||||
"help": "",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": ""
|
||||
},
|
||||
"burst2": {
|
||||
"name": "Explosive 2",
|
||||
"help": "",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": ""
|
||||
},
|
||||
"pierce1": {
|
||||
"name": "Piercing 1",
|
||||
"help": "",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": ""
|
||||
},
|
||||
"pierce2": {
|
||||
"name": "Piercing 2",
|
||||
"help": "",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": ""
|
||||
},
|
||||
"mystic1": {
|
||||
"name": "Mystic 1",
|
||||
"help": "",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": ""
|
||||
},
|
||||
"mystic2": {
|
||||
"name": "Mystic 2",
|
||||
"help": "",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": ""
|
||||
},
|
||||
"Substitute": {
|
||||
"name": "Find Alternatives",
|
||||
"help": "In case you set the preset for some types to be the same and the stage requires all of those types, AAS will try to find alternatives. For example, if you set Explosive 1 and Explosive 2 to be the same and the stage requires both of them, AAS will replace Explosive 2 with Piercing 1."
|
||||
}
|
||||
},
|
||||
"ManualBoss": {
|
||||
@@ -899,7 +879,7 @@
|
||||
},
|
||||
"Area": {
|
||||
"name": "Area",
|
||||
"help": ""
|
||||
"help": "Currently only between 4 and 16. Use > to connect multiple areas. Example: 6 > 7 > 8"
|
||||
},
|
||||
"Completion": {
|
||||
"name": "Completion level",
|
||||
@@ -919,7 +899,7 @@
|
||||
},
|
||||
"Area": {
|
||||
"name": "Area",
|
||||
"help": ""
|
||||
"help": "Currently only between 6 and 16. Use > to connect multiple areas. Example: 6 > 7 > 8"
|
||||
},
|
||||
"Completion": {
|
||||
"name": "Completion level",
|
||||
|
||||
@@ -831,51 +831,31 @@
|
||||
},
|
||||
"burst1": {
|
||||
"name": "Formation.burst1.name",
|
||||
"help": "Formation.burst1.help",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": "Formation.burst1.help"
|
||||
},
|
||||
"burst2": {
|
||||
"name": "Formation.burst2.name",
|
||||
"help": "Formation.burst2.help",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": "Formation.burst2.help"
|
||||
},
|
||||
"pierce1": {
|
||||
"name": "Formation.pierce1.name",
|
||||
"help": "Formation.pierce1.help",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": "Formation.pierce1.help"
|
||||
},
|
||||
"pierce2": {
|
||||
"name": "Formation.pierce2.name",
|
||||
"help": "Formation.pierce2.help",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": "Formation.pierce2.help"
|
||||
},
|
||||
"mystic1": {
|
||||
"name": "Formation.mystic1.name",
|
||||
"help": "Formation.mystic1.help",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": "Formation.mystic1.help"
|
||||
},
|
||||
"mystic2": {
|
||||
"name": "Formation.mystic2.name",
|
||||
"help": "Formation.mystic2.help",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
"help": "Formation.mystic2.help"
|
||||
},
|
||||
"Substitute": {
|
||||
"name": "Formation.Substitute.name",
|
||||
"help": "Formation.Substitute.help"
|
||||
}
|
||||
},
|
||||
"ManualBoss": {
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
"""
|
||||
Original Author: sanmusen214(https://github.com/sanmusen214)
|
||||
Adapted from https://github.com/sanmusen214/BAAH/blob/1.2/modules/AllTask/SubTask/ScrollSelect.py
|
||||
"""
|
||||
|
||||
from module.base.timer import Timer
|
||||
from module.logger import logger
|
||||
|
||||
|
||||
class ScrollSelect:
|
||||
"""
|
||||
Scroll and select the corresponding level by clicking on the right-side window.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
window_starty:
|
||||
Y-coordinate of the upper edge of the window
|
||||
first_item_endy:
|
||||
Y-coordinate of the lower edge of the first item
|
||||
window_endy:
|
||||
Y-coordinate of the lower edge of the window
|
||||
clickx: int
|
||||
Base X-coordinate for sliding and clicking the button
|
||||
hasexpectimage: function
|
||||
Function to determine the appearance of the expected image after clicking, returns a boolean
|
||||
swipeoffsetx: int
|
||||
X offset of the base X-coordinate during sliding to prevent accidental button clicks
|
||||
finalclick: bool
|
||||
Whether to click on clickx and the last row after the sliding ends
|
||||
"""
|
||||
|
||||
def __init__(self, window_button, first_item_button, expected_button, clickx, swipeoffsetx=-100, responsey=40,
|
||||
finalclick=True) -> None:
|
||||
# TODO: Actually, only concerned about the height of one element, completely displaying the Y of the first button, completely displaying the Y of the bottom button, the number of complete elements that the window can contain, the height of the last element in the window, and the left offset and response distance.
|
||||
self.window_starty = window_button.area[1]
|
||||
self.window_endy = window_button.area[3]
|
||||
self.first_item_endy = first_item_button.area[3]
|
||||
self.windowheight = window_button.height
|
||||
self.itemheight = first_item_button.height
|
||||
self.clickx = clickx
|
||||
self.expected_button = expected_button
|
||||
self.swipeoffsetx = swipeoffsetx
|
||||
self.responsey = responsey
|
||||
self.finalclick = finalclick
|
||||
|
||||
def compute_swipe(self, main, x1, y1, distance, responsey):
|
||||
"""
|
||||
Swipe vertically from bottom to top, actual swipe distance calculated based on the distance between two target points, considering inertia.
|
||||
"""
|
||||
distance = abs(distance)
|
||||
logger.info(f"Swipe distance: {distance}")
|
||||
# 0-50
|
||||
if distance < 50:
|
||||
main.device.swipe((x1, y1), (x1, y1 - (distance + responsey)), duration=2)
|
||||
else:
|
||||
# Effective swipe distance for the Chinese server is 60
|
||||
main.device.swipe((x1, y1), (x1, int(y1 - (distance + responsey - 4 * (1 + distance / 100)))),
|
||||
duration=1 + distance / 100)
|
||||
|
||||
def select_index(self, main, target_index, clickoffsety=0) -> None:
|
||||
click_coords = main.device.click_methods.get(main.config.Emulator_ControlMethod, main.device.click_adb)
|
||||
logger.info("Scroll and select the {}-th level".format(target_index + 1))
|
||||
self.scroll_right_up(main, scrollx=self.clickx + self.swipeoffsetx)
|
||||
# Calculate how many complete elements are on one page
|
||||
itemcount = self.windowheight // self.itemheight
|
||||
# Calculate how much height the last incomplete element on this page occupies
|
||||
lastitemheight = self.windowheight % self.itemheight
|
||||
# Height below the incomplete element
|
||||
hiddenlastitemheight = self.itemheight - lastitemheight
|
||||
# Center point of the height of the first element
|
||||
start_center_y = self.window_starty + self.itemheight // 2
|
||||
# Center point of the last complete element on this page
|
||||
end_center_y = start_center_y + (itemcount - 1) * self.itemheight
|
||||
# If the target element is on the current page
|
||||
if target_index < itemcount:
|
||||
# Center point of the target element
|
||||
target_center_y = start_center_y + self.itemheight * target_index
|
||||
self.run_until(main,
|
||||
lambda: click_coords(self.clickx, target_center_y),
|
||||
lambda: main.appear(self.expected_button),
|
||||
)
|
||||
else:
|
||||
# Start scrolling from the gap in the middle of the levels
|
||||
scroll_start_from_y = self.window_endy - self.itemheight // 2
|
||||
# The target element is on subsequent pages
|
||||
# Calculate how much the page should be scrolled
|
||||
scrolltotal_distance = (target_index - itemcount) * self.itemheight + hiddenlastitemheight
|
||||
logger.info("Height hidden by the last element: %d" % hiddenlastitemheight)
|
||||
# First, slide up the hidden part, add a little distance to let the system recognize it as a swipe event
|
||||
self.compute_swipe(main, self.clickx + self.swipeoffsetx, scroll_start_from_y, hiddenlastitemheight,
|
||||
self.responsey)
|
||||
logger.info(f"Swipe distance: {hiddenlastitemheight}")
|
||||
# Update scrolltotal_distance
|
||||
scrolltotal_distance -= hiddenlastitemheight
|
||||
# Still need to scroll up (target_index - itemcount) * self.itemheight
|
||||
# Important: slide the height of (itemcount - 1) elements each time
|
||||
if itemcount == 1:
|
||||
scroll_distance = itemcount * self.itemheight
|
||||
else:
|
||||
scroll_distance = (itemcount - 1) * self.itemheight
|
||||
while scroll_distance <= scrolltotal_distance:
|
||||
self.compute_swipe(main, self.clickx + self.swipeoffsetx, scroll_start_from_y, scroll_distance,
|
||||
self.responsey)
|
||||
scrolltotal_distance -= scroll_distance
|
||||
if scrolltotal_distance > 5:
|
||||
# Last slide
|
||||
self.compute_swipe(main, self.clickx + self.swipeoffsetx, scroll_start_from_y, scrolltotal_distance,
|
||||
self.responsey)
|
||||
if self.finalclick:
|
||||
# Click on the last row
|
||||
clicky = (self.window_endy - self.itemheight // 2) + clickoffsety
|
||||
logger.info(clicky)
|
||||
self.run_until(main,
|
||||
lambda: click_coords(self.clickx, clicky),
|
||||
lambda: main.appear(self.expected_button)
|
||||
)
|
||||
|
||||
def run_until(self, main, func1, func2, times=6, sleeptime=1.5) -> bool:
|
||||
"""
|
||||
Repeat the execution of func1 up to a maximum of times or until func2 evaluates to True.
|
||||
|
||||
func1 should perform a single valid operation or internally call a screenshot function.
|
||||
A screenshot is triggered before evaluating func2.
|
||||
|
||||
After each execution of func1, wait for sleeptime seconds.
|
||||
|
||||
If func2 evaluates to True, exit and return True. Otherwise, return False.
|
||||
|
||||
Note: The comment assumes that func1 produces a meaningful operation or internally calls a screenshot function,
|
||||
and func2 is evaluated after each execution of func1.
|
||||
"""
|
||||
for i in range(times):
|
||||
main.device.screenshot()
|
||||
if func2():
|
||||
return True
|
||||
func1()
|
||||
timer = Timer(sleeptime).start()
|
||||
while not timer.reached_and_reset():
|
||||
pass
|
||||
main.device.screenshot()
|
||||
if func2():
|
||||
return True
|
||||
logger.warning("run_until exceeded max times")
|
||||
return False
|
||||
|
||||
def scroll_right_up(self, main, scrollx=928, times=3):
|
||||
"""
|
||||
scroll to top
|
||||
"""
|
||||
for i in range(times):
|
||||
main.device.swipe((scrollx, 226), (scrollx, 561), duration=0.2)
|
||||
timer = Timer(0.5).start()
|
||||
while not timer.reached_and_reset():
|
||||
pass
|
||||
Reference in New Issue
Block a user