use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use crate::game::state::GameState;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum BuffV1 {
ClickFrenzy {
ticks_remaining: u32,
initial_ticks: u32,
mult: f64,
},
FingererBoost {
ticks_remaining: u32,
initial_ticks: u32,
fingerer_id: String,
mult: f64,
},
}
#[derive(Clone, Serialize, Deserialize)]
pub struct GameStateV1 {
#[serde(default)]
pub cuques: f64,
#[serde(default)]
pub total_clicks: u64,
#[serde(default)]
pub lifetime_cuques: f64,
#[serde(default)]
pub best_fps: f64,
#[serde(default)]
pub golden_caught: u64,
#[serde(default)]
pub fingerers_owned: HashMap<String, u32>,
#[serde(default)]
pub achievements_earned: HashSet<String>,
#[serde(default)]
pub upgrades_earned: HashSet<String>,
#[serde(default)]
pub prestige: u64,
#[serde(default)]
pub total_play_ticks: u64,
#[serde(default)]
pub buffs: Vec<BuffV1>,
}
impl GameStateV1 {
pub fn into_current(self) -> GameState {
super::v2::GameStateV2::from(self).into_current()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::game::state::Buff;
#[test]
fn into_current_preserves_all_persisted_fields() {
let v1 = GameStateV1 {
cuques: 12345.6,
total_clicks: 42,
lifetime_cuques: 99999.0,
best_fps: 17.5,
golden_caught: 3,
fingerers_owned: [("index_finger".into(), 9), ("latex_glove".into(), 4)]
.into_iter()
.collect(),
achievements_earned: ["first_finger".into()].into_iter().collect(),
upgrades_earned: ["click_mult_1".into()].into_iter().collect(),
prestige: 7,
total_play_ticks: 1000,
buffs: vec![BuffV1::ClickFrenzy {
ticks_remaining: 100,
initial_ticks: 260,
mult: 777.0,
}],
};
let s = v1.into_current();
assert_eq!(s.version, crate::save::CURRENT_VERSION);
assert_eq!(s.cuques, crate::bignum::Mag::from_f64(12345.6));
assert_eq!(s.total_clicks, 42);
assert_eq!(s.lifetime_cuques, crate::bignum::Mag::from_f64(99999.0));
assert_eq!(s.best_fps, crate::bignum::Mag::from_f64(17.5));
assert_eq!(s.golden_caught, 3);
assert_eq!(s.fingerer_count("index_finger"), 9);
assert_eq!(s.fingerer_count("latex_glove"), 4);
assert!(s.has_achievement("first_finger"));
assert!(s.tree.bought.is_empty());
assert_eq!(s.prestige, 7);
assert_eq!(s.total_play_ticks, 1000);
assert_eq!(s.buffs.len(), 1);
assert!(matches!(
s.buffs[0],
Buff::ClickFrenzy {
ticks_remaining: 100,
..
}
));
}
#[test]
fn in_flight_fingerer_boost_becomes_purple_modifier() {
let v1 = GameStateV1 {
buffs: vec![BuffV1::FingererBoost {
ticks_remaining: 600,
initial_ticks: 1200,
fingerer_id: "latex_glove".into(),
mult: 7.0,
}],
..GameStateV1 {
cuques: 0.0,
total_clicks: 0,
lifetime_cuques: 0.0,
best_fps: 0.0,
golden_caught: 0,
fingerers_owned: HashMap::new(),
achievements_earned: HashSet::new(),
upgrades_earned: HashSet::new(),
prestige: 0,
total_play_ticks: 0,
buffs: vec![],
}
};
let s = v1.into_current();
assert!(
s.buffs
.iter()
.all(|b| matches!(b, Buff::ClickFrenzy { .. }))
);
let st = s
.fingerers_state
.get("latex_glove")
.expect("modifier attached to target fingerer");
assert_eq!(st.modifiers.len(), 1);
let m = &st.modifiers[0];
assert!(matches!(
m.source,
crate::game::modifier::ModifierSource::PurpleCoin
));
assert!(matches!(
m.duration,
crate::game::modifier::ModifierDuration::Ticks(600)
));
assert!((st.aggregate.mul_factor.to_f64() - 7.0).abs() < 1e-9);
}
}