internal void CalculateStrains(DifficultyHitObjectFruits PreviousHitObject, double TimeRate) { // Rather simple, but more specialized things are inherently inaccurate due to the big difference playstyles and opinions make. // See Taiko feedback thread. double TimeElapsed = (double)(BaseHitObject.StartTime - PreviousHitObject.BaseHitObject.StartTime) / TimeRate; double Decay = Math.Pow(DECAY_BASE, TimeElapsed / 1000); // Update new position with lazy movement. PlayerPositionOffset = OsuMathHelper.Clamp( PreviousHitObject.ActualNormalizedPosition, NormalizedPosition - (NORMALIZED_HITOBJECT_RADIUS - playerPositioningError), NormalizedPosition + (NORMALIZED_HITOBJECT_RADIUS - playerPositioningError)) // Obtain new lazy position, but be stricter by allowing for an error of a certain degree of the player. - NormalizedPosition; // Subtract HitObject position to obtain offset LastMovement = DistanceTo(PreviousHitObject); double Addition = SpacingWeight(LastMovement); if (NormalizedPosition < PreviousHitObject.NormalizedPosition) { LastMovement = -LastMovement; } HitCircleFruits previousHitCircle = PreviousHitObject.BaseHitObject as HitCircleFruits; double additionBonus = 0; double sqrtTime = Math.Sqrt(Math.Max(TimeElapsed, 25)); // Direction changes give an extra point! if (Math.Abs(LastMovement) > 0.1) { if (Math.Abs(PreviousHitObject.LastMovement) > 0.1 && Math.Sign(LastMovement) != Math.Sign(PreviousHitObject.LastMovement)) { double bonus = DIRECTION_CHANGE_BONUS / sqrtTime; // Weight bonus by how double bonusFactor = Math.Min(playerPositioningError, Math.Abs(LastMovement)) / playerPositioningError; // We want time to play a role twice here! Addition += bonus * bonusFactor; // Bonus for tougher direction switches and "almost" hyperdashes at this point if (previousHitCircle != null && previousHitCircle.DistanceToHyperDash <= 10) { additionBonus += 0.3 * bonusFactor; } } // Base bonus for every movement, giving some weight to streams. Addition += 7.5 * Math.Min(Math.Abs(LastMovement), NORMALIZED_HITOBJECT_RADIUS * 2) / (NORMALIZED_HITOBJECT_RADIUS * 6) / sqrtTime; } // Bonus for "almost" hyperdashes at corner points if (previousHitCircle != null && previousHitCircle.DistanceToHyperDash <= 10) { if (!previousHitCircle.HyperDash) { additionBonus += 1.0; } else { // After a hyperdash we ARE in the correct position. Always! PlayerPositionOffset = 0; } Addition *= 1.0 + additionBonus * ((10 - previousHitCircle.DistanceToHyperDash) / 10); } Addition *= 850.0 / Math.Max(TimeElapsed, 25); Strain = PreviousHitObject.Strain * Decay + Addition; }
internal float DistanceTo(DifficultyHitObjectFruits other) { return(Math.Abs(ActualNormalizedPosition - other.ActualNormalizedPosition)); }