Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
7d7d9bdc1c | |||
1e2918db8f | |||
34a25641d6 | |||
9c6249ca41 | |||
713d264544 |
@ -0,0 +1 @@
|
|||||||
|
DISCORD_TOKEN=changeme
|
103
.github/workflows/ci.yaml
vendored
Normal file
103
.github/workflows/ci.yaml
vendored
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
name: CI/CD Pipeline
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: labs.phundrak.com
|
||||||
|
IMAGE_NAME: phundrak/roll-one-ring
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Install Nix
|
||||||
|
uses: cachix/install-nix-action@v31.6.0
|
||||||
|
|
||||||
|
- name: Setup Cachix
|
||||||
|
uses: cachix/cachix-action@v16
|
||||||
|
with:
|
||||||
|
name: roll-one-ring
|
||||||
|
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||||
|
skipPush: ${{ github.event_name == 'pull_request' }}
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Get version from Cargo.toml
|
||||||
|
id: get-version
|
||||||
|
run: |
|
||||||
|
VERSION=$(nix run .#version 2>/dev/null || echo "unknown")
|
||||||
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Determine tags
|
||||||
|
id: determine-tags
|
||||||
|
run: |
|
||||||
|
TAGS=""
|
||||||
|
|
||||||
|
if [[ "${{ github.event_name }}" == "push" ]]; then
|
||||||
|
if [[ "${{ github.ref }}" == "refs/heads/develop" ]]; then
|
||||||
|
# Push to develop branch
|
||||||
|
TAGS="${{ env.IMAGE_NAME }}:develop"
|
||||||
|
elif [[ "${{ github.ref }}" == refs/tags/* ]]; then
|
||||||
|
# Tag push
|
||||||
|
VERSION_TAG=${GITHUB_REF#refs/tags/}
|
||||||
|
# Remove 'v' prefix if present
|
||||||
|
VERSION_TAG=${VERSION_TAG#v}
|
||||||
|
TAGS="${{ env.IMAGE_NAME }}:latest,${{ env.IMAGE_NAME }}:${VERSION_TAG}"
|
||||||
|
fi
|
||||||
|
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
||||||
|
# Pull request
|
||||||
|
PR_NUMBER=${{ github.event.number }}
|
||||||
|
TAGS="${{ env.IMAGE_NAME }}:pr${PR_NUMBER}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "tags=$TAGS" >> $GITHUB_OUTPUT
|
||||||
|
echo "Tags to build: $TAGS"
|
||||||
|
|
||||||
|
- name: Build Docker image with Nix
|
||||||
|
run: |
|
||||||
|
echo "Building Docker image..."
|
||||||
|
nix build .#docker
|
||||||
|
|
||||||
|
# Load the image into Docker
|
||||||
|
docker load < result
|
||||||
|
|
||||||
|
# Get the image ID that was just loaded
|
||||||
|
IMAGE_ID=$(docker images --format "table {{.Repository}}:{{.Tag}}\t{{.ID}}" | grep "${{ env.IMAGE_NAME }}:latest" | awk '{print $2}' | head -1)
|
||||||
|
echo "Loaded image ID: $IMAGE_ID"
|
||||||
|
echo "image_id=$IMAGE_ID" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Tag and push Docker image
|
||||||
|
run: |
|
||||||
|
TAGS="${{ steps.determine-tags.outputs.tags }}"
|
||||||
|
|
||||||
|
if [ -n "$TAGS" ]; then
|
||||||
|
IFS=',' read -ra TAG_ARRAY <<< "$TAGS"
|
||||||
|
for tag in "${TAG_ARRAY[@]}"; do
|
||||||
|
echo "Tagging and pushing: $tag"
|
||||||
|
docker tag ${{ env.image_id }} "$tag"
|
||||||
|
docker push "$tag"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Output image tags
|
||||||
|
run: |
|
||||||
|
echo "Built and pushed the following tags:"
|
||||||
|
echo "${{ steps.determine-tags.outputs.tags }}"
|
2648
Cargo.lock
generated
2648
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -4,3 +4,11 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bytecount = "0.6.9"
|
||||||
|
color-eyre = "0.6.5"
|
||||||
|
dotenvy = "0.15.7"
|
||||||
|
poise = "0.6.1"
|
||||||
|
rand = "0.9.2"
|
||||||
|
tokio = { version = "1.47.1", features = ["macros", "rt-multi-thread"] }
|
||||||
|
tracing = "0.1.41"
|
||||||
|
tracing-subscriber = "0.3.20"
|
||||||
|
96
flake.lock
generated
Normal file
96
flake.lock
generated
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1756542300,
|
||||||
|
"narHash": "sha256-tlOn88coG5fzdyqz6R93SQL5Gpq+m/DsWpekNFhqPQk=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "d7600c775f877cd87b4f5a831c28aa94137377aa",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1744536153,
|
||||||
|
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"rust-overlay": "rust-overlay"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-overlay": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1756780571,
|
||||||
|
"narHash": "sha256-xX0B7Sgx3OQvf6anaNW0vXyYDXbchSx2mnT8rqAPbWA=",
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"rev": "2c18db2acc837a71146ed2d6dae27bf03e3b7a4b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "oxalica",
|
||||||
|
"repo": "rust-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
29
flake.nix
29
flake.nix
@ -17,28 +17,45 @@
|
|||||||
cargo = rustVersion;
|
cargo = rustVersion;
|
||||||
rustc = rustVersion;
|
rustc = rustVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
appName = "roll-one-ring";
|
appName = "roll-one-ring";
|
||||||
|
cargoToml = builtins.fromTOML (builtins.readFile ./Cargo.toml);
|
||||||
|
version = cargoToml.package.version;
|
||||||
appRustBuild = rustPlatform.buildRustPackage {
|
appRustBuild = rustPlatform.buildRustPackage {
|
||||||
pname = appName;
|
pname = appName;
|
||||||
version = "0.1.0";
|
version = version;
|
||||||
src = ./.;
|
src = ./.;
|
||||||
cargoLock.lockFile = ./Cargo.lock;
|
cargoLock.lockFile = ./Cargo.lock;
|
||||||
};
|
};
|
||||||
dockerImage = pkgs.dockerTools.buildLayeredImage {
|
|
||||||
name = appName;
|
makeDockerImage = tag: pkgs.dockerTools.buildLayeredImage {
|
||||||
|
name = "phundrak/${appName}";
|
||||||
|
inherit tag;
|
||||||
config = {
|
config = {
|
||||||
Entrypoint = ["${appRustBuild}/bin/${appName}"];
|
Entrypoint = ["${appRustBuild}/bin/${appName}"];
|
||||||
Env = [ "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" ];
|
Env = [ "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" ];
|
||||||
Tag = "latest";
|
|
||||||
};
|
};
|
||||||
contents = [appRustBuild pkgs.cacert];
|
contents = [appRustBuild pkgs.cacert];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dockerImageLatest = makeDockerImage "latest";
|
||||||
|
dockerImageVersioned = makeDockerImage version;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
packages = {
|
packages = {
|
||||||
rustPackage = appRustBuild;
|
rustPackage = appRustBuild;
|
||||||
docker = dockerImage;
|
docker = dockerImageLatest;
|
||||||
|
docker-versioned = dockerImageVersioned;
|
||||||
|
};
|
||||||
|
defaultPackage = dockerImageLatest;
|
||||||
|
apps = {
|
||||||
|
version = {
|
||||||
|
type = "app";
|
||||||
|
program = "${pkgs.writeShellScript "version" ''
|
||||||
|
echo "${version}"
|
||||||
|
''}";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
defaultPackage = dockerImage;
|
|
||||||
devShell = with pkgs; mkShell {
|
devShell = with pkgs; mkShell {
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
bacon
|
bacon
|
||||||
|
40
src/discord/mod.rs
Normal file
40
src/discord/mod.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use color_eyre::eyre::{Error, Result};
|
||||||
|
use poise::serenity_prelude::{self as serenity, FullEvent};
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
|
mod roll_dice;
|
||||||
|
mod source;
|
||||||
|
|
||||||
|
type Context<'a> = poise::Context<'a, (), Error>;
|
||||||
|
|
||||||
|
fn event_handler(_ctx: serenity::Context, event: &FullEvent) {
|
||||||
|
if let FullEvent::Ready { data_about_bot } = event {
|
||||||
|
info!("Logged in as {}", data_about_bot.user.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn make_bot() -> Result<serenity::Client> {
|
||||||
|
let token = std::env::var("DISCORD_TOKEN").expect("DISCORD_TOKEN environment variable is missing");
|
||||||
|
let intents = serenity::GatewayIntents::non_privileged();
|
||||||
|
let framework = poise::Framework::<(), Error>::builder()
|
||||||
|
.options(poise::FrameworkOptions {
|
||||||
|
commands: vec![roll_dice::roll(), source::source()],
|
||||||
|
event_handler: |ctx, event, _framework: poise::FrameworkContext<'_, (), _>, _data| {
|
||||||
|
Box::pin(async move {
|
||||||
|
event_handler(ctx.clone(), event);
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.setup(|ctx, _ready, framework| {
|
||||||
|
Box::pin(async move {
|
||||||
|
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
Ok(serenity::ClientBuilder::new(token, intents)
|
||||||
|
.framework(framework)
|
||||||
|
.await?)
|
||||||
|
}
|
41
src/discord/roll_dice/advantage.rs
Normal file
41
src/discord/roll_dice/advantage.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use color_eyre::eyre::Error;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum Advantage {
|
||||||
|
None,
|
||||||
|
Beni,
|
||||||
|
Maudit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Advantage {
|
||||||
|
type Err = color_eyre::eyre::Report;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"aucun" => Ok(Self::None),
|
||||||
|
"béni" => Ok(Self::Beni),
|
||||||
|
"maudit" => Ok(Self::Maudit),
|
||||||
|
other => Err(Error::msg(format!("Could not parse {other} into an Advantage enum"))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Option<String>> for Advantage {
|
||||||
|
type Error = color_eyre::eyre::Report;
|
||||||
|
|
||||||
|
fn try_from(value: Option<String>) -> std::result::Result<Self, Self::Error> {
|
||||||
|
value.map_or_else(|| Ok(Self::None), |str| Self::from_str(&str))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Advantage {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
let str = match self {
|
||||||
|
Self::None => "aucun".to_string(),
|
||||||
|
Self::Beni => "béni".to_string(),
|
||||||
|
Self::Maudit => "maudit".to_string(),
|
||||||
|
};
|
||||||
|
write!(f, "{str}")
|
||||||
|
}
|
||||||
|
}
|
45
src/discord/roll_dice/mod.rs
Normal file
45
src/discord/roll_dice/mod.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
mod advantage;
|
||||||
|
mod roll;
|
||||||
|
mod roll_result;
|
||||||
|
mod success;
|
||||||
|
|
||||||
|
use advantage::Advantage;
|
||||||
|
use roll::Roll;
|
||||||
|
use roll_result::RollResult;
|
||||||
|
use success::Success;
|
||||||
|
|
||||||
|
use super::Context;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
|
async fn advantage_autocomplete(_ctx: Context<'_>, _: &str) -> impl Iterator<Item = String> {
|
||||||
|
[Advantage::None, Advantage::Beni, Advantage::Maudit]
|
||||||
|
.iter()
|
||||||
|
.map(std::string::ToString::to_string)
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[poise::command(slash_command)]
|
||||||
|
pub async fn roll(
|
||||||
|
ctx: Context<'_>,
|
||||||
|
#[description = "Seuil de réussite"]
|
||||||
|
#[min = 0]
|
||||||
|
#[max = 100]
|
||||||
|
sr: u8,
|
||||||
|
#[description = "Maîtrise"]
|
||||||
|
#[min = 0]
|
||||||
|
#[max = 6]
|
||||||
|
mastery: u8,
|
||||||
|
#[description = "Avantage"]
|
||||||
|
#[autocomplete = "advantage_autocomplete"]
|
||||||
|
advantage: Option<String>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let advantage = Advantage::try_from(advantage)?;
|
||||||
|
let roll = Roll::new(sr, mastery, advantage);
|
||||||
|
info!("Received roll {roll:?}");
|
||||||
|
let result: RollResult = roll.into();
|
||||||
|
info!("Result: {result:?}");
|
||||||
|
ctx.say(result.to_string()).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
14
src/discord/roll_dice/roll.rs
Normal file
14
src/discord/roll_dice/roll.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use super::Advantage;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Roll {
|
||||||
|
pub sr: u8,
|
||||||
|
pub mastery: u8,
|
||||||
|
pub advantage: Advantage,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Roll {
|
||||||
|
pub const fn new(sr: u8, mastery: u8, advantage: Advantage) -> Self {
|
||||||
|
Self { sr, mastery, advantage }
|
||||||
|
}
|
||||||
|
}
|
73
src/discord/roll_dice/roll_result.rs
Normal file
73
src/discord/roll_dice/roll_result.rs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
use super::{Advantage, Roll, Success};
|
||||||
|
|
||||||
|
fn roll_main_dice() -> u8 {
|
||||||
|
rand::random_range(0..=11)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn roll_mastery_dice() -> u8 {
|
||||||
|
rand::random_range(1..=6)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RollResult {
|
||||||
|
sr: u8,
|
||||||
|
main_dice: u8,
|
||||||
|
all_main_dice: Vec<u8>,
|
||||||
|
mastery: Vec<u8>,
|
||||||
|
result: u8,
|
||||||
|
success: Success,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RollResult {
|
||||||
|
pub fn main_dice_result(main_dice: &[u8], advantage: &Advantage) -> u8 {
|
||||||
|
match advantage {
|
||||||
|
Advantage::None => *main_dice.first().unwrap(),
|
||||||
|
Advantage::Beni => *main_dice.iter().max().unwrap_or(&0),
|
||||||
|
Advantage::Maudit => *main_dice.iter().min().unwrap_or(&0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_result(main_dice: &[u8], mastery: &[u8], advantage: &Advantage) -> u8 {
|
||||||
|
let main_dice = Self::main_dice_result(main_dice, advantage);
|
||||||
|
main_dice + mastery.iter().sum::<u8>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Roll> for RollResult {
|
||||||
|
fn from(value: Roll) -> Self {
|
||||||
|
let all_main_dice: Vec<u8> = if value.advantage == Advantage::None {
|
||||||
|
vec![roll_main_dice()]
|
||||||
|
} else {
|
||||||
|
(0..2).map(|_| roll_mastery_dice()).collect()
|
||||||
|
};
|
||||||
|
let mastery: Vec<u8> = std::iter::repeat_with(roll_mastery_dice)
|
||||||
|
.take(value.mastery.into())
|
||||||
|
.collect();
|
||||||
|
let sr = value.sr;
|
||||||
|
let result = Self::compute_result(&all_main_dice, &mastery, &value.advantage);
|
||||||
|
let main_dice = Self::main_dice_result(&all_main_dice, &value.advantage);
|
||||||
|
let success = Success::new(main_dice, result, sr, &mastery);
|
||||||
|
Self {
|
||||||
|
sr,
|
||||||
|
main_dice,
|
||||||
|
all_main_dice,
|
||||||
|
mastery,
|
||||||
|
result,
|
||||||
|
success,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for RollResult {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
let result = format!(
|
||||||
|
"Seuil de réussite : {}
|
||||||
|
Dé(s) du destin: {} ({:?})
|
||||||
|
Dé(s) de maîtrise: {:?}
|
||||||
|
Résultat : {}
|
||||||
|
Réussite : {}",
|
||||||
|
self.sr, self.main_dice, self.all_main_dice, self.mastery, self.result, self.success
|
||||||
|
);
|
||||||
|
write!(f, "{result}")
|
||||||
|
}
|
||||||
|
}
|
59
src/discord/roll_dice/success.rs
Normal file
59
src/discord/roll_dice/success.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Success {
|
||||||
|
Failure,
|
||||||
|
Success(SuccessLevel),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Success {
|
||||||
|
pub fn new(main_dice: u8, result: u8, sr: u8, mastery: &[u8]) -> Self {
|
||||||
|
let success_level = SuccessLevel::from(mastery);
|
||||||
|
match main_dice {
|
||||||
|
11 => Self::Success(success_level),
|
||||||
|
_ => {
|
||||||
|
if result >= sr {
|
||||||
|
Self::Success(success_level)
|
||||||
|
} else {
|
||||||
|
Self::Failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Success {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
let str = match self {
|
||||||
|
Self::Failure => "échec".to_owned(),
|
||||||
|
Self::Success(success_level) => success_level.to_string(),
|
||||||
|
};
|
||||||
|
write!(f, "{str}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SuccessLevel {
|
||||||
|
Normal,
|
||||||
|
Great,
|
||||||
|
Incredible,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&[u8]> for SuccessLevel {
|
||||||
|
fn from(value: &[u8]) -> Self {
|
||||||
|
match bytecount::count(value, 6) {
|
||||||
|
0 => Self::Normal,
|
||||||
|
1 => Self::Great,
|
||||||
|
_ => Self::Incredible,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for SuccessLevel {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
let level = match self {
|
||||||
|
Self::Normal => "réussite normale",
|
||||||
|
Self::Great => "grande réussite",
|
||||||
|
Self::Incredible => "très grande réussite",
|
||||||
|
};
|
||||||
|
write!(f, "{level}")
|
||||||
|
}
|
||||||
|
}
|
10
src/discord/source.rs
Normal file
10
src/discord/source.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
|
use super::Context;
|
||||||
|
|
||||||
|
#[poise::command(slash_command)]
|
||||||
|
pub async fn source(ctx: Context<'_>) -> Result<()> {
|
||||||
|
let message = "Mon code source se situe [là](https://labs.phundrak.com/phundrak/roll-one-ring)";
|
||||||
|
ctx.say(message).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
27
src/main.rs
27
src/main.rs
@ -1,3 +1,26 @@
|
|||||||
fn main() {
|
#![deny(clippy::all, clippy::pedantic, clippy::nursery)]
|
||||||
println!("Hello, world!");
|
#![warn(missing_docs)]
|
||||||
|
#![allow(
|
||||||
|
clippy::module_name_repetitions,
|
||||||
|
clippy::redundant_pub_crate,
|
||||||
|
clippy::enum_variant_names
|
||||||
|
)]
|
||||||
|
#![allow(clippy::unused_async)]
|
||||||
|
|
||||||
|
mod discord;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
|
use color_eyre::Result;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
utils::setup_logging();
|
||||||
|
info!("Setting up color_eyre...");
|
||||||
|
color_eyre::install()?;
|
||||||
|
info!("Reading dotenv...");
|
||||||
|
let _ = dotenvy::dotenv().map_err(|_| info!("No dotenv file found, skipping."));
|
||||||
|
let mut bot = discord::make_bot().await?;
|
||||||
|
bot.start().await?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
7
src/utils.rs
Normal file
7
src/utils.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
use tracing::Level;
|
||||||
|
use tracing_subscriber::FmtSubscriber;
|
||||||
|
|
||||||
|
pub fn setup_logging() {
|
||||||
|
let subscriber = FmtSubscriber::builder().with_max_level(Level::INFO).finish();
|
||||||
|
tracing::subscriber::set_global_default(subscriber).expect("Setting default logging subscriber failed");
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user