1
0
forked from sass/tipibot
Files
tipibot/docs/DEV_NOTES.md
2026-05-04 20:50:30 +03:00

13 KiB
Raw Blame History

TipiLAN Bot - Developer Reference

File Structure

The codebase is split into core/ (domain logic), commands/ (Discord slash command handlers), and a thin bot.py that wires everything together.

Top level

File Purpose
bot.py Discord client, event handlers (on_ready, on_member_join, ...), background tasks (presence rotation, daily birthday loop), shared helpers (_award_exp, _maybe_remind, _parse_amount, _PAUSED), and register_*_commands(...) wiring for every command module
strings.py Single source of truth for all user-facing text. Edit here to change any message.
config.py Environment variables (TOKEN, GUILD_ID, PB_URL, etc.)

core/ - domain logic, no Discord coupling

File Purpose
core/economy.py All economy business logic (do_daily, do_work, ...), data model, constants (SHOP, COOLDOWNS, LEVEL_ROLES, EXP_REWARDS, JAIL_DURATION, ...)
core/pb_client.py Async PocketBase REST client - auth token cache, CRUD on economy_users collection
core/sheets.py Google Sheets integration (member sync)
core/member_sync.py Birthday/member sync helpers

commands/ - one slash-command group per file

Each file exposes a register_<group>_commands(tree, bot, ...) function. bot.py calls them all once on startup, passing in shared helpers (coin, cd_ts, award_exp, maybe_remind, parse_amount, ...).

File Commands / Responsibility
commands/dev_member_commands.py /check, /member (dev profile only)
commands/dev_member_runtime.py on_member_join flow + birthday_daily task body
commands/economy_income_commands.py /daily, /work, /beg, /crime, /rob
commands/economy_games_commands.py /roulette, /slots, /blackjack, /rps
commands/economy_extra_commands.py /heist, /jailbreak, /reminders, /request, ...
commands/economy_fish_commands.py /fish, /fishbook, /fishsell
commands/economy_profile_commands.py /balance, /rank, /stats, /cooldowns, /leaderboard
commands/economy_support_commands.py /shop, /buy, /give, /economysetup
commands/economy_prestige_commands.py /prestige, /prestigeshop, /prestigebuy
commands/economy_admin_commands.py /admincoins, /adminexp, /adminitem, /adminjail, /adminban, /adminreset, /adminview
commands/ops_admin_commands.py /sync, /restart, /shutdown, /pause, /send, /status
commands/ops_channel_commands.py Channel allowlist commands
commands/info_commands.py /patchnotes and other lightweight info commands

scripts/

File Purpose
scripts/migrate_to_pb.py One-time legacy migration: data/economy.json → PocketBase. Only relevant if you still have a pre-PB JSON store.
scripts/add_stats_fields.py Schema migration: adds new fields to the economy_users collection. Idempotent.
scripts/reset_pb_collections.py Destructive - deletes and recreates the dev + economy collections. Requires --confirm. Use only in dev.

Adding a New Economy Command

Pick the commands/economy_*_commands.py file that matches the new command's category (income, games, profile, ...) and add the handler inside its register_*_commands function. If none fit, create a new module and register it from bot.py.

Checklist - do all of these, in order:

  1. core/economy.py - add the do_<cmd> async function with cooldown check, logic, _commit, and _txn logging
  2. core/economy.py - add the cooldown to COOLDOWNS dict if it has one
  3. core/economy.py - add the EXP reward to EXP_REWARDS dict
  4. strings.py CMD - add the slash command description
  5. strings.py OPT - add any parameter descriptions
  6. strings.py TITLE - add embed title(s) for success/fail states
  7. strings.py ERR - add any error messages (banned, cooldown uses CD_MSG, jailed uses CD_MSG["jailed"])
  8. strings.py CD_MSG - add cooldown message if command has a cooldown
  9. strings.py HELP_CATEGORIES["tipibot"]["fields"] - add the command to the help embed
  10. commands/economy_<group>_commands.py - inside register_*_commands, add @tree.command(name="<cmd>", ...) cmd_<name>; handle all res["reason"] cases
  11. commands/economy_<group>_commands.py - call maybe_remind(user_id, "<cmd>") if the command has a cooldown and reminders make sense (the helper is passed in via the register_* signature)
  12. commands/economy_<group>_commands.py - call await award_exp(interaction, economy.EXP_REWARDS["<cmd>"]) on success
  13. strings.py REMINDER_OPTS - add a reminder option if the command needs one
  14. bot.py _maybe_remind - if the command has an item-modified cooldown, add an elif branch (this helper still lives in bot.py and is shared across all command modules)

