feat(stamina): Implement daily gem reward claiming logic and fix button detection
This commit is contained in:
parent
5a78e8ef11
commit
3c47fabd87
@ -23,6 +23,25 @@ MISSION_ICON = (75, 350)
|
|||||||
# grey (r-b<20) when not. Calibrated live at 1920x1200.
|
# grey (r-b<20) when not. Calibrated live at 1920x1200.
|
||||||
MISSION_CLAIM_PROBE = (1600, 1100)
|
MISSION_CLAIM_PROBE = (1600, 1100)
|
||||||
|
|
||||||
|
# Separate "デイリーミッションを8回クリア" (clear 8 daily missions) summary
|
||||||
|
# bar's own 受取 (claim) button, ported from the reference's own
|
||||||
|
# `collect_daily_task_power.py::implement` -- it checks TWO distinct
|
||||||
|
# button regions, not one: the main 一括受取 area (MISSION_CLAIM_PROBE
|
||||||
|
# above) is drained in a loop first, then this second, separate button
|
||||||
|
# (reference's own "claim daily pyroxenes" region, positioned to the LEFT
|
||||||
|
# of the main claim-all button in both the reference's layout and this
|
||||||
|
# client's) is checked independently -- 一括受取 does NOT also claim this,
|
||||||
|
# confirmed live (2026-07-16): a real account state showed this button
|
||||||
|
# still claimable (a gem x20 reward) after 一括受取's own area had already
|
||||||
|
# gone grey. Also unlike 一括受取, this button has no Enter keybind shown
|
||||||
|
# on screen, so it needs an actual coordinate click rather than a keypress
|
||||||
|
# (matching the reference's own raw click here too, `self.click(976, 670,
|
||||||
|
# ...)`, rather than the img_reactions-driven Enter used elsewhere).
|
||||||
|
# Same bright-yellow-vs-grey signature as MISSION_CLAIM_PROBE, confirmed
|
||||||
|
# live at this exact point; pixel-scanned to sit clearly inside the button
|
||||||
|
# and off the "受取" text glyphs (which read near-black, ~(75,33,22)).
|
||||||
|
MISSION_DAILY_GEM_CLAIM_BUTTON = (1400, 1095)
|
||||||
|
|
||||||
CAFE_ICON = (165, 1100)
|
CAFE_ICON = (165, 1100)
|
||||||
CAFE_ROOM_SWITCH = (190, 160)
|
CAFE_ROOM_SWITCH = (190, 160)
|
||||||
CAFE_INCOME = (1780, 1105)
|
CAFE_INCOME = (1780, 1105)
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1,4 +1,15 @@
|
|||||||
"""Mission/task-menu AP+pyroxene claim. Ported from baas-reference module/collect_daily_task_power.py's claim-loop pattern (its rgb_in_range checks replaced with driver.color_at probes)."""
|
"""Mission/task-menu AP+pyroxene claim. Ported from baas-reference module/collect_daily_task_power.py's claim-loop pattern (its rgb_in_range checks replaced with driver.color_at probes).
|
||||||
|
|
||||||
|
The reference's `implement` checks TWO separate button regions, not one:
|
||||||
|
the main 一括受取 (claim-all) area is drained in a loop first, then a
|
||||||
|
second, separate "claim daily pyroxenes" button is checked and clicked
|
||||||
|
independently -- 一括受取 does not also claim it. This was originally
|
||||||
|
missed here (only the first region was ported), reported live by the user
|
||||||
|
against a real account state where the second button ("デイリーミッショ
|
||||||
|
ンを8回クリア", a gem x20 reward) was still showing claimable after
|
||||||
|
一括受取 had already gone grey -- see config.py's
|
||||||
|
`MISSION_DAILY_GEM_CLAIM_BUTTON` for the live-calibration writeup.
|
||||||
|
"""
|
||||||
|
|
||||||
from ba_auto import navigation
|
from ba_auto import navigation
|
||||||
|
|
||||||
@ -6,20 +17,46 @@ OPEN_RETRIES = 3
|
|||||||
# One claim-all round is normally enough (button goes grey right after), but
|
# One claim-all round is normally enough (button goes grey right after), but
|
||||||
# bound it in case multiple reward reveals need dismissing in sequence.
|
# bound it in case multiple reward reveals need dismissing in sequence.
|
||||||
CLAIM_MAX_ROUNDS = 5
|
CLAIM_MAX_ROUNDS = 5
|
||||||
|
DAILY_GEM_CLAIM_MAX_ATTEMPTS = 3
|
||||||
|
|
||||||
# Yellow "one-click claim all" button vs. its own flat-grey disabled state --
|
# Yellow "one-click claim all" button vs. its own flat-grey disabled state --
|
||||||
# same background-pixel-probe idea as mailbox.CLAIM_ALL_PROBE/cafe.CLAIM_PROBE,
|
# same background-pixel-probe idea as mailbox.CLAIM_ALL_PROBE/cafe.CLAIM_PROBE,
|
||||||
# but distinguished by hue (yellow has a big r-b gap; grey doesn't) since the
|
# but distinguished by hue (yellow has a big r-b gap; grey doesn't) since the
|
||||||
# button's grey isn't a single fixed RGB the way mailbox/cafe's are.
|
# button's grey isn't a single fixed RGB the way mailbox/cafe's are. Also
|
||||||
|
# shared by the separate daily-gem claim button (config.MISSION_DAILY_GEM_CLAIM_BUTTON),
|
||||||
|
# which uses the same bright-yellow-vs-grey visual style.
|
||||||
CLAIM_ENABLED_MIN_R = 230
|
CLAIM_ENABLED_MIN_R = 230
|
||||||
CLAIM_ENABLED_MIN_RB_GAP = 100
|
CLAIM_ENABLED_MIN_RB_GAP = 100
|
||||||
|
|
||||||
|
|
||||||
def _claim_enabled(driver, config):
|
def _button_claimable(driver, probe):
|
||||||
r, g, b = driver.color_at(*config.MISSION_CLAIM_PROBE)
|
r, g, b = driver.color_at(*probe)
|
||||||
return r > CLAIM_ENABLED_MIN_R and (r - b) > CLAIM_ENABLED_MIN_RB_GAP
|
return r > CLAIM_ENABLED_MIN_R and (r - b) > CLAIM_ENABLED_MIN_RB_GAP
|
||||||
|
|
||||||
|
|
||||||
|
def _claim_enabled(driver, config):
|
||||||
|
return _button_claimable(driver, config.MISSION_CLAIM_PROBE)
|
||||||
|
|
||||||
|
|
||||||
|
def _daily_gem_claimable(driver, config):
|
||||||
|
return _button_claimable(driver, config.MISSION_DAILY_GEM_CLAIM_BUTTON)
|
||||||
|
|
||||||
|
|
||||||
|
def _claim_daily_gem(driver, config):
|
||||||
|
for attempt in range(1, DAILY_GEM_CLAIM_MAX_ATTEMPTS + 1):
|
||||||
|
driver.click(*config.MISSION_DAILY_GEM_CLAIM_BUTTON)
|
||||||
|
driver.wait(1.5)
|
||||||
|
# Dismiss the reward-reveal popup the same way the main claim-all
|
||||||
|
# loop does below -- this button has no Enter keybind of its own,
|
||||||
|
# but Enter still dismisses the reward card that appears after.
|
||||||
|
driver.keypress("Return")
|
||||||
|
driver.wait(1.5)
|
||||||
|
if not _daily_gem_claimable(driver, config):
|
||||||
|
return True
|
||||||
|
print(f"[stamina] daily gem reward still showing claimable after click (attempt {attempt}/{DAILY_GEM_CLAIM_MAX_ATTEMPTS})")
|
||||||
|
return not _daily_gem_claimable(driver, config)
|
||||||
|
|
||||||
|
|
||||||
def run(driver, config):
|
def run(driver, config):
|
||||||
driver.focus_game()
|
driver.focus_game()
|
||||||
|
|
||||||
@ -50,6 +87,13 @@ def run(driver, config):
|
|||||||
driver.wait(1.5)
|
driver.wait(1.5)
|
||||||
claimed_any = True
|
claimed_any = True
|
||||||
|
|
||||||
|
if _daily_gem_claimable(driver, config):
|
||||||
|
print("[stamina] claiming daily gem mission reward")
|
||||||
|
if _claim_daily_gem(driver, config):
|
||||||
|
claimed_any = True
|
||||||
|
else:
|
||||||
|
print("[stamina] warning: could not confirm the daily gem reward was claimed")
|
||||||
|
|
||||||
if not claimed_any:
|
if not claimed_any:
|
||||||
print("[stamina] nothing to claim")
|
print("[stamina] nothing to claim")
|
||||||
|
|
||||||
|
|||||||
10
plan.md
10
plan.md
@ -388,6 +388,16 @@ Not yet done: Group/Club AP, and Daily Free Power (see above).
|
|||||||
|
|
||||||
The 青輝石購入 menu deliberately left unautomated above turned out to gate a real-money purchase UI in general, but the specific card this was always about (`module/collect_daily_free_power.py`'s 毎日無料パッケージ, 0 yen, AP+credits) is safe to automate on its own — it's a fixed, non-selectable, always-free claim with no purchase decision to make, same category as this phase's own Mission-panel claim. Built as a separate `ba_auto/tasks/gem_shop.py` rather than folded into `stamina.py`, since it's a different reference file/UI entry point. See Phase 16.
|
The 青輝石購入 menu deliberately left unautomated above turned out to gate a real-money purchase UI in general, but the specific card this was always about (`module/collect_daily_free_power.py`'s 毎日無料パッケージ, 0 yen, AP+credits) is safe to automate on its own — it's a fixed, non-selectable, always-free claim with no purchase decision to make, same category as this phase's own Mission-panel claim. Built as a separate `ba_auto/tasks/gem_shop.py` rather than folded into `stamina.py`, since it's a different reference file/UI entry point. See Phase 16.
|
||||||
|
|
||||||
|
#### Phase 8 follow-up #2: daily gem reward wasn't being claimed (2026-07-16)
|
||||||
|
|
||||||
|
Reported live by the user, with a saved reference screenshot (`screenshots/stamina/daily gem available.png`): stamina "should collect all reward in the mission, but it didn't collect the daily gem reward."
|
||||||
|
|
||||||
|
Re-reading `module/collect_daily_task_power.py::implement` (already the reference for this task, but not fully ported the first time) confirmed the gap: it checks TWO separate button regions, not one. The main 一括受取 area is drained in a loop first (region A, the only one originally ported into `stamina.py`); then, independently, a second, separate button (region B, the reference's own "claim daily pyroxenes" check, positioned to the left of region A in both the reference's raw coordinates and this client's own layout) is checked and clicked -- 一括受取 does not also claim it. Live on nik-gpu, this second button corresponds to the "デイリーミッションを8回クリア" (clear 8 daily missions) summary bar's own 受取 button, a gem x20 reward, which was confirmed still showing claimable after 一括受取 had already gone flat grey.
|
||||||
|
|
||||||
|
Ported region B as `MISSION_DAILY_GEM_CLAIM_BUTTON` (config.py), pixel-scanned live at native 1920x1200 (button spans roughly x=1385-1535, y=1080-1165; click point `(1400, 1095)` confirmed clean and off the "受取" text glyphs, which read near-black). Reuses the exact same bright-yellow-vs-grey color signature already established for `MISSION_CLAIM_PROBE` (`CLAIM_ENABLED_MIN_R`/`CLAIM_ENABLED_MIN_RB_GAP`, refactored into a shared `_button_claimable` helper rather than duplicated). Unlike 一括受取, this button shows no Enter keybind on screen, so it's claimed via an actual `driver.click` (matching the reference's own raw `self.click(976, 670, ...)` for this exact region) followed by an Enter press to dismiss the reward-reveal card, wrapped in a click-then-verify bounded retry (`_claim_daily_gem`, `DAILY_GEM_CLAIM_MAX_ATTEMPTS = 3`) matching this project's established discipline rather than trusting an unverified click.
|
||||||
|
|
||||||
|
**Confirmed live** via the real `./ba_dailies.sh stamina` CLI path against a genuinely claimable reward (the account's real daily-mission-count tracker was at 8/8, gem reward pending): gem balance went from 12,384 → 12,404 -- exactly the reward's own stated +20 -- with the existing main claim-all also firing normally in the same run, and a clean, warning-free return to the true home screen afterward.
|
||||||
|
|
||||||
### Phase 9: Normal/Hard story AP sweep
|
### Phase 9: Normal/Hard story AP sweep
|
||||||
|
|
||||||
**Status: Done.** Read `module/explore_tasks/sweep_task.py` and `module/explore_tasks/task_utils.py` — the reference flow reads the current region number and matches stage-name text via OCR (`swipe_search_target_str`) to navigate to a configured target stage, then runs a per-stage claim loop. This client exposes a much simpler path to the same goal (burn AP via already-3-starred stages) that avoids porting the OCR-based lookup entirely: each stage's own 任務情報 (task info) modal has a self-contained 掃討 (sweep) sub-panel with a MIN/-/+/MAX count stepper and a start button.
|
**Status: Done.** Read `module/explore_tasks/sweep_task.py` and `module/explore_tasks/task_utils.py` — the reference flow reads the current region number and matches stage-name text via OCR (`swipe_search_target_str`) to navigate to a configured target stage, then runs a per-stage claim loop. This client exposes a much simpler path to the same goal (burn AP via already-3-starred stages) that avoids porting the OCR-based lookup entirely: each stage's own 任務情報 (task info) modal has a self-contained 掃討 (sweep) sub-panel with a MIN/-/+/MAX count stepper and a start button.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user