rosu_pp/catch/
attributes.rs1use std::mem;
2
3use crate::catch::performance::CatchPerformance;
4
5#[derive(Clone, Debug, Default, PartialEq)]
7pub struct CatchDifficultyAttributes {
8 pub stars: f64,
10 pub ar: f64,
12 pub n_fruits: u32,
14 pub n_droplets: u32,
16 pub n_tiny_droplets: u32,
18 pub is_convert: bool,
22}
23
24impl CatchDifficultyAttributes {
25 pub const fn max_combo(&self) -> u32 {
27 self.n_fruits + self.n_droplets
28 }
29
30 pub const fn is_convert(&self) -> bool {
34 self.is_convert
35 }
36
37 pub fn performance<'a>(self) -> CatchPerformance<'a> {
39 self.into()
40 }
41
42 pub(crate) const fn set_object_count(&mut self, count: &ObjectCount) {
43 self.n_fruits = count.fruits;
44 self.n_droplets = count.droplets;
45 self.n_tiny_droplets = count.tiny_droplets;
46 }
47
48 pub(crate) const fn add_object_count(&mut self, count: GradualObjectCount) {
49 if count.fruit {
50 self.n_fruits += 1;
51 } else {
52 self.n_droplets += 1;
53 }
54
55 self.n_tiny_droplets += count.tiny_droplets;
56 }
57}
58
59#[derive(Clone, Debug, Default, PartialEq)]
61pub struct CatchPerformanceAttributes {
62 pub difficulty: CatchDifficultyAttributes,
64 pub pp: f64,
66}
67
68impl CatchPerformanceAttributes {
69 pub const fn stars(&self) -> f64 {
71 self.difficulty.stars
72 }
73
74 pub const fn pp(&self) -> f64 {
76 self.pp
77 }
78
79 pub const fn max_combo(&self) -> u32 {
81 self.difficulty.max_combo()
82 }
83
84 pub const fn is_convert(&self) -> bool {
88 self.difficulty.is_convert
89 }
90
91 pub fn performance<'a>(self) -> CatchPerformance<'a> {
93 self.difficulty.into()
94 }
95}
96
97impl From<CatchPerformanceAttributes> for CatchDifficultyAttributes {
98 fn from(attributes: CatchPerformanceAttributes) -> Self {
99 attributes.difficulty
100 }
101}
102
103#[derive(Clone, Default)]
104pub struct ObjectCount {
105 fruits: u32,
106 droplets: u32,
107 tiny_droplets: u32,
108}
109
110#[derive(Copy, Clone, Default)]
111pub struct GradualObjectCount {
112 fruit: bool,
113 tiny_droplets: u32,
114}
115
116pub enum ObjectCountBuilder {
117 Regular {
118 count: ObjectCount,
119 take: usize,
120 },
121 Gradual {
122 count: GradualObjectCount,
123 all: Vec<GradualObjectCount>,
124 },
125}
126
127impl ObjectCountBuilder {
128 pub fn new_regular(take: usize) -> Self {
129 Self::Regular {
130 count: ObjectCount::default(),
131 take,
132 }
133 }
134
135 pub fn new_gradual() -> Self {
136 Self::Gradual {
137 count: GradualObjectCount::default(),
138 all: Vec::with_capacity(512),
139 }
140 }
141
142 pub fn into_regular(self) -> ObjectCount {
143 if let Self::Regular { count, .. } = self {
144 count
145 } else {
146 unreachable!()
147 }
148 }
149
150 pub fn into_gradual(self) -> Vec<GradualObjectCount> {
151 if let Self::Gradual { all, .. } = self {
152 all
153 } else {
154 unreachable!()
155 }
156 }
157
158 pub fn record_fruit(&mut self) {
159 match self {
160 Self::Regular { count, take } => {
161 if *take > 0 {
162 *take -= 1;
163 count.fruits += 1;
164 }
165 }
166 Self::Gradual { count, all } => {
167 count.fruit = true;
168 all.push(mem::take(count));
169 }
170 }
171 }
172
173 pub fn record_droplet(&mut self) {
174 match self {
175 Self::Regular { count, take } => {
176 if *take > 0 {
177 *take -= 1;
178 count.droplets += 1;
179 }
180 }
181 Self::Gradual { count, all } => all.push(mem::take(count)),
182 }
183 }
184
185 pub const fn record_tiny_droplets(&mut self, n: u32) {
186 match self {
187 Self::Regular { count, take } => {
188 if *take > 0 {
189 count.tiny_droplets += n;
190 }
191 }
192 Self::Gradual { count, .. } => count.tiny_droplets += n,
193 }
194 }
195}