150 lines
4.2 KiB
Rust
150 lines
4.2 KiB
Rust
use log::{error, warn};
|
|
use rand::Rng;
|
|
use serenity::{
|
|
builder::CreateApplicationCommand,
|
|
client::Context,
|
|
model::application::{
|
|
command::CommandOptionType, interaction::application_command::ApplicationCommandInteraction,
|
|
},
|
|
};
|
|
|
|
use crate::bot::commands::audio::edit_response;
|
|
|
|
use super::audio::create_response;
|
|
|
|
pub async fn run(ctx: &Context, command: &ApplicationCommandInteraction) {
|
|
if let Err(why) = create_response(&ctx, &command, format!("Processing command...")).await {
|
|
error!("Failed to create response message: {}", why);
|
|
return;
|
|
}
|
|
let dice_string: String = match command.data.options.get(0) {
|
|
Some(o) => match &o.value {
|
|
Some(v) => match v.as_str() {
|
|
Some(s) => s.split_whitespace().collect::<String>(),
|
|
None => {
|
|
warn!("Missing dice option");
|
|
if let Err(why) = edit_response(&ctx, &command, format!("Dice option is missing")).await {
|
|
error!("Failed to create response message: {}", why);
|
|
}
|
|
return;
|
|
}
|
|
},
|
|
None => {
|
|
warn!("Missing dice option");
|
|
if let Err(why) = edit_response(&ctx, &command, format!("Dice option is missing")).await {
|
|
error!("Failed to create response message: {}", why);
|
|
}
|
|
return;
|
|
}
|
|
},
|
|
None => {
|
|
warn!("Missing dice option");
|
|
if let Err(why) = edit_response(&ctx, &command, format!("Dice option is missing")).await {
|
|
error!("Failed to create response message: {}", why);
|
|
}
|
|
return;
|
|
}
|
|
};
|
|
let dice = parse_dice(dice_string.as_str());
|
|
match dice {
|
|
Ok((count, sides, modifier)) => {
|
|
let mut rolls = Vec::new();
|
|
let mut total = 0;
|
|
for _ in 0..count {
|
|
let roll = rand::thread_rng().gen_range(1..=sides);
|
|
total += roll;
|
|
rolls.push(roll);
|
|
}
|
|
let response = format!(
|
|
"{}d{}{} = {}",
|
|
count,
|
|
sides,
|
|
if modifier > 0 {
|
|
format!("+{}", modifier)
|
|
} else if modifier < 0 {
|
|
format!("-{}", modifier)
|
|
} else {
|
|
"".to_string()
|
|
},
|
|
total + (modifier as u32)
|
|
);
|
|
if let Err(why) = edit_response(&ctx, &command, response).await {
|
|
error!("Failed to create response message: {}", why);
|
|
}
|
|
}
|
|
Err(why) => {
|
|
if let Err(why) = edit_response(&ctx, &command, format!("Invalid dice string: {}", why)).await
|
|
{
|
|
error!("Failed to create response message: {}", why);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn parse_dice(dice: &str) -> Result<(u32, u32, i32), String> {
|
|
let mut parts = dice.split("d");
|
|
let count = match parts.next() {
|
|
Some(c) => match c.parse::<u32>() {
|
|
Ok(n) => n,
|
|
Err(_) => return Err(format!("Invalid dice count: {}", c)),
|
|
},
|
|
None => return Err(format!("Invalid dice string: {}", dice)),
|
|
};
|
|
let mut positive_modifier = true;
|
|
let mut parts = match parts.next() {
|
|
Some(p) => {
|
|
// Check if contains a +/- modifier
|
|
if p.contains("+") {
|
|
positive_modifier = true;
|
|
p.split("+")
|
|
} else if p.contains("-") {
|
|
positive_modifier = false;
|
|
p.split("-")
|
|
} else {
|
|
p.split("+")
|
|
}
|
|
}
|
|
None => return Err(format!("Invalid dice string: {}", dice)),
|
|
};
|
|
let sides = match parts.next() {
|
|
Some(s) => match s.parse::<u32>() {
|
|
Ok(n) => {
|
|
if n == 4 || n == 6 || n == 8 || n == 10 || n == 12 || n == 20 || n == 100 {
|
|
n
|
|
} else {
|
|
return Err(format!("Invalid dice sides: {}", s));
|
|
}
|
|
}
|
|
Err(_) => return Err(format!("Invalid dice sides: {}", s)),
|
|
},
|
|
None => return Err(format!("Invalid dice string: {}", dice)),
|
|
};
|
|
let modifier = match parts.next() {
|
|
Some(m) => match m.parse::<i32>() {
|
|
Ok(n) => {
|
|
if positive_modifier {
|
|
n
|
|
} else {
|
|
n * -1
|
|
}
|
|
}
|
|
Err(_) => return Err(format!("Invalid dice modifier: {}", m)),
|
|
},
|
|
None => 0,
|
|
};
|
|
Ok((count, sides, modifier))
|
|
}
|
|
|
|
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
|
command
|
|
.name("roll")
|
|
.description("Rolls D&D dice")
|
|
.create_option(|option| {
|
|
option
|
|
.name("dice")
|
|
.description("Dice to roll")
|
|
.kind(CommandOptionType::String)
|
|
.required(true)
|
|
})
|
|
}
|