Template

Text Game Engine (RPG, Economy, Casino)

A text game inside your bot. Players take jobs and earn salaries in real time, spend money in a shop, try a dice casino and compete on a shared leaderboard. The owner gets a private admin panel.

Who it's for: For bot owners who want a game in their chat, such as a city or farm life game, a tycoon or an RPG with a shop. It saves each player's progress and can grow from a few items to hundreds.

  1. /start
  2. šŸ™ Pocket City — Anna šŸ’° $1,000 šŸ’¼ no job šŸŖ Business income: $0/month 1 game month = 10 min
    šŸ’¼ WorkšŸ›’ ShopšŸŽ² Casino
    šŸ† Top
  3. šŸŽ² Casino
  4. šŸŽ² Roll higher than the house to win Ɨ2 (a tie loses). Bet: $100. You have $1,000.
    Bet $100šŸŽ² RollšŸ  Menu
  5. šŸŽ² Roll
  6. šŸŽ² 5 vs 3 — you win $100!
    šŸŽ² RollšŸ  Menu
A player opens the game and tries the casino

How it works

  • /start → set game_tap to "__open" → the Game Engine code step runs
  • The engine loads the player (contact OBJECT game_player) and shared state (bot OBJECT game_world) through ctx.chatState.atomicUpdate, applies the tapped command, updates the leaderboard, and returns the screen text plus a JSON array of button labels
  • Game Screen shows the text with those labels as dynamic buttons; a tap writes the label into game_tap and loops back to the engine
  • The engine keeps a label → command map for the buttons on screen, so an old or unknown label simply opens the main screen

Setup requirements

  • Put your own Telegram user id into the application variable game_admin_id (it starts as 0 = nobody) to unlock the admin panel.
  • Publish the bot, then send /start in Telegram — the game state is saved only on a published version.
  • Tune prices, jobs, items and texts in rules.ts inside the Game Engine step.

Details

Good to know

  • This is the pattern for stateful games: ONE engine CUSTOM_CODE action + ONE message with dynamic buttons + ONE loop link. Do not build a block per screen, per item or per job — that does not scale past a handful of screens and every change touches the graph.
  • Split the code into files: index.ts (entry, state reads/writes), rules.ts (everything the owner tunes: prices, jobs, items, texts), game.ts (what a tap does), screens.ts (text + buttons per screen), state.ts, types.ts. Imports are relative ('./rules'). Keep user-facing texts in rules.ts, in every language the bot speaks.
  • Player state lives in a contact OBJECT variable and shared state (leaderboard, clans, settings) in a bot OBJECT variable, written ONLY with ctx.chatState.atomicUpdate — it retries on conflict, so updaters must be synchronous and pure: draw random numbers before calling it. chatState reads the DEPLOYED version: publish before testing in Telegram.
  • Time-based mechanics (salary, hunger, energy) are computed lazily on each tap from stored timestamps — no scheduler needed. Cap how much offline time counts.
  • Button labels are what the user taps; map each label to a command in the player state when rendering and resolve the tapped label through that map. Keep labels unique per screen.
  • To add a feature later, edit one file with apply_actions update_custom_code_file — never resend the whole action. Code that does not compile is rejected at apply time.
  • The admin panel is shown only when the player's Telegram id equals the application variable game_admin_id; it is 0 (nobody) until the owner sets it.
  • Admin actions on ANOTHER player (give or take money, reset) need no live bot: parse "/give @user 100" in the engine, then const target = await ctx.contacts.findByUsername('@user') — { contactId, platformId }, or null when that person never wrote to this bot (tell the admin so). A balance kept in its own NUMBER contact variable changes with await ctx.contacts.increment(target.contactId, 'balance', 100). This example keeps money inside the game_player object, which ctx.chatState can change only for the CURRENT player — so the admin adds it to game_world.grants[target.contactId] inside the world atomicUpdate, and each player's engine moves their grant into their balance on their next tap.

Common questions

  • What is the game about — city life, farm, fantasy RPG, business tycoon, casino?
  • Which mechanics matter first: money and jobs, shop, casino, clans and territories, needs like food and health?
  • Should game time run faster than real time (for example 1 game month = 3 real minutes)?
  • Who should be able to change prices and settings in the admin panel?

Keep in mind

  • Do not build one block per screen, item or job; use the engine pattern.
  • Do not keep game state in many separate SET_VARIABLE writes; keep it in one OBJECT per player and one shared OBJECT, updated atomically.
  • Do not ship a placeholder screen ("coming soon") for a mechanic the user asked for — build it, or say plainly that it is not built yet.
  • Do not call Math.random() or any side effect inside an atomicUpdate updater; it may run more than once.
  • Do not show a setting in the admin panel that the game does not actually use.

The flow behind this bot

This is the whole flow you get. Once you add the template, you can change any message, button or step.

Ready to build on this?

Clone the template into your workspace and edit every message, button and action — nothing is locked.