-
Notifications
You must be signed in to change notification settings - Fork 120
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Rework of builtins::help() * Use find_command instead of duplicating code * Fix env variable `set` -> `export` for Unix * Fix unneeded mut * cargo fmt --------- Co-authored-by: kangalioo <jannik.a.schaper@web.de>
- Loading branch information
Showing
6 changed files
with
482 additions
and
62 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,305 @@ | ||
use poise::{samples::HelpConfiguration, serenity_prelude as serenity}; | ||
use rand::Rng; | ||
|
||
struct Data {} // User data, which is stored and accessible in all command invocations | ||
type Error = Box<dyn std::error::Error + Send + Sync>; | ||
type Context<'a> = poise::Context<'a, Data, Error>; | ||
|
||
const FRUIT: &[&str] = &["🍎", "🍌", "🍊", "🍉", "🍇", "🍓"]; | ||
const VEGETABLES: &[&str] = &["🥕", "🥦", "🥬", "🥒", "🌽", "🥔"]; | ||
const MEAT: &[&str] = &["🥩", "🍗", "🍖", "🥓", "🍔", "🍕"]; | ||
const DAIRY: &[&str] = &["🥛", "🧀", "🍦", "🍨", "🍩", "🍪"]; | ||
const FOOD: &[&str] = &[ | ||
"🍎", "🍌", "🍊", "🍉", "🍇", "🍓", "🥕", "🥦", "🥬", "🥒", "🌽", "🥔", "🥩", "🍗", "🍖", "🥓", | ||
"🍔", "🍕", "🥛", "🧀", "🍦", "🍨", "🍩", "🍪", | ||
]; | ||
|
||
fn ninetynine_bottles() -> String { | ||
let mut bottles = String::new(); | ||
for i in (95..100).rev() { | ||
bottles.push_str(&format!( | ||
"{0} bottles of beer on the wall, {0} bottles of beer!\n", | ||
i | ||
)); | ||
bottles.push_str(&format!( | ||
"Take one down, pass it around, {0} bottles of beer on the wall!\n", | ||
i - 1 | ||
)); | ||
} | ||
bottles += "That's quite enough to demonstrate this function!"; | ||
bottles | ||
} | ||
|
||
#[poise::command( | ||
slash_command, | ||
prefix_command, | ||
category = "Vegan", | ||
help_text_fn = "ninetynine_bottles" | ||
)] | ||
async fn beer(ctx: Context<'_>) -> Result<(), Error> { | ||
ctx.say("🍺").await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with a random fruit | ||
/// | ||
/// Subcommands can be used to get a specific fruit | ||
#[poise::command( | ||
slash_command, | ||
prefix_command, | ||
subcommands( | ||
"apple", | ||
"banana", | ||
"orange", | ||
"watermelon", | ||
"grape", | ||
"strawberry", | ||
"help" | ||
), | ||
category = "Vegan" | ||
)] | ||
async fn fruit(ctx: Context<'_>) -> Result<(), Error> { | ||
let response = FRUIT[rand::thread_rng().gen_range(0..FRUIT.len())]; | ||
ctx.say(response).await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with an apple | ||
#[poise::command(slash_command, prefix_command, subcommands("red", "green"))] | ||
async fn apple(ctx: Context<'_>) -> Result<(), Error> { | ||
ctx.say("🍎").await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with a red apple | ||
#[poise::command(slash_command, prefix_command)] | ||
async fn red(ctx: Context<'_>) -> Result<(), Error> { | ||
ctx.say("🍎").await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with a green apple | ||
#[poise::command(slash_command, prefix_command)] | ||
async fn green(ctx: Context<'_>) -> Result<(), Error> { | ||
ctx.say("🍏").await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with a banana | ||
#[poise::command(slash_command, prefix_command)] | ||
async fn banana(ctx: Context<'_>) -> Result<(), Error> { | ||
ctx.say("🍌").await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with an orange | ||
#[poise::command(slash_command, prefix_command)] | ||
async fn orange(ctx: Context<'_>) -> Result<(), Error> { | ||
ctx.say("🍊").await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with a watermelon | ||
#[poise::command(slash_command, prefix_command)] | ||
async fn watermelon(ctx: Context<'_>) -> Result<(), Error> { | ||
ctx.say("🍉").await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with a grape | ||
#[poise::command(slash_command, prefix_command)] | ||
async fn grape(ctx: Context<'_>) -> Result<(), Error> { | ||
ctx.say("🍇").await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with a strawberry | ||
#[poise::command(slash_command, prefix_command)] | ||
async fn strawberry(ctx: Context<'_>) -> Result<(), Error> { | ||
ctx.say("🍓").await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with a random vegetable | ||
#[poise::command(slash_command, prefix_command, category = "Vegan")] | ||
async fn vegetable(ctx: Context<'_>) -> Result<(), Error> { | ||
let response = VEGETABLES[rand::thread_rng().gen_range(0..VEGETABLES.len())]; | ||
ctx.say(response).await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with a random meat | ||
#[poise::command(slash_command, prefix_command, category = "Other")] | ||
async fn meat(ctx: Context<'_>) -> Result<(), Error> { | ||
let response = MEAT[rand::thread_rng().gen_range(0..MEAT.len())]; | ||
ctx.say(response).await?; | ||
Ok(()) | ||
} | ||
|
||
/// Respond with a random dairy product | ||
#[poise::command(slash_command, prefix_command, category = "Other")] | ||
async fn dairy(ctx: Context<'_>) -> Result<(), Error> { | ||
let response = DAIRY[rand::thread_rng().gen_range(0..DAIRY.len())]; | ||
ctx.say(response).await?; | ||
Ok(()) | ||
} | ||
|
||
/// Give a user some random food | ||
#[poise::command(context_menu_command = "Give food")] | ||
async fn context_food( | ||
ctx: Context<'_>, | ||
#[description = "User to give food to"] user: serenity::User, | ||
) -> Result<(), Error> { | ||
let response = format!( | ||
"<@{}>: {}", | ||
user.id, | ||
FOOD[rand::thread_rng().gen_range(0..FOOD.len())] | ||
); | ||
|
||
ctx.say(response).await?; | ||
Ok(()) | ||
} | ||
|
||
/// Give a user some random fruit | ||
#[poise::command( | ||
slash_command, | ||
context_menu_command = "Give fruit", | ||
category = "Context menu but also slash/prefix" | ||
)] | ||
async fn context_fruit( | ||
ctx: Context<'_>, | ||
#[description = "User to give fruit to"] user: serenity::User, | ||
) -> Result<(), Error> { | ||
let response = format!( | ||
"<@{}>: {}", | ||
user.id, | ||
FRUIT[rand::thread_rng().gen_range(0..FRUIT.len())] | ||
); | ||
|
||
ctx.say(response).await?; | ||
Ok(()) | ||
} | ||
|
||
/// Give a user some random vegetable | ||
#[poise::command( | ||
prefix_command, | ||
context_menu_command = "Give vegetable", | ||
category = "Context menu but also slash/prefix" | ||
)] | ||
async fn context_vegetable( | ||
ctx: Context<'_>, | ||
#[description = "User to give vegetable to"] user: serenity::User, | ||
) -> Result<(), Error> { | ||
let response = format!( | ||
"<@{}>: {}", | ||
user.id, | ||
VEGETABLES[rand::thread_rng().gen_range(0..VEGETABLES.len())] | ||
); | ||
|
||
ctx.say(response).await?; | ||
Ok(()) | ||
} | ||
|
||
/// Give a user some random meat | ||
#[poise::command( | ||
prefix_command, | ||
slash_command, | ||
context_menu_command = "Give meat", | ||
category = "Context menu but also slash/prefix" | ||
)] | ||
async fn context_meat( | ||
ctx: Context<'_>, | ||
#[description = "User to give meat to"] user: serenity::User, | ||
) -> Result<(), Error> { | ||
let response = format!( | ||
"<@{}>: {}", | ||
user.id, | ||
MEAT[rand::thread_rng().gen_range(0..MEAT.len())] | ||
); | ||
|
||
ctx.say(response).await?; | ||
Ok(()) | ||
} | ||
|
||
/// React to a message with random food | ||
#[poise::command(slash_command, context_menu_command = "React with food", ephemeral)] | ||
async fn food_react( | ||
ctx: Context<'_>, | ||
#[description = "Message to react to (enter a link or ID)"] msg: serenity::Message, | ||
) -> Result<(), Error> { | ||
let reaction = FOOD[rand::thread_rng().gen_range(0..FOOD.len())].to_string(); | ||
msg.react(ctx, serenity::ReactionType::Unicode(reaction)) | ||
.await?; | ||
ctx.say("Reacted!").await?; | ||
Ok(()) | ||
} | ||
|
||
/// Show help message | ||
#[poise::command(prefix_command, track_edits, category = "Utility")] | ||
async fn help( | ||
ctx: Context<'_>, | ||
#[description = "Command to get help for"] | ||
#[rest] | ||
mut command: Option<String>, | ||
) -> Result<(), Error> { | ||
// This makes it possible to just make `help` a subcommand of any command | ||
// `/fruit help` turns into `/help fruit` | ||
// `/fruit help apple` turns into `/help fruit apple` | ||
if ctx.invoked_command_name() != "help" { | ||
command = match command { | ||
Some(c) => Some(format!("{} {}", ctx.invoked_command_name(), c)), | ||
None => Some(ctx.invoked_command_name().to_string()), | ||
}; | ||
} | ||
let extra_text_at_bottom = "\ | ||
Type `?help command` for more info on a command. | ||
You can edit your `?help` message to the bot and the bot will edit its response."; | ||
|
||
let config = HelpConfiguration { | ||
show_subcommands: true, | ||
show_context_menu_commands: true, | ||
ephemeral: true, | ||
extra_text_at_bottom, | ||
|
||
..Default::default() | ||
}; | ||
poise::builtins::help(ctx, command.as_deref(), config).await?; | ||
Ok(()) | ||
} | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
let framework = poise::Framework::builder() | ||
.options(poise::FrameworkOptions { | ||
commands: vec![ | ||
fruit(), | ||
vegetable(), | ||
beer(), | ||
meat(), | ||
dairy(), | ||
help(), | ||
context_food(), | ||
context_fruit(), | ||
context_vegetable(), | ||
context_meat(), | ||
food_react(), | ||
], | ||
prefix_options: poise::PrefixFrameworkOptions { | ||
prefix: Some("?".into()), | ||
..Default::default() | ||
}, | ||
..Default::default() | ||
}) | ||
.token(std::env::var("DISCORD_TOKEN").expect("missing DISCORD_TOKEN")) | ||
.intents( | ||
serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::MESSAGE_CONTENT, | ||
) | ||
.setup(|ctx, _ready, framework| { | ||
Box::pin(async move { | ||
poise::builtins::register_globally(ctx, &framework.options().commands).await?; | ||
Ok(Data {}) | ||
}) | ||
}); | ||
|
||
framework.run().await.unwrap(); | ||
} |
Oops, something went wrong.