Bounty Board (Daily)
Status: SHIPPED (E5 of the shared Daily framework). The DT theming of the shared Daily framework; the framework owns selection, streak,
Last updated: October 27, 2026
Dark Tower — Bounty Board (Daily)
Status: SHIPPED (E5 of the shared Daily framework). The DT theming of the shared Daily framework; the framework owns selection, streak, reward delivery, the NLU surface, and the regression shape — this doc is only DT's theme.
Parent: index.md. Framework: engine/daily-framework.md. Currency path: economy.md. Counters: combat.md.
Thesis
A returning Dark Tower player always has one small fresh thing to do today: the Bounty Board. It is a single daily bounty drawn from a stable pool, themed to DT and built entirely on counters the game already maintains — no new gameplay telemetry.
The daily (what it IS)
- Title: "Bounty Board" (the stable, hermetic-assertable themed label).
- Selection: SHARED, date-seeded (
DailySelector.pickForDate) — everyone gets the same bounty today, so the per-day standing is comparable. Resets at the UTC date boundary; no cron, no stored cursor (the framework's deterministic-rotation model). - Objective pool (stable order):
Key Spoken objective Tracker Target Mode DT_BOUNTY_KILLS_TENdefeat ten enemies in combat enemyKills10 DELTA_SINCE_DAY_START DT_BOUNTY_CLUES_THREEdiscover three clues in your travels cluesDiscovered3 DELTA_SINCE_DAY_START DT_BOUNTY_ENCOUNTERwin a combat encounter enemyKills1 DELTA_SINCE_DAY_START
Where a returning player hears it
On the first launch of each UTC day, a returning player hears today's bounty as one line right after the welcome: "Today's bounty: defeat ten enemies in combat, for 200 gold." A later launch the same day does not repeat it. The line is , read from the pool and the completion reward above, and the once-a-day marker is (a daily marker in the player's timeouts). The marker and the bounty pick read one clock's one UTC day, so the line turns over when the board does. On a launch that offers the recap, the line sits between the welcome back and the recap question. A player still naming a hero does not hear it.
Objectives reuse existing trackers (no new counter)
Every bounty reads an EXISTING lifetime counter on as a
DELTA_SINCE_DAY_START (the framework snapshots the lifetime value when the day's bounty is first
viewed, then progress = current − snapshot):
- Enemies defeated — sum of every per-type count in
enemyKills(incremented byDarkTowerStatsUtilityon each kill; the same total reports). - Clues discovered — the size of the
cluesDiscoveredset (added by on discovery).
"Win a combat encounter" is the lightweight bounty — a kill target of one off the same kill counter, the "complete an encounter" objective from the framework's DT row.
Reward model
- Completion: GOLD (soft) — base 200, +25 per consecutive-day streak (capped at the
framework's 7-day bonus cap, so a 7-day streak pays 350). Delivered through
(the DT soft-currency branch in ,
with
DARK_TOWERinSOFT_WIRED_GAMES). Soft gold intentionally skips the premium audit ledger (economy.md § soft-currency carve-out); it is double-money-weekend and money-cap aware like every other DT gold reward. - Streak milestone: earned SPECIAL TOKENS (premium) — a flat 5 special tokens on every
7th consecutive completed day (
getStreakMilestoneInterval() == 7). Delivered ONLY through with sourcePremiumCurrencySource.DAILY_CHALLENGE, which writes the mandatorygame_log.purchase_transactionsaudit row in the same call. The milestone is an EARNED faucet, so it pays theDARK_TOWER_TOKENcurrency (ledger keydark_tower_tokens), NOT purchase-only Diamonds (epic 24205, 2026-07-13 — no free faucet may credit Diamonds). - Boot-time wiring assertion: (
@PostConstruct) validates BOTH the completion gold and the milestone special tokens are deliverable, so a half-wired DT daily cannot ship.
NLU surface
Inherits the framework's always-available Tier-5 BASELINE_DAILY* commands (daily, claim daily,
daily challenge streak, ...) routed by to this provider in any DARK_TOWER session.
Two DT-specific NLU adjustments were needed:
- Retired the
dailyshadow. A legacy tier-4DARK_TOWER_DAILY_PACKS -> "daily"synonym shadowed the Tier-5 baseline, so in Dark Towerdailyreached the daily-packs shop ("nothing to collect right now") instead of the Bounty Board. The row is DELETED. Note the synonym mappergetSynonymsToCompareTodoes NOT honor theenabledflag, so a shadowing synonym must be removed, not merely disabled. Baredailynow reaches the Bounty Board; the daily-packs shop stays reachable viadaily packs/daily rewards. - Added a themed
bounty boardsynonym. A tier-4 DARK_TOWERBASELINE_DAILY -> "bounty board"row lets a player reach the board by its own name.bountyalone stays mapped toMESSAGE_BOARD_BOUNTY(the separate message-board feature).
Guarded by scenario_tests 2174 (daily reaches the Bounty Board) and 2175 (bounty board reaches it).
Code
| Component | Path |
|---|---|
| Provider | engines/handlers/darktower/daily/.java |
| Soft gold branch | engines/handlers/common/daily/.deliverSoft (DARK_TOWER) |
| Reward JUnit | test/.../darktower/daily/DarkTowerDailyProviderTest.java |