squad-quest/discord/src/commands/account.rs
2ndbeam 60aa5fcb34 feat(discord): Commands description
- Added english commands description
- Added russian commands description
- Changed override option on /quest update to reset dates
- Commented out all deadline functionality
2025-12-18 13:33:42 +03:00

215 lines
6.4 KiB
Rust

use poise::serenity_prelude::User;
use squad_quest::{SquadObject, account::Account, map::Map};
use crate::{Context, Error, account::{account_full_balance, account_user_id, fetch_or_init_account}, strings::StringFormatter};
async fn account_balance_string(
ctx: &Context<'_>,
account: &Account,
map: &Map,
mut formatter: StringFormatter
) -> String {
let account_id = account_user_id(&account);
let Ok(user) = account_id.to_user(ctx).await else {
return String::new();
};
let strings = &ctx.data().strings;
formatter = formatter.user(&user).balance(account, map);
formatter.fmt(&strings.scoreboard.line_format)
}
/// Reset user account, including balance, unlocked rooms and completed quests
#[poise::command(
prefix_command,
slash_command,
guild_only,
required_permissions = "ADMINISTRATOR",
name_localized("ru", "сбросить"),
description_localized("ru", "Сбросить аккаунт пользователя, вкл. баланс, открытые комнаты и пройденные квесты"),
)]
pub async fn reset(
ctx: Context<'_>,
#[description = "The user to reset"]
#[name_localized("ru", "кого")]
#[description_localized("ru", "Сбрасываемый пользователь")]
who: User,
) -> Result<(), Error> {
let accounts = ctx.data().config.load_accounts();
let acc_id = format!("{}", who.id.get());
if let None = accounts.iter().find(|a| a.id == acc_id) {
return Err(Error::AccountNotFound);
}
let mut path = ctx.data().config.full_accounts_path();
path.push(format!("{acc_id}.toml"));
Account::delete(path)?;
let strings = &ctx.data().strings;
let formatter = strings.formatter().user(&who);
let reply_string = formatter.fmt(&strings.account.reset);
ctx.reply(reply_string).await?;
Ok(())
}
/// Show scoreboard
#[poise::command(
prefix_command,
slash_command,
guild_only,
name_localized("ru", "счёт"),
description_localized("ru", "Отобразить таблицу лидеров"),
)]
pub async fn scoreboard(
ctx: Context<'_>,
) -> Result<(), Error> {
let map_path = ctx.data().config.full_map_path();
let map = Map::load(map_path).expect("map.toml should exist");
let strings = &ctx.data().strings;
let mut formatter = strings.formatter();
let mut accounts = ctx.data().config.load_accounts();
accounts.sort_by(|a,b| {
let a_balance = account_full_balance(a, &map);
let b_balance = account_full_balance(b, &map);
b_balance.cmp(&a_balance)
});
let this_user = ctx.author().id;
let mut reply_string = formatter.fmt(&strings.scoreboard.header);
for account in accounts {
let user_id = account_user_id(&account);
let mut str = account_balance_string(&ctx, &account, &map, formatter.clone()).await;
if user_id == this_user {
formatter = formatter.text(&str);
str = formatter.fmt(&strings.scoreboard.you_format);
}
reply_string.push_str(&str);
}
ctx.reply(reply_string).await?;
Ok(())
}
#[poise::command(
prefix_command,
slash_command,
guild_only,
subcommands("give", "set"),
name_localized("ru", "баланс"),
)]
pub async fn balance(
_ctx: Context<'_>,
) -> Result<(), Error> {
Ok(())
}
/// Give points to another user
#[poise::command(
prefix_command,
slash_command,
guild_only,
name_localized("ru", "передать"),
description_localized("ru", "Передать очки другому пользователю"),
)]
pub async fn give(
ctx: Context<'_>,
#[description = "Recipient"]
#[name_localized("ru", "кому")]
#[description_localized("ru", "Получатель")]
who: User,
#[description = "Amount of the points to give"]
#[name_localized("ru", "количество")]
#[description_localized("ru", "Количество очков для передачи")]
amount: u32,
) -> Result<(), Error> {
if ctx.author() == &who {
return Err(Error::AccountIsSelf);
}
let config = &ctx.data().config;
let mut accounts = config.load_accounts();
let user_id = format!("{}", ctx.author().id.get());
let mut user_account = fetch_or_init_account(config, user_id);
let who_id = format!("{}", who.id.get());
let Some(other_account) = accounts.iter_mut().find(|a| a.id == who_id ) else {
return Err(Error::AccountNotFound);
};
if user_account.balance < amount {
return Err(Error::InsufficientFunds(amount));
}
user_account.balance -= amount;
other_account.balance += amount;
let accounts_path = config.full_accounts_path();
user_account.save(accounts_path.clone())?;
other_account.save(accounts_path)?;
let strings = &ctx.data().strings;
let formatter = strings.formatter()
.user(&who)
.value(amount)
.current_balance(&user_account);
let reply_string = formatter.fmt(&strings.account.give_pt);
ctx.reply(reply_string).await?;
Ok(())
}
/// Set current user balance
#[poise::command(
prefix_command,
slash_command,
guild_only,
required_permissions = "ADMINISTRATOR",
name_localized("ru", "установить"),
description_localized("ru", "Устанавливает текущий баланс пользователя"),
)]
pub async fn set(
ctx: Context<'_>,
#[description = "User, whose balance will be modified"]
#[name_localized("ru", "чей")]
#[description_localized("ru", "Пользователь, чей баланс будет изменён")]
who: User,
#[description = "New balance of the user"]
#[name_localized("ru", "количество")]
#[description_localized("ru", "Новый баланс пользователя")]
amount: u32,
) -> Result<(), Error> {
let mut accounts = ctx.data().config.load_accounts();
let who_id = format!("{}", who.id.get());
let Some(account) = accounts.iter_mut().find(|a| a.id == who_id ) else {
return Err(Error::AccountNotFound);
};
account.balance = amount;
let accounts_path = ctx.data().config.full_accounts_path();
account.save(accounts_path)?;
let strings = &ctx.data().strings;
let formatter = strings.formatter()
.user(&who)
.current_balance(&account);
let reply_string = formatter.fmt(&strings.account.set_pt);
ctx.reply(reply_string).await?;
Ok(())
}