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, 12345.6);
107 assert_eq!(s.total_clicks, 42);
108 assert_eq!(s.lifetime_cuques, 99999.0);
109 assert_eq!(s.best_fps, 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.has_upgrade("click_mult_1"));
115 assert_eq!(s.prestige, 7);
116 assert_eq!(s.total_play_ticks, 1000);
117 assert_eq!(s.buffs.len(), 1);
118 assert!(matches!(
119 s.buffs[0],
120 Buff::ClickFrenzy {
121 ticks_remaining: 100,
122 ..
123 }
124 ));
125 }
126
127 #[test]
128 fn in_flight_fingerer_boost_becomes_purple_modifier() {
129 let v1 = GameStateV1 {
133 buffs: vec![BuffV1::FingererBoost {
134 ticks_remaining: 600,
135 initial_ticks: 1200,
136 fingerer_id: "latex_glove".into(),
137 mult: 7.0,
138 }],
139 ..GameStateV1 {
140 cuques: 0.0,
141 total_clicks: 0,
142 lifetime_cuques: 0.0,
143 best_fps: 0.0,
144 golden_caught: 0,
145 fingerers_owned: HashMap::new(),
146 achievements_earned: HashSet::new(),
147 upgrades_earned: HashSet::new(),
148 prestige: 0,
149 total_play_ticks: 0,
150 buffs: vec![],
151 }
152 };
153
154 let s = v1.into_current();
155
156 assert!(
158 s.buffs
159 .iter()
160 .all(|b| matches!(b, Buff::ClickFrenzy { .. }))
161 );
162
163 let st = s
164 .fingerers_state
165 .get("latex_glove")
166 .expect("modifier attached to target fingerer");
167 assert_eq!(st.modifiers.len(), 1);
168 let m = &st.modifiers[0];
169 assert!(matches!(
170 m.source,
171 crate::game::modifier::ModifierSource::PurpleCoin
172 ));
173 assert!(matches!(
174 m.duration,
175 crate::game::modifier::ModifierDuration::Ticks(600)
176 ));
177 assert!((st.aggregate.mul_factor - 7.0).abs() < 1e-9);
179 }
180}