Wire a curated set of crypto assets (BTC, ETH, SOL, XRP, DOGE, ADA, LTC)
into the !fx conversion path only. fxLivePairRate now resolves each side
to units-per-USD and crosses them, so USD/fiat/crypto mix uniformly; fiat
sides still batch into one Frankfurter call, crypto hits CoinGecko's
keyless simple/price with a 60s cache.
Analysis (rate/report/setalert) stays fiat-only on purpose -- a daily
snapshot buy-signal/52w range is meaningless for 24/7 crypto.
- Co-op: when a run wipes or completes, clear the 99-sentinel combat
lock for participants and pin combat_actions_used to maxCombatActions.
Previously the lock only released on the next midnight reset, so
members were stuck unable to combat for the rest of the day after
their run ended.
- Holidays: !holidays now prints the full list. Previously it called
the same featured-only formatter as TwinBee's morning auto-post,
so users saw the same truncated message twice with a misleading
"Use !holidays for the full list" hint that pointed at itself.
- Forex: add currency conversion. Auto-detects when the first arg is
numeric (`!fx 1500 USD EUR`) and also accepts an explicit `convert`
subcommand. Tolerant parsing: "to"/"into"/"in"/"=" filters, comma
and k/m suffix support, and any of `1500 USD EUR`, `1500 USD/EUR`,
`USD/EUR 1500` orderings. Includes parser + comma-formatter tests.
- Lottery: drop 2-match prize tier. At 1/16 odds × €25 it was +EV per
ticket on its own and bled the community pot (~€775/wk recently),
preventing jackpot rollover from accumulating. Removed from scoring,
payout loops, draw announcement, !lottery odds, and !lottery history.
Match2Winners DB column kept (history rows preserved); always written
as 0 going forward.
- Lottery: shift week boundary so Sat/Sun return next Monday. Friday's
23:59 draw used to leave players locked at their 100-ticket cap until
next Monday rolled in; now the cap resets immediately after the draw.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Forex: add CAD to tracked currencies, add cross-pair syntax (EUR/USD,
EUR|JPY, etc.) for both !fx rate and !fx report with full historical
analysis computed from stored USD-base rates.
Adventure: fix midnight reset silently failing due to SQLite busy
contention with the reminder fire loop — propagate errors so the job
isn't marked complete on failure, add retry with backoff, and add
startup catch-up for missed resets and expired death timers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add forex plugin (Frankfurter v2 API) with rate lookups, analysis,
DM-based alerts, and daily cron poll. Backfills 1 year of history
on startup for moving averages and buy signal scoring.
- Fix bot hang caused by SQLite lock contention in reminder polling:
rows cursor was held open while writing to the same DB. Collect
results first, close cursor, then process. Same fix in milkcarton.
- Add sync retry loop so the bot reconnects after network drops
instead of silently exiting. StopSync() for clean Ctrl+C shutdown.
- Add panic recovery to all dispatch, syncer, and cron paths.
- Make all HTTP-calling plugin commands async (goroutines) so a slow
or dead external API cannot block the message dispatch pipeline.
Affects: lookup, stocks, forex, anime, movies, concerts, gaming,
retro, wotd, urls, howami.
- Extract DisplayName to Base, add db.Exec helper, convert silent
error discards across the codebase.
- Fix UNO mercy-kill bug (eliminated bot continues playing), adventure
DM nag spam, stats column mismatch, per-call regex/replacer allocs.
- Update README: forex commands, Finance section, 47 plugins.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>