Refactor directory labels and update task migration status

- Changed directory labels from ".scratchpad/" to "scratchpad/" in graph.json and related documentation for consistency.
- Updated plan.md to reflect the current status of the Stamina/AP task migration, including details on the mission claim process and identified bugs.
- Modified setup.sh to include 'stamina' in the run command options for the daily script.
This commit is contained in:
Nik Afiq 2026-07-05 19:15:32 +09:00
parent a04ef5d0c5
commit 0b16399948
12 changed files with 113 additions and 25 deletions

2
.gitignore vendored
View File

@ -3,4 +3,4 @@ graphify-out/cost.json
graphify-out/cache/ graphify-out/cache/
__pycache__/ __pycache__/
*.pyc *.pyc
.scratchpad/ scratchpad/

View File

@ -197,7 +197,7 @@ Do not introduce OCR casually. Add it only when implementing a feature that actu
## Working conventions ## Working conventions
Use `.scratchpad/` (create if missing) in the project root for temporary/intermediate files — e.g. cropped calibration images from `screenshots/cafe/sparkle/`, one-off debug output. Never write to `/tmp` or `/private/tmp`. Use `scratchpad/` (create if missing) in the project root for temporary/intermediate files — e.g. cropped calibration images from `screenshots/cafe/sparkle/`, one-off debug output. Never write to `/tmp` or `/private/tmp`.
## Bash policy ## Bash policy
@ -319,7 +319,7 @@ The detector should support:
- threshold tuning - threshold tuning
- masked matching - masked matching
- click-offset handling - click-offset handling
- debug image output to `.scratchpad/` - debug image output to `scratchpad/`
Avoid one Python cold start per click attempt where possible. Prefer long-running Python task logic that can take repeated screenshots and click repeatedly from one process. Avoid one Python cold start per click attempt where possible. Prefer long-running Python task logic that can take repeated screenshots and click repeatedly from one process.
@ -385,7 +385,7 @@ Use this format:
## Working conventions ## Working conventions
Use `.scratchpad/` for temporary or intermediate files. Use `scratchpad/` for temporary or intermediate files.
Examples: Examples:
@ -421,7 +421,7 @@ Example:
ssh nik-gpu "~/ba_dailies.sh cafe" ssh nik-gpu "~/ba_dailies.sh cafe"
``` ```
When debugging image matching, write debug images to `.scratchpad/`. When debugging image matching, write debug images to `scratchpad/`.
## Existing features ## Existing features

View File

@ -29,6 +29,7 @@ Current task status:
|---|---| |---|---|
| `mailbox` | Real Python (`ba_auto/tasks/mailbox.py`). Verifies the mailbox panel actually opened (via a pixel-color probe, `driver.color_at`) before clicking "claim all" or pressing any further keys. Retries the open-click up to 3 times before giving up safely. | | `mailbox` | Real Python (`ba_auto/tasks/mailbox.py`). Verifies the mailbox panel actually opened (via a pixel-color probe, `driver.color_at`) before clicking "claim all" or pressing any further keys. Retries the open-click up to 3 times before giving up safely. |
| `cafe` | Real Python (`ba_auto/tasks/cafe.py`). Verifies each room/dialog transition the same way as `mailbox` before acting; sparkle detection runs in-process via `ba_auto/detector.py` instead of shelling out per click. See "Fixed: the exit-game dialog bug" below for what this replaced, and `plan.md` Phase 6 follow-up for the multi-scale detection + persistent-polling changes made after a "farming affection doesn't happen" report. | | `cafe` | Real Python (`ba_auto/tasks/cafe.py`). Verifies each room/dialog transition the same way as `mailbox` before acting; sparkle detection runs in-process via `ba_auto/detector.py` instead of shelling out per click. See "Fixed: the exit-game dialog bug" below for what this replaced, and `plan.md` Phase 6 follow-up for the multi-scale detection + persistent-polling changes made after a "farming affection doesn't happen" report. |
| `stamina` | Real Python (`ba_auto/tasks/stamina.py`). Opens the Mission panel and claims via its bulk "一括受取" button (Enter key) when enabled. Does **not** touch the Pyroxene Purchase (青輝石購入) menu's free-AP claim — that's a real-money purchase screen and was deliberately left unautomated; see `plan.md` Phase 8. |
## Prerequisites on nik-gpu ## Prerequisites on nik-gpu
@ -62,9 +63,10 @@ ssh nik-gpu "cd ~/repo/ba-auto-daily && ./setup.sh"
The game must already be running on `nik-gpu` (window titled `BlueArchive`). Then, on `nik-gpu`: The game must already be running on `nik-gpu` (window titled `BlueArchive`). Then, on `nik-gpu`:
```bash ```bash
~/ba_dailies.sh # default: mailbox, then cafe ~/ba_dailies.sh # default: mailbox, cafe, then stamina
~/ba_dailies.sh mailbox # just mailbox ~/ba_dailies.sh mailbox # just mailbox
~/ba_dailies.sh cafe # just cafe ~/ba_dailies.sh cafe # just cafe
~/ba_dailies.sh stamina # just the Mission-panel bulk claim
``` ```
You can also run these remotely without a separate `ssh` login step: You can also run these remotely without a separate `ssh` login step:
@ -73,7 +75,7 @@ You can also run these remotely without a separate `ssh` login step:
ssh nik-gpu "~/ba_dailies.sh mailbox" ssh nik-gpu "~/ba_dailies.sh mailbox"
``` ```
Exit code `0` means the script ran to completion without a Python exception — it does **not** by itself guarantee the in-game action succeeded. Both `mailbox` and `cafe` log what they actually detected and did (or why they safely aborted), so check the log output, not just the exit code. Exit code `0` means the script ran to completion without a Python exception — it does **not** by itself guarantee the in-game action succeeded. `mailbox`, `cafe`, and `stamina` all log what they actually detected and did (or why they safely aborted), so check the log output, not just the exit code.
## How to watch/verify it ## How to watch/verify it

