Compare commits

...

4 commits

Author SHA1 Message Date
4c3eaef108 Merge branch 'clue'
All checks were successful
ci/woodpecker/push/check_format Pipeline was successful
2025-06-29 20:29:12 +08:00
6d3640aea0 线索改进 2025-06-29 20:28:54 +08:00
fe6a59b0f6 线索数量获取场景修复
All checks were successful
ci/woodpecker/push/check_format Pipeline was successful
2025-06-29 15:20:15 +08:00
706fa6a4c0 线索相关Solver使用TransitionOn新写法
All checks were successful
ci/woodpecker/push/check_format Pipeline was successful
2025-06-29 15:06:32 +08:00
13 changed files with 356 additions and 286 deletions

BIN
mower/resources/clue/filter_all_on.png (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -1,36 +1,36 @@
from mower.solvers.infra.base_mixin import BaseMixin from datetime import timedelta
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils.log import logger from mower.utils.log import logger
from mower.utils.recognize import Scene from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver from mower.utils.solver import BaseSolver, TransitionOn
from .utils import clue_cls from .utils import ClueMainSolver, clue_cls
class DailySolver(BaseSolver, BaseMixin): class DailySolver(BaseSolver):
solver_name = "每日线索领取" solver_name = "每日线索领取"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
def run(self) -> None: def run(self) -> None:
self.success = False self.success = False
super().run() super().run()
def transition(self) -> bool: @TransitionOn(Scene.INFRA_CONFIDENTIAL)
if ( def _(self):
scene := self.scene()
) == Scene.INFRA_DETAILS and self.detect_room() == "meeting":
self.tap((500, 1000))
elif scene == Scene.INFRA_CONFIDENTIAL:
if self.animation():
return
if self.success: if self.success:
return True return True
if self.animation():
return
# 检查是否领过线索 # 检查是否领过线索
daily_scope = ((1822, 208), (1886, 243)) daily_scope = ((1822, 208), (1886, 243))
if self.find("clue/badge_new", scope=daily_scope): if self.find("clue/badge_new", scope=daily_scope):
self.tap((1800, 270)) self.tap((1800, 270))
else: else:
return True return True
elif scene == Scene.CLUE_DAILY:
@TransitionOn(Scene.CLUE_DAILY)
def _(self):
exit_pos = (1484, 152) exit_pos = (1484, 152)
if self.find("clue/icon_notification"): if self.find("clue/icon_notification"):
logger.info("当前获得线索数已经达到最大值") logger.info("当前获得线索数已经达到最大值")
@ -43,9 +43,11 @@ class DailySolver(BaseSolver, BaseMixin):
# 今日线索已领取,点X退出 # 今日线索已领取,点X退出
self.tap(exit_pos) self.tap(exit_pos)
self.success = True self.success = True
elif scene == Scene.CLUE_MESSAGE_BOARD:
self.cback(3, id="infra_back") @TransitionOn(BaseSolver.waiting_scene)
elif scene in self.waiting_scene: def _(self):
self.waiting_solver() self.waiting_solver()
else:
EnterRoomSolver().run("meeting", detail=False) @TransitionOn()
def _(self):
ClueMainSolver().run()

View file

@ -1,13 +1,18 @@
from datetime import timedelta
from mower.solvers.infra.base_mixin import BaseMixin from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config from mower.utils import config
from mower.utils.log import logger from mower.utils.log import logger
from mower.utils.recognize import Scene from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver from mower.utils.solver import BaseSolver, TransitionOn
from .utils import MeetingSolver
class GetClueCountSolver(BaseSolver, BaseMixin): class GetClueCountSolver(BaseSolver, BaseMixin):
solver_name = "线索数量" solver_name = "线索数量"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
def run(self) -> int: def run(self) -> int:
self.res = -1 self.res = -1
@ -16,16 +21,19 @@ class GetClueCountSolver(BaseSolver, BaseMixin):
return self.res return self.res
raise ValueError("未找到线索数量") raise ValueError("未找到线索数量")
def transition(self) -> bool: @TransitionOn(Scene.INFRA_DETAILS)
if self.find("meeting_arrange_check_in"): def _(self):
MeetingSolver().run()
self.res = self.read_screen( self.res = self.read_screen(
config.recog.img, limit=10, cord=((476, 985), (519, 1020)) config.recog.img, limit=10, cord=((476, 985), (519, 1020))
) )
logger.info(f"当前拥有线索数量为{self.res}") logger.info(f"当前拥有线索数量为{self.res}")
return True return True
elif (scene := self.scene()) == Scene.INFRA_CONFIDENTIAL:
self.cback(3, id="infra_back") @TransitionOn(BaseSolver.waiting_scene)
elif scene in self.waiting_scene: def _(self):
self.waiting_solver() self.waiting_solver()
else:
EnterRoomSolver().run("meeting", detail=False) @TransitionOn()
def _(self):
MeetingSolver().run()

View file

@ -1,18 +1,20 @@
from mower.solvers.infra.base_mixin import BaseMixin from datetime import timedelta
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config from mower.utils import config
from mower.utils.image import cmatch, crop2content, cropimg, loadres, thres2 from mower.utils.image import cmatch, crop2content, cropimg, loadres, thres2
from mower.utils.log import logger from mower.utils.log import logger
from mower.utils.rapidocr import ocr_rec from mower.utils.rapidocr import ocr_rec
from mower.utils.recognize import Scene from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver from mower.utils.solver import BaseSolver, TransitionOn
from mower.utils.vector import va from mower.utils.vector import va
from .utils import clue_cls, clue_scope from .utils import ClueMainSolver, clue_cls, clue_scope
class GiveAwaySolver(BaseSolver, BaseMixin): class GiveAwaySolver(BaseSolver):
solver_name = "传递线索" solver_name = "传递线索"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
def run(self, clue_count) -> None: def run(self, clue_count) -> None:
self.clue_count = clue_count self.clue_count = clue_count
@ -20,28 +22,22 @@ class GiveAwaySolver(BaseSolver, BaseMixin):
return return
super().run() super().run()
def transition(self) -> bool: @TransitionOn(Scene.INFRA_CONFIDENTIAL)
if ( def _(self):
scene := self.scene()
) == Scene.INFRA_DETAILS and self.detect_room() == "meeting":
self.tap((500, 1000))
elif scene == Scene.INFRA_CONFIDENTIAL:
self.ctap((1799, 578)) self.ctap((1799, 578))
elif scene == Scene.CLUE_GIVE_AWAY:
@TransitionOn(Scene.CLUE_GIVE_AWAY)
def _(self):
if not (config.conf.leifeng_mode or self.clue_count > 9): if not (config.conf.leifeng_mode or self.clue_count > 9):
self.tap((1868, 54))
return True return True
if self.animation(): if self.animation():
return return
if (c := clue_cls("give_away")) is None: if (c := clue_cls("give_away")) is None:
self.tap((1868, 54))
return True return True
if config.recog.gray[230][600] < 90: if config.recog.gray[230][600] < 90:
self.ctap(clue_scope["give_away"], 5) self.ctap(clue_scope["give_away"], 5)
return return
if self.find("clue/icon_notification"): if self.find("product_complete"):
return
if self.detect_product_complete():
return return
orange = False orange = False
for i in range(4): for i in range(4):
@ -63,7 +59,11 @@ class GiveAwaySolver(BaseSolver, BaseMixin):
name = ocr_rec(name) name = ocr_rec(name)
logger.info(f"{name}送一张线索{c}") logger.info(f"{name}送一张线索{c}")
self.tap((1808, 200 + i * 255)) self.tap((1808, 200 + i * 255))
elif scene in self.waiting_scene:
@TransitionOn(BaseSolver.waiting_scene)
def _(self):
self.waiting_solver() self.waiting_solver()
else:
EnterRoomSolver().run("meeting", detail=False) @TransitionOn()
def _(self):
ClueMainSolver().run()

View file

@ -1,20 +1,20 @@
from datetime import timedelta from datetime import timedelta
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config from mower.utils import config
from mower.utils.scene import Scene from mower.utils.scene import Scene
from mower.utils.solver import BaseSolver from mower.utils.solver import BaseSolver, TransitionOn
from .utils import MeetingSolver
class MessageBoard(BaseSolver, BaseMixin): class MessageBoard(BaseSolver):
solver_name = "留言板" solver_name = "留言板"
solver_max_duration = timedelta(minutes=2) solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
def transition(self): @TransitionOn(Scene.INFRA_DETAILS)
if ( def _(self):
scene := self.scene() MeetingSolver().run()
) == Scene.INFRA_DETAILS and self.detect_room() == "meeting":
if pos := self.find("clue/title_party"): if pos := self.find("clue/title_party"):
self.tap(pos) self.tap(pos)
return return
@ -23,20 +23,20 @@ class MessageBoard(BaseSolver, BaseMixin):
self.ctap(scope) self.ctap(scope)
return return
self.tap("clue/interact") self.tap("clue/interact")
elif scene == Scene.CLUE_MESSAGE_BOARD:
@TransitionOn(Scene.CLUE_MESSAGE_BOARD)
def _(self):
if self.animation(): if self.animation():
return return
if pos := self.find("clue/message_board_collect"): if pos := self.find("clue/message_board_collect"):
self.tap(pos) self.tap(pos)
return return
return True return True
elif scene in [
Scene.INFRA_CONFIDENTIAL, @TransitionOn(BaseSolver.waiting_scene)
Scene.CLUE_MESSAGE_BOARD_FRIEND, def _(self):
Scene.CLUE_ACCESS_RECORD,
]:
self.cback(3, id="infra_back")
elif scene in self.waiting_scene:
self.waiting_solver() self.waiting_solver()
else:
EnterRoomSolver().run("meeting", detail=False) @TransitionOn()
def _(self):
MeetingSolver().run()

View file

@ -1,12 +1,13 @@
from datetime import timedelta from datetime import timedelta
from mower.solvers.infra.base_mixin import BaseMixin from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config from mower.utils import config
from mower.utils.log import logger from mower.utils.log import logger
from mower.utils.recognize import Scene from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver, TransitionOn from mower.utils.solver import BaseSolver, TransitionOn
from .utils import MeetingSolver
class PartyTimeSolver(BaseSolver, BaseMixin): class PartyTimeSolver(BaseSolver, BaseMixin):
solver_name = "线索交流结束时间" solver_name = "线索交流结束时间"
@ -15,9 +16,7 @@ class PartyTimeSolver(BaseSolver, BaseMixin):
@TransitionOn(Scene.INFRA_DETAILS) @TransitionOn(Scene.INFRA_DETAILS)
def _(self): def _(self):
if self.detect_room() != "meeting": MeetingSolver().run()
EnterRoomSolver().run("meeting", detail=False)
return
if not self.find("clue/party_on"): if not self.find("clue/party_on"):
config.party_time = None config.party_time = None
logger.info("线索交流未开启") logger.info("线索交流未开启")
@ -28,7 +27,6 @@ class PartyTimeSolver(BaseSolver, BaseMixin):
return True return True
if pos := self.find("clue/show_party_details"): if pos := self.find("clue/show_party_details"):
self.tap(pos) self.tap(pos)
return
@TransitionOn(BaseSolver.waiting_scene) @TransitionOn(BaseSolver.waiting_scene)
def _(self): def _(self):
@ -36,8 +34,4 @@ class PartyTimeSolver(BaseSolver, BaseMixin):
@TransitionOn() @TransitionOn()
def _(self): def _(self):
EnterRoomSolver().run("meeting", detail=False) MeetingSolver().run()
@TransitionOn(Scene.INFRA_CONFIDENTIAL)
def _(self):
self.cback(3, id="infra_back")

View file

@ -1,19 +1,19 @@
from datetime import timedelta
import cv2 import cv2
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config from mower.utils import config
from mower.utils.image import crop2content, cropimg, loadres, thres2 from mower.utils.image import crop2content, cropimg, loadres, thres2
from mower.utils.log import logger from mower.utils.log import logger
from mower.utils.rapidocr import ocr_rec from mower.utils.rapidocr import ocr_rec
from mower.utils.recognize import Scene from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver from mower.utils.solver import BaseSolver, TransitionOn
from mower.utils.vector import va from mower.utils.vector import va
from .utils import ( from .utils import (
ClueMainSolver,
clue_cls, clue_cls,
clue_scope, clue_scope,
exit_pos,
is_orange, is_orange,
main_dots, main_dots,
main_scope, main_scope,
@ -27,8 +27,10 @@ filter_receive = (1900, 45)
filter_self = (1610, 70) filter_self = (1610, 70)
class PlaceSolver(BaseSolver, BaseMixin): class PlaceSolver(BaseSolver):
solver_name = "放置线索" solver_name = "放置线索"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
def run(self) -> None: def run(self) -> None:
self.clue_status = {} self.clue_status = {}
@ -49,12 +51,8 @@ class PlaceSolver(BaseSolver, BaseMixin):
return cl, st return cl, st
return None, None return None, None
def transition(self) -> bool: @TransitionOn(Scene.INFRA_CONFIDENTIAL)
if ( def _(self):
scene := self.scene()
) == Scene.INFRA_DETAILS and self.detect_room() == "meeting":
self.tap((500, 1000))
elif scene == Scene.INFRA_CONFIDENTIAL:
if self.animation(): if self.animation():
return return
if unlock_pos := self.detect_unlock(): if unlock_pos := self.detect_unlock():
@ -75,17 +73,16 @@ class PlaceSolver(BaseSolver, BaseMixin):
if st in ["available", "self", "available_self_only"]: if st in ["available", "self", "available_self_only"]:
self.ctap(main_scope[cl], 1) self.ctap(main_scope[cl], 1)
return return
else:
return True return True
elif scene == Scene.CLUE_PLACE:
@TransitionOn(Scene.CLUE_PLACE)
def _(self):
cl, st = self.place_index() cl, st = self.place_index()
if cl is None: if cl is None:
if unlock_pos := self.detect_unlock(): if unlock_pos := self.detect_unlock():
self.tap(unlock_pos) self.tap(unlock_pos)
return return
else:
self.tap(exit_pos)
return True return True
if self.get_color((1328 + 77 * cl, 114))[0] < 150: if self.get_color((1328 + 77 * cl, 114))[0] < 150:
# 右上角 1-7 # 右上角 1-7
@ -114,9 +111,7 @@ class PlaceSolver(BaseSolver, BaseMixin):
time = ocr_rec(time_img) time = ocr_rec(time_img)
else: else:
time = None time = None
self.clue_list.append( self.clue_list.append({"name": name, "time": time, "scope": tl2p(cp)})
{"name": name, "time": time, "scope": tl2p(cp)}
)
else: else:
break break
if self.clue_list: if self.clue_list:
@ -146,7 +141,11 @@ class PlaceSolver(BaseSolver, BaseMixin):
self.clue_status[cl] = "self_only" self.clue_status[cl] = "self_only"
else: else:
self.clue_status[cl] = None self.clue_status[cl] = None
elif scene in self.waiting_scene:
@TransitionOn(BaseSolver.waiting_scene)
def _(self):
self.waiting_solver() self.waiting_solver()
else:
EnterRoomSolver().run("meeting", detail=False) @TransitionOn()
def _(self):
ClueMainSolver().run()

View file

@ -1,45 +1,44 @@
from mower.solvers.infra.base_mixin import BaseMixin from datetime import timedelta
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config from mower.utils import config
from mower.utils.image import cropimg from mower.utils.image import cropimg
from mower.utils.log import logger from mower.utils.log import logger
from mower.utils.rapidocr import ocr_rec from mower.utils.rapidocr import ocr_rec
from mower.utils.recognize import Scene from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver from mower.utils.solver import BaseSolver, TransitionOn
from .utils import clue_cls, exit_pos from .utils import ClueMainSolver, clue_cls
class ReceiveSolver(BaseSolver, BaseMixin): class ReceiveSolver(BaseSolver):
solver_name = "接收好友线索" solver_name = "接收好友线索"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
def run(self): @TransitionOn(Scene.INFRA_CONFIDENTIAL)
super().run() def _(self):
def transition(self) -> bool:
if (
scene := self.scene()
) == Scene.INFRA_DETAILS and self.detect_room() == "meeting":
self.tap((500, 1000))
elif scene == Scene.INFRA_CONFIDENTIAL:
receive_scope = ((1822, 365), (1886, 400)) receive_scope = ((1822, 365), (1886, 400))
if self.find("clue/badge_new", scope=receive_scope): if self.find("clue/badge_new", scope=receive_scope):
self.ctap((1800, 430)) self.ctap((1800, 430))
else:
return True
elif scene == Scene.CLUE_RECEIVE:
if self.find("infra_complete/信用", scope=((1440, 130), (1920, 193))):
self.sleep()
return return
if clue := clue_cls("receive"): return True
@TransitionOn(Scene.CLUE_RECEIVE)
def _(self):
if self.find("product_complete"):
return
if (clue := clue_cls("receive")) is None:
return True
name_scope = ((1580, 220), (1880, 255)) name_scope = ((1580, 220), (1880, 255))
name_img = cropimg(config.recog.gray, name_scope) name_img = cropimg(config.recog.gray, name_scope)
name = ocr_rec(name_img) or "好友" name = ocr_rec(name_img) or "好友"
logger.info(f"接收{name}{clue}号线索") logger.info(f"接收{name}{clue}号线索")
self.tap(name_scope) self.tap(name_scope)
else:
self.tap(exit_pos) @TransitionOn(BaseSolver.waiting_scene)
elif scene in self.waiting_scene: def _(self):
self.waiting_solver() self.waiting_solver()
else:
EnterRoomSolver().run("meeting", detail=False) @TransitionOn()
def _(self):
ClueMainSolver().run()

View file

@ -1,7 +1,15 @@
import cv2 from datetime import timedelta
import cv2
import networkx as nx
from mower.solvers.infra.base_mixin import BaseMixin
from mower.solvers.infra.enter_room import EnterRoomSolver
from mower.utils import config from mower.utils import config
from mower.utils.graph.utils import DG
from mower.utils.image import cropimg, loadres from mower.utils.image import cropimg, loadres
from mower.utils.recognize import Scene
from mower.utils.solver import BaseSolver, TransitionOn
from mower.utils.vector import va from mower.utils.vector import va
clue_size = (162, 216) clue_size = (162, 216)
@ -45,7 +53,6 @@ for i in range(1, 8):
main_time[i] = va(clue_top_left[i], main_time_offset) main_time[i] = va(clue_top_left[i], main_time_offset)
main_scope[i] = tl2p(va(clue_top_left[i], main_offset)) main_scope[i] = tl2p(va(clue_top_left[i], main_offset))
tm_thres = 0.6 tm_thres = 0.6
exit_pos = (1239, 144)
def clue_cls(scope): def clue_cls(scope):
@ -58,3 +65,53 @@ def clue_cls(scope):
if max_val > tm_thres: if max_val > tm_thres:
return i return i
return None return None
class MeetingSolver(BaseSolver, BaseMixin):
solver_name = "会客室"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
@TransitionOn(Scene.INFRA_MAIN)
def _(self):
EnterRoomSolver().run("meeting", detail=False)
@TransitionOn(Scene.INFRA_DETAILS)
def _(self):
if self.detect_room() != "meeting":
self.scene_graph_step(Scene.INFRA_MAIN)
return
if self.find("meeting_arrange_check_in"):
return True
self.tap((960, 540))
@TransitionOn()
def _(self):
try:
nx.shortest_path(DG, self.scene(), Scene.INFRA_DETAILS)
self.scene_graph_step(Scene.INFRA_DETAILS)
except nx.NetworkXNoPath:
self.scene_graph_step(Scene.INFRA_MAIN)
class ClueMainSolver(BaseSolver):
solver_name = "主界面"
solver_max_duration = timedelta(minutes=2)
solver_default_scene = None
@TransitionOn(Scene.INFRA_DETAILS)
def _(self):
MeetingSolver().run()
self.tap((500, 1000))
@TransitionOn(Scene.INFRA_CONFIDENTIAL)
def _(self):
return True
@TransitionOn()
def _(self):
try:
nx.shortest_path(DG, self.scene(), Scene.INFRA_CONFIDENTIAL)
self.scene_graph_step(Scene.INFRA_CONFIDENTIAL)
except nx.NetworkXNoPath:
self.scene_graph_step(Scene.INFRA_MAIN)

View file

@ -18,10 +18,10 @@ def todo_complete(solver: BaseSolver):
@edge(Scene.ACTIVITY_ROOM_DETAILS, Scene.INFRA_MAIN) @edge(Scene.ACTIVITY_ROOM_DETAILS, Scene.INFRA_MAIN)
@edge(Scene.CTRLCENTER_ASSISTANT, Scene.INFRA_MAIN) @edge(Scene.CTRLCENTER_ASSISTANT, Scene.INFRA_MAIN)
@edge(Scene.CLUE_DAILY, Scene.INFRA_CONFIDENTIAL) @edge(Scene.CLUE_DAILY, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_RECEIVE, Scene.INFRA_CONFIDENTIAL) @edge(Scene.CLUE_RECEIVE, Scene.INFRA_DETAILS)
@edge(Scene.CLUE_GIVE_AWAY, Scene.INFRA_CONFIDENTIAL) @edge(Scene.CLUE_GIVE_AWAY, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_SUMMARY, Scene.INFRA_CONFIDENTIAL) @edge(Scene.CLUE_SUMMARY, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_PLACE, Scene.INFRA_CONFIDENTIAL) @edge(Scene.CLUE_PLACE, Scene.INFRA_DETAILS)
@edge(Scene.CLUE_MESSAGE_BOARD, Scene.INFRA_CONFIDENTIAL) @edge(Scene.CLUE_MESSAGE_BOARD, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_MESSAGE_BOARD_FRIEND, Scene.CLUE_MESSAGE_BOARD) @edge(Scene.CLUE_MESSAGE_BOARD_FRIEND, Scene.CLUE_MESSAGE_BOARD)
@edge(Scene.CLUE_ACCESS_RECORD, Scene.CLUE_MESSAGE_BOARD) @edge(Scene.CLUE_ACCESS_RECORD, Scene.CLUE_MESSAGE_BOARD)
@ -33,6 +33,12 @@ def infra_back(solver: BaseSolver):
solver.cback(3, id="infra_back") solver.cback(3, id="infra_back")
@edge(Scene.CLUE_RECEIVE, Scene.INFRA_CONFIDENTIAL)
@edge(Scene.CLUE_PLACE, Scene.INFRA_CONFIDENTIAL)
def clue_receive_back(solver: BaseSolver):
solver.tap((960, 1000))
@edge(Scene.RIIC_OPERATOR_SELECT, Scene.INFRA_DETAILS) @edge(Scene.RIIC_OPERATOR_SELECT, Scene.INFRA_DETAILS)
def riic_operator_select(solver: BaseSolver): def riic_operator_select(solver: BaseSolver):
solver.ctap("confirm_blue", 3) solver.ctap("confirm_blue", 3)

View file

@ -283,7 +283,7 @@ class Recognizer:
self.scene = Scene.CLUE_GIVE_AWAY self.scene = Scene.CLUE_GIVE_AWAY
elif self.find("clue/summary"): elif self.find("clue/summary"):
self.scene = Scene.CLUE_SUMMARY self.scene = Scene.CLUE_SUMMARY
elif self.find("clue/filter_all"): elif self.find("clue/filter_all") or self.find("clue/filter_all_on"):
self.scene = Scene.CLUE_PLACE self.scene = Scene.CLUE_PLACE
elif self.find("clue/message_board_banner"): elif self.find("clue/message_board_banner"):
self.scene = Scene.CLUE_MESSAGE_BOARD self.scene = Scene.CLUE_MESSAGE_BOARD

View file

@ -18,6 +18,7 @@ color = {
"clue/access_records.jpg": (843, 279), "clue/access_records.jpg": (843, 279),
"clue/daily": (526, 623), "clue/daily": (526, 623),
"clue/filter_all": (1297, 99), "clue/filter_all": (1297, 99),
"clue/filter_all_on": (1299, 100),
"clue/give_away": (25, 18), "clue/give_away": (25, 18),
"clue/message_board_banner": (19, 1006), "clue/message_board_banner": (19, 1006),
"clue/message_board_collect": (1657, 876), "clue/message_board_collect": (1657, 876),

View file

@ -69,6 +69,7 @@ Res = Literal[
"clue/button_unlock", "clue/button_unlock",
"clue/daily", "clue/daily",
"clue/filter_all", "clue/filter_all",
"clue/filter_all_on",
"clue/give_away", "clue/give_away",
"clue/give_away_digit_bg", "clue/give_away_digit_bg",
"clue/icon_notification", "clue/icon_notification",