Adding a New Shop Item

Checklist:

  1. core/economy.py SHOP - add the item dict {name, emoji, cost, description: strings.ITEM_DESCRIPTIONS["key"]}
  2. core/economy.py SHOP_TIERS - add the key to the correct tier list (1/2/3)
  3. core/economy.py SHOP_LEVEL_REQ - add minimum level if it is T2 (≥10) or T3 (≥20)
  4. strings.py ITEM_DESCRIPTIONS - add the item description (Estonian flavour + English effect)
  5. strings.py HELP_CATEGORIES["shop"]["fields"] - add display entry (sorted by cost)
  6. If the item modifies a cooldown:
    • core/economy.py - add the if "item" in user["items"] branch in the relevant do_<cmd> function
    • bot.py _maybe_remind - add elif cmd == "<cmd>" and "<item>" in items: branch with the new delay
    • commands/economy_profile_commands.py cmd_cooldowns - add the item annotation to the relevant status line

Adding a New Level Role

  1. core/economy.py LEVEL_ROLES - add (min_level, "RoleName") in descending level order (highest first)
  2. bot.py _ensure_level_role - no changes needed (uses LEVEL_ROLES dynamically)
  3. Run /economysetup in the server to create the role and set its position

Adding a New Admin Command

  1. strings.py CMD - add "[Admin] ..." description
  2. strings.py HELP_CATEGORIES["admin"]["fields"] - add the entry
  3. commands/economy_admin_commands.py (or commands/ops_admin_commands.py for non-economy ops) - add the handler with @app_commands.default_permissions(manage_guild=True) and @app_commands.guild_only()

Economy System Design

Storage

All economy state is stored in PocketBase (economy_users collection). core/pb_client.py owns all reads/writes. Each do_* function in core/economy.py calls get_user() → mutates the local dict → calls _commit(). _commit does a PATCH to PocketBase.

Currency & Income Sources

Command Cooldown Base Earn Notes
/daily 20h (18h w/ korvaklapid) 150⬡ ×streak multiplier, ×2 w/ lan_pass, +5% interest w/ gaming_laptop
/work 1h (40min w/ monitor) 15-75⬡ ×1.5 w/ gaming_hiir, ×1.25 w/ reguleeritav_laud, ×3 30% chance w/ energiajook
/beg 5min (3min w/ hiirematt) 10-40⬡ ×2 w/ klaviatuur
/crime 2h 200-500⬡ win 60% success (75% w/ cat6), +30% w/ mikrofon; fail = fine + jail
/rob 2h 1025% of target 45% success (60% w/ jellyfin); fail = fine; house rob: 35% success, 540% jackpot
/slots - varies jackpot=10× (15× w/ monitor_360), triple=4× (6×), pair=1×
/roulette - 2× red/black, 14× green 1/37 green chance
/blackjack - 1:1 win, 3:2 BJ, 2:1 double Dealer stands on 17+; double down on first action only

"all" Keyword

Commands that accept a coin amount (/give, /roulette, /rps, /slots, /blackjack) accept "all" to mean the user's full current balance. Parsed by _parse_amount(value, balance) in bot.py.

Daily Streak Multipliers

  • 1-2 days: ×1.0 (150⬡)
  • 3-6 days: ×1.5 (225⬡)
  • 7-13 days: ×2.0 (300⬡)
  • 14+ days: ×3.0 (450⬡)
  • karikas item: streak survives missed days

Jail

  • Duration: 30 minutes (JAIL_DURATION)
  • gaming_tool: prevents jail on crime fail
  • /jailbreak: 3 dice rolls, need doubles to escape free. On fail - bail = 20-30% of balance, min 350⬡. If balance < 350⬡, player stays jailed until timer.
  • Blocked while jailed: /work, /beg, /crime, /rob, /give (checked in do_* functions via _is_jailed)

EXP Rewards (from EXP_REWARDS in core/economy.py)

EXP is awarded on every successful command use. Level formula: level = max(1, floor(sqrt(exp / 6))) (see get_level / exp_for_level). Thresholds: Level 5 = 150 EXP, Level 10 = 600, Level 20 = 2 400, Level 30 = 5 400.

Gambling EXP is bet-scaled via gamble_exp(bet); fish EXP is per-species in FISH (common 23, uncommon 67, rare 10, epic 1415, legendary 25).


