DuckHunt is an asyncio-based IRC bot that runs a classic "duck hunting" mini-game in IRC channels.
- Originally written by Computertech
- New features, fixes, and maintenance added by End3r
- Multi-channel support - Bot can be in multiple channels simultaneously
- Per-channel game toggle - Admins can enable or disable the game per channel (
!dh on/!dh off) - Persistent channel membership - Remembers and rejoins dynamically joined channels across disconnects and restarts
- Per-channel player stats - Stats are tracked separately per channel
- Global leaderboard - View the global top 5 across all channels
- Achievement System - Earn badges for milestones (e.g., First Blood, Sharpshooter, Golden Slayer)
- Duck Types & Flocks - Normal, Golden, Fast, Ninja, and flock events
- Shop system - Buy items, use them, or gift them to others
- Leveling system - Gain XP, increase your level, and unlock permanent upgrades
- JSON persistence & Auto-save - All stats saved to disk automatically after each action
- Python 3.8+
From the repo root:
python3 duckhunt.pyCopy the example config and edit it:
cp config.json.example config.jsonThen edit config.json:
connection.server,connection.port,connection.nickconnection.channels(list of channels to join on connect)connection.ssland optional password/SASL settingsconnection.ssl_verify(defaulttrue) validates the server's TLS certificate. Only set tofalsefor testing or trusted self-signed certificates; disabling it removes protection against man-in-the-middle attacks.admins(list of admin nicks). Each entry can be either:- a plain string nick, e.g.
"colby"— simple, but authenticates by nick alone, so anyone who takes that nick on the server (e.g. after the real admin disconnects) is granted admin access. The bot logs a startup warning for any admin configured this way. - a dict with a hostmask, e.g.
{"nick": "colby", "hostmask": "*!colby@trusted.host"}— recommended, since it also requires the connecting user/host to match.
- a plain string nick, e.g.
commands.prefix(default"!") - the character(s) that trigger bot commands, e.g.!bang,@bang,$bang. Must be non-empty and contain no whitespace. All command usage/help text (including!duckhelp) automatically reflects whatever prefix you configure.
Duck spawning is controlled by duck_spawning.spawn_min and duck_spawning.spawn_max (in seconds). Default is 1–2 hours (3600–7200).
Security note: config.json is ignored by git — don't commit real IRC passwords/tokens.
Four duck types plus flock events:
- Normal - Standard duck, 1 HP, base XP.
- Golden - Multi-HP duck (3–5 HP), higher XP, awards XP per hit.
- Fast - Quick duck, 1 HP, flies away faster.
- Ninja - Has a dodge chance making it harder to hit.
- Flock - 2–4 normal ducks spawn at once — shoot them one by one.
Duck spawn behavior is configured in config.json under duck_types.
Player stats are saved to duckhunt.json:
- Per-channel stats - Players have separate stats per channel (stored under
channels). - Global top 5 -
!globaltopaggregates XP across all channels. - Atomic writes & retry logic - Safe file handling prevents database corruption.
All commands below use the default ! prefix. This is configurable via commands.prefix
in config.json (see Configuration) — if you set it to e.g. @, use
@bang instead of !bang, and so on for every command.
!bang- Shoot at a duck!bef/!befriend- Try to befriend a duck!reload- Reload your gun!daily- Claim your daily XP bonus (resets every 24h, builds streaks)!duckstats [player]- View hunting statistics for the current channel!profile- Get a detailed hunter stat card sent to your PM!topduck- View channel leaderboard!globaltop- View global leaderboard (top 5 across all channels)!achievements- Check your earned badges (sent via PM)!effects- View active temporary buffs and their timers!inv- Quick inline view of your inventory!duckhelp- Get the full command list via PM
!shop- View available items!shop buy <item_name|id>- Purchase an item from the shop (by name or ID)!use <item_name|id> [target]- Use an item from your inventory (by name or ID)!give <item_name|id> <player>- Give an inventory item to another player (by name or ID)
!dh <on|off|status> [#channel]- Enable or disable DuckHunt in a channel (per-channel toggle)!rearm <player|all>- Give a player a gun!disarm <player>- Confiscate a player's gun!ignore <player>/!unignore <player>- Ignore/unignore commands from a player!ducklaunch [duck_type]- Force spawn a duck (normal, golden, fast, ninja, flock)!join <#channel>- Make the bot join a channel!part <#channel>- Make the bot leave a channel!reload(in PM) - Restart the bot process smoothly
Seven items available (use !shop to see current prices and IDs):
| ID | Name | Cost | Effect |
|---|---|---|---|
| 1 | Single Bullet | 5 XP | Add 1 bullet to your current magazine |
| 2 | Magazine | 15 XP | Add a spare magazine |
| 4 | Gun Brush | 20 XP | Reduce your jam chance by 10% |
| 5 | Bread | 50 XP | Double duck spawn rate for 20 minutes |
| 7 | Buy Gun Back | 40 XP | Recover your confiscated gun |
| 13 | Scope | 60 XP | +20% accuracy for your next 5 shots |
| 14 | Body Armor | 100 XP | Absorbs your next XP-loss event |
- Wait for a duck to spawn (appears randomly in channel, roughly every 1–2 hours).
- Type
!bangto shoot it or!befto befriend it. - Earn XP for successful hits or befriending.
- Level up to improve your stats (accuracy, magazine size, jam chance).
- Buy items from
!shopto enhance your hunting.
- XP, Level, Current & Best Hit Streaks
- Ducks shot & befriended
- Accuracy, Hit Rate, Daily Bonus Streak
- Current Inventory, Active Effects
- Achievements Earned
- Total XP spent in the shop
duckhunt/
├── duckhunt.py # Entry point
├── config.json # Bot configuration (ignored by git)
├── config.json.example # Safe template to copy
├── duckhunt.json # Player database (auto-generated)
├── levels.json # Level definitions
├── shop.json # Shop item catalog
├── messages.json # Bot messages
└── src/
├── duckhuntbot.py # IRC bot + command routing
├── game.py # Duck game logic
├── db.py # Database persistence
├── shop.py # Shop/inventory system
├── levels.py # Leveling system
├── sasl.py # SASL authentication
├── error_handling.py # Error recovery
└── utils.py # Utility functions
- Per-Channel Game Toggle (
!dh on/!dh off/!dh status) - Bot admins can enable or disable DuckHunt on a per-channel basis. Duck spawning pauses and gameplay commands are blocked in disabled channels while admin commands remain active. - Persistent Channel Membership - Channels joined via
!joinor parted via!partpersist in the database, ensuring the bot automatically rejoins all active channels across IRC lag/ping timeouts and full bot restarts. - Item Name Support & Display Fixes - Commands (
!use,!give,!shop buy) now support full item names (e.g.!use scope,!give bread Alice), and all output across inventory, profile, and duck drops strictly uses real item names instead of generic item numbers. - Asynchronous Non-blocking Message Loops - Converted the bot message-sending queue to run asynchronously, resolving loop blocking issues caused by synchronous message-throttling delay sleep.
- Config & Duck Types Syncing - Removed dead/unimplemented duck types from the configuration template and added proper config schema for the
ninjaduck. - Decoy Duck Removal - Completely removed vestigial decoy duck references, comments, and handling branches from the shooting and befriending mechanics.
- Redundant Schema Clean-up - Stripped legacy player database fields (
ammo,max_ammo,chargers) from defaults, creation, and runtime sanitization logic. - Configurable Command Prefix - Added
commands.prefixconfig option so the bot's trigger character (!,@,$, etc.) is no longer hardcoded. All help/usage text and message templates dynamically reflect the configured prefix. - Dead Decoy Message Strings Removed - Cleaned up orphaned
decoy_duck_flies_away/bang_decoy/bef_decoymessage strings left over after decoy duck removal. - Dynamic Inventory Sanitization - Implemented automated sanitization on player load to filter out and remove invalid or orphaned item IDs.
- Command & Shop Fixes - Corrected config key path mismatches, synced the default fallback shop with the active catalog, and updated the mystery box fallback pool.
- Multi-channel safety - Database warns when player nicks collide across channels, preventing silent data loss.
- Robust error handling - Improved async function detection and lambda logging in error recovery.
- Type hints - Core database functions now have full type annotations for better IDE support.
- Comprehensive error recovery - Circuit breakers and retry logic prevent cascading failures.
- Atomic database writes with JSON validation.
- Comprehensive input sanitization.
- Health check monitoring.
- Per-player rate limiting to prevent abuse.
Happy Duck Hunting!