A Discord bot written using PyCord. Features moderation, economy, and more.
β οΈ An abundance of this code is written specifically for my use case. Many of the features are specific to my guild and database schema. There wasn't initially a plan to publish this project, so you'll observe a lack of abstraction in many places. This repo is mostly a showcase of what is possible with the Discord API. Feel free to pull any features that you want to use in your own bot.
This bot is up to standard with the newest features of the Discord API (utilizes Views, Discord UI, Context Commands, etc.)
Commands are invoked with /<command>
, or with context menus where applicable.
Let's get the boring stuff out of the way. The bot has application commands for all the usual moderation tasks, like kicking, banning, etc. It also features a few additional administration commands pertaining to the economy system (more on that later).
Both the bot and the Flask application sustain the made up pseudo-economy based on "Monkeycoin." The Monkeycoin is the currency used to play gambling games, purchase items, pay other users, and more. The theme came from a Dall-E generated image of King Kong throwing cash in the air.
Users can pay each other by invoking the /pay
command. The command will perform the appropriate checks to ensure that the transaction is valid, and will manipulate the database accordingly.
Users may also request money from other users by invoking the /request
command.
As with any good economy, there must be some form of gambling. The bot features several casino games such as
Crash, Blackjack, Horse Racing, and more. To initiate a gamble, a user can simply invoke /gamble
. This command, among others, utilizes discord.Option.autocomplete to populate a list of valid games.
Example of a Horse Race, made with updating embeds and Racehorse
objects
Example of Blackjack, made using updating embeds and PIL
Example of Crash, made using updating embeds
There are some commands that shouldn't be spammed all the time. For instance, I have written a command which connects to OpenAI's Dall-E to generate images based on text. This API costs me money, so to prevent users from overdoing it, they must spend 100 of their hard earned Monkeycoins to use the command.
This obviously does not negate the cost to me, but it certainly alleviates some of it. This can be applied to any command.
For any economy to work, there must be purchasable items to reinforce the value of the currency.
I have created an assortment of items that can be purchased, sold, traded, and crafted. Many of the items perform some sort of function, while others are simply ingredients for larger items or are sellable for profit.
For instance, the I.C.B.M.
costs 100,000 Monkeycoins, and can be fired at another user to instantly destroy 50% of their Monkeycoin balance. This adds incentive to earn Monkeycoins and significantly increases user engagement.
There are numerous ways a user can obtain items:
- Purchasing them in the shop (via the web application)
- Collecting Airdrops which randomly spawn throughout the day
- Trading with other users
- Opening Lootboxes
Users can sell items by invoking /sell
in the bot, or by using the web application.
The selling wizard will guide them through a sale.
A user can either:
- Sell an item back to the shop for 50% of its value (quick buck)
- List in on the declassifieds (via the web application)
Items can be used by invoking /use
followed by the item name or alias.
If the item has some sort of actual function, it will be performed. Otherwise, if the item is simply a prop, it will display a message explaining what the item is used for.
Like the commands, items also use the newest Discord API features like Discord UI.
An example of what happens when /use ICBM
is invoked
One user may attempt to pickpocket another user by invoking /pickpocket
, or by using the context menu under another user:
Once a pickpocket is initiated, an embed will appear, and the victim will be notified via DM. A timer will countdown, stating that the victim has 60 seconds to stop the pickpocket. The user may stop the pickpocket by opening the channel and clicking on the embed's button. If the victim fails to stop the pickpocket, the attacker is rewarded with a random amount of the victim's total balance, between 3% and 8%.
Example of an ongoing pickpocket
Example of a successful pickpocket
Example of the direct message you receive when being pickpocketted.
The bot is linked to popular game APIs to reward players in Monkeycoin for performing well in their favorite game. Most commonly, users will play the game Valorant to earn Monkeycoin. There is a task coroutine which polls the Valorant API every few minutes to check if any participating users have played a match. The match data is then passed through some scrutiny to assure that the game mode is valid, then the reward is calculated. Once the reward is calculated, the user will receive a direct message notifying them of their earnings:
There is a known bug where the embed is missing some calculations, and therefore does not accurately reflect the total amount received. It's on the todo list.
Each user is given a tycoon. They can upgrade their tycoon by spending Monkeycoins on it, in exchange for a daily payout + other perks, like shop discounts and auto-pickpockets. Users can upgrade their tycoon via the web application.
At random times throughout the day, the bot will send an Airdrop to a random channel. The Airdrop takes 30 seconds to land, which gives users ample time to open Discord and fight for it. The dropped crate can contain rare items, coins, etc.
The embed plays a gif displaying a supply plane dropping a crate
Once the airdrop lands, it will sit in this state until it is claimed, with no timeout.
Once claimed, the user is rewarded with the contents of the airdrop, and it is no longer claimable.
Along with the bot itself, a web application is also served via Flask. This application serves as something of a "Dashboard" for users to interact with. Users authenticate to the app by using Discord OAuth, where my script will pull their Discord information to accordingly interact with the database. The app is built using Flask, vanilla HTML/CSS/JS, Jinja2, SQL, etc. It's approaching Christmas at the time of this documentation, so excuse our falling snow and candycanes in the screenshots.
A stats page is available for a user to see how they stack up against the competition.
The page for users to buy items they want. The item shop is randomized and restocked every night at 12:00AM.
The page where users can upgrade their Tycoon to earn more coins each day and unlock special perks.
An obvious Craigslist knockoff where users can sell and trade items. (The page intentionally looks as bad as Craigslist lol)
The main dashboard where users can see stats about themselves and manage their inventories. Includes visuals built with Chart.js
A special page which can be accessed by clicking the little sign at the bottom right corner of any page. I've set up a little Christmas tree with gifts underneath for each one of my friends. They can only be opened after Christmas. Everything is animated and audio coordinated, built on top of a Canvas.
There are some specific pages only available to me for managing other user inventories, viewing all transactions, etc
This project has been a joy to write (although the code has certainly gotten out of control in some areas). At the time of writing, there have been over 2,500 transactions made in Monkeycoin (holy crap). This project was started in early November of 2022, when I couldn't figure out how to get the bot to respond to me:
It has certainly come a long way.
- Python
- PyCord
- SQLite3
- Async
- APIs
- OOP
- Flask
- Jinja2
- HTML
- CSS
- JavaScript
- AJAX
- Threading
- Photoshop
- Illustrator
- AWS EC2
- Ubuntu
- OAuth2
- SocketIO