Compare commits
2 Commits
91bdc79fa9
...
2a1e7686f0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a1e7686f0 | ||
|
|
78c12a21dc |
BIN
assets/en/auto_mission/LAYOUT.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
assets/en/auto_mission/PRESET1_ON.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
assets/en/auto_mission/PRESET2_ON.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/en/auto_mission/PRESET3_ON.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
assets/en/auto_mission/PRESET4_ON.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/en/auto_mission/PRESET_FIRST_ITEM.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
assets/en/auto_mission/PRESET_LIST.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
assets/en/auto_mission/PRESET_WINDOW.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
assets/en/auto_mission/RECEIVED_CHEST.BUTTON.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/en/auto_mission/RECEIVED_CHEST.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/zht/auto_mission/LAYOUT.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
assets/zht/auto_mission/PRESET1_OFF.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
assets/zht/auto_mission/PRESET1_ON.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
assets/zht/auto_mission/PRESET2_OFF.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
assets/zht/auto_mission/PRESET2_ON.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/zht/auto_mission/PRESET3_OFF.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
assets/zht/auto_mission/PRESET3_ON.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
assets/zht/auto_mission/PRESET4_OFF.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/zht/auto_mission/PRESET4_ON.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/zht/auto_mission/PRESET_FIRST_ITEM.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
assets/zht/auto_mission/PRESET_LIST.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
assets/zht/auto_mission/PRESET_WINDOW.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
assets/zht/auto_mission/RECEIVED_CHEST.BUTTON.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/zht/auto_mission/RECEIVED_CHEST.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
@ -57,24 +57,25 @@
|
|||||||
"ServerUpdate": "04:00"
|
"ServerUpdate": "04:00"
|
||||||
},
|
},
|
||||||
"Formation": {
|
"Formation": {
|
||||||
"burst1": 1,
|
"burst1": "1-1",
|
||||||
"burst2": 4,
|
"burst2": "1-2",
|
||||||
"pierce1": 2,
|
"pierce1": "1-3",
|
||||||
"pierce2": 4,
|
"pierce2": "1-4",
|
||||||
"mystic1": 3,
|
"mystic1": "1-5",
|
||||||
"mystic2": 4
|
"mystic2": "2-1",
|
||||||
|
"Substitute": false
|
||||||
},
|
},
|
||||||
"ManualBoss": {
|
"ManualBoss": {
|
||||||
"Enable": false
|
"Enable": false
|
||||||
},
|
},
|
||||||
"Normal": {
|
"Normal": {
|
||||||
"Enable": false,
|
"Enable": false,
|
||||||
"Area": 4,
|
"Area": null,
|
||||||
"Completion": "clear"
|
"Completion": "clear"
|
||||||
},
|
},
|
||||||
"Hard": {
|
"Hard": {
|
||||||
"Enable": false,
|
"Enable": false,
|
||||||
"Area": 6,
|
"Area": null,
|
||||||
"Completion": "clear"
|
"Completion": "clear"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -274,64 +274,32 @@
|
|||||||
},
|
},
|
||||||
"Formation": {
|
"Formation": {
|
||||||
"burst1": {
|
"burst1": {
|
||||||
"type": "select",
|
"type": "input",
|
||||||
"value": 1,
|
"value": "1-1"
|
||||||
"option": [
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"burst2": {
|
"burst2": {
|
||||||
"type": "select",
|
"type": "input",
|
||||||
"value": 4,
|
"value": "1-2"
|
||||||
"option": [
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"pierce1": {
|
"pierce1": {
|
||||||
"type": "select",
|
"type": "input",
|
||||||
"value": 2,
|
"value": "1-3"
|
||||||
"option": [
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"pierce2": {
|
"pierce2": {
|
||||||
"type": "select",
|
"type": "input",
|
||||||
"value": 4,
|
"value": "1-4"
|
||||||
"option": [
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"mystic1": {
|
"mystic1": {
|
||||||
"type": "select",
|
"type": "input",
|
||||||
"value": 3,
|
"value": "1-5"
|
||||||
"option": [
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"mystic2": {
|
"mystic2": {
|
||||||
"type": "select",
|
"type": "input",
|
||||||
"value": 4,
|
"value": "2-1"
|
||||||
"option": [
|
},
|
||||||
1,
|
"Substitute": {
|
||||||
2,
|
"type": "checkbox",
|
||||||
3,
|
"value": false
|
||||||
4
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ManualBoss": {
|
"ManualBoss": {
|
||||||
@ -346,8 +314,8 @@
|
|||||||
"value": false
|
"value": false
|
||||||
},
|
},
|
||||||
"Area": {
|
"Area": {
|
||||||
"type": "input",
|
"type": "textarea",
|
||||||
"value": 4
|
"value": null
|
||||||
},
|
},
|
||||||
"Completion": {
|
"Completion": {
|
||||||
"type": "select",
|
"type": "select",
|
||||||
@ -364,8 +332,8 @@
|
|||||||
"value": false
|
"value": false
|
||||||
},
|
},
|
||||||
"Area": {
|
"Area": {
|
||||||
"type": "input",
|
"type": "textarea",
|
||||||
"value": 6
|
"value": null
|
||||||
},
|
},
|
||||||
"Completion": {
|
"Completion": {
|
||||||
"type": "select",
|
"type": "select",
|
||||||
|
|||||||
@ -243,38 +243,31 @@ TacticalChallengeShop:
|
|||||||
"15": false
|
"15": false
|
||||||
|
|
||||||
Formation:
|
Formation:
|
||||||
burst1:
|
burst1: 1-1
|
||||||
value: 1
|
burst2: 1-2
|
||||||
option: [ 1, 2, 3, 4 ]
|
pierce1: 1-3
|
||||||
burst2:
|
pierce2: 1-4
|
||||||
value: 4
|
mystic1: 1-5
|
||||||
option: [ 1, 2, 3, 4 ]
|
mystic2: 2-1
|
||||||
pierce1:
|
Substitute: false
|
||||||
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 ]
|
|
||||||
|
|
||||||
ManualBoss:
|
ManualBoss:
|
||||||
Enable: false
|
Enable: false
|
||||||
|
|
||||||
Normal:
|
Normal:
|
||||||
Enable: false
|
Enable: false
|
||||||
Area: 4
|
Area:
|
||||||
|
value: null
|
||||||
|
type: textarea
|
||||||
Completion:
|
Completion:
|
||||||
value: clear
|
value: clear
|
||||||
option: [ clear, three_stars]
|
option: [ clear, three_stars]
|
||||||
|
|
||||||
Hard:
|
Hard:
|
||||||
Enable: false
|
Enable: false
|
||||||
Area: 6
|
Area:
|
||||||
|
value: null
|
||||||
|
type: textarea
|
||||||
Completion:
|
Completion:
|
||||||
value: clear
|
value: clear
|
||||||
option: [ clear, three_stars, three_stars_chest]
|
option: [ clear, three_stars, three_stars_chest]
|
||||||
|
|||||||
@ -160,24 +160,25 @@ class GeneratedConfig:
|
|||||||
TacticalChallengeShop_15 = False
|
TacticalChallengeShop_15 = False
|
||||||
|
|
||||||
# Group `Formation`
|
# Group `Formation`
|
||||||
Formation_burst1 = 1 # 1, 2, 3, 4
|
Formation_burst1 = '1-1'
|
||||||
Formation_burst2 = 4 # 1, 2, 3, 4
|
Formation_burst2 = '1-2'
|
||||||
Formation_pierce1 = 2 # 1, 2, 3, 4
|
Formation_pierce1 = '1-3'
|
||||||
Formation_pierce2 = 4 # 1, 2, 3, 4
|
Formation_pierce2 = '1-4'
|
||||||
Formation_mystic1 = 3 # 1, 2, 3, 4
|
Formation_mystic1 = '1-5'
|
||||||
Formation_mystic2 = 4 # 1, 2, 3, 4
|
Formation_mystic2 = '2-1'
|
||||||
|
Formation_Substitute = False
|
||||||
|
|
||||||
# Group `ManualBoss`
|
# Group `ManualBoss`
|
||||||
ManualBoss_Enable = False
|
ManualBoss_Enable = False
|
||||||
|
|
||||||
# Group `Normal`
|
# Group `Normal`
|
||||||
Normal_Enable = False
|
Normal_Enable = False
|
||||||
Normal_Area = 4
|
Normal_Area = None
|
||||||
Normal_Completion = 'clear' # clear, three_stars
|
Normal_Completion = 'clear' # clear, three_stars
|
||||||
|
|
||||||
# Group `Hard`
|
# Group `Hard`
|
||||||
Hard_Enable = False
|
Hard_Enable = False
|
||||||
Hard_Area = 6
|
Hard_Area = None
|
||||||
Hard_Completion = 'clear' # clear, three_stars, three_stars_chest
|
Hard_Completion = 'clear' # clear, three_stars, three_stars_chest
|
||||||
|
|
||||||
# Group `ItemStorage`
|
# Group `ItemStorage`
|
||||||
|
|||||||
@ -827,55 +827,35 @@
|
|||||||
"Formation": {
|
"Formation": {
|
||||||
"_info": {
|
"_info": {
|
||||||
"name": "Formation",
|
"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": {
|
"burst1": {
|
||||||
"name": "Explosive 1",
|
"name": "Explosive 1",
|
||||||
"help": "",
|
"help": ""
|
||||||
"1": "1",
|
|
||||||
"2": "2",
|
|
||||||
"3": "3",
|
|
||||||
"4": "4"
|
|
||||||
},
|
},
|
||||||
"burst2": {
|
"burst2": {
|
||||||
"name": "Explosive 2",
|
"name": "Explosive 2",
|
||||||
"help": "",
|
"help": ""
|
||||||
"1": "1",
|
|
||||||
"2": "2",
|
|
||||||
"3": "3",
|
|
||||||
"4": "4"
|
|
||||||
},
|
},
|
||||||
"pierce1": {
|
"pierce1": {
|
||||||
"name": "Piercing 1",
|
"name": "Piercing 1",
|
||||||
"help": "",
|
"help": ""
|
||||||
"1": "1",
|
|
||||||
"2": "2",
|
|
||||||
"3": "3",
|
|
||||||
"4": "4"
|
|
||||||
},
|
},
|
||||||
"pierce2": {
|
"pierce2": {
|
||||||
"name": "Piercing 2",
|
"name": "Piercing 2",
|
||||||
"help": "",
|
"help": ""
|
||||||
"1": "1",
|
|
||||||
"2": "2",
|
|
||||||
"3": "3",
|
|
||||||
"4": "4"
|
|
||||||
},
|
},
|
||||||
"mystic1": {
|
"mystic1": {
|
||||||
"name": "Mystic 1",
|
"name": "Mystic 1",
|
||||||
"help": "",
|
"help": ""
|
||||||
"1": "1",
|
|
||||||
"2": "2",
|
|
||||||
"3": "3",
|
|
||||||
"4": "4"
|
|
||||||
},
|
},
|
||||||
"mystic2": {
|
"mystic2": {
|
||||||
"name": "Mystic 2",
|
"name": "Mystic 2",
|
||||||
"help": "",
|
"help": ""
|
||||||
"1": "1",
|
},
|
||||||
"2": "2",
|
"Substitute": {
|
||||||
"3": "3",
|
"name": "Find Alternatives",
|
||||||
"4": "4"
|
"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": {
|
"ManualBoss": {
|
||||||
@ -899,7 +879,7 @@
|
|||||||
},
|
},
|
||||||
"Area": {
|
"Area": {
|
||||||
"name": "Area",
|
"name": "Area",
|
||||||
"help": ""
|
"help": "Currently only between 4 and 16. Use > to connect multiple areas. Example: 6 > 7 > 8"
|
||||||
},
|
},
|
||||||
"Completion": {
|
"Completion": {
|
||||||
"name": "Completion level",
|
"name": "Completion level",
|
||||||
@ -919,7 +899,7 @@
|
|||||||
},
|
},
|
||||||
"Area": {
|
"Area": {
|
||||||
"name": "Area",
|
"name": "Area",
|
||||||
"help": ""
|
"help": "Currently only between 6 and 16. Use > to connect multiple areas. Example: 6 > 7 > 8"
|
||||||
},
|
},
|
||||||
"Completion": {
|
"Completion": {
|
||||||
"name": "Completion level",
|
"name": "Completion level",
|
||||||
|
|||||||
@ -831,51 +831,31 @@
|
|||||||
},
|
},
|
||||||
"burst1": {
|
"burst1": {
|
||||||
"name": "Formation.burst1.name",
|
"name": "Formation.burst1.name",
|
||||||
"help": "Formation.burst1.help",
|
"help": "Formation.burst1.help"
|
||||||
"1": "1",
|
|
||||||
"2": "2",
|
|
||||||
"3": "3",
|
|
||||||
"4": "4"
|
|
||||||
},
|
},
|
||||||
"burst2": {
|
"burst2": {
|
||||||
"name": "Formation.burst2.name",
|
"name": "Formation.burst2.name",
|
||||||
"help": "Formation.burst2.help",
|
"help": "Formation.burst2.help"
|
||||||
"1": "1",
|
|
||||||
"2": "2",
|
|
||||||
"3": "3",
|
|
||||||
"4": "4"
|
|
||||||
},
|
},
|
||||||
"pierce1": {
|
"pierce1": {
|
||||||
"name": "Formation.pierce1.name",
|
"name": "Formation.pierce1.name",
|
||||||
"help": "Formation.pierce1.help",
|
"help": "Formation.pierce1.help"
|
||||||
"1": "1",
|
|
||||||
"2": "2",
|
|
||||||
"3": "3",
|
|
||||||
"4": "4"
|
|
||||||
},
|
},
|
||||||
"pierce2": {
|
"pierce2": {
|
||||||
"name": "Formation.pierce2.name",
|
"name": "Formation.pierce2.name",
|
||||||
"help": "Formation.pierce2.help",
|
"help": "Formation.pierce2.help"
|
||||||
"1": "1",
|
|
||||||
"2": "2",
|
|
||||||
"3": "3",
|
|
||||||
"4": "4"
|
|
||||||
},
|
},
|
||||||
"mystic1": {
|
"mystic1": {
|
||||||
"name": "Formation.mystic1.name",
|
"name": "Formation.mystic1.name",
|
||||||
"help": "Formation.mystic1.help",
|
"help": "Formation.mystic1.help"
|
||||||
"1": "1",
|
|
||||||
"2": "2",
|
|
||||||
"3": "3",
|
|
||||||
"4": "4"
|
|
||||||
},
|
},
|
||||||
"mystic2": {
|
"mystic2": {
|
||||||
"name": "Formation.mystic2.name",
|
"name": "Formation.mystic2.name",
|
||||||
"help": "Formation.mystic2.help",
|
"help": "Formation.mystic2.help"
|
||||||
"1": "1",
|
},
|
||||||
"2": "2",
|
"Substitute": {
|
||||||
"3": "3",
|
"name": "Formation.Substitute.name",
|
||||||
"4": "4"
|
"help": "Formation.Substitute.help"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ManualBoss": {
|
"ManualBoss": {
|
||||||
|
|||||||
@ -13,8 +13,6 @@ class ScrollSelect:
|
|||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
targetind : int
|
|
||||||
Index of the target level
|
|
||||||
window_starty:
|
window_starty:
|
||||||
Y-coordinate of the upper edge of the window
|
Y-coordinate of the upper edge of the window
|
||||||
first_item_endy:
|
first_item_endy:
|
||||||
@ -31,7 +29,7 @@ class ScrollSelect:
|
|||||||
Whether to click on clickx and the last row after the sliding ends
|
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,
|
def __init__(self, window_button, first_item_button, expected_button, clickx, swipeoffsetx=-100, responsey=40,
|
||||||
finalclick=True) -> None:
|
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.
|
# 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_starty = window_button.area[1]
|
||||||
@ -42,7 +40,7 @@ class ScrollSelect:
|
|||||||
self.clickx = clickx
|
self.clickx = clickx
|
||||||
self.expected_button = expected_button
|
self.expected_button = expected_button
|
||||||
self.swipeoffsetx = swipeoffsetx
|
self.swipeoffsetx = swipeoffsetx
|
||||||
self.responsey = 40
|
self.responsey = responsey
|
||||||
self.finalclick = finalclick
|
self.finalclick = finalclick
|
||||||
|
|
||||||
def compute_swipe(self, main, x1, y1, distance, responsey):
|
def compute_swipe(self, main, x1, y1, distance, responsey):
|
||||||
@ -59,7 +57,7 @@ class ScrollSelect:
|
|||||||
main.device.swipe((x1, y1), (x1, int(y1 - (distance + responsey - 4 * (1 + distance / 100)))),
|
main.device.swipe((x1, y1), (x1, int(y1 - (distance + responsey - 4 * (1 + distance / 100)))),
|
||||||
duration=1 + distance / 100)
|
duration=1 + distance / 100)
|
||||||
|
|
||||||
def select_location(self, main, target_index) -> None:
|
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)
|
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))
|
logger.info("Scroll and select the {}-th level".format(target_index + 1))
|
||||||
self.scroll_right_up(main, scrollx=self.clickx + self.swipeoffsetx)
|
self.scroll_right_up(main, scrollx=self.clickx + self.swipeoffsetx)
|
||||||
@ -110,8 +108,10 @@ class ScrollSelect:
|
|||||||
self.responsey)
|
self.responsey)
|
||||||
if self.finalclick:
|
if self.finalclick:
|
||||||
# Click on the last row
|
# Click on the last row
|
||||||
|
clicky = (self.window_endy - self.itemheight // 2) + clickoffsety
|
||||||
|
logger.info(clicky)
|
||||||
self.run_until(main,
|
self.run_until(main,
|
||||||
lambda: click_coords(self.clickx, self.window_endy - self.itemheight // 2),
|
lambda: click_coords(self.clickx, clicky),
|
||||||
lambda: main.appear(self.expected_button)
|
lambda: main.appear(self.expected_button)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -183,6 +183,24 @@ ENTER_SUB = ButtonWrapper(
|
|||||||
button=(553, 490, 712, 538),
|
button=(553, 490, 712, 538),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
LAYOUT = ButtonWrapper(
|
||||||
|
name='LAYOUT',
|
||||||
|
jp=None,
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/auto_mission/LAYOUT.png',
|
||||||
|
area=(1179, 461, 1226, 504),
|
||||||
|
search=(1159, 441, 1246, 524),
|
||||||
|
color=(189, 198, 210),
|
||||||
|
button=(1179, 461, 1226, 504),
|
||||||
|
),
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/LAYOUT.png',
|
||||||
|
area=(1179, 461, 1226, 504),
|
||||||
|
search=(1159, 441, 1246, 524),
|
||||||
|
color=(189, 198, 210),
|
||||||
|
button=(1179, 461, 1226, 504),
|
||||||
|
),
|
||||||
|
)
|
||||||
MISSION_COMPLETE = ButtonWrapper(
|
MISSION_COMPLETE = ButtonWrapper(
|
||||||
name='MISSION_COMPLETE',
|
name='MISSION_COMPLETE',
|
||||||
jp=None,
|
jp=None,
|
||||||
@ -327,6 +345,180 @@ ONE_STAR = ButtonWrapper(
|
|||||||
button=(148, 349, 183, 390),
|
button=(148, 349, 183, 390),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
PRESET1_OFF = ButtonWrapper(
|
||||||
|
name='PRESET1_OFF',
|
||||||
|
jp=None,
|
||||||
|
en=None,
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/PRESET1_OFF.png',
|
||||||
|
area=(52, 143, 197, 181),
|
||||||
|
search=(32, 123, 217, 201),
|
||||||
|
color=(253, 253, 254),
|
||||||
|
button=(52, 143, 197, 181),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
PRESET1_ON = ButtonWrapper(
|
||||||
|
name='PRESET1_ON',
|
||||||
|
jp=None,
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/auto_mission/PRESET1_ON.png',
|
||||||
|
area=(54, 146, 200, 182),
|
||||||
|
search=(34, 126, 220, 202),
|
||||||
|
color=(48, 77, 115),
|
||||||
|
button=(54, 146, 200, 182),
|
||||||
|
),
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/PRESET1_ON.png',
|
||||||
|
area=(54, 146, 200, 182),
|
||||||
|
search=(34, 126, 220, 202),
|
||||||
|
color=(48, 77, 115),
|
||||||
|
button=(54, 146, 200, 182),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
PRESET2_OFF = ButtonWrapper(
|
||||||
|
name='PRESET2_OFF',
|
||||||
|
jp=None,
|
||||||
|
en=None,
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/PRESET2_OFF.png',
|
||||||
|
area=(214, 144, 355, 180),
|
||||||
|
search=(194, 124, 375, 200),
|
||||||
|
color=(252, 253, 253),
|
||||||
|
button=(214, 144, 355, 180),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
PRESET2_ON = ButtonWrapper(
|
||||||
|
name='PRESET2_ON',
|
||||||
|
jp=None,
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/auto_mission/PRESET2_ON.png',
|
||||||
|
area=(211, 147, 355, 182),
|
||||||
|
search=(191, 127, 375, 202),
|
||||||
|
color=(50, 78, 116),
|
||||||
|
button=(211, 147, 355, 182),
|
||||||
|
),
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/PRESET2_ON.png',
|
||||||
|
area=(211, 147, 355, 182),
|
||||||
|
search=(191, 127, 375, 202),
|
||||||
|
color=(50, 78, 116),
|
||||||
|
button=(211, 147, 355, 182),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
PRESET3_OFF = ButtonWrapper(
|
||||||
|
name='PRESET3_OFF',
|
||||||
|
jp=None,
|
||||||
|
en=None,
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/PRESET3_OFF.png',
|
||||||
|
area=(369, 143, 516, 186),
|
||||||
|
search=(349, 123, 536, 206),
|
||||||
|
color=(251, 252, 252),
|
||||||
|
button=(369, 143, 516, 186),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
PRESET3_ON = ButtonWrapper(
|
||||||
|
name='PRESET3_ON',
|
||||||
|
jp=None,
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/auto_mission/PRESET3_ON.png',
|
||||||
|
area=(365, 146, 517, 184),
|
||||||
|
search=(345, 126, 537, 204),
|
||||||
|
color=(49, 78, 116),
|
||||||
|
button=(365, 146, 517, 184),
|
||||||
|
),
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/PRESET3_ON.png',
|
||||||
|
area=(365, 146, 517, 184),
|
||||||
|
search=(345, 126, 537, 204),
|
||||||
|
color=(49, 78, 116),
|
||||||
|
button=(365, 146, 517, 184),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
PRESET4_OFF = ButtonWrapper(
|
||||||
|
name='PRESET4_OFF',
|
||||||
|
jp=None,
|
||||||
|
en=None,
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/PRESET4_OFF.png',
|
||||||
|
area=(527, 146, 675, 183),
|
||||||
|
search=(507, 126, 695, 203),
|
||||||
|
color=(252, 252, 253),
|
||||||
|
button=(527, 146, 675, 183),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
PRESET4_ON = ButtonWrapper(
|
||||||
|
name='PRESET4_ON',
|
||||||
|
jp=None,
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/auto_mission/PRESET4_ON.png',
|
||||||
|
area=(528, 148, 676, 178),
|
||||||
|
search=(508, 128, 696, 198),
|
||||||
|
color=(50, 78, 117),
|
||||||
|
button=(528, 148, 676, 178),
|
||||||
|
),
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/PRESET4_ON.png',
|
||||||
|
area=(528, 148, 676, 178),
|
||||||
|
search=(508, 128, 696, 198),
|
||||||
|
color=(50, 78, 117),
|
||||||
|
button=(528, 148, 676, 178),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
PRESET_FIRST_ITEM = ButtonWrapper(
|
||||||
|
name='PRESET_FIRST_ITEM',
|
||||||
|
jp=None,
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/auto_mission/PRESET_FIRST_ITEM.png',
|
||||||
|
area=(28, 184, 1252, 397),
|
||||||
|
search=(8, 164, 1272, 417),
|
||||||
|
color=(214, 224, 231),
|
||||||
|
button=(28, 184, 1252, 397),
|
||||||
|
),
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/PRESET_FIRST_ITEM.png',
|
||||||
|
area=(28, 184, 1252, 397),
|
||||||
|
search=(8, 164, 1272, 417),
|
||||||
|
color=(214, 224, 231),
|
||||||
|
button=(28, 184, 1252, 397),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
PRESET_LIST = ButtonWrapper(
|
||||||
|
name='PRESET_LIST',
|
||||||
|
jp=None,
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/auto_mission/PRESET_LIST.png',
|
||||||
|
area=(556, 85, 726, 120),
|
||||||
|
search=(536, 65, 746, 140),
|
||||||
|
color=(197, 205, 213),
|
||||||
|
button=(556, 85, 726, 120),
|
||||||
|
),
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/PRESET_LIST.png',
|
||||||
|
area=(567, 83, 708, 120),
|
||||||
|
search=(547, 63, 728, 140),
|
||||||
|
color=(177, 187, 197),
|
||||||
|
button=(567, 83, 708, 120),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
PRESET_WINDOW = ButtonWrapper(
|
||||||
|
name='PRESET_WINDOW',
|
||||||
|
jp=None,
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/auto_mission/PRESET_WINDOW.png',
|
||||||
|
area=(28, 184, 1252, 649),
|
||||||
|
search=(8, 164, 1272, 669),
|
||||||
|
color=(215, 226, 233),
|
||||||
|
button=(28, 184, 1252, 649),
|
||||||
|
),
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/PRESET_WINDOW.png',
|
||||||
|
area=(28, 184, 1252, 649),
|
||||||
|
search=(8, 164, 1272, 669),
|
||||||
|
color=(215, 226, 233),
|
||||||
|
button=(28, 184, 1252, 649),
|
||||||
|
),
|
||||||
|
)
|
||||||
RANK = ButtonWrapper(
|
RANK = ButtonWrapper(
|
||||||
name='RANK',
|
name='RANK',
|
||||||
jp=None,
|
jp=None,
|
||||||
@ -345,6 +537,24 @@ RANK = ButtonWrapper(
|
|||||||
button=(540, 628, 738, 689),
|
button=(540, 628, 738, 689),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
RECEIVED_CHEST = ButtonWrapper(
|
||||||
|
name='RECEIVED_CHEST',
|
||||||
|
jp=None,
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/auto_mission/RECEIVED_CHEST.png',
|
||||||
|
area=(502, 188, 774, 226),
|
||||||
|
search=(482, 168, 794, 246),
|
||||||
|
color=(198, 208, 217),
|
||||||
|
button=(547, 487, 738, 547),
|
||||||
|
),
|
||||||
|
zht=Button(
|
||||||
|
file='./assets/zht/auto_mission/RECEIVED_CHEST.png',
|
||||||
|
area=(569, 192, 704, 226),
|
||||||
|
search=(549, 172, 724, 246),
|
||||||
|
color=(177, 187, 197),
|
||||||
|
button=(549, 488, 736, 543),
|
||||||
|
),
|
||||||
|
)
|
||||||
REWARD_ACQUIRED = ButtonWrapper(
|
REWARD_ACQUIRED = ButtonWrapper(
|
||||||
name='REWARD_ACQUIRED',
|
name='REWARD_ACQUIRED',
|
||||||
jp=None,
|
jp=None,
|
||||||
|
|||||||
@ -7,60 +7,34 @@ from module.base.timer import Timer
|
|||||||
from module.exception import RequestHumanTakeover
|
from module.exception import RequestHumanTakeover
|
||||||
from module.logger import logger
|
from module.logger import logger
|
||||||
from tasks.item.data_update import DataUpdate
|
from tasks.item.data_update import DataUpdate
|
||||||
from module.base.decorator import cached_property
|
|
||||||
|
import re
|
||||||
|
|
||||||
class AutoMissionStatus(Enum):
|
class AutoMissionStatus(Enum):
|
||||||
AP = 0 # Calculate AP and decide to terminate Auto-Mission module or not
|
AP = 0 # Calculate AP and decide to terminate Auto-Mission module or not
|
||||||
NAVIGATE = 1 # Navigate to the area and select mode
|
STAGES_DATA = 1
|
||||||
ENTER = 2 # Enter the first stage in the stage list
|
NAVIGATE = 2 # Navigate to the area and select mode
|
||||||
CHECK = 3 # Check stages and find a stage that requires to be completed
|
ENTER = 3 # Enter the first stage in the stage list
|
||||||
START = 4 # Start the stage
|
CHECK = 4 # Check stages and find a stage that requires to be completed
|
||||||
FORMATION = 5 # Select units based on the types required by the stage
|
START = 5 # Start the stage
|
||||||
FIGHT = 6 # Fight the stage
|
FORMATION = 6 # Select units based on the types required by the stage
|
||||||
|
FIGHT = 7 # Fight the stage
|
||||||
|
END = 8
|
||||||
FINISH = -1 # Indicate termination of Auto-Mission module
|
FINISH = -1 # Indicate termination of Auto-Mission module
|
||||||
|
|
||||||
class AutoMission(AutoMissionUI, Mission):
|
class AutoMission(AutoMissionUI, Mission):
|
||||||
@property
|
def __init__(self, config, device):
|
||||||
def mission_info(self) -> list:
|
super().__init__(config, device)
|
||||||
valid = True
|
self.task = None
|
||||||
mode = ("N", "H")
|
self.previous_mode = None
|
||||||
enable = (self.config.Normal_Enable, self.config.Hard_Enable)
|
self.previous_area = None
|
||||||
area = (self.config.Normal_Area, self.config.Hard_Area)
|
self._stage = None
|
||||||
stages_data = [None, None]
|
self.stages_data = None
|
||||||
completion_level = (self.config.Normal_Completion, self.config.Hard_Completion)
|
self.default_type_to_preset = self.get_default_type_to_preset()
|
||||||
for index in range(2):
|
self.current_type_to_preset = None
|
||||||
if enable[index]:
|
|
||||||
stages_data[index] = self.get_stages_data(mode[index], area[index])
|
|
||||||
valid = valid if self.check_formation(mode[index], area[index], stages_data[index]) else False
|
|
||||||
if valid:
|
|
||||||
info = zip(mode, area, stages_data, completion_level)
|
|
||||||
return list(filter(lambda x: x[2], info))
|
|
||||||
|
|
||||||
def check_formation(self, mode, area, stages_data):
|
|
||||||
mode_name = "Normal" if mode == "N" else "Hard"
|
|
||||||
if stages_data:
|
|
||||||
for stage, info in stages_data.items():
|
|
||||||
if "start" in info:
|
|
||||||
types = info["start"]
|
|
||||||
list_unit = []
|
|
||||||
list_type = []
|
|
||||||
for type in types:
|
|
||||||
list_type.append(type)
|
|
||||||
unit = self.type_to_unit[type]
|
|
||||||
if unit in list_unit:
|
|
||||||
logger.error(f"Mission {mode_name} {area} requires {list_type} but they are both set to unit {unit}")
|
|
||||||
return False
|
|
||||||
list_unit.append(unit)
|
|
||||||
if list_unit and list_unit[0] > unit:
|
|
||||||
logger.error(f"Mission {mode_name} {area} requires {list_type} but they are set to units {list_unit} respectively.\
|
|
||||||
Due to Auto-Mission's implementation, the first unit's index must be smaller than the second unit's index.")
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
@cached_property
|
def get_default_type_to_preset(self):
|
||||||
def type_to_unit(self):
|
type_to_preset = {
|
||||||
return {
|
|
||||||
"burst1": self.config.Formation_burst1,
|
"burst1": self.config.Formation_burst1,
|
||||||
"burst2": self.config.Formation_burst2,
|
"burst2": self.config.Formation_burst2,
|
||||||
"pierce1": self.config.Formation_pierce1,
|
"pierce1": self.config.Formation_pierce1,
|
||||||
@ -68,6 +42,83 @@ class AutoMission(AutoMissionUI, Mission):
|
|||||||
"mystic1": self.config.Formation_mystic1,
|
"mystic1": self.config.Formation_mystic1,
|
||||||
"mystic2": self.config.Formation_mystic2
|
"mystic2": self.config.Formation_mystic2
|
||||||
}
|
}
|
||||||
|
valid = True
|
||||||
|
|
||||||
|
for type, preset in type_to_preset.items():
|
||||||
|
preset_list = []
|
||||||
|
if isinstance(preset, str):
|
||||||
|
preset = re.sub(r'[ \t\r\n]', '', preset)
|
||||||
|
preset = preset.split("-")
|
||||||
|
if len(preset) == 2:
|
||||||
|
column = preset[0]
|
||||||
|
row = preset[1]
|
||||||
|
if (column.isdigit() and 1 <= int(column) <= 4) and (row.isdigit() and 1 <= int(row) <= 5):
|
||||||
|
preset_list = [int(num) for num in preset]
|
||||||
|
if not preset_list:
|
||||||
|
logger.error(f"Failed to read {type}'s preset settings")
|
||||||
|
valid = False
|
||||||
|
continue
|
||||||
|
type_to_preset[type] = preset_list
|
||||||
|
|
||||||
|
if not valid:
|
||||||
|
raise RequestHumanTakeover
|
||||||
|
return type_to_preset
|
||||||
|
|
||||||
|
def validate_area(self, mode, area_input):
|
||||||
|
area_list = []
|
||||||
|
if isinstance(area_input, str):
|
||||||
|
area_input = re.sub(r'[ \t\r\n]', '', area_input)
|
||||||
|
area_input = (re.sub(r'[>﹥›˃ᐳ❯]', '>', area_input)).split('>')
|
||||||
|
# tried to convert to set to remove duplicates but doesn't maintain order
|
||||||
|
[area_list.append(x) for x in area_input if x not in area_list]
|
||||||
|
elif isinstance(area_input, int):
|
||||||
|
area_list = [str(area_input)]
|
||||||
|
|
||||||
|
if area_list and len([x for x in area_list if x.isdigit()]) == len(area_list):
|
||||||
|
return area_list
|
||||||
|
|
||||||
|
mode_name = "Normal" if mode == "N" else "H"
|
||||||
|
logger.error(f"Failed to read Mission {mode_name}'s area settings")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def find_alternative(self, type, preset_list):
|
||||||
|
if not self.config.Formation_Substitute:
|
||||||
|
return None
|
||||||
|
|
||||||
|
alternatives_dictionary = {
|
||||||
|
'pierce1': ['pierce2', 'burst1', 'burst2', 'mystic1', 'mystic2'],
|
||||||
|
'pierce2': ['burst1', 'burst2', 'mystic1', 'mystic2'],
|
||||||
|
'burst1': ['burst2', 'pierce1', 'pierce2', 'mystic1', 'mystic2'],
|
||||||
|
'burst2': ['pierce1', 'pierce2', 'mystic1', 'mystic2'],
|
||||||
|
'mystic1': ['mystic2', 'burst1', 'burst2', 'pierce1', 'pierce2'],
|
||||||
|
'mystic2': ['burst1', 'burst2', 'pierce1', 'pierce2'],
|
||||||
|
}
|
||||||
|
alternatives = alternatives_dictionary[type]
|
||||||
|
for alternative in alternatives:
|
||||||
|
alternative_preset = self.default_type_to_preset[alternative]
|
||||||
|
if alternative_preset not in preset_list:
|
||||||
|
preset_list.append(alternative_preset)
|
||||||
|
logger.warning(f"{type} was replaced by {alternative}")
|
||||||
|
return preset_list
|
||||||
|
logger.error(f"Unable to find replacements for {type}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mission_info(self) -> list:
|
||||||
|
valid = True
|
||||||
|
mode = ("N", "H")
|
||||||
|
enable = (self.config.Normal_Enable, self.config.Hard_Enable)
|
||||||
|
area = (self.config.Normal_Area, self.config.Hard_Area)
|
||||||
|
area_list = [None, None]
|
||||||
|
completion_level = (self.config.Normal_Completion, self.config.Hard_Completion)
|
||||||
|
for index in range(2):
|
||||||
|
if enable[index]:
|
||||||
|
area_list[index] = self.validate_area(mode[index], area[index])
|
||||||
|
valid = valid if area_list[index] else False
|
||||||
|
if valid:
|
||||||
|
info = zip(mode, area_list, completion_level)
|
||||||
|
return list(filter(lambda x: x[1], info))
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_mode(self):
|
def current_mode(self):
|
||||||
@ -75,7 +126,7 @@ class AutoMission(AutoMissionUI, Mission):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def current_area(self):
|
def current_area(self):
|
||||||
return self.task[0][1]
|
return int(self.task[0][1][0])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_stage(self):
|
def current_stage(self):
|
||||||
@ -85,20 +136,67 @@ class AutoMission(AutoMissionUI, Mission):
|
|||||||
def current_stage(self, value):
|
def current_stage(self, value):
|
||||||
self._stage = value
|
self._stage = value
|
||||||
|
|
||||||
@property
|
|
||||||
def current_stages_data(self):
|
|
||||||
return self.task[0][2]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_completion_level(self):
|
def current_completion_level(self):
|
||||||
return self.task[0][3]
|
return self.task[0][2]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_count(self):
|
def current_count(self):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
def update_stages_data(self):
|
||||||
|
if [self.previous_mode, self.previous_area] != [self.current_mode, self.current_area]:
|
||||||
|
self.stages_data = self.get_stages_data(self.current_mode, self.current_area)
|
||||||
|
if self.stages_data:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def update_current_type_to_preset(self):
|
||||||
|
if [self.previous_mode, self.previous_area] == [self.current_mode, self.current_area]:
|
||||||
|
self.current_type_to_preset = None
|
||||||
|
return True
|
||||||
|
|
||||||
|
mode_name = "Normal" if self.current_mode == "N" else "Hard"
|
||||||
|
use_alternative = False
|
||||||
|
for stage, info in self.stages_data.items():
|
||||||
|
if "start" not in info:
|
||||||
|
continue
|
||||||
|
|
||||||
|
list_preset = []
|
||||||
|
list_type = []
|
||||||
|
for type in info["start"]:
|
||||||
|
preset = self.default_type_to_preset[type]
|
||||||
|
list_type.append(type)
|
||||||
|
|
||||||
|
if preset not in list_preset:
|
||||||
|
list_preset.append(preset)
|
||||||
|
continue
|
||||||
|
logger.error(f"Mission {mode_name} {self.current_area} requires {list_type} but they are both set to preset {preset}")
|
||||||
|
list_preset = self.find_alternative(type, list_preset)
|
||||||
|
use_alternative = True
|
||||||
|
if list_preset:
|
||||||
|
continue
|
||||||
|
return False
|
||||||
|
|
||||||
|
if use_alternative:
|
||||||
|
d = {}
|
||||||
|
for index in range(len(list_type)):
|
||||||
|
type, preset = list_type[index], list_preset[index]
|
||||||
|
d[type] = preset
|
||||||
|
self.current_type_to_preset = d
|
||||||
|
else:
|
||||||
|
self.current_type_to_preset = self.default_type_to_preset
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def update_task(self):
|
def update_task(self):
|
||||||
self.task.pop(0)
|
self.previous_mode = self.current_mode
|
||||||
|
self.previous_area = self.current_area
|
||||||
|
area_list = self.task[0][1]
|
||||||
|
area_list.pop(0)
|
||||||
|
if not area_list:
|
||||||
|
self.task.pop(0)
|
||||||
|
|
||||||
def handle_auto_mission(self, status):
|
def handle_auto_mission(self, status):
|
||||||
match status:
|
match status:
|
||||||
@ -106,42 +204,49 @@ class AutoMission(AutoMissionUI, Mission):
|
|||||||
if self.task:
|
if self.task:
|
||||||
self.realistic_count = self.get_realistic_count()
|
self.realistic_count = self.get_realistic_count()
|
||||||
if self.realistic_count != 0:
|
if self.realistic_count != 0:
|
||||||
return AutoMissionStatus.NAVIGATE
|
return AutoMissionStatus.STAGES_DATA
|
||||||
return AutoMissionStatus.FINISH
|
return AutoMissionStatus.FINISH
|
||||||
|
|
||||||
|
case AutoMissionStatus.STAGES_DATA:
|
||||||
|
if self.update_stages_data() and self.update_current_type_to_preset():
|
||||||
|
return AutoMissionStatus.NAVIGATE
|
||||||
|
return AutoMissionStatus.END
|
||||||
|
|
||||||
case AutoMissionStatus.NAVIGATE:
|
case AutoMissionStatus.NAVIGATE:
|
||||||
switch = SWITCH_NORMAL if self.current_mode == "N" else SWITCH_HARD
|
switch = SWITCH_NORMAL if self.current_mode == "N" else SWITCH_HARD
|
||||||
self.navigate(self.previous_mode, self.current_mode)
|
self.navigate(self.previous_mode, self.current_mode)
|
||||||
if self.select_area(self.current_area) and self.select_mode(switch):
|
if self.select_area(self.current_area) and self.select_mode(switch):
|
||||||
return AutoMissionStatus.ENTER
|
return AutoMissionStatus.ENTER
|
||||||
raise RequestHumanTakeover
|
raise RequestHumanTakeover
|
||||||
|
|
||||||
case AutoMissionStatus.ENTER:
|
case AutoMissionStatus.ENTER:
|
||||||
if self.wait_mission_info(self.current_mode, open_task=True):
|
if self.wait_mission_info(self.current_mode, open_task=True):
|
||||||
return AutoMissionStatus.CHECK
|
return AutoMissionStatus.CHECK
|
||||||
raise RequestHumanTakeover
|
raise RequestHumanTakeover
|
||||||
|
|
||||||
case AutoMissionStatus.CHECK:
|
case AutoMissionStatus.CHECK:
|
||||||
self.current_stage = self.check_stages(*self.task[0])
|
self.current_stage = self.check_stages(self.current_mode, self.current_area, self.stages_data, self.current_completion_level)
|
||||||
if self.current_stage:
|
if self.current_stage:
|
||||||
return AutoMissionStatus.START
|
return AutoMissionStatus.START
|
||||||
self.update_task()
|
return AutoMissionStatus.END
|
||||||
return AutoMissionStatus.AP
|
|
||||||
|
|
||||||
case AutoMissionStatus.START:
|
case AutoMissionStatus.START:
|
||||||
self.start_stage(self.current_stage)
|
self.start_stage(self.current_stage)
|
||||||
return AutoMissionStatus.FORMATION
|
return AutoMissionStatus.FORMATION
|
||||||
|
|
||||||
case AutoMissionStatus.FORMATION:
|
case AutoMissionStatus.FORMATION:
|
||||||
self.formation(self.current_stage, self.type_to_unit)
|
self.formation(self.current_stage, self.current_type_to_preset)
|
||||||
return AutoMissionStatus.FIGHT
|
return AutoMissionStatus.FIGHT
|
||||||
|
|
||||||
case AutoMissionStatus.FIGHT:
|
case AutoMissionStatus.FIGHT:
|
||||||
self.fight(self.current_stage, manual_boss=self.config.ManualBoss_Enable)
|
self.fight(self.current_stage, manual_boss=self.config.ManualBoss_Enable)
|
||||||
# Return to the previous region to prevent map unlock card recognition
|
|
||||||
self.select_area(self.current_area - 1)
|
|
||||||
self.update_ap()
|
self.update_ap()
|
||||||
self.previous_mode = self.current_mode
|
self.previous_mode = self.current_mode
|
||||||
|
self.previous_area = self.current_area
|
||||||
|
return AutoMissionStatus.AP
|
||||||
|
|
||||||
|
case AutoMissionStatus.END:
|
||||||
|
self.update_task()
|
||||||
return AutoMissionStatus.AP
|
return AutoMissionStatus.AP
|
||||||
|
|
||||||
case AutoMissionStatus.FINISH:
|
case AutoMissionStatus.FINISH:
|
||||||
@ -153,8 +258,6 @@ class AutoMission(AutoMissionUI, Mission):
|
|||||||
return status
|
return status
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.previous_mode = None
|
|
||||||
self._stage = None
|
|
||||||
self.task = self.valid_task
|
self.task = self.valid_task
|
||||||
if self.task:
|
if self.task:
|
||||||
action_timer = Timer(0.5, 1)
|
action_timer = Timer(0.5, 1)
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
from module.base.timer import Timer
|
from module.base.timer import Timer
|
||||||
from module.logger import logger
|
from module.logger import logger
|
||||||
from module.ui.switch import Switch
|
from module.ui.switch import Switch
|
||||||
|
from module.ui.scroll_select import ScrollSelect
|
||||||
from module.ocr.ocr import Digit
|
from module.ocr.ocr import Digit
|
||||||
from tasks.base.ui import UI
|
from tasks.base.ui import UI
|
||||||
from tasks.base.assets.assets_base_page import MISSION_CHECK
|
from tasks.base.assets.assets_base_page import MISSION_CHECK
|
||||||
from tasks.auto_mission.assets.assets_auto_mission import *
|
from tasks.auto_mission.assets.assets_auto_mission import *
|
||||||
from tasks.auto_mission.stage import StageState
|
from tasks.auto_mission.stage import StageState
|
||||||
|
|
||||||
|
SCROLL_SELECT = ScrollSelect(PRESET_WINDOW, PRESET_FIRST_ITEM, MOBILIZE, clickx=1150, responsey=60, swipeoffsetx=-600)
|
||||||
|
PRESETS = [PRESET1_ON, PRESET2_ON, PRESET3_ON, PRESET4_ON]
|
||||||
|
|
||||||
SWITCH_UNIT1 = Switch('Unit1_Switch')
|
SWITCH_UNIT1 = Switch('Unit1_Switch')
|
||||||
SWITCH_UNIT1.add_state('on', UNIT1_ON)
|
SWITCH_UNIT1.add_state('on', UNIT1_ON)
|
||||||
SWITCH_UNIT1.add_state('off', UNIT1_OFF)
|
SWITCH_UNIT1.add_state('off', UNIT1_OFF)
|
||||||
@ -74,8 +78,21 @@ class Copilot(UI):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
"""Formation methods"""
|
"""Formation methods"""
|
||||||
def choose_unit(self, type, type_to_unit):
|
def choose_from_preset(self, type, type_to_preset):
|
||||||
unit_index = type_to_unit[type] - 1
|
preset, row = type_to_preset[type]
|
||||||
|
preset_index = preset - 1
|
||||||
|
row_index = row - 1
|
||||||
|
self.select_then_check(LAYOUT, PRESET_LIST)
|
||||||
|
#self.set_switch(PRESET_SWITCHES[preset_index])
|
||||||
|
PRESET = PRESETS[preset_index]
|
||||||
|
while not self.match_color(PRESET, threshold=50):
|
||||||
|
self.device.screenshot()
|
||||||
|
self.click_with_interval(PRESET, interval=1)
|
||||||
|
clickoffsety = [85, 85, 0, -120, 0]
|
||||||
|
SCROLL_SELECT.select_index(main=self, target_index=row_index, clickoffsety=clickoffsety[row_index])
|
||||||
|
|
||||||
|
def choose_unit(self, unit):
|
||||||
|
unit_index = unit - 1
|
||||||
unit_switch = UNIT_SWITCHES[unit_index]
|
unit_switch = UNIT_SWITCHES[unit_index]
|
||||||
self.set_switch(unit_switch)
|
self.set_switch(unit_switch)
|
||||||
|
|
||||||
@ -86,16 +103,23 @@ class Copilot(UI):
|
|||||||
return True
|
return True
|
||||||
self.click(*start_coords, interval=2)
|
self.click(*start_coords, interval=2)
|
||||||
|
|
||||||
def formation(self, stage, type_to_unit):
|
def formation(self, stage, type_to_preset):
|
||||||
if stage.state == StageState.SUB:
|
if stage.state == StageState.SUB:
|
||||||
# Select a unit to start the battle
|
# Select a unit to start the battle
|
||||||
self.choose_unit(stage.formation_info, type_to_unit)
|
self.choose_unit(1)
|
||||||
|
if type_to_preset:
|
||||||
|
type = stage.formation_info
|
||||||
|
self.choose_from_preset(type, type_to_preset)
|
||||||
self.click_with_interval(MOBILIZE, interval=1)
|
self.click_with_interval(MOBILIZE, interval=1)
|
||||||
else:
|
else:
|
||||||
|
unit = 1
|
||||||
for type, start_coords in stage.formation_start_info:
|
for type, start_coords in stage.formation_start_info:
|
||||||
self.goto_formation_page(start_coords)
|
self.goto_formation_page(start_coords)
|
||||||
self.choose_unit(type, type_to_unit)
|
self.choose_unit(unit)
|
||||||
|
if type_to_preset:
|
||||||
|
self.choose_from_preset(type, type_to_preset)
|
||||||
self.select_then_check(MOBILIZE, MISSION_INFO)
|
self.select_then_check(MOBILIZE, MISSION_INFO)
|
||||||
|
unit += 1
|
||||||
|
|
||||||
"""Fight methods"""
|
"""Fight methods"""
|
||||||
def begin_mission(self):
|
def begin_mission(self):
|
||||||
@ -122,7 +146,20 @@ class Copilot(UI):
|
|||||||
force_index = self.get_force()
|
force_index = self.get_force()
|
||||||
self.sleep(1)
|
self.sleep(1)
|
||||||
return force_index
|
return force_index
|
||||||
|
|
||||||
|
def handle_all_mission_popup(self):
|
||||||
|
self.sleep(2)
|
||||||
|
while not self.match_color(MISSION_INFO):
|
||||||
|
self.device.screenshot()
|
||||||
|
if self.match_color(MISSION_INFO):
|
||||||
|
break
|
||||||
|
if self.appear_then_click(MISSION_INFO_POPUP):
|
||||||
|
continue
|
||||||
|
if self.appear_then_click(MOVE_UNIT):
|
||||||
|
continue
|
||||||
|
if self.appear_then_click(RECEIVED_CHEST):
|
||||||
|
continue
|
||||||
|
|
||||||
def handle_mission_popup(self, button, skip_first_screenshot=True):
|
def handle_mission_popup(self, button, skip_first_screenshot=True):
|
||||||
while 1:
|
while 1:
|
||||||
if skip_first_screenshot:
|
if skip_first_screenshot:
|
||||||
@ -146,9 +183,10 @@ class Copilot(UI):
|
|||||||
while 1:
|
while 1:
|
||||||
self.device.screenshot()
|
self.device.screenshot()
|
||||||
if not self.match_color(END_PHASE):
|
if not self.match_color(END_PHASE):
|
||||||
self.handle_mission_popup(END_PHASE_POPUP)
|
self.handle_all_mission_popup()
|
||||||
break
|
break
|
||||||
self.appear_then_click(END_PHASE)
|
self.appear_then_click(END_PHASE)
|
||||||
|
self.sleep(2)
|
||||||
|
|
||||||
def wait_over(self):
|
def wait_over(self):
|
||||||
#self.sleep(2)
|
#self.sleep(2)
|
||||||
@ -220,6 +258,8 @@ class Copilot(UI):
|
|||||||
if 'wait-over' in act:
|
if 'wait-over' in act:
|
||||||
self.wait_over()
|
self.wait_over()
|
||||||
self.sleep(2)
|
self.sleep(2)
|
||||||
|
if i != len(actions) - 1:
|
||||||
|
self.handle_all_mission_popup()
|
||||||
|
|
||||||
logger.warning("Actions completed, waiting to enter the battle...")
|
logger.warning("Actions completed, waiting to enter the battle...")
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,8 @@ class AutoMissionUI(Copilot):
|
|||||||
# Get stage_data data from the module
|
# Get stage_data data from the module
|
||||||
return stage_data
|
return stage_data
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
logger.error(f"Exploration not supported for area {area}, under development...")
|
mode_name = "Normal" if mode == "N" else "Hard"
|
||||||
|
logger.error(f"Exploration not supported for Mission {mode_name} area {area}, under development...")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def wait_mission_info(self, mode, open_task=False, max_retry=99999):
|
def wait_mission_info(self, mode, open_task=False, max_retry=99999):
|
||||||
|
|||||||
@ -4,10 +4,10 @@ from module.base.decorator import Config
|
|||||||
from module.base.timer import Timer
|
from module.base.timer import Timer
|
||||||
from module.logger import logger
|
from module.logger import logger
|
||||||
from module.ocr.ocr import DigitCounter
|
from module.ocr.ocr import DigitCounter
|
||||||
|
from module.ui.scroll_select import ScrollSelect
|
||||||
from tasks.base.assets.assets_base_page import SCHEDULE_CHECK
|
from tasks.base.assets.assets_base_page import SCHEDULE_CHECK
|
||||||
from tasks.base.ui import UI
|
from tasks.base.ui import UI
|
||||||
from tasks.schedule.assets.assets_schedule import *
|
from tasks.schedule.assets.assets_schedule import *
|
||||||
from tasks.schedule.scroll_select import ScrollSelect
|
|
||||||
|
|
||||||
SCROLL_SELECT = ScrollSelect(window_button=SCROLL, first_item_button=FIRST_ITEM, expected_button=LOCATIONS, clickx=1116)
|
SCROLL_SELECT = ScrollSelect(window_button=SCROLL, first_item_button=FIRST_ITEM, expected_button=LOCATIONS, clickx=1116)
|
||||||
xs = np.linspace(299, 995, 3, dtype=int)
|
xs = np.linspace(299, 995, 3, dtype=int)
|
||||||
@ -51,7 +51,7 @@ class ScheduleUI(UI):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def enter_location(self, location):
|
def enter_location(self, location):
|
||||||
SCROLL_SELECT.select_location(self, location)
|
SCROLL_SELECT.select_index(main=self, target_index=location)
|
||||||
if not self.appear(LOCATIONS):
|
if not self.appear(LOCATIONS):
|
||||||
logger.error("Unable to navigate to page for location {}".format(location + 1))
|
logger.error("Unable to navigate to page for location {}".format(location + 1))
|
||||||
return False
|
return False
|
||||||
|
|||||||