internal void ApplySamplesets(HitCircleFruits fruit, int index) { HitSoundInfo hitSoundInfo = GetHitSoundInfo(index); fruit.SampleSet = hitSoundInfo.SampleSet; fruit.SampleSetAdditions = hitSoundInfo.SampleSetAdditions; }
internal override HitCircle CreateHitCircle(Vector2 startPosition, int startTime, bool newCombo, HitObjectSoundType soundType, int comboOffset, SampleSet sampleSet, SampleSet addSet, CustomSampleSet customSampleSet, int volume, string sampleFile) { WarpSpacing(ref startPosition, startTime); HitCircleFruits h = new HitCircleFruits(hitObjectManager, startPosition, startTime, newCombo, soundType, GetNextFruit()); h.Type |= HitObjectType.NewCombo; //because sorting colours needs this to make each fruit a different colour. h.SampleSet = sampleSet; h.SampleSetAdditions = addSet; h.CustomSampleSet = customSampleSet; h.SampleVolume = volume; h.ProcessSampleFile(sampleFile); return(h); }
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 override void UpdateCalculations(bool force = true) { base.UpdateCalculations(force); // We need to abort here, otherwise we will run out of memory by creating too many tiny ticks for this slider. if (Length > 60000) { throw new ArgumentOutOfRangeException("Slider is too long. (Over 1 minute!)"); } bool useCorrectSamplesets = hitObjectManager.Beatmap.PlayMode != PlayModes.CatchTheBeat || hitObjectManager.Beatmap.BeatmapVersion >= 14; Fruits.Clear(); HitCircleFruits f1 = new HitCircleFruits(hitObjectManager, Position, StartTime, NewCombo, unifiedSoundAddition ? SoundType : SoundTypeList[0], fruit); if (useCorrectSamplesets) { ApplySamplesets(f1, 0); } else { f1.SampleSetAdditions = SampleSetAdditionList.Count > 0 && SampleSetAdditionList[0] != Audio.SampleSet.None ? SampleSetAdditionList[0] : SampleSetAdditions; } f1.Type |= HitObjectType.NewCombo; //new colour Fruits.Add(f1); int lastTime = StartTime; HitFactoryFruits hitFactoryFruits = hitObjectManager.hitFactory as HitFactoryFruits; int fruitIndex = 1; for (int i = 0; i < sliderScoreTimingPoints.Count; i++) { int time = sliderScoreTimingPoints[i]; if (time - lastTime > 80) { float var = (time - lastTime); while (var > 100) { var /= 2; } for (float j = lastTime + var; j < time; j += var) { HitCircleFruitsTickTiny f = new HitCircleFruitsTickTiny(hitObjectManager, PositionAtTime((int)j) + new Vector2(hitFactoryFruits.random.Next(-20, 20), 0), (int)j, false, SoundType, fruit); Fruits.Add(f); } } lastTime = time; if (i < sliderScoreTimingPoints.Count - 1) { int repeatLocation = sliderRepeatPoints.BinarySearch(time); if (repeatLocation >= 0) { HitCircleFruits f = new HitCircleFruits(hitObjectManager, repeatLocation % 2 == 1 ? Position : Position2, time, false, unifiedSoundAddition ? SoundType : SoundTypeList[repeatLocation + 1], fruit); if (useCorrectSamplesets) { ApplySamplesets(f, fruitIndex); } Fruits.Add(f); fruitIndex++; } else { HitCircleFruitsTick f = new HitCircleFruitsTick(hitObjectManager, PositionAtTime(time), time, false, SoundType, fruit); Fruits.Add(f); } } } HitCircleFruits f2 = new HitCircleFruits(hitObjectManager, EndPosition, EndTime, false, unifiedSoundAddition ? SoundType : SoundTypeList[SoundTypeList.Count - 1], fruit); if (useCorrectSamplesets) { ApplySamplesets(f2, SampleSetAdditionList.Count - 1); } else { f2.SampleSetAdditions = SampleSetAdditionList.Count > 0 && SampleSetAdditionList[1] != Audio.SampleSet.None ? SampleSetAdditionList[1] : SampleSetAdditions; } Fruits.Add(f2); }