A feature-rich Discord bot for organizing Counter-Strike draft matches with automated team selection, statistics tracking, and voice channel management.
A simple Discord bot for organizing CS2 inhouse matches with:
- Automated queue, readycheck, and captain draft flow
- Player stats tracking (wins, captain picks, first/last pick counts)
- Pick turn breakdowns with average pick round stats
- Elo ratings with leaderboards
- Winrate comparisons between players
- Optional automatic voice channel moves
- Opt-out controls for captain selection
Please don't let this ruin your friendships too much. :3
- Python 3.10 or higher
- Discord Bot Token (Create one here)
- Discord Server with voice channels
-
Configure voice channels (Optional)
Edit
main.pylines 24-27 with your Discord voice channel IDs:TEAM1_VOICE_CHANNEL_ID = <id> TEAM2_VOICE_CHANNEL_ID = <id> VOICE_LOBBY_CHANNEL_ID = <id>
To get channel IDs: Enable Developer Mode in Discord → Right-click channel → Copy ID
Key settings in main.py:
QUEUE_SIZE = 10 # Players needed for a draft
READYCHECK_SECONDS = 120 # Readycheck timeout (2 minutes)
PICK_TIMEOUT_SECONDS = 45 # Captain pick timeout
AUTO_VOICE_CHANNELS = True # Enable automatic voice channel moves
EMBED_COLOR_PRIMARY = 0x29377e # Embed color (hex)| Command | Aliases | Description |
|---|---|---|
/add |
!add, !dad, !ad, etc. |
Join the draft queue |
/rm |
!rm, !remove |
Leave the queue |
/r |
!r, !ready |
Ready up during readycheck (or click button) |
/pstats [user] |
!pstats |
View player statistics and rankings |
/pickstats [user] |
!pickstats |
View pick turn counts and average pick round |
/winrate <user> |
!winrate, !wr |
Compare your winrate against another player |
/elo [user] |
!elo |
View Elo rating and ranking |
/dstatus |
!dstatus |
Check current queue/draft status |
/pick <number> |
!pick, !p |
Captain: Pick a player by number |
/nocaptain |
!nocaptain |
Opt out of being randomly selected as captain |
/allowcaptain |
!allowcaptain |
Re-allow captain selection |
| Command | Description |
|---|---|
/top10 |
Players with most games |
/topelo |
Top 10 Elo rankings |
/winners |
Players with most wins (sorted by win rate) |
/captains |
Players who've captained most |
/thinkids |
Players picked first most often |
/fatkids |
Players picked last most often |
| Command | Description |
|---|---|
/setwinner <game_id> <1|2|0> |
Set winning team for a game (0 = draw) |
/setdraw <game_id> |
Mark game as a draw |
/reset |
Clear queue and draft state (requires Manage Server) |
/recalcelo |
Recalculate Elo from all recorded games |
/filltest |
Fill queue with test players (dev only) |
Players use /add to join the queue. When 10 players are queued, readycheck begins automatically.
Players have 120 seconds to click the ready button or type /r. Players who don't ready up are removed from the queue.
- Two captains are selected from eligible players (defaults to 20+ games played; if fewer than two meet the threshold, falls back to anyone who has not opted out)
- First captain is chosen at random from the eligible pool
- Second captain is chosen from the remaining eligible pool with the closest Elo rating to the first captain (ties randomized)
- Captains take turns picking players using
/p <number> - Pick order: Team1 → Team2 → Team1 → Team2 → Team1 → Team2 → Team2
- Each captain has 45 seconds per pick (auto-pick if timeout)
- Last player automatically assigned to Team 1
- Teams are displayed in an embed
- If enabled, players are automatically moved to team voice channels after 15 seconds
- Game ID is generated for stat tracking
- Typically captain sets winner with
/setwinner <game_id> <1|2>or/setdraw <game_id> - Stats are updated automatically
- Players moved back to lobby voice channel after 15 seconds
The bot uses SQLite with the following tables:
user_id- Discord user ID (primary key)games_played- Total games participated inwins- Total winscaptain_wins- Wins as captaincaptain_count- Times selected as captainfirst_pick_count- Times picked firstlast_pick_count- Times picked last
id- Auto-incrementing game IDguild_id- Discord server IDteam1- JSON array of Team 1 user IDsteam2- JSON array of Team 2 user IDswinner- 1, 2, 0 (draw), or NULL (unset)created_at- Timestamp
user_id- Discord user ID (primary key)rating- Elo ratingelo_games- Elo games counted
game_id- Game IDuser_id- Discord user IDpre_rating- Elo before the matchpost_rating- Elo after the matchdelta- Elo changecreated_at- Timestamp
user_id- Discord user ID (primary key)
Database file: draftbot.sqlite3
Backups: backups/ directory (last 10 kept)
Elo ratings are calculated per match using the team average ratings, then applied to every player on the team:
- Initial rating: 1000
- Expected score:
1 / (1 + 10^((team_b_avg - team_a_avg) / 400)) - Delta:
BASE_MATCH_DELTA * (score - expected)where score is 1.0 for a win, 0.0 for a loss, and 0.5 for a draw - Caps: win/loss deltas are clamped to ±30; draw deltas are clamped to ±5
- Tracking: every rating change is saved to
rating_historywith pre/post ratings and the delta
Use /filltest to automatically fill the queue with fake players for testing:
- Adds 9 test players to complete the queue
- Test players auto-ready during readycheck
- Test players skipped for voice channel operations
- Only accessible to developer (hardcoded user ID)
Each Discord server (guild) maintains independent state:
- Queue contents
- Readycheck status
- Draft progress
- Team compositions
Developer: AlexNB01
Contributor: TomG-FIN
Built with: discord.py, aiosqlite, Python 3.10+