All checks were successful
ci/woodpecker/push/check_format Pipeline was successful
146 lines
4.7 KiB
Python
146 lines
4.7 KiB
Python
from datetime import datetime
|
|
from typing import Literal
|
|
|
|
import cv2
|
|
|
|
from mower.utils import config
|
|
from mower.utils.log import logger
|
|
from mower.utils.scene import Scene
|
|
from mower.utils.solver import BaseSolver
|
|
from mower.utils.vector import va, vs
|
|
|
|
from .utils import generate_name
|
|
|
|
|
|
class classproperty:
|
|
def __init__(self, method=None):
|
|
self.fget = method
|
|
|
|
def __get__(self, instance, cls=None):
|
|
return self.fget(cls)
|
|
|
|
def getter(self, method):
|
|
self.fget = method
|
|
return self
|
|
|
|
|
|
class ActivityNavigation(BaseSolver):
|
|
solver_name = "活动关卡导航"
|
|
|
|
_location = {
|
|
"normal": {
|
|
"BP-1": (0, 0),
|
|
"BP-2": (428, 76),
|
|
"BP-3": (690, -67),
|
|
"BP-4": (956, 48),
|
|
"BP-5": (1221, 160),
|
|
"BP-6": (1550, 1),
|
|
"BP-7": (1791, 471),
|
|
"BP-8": (2001, 341),
|
|
},
|
|
"ex": {},
|
|
}
|
|
|
|
@classproperty
|
|
def location(cls):
|
|
result = {"normal": {}, "ex": {}}
|
|
if (now := datetime.now()) < datetime(2025, 6, 29, 4):
|
|
result["normal"] = cls._location["normal"]
|
|
if now > datetime(2025, 6, 12, 16):
|
|
result["ex"] = cls._location["ex"]
|
|
return result
|
|
|
|
def generate_names(self):
|
|
names = {}
|
|
font_size = 37 if self.difficulty == "ex" else 40
|
|
for name in self._location[self.difficulty].keys():
|
|
style = "dark" if "TR-" in self.name else "light"
|
|
names[name] = generate_name(name, font_size, pad_right=10, style=style)
|
|
self.names = names
|
|
|
|
def run(
|
|
self,
|
|
name: str,
|
|
mode: Literal["auto", "copy"] = "auto",
|
|
switch_to_ex: bool = False,
|
|
) -> None:
|
|
logger.info("导航至活动关卡")
|
|
self.switch_to_ex = switch_to_ex # 是否切换到突袭模式
|
|
self.difficulty = "ex" if "-EX-" in name else "normal"
|
|
self.name = name
|
|
self.mode = mode
|
|
self.generate_names()
|
|
super().run()
|
|
return True
|
|
|
|
def transition(self) -> bool:
|
|
if (scene := self.scene()) == Scene.TERMINAL_MAIN:
|
|
self.terminal_entry("navigation/activity/terminal.jpg")
|
|
elif scene == Scene.ACTIVITY_MAIN:
|
|
self.ctap(f"navigation/activity/entry_{self.difficulty}", 5)
|
|
elif scene in [
|
|
Scene.ACTIVITY_NORMAL_CHOOSE_LEVEL,
|
|
Scene.ACTIVITY_EX_CHOOSE_LEVEL,
|
|
]:
|
|
if (
|
|
self.mode == "copy"
|
|
and (result := config.recog.match("story_stage"))
|
|
and result[0] > 0.8
|
|
):
|
|
self.ctap(result[1], 3)
|
|
return
|
|
|
|
name, val, loc = None, 1, None
|
|
for n, img in self.names.items():
|
|
result = cv2.matchTemplate(config.recog.gray, img, cv2.TM_SQDIFF_NORMED)
|
|
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
|
|
if min_val < val:
|
|
val = min_val
|
|
loc = min_loc
|
|
name = n
|
|
logger.debug(f"在{loc}找到关卡{name}")
|
|
|
|
target = va(
|
|
vs(loc, self.location[self.difficulty][name]),
|
|
self.location[self.difficulty][self.name],
|
|
)
|
|
if target[0] > 1920:
|
|
self.swipe_ext(
|
|
[(1400, 540), (400, 540), (400, 800)], [200, 300], 0, 0.1
|
|
)
|
|
elif target[0] < 0:
|
|
self.swipe_ext(
|
|
[(400, 540), (1400, 540), (1400, 800)], [200, 300], 0, 0.1
|
|
)
|
|
else:
|
|
self.ctap(va(target, (60, 20)), 6)
|
|
elif scene == Scene.OPERATOR_BEFORE:
|
|
if self.find("ope_ex_mode") and self.switch_to_ex:
|
|
self.ctap("ope_ex_mode", 3)
|
|
return
|
|
|
|
if self.mode == "auto":
|
|
return True
|
|
elif self.mode == "copy":
|
|
if not self.switch_to_ex:
|
|
if config.recog.gray[65][1333] < 200:
|
|
self.sleep()
|
|
return
|
|
# 取消代理作战
|
|
if config.recog.gray[907][1600] > 127 and not self.find(
|
|
"ope_agency_lock"
|
|
):
|
|
self.ctap((1776, 908), 3)
|
|
return
|
|
self.ctap("ope_start", 3)
|
|
else:
|
|
self.ctap("ope_ex_start", 3)
|
|
elif scene == Scene.OPERATOR_SELECT and self.mode == "copy":
|
|
return True
|
|
elif scene in [Scene.OPERATOR_RECOVER_ORIGINITE, Scene.OPERATOR_RECOVER_POTION]:
|
|
return True
|
|
elif scene == Scene.STORY_STAGE:
|
|
self.tap("start_story")
|
|
|
|
else:
|
|
self.scene_graph_step(Scene.TERMINAL_MAIN)
|