Role Hierarchy (Discord)

Order top to bottom in server roles:

[Bot managed role]  ← bot's own role, always at top of our stack
ECONOMY             ← given to everyone who uses any economy command
TipiLEGEND          ← level 30+
TipiCHAD            ← level 20+
TipiHUSTLER         ← level 10+
TipiGRINDER         ← level 5+
TipiNOOB            ← level 1+

Run /economysetup to auto-create all roles and set their positions. The command is idempotent - safe to run multiple times.

Role assignment:

  • ECONOMY role: given automatically on first EXP award (i.e. first successful economy command)
  • Level roles: given/swapped automatically on level-up; synced on /rank

Shop Tiers & Level Requirements

Tier Level Required Items
T1 0 (any) gaming_hiir, hiirematt, korvaklapid, lan_pass, anticheat, energiajook, gaming_laptop
T2 10 reguleeritav_laud, jellyfin, mikrofon, klaviatuur, monitor, cat6
T3 20 monitor_360, karikas, gaming_tool

Shop display is sorted by cost (ascending) within each tier. The SHOP_LEVEL_REQ dict in core/economy.py controls per-item lock thresholds.


strings.py Organisation

Imported as import strings as S everywhere. Dicts are read from bot.py and from every commands/*.py module.

Section Dict Typical usage
Flavour text WORK_JOBS, BEG_LINES, CRIME_WIN, CRIME_LOSE Randomised descriptions
Command descriptions CMD["key"] @tree.command(description=S.CMD["key"])
Parameter descriptions OPT["key"] @app_commands.describe(param=S.OPT["key"])
Help embed HELP_CATEGORIES["cat"] cmd_help (in bot.py)
Banned message MSG_BANNED All banned checks
Maintenance mode MSG_MAINTENANCE Shown when _PAUSED=True in bot.py (toggled by /pause in commands/ops_admin_commands.py)
Reminder options REMINDER_OPTS RemindersSelect dropdown
Slots outcomes SLOTS_TIERS["tier"](title, color) cmd_slots (in commands/economy_games_commands.py)
Embed titles TITLE["key"] discord.Embed(title=S.TITLE["key"])
Error messages ERR["key"] send_message(S.ERR["key"]) - use .format(**kwargs) for dynamic parts
Cooldown messages CD_MSG["cmd"].format(ts=cd_ts(...)) Cooldown responses (cd_ts helper passed in by bot.py)
Shop UI SHOP_UI["key"] _shop_embed (in commands/economy_support_commands.py)
Item descriptions ITEM_DESCRIPTIONS["item_key"] core/economy.py SHOP[key]["description"]
Patch notes UI PATCHNOTES_UI["key"] commands/info_commands.py (/patchnotes)

Constants Location Quick-Reference

Constant File Description
SHOP core/economy.py All shop items (name, emoji, cost, description)
SHOP_TIERS core/economy.py Which items are in T1/T2/T3
SHOP_LEVEL_REQ core/economy.py Min level per item
COOLDOWNS core/economy.py Base cooldown per command
JAIL_DURATION core/economy.py How long jail lasts
LEVEL_ROLES core/economy.py [(min_level, "RoleName"), ...] highest first
ECONOMY_ROLE core/economy.py Name of the base economy participation role
EXP_REWARDS core/economy.py EXP per command
FISH core/economy.py Fish species table (rarity, weight, coins, exp)
HOUSE_ID core/economy.py Bot's user ID (house account for /rob)
MIN_BAIL core/economy.py Minimum bail payment (350⬡)
COIN core/economy.py The coin emoji string
_PAUSED bot.py In-memory maintenance flag; toggled by /pause; blocks all non-admin commands

Balance Notes (as of current version)

  • Beg is most efficient for active players (3min cooldown + 2× multiplier w/ klaviatuur = high ⬡/hr)
  • Work is best for passive players (1h cooldown, fire and forget)
  • Crime is high risk/reward - best with cat6 + mikrofon
  • lan_pass (1200⬡) doubles daily - good long-term investment
  • gaming_laptop (1500⬡) 5% interest, capped 500⬡/day - snowballs with large balance
  • anticheat is consumable (2 uses) - only item that can be re-bought
  • karikas (T3) is the only item that preserves a daily streak across missed days
  • reguleeritav_laud (T2) stacks with gaming_hiir: combined ×1.5 × ×1.25 = ×1.875