"""Cafe daily task. Ported from baas-reference module/cafe_reward.py's state-probe pattern.""" from ba_auto import detector, navigation ROOM_OPEN_RETRIES = 3 # "受取" (claim) renders as flat grey when there is nothing to collect yet. CLAIM_PROBE = (960, 850) CLAIM_DISABLED_RGB = (218, 218, 218) CLAIM_DISABLED_TOLERANCE = 15 def _claim_disabled(driver): r, g, b = driver.color_at(*CLAIM_PROBE) tr, tg, tb = CLAIM_DISABLED_RGB return ( abs(r - tr) <= CLAIM_DISABLED_TOLERANCE and abs(g - tg) <= CLAIM_DISABLED_TOLERANCE and abs(b - tb) <= CLAIM_DISABLED_TOLERANCE ) def _enter_room(driver, coords): for attempt in range(1, ROOM_OPEN_RETRIES + 1): driver.click(*coords) driver.wait(3) if navigation.is_on_subscreen(driver): # dismiss the "visited student list" notice shown on room entry driver.keypress("Return") driver.wait(1) return True print(f"[cafe] room not detected after click (attempt {attempt}/{ROOM_OPEN_RETRIES})") return False def _pat_room(driver, config): # Sparkles appear on a per-student cooldown, so most single checks find # nothing -- the old Bash loop (and an earlier version of this one) gave # up on the very first miss, which meant it essentially never farmed. # Keep polling for the full budget instead of bailing early. patted = 0 for _ in range(config.CAFE_MAX_CLICKS_PER_ROOM): match = detector.find_cafe_sparkle() if match is None: driver.wait(1) continue x, y, score = match driver.click(x, y) driver.wait(1) driver.keypress("Return") # park the cursor away from the sparkle area so it can't occlude the # next detection screenshot (see screenshots/cafe/sparkle/02_*_cursor_on_head.png) driver.move_mouse(10, 1190) patted += 1 print(f"[cafe] patted sparkle at ({x}, {y}), score={score:.3f}") print(f"[cafe] patted {patted} sparkle(s)" if patted else "[cafe] no sparkle found") def _claim_income(driver, config): driver.click(*config.CAFE_INCOME) driver.wait(2) if not navigation.is_modal_open(driver): print("[cafe] income panel not detected, skipping claim") return if _claim_disabled(driver): print("[cafe] nothing to claim") else: print("[cafe] claiming income") driver.keypress("Return") driver.wait(2) driver.keypress("Return") driver.wait(2) if navigation.is_modal_open(driver): driver.keypress("Escape") driver.wait(1.5) def run(driver, config): driver.focus_game() if not _enter_room(driver, config.CAFE_ICON): print("[cafe] could not confirm cafe is open, aborting without pressing further keys") return print("[cafe] room 1: farming affection") _pat_room(driver, config) if not _enter_room(driver, config.CAFE_ROOM_SWITCH): print("[cafe] could not confirm room switch, stopping before income claim") if navigation.is_on_subscreen(driver): driver.keypress("Escape") driver.wait(1.5) return print("[cafe] room 2: farming affection") _pat_room(driver, config) _claim_income(driver, config) if navigation.is_on_subscreen(driver): driver.keypress("Escape") driver.wait(1.5) print("[cafe] Done.")