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

Compare commits

...

74 Commits

Author SHA1 Message Date
0d1c936541
fix: update assets file 2025-09-23 20:03:39 +08:00
6581511e1a
fix: update configs to enable new bounty stage for OVERSEA server 2025-09-23 20:03:20 +08:00
c562913778
fix: update ui assets for en 2025-09-23 20:03:19 +08:00
95148d2548
fix: update assets file 2025-08-09 13:20:45 +08:00
44605f42cd
fix: update ui assets for OVERSEA server 2025-08-09 13:20:21 +08:00
fdc50c77a5
fix: update assets file 2025-07-22 20:21:06 +08:00
15ebf70681
fix: update ui assets for jp 2025-07-22 20:20:36 +08:00
b34c37a4b7
fix: update configs 2025-05-18 19:58:36 +08:00
92408edd79
fix(bounty): update stage select option 2025-05-18 19:58:35 +08:00
49c0894227
fix: update assets file 2025-05-13 21:56:02 +08:00
1497a0a825
fix(cafe): update ui assets for jp & en 2025-05-13 21:55:42 +08:00
e41b8bf54a
fix(cafe): synchronize Cafe No.2 for global server 2025-05-13 21:55:41 +08:00
cae02d62ec
fix: update assets file 2025-04-22 19:54:32 +08:00
b16d25f9f5
fix: update ui assets for jp 2025-04-22 19:53:39 +08:00
6cd0ded0c9
fix(cafe): correct invitation detection of Cafe No.2 in OVERSEA server 2025-03-08 18:44:34 +08:00
62c147fdab
fix(cafe): adjust timer of Cafe No.2 2025-01-22 19:40:43 +08:00
5d4c5f939b
fix(cafe): adjust click template offset 2025-01-22 19:40:32 +08:00
e6649762c8
fix: update assets file 2025-01-20 23:19:29 +08:00
8cb4803f80
fix(cafe): update ui assets for jp 2025-01-20 23:18:06 +08:00
51c7a5fed2
fix(cafe): update latest Cafe No.2 switch for jp 2025-01-20 23:17:39 +08:00
e7ecf0e94f
fix: update assets file 2024-11-12 18:16:45 +08:00
2a1394d733
fix(cafe): update ui assets for en 2024-11-12 18:16:45 +08:00
164dee90d9
lang(cafe): correct Cafe No.2 description 2024-11-12 18:16:44 +08:00
f0da132f4e
fix(cafe): enable Cafe No.2 for OVERSEA server 2024-11-12 18:03:30 +08:00
191c3b31dc
fix: update assets file 2024-10-23 23:32:55 +08:00
a5d20a95be
fix: update ui assets for en 2024-10-23 23:32:47 +08:00
7f0b2ff73f
fix: update assets file 2024-09-24 14:07:02 +08:00
daf55b76e2
fix: update ui assets for en 2024-09-24 14:06:27 +08:00
5b2e22163a
fix: update assets file 2024-07-24 17:27:50 +08:00
2ec7e45172
fix: update ui assets and circle for en 2024-07-24 17:27:38 +08:00
cd27718801
fix: update assets file 2024-07-11 18:03:37 +08:00
2b12f51110
fix: update jp ui assets 2024-07-11 18:02:45 +08:00
a059394b71
fix: update assets file 2024-07-09 16:05:05 +08:00
cdccc85207
fix: update en ui assets 2024-07-09 16:04:18 +08:00
9a1d8f101d
fix: update assets file 2024-05-04 20:15:01 +08:00
bb5224d721
fix: update en ui assets 2024-05-04 20:11:50 +08:00
573d742c03
fix: update assets file 2024-05-04 19:55:41 +08:00
f9076ae537
fix: update en ui assets 2024-05-04 19:54:57 +08:00
9d9e3c0f91
fix: update ui assets for jp 2024-04-24 19:38:24 +08:00
c6063a4f3d
fix: update ui assets for jp 2024-03-27 20:35:23 +08:00
b9cf5aa910
fix: update ui assets for jp 2024-02-21 18:26:00 +08:00
d082df0f03
fix: update ui assets and circle for jp 2024-01-25 19:40:09 +08:00
Cheong Sik Feng
2f44074400 Fix Tactical Challenge button mask image
With the addition of the Grand Assault, the Joint Firing Drill button was moved to the top half of where the Tactical Challenge button previously was, and the new Tactical Challenge button is only the lower half.
2023-12-25 16:26:57 +08:00
0f6dd93608
fix(sweep): remove index if equal 0 2023-12-09 21:22:11 +08:00
f5cf0a7fbe
fix(tc): add handle ui_additional 2023-12-07 18:24:09 +08:00
16d78e1e16
fix(sweep): correct load index situation 2023-12-07 13:04:05 +08:00
7b707be841
refactor(scrimmage): use stage ap count 2023-12-06 17:11:50 +08:00
93bf1f73e2
feat: separate stage ap count 2023-12-05 16:21:19 +08:00
71da6fd996
feat: add auto select for bounty and scrimmage 2023-11-30 14:21:19 +08:00
ecd4ba0a7c
doc: update readme 2023-11-29 18:38:59 +08:00
d684fd79f6
feat(sweep): support finding max sweepable index 2023-11-29 14:55:55 +08:00
6ae785634c
refactor(sweep): separate sweepable check and search_box generate 2023-11-29 14:11:51 +08:00
a0d3fd75af
refactor(sweep): change current_indexes 2023-11-29 14:05:50 +08:00
257e092936
refactor(sweep): use regex for index match 2023-11-29 13:54:55 +08:00
32cee3f6b5
fix(cafe): adjust name of invitation 2023-11-29 12:39:51 +08:00
659f58db38
fix(cafe): add check of null invitation name 2023-11-28 21:46:21 +08:00
6dac8a1de2
feat(cafe): add invitation assets for en 2023-11-28 20:53:24 +08:00
b1aeb64768
lang: change option description 2023-11-28 20:53:01 +08:00
88e8a98b76
fix(cafe): apply config of choice only when not set before 2023-11-28 16:18:34 +08:00
39d00ac549
fix(cafe): correct target name check 2023-11-28 16:11:50 +08:00
11d2a6ef7e
feat(cafe): add invitation condition check 2023-11-28 14:04:37 +08:00
1f5b68d095
feat(webui): add invitation condition options 2023-11-28 14:04:07 +08:00
5f3ff140dd
feat(cafe): add invitation 2023-11-27 22:02:50 +08:00
8698fa20c2
feat(webui): add config of invitation options 2023-11-27 20:48:37 +08:00
b426c6caac
feat(cafe): add invitation assets for jp 2023-11-27 15:44:56 +08:00
8d83ec1657
fix: add swipe name 2023-11-27 15:26:27 +08:00
7fcda15329
perf(sweep): improve list insight logic 2023-11-27 13:17:29 +08:00
54aa1bafb5
refactor(sweep): simplify list enter match 2023-11-26 18:54:26 +08:00
d756b0dc3f
perf: reduce config save times 2023-11-25 15:28:57 +08:00
e71118c09e
fix: improve data update stability 2023-11-25 15:28:07 +08:00
44b6d5cdf8
fix: expand ticket ocr region 2023-11-25 14:27:01 +08:00
f92dba92c9
fix(sweep): use swipe instead of drag in list 2023-11-24 14:30:43 +08:00
86ce04cff9
fix(sweep): extend timer stable 2023-11-24 13:59:39 +08:00
f2065507c2
fix(ui): change task order 2023-11-23 16:37:16 +08:00
105 changed files with 1117 additions and 395 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] **悬赏通缉** 自动扫荡

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
assets/en/cafe/OCR_NAME.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
assets/en/circle/CIRCLE.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
assets/jp/cafe/OCR_NAME.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
assets/jp/circle/CIRCLE.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -45,14 +45,13 @@
"Touch": true,
"AutoAdjust": true,
"SecondCafe": true
}
},
"Mail": {
"Scheduler": {
},
"Invitation": {
"Enable": true,
"NextRun": "2020-01-01 00:00:00",
"Command": "Mail",
"ServerUpdate": "04:00"
"WaitingHour": 0,
"Choice": "list_top",
"Name": null,
"Substitute": false
}
},
"Circle": {
@ -63,6 +62,14 @@
"ServerUpdate": "04:00"
}
},
"Mail": {
"Scheduler": {
"Enable": true,
"NextRun": "2020-01-01 00:00:00",
"Command": "Mail",
"ServerUpdate": "04:00"
}
},
"Bounty": {
"Scheduler": {
"Enable": true,
@ -74,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
}
},
@ -97,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

