1use rosu_map::section::general::GameMode;
2
3use crate::{
4 catch::{CatchHitResults, CatchScoreState},
5 mania::ManiaScoreState,
6 osu::{OsuHitResults, OsuScoreState},
7 taiko::{TaikoHitResults, TaikoScoreState},
8};
9
10#[derive(Clone, Debug, Eq, PartialEq)]
12pub struct ScoreState {
13 pub max_combo: u32,
21 pub osu_large_tick_hits: u32,
32 pub osu_small_tick_hits: u32,
39 pub slider_end_hits: u32,
43 pub n_geki: u32,
45 pub n_katu: u32,
48 pub n300: u32,
50 pub n100: u32,
52 pub n50: u32,
54 pub misses: u32,
56 pub legacy_total_score: Option<u32>,
60}
61
62impl ScoreState {
63 pub const fn new() -> Self {
65 Self {
66 max_combo: 0,
67 osu_large_tick_hits: 0,
68 osu_small_tick_hits: 0,
69 slider_end_hits: 0,
70 n_geki: 0,
71 n_katu: 0,
72 n300: 0,
73 n100: 0,
74 n50: 0,
75 misses: 0,
76 legacy_total_score: None,
77 }
78 }
79
80 pub fn total_hits(&self, mode: GameMode) -> u32 {
83 let mut amount = self.n300 + self.n100 + self.misses;
84
85 if mode != GameMode::Taiko {
86 amount += self.n50;
87
88 if mode != GameMode::Osu {
89 amount += self.n_katu;
90 amount += u32::from(mode != GameMode::Catch) * self.n_geki;
91 }
92 }
93
94 amount
95 }
96}
97
98impl From<ScoreState> for OsuScoreState {
99 fn from(state: ScoreState) -> Self {
100 Self {
101 max_combo: state.max_combo,
102 hitresults: OsuHitResults {
103 large_tick_hits: state.osu_large_tick_hits,
104 small_tick_hits: state.osu_small_tick_hits,
105 slider_end_hits: state.slider_end_hits,
106 n300: state.n300,
107 n100: state.n100,
108 n50: state.n50,
109 misses: state.misses,
110 },
111 legacy_total_score: state.legacy_total_score,
112 }
113 }
114}
115
116impl From<ScoreState> for TaikoScoreState {
117 fn from(state: ScoreState) -> Self {
118 Self {
119 max_combo: state.max_combo,
120 hitresults: TaikoHitResults {
121 n300: state.n300,
122 n100: state.n100,
123 misses: state.misses,
124 },
125 }
126 }
127}
128
129impl From<ScoreState> for CatchScoreState {
130 fn from(state: ScoreState) -> Self {
131 Self {
132 max_combo: state.max_combo,
133 hitresults: CatchHitResults {
134 fruits: state.n300,
135 droplets: state.n100,
136 tiny_droplets: state.n50,
137 tiny_droplet_misses: state.n_katu,
138 misses: state.misses,
139 },
140 }
141 }
142}
143
144impl From<ScoreState> for ManiaScoreState {
145 fn from(state: ScoreState) -> Self {
146 Self {
147 n320: state.n_geki,
148 n300: state.n300,
149 n200: state.n_katu,
150 n100: state.n100,
151 n50: state.n50,
152 misses: state.misses,
153 }
154 }
155}
156
157impl From<OsuScoreState> for ScoreState {
158 fn from(state: OsuScoreState) -> Self {
159 Self {
160 max_combo: state.max_combo,
161 osu_large_tick_hits: state.hitresults.large_tick_hits,
162 osu_small_tick_hits: state.hitresults.small_tick_hits,
163 slider_end_hits: state.hitresults.slider_end_hits,
164 n_geki: 0,
165 n_katu: 0,
166 n300: state.hitresults.n300,
167 n100: state.hitresults.n100,
168 n50: state.hitresults.n50,
169 misses: state.hitresults.misses,
170 legacy_total_score: state.legacy_total_score,
171 }
172 }
173}
174
175impl From<TaikoScoreState> for ScoreState {
176 fn from(state: TaikoScoreState) -> Self {
177 Self {
178 max_combo: state.max_combo,
179 osu_large_tick_hits: 0,
180 osu_small_tick_hits: 0,
181 slider_end_hits: 0,
182 n_geki: 0,
183 n_katu: 0,
184 n300: state.hitresults.n300,
185 n100: state.hitresults.n100,
186 n50: 0,
187 misses: state.hitresults.misses,
188 legacy_total_score: None,
189 }
190 }
191}
192
193impl From<CatchScoreState> for ScoreState {
194 fn from(state: CatchScoreState) -> Self {
195 Self {
196 max_combo: state.max_combo,
197 osu_large_tick_hits: 0,
198 osu_small_tick_hits: 0,
199 slider_end_hits: 0,
200 n_geki: 0,
201 n_katu: state.hitresults.tiny_droplet_misses,
202 n300: state.hitresults.fruits,
203 n100: state.hitresults.droplets,
204 n50: state.hitresults.tiny_droplets,
205 misses: state.hitresults.misses,
206 legacy_total_score: None,
207 }
208 }
209}
210
211impl From<ManiaScoreState> for ScoreState {
212 fn from(state: ManiaScoreState) -> Self {
213 Self {
214 max_combo: 0,
215 osu_large_tick_hits: 0,
216 osu_small_tick_hits: 0,
217 slider_end_hits: 0,
218 n_geki: state.n320,
219 n_katu: state.n200,
220 n300: state.n300,
221 n100: state.n100,
222 n50: state.n50,
223 misses: state.misses,
224 legacy_total_score: None,
225 }
226 }
227}
228
229impl Default for ScoreState {
230 fn default() -> Self {
231 Self::new()
232 }
233}