public ManiaRulesetContainer(Ruleset ruleset, WorkingBeatmap beatmap) : base(ruleset, beatmap) { // Generate the bar lines double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; var timingPoints = Beatmap.ControlPointInfo.TimingPoints; var barLines = new List <BarLine>(); for (int i = 0; i < timingPoints.Count; i++) { TimingControlPoint point = timingPoints[i]; // Stop on the beat before the next timing point, or if there is no next timing point stop slightly past the last object double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time - point.BeatLength : lastObjectTime + point.BeatLength * (int)point.TimeSignature; int index = 0; for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++) { barLines.Add(new BarLine { StartTime = t, ControlPoint = point, BeatIndex = index }); } } BarLines = barLines; }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { float livesPercentage = LivesLeft.Value / (float)LivesLeft.MaxValue; int panicLevel = 0; if (livesPercentage <= 0.1f) { panicLevel = 3; } else if (livesPercentage <= 0.25f) { panicLevel = 2; } else if (livesPercentage <= 0.5f) { panicLevel = 1; } // Heart Rate increases when panicking (lives <= 20% MaxLives) // It also beats harder float panicDurationMultiplier = 1 * MathF.Pow(0.75f, panicLevel); float beatMagnitude = 0.1f + (0.05f * panicLevel); if (beatIndex % (int)((int)timingPoint.TimeSignature * Math.Max(panicDurationMultiplier, 0.5f)) == 0) { this.ScaleTo(1 + beatMagnitude, 200 * panicDurationMultiplier) .Then().ScaleTo(1, 120 * panicDurationMultiplier) .Then().ScaleTo(1 + beatMagnitude, 160 * panicDurationMultiplier) .Then().ScaleTo(1, 320 * panicDurationMultiplier); } }
private void load(IBindable <WorkingBeatmap> beatmap) { Beatmap.BindTo(beatmap); defaultTiming = new TimingControlPoint { BeatLength = default_beat_length, AutoGenerated = true, Time = 0 }; defaultEffect = new EffectControlPoint { Time = 0, AutoGenerated = true, KiaiMode = false, OmitFirstBarLine = false }; defaultAmplitudes = new TrackAmplitudes { FrequencyAmplitudes = new float[256], LeftChannel = 0, RightChannel = 0 }; }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { if (!drawableRepeat.IsHit) { Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out); } }
public TimingPointTimeline(TimingControlPoint timingPoint, double endTime, double fullDuration) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Box createMainTick(double time) => new Box { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomCentre, RelativePositionAxes = Axes.X, X = (float)(time / fullDuration), Height = 10, Width = 2 }; Box createBeatTick(double time) => new Box { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomCentre, RelativePositionAxes = Axes.X, X = (float)(time / fullDuration), Height = 5, Width = 2, Colour = time > endTime ? Color4.Gray : Color4.Yellow }; AddInternal(createMainTick(timingPoint.Time)); AddInternal(createMainTick(endTime)); for (double t = timingPoint.Time + timingPoint.BeatLength / 4; t < fullDuration; t += timingPoint.BeatLength / 4) { AddInternal(createBeatTick(t)); } }
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap) : base(random, hitObject, beatmap, previousPattern, originalBeatmap) { convertType = PatternType.None; if (!Beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime).KiaiMode) { convertType = PatternType.LowProbability; } var distanceData = hitObject as IHasDistance; var repeatsData = hitObject as IHasRepeats; spanCount = repeatsData?.SpanCount() ?? 1; TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime); DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(hitObject.StartTime); // The true distance, accounting for any repeats double distance = (distanceData?.Distance ?? 0) * spanCount; // The velocity of the osu! hit object - calculated as the velocity of a slider double osuVelocity = osu_base_scoring_distance * beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / timingPoint.BeatLength; // The duration of the osu! hit object double osuDuration = distance / osuVelocity; EndTime = hitObject.StartTime + osuDuration; SegmentDuration = (EndTime - HitObject.StartTime) / spanCount; }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { if (effectPoint.KiaiMode) { kiaiBeatIndex += 1; if (firstKiaiBeat) { visualisation.FlashColour(Color4.White, timingPoint.BeatLength * 4, Easing.In); firstKiaiBeat = false; return; } if (kiaiBeatIndex >= 5) { visualisation.FlashColour(Color4.White.Opacity(0.15f), timingPoint.BeatLength, Easing.In); } } else { firstKiaiBeat = true; kiaiBeatIndex = 0; } }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) { base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); lastBeatIndex = beatIndex; var beatLength = timingPoint.BeatLength; float amplitudeAdjust = Math.Min(1, 0.4f + amplitudes.Maximum); if (beatIndex < 0) return; logoBeatContainer.ScaleTo(1 - 0.02f * amplitudeAdjust, beat_in_time, EasingTypes.Out); using (logoBeatContainer.BeginDelayedSequence(beat_in_time)) logoBeatContainer.ScaleTo(1, beatLength * 2, EasingTypes.OutQuint); ripple.ClearTransforms(); ripple.ScaleTo(logoAmplitudeContainer.Scale); ripple.Alpha = 0.15f * amplitudeAdjust; ripple.ScaleTo(logoAmplitudeContainer.Scale * (1 + 0.04f * amplitudeAdjust), beatLength, EasingTypes.OutQuint); ripple.FadeOut(beatLength, EasingTypes.OutQuint); if (effectPoint.KiaiMode && flashLayer.Alpha < 0.4f) { flashLayer.ClearTransforms(); flashLayer.FadeTo(0.2f * amplitudeAdjust, beat_in_time, EasingTypes.Out); using (flashLayer.BeginDelayedSequence(beat_in_time)) flashLayer.FadeOut(beatLength); } }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) { if (effectPoint.KiaiMode) { fill.FlashColour(colours.PinkLight, 800, Easing.In); } }
public void TestDisallowMistimedEventFiring(bool allowMistimed) { int? lastBeatIndex = null; double? lastActuationTime = null; TimingControlPoint lastTimingPoint = null; AddStep($"set mistimed to {(allowMistimed ? "allowed" : "disallowed")}", () => beatContainer.AllowMistimedEventFiring = allowMistimed); AddStep("Set time before zero", () => { beatContainer.NewBeat = (i, timingControlPoint, effectControlPoint, channelAmplitudes) => { lastActuationTime = gameplayClockContainer.CurrentTime; lastTimingPoint = timingControlPoint; lastBeatIndex = i; beatContainer.NewBeat = null; }; gameplayClockContainer.Seek(-1000); }); AddUntilStep("wait for trigger", () => lastBeatIndex != null); if (!allowMistimed) { AddAssert("trigger is near beat length", () => lastActuationTime != null && lastBeatIndex != null && Precision.AlmostEquals(lastTimingPoint.Time + lastBeatIndex.Value * lastTimingPoint.BeatLength, lastActuationTime.Value, BeatSyncedContainer.MISTIMED_ALLOWANCE)); } else { AddAssert("trigger is not near beat length", () => lastActuationTime != null && lastBeatIndex != null && !Precision.AlmostEquals(lastTimingPoint.Time + lastBeatIndex.Value * lastTimingPoint.BeatLength, lastActuationTime.Value, BeatSyncedContainer.MISTIMED_ALLOWANCE)); } }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { if (!hasSelection) { this.FadeTo(0.7f).FadeTo(0.4f, timingPoint.BeatLength, Easing.InOutSine); } }
private void load() { var maniaPlayfield = (ManiaPlayfield)Playfield; double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; SortedList <TimingControlPoint> timingPoints = Beatmap.ControlPointInfo.TimingPoints; for (int i = 0; i < timingPoints.Count; i++) { TimingControlPoint point = timingPoints[i]; // Stop on the beat before the next timing point, or if there is no next timing point stop slightly past the last object double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time - point.BeatLength : lastObjectTime + point.BeatLength * (int)point.TimeSignature; int index = 0; for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++) { maniaPlayfield.Add(new DrawableBarLine(new BarLine { StartTime = t, ControlPoint = point, BeatIndex = index })); } } }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { float maximumDankness = 15 * amplitudes.Average; rContainer.MoveToOffset(new Vector2(RNG.NextSingle(-maximumDankness, maximumDankness), RNG.NextSingle(-maximumDankness, maximumDankness)), 50).Then().MoveTo(new Vector2(0), 100); gContainer.MoveToOffset(new Vector2(RNG.NextSingle(-maximumDankness, maximumDankness), RNG.NextSingle(-maximumDankness, maximumDankness)), 50).Then().MoveTo(new Vector2(0), 100); bContainer.MoveToOffset(new Vector2(RNG.NextSingle(-maximumDankness, maximumDankness), RNG.NextSingle(-maximumDankness, maximumDankness)), 50).Then().MoveTo(new Vector2(0), 100); }
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); tickSpacing = timingPoint.BeatLength / difficulty.SliderTickRate; }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) { base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); this.ScaleTo(1.2f) .Then() .ScaleTo(1f, timingPoint.BeatLength, Easing.Out); }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { kiaiBindable.Value = effectPoint.KiaiMode; float expandSize = 5 * amplitudes.Average * (effectPoint.KiaiMode ? 2 : 1); FinishTransforms(false, nameof(Size)); this.ResizeTo(450 + expandSize, 100).Then().ResizeTo(450, 50); }
private int calculateBeatCount(TimingControlPoint current) { if (timingPoints[timingPoints.Count - 1] == current) { return((int)Math.Ceiling((Beatmap.Value.Track.Length - current.Time) / current.BeatLength)); } return((int)Math.Ceiling((getNextTimingPoint(current).Time - current.Time) / current.BeatLength)); }
private TimingControlPoint getNextTimingPoint(TimingControlPoint current) { if (timingPoints[timingPoints.Count - 1] == current) { return(current); } return(timingPoints[timingPoints.IndexOf(current) + 1]); }
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty) { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); velocityFactor = base_scoring_distance * difficulty.SliderMultiplier / timingPoint.BeatLength; tickDistanceFactor = base_scoring_distance * difficulty.SliderMultiplier / difficulty.SliderTickRate; }
protected override float GetVelocity(double time, ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(time); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(time); double scoringDistance = OsuHitObject.BASE_SCORING_DISTANCE * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; return((float)(scoringDistance / timingPoint.BeatLength)); }
public TimingPointVisualiser(Beatmap beatmap, double length) { this.length = length; Anchor = Anchor.Centre; Origin = Anchor.Centre; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Width = 0.75f; FillFlowContainer timelineContainer; InternalChildren = new Drawable[] { new Box { Name = "Background", RelativeSizeAxes = Axes.Both, Colour = Color4.Black.Opacity(85f) }, new Container { Name = "Tracks", RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Padding = new MarginPadding(15), Children = new[] { tracker = new Box { Anchor = Anchor.CentreLeft, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Y, RelativePositionAxes = Axes.X, Width = 2, Colour = Color4.Red, }, timelineContainer = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Spacing = new Vector2(0, 5) }, } } }; var timingPoints = beatmap.ControlPointInfo.TimingPoints; for (int i = 0; i < timingPoints.Count; i++) { TimingControlPoint next = i == timingPoints.Count - 1 ? null : timingPoints[i + 1]; timelineContainer.Add(new TimingPointTimeline(timingPoints[i], next?.Time ?? length, length)); } }
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, Beatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, PatternType lastStair) : base(random, hitObject, beatmap, previousPattern) { StairType = lastStair; TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime); EffectControlPoint effectPoint = beatmap.ControlPointInfo.EffectPointAt(hitObject.StartTime); var positionData = hitObject as IHasPosition; float positionSeparation = ((positionData?.Position ?? Vector2.Zero) - previousPosition).Length; double timeSeparation = hitObject.StartTime - previousTime; if (timeSeparation <= 80) { // More than 187 BPM convertType |= PatternType.ForceNotStack | PatternType.KeepSingle; } else if (timeSeparation <= 95) { // More than 157 BPM convertType |= PatternType.ForceNotStack | PatternType.KeepSingle | lastStair; } else if (timeSeparation <= 105) { // More than 140 BPM convertType |= PatternType.ForceNotStack | PatternType.LowProbability; } else if (timeSeparation <= 125) { // More than 120 BPM convertType |= PatternType.ForceNotStack; } else if (timeSeparation <= 135 && positionSeparation < 20) { // More than 111 BPM stream convertType |= PatternType.Cycle | PatternType.KeepSingle; } else if (timeSeparation <= 150 && positionSeparation < 20) { // More than 100 BPM stream convertType |= PatternType.ForceStack | PatternType.LowProbability; } else if (positionSeparation < 20 && density >= timingPoint.BeatLength / 2.5) { // Low density stream convertType |= PatternType.Reverse | PatternType.LowProbability; } else if (density < timingPoint.BeatLength / 2.5 || effectPoint.KiaiMode) { // High density } else { convertType |= PatternType.LowProbability; } }
private void load() { // Calculate default multiplier control points var lastTimingPoint = new TimingControlPoint(); var lastDifficultyPoint = new DifficultyControlPoint(); // Merge timing + difficulty points var allPoints = new SortedList <ControlPoint>(Comparer <ControlPoint> .Default); allPoints.AddRange(Beatmap.ControlPointInfo.TimingPoints); allPoints.AddRange(Beatmap.ControlPointInfo.DifficultyPoints); // Generate the timing points, making non-timing changes use the previous timing change var timingChanges = allPoints.Select(c => { var timingPoint = c as TimingControlPoint; var difficultyPoint = c as DifficultyControlPoint; if (timingPoint != null) { lastTimingPoint = timingPoint; } if (difficultyPoint != null) { lastDifficultyPoint = difficultyPoint; } return(new MultiplierControlPoint(c.Time) { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier, TimingPoint = lastTimingPoint, DifficultyPoint = lastDifficultyPoint }); }); double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; // Perform some post processing of the timing changes timingChanges = timingChanges // Collapse sections after the last hit object .Where(s => s.StartTime <= lastObjectTime) // Collapse sections with the same start time .GroupBy(s => s.StartTime).Select(g => g.Last()).OrderBy(s => s.StartTime); DefaultControlPoints.AddRange(timingChanges); // If we have no control points, add a default one if (DefaultControlPoints.Count == 0) { DefaultControlPoints.Add(new MultiplierControlPoint { Velocity = Beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier }); } DefaultControlPoints.ForEach(c => applySpeedAdjustment(c, Playfield)); }
public ManiaHitRenderer(WorkingBeatmap beatmap, bool isForCurrentRuleset) : base(beatmap, isForCurrentRuleset) { // Generate the speed adjustment container lists hitObjectSpeedAdjustments = new List <SpeedAdjustmentContainer> [PreferredColumns]; for (int i = 0; i < PreferredColumns; i++) { hitObjectSpeedAdjustments[i] = new List <SpeedAdjustmentContainer>(); } // Generate the bar lines double lastObjectTime = (Objects.LastOrDefault() as IHasEndTime)?.EndTime ?? Objects.LastOrDefault()?.StartTime ?? double.MaxValue; SortedList <TimingControlPoint> timingPoints = Beatmap.ControlPointInfo.TimingPoints; var barLines = new List <DrawableBarLine>(); for (int i = 0; i < timingPoints.Count; i++) { TimingControlPoint point = timingPoints[i]; // Stop on the beat before the next timing point, or if there is no next timing point stop slightly past the last object double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time - point.BeatLength : lastObjectTime + point.BeatLength * (int)point.TimeSignature; int index = 0; for (double t = timingPoints[i].Time; Precision.DefinitelyBigger(endTime, t); t += point.BeatLength, index++) { barLines.Add(new DrawableBarLine(new BarLine { StartTime = t, ControlPoint = point, BeatIndex = index })); } } BarLines = barLines; // Generate speed adjustments from mods first bool useDefaultSpeedAdjustments = true; if (Mods != null) { foreach (var speedAdjustmentMod in Mods.OfType <IGenerateSpeedAdjustments>()) { useDefaultSpeedAdjustments = false; speedAdjustmentMod.ApplyToHitRenderer(this, ref hitObjectSpeedAdjustments, ref barLineSpeedAdjustments); } } // Generate the default speed adjustments if (useDefaultSpeedAdjustments) { generateDefaultSpeedAdjustments(); } }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) { // assume that if the animation is playing on its own, it's independent from the beat and doesn't need to be touched. if (textureAnimation.FrameCount == 0 || textureAnimation.IsPlaying) { return; } textureAnimation.GotoFrame(currentFrame); currentFrame = (currentFrame + 1) % textureAnimation.FrameCount; }
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; Velocity = scoringDistance / timingPoint.BeatLength; }
protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) { if (effectPoint.KiaiMode && kiaiEffect.Value) { visualisation.FadeIn(200); } else { visualisation.FadeOut(500); } }
private TimingControlPoint getNextTimingPoint(TimingControlPoint current) { if (timingPoints[timingPoints.Count - 1] == current) { return(current); } int index = timingPoints.IndexOf(current); // -1 means that this is a "default beat" return(index == -1 ? current : timingPoints[index + 1]); }
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); tickSpacing = timingPoint.BeatLength / TickRate; RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty); RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty); }
public override void ApplyDefaults(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) { base.ApplyDefaults(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); tickSpacing = timingPoint.BeatLength / TickRate; RequiredGoodHits = TotalTicks * Math.Min(0.15, 0.05 + 0.10 / 6 * difficulty.OverallDifficulty); RequiredGreatHits = TotalTicks * Math.Min(0.30, 0.10 + 0.20 / 6 * difficulty.OverallDifficulty); }