@ -205,32 +205,37 @@
"type": "checkbox",
"value": true
}
}
},
"Mail": {
"Scheduler": {
},
"Invitation": {
"Enable": {
"type": "checkbox",
"value": true,
"value": true
},
"WaitingHour": {
"type": "select",
"value": 0,
"option": [
true,
false
0,
3,
6,
9
]
},
"NextRun": {
"type": "datetime",
"value": "2020-01-01 00:00:00",
"validate": "datetime"
"Choice": {
"type": "select",
"value": "list_top",
"option": [
"list_top",
"by_name"
]
},
"Command": {
"type": "input",
"value": "Mail",
"display": "hide"
"Name": {
"type": "textarea",
"value": null
},
"ServerUpdate": {
"type": "input",
"value": "04:00",
"display": "hide"
"Substitute": {
"type": "checkbox",
"value": false
}
}
},
@ -261,6 +266,33 @@
}
}
},
"Mail": {
"Scheduler": {
"Enable": {
"type": "checkbox",
"value": true,
"option": [
true,
false
]
},
"NextRun": {
"type": "datetime",
"value": "2020-01-01 00:00:00",
"validate": "datetime"
},
"Command": {
"type": "input",
"value": "Mail",
"display": "hide"
},
"ServerUpdate": {
"type": "input",
"value": "04:00",
"display": "hide"
}
}
},
"Bounty": {
"Scheduler": {
"Enable": {
@ -300,8 +332,9 @@
"Highway": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,
@ -310,7 +343,8 @@
6,
7,
8,
9
9,
10
]
},
"Count": {
@ -321,8 +355,9 @@
"DesertRailroad": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,
@ -331,7 +366,8 @@
6,
7,
8,
9
9,
10
]
},
"Count": {
@ -342,8 +378,9 @@
"Schoolhouse": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,
@ -352,7 +389,8 @@
6,
7,
8,
9
9,
10
]
},
"Count": {
@ -400,8 +438,9 @@
"Trinity": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,
@ -416,8 +455,9 @@
"Gehenna": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,
@ -432,8 +472,9 @@
"Millennium": {
"Stage": {
"type": "select",
"value": 1,
"value": 0,
"option": [
0,
1,
2,
3,

View File

@ -80,6 +80,18 @@ Cafe:
Touch: true
AutoAdjust: true
SecondCafe: true
Invitation:
Enable: true
WaitingHour:
value: 0
option: [ 0, 3, 6, 9 ]
Choice:
value: list_top
option: [ list_top, by_name ]
Name:
value: null
type: textarea
Substitute: false
Bounty:
OnError:
@ -88,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, 10 ]
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, 10 ]
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, 10 ]
Count: 2
Scrimmage:
@ -109,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

@ -12,8 +12,8 @@
"page": "setting",
"tasks": [
"Cafe",
"Mail",
"Circle",
"Mail",
"Bounty",
"Scrimmage",
"TacticalChallenge",

View File

@ -25,10 +25,11 @@ Daily:
Cafe:
- Scheduler
- Cafe
Mail:
- Scheduler
- Invitation
Circle:
- Scheduler
Mail:
- Scheduler
Bounty:
- Scheduler
- Bounty

View File

@ -45,34 +45,41 @@ class GeneratedConfig:
Cafe_AutoAdjust = True
Cafe_SecondCafe = True
# Group `Invitation`
Invitation_Enable = True
Invitation_WaitingHour = 0 # 0, 3, 6, 9
Invitation_Choice = 'list_top' # list_top, by_name
Invitation_Name = None
Invitation_Substitute = False
# Group `Bounty`
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, 10
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, 10
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, 10
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

@ -22,14 +22,14 @@
"name": "Cafe",
"help": ""
},
"Mail": {
"name": "Mailbox",
"help": ""
},
"Circle": {
"name": "Club",
"help": ""
},
"Mail": {
"name": "Mailbox",
"help": ""
},
"Bounty": {
"name": "Bounty",
"help": ""
@ -218,7 +218,39 @@
},
"SecondCafe": {
"name": "Second Floor",
"help": "JP server only\nEnable auto switch to second floor and perform interaction"
"help": "Enable auto switch to second floor and perform interaction"
}
},
"Invitation": {
"_info": {
"name": "Invitation Settings",
"help": ""
},
"Enable": {
"name": "Enable",
"help": "Enable cafe invitation"
},
"WaitingHour": {
"name": "Invitation Condition",
"help": "Choose whether to invite students based on the remaining time before next cafe refresh\nThis is for obtaining maximum student interation and maximum affection when AFK. Recommended option:\n24*7 AFK:\t\t Choose \"If 9 more hours remaining\"\nNormal usage:\t Choose \"Invite immediately\"",
"0": "Invite immediately",
"3": "If 3 more hours remaining",
"6": "If 6 more hours remaining",
"9": "If 9 more hours remaining"
},
"Choice": {
"name": "Choose Inviting Student",
"help": "Top first student of list: Invite the student at the top first of the list\nBy name: Invite the student with the name you set below",
"list_top": "Top first student of list",
"by_name": "By name"
},
"Name": {
"name": "Inviting Student Name",
"help": "Fill in the name of the student to be invited. Use in-game text language. Use > to connect multiple students. Example:\nJP: ホシノ(水着) > 御坂美琴 > ユズ\nOVERSEA: Hoshino(Swimsuit) > Yuuka > Kayoko(New Year)"
},
"Substitute": {
"name": "Replace existing student",
"help": "Whether to replace the existing student with their alt.\nIf not, try to match the next student"
}
},
"Bounty": {
@ -241,6 +273,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Overpass A",
"2": "02 - Overpass B",
"3": "03 - Overpass C",
@ -249,7 +282,8 @@
"6": "06 - Overpass F",
"7": "07 - Overpass G",
"8": "08 - Overpass H",
"9": "09 - Overpass I"
"9": "09 - Overpass I",
"10": "10 - Overpass J"
},
"Count": {
"name": "Sweep X times",
@ -264,6 +298,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Abandoned Train A",
"2": "02 - Abandoned Train B",
"3": "03 - Abandoned Train C",
@ -272,7 +307,8 @@
"6": "06 - Abandoned Train F",
"7": "07 - Abandoned Train G",
"8": "08 - Abandoned Train H",
"9": "09 - Abandoned Train I"
"9": "09 - Abandoned Train I",
"10": "10 - Abandoned Train J"
},
"Count": {
"name": "Sweep X times",
@ -287,6 +323,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Besieged Classroom A",
"2": "02 - Besieged Classroom B",
"3": "03 - Besieged Classroom C",
@ -295,7 +332,8 @@
"6": "06 - Besieged Classroom F",
"7": "07 - Besieged Classroom G",
"8": "08 - Besieged Classroom H",
"9": "09 - Besieged Classroom I"
"9": "09 - Besieged Classroom I",
"10": "10 - Besieged Classroom J"
},
"Count": {
"name": "Sweep X times",
@ -322,6 +360,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Trinity A",
"2": "02 - Trinity B",
"3": "03 - Trinity C",
@ -340,6 +379,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Gehenna A",
"2": "02 - Gehenna B",
"3": "03 - Gehenna C",
@ -358,6 +398,7 @@
"Stage": {
"name": "Select Stage",
"help": "",
"0": "Auto select",
"1": "01 - Millennium A",
"2": "02 - Millennium B",
"3": "03 - Millennium C",

View File

@ -22,14 +22,14 @@
"name": "咖啡厅",
"help": ""
},
"Mail": {
"name": "邮箱",
"help": ""
},
"Circle": {
"name": "公会",
"help": "社团 / 小组"
},
"Mail": {
"name": "邮箱",
"help": ""
},
"Bounty": {
"name": "悬赏通缉",
"help": ""
@ -218,7 +218,39 @@
},
"SecondCafe": {
"name": "第二咖啡厅",
"help": "仅支持日服\n自动切换第二咖啡厅进行互动点击"
"help": "自动切换第二咖啡厅进行互动点击"
}
},
"Invitation": {
"_info": {
"name": "邀请设置",
"help": ""
},
"Enable": {
"name": "启用",
"help": "是否启用咖啡厅邀请功能"
},
"WaitingHour": {
"name": "邀请条件",
"help": "根据距离下一次咖啡厅刷新的时长,选择是否邀请学生\n此项设立是为了后台挂机最大化收益使得邀请券能被最大化利用。推荐选项\n常驻挂机\t选择“离下次刷新 9 小时以上”\n非常驻挂机\t选择“不等待刷新立即邀请”或根据自己挂机时长选择",
"0": "不等待刷新,立即邀请",
"3": "离下次刷新 3 小时以上",
"6": "离下次刷新 6 小时以上",
"9": "离下次刷新 9 小时以上"
},
"Choice": {
"name": "选择邀请学生",
"help": "按列表第一个:优先邀请列表中第一个学生,若失败则则尝试下一个\n按名字优先邀请下方填写学生名的第一个若失败则尝试下一个",
"list_top": "按列表第一个",
"by_name": "按名字"
},
"Name": {
"name": "邀请学生名",
"help": "填写要邀请的学生的名字,使用游戏内语言填写,多个学生使用 > 连接。例:\n日服\tホシ(水着) > 御坂美琴 > ユズ\n国际服\tHoshino(Swimsuit) > Yuuka > Kayoko(New Year)"
},
"Substitute": {
"name": "是否替换已存在学生",
"help": "若咖啡厅已存在所邀请学生的不同服装,选择是否替换该学生\n若不替换则尝试匹配下一位学生"
}
},
"Bounty": {
@ -241,6 +273,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 高架公路 A",
"2": "02 - 高架公路 B",
"3": "03 - 高架公路 C",
@ -249,7 +282,8 @@
"6": "06 - 高架公路 F",
"7": "07 - 高架公路 G",
"8": "08 - 高架公路 H",
"9": "09 - 高架公路 I"
"9": "09 - 高架公路 I",
"10": "10 - 高架公路 J"
},
"Count": {
"name": "扫荡次数",
@ -264,6 +298,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 被遗弃的列车 A",
"2": "02 - 被遗弃的列车 B",
"3": "03 - 被遗弃的列车 C",
@ -272,7 +307,8 @@
"6": "06 - 被遗弃的列车 F",
"7": "07 - 被遗弃的列车 G",
"8": "08 - 被遗弃的列车 H",
"9": "09 - 被遗弃的列车 I"
"9": "09 - 被遗弃的列车 I",
"10": "10 - 被遗弃的列车 J"
},
"Count": {
"name": "扫荡次数",
@ -287,6 +323,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 被袭击的教室 A",
"2": "02 - 被袭击的教室 B",
"3": "03 - 被袭击的教室 C",
@ -295,7 +332,8 @@
"6": "06 - 被袭击的教室 F",
"7": "07 - 被袭击的教室 G",
"8": "08 - 被袭击的教室 H",
"9": "09 - 被袭击的教室 I"
"9": "09 - 被袭击的教室 I",
"10": "10 - 被袭击的教室 J"
},
"Count": {
"name": "扫荡次数",
@ -322,6 +360,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 三一 A",
"2": "02 - 三一 B",
"3": "03 - 三一 C",
@ -340,6 +379,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 格黑娜 A",
"2": "02 - 格黑娜 B",
"3": "03 - 格黑娜 C",
@ -358,6 +398,7 @@
"Stage": {
"name": "选择关卡",
"help": "",
"0": "自动选择",
"1": "01 - 千年 A",
"2": "02 - 千年 B",
"3": "03 - 千年 C",

View File

@ -51,17 +51,17 @@ CAFE_CHECK = ButtonWrapper(
name='CAFE_CHECK',
jp=Button(
file='./assets/jp/base/page/CAFE_CHECK.png',
area=(264, 11, 337, 35),
search=(244, 0, 357, 55),
color=(188, 197, 205),
button=(264, 11, 337, 35),
area=(108, 11, 182, 36),
search=(88, 0, 202, 56),
color=(191, 200, 208),
button=(108, 11, 182, 36),
),
en=Button(
file='./assets/en/base/page/CAFE_CHECK.png',
area=(196, 8, 259, 37),
search=(176, 0, 279, 57),
color=(188, 197, 206),
button=(196, 8, 259, 37),
area=(106, 12, 167, 36),
search=(86, 0, 187, 56),
color=(173, 184, 194),
button=(106, 12, 167, 36),
),
)
CIRCLE_CHECK = ButtonWrapper(
@ -183,10 +183,10 @@ MAIN_GO_TO_CIRCLE = ButtonWrapper(
name='MAIN_GO_TO_CIRCLE',
share=Button(
file='./assets/share/base/page/MAIN_GO_TO_CIRCLE.png',
area=(540, 631, 583, 660),
search=(520, 611, 603, 680),
color=(131, 204, 234),
button=(540, 631, 583, 660),
area=(542, 630, 581, 665),
search=(522, 610, 601, 685),
color=(163, 225, 242),
button=(542, 630, 581, 665),
),
)
MAIN_GO_TO_CRAFTING = ButtonWrapper(
@ -233,10 +233,10 @@ MAIN_GO_TO_PURCHASE = ButtonWrapper(
name='MAIN_GO_TO_PURCHASE',
share=Button(
file='./assets/share/base/page/MAIN_GO_TO_PURCHASE.png',
area=(148, 204, 183, 253),
search=(128, 184, 203, 273),
color=(172, 214, 239),
button=(148, 204, 183, 253),
area=(147, 214, 179, 254),
search=(127, 194, 199, 274),
color=(171, 216, 241),
button=(147, 214, 179, 254),
),
)
MAIN_GO_TO_SCHEDULE = ButtonWrapper(
@ -273,17 +273,17 @@ MAIN_GO_TO_WORK = ButtonWrapper(
name='MAIN_GO_TO_WORK',
jp=Button(
file='./assets/jp/base/page/MAIN_GO_TO_WORK.png',
area=(1167, 605, 1241, 632),
search=(1147, 585, 1261, 652),
color=(135, 149, 169),
button=(1167, 605, 1241, 632),
area=(1169, 588, 1239, 612),
search=(1149, 568, 1259, 632),
color=(150, 162, 180),
button=(1169, 588, 1239, 612),
),
en=Button(
file='./assets/en/base/page/MAIN_GO_TO_WORK.png',
area=(1127, 605, 1250, 637),
search=(1107, 585, 1270, 657),
color=(90, 112, 141),
button=(1127, 605, 1250, 637),
area=(1143, 591, 1241, 613),
search=(1123, 571, 1261, 633),
color=(110, 129, 154),
button=(1143, 591, 1241, 613),
),
)
MISSION_CHECK = ButtonWrapper(
@ -446,101 +446,101 @@ WORK_GO_TO_BOUNTY = ButtonWrapper(
name='WORK_GO_TO_BOUNTY',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_BOUNTY.png',
area=(669, 412, 765, 436),
search=(649, 392, 785, 456),
color=(165, 181, 208),
button=(669, 412, 765, 436),
area=(667, 383, 764, 409),
search=(647, 363, 784, 429),
color=(171, 187, 212),
button=(667, 383, 764, 409),
),
en=Button(
file='./assets/en/base/page/WORK_GO_TO_BOUNTY.png',
area=(671, 409, 760, 440),
search=(651, 389, 780, 460),
color=(183, 202, 227),
button=(671, 409, 760, 440),
area=(668, 385, 756, 412),
search=(648, 365, 776, 432),
color=(180, 198, 223),
button=(668, 385, 756, 412),
),
)
WORK_GO_TO_COMMISSIONS = ButtonWrapper(
name='WORK_GO_TO_COMMISSIONS',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_COMMISSIONS.png',
area=(655, 494, 751, 518),
search=(635, 474, 771, 538),
color=(165, 179, 204),
button=(655, 494, 751, 518),
area=(653, 475, 749, 501),
search=(633, 455, 769, 521),
color=(171, 185, 208),
button=(653, 475, 749, 501),
),
en=Button(
file='./assets/en/base/page/WORK_GO_TO_COMMISSIONS.png',
area=(656, 494, 803, 517),
search=(636, 474, 823, 537),
color=(192, 204, 221),
button=(656, 494, 803, 517),
area=(653, 477, 787, 496),
search=(633, 457, 807, 516),
color=(187, 199, 218),
button=(653, 477, 787, 496),
),
)
WORK_GO_TO_MISSION = ButtonWrapper(
name='WORK_GO_TO_MISSION',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_MISSION.png',
area=(720, 160, 803, 199),
search=(700, 140, 823, 219),
color=(165, 178, 204),
button=(720, 160, 803, 199),
area=(722, 155, 807, 199),
search=(702, 135, 827, 219),
color=(173, 188, 211),
button=(722, 155, 807, 199),
),
en=Button(
file='./assets/en/base/page/WORK_GO_TO_MISSION.png',
area=(720, 160, 871, 206),
search=(700, 140, 891, 226),
color=(192, 204, 221),
button=(720, 160, 871, 206),
area=(721, 158, 873, 197),
search=(701, 138, 893, 217),
color=(180, 195, 215),
button=(721, 158, 873, 197),
),
)
WORK_GO_TO_SCHOOL_EXCHANGE = ButtonWrapper(
name='WORK_GO_TO_SCHOOL_EXCHANGE',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_SCHOOL_EXCHANGE.png',
area=(641, 575, 758, 599),
search=(621, 555, 778, 619),
color=(165, 179, 204),
button=(641, 575, 758, 599),
area=(636, 566, 753, 592),
search=(616, 546, 773, 612),
color=(176, 187, 207),
button=(636, 566, 753, 592),
),
en=Button(
file='./assets/en/base/page/WORK_GO_TO_SCHOOL_EXCHANGE.png',
area=(643, 572, 778, 602),
search=(623, 552, 798, 622),
color=(190, 203, 221),
button=(643, 572, 778, 602),
area=(635, 569, 769, 597),
search=(615, 549, 789, 617),
color=(198, 204, 216),
button=(635, 569, 769, 597),
),
)
WORK_GO_TO_STORY = ButtonWrapper(
name='WORK_GO_TO_STORY',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_STORY.png',
area=(995, 163, 1032, 197),
search=(975, 143, 1052, 217),
color=(191, 201, 219),
button=(995, 163, 1032, 197),
area=(998, 155, 1078, 199),
search=(978, 135, 1098, 219),
color=(215, 221, 232),
button=(998, 155, 1078, 199),
),
en=Button(
file='./assets/en/base/page/WORK_GO_TO_STORY.png',
area=(994, 159, 1109, 211),
search=(974, 139, 1129, 231),
color=(208, 215, 228),
button=(994, 159, 1109, 211),
area=(996, 159, 1112, 205),
search=(976, 139, 1132, 225),
color=(200, 209, 225),
button=(996, 159, 1112, 205),
),
)
WORK_GO_TO_TACTICAL_CHALLENGE = ButtonWrapper(
name='WORK_GO_TO_TACTICAL_CHALLENGE',
jp=Button(
file='./assets/jp/base/page/WORK_GO_TO_TACTICAL_CHALLENGE.png',
area=(1012, 535, 1151, 562),
search=(992, 515, 1171, 582),
color=(159, 174, 200),
button=(1012, 535, 1151, 562),
area=(801, 565, 920, 593),
search=(781, 545, 940, 613),
color=(172, 186, 209),
button=(801, 565, 920, 593),
),
en=Button(
file='./assets/en/base/page/WORK_GO_TO_TACTICAL_CHALLENGE.png',
area=(1034, 435, 1162, 466),
search=(1014, 415, 1182, 486),
color=(179, 199, 221),
button=(1034, 435, 1162, 466),
area=(803, 566, 922, 623),
search=(783, 546, 942, 643),
color=(186, 201, 220),
button=(803, 566, 922, 623),
),
)

View File

@ -75,17 +75,17 @@ OCR_TICKET = ButtonWrapper(
name='OCR_TICKET',
jp=Button(
file='./assets/jp/bounty/OCR_TICKET.png',
area=(195, 85, 237, 113),
search=(175, 65, 257, 133),
color=(197, 206, 213),
button=(195, 85, 237, 113),
area=(196, 87, 258, 113),
search=(176, 67, 278, 133),
color=(173, 197, 212),
button=(196, 87, 258, 113),
),
en=Button(
file='./assets/en/bounty/OCR_TICKET.png',
area=(225, 85, 267, 114),
search=(205, 65, 287, 134),
color=(197, 206, 213),
button=(225, 85, 267, 114),
area=(229, 89, 285, 112),
search=(209, 69, 305, 132),
color=(177, 194, 207),
button=(229, 89, 285, 112),
),
)
SELECT_DESERT_RAILROAD = ButtonWrapper(

View File

@ -41,8 +41,9 @@ class Bounty(BountyUI):
if action == 'stop':
raise RequestHumanTakeover
elif action == 'skip':
self.config.task_delay(server_update=True)
self.config.task_stop()
with self.config.multi_set():
self.config.task_delay(server_update=True)
self.config.task_stop()
@property
def is_ticket_enough(self) -> bool:

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

@ -27,85 +27,102 @@ CAFE_FIRST = ButtonWrapper(
name='CAFE_FIRST',
jp=Button(
file='./assets/jp/cafe/CAFE_FIRST.png',
area=(82, 152, 136, 175),
search=(62, 132, 156, 195),
color=(111, 127, 147),
button=(82, 152, 136, 175),
area=(96, 92, 111, 110),
search=(76, 72, 131, 130),
color=(185, 192, 200),
button=(96, 92, 111, 110),
),
en=Button(
file='./assets/en/cafe/CAFE_FIRST.png',
area=(82, 152, 136, 175),
search=(62, 132, 156, 195),
color=(111, 127, 147),
button=(82, 152, 136, 175),
area=(205, 96, 215, 107),
search=(185, 76, 235, 127),
color=(176, 184, 194),
button=(205, 96, 215, 107),
),
)
CAFE_INVITE = ButtonWrapper(
name='CAFE_INVITE',
jp=Button(
file='./assets/jp/cafe/CAFE_INVITE.png',
area=(870, 637, 903, 663),
search=(850, 617, 923, 683),
color=(253, 217, 235),
button=(870, 637, 903, 663),
),
en=Button(
file='./assets/en/cafe/CAFE_INVITE.png',
area=(870, 637, 903, 663),
search=(850, 617, 923, 683),
color=(253, 217, 235),
button=(870, 637, 903, 663),
),
)
CAFE_INVITED = ButtonWrapper(
name='CAFE_INVITED',
jp=Button(
file='./assets/jp/cafe/CAFE_INVITED.png',
area=(870, 637, 903, 663),
search=(850, 617, 923, 683),
color=(111, 109, 109),
button=(870, 637, 903, 663),
),
en=Button(
file='./assets/en/cafe/CAFE_INVITED.png',
area=(870, 637, 903, 663),
search=(850, 617, 923, 683),
color=(111, 109, 109),
button=(870, 637, 903, 663),
),
)
CAFE_SECOND = ButtonWrapper(
name='CAFE_SECOND',
jp=Button(
file='./assets/jp/cafe/CAFE_SECOND.png',
area=(219, 152, 279, 175),
search=(199, 132, 299, 195),
color=(110, 126, 146),
button=(219, 152, 279, 175),
area=(99, 92, 108, 110),
search=(79, 72, 128, 130),
color=(193, 200, 209),
button=(99, 92, 108, 110),
),
en=Button(
file='./assets/en/cafe/CAFE_SECOND.png',
area=(219, 152, 279, 175),
search=(199, 132, 299, 195),
color=(110, 126, 146),
button=(219, 152, 279, 175),
area=(207, 96, 214, 107),
search=(187, 76, 234, 127),
color=(174, 182, 192),
button=(207, 96, 214, 107),
),
)
CHANGE_CAFE_NOT_SELECTED = ButtonWrapper(
name='CHANGE_CAFE_NOT_SELECTED',
CHECK_MOMOTALK = ButtonWrapper(
name='CHECK_MOMOTALK',
jp=Button(
file='./assets/jp/cafe/CHANGE_CAFE_NOT_SELECTED.png',
area=(84, 89, 178, 109),
search=(64, 69, 198, 129),
color=(185, 193, 203),
button=(84, 89, 178, 109),
file='./assets/jp/cafe/CHECK_MOMOTALK.png',
area=(421, 83, 447, 108),
search=(401, 63, 467, 128),
color=(253, 203, 212),
button=(421, 83, 447, 108),
),
en=Button(
file='./assets/en/cafe/CHANGE_CAFE_NOT_SELECTED.png',
area=(84, 89, 178, 109),
search=(64, 69, 198, 129),
color=(185, 193, 203),
button=(84, 89, 178, 109),
),
)
CHANGE_CAFE_SELECTED = ButtonWrapper(
name='CHANGE_CAFE_SELECTED',
jp=Button(
file='./assets/jp/cafe/CHANGE_CAFE_SELECTED.png',
area=(40, 87, 191, 112),
search=(20, 67, 211, 132),
color=(82, 105, 130),
button=(40, 87, 191, 112),
),
en=Button(
file='./assets/en/cafe/CHANGE_CAFE_SELECTED.png',
area=(40, 87, 191, 112),
search=(20, 67, 211, 132),
color=(82, 105, 130),
button=(40, 87, 191, 112),
file='./assets/en/cafe/CHECK_MOMOTALK.png',
area=(421, 83, 447, 108),
search=(401, 63, 467, 128),
color=(253, 203, 212),
button=(421, 83, 447, 108),
),
)
CHECK_REWARD = ButtonWrapper(
name='CHECK_REWARD',
jp=Button(
file='./assets/jp/cafe/CHECK_REWARD.png',
area=(1095, 621, 1146, 637),
search=(1075, 601, 1166, 657),
color=(82, 105, 129),
button=(1086, 607, 1225, 685),
area=(1120, 635, 1166, 651),
search=(1100, 615, 1186, 671),
color=(79, 102, 127),
button=(1109, 627, 1239, 691),
),
en=Button(
file='./assets/en/cafe/CHECK_REWARD.png',
area=(1090, 613, 1229, 644),
search=(1070, 593, 1249, 664),
color=(64, 88, 115),
button=(1086, 611, 1229, 685),
area=(1116, 636, 1218, 654),
search=(1096, 616, 1238, 674),
color=(77, 100, 125),
button=(1113, 625, 1239, 692),
),
)
CLICKABLE_TEMPLATE = ButtonWrapper(
@ -129,10 +146,10 @@ GET_REWARD = ButtonWrapper(
),
en=Button(
file='./assets/en/cafe/GET_REWARD.png',
area=(581, 503, 692, 536),
search=(561, 483, 712, 556),
color=(208, 190, 63),
button=(539, 491, 741, 555),
area=(593, 506, 687, 548),
search=(573, 486, 707, 568),
color=(211, 193, 64),
button=(543, 492, 736, 564),
),
)
GET_REWARD_CLOSE = ButtonWrapper(
@ -146,10 +163,10 @@ GET_REWARD_CLOSE = ButtonWrapper(
),
en=Button(
file='./assets/en/cafe/GET_REWARD_CLOSE.png',
area=(883, 134, 926, 178),
search=(863, 114, 946, 198),
color=(215, 220, 224),
button=(883, 134, 926, 178),
area=(968, 132, 997, 162),
search=(948, 112, 1017, 182),
color=(187, 193, 201),
button=(968, 132, 997, 162),
),
)
GOT_REWARD = ButtonWrapper(
@ -163,10 +180,10 @@ GOT_REWARD = ButtonWrapper(
),
en=Button(
file='./assets/en/cafe/GOT_REWARD.png',
area=(543, 489, 741, 558),
search=(523, 469, 761, 578),
color=(211, 212, 212),
button=(543, 489, 741, 558),
area=(544, 493, 735, 563),
search=(524, 473, 755, 583),
color=(213, 213, 212),
button=(544, 493, 735, 563),
),
)
INVENTORY = ButtonWrapper(
@ -186,6 +203,91 @@ INVENTORY = ButtonWrapper(
button=(1123, 90, 1165, 130),
),
)
INVITE_CONFIRM = ButtonWrapper(
name='INVITE_CONFIRM',
jp=Button(
file='./assets/jp/cafe/INVITE_CONFIRM.png',
area=(609, 147, 671, 178),
search=(589, 127, 691, 198),
color=(152, 164, 177),
button=(665, 471, 870, 533),
),
en=Button(
file='./assets/en/cafe/INVITE_CONFIRM.png',
area=(592, 149, 689, 176),
search=(572, 129, 709, 196),
color=(169, 179, 191),
button=(664, 470, 872, 534),
),
)
INVITE_IN_SECOND = ButtonWrapper(
name='INVITE_IN_SECOND',
jp=Button(
file='./assets/jp/cafe/INVITE_IN_SECOND.png',
area=(482, 147, 799, 177),
search=(462, 127, 819, 197),
color=(166, 177, 188),
button=(482, 147, 799, 177),
),
en=Button(
file='./assets/en/cafe/INVITE_IN_SECOND.png',
area=(482, 147, 799, 177),
search=(462, 127, 819, 197),
color=(166, 177, 188),
button=(482, 147, 799, 177),
),
)
INVITE_IN_SECOND_CLOSE = ButtonWrapper(
name='INVITE_IN_SECOND_CLOSE',
jp=Button(
file='./assets/jp/cafe/INVITE_IN_SECOND_CLOSE.png',
area=(874, 150, 900, 176),
search=(854, 130, 920, 196),
color=(180, 189, 198),
button=(874, 150, 900, 176),
),
en=Button(
file='./assets/en/cafe/INVITE_IN_SECOND_CLOSE.png',
area=(874, 150, 900, 176),
search=(854, 130, 920, 196),
color=(180, 189, 198),
button=(874, 150, 900, 176),
),
)
INVITE_SUBSTITUTE = ButtonWrapper(
name='INVITE_SUBSTITUTE',
jp=Button(
file='./assets/jp/cafe/INVITE_SUBSTITUTE.png',
area=(582, 154, 698, 184),
search=(562, 134, 718, 204),
color=(154, 166, 179),
button=(673, 478, 858, 541),
),
en=Button(
file='./assets/en/cafe/INVITE_SUBSTITUTE.png',
area=(506, 157, 775, 186),
search=(486, 137, 795, 206),
color=(176, 186, 196),
button=(673, 477, 857, 542),
),
)
INVITE_SUBSTITUTE_CLOSE = ButtonWrapper(
name='INVITE_SUBSTITUTE_CLOSE',
jp=Button(
file='./assets/jp/cafe/INVITE_SUBSTITUTE_CLOSE.png',
area=(867, 158, 893, 184),
search=(847, 138, 913, 204),
color=(180, 189, 199),
button=(867, 158, 893, 184),
),
en=Button(
file='./assets/en/cafe/INVITE_SUBSTITUTE_CLOSE.png',
area=(867, 158, 893, 184),
search=(847, 138, 913, 204),
color=(180, 189, 199),
button=(867, 158, 893, 184),
),
)
MOMOTALK_CLOSE = ButtonWrapper(
name='MOMOTALK_CLOSE',
jp=Button(
@ -203,21 +305,72 @@ MOMOTALK_CLOSE = ButtonWrapper(
button=(824, 82, 850, 108),
),
)
MOMOTALK_INVITE = ButtonWrapper(
name='MOMOTALK_INVITE',
jp=Button(
file='./assets/jp/cafe/MOMOTALK_INVITE.png',
area=(764, 211, 809, 234),
search=(744, 191, 829, 254),
color=(90, 163, 195),
button=(764, 211, 809, 234),
),
en=Button(
file='./assets/en/cafe/MOMOTALK_INVITE.png',
area=(755, 210, 817, 233),
search=(735, 190, 837, 253),
color=(98, 179, 211),
button=(755, 210, 817, 233),
),
)
MOMOTALK_ITEM = ButtonWrapper(
name='MOMOTALK_ITEM',
jp=Button(
file='./assets/jp/cafe/MOMOTALK_ITEM.png',
area=(489, 193, 864, 259),
search=(469, 173, 884, 279),
color=(203, 230, 240),
button=(489, 193, 864, 259),
),
en=Button(
file='./assets/en/cafe/MOMOTALK_ITEM.png',
area=(489, 193, 864, 259),
search=(469, 173, 884, 279),
color=(203, 230, 240),
button=(489, 193, 864, 259),
),
)
OCR_CAFE = ButtonWrapper(
name='OCR_CAFE',
jp=Button(
file='./assets/jp/cafe/OCR_CAFE.png',
area=(1103, 642, 1202, 672),
search=(1083, 622, 1222, 692),
color=(87, 107, 129),
button=(1103, 642, 1202, 672),
area=(1127, 657, 1219, 682),
search=(1107, 637, 1239, 702),
color=(93, 112, 134),
button=(1127, 657, 1219, 682),
),
en=Button(
file='./assets/en/cafe/OCR_CAFE.png',
area=(1105, 639, 1195, 674),
search=(1085, 619, 1215, 694),
color=(84, 104, 127),
button=(1105, 639, 1195, 674),
area=(1127, 657, 1219, 682),
search=(1107, 637, 1239, 702),
color=(93, 112, 134),
button=(1127, 657, 1219, 682),
),
)
OCR_NAME = ButtonWrapper(
name='OCR_NAME',
jp=Button(
file='./assets/jp/cafe/OCR_NAME.png',
area=(488, 194, 704, 588),
search=(468, 174, 724, 608),
color=(237, 239, 241),
button=(488, 194, 704, 588),
),
en=Button(
file='./assets/en/cafe/OCR_NAME.png',
area=(488, 194, 704, 588),
search=(468, 174, 724, 608),
color=(237, 239, 241),
button=(488, 194, 704, 588),
),
)
STUDENT_LIST = ButtonWrapper(

View File

@ -1,17 +1,13 @@
from enum import Enum
from module.base.decorator import Config
from module.base.timer import Timer
from module.logger import logger
from module.ui.switch import Switch
from tasks.base.page import page_cafe
from tasks.cafe.assets.assets_cafe import *
from tasks.cafe.invitation import handle_invitation
from tasks.cafe.ui import CafeUI
SWITCH_CAFE = Switch('Cafe_switch')
SWITCH_CAFE.add_state('off', CHANGE_CAFE_NOT_SELECTED)
SWITCH_CAFE.add_state('on', CHANGE_CAFE_SELECTED)
SWITCH_CAFE_SELECT = Switch('Cafe_switch_select')
SWITCH_CAFE_SELECT.add_state('1', CAFE_FIRST)
SWITCH_CAFE_SELECT.add_state('2', CAFE_SECOND)
@ -22,22 +18,17 @@ class CafeStatus(Enum):
OCR = 1
REWARD = 2
GOT = 3
CLICK = 4
CHECK = 5
INVITATION = 4
CLICK = 5
CHECK = 6
FINISHED = -1
class Cafe(CafeUI):
@Config.when(Emulator_GameLanguage='jp')
def _is_second_cafe_on(self):
@property
def is_second_cafe_on(self):
return self.config.Cafe_SecondCafe
@Config.when(Emulator_GameLanguage=None)
def _is_second_cafe_on(self):
return False
is_second_cafe_on = property(_is_second_cafe_on)
def _handle_cafe(self, status):
match status:
case CafeStatus.STUDENT_LIST:
@ -63,9 +54,12 @@ class Cafe(CafeUI):
logger.info('Cafe reward have been got')
self.appear_then_click(GET_REWARD_CLOSE)
if not self.appear(GET_REWARD_CLOSE):
return CafeStatus.INVITATION
case CafeStatus.INVITATION:
if handle_invitation(self):
return CafeStatus.CLICK
case CafeStatus.CLICK:
buttons = self.get_clickable_buttons(offset=(45, 10))
buttons = self.get_clickable_buttons()
self.click = len(buttons)
logger.attr('Clickable', self.click)
if not buttons:
@ -111,7 +105,6 @@ class Cafe(CafeUI):
status = CafeStatus.STUDENT_LIST
loading_timer = Timer(2).start()
action_timer = Timer(1, count=1)
is_list = False
is_reset = False
is_second = False
is_enable = is_reward_on or is_touch_on
@ -128,11 +121,6 @@ class Cafe(CafeUI):
if not loading_timer.reached():
continue
if not is_list and status == CafeStatus.STUDENT_LIST and self.appear(STUDENT_LIST):
is_list = True
loading_timer = Timer(3).start()
continue
if not is_reward_on and status == CafeStatus.OCR:
logger.info('Skip reward')
status = CafeStatus.CLICK
@ -149,26 +137,19 @@ class Cafe(CafeUI):
continue
if self.is_second_cafe_on and not is_second and status == CafeStatus.FINISHED:
if not SWITCH_CAFE.appear(main=self):
logger.warning('Cafe switch not found')
continue
if SWITCH_CAFE.get(main=self) == 'off':
SWITCH_CAFE.set('on', main=self)
logger.info('Switching to second cafe')
if not SWITCH_CAFE_SELECT.appear(main=self):
logger.info('Cafe switch select not found')
logger.info('Cafe switch not found')
continue
match (SWITCH_CAFE_SELECT.get(main=self)):
match SWITCH_CAFE_SELECT.get(main=self):
case '1':
if self.click_with_interval(CAFE_SECOND):
if self.click_with_interval(CAFE_FIRST):
continue
case '2':
logger.info('Cafe second arrived')
SWITCH_CAFE.set('off', main=self)
status = CafeStatus.STUDENT_LIST
is_list = False
is_second = True
self.check = 0
loading_timer.reset().start()
if action_timer.reached_and_reset():
logger.attr('Status', status)

314
tasks/cafe/invitation.py Normal file
View File

@ -0,0 +1,314 @@
import re
from datetime import datetime, timedelta
from enum import Enum
import numpy as np
from module.base.base import ModuleBase
from module.base.timer import Timer
from module.base.utils import area_offset, area_size
from module.config.utils import get_server_next_update
from module.logger import logger
from module.ocr.ocr import Ocr
from tasks.cafe.assets.assets_cafe import *
class InvitationOcr(Ocr):
def after_process(self, result):
result = super().after_process(result)
result = result.replace('モI', 'モエ')
return result
class InvitationStatus(Enum):
MOMOTALK = 0
OCR = 1
SELECT = 2
CONFIRM = 3
SUBSTITUTE = 4
IN_SECOND = 5
INVITED = 6
FAILED = 7
FINISHED = -1
class Invitation:
swipe_vector_range = (0.65, 0.85)
cafe_update = ["04:00", "16:00"]
def __init__(self, name: str):
self.name = name
self.ocr = InvitationOcr(OCR_NAME)
self.list = OCR_NAME
self.item = MOMOTALK_ITEM
self.invite = MOMOTALK_INVITE
self.target_names = []
self.waiting_hour = None
self.substitute = None
self.choice = None
self.invited = []
self.current_names = []
def __str__(self):
return f'Invitation({self.name})'
__repr__ = __str__
def __eq__(self, other):
return str(self) == str(other)
def __hash__(self):
return hash(self.name)
def swipe_page(self, main: ModuleBase, vector_range=None, reverse=False):
"""
Args:
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)
vector = (0, -vector * height)
if reverse:
vector = (-vector[0], -vector[1])
name = f'{self.name}_SWIPE'
main.device.swipe_vector(vector, self.list.button, name=name)
main.device.click_record_remove(name)
def load_names(self, main: ModuleBase):
names = self.ocr.detect_and_ocr(main.device.image)
if not names:
logger.warning(f'No valid names in {self.ocr.name}')
return
self.current_names = []
for name_ in names:
name: str = name_.ocr_text.replace(' ', '')
if name.isdigit():
continue
if name.startswith('('):
if not self.current_names:
continue
n = self.current_names.pop(len(self.current_names) - 1)
self.current_names.append((n[0] + name, n[1]))
continue
self.current_names.append((name, name_.box))
@property
def is_invitation(self) -> bool:
return get_server_next_update(self.cafe_update) - datetime.now() > timedelta(hours=self.waiting_hour)
@property
def names(self):
return list(map(lambda x: x[0], self.current_names))
@property
def target_name(self):
return self.target_names[0] if self.target_names else None
def on_success(self):
logger.info(f'Invited {self.target_name}')
self.invited.append(self.target_name)
self.target_names.pop(0)
def on_failed(self):
logger.warning(f'Failed to invite {self.target_name}')
self.target_names.pop(0)
def insight_name(self, name: str, main: ModuleBase, skip_first_screenshot=True) -> bool:
"""
Args:
name:
main:
skip_first_screenshot:
"""
logger.info(f'Insight name: {name}')
last_names: set[str] = set()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
main.device.screenshot()
self.load_names(main)
if name in self.names:
return True
names = self.names
if names and last_names == set(names):
logger.warning(f'Name not found: {name}')
return False
last_names = set(names)
self.swipe_page(main)
main.wait_until_stable(
self.list.button,
timer=Timer(0, 0),
timeout=Timer(1.5, 5)
)
def select_name_invite(
self,
main: ModuleBase,
name: str = None,
insight: bool = True,
skip_first_screenshot: bool = True
) -> bool:
"""
Args:
main:
name:
insight:
skip_first_screenshot:
Returns:
If success
"""
if name is None:
if not self.target_name:
return False
name = self.target_name
if insight and not self.insight_name(name, main, skip_first_screenshot):
return False
logger.info(f'Select name: {name}')
click_interval = Timer(1, 2)
load_names_interval = Timer(1, 5)
timeout = Timer(10, 10).start()
while 1:
if skip_first_screenshot:
skip_first_screenshot = False
else:
main.device.screenshot()
if load_names_interval.reached_and_reset() and not insight:
self.load_names(main)
name_box = next(filter(lambda x: x[0] == name, self.current_names), None)
if name_box is None:
logger.warning(f'No name {name} in {self.ocr.name}')
continue
search_box = area_offset((0, 0, *area_size(self.item.area)), name_box[1][:2])
self.invite.load_search(search_box)
click_button = self.invite.match_multi_template(main.device.image)
if not click_button:
logger.warning(f'No clickable {self.invite.name}')
continue
if click_interval.reached_and_reset():
main.device.click(click_button[0])
return True
if timeout.reached():
logger.warning(f'No clickable {self.invite.name}')
return False
invitation = Invitation('CafeInvitation')
def handle_invitation_status(status: InvitationStatus, main: ModuleBase) -> InvitationStatus:
match status:
case InvitationStatus.MOMOTALK:
if not invitation.is_invitation:
logger.info('Invitation waiting until next refresh')
return InvitationStatus.FINISHED
if main.match_color(CAFE_INVITED):
logger.info('Invitation in cooldown')
return InvitationStatus.FINISHED
if invitation.choice != 'list_top' and invitation.target_name is None:
logger.warning('No student to be invited or all invitations failed')
return InvitationStatus.FINISHED
if main.appear(CHECK_MOMOTALK):
return InvitationStatus.OCR
main.appear_then_click(CAFE_INVITE)
case InvitationStatus.OCR:
if invitation.choice == 'list_top':
invitation.load_names(main)
invitation.target_names = invitation.names
invitation.choice = 'list'
if invitation.select_name_invite(main):
return InvitationStatus.SELECT
return InvitationStatus.FAILED
case InvitationStatus.SELECT:
if main.appear(INVITE_CONFIRM):
return InvitationStatus.CONFIRM
if main.appear(INVITE_IN_SECOND):
return InvitationStatus.IN_SECOND
if main.appear(INVITE_SUBSTITUTE):
return InvitationStatus.SUBSTITUTE
case InvitationStatus.CONFIRM:
main.appear_then_click(INVITE_CONFIRM)
if not main.appear(INVITE_CONFIRM):
invitation.on_success()
return InvitationStatus.INVITED
case InvitationStatus.IN_SECOND:
main.appear_then_click(INVITE_IN_SECOND_CLOSE)
return InvitationStatus.FAILED
case InvitationStatus.SUBSTITUTE:
if not invitation.substitute:
main.appear_then_click(INVITE_SUBSTITUTE_CLOSE)
return InvitationStatus.FAILED
else:
main.appear_then_click(INVITE_SUBSTITUTE)
if not main.appear(INVITE_SUBSTITUTE):
return InvitationStatus.INVITED
case InvitationStatus.INVITED:
main.appear_then_click(MOMOTALK_CLOSE)
if not main.appear(MOMOTALK_CLOSE):
return InvitationStatus.FINISHED
case InvitationStatus.FAILED:
main.appear_then_click(MOMOTALK_CLOSE)
if not main.appear(CHECK_MOMOTALK):
invitation.on_failed()
return InvitationStatus.MOMOTALK
case InvitationStatus.FINISHED:
pass
case _:
logger.warning(f'Invalid status: {status}')
return status
def handle_invitation(main: ModuleBase):
if not main.config.Invitation_Enable:
logger.info('Invitation disabled')
return True
invitation.waiting_hour = main.config.Invitation_WaitingHour
invitation.substitute = main.config.Invitation_Substitute
if invitation.choice is None:
invitation.choice = main.config.Invitation_Choice
if invitation.choice == 'by_name' and not invitation.target_names:
name = main.config.Invitation_Name
if name is None:
logger.warning('Choose By Name but Inviting Student Name is blank')
return True
name = re.sub(r'[ \t\r\n]', '', name)
name = re.sub(r'[>﹥›˃ᐳ❯]', '>', name)
name = re.sub(r'', '(', name)
name = re.sub(r'', ')', name)
invitation.target_names = name.split('>')
status = InvitationStatus.MOMOTALK
action_timer = Timer(1, 1)
loading_timer = Timer(1, 1)
while 1:
main.device.screenshot()
if not loading_timer.reached():
continue
if action_timer.reached_and_reset():
logger.attr('Status', status)
status = handle_invitation_status(status, main)
if status == InvitationStatus.FINISHED:
return True

View File

@ -31,7 +31,7 @@ class CafeUI(UI):
# generate result
return cv2.bitwise_and(image, image, mask=mask)
def get_clickable_buttons(self, similarity=0.8, offset=(45, 10)):
def get_clickable_buttons(self, similarity=0.8, offset=(40, 10)):
image = self.extract_clickable_from_image(self.device.image)
self.template.matched_button._button_offset = offset
self.template.load_offset(self.template)
@ -48,21 +48,22 @@ class CafeUI(UI):
vector_left = (-width * r, 0)
vector_right = (width * r, 0)
random_r = (-5, -5, 5, 5)
name = 'CAFE_SWIPE'
match direction:
case 'init':
self.device.pinch()
self.device.swipe_vector(vector_down, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_up, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_up, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_down, box=BOX_CAFE.area, random_range=random_r, padding=5, name=name)
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5, name=name)
self.device.swipe_vector(vector_up, box=BOX_CAFE.area, random_range=random_r, padding=5, name=name)
self.device.swipe_vector(vector_up, box=BOX_CAFE.area, random_range=random_r, padding=5, name=name)
case 'left':
self.device.swipe_vector(vector_left, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_left, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_left, box=BOX_CAFE.area, random_range=random_r, padding=5, name=name)
self.device.swipe_vector(vector_left, box=BOX_CAFE.area, random_range=random_r, padding=5, name=name)
case 'right':
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5)
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5, name=name)
self.device.swipe_vector(vector_right, box=BOX_CAFE.area, random_range=random_r, padding=5, name=name)
# solve too much swipe causing restart
self.device.click_record_clear()
self.device.click_record_remove(name)
def cafe_additional(self) -> bool:
if self.appear_then_click(INVENTORY):

View File

@ -3,6 +3,23 @@ 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 ```
CIRCLE = ButtonWrapper(
name='CIRCLE',
jp=Button(
file='./assets/jp/circle/CIRCLE.png',
area=(191, 314, 233, 356),
search=(171, 294, 253, 376),
color=(191, 224, 240),
button=(188, 299, 435, 456),
),
en=Button(
file='./assets/en/circle/CIRCLE.png',
area=(196, 314, 235, 355),
search=(176, 294, 255, 375),
color=(183, 221, 238),
button=(191, 298, 434, 457),
),
)
GET_REWARD_AP = ButtonWrapper(
name='GET_REWARD_AP',
jp=Button(

View File

@ -2,7 +2,7 @@ from enum import Enum
from module.base.timer import Timer
from module.logger import logger
from tasks.base.page import page_circle
from tasks.base.page import CIRCLE_CHECK, MAIN_GO_TO_CIRCLE
from tasks.base.ui import UI
from tasks.circle.assets.assets_circle import *
@ -17,6 +17,19 @@ class CircleStatus(Enum):
class Circle(UI):
def _enter_circle(self):
self.ui_goto_main()
action_timer = Timer(1, 8)
while not self.appear(CIRCLE_CHECK):
self.device.screenshot()
if not action_timer.reached_and_reset():
continue
if self.appear(CIRCLE):
self.click_with_interval(CIRCLE, 3)
continue
else:
self.device.click(MAIN_GO_TO_CIRCLE)
def _handle_circle(self, status):
match status:
case CircleStatus.REWARD:
@ -31,7 +44,7 @@ class Circle(UI):
return status
def run(self):
self.ui_ensure(page_circle)
self._enter_circle()
status = CircleStatus.REWARD
action_timer = Timer(0.5)

View File

@ -7,19 +7,19 @@ OCR_AP = ButtonWrapper(
name='OCR_AP',
share=Button(
file='./assets/share/item/data/OCR_AP.png',
area=(560, 11, 667, 37),
search=(540, 0, 687, 57),
color=(211, 216, 219),
button=(560, 11, 667, 37),
area=(535, 13, 660, 36),
search=(515, 0, 680, 56),
color=(207, 215, 220),
button=(535, 13, 660, 36),
),
)
OCR_DATA = ButtonWrapper(
name='OCR_DATA',
share=Button(
file='./assets/share/item/data/OCR_DATA.png',
area=(768, 12, 1072, 37),
search=(748, 0, 1092, 57),
color=(212, 220, 224),
button=(768, 12, 1072, 37),
area=(745, 11, 1069, 39),
search=(725, 0, 1089, 59),
color=(216, 223, 227),
button=(745, 11, 1069, 39),
),
)

View File

@ -12,7 +12,10 @@ class DataUpdate(UI):
Page:
in: page_work
"""
ap = DigitCounter(OCR_AP).ocr_single_line(self.device.image)
ap, _, ap_total = DigitCounter(OCR_AP).ocr_single_line(self.device.image)
if ap_total == 0:
logger.warning('Invalid AP')
return False
# Data for Credit and Pyroxene
ocr = Digit(OCR_DATA)
timeout = Timer(2, count=6).start()
@ -21,27 +24,28 @@ class DataUpdate(UI):
if len(data) != 2:
data = [data[0], data[-1]]
logger.attr('Data', data)
credit, pyroxene = [int(''.join([v for v in d.ocr_text if v.isdigit()])) for d in data]
credit, pyroxene = [int(''.join(filter(lambda x: x.isdigit(), d.ocr_text))) for d in data]
if credit > 0 or pyroxene > 0:
break
logger.warning(f'Invalid credit and pyroxene: {data}')
if timeout.reached():
logger.warning('Get data timeout')
break
return False
logger.attr('Credit', credit)
logger.attr('Pyroxene', pyroxene)
with self.config.multi_set():
self.config.stored.AP.set(ap[0], ap[2])
self.config.stored.AP.set(ap, ap_total)
self.config.stored.Credit.value = credit
self.config.stored.Pyroxene.value = pyroxene
return ap, credit, pyroxene
return True
def run(self):
self.ui_ensure(page_work, acquire_lang_checked=False)
with self.config.multi_set():
self._get_data()
if self._get_data():
self.config.task_delay(server_update=True)
else:
self.config.task_delay(minute=1)

View File

@ -75,17 +75,17 @@ OCR_TICKET = ButtonWrapper(
name='OCR_TICKET',
jp=Button(
file='./assets/jp/scrimmage/OCR_TICKET.png',
area=(195, 85, 235, 113),
search=(175, 65, 255, 133),
color=(206, 211, 215),
button=(195, 85, 235, 113),
area=(194, 87, 258, 112),
search=(174, 67, 278, 132),
color=(207, 213, 218),
button=(194, 87, 258, 112),
),
en=Button(
file='./assets/en/scrimmage/OCR_TICKET.png',
area=(227, 84, 265, 115),
search=(207, 64, 285, 135),
color=(207, 212, 216),
button=(227, 84, 265, 115),
area=(229, 88, 289, 112),
search=(209, 68, 309, 132),
color=(199, 206, 212),
button=(229, 88, 289, 112),
),
)
SELECT_GEHENNA = ButtonWrapper(

View File

@ -7,6 +7,7 @@ from tasks.base.assets.assets_base_page import BACK
from tasks.base.page import page_school_exchange
from tasks.scrimmage.assets.assets_scrimmage import *
from tasks.scrimmage.ui import ScrimmageUI
from tasks.stage.ap import AP
class ScrimmageStatus(Enum):
@ -18,15 +19,20 @@ class ScrimmageStatus(Enum):
FINISH = 5
class Scrimmage(ScrimmageUI):
class Scrimmage(ScrimmageUI, AP):
_stage_ap = [10, 15, 15, 15]
@property
def stage_ap(self):
return self._stage_ap
@property
def scrimmage_info(self):
scrimmage = (SELECT_TRINITY, SELECT_GEHENNA, SELECT_MILLENNIUM)
check = (CHECK_TRINITY, CHECK_GEHENNA, CHECK_MILLENNIUM)
stage = (self.config.Trinity_Stage, self.config.Gehenna_Stage, self.config.Millennium_Stage)
count = (self.config.Trinity_Count, self.config.Gehenna_Count, self.config.Millennium_Count)
ap = (10 if stage == 1 else 15 for stage in stage)
info = zip(scrimmage, check, stage, count, ap)
info = zip(scrimmage, check, stage, count)
return filter(lambda x: x[3] > 0, info)
@property
@ -42,17 +48,14 @@ class Scrimmage(ScrimmageUI):
if action == 'stop':
raise RequestHumanTakeover
elif action == 'skip':
self.config.task_delay(server_update=True)
self.config.task_stop()
with self.config.multi_set():
self.config.task_delay(server_update=True)
self.config.task_stop()
@property
def is_ticket_enough(self) -> bool:
return self.current_ticket >= self.current_count
@property
def is_ap_enough(self) -> bool:
return self.current_ap >= self.current_task_ap
@property
def current_scrimmage(self):
return self.task[0][:2]
@ -65,25 +68,10 @@ class Scrimmage(ScrimmageUI):
def current_count(self):
return self.task[0][3]
@property
def current_task_ap(self):
return self.task[0][4] * self.current_count
@property
def current_ticket(self):
return self.config.stored.ScrimmageTicket.value
@property
def current_ap(self):
return self.config.stored.AP.value
def update_ap(self):
ap = self.config.stored.AP
ap_old = ap.value
ap_new = ap_old - self.current_task_ap
ap.set(ap_new, ap.total)
logger.info(f'Set AP: {ap_old} -> {ap_new}')
def handle_scrimmage(self, status):
match status:
case ScrimmageStatus.OCR:
@ -95,19 +83,16 @@ class Scrimmage(ScrimmageUI):
if not self.is_ticket_enough:
logger.warning('Scrimmage ticket not enough')
self.error_handler()
if not self.is_ap_enough:
logger.warning('AP not enough')
self.error_handler()
if self.select_scrimmage(*self.current_scrimmage):
return ScrimmageStatus.ENTER
case ScrimmageStatus.ENTER:
if self.enter_stage(self.current_stage):
if self.enter_stage(self.current_stage) and self.is_ap_enough(self.current_count, self.current_stage):
return ScrimmageStatus.SWEEP
else:
self.error_handler()
case ScrimmageStatus.SWEEP:
if self.do_sweep(self.current_count):
self.update_ap()
self.update_ap(self.current_count, self.current_stage)
self.task.pop(0)
return ScrimmageStatus.END
return ScrimmageStatus.ENTER

View File

@ -3,6 +3,7 @@ from module.logger import logger
from module.ocr.ocr import DigitCounter
from tasks.base.ui import UI
from tasks.scrimmage.assets.assets_scrimmage import *
from tasks.stage.ap import AP
from tasks.stage.list import StageList
from tasks.stage.sweep import StageSweep
@ -10,7 +11,7 @@ SCRIMMAGE_LIST = StageList('ScrimmageList')
SCRIMMAGE_SWEEP = StageSweep('ScrimmageSweep', 6)
class ScrimmageUI(UI):
class ScrimmageUI(UI, AP):
def select_scrimmage(self, dest_enter: ButtonWrapper, dest_check: ButtonWrapper):
timer = Timer(5, 10).start()
while 1:
@ -22,6 +23,10 @@ class ScrimmageUI(UI):
return False
def enter_stage(self, index: int) -> bool:
if not index:
index = SCRIMMAGE_LIST.insight_max_sweepable_index(self)
# set AP stage
self.set_stage(index)
if SCRIMMAGE_LIST.select_index_enter(self, index, insight=False):
return True
return False

Some files were not shown because too many files have changed in this diff Show More