feat(economy): add vanity shop and harden economy money-safety
Vanity shop (/vanity): cosmetic badges/titles as a pure whale coin sink - purchases burn coins (not credited to the house) and equip a badge shown on /profile. New vanity_owned/vanity_active fields, schema sync, and tests. Money-safety and robustness fixes from a codebase review: - _parse_amount now rejects negative amounts. Every bet/give/request flows through it, so a negative value can no longer mint coins on a loss/transfer path that trusts the caller's sign (all call sites already guarded <= 0; this closes the source). - do_blackjack_payout no longer raises on a DB failure. The stake was already deducted in do_blackjack_bet, so it now logs critical with the owed amount (for admin reconciliation) and returns db_error; all payout call sites render a clear "payout failed" notice instead of crashing the interaction. - Instant "kohv" consumable now cancels the pending reminder DMs for the cooldowns it wipes (via new INSTANT_RESET_COMMANDS), so no stale/duplicate reminders fire. - Renamed the misleadingly-named _refund_user_safe -> _debit_house_safe (it debits the house) and dropped its ignored first arg. - Added __all__ to vanity.py and consumables.py so `import *` no longer leaks incidental imports into the economy namespace. - Documented Kõrvaklapid's +25 coin daily bonus in README and DEV_NOTES. Tests: blackjack payout DB-failure safety and INSTANT_RESET_COMMANDS lockstep. 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:
@@ -23,6 +23,17 @@ from ..pb_client import DatabaseError
|
||||
from ..emoji import EMOJI as E
|
||||
from .store import _commit, _locked_by, _now, _parse_dt, _txn, get_user
|
||||
|
||||
__all__ = [
|
||||
"Consumable",
|
||||
"CONSUMABLES",
|
||||
"INSTANT_RESET_COMMANDS",
|
||||
"active_buffs",
|
||||
"buff_remaining",
|
||||
"earn_mult",
|
||||
"exp_buff_mult",
|
||||
"do_buy_consumable",
|
||||
]
|
||||
|
||||
|
||||
class Consumable(TypedDict):
|
||||
name: str
|
||||
@@ -66,6 +77,11 @@ _BUFF_MULT: dict[str, float] = {"earn": 2.0, "exp": 2.0}
|
||||
# Cooldown timestamps an instant "kohv" clears.
|
||||
_COOLDOWN_FIELDS = ("last_work", "last_beg", "last_crime", "last_rob", "last_fish")
|
||||
|
||||
# The slash-command names whose cooldowns an instant "kohv" clears. The Discord
|
||||
# layer uses these to cancel any pending reminder DMs, since the cooldowns they
|
||||
# were scheduled for no longer exist.
|
||||
INSTANT_RESET_COMMANDS = tuple(f.removeprefix("last_") for f in _COOLDOWN_FIELDS)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Buff inspection helpers (pure - safe to call while holding a user lock)
|
||||
|
||||
Reference in New Issue
Block a user