cuqueclicker_lib/save/versions/
v1.rs1use serde::{Deserialize, Serialize};
13use std::collections::{HashMap, HashSet};
14
15use crate::game::state::GameState;
16
17#[derive(Clone, Debug, Serialize, Deserialize)]
22pub enum BuffV1 {
23 ClickFrenzy {
24 ticks_remaining: u32,
25 initial_ticks: u32,
26 mult: f64,
27 },
28 FingererBoost {
29 ticks_remaining: u32,
30 initial_ticks: u32,
31 fingerer_id: String,
32 mult: f64,
33 },
34}
35
36#[derive(Clone, Serialize, Deserialize)]
40pub struct GameStateV1 {
41 #[serde(default)]
42 pub cuques: f64,
43 #[serde(default)]
44 pub total_clicks: u64,
45 #[serde(default)]
46 pub lifetime_cuques: f64,
47 #[serde(default)]
48 pub best_fps: f64,
49 #[serde(default)]
50 pub golden_caught: u64,
51 #[serde(default)]
52 pub fingerers_owned: HashMap<String, u32>,
53 #[serde(default)]
54 pub achievements_earned: HashSet<String>,
55 #[serde(default)]
56 pub upgrades_earned: HashSet<String>,
57 #[serde(default)]
58 pub prestige: u64,
59 #[serde(default)]
60 pub total_play_ticks: u64,
61 #[serde(default)]
62 pub buffs: Vec<BuffV1>,
63}
64
65impl GameStateV1 {
66 pub fn into_current(self) -> GameState {
72 super::v2::GameStateV2::from(self).into_current()
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use crate::game::state::Buff;
80
81 #[test]
82 fn into_current_preserves_all_persisted_fields() {
83 let v1 = GameStateV1 {
84 cuques: 12345.6,
85 total_clicks: 42,
86 lifetime_cuques: 99999.0,
87 best_fps: 17.5,
88 golden_caught: 3,
89 fingerers_owned: [("index_finger".into(), 9), ("latex_glove".into(), 4)]
90 .into_iter()
91 .collect(),
92 achievements_earned: ["first_finger".into()].into_iter().collect(),
93 upgrades_earned: ["click_mult_1".into()].into_iter().collect(),
94 prestige: 7,
95 total_play_ticks: 1000,
96 buffs: vec![BuffV1::ClickFrenzy {
97 ticks_remaining: 100,
98 initial_ticks: 260,
99 mult: 777.0,
100 }],
101 };
102
103 let s = v1.into_current();
104
105 assert_eq!(s.version, crate::save::CURRENT_VERSION);
106 assert_eq!(s.cuques, crate::bignum::Mag::from_f64(12345.6));
107 assert_eq!(s.total_clicks, 42);
108 assert_eq!(s.lifetime_cuques, crate::bignum::Mag::from_f64(99999.0));
109 assert_eq!(s.best_fps, crate::bignum::Mag::from_f64(17.5));
110 assert_eq!(s.golden_caught, 3);
111 assert_eq!(s.fingerer_count("index_finger"), 9);
112 assert_eq!(s.fingerer_count("latex_glove"), 4);
113 assert!(s.has_achievement("first_finger"));
114 assert!(s.tree.bought.is_empty());
119 assert_eq!(s.prestige, 7);
120 assert_eq!(s.total_play_ticks, 1000);
121 assert_eq!(s.buffs.len(), 1);
122 assert!(matches!(
123 s.buffs[0],
124 Buff::ClickFrenzy {
125 ticks_remaining: 100,
126 ..
127 }
128 ));
129 }
130
131 #[test]
132 fn in_flight_fingerer_boost_becomes_purple_modifier() {
133 let v1 = GameStateV1 {
137 buffs: vec![BuffV1::FingererBoost {
138 ticks_remaining: 600,
139 initial_ticks: 1200,
140 fingerer_id: "latex_glove".into(),
141 mult: 7.0,
142 }],
143 ..GameStateV1 {
144 cuques: 0.0,
145 total_clicks: 0,
146 lifetime_cuques: 0.0,
147 best_fps: 0.0,
148 golden_caught: 0,
149 fingerers_owned: HashMap::new(),
150 achievements_earned: HashSet::new(),
151 upgrades_earned: HashSet::new(),
152 prestige: 0,
153 total_play_ticks: 0,
154 buffs: vec![],
155 }
156 };
157
158 let s = v1.into_current();
159
160 assert!(
162 s.buffs
163 .iter()
164 .all(|b| matches!(b, Buff::ClickFrenzy { .. }))
165 );
166
167 let st = s
168 .fingerers_state
169 .get("latex_glove")
170 .expect("modifier attached to target fingerer");
171 assert_eq!(st.modifiers.len(), 1);
172 let m = &st.modifiers[0];
173 assert!(matches!(
174 m.source,
175 crate::game::modifier::ModifierSource::PurpleCoin
176 ));
177 assert!(matches!(
178 m.duration,
179 crate::game::modifier::ModifierDuration::Ticks(600)
180 ));
181 assert!((st.aggregate.mul_factor.to_f64() - 7.0).abs() < 1e-9);
183 }
184}