IdleRPG-style IRC game: a Node.js bot runs timers, penalties, and quests in your channel and persists state to SQLite. A PHP dashboard under public/ reads the same database for a live leaderboard and player API—no Node runtime on the web server.
| Live demo | idlerpg.netirc.eu |
| Concept | IdleRPG · implementations this work echoes: falsovsky/idlerpg, idlerpg-site-ng |
Further reading: DEPLOY.md (hosting, SQLite permissions, troubleshooting) · SECURITY.md · LICENSE
| Layer | Responsibility |
|---|---|
IRC bot (src/) |
Normal client connection (not server / P10). Registration, login, idle ticks, channel penalties, optional quests, lucky hour, Hand of God, alignment, charms, season pass, world boss, guild/relic/prestige systems. |
Web UI (public/) |
index.php leaderboard, detail pane, rules, bot online/offline banner. public/.htaccess: HTTPS (non-local), security headers. |
| HTTP API | Read-only JSON: /api/health.php, /api/leaderboard.php, /api/player.php (?name=…), /api/chronicle.php (limit, kind, search, since, until). |
| Data | Single SQLite file (e.g. data/idlerpg.db). The bot and site.config.php must use the same path. |
| Component | Version / notes |
|---|---|
| Runtime (bot) | Node.js 20+, npm |
| Runtime (site) | PHP 8+ with PDO and pdo_sqlite |
| HTTP server | Apache: DocumentRoot → public/, AllowOverride for .htaccess. Or Nginx with equivalent TLS and routing. |
git clone https://github.com/NetIRC/idlerpg.git
cd idlerpgnpm install
cp .env.example .envEdit .env: IRC host, channel, IRPG_DB_PATH, and any network options (see comments in .env.example).
npm startLinux / macOS — background process (optional):
chmod +x scripts/idlerpg.sh
./scripts/idlerpg.sh start # logs: data/bot.log
./scripts/idlerpg.sh stop
./scripts/idlerpg.sh restart
./scripts/idlerpg.sh start -f # foreground for debuggingcp site.config.php.example site.config.phpEdit site.config.php:
db_path: same database file asIRPG_DB_PATHin.env(absolute path recommended on servers).case_sensitive_names: must matchIRPG_CASE_SENSITIVE_NAMESin.env.- If
site.config.phpcannot live next topublic/, copypublic/includes/local-root.php.exampletolocal-root.phpand return the directory that containssite.config.php.
Point the virtual host document root at public/. Enable mod_rewrite and mod_headers so public/.htaccess applies.
| Check | Expected result |
|---|---|
GET /api/health.php |
JSON with "ok": true |
GET /api/leaderboard.php |
JSON including a players array |
GET /api/chronicle.php |
JSON with an events array (realm log; default limit matches IRC !chronicle) |
| Concern | File |
|---|---|
| Bot: IRC, database path, timers, quests, lucky hour, owner account, … | .env.example → copy to .env (the real .env is not in the repo). |
Site: database path, debug |
site.config.php (copy from site.config.php.example) |
Optional AI lore/banter (!lore / LORE) |
Set IRPG_AI_* in .env (IRPG_AI_ENABLED=true, Groq key/model/timeout/cooldowns). Default model is llama-3.1-8b-instant for low-cost/free-friendly usage. |
Release branding: IDLE_RPG_VERSION in src/config.ts drives CTCP VERSION, channel !ping, and the default IRPG_IRC_GECOS real name. Keep it in step with .env / .env.example and bump package.json version when you tag a release.
Keep your AI API key only in your local .env (gitignored). Preferred variable is IRPG_AI_GROQ_API_KEY (or GROQ_API_KEY); never paste or commit real API keys to the repository.
For production, set debug ⇒ false in site.config.php. Do not place the SQLite file under the public document root.
Game channel is IRPG_IRC_CHANNEL (default #IdleRPG). For REGISTER and LOGIN, your IRC nick must be in that channel while you message the bot.
Private commands are rate-limited per nick via IRPG_PM_FLOOD_MAX and IRPG_PM_FLOOD_WINDOW_MS (see .env.example; set max to 0 to disable). CTCP VERSION does not count toward that limit.
Durations (timers, lucky hour, penalties): the bot and PHP API use the same human-readable rules: under 1 minute as 45s; under 1 hour as 13m 5s or 10m; under 1 day as 14h 18m 29s; 1+ days as 2d 14h 18m 29s. Chronicle / site “time ago” uses compact s / m / h / d.
If IRPG_IRC_CHAN_BANTER_MS is set > 0, the bot also posts occasional ambient lines and contextual tips (REGISTER / LOGIN / ! commands you can actually use right then). Set to 0 to disable.
If IRPG_IRC_TOPIC_ENABLED=true, the bot updates the channel TOPIC only on key state changes (season rollover or world-boss state change) using a low-noise format. The bot needs topic privileges (+o / +h depending on network mode policy).
| Topic | Detail |
|---|---|
| Goal | Gain levels by idling: your next level timer (next_seconds) counts down while you are logged in and your nick is present in the game channel. |
| Silence | Staying quiet in channel is the main loop; the bot ticks once per IRPG_SELF_CLOCK_MS (default 1s). |
| Talking in channel | Normal channel lines add a time penalty when you are logged in: scales roughly with message length and level (via penttl / rpbase). You get a NOTICE with the penalty amount. |
! commands |
Recognized lines that start with ! (commands below) do not add that speaking penalty. Unrecognized !foo still counts as normal speech. |
| Alignment | n / g / e affects idle rate slightly and duel power; Hand of God events can nudge alignment. |
| Charm / trinket | Milestone levels may grant a cosmetic trinket (~0.3% faster idle while set). |
| Quests | If enabled, party quests start automatically when enough heroes are online (see IRPG_QUEST_* in .env). |
| Lucky hour | If enabled, random windows where Hand-of-God odds are boosted. |
| V3 daily trial | Optional shard event (IRPG_V3_*): one online hero gets a timed challenge with bounded timer reward/penalty and chronicle log. |
| V3 bounty board | Optional daily idle contract (!bounty): stay quiet/present to fill progress and auto-claim one timer reduction when target is reached. |
| V3 season pass | Optional monthly season ladder with separate seasonal XP/tier progression (!season) and no reset of base hero progression. |
Season numbering is anchored by IRPG_V3_SEASON_EPOCH_SEC (Unix seconds) plus IRPG_V3_SEASON_LENGTH_DAYS, so you can keep human-friendly season counts across shards. |
| V3 world boss | Optional cooperative periodic event: online idlers contribute passive damage and share timer reward on kill (!boss). |
| V3 guilds / relics / prestige | Optional social and meta loops: guild tags + bonus (!guild), one active relic perk (!relic), rebirth for soft permanent bonus (!prestige). |
| V3 idle streak | Optional reward loop: uninterrupted in-channel idle grants periodic timer reductions. In strict mode, any channel activity (including ! commands) breaks the streak; penalties/combat outcomes also reset it. |
| Level-up action window | After a level-up, the hero gets a 5-minute hint window (notice) suggesting currently available !duel / !omen / !gauntlet; one reminder appears at half-window. This is informational only and does not bypass cooldowns. |
| REGISTER | PM the bot: one-word password; class can be multiple words. Character name must be unique in the database. |
| LOGIN / LOGOUT | LOGIN / LOGOUT via PM. LOGOUT applies a logout penalty (timer increase). |
| PART (leave channel) while logged in | Suspended session: online clears and PART penalty applies; session_open stays 1. Rejoin the channel → session resumes (no second LOGIN). Idle time did not advance while you were gone. |
| QUIT (leave IRC) while logged in | Session ends (session_open = 0); QUIT penalty; you must LOGIN again next time. |
| KICK | Logged-out + kick penalty (strong). |
| NICK change while logged in | Penalty + DB irc_nick updated to the new nick. |
| Not in channel | If you are logged in but your nick is not in the game channel, idle time does not advance for that character. |
| Bot offline | Timers do not advance while the bot is disconnected. |
| Password recovery | No self-service reset: ask a game admin (see Staff). |
| Privacy | Do not paste passwords in the channel; use PM only. |
The site sidebar Rules panel is a short summary; this section matches the bot behaviour in code.
All commands are case-insensitive on the !word token (e.g. !HELP). Optional arguments are in [brackets]; literals in ⟨angle brackets⟩.
| Command | Arguments | Description |
|---|---|---|
| !help | — | Short help (registration / login); use !cmds for the full channel list. |
| !cmds | — | Longer list of channel commands. Alias: !commands. |
| !rules | — | One-line summary (idle, penalties, PM register/login, quests/lucky). |
| !ping | — | Bot check (pong — IdleRPG V3.0 NetIRC). |
| !top | — | Top 3 heroes (name, level, class, time to level). |
| !stats | [character name] |
Your stats if omitted; otherwise lookup by character name (may be case-sensitive; see IRPG_CASE_SENSITIVE_NAMES). |
| !time | [character name] |
Time to next level (self or named character). |
| !whoami | — | Logged-in identity + cooldown summary (omen/duel/gauntlet/daily trial) and, when active, remaining level-up hint window time. |
| !records | — | Realm records / highs (same source as the site). |
| !quest | — | Quest status line (team quest window, etc.). |
| !bounty | — | Daily idle contract progress/reward status (V3 optional). Shows progress, reward size, and quiet-gate countdown when active. |
| !season | — | Current season label, your season XP/tier, and time left before rollover. |
| !boss | — | Current world boss status (HP/time) or next spawn timer. |
| !guild | [status/create/join/leave ...] |
Minimal clan system: create tag/name, join/leave guild, and status. |
| !relic | [status/list/equip key] |
Show/equip your single active relic perk. |
| !prestige | [now] |
Show prestige rank/bonus; with now, rebirth at min level and gain permanent soft bonus. |
| !realm | — | One-line realm pulse: heroes online, quest, lucky hour, peak level. Alias: !pulse. |
| !chronicle | — | Recent realm events on one IRC line (newest 15 events, same default count as the web feed; ~480 chars max). |
| !omen | — | Personal omen (~8h cooldown); must be logged in and in channel; can change your timer (boon/curse/rare). |
| !duel | ⟨irc_nick⟩ |
Arena PvP vs another logged-in hero in channel; ±11 levels; initiator cooldown ~5h; same pair ~20h; timer shifts + flair; medals possible. |
| !gauntlet | — | PvE shadow trial; ~16h cooldown after a run; timer swing + medals at milestones. |
| !lore | [topic] |
Optional AI flavor line (Groq) with cooldown and local fallback. Replies show AI lore: on successful API output, otherwise AI unavailable... + local lore fallback. When AI is enabled, ambient channel banter may also become hero-aware. |
| !medals | [character name] |
Medal rack + duel/gauntlet win counts (self if omitted; otherwise by character look‑up). Alias: !badges. |
Send as PM (private message) to the bot nick. For REGISTER, LOGIN, and combat-read commands, you must be in the game channel on that IRC session (the bot checks namesInChannel).
| Command | Arguments | Description |
|---|---|---|
| HELP | — | Page 1: register/login syntax, recovery note. |
| CMDS | — | Page 2: extra commands + ADMIN summary. Aliases: COMMANDS. |
| REGISTER | Name Password Class… |
Create account; password = one word; class phrase allowed. |
| LOGIN | Name Password |
Start session (must be in game channel). |
| LOGOUT | — | End session + logout penalty. |
| PING | — | Bot check (same build id as !ping / CTCP VERSION). |
| STATS | [name] |
Same idea as !stats. |
| TOP | — | Top 5 (PM uses wider list than !top). |
| WHOAMI | — | Same as !whoami (includes cooldown summary and level-up hint window status when active). |
| TIME | [name] |
Same as !time. |
| RECORDS | — | Same as !records. |
| QUEST | — | Same as !quest. |
| BOUNTY | — | Same as !bounty (daily contract status). |
| SEASON | — | Same as !season. |
| BOSS | — | Same as !boss. |
| GUILD | status/create/join/leave ... |
Same as !guild. |
| RELIC | status/list/equip key |
Same as !relic. |
| PRESTIGE | [now] |
Same as !prestige. |
| REALM / PULSE | — | Same as !realm. |
| CHRONICLE | — | Same as !chronicle. |
| OMEN | — | Same as !omen (must be in game channel). |
| DUEL | irc_nick |
Same rules as !duel (must be in game channel). |
| GAUNTLET | — | Same as !gauntlet (must be in game channel). |
| LORE | [topic] |
Optional AI lore line via Groq (assistive flavor only, no gameplay impact). Same source labels as !lore (AI lore: vs AI unavailable... fallback). |
| MEDALS / BADGES | [name] |
Same as !medals. |
| ADMIN | subcommand … |
Staff only. Try ADMIN HELP. |
When you join the game channel, the bot sends a throttled onboarding NOTICE: if your prior session was suspended after PART, it confirms automatic resume; if your nick is registered but logged out, it prompts LOGIN; otherwise it shows a welcome with REGISTER syntax.
Who may use ADMIN:
| Eligibility | Detail |
|---|---|
IRPG_ADMIN_IRC_NICKS |
Comma-separated IRC nicks in .env (see .env.example): can ADMIN by PM without a logged-in game character. Status prefixes (~&@%+) are ignored when matching. |
| Logged-out / online | A player row whose irc_nick matches yours may ADMIN if is_admin is set or the character name matches IRPG_OWNER_ACCOUNT — even when online = 0 (e.g. after LOGOUT), as long as the nick is still stored on that row. |
| In channel | Not required for ADMIN itself (PM only). Subcommands that need channel state (STARTQUEST, etc.) still use the bot’s live presence list. |
Message the bot in PM: ADMIN HELP
| ADMIN subcommand | Syntax | Effect |
|---|---|---|
| FORCELOGOUT | ADMIN FORCELOGOUT CharacterName |
Clears online session for that character. |
| DELETEUSER | ADMIN DELETEUSER CharacterName |
Permanently deletes the character from players, their player_medals, and clears realm peak metadata if it was theirs. Irreversible. Alias: ADMIN DELETE (same arguments). |
| RESETPASS | ADMIN RESETPASS CharacterName newpassword |
Sets a new password (max 128 chars), clears session; player must LOGIN again. Alias: SETPASS. |
| STARTQUEST | ADMIN STARTQUEST |
Force-start a quest (if configuration allows and enough players are in channel). |
| LUCKY | ADMIN LUCKY |
Broadcast staff lucky hour window. |
| SAY | ADMIN SAY …text… |
Bot sends the text as a normal message in the game channel. |
| SHUTDOWN | ADMIN SHUTDOWN optional note |
Writes admin_shutdown to the realm chronicle, posts a short line in channel, sends QUIT, clears bot heartbeat, then exits the Node process (process.exit(0)). Restart the bot on the host (e.g. ./scripts/idlerpg.sh start, systemd, or your supervisor). Optional words after SHUTDOWN are stored in the chronicle detail for logging. Does not stop PHP or your web server — only the bot process. |
Security: treat IRPG_ADMIN_IRC_NICKS and owner account like root access. Do not publish full admin syntax publicly for password resets; players should ask staff in channel.
npm run dev:bot # bot with file watcherGame time is stored in SQLite (next_seconds). Timers do not advance while the bot is disconnected.
| Path | Purpose |
|---|---|
web/ |
React + Vite front-end for local experiments: cd web && npm install && npm run dev. Not required for the PHP dashboard. |
npm run api |
Express API for local development; production can rely on public/api/*.php only. |
MIT. Original IdleRPG concept: idlerpg.net.