1
0
mirror of https://github.com/TheFunny/ArisuAutoSweeper synced 2026-06-24 03:04:51 +00:00

refactor: auto-mission

This commit is contained in:
RedDeadDepresso
2024-01-21 19:12:58 +00:00
parent 91bdc79fa9
commit 78c12a21dc
32 changed files with 496 additions and 229 deletions
+20 -52
View File
@@ -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",
+13 -20
View File
@@ -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]
+9 -8
View File
@@ -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`
+13 -33
View File
@@ -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",
+10 -30
View File
@@ -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": {
+154
View File
@@ -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