Files
tipibot/docs/DEV_NOTES.md
2026-03-20 17:35:35 +02:00

195 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.) |
| `scripts/migrate_to_pb.py` | One-time utility: migrate `data/economy.json` → PocketBase |
---
## Adding a New Economy Command
Checklist - do all of these, in order:
1. **`economy.py`** - add the `do_<cmd>` async function with cooldown check, logic, `_commit`, and `_txn` logging
2. **`economy.py`** - add the cooldown to `COOLDOWNS` dict if it has one
3. **`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. **`bot.py`** - implement the `cmd_<name>` function, handle all `res["reason"]` cases
11. **`bot.py`** - call `_maybe_remind` if the command has a cooldown and reminders make sense
12. **`bot.py`** - call `_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
---
## Adding a New Shop Item
Checklist:
1. **`economy.py` `SHOP`** - add the item dict `{name, emoji, cost, description: strings.ITEM_DESCRIPTIONS["key"]}`
2. **`economy.py` `SHOP_TIERS`** - add the key to the correct tier list (1/2/3)
3. **`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:
- **`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
- **`bot.py` `cmd_cooldowns`** - add the item annotation to the relevant status line
---
## Adding a New Level Role
1. **`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. **`bot.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 | 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 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 |
| Maintenance mode | `MSG_MAINTENANCE` | Shown when `_PAUSED=True` in bot.py (toggled by `/pause`) |
| 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 |
| `_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