diff --git a/data/locales/en/LC_MESSAGES/ocr.mo b/data/locales/en/LC_MESSAGES/ocr.mo index a52de708..82c87f9a 100644 Binary files a/data/locales/en/LC_MESSAGES/ocr.mo and b/data/locales/en/LC_MESSAGES/ocr.mo differ diff --git a/data/locales/ocr/en.po b/data/locales/ocr/en.po index 4b223b33..84bd64ef 100644 --- a/data/locales/ocr/en.po +++ b/data/locales/ocr/en.po @@ -201,7 +201,7 @@ msgstr "Monitoring Room" msgid "接待中心" msgstr "Reception Center" -msgid "空海之形" +msgid "空海之形凝滞虚影" msgstr "Stagnant Shadow" # Special Point - Herta Space Station - Storage Zone @@ -217,10 +217,10 @@ msgstr "Special Purpose Lab" msgid "无明之间" msgstr "Gallery of Shadow" -msgid "毁灭之蕾" +msgid "毁灭之蕾拟造花萼赤" msgstr "Bud of Destruction" -msgid "霜风之径" +msgid "霜风之径侵蚀隧洞" msgstr "Path of Gelid Wind" msgid "裂界征兆" @@ -236,7 +236,7 @@ msgstr "Railway Platform" msgid "电力室" msgstr "Electrical Room" -msgid "存护之蕾" +msgid "存护之蕾拟造花萼赤" msgstr "Bud of Preservation" msgid "毁灭的开端" @@ -299,10 +299,10 @@ msgstr "Long Slope" msgid "着陆点" msgstr "Landing Point" -msgid "巡猎之蕾" +msgid "巡猎之蕾拟造花萼赤" msgstr "Bud of The Hunt" -msgid "回忆之蕾" +msgid "回忆之蕾拟造花萼金" msgstr "Bud of Memories" msgid "玲可" @@ -318,13 +318,13 @@ msgstr "Leisure Plaza" msgid "歌德旧宅" msgstr "Goethe Mansion" -msgid "幻光之形" +msgid "幻光之形凝滞虚影" msgstr "Shape of Mirage" -msgid "丰饶之蕾" +msgid "丰饶之蕾拟造花萼赤" msgstr "Bud of Abundance" -msgid "以太之蕾" +msgid "以太之蕾拟造花萼金" msgstr "Bud of Aether" # Special Point - Jarilo-VI - Silvermane Guard Restricted Zone @@ -337,10 +337,10 @@ msgstr "Frontline" msgid "能源枢纽" msgstr "Energy Hub" -msgid "炎华之形" +msgid "炎华之形凝滞虚影" msgstr "Shape of Blaze" -msgid "迅拳之径" +msgid "迅拳之径侵蚀隧洞" msgstr "Path of Jabbing Punch" msgid "以眼还眼" @@ -362,13 +362,13 @@ msgstr "Command Center" msgid "古战场前线" msgstr "Ancient Battlefield: Frontline" -msgid "鸣雷之形" +msgid "鸣雷之形凝滞虚影" msgstr "Shape of Fulmination" -msgid "霜晶之形" +msgid "霜晶之形凝滞虚影" msgstr "Shape of Rime" -msgid "漂泊之径" +msgid "漂泊之径侵蚀隧洞" msgstr "Path of Drifting" # Special Point - Jarilo-VI - Everwinter Hill @@ -378,7 +378,7 @@ msgstr "Ancient Battlefield" msgid "造物平台" msgstr "Deck of Creation" -msgid "睿治之径" +msgid "睿治之径侵蚀隧洞" msgstr "Path of Providence" msgid "寒潮的落幕" @@ -433,16 +433,16 @@ msgstr "Overlook" msgid "主矿道" msgstr "Main Mine Shaft" -msgid "锋芒之形" +msgid "锋芒之形凝滞虚影" msgstr "Shape of Spike" -msgid "燔灼之形" +msgid "燔灼之形凝滞虚影" msgstr "Shape of Scorch" -msgid "虚无之蕾" +msgid "虚无之蕾拟造花萼赤" msgstr "Bud of Nihility" -msgid "藏珍之蕾" +msgid "藏珍之蕾拟造花萼金" msgstr "Bud of Treasures" # Special Point - Jarilo-VI - Rivet Town @@ -452,10 +452,10 @@ msgstr "Orphanage" msgid "废弃市集" msgstr "Abandoned Market" -msgid "巽风之形" +msgid "巽风之形凝滞虚影" msgstr "Shape of Gust" -msgid "智识之蕾" +msgid "智识之蕾拟造花萼赤" msgstr "Bud of Erudition" # Special Point - Jarilo-VI - Robot Settlement @@ -468,7 +468,7 @@ msgstr "Svarog's Base" msgid "能源转换设施" msgstr "Energy Conversion Station" -msgid "同谐之蕾" +msgid "同谐之蕾拟造花萼赤" msgstr "Bud of Harmony" # Special Point - The Xianzhou Luofu - Central Starskiff Haven @@ -512,10 +512,10 @@ msgstr "Trove of Verdure: South Wing" msgid "流云渡乘槎处" msgstr "Cloudford: Skiff Boarding Area" -msgid "冰棱之形" +msgid "冰棱之形凝滞虚影" msgstr "Shape of Icicle" -msgid "圣颂之径" +msgid "圣颂之径侵蚀隧洞" msgstr "Path of Holy Hymn" msgid "过期邮包收购处" @@ -534,10 +534,10 @@ msgstr "Ship Nursery - The Burgeoning" msgid "泊航区" msgstr "The Mooring" -msgid "震厄之形" +msgid "震厄之形凝滞虚影" msgstr "Shape of Doom" -msgid "野焰之径" +msgid "野焰之径侵蚀隧洞" msgstr "Path of Conflagration" # Special Point - The Xianzhou Luofu - Exalting Sanctum @@ -631,7 +631,7 @@ msgstr "Arcane Moorage" msgid "造化洪炉" msgstr "Creation Furnace" -msgid "偃偶之形" +msgid "偃偶之形凝滞虚影" msgstr "Shape of Puppetry" # Interact @@ -651,10 +651,10 @@ msgstr "Healer's Market" msgid "岐黄署" msgstr "Medicine Bureau" -msgid "天人之形" +msgid "天人之形凝滞虚影" msgstr "Shape of Celestial" -msgid "药使之径" +msgid "药使之径侵蚀隧洞" msgstr "Path of Elixir Seekers" msgid "祈龙坛" @@ -679,7 +679,7 @@ msgstr "Ancient Sea Palace Ruins" msgid "显龙大雩殿" msgstr "Draggonvista Rain Hall" -msgid "孽兽之形" +msgid "孽兽之形凝滞虚影" msgstr "Shape of Abomination" msgid "不死的神实" @@ -698,10 +698,10 @@ msgstr "Verdant Terrace Entrance" msgid "燕乐亭入口" msgstr "Swallowsong Pavilion Entrance" -msgid "幽府之形" +msgid "幽府之形凝滞虚影" msgstr "Shape of Perdition" -msgid "幽冥之径" +msgid "幽冥之径侵蚀隧洞" msgstr "Path of Darkness" # Large Map Btn diff --git a/images/template/battle_times_minus/origin.png b/images/template/battle_times_minus/origin.png new file mode 100644 index 00000000..f7886e34 Binary files /dev/null and b/images/template/battle_times_minus/origin.png differ diff --git a/images/template/battle_times_minus/raw.png b/images/template/battle_times_minus/raw.png new file mode 100644 index 00000000..e3a8d5a5 Binary files /dev/null and b/images/template/battle_times_minus/raw.png differ diff --git a/images/template/battle_times_plus/origin.png b/images/template/battle_times_plus/origin.png new file mode 100644 index 00000000..adf8a510 Binary files /dev/null and b/images/template/battle_times_plus/origin.png differ diff --git a/images/template/battle_times_plus/raw.png b/images/template/battle_times_plus/raw.png new file mode 100644 index 00000000..148e49e4 Binary files /dev/null and b/images/template/battle_times_plus/raw.png differ diff --git a/src/basic/str_utils.py b/src/basic/str_utils.py index 82806300..2abcc127 100644 --- a/src/basic/str_utils.py +++ b/src/basic/str_utils.py @@ -1,3 +1,8 @@ +import re + +from basic.log_utils import log + + def find(source: str, target: str, ignore_case: bool = False) -> int: """ 字符串find的封装 在原目标串中招目标字符串 @@ -57,3 +62,16 @@ def longest_common_subsequence_length(str1: str, str2: str): dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) return dp[m][n] + + +def get_digits(v: str) -> int: + """ + 返回字符串中的数字部分 + :param v: + :return: + """ + try: + return int(re.sub(r"\D", "", v)) + except Exception: + log.error('目标字符串中没有数字 %s', v) + return 0 diff --git a/src/sr/app/routine/trailblaze_power.py b/src/sr/app/routine/trailblaze_power.py index aaec8e48..b613e716 100644 --- a/src/sr/app/routine/trailblaze_power.py +++ b/src/sr/app/routine/trailblaze_power.py @@ -3,7 +3,7 @@ from cv2.typing import MatLike -from basic import Rect +from basic import Rect, str_utils from basic.i18_utils import gt from basic.img import cv2_utils from basic.log_utils import log @@ -14,7 +14,7 @@ from sr.operation.combine.use_trailblaze_power import get_point_by_unique_id, TrailblazePowerPoint, UseTrailblazePower from sr.operation.unit.open_map import OpenMap -TRAILBLAZE_POWER = AppDescription(cn='开拓力(测试中)', id='trailblaze_power') +TRAILBLAZE_POWER = AppDescription(cn='开拓力', id='trailblaze_power') register_app(TRAILBLAZE_POWER) @@ -127,8 +127,7 @@ def _execute_one_round(self) -> int: screen: MatLike = self.screenshot() part, _ = cv2_utils.crop_image(screen, TrailblazePower.MAP_POWER_RECT) ocr_result = self.ctx.ocr.ocr_for_single_line(part, strict_one_line=True) - digit_result = re.sub(r"\D", "", ocr_result) - self.power = int(digit_result) + self.power = str_utils.get_digits(ocr_result) log.info('当前体力 %d', self.power) self.phase += 1 return Operation.WAIT diff --git a/src/sr/const/map_const.py b/src/sr/const/map_const.py index 8be7486e..d33909a0 100644 --- a/src/sr/const/map_const.py +++ b/src/sr/const/map_const.py @@ -222,7 +222,7 @@ def unique_id(self): # 空间站黑塔 - 基座舱段 P01_R02_SP01 = TransportPoint('JKS', '监控室', P01_R02, 'mm_tp_03', (635, 143), (642, 133)) P01_R02_SP02 = TransportPoint('JDZX', '接待中心', P01_R02, 'mm_tp_03', (493, 500), (503, 496)) -P01_R02_SP03 = TransportPoint('KHZX', '空海之形', P01_R02, 'mm_tp_06', (540, 938), (554, 923)) +P01_R02_SP03 = TransportPoint('KHZX', '空海之形凝滞虚影', P01_R02, 'mm_tp_06', (540, 938), (554, 923)) P01_R02_SP04 = TransportPoint('TKDT', '太空电梯', P01_R02, 'mm_sp_02', (556, 986)) # 空间站黑塔 - 收容舱段 @@ -230,8 +230,8 @@ def unique_id(self): P01_R03_SP02 = TransportPoint('KZZXW', '控制中心外', P01_R03_L1, 'mm_tp_03', (372, 375)) P01_R03_SP03 = TransportPoint('TSJXS', '特殊解析室', P01_R03_L2, 'mm_tp_03', (765, 439)) P01_R03_SP04 = TransportPoint('WMZJ', '无明之间', P01_R03_L1, 'mm_tp_03', (1040, 510)) -P01_R03_SP05 = TransportPoint('HMZL', '毁灭之蕾', P01_R03_L1, 'mm_tp_07', (316, 325)) -P01_R03_SP06 = TransportPoint('SFZJ', '霜风之径', P01_R03_L1, 'mm_tp_09', (847, 367)) +P01_R03_SP05 = TransportPoint('HMZL', '毁灭之蕾拟造花萼赤', P01_R03_L1, 'mm_tp_07', (316, 325)) +P01_R03_SP06 = TransportPoint('SFZJ', '霜风之径侵蚀隧洞', P01_R03_L1, 'mm_tp_09', (847, 367)) P01_R03_SP07 = TransportPoint('LJZZ', '裂界征兆', P01_R03_L1, 'mm_sp_01', (459, 342)) P01_R03_SP08 = TransportPoint('TKDT', '太空电梯', P01_R03_L1, 'mm_sp_02', (607, 364)) @@ -239,7 +239,7 @@ def unique_id(self): P01_R04_SP01 = TransportPoint('BJKF', '备件库房', P01_R04_L2, 'mm_tp_03', (434, 240)) P01_R04_SP02 = TransportPoint('YT', '月台', P01_R04_L2, 'mm_tp_03', (789, 404)) P01_R04_SP03 = TransportPoint('DLS', '电力室', P01_R04_L2, 'mm_tp_03', (165, 414)) -P01_R04_SP04 = TransportPoint('CHZL', '存护之蕾', P01_R04_L2, 'mm_tp_07', (467, 322)) +P01_R04_SP04 = TransportPoint('CHZL', '存护之蕾拟造花萼赤', P01_R04_L2, 'mm_tp_07', (467, 322)) P01_R04_SP05 = TransportPoint('TKDT', '太空电梯', P01_R04_L2, 'mm_sp_02', (105, 345)) P01_R04_SP06 = TransportPoint('HMDKD', '毁灭的开端', P01_R04_L2, 'mm_boss_01', (1010, 286)) @@ -267,8 +267,8 @@ def unique_id(self): # 雅利洛 - 城郊雪原 P02_R02_SP01 = TransportPoint('CP', '长坡', P02_R02, 'mm_tp_03', (1035, 319)) P02_R02_SP02 = TransportPoint('ZLD', '着陆点', P02_R02, 'mm_tp_03', (1283, 367)) -P02_R02_SP03 = TransportPoint('XLZL', '巡猎之蕾', P02_R02, 'mm_tp_07', (946, 244)) -P02_R02_SP04 = TransportPoint('HYZL', '回忆之蕾', P02_R02, 'mm_tp_08', (1098, 391)) +P02_R02_SP03 = TransportPoint('XLZL', '巡猎之蕾拟造花萼赤', P02_R02, 'mm_tp_07', (946, 244)) +P02_R02_SP04 = TransportPoint('HYZL', '回忆之蕾拟造花萼金', P02_R02, 'mm_tp_08', (1098, 391)) P02_R02_SP05 = TransportPoint('XZQ', '行政区', P02_R02, 'mm_sp_02', (444, 109)) P02_R02_SP06 = TransportPoint('LK', '玲可', P02_R02, 'mm_sp_03', (1032, 342)) @@ -276,16 +276,16 @@ def unique_id(self): P02_R03_SP01 = TransportPoint('HCGC', '候车广场', P02_R03, 'mm_tp_03', (598, 832)) P02_R03_SP02 = TransportPoint('XXGC', '休闲广场', P02_R03, 'mm_tp_03', (690, 480)) P02_R03_SP03 = TransportPoint('GDJZ', '歌德旧宅', P02_R03, 'mm_tp_03', (811, 259)) -P02_R03_SP04 = TransportPoint('HGZX', '幻光之形', P02_R03, 'mm_tp_06', (450, 840)) -P02_R03_SP05 = TransportPoint('FRZL', '丰饶之蕾', P02_R03, 'mm_tp_07', (659, 509)) -P02_R03_SP06 = TransportPoint('YTZL', '以太之蕾', P02_R03, 'mm_tp_08', (596, 194)) +P02_R03_SP04 = TransportPoint('HGZX', '幻光之形凝滞虚影', P02_R03, 'mm_tp_06', (450, 840)) +P02_R03_SP05 = TransportPoint('FRZL', '丰饶之蕾拟造花萼赤', P02_R03, 'mm_tp_07', (659, 509)) +P02_R03_SP06 = TransportPoint('YTZL', '以太之蕾拟造花萼金', P02_R03, 'mm_tp_08', (596, 194)) # 雅利洛 - 铁卫禁区 P02_R04_SP01 = TransportPoint('JQGS', '禁区岗哨', P02_R04, 'mm_tp_03', (1162, 576)) P02_R04_SP02 = TransportPoint('JQQX', '禁区前线', P02_R04, 'mm_tp_03', (538, 596)) P02_R04_SP03 = TransportPoint('NYSN', '能源枢纽', P02_R04, 'mm_tp_03', (750, 1102)) -P02_R04_SP04 = TransportPoint('YHZX', '炎华之形', P02_R04, 'mm_tp_06', (463, 442)) -P02_R04_SP05 = TransportPoint('XQZJ', '迅拳之径', P02_R04, 'mm_tp_09', (1143, 624)) +P02_R04_SP04 = TransportPoint('YHZX', '炎华之形凝滞虚影', P02_R04, 'mm_tp_06', (463, 442)) +P02_R04_SP05 = TransportPoint('XQZJ', '迅拳之径侵蚀隧洞', P02_R04, 'mm_tp_09', (1143, 624)) P02_R04_SP06 = TransportPoint('YYHY', '以眼还眼', P02_R04, 'mm_sp_01', (438, 578)) P02_R04_SP07 = TransportPoint('DBJXQ', '冬兵进行曲', P02_R04, 'mm_sp_01', (723, 1073)) P02_R04_SP08 = TransportPoint('CXHL', '残响回廊', P02_R04, 'mm_sp_02', (314, 589)) @@ -295,16 +295,16 @@ def unique_id(self): P02_R05_SP02 = TransportPoint('WRGC', '污染广场', P02_R05, 'mm_tp_03', (381, 655)) P02_R05_SP03 = TransportPoint('ZZZHS', '作战指挥室', P02_R05, 'mm_tp_03', (495, 856)) P02_R05_SP04 = TransportPoint('GZCQX', '古战场前线', P02_R05, 'mm_tp_03', (570, 1243)) -P02_R05_SP05 = TransportPoint('MLZX', '鸣雷之形', P02_R05, 'mm_tp_06', (526, 640)) -P02_R05_SP06 = TransportPoint('SJZX', '霜晶之形', P02_R05, 'mm_tp_06', (681, 1231)) -P02_R05_SP07 = TransportPoint('PBZJ', '漂泊之径', P02_R05, 'mm_tp_09', (654, 242)) +P02_R05_SP05 = TransportPoint('MLZX', '鸣雷之形凝滞虚影', P02_R05, 'mm_tp_06', (526, 640)) +P02_R05_SP06 = TransportPoint('SJZX', '霜晶之形凝滞虚影', P02_R05, 'mm_tp_06', (681, 1231)) +P02_R05_SP07 = TransportPoint('PBZJ', '漂泊之径侵蚀隧洞', P02_R05, 'mm_tp_09', (654, 242)) P02_R05_SP08 = TransportPoint('TWJQ', '铁卫禁区', P02_R05, 'mm_sp02', (389, 626)) P02_R05_SP09 = TransportPoint('YDL', '永冬岭', P02_R05, 'mm_sp02', (733, 1280)) # 这里旁边站着一个传送到造物之柱的士兵 # 雅利洛 - 永冬岭 P02_R06_SP01 = TransportPoint('GZC', '古战场', P02_R06, 'mm_tp_03', (366, 776)) P02_R06_SP02 = TransportPoint('ZWPT', '造物平台', P02_R06, 'mm_tp_03', (784, 571)) -P02_R06_SP03 = TransportPoint('RZZJ', '睿治之径', P02_R06, 'mm_tp_09', (585, 663)) +P02_R06_SP03 = TransportPoint('RZZJ', '睿治之径侵蚀隧洞', P02_R06, 'mm_tp_09', (585, 663)) P02_R06_SP04 = TransportPoint('CXHL', '残响回廊', P02_R06, 'mm_sp_02', (338, 793)) P02_R06_SP05 = TransportPoint('HCDLM', '寒潮的落幕', P02_R06, 'mm_boss_02', (814, 701)) @@ -335,18 +335,18 @@ def unique_id(self): P02_R10_SP02 = TransportPoint('LLZBNS', '流浪者避难所', P02_R10, 'mm_tp_03', (778, 349)) P02_R10_SP03 = TransportPoint('FKD', '俯瞰点', P02_R10, 'mm_tp_03', (565, 641)) P02_R10_SP04 = TransportPoint('ZKD', '主矿道', P02_R10, 'mm_tp_03', (530, 757)) -P02_R10_SP05 = TransportPoint('FMZX', '锋芒之形', P02_R10, 'mm_tp_06', (561, 536)) -P02_R10_SP06 = TransportPoint('FZZX', '燔灼之形', P02_R10, 'mm_tp_06', (836, 630)) -P02_R10_SP07 = TransportPoint('XWZL', '虚无之蕾', P02_R10, 'mm_tp_07', (295, 243)) -P02_R10_SP08 = TransportPoint('CZZL', '藏珍之蕾', P02_R10, 'mm_tp_08', (554, 686)) +P02_R10_SP05 = TransportPoint('FMZX', '锋芒之形凝滞虚影', P02_R10, 'mm_tp_06', (561, 536)) +P02_R10_SP06 = TransportPoint('FZZX', '燔灼之形凝滞虚影', P02_R10, 'mm_tp_06', (836, 630)) +P02_R10_SP07 = TransportPoint('XWZL', '虚无之蕾拟造花萼赤', P02_R10, 'mm_tp_07', (295, 243)) +P02_R10_SP08 = TransportPoint('CZZL', '藏珍之蕾拟造花萼金', P02_R10, 'mm_tp_08', (554, 686)) P02_R10_SP09 = TransportPoint('PYZ', '磐岩镇', P02_R10, 'mm_sp_02', (351, 144)) # 雅利洛 - 铆钉镇 P02_R11_SP01 = TransportPoint('GEY', '孤儿院', P02_R11_L1, 'mm_tp_03', (600, 211)) P02_R11_SP02 = TransportPoint('FQSJ', '废弃市集', P02_R11_L1, 'mm_tp_03', (465, 374)) P02_R11_SP03 = TransportPoint('RK', '入口', P02_R11_L1, 'mm_tp_03', (613, 675)) -P02_R11_SP04 = TransportPoint('XFZX', '巽风之形', P02_R11_L1, 'mm_tp_06', (580, 374)) -P02_R11_SP05 = TransportPoint('ZSZL', '智识之蕾', P02_R11_L1, 'mm_tp_07', (609, 608)) +P02_R11_SP04 = TransportPoint('XFZX', '巽风之形凝滞虚影', P02_R11_L1, 'mm_tp_06', (580, 374)) +P02_R11_SP05 = TransportPoint('ZSZL', '智识之蕾拟造花萼赤', P02_R11_L1, 'mm_tp_07', (609, 608)) P02_R11_SP06 = TransportPoint('JWQSYC', '旧武器试验场', P02_R11_L1, 'mm_sp_02', (767, 244)) # 与 机械聚落 重合 P02_R11_SP07 = TransportPoint('PYZ', '磐岩镇', P02_R11_L1, 'mm_sp_02', (597, 698)) @@ -354,7 +354,7 @@ def unique_id(self): P02_R12_SP01 = TransportPoint('LLZYD', '流浪者营地', P02_R12_L2, 'mm_tp_03', (556, 174)) P02_R12_SP02 = TransportPoint('SQLZD', '史瓦罗驻地', P02_R12_L2, 'mm_tp_03', (554, 506)) P02_R12_SP03 = TransportPoint('NYZHSS', '能源转换设施', P02_R12_L1, 'mm_tp_03', (413, 527)) -P02_R12_SP04 = TransportPoint('TXZL', '同谐之蕾', P02_R12_L1, 'mm_tp_07', (298, 564)) +P02_R12_SP04 = TransportPoint('TXZL', '同谐之蕾拟造花萼赤', P02_R12_L1, 'mm_tp_07', (298, 564)) # 仙舟罗浮 - 星槎海中枢 P03_R01_SP01 = TransportPoint('XCMT', '星槎码头', P03_R01, 'mm_tp_03', (443, 341)) @@ -379,8 +379,8 @@ def unique_id(self): P03_R02_SP02 = TransportPoint('JYF', '积玉坊', P03_R02_L1, 'mm_tp_03', (541, 795)) P03_R02_SP03 = TransportPoint('JYFNC', '积玉坊南侧', P03_R02_L1, 'mm_tp_03', (567, 986)) P03_R02_SP04 = TransportPoint('LYDCCC', '流云渡乘槎处', P03_R02_L1, 'mm_tp_03', (579, 1369)) -P03_R02_SP05 = TransportPoint('BLZX', '冰棱之形', P03_R02_L1, 'mm_tp_06', (730, 1367)) -P03_R02_SP06 = TransportPoint('SSZJ', '圣颂之径', P03_R02_L1, 'mm_tp_09', (542, 1153)) +P03_R02_SP05 = TransportPoint('BLZX', '冰棱之形凝滞虚影', P03_R02_L1, 'mm_tp_06', (730, 1367)) +P03_R02_SP06 = TransportPoint('SSZJ', '圣颂之径侵蚀隧洞', P03_R02_L1, 'mm_tp_09', (542, 1153)) P03_R02_SP07 = TransportPoint('XCHZS', '星槎海中枢', P03_R02_L1, 'mm_sp_02', (578, 1503)) P03_R02_SP08 = TransportPoint('GQYBSGC', '过期邮包收购处', P03_R02_L1, 'mm_sp_03', (388, 777)) @@ -389,8 +389,8 @@ def unique_id(self): P03_R03_SP02 = TransportPoint('ZCQMJ', '植船区萌甲', P03_R03_L1, 'mm_tp_03', (441, 465)) P03_R03_SP03 = TransportPoint('ZCQFS', '植船区繁生', P03_R03_L1, 'mm_tp_03', (523, 609)) P03_R03_SP04 = TransportPoint('BHQ', '泊航区', P03_R03_L1, 'mm_tp_03', (647, 707)) -P03_R03_SP05 = TransportPoint('ZEZX', '震厄之形', P03_R03_L1, 'mm_tp_06', (729, 803)) -P03_R03_SP06 = TransportPoint('YYZJ', '野焰之径', P03_R03_L1, 'mm_tp_09', (455, 374)) +P03_R03_SP05 = TransportPoint('ZEZX', '震厄之形凝滞虚影', P03_R03_L1, 'mm_tp_06', (729, 803)) +P03_R03_SP06 = TransportPoint('YYZJ', '野焰之径侵蚀隧洞', P03_R03_L1, 'mm_tp_09', (455, 374)) P03_R03_SP07 = TransportPoint('XCHZS', '星槎海中枢', P03_R03_L2, 'mm_sp_02', (881, 222)) # 仙舟罗浮 - 长乐天 @@ -438,7 +438,7 @@ def unique_id(self): P03_R07_SP02 = TransportPoint('RJFTD', '镕金坊通道', P03_R07, 'mm_tp_03', (821, 602)) P03_R07_SP03 = TransportPoint('XJP', '玄机坪', P03_R07, 'mm_tp_03', (189, 865)) P03_R07_SP04 = TransportPoint('ZHHL', '造化洪炉', P03_R07, 'mm_tp_03', (758, 964)) -P03_R07_SP05 = TransportPoint('YOZX', '偃偶之形', P03_R07, 'mm_tp_06', (388, 655)) +P03_R07_SP05 = TransportPoint('YOZX', '偃偶之形凝滞虚影', P03_R07, 'mm_tp_06', (388, 655)) P03_R07_SP06 = TransportPoint('DDS', '丹鼎司', P03_R07, 'mm_sp_02', (1029, 767)) P03_R07_SP07 = TransportPoint('TBS', '太卜司', P03_R07, 'mm_sp_02', (170, 928)) @@ -447,8 +447,8 @@ def unique_id(self): P03_R08_SP02 = TransportPoint('GYT', '观颐台', P03_R08_L1, 'mm_tp_03', (438, 694)) P03_R08_SP03 = TransportPoint('XYSJ', '行医市集', P03_R08_L2, 'mm_tp_03', (826, 898)) P03_R08_SP04 = TransportPoint('QHS', '岐黄署', P03_R08_L2, 'mm_tp_03', (819, 1533)) -P03_R08_SP05 = TransportPoint('TRZX', '天人之形', P03_R08_L2, 'mm_tp_06', (1225, 1087)) -P03_R08_SP06 = TransportPoint('YSZJ', '药使之径', P03_R08_L2, 'mm_tp_09', (667, 1504)) +P03_R08_SP05 = TransportPoint('TRZX', '天人之形凝滞虚影', P03_R08_L2, 'mm_tp_06', (1225, 1087)) +P03_R08_SP06 = TransportPoint('YSZJ', '药使之径侵蚀隧洞', P03_R08_L2, 'mm_tp_09', (667, 1504)) P03_R08_SP07 = TransportPoint('LYJ', '麟渊境', P03_R08_L1, 'mm_sp_02', (453, 218)) P03_R08_SP08 = TransportPoint('QLT', '祈龙坛', P03_R08_L1, 'mm_sp_02', (186, 710)) P03_R08_SP09 = TransportPoint('SLDY', '蜃楼遁影', P03_R08_L2, 'mm_sp_01', (846, 815)) @@ -460,7 +460,7 @@ def unique_id(self): P03_R09_SP01 = TransportPoint('GXSC', '宫墟深处', P03_R09, 'mm_tp_03', (891, 425)) P03_R09_SP02 = TransportPoint('GHGX', '古海宫墟', P03_R09, 'mm_tp_03', (1113, 425)) P03_R09_SP03 = TransportPoint('XLDYD', '显龙大雩殿', P03_R09, 'mm_tp_03', (1599, 444)) -P03_R09_SP04 = TransportPoint('NSZX', '孽兽之形', P03_R09, 'mm_tp_06', (917, 169)) +P03_R09_SP04 = TransportPoint('NSZX', '孽兽之形凝滞虚影', P03_R09, 'mm_tp_06', (917, 169)) P03_R09_SP05 = TransportPoint('DDS', '丹鼎司', P03_R09, 'mm_sp_02', (1891, 391)) P03_R09_SP06 = TransportPoint('BSDSS', '不死的神实', P03_R09, 'mm_boss_03', (470, 450)) @@ -469,8 +469,8 @@ def unique_id(self): P03_R10_SP02 = TransportPoint('THLHM', '谈狐林后门', P03_R10, 'mm_tp_03', (209, 480), (235, 480)) P03_R10_SP03 = TransportPoint('TQTRK', '青丘台入口', P03_R10, 'mm_tp_03', (606, 646), (617, 647)) P03_R10_SP04 = TransportPoint('YYTRK', '燕乐亭入口', P03_R10, 'mm_tp_03', (838, 796), (855, 777)) -P03_R10_SP05 = TransportPoint('YFZX', '幽府之形', P03_R10, 'mm_tp_06', (152, 678), (155, 658)) -P03_R10_SP06 = TransportPoint('YMZJ', '幽冥之径', P03_R10, 'mm_tp_09', (418, 462), (423, 459)) +P03_R10_SP05 = TransportPoint('YFZX', '幽府之形凝滞虚影', P03_R10, 'mm_tp_06', (152, 678), (155, 658)) +P03_R10_SP06 = TransportPoint('YMZJ', '幽冥之径侵蚀隧洞', P03_R10, 'mm_tp_09', (418, 462), (423, 459)) P03_R10_SP07 = TransportPoint('CLT', '长乐天', P03_R10, 'mm_sp_02', (628, 771)) REGION_2_SP = { diff --git a/src/sr/image/sceenshot/icon.py b/src/sr/image/sceenshot/icon.py index 686f3ac5..ddadd0ac 100644 --- a/src/sr/image/sceenshot/icon.py +++ b/src/sr/image/sceenshot/icon.py @@ -384,3 +384,12 @@ def init_store_buy_num_ctrl(template_id: str): save_template_image(origin, template_id, 'origin') +def init_battle_times_control(template_id: str): + """ + 战斗次数的加减号 + :param template_id: + :return: + """ + raw = _read_template_raw_image(template_id) + origin = cv2.cvtColor(raw, cv2.COLOR_BGRA2BGR) + save_template_image(origin, template_id, 'origin') diff --git a/src/sr/operation/__init__.py b/src/sr/operation/__init__.py index 6e48529a..89017b99 100644 --- a/src/sr/operation/__init__.py +++ b/src/sr/operation/__init__.py @@ -22,7 +22,7 @@ class Operation: WAIT = 2 # 等待 本轮不计入 FAIL = -1 # 失败 - def __init__(self, ctx: Context, try_times: int = 2, op_name: str = ''): + def __init__(self, ctx: Context, try_times: int = 2, op_name: str = '', timeout_seconds: float = -1): self.op_name: str = gt(op_name, 'ui') self.try_times: int = try_times self.op_round: int = 0 @@ -30,14 +30,21 @@ def __init__(self, ctx: Context, try_times: int = 2, op_name: str = ''): ctx.register_pause(self, self.on_pause, self.on_resume) self.last_screenshot: MatLike = None self.gc: GameConfig = game_config.get() - self.pause_start_time = time.time() - self.pause_end_time = time.time() + + self.timeout_seconds: float = -1 # 本操作的超时时间 + self.operation_start_time: float = 0 # 开始时间 + self.pause_start_time = time.time() # 本次暂停的开始时间 + self.pause_end_time = time.time() # 本次暂停的结束时间 + self.pause_total_time = 0 # 暂停的总时间 def _init_before_execute(self): """ 执行前的初始化 """ - pass + now = time.time() + self.operation_start_time = now + self.pause_start_time = now + self.pause_end_time = now def execute(self) -> bool: """ @@ -46,6 +53,9 @@ def execute(self) -> bool: self._init_before_execute() result: bool = False while self.op_round < self.try_times: + if self.timeout_seconds != -1 and self._operation_usage_time >= self.timeout_seconds: + log.error('%s执行超时', self.display_name, exc_info=True) + return False if self.ctx.running == 0: break elif self.ctx.running == 2: @@ -62,9 +72,9 @@ def execute(self) -> bool: if self.last_screenshot is not None: to_save = fill_uid_black(self.last_screenshot) file_name = save_debug_image(to_save, prefix=self.__class__.__name__) - log.error('%s执行出错 相关截图保存至 %s', self.get_display_name(), file_name, exc_info=True) + log.error('%s执行出错 相关截图保存至 %s', self.display_name, file_name, exc_info=True) else: - log.error('%s执行出错', self.get_display_name(), exc_info=True) + log.error('%s执行出错', self.display_name, exc_info=True) if op_result == Operation.RETRY: continue elif op_result == Operation.SUCCESS: @@ -73,13 +83,13 @@ def execute(self) -> bool: elif op_result == Operation.FAIL: result = False if not self.allow_fail(): - log.error('%s执行失败', self.get_display_name()) + log.error('%s执行失败', self.display_name) break elif op_result == Operation.WAIT: self.op_round -= 1 continue else: - log.error('%s执行返回结果错误 %s', self.get_display_name(), result) + log.error('%s执行返回结果错误 %s', self.display_name, result) result = False break self.ctx.unregister(self) @@ -94,6 +104,15 @@ def on_pause(self): def on_resume(self): self.pause_end_time = time.time() + self.pause_total_time += self.pause_end_time - self.pause_start_time + + @property + def _operation_usage_time(self) -> float: + """ + 获取指令的耗时 + :return: + """ + return time.time() - self.operation_start_time - self.pause_start_time def screenshot(self): """ @@ -103,7 +122,8 @@ def screenshot(self): self.last_screenshot = self.ctx.controller.screenshot() return self.last_screenshot - def get_display_name(self) -> str: + @property + def display_name(self) -> str: """ 用于展示的名称 :return: diff --git a/src/sr/operation/combine/use_trailblaze_power.py b/src/sr/operation/combine/use_trailblaze_power.py index 717b8f5d..aa2739a1 100644 --- a/src/sr/operation/combine/use_trailblaze_power.py +++ b/src/sr/operation/combine/use_trailblaze_power.py @@ -1,17 +1,22 @@ from typing import List, Optional from basic.i18_utils import gt +from basic.log_utils import log from sr.const import map_const from sr.const.map_const import TransportPoint from sr.context import Context from sr.operation import Operation from sr.operation.combine import CombineOperation from sr.operation.combine.transport import Transport +from sr.operation.unit.battle.choose_challenge_times import ChooseChallengeTimes from sr.operation.unit.battle.choose_team import ChooseTeam from sr.operation.unit.battle.click_challenge import ClickChallenge from sr.operation.unit.battle.click_start_challenge import ClickStartChallenge from sr.operation.unit.battle.get_reward_and_retry import GetRewardAndRetry +from sr.operation.unit.battle.start_fight import StartFight +from sr.operation.unit.enter_auto_fight import EnterAutoFight from sr.operation.unit.interact import Interact +from sr.operation.unit.wait_in_world import WaitInWorld CATEGORY_1 = '经验信用' CATEGORY_2 = '光锥技能' @@ -96,13 +101,96 @@ class UseTrailblazePower(CombineOperation): def __init__(self, ctx: Context, tpp: TrailblazePowerPoint, team_num: int, run_times: int, on_battle_success=None): + self.ctx: Context = ctx + self.tpp: TrailblazePowerPoint = tpp + self.team_num: int = team_num + self.run_times: int = run_times + self.on_battle_success = on_battle_success + + self.current_success_round: int = 0 # 第几轮战斗胜利 + self.trigger_success_times_arr = [] # 每轮战斗胜利触发多少次回调 + ops: List[Operation] = [ Transport(ctx, tpp.tp), # 传送到对应位置 - Interact(ctx, tpp.tp.cn, 0.5), # 交互进入副本 - ClickChallenge(ctx), # 点击挑战 - ChooseTeam(ctx, team_num), # 选择配队 - ClickStartChallenge(ctx), # 开始挑战 - GetRewardAndRetry(ctx, run_times, on_battle_success), # 领奖 重复挑战 ] + if tpp.category in (CATEGORY_1, CATEGORY_2): + times_6 = run_times // 6 + times_left = run_times % 6 + if times_6 > 0: + for i in self._ops_for_cate_12(6, times_6): + ops.append(i) + for _ in range(times_6): + self.trigger_success_times_arr.append(6) + if times_left > 0: + for i in self._ops_for_cate_12(times_left, 1): + ops.append(i) + self.trigger_success_times_arr.append(times_left) + elif tpp.category == CATEGORY_3: + for i in self._ops_for_cate_3(run_times): + ops.append(i) + for _ in range(run_times): + self.trigger_success_times_arr.append(1) + elif tpp.category == CATEGORY_4: + for i in self._ops_for_cate_4(run_times): + ops.append(i) + for _ in range(run_times): + self.trigger_success_times_arr.append(1) + super().__init__(ctx, ops, op_name='%s %s %d' % (gt(tpp.tp.cn, 'ui'), gt('次数', 'ui'), run_times)) + + def _ops_for_cate_12(self, times_per_round: int, round_num: int) -> List[Operation]: + """ + 拟造花萼金的挑战指令 - 经验、信用、光锥技能材料 + :param times_per_round: 每轮挑战次数 + :param round_num: 挑战多少轮 + :return: + """ + return [ + Interact(self.ctx, self.tpp.tp.cn, 0.5), # 交互进入副本 + ChooseChallengeTimes(self.ctx, times_per_round), # 挑战次数 + ClickChallenge(self.ctx), # 点击挑战 + ChooseTeam(self.ctx, self.team_num), # 选择配队 + ClickStartChallenge(self.ctx), # 开始挑战 + GetRewardAndRetry(self.ctx, round_num, self._on_battle_success), # 领奖 重复挑战 + ] + + def _ops_for_cate_3(self, round_num: int) -> List[Operation]: + """ + 凝滞虚影的挑战指令 - 角色突破材料 + :param round_num: 挑战多少轮 + :return: + """ + return [ + Interact(self.ctx, self.tpp.tp.cn, 0.5), # 交互进入副本 + ClickChallenge(self.ctx), # 点击挑战 + ChooseTeam(self.ctx, self.team_num), # 选择配队 + ClickStartChallenge(self.ctx), # 开始挑战 + WaitInWorld(self.ctx), # 等待界面 + StartFight(self.ctx), # 主动攻击 + GetRewardAndRetry(self.ctx, round_num, self._on_battle_success), # 领奖 重复挑战 + ] + + def _ops_for_cate_4(self, round_num: int) -> List[Operation]: + """ + 侵蚀隧洞的挑战指令 - 遗器 + :param round_num: 挑战多少轮 + :return: + """ + return [ + Interact(self.ctx, self.tpp.tp.cn, 0.5), # 交互进入副本 + ClickChallenge(self.ctx), # 点击挑战 + ChooseTeam(self.ctx, self.team_num), # 选择配队 + ClickStartChallenge(self.ctx), # 开始挑战 + GetRewardAndRetry(self.ctx, round_num, self._on_battle_success), # 领奖 重复挑战 + ] + + def _on_battle_success(self): + if self.on_battle_success is None: + return + if self.current_success_round < len(self.trigger_success_times_arr): + for _ in range(self.trigger_success_times_arr[self.current_success_round]): + self.on_battle_success() + self.current_success_round += 1 + else: + log.error('胜利次数多余预期 %s %s', self.current_success_round, self.trigger_success_times_arr) \ No newline at end of file diff --git a/src/sr/operation/unit/battle/choose_challenge_times.py b/src/sr/operation/unit/battle/choose_challenge_times.py new file mode 100644 index 00000000..5effccff --- /dev/null +++ b/src/sr/operation/unit/battle/choose_challenge_times.py @@ -0,0 +1,101 @@ +import time + +from cv2.typing import MatLike + +from basic import Rect, str_utils, Point +from basic.i18_utils import gt +from basic.img import cv2_utils +from sr.context import Context +from sr.operation import Operation + + +class ChooseChallengeTimes(Operation): + + """ + 在挑战副本的选择难度页面 + 选择挑战次数 + """ + + CURRENT_TIMES_RECT = Rect(1470, 850, 1620, 890) + MINUS_BTN_RECT = Rect(1190, 870, 1300, 930) + PLUS_BTN_RECT = Rect(1800, 870, 1900, 930) + + def __init__(self, ctx: Context, total_times: int): + """ + :param ctx: + :param total_times: 总共挑战次数 <=6 + """ + super().__init__(ctx, try_times=5, op_name=gt('选择挑战次数', 'ui')) + self.total_times: int = total_times + + def _execute_one_round(self) -> int: + screen: MatLike = self.screenshot() + + current = self._get_current_times(screen) + if current == 0: # 可能界面还没有加载出来 等等 + time.sleep(0.5) + return Operation.RETRY + + if current == self.total_times: + return Operation.SUCCESS + elif current < self.total_times: + if self._click_plus(screen, self.total_times - current): + return Operation.WAIT + else: + if self._click_minus(screen, self.total_times - current): + return Operation.WAIT + + def _get_current_times(self, screen: MatLike) -> int: + """ + 判断当前选择的次数 + :param screen: 屏幕截图 + :return: 当前选择次数 + """ + part, _ = cv2_utils.crop_image(screen, ChooseChallengeTimes.CURRENT_TIMES_RECT) + cv2_utils.show_image(part, win_name='_get_current_times') + ocr_result = self.ctx.ocr.ocr_for_single_line(part, strict_one_line=True) + return str_utils.get_digits(ocr_result) + + def _click_plus(self, screen: MatLike, click_times: int) -> bool: + """ + 找到加号并点击 + :param screen: 屏幕截图 + :param click_times: 需要点击的次数 + :return: 是否点击成功 + """ + part, _ = cv2_utils.crop_image(screen, ChooseChallengeTimes.PLUS_BTN_RECT) + result_list = self.ctx.im.match_template(part, 'battle_times_plus', ignore_template_mask=True, only_best=True) + result = result_list.max + + if result is None: + return False + + to_click: Point = result.center + ChooseChallengeTimes.PLUS_BTN_RECT.left_top + for _ in range(click_times): + if not self.ctx.controller.click(to_click): + return False + time.sleep(0.2) + + return True + + def _click_minus(self, screen: MatLike, click_times: int) -> bool: + """ + 找到减号并点击 + :param screen: 屏幕截图 + :param click_times: 需要点击的次数 + :return: 是否点击成功 + """ + part, _ = cv2_utils.crop_image(screen, ChooseChallengeTimes.MINUS_BTN_RECT) + result_list = self.ctx.im.match_template(part, 'battle_times_minus', ignore_template_mask=True, only_best=True) + result = result_list.max + + if result is None: + return False + + to_click: Point = result.center + ChooseChallengeTimes.MINUS_BTN_RECT.left_top + for _ in range(click_times): + if not self.ctx.controller.click(to_click): + return False + time.sleep(0.2) + + return True diff --git a/src/sr/operation/unit/battle/start_fight.py b/src/sr/operation/unit/battle/start_fight.py new file mode 100644 index 00000000..e9a82977 --- /dev/null +++ b/src/sr/operation/unit/battle/start_fight.py @@ -0,0 +1,32 @@ +import time + +from basic.i18_utils import gt +from sr.context import Context +from sr.image.sceenshot import battle +from sr.operation import Operation + + +class StartFight(Operation): + """ + 空地上攻击 尝试发动攻击 + """ + + def __init__(self, ctx: Context): + super().__init__(ctx, op_name=gt('主动攻击进入战斗', 'ui'), timeout_seconds=10) + + def _init_before_execute(self): + super()._init_before_execute() + + def _execute_one_round(self) -> int: + screen = self.screenshot() + + now_time = time.time() + screen_status = battle.get_battle_status(screen, self.ctx.im) + if screen_status != battle.IN_WORLD: # 在战斗界面 + return Operation.SUCCESS + + self.ctx.controller.initiate_attack() # 主动攻击 + time.sleep(0.5) + + return Operation.WAIT + diff --git a/src/sr/operation/unit/wait_in_world.py b/src/sr/operation/unit/wait_in_world.py index 4520349b..0e9e7651 100644 --- a/src/sr/operation/unit/wait_in_world.py +++ b/src/sr/operation/unit/wait_in_world.py @@ -17,12 +17,7 @@ def __init__(self, ctx: Context, wait: float = 20): :param ctx: :param wait: 最多等待多少秒 """ - super().__init__(ctx, op_name=gt('等待主界面')) - self.timeout_seconds: float = float(wait) - self.start_time = 0 - - def _init_before_execute(self): - self.start_time = time.time() + super().__init__(ctx, op_name=gt('等待主界面'), timeout_seconds=wait) def _execute_one_round(self) -> int: screen = self.screenshot() @@ -31,6 +26,4 @@ def _execute_one_round(self) -> int: return Operation.SUCCESS time.sleep(1) - if time.time() - self.start_time > self.timeout_seconds: - return Operation.FAIL return Operation.WAIT diff --git a/test/src/sr/image/screenshot/icon_test.py b/test/src/sr/image/screenshot/icon_test.py index 79da6ff2..aedc053f 100644 --- a/test/src/sr/image/screenshot/icon_test.py +++ b/test/src/sr/image/screenshot/icon_test.py @@ -52,4 +52,5 @@ def _test_init_template_feature(): # icon.init_ui_ellipsis('ui_ellipsis') # icon.init_nameless_honor_icon('nameless_honor_3') # icon.init_training_reward_gift() - icon.init_store_buy_num_ctrl('store_buy_max') \ No newline at end of file + # icon.init_store_buy_num_ctrl('store_buy_max') + icon.init_battle_times_control('battle_times_plus') \ No newline at end of file diff --git a/version.yml b/version.yml index 0d3421f0..7e1cc2b9 100644 --- a/version.yml +++ b/version.yml @@ -1 +1 @@ -version: "v0.7.1" \ No newline at end of file +version: "v0.7.2" \ No newline at end of file