View File

@ -17,6 +17,12 @@ os.makedirs(SCRATCHPAD_DIR, exist_ok=True)
MAILBOX_ICON = (1732, 50) MAILBOX_ICON = (1732, 50)
CLAIM_ALL = (1691, 1128) CLAIM_ALL = (1691, 1128)
MISSION_ICON = (75, 350)
# Background pixel inside the "一括受取" (claim all) button on the Mission
# panel: bright yellow (r~250, r-b~180+) when something is claimable, flat
# grey (r-b<20) when not. Calibrated live at 1920x1200.
MISSION_CLAIM_PROBE = (1600, 1100)
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)

View File

@ -29,7 +29,13 @@ def focus_game():
def click(x, y): def click(x, y):
run_command(["xdotool", "mousemove", str(x), str(y), "click", "1"]) # A combined "mousemove X Y click 1" invocation is unreliable here --
# empirically (see plan.md's click-flakiness writeups) the game's input
# handler sometimes misses clicks fired before it's processed the move.
# Splitting into separate commands with a short pause between fixes it.
run_command(["xdotool", "mousemove", str(x), str(y)])
wait(0.2)
run_command(["xdotool", "click", "1"])
wait(0.5) wait(0.5)

View File

@ -6,7 +6,7 @@ Maps each local feature to the corresponding `~/repo/baas-reference/module/...`
|---|---|---|---|---|---| |---|---|---|---|---|---|
| Mailbox | `module/mail.py` | `to_mail`, `implement` | `ba_auto/tasks/mailbox.py` | tap/click via xdotool, screenshot via scrot, `color.rgb_in_range``driver.color_at` pixel-probe check | Migrated: real Python, state-verified via color probe (no legacy bridge) | | Mailbox | `module/mail.py` | `to_mail`, `implement` | `ba_auto/tasks/mailbox.py` | tap/click via xdotool, screenshot via scrot, `color.rgb_in_range``driver.color_at` pixel-probe check | Migrated: real Python, state-verified via color probe (no legacy bridge) |
| Cafe | `module/cafe_reward.py` | `to_cafe`, `interaction_for_cafe_solve_method3`, `collect` | `ba_auto/tasks/cafe.py` | `picture.co_detect`/`color.rgb_in_range``driver.color_at` pixel-probe checks; sparkle template match ported in-process into `ba_auto/detector.py` (`find_cafe_sparkle`, now multi-scale) | Migrated: real Python, state-verified via color probes (no legacy bridge). Pat loop now polls for the full attempt budget instead of stopping on the first miss (see `plan.md` Phase 6 follow-up) — not yet confirmed against a live sparkle since none was available during testing | | Cafe | `module/cafe_reward.py` | `to_cafe`, `interaction_for_cafe_solve_method3`, `collect` | `ba_auto/tasks/cafe.py` | `picture.co_detect`/`color.rgb_in_range``driver.color_at` pixel-probe checks; sparkle template match ported in-process into `ba_auto/detector.py` (`find_cafe_sparkle`, now multi-scale) | Migrated: real Python, state-verified via color probes (no legacy bridge). Pat loop now polls for the full attempt budget instead of stopping on the first miss (see `plan.md` Phase 6 follow-up) — not yet confirmed against a live sparkle since none was available during testing |
| Stamina/AP | `module/collect_daily_free_power.py`, `module/collect_daily_task_power.py` | Need to inspect | `ba_auto/tasks/stamina.py` | color checks/clicks via local driver | Not started | | Stamina/AP | `module/collect_daily_free_power.py`, `module/collect_daily_task_power.py` | `to_tasks`/`implement` (task-power, ported); `to_purchase_pyroxenes_menu` (free-power, not ported) | `ba_auto/tasks/stamina.py` | `color.rgb_in_range``driver.color_at`; reference's per-tab claim loop → live UI's single "一括受取" bulk-claim button + Enter | Partially migrated: Mission-panel claim done (see `plan.md` Phase 8). Daily Free Power (real-money purchase menu) deliberately not automated |
| Group/Club AP | `module/group.py` | Need to inspect | `ba_auto/tasks/group.py` | fixed click + state check via local driver | Not started | | Group/Club AP | `module/group.py` | Need to inspect | `ba_auto/tasks/group.py` | fixed click + state check via local driver | Not started |
| Bounty | `module/rewarded_task.py` | Need to inspect | `ba_auto/tasks/bounty.py` | sweep/color/OCR adaptation | Not started | | Bounty | `module/rewarded_task.py` | Need to inspect | `ba_auto/tasks/bounty.py` | sweep/color/OCR adaptation | Not started |
| Commissions | `module/clear_special_task_power.py` | Need to inspect | `ba_auto/tasks/commission.py` | sweep/color adaptation | Not started | | Commissions | `module/clear_special_task_power.py` | Need to inspect | `ba_auto/tasks/commission.py` | sweep/color adaptation | Not started |

