feat(economy): add /lootbox mystery box (coin sink with random reward)
A pay-to-open box (1000 coins) with a weighted reward: coin tiers (usually a net loss - the sink), a random 30-min earn/exp buff, or a rare jackpot. All rolling lives in do_open_lootbox for testability; the command adds a short reveal. - New core module lootbox.py; extracted consumables.grant_buff (reused by both consumables and lootbox) to avoid duplicating the buff-stacking logic. - New lootboxes_opened stat; pending schema syncs as a number automatically. - Added /consumables, /lootbox, /vanity to the help embed (the first two were previously missing from /help). Tests cover charging, insufficient/banned, the coin and buff outcomes, the net-vs-reward invariant, and that balance never goes negative. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013VbAVsrZuYesea99mPMmPT
This commit is contained in:
@@ -152,6 +152,7 @@ class UserData(TypedDict, total=False):
|
||||
total_given: int
|
||||
total_received: int
|
||||
best_daily_streak: int
|
||||
lootboxes_opened: int
|
||||
heist_global_cd_until: float
|
||||
# Prestige system
|
||||
prestige_level: int
|
||||
@@ -213,6 +214,7 @@ def _default_user() -> UserData:
|
||||
"total_given": 0,
|
||||
"total_received": 0,
|
||||
"best_daily_streak": 0,
|
||||
"lootboxes_opened": 0,
|
||||
"heist_global_cd_until": 0.0,
|
||||
# ── Prestige ─────────────────────────────────────────────────────────
|
||||
"prestige_level": 0,
|
||||
|
||||
Reference in New Issue
Block a user