All checks were successful
ci/woodpecker/push/check_format Pipeline was successful
223 lines
7.9 KiB
Python
223 lines
7.9 KiB
Python
from typing import Literal
|
|
|
|
import cv2
|
|
from scipy.signal import argrelmin
|
|
from skimage.metrics import structural_similarity
|
|
|
|
from mower.data import agent_list
|
|
from mower.utils import config
|
|
from mower.utils import typealias as tp
|
|
from mower.utils.character_recognize import match_portrait
|
|
from mower.utils.graph import SceneGraphSolver
|
|
from mower.utils.image import cmatch, cropimg, loadres, thres2
|
|
from mower.utils.log import logger
|
|
from mower.utils.recognize import Scene
|
|
from mower.utils.solver import BaseSolver
|
|
|
|
profession_pos = {
|
|
"PIONEER": ((30, 150), (40, 160)),
|
|
"WARRIOR": ((30, 263), (40, 273)),
|
|
"TANK": ((30, 376), (40, 386)),
|
|
"SNIPER": ((30, 489), (40, 499)),
|
|
"CASTER": ((30, 602), (40, 612)),
|
|
"MEDIC": ((30, 715), (40, 725)),
|
|
"SUPPORT": ((30, 830), (40, 840)),
|
|
"SPECIAL": ((30, 944), (40, 954)),
|
|
}
|
|
skill_pos = (
|
|
((1237, 390), (1252, 405)),
|
|
((1409, 390), (1424, 405)),
|
|
((1582, 390), (1597, 405)),
|
|
)
|
|
|
|
|
|
class ChooseSupportSolver(BaseSolver):
|
|
solver_name = "选择助战干员"
|
|
|
|
def run(self, opers: list = [], mode: Literal["normal", "rogue"] = "normal"):
|
|
"""
|
|
Args:
|
|
opers: 包含name和skill,若传入多个干员会选择其中练度最高的
|
|
mode: 模式选择,normal为普通选助战,rogue为肉鸽选助战
|
|
"""
|
|
self.mode = mode
|
|
self.opers_skill = {}
|
|
if len(opers) == 0:
|
|
return True
|
|
for i in range(len(opers) - 1, -1, -1): # 改变group的结构
|
|
op = opers[i]
|
|
if "opers" in op:
|
|
opers += op["opers"]
|
|
del opers[i]
|
|
for op in opers:
|
|
self.opers_skill[op["name"]] = op["skill"]
|
|
logger.info(f"助战干员:{self.opers_skill}")
|
|
self.min_progression = (
|
|
config.conf.support.elite * 100 + config.conf.support.level
|
|
) # 最低练度要求
|
|
self.retry_times = config.conf.support.refresh # 刷新次数
|
|
self.profession = agent_list[opers[0]["name"]]["profession"] # 目标干员职业
|
|
self.matched = False # 是否匹配过干员
|
|
self.swiped = False # 是否滑动过
|
|
self.success = False # 是否成功选择到干员
|
|
self.skill = None # 选中干员需要的技能
|
|
super().run()
|
|
return self.success
|
|
|
|
def check_profession_focus(self) -> bool:
|
|
img = cropimg(config.recog.img, profession_pos[self.profession])
|
|
res = loadres("fight/profession_not_be_choosen")
|
|
return not cmatch(img, res, 70)
|
|
|
|
def get_oper_pos(self):
|
|
y = 908 if self.mode == "normal" else 917
|
|
if not self.swiped:
|
|
img = cropimg(config.recog.gray, ((0, y), (1920, y + 75)))
|
|
else:
|
|
img = cropimg(config.recog.gray, ((1600, y), (1920, y + 75)))
|
|
res = loadres("fight/choose", True)
|
|
result = cv2.matchTemplate(img, res, cv2.TM_SQDIFF_NORMED)[0]
|
|
threshold = 0.1
|
|
match = []
|
|
for i in argrelmin(result, order=100)[0]:
|
|
if result[i] < threshold:
|
|
if self.swiped:
|
|
match.append(((i + 1600, 500), (i + 1794, 625)))
|
|
else:
|
|
match.append(((i, 500), (i + 194, 625)))
|
|
logger.debug(match)
|
|
match_opers = dict(match_portrait(config.recog.gray, segment=match))
|
|
result = {}
|
|
for op in self.opers_skill:
|
|
if op in match_opers:
|
|
result[op] = match_opers[op]
|
|
return result
|
|
|
|
def get_agent_elite(self, scope: tp.Scope) -> int:
|
|
"获取干员精英等级"
|
|
img = cropimg(
|
|
config.recog.gray,
|
|
(
|
|
(scope[0][0] + 55, scope[0][1] + 140),
|
|
(scope[1][0] - 54, scope[1][1] + 80),
|
|
),
|
|
)
|
|
img = thres2(img, 200)
|
|
e1 = loadres("fight/elite1", True)
|
|
e2 = loadres("fight/elite2", True)
|
|
ssim1 = structural_similarity(img, e1)
|
|
ssim2 = structural_similarity(img, e2)
|
|
if ssim2 > 0.8:
|
|
return 2
|
|
elif ssim1 > 0.8:
|
|
return 1
|
|
else:
|
|
return 0
|
|
|
|
def number(self, scope: tp.Scope, height: int, thres: int) -> int:
|
|
"数字识别"
|
|
return config.recog.num.number_int("secret_front", scope, height, thres)
|
|
|
|
def get_agent_progression(self, scope: tp.Scope) -> int:
|
|
"获取干员练度"
|
|
elite = self.get_agent_elite(scope)
|
|
level = self.number(
|
|
(
|
|
(scope[0][0] + 125, scope[0][1] + 220),
|
|
(scope[1][0] - 19, scope[1][1] + 130),
|
|
),
|
|
24,
|
|
180,
|
|
)
|
|
logger.debug(f"elite: {elite}, level: {level}")
|
|
return elite * 100 + level
|
|
|
|
def check_agent(self, cur_opers: dict):
|
|
"检查干员是否符合要求"
|
|
if cur_opers is None:
|
|
return None
|
|
result = None
|
|
max_progression = self.min_progression - 1
|
|
for op in cur_opers:
|
|
progression = self.get_agent_progression(cur_opers[op])
|
|
if progression > max_progression:
|
|
max_progression = progression
|
|
result = cur_opers[op]
|
|
self.skill = self.opers_skill[op]
|
|
return result
|
|
|
|
def transition(self):
|
|
if (scene := self.scene()) == Scene.OPERATOR_SUPPORT:
|
|
if self.animation():
|
|
return
|
|
if self.retry_times < 0:
|
|
SceneGraphSolver().step(Scene.OPERATOR_SELECT)
|
|
return
|
|
if not self.check_profession_focus():
|
|
self.tap(profession_pos[self.profession])
|
|
return
|
|
if self.matched:
|
|
if self.swiped:
|
|
self.swipe_noinertia((800, 350), (150, 0))
|
|
self.swiped = False
|
|
if self.find("fight/refresh"):
|
|
for _ in range(10):
|
|
if pos := self.find("fight/refresh"):
|
|
self.tap(pos)
|
|
self.sleep(0.2)
|
|
else:
|
|
break
|
|
self.retry_times -= 1
|
|
self.matched = False
|
|
else:
|
|
self.sleep(0.5)
|
|
else:
|
|
if result := self.check_agent(self.get_oper_pos()):
|
|
self.ctap(result, 3)
|
|
elif not self.swiped:
|
|
self.swiped = True
|
|
self.swipe_noinertia((800, 350), (-150, 0))
|
|
self.sleep(0.4)
|
|
else:
|
|
self.matched = True
|
|
|
|
elif scene == Scene.OPERATOR_SUPPORT_AGENT:
|
|
if self.animation():
|
|
return
|
|
if not self.find(
|
|
"choose_agent/support_skill_be_choosen", scope=skill_pos[self.skill - 1]
|
|
):
|
|
self.tap(skill_pos[self.skill - 1])
|
|
else:
|
|
self.ctap("fight/use", 3)
|
|
self.success = True
|
|
|
|
elif scene == Scene.ROGUE_USE_SUPPORT:
|
|
self.tap("rogue/recruit/use_support")
|
|
self.success = True
|
|
|
|
elif scene == Scene.OPERATOR_SELECT:
|
|
if self.success:
|
|
return True
|
|
elif self.retry_times < 0:
|
|
logger.warning("选择助战干员失败,请降低练度要求或添加好友")
|
|
return True
|
|
else:
|
|
self.ctap((1660, 315))
|
|
|
|
elif scene == Scene.SSS_SQUAD:
|
|
if self.success:
|
|
return True
|
|
elif self.retry_times < 0:
|
|
logger.warning("选择助战干员失败,请降低练度要求或添加好友")
|
|
return True
|
|
else:
|
|
self.tap("sss/choose/choose_support")
|
|
|
|
elif scene == Scene.ROGUE_RECRUIT_AGENT_SELECT:
|
|
self.ctap("rogue/recruit/choose_support", 3)
|
|
|
|
elif scene in self.waiting_scene:
|
|
self.waiting_solver()
|
|
else:
|
|
return True
|