Overview
A text-based roguelike RPG Telegram bot built with Python 3.10 and python-telegram-bot. Players traverse procedurally selected dungeon rooms, fight monsters, collect items, pray to gods, and compete in leaderboards — all via Telegram chat buttons.
Roguelike RPG via Telegram
RogueBot is a fully-featured dungeon crawler game delivered entirely through a Telegram bot interface. Players interact by pressing reply-keyboard buttons — the bot generates story text, combat choices, item actions, and NPC dialogue as messages. There is no external UI; the game loop runs entirely in chat.
Dual Platform Support
The project ships with two separate entry points: main.py for Telegram (via python-telegram-bot) and main_vk.py for VKontakte. There is also an main_alice.py for Yandex Alice integration. All share the same game engine and user/room/item code.
Persistent State via Pickle
Each player's state (HP, MP, gold, inventory, current room, gods level, missions, buffs, pets, costume, variables) is serialized to a .usr file using Python pickle. A MongoDB database (via pymongo) stores global state: leaderboards, boss state, tournament data, and shared variables. Previously TinyDB, migrated to MongoDB in the EN modernization build.
Game Loop Summary
On /start, a new player character is created. The player enters the corridor and can open a door (random room), pray to a god, visit the shop, check inventory, or manage levels. Each room encounter resolves via text choices and dice rolls. Death records to the leaderboard; players can reborn. Bosses are shared global events updated by a background job.
python-telegram-bot
Telegram integration layer. Updated to PTB v13 — CommandHandler and MessageHandler now use (update, context) callback signature. Background tasks use JobQueue.run_repeating(). No deprecated @run_async or Job() constructor.
MongoDB (pymongo)
MongoDB database for global state. Stores leaderboards, boss HP, tournament brackets, and shared variables. Replaced TinyDB/mongothon. Requires mongod running locally. Uses native pymongo update_one(upsert=True) and aggregate().
Pickle User State
Each player serialised as a User object pickled to users/<uid>.usr. Supports VK users (prefixed vk) vs. Telegram users.
Botan Analytics
Optional Botan.io integration for tracking user events and generating referral links via /rate. Gracefully skipped if token absent.
Updates
Latest engineering-level maintenance changes made to stabilize and modernize the bot runtime.
Handler Signature: (bot, update) → (update, context)
All command and message handlers in main.py were rewritten to use the PTB v13 callback-style signature (update, context). The old positional (bot, update) pattern was removed from every handler function. context.bot is now used instead of the free bot parameter.
Job Queue API: Job() → JobQueue.run_repeating()
The legacy Job(divine_intervention, 3*60*60.0) + updater.job_queue.put() pattern was replaced with jq.run_repeating(divine_intervention, interval=3*60*60, first=10). All three background jobs (divine intervention, tournament update, queue reply) now use the modern PTB v13 API. The @run_async decorator was removed entirely — deprecated and unused in v13.
mongothon Removed — Dead Package
mongothon3 was a dead PyPI package that caused import failures on install. All three model files (leaderboard_model.py, variable_model.py, lists_model.py) were rewritten using plain pymongo with native find_one, update_one(upsert=True), and insert_one calls.
Death Aggregation: .group() → $group Pipeline
The deprecated MongoDB collection.group() call in leaderboard_model.py was replaced with a proper aggregate() pipeline using $match, $group, $sort, and $limit. This is the correct approach for pymongo 4.x.
Bug Fix: add_to_list() Wrong Variable
The original databasemanager/__init__.py called Lists.add_to_list(name, val, force) — passing the undefined local name val instead of the parameter value. This caused a silent NameError on all list additions. Fixed.
imp → importlibitemloader.py and roomloader.py — Replaced Deprecated imp
Both dynamic module loaders used imp.load_source() and imp.load_compiled(), which were deprecated in Python 3.4 and removed in Python 3.12. Replaced with importlib.machinery.SourceFileLoader / SourcelessFileLoader and spec_from_file_location + module_from_spec. Also replaced the deprecated room_loader.load_module() call with spec.loader.exec_module(mod).
logger.warn() → logger.warning()Python 3.12 Compatibility
logger.warn() was deprecated since Python 3.2 and removed in 3.12. All occurrences across main.py, itemloader.py, roomloader.py, and localizations/locale_manager.py were updated to logger.warning().
requirements.txt — Pinned to Modern Versions
Dead and incompatible packages removed: mongothon3, vk_api, codecov. Replaced with pinned working versions: python-telegram-bot==13.15, pymongo==4.6.1, tinydb==4.8.0, requests==2.31.0, tweepy==4.14.0, sortedcontainers==2.4.0.
New localizations/en.json + config.LANG = 'en'
A complete English locale file (en.json) was created with all 80+ game strings, UI labels, combat messages, god dialogues, shop receipts, and inventory labels. The config now defaults to LANG = 'en'. All inline hardcoded Russian strings throughout main.py, tornamentmanager.py, usermanager.py, and all 274 room/item/user files were translated to English.
Zero Syntax Errors Across All 274 Files
Every .py file in the project was verified with ast.parse() after translation. Four apostrophe-in-single-quoted-string errors discovered during translation were fixed. Final check: python3 -m py_compile on all core modules passed clean.
Architecture
How the modules fit together — from Telegram message receipt to game state change and reply dispatch.
Locale Strings
All game text is loaded from localizations/en.json via locale_manager.get(key). The config value LANG = 'en' routes to the English file. Buttons, death messages, shop text, and combat replies are all resolved at runtime from this single source — making the bot fully internationalizable without code changes.
Telegram Message Received
main.py receives a message via start_polling(). A reply() closure is constructed that enqueues outgoing messages into a deque. This prevents Telegram 429 rate-limit errors via a 35ms dispatch job.
Command or Message Routing
Slash commands (/start, /leaderboard, etc.) are routed via CommandHandler. All other text goes to msg() → usermanager.message() → user.message() state machine.
User State Machine
The User.message() method dispatches based on self.state: name, name_confirm, first_msg, corridor, pray, shop, inventory, room, dice, pet, reborned, or restart. Each state calls a definition method imported from user/ sub-modules.
Room Loading
rooms/roomloader.py dynamically imports the room Python module by name and level. Each room class has an enter() method and optionally make_damage(), escape(), won(), and item interaction hooks.
Item Loading
items/itemloader.py loads items from items/good/, items/bad/, items/loot/, items/neutral/, and items/pets/. Items define on_use(), on_fight(), on_corridor(), on_shop(), get_damage_bonus(), and stat fields.
State Persisted
After every operation, usermanager.save_user(usr) pickles the modified User back to disk. Global state (boss, leaderboard, tournaments, shared vars) is written to MongoDB via databasemanager using pymongo with upsert writes.
main.py
Rewritten for PTB v13 callback-style handlers ((update, context) signature). Replaced legacy Job()/run_async with JobQueue.run_repeating(). Manages message queue to avoid Telegram 429 errors.
usermanager.py
CRUD for User pickle files. Provides get_user, save_user, new_user, delete, random_user, and helper wrappers called by main.py handlers.
user/
User class mixin-imports: corridor, death, fight, gods, inventory, items, levels, meet, missions, money, pets, room, save, shop, stats. Each file is imported directly into the User class body.
rooms/roomloader.py
Resolves room by (level, type, name) → Python module path, imports it, and instantiates the room object. Supports default and vietnam zone packs.
items/itemloader.py
Loads all item classes, builds the shop pool (4 random items per visit), and provides load_item() and load_shop_items().
databasemanager/
Provides get_variable, set_variable, get_leaderboard, add_to_list, and leaderboard model for rooms and deaths.
bossmanager.py
Manages the shared world boss (one at a time). Boss respawns after 1 hour. Six possible bosses with varying HP pools (49k – 575k) and coin rewards.
tornamentmanager.py
Players sign up via the Coliseum room. When 10+ players queue, a tournament starts. Every 10 seconds damage is exchanged round-robin until one player remains. Winner receives 10–20k gold.
File Structure
274 source files across the project. Hover any file or folder for a description of its role.
All Commands
RogueBot registers 18 slash commands across three access levels: public, moderator, and admin.
Player Commands
Commands available to all players. No special permissions required.
Admin & Mod Commands
Privileged commands gated by ADMINS_IDS or MODERS_IDS environment variables.
Voting Commands
A built-in yes/no voting system with persistent tracking. Each user can vote once per question.
Combat System
Turn-based combat using keyboard button choices and a dice roll system for bonus damage.
Hit with your hand
Physical attack. Damage = user.get_damage() (base 10 + item bonuses + pet bonus) + get_damage_bonus() (dice roll / item procs). The most reliable option.
Conjure a blow
Magic attack. Costs 5 MP. Damage = get_mana_damage() (base 0 + staff/amulet bonuses). Low damage early; scales with mage items. Fails if MP < 5.
Use: Imagination
Triggers a dice roll. On a high roll, deals dice_result + damage_bonus // 2 damage. Adds creative chaos — the dice result is between 1 and 32 (DICE_MAX).
Use: <Item Name>
For any fightable=True item in inventory. Each item defines its own get_damage_bonus(user, reply) method with unique effects — the Scroll of a Thousand Lightnings does 1800+ dmg on wet enemies; the AK-47 grants flat bonus shots.
Escape
Attempt to flee. Some rooms allow escape; others trap the player. Escape success may depend on charisma, items, or room-specific logic. The Scroll of Flash guarantees escape.
Dice Roll (1–32)
A dice roll is requested by the game and the player must press the 🎲 Throw button. The result (1–32) modifies outcomes in combat, room events, and special encounters. Items like the Storyteller's Die grant bonus results. The result threshold DICE_MIDDLE = 16 separates success/fail in many checks. SMART_LEVEL = 10 and DUMMY_LEVEL = -10 gate intelligence-based checks.
Every 3 Hours — For All Players
A background job fires every 3 hours for all active Telegram users. Gods may grant: full MP restore (Buddha), a wine item (Jesus), full HP restore (Allah), a special room preview (Author), or the Iron Halo buff (God-Emperor). This replaces the prayed flag and delivers blessings passively.
Rooms
60+ room modules across two zone packs (default, vietnam), three room types (usual, special, monster), and four difficulty tiers.
Monsters
28 monster types across 3 difficulty tiers plus Vietnam zone enemies. HP and damage ranges shown.
| Name | HP | Damage Range | Notes |
|---|---|---|---|
| Rat | 20 | 2 – 4 | Basic starter enemy |
| Slug (Slime) | 30 | 0 – 3 | Almost harmless; drops slime |
| Flying Rat (Bat) | 15 | 5 – 7 | Fast; drops bat wing |
| Grass | 12 | 0 – 0 | Does zero damage; comedic |
| Minion | 23 | 1 – 4 | Banana makes him confused |
| Duck (Fire) | 10 | 5 – 7 | Fire duck; bread interacts |
| Spirit | 10 | 1 – 5 | Disembodied; low threat |
| Zombie | 20 | 0 – 2 | Slow; minimal damage |
| Sylphide | 25 | 7 – 14 | Air element; moderate |
| Werewolf | 35 | 15 – 23 | Highest-damage easy mob |
| Archmage (past) | 50 | 15 – 20 | Magic-heavy; tough for tier |
| Unnatural Seven-Legged | 50 | 15 – 30 | Dragon Slayer does extra dmg |
| Name | HP | Damage Range | Notes |
|---|---|---|---|
| Bear | 70 | 15 – 30 | Solid mid-tier fighter |
| Dipper | 60 | 3 – 8 | Gravity Falls reference; low dmg |
| Ghoul | 10 | 15 – 35 | Glass cannon; glass HP, nasty atk |
| Internet Troll | 100 | 10 – 20 | Tanky; charisma-based interactions |
| Knight | 170 | 30 – 40 | Drops helmet/sword/shield loot |
| Mimic (Box) | 50 | 50 – 50 | Always hits for exactly 50; surprise |
| Mirror | 1 | 0 – 0 | Special mechanic; reflects player |
| Nazgul | 100 | 10 – 15 | LotR enemy; steady damage |
| Promoter | 100 | 15 – 17 | Ad-man; charisma mechanics |
| Rabbit | 250 | 1 – 3 | Monty Python ref; huge HP, tiny atk |
| Mechano Turtle | 200 | 10 – 12 | Armored; high HP |
| Long-Haired Brunette | 120 | 16 – 18 | Chewbacca reference |
| Group of Bandits | 400 | 30 – 60 | High threat; multiple enemies |
| Name | HP | Damage Range | Notes |
|---|---|---|---|
| Basilisk | 135 | 16 – 25 | Drops basilisk tooth |
| Dark Lord | 1,000 | 20 – 25 | "Must be a fierce guy" — source code |
| Jason Voorhees | 100 | 15 – 30 | Horror icon encounter |
| Orc | 130 | 20 – 40 | Standard hard-tier brawler |
| Vaper | 80 | 10 – 20 | Vape-themed; special interactions |
| Name | HP | Damage Range | Notes |
|---|---|---|---|
| Bush (Soldier) | 280 | 20 – 35 | Guerrilla enemy; camouflaged |
| Hippie | 200 | 40 – 50 | Surprisingly dangerous |
| Vietnamese Army | 1,500 | 40 – 70 | Elite; highest base HP non-boss |
| Name | Type | Notes |
|---|---|---|
| Dragon | boss | Dragon Slayer does bonus damage |
| Doctor Who Monster | special | Laser Screwdriver interaction |
| Twi Monster | special | Uses twi_phrases taunts |
| Kids Monster | misc | Beginner-level encounter |
Items
70+ items across 5 categories. Sold in the Alchemist's Shop (4 random items per visit) or found as room loot.
World Bosses
Six global bosses managed by bossmanager.py. One is active at a time. Bosses respawn 1 hour after death. Killing a boss rewards the whole server with coins from its pool.
How World Bosses Work
The current boss is stored in TinyDB as a shared variable. Any player can encounter and damage the active boss. Boss HP persists across all players — collective effort is required to kill it. When it dies, its coin pool (randomized per spawn) is distributed. After 1 hour, a new random boss spawns.
Coliseum — Caesar's Tournament
Players sign up via the Coliseum room (caesar.py). When the queue reaches 10 players, tornamentmanager.start_tornament() fires. Every 10 seconds, all players simultaneously deal their queued damage to the next player in a round-robin. Dead players are eliminated. The last survivor wins 10,000–20,000 gold from Caesar. Attacks are single-use per cycle — players who haven't attacked yet do 0 damage that round.
Gods System
Five gods can be prayed to once per corridor visit. Accumulated devotion unlocks blessings — but abandoning a god triggers wrath.
How Praying Works
From the corridor, players tap 🙏 Pray to God. They choose from their five gods. Each prayer increments gods_level[god_num]. At GOD_LEVEL = 3 threshold, a god_love() blessing fires. Praying too fast triggers the "Not so often" cooldown message. Switching to a different god after committing resets all levels and triggers evilgod() wrath.
— nothing bad happens (peaceful)
Zones & Levels
Two room packs (zones) with a multi-floor dungeon level system. Players traverse floors and can travel up/down between discovered levels.
Default Zone
The main dungeon. 4 difficulty tiers: easy, medium, hard, expert. Contains 40+ usual rooms, 14 special rooms, and 28 monster types. All players start here in the easy level.
Vietnam Zone
Unlockable alternate zone with a Vietnam War theme. New monster types (Bush Soldier, Hippie, Vietnamese Army), Vietnam-specific missions (Caravan, Leprechaun, Main mission), and zone-exclusive rooms. Accessed by changing rooms_pack.
Multi-Floor Dungeon
Players start on the easy floor. As they progress, new levels unlock: easy → medium → hard → expert. The corridor shows ⬆ Go Upstairs and ⬇ Go Down buttons when adjacent floors are available. When changing floors, the bot displays a scraped list of room names found on that floor (a "someone scratched it on the wall" narrative). Each floor has its own monster pool weighted to its difficulty.
Three Concurrent Missions
On character creation, three missions are initialised: main (story), tips (30-room tutorial path), and caravan (20-room side quest). Missions are stored as a stack per player. get_last_mission() returns the active one; pop_mission() completes it. Mission rooms are gated and progress through multi-part scripted encounters in rooms/vietnam/missions/.
Deployment
Everything you need to run RogueBot-EN from scratch on a fresh Python 3.10+ environment.
Python 3.10+
The bot uses Python 3.10+ syntax and type constructs. Tested on 3.10 and 3.11. The importlib.machinery changes and logger.warning() fixes ensure compatibility up to Python 3.12+.
MongoDB
A running local MongoDB instance is required. The bot connects to the rogbot database automatically on first run. No schema setup needed — collections are created on first write. Install via apt install mongodb or brew.
Telegram Bot Token
Create a bot via @BotFather on Telegram to get your TELEGRAM_TOKEN. Set in config.py before running. Optionally set ADMINS_IDS and MODERS_IDS as lists of Telegram user ID strings.
pip packages
All pinned to tested versions. Install with pip install -r requirements.txt. On system Python (Kali/Debian) add --break-system-packages flag. Main deps: python-telegram-bot==13.15, pymongo==4.6.1.
Install dependencies
pip install -r requirements.txt — installs all pinned packages. On Kali NetHunter: pip install -r requirements.txt --break-system-packages
Start MongoDB
mongod --dbpath ./data/db & — or use the system service: sudo systemctl start mongod. The database will be auto-created as rogbot.
Edit config.py
Open config.py and set TELEGRAM_TOKEN = 'your_token_here'. Optionally add your Telegram user ID to MODERS_IDS and ADMINS_IDS for admin commands. Leave Twitter and Botan fields commented out if unused.
Create users directory
mkdir -p users — The bot does this automatically, but creating it manually avoids the first-run log message. Pickle user files will be saved here as users/<uid>.usr.
Run the bot
python main.py — The bot starts polling. You should see "Bot officially started!" in the logs. Send /start to your bot on Telegram to begin playing.
Terminal-First Environment
The bot is fully terminal-compatible — no GUI required. MongoDB can be run via mongod in the background. Use tmux or screen to keep the bot session alive. If MongoDB is unavailable, install via apt install -y mongodb or use a remote MongoDB Atlas URI by patching the MongoClient() call in databasemanager/__init__.py.
Changelog
Full audit of every change made to produce RogueBot-EN from the original 10-year-old Russian codebase.
| File | Issue | Fix |
|---|---|---|
| main.py | PTB v12→v13: (bot, update) handler signature | All handlers → (update, context) |
| main.py | Deprecated @run_async decorator | Removed entirely |
| main.py | Legacy Job(fn, interval) + .put() | → jq.run_repeating(fn, interval) |
| main.py | Old MessageHandler(False, msg) | → Filters.text & ~Filters.command |
| itemloader.py | imp.load_source() — removed in Python 3.12 | → importlib.machinery.SourceFileLoader |
| roomloader.py | imp.load_module() + SourceFileLoader deprecation | → spec_from_file_location + exec_module |
| databasemanager/ | mongothon3 uninstallable dead package | Rewritten with plain pymongo |
| leaderboard_model.py | Deprecated collection.group() | → aggregate() pipeline |
| __init__.py (db) | add_to_list(name, val) — wrong variable name | Fixed: val → value |
| All .py files | logger.warn() removed in Python 3.12 | → logger.warning() |
| Package | Old | New | Reason |
|---|---|---|---|
| python-telegram-bot | unpinned | 13.15 | Latest stable v13 with context callbacks |
| pymongo | via mongothon3 | 4.6.1 | Direct modern driver; mongothon removed |
| tinydb | unpinned | 4.8.0 | Kept as optional; pinned for compat |
| requests | unpinned | 2.31.0 | Pinned for security |
| tweepy | unpinned | 4.14.0 | Modern Twitter v2 API support |
| mongothon3 | required | REMOVED | Dead package, import error on install |
| vk_api | required | REMOVED | VK integration not in EN build |
| codecov | required | REMOVED | CI tool, not a runtime dependency |
| File | Description |
|---|---|
| config.py | Configuration template with all keys documented |
| localizations/en.json | Full English locale — 80+ game string keys |
| README_EN.md | English deployment README with setup steps |
| tests.py | Basic smoke tests for database variable and list operations |
274 Files — Inline Strings, Comments, Button Labels
Every Python file had Russian inline strings, button labels, story text, NPC dialogue, monster taunts, and code comments translated to English. This includes all 41 usual rooms, 14 special rooms, 28 monster rooms, 6 boss rooms, all mission rooms, 70+ item files, all 14 user definition files, all 3 databasemanager models, all utility files, and the main entry point. The localization JSON captures the 80+ shared UI strings; the remaining room-specific narrative is embedded directly in each module.