Merge pull request #113 from Zebartin/dev
Add: Event assignments (Space Station Task Force)
BIN
assets/cn/assignment/claim/REPORT.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
assets/cn/assignment/dispatch/ASSIGNMENT_START.SEARCH.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
assets/cn/assignment/dispatch/CHARACTER_SUPPORT_LIST.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
assets/cn/assignment/ui/CHARACTER_MATERIALS_CHECK.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
assets/cn/assignment/ui/CHARACTER_MATERIALS_CLICK.png
Normal file
After Width: | Height: | Size: 8.0 KiB |
BIN
assets/cn/assignment/ui/EXP_MATERIALS_CREDITS_CHECK.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
assets/cn/assignment/ui/EXP_MATERIALS_CREDITS_CLICK.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
assets/cn/assignment/ui/SPACE_STATION_TASK_FORCE_CHECK.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
assets/cn/assignment/ui/SPACE_STATION_TASK_FORCE_CLICK.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
BIN
assets/cn/assignment/ui/SYNTHESIS_MATERIALS_CLICK.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
assets/en/assignment/claim/REPORT.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
assets/en/assignment/dispatch/ASSIGNMENT_START.SEARCH.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
assets/en/assignment/dispatch/CHARACTER_SUPPORT_LIST.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
assets/en/assignment/ui/CHARACTER_MATERIALS_CHECK.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
assets/en/assignment/ui/CHARACTER_MATERIALS_CLICK.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
assets/en/assignment/ui/EXP_MATERIALS_CREDITS_CHECK.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
BIN
assets/en/assignment/ui/EXP_MATERIALS_CREDITS_CLICK.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
assets/en/assignment/ui/SPACE_STATION_TASK_FORCE_CHECK.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
assets/en/assignment/ui/SPACE_STATION_TASK_FORCE_CLICK.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
assets/en/assignment/ui/SYNTHESIS_MATERIALS_CHECK.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
assets/en/assignment/ui/SYNTHESIS_MATERIALS_CLICK.png
Normal file
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 5.3 KiB |
BIN
assets/share/assignment/dispatch/CHARACTER_SUPPORT.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
assets/share/assignment/dispatch/CHARACTER_SUPPORT_SELECTED.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 39 KiB |
BIN
assets/share/assignment/dispatch/EMPTY_SLOT_SUPPORT.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 10 KiB |
BIN
assets/share/assignment/ui/GROUP_SEARCH.png
Normal file
After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
@ -139,6 +139,7 @@
|
|||||||
"Name_3": "The_Invisible_Hand",
|
"Name_3": "The_Invisible_Hand",
|
||||||
"Name_4": "Nine_Billion_Names",
|
"Name_4": "Nine_Billion_Names",
|
||||||
"Duration": 20,
|
"Duration": 20,
|
||||||
|
"Event": true,
|
||||||
"Assignment": {}
|
"Assignment": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -200,6 +200,8 @@ def generate_code():
|
|||||||
output = os.path.join(path, 'assets')
|
output = os.path.join(path, 'assets')
|
||||||
os.makedirs(output, exist_ok=True)
|
os.makedirs(output, exist_ok=True)
|
||||||
for prev in iter_folder(output, ext='.py'):
|
for prev in iter_folder(output, ext='.py'):
|
||||||
|
if os.path.basename(prev) == '__init__.py':
|
||||||
|
continue
|
||||||
os.remove(prev)
|
os.remove(prev)
|
||||||
|
|
||||||
for module, module_data in all.items():
|
for module, module_data in all.items():
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import typing as t
|
import typing as t
|
||||||
from collections import namedtuple
|
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
|
|
||||||
from module.base.code_generator import CodeGenerator
|
from module.base.code_generator import CodeGenerator
|
||||||
@ -254,14 +253,19 @@ class KeywordExtract:
|
|||||||
self.clear_keywords()
|
self.clear_keywords()
|
||||||
|
|
||||||
def generate_assignment_keywords(self):
|
def generate_assignment_keywords(self):
|
||||||
KeywordFromFile = namedtuple('KeywordFromFile', ('file', 'class_name', 'output_file'))
|
self.load_keywords(['空间站特派'])
|
||||||
for keyword in (
|
self.write_keywords(
|
||||||
KeywordFromFile('ExpeditionGroup.json', 'AssignmentGroup', './tasks/assignment/keywords/group.py'),
|
keyword_class='AssignmentEventGroup',
|
||||||
KeywordFromFile('ExpeditionData.json', 'AssignmentEntry', './tasks/assignment/keywords/entry.py')
|
output_file='./tasks/assignment/keywords/event_group.py'
|
||||||
|
)
|
||||||
|
for file_name, class_name, output_file in (
|
||||||
|
('ExpeditionGroup.json', 'AssignmentGroup', './tasks/assignment/keywords/group.py'),
|
||||||
|
('ExpeditionData.json', 'AssignmentEntry', './tasks/assignment/keywords/entry.py'),
|
||||||
|
('ActivityExpedition.json', 'AssignmentEventEntry', './tasks/assignment/keywords/event_entry.py'),
|
||||||
):
|
):
|
||||||
file = os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', keyword.file)
|
file = os.path.join(TextMap.DATA_FOLDER, 'ExcelOutput', file_name)
|
||||||
self.load_keywords(deep_get(data, 'Name.Hash') for data in read_file(file).values())
|
self.load_keywords(deep_get(data, 'Name.Hash') for data in read_file(file).values())
|
||||||
self.write_keywords(keyword_class=keyword.class_name, output_file=keyword.output_file)
|
self.write_keywords(keyword_class=class_name, output_file=output_file)
|
||||||
|
|
||||||
def generate_map_planes(self):
|
def generate_map_planes(self):
|
||||||
planes = {
|
planes = {
|
||||||
|
@ -1046,6 +1046,10 @@
|
|||||||
20
|
20
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"Event": {
|
||||||
|
"type": "checkbox",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
"Assignment": {
|
"Assignment": {
|
||||||
"type": "stored",
|
"type": "stored",
|
||||||
"value": {},
|
"value": {},
|
||||||
|
@ -176,6 +176,7 @@ Assignment:
|
|||||||
Duration:
|
Duration:
|
||||||
value: 20
|
value: 20
|
||||||
option: [ 4, 8, 12, 20 ]
|
option: [ 4, 8, 12, 20 ]
|
||||||
|
Event: true
|
||||||
Assignment:
|
Assignment:
|
||||||
stored: StoredAssignment
|
stored: StoredAssignment
|
||||||
order: 3
|
order: 3
|
||||||
|
@ -106,6 +106,7 @@ class GeneratedConfig:
|
|||||||
Assignment_Name_3 = 'The_Invisible_Hand' # Nine_Billion_Names, Destruction_of_the_Destroyer, Winter_Soldiers, Born_to_Obey, Root_Out_the_Turpitude, Fire_Lord_Inflames_Blades_of_War, Nameless_Land_Nameless_People, Akashic_Records, The_Invisible_Hand, Abandoned_and_Insulted, Spring_of_Life, The_Land_of_Gold, The_Blossom_in_the_Storm, Legend_of_the_Puppet_Master, The_Wages_of_Humanity
|
Assignment_Name_3 = 'The_Invisible_Hand' # Nine_Billion_Names, Destruction_of_the_Destroyer, Winter_Soldiers, Born_to_Obey, Root_Out_the_Turpitude, Fire_Lord_Inflames_Blades_of_War, Nameless_Land_Nameless_People, Akashic_Records, The_Invisible_Hand, Abandoned_and_Insulted, Spring_of_Life, The_Land_of_Gold, The_Blossom_in_the_Storm, Legend_of_the_Puppet_Master, The_Wages_of_Humanity
|
||||||
Assignment_Name_4 = 'Nine_Billion_Names' # Nine_Billion_Names, Destruction_of_the_Destroyer, Winter_Soldiers, Born_to_Obey, Root_Out_the_Turpitude, Fire_Lord_Inflames_Blades_of_War, Nameless_Land_Nameless_People, Akashic_Records, The_Invisible_Hand, Abandoned_and_Insulted, Spring_of_Life, The_Land_of_Gold, The_Blossom_in_the_Storm, Legend_of_the_Puppet_Master, The_Wages_of_Humanity
|
Assignment_Name_4 = 'Nine_Billion_Names' # Nine_Billion_Names, Destruction_of_the_Destroyer, Winter_Soldiers, Born_to_Obey, Root_Out_the_Turpitude, Fire_Lord_Inflames_Blades_of_War, Nameless_Land_Nameless_People, Akashic_Records, The_Invisible_Hand, Abandoned_and_Insulted, Spring_of_Life, The_Land_of_Gold, The_Blossom_in_the_Storm, Legend_of_the_Puppet_Master, The_Wages_of_Humanity
|
||||||
Assignment_Duration = 20 # 4, 8, 12, 20
|
Assignment_Duration = 20 # 4, 8, 12, 20
|
||||||
|
Assignment_Event = True
|
||||||
Assignment_Assignment = {}
|
Assignment_Assignment = {}
|
||||||
|
|
||||||
# Group `ItemStorage`
|
# Group `ItemStorage`
|
||||||
|
@ -728,6 +728,10 @@
|
|||||||
"12": "12 Hours",
|
"12": "12 Hours",
|
||||||
"20": "20 Hours"
|
"20": "20 Hours"
|
||||||
},
|
},
|
||||||
|
"Event": {
|
||||||
|
"name": "Complete Event Assignments First",
|
||||||
|
"help": ""
|
||||||
|
},
|
||||||
"Assignment": {
|
"Assignment": {
|
||||||
"name": "Assign.",
|
"name": "Assign.",
|
||||||
"help": ""
|
"help": ""
|
||||||
|
@ -728,6 +728,10 @@
|
|||||||
"12": "12 horas",
|
"12": "12 horas",
|
||||||
"20": "20 horas"
|
"20": "20 horas"
|
||||||
},
|
},
|
||||||
|
"Event": {
|
||||||
|
"name": "Assignment.Event.name",
|
||||||
|
"help": ""
|
||||||
|
},
|
||||||
"Assignment": {
|
"Assignment": {
|
||||||
"name": "Encargo",
|
"name": "Encargo",
|
||||||
"help": ""
|
"help": ""
|
||||||
|
@ -728,6 +728,10 @@
|
|||||||
"12": "12",
|
"12": "12",
|
||||||
"20": "20"
|
"20": "20"
|
||||||
},
|
},
|
||||||
|
"Event": {
|
||||||
|
"name": "Assignment.Event.name",
|
||||||
|
"help": ""
|
||||||
|
},
|
||||||
"Assignment": {
|
"Assignment": {
|
||||||
"name": "Assignment.Assignment.name",
|
"name": "Assignment.Assignment.name",
|
||||||
"help": "Assignment.Assignment.help"
|
"help": "Assignment.Assignment.help"
|
||||||
|
@ -728,6 +728,10 @@
|
|||||||
"12": "12小时",
|
"12": "12小时",
|
||||||
"20": "20小时"
|
"20": "20小时"
|
||||||
},
|
},
|
||||||
|
"Event": {
|
||||||
|
"name": "有活动时优先做活动委托",
|
||||||
|
"help": ""
|
||||||
|
},
|
||||||
"Assignment": {
|
"Assignment": {
|
||||||
"name": "委托",
|
"name": "委托",
|
||||||
"help": ""
|
"help": ""
|
||||||
|
@ -728,6 +728,10 @@
|
|||||||
"12": "12小時",
|
"12": "12小時",
|
||||||
"20": "20小時"
|
"20": "20小時"
|
||||||
},
|
},
|
||||||
|
"Event": {
|
||||||
|
"name": "有活動時優先做活動委託",
|
||||||
|
"help": ""
|
||||||
|
},
|
||||||
"Assignment": {
|
"Assignment": {
|
||||||
"name": "委託",
|
"name": "委託",
|
||||||
"help": ""
|
"help": ""
|
||||||
|
@ -375,17 +375,17 @@ class Duration(Ocr):
|
|||||||
def timedelta_regex(cls, lang):
|
def timedelta_regex(cls, lang):
|
||||||
regex_str = {
|
regex_str = {
|
||||||
'cn': r'^(?P<prefix>.*?)'
|
'cn': r'^(?P<prefix>.*?)'
|
||||||
r'((?P<days>\d{1,2})天)?'
|
r'((?P<days>\d{1,2})\s*天\s*)?'
|
||||||
r'((?P<hours>\d{1,2})小时)?'
|
r'((?P<hours>\d{1,2})\s*小时\s*)?'
|
||||||
r'((?P<minutes>\d{1,2})分钟)?'
|
r'((?P<minutes>\d{1,2})\s*分钟\s*)?'
|
||||||
r'((?P<seconds>\d{1,2})秒)?'
|
r'((?P<seconds>\d{1,2})\s*秒)?'
|
||||||
r'$',
|
r'(?P<suffix>[^天时钟秒]*?)$',
|
||||||
'en': r'^(?P<prefix>.*?)'
|
'en': r'^(?P<prefix>.*?)'
|
||||||
r'((?P<days>\d{1,2})\s*d\s*)?'
|
r'((?P<days>\d{1,2})\s*d\s*)?'
|
||||||
r'((?P<hours>\d{1,2})\s*h\s*)?'
|
r'((?P<hours>\d{1,2})\s*h\s*)?'
|
||||||
r'((?P<minutes>\d{1,2})\s*m\s*)?'
|
r'((?P<minutes>\d{1,2})\s*m\s*)?'
|
||||||
r'((?P<seconds>\d{1,2})\s*s)?'
|
r'((?P<seconds>\d{1,2})\s*s)?'
|
||||||
r'$'
|
r'(?P<suffix>[^dhms]*?)$'
|
||||||
}[lang]
|
}[lang]
|
||||||
return re.compile(regex_str)
|
return re.compile(regex_str)
|
||||||
|
|
||||||
|
18
tasks/assignment/assets/__init__.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from module.config.server import VALID_LANG
|
||||||
|
from tasks.assignment.assets.assets_assignment_ui import (
|
||||||
|
CHARACTER_MATERIALS_CHECK, CHARACTER_MATERIALS_CLICK,
|
||||||
|
EXP_MATERIALS_CREDITS_CHECK, EXP_MATERIALS_CREDITS_CLICK, GROUP_SEARCH,
|
||||||
|
SPACE_STATION_TASK_FORCE_CHECK, SPACE_STATION_TASK_FORCE_CLICK,
|
||||||
|
SYNTHESIS_MATERIALS_CHECK, SYNTHESIS_MATERIALS_CLICK)
|
||||||
|
|
||||||
|
for group_button_wrapper in (
|
||||||
|
SPACE_STATION_TASK_FORCE_CHECK, SPACE_STATION_TASK_FORCE_CLICK,
|
||||||
|
CHARACTER_MATERIALS_CHECK, CHARACTER_MATERIALS_CLICK,
|
||||||
|
EXP_MATERIALS_CREDITS_CHECK, EXP_MATERIALS_CREDITS_CLICK,
|
||||||
|
SYNTHESIS_MATERIALS_CHECK, SYNTHESIS_MATERIALS_CLICK,
|
||||||
|
):
|
||||||
|
for lang in VALID_LANG:
|
||||||
|
button = getattr(group_button_wrapper, lang, None)
|
||||||
|
if button is None:
|
||||||
|
continue
|
||||||
|
button.search = GROUP_SEARCH.button
|
@ -43,3 +43,20 @@ REDISPATCH = ButtonWrapper(
|
|||||||
button=(779, 592, 905, 629),
|
button=(779, 592, 905, 629),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
REPORT = ButtonWrapper(
|
||||||
|
name='REPORT',
|
||||||
|
cn=Button(
|
||||||
|
file='./assets/cn/assignment/claim/REPORT.png',
|
||||||
|
area=(537, 80, 742, 128),
|
||||||
|
search=(517, 60, 762, 148),
|
||||||
|
color=(102, 90, 68),
|
||||||
|
button=(537, 80, 742, 128),
|
||||||
|
),
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/assignment/claim/REPORT.png',
|
||||||
|
area=(393, 83, 885, 137),
|
||||||
|
search=(373, 63, 905, 157),
|
||||||
|
color=(71, 63, 49),
|
||||||
|
button=(393, 83, 885, 137),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@ -8,14 +8,14 @@ ASSIGNMENT_START = ButtonWrapper(
|
|||||||
cn=Button(
|
cn=Button(
|
||||||
file='./assets/cn/assignment/dispatch/ASSIGNMENT_START.png',
|
file='./assets/cn/assignment/dispatch/ASSIGNMENT_START.png',
|
||||||
area=(581, 321, 699, 349),
|
area=(581, 321, 699, 349),
|
||||||
search=(561, 301, 719, 369),
|
search=(573, 299, 707, 412),
|
||||||
color=(93, 84, 66),
|
color=(93, 84, 66),
|
||||||
button=(581, 321, 699, 349),
|
button=(581, 321, 699, 349),
|
||||||
),
|
),
|
||||||
en=Button(
|
en=Button(
|
||||||
file='./assets/en/assignment/dispatch/ASSIGNMENT_START.png',
|
file='./assets/en/assignment/dispatch/ASSIGNMENT_START.png',
|
||||||
area=(679, 323, 784, 347),
|
area=(679, 323, 784, 347),
|
||||||
search=(659, 303, 804, 367),
|
search=(669, 297, 794, 416),
|
||||||
color=(93, 83, 65),
|
color=(93, 83, 65),
|
||||||
button=(679, 323, 784, 347),
|
button=(679, 323, 784, 347),
|
||||||
),
|
),
|
||||||
@ -24,10 +24,10 @@ ASSIGNMENT_STARTED_CHECK = ButtonWrapper(
|
|||||||
name='ASSIGNMENT_STARTED_CHECK',
|
name='ASSIGNMENT_STARTED_CHECK',
|
||||||
share=Button(
|
share=Button(
|
||||||
file='./assets/share/assignment/dispatch/ASSIGNMENT_STARTED_CHECK.png',
|
file='./assets/share/assignment/dispatch/ASSIGNMENT_STARTED_CHECK.png',
|
||||||
area=(1174, 297, 1211, 514),
|
area=(542, 412, 1156, 422),
|
||||||
search=(1154, 277, 1231, 534),
|
search=(522, 392, 1176, 442),
|
||||||
color=(86, 81, 78),
|
color=(232, 230, 226),
|
||||||
button=(1174, 297, 1211, 514),
|
button=(542, 412, 1156, 422),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
CHARACTER_1 = ButtonWrapper(
|
CHARACTER_1 = ButtonWrapper(
|
||||||
@ -87,6 +87,43 @@ CHARACTER_LIST = ButtonWrapper(
|
|||||||
button=(91, 163, 136, 180),
|
button=(91, 163, 136, 180),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
CHARACTER_SUPPORT = ButtonWrapper(
|
||||||
|
name='CHARACTER_SUPPORT',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/assignment/dispatch/CHARACTER_SUPPORT.png',
|
||||||
|
area=(103, 212, 435, 302),
|
||||||
|
search=(83, 192, 455, 322),
|
||||||
|
color=(69, 65, 80),
|
||||||
|
button=(103, 212, 435, 302),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
CHARACTER_SUPPORT_LIST = ButtonWrapper(
|
||||||
|
name='CHARACTER_SUPPORT_LIST',
|
||||||
|
cn=Button(
|
||||||
|
file='./assets/cn/assignment/dispatch/CHARACTER_SUPPORT_LIST.png',
|
||||||
|
area=(91, 166, 171, 186),
|
||||||
|
search=(71, 146, 191, 206),
|
||||||
|
color=(147, 146, 143),
|
||||||
|
button=(91, 166, 171, 186),
|
||||||
|
),
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/assignment/dispatch/CHARACTER_SUPPORT_LIST.png',
|
||||||
|
area=(90, 167, 267, 189),
|
||||||
|
search=(70, 147, 287, 209),
|
||||||
|
color=(169, 168, 165),
|
||||||
|
button=(90, 167, 267, 189),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
CHARACTER_SUPPORT_SELECTED = ButtonWrapper(
|
||||||
|
name='CHARACTER_SUPPORT_SELECTED',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/assignment/dispatch/CHARACTER_SUPPORT_SELECTED.png',
|
||||||
|
area=(190, 270, 266, 295),
|
||||||
|
search=(170, 250, 286, 315),
|
||||||
|
color=(39, 39, 39),
|
||||||
|
button=(190, 270, 266, 295),
|
||||||
|
),
|
||||||
|
)
|
||||||
CONFIRM_ASSIGNMENT = ButtonWrapper(
|
CONFIRM_ASSIGNMENT = ButtonWrapper(
|
||||||
name='CONFIRM_ASSIGNMENT',
|
name='CONFIRM_ASSIGNMENT',
|
||||||
cn=Button(
|
cn=Button(
|
||||||
@ -149,8 +186,18 @@ EMPTY_SLOT = ButtonWrapper(
|
|||||||
share=Button(
|
share=Button(
|
||||||
file='./assets/share/assignment/dispatch/EMPTY_SLOT.png',
|
file='./assets/share/assignment/dispatch/EMPTY_SLOT.png',
|
||||||
area=(1075, 562, 1110, 597),
|
area=(1075, 562, 1110, 597),
|
||||||
search=(1054, 542, 1220, 616),
|
search=(873, 542, 1136, 608),
|
||||||
color=(200, 200, 195),
|
color=(200, 200, 195),
|
||||||
button=(1075, 562, 1110, 597),
|
button=(1075, 562, 1110, 597),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
EMPTY_SLOT_SUPPORT = ButtonWrapper(
|
||||||
|
name='EMPTY_SLOT_SUPPORT',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/assignment/dispatch/EMPTY_SLOT_SUPPORT.png',
|
||||||
|
area=(1152, 561, 1187, 592),
|
||||||
|
search=(1132, 541, 1207, 612),
|
||||||
|
color=(203, 202, 198),
|
||||||
|
button=(1152, 561, 1187, 592),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@ -3,14 +3,38 @@ from module.base.button import Button, ButtonWrapper
|
|||||||
# This file was auto-generated, do not modify it manually. To generate:
|
# This file was auto-generated, do not modify it manually. To generate:
|
||||||
# ``` python -m dev_tools.button_extract ```
|
# ``` python -m dev_tools.button_extract ```
|
||||||
|
|
||||||
CHARACTER_MATERIALS = ButtonWrapper(
|
CHARACTER_MATERIALS_CHECK = ButtonWrapper(
|
||||||
name='CHARACTER_MATERIALS',
|
name='CHARACTER_MATERIALS_CHECK',
|
||||||
share=Button(
|
cn=Button(
|
||||||
file='./assets/share/assignment/ui/CHARACTER_MATERIALS.png',
|
file='./assets/cn/assignment/ui/CHARACTER_MATERIALS_CHECK.png',
|
||||||
area=(146, 91, 255, 124),
|
area=(346, 97, 421, 117),
|
||||||
search=(126, 71, 275, 144),
|
search=(326, 77, 441, 137),
|
||||||
color=(213, 213, 208),
|
color=(177, 176, 173),
|
||||||
button=(146, 91, 255, 124),
|
button=(346, 97, 421, 117),
|
||||||
|
),
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/assignment/ui/CHARACTER_MATERIALS_CHECK.png',
|
||||||
|
area=(339, 88, 429, 126),
|
||||||
|
search=(319, 68, 449, 146),
|
||||||
|
color=(193, 192, 189),
|
||||||
|
button=(339, 88, 429, 126),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
CHARACTER_MATERIALS_CLICK = ButtonWrapper(
|
||||||
|
name='CHARACTER_MATERIALS_CLICK',
|
||||||
|
cn=Button(
|
||||||
|
file='./assets/cn/assignment/ui/CHARACTER_MATERIALS_CLICK.png',
|
||||||
|
area=(347, 97, 421, 117),
|
||||||
|
search=(327, 77, 441, 137),
|
||||||
|
color=(60, 60, 60),
|
||||||
|
button=(347, 97, 421, 117),
|
||||||
|
),
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/assignment/ui/CHARACTER_MATERIALS_CLICK.png',
|
||||||
|
area=(339, 88, 429, 127),
|
||||||
|
search=(319, 68, 449, 147),
|
||||||
|
color=(49, 49, 49),
|
||||||
|
button=(339, 88, 429, 127),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
DISPATCHED = ButtonWrapper(
|
DISPATCHED = ButtonWrapper(
|
||||||
@ -40,14 +64,58 @@ ENTRY_LOADED = ButtonWrapper(
|
|||||||
button=(467, 235, 498, 619),
|
button=(467, 235, 498, 619),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
EXP_MATERIALS_CREDITS = ButtonWrapper(
|
EXP_MATERIALS_CREDITS_CHECK = ButtonWrapper(
|
||||||
name='EXP_MATERIALS_CREDITS',
|
name='EXP_MATERIALS_CREDITS_CHECK',
|
||||||
|
cn=Button(
|
||||||
|
file='./assets/cn/assignment/ui/EXP_MATERIALS_CREDITS_CHECK.png',
|
||||||
|
area=(514, 97, 614, 117),
|
||||||
|
search=(494, 77, 634, 137),
|
||||||
|
color=(178, 177, 174),
|
||||||
|
button=(514, 97, 614, 117),
|
||||||
|
),
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/assignment/ui/EXP_MATERIALS_CREDITS_CHECK.png',
|
||||||
|
area=(529, 88, 599, 126),
|
||||||
|
search=(509, 68, 619, 146),
|
||||||
|
color=(202, 201, 198),
|
||||||
|
button=(529, 88, 599, 126),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
EXP_MATERIALS_CREDITS_CLICK = ButtonWrapper(
|
||||||
|
name='EXP_MATERIALS_CREDITS_CLICK',
|
||||||
|
cn=Button(
|
||||||
|
file='./assets/cn/assignment/ui/EXP_MATERIALS_CREDITS_CLICK.png',
|
||||||
|
area=(514, 97, 614, 117),
|
||||||
|
search=(494, 77, 634, 137),
|
||||||
|
color=(61, 60, 60),
|
||||||
|
button=(514, 97, 614, 117),
|
||||||
|
),
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/assignment/ui/EXP_MATERIALS_CREDITS_CLICK.png',
|
||||||
|
area=(528, 88, 599, 127),
|
||||||
|
search=(508, 68, 619, 147),
|
||||||
|
color=(42, 42, 42),
|
||||||
|
button=(528, 88, 599, 127),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
GROUP_SEARCH = ButtonWrapper(
|
||||||
|
name='GROUP_SEARCH',
|
||||||
share=Button(
|
share=Button(
|
||||||
file='./assets/share/assignment/ui/EXP_MATERIALS_CREDITS.png',
|
file='./assets/share/assignment/ui/GROUP_SEARCH.png',
|
||||||
area=(310, 85, 447, 134),
|
area=(111, 76, 835, 140),
|
||||||
search=(290, 65, 467, 154),
|
search=(91, 56, 855, 160),
|
||||||
color=(214, 214, 210),
|
color=(82, 79, 77),
|
||||||
button=(310, 85, 447, 134),
|
button=(111, 76, 835, 140),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
OCR_ASSIGNMENT_ENTRY_LIST = ButtonWrapper(
|
||||||
|
name='OCR_ASSIGNMENT_ENTRY_LIST',
|
||||||
|
share=Button(
|
||||||
|
file='./assets/share/assignment/ui/OCR_ASSIGNMENT_ENTRY_LIST.png',
|
||||||
|
area=(133, 139, 494, 620),
|
||||||
|
search=(113, 119, 514, 640),
|
||||||
|
color=(201, 199, 193),
|
||||||
|
button=(133, 139, 494, 620),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
OCR_ASSIGNMENT_LIMIT = ButtonWrapper(
|
OCR_ASSIGNMENT_LIMIT = ButtonWrapper(
|
||||||
@ -60,16 +128,6 @@ OCR_ASSIGNMENT_LIMIT = ButtonWrapper(
|
|||||||
button=(1095, 95, 1180, 119),
|
button=(1095, 95, 1180, 119),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
OCR_ASSIGNMENT_LIST = ButtonWrapper(
|
|
||||||
name='OCR_ASSIGNMENT_LIST',
|
|
||||||
share=Button(
|
|
||||||
file='./assets/share/assignment/ui/OCR_ASSIGNMENT_LIST.png',
|
|
||||||
area=(133, 139, 494, 620),
|
|
||||||
search=(113, 119, 514, 640),
|
|
||||||
color=(201, 199, 193),
|
|
||||||
button=(133, 139, 494, 620),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
OCR_ASSIGNMENT_TIME = ButtonWrapper(
|
OCR_ASSIGNMENT_TIME = ButtonWrapper(
|
||||||
name='OCR_ASSIGNMENT_TIME',
|
name='OCR_ASSIGNMENT_TIME',
|
||||||
share=Button(
|
share=Button(
|
||||||
@ -80,13 +138,71 @@ OCR_ASSIGNMENT_TIME = ButtonWrapper(
|
|||||||
button=(605, 564, 886, 589),
|
button=(605, 564, 886, 589),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
SYNTHESIS_MATERIALS = ButtonWrapper(
|
SPACE_STATION_TASK_FORCE_CHECK = ButtonWrapper(
|
||||||
name='SYNTHESIS_MATERIALS',
|
name='SPACE_STATION_TASK_FORCE_CHECK',
|
||||||
share=Button(
|
cn=Button(
|
||||||
file='./assets/share/assignment/ui/SYNTHESIS_MATERIALS.png',
|
file='./assets/cn/assignment/ui/SPACE_STATION_TASK_FORCE_CHECK.png',
|
||||||
area=(521, 91, 603, 128),
|
area=(157, 97, 249, 117),
|
||||||
search=(501, 71, 623, 148),
|
search=(137, 77, 269, 137),
|
||||||
color=(208, 208, 203),
|
color=(181, 181, 178),
|
||||||
button=(521, 91, 603, 128),
|
button=(157, 97, 249, 117),
|
||||||
|
),
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/assignment/ui/SPACE_STATION_TASK_FORCE_CHECK.png',
|
||||||
|
area=(176, 88, 239, 126),
|
||||||
|
search=(156, 68, 259, 146),
|
||||||
|
color=(198, 197, 194),
|
||||||
|
button=(176, 88, 239, 126),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
SPACE_STATION_TASK_FORCE_CLICK = ButtonWrapper(
|
||||||
|
name='SPACE_STATION_TASK_FORCE_CLICK',
|
||||||
|
cn=Button(
|
||||||
|
file='./assets/cn/assignment/ui/SPACE_STATION_TASK_FORCE_CLICK.png',
|
||||||
|
area=(157, 97, 249, 117),
|
||||||
|
search=(137, 77, 269, 137),
|
||||||
|
color=(71, 70, 68),
|
||||||
|
button=(157, 97, 249, 117),
|
||||||
|
),
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/assignment/ui/SPACE_STATION_TASK_FORCE_CLICK.png',
|
||||||
|
area=(176, 88, 239, 126),
|
||||||
|
search=(156, 68, 259, 146),
|
||||||
|
color=(60, 58, 56),
|
||||||
|
button=(176, 88, 239, 126),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
SYNTHESIS_MATERIALS_CHECK = ButtonWrapper(
|
||||||
|
name='SYNTHESIS_MATERIALS_CHECK',
|
||||||
|
cn=Button(
|
||||||
|
file='./assets/cn/assignment/ui/SYNTHESIS_MATERIALS_CHECK.png',
|
||||||
|
area=(708, 97, 783, 117),
|
||||||
|
search=(688, 77, 803, 137),
|
||||||
|
color=(180, 179, 176),
|
||||||
|
button=(708, 97, 783, 117),
|
||||||
|
),
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/assignment/ui/SYNTHESIS_MATERIALS_CHECK.png',
|
||||||
|
area=(703, 88, 790, 126),
|
||||||
|
search=(683, 68, 810, 146),
|
||||||
|
color=(189, 188, 185),
|
||||||
|
button=(703, 88, 790, 126),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
SYNTHESIS_MATERIALS_CLICK = ButtonWrapper(
|
||||||
|
name='SYNTHESIS_MATERIALS_CLICK',
|
||||||
|
cn=Button(
|
||||||
|
file='./assets/cn/assignment/ui/SYNTHESIS_MATERIALS_CLICK.png',
|
||||||
|
area=(709, 97, 783, 117),
|
||||||
|
search=(689, 77, 803, 137),
|
||||||
|
color=(68, 66, 65),
|
||||||
|
button=(709, 97, 783, 117),
|
||||||
|
),
|
||||||
|
en=Button(
|
||||||
|
file='./assets/en/assignment/ui/SYNTHESIS_MATERIALS_CLICK.png',
|
||||||
|
area=(702, 88, 790, 126),
|
||||||
|
search=(682, 68, 810, 146),
|
||||||
|
color=(61, 59, 58),
|
||||||
|
button=(702, 88, 790, 126),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from module.logger import logger
|
from module.logger import logger
|
||||||
from module.ocr.ocr import Duration
|
|
||||||
from tasks.assignment.assets.assets_assignment_claim import CLAIM
|
|
||||||
from tasks.assignment.assets.assets_assignment_ui import (
|
|
||||||
DISPATCHED,
|
|
||||||
OCR_ASSIGNMENT_TIME,
|
|
||||||
)
|
|
||||||
from tasks.assignment.claim import AssignmentClaim
|
from tasks.assignment.claim import AssignmentClaim
|
||||||
from tasks.assignment.keywords import (
|
from tasks.assignment.keywords import (KEYWORDS_ASSIGNMENT_GROUP,
|
||||||
AssignmentEntry,
|
AssignmentEntry, AssignmentEventGroup)
|
||||||
KEYWORDS_ASSIGNMENT_GROUP,
|
from tasks.assignment.ui import AssignmentStatus
|
||||||
)
|
|
||||||
from tasks.base.page import page_assignment, page_menu
|
from tasks.base.page import page_assignment, page_menu
|
||||||
from tasks.battle_pass.keywords import KEYWORD_BATTLE_PASS_QUEST
|
from tasks.battle_pass.keywords import KEYWORD_BATTLE_PASS_QUEST
|
||||||
from tasks.daily.keywords import KEYWORDS_DAILY_QUEST
|
from tasks.daily.keywords import KEYWORDS_DAILY_QUEST
|
||||||
@ -19,7 +12,7 @@ from tasks.daily.synthesize import SynthesizeUI
|
|||||||
|
|
||||||
|
|
||||||
class Assignment(AssignmentClaim, SynthesizeUI):
|
class Assignment(AssignmentClaim, SynthesizeUI):
|
||||||
def run(self, assignments: list[AssignmentEntry] = None, duration: int = None):
|
def run(self, assignments: list[AssignmentEntry] = None, duration: int = None, event_first: bool = None):
|
||||||
self.config.update_battle_pass_quests()
|
self.config.update_battle_pass_quests()
|
||||||
self.config.update_daily_quests()
|
self.config.update_daily_quests()
|
||||||
|
|
||||||
@ -35,14 +28,26 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
'There are duplicate assignments in config, check it out')
|
'There are duplicate assignments in config, check it out')
|
||||||
if duration is None:
|
if duration is None:
|
||||||
duration = self.config.Assignment_Duration
|
duration = self.config.Assignment_Duration
|
||||||
|
if event_first is None:
|
||||||
|
event_first = self.config.Assignment_Event
|
||||||
|
|
||||||
self.dispatched = dict()
|
self.dispatched = dict()
|
||||||
self.has_new_dispatch = False
|
self.has_new_dispatch = False
|
||||||
self.ensure_scroll_top(page_menu)
|
self.ensure_scroll_top(page_menu)
|
||||||
self.ui_ensure(page_assignment)
|
self.ui_ensure(page_assignment)
|
||||||
|
event_ongoing = next((
|
||||||
|
g for g in self._iter_groups()
|
||||||
|
if isinstance(g, AssignmentEventGroup)
|
||||||
|
), None)
|
||||||
|
if event_first and event_ongoing is not None:
|
||||||
|
undispatched = assignments
|
||||||
|
remain = self._check_all()
|
||||||
|
remain = self._dispatch_event(remain)
|
||||||
|
else:
|
||||||
# Iterate in user-specified order, return undispatched ones
|
# Iterate in user-specified order, return undispatched ones
|
||||||
undispatched = list(self._check_inlist(assignments, duration))
|
undispatched = list(self._check_inlist(assignments, duration))
|
||||||
remain = self._check_all()
|
remain = self._check_all()
|
||||||
|
undispatched = [x for x in undispatched if x not in self.dispatched]
|
||||||
# There are unchecked assignments
|
# There are unchecked assignments
|
||||||
if remain > 0:
|
if remain > 0:
|
||||||
for assignment in undispatched[:remain]:
|
for assignment in undispatched[:remain]:
|
||||||
@ -53,7 +58,8 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
f'{", ".join([x.name for x in undispatched[remain:]])}')
|
f'{", ".join([x.name for x in undispatched[remain:]])}')
|
||||||
elif remain > len(undispatched):
|
elif remain > len(undispatched):
|
||||||
self._dispatch_remain(duration, remain - len(undispatched))
|
self._dispatch_remain(duration, remain - len(undispatched))
|
||||||
|
# Refresh dashboard before return
|
||||||
|
_ = self._limit_status
|
||||||
# Scheduler
|
# Scheduler
|
||||||
logger.attr('has_new_dispatch', self.has_new_dispatch)
|
logger.attr('has_new_dispatch', self.has_new_dispatch)
|
||||||
with self.config.multi_set():
|
with self.config.multi_set():
|
||||||
@ -61,7 +67,8 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
quests = self.config.stored.BattlePassTodayQuest.load_quests()
|
quests = self.config.stored.BattlePassTodayQuest.load_quests()
|
||||||
if self.has_new_dispatch:
|
if self.has_new_dispatch:
|
||||||
if KEYWORD_BATTLE_PASS_QUEST.Dispatch_1_assignments in quests:
|
if KEYWORD_BATTLE_PASS_QUEST.Dispatch_1_assignments in quests:
|
||||||
logger.info('Achieved battle pass quest Dispatch_1_assignments')
|
logger.info(
|
||||||
|
'Achieved battle pass quest Dispatch_1_assignments')
|
||||||
self.config.task_call('BattlePass')
|
self.config.task_call('BattlePass')
|
||||||
# Check daily
|
# Check daily
|
||||||
quests = self.config.stored.DailyQuest.load_quests()
|
quests = self.config.stored.DailyQuest.load_quests()
|
||||||
@ -93,21 +100,25 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
f'User specified assignments: {", ".join([x.name for x in assignments])}')
|
f'User specified assignments: {", ".join([x.name for x in assignments])}')
|
||||||
_, remain, _ = self._limit_status
|
_, remain, _ = self._limit_status
|
||||||
for assignment in assignments:
|
for assignment in assignments:
|
||||||
|
if assignment in self.dispatched:
|
||||||
|
continue
|
||||||
|
if remain <= 0:
|
||||||
|
yield assignment
|
||||||
|
continue
|
||||||
logger.hr('Assignment inlist', level=2)
|
logger.hr('Assignment inlist', level=2)
|
||||||
logger.info(f'Check assignment inlist: {assignment}')
|
logger.info(f'Check assignment inlist: {assignment}')
|
||||||
self.goto_entry(assignment)
|
self.goto_entry(assignment)
|
||||||
if self.appear(CLAIM):
|
status = self._check_assignment_status()
|
||||||
|
if status == AssignmentStatus.CLAIMABLE:
|
||||||
self.claim(assignment, duration, should_redispatch=True)
|
self.claim(assignment, duration, should_redispatch=True)
|
||||||
continue
|
continue
|
||||||
if self.appear(DISPATCHED):
|
if status == AssignmentStatus.DISPATCHED:
|
||||||
self.dispatched[assignment] = datetime.now() + Duration(
|
self.dispatched[assignment] = datetime.now() + \
|
||||||
OCR_ASSIGNMENT_TIME).ocr_single_line(self.device.image)
|
self._get_assignment_time()
|
||||||
continue
|
continue
|
||||||
if remain > 0:
|
# General assignments must be dispatchable here
|
||||||
self.dispatch(assignment, duration)
|
self.dispatch(assignment, duration)
|
||||||
remain -= 1
|
remain -= 1
|
||||||
else:
|
|
||||||
yield assignment
|
|
||||||
|
|
||||||
def _check_all(self):
|
def _check_all(self):
|
||||||
"""
|
"""
|
||||||
@ -118,28 +129,31 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
Break when a dispatchable assignment is encountered
|
Break when a dispatchable assignment is encountered
|
||||||
"""
|
"""
|
||||||
logger.hr('Assignment check all', level=1)
|
logger.hr('Assignment check all', level=1)
|
||||||
_, remain, total = self._limit_status
|
current, remain, _ = self._limit_status
|
||||||
if total == len(self.dispatched):
|
if current == len(self.dispatched):
|
||||||
return remain
|
return remain
|
||||||
for group in self._iter_groups():
|
for group in self._iter_groups():
|
||||||
self.goto_group(group)
|
self.goto_group(group)
|
||||||
entries = self._iter_entries()
|
insight = False
|
||||||
for _ in range(len(group.entries)):
|
for assignment in self._iter_entries():
|
||||||
assignment = next(entries)
|
|
||||||
if assignment in self.dispatched:
|
if assignment in self.dispatched:
|
||||||
continue
|
continue
|
||||||
logger.hr('Assignment all', level=2)
|
logger.hr('Assignment all', level=2)
|
||||||
logger.info(f'Check assignment all: {assignment}')
|
logger.info(f'Check assignment all: {assignment}')
|
||||||
self.goto_entry(assignment)
|
self.goto_entry(assignment, insight)
|
||||||
if self.appear(CLAIM):
|
status = self._check_assignment_status()
|
||||||
|
if status == AssignmentStatus.CLAIMABLE:
|
||||||
self.claim(assignment, None, should_redispatch=False)
|
self.claim(assignment, None, should_redispatch=False)
|
||||||
|
current -= 1
|
||||||
remain += 1
|
remain += 1
|
||||||
|
insight = True # Order of entries change after claiming
|
||||||
continue
|
continue
|
||||||
if self.appear(DISPATCHED):
|
if status == AssignmentStatus.DISPATCHED:
|
||||||
self.dispatched[assignment] = datetime.now() + Duration(
|
self.dispatched[assignment] = datetime.now() + \
|
||||||
OCR_ASSIGNMENT_TIME).ocr_single_line(self.device.image)
|
self._get_assignment_time()
|
||||||
if total == len(self.dispatched):
|
if current == len(self.dispatched):
|
||||||
return remain
|
return remain
|
||||||
|
insight = False # Order of entries does not change here
|
||||||
continue
|
continue
|
||||||
break
|
break
|
||||||
return remain
|
return remain
|
||||||
@ -174,3 +188,29 @@ class Assignment(AssignmentClaim, SynthesizeUI):
|
|||||||
remain -= 1
|
remain -= 1
|
||||||
if remain <= 0:
|
if remain <= 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _dispatch_event(self, remain: int):
|
||||||
|
if remain <= 0:
|
||||||
|
return remain
|
||||||
|
logger.hr('Assignment dispatch event', level=1)
|
||||||
|
for group in self._iter_groups():
|
||||||
|
if not isinstance(group, AssignmentEventGroup):
|
||||||
|
continue
|
||||||
|
self.goto_group(group)
|
||||||
|
for assignment in self._iter_entries():
|
||||||
|
if assignment in self.dispatched:
|
||||||
|
continue
|
||||||
|
logger.hr('Assignment event', level=2)
|
||||||
|
logger.info(f'Check assignment event: {assignment}')
|
||||||
|
# Order of entries does not change during iteration
|
||||||
|
self.goto_entry(assignment, insight=False)
|
||||||
|
status = self._check_assignment_status()
|
||||||
|
# Should only be dispatchable or locked after _check_all
|
||||||
|
if status == AssignmentStatus.DISPATCHABLE:
|
||||||
|
self.dispatch(assignment, None)
|
||||||
|
remain -= 1
|
||||||
|
if remain <= 0:
|
||||||
|
return remain
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
return remain
|
||||||
|
@ -41,7 +41,7 @@ class AssignmentClaim(AssignmentDispatch):
|
|||||||
"""
|
"""
|
||||||
Pages:
|
Pages:
|
||||||
in: CLAIM
|
in: CLAIM
|
||||||
out: REDISPATCH
|
out: REPORT
|
||||||
"""
|
"""
|
||||||
skip_first_screenshot = True
|
skip_first_screenshot = True
|
||||||
while 1:
|
while 1:
|
||||||
@ -50,7 +50,9 @@ class AssignmentClaim(AssignmentDispatch):
|
|||||||
else:
|
else:
|
||||||
self.device.screenshot()
|
self.device.screenshot()
|
||||||
# End
|
# End
|
||||||
if self.appear(REDISPATCH):
|
# Neither CLOSE_REPORT nor REDISPATCH is shown
|
||||||
|
# If it is an EVENT assignment
|
||||||
|
if self.appear(REPORT):
|
||||||
logger.info('Assignment report appears')
|
logger.info('Assignment report appears')
|
||||||
break
|
break
|
||||||
# Claim rewards
|
# Claim rewards
|
||||||
@ -63,7 +65,7 @@ class AssignmentClaim(AssignmentDispatch):
|
|||||||
should_redispatch (bool): determined by user config and duration in report
|
should_redispatch (bool): determined by user config and duration in report
|
||||||
|
|
||||||
Pages:
|
Pages:
|
||||||
in: CLOSE_REPORT and REDISPATCH
|
in: REPORT
|
||||||
out: page_assignment
|
out: page_assignment
|
||||||
"""
|
"""
|
||||||
click_button = REDISPATCH if should_redispatch else CLOSE_REPORT
|
click_button = REDISPATCH if should_redispatch else CLOSE_REPORT
|
||||||
@ -78,7 +80,8 @@ class AssignmentClaim(AssignmentDispatch):
|
|||||||
logger.info('Assignment report is closed')
|
logger.info('Assignment report is closed')
|
||||||
break
|
break
|
||||||
# Close report
|
# Close report
|
||||||
if self.appear_then_click(click_button, interval=2):
|
if self.appear(REPORT, interval=2):
|
||||||
|
self.device.click(click_button)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def _is_duration_expected(self, duration: int) -> bool:
|
def _is_duration_expected(self, duration: int) -> bool:
|
||||||
|
@ -1,12 +1,37 @@
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from module.base.base import ModuleBase
|
||||||
from module.base.timer import Timer
|
from module.base.timer import Timer
|
||||||
from module.config.stored.classes import now
|
from module.config.stored.classes import now
|
||||||
from module.logger import logger
|
from module.logger import logger
|
||||||
|
from module.ui.switch import Switch
|
||||||
from tasks.assignment.assets.assets_assignment_dispatch import *
|
from tasks.assignment.assets.assets_assignment_dispatch import *
|
||||||
from tasks.assignment.assets.assets_assignment_ui import DISPATCHED
|
from tasks.assignment.assets.assets_assignment_ui import DISPATCHED
|
||||||
from tasks.assignment.keywords import *
|
from tasks.assignment.keywords import *
|
||||||
from tasks.assignment.ui import AssignmentSwitch, AssignmentUI
|
from tasks.assignment.ui import AssignmentUI
|
||||||
|
|
||||||
|
|
||||||
|
class AssignmentSwitch(Switch):
|
||||||
|
def __init__(self, name, active_color: tuple[int, int, int], is_selector=True):
|
||||||
|
super().__init__(name, is_selector)
|
||||||
|
self.active_color = active_color
|
||||||
|
|
||||||
|
def get(self, main: ModuleBase):
|
||||||
|
"""
|
||||||
|
Use image_color_count instead to determine whether the button is selected/active
|
||||||
|
|
||||||
|
Args:
|
||||||
|
main (ModuleBase):
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: state name or 'unknown'.
|
||||||
|
"""
|
||||||
|
for data in self.state_list:
|
||||||
|
if main.image_color_count(data['check_button'], self.active_color):
|
||||||
|
return data['state']
|
||||||
|
|
||||||
|
return 'unknown'
|
||||||
|
|
||||||
|
|
||||||
ASSIGNMENT_DURATION_SWITCH = AssignmentSwitch(
|
ASSIGNMENT_DURATION_SWITCH = AssignmentSwitch(
|
||||||
'AssignmentDurationSwitch',
|
'AssignmentDurationSwitch',
|
||||||
@ -22,20 +47,24 @@ class AssignmentDispatch(AssignmentUI):
|
|||||||
dispatched: dict[AssignmentEntry, datetime] = dict()
|
dispatched: dict[AssignmentEntry, datetime] = dict()
|
||||||
has_new_dispatch: bool = False
|
has_new_dispatch: bool = False
|
||||||
|
|
||||||
def dispatch(self, assignment: AssignmentEntry, duration: int):
|
def dispatch(self, assignment: AssignmentEntry, duration: int | None):
|
||||||
"""
|
"""
|
||||||
Dispatch assignment.
|
Dispatch assignment.
|
||||||
Should be called only when limit is checked
|
Should be called only when limit is checked
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
assignment (AssignmentEntry):
|
assignment (AssignmentEntry):
|
||||||
duration (int): user specified duration
|
duration (int | None): user specified duration, None for event assignments
|
||||||
|
|
||||||
Pages:
|
Pages:
|
||||||
in: EMPTY_SLOT
|
in: EMPTY_SLOT
|
||||||
out: DISPATCHED
|
out: DISPATCHED
|
||||||
"""
|
"""
|
||||||
self._select_characters()
|
self._select_characters()
|
||||||
|
if isinstance(assignment, AssignmentEventEntry):
|
||||||
|
self._select_support()
|
||||||
|
duration = self._get_assignment_time().total_seconds() / 3600
|
||||||
|
else:
|
||||||
self._select_duration(duration)
|
self._select_duration(duration)
|
||||||
self._confirm_assignment()
|
self._confirm_assignment()
|
||||||
self._wait_until_assignment_started()
|
self._wait_until_assignment_started()
|
||||||
@ -63,7 +92,8 @@ class AssignmentDispatch(AssignmentUI):
|
|||||||
logger.info('Characters are all selected')
|
logger.info('Characters are all selected')
|
||||||
break
|
break
|
||||||
# Ensure character list
|
# Ensure character list
|
||||||
if not self.appear(CHARACTER_LIST):
|
# Search EMPTY_SLOT to load offset
|
||||||
|
if not self.appear(CHARACTER_LIST) and self.appear(EMPTY_SLOT):
|
||||||
if self.interval_is_reached(CHARACTER_LIST, interval=2):
|
if self.interval_is_reached(CHARACTER_LIST, interval=2):
|
||||||
self.interval_reset(CHARACTER_LIST, interval=2)
|
self.interval_reset(CHARACTER_LIST, interval=2)
|
||||||
self.device.click(EMPTY_SLOT)
|
self.device.click(EMPTY_SLOT)
|
||||||
@ -78,6 +108,30 @@ class AssignmentDispatch(AssignmentUI):
|
|||||||
if not self.image_color_count(CHARACTER_2_SELECTED, (240, 240, 240)):
|
if not self.image_color_count(CHARACTER_2_SELECTED, (240, 240, 240)):
|
||||||
self.device.click(CHARACTER_2)
|
self.device.click(CHARACTER_2)
|
||||||
|
|
||||||
|
def _select_support(self):
|
||||||
|
skip_first_screenshot = True
|
||||||
|
self.interval_clear(
|
||||||
|
(CHARACTER_SUPPORT_LIST, CHARACTER_SUPPORT_SELECTED), interval=2)
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
self.device.screenshot()
|
||||||
|
# End
|
||||||
|
if self.match_color(CHARACTER_SUPPORT_SELECTED):
|
||||||
|
logger.info('Support character is selected')
|
||||||
|
break
|
||||||
|
# Ensure support list
|
||||||
|
if not self.appear(CHARACTER_SUPPORT_LIST):
|
||||||
|
if self.interval_is_reached(CHARACTER_SUPPORT_LIST, interval=2):
|
||||||
|
self.interval_reset(CHARACTER_SUPPORT_LIST, interval=2)
|
||||||
|
self.device.click(EMPTY_SLOT_SUPPORT)
|
||||||
|
continue
|
||||||
|
# Select
|
||||||
|
if self.interval_is_reached(CHARACTER_SUPPORT_SELECTED, interval=2):
|
||||||
|
self.interval_reset(CHARACTER_SUPPORT_SELECTED, interval=2)
|
||||||
|
self.device.click(CHARACTER_SUPPORT)
|
||||||
|
|
||||||
def _select_duration(self, duration: int):
|
def _select_duration(self, duration: int):
|
||||||
if duration not in {4, 8, 12, 20}:
|
if duration not in {4, 8, 12, 20}:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
@ -133,6 +187,6 @@ class AssignmentDispatch(AssignmentUI):
|
|||||||
else:
|
else:
|
||||||
self.device.screenshot()
|
self.device.screenshot()
|
||||||
# End
|
# End
|
||||||
if self.appear(ASSIGNMENT_STARTED_CHECK):
|
if self.match_color(ASSIGNMENT_STARTED_CHECK):
|
||||||
logger.info('Assignment started')
|
logger.info('Assignment started')
|
||||||
break
|
break
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import tasks.assignment.keywords.entry as KEYWORDS_ASSIGNMENT_ENTRY
|
import tasks.assignment.keywords.entry as KEYWORDS_ASSIGNMENT_ENTRY
|
||||||
import tasks.assignment.keywords.group as KEYWORDS_ASSIGNMENT_GROUP
|
import tasks.assignment.keywords.group as KEYWORDS_ASSIGNMENT_GROUP
|
||||||
from tasks.assignment.keywords.classes import AssignmentEntry, AssignmentGroup
|
import tasks.assignment.keywords.event_entry as KEYWORDS_ASSIGNMENT_EVENT_ENTRY
|
||||||
|
import tasks.assignment.keywords.event_group as KEYWORDS_ASSIGNMENT_EVENT_GROUP
|
||||||
|
from tasks.assignment.keywords.classes import *
|
||||||
|
|
||||||
KEYWORDS_ASSIGNMENT_GROUP.Character_Materials.entries = (
|
KEYWORDS_ASSIGNMENT_GROUP.Character_Materials.entries = (
|
||||||
KEYWORDS_ASSIGNMENT_ENTRY.Nine_Billion_Names,
|
KEYWORDS_ASSIGNMENT_ENTRY.Nine_Billion_Names,
|
||||||
@ -23,10 +25,37 @@ KEYWORDS_ASSIGNMENT_GROUP.Synthesis_Materials.entries = (
|
|||||||
KEYWORDS_ASSIGNMENT_ENTRY.Legend_of_the_Puppet_Master,
|
KEYWORDS_ASSIGNMENT_ENTRY.Legend_of_the_Puppet_Master,
|
||||||
KEYWORDS_ASSIGNMENT_ENTRY.The_Wages_of_Humanity,
|
KEYWORDS_ASSIGNMENT_ENTRY.The_Wages_of_Humanity,
|
||||||
)
|
)
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_GROUP.Space_Station_Task_Force.entries = (
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Repulsion_Bridge_Errors,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Meal_Delivery_Robot_Check_Up,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Noise_Complaint,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Interior_Temperature_Modulator,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Researcher_Health_Reports,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Confidential_Investigation,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Borrowed_Equipment,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Booking_System,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Non_Digital_Documents,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Drip_Feed_Errors,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Pet_Movement_Route_Planning,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Food_Improvement_Plan,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Curio_Distribution,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Super_Urgent_Waiting_Online,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Ventilation_Problem,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Unstable_Connection,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Chronology_Checks,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Supply_Chain_Management,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Malicious_Occupation_of_Public_Space,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Uniform_Material,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Virus_Re_creation_Report,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Abnormal_Signal,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Flexible_Working_Approval,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Lighting_Issue,
|
||||||
|
)
|
||||||
for group in (
|
for group in (
|
||||||
KEYWORDS_ASSIGNMENT_GROUP.Character_Materials,
|
KEYWORDS_ASSIGNMENT_GROUP.Character_Materials,
|
||||||
KEYWORDS_ASSIGNMENT_GROUP.EXP_Materials_Credits,
|
KEYWORDS_ASSIGNMENT_GROUP.EXP_Materials_Credits,
|
||||||
KEYWORDS_ASSIGNMENT_GROUP.Synthesis_Materials,
|
KEYWORDS_ASSIGNMENT_GROUP.Synthesis_Materials,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_GROUP.Space_Station_Task_Force,
|
||||||
):
|
):
|
||||||
for entry in group.entries:
|
for entry in group.entries:
|
||||||
assert entry.group is None
|
assert entry.group is None
|
||||||
|
@ -15,6 +15,19 @@ class AssignmentGroup(Keyword):
|
|||||||
class AssignmentEntry(Keyword):
|
class AssignmentEntry(Keyword):
|
||||||
instances: ClassVar = {}
|
instances: ClassVar = {}
|
||||||
group: AssignmentGroup = None
|
group: AssignmentGroup = None
|
||||||
|
|
||||||
def __hash__(self) -> int:
|
def __hash__(self) -> int:
|
||||||
return super().__hash__()
|
return super().__hash__()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(repr=False)
|
||||||
|
class AssignmentEventGroup(AssignmentGroup):
|
||||||
|
instances: ClassVar = {}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(repr=False)
|
||||||
|
class AssignmentEventEntry(AssignmentEntry):
|
||||||
|
instances: ClassVar = {}
|
||||||
|
|
||||||
|
def __hash__(self) -> int:
|
||||||
|
return super().__hash__()
|
||||||
|
221
tasks/assignment/keywords/event_entry.py
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
from .classes import AssignmentEventEntry
|
||||||
|
|
||||||
|
# This file was auto-generated, do not modify it manually. To generate:
|
||||||
|
# ``` python -m dev_tools.keyword_extract ```
|
||||||
|
|
||||||
|
Repulsion_Bridge_Errors = AssignmentEventEntry(
|
||||||
|
id=1,
|
||||||
|
name='Repulsion_Bridge_Errors',
|
||||||
|
cn='斥力桥报错',
|
||||||
|
cht='斥力橋錯誤',
|
||||||
|
en='Repulsion Bridge Errors',
|
||||||
|
jp='斥力ブリッジエラー',
|
||||||
|
es='Reporte de error del puente de rechazo',
|
||||||
|
)
|
||||||
|
Meal_Delivery_Robot_Check_Up = AssignmentEventEntry(
|
||||||
|
id=2,
|
||||||
|
name='Meal_Delivery_Robot_Check_Up',
|
||||||
|
cn='送餐机器人检修',
|
||||||
|
cht='送餐機器人檢修',
|
||||||
|
en='Meal-Delivery Robot Check-Up',
|
||||||
|
jp='配膳ロボット点検修理',
|
||||||
|
es='Mantenimiento de los robots de reparto de comida',
|
||||||
|
)
|
||||||
|
Noise_Complaint = AssignmentEventEntry(
|
||||||
|
id=3,
|
||||||
|
name='Noise_Complaint',
|
||||||
|
cn='噪音投诉问题',
|
||||||
|
cht='噪音投訴問題',
|
||||||
|
en='Noise Complaint',
|
||||||
|
jp='騒音苦情問題',
|
||||||
|
es='Quejas por ruidos',
|
||||||
|
)
|
||||||
|
Interior_Temperature_Modulator = AssignmentEventEntry(
|
||||||
|
id=4,
|
||||||
|
name='Interior_Temperature_Modulator',
|
||||||
|
cn='室内温度调节器',
|
||||||
|
cht='室內溫度調節器',
|
||||||
|
en='Interior Temperature Modulator',
|
||||||
|
jp='室内温度調節器',
|
||||||
|
es='Regulador de temperatura ambiental',
|
||||||
|
)
|
||||||
|
Researcher_Health_Reports = AssignmentEventEntry(
|
||||||
|
id=5,
|
||||||
|
name='Researcher_Health_Reports',
|
||||||
|
cn='科员的体检报告',
|
||||||
|
cht='組員的體檢報告',
|
||||||
|
en="Researchers' Health Reports",
|
||||||
|
jp='スタッフの健康診断報告',
|
||||||
|
es='Informe médico de los investigadores',
|
||||||
|
)
|
||||||
|
Confidential_Investigation = AssignmentEventEntry(
|
||||||
|
id=6,
|
||||||
|
name='Confidential_Investigation',
|
||||||
|
cn='秘密调查行动',
|
||||||
|
cht='秘密調查行動',
|
||||||
|
en='Confidential Investigation',
|
||||||
|
jp='秘密裏の調査',
|
||||||
|
es='Investigación encubierta',
|
||||||
|
)
|
||||||
|
Borrowed_Equipment = AssignmentEventEntry(
|
||||||
|
id=7,
|
||||||
|
name='Borrowed_Equipment',
|
||||||
|
cn='实验器械借用',
|
||||||
|
cht='實驗器械借用',
|
||||||
|
en='Borrowed Equipment',
|
||||||
|
jp='実験機器借用',
|
||||||
|
es='Préstamo de instrumentos de laboratorio',
|
||||||
|
)
|
||||||
|
Booking_System = AssignmentEventEntry(
|
||||||
|
id=8,
|
||||||
|
name='Booking_System',
|
||||||
|
cn='会议室预约系统',
|
||||||
|
cht='會議室預約系統',
|
||||||
|
en='Booking System',
|
||||||
|
jp='会議室予約システム',
|
||||||
|
es='Sistema de reserva de las salas de reuniones',
|
||||||
|
)
|
||||||
|
Non_Digital_Documents = AssignmentEventEntry(
|
||||||
|
id=9,
|
||||||
|
name='Non_Digital_Documents',
|
||||||
|
cn='非电子版文件',
|
||||||
|
cht='非電子版文件',
|
||||||
|
en='Non-Digital Documents',
|
||||||
|
jp='非デジタル版ファイル',
|
||||||
|
es='Documentos no electrónicos',
|
||||||
|
)
|
||||||
|
Drip_Feed_Errors = AssignmentEventEntry(
|
||||||
|
id=10,
|
||||||
|
name='Drip_Feed_Errors',
|
||||||
|
cn='液滴系统报错',
|
||||||
|
cht='液滴系統錯誤',
|
||||||
|
en='Drip-Feed Errors',
|
||||||
|
jp='水やりシステムエラー',
|
||||||
|
es='Reporte de error del sistema de goteo',
|
||||||
|
)
|
||||||
|
Pet_Movement_Route_Planning = AssignmentEventEntry(
|
||||||
|
id=11,
|
||||||
|
name='Pet_Movement_Route_Planning',
|
||||||
|
cn='宠物行动路线规划',
|
||||||
|
cht='寵物行動路線規劃',
|
||||||
|
en='Pet Movement Route Planning',
|
||||||
|
jp='ペットの行動ルート規制',
|
||||||
|
es='Planificación de las rutas de paseo de mascotas',
|
||||||
|
)
|
||||||
|
Food_Improvement_Plan = AssignmentEventEntry(
|
||||||
|
id=12,
|
||||||
|
name='Food_Improvement_Plan',
|
||||||
|
cn='餐饮优化方案',
|
||||||
|
cht='餐飲改良方案',
|
||||||
|
en='Food Improvement Plan',
|
||||||
|
jp='飲食優良化法案',
|
||||||
|
es='Programa de mejora de comida',
|
||||||
|
)
|
||||||
|
Curio_Distribution = AssignmentEventEntry(
|
||||||
|
id=13,
|
||||||
|
name='Curio_Distribution',
|
||||||
|
cn='奇物借用问题',
|
||||||
|
cht='奇物借用問題',
|
||||||
|
en='Curio Distribution',
|
||||||
|
jp='奇物借用問題',
|
||||||
|
es='Problemas con el préstamo de objetos raros',
|
||||||
|
)
|
||||||
|
Super_Urgent_Waiting_Online = AssignmentEventEntry(
|
||||||
|
id=14,
|
||||||
|
name='Super_Urgent_Waiting_Online',
|
||||||
|
cn='来活人很急在线等',
|
||||||
|
cht='急,線上等',
|
||||||
|
en='Super Urgent, Waiting Online',
|
||||||
|
jp='緊急助っ人求むオンラインにて待つ',
|
||||||
|
es='Muy urgente, esperando en línea',
|
||||||
|
)
|
||||||
|
Ventilation_Problem = AssignmentEventEntry(
|
||||||
|
id=15,
|
||||||
|
name='Ventilation_Problem',
|
||||||
|
cn='空气流通问题',
|
||||||
|
cht='空氣流通問題',
|
||||||
|
en='Ventilation Problem',
|
||||||
|
jp='換気問題',
|
||||||
|
es='Problemas con la circulación del aire',
|
||||||
|
)
|
||||||
|
Unstable_Connection = AssignmentEventEntry(
|
||||||
|
id=16,
|
||||||
|
name='Unstable_Connection',
|
||||||
|
cn='连接不稳定问题',
|
||||||
|
cht='連線不穩定問題',
|
||||||
|
en='Unstable Connection',
|
||||||
|
jp='接続不安定問題',
|
||||||
|
es='Conexión inestable',
|
||||||
|
)
|
||||||
|
Chronology_Checks = AssignmentEventEntry(
|
||||||
|
id=17,
|
||||||
|
name='Chronology_Checks',
|
||||||
|
cn='编年史校对',
|
||||||
|
cht='編年史校對',
|
||||||
|
en='Chronology Checks',
|
||||||
|
jp='編年史校正',
|
||||||
|
es='Corrección de registros',
|
||||||
|
)
|
||||||
|
Supply_Chain_Management = AssignmentEventEntry(
|
||||||
|
id=18,
|
||||||
|
name='Supply_Chain_Management',
|
||||||
|
cn='物流供应链管理',
|
||||||
|
cht='物流供應鏈管理',
|
||||||
|
en='Supply Chain Management',
|
||||||
|
jp='物流供給路線管理',
|
||||||
|
es='Gestión de pedidos',
|
||||||
|
)
|
||||||
|
Malicious_Occupation_of_Public_Space = AssignmentEventEntry(
|
||||||
|
id=19,
|
||||||
|
name='Malicious_Occupation_of_Public_Space',
|
||||||
|
cn='公共区域被恶意侵占',
|
||||||
|
cht='公共區域被惡意侵佔',
|
||||||
|
en='Malicious Occupation of Public Space',
|
||||||
|
jp='公共区域の悪意による独占',
|
||||||
|
es='Invasión de espacios públicos',
|
||||||
|
)
|
||||||
|
Uniform_Material = AssignmentEventEntry(
|
||||||
|
id=20,
|
||||||
|
name='Uniform_Material',
|
||||||
|
cn='科室服装面料',
|
||||||
|
cht='科室服裝材質',
|
||||||
|
en='Uniform Material',
|
||||||
|
jp='スタッフ制服の素材',
|
||||||
|
es='Material del uniforme',
|
||||||
|
)
|
||||||
|
Virus_Re_creation_Report = AssignmentEventEntry(
|
||||||
|
id=21,
|
||||||
|
name='Virus_Re_creation_Report',
|
||||||
|
cn='病毒溯源报告',
|
||||||
|
cht='病毒溯源報告',
|
||||||
|
en='Virus Re-creation Report',
|
||||||
|
jp='ウイルス根源報告',
|
||||||
|
es='Informe de rastreo de virus',
|
||||||
|
)
|
||||||
|
Abnormal_Signal = AssignmentEventEntry(
|
||||||
|
id=22,
|
||||||
|
name='Abnormal_Signal',
|
||||||
|
cn='舱段信号异常',
|
||||||
|
cht='艙段訊號異常',
|
||||||
|
en='Abnormal Signal',
|
||||||
|
jp='部分の信号異常',
|
||||||
|
es='Mala señal en las cabinas',
|
||||||
|
)
|
||||||
|
Flexible_Working_Approval = AssignmentEventEntry(
|
||||||
|
id=23,
|
||||||
|
name='Flexible_Working_Approval',
|
||||||
|
cn='轮休审批流程',
|
||||||
|
cht='輪休審批流程',
|
||||||
|
en='Flexible Working Approval',
|
||||||
|
jp='交代休み審査フロー',
|
||||||
|
es='Aprobación de días de descanso',
|
||||||
|
)
|
||||||
|
Lighting_Issue = AssignmentEventEntry(
|
||||||
|
id=24,
|
||||||
|
name='Lighting_Issue',
|
||||||
|
cn='灯光照明问题',
|
||||||
|
cht='燈光照明問題',
|
||||||
|
en='Lighting Issue',
|
||||||
|
jp='照明の色問題',
|
||||||
|
es='Problemas de iluminación',
|
||||||
|
)
|
14
tasks/assignment/keywords/event_group.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from .classes import AssignmentEventGroup
|
||||||
|
|
||||||
|
# This file was auto-generated, do not modify it manually. To generate:
|
||||||
|
# ``` python -m dev_tools.keyword_extract ```
|
||||||
|
|
||||||
|
Space_Station_Task_Force = AssignmentEventGroup(
|
||||||
|
id=1,
|
||||||
|
name='Space_Station_Task_Force',
|
||||||
|
cn='空间站特派',
|
||||||
|
cht='太空站特派',
|
||||||
|
en='Space Station Task Force',
|
||||||
|
jp='ステーション特派',
|
||||||
|
es='Comando de la Estación Espacial',
|
||||||
|
)
|
@ -1,39 +1,27 @@
|
|||||||
import re
|
import re
|
||||||
|
from collections.abc import Iterator
|
||||||
|
from datetime import timedelta
|
||||||
|
from enum import Enum
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from typing import Iterator
|
|
||||||
|
|
||||||
from module.base.base import ModuleBase
|
|
||||||
from module.base.timer import Timer
|
from module.base.timer import Timer
|
||||||
from module.exception import ScriptError
|
from module.exception import ScriptError
|
||||||
from module.logger import logger
|
from module.logger import logger
|
||||||
from module.ocr.ocr import DigitCounter, Duration, Ocr
|
from module.ocr.ocr import DigitCounter, Duration, Ocr
|
||||||
|
from tasks.dungeon.ui import DungeonTabSwitch as Switch
|
||||||
from module.ui.draggable_list import DraggableList
|
from module.ui.draggable_list import DraggableList
|
||||||
from module.ui.switch import Switch
|
from tasks.assignment.assets.assets_assignment_claim import CLAIM
|
||||||
|
from tasks.assignment.assets.assets_assignment_dispatch import EMPTY_SLOT
|
||||||
from tasks.assignment.assets.assets_assignment_ui import *
|
from tasks.assignment.assets.assets_assignment_ui import *
|
||||||
from tasks.assignment.keywords import *
|
from tasks.assignment.keywords import *
|
||||||
from tasks.base.ui import UI
|
from tasks.base.ui import UI
|
||||||
|
|
||||||
|
|
||||||
class AssignmentSwitch(Switch):
|
class AssignmentStatus(Enum):
|
||||||
def __init__(self, name, active_color: tuple[int, int, int], is_selector=True):
|
CLAIMABLE = 0
|
||||||
super().__init__(name, is_selector)
|
DISPATCHED = 1
|
||||||
self.active_color = active_color
|
DISPATCHABLE = 2
|
||||||
|
LOCKED = 3
|
||||||
def get(self, main: ModuleBase):
|
|
||||||
"""
|
|
||||||
Use image_color_count instead to determine whether the button is selected/active
|
|
||||||
|
|
||||||
Args:
|
|
||||||
main (ModuleBase):
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: state name or 'unknown'.
|
|
||||||
"""
|
|
||||||
for data in self.state_list:
|
|
||||||
if main.image_color_count(data['check_button'], self.active_color):
|
|
||||||
return data['state']
|
|
||||||
|
|
||||||
return 'unknown'
|
|
||||||
|
|
||||||
|
|
||||||
class AssignmentOcr(Ocr):
|
class AssignmentOcr(Ocr):
|
||||||
@ -50,6 +38,10 @@ class AssignmentOcr(Ocr):
|
|||||||
(KEYWORDS_ASSIGNMENT_ENTRY.Akashic_Records.name, '阿[未][夏复]记录'),
|
(KEYWORDS_ASSIGNMENT_ENTRY.Akashic_Records.name, '阿[未][夏复]记录'),
|
||||||
(KEYWORDS_ASSIGNMENT_ENTRY.Legend_of_the_Puppet_Master.name, '^师传说'),
|
(KEYWORDS_ASSIGNMENT_ENTRY.Legend_of_the_Puppet_Master.name, '^师传说'),
|
||||||
(KEYWORDS_ASSIGNMENT_ENTRY.The_Wages_of_Humanity.name, '[赠]养人类'),
|
(KEYWORDS_ASSIGNMENT_ENTRY.The_Wages_of_Humanity.name, '[赠]养人类'),
|
||||||
|
],
|
||||||
|
'en': [
|
||||||
|
(KEYWORDS_ASSIGNMENT_EVENT_ENTRY.Food_Improvement_Plan.name,
|
||||||
|
'Food\s*[I]{0}mprovement Plan'),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +55,15 @@ class AssignmentOcr(Ocr):
|
|||||||
def filter_detected(self, result) -> bool:
|
def filter_detected(self, result) -> bool:
|
||||||
# Drop duration rows
|
# Drop duration rows
|
||||||
res = Duration.timedelta_regex(self.lang).search(result.ocr_text)
|
res = Duration.timedelta_regex(self.lang).search(result.ocr_text)
|
||||||
return not bool(res.group('seconds'))
|
if res.group('hours') or res.group('seconds'):
|
||||||
|
return False
|
||||||
|
# Locked event assignments
|
||||||
|
locked_pattern = {
|
||||||
|
'cn': '解锁$',
|
||||||
|
'en': 'Locked$',
|
||||||
|
}[self.lang]
|
||||||
|
res = re.search(locked_pattern, result.ocr_text)
|
||||||
|
return not res
|
||||||
|
|
||||||
def after_process(self, result: str):
|
def after_process(self, result: str):
|
||||||
result = super().after_process(result)
|
result = super().after_process(result)
|
||||||
@ -74,38 +74,57 @@ class AssignmentOcr(Ocr):
|
|||||||
if matched is None:
|
if matched is None:
|
||||||
return result
|
return result
|
||||||
keyword_lang = self.lang
|
keyword_lang = self.lang
|
||||||
matched = getattr(KEYWORDS_ASSIGNMENT_ENTRY, matched.lastgroup)
|
for keyword_class in (
|
||||||
|
KEYWORDS_ASSIGNMENT_ENTRY,
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_ENTRY,
|
||||||
|
):
|
||||||
|
matched = getattr(keyword_class, matched.lastgroup, None)
|
||||||
|
if matched is not None:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ScriptError(f'No keyword found for {matched.lastgroup}')
|
||||||
matched = getattr(matched, keyword_lang)
|
matched = getattr(matched, keyword_lang)
|
||||||
logger.attr(name=f'{self.name} after_process',
|
logger.attr(name=f'{self.name} after_process',
|
||||||
text=f'{result} -> {matched}')
|
text=f'{result} -> {matched}')
|
||||||
return matched
|
return matched
|
||||||
|
|
||||||
|
|
||||||
ASSIGNMENT_TOP_SWITCH = AssignmentSwitch(
|
ASSIGNMENT_GROUP_SWITCH = Switch(
|
||||||
'AssignmentTopSwitch',
|
'AssignmentGroupSwitch',
|
||||||
(240, 240, 240)
|
is_selector=True
|
||||||
)
|
)
|
||||||
ASSIGNMENT_TOP_SWITCH.add_state(
|
ASSIGNMENT_GROUP_SWITCH.add_state(
|
||||||
|
KEYWORDS_ASSIGNMENT_EVENT_GROUP.Space_Station_Task_Force,
|
||||||
|
check_button=SPACE_STATION_TASK_FORCE_CHECK,
|
||||||
|
click_button=SPACE_STATION_TASK_FORCE_CLICK
|
||||||
|
)
|
||||||
|
ASSIGNMENT_GROUP_SWITCH.add_state(
|
||||||
KEYWORDS_ASSIGNMENT_GROUP.Character_Materials,
|
KEYWORDS_ASSIGNMENT_GROUP.Character_Materials,
|
||||||
check_button=CHARACTER_MATERIALS
|
check_button=CHARACTER_MATERIALS_CHECK,
|
||||||
|
click_button=CHARACTER_MATERIALS_CLICK
|
||||||
)
|
)
|
||||||
ASSIGNMENT_TOP_SWITCH.add_state(
|
ASSIGNMENT_GROUP_SWITCH.add_state(
|
||||||
KEYWORDS_ASSIGNMENT_GROUP.EXP_Materials_Credits,
|
KEYWORDS_ASSIGNMENT_GROUP.EXP_Materials_Credits,
|
||||||
check_button=EXP_MATERIALS_CREDITS
|
check_button=EXP_MATERIALS_CREDITS_CHECK,
|
||||||
|
click_button=EXP_MATERIALS_CREDITS_CLICK
|
||||||
)
|
)
|
||||||
ASSIGNMENT_TOP_SWITCH.add_state(
|
ASSIGNMENT_GROUP_SWITCH.add_state(
|
||||||
KEYWORDS_ASSIGNMENT_GROUP.Synthesis_Materials,
|
KEYWORDS_ASSIGNMENT_GROUP.Synthesis_Materials,
|
||||||
check_button=SYNTHESIS_MATERIALS
|
check_button=SYNTHESIS_MATERIALS_CHECK,
|
||||||
|
click_button=SYNTHESIS_MATERIALS_CLICK
|
||||||
)
|
)
|
||||||
|
|
||||||
ASSIGNMENT_ENTRY_LIST = DraggableList(
|
ASSIGNMENT_ENTRY_LIST = DraggableList(
|
||||||
'AssignmentEntryList',
|
'AssignmentEntryList',
|
||||||
keyword_class=AssignmentEntry,
|
keyword_class=[AssignmentEntry, AssignmentEventEntry],
|
||||||
ocr_class=AssignmentOcr,
|
ocr_class=AssignmentOcr,
|
||||||
search_button=OCR_ASSIGNMENT_LIST,
|
search_button=OCR_ASSIGNMENT_ENTRY_LIST,
|
||||||
check_row_order=False,
|
check_row_order=False,
|
||||||
active_color=(40, 40, 40)
|
active_color=(40, 40, 40)
|
||||||
)
|
)
|
||||||
|
ASSIGNMENT_ENTRY_LIST.known_rows = [
|
||||||
|
kw for kc in ASSIGNMENT_ENTRY_LIST.keyword_class
|
||||||
|
for kw in kc.instances.values()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class AssignmentUI(UI):
|
class AssignmentUI(UI):
|
||||||
@ -119,14 +138,17 @@ class AssignmentUI(UI):
|
|||||||
self.device.screenshot()
|
self.device.screenshot()
|
||||||
self.goto_group(KEYWORDS_ASSIGNMENT_GROUP.Character_Materials)
|
self.goto_group(KEYWORDS_ASSIGNMENT_GROUP.Character_Materials)
|
||||||
"""
|
"""
|
||||||
|
if ASSIGNMENT_GROUP_SWITCH.get(self) == group:
|
||||||
|
return
|
||||||
logger.hr('Assignment group goto', level=3)
|
logger.hr('Assignment group goto', level=3)
|
||||||
if ASSIGNMENT_TOP_SWITCH.set(group, main=self):
|
if ASSIGNMENT_GROUP_SWITCH.set(group, self):
|
||||||
self._wait_until_entry_loaded()
|
self._wait_until_entry_loaded()
|
||||||
|
|
||||||
def goto_entry(self, entry: AssignmentEntry):
|
def goto_entry(self, entry: AssignmentEntry, insight: bool = True):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
entry (AssignmentEntry):
|
entry (AssignmentEntry):
|
||||||
|
insight (bool): skip ocr to save time if insight is False
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
self = AssignmentUI('src')
|
self = AssignmentUI('src')
|
||||||
@ -143,7 +165,24 @@ class AssignmentUI(UI):
|
|||||||
raise ScriptError(err_msg)
|
raise ScriptError(err_msg)
|
||||||
else:
|
else:
|
||||||
self.goto_group(entry.group)
|
self.goto_group(entry.group)
|
||||||
ASSIGNMENT_ENTRY_LIST.select_row(entry, self)
|
ASSIGNMENT_ENTRY_LIST.select_row(entry, self, insight=insight)
|
||||||
|
|
||||||
|
def _wait_until_group_loaded(self):
|
||||||
|
skip_first_screenshot = True
|
||||||
|
timeout = Timer(2, count=3).start()
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
self.device.screenshot()
|
||||||
|
|
||||||
|
if timeout.reached():
|
||||||
|
logger.warning('Wait group loaded timeout')
|
||||||
|
break
|
||||||
|
if self.image_color_count(GROUP_SEARCH, (40, 40, 40), count=25000) and \
|
||||||
|
self.image_color_count(GROUP_SEARCH, (240, 240, 240), count=8000):
|
||||||
|
logger.info('Group loaded')
|
||||||
|
break
|
||||||
|
|
||||||
def _wait_until_entry_loaded(self):
|
def _wait_until_entry_loaded(self):
|
||||||
skip_first_screenshot = True
|
skip_first_screenshot = True
|
||||||
@ -175,8 +214,42 @@ class AssignmentUI(UI):
|
|||||||
self.config.stored.Assignment.set(0, 0)
|
self.config.stored.Assignment.set(0, 0)
|
||||||
return current, remain, total
|
return current, remain, total
|
||||||
|
|
||||||
|
def _check_assignment_status(self) -> AssignmentStatus:
|
||||||
|
skip_first_screenshot = True
|
||||||
|
timeout = Timer(2, count=3).start()
|
||||||
|
ret = AssignmentStatus.LOCKED
|
||||||
|
while 1:
|
||||||
|
if skip_first_screenshot:
|
||||||
|
skip_first_screenshot = False
|
||||||
|
else:
|
||||||
|
self.device.screenshot()
|
||||||
|
|
||||||
|
if timeout.reached():
|
||||||
|
logger.info(
|
||||||
|
'Check assignment status timeout, assume LOCKED'
|
||||||
|
)
|
||||||
|
break
|
||||||
|
if self.appear(CLAIM):
|
||||||
|
ret = AssignmentStatus.CLAIMABLE
|
||||||
|
break
|
||||||
|
if self.appear(DISPATCHED):
|
||||||
|
ret = AssignmentStatus.DISPATCHED
|
||||||
|
break
|
||||||
|
if self.appear(EMPTY_SLOT):
|
||||||
|
ret = AssignmentStatus.DISPATCHABLE
|
||||||
|
break
|
||||||
|
logger.attr('AssignmentStatus', ret.name)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def _get_assignment_time(self) -> timedelta:
|
||||||
|
return Duration(OCR_ASSIGNMENT_TIME).ocr_single_line(self.device.image)
|
||||||
|
|
||||||
def _iter_groups(self) -> Iterator[AssignmentGroup]:
|
def _iter_groups(self) -> Iterator[AssignmentGroup]:
|
||||||
for state in ASSIGNMENT_TOP_SWITCH.state_list:
|
self._wait_until_group_loaded()
|
||||||
|
for state in ASSIGNMENT_GROUP_SWITCH.state_list:
|
||||||
|
check = state['check_button']
|
||||||
|
click = state['click_button']
|
||||||
|
if self.appear(check) or self.appear(click):
|
||||||
yield state['state']
|
yield state['state']
|
||||||
|
|
||||||
def _iter_entries(self) -> Iterator[AssignmentEntry]:
|
def _iter_entries(self) -> Iterator[AssignmentEntry]:
|
||||||
@ -184,5 +257,8 @@ class AssignmentUI(UI):
|
|||||||
Iterate entries from top to bottom
|
Iterate entries from top to bottom
|
||||||
"""
|
"""
|
||||||
ASSIGNMENT_ENTRY_LIST.load_rows(main=self)
|
ASSIGNMENT_ENTRY_LIST.load_rows(main=self)
|
||||||
for button in ASSIGNMENT_ENTRY_LIST.cur_buttons:
|
# Freeze ocr results here
|
||||||
yield button.matched_keyword
|
yield from [
|
||||||
|
button.matched_keyword
|
||||||
|
for button in ASSIGNMENT_ENTRY_LIST.cur_buttons
|
||||||
|
]
|
||||||
|
@ -61,6 +61,8 @@ class Login(UI):
|
|||||||
# Additional
|
# Additional
|
||||||
if self.handle_popup_single():
|
if self.handle_popup_single():
|
||||||
continue
|
continue
|
||||||
|
if self.handle_popup_confirm():
|
||||||
|
continue
|
||||||
if self.ui_additional():
|
if self.ui_additional():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|