diff --git a/oppai.c b/oppai.c index 41a3405..59ba5e0 100644 --- a/oppai.c +++ b/oppai.c @@ -219,6 +219,8 @@ typedef struct object { float angle; float strains[2]; int is_single; /* 1 if diff calc sees this as a singletap */ + float delta_time; + float d_distance; float pos[2]; float distance; /* only for sliders */ @@ -1819,11 +1821,22 @@ void d_free(diff_calc_t* d) { #define MIN_SPEED_BONUS 45.0f /* ~200BPM 1/4 streams */ #define MAX_SPEED_BONUS 75.0f /* ~330BPM 1/4 streams */ +#define ANGLE_BONUS_SCALE 90 +#define AIM_TIMING_THRESHOLD 107 +#define SPEED_ANGLE_BONUS_BEGIN (5 * M_PI / 6) +#define AIM_ANGLE_BONUS_BEGIN (M_PI / 3) +/* + * TODO: unbloat these params + * this function has become a mess with the latest changes, I should split + * it into separate funcs for speed and im + */ float d_spacing_weight(float distance, float delta_time, + float prev_distance, float prev_delta_time, float angle, int type, int* is_single) { float angle_bonus; + float strain_time = al_max(delta_time, 50.0f); switch (type) { case DIFF_SPEED: { float speed_bonus; @@ -1835,31 +1848,45 @@ float d_spacing_weight(float distance, float delta_time, pow((MIN_SPEED_BONUS - delta_time) / 40.0f, 2); } angle_bonus = 1.0f; - if (!is_nan(angle)) { - angle_bonus = al_clamp( - (3 * M_PI / 4 - angle) * 2 / M_PI + 1.0f, - 1.0f, 1.25f - ); + if (!is_nan(angle) && angle < SPEED_ANGLE_BONUS_BEGIN) { + float s = (float)sin(1.5 * (SPEED_ANGLE_BONUS_BEGIN - angle)); + angle_bonus += (float)pow(s, 2) / 3.57f; + if (angle < M_PI / 2) { + angle_bonus = 1.28f; + if (distance < ANGLE_BONUS_SCALE && angle < M_PI / 4) { + angle_bonus += (1 - angle_bonus) + * al_min((ANGLE_BONUS_SCALE - distance) / 10, 1); + } + else if (distance < ANGLE_BONUS_SCALE) { + angle_bonus += (1 - angle_bonus) + * al_min((ANGLE_BONUS_SCALE - distance) / 10, 1) + * (float)sin((M_PI / 2 - angle) * 4 / M_PI); + } + } } return ( - speed_bonus * + (1 + (speed_bonus - 1) * 0.75) * angle_bonus * - (0.95f + (float)pow(distance / SINGLE_SPACING, 4.0f)) - ); + (0.95f + speed_bonus * (float)pow(distance / SINGLE_SPACING, 3.5)) + ) / strain_time; } case DIFF_AIM: { - angle_bonus = 0.0f; - if (!is_nan(angle)) { - angle_bonus = al_clamp( - (angle - (float)(5 * M_PI / 12)) * 2 / M_PI, - 0, 0.5f + float result = 0; + float prev_strain_time = al_max(prev_delta_time, 50.0f); + if (!is_nan(angle) && angle > AIM_ANGLE_BONUS_BEGIN) { + float angle_bonus = (float)sqrt( + al_max(prev_distance - ANGLE_BONUS_SCALE, 0) + * pow(sin(angle - AIM_ANGLE_BONUS_BEGIN), 2) + * al_max(distance - ANGLE_BONUS_SCALE, 0) ); + result = 1.5f * (float)pow(al_max(0, angle_bonus), 0.99) + / al_max(AIM_TIMING_THRESHOLD, prev_strain_time); } - return ( - angle_bonus - * (float)pow(al_max(0, distance - SINGLE_SPACING), 0.99f) - + pow(distance, 0.99f) + result += ( + (float)pow(distance, 0.99) + (float)sqrt(pow(distance, 0.99)) ); + return al_max(result / al_max(AIM_TIMING_THRESHOLD, strain_time), + result / strain_time); } } return 0.0f; @@ -1871,17 +1898,18 @@ void d_calc_strain(int type, object_t* o, object_t* prev, float speedmul) { float decay = (float)pow(decay_base[type], time_elapsed / 1000.0f); float scaling = weight_scaling[type]; + o->delta_time = time_elapsed; + /* this implementation doesn't account for sliders */ if (o->type & (OBJ_SLIDER | OBJ_CIRCLE)) { float diff[2]; v2f_sub(diff, o->normpos, prev->normpos); - res = d_spacing_weight(v2f_len(diff), time_elapsed, o->angle, type, - &o->is_single); + o->d_distance = v2f_len(diff); + res = d_spacing_weight(o->d_distance, time_elapsed, prev->d_distance, + prev->delta_time, o->angle, type, &o->is_single); res *= scaling; } - /* prevents retarded results for hit object spams */ - res /= mymax(time_elapsed, 50.0f); o->strains[type] = prev->strains[type] * decay + res; }