Skip to content
This repository has been archived by the owner on Nov 6, 2023. It is now read-only.

Commit

Permalink
Add dice roll command to discord bot (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
sneakycrow authored Sep 16, 2023
1 parent a6c4ad6 commit f2ac78e
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 30 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion lib/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ repository = "https://github.com/sneakycrow/zachsbot"
axum = { version = "0.6" }
tokio = { version = "1.12.0", features = ["full"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"]}
tracing-subscriber = { version = "0.3", features = ["env-filter"]}
hyper = "0.14.27"
17 changes: 9 additions & 8 deletions lib/core/src/health_check.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
use axum::{
routing::get,
Router,
};
use axum::{Error, Router, routing::get};
use axum::http::StatusCode;
use axum::response::IntoResponse;

pub async fn health_check() -> impl IntoResponse {
(StatusCode::OK, "OK".to_string()).into_response()
}

const PORT: &str = "3000";
const HOST: &str = "0.0.0.0";

/// A function that starts a health check server using axum
pub async fn start_server() {
pub async fn start_server() -> hyper::Result<()> {
// Initialize router
let app = Router::new()
.route("/health", get(health_check));

axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
// Parse intended address
let addr = format!("{HOST}{PORT}");
// Start server
axum::Server::bind(&addr.parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
3 changes: 2 additions & 1 deletion packages/discord/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ edition = "2021"
[dependencies]
poise = "0.5.5"
tokio = { version = "1.12.0", features = ["full"] }
zachsbot = "0.0.2"
zachsbot = "0.0.2"
rand = "0.8.5"
25 changes: 5 additions & 20 deletions packages/discord/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,14 @@
mod slash_commands;

use poise::serenity_prelude as serenity;
use rand::{Rng, thread_rng};
use zachsbot::{debug, info};
use crate::slash_commands::dice_roll::roll;

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>;

/// Displays your or another user's account creation date
#[poise::command(slash_command, prefix_command)]
async fn age(
ctx: Context<'_>,
#[description = "Selected user"] user: Option<serenity::User>,
) -> Result<(), Error> {
let u = user.as_ref().unwrap_or_else(|| ctx.author());
let response = format!("{}'s account was created at {}", u.name, u.created_at());
ctx.say(response).await?;
Ok(())
}

/// Responds with "pong"
#[poise::command(slash_command, prefix_command)]
async fn ping(ctx: Context<'_>) -> Result<(), Error> {
ctx.say("pong").await?;
Ok(())
}

#[tokio::main]
async fn main() {
// Initialize tracing
Expand All @@ -32,7 +17,7 @@ async fn main() {
debug!("Initializing framework");
let framework = poise::Framework::builder()
.options(poise::FrameworkOptions {
commands: vec![age(), ping()],
commands: vec![roll()],
..Default::default()
})
.token(std::env::var("DISCORD_TOKEN").expect("missing DISCORD_TOKEN"))
Expand Down
80 changes: 80 additions & 0 deletions packages/discord/src/slash_commands/dice_roll.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use rand::Rng;

use crate::{Context, Error};

struct DiceRoll(u32, u32, Option<i32>);

impl DiceRoll {
/// A function for calculating the result of a dice roll
fn roll(&self) -> u32 {
let mut rng = rand::thread_rng();
let mut total = 0;
// Create a history of rolls
let mut rolls = Vec::new();
let num_dice = self.dice_roll();
let num_sides = self.dice_sides();
// For every dice to roll, roll it and add it to the total
for _ in 0..num_dice {
// Roll a random number between 1 and the number of sides on the dice
let roll = rng.gen_range(1..num_sides);
// Add the roll to the total
total += rng.gen_range(1..num_sides);
// Add the roll to the history of rolls
rolls.push(roll);
}
let modifier = self.2.unwrap_or(0);
total + modifier as u32
}
/// A function for getting the number of dice to roll
fn dice_roll(&self) -> u32 {
self.0
}
/// A function for getting the number of sides on the dice
fn dice_sides(&self) -> u32 {
self.1
}
/// A function for getting the modifier
fn modifier(&self) -> Option<i32> {
self.2
}
}

/// Parses the syntax of the dice rolls
/// It returns a tuple of the number of dice to roll, the number of sides on the dice, and the modifier
// Format is: 1d20+5, which means roll 1 20-sided dice and add 5 to the result
fn parse_dice_roll(roll: &str) -> DiceRoll {
// Get the number before the d
let dice_roll: u32 = roll.clone().split("d").collect::<Vec<&str>>()[0].parse().unwrap();
// Get the number after the d and before the +
let dice_sides: u32 = roll.clone().split("d").collect::<Vec<&str>>()[1].split("+").collect::<Vec<&str>>()[0].parse().unwrap();
// Get the number after the +
let modifier = roll.clone().split("+").collect::<Vec<&str>>();
// The modifier is optional, so if it's not there, set it to 0
let modifier = if modifier.len() > 1 {
Some(modifier[1].parse().unwrap())
} else {
None
};

DiceRoll(dice_roll, dice_sides, modifier)
}

/// Poise command to roll dice
#[poise::command(slash_command, prefix_command)]
pub(crate) async fn roll(
ctx: Context<'_>,
#[description = "Dice roll syntax"] roll: String,
) -> Result<(), Error> {
let roll = parse_dice_roll(&roll);
let base_response = format!("Rolling {} dice with {} sides...", roll.dice_roll(), roll.dice_sides());
let response = if roll.modifier().is_none() {
base_response
} else {
format!("{} and then adding {} to modify roll...", base_response, roll.modifier().unwrap())
};
ctx.say(response).await?;
let result = roll.roll();
let response = format!("The result is {}", result);
ctx.say(response).await?;
Ok(())
}
1 change: 1 addition & 0 deletions packages/discord/src/slash_commands/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod dice_roll;

0 comments on commit f2ac78e

Please sign in to comment.