mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 10:52:53 +08:00
Merge pull request #8632 from frenzibyte/fix-draining-in-between-break-sections
Disallow HP draining in non-play sections
This commit is contained in:
commit
b100fc7fc7
@ -2,12 +2,12 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Timing;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -18,7 +18,6 @@ namespace osu.Game.Tests.Gameplay
|
||||
[HeadlessTest]
|
||||
public class TestSceneDrainingHealthProcessor : OsuTestScene
|
||||
{
|
||||
private Bindable<bool> breakTime;
|
||||
private HealthProcessor processor;
|
||||
private ManualClock clock;
|
||||
|
||||
@ -41,6 +40,64 @@ namespace osu.Game.Tests.Gameplay
|
||||
assertHealthEqualTo(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHealthDrainBetweenBreakAndObjects()
|
||||
{
|
||||
createProcessor(createBeatmap(0, 2000, new BreakPeriod(325, 375)));
|
||||
|
||||
// 275 300 325 350 375 400 425
|
||||
// hitobjects o o
|
||||
// break [-------------]
|
||||
// no drain [---------------------------]
|
||||
|
||||
setTime(285);
|
||||
setHealth(1);
|
||||
|
||||
setTime(295);
|
||||
assertHealthNotEqualTo(1);
|
||||
|
||||
setTime(305);
|
||||
setHealth(1);
|
||||
|
||||
setTime(315);
|
||||
assertHealthEqualTo(1);
|
||||
|
||||
setTime(365);
|
||||
assertHealthEqualTo(1);
|
||||
|
||||
setTime(395);
|
||||
assertHealthEqualTo(1);
|
||||
|
||||
setTime(425);
|
||||
assertHealthNotEqualTo(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHealthDrainDuringMaximalBreak()
|
||||
{
|
||||
createProcessor(createBeatmap(0, 2000, new BreakPeriod(300, 400)));
|
||||
|
||||
// 275 300 325 350 375 400 425
|
||||
// hitobjects o o
|
||||
// break [---------------------------]
|
||||
// no drain [---------------------------]
|
||||
|
||||
setTime(285);
|
||||
setHealth(1);
|
||||
|
||||
setTime(295);
|
||||
assertHealthNotEqualTo(1);
|
||||
|
||||
setTime(305);
|
||||
setHealth(1);
|
||||
|
||||
setTime(395);
|
||||
assertHealthEqualTo(1);
|
||||
|
||||
setTime(425);
|
||||
assertHealthNotEqualTo(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHealthNotDrainedAfterGameplayEnd()
|
||||
{
|
||||
@ -54,18 +111,6 @@ namespace osu.Game.Tests.Gameplay
|
||||
assertHealthEqualTo(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHealthNotDrainedDuringBreak()
|
||||
{
|
||||
createProcessor(createBeatmap(0, 2000));
|
||||
setBreak(true);
|
||||
|
||||
setTime(700);
|
||||
assertHealthEqualTo(1);
|
||||
setTime(900);
|
||||
assertHealthEqualTo(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHealthDrainedDuringGameplay()
|
||||
{
|
||||
@ -112,30 +157,31 @@ namespace osu.Game.Tests.Gameplay
|
||||
assertHealthNotEqualTo(1);
|
||||
}
|
||||
|
||||
private Beatmap createBeatmap(double startTime, double endTime)
|
||||
private Beatmap createBeatmap(double startTime, double endTime, params BreakPeriod[] breaks)
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
{
|
||||
BeatmapInfo = { BaseDifficulty = { DrainRate = 5 } },
|
||||
BeatmapInfo = { BaseDifficulty = { DrainRate = 10 } },
|
||||
};
|
||||
|
||||
for (double time = startTime; time <= endTime; time += 100)
|
||||
{
|
||||
beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = time });
|
||||
}
|
||||
|
||||
beatmap.Breaks.AddRange(breaks);
|
||||
|
||||
return beatmap;
|
||||
}
|
||||
|
||||
private void createProcessor(Beatmap beatmap) => AddStep("create processor", () =>
|
||||
{
|
||||
breakTime = new Bindable<bool>();
|
||||
|
||||
Child = processor = new DrainingHealthProcessor(beatmap.HitObjects[0].StartTime).With(d =>
|
||||
{
|
||||
d.RelativeSizeAxes = Axes.Both;
|
||||
d.Clock = new FramedClock(clock = new ManualClock());
|
||||
});
|
||||
|
||||
processor.IsBreakTime.BindTo(breakTime);
|
||||
processor.ApplyBeatmap(beatmap);
|
||||
});
|
||||
|
||||
@ -143,8 +189,6 @@ namespace osu.Game.Tests.Gameplay
|
||||
|
||||
private void setHealth(double health) => AddStep($"set health = {health}", () => processor.Health.Value = health);
|
||||
|
||||
private void setBreak(bool enabled) => AddStep($"{(enabled ? "enable" : "disable")} break", () => breakTime.Value = enabled);
|
||||
|
||||
private void assertHealthEqualTo(double value)
|
||||
=> AddAssert($"health = {value}", () => Precision.AlmostEquals(value, processor.Health.Value, 0.0001f));
|
||||
|
||||
|
@ -3,9 +3,11 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Utils;
|
||||
|
||||
namespace osu.Game.Rulesets.Scoring
|
||||
{
|
||||
@ -47,6 +49,8 @@ namespace osu.Game.Rulesets.Scoring
|
||||
private double targetMinimumHealth;
|
||||
private double drainRate = 1;
|
||||
|
||||
private PeriodTracker noDrainPeriodTracker;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="DrainingHealthProcessor"/>.
|
||||
/// </summary>
|
||||
@ -60,15 +64,15 @@ namespace osu.Game.Rulesets.Scoring
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (!IsBreakTime.Value)
|
||||
{
|
||||
if (noDrainPeriodTracker?.IsInAny(Time.Current) == true)
|
||||
return;
|
||||
|
||||
// When jumping in and out of gameplay time within a single frame, health should only be drained for the period within the gameplay time
|
||||
double lastGameplayTime = Math.Clamp(Time.Current - Time.Elapsed, drainStartTime, gameplayEndTime);
|
||||
double currentGameplayTime = Math.Clamp(Time.Current, drainStartTime, gameplayEndTime);
|
||||
|
||||
Health.Value -= drainRate * (currentGameplayTime - lastGameplayTime);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ApplyBeatmap(IBeatmap beatmap)
|
||||
{
|
||||
@ -77,6 +81,19 @@ namespace osu.Game.Rulesets.Scoring
|
||||
if (beatmap.HitObjects.Count > 0)
|
||||
gameplayEndTime = beatmap.HitObjects[^1].GetEndTime();
|
||||
|
||||
noDrainPeriodTracker = new PeriodTracker(beatmap.Breaks.Select(breakPeriod => new Period(
|
||||
beatmap.HitObjects
|
||||
.Select(hitObject => hitObject.GetEndTime())
|
||||
.Where(endTime => endTime <= breakPeriod.StartTime)
|
||||
.DefaultIfEmpty(double.MinValue)
|
||||
.Last(),
|
||||
beatmap.HitObjects
|
||||
.Select(hitObject => hitObject.StartTime)
|
||||
.Where(startTime => startTime >= breakPeriod.EndTime)
|
||||
.DefaultIfEmpty(double.MaxValue)
|
||||
.First()
|
||||
)));
|
||||
|
||||
targetMinimumHealth = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, min_health_target, mid_health_target, max_health_target);
|
||||
|
||||
base.ApplyBeatmap(beatmap);
|
||||
|
@ -26,11 +26,6 @@ namespace osu.Game.Rulesets.Scoring
|
||||
/// </summary>
|
||||
public readonly BindableDouble Health = new BindableDouble(1) { MinValue = 0, MaxValue = 1 };
|
||||
|
||||
/// <summary>
|
||||
/// Whether gameplay is currently in a break.
|
||||
/// </summary>
|
||||
public readonly IBindable<bool> IsBreakTime = new Bindable<bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Whether this ScoreProcessor has already triggered the failed state.
|
||||
/// </summary>
|
||||
|
@ -259,8 +259,6 @@ namespace osu.Game.Screens.Play
|
||||
Breaks = working.Beatmap.Breaks
|
||||
}
|
||||
});
|
||||
|
||||
HealthProcessor.IsBreakTime.BindTo(breakTracker.IsBreakTime);
|
||||
}
|
||||
|
||||
private void addOverlayComponents(Container target, WorkingBeatmap working)
|
||||
|
Loading…
Reference in New Issue
Block a user