59
ba_auto/tasks/stamina.py Normal file
View File

@ -0,0 +1,59 @@
"""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)."""
from ba_auto import navigation
OPEN_RETRIES = 3
# One claim-all round is normally enough (button goes grey right after), but
# bound it in case multiple reward reveals need dismissing in sequence.
CLAIM_MAX_ROUNDS = 5
# 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,
# 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.
CLAIM_ENABLED_MIN_R = 230
CLAIM_ENABLED_MIN_RB_GAP = 100
def _claim_enabled(driver, config):
r, g, b = driver.color_at(*config.MISSION_CLAIM_PROBE)
return r > CLAIM_ENABLED_MIN_R and (r - b) > CLAIM_ENABLED_MIN_RB_GAP
def run(driver, config):
driver.focus_game()
opened = False
for attempt in range(1, OPEN_RETRIES + 1):
driver.focus_game()
driver.click(*config.MISSION_ICON)
driver.wait(2)
if navigation.is_on_subscreen(driver):
opened = True
break
print(f"[stamina] mission panel not detected after click (attempt {attempt}/{OPEN_RETRIES})")
if not opened:
print("[stamina] could not confirm mission panel is open, aborting without pressing further keys")
return
claimed_any = False
for _ in range(CLAIM_MAX_ROUNDS):
if not _claim_enabled(driver, config):
break
print("[stamina] claiming mission rewards")
driver.keypress("Return")
driver.wait(1.5)
# dismiss the reward-reveal popup ("TOUCH" prompt); harmless no-op if
# nothing is actually showing, same assumption as cafe's room-entry dismiss
driver.keypress("Return")
driver.wait(1.5)
claimed_any = True
if not claimed_any:
print("[stamina] nothing to claim")
if navigation.is_on_subscreen(driver):
driver.keypress("Escape")
driver.wait(1.5)
print("[stamina] Done.")

View File

@ -3,13 +3,14 @@
import sys import sys
from ba_auto import config, driver from ba_auto import config, driver
from ba_auto.tasks import cafe, mailbox from ba_auto.tasks import cafe, mailbox, stamina
TASKS = { TASKS = {
"mailbox": mailbox.run, "mailbox": mailbox.run,
"cafe": cafe.run, "cafe": cafe.run,
"stamina": stamina.run,
} }
DEFAULT_ORDER = ["mailbox", "cafe"] DEFAULT_ORDER = ["mailbox", "cafe", "stamina"]
def main(argv): def main(argv):

