- Recalibrated gem shop task after client UI update, replacing the old overlay dialog with a full subscreen. - Removed custom dialog open/close checks in favor of shared navigation functions. - Updated method names and logic to reflect new tab structure and improve clarity. - Enhanced error handling for dialog closure and navigation return to home. - Verified live against real account states to ensure functionality and correctness.
125 lines
5.6 KiB
Python
125 lines
5.6 KiB
Python
"""Gem shop (青輝石購入) daily free package. Ports module/collect_daily_free_power.py.
|
|
|
|
Reference flow (`implement`): to_main_page -> to_purchase_pyroxenes_menu
|
|
(open the dialog via the home-screen 青輝石購入 icon) -> to_purchase_type
|
|
("package") -> detect_free_power_availability -> if purchasable,
|
|
collect_daily_free_power (click the free card, confirm the 0-yen purchase,
|
|
wait for the reward) else log "already collected" -> return_to_main_page
|
|
(close the dialog). Skips entirely on CN server (JP/Global only) -- no
|
|
equivalent server concept in this project, so not ported.
|
|
|
|
The reference detects every step via image template matching (no OCR
|
|
anywhere in this flow) -- this port uses plain color probes for the same
|
|
states instead (see config.py's "Gem shop daily free package" section for
|
|
the full live-calibration writeup and exact pixel values), matching this
|
|
project's own established equivalent for a simple, high-contrast
|
|
state-A/state-B visual difference, same as cafe.py's CLAIM_DISABLED_RGB or
|
|
stamina.py's MISSION_CLAIM_PROBE.
|
|
|
|
Live-calibrated 2026-07-15 by manually driving the real dialog end-to-end
|
|
on nik-gpu, which genuinely claimed the account's real free package for the
|
|
day (0 yen, confirmed +10 AP / +10,000 credits via before/after counter
|
|
values) -- see scratchpad/gem_shop_*.png for the captures. That exercised
|
|
the "available -> claim it" path for real, via raw xdotool/scrot rather
|
|
than this actual module.
|
|
|
|
RECALIBRATED 2026-07-29 after a real Blue Archive client UI update replaced
|
|
the old 3-top-tab overlay dialog (期間限定/青輝石/パッケージ) with a real
|
|
full subscreen (left sidebar + デイリー/ウィークリー/マンスリー sub-tabs
|
|
under 一般商品). See config.py's "Gem shop daily free package" section for
|
|
the full writeup of what was re-verified live and what's still an inferred
|
|
value. The old `_dialog_open`/`_close_gem_shop` custom probes existed only
|
|
because the pre-redesign overlay dialog was invisible to
|
|
navigation.is_on_subscreen/is_modal_open; the redesigned screen is a real
|
|
subscreen, confirmed live, so this module now shares the same
|
|
is_on_subscreen/return_to_home machinery every other subscreen-based task
|
|
(mailbox/cafe/shop/lesson) already uses, and those two custom probes are
|
|
gone.
|
|
|
|
A `reference-parity-reviewer` pass on the original version caught a real
|
|
bug: the final dialog-close step verified success via
|
|
`navigation.is_on_subscreen`, which the pre-redesign overlay dialog read
|
|
identically whether open or closed -- so that check could never fail,
|
|
making a stuck-open dialog unrecoverable. That specific blindness no longer
|
|
applies post-redesign (is_on_subscreen now genuinely distinguishes this
|
|
screen from home, confirmed live), which is what made switching to the
|
|
shared navigation.return_to_home safe here.
|
|
"""
|
|
|
|
from ba_auto import navigation
|
|
|
|
|
|
def _open_gem_shop(driver, config):
|
|
for attempt in range(1, config.GEM_SHOP_ICON_RETRIES + 1):
|
|
driver.click(*config.GEM_SHOP_ICON)
|
|
driver.wait(2)
|
|
if navigation.is_on_subscreen(driver):
|
|
return True
|
|
print(f"[gem_shop] subscreen not detected after click (attempt {attempt}/{config.GEM_SHOP_ICON_RETRIES})")
|
|
return False
|
|
|
|
|
|
def _open_daily_general_tab(driver, config):
|
|
for attempt in range(1, config.GEM_SHOP_ICON_RETRIES + 1):
|
|
driver.click(*config.GEM_SHOP_GENERAL_PRODUCTS_TAB)
|
|
driver.wait(1)
|
|
driver.click(*config.GEM_SHOP_DAILY_SUBTAB)
|
|
driver.wait(1.5)
|
|
status = _read_free_card_status(driver, config)
|
|
if status != "unknown":
|
|
return status
|
|
print(f"[gem_shop] free card status not recognized after click (attempt {attempt}/{config.GEM_SHOP_ICON_RETRIES})")
|
|
return "unknown"
|
|
|
|
|
|
def _color_matches(rgb, target, tolerance):
|
|
return all(abs(c - t) <= tolerance for c, t in zip(rgb, target))
|
|
|
|
|
|
def _read_free_card_status(driver, config):
|
|
rgb = driver.color_at(*config.GEM_SHOP_FREE_CARD_STATUS_PROBE)
|
|
if _color_matches(rgb, config.GEM_SHOP_STATUS_CLAIMED_RGB, config.GEM_SHOP_STATUS_TOLERANCE):
|
|
return "claimed"
|
|
if _color_matches(rgb, config.GEM_SHOP_STATUS_AVAILABLE_RGB, config.GEM_SHOP_STATUS_TOLERANCE):
|
|
return "available"
|
|
return "unknown"
|
|
|
|
|
|
def _claim_free_package(driver, config):
|
|
driver.click(*config.GEM_SHOP_FREE_CARD_BUY_BUTTON)
|
|
driver.wait(2)
|
|
for _ in range(config.GEM_SHOP_CLAIM_MAX_ATTEMPTS):
|
|
if _read_free_card_status(driver, config) == "claimed":
|
|
return True
|
|
driver.keypress("Return")
|
|
driver.wait(2)
|
|
return _read_free_card_status(driver, config) == "claimed"
|
|
|
|
|
|
def run(driver, config):
|
|
driver.focus_game()
|
|
|
|
if not _open_gem_shop(driver, config):
|
|
print("[gem_shop] could not confirm the gem shop screen opened, aborting without pressing further keys")
|
|
return
|
|
|
|
status = _open_daily_general_tab(driver, config)
|
|
if status == "unknown":
|
|
print("[gem_shop] could not read the free package card's status, aborting without pressing further keys")
|
|
if not navigation.return_to_home(driver):
|
|
print("[gem_shop] warning: could not confirm return to home")
|
|
return
|
|
|
|
if status == "claimed":
|
|
print("[gem_shop] daily free package already collected today")
|
|
else:
|
|
print("[gem_shop] claiming daily free package (+10 AP, +10,000 credits)")
|
|
if _claim_free_package(driver, config):
|
|
print("[gem_shop] claimed daily free package")
|
|
else:
|
|
print("[gem_shop] warning: could not confirm the free package was claimed after retries")
|
|
|
|
if not navigation.return_to_home(driver):
|
|
print("[gem_shop] warning: could not confirm return to home")
|
|
print("[gem_shop] Done.")
|