attempt speed pp
This commit is contained in:
+1
-3
@@ -139,8 +139,6 @@ impl<'map> OsuStars<'map> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let aim_difficult_strain_count = skills::OsuStrainSkill::count_difficult_strains(&mut aim);
|
let aim_difficult_strain_count = skills::OsuStrainSkill::count_difficult_strains(&mut aim);
|
||||||
|
|
||||||
// currently unused as relax pp doesn't include speed
|
|
||||||
let speed_difficult_strain_count =
|
let speed_difficult_strain_count =
|
||||||
skills::OsuStrainSkill::count_difficult_strains(&mut speed);
|
skills::OsuStrainSkill::count_difficult_strains(&mut speed);
|
||||||
|
|
||||||
@@ -150,7 +148,7 @@ impl<'map> OsuStars<'map> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if mods.rx() {
|
if mods.rx() {
|
||||||
speed_rating = 0.0;
|
speed_rating *= 0.8;
|
||||||
flashlight_rating *= 0.7;
|
flashlight_rating *= 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+33
-17
@@ -402,6 +402,10 @@ impl OsuPpInner {
|
|||||||
|
|
||||||
let mut multiplier = PERFORMANCE_BASE_MULTIPLIER;
|
let mut multiplier = PERFORMANCE_BASE_MULTIPLIER;
|
||||||
|
|
||||||
|
if self.mods.rx() {
|
||||||
|
multiplier *= 1.02;
|
||||||
|
}
|
||||||
|
|
||||||
if self.mods.nf() {
|
if self.mods.nf() {
|
||||||
multiplier *= (1.0 - 0.02 * self.effective_miss_count).max(0.9);
|
multiplier *= (1.0 - 0.02 * self.effective_miss_count).max(0.9);
|
||||||
}
|
}
|
||||||
@@ -411,10 +415,19 @@ impl OsuPpInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let aim_value = self.compute_aim_value();
|
let aim_value = self.compute_aim_value();
|
||||||
let speed_value = self.compute_speed_value();
|
let mut speed_value = self.compute_speed_value();
|
||||||
let acc_value = self.compute_accuracy_value();
|
let acc_value = self.compute_accuracy_value();
|
||||||
let flashlight_value = self.compute_flashlight_value();
|
let flashlight_value = self.compute_flashlight_value();
|
||||||
|
|
||||||
|
if self.mods.rx() {
|
||||||
|
let stream_factor = aim_value / speed_value;
|
||||||
|
|
||||||
|
if stream_factor < 1.0 {
|
||||||
|
let accuracy_factor = (1.0 - self.acc).abs();
|
||||||
|
speed_value *= 0.96 - accuracy_factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let pp = (aim_value.powf(1.1)
|
let pp = (aim_value.powf(1.1)
|
||||||
+ speed_value.powf(1.1)
|
+ speed_value.powf(1.1)
|
||||||
+ acc_value.powf(1.1)
|
+ acc_value.powf(1.1)
|
||||||
@@ -500,31 +513,34 @@ impl OsuPpInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compute_speed_value(&self) -> f64 {
|
fn compute_speed_value(&self) -> f64 {
|
||||||
if self.mods.rx() {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut speed_value =
|
let mut speed_value =
|
||||||
(5.0 * (self.attrs.speed / 0.0675).max(1.0) - 4.0).powi(3) / 100_000.0;
|
(5.0 * (self.attrs.speed / 0.0675).max(1.0) - 4.0).powi(3) / 100_000.0;
|
||||||
|
|
||||||
let total_hits = self.total_hits();
|
let total_hits = self.total_hits();
|
||||||
|
|
||||||
let len_bonus = 0.95
|
let mut len_bonus = 1.0;
|
||||||
+ 0.4 * (total_hits / 2000.0).min(1.0)
|
if self.mods.rx() {
|
||||||
+ (total_hits > 2000.0) as u8 as f64 * (total_hits / 2000.0).log10() * 0.5;
|
if self.effective_miss_count > 0.0 {
|
||||||
|
speed_value *= self.calculate_miss_penalty(self.attrs.speed_difficult_strain_count);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
len_bonus = 0.95
|
||||||
|
+ 0.4 * (total_hits / 2000.0).min(1.0)
|
||||||
|
+ (total_hits > 2000.0) as u8 as f64 * (total_hits / 2000.0).log10() * 0.5;
|
||||||
|
|
||||||
speed_value *= len_bonus;
|
speed_value *= len_bonus;
|
||||||
|
|
||||||
// * Penalize misses by assessing # of misses relative to the total # of objects.
|
// * Penalize misses by assessing # of misses relative to the total # of objects.
|
||||||
// * Default a 3% reduction for any # of misses.
|
// * Default a 3% reduction for any # of misses.
|
||||||
if self.effective_miss_count > 0.0 {
|
if self.effective_miss_count > 0.0 {
|
||||||
speed_value *= 0.97
|
speed_value *= 0.97
|
||||||
* (1.0 - (self.effective_miss_count / total_hits).powf(0.775))
|
* (1.0 - (self.effective_miss_count / total_hits).powf(0.775))
|
||||||
.powf(self.effective_miss_count.powf(0.875));
|
.powf(self.effective_miss_count.powf(0.875));
|
||||||
|
}
|
||||||
|
|
||||||
|
speed_value *= self.get_combo_scaling_factor();
|
||||||
}
|
}
|
||||||
|
|
||||||
speed_value *= self.get_combo_scaling_factor();
|
|
||||||
|
|
||||||
let ar_factor = if self.attrs.ar > 10.33 {
|
let ar_factor = if self.attrs.ar > 10.33 {
|
||||||
0.3 * (self.attrs.ar - 10.33)
|
0.3 * (self.attrs.ar - 10.33)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ impl Skills {
|
|||||||
Self {
|
Self {
|
||||||
aim: Aim::new(true),
|
aim: Aim::new(true),
|
||||||
aim_no_sliders: Aim::new(false),
|
aim_no_sliders: Aim::new(false),
|
||||||
speed: Speed::new(hit_window),
|
speed: Speed::new(hit_window, mods),
|
||||||
flashlight: Flashlight::new(mods, radius, time_preempt, time_fade_in),
|
flashlight: Flashlight::new(mods, radius, time_preempt, time_fade_in),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-4
@@ -1,6 +1,6 @@
|
|||||||
use std::{cmp::Ordering, f64::consts::PI};
|
use std::{cmp::Ordering, f64::consts::PI};
|
||||||
|
|
||||||
use crate::osu::difficulty_object::OsuDifficultyObject;
|
use crate::{osu::difficulty_object::OsuDifficultyObject, Mods};
|
||||||
|
|
||||||
use super::{next, previous, previous_start_time, OsuStrainSkill, Skill, StrainSkill};
|
use super::{next, previous, previous_start_time, OsuStrainSkill, Skill, StrainSkill};
|
||||||
|
|
||||||
@@ -13,13 +13,14 @@ pub(crate) struct Speed {
|
|||||||
pub(crate) strain_peaks: Vec<f64>,
|
pub(crate) strain_peaks: Vec<f64>,
|
||||||
object_strains: Vec<f64>,
|
object_strains: Vec<f64>,
|
||||||
hit_window: f64,
|
hit_window: f64,
|
||||||
|
pub(crate) mods: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Speed {
|
impl Speed {
|
||||||
const SKILL_MULTIPLIER: f64 = 1375.0;
|
const SKILL_MULTIPLIER: f64 = 1375.0;
|
||||||
const STRAIN_DECAY_BASE: f64 = 0.3;
|
const STRAIN_DECAY_BASE: f64 = 0.3;
|
||||||
|
|
||||||
pub(crate) fn new(hit_window: f64) -> Self {
|
pub(crate) fn new(hit_window: f64, mods: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
curr_strain: 0.0,
|
curr_strain: 0.0,
|
||||||
curr_section_peak: 0.0,
|
curr_section_peak: 0.0,
|
||||||
@@ -28,6 +29,7 @@ impl Speed {
|
|||||||
strain_peaks: Vec::new(),
|
strain_peaks: Vec::new(),
|
||||||
object_strains: Vec::new(),
|
object_strains: Vec::new(),
|
||||||
hit_window,
|
hit_window,
|
||||||
|
mods,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,9 +92,15 @@ impl StrainSkill for Speed {
|
|||||||
self.curr_strain *= Self::strain_decay(curr.strain_time);
|
self.curr_strain *= Self::strain_decay(curr.strain_time);
|
||||||
self.curr_strain += SpeedEvaluator::evaluate_diff_of(curr, diff_objects, self.hit_window)
|
self.curr_strain += SpeedEvaluator::evaluate_diff_of(curr, diff_objects, self.hit_window)
|
||||||
* Self::SKILL_MULTIPLIER;
|
* Self::SKILL_MULTIPLIER;
|
||||||
self.curr_rhythm = RhythmEvaluator::evaluate_diff_of(curr, diff_objects, self.hit_window);
|
|
||||||
|
|
||||||
let total_strain = self.curr_strain * self.curr_rhythm;
|
let mut total_strain = self.curr_strain;
|
||||||
|
if !self.mods.rx() {
|
||||||
|
self.curr_rhythm =
|
||||||
|
RhythmEvaluator::evaluate_diff_of(curr, diff_objects, self.hit_window);
|
||||||
|
|
||||||
|
total_strain *= self.curr_rhythm;
|
||||||
|
}
|
||||||
|
|
||||||
self.object_strains.push(total_strain);
|
self.object_strains.push(total_strain);
|
||||||
|
|
||||||
total_strain
|
total_strain
|
||||||
|
|||||||
Reference in New Issue
Block a user