feat(discord): Added /balance {give,set} commands
- Also, you cannot /answer to unpublished quest - Also, changed /scoreboard to print name instead of mentioning - Also, made --config an option, defaulting to "cfg/config.toml"
This commit is contained in:
parent
99812c5d7c
commit
4ba57b925a
6 changed files with 111 additions and 10 deletions
|
|
@ -6,5 +6,5 @@ use clap::Parser;
|
|||
pub struct Cli {
|
||||
/// Path to config.toml
|
||||
#[arg(long, short)]
|
||||
pub config: PathBuf,
|
||||
pub config: Option<PathBuf>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,21 @@
|
|||
use poise::serenity_prelude::{Mentionable, UserId};
|
||||
use poise::serenity_prelude::UserId;
|
||||
use squad_quest::{SquadObject, account::Account, map::Map};
|
||||
|
||||
use crate::{Context, Error};
|
||||
use crate::{Context, Error, account::fetch_or_init_account};
|
||||
|
||||
fn account_balance_string(account: &Account, map: &Map) -> String {
|
||||
async fn account_balance_string(ctx: &Context<'_>, account: &Account, map: &Map) -> String {
|
||||
let rooms_value = account_rooms_value(account, map);
|
||||
let full_balance = account_full_balance(account, map);
|
||||
format!("\n{account}: **{full_balance}** points (**{balance}** on balance \
|
||||
let account_id = account_user_id(&account);
|
||||
|
||||
let Ok(user) = account_id
|
||||
.to_user(ctx)
|
||||
.await else {
|
||||
return String::new();
|
||||
};
|
||||
let name = user.display_name();
|
||||
format!("\n{name}: **{full_balance}** points (**{balance}** on balance \
|
||||
+ **{rooms_value}** unlocked rooms networth)",
|
||||
account = account_user_id(&account).mention(),
|
||||
balance = account.balance,
|
||||
)
|
||||
}
|
||||
|
|
@ -57,7 +64,7 @@ pub async fn scoreboard(
|
|||
for account in accounts {
|
||||
let user_id = account_user_id(&account);
|
||||
|
||||
let mut str = account_balance_string(&account, &map);
|
||||
let mut str = account_balance_string(&ctx, &account, &map).await;
|
||||
if user_id == this_user {
|
||||
str = format!("__{str}__ << You");
|
||||
}
|
||||
|
|
@ -69,3 +76,82 @@ pub async fn scoreboard(
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[poise::command(
|
||||
prefix_command,
|
||||
slash_command,
|
||||
guild_only,
|
||||
subcommands("give", "set"),
|
||||
)]
|
||||
pub async fn balance(
|
||||
_ctx: Context<'_>,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[poise::command(
|
||||
prefix_command,
|
||||
slash_command,
|
||||
guild_only,
|
||||
)]
|
||||
pub async fn give(
|
||||
ctx: Context<'_>,
|
||||
who: UserId,
|
||||
amount: u32,
|
||||
) -> Result<(), Error> {
|
||||
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.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 reply_string = format!("Given money to user.\n\
|
||||
Your new balance: {} points.", user_account.balance);
|
||||
ctx.reply(reply_string).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[poise::command(
|
||||
prefix_command,
|
||||
slash_command,
|
||||
guild_only,
|
||||
required_permissions = "ADMINISTRATOR",
|
||||
)]
|
||||
pub async fn set(
|
||||
ctx: Context<'_>,
|
||||
who: UserId,
|
||||
amount: u32,
|
||||
) -> Result<(), Error> {
|
||||
let mut accounts = ctx.data().config.load_accounts();
|
||||
|
||||
let who_id = format!("{}", who.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 reply_string = format!("Set user balance to {amount}.");
|
||||
ctx.reply(reply_string).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ pub async fn answer(
|
|||
}
|
||||
|
||||
let quests = ctx.data().config.load_quests();
|
||||
let Some(quest) = quests.iter().find(|q| q.id == quest_id) else {
|
||||
let Some(quest) = quests.iter()
|
||||
.filter(|q| q.public)
|
||||
.find(|q| q.id == quest_id) else {
|
||||
return Err(Error::QuestNotFound(quest_id));
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ fn make_quest_message_content(quest: &Quest) -> String {
|
|||
#[poise::command(
|
||||
prefix_command,
|
||||
slash_command,
|
||||
guild_only,
|
||||
subcommands("list", "create", "update", "publish", "delete"),
|
||||
required_permissions = "ADMINISTRATOR",
|
||||
)]
|
||||
pub async fn quest(
|
||||
_ctx: Context<'_>,
|
||||
|
|
@ -50,6 +52,8 @@ pub async fn quest(
|
|||
#[poise::command(
|
||||
prefix_command,
|
||||
slash_command,
|
||||
guild_only,
|
||||
required_permissions = "ADMINISTRATOR",
|
||||
)]
|
||||
pub async fn list(
|
||||
ctx: Context<'_>,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ pub enum Error {
|
|||
BothChannelAndUser,
|
||||
SerenityError(serenity::Error),
|
||||
SquadQuestError(squad_quest::error::Error),
|
||||
AccountNotFound,
|
||||
InsufficientFunds(u32),
|
||||
}
|
||||
|
||||
impl From<serenity::Error> for Error {
|
||||
|
|
@ -38,6 +40,8 @@ impl Display for Error {
|
|||
Self::BothChannelAndUser => write!(f, "both channel and user was specified"),
|
||||
Self::SerenityError(_) => write!(f, "discord interaction error"),
|
||||
Self::SquadQuestError(_) => write!(f, "internal logic error"),
|
||||
Self::AccountNotFound => write!(f, "account not found"),
|
||||
Self::InsufficientFunds(amount) => write!(f, "account does not have {amount} points"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,7 +54,9 @@ impl std::error::Error for Error {
|
|||
Self::QuestIsCompleted(_) |
|
||||
Self::NoContent |
|
||||
Self::NoChannelOrUser |
|
||||
Self::BothChannelAndUser => None,
|
||||
Self::BothChannelAndUser |
|
||||
Self::AccountNotFound |
|
||||
Self::InsufficientFunds(_) => None,
|
||||
Self::SerenityError(error) => Some(error),
|
||||
Self::SquadQuestError(error) => Some(error),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ mod config;
|
|||
mod account;
|
||||
mod error;
|
||||
|
||||
const CONFIG_PATH: &str = "cfg/config.toml";
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Data {
|
||||
pub config: Config,
|
||||
|
|
@ -25,7 +27,7 @@ async fn main() {
|
|||
dotenv().unwrap();
|
||||
|
||||
let cli = cli::Cli::parse();
|
||||
let config = Config::load(cli.config.clone());
|
||||
let config = Config::load(cli.config.clone().unwrap_or(CONFIG_PATH.into()));
|
||||
let discord = config.discord_impl().unwrap_or_else(|_| {
|
||||
config.init_impl().unwrap();
|
||||
config.discord_impl().unwrap()
|
||||
|
|
@ -44,6 +46,7 @@ async fn main() {
|
|||
commands::answer::answer(),
|
||||
commands::social::social(),
|
||||
commands::account::scoreboard(),
|
||||
commands::account::balance(),
|
||||
],
|
||||
..Default::default()
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue