1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use crate::{
    checks::ENABLED_CHECK,
    database::model::TicTacToePlayer,
    ClientDataKey,
};
use serenity::{
    builder::{
        CreateAttachment,
        CreateMessage,
    },
    client::Context,
    framework::standard::{
        macros::command,
        Args,
        CommandResult,
    },
    model::prelude::*,
};
use tracing::error;

#[command]
#[description("Concede a game of Tic-Tac-Toe")]
#[usage("")]
#[example("")]
#[min_args(0)]
#[max_args(0)]
#[checks(Enabled)]
#[bucket("default")]
pub async fn concede(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
    let data_lock = ctx.data.read().await;
    let client_data = data_lock
        .get::<ClientDataKey>()
        .expect("missing client data");
    let tic_tac_toe_data = client_data.tic_tac_toe_data.clone();
    let db = client_data.db.clone();
    drop(data_lock);

    let guild_id = msg.guild_id;
    let author_id = msg.author.id;

    let game = match db
        .concede_tic_tac_toe_game(guild_id.into(), author_id)
        .await
    {
        Ok(Some(game)) => game,
        Ok(None) => {
            let response = "Failed to concede as you have no games in this server".to_string();
            msg.channel_id.say(&ctx.http, response).await?;
            return Ok(());
        }
        Err(e) => {
            error!("{:?}", e);
            msg.channel_id.say(&ctx.http, "database error").await?;
            return Ok(());
        }
    };

    let opponent = game
        .get_opponent(TicTacToePlayer::User(author_id))
        .expect("author is not playing the game");

    let file = match tic_tac_toe_data
        .renderer
        .render_board_async(game.board)
        .await
    {
        Ok(file) => CreateAttachment::bytes(file, format!("ttt-{}.png", game.board.encode_u16())),
        Err(error) => {
            error!("failed to render Tic-Tac-Toe board: {error}");
            msg.channel_id
                .say(
                    &ctx.http,
                    format!("Failed to render Tic-Tac-Toe board: {error}"),
                )
                .await?;
            return Ok(());
        }
    };

    let content = format!(
        "{} has conceded to {}.",
        author_id.mention(),
        opponent.mention()
    );

    let message_builder = CreateMessage::new().content(content).add_file(file);
    msg.channel_id
        .send_message(&ctx.http, message_builder)
        .await?;

    Ok(())
}