Files
my-botty/test/assets
alexpolo1andClaude Opus 5 5276c33ba8 feat(baal_xp): leech public Baal runs — label-gated portals, chat signals, no own game
Makes the baal_xp route actually earn XP unattended. Verified live at ~9.4M
XP/hour (paladalla 25 -> 32 over the session).

Portal selection is the core of it. A Baal town has several portals up at once
— the host's to the Throne plus other players' portals to wherever they were
standing — so taking the best template match picked an arbitrary one; the bot
sat in FRIGID HIGHLANDS (ARTEMIS) earning nothing. Every portal on screen is
now enumerated, hovered and its label read, and only a THRONE match is entered.
The labels sit on a bright animated ring and OCR badly, so matching is fuzzy:
measured over 21 real labels, the Throne portal scores 1.00 and every other
portal in the same town <= 0.50, which is what makes 0.7 safe. That tolerance
matters — a live run entered on 'THIR(NE ()F I)F GTTRIICT T()N', which exact
matching would have skipped.

Ending a run is driven by what the game actually tells us. D2R prints
"<name> left our world" per departure; OCR mangles it but MINIONS survives
(3/3 matched, 0/7 false positives at 0.8). Counting is baselined on arrival —
the chat log persists from before we join, and counting it wholesale abandoned
a fresh game after 28s over departures we never witnessed. Flat XP remains the
primary end-of-run signal; a gradual 8->5->4 drain never trips a departure
threshold, but idle XP catches it immediately.

Dropped the own-game round trip. The cycle used to click PLAY, create a game,
save-and-exit it, join a public one, then create another game just to leave it
again — two creations and two exits per cycle, each a way to fail. A leech only
needs the character screen. Cycles now re-arm without ending the game, with a
5-failure cutout so the controller's own circuit breaker still gets its say.

Town maintenance is skipped for this route: a leech buys, repairs and stashes
nothing, and the vendor/waypoint pathing stranded the character against the
town wall, which then hid the town markers and broke act detection for the rest
of the game.

Bugs fixed along the way:
- bot.py never imported mouse, so the hide step died with NameError on first use
- main_menu.start_game() dereferenced _wait_for_play_btn() without a None check
- game_browser passed a label into select_screen_object_match's delay_factor,
  crashing in random.uniform
- server-error dialogs were left up, so the next join candidate failed with
  "JOIN GAME button not visible" and aborted the whole join
- at_character_select() keyed on one template; when LOBBY_BTN went stale every
  save-and-exit failed while the screen was plainly showing
- difficulty was read by OCR and became "nrit al" after a font change, aborting
  every join before the game list; it is a template match now
- the chat-triggered portal hunt inherited the full 8-minute budget inside the
  hide loop, suspending the HP and timeout checks
- a portal that reads fine but will not open is given up on after 3 attempts

Lobby templates were re-cut after removing stale mods (which carried a font
replacement); all verify at 1.000.

test/baal_xp_test.py covers the decision logic against the real OCR strings and
captures each bug was diagnosed from — 27 tests, no game required.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 21:45:17 +02:00
..