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(()) }