Skip to content

Commit

Permalink
feat: include latest taiko changes
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxOhn committed Nov 8, 2024
1 parent 45cd1ed commit 9e4db40
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 49 deletions.
3 changes: 3 additions & 0 deletions src/taiko/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ pub struct TaikoDifficultyAttributes {
pub great_hit_window: f64,
/// The perceived hit window for an n100 inclusive of rate-adjusting mods (DT/HT/etc)
pub ok_hit_window: f64,
/// The ratio of stamina difficulty from mono-color (single color) streams to total
/// stamina difficulty.
pub mono_stamina_factor: f64,
/// The final star rating.
pub stars: f64,
/// The maximum combo.
Expand Down
5 changes: 5 additions & 0 deletions src/taiko/difficulty/gradual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ impl Iterator for TaikoGradualDifficulty {
Skill::new(&mut self.skills.rhythm, &self.diff_objects).process(&borrowed);
Skill::new(&mut self.skills.color, &self.diff_objects).process(&borrowed);
Skill::new(&mut self.skills.stamina, &self.diff_objects).process(&borrowed);
Skill::new(&mut self.skills.single_color_stamina, &self.diff_objects)
.process(&borrowed);

if borrowed.base_hit_type.is_hit() {
self.attrs.max_combo += 1;
Expand Down Expand Up @@ -231,6 +233,8 @@ impl Iterator for TaikoGradualDifficulty {
let mut rhythm = Skill::new(&mut self.skills.rhythm, &self.diff_objects);
let mut color = Skill::new(&mut self.skills.color, &self.diff_objects);
let mut stamina = Skill::new(&mut self.skills.stamina, &self.diff_objects);
let mut single_color_stamina =
Skill::new(&mut self.skills.single_color_stamina, &self.diff_objects);

for _ in 0..take {
loop {
Expand All @@ -239,6 +243,7 @@ impl Iterator for TaikoGradualDifficulty {
rhythm.process(&borrowed);
color.process(&borrowed);
stamina.process(&borrowed);
single_color_stamina.process(&borrowed);

if borrowed.base_hit_type.is_hit() {
self.attrs.max_combo += 1;
Expand Down
22 changes: 21 additions & 1 deletion src/taiko/difficulty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,14 @@ impl DifficultyValues {
let mut rhythm = Skill::new(&mut skills.rhythm, &diff_objects);
let mut color = Skill::new(&mut skills.color, &diff_objects);
let mut stamina = Skill::new(&mut skills.stamina, &diff_objects);
let mut single_color_stamina =
Skill::new(&mut skills.single_color_stamina, &diff_objects);

for hit_object in diff_objects.iter().take(n_diff_objects) {
rhythm.process(&hit_object.get());
color.process(&hit_object.get());
stamina.process(&hit_object.get());
single_color_stamina.process(&hit_object.get());
}
}

Expand All @@ -157,15 +160,32 @@ impl DifficultyValues {
let color_rating = skills.color.as_difficulty_value() * COLOR_SKILL_MULTIPLIER;
let rhythm_rating = skills.rhythm.as_difficulty_value() * RHYTHM_SKILL_MULTIPLIER;
let stamina_rating = skills.stamina.as_difficulty_value() * STAMINA_SKILL_MULTIPLIER;
let mono_stamina_rating =
skills.single_color_stamina.as_difficulty_value() * STAMINA_SKILL_MULTIPLIER;
let mono_stamina_factor = if stamina_rating.abs() >= f64::EPSILON {
(mono_stamina_rating / stamina_rating).powf(5.0)
} else {
1.0
};
let combined_rating =
combined_difficulty_value(skills.color, skills.rhythm, skills.stamina);

let star_rating = rescale(combined_rating * 1.4);
let mut star_rating = rescale(combined_rating * 1.4);

// * TODO: This is temporary measure as we don't detect abuse of multiple-input playstyles of converts within the current system.
if attrs.is_convert {
star_rating *= 0.925;
// * For maps with low colour variance and high stamina requirement, multiple inputs are more likely to be abused.
if color_rating < 2.0 && stamina_rating > 8.0 {
star_rating *= 0.80;
}
}

attrs.stamina = stamina_rating;
attrs.rhythm = rhythm_rating;
attrs.color = color_rating;
attrs.peak = combined_rating;
attrs.mono_stamina_factor = mono_stamina_factor;
attrs.stars = star_rating;
}

Expand Down
4 changes: 3 additions & 1 deletion src/taiko/difficulty/skills/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ pub struct TaikoSkills {
pub rhythm: Rhythm,
pub color: Color,
pub stamina: Stamina,
pub single_color_stamina: Stamina,
}

impl TaikoSkills {
pub fn new() -> Self {
Self {
rhythm: Rhythm::default(),
color: Color::default(),
stamina: Stamina::default(),
stamina: Stamina::new(false),
single_color_stamina: Stamina::new(true),
}
}
}
65 changes: 48 additions & 17 deletions src/taiko/difficulty/skills/stamina.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
use crate::{
any::difficulty::{
object::IDifficultyObject,
skills::{strain_decay, ISkill, Skill, StrainDecaySkill},
skills::{strain_decay, ISkill, Skill, StrainDecaySkill, StrainSkill},
},
taiko::{
difficulty::object::{TaikoDifficultyObject, TaikoDifficultyObjects},
object::HitType,
},
util::strains_vec::StrainsVec,
util::{strains_vec::StrainsVec, sync::Weak},
};

const SKILL_MULTIPLIER: f64 = 1.1;
const STRAIN_DECAY_BASE: f64 = 0.4;

#[derive(Clone, Default)]
#[derive(Clone)]
pub struct Stamina {
inner: StrainDecaySkill,
inner: StrainSkill,
single_color: bool,
curr_strain: f64,
}

impl Stamina {
pub fn new(single_color: bool) -> Self {
Self {
inner: StrainSkill::default(),
single_color,
curr_strain: 0.0,
}
}

pub fn get_curr_strain_peaks(self) -> StrainsVec {
self.inner.get_curr_strain_peaks()
}
Expand All @@ -36,6 +46,10 @@ impl ISkill for Stamina {

impl Skill<'_, Stamina> {
fn calculate_initial_strain(&mut self, time: f64, curr: &TaikoDifficultyObject) -> f64 {
if self.inner.single_color {
return 0.0;
}

let prev_start_time = curr
.previous(0, &self.diff_objects.objects)
.map_or(0.0, |prev| prev.get().start_time);
Expand All @@ -44,27 +58,27 @@ impl Skill<'_, Stamina> {
}

const fn curr_strain(&self) -> f64 {
self.inner.inner.curr_strain
self.inner.curr_strain
}

fn curr_strain_mut(&mut self) -> &mut f64 {
&mut self.inner.inner.curr_strain
&mut self.inner.curr_strain
}

const fn curr_section_peak(&self) -> f64 {
self.inner.inner.inner.curr_section_peak
self.inner.inner.curr_section_peak
}

fn curr_section_peak_mut(&mut self) -> &mut f64 {
&mut self.inner.inner.inner.curr_section_peak
&mut self.inner.inner.curr_section_peak
}

const fn curr_section_end(&self) -> f64 {
self.inner.inner.inner.curr_section_end
self.inner.inner.curr_section_end
}

fn curr_section_end_mut(&mut self) -> &mut f64 {
&mut self.inner.inner.inner.curr_section_end
&mut self.inner.inner.curr_section_end
}

pub fn process(&mut self, curr: &TaikoDifficultyObject) {
Expand All @@ -86,13 +100,30 @@ impl Skill<'_, Stamina> {

fn strain_value_at(&mut self, curr: &TaikoDifficultyObject) -> f64 {
*self.curr_strain_mut() *= strain_decay(curr.delta_time, STRAIN_DECAY_BASE);
*self.curr_strain_mut() += self.strain_value_of(curr) * SKILL_MULTIPLIER;

self.curr_strain()
}

fn strain_value_of(&self, curr: &TaikoDifficultyObject) -> f64 {
StaminaEvaluator::evaluate_diff_of(curr, self.diff_objects)
*self.curr_strain_mut() +=
StaminaEvaluator::evaluate_diff_of(curr, self.diff_objects) * SKILL_MULTIPLIER;

// Safely prevents previous strains from shifting as new notes are added.
let index = curr
.color
.mono_streak
.as_ref()
.and_then(Weak::upgrade)
.and_then(|mono| {
mono.get().hit_objects.iter().position(|h| {
let Some(h) = h.upgrade() else { return false };
let h = h.get();

h.idx == curr.idx
})
})
.unwrap_or(0);

if self.inner.single_color {
self.curr_strain() / (1.0 + ((-(index as isize - 10)) as f64 / 2.0).exp())
} else {
self.curr_strain()
}
}
}

Expand Down
20 changes: 14 additions & 6 deletions src/taiko/performance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,12 +416,12 @@ impl TaikoPerformanceInner<'_> {

let mut multiplier = 1.13;

if self.mods.hd() {
if self.mods.hd() && !self.attrs.is_convert {
multiplier *= 1.075;
}

if self.mods.ez() {
multiplier *= 0.975;
multiplier *= 0.95;
}

let diff_value =
Expand Down Expand Up @@ -459,10 +459,10 @@ impl TaikoPerformanceInner<'_> {
diff_value *= 0.986_f64.powf(effective_miss_count);

if self.mods.ez() {
diff_value *= 0.985;
diff_value *= 0.9;
}

if self.mods.hd() && !self.attrs.is_convert {
if self.mods.hd() {
diff_value *= 1.025;
}

Expand All @@ -471,11 +471,19 @@ impl TaikoPerformanceInner<'_> {
}

if self.mods.fl() {
diff_value *= 1.05 * len_bonus;
diff_value *=
(1.05 - (self.attrs.mono_stamina_factor / 50.0).min(1.0) * len_bonus).max(1.0);
}

// * Scale accuracy more harshly on nearly-completely mono (single coloured) speed maps.
let acc_scaling_exp = f64::from(2) + self.attrs.mono_stamina_factor;
let acc_scaling_shift = f64::from(300) - f64::from(100) * self.attrs.mono_stamina_factor;

diff_value
* (special_functions::erf(400.0 / (2.0_f64.sqrt() * estimated_unstable_rate))).powf(2.0)
* (special_functions::erf(
acc_scaling_shift / (2.0_f64.sqrt() * estimated_unstable_rate),
))
.powf(acc_scaling_exp)
}

fn compute_accuracy_value(&self, estimated_unstable_rate: Option<f64>) -> f64 {
Expand Down
16 changes: 12 additions & 4 deletions tests/difficulty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ macro_rules! test_cases {
rhythm: $rhythm:literal,
color: $color:literal,
peak: $peak:literal,
mono_stamina_factor: $mono_stamina_factor:literal,
great_hit_window: $great_hit_window:literal,
ok_hit_window: $ok_hit_window:literal,
stars: $stars:literal,
Expand All @@ -82,6 +83,7 @@ macro_rules! test_cases {
rhythm: $rhythm,
color: $color,
peak: $peak,
mono_stamina_factor: $mono_stamina_factor,
great_hit_window: $great_hit_window,
ok_hit_window: $ok_hit_window,
stars: $stars,
Expand Down Expand Up @@ -362,6 +364,7 @@ fn basic_taiko() {
rhythm: 0.20130047251681948,
color: 1.0487315549761433,
peak: 1.8422453377400778,
mono_stamina_factor: 2.66403971858592e-07,
great_hit_window: 35.0,
ok_hit_window: 80.0,
stars: 2.914589700180437,
Expand All @@ -373,6 +376,7 @@ fn basic_taiko() {
rhythm: 0.20130047251681948,
color: 1.0487315549761433,
peak: 1.8422453377400778,
mono_stamina_factor: 2.66403971858592e-07,
great_hit_window: 29.0,
ok_hit_window: 68.0,
stars: 2.914589700180437,
Expand All @@ -384,6 +388,7 @@ fn basic_taiko() {
rhythm: 0.4448175371191029,
color: 1.363762496098889,
peak: 2.625066421324458,
mono_stamina_factor: 2.515617502055679e-07,
great_hit_window: 23.333333333333332,
ok_hit_window: 53.333333333333336,
stars: 3.942709244618132,
Expand All @@ -403,9 +408,10 @@ fn convert_taiko() {
rhythm: 1.4696991260446617,
color: 2.303228172964907,
peak: 4.117779264387738,
mono_stamina_factor: 0.0016957378202796742,
great_hit_window: 23.59999942779541,
ok_hit_window: 57.19999885559082,
stars: 5.660149021515273,
stars: 5.235637844901627,
max_combo: 908,
is_convert: true,
};
Expand All @@ -414,9 +420,10 @@ fn convert_taiko() {
rhythm: 1.4696991260446617,
color: 2.303228172964907,
peak: 4.117779264387738,
mono_stamina_factor: 0.0016957378202796742,
great_hit_window: 20.0,
ok_hit_window: 50.0,
stars: 5.660149021515273,
ok_hit_window: 50.0
stars: 5.235637844901627,
max_combo: 908,
is_convert: true,
};
Expand All @@ -425,9 +432,10 @@ fn convert_taiko() {
rhythm: 2.002843919169095,
color: 3.1864894777399986,
peak: 6.103209631166694,
mono_stamina_factor: 0.0017075184344987763,
great_hit_window: 15.733332951863607,
ok_hit_window: 38.13333257039388,
stars: 7.578560915020682,
stars: 7.010168846394131,
max_combo: 908,
is_convert: true,
};
Expand Down
Loading

0 comments on commit 9e4db40

Please sign in to comment.