File diff suppressed because one or more lines are too long

View File

@ -348,7 +348,7 @@
"norm_label": "screenshots/ reference-capture directory" "norm_label": "screenshots/ reference-capture directory"
}, },
{ {
"label": ".scratchpad/ working-file convention", "label": "scratchpad/ working-file convention",
"file_type": "concept", "file_type": "concept",
"source_file": "CLAUDE.md", "source_file": "CLAUDE.md",
"source_location": "L38", "source_location": "L38",
@ -358,7 +358,7 @@
"contributor": null, "contributor": null,
"id": "claude_scratchpad_dir", "id": "claude_scratchpad_dir",
"community": 0, "community": 0,
"norm_label": ".scratchpad/ working-file convention" "norm_label": "scratchpad/ working-file convention"
}, },
{ {
"label": "~/.venvs/ba-auto-daily Python venv (opencv-python, numpy)", "label": "~/.venvs/ba-auto-daily Python venv (opencv-python, numpy)",

34
plan.md
View File

@ -136,7 +136,7 @@ Initial seed:
|---|---|---|---|---|---| |---|---|---|---|---|---|
| Mailbox | Need to confirm in reference | Need to inspect | `ba_auto/tasks/mailbox.py` | tap/click via xdotool, screenshot via scrot | Existing Bash behavior; migrate to Python | | Mailbox | Need to confirm in reference | Need to inspect | `ba_auto/tasks/mailbox.py` | tap/click via xdotool, screenshot via scrot | Existing Bash behavior; migrate to Python |
| Cafe | `module/cafe_reward.py` | `to_cafe`, `interaction_for_cafe_solve_method3`, `collect` | `ba_auto/tasks/cafe.py` | `picture.co_detect`/`color.rgb_in_range``driver.color_at` pixel-probe checks; sparkle template match ported in-process into `ba_auto/detector.py` | Migrated: real Python, state-verified via color probes, no legacy bridge | | Cafe | `module/cafe_reward.py` | `to_cafe`, `interaction_for_cafe_solve_method3`, `collect` | `ba_auto/tasks/cafe.py` | `picture.co_detect`/`color.rgb_in_range``driver.color_at` pixel-probe checks; sparkle template match ported in-process into `ba_auto/detector.py` | Migrated: real Python, state-verified via color probes, no legacy bridge |
| Stamina/AP | `module/collect_daily_free_power.py`, `module/collect_daily_task_power.py` | Need to inspect | `ba_auto/tasks/stamina.py` | color checks/clicks via local driver | Not started | | Stamina/AP | `module/collect_daily_free_power.py`, `module/collect_daily_task_power.py` | `to_tasks`/`implement` (task-power, ported); `to_purchase_pyroxenes_menu`/`detect_free_power_availability` (free-power, not ported — real-money purchase menu) | `ba_auto/tasks/stamina.py` | `color.rgb_in_range``driver.color_at`; reference's per-tab claim loop replaced by the live UI's single "一括受取" (claim-all) button, triggered via Enter | Partially migrated (Phase 8): Mission-panel task/weekly/achievement claim done. Daily Free Power deliberately not implemented. |
| Group/Club AP | `module/group.py` | Need to inspect | `ba_auto/tasks/group.py` | fixed click + state check via local driver | Not started | | Group/Club AP | `module/group.py` | Need to inspect | `ba_auto/tasks/group.py` | fixed click + state check via local driver | Not started |
| Bounty | `module/rewarded_task.py` | Need to inspect | `ba_auto/tasks/bounty.py` | sweep/color/OCR adaptation | Not started | | Bounty | `module/rewarded_task.py` | Need to inspect | `ba_auto/tasks/bounty.py` | sweep/color/OCR adaptation | Not started |
| Commissions | `module/clear_special_task_power.py` | Need to inspect | `ba_auto/tasks/commission.py` | sweep/color adaptation | Not started | | Commissions | `module/clear_special_task_power.py` | Need to inspect | `ba_auto/tasks/commission.py` | sweep/color adaptation | Not started |
@ -153,8 +153,9 @@ Do not implement a feature without filling at least the relevant row.
|---|---|---| |---|---|---|
| Mailbox claim | Migrated: `ba_auto/tasks/mailbox.py` uses `driver.color_at` to verify the panel opened before acting (found live-testing bug: a marginal icon coordinate could miss and cascade into pressing Escape on the home screen, which triggers Blue Archive's own exit-game confirmation) | Done | | Mailbox claim | Migrated: `ba_auto/tasks/mailbox.py` uses `driver.color_at` to verify the panel opened before acting (found live-testing bug: a marginal icon coordinate could miss and cascade into pressing Escape on the home screen, which triggers Blue Archive's own exit-game confirmation) | Done |
| Cafe pats + income | Migrated: `ba_auto/tasks/cafe.py` verifies each room/dialog opened via `driver.color_at` before acting; sparkle detection now runs in-process via `ba_auto/detector.py` instead of a per-click subprocess | Done | | Cafe pats + income | Migrated: `ba_auto/tasks/cafe.py` verifies each room/dialog opened via `driver.color_at` before acting; sparkle detection now runs in-process via `ba_auto/detector.py` instead of a per-click subprocess | Done |
| Shared driver | `ba_auto/driver.py` built (`run_command`, `focus_game`, `click`, `keypress`, `screenshot`, `wait`, `color_at`); wired into both `mailbox.py` and `cafe.py` | Extend with new primitives as future tasks need them | | Stamina/AP (mission claim) | Migrated (partial, Phase 8): `ba_auto/tasks/stamina.py` claims the Mission panel's bulk "一括受取" button. Daily Free Power (real-money purchase menu) intentionally not implemented | Daily Free Power still not started |
| Python CLI | Built: `ba_daily.py` dispatches `mailbox`/`cafe`/default flow | Extend as new tasks are added | | Shared driver | `ba_auto/driver.py` built (`run_command`, `focus_game`, `click`, `move_mouse`, `keypress`, `screenshot`, `wait`, `color_at`); `click()` now splits `mousemove`/`click` into two xdotool calls (Phase 8 finding — fixes a real source of click flakiness); wired into `mailbox.py`, `cafe.py`, `stamina.py` | Extend with new primitives as future tasks need them |
| Python CLI | Built: `ba_daily.py` dispatches `mailbox`/`cafe`/`stamina`/default flow | Extend as new tasks are added |
| Reference mapping | Built: `ba_auto/reference_notes/mapping.md` | Fill in reference file/function columns per feature | | Reference mapping | Built: `ba_auto/reference_notes/mapping.md` | Fill in reference file/function columns per feature |
| Everything else | Not started | Implement reference-first in Python | | Everything else | Not started | Implement reference-first in Python |
@ -289,6 +290,19 @@ What was directly verified live after these changes:
**Not yet verified**: an actual end-to-end pat (detect → click → affection-up dialog dismissed) succeeding after this round's changes, because no interactable sparkle was available during testing to exercise it against. Re-run `~/ba_dailies.sh cafe` once interactions have had time to regenerate and confirm `[cafe] patted N sparkle(s)` appears with N > 0. **Not yet verified**: an actual end-to-end pat (detect → click → affection-up dialog dismissed) succeeding after this round's changes, because no interactable sparkle was available during testing to exercise it against. Re-run `~/ba_dailies.sh cafe` once interactions have had time to regenerate and confirm `[cafe] patted N sparkle(s)` appears with N > 0.
### Phase 8: Stamina/AP mission claim
**Status: Partially done.** Read `module/collect_daily_task_power.py` (the "Tasks" menu claim loop — `to_tasks` + `rgb_in_range` checks against two fixed pixel pairs, click, dismiss, repeat) and `module/collect_daily_free_power.py` (a `picture.co_detect` state-machine walk into the Pyroxene Purchase menu's Package tab to claim a genuinely free 10 AP item). Live reconnaissance on the home screen found the direct local equivalents: a `ミッション` (Mission) icon opening a panel with per-tab claim buttons *and* a single bulk "一括受取" (claim all) button whose keyboard shortcut is literally Enter — much simpler than porting the reference's per-tab color-probe loop. `ba_auto/tasks/stamina.py` opens the Mission panel, checks whether "一括受取" is enabled (bright yellow vs. flat grey background probe at `config.MISSION_CLAIM_PROBE`), and if so presses Enter to claim, Enter again to dismiss the reward-reveal card (same "harmless no-op if absent" assumption as cafe's room-entry dismiss), bounded to a few rounds in case multiple rewards queue up.
The 青輝石購入 (Pyroxene Purchase) icon — reference's Daily Free Power entry point — was opened once to confirm the free-claim flow's location, but turned out to be a real-money purchase menu (¥3,000¥4,900 package buttons visible immediately) with the genuinely-free item buried in a further tab. Given `plan.md`'s own purchase-safety rules ("avoid unbounded spending", "avoid buying unknown items"), this was **deliberately not automated this round** — the dialog was closed without navigating further. Treat this as a separate, explicitly-confirmed piece of future work, not an oversight.
Two real bugs found and fixed during live calibration, both worth remembering for future coordinate-hunting:
- **Visual gridline coordinate estimates were wrong twice in a row.** Reading icon bounds off a scaled/annotated screenshot crop by eye put the Mission icon's center at `(146, 352)` — which is actually in the dead space between the Mission and Pyroxene-Purchase icons, close enough to the latter's edge that clicks there landed on Pyroxene Purchase instead. The fix was sampling actual pixel colors along a scanline (`img.getpixel`) to find each icon's true left/right edge against the background, rather than eyeballing gridlines — this put the real center at `(75, 350)`, squarely inside the icon graphic, confirmed live. Lesson: for icon coordinates, prefer a pixel-boundary scan over a visual grid-overlay estimate.
- **`driver.click()`'s combined `xdotool mousemove X Y click 1` invocation is unreliable; splitting it fixed a chunk of this project's long-documented click flakiness.** Repeated single-click tests at a *verified-correct* coordinate still missed intermittently until the mousemove and click were issued as two separate `xdotool` calls with a short (0.2s) pause between them — after that, every subsequent click registered. This plausibly explains some of the "icon click missed on the first attempt, worked on retry" flakiness documented in Phases 56 (mailbox/cafe icons). Applied to `driver.click()` itself (project-wide, since all tasks share it) rather than special-cased in `stamina.py`; regression-tested live against `mailbox` and `cafe` after the change — both still work.
Not yet done: Group/Club AP, and Daily Free Power (see above).
### Phase 7: setup.sh update ### Phase 7: setup.sh update
**Status: Done — `setup.sh` deploys `ba_daily.py` and `ba_auto/`.** `scripts/ba_dailies_legacy.sh` and `scripts/detect_and_click.py` were deleted once mailbox and cafe both migrated off them (Phases 56); `setup.sh` no longer references either. **Status: Done — `setup.sh` deploys `ba_daily.py` and `ba_auto/`.** `scripts/ba_dailies_legacy.sh` and `scripts/detect_and_click.py` were deleted once mailbox and cafe both migrated off them (Phases 56); `setup.sh` no longer references either.
@ -380,12 +394,12 @@ Goal (all done):
### 2. Stamina/AP sweep ### 2. Stamina/AP sweep
**Status: Partially done — see Phase 8.**
Claim: Claim:
- daily free AP purchase - ~~daily free AP purchase~~ — deferred; entry point is a real-money purchase menu, needs explicit confirmation before automating
- daily task-menu AP/pyroxene rewards - daily task-menu AP/pyroxene rewards — done, via the Mission panel's bulk claim button
Likely mostly color/state detection and fixed clicks.
Reference: Reference:
@ -396,7 +410,7 @@ Reference:
Local target: `ba_auto/tasks/stamina.py` Local target: `ba_auto/tasks/stamina.py`
OCR: Probably not needed for first version. OCR: Not needed — turned out to be a single bulk-claim button + Enter, no per-item detection required.
### 3. Club/Group AP claim ### 3. Club/Group AP claim
@ -717,7 +731,7 @@ server = JP
game_window_name = BlueArchive game_window_name = BlueArchive
display = :0 display = :0
asset_dir = ~/ba_assets asset_dir = ~/ba_assets
screenshot_dir = .scratchpad/ screenshot_dir = scratchpad/
cafe_max_clicks_per_room cafe_max_clicks_per_room
story_sweep_target story_sweep_target
shop_buy_list shop_buy_list
@ -730,7 +744,7 @@ Keep config explicit. Do not bury user-specific settings deep inside task logic.
## Debugging conventions ## Debugging conventions
Use `.scratchpad/` for: Use `scratchpad/` for:
- temporary screenshots - temporary screenshots
- cropped templates - cropped templates

View File

@ -47,5 +47,5 @@ rm -rf "$HOME/ba_auto"
cp -r ba_auto "$HOME/ba_auto" cp -r ba_auto "$HOME/ba_auto"
echo "== Done ==" echo "== Done =="
echo "Run with: ~/ba_dailies.sh [mailbox|cafe]" echo "Run with: ~/ba_dailies.sh [mailbox|cafe|stamina]"
echo "(requires the game already running, window titled 'BlueArchive')" echo "(requires the game already running, window titled 'BlueArchive')"