Add the ability to contribute to improvements without buying them outright
This commit is contained in:
parent
30767e8e0e
commit
d03f33ea6d
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1093,7 +1093,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fren"
|
name = "fren"
|
||||||
version = "2.5.1"
|
version = "2.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum 0.8.1",
|
"axum 0.8.1",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "fren"
|
name = "fren"
|
||||||
version = "2.5.1"
|
version = "2.6.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
@ -15,22 +15,33 @@ pub async fn improvements(ctx: Context<'_>) -> Result<(), Error> {
|
|||||||
msg_builder.push_line("Anything can be improved with enough Fren Coins!");
|
msg_builder.push_line("Anything can be improved with enough Fren Coins!");
|
||||||
msg_builder.push_line("");
|
msg_builder.push_line("");
|
||||||
|
|
||||||
|
let improvements = Improvements::get_improvement_config(&ctx.data().db)?;
|
||||||
|
|
||||||
for improvement_type in ImprovementType::iter() {
|
for improvement_type in ImprovementType::iter() {
|
||||||
msg_builder.push("* ");
|
msg_builder.push("* ");
|
||||||
if let Some(improvement) = Improvements::get_improvement(&ctx.data().db, improvement_type)?
|
|
||||||
{
|
if let Some(improvement) = improvements.get_improvement(&improvement_type) {
|
||||||
if improvement_type.has_levels() {
|
if improvement.has_at_least_one_level() {
|
||||||
msg_builder.push(format!(
|
if improvement_type.has_levels() {
|
||||||
"({} FC Level={}) ",
|
msg_builder.push(format!(
|
||||||
improvement_type.price().separate_with_commas(),
|
"({}/{} FC Level={}) ",
|
||||||
improvement.level
|
improvement.funding_amount.separate_with_commas(),
|
||||||
));
|
improvement_type.price().separate_with_commas(),
|
||||||
|
improvement.level
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
msg_builder.push(" (✅) ");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
msg_builder.push(" (✅) ");
|
msg_builder.push(format!(
|
||||||
|
"({}/{} FC) ",
|
||||||
|
improvement.funding_amount.separate_with_commas(),
|
||||||
|
improvement_type.price().separate_with_commas(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
msg_builder.push(format!(
|
msg_builder.push(format!(
|
||||||
"({} FC) ",
|
"(0/{} FC) ",
|
||||||
improvement_type.price().separate_with_commas()
|
improvement_type.price().separate_with_commas()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -51,13 +62,14 @@ pub async fn improvements(ctx: Context<'_>) -> Result<(), Error> {
|
|||||||
#[poise::command(prefix_command, guild_only, category = "Improvements")]
|
#[poise::command(prefix_command, guild_only, category = "Improvements")]
|
||||||
pub async fn buy_improvement(
|
pub async fn buy_improvement(
|
||||||
ctx: Context<'_>,
|
ctx: Context<'_>,
|
||||||
#[description = "Improvement to buy"]
|
#[min = 0u32]
|
||||||
|
#[description = "Amount to contribute"]
|
||||||
|
amount: u32,
|
||||||
|
#[description = "Improvement to contribute to"]
|
||||||
#[rest]
|
#[rest]
|
||||||
improvement_type: ImprovementType,
|
improvement_type: ImprovementType,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if Improvements::get_improvement(&ctx.data().db, improvement_type)?.is_some()
|
if Improvements::check_is_completed(&ctx.data().db, improvement_type)? {
|
||||||
&& !improvement_type.has_levels()
|
|
||||||
{
|
|
||||||
ctx.reply("Sorry, that improvement has already been purchased.")
|
ctx.reply("Sorry, that improvement has already been purchased.")
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -69,9 +81,18 @@ pub async fn buy_improvement(
|
|||||||
improvement_type.price() as u32,
|
improvement_type.price() as u32,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Improvements::increment_improvement(&ctx.data().db, improvement_type)?;
|
let (has_improved, _) =
|
||||||
|
Improvements::contribute_to_improvement(&ctx.data().db, improvement_type, amount as u64)?;
|
||||||
|
|
||||||
ctx.reply(improvement_type.post_buy_description()).await?;
|
if has_improved {
|
||||||
|
ctx.reply(improvement_type.post_buy_description()).await?;
|
||||||
|
} else {
|
||||||
|
ctx.reply(format!(
|
||||||
|
"Thank you for contributing to {}",
|
||||||
|
improvement_type.name()
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -79,9 +100,8 @@ pub async fn buy_improvement(
|
|||||||
/// View Friendship Tower and all its glory!!!
|
/// View Friendship Tower and all its glory!!!
|
||||||
#[poise::command(prefix_command, guild_only, category = "Improvements")]
|
#[poise::command(prefix_command, guild_only, category = "Improvements")]
|
||||||
pub async fn friendship_tower(ctx: Context<'_>) -> Result<(), Error> {
|
pub async fn friendship_tower(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
if let Some(tower) =
|
let improvements = Improvements::get_improvement_config(&ctx.data().db)?;
|
||||||
Improvements::get_improvement(&ctx.data().db, ImprovementType::FriendshipTower)?
|
if let Some(tower) = improvements.get_improvement(&ImprovementType::FriendshipTower) {
|
||||||
{
|
|
||||||
let buffer = 2;
|
let buffer = 2;
|
||||||
let pic_height = tower.level as usize + buffer + 1;
|
let pic_height = tower.level as usize + buffer + 1;
|
||||||
let width = 5;
|
let width = 5;
|
||||||
@ -116,13 +136,13 @@ pub async fn friendship_tower(ctx: Context<'_>) -> Result<(), Error> {
|
|||||||
/// See how big Jotchua's college fund is!
|
/// See how big Jotchua's college fund is!
|
||||||
#[poise::command(prefix_command, guild_only, category = "Improvements")]
|
#[poise::command(prefix_command, guild_only, category = "Improvements")]
|
||||||
pub async fn jotchua_college_fund(ctx: Context<'_>) -> Result<(), Error> {
|
pub async fn jotchua_college_fund(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
let funds_level = if let Some(fund) =
|
let improvements = Improvements::get_improvement_config(&ctx.data().db)?;
|
||||||
Improvements::get_improvement(&ctx.data().db, ImprovementType::JotchuaCollegeFund)?
|
let funds_level =
|
||||||
{
|
if let Some(fund) = improvements.get_improvement(&ImprovementType::JotchuaCollegeFund) {
|
||||||
fund.level
|
fund.level
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
let college_savings = funds_level as u64 * ImprovementType::JotchuaCollegeFund.price();
|
let college_savings = funds_level as u64 * ImprovementType::JotchuaCollegeFund.price();
|
||||||
|
|
||||||
|
|||||||
49
src/migrations/migration_10_add_funding_amount.rs
Normal file
49
src/migrations/migration_10_add_funding_amount.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use j_db::database::Database;
|
||||||
|
use j_db::migration::Migration;
|
||||||
|
use json::JsonValue;
|
||||||
|
|
||||||
|
pub struct Migration10AddFundingAmount {}
|
||||||
|
|
||||||
|
impl Migration for Migration10AddFundingAmount {
|
||||||
|
fn up(&self, db: &Database) -> j_db::error::Result<()> {
|
||||||
|
let tree = db.db.open_tree("Improvements")?;
|
||||||
|
|
||||||
|
for improvement_entry in tree.iter() {
|
||||||
|
let (id, improvement_bytes) = improvement_entry?;
|
||||||
|
|
||||||
|
let mut improvement_cfg =
|
||||||
|
json::parse(std::str::from_utf8(&improvement_bytes).unwrap())?;
|
||||||
|
|
||||||
|
for (_, improvement) in improvement_cfg["improvements"].entries_mut() {
|
||||||
|
improvement["funding_amount"] = JsonValue::Number(json::number::Number::from(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.insert(id, improvement_cfg.to_string().into_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn down(&self, db: &Database) -> j_db::error::Result<()> {
|
||||||
|
let tree = db.db.open_tree("Improvements")?;
|
||||||
|
|
||||||
|
for improvement_entry in tree.iter() {
|
||||||
|
let (id, improvement_bytes) = improvement_entry?;
|
||||||
|
|
||||||
|
let mut improvement_cfg =
|
||||||
|
json::parse(std::str::from_utf8(&improvement_bytes).unwrap())?;
|
||||||
|
|
||||||
|
for improvement in improvement_cfg["improvements"].members_mut() {
|
||||||
|
improvement.remove("funding_amount");
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.insert(id, improvement_cfg.to_string().into_bytes())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(&self) -> u64 {
|
||||||
|
10
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ use crate::migrations::migration_6_add_social_credit::Migration6AddSocialCredit;
|
|||||||
use crate::migrations::migration_7_flip_bounds::Migration7FlipBounds;
|
use crate::migrations::migration_7_flip_bounds::Migration7FlipBounds;
|
||||||
use crate::migrations::migration_8_fix_metadata_id::Migration8FixMetadataId;
|
use crate::migrations::migration_8_fix_metadata_id::Migration8FixMetadataId;
|
||||||
use crate::migrations::migration_9_update_to_emp::Migration9UpdateToEMP;
|
use crate::migrations::migration_9_update_to_emp::Migration9UpdateToEMP;
|
||||||
|
use crate::migrations::migration_10_add_funding_amount::Migration10AddFundingAmount;
|
||||||
use crate::migrations::migration2_remove_imgur::Migration2RemoveImgur;
|
use crate::migrations::migration2_remove_imgur::Migration2RemoveImgur;
|
||||||
use crate::migrations::migration3_remove_img::Migration3RemoveImage;
|
use crate::migrations::migration3_remove_img::Migration3RemoveImage;
|
||||||
use j_db::database::Database;
|
use j_db::database::Database;
|
||||||
@ -12,6 +13,7 @@ use j_db::migration::Direction;
|
|||||||
|
|
||||||
mod migration2_remove_imgur;
|
mod migration2_remove_imgur;
|
||||||
mod migration3_remove_img;
|
mod migration3_remove_img;
|
||||||
|
mod migration_10_add_funding_amount;
|
||||||
mod migration_4_update_random;
|
mod migration_4_update_random;
|
||||||
mod migration_5_update_motivation;
|
mod migration_5_update_motivation;
|
||||||
mod migration_6_add_social_credit;
|
mod migration_6_add_social_credit;
|
||||||
@ -19,7 +21,7 @@ mod migration_7_flip_bounds;
|
|||||||
mod migration_8_fix_metadata_id;
|
mod migration_8_fix_metadata_id;
|
||||||
mod migration_9_update_to_emp;
|
mod migration_9_update_to_emp;
|
||||||
|
|
||||||
pub const CURRENT_DB_VERSION: u64 = 9;
|
pub const CURRENT_DB_VERSION: u64 = 10;
|
||||||
|
|
||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
pub fn do_migration(db: &Database) {
|
pub fn do_migration(db: &Database) {
|
||||||
@ -80,6 +82,12 @@ pub fn do_migration(db: &Database) {
|
|||||||
Direction::Up,
|
Direction::Up,
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
10 => migration::do_migration::<Migration10AddFundingAmount>(
|
||||||
|
db,
|
||||||
|
Migration10AddFundingAmount {},
|
||||||
|
Direction::Up,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,7 +84,7 @@ impl GogurtReserves {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_night_market(db: &Database) -> Result<bool, Error> {
|
pub fn has_night_market(db: &Database) -> Result<bool, Error> {
|
||||||
Ok(Improvements::get_improvement(db, ImprovementType::GogurtNightMarket)?.is_some())
|
Improvements::check_is_completed(db, ImprovementType::GogurtNightMarket)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_next_market_update_time(db: &Database) -> Result<DateTime<Utc>, Error> {
|
pub fn get_next_market_update_time(db: &Database) -> Result<DateTime<Utc>, Error> {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use j_db::database::Database;
|
use j_db::database::Database;
|
||||||
use j_db::model::JdbModel;
|
use j_db::model::JdbModel;
|
||||||
|
use log::info;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
@ -105,6 +106,13 @@ impl FromStr for ImprovementType {
|
|||||||
#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)]
|
#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)]
|
||||||
pub struct Improvement {
|
pub struct Improvement {
|
||||||
pub level: u32,
|
pub level: u32,
|
||||||
|
pub funding_amount: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Improvement {
|
||||||
|
pub fn has_at_least_one_level(&self) -> bool {
|
||||||
|
self.level > 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
@ -121,40 +129,71 @@ impl Improvements {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_improvement(
|
pub fn get_improvement_mut(&mut self, improvement_type: ImprovementType) -> &mut Improvement {
|
||||||
db: &Database,
|
(self
|
||||||
improvement_type: ImprovementType,
|
|
||||||
) -> Result<Option<Improvement>, Error> {
|
|
||||||
let improvements = Self::get_improvement_config(db)?;
|
|
||||||
|
|
||||||
Ok(improvements.improvements.get(&improvement_type).cloned())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn increment_improvement(
|
|
||||||
db: &Database,
|
|
||||||
improvement_type: ImprovementType,
|
|
||||||
) -> Result<u32, Error> {
|
|
||||||
let mut improvements = Self::get_improvement_config(db)?;
|
|
||||||
|
|
||||||
let entry = improvements
|
|
||||||
.improvements
|
.improvements
|
||||||
.entry(improvement_type)
|
.entry(improvement_type)
|
||||||
.or_insert(Improvement { level: 0 });
|
.or_insert(Improvement {
|
||||||
|
level: 0,
|
||||||
|
funding_amount: 0,
|
||||||
|
})) as _
|
||||||
|
}
|
||||||
|
|
||||||
entry.level += 1;
|
pub fn get_improvement(&self, improvement_type: &ImprovementType) -> Option<&Improvement> {
|
||||||
|
self.improvements.get(improvement_type)
|
||||||
|
}
|
||||||
|
|
||||||
let level = entry.level;
|
pub fn contribute_to_improvement(
|
||||||
|
db: &Database,
|
||||||
|
improvement_type: ImprovementType,
|
||||||
|
amount: u64,
|
||||||
|
) -> Result<(bool, u32), Error> {
|
||||||
|
let mut improvements = Self::get_improvement_config(db)?;
|
||||||
|
|
||||||
|
let improvement = improvements.get_improvement_mut(improvement_type);
|
||||||
|
|
||||||
|
improvement.funding_amount += amount;
|
||||||
|
|
||||||
|
let has_improved = if improvement.funding_amount >= improvement_type.price() {
|
||||||
|
let levels_to_fund = improvement.funding_amount / improvement_type.price();
|
||||||
|
info!(
|
||||||
|
"Increasing improvement {} by {} levels",
|
||||||
|
improvement_type.name(),
|
||||||
|
levels_to_fund,
|
||||||
|
);
|
||||||
|
|
||||||
|
improvement.level += levels_to_fund as u32;
|
||||||
|
improvement.funding_amount -= improvement_type.price() * levels_to_fund;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
let level = improvement.level;
|
||||||
|
|
||||||
db.insert(improvements)?;
|
db.insert(improvements)?;
|
||||||
|
|
||||||
Ok(level)
|
Ok((has_improved, level))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_improvement(
|
pub fn has_improvement(&self, improvement_type: ImprovementType) -> bool {
|
||||||
|
if let Some(improvement) = self.get_improvement(&improvement_type) {
|
||||||
|
improvement.has_at_least_one_level()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_completed(&self, improvement_type: ImprovementType) -> bool {
|
||||||
|
self.has_improvement(improvement_type) && !improvement_type.has_levels()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_is_completed(
|
||||||
db: &Database,
|
db: &Database,
|
||||||
improvement_type: ImprovementType,
|
improvement_type: ImprovementType,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
Ok(Self::get_improvement(db, improvement_type)?.is_some())
|
let improvements = Improvements::get_improvement_config(db)?;
|
||||||
|
Ok(improvements.is_completed(improvement_type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -338,7 +338,7 @@ impl LilFren {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if lil_fren.hunger < 0.25
|
if lil_fren.hunger < 0.25
|
||||||
&& Improvements::has_improvement(db, ImprovementType::LilBuddyAutoFeeder)?
|
&& Improvements::check_is_completed(db, ImprovementType::LilBuddyAutoFeeder)?
|
||||||
{
|
{
|
||||||
lil_fren.hunger = 0.25;
|
lil_fren.hunger = 0.25;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user