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]]
|
||||
name = "fren"
|
||||
version = "2.5.1"
|
||||
version = "2.6.0"
|
||||
dependencies = [
|
||||
"axum 0.8.1",
|
||||
"base64 0.22.1",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "fren"
|
||||
version = "2.5.1"
|
||||
version = "2.6.0"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -15,13 +15,17 @@ pub async fn improvements(ctx: Context<'_>) -> Result<(), Error> {
|
||||
msg_builder.push_line("Anything can be improved with enough Fren Coins!");
|
||||
msg_builder.push_line("");
|
||||
|
||||
let improvements = Improvements::get_improvement_config(&ctx.data().db)?;
|
||||
|
||||
for improvement_type in ImprovementType::iter() {
|
||||
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.has_at_least_one_level() {
|
||||
if improvement_type.has_levels() {
|
||||
msg_builder.push(format!(
|
||||
"({} FC Level={}) ",
|
||||
"({}/{} FC Level={}) ",
|
||||
improvement.funding_amount.separate_with_commas(),
|
||||
improvement_type.price().separate_with_commas(),
|
||||
improvement.level
|
||||
));
|
||||
@ -30,7 +34,14 @@ pub async fn improvements(ctx: Context<'_>) -> Result<(), Error> {
|
||||
}
|
||||
} else {
|
||||
msg_builder.push(format!(
|
||||
"({} FC) ",
|
||||
"({}/{} FC) ",
|
||||
improvement.funding_amount.separate_with_commas(),
|
||||
improvement_type.price().separate_with_commas(),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
msg_builder.push(format!(
|
||||
"(0/{} FC) ",
|
||||
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")]
|
||||
pub async fn buy_improvement(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Improvement to buy"]
|
||||
#[min = 0u32]
|
||||
#[description = "Amount to contribute"]
|
||||
amount: u32,
|
||||
#[description = "Improvement to contribute to"]
|
||||
#[rest]
|
||||
improvement_type: ImprovementType,
|
||||
) -> Result<(), Error> {
|
||||
if Improvements::get_improvement(&ctx.data().db, improvement_type)?.is_some()
|
||||
&& !improvement_type.has_levels()
|
||||
{
|
||||
if Improvements::check_is_completed(&ctx.data().db, improvement_type)? {
|
||||
ctx.reply("Sorry, that improvement has already been purchased.")
|
||||
.await?;
|
||||
return Ok(());
|
||||
@ -69,9 +81,18 @@ pub async fn buy_improvement(
|
||||
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)?;
|
||||
|
||||
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(())
|
||||
}
|
||||
@ -79,9 +100,8 @@ pub async fn buy_improvement(
|
||||
/// View Friendship Tower and all its glory!!!
|
||||
#[poise::command(prefix_command, guild_only, category = "Improvements")]
|
||||
pub async fn friendship_tower(ctx: Context<'_>) -> Result<(), Error> {
|
||||
if let Some(tower) =
|
||||
Improvements::get_improvement(&ctx.data().db, ImprovementType::FriendshipTower)?
|
||||
{
|
||||
let improvements = Improvements::get_improvement_config(&ctx.data().db)?;
|
||||
if let Some(tower) = improvements.get_improvement(&ImprovementType::FriendshipTower) {
|
||||
let buffer = 2;
|
||||
let pic_height = tower.level as usize + buffer + 1;
|
||||
let width = 5;
|
||||
@ -116,9 +136,9 @@ pub async fn friendship_tower(ctx: Context<'_>) -> Result<(), Error> {
|
||||
/// See how big Jotchua's college fund is!
|
||||
#[poise::command(prefix_command, guild_only, category = "Improvements")]
|
||||
pub async fn jotchua_college_fund(ctx: Context<'_>) -> Result<(), Error> {
|
||||
let funds_level = if let Some(fund) =
|
||||
Improvements::get_improvement(&ctx.data().db, ImprovementType::JotchuaCollegeFund)?
|
||||
{
|
||||
let improvements = Improvements::get_improvement_config(&ctx.data().db)?;
|
||||
let funds_level =
|
||||
if let Some(fund) = improvements.get_improvement(&ImprovementType::JotchuaCollegeFund) {
|
||||
fund.level
|
||||
} else {
|
||||
0
|
||||
|
||||
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_8_fix_metadata_id::Migration8FixMetadataId;
|
||||
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::migration3_remove_img::Migration3RemoveImage;
|
||||
use j_db::database::Database;
|
||||
@ -12,6 +13,7 @@ use j_db::migration::Direction;
|
||||
|
||||
mod migration2_remove_imgur;
|
||||
mod migration3_remove_img;
|
||||
mod migration_10_add_funding_amount;
|
||||
mod migration_4_update_random;
|
||||
mod migration_5_update_motivation;
|
||||
mod migration_6_add_social_credit;
|
||||
@ -19,7 +21,7 @@ mod migration_7_flip_bounds;
|
||||
mod migration_8_fix_metadata_id;
|
||||
mod migration_9_update_to_emp;
|
||||
|
||||
pub const CURRENT_DB_VERSION: u64 = 9;
|
||||
pub const CURRENT_DB_VERSION: u64 = 10;
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
pub fn do_migration(db: &Database) {
|
||||
@ -80,6 +82,12 @@ pub fn do_migration(db: &Database) {
|
||||
Direction::Up,
|
||||
)
|
||||
.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> {
|
||||
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> {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use crate::error::Error;
|
||||
use j_db::database::Database;
|
||||
use j_db::model::JdbModel;
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
@ -105,6 +106,13 @@ impl FromStr for ImprovementType {
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)]
|
||||
pub struct Improvement {
|
||||
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)]
|
||||
@ -121,40 +129,71 @@ impl Improvements {
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn get_improvement(
|
||||
db: &Database,
|
||||
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
|
||||
pub fn get_improvement_mut(&mut self, improvement_type: ImprovementType) -> &mut Improvement {
|
||||
(self
|
||||
.improvements
|
||||
.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)?;
|
||||
|
||||
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,
|
||||
improvement_type: ImprovementType,
|
||||
) -> 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
|
||||
&& Improvements::has_improvement(db, ImprovementType::LilBuddyAutoFeeder)?
|
||||
&& Improvements::check_is_completed(db, ImprovementType::LilBuddyAutoFeeder)?
|
||||
{
|
||||
lil_fren.hunger = 0.25;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user