"""Jail, jailbreak and bail.""" from __future__ import annotations import random from datetime import timedelta from .store import ( _commit, _is_jailed, _locked_by, _now, _txn, get_all_users_raw, get_user, ) @_locked_by(0) async def do_spam_jail(user_id: int) -> None: """Jail a user for 30 minutes due to suspected automated command spam.""" user = await get_user(user_id) user["jailed_until"] = (_now() + timedelta(minutes=30)).isoformat() user["jailbreak_used"] = False user["times_jailed"] = user.get("times_jailed", 0) + 1 await _commit(user_id, user) _txn("SPAM_JAIL", user=user_id, until=user["jailed_until"]) # --------------------------------------------------------------------------- # /jailbreak (Monopoly-style dice rolls) # --------------------------------------------------------------------------- @_locked_by(0) async def set_jailbreak_used(user_id: int) -> None: """Mark that the user has consumed their dice attempt for this jail sentence.""" user = await get_user(user_id) user["jailbreak_used"] = True await _commit(user_id, user) @_locked_by(0) async def do_jail_free(user_id: int) -> dict: """Remove jail status after rolling doubles.""" user = await get_user(user_id) user["jailed_until"] = None user["jailbreak_used"] = False await _commit(user_id, user) _txn("JAIL_FREE", user=user_id, method="doubles") return {"ok": True, "balance": user["balance"]} MIN_BAIL = 350 @_locked_by(0) async def do_bail(user_id: int) -> dict: """Charge bail fine after exhausting jailbreak rolls and free the user. Fine = 20-30% of current balance, floored at 350. If balance < 350, stay jailed.""" user = await get_user(user_id) if user["balance"] < MIN_BAIL: return {"ok": False, "reason": "broke", "balance": user["balance"]} pct = random.uniform(0.20, 0.30) fine = max(MIN_BAIL, int(user["balance"] * pct)) user["balance"] = max(0, user["balance"] - fine) user["jailed_until"] = None user["jailbreak_used"] = False user["lifetime_lost"] = user.get("lifetime_lost", 0) + fine user["total_bail_paid"] = user.get("total_bail_paid", 0) + fine await _commit(user_id, user) _txn("BAIL_PAID", user=user_id, fine=f"-{fine}", pct=f"{pct:.0%}", bal=user["balance"]) return {"ok": True, "fine": fine, "balance": user["balance"]} # --------------------------------------------------------------------------- # /jailed # --------------------------------------------------------------------------- async def do_get_jailed() -> list[tuple[int, timedelta]]: """Return [(user_id, remaining)] for every user currently in jail.""" all_users = await get_all_users_raw() result: list[tuple[int, timedelta]] = [] for uid_str, user in all_users.items(): if rem := _is_jailed(user): result.append((int(uid_str), rem)) result.sort(key=lambda x: x[1]) return result