174 lines
6.5 KiB
Rust
174 lines
6.5 KiB
Rust
use built::chrono;
|
|
use manifold::error::{ManifoldError, ManifoldResult};
|
|
use manifold::{ManifoldContext, ManifoldData};
|
|
use poise::serenity_prelude::{CreateEmbed, Mentionable, RoleId};
|
|
use to_markdown_table::MarkdownTable;
|
|
use crate::badgey::models::xp::{Leaderboard, Rank, Track, Xp};
|
|
|
|
#[poise::command(prefix_command, slash_command, user_cooldown = 86400)]
|
|
async fn switch_rank_track(ctx: ManifoldContext<'_>, #[description = "Track to switch to: officer or enlisted"] track: String) -> ManifoldResult<()> {
|
|
let db = &ctx.data().database;
|
|
let user_id_i64 = ctx.author().id.as_u64().clone() as i64;
|
|
|
|
let mut xp = match Xp::get(db, &user_id_i64) {
|
|
Ok(x) => x,
|
|
Err(_) => Xp::new(&user_id_i64)
|
|
};
|
|
|
|
let parsed_track = Track::get_track_by_name(db, &track)?;
|
|
if xp.rank_track != parsed_track.track_id {
|
|
let current_level_rank = Rank::get_rank_for_level(db, &xp.user_current_level, &xp.rank_track)?;
|
|
let new_level_rank = Rank::get_rank_for_level(db, &xp.user_current_level, &parsed_track.track_id)?;
|
|
|
|
if let Some(mut member) = ctx.author_member().await {
|
|
member.to_mut().remove_role(ctx, current_level_rank.role_id as u64).await?;
|
|
member.to_mut().add_role(ctx, new_level_rank.role_id as u64).await?;
|
|
}
|
|
|
|
xp.rank_track = parsed_track.track_id;
|
|
|
|
ctx.reply(t!("commands.ranks.track_switch", new_track = parsed_track.track_name, new_rank = new_level_rank.rank_name)).await?;
|
|
xp.rank_track_last_changed = Some(chrono::Utc::now().timestamp());
|
|
xp.insert(db)?;
|
|
} else {
|
|
ctx.reply(t!("commands.ranks.track_switch.failure", rank_track = parsed_track.track_name)).await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(prefix_command, slash_command, user_cooldown = 86400)]
|
|
async fn freeze_rank(ctx: ManifoldContext<'_>, #[rest] #[description = "Rank to lock yourself at. Omit to unfreeze your progression."] rank: Option<String>) -> ManifoldResult<()> {
|
|
let db = &ctx.data().database;
|
|
let user_id_i64 = ctx.author().id.as_u64().clone() as i64;
|
|
|
|
let mut xp = match Xp::get(db, &user_id_i64) {
|
|
Ok(x) => x,
|
|
Err(_) => Xp::new(&user_id_i64)
|
|
};
|
|
|
|
if let Some(r) = rank {
|
|
let frozen_rank = match Rank::get_rank_by_name(db, &r, &xp.rank_track) {
|
|
Ok(r) => r,
|
|
Err(e) => {
|
|
error!("Rank lookup error: {}", e);
|
|
ctx.reply(t!("commands.ranks.rank_freeze.not_found")).await?;
|
|
Err(e)?
|
|
}
|
|
};
|
|
|
|
if let Some(fr) = xp.freeze_rank {
|
|
// Remove any old frozen rank
|
|
if let Some(mut member) = ctx.author_member().await {
|
|
member.to_mut().remove_role(ctx, fr as u64).await?;
|
|
}
|
|
}
|
|
|
|
xp.freeze_rank = Some(frozen_rank.role_id.clone() as i64);
|
|
|
|
if let Some(mut member) = ctx.author_member().await {
|
|
member.to_mut().add_role(ctx, frozen_rank.role_id as u64).await?;
|
|
ctx.reply(t!("commands.ranks.rank_freeze.success", rank = frozen_rank.rank_name)).await?;
|
|
}
|
|
|
|
} else {
|
|
if let Some(fr) = xp.freeze_rank {
|
|
// Remove any old frozen rank
|
|
if let Some(mut member) = ctx.author_member().await {
|
|
member.to_mut().remove_role(ctx, fr as u64).await?;
|
|
}
|
|
|
|
xp.freeze_rank = None;
|
|
ctx.reply(t!("commands.ranks.rank_unfreeze.success")).await?;
|
|
} else {
|
|
ctx.reply(t!("commands.ranks.rank_unfreeze.failure")).await?;
|
|
}
|
|
}
|
|
|
|
xp.freeze_rank_last_changed = Some(chrono::Utc::now().timestamp());
|
|
xp.insert(db)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(prefix_command, slash_command)]
|
|
async fn rank(ctx: ManifoldContext<'_>) -> ManifoldResult<()> {
|
|
let db = &ctx.data().database;
|
|
let user_id_i64 = ctx.author().id.as_u64().clone() as i64;
|
|
|
|
let xp = match Xp::get(db, &user_id_i64) {
|
|
Ok(x) => x,
|
|
Err(_) => Xp::new(&user_id_i64)
|
|
};
|
|
|
|
let current_rank = Rank::get_rank_for_level(db, &xp.user_current_level, &xp.rank_track).unwrap_or(Rank::new());
|
|
|
|
let next_level_xp = xp.get_xp_to_next_level(&db);
|
|
let next_rank_xp = xp.get_xp_to_next_rank(&db).unwrap_or(0);
|
|
|
|
let mut response = t!("commands.ranks.rank.current_rank", current_rank = RoleId::from(current_rank.role_id as u64).mention(), next_level_xp = next_level_xp);
|
|
if next_rank_xp == 0 {
|
|
response = t!("commands.ranks.rank.max_rank", reponse = response);
|
|
} else if next_rank_xp == next_level_xp {
|
|
response = t!("commands.ranks.rank.and_rank", response = response);
|
|
} else {
|
|
response = t!("commands.ranks.rank.and_rank_different_level", response = response, next_rank_xp = next_rank_xp);
|
|
}
|
|
|
|
ctx.reply(response).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[poise::command(prefix_command, slash_command)]
|
|
async fn leaderboard(ctx: ManifoldContext<'_>) -> ManifoldResult<()> {
|
|
|
|
let reply_handle = ctx.reply("Retrieving leaderboard, please stand by...".to_string()).await?;
|
|
let entries_per_page = 20;
|
|
let mut pages = Vec::<CreateEmbed>::new();
|
|
let leaderboard = Leaderboard::get_leaderboard(&ctx.data().database)?;
|
|
let userinfo = ctx.data().user_info.lock().await;
|
|
let total = leaderboard.rows.len();
|
|
let pages_needed = (total / entries_per_page) + 1;
|
|
|
|
for i in 0..pages_needed {
|
|
let mut page = CreateEmbed::default()
|
|
.title(format!("XP Leaderboard Page {page} of {total_pages}", page=(i + 1), total_pages=&pages_needed)).to_owned();
|
|
|
|
let offset = i*entries_per_page;
|
|
let mut leaderboard_rows = Vec::new();
|
|
|
|
leaderboard.rows.iter().skip(offset).enumerate().for_each(|(j, f)| {
|
|
// cap at per-page limit
|
|
if j >= entries_per_page {
|
|
return;
|
|
}
|
|
|
|
let mut row = f.to_owned();
|
|
row.rank = (j + 1 + offset) as i32;
|
|
row.user_name = userinfo.get(&(row.uid as u64)).unwrap().username.clone();
|
|
|
|
leaderboard_rows.push(row);
|
|
});
|
|
|
|
let leaderboard_table = MarkdownTable::new(Some(vec!["Rank".to_string(), "User".to_string(), "XP".to_string()]), leaderboard_rows)?;
|
|
|
|
page.description(format!("```{table}```", table=leaderboard_table));
|
|
|
|
pages.push(page);
|
|
}
|
|
|
|
if pages.len() == 0 {
|
|
ctx.reply("No leaderboard entries yet!".to_string()).await?;
|
|
return Ok(())
|
|
}
|
|
|
|
manifold::helpers::paginate(ctx, reply_handle, pages, 0).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn commands() -> [poise::Command<ManifoldData, ManifoldError>; 4] {
|
|
[switch_rank_track(), freeze_rank(), rank(), leaderboard()]
|
|
}
|