From c3371fb4c73ace0f2352329c32275a88a6265cd9 Mon Sep 17 00:00:00 2001 From: YetAnotherMechanicusEnjoyer Date: Sun, 31 Aug 2025 14:10:32 +0200 Subject: [PATCH 1/4] [ADD] discord/src/events/discord/interaction_create/accept_duel.rs --- .../discord/interaction_create/accept_duel.rs | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 discord/src/events/discord/interaction_create/accept_duel.rs diff --git a/discord/src/events/discord/interaction_create/accept_duel.rs b/discord/src/events/discord/interaction_create/accept_duel.rs new file mode 100644 index 0000000..d36dde8 --- /dev/null +++ b/discord/src/events/discord/interaction_create/accept_duel.rs @@ -0,0 +1,61 @@ +use poise::serenity_prelude::{ + self as serenity, ComponentInteraction, CreateEmbed, CreateInteractionResponse, + CreateInteractionResponseMessage, +}; + +use super::create_combat_ui; +use crate::{Error, GameState}; + +pub async fn accept_duel( + ctx: &serenity::Context, + component: ComponentInteraction, + game_state: GameState, +) -> Result<(), Error> { + if component.user.id != game_state.player2_id { + component + .create_response( + &ctx, + CreateInteractionResponse::Message( + CreateInteractionResponseMessage::new() + .content("This duel challenge is not for you!") + .ephemeral(true), + ), + ) + .await + .ok(); + return Ok(()); + } + + let p1_user = game_state.player1_id.to_user(&ctx).await.unwrap(); + let p2_user = game_state.player2_id.to_user(&ctx).await.unwrap(); + let new_embed = CreateEmbed::new() + .title("Duel Started!") + .description(format!( + "{p1_user} vs {p2_user}\n\nIt is {p1_user}'s turn to attack!", + )) + .field( + format!("{}`s HP", p1_user.name), + game_state.player1_hp.to_string(), + true, + ) + .field( + format!("{}`s HP", p2_user.name), + game_state.player2_hp.to_string(), + true, + ); + + let components = create_combat_ui(&p1_user); + + component + .create_response( + &ctx, + CreateInteractionResponse::UpdateMessage( + CreateInteractionResponseMessage::new() + .embeds(vec![new_embed]) + .components(components), + ), + ) + .await + .ok(); + Ok(()) +} From d1a85e18446781ff928994729d7a901eb9d074d8 Mon Sep 17 00:00:00 2001 From: YetAnotherMechanicusEnjoyer Date: Sun, 31 Aug 2025 14:10:50 +0200 Subject: [PATCH 2/4] [ADD] discord/src/events/discord/interaction_create/attack_action.rs --- .../interaction_create/attack_action.rs | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 discord/src/events/discord/interaction_create/attack_action.rs diff --git a/discord/src/events/discord/interaction_create/attack_action.rs b/discord/src/events/discord/interaction_create/attack_action.rs new file mode 100644 index 0000000..284a6b7 --- /dev/null +++ b/discord/src/events/discord/interaction_create/attack_action.rs @@ -0,0 +1,123 @@ +use std::collections::HashMap; + +use poise::serenity_prelude::{ + self as serenity, Colour, ComponentInteraction, CreateEmbed, CreateInteractionResponse, + CreateInteractionResponseMessage, MessageId, +}; +use tokio::sync::MutexGuard; + +use super::create_combat_ui; +use crate::{Error, GameState}; + +pub async fn attack_action( + ctx: &serenity::Context, + mut data: MutexGuard<'_, HashMap>, + component: ComponentInteraction, + mut game_state: GameState, +) -> Result<(), Error> { + if component.user.id != game_state.turn { + component + .create_response( + &ctx, + CreateInteractionResponse::Message( + CreateInteractionResponseMessage::new() + .content("It's not your turn!") + .ephemeral(true), + ), + ) + .await + .ok(); + return Ok(()); + } + + let (_attacker_id, defender_id) = if component.user.id == game_state.player1_id { + (game_state.player1_id, game_state.player2_id) + } else { + (game_state.player2_id, game_state.player1_id) + }; + + let damage = 10; + + if defender_id == game_state.player1_id { + game_state.player1_hp = game_state.player1_hp.saturating_sub(damage); + } else { + game_state.player2_hp = game_state.player2_hp.saturating_sub(damage); + } + + let winner = if game_state.player1_hp == 0 { + Some(game_state.player2_id) + } else if game_state.player2_hp == 0 { + Some(game_state.player1_id) + } else { + None + }; + + let next_turn = if game_state.turn == game_state.player1_id { + game_state.player2_id + } else { + game_state.player1_id + }; + game_state.turn = next_turn; + + let p1_user = game_state.player1_id.to_user(&ctx).await.unwrap(); + let p2_user = game_state.player2_id.to_user(&ctx).await.unwrap(); + + let description = if let Some(winner_id) = winner { + let winner_user = winner_id.to_user(&ctx).await.unwrap(); + format!( + "{} defeated {}!", + winner_user, + if winner_id == p1_user.id { + p2_user.clone() + } else { + p1_user.clone() + } + ) + } else { + format!( + "{} attacked {} for {} damage! It is now {}'s turn.", + component.user, + next_turn.to_user(&ctx).await.unwrap(), + damage, + next_turn.to_user(&ctx).await.unwrap() + ) + }; + + let new_embed = CreateEmbed::new() + .title("Duel in Progress") + .description(description) + .field( + format!("{}`s HP", p1_user.name), + game_state.player1_hp.to_string(), + true, + ) + .field( + format!("{}`s HP", p2_user.name), + game_state.player2_hp.to_string(), + true, + ) + .color(Colour::from_rgb(0, 100, 255)); + + let components = if winner.is_some() { + data.remove(&component.message.id); + vec![] + } else { + let next_user = next_turn.to_user(&ctx).await.unwrap(); + create_combat_ui(&next_user) + }; + + data.insert(component.message.id, game_state); + + component + .create_response( + &ctx, + CreateInteractionResponse::UpdateMessage( + CreateInteractionResponseMessage::new() + .embeds(vec![new_embed]) + .components(components), + ), + ) + .await + .ok(); + Ok(()) +} From 682e8ddae8360d882845ab4ee11a7a893a76aec8 Mon Sep 17 00:00:00 2001 From: YetAnotherMechanicusEnjoyer Date: Sun, 31 Aug 2025 14:11:08 +0200 Subject: [PATCH 3/4] [ADD] discord/src/events/discord/interaction_create/cancel_duel.rs --- .../discord/interaction_create/cancel_duel.rs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 discord/src/events/discord/interaction_create/cancel_duel.rs diff --git a/discord/src/events/discord/interaction_create/cancel_duel.rs b/discord/src/events/discord/interaction_create/cancel_duel.rs new file mode 100644 index 0000000..3dffda9 --- /dev/null +++ b/discord/src/events/discord/interaction_create/cancel_duel.rs @@ -0,0 +1,49 @@ +use std::collections::HashMap; + +use poise::serenity_prelude::{ + self as serenity, ComponentInteraction, CreateEmbed, CreateInteractionResponse, + CreateInteractionResponseMessage, MessageId, +}; +use tokio::sync::MutexGuard; + +use crate::{Error, GameState}; + +pub async fn cancel_duel( + ctx: &serenity::Context, + mut data: MutexGuard<'_, HashMap>, + component: ComponentInteraction, + game_state: GameState, +) -> Result<(), Error> { + if component.user.id != game_state.player1_id && component.user.id != game_state.player2_id { + component + .create_response( + &ctx, + CreateInteractionResponse::Message( + CreateInteractionResponseMessage::new() + .content("This duel challenge is not for you!") + .ephemeral(true), + ), + ) + .await + .ok(); + return Ok(()); + } + + data.remove(&component.message.id); + let new_embed = CreateEmbed::new() + .title("Duel Cancelled") + .description("The duel has been cancelled."); + + component + .create_response( + &ctx, + CreateInteractionResponse::UpdateMessage( + CreateInteractionResponseMessage::new() + .embeds(vec![new_embed]) + .components(vec![]), + ), + ) + .await + .ok(); + Ok(()) +} From 14b63399387feda9d3ac2628418fc76f4955c8bc Mon Sep 17 00:00:00 2001 From: YetAnotherMechanicusEnjoyer Date: Sun, 31 Aug 2025 14:11:38 +0200 Subject: [PATCH 4/4] [UPDATE] interaction_create.rs [EDIT] match components id now in other files --- .../src/events/discord/interaction_create.rs | 202 +----------------- 1 file changed, 10 insertions(+), 192 deletions(-) diff --git a/discord/src/events/discord/interaction_create.rs b/discord/src/events/discord/interaction_create.rs index b900f84..cc2c23a 100644 --- a/discord/src/events/discord/interaction_create.rs +++ b/discord/src/events/discord/interaction_create.rs @@ -1,11 +1,14 @@ use poise::serenity_prelude::{ - self as serenity, ButtonStyle, Colour, CreateActionRow, CreateButton, CreateEmbed, - CreateInteractionResponse, CreateInteractionResponseMessage, EmojiId, Interaction, + self as serenity, ButtonStyle, CreateActionRow, CreateButton, EmojiId, Interaction, ReactionType, User, }; use crate::{Data, Error}; +mod accept_duel; +mod attack_action; +mod cancel_duel; + fn create_combat_ui(turn_user: &User) -> Vec { let attack_button = CreateButton::new("attack_action") .style(ButtonStyle::Primary) @@ -35,201 +38,16 @@ pub async fn interaction_create( _data: &Data, ) -> Result<(), Error> { if let serenity::Interaction::Component(component) = interaction { - let mut data = framework.user_data().await.active_duels.lock().await; + let data = framework.user_data().await.active_duels.lock().await; let game_state_option = data.get(&component.message.id).cloned(); - if let Some(mut game_state) = game_state_option { + if let Some(game_state) = game_state_option { match component.data.custom_id.as_str() { - "accept_duel" => { - if component.user.id != game_state.player2_id { - component - .create_response( - &ctx, - CreateInteractionResponse::Message( - CreateInteractionResponseMessage::new() - .content("This duel challenge is not for you!") - .ephemeral(true), - ), - ) - .await - .ok(); - return Ok(()); - } - - let p1_user = game_state.player1_id.to_user(&ctx).await.unwrap(); - let p2_user = game_state.player2_id.to_user(&ctx).await.unwrap(); - let new_embed = CreateEmbed::new() - .title("Duel Started!") - .description(format!( - "{p1_user} vs {p2_user}\n\nIt is {p1_user}'s turn to attack!", - )) - .field( - format!("{}`s HP", p1_user.name), - game_state.player1_hp.to_string(), - true, - ) - .field( - format!("{}`s HP", p2_user.name), - game_state.player2_hp.to_string(), - true, - ); - - let components = create_combat_ui(&p1_user); - - component - .create_response( - &ctx, - CreateInteractionResponse::UpdateMessage( - CreateInteractionResponseMessage::new() - .embeds(vec![new_embed]) - .components(components), - ), - ) - .await - .ok(); - } - "cancel_duel" => { - if component.user.id != game_state.player1_id - && component.user.id != game_state.player2_id - { - component - .create_response( - &ctx, - CreateInteractionResponse::Message( - CreateInteractionResponseMessage::new() - .content("This duel challenge is not for you!") - .ephemeral(true), - ), - ) - .await - .ok(); - return Ok(()); - } - - data.remove(&component.message.id); - let new_embed = CreateEmbed::new() - .title("Duel Cancelled") - .description("The duel has been cancelled."); - - component - .create_response( - &ctx, - CreateInteractionResponse::UpdateMessage( - CreateInteractionResponseMessage::new() - .embeds(vec![new_embed]) - .components(vec![]), - ), - ) - .await - .ok(); - } + "accept_duel" => accept_duel::accept_duel(ctx, component, game_state).await?, + "cancel_duel" => cancel_duel::cancel_duel(ctx, data, component, game_state).await?, "attack_action" => { - if component.user.id != game_state.turn { - component - .create_response( - &ctx, - CreateInteractionResponse::Message( - CreateInteractionResponseMessage::new() - .content("It's not your turn!") - .ephemeral(true), - ), - ) - .await - .ok(); - return Ok(()); - } - - let (_attacker_id, defender_id) = if component.user.id == game_state.player1_id - { - (game_state.player1_id, game_state.player2_id) - } else { - (game_state.player2_id, game_state.player1_id) - }; - - let damage = 10; - - if defender_id == game_state.player1_id { - game_state.player1_hp = game_state.player1_hp.saturating_sub(damage); - } else { - game_state.player2_hp = game_state.player2_hp.saturating_sub(damage); - } - - let winner = if game_state.player1_hp == 0 { - Some(game_state.player2_id) - } else if game_state.player2_hp == 0 { - Some(game_state.player1_id) - } else { - None - }; - - let next_turn = if game_state.turn == game_state.player1_id { - game_state.player2_id - } else { - game_state.player1_id - }; - game_state.turn = next_turn; - - let p1_user = game_state.player1_id.to_user(&ctx).await.unwrap(); - let p2_user = game_state.player2_id.to_user(&ctx).await.unwrap(); - - let description = if let Some(winner_id) = winner { - let winner_user = winner_id.to_user(&ctx).await.unwrap(); - format!( - "{} defeated {}!", - winner_user, - if winner_id == p1_user.id { - p2_user.clone() - } else { - p1_user.clone() - } - ) - } else { - format!( - "{} attacked {} for {} damage! It is now {}'s turn.", - component.user, - next_turn.to_user(&ctx).await.unwrap(), - damage, - next_turn.to_user(&ctx).await.unwrap() - ) - }; - - let new_embed = CreateEmbed::new() - .title("Duel in Progress") - .description(description) - .field( - format!("{}`s HP", p1_user.name), - game_state.player1_hp.to_string(), - true, - ) - .field( - format!("{}`s HP", p2_user.name), - game_state.player2_hp.to_string(), - true, - ) - .color(Colour::from_rgb(0, 100, 255)); - - let components = if winner.is_some() { - data.remove(&component.message.id); - vec![] - } else { - let next_user = next_turn.to_user(&ctx).await.unwrap(); - create_combat_ui(&next_user) - }; - - data.insert(component.message.id, game_state); - - component - .create_response( - &ctx, - CreateInteractionResponse::UpdateMessage( - CreateInteractionResponseMessage::new() - .embeds(vec![new_embed]) - .components(components), - ), - ) - .await - .ok(); + attack_action::attack_action(ctx, data, component, game_state).await? } _ => {} }