9.7 KiB
TipiLAN Bot - Developer Reference
File Structure
| File | Purpose |
|---|---|
bot.py |
All Discord commands, views (UI components), event handlers, reminder system |
economy.py |
All economy logic, data model, constants (SHOP, COOLDOWNS, LEVEL_ROLES, etc.) |
pb_client.py |
Async PocketBase REST client - auth token cache, CRUD on economy_users collection |
strings.py |
Single source of truth for all user-facing text. Edit here to change any message. |
sheets.py |
Google Sheets integration (member sync) |
member_sync.py |
Birthday/member sync background task |
config.py |
Environment variables (TOKEN, GUILD_ID, PB_URL, etc.) |
migrate_to_pb.py |
One-time utility: migrate data/economy.json → PocketBase |
add_stats_fields.py |
Schema migration: add new fields to economy_users PocketBase collection |
Adding a New Economy Command
Checklist - do all of these, in order:
economy.py- add thedo_<cmd>async function with cooldown check, logic,_commit, and_txnloggingeconomy.py- add the cooldown toCOOLDOWNSdict if it has oneeconomy.py- add the EXP reward toEXP_REWARDSdict 3a. PocketBase - if the function stores new fields, add them as columns viapython scripts/add_stats_fields.py(or manually in the PB admin UI athttp://127.0.0.1:8090/_/). Fields not in the PB schema are silently dropped on PATCH.strings.pyCMD- add the slash command descriptionstrings.pyOPT- add any parameter descriptionsstrings.pyTITLE- add embed title(s) for success/fail statesstrings.pyERR- add any error messages (banned, cooldown usesCD_MSG, jailed usesCD_MSG["jailed"])strings.pyCD_MSG- add cooldown message if command has a cooldownstrings.pyHELP_CATEGORIES["tipibot"]["fields"]- add the command to the help embedbot.py- implement thecmd_<name>function, handle allres["reason"]casesbot.py- call_maybe_remindif the command has a cooldown and reminders make sensebot.py- call_award_exp(interaction, economy.EXP_REWARDS["<cmd>"])on successstrings.pyREMINDER_OPTS- add a reminder option if the command needs onebot.py_maybe_remind- if the command has an item-modified cooldown, add anelifbranch
Adding a New Shop Item
Checklist:
economy.pySHOP- add the item dict{name, emoji, cost, description: strings.ITEM_DESCRIPTIONS["key"]}economy.pySHOP_TIERS- add the key to the correct tier list (1/2/3)economy.pySHOP_LEVEL_REQ- add minimum level if it is T2 (≥10) or T3 (≥20)strings.pyITEM_DESCRIPTIONS- add the item description (Estonian flavour + English effect)strings.pyHELP_CATEGORIES["shop"]["fields"]- add display entry (sorted by cost)- If the item modifies a cooldown:
economy.py- add theif "item" in user["items"]branch in the relevantdo_<cmd>functionbot.py_maybe_remind- addelif cmd == "<cmd>" and "<item>" in items:branch with the new delaybot.pycmd_cooldowns- add the item annotation to the relevant status line
Adding a New Level Role
economy.pyLEVEL_ROLES- add(min_level, "RoleName")in descending level order (highest first)bot.py_ensure_level_role- no changes needed (usesLEVEL_ROLESdynamically)- Run
/economysetupin the server to create the role and set its position
Adding a New Admin Command
strings.pyCMD- add"[Admin] ..."descriptionstrings.pyHELP_CATEGORIES["admin"]["fields"]- add the entrybot.py- add@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). pb_client.py owns all reads/writes. Each do_* function in 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 | 10–25% of target | 45% success (60% w/ jellyfin); fail = fine; cannot rob TipiBOT |
/heist |
4h personal + 1h global | 20–55% of house / n players | solo allowed, max 8; 35%+5%/player success (cap 65%); fail = 3h jail + ~15% balance fine |
/slots |
- | varies | pair=+0.5× bet; triple tiered: heart×4, fire×5, troll×7, cry×10, skull×15, karikas×25 (jackpot); ×1.5 w/ monitor_360; miss=lose bet; house edge ~5% |
/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⬡)
karikasitem: streak survives missed days
Jail
- Normal duration: 30 minutes (
JAIL_DURATION) - Heist fail duration: 3 hours (
HEIST_JAIL) + fine 15% of balance (min 150⨡, max 1000⨡) 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.
EXP Rewards (from EXP_REWARDS in economy.py)
EXP is awarded on every successful command use. Level formula: floor(sqrt(exp / 10)), so Level 5 = 250 EXP, Level 10 = 1000, Level 20 = 4000, Level 30 = 9000.
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 economy.py controls per-item lock thresholds.
strings.py Organisation
| Section | Dict | Usage in bot.py |
|---|---|---|
| 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 |
| Banned message | MSG_BANNED |
All banned checks |
| Reminder options | REMINDER_OPTS |
RemindersSelect dropdown |
| Slots outcomes | SLOTS_TIERS["tier"] → (title, color) |
cmd_slots |
| 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 |
| Shop UI | SHOP_UI["key"] |
_shop_embed |
| Item descriptions | ITEM_DESCRIPTIONS["item_key"] |
economy.SHOP[key]["description"] |
Constants Location Quick-Reference
| Constant | File | Description |
|---|---|---|
SHOP |
economy.py |
All shop items (name, emoji, cost, description) |
SHOP_TIERS |
economy.py |
Which items are in T1/T2/T3 |
SHOP_LEVEL_REQ |
economy.py |
Min level per item |
COOLDOWNS |
economy.py |
Base cooldown per command |
JAIL_DURATION |
economy.py |
How long jail lasts |
LEVEL_ROLES |
economy.py |
[(min_level, "RoleName"), ...] highest first |
ECONOMY_ROLE |
economy.py |
Name of the base economy participation role |
EXP_REWARDS |
economy.py |
EXP per command |
HOUSE_ID |
economy.py |
Bot's user ID (house account for /rob) |
MIN_BAIL |
economy.py |
Minimum bail payment (350⬡) |
COIN |
economy.py |
The coin emoji string |
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 investmentgaming_laptop(1500⬡) 5% interest, capped 500⬡/day - snowballs with large balanceanticheatis consumable (2 uses) - only item that can be re-boughtkarikas(T3) is the only item that preserves a daily streak across missed daysreguleeritav_laud(T2) stacks withgaming_hiir: combined ×1.5 × ×1.25 = ×1.875