mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 15:47:26 +08:00
Merge remote-tracking branch 'upstream/master' into mania-judgement
This commit is contained in:
commit
5260eb76d0
@ -30,7 +30,10 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new CatchScoreProcessor(beatmap);
|
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new CatchScoreProcessor(beatmap);
|
||||||
|
|
||||||
|
public override HealthProcessor CreateHealthProcessor(IBeatmap beatmap) => new CatchHealthProcessor(beatmap);
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new CatchBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap);
|
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new CatchBeatmapProcessor(beatmap);
|
||||||
|
|
||||||
public const string SHORT_NAME = "fruits";
|
public const string SHORT_NAME = "fruits";
|
||||||
|
38
osu.Game.Rulesets.Catch/Scoring/CatchHealthProcessor.cs
Normal file
38
osu.Game.Rulesets.Catch/Scoring/CatchHealthProcessor.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Scoring
|
||||||
|
{
|
||||||
|
public class CatchHealthProcessor : HealthProcessor
|
||||||
|
{
|
||||||
|
public CatchHealthProcessor(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private float hpDrainRate;
|
||||||
|
|
||||||
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override double HealthAdjustmentFactorFor(JudgementResult result)
|
||||||
|
{
|
||||||
|
switch (result.Type)
|
||||||
|
{
|
||||||
|
case HitResult.Miss:
|
||||||
|
return hpDrainRate;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 10.2 - hpDrainRate; // Award less HP as drain rate is increased
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,6 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Scoring
|
namespace osu.Game.Rulesets.Catch.Scoring
|
||||||
@ -14,27 +13,6 @@ namespace osu.Game.Rulesets.Catch.Scoring
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private float hpDrainRate;
|
|
||||||
|
|
||||||
protected override void ApplyBeatmap(IBeatmap beatmap)
|
|
||||||
{
|
|
||||||
base.ApplyBeatmap(beatmap);
|
|
||||||
|
|
||||||
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override double HealthAdjustmentFactorFor(JudgementResult result)
|
|
||||||
{
|
|
||||||
switch (result.Type)
|
|
||||||
{
|
|
||||||
case HitResult.Miss:
|
|
||||||
return hpDrainRate;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 10.2 - hpDrainRate; // Award less HP as drain rate is increased
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override HitWindows CreateHitWindows() => new CatchHitWindows();
|
public override HitWindows CreateHitWindows() => new CatchHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,8 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new ManiaScoreProcessor(beatmap);
|
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new ManiaScoreProcessor(beatmap);
|
||||||
|
|
||||||
|
public override HealthProcessor CreateHealthProcessor(IBeatmap beatmap) => new ManiaHealthProcessor(beatmap);
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new ManiaBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score);
|
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new ManiaPerformanceCalculator(this, beatmap, score);
|
||||||
|
69
osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs
Normal file
69
osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Scoring
|
||||||
|
{
|
||||||
|
public class ManiaHealthProcessor : HealthProcessor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The hit HP multiplier at OD = 0.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_min = 0.75;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The hit HP multiplier at OD = 0.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_mid = 0.85;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The hit HP multiplier at OD = 0.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_max = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MISS HP multiplier at OD = 0.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_miss_min = 0.5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MISS HP multiplier at OD = 5.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_miss_mid = 0.75;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MISS HP multiplier at OD = 10.
|
||||||
|
/// </summary>
|
||||||
|
private const double hp_multiplier_miss_max = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The MISS HP multiplier. This is multiplied to the miss hp increase.
|
||||||
|
/// </summary>
|
||||||
|
private double hpMissMultiplier = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The HIT HP multiplier. This is multiplied to hit hp increases.
|
||||||
|
/// </summary>
|
||||||
|
private double hpMultiplier = 1;
|
||||||
|
|
||||||
|
public ManiaHealthProcessor(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
BeatmapDifficulty difficulty = beatmap.BeatmapInfo.BaseDifficulty;
|
||||||
|
hpMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_min, hp_multiplier_mid, hp_multiplier_max);
|
||||||
|
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override double HealthAdjustmentFactorFor(JudgementResult result)
|
||||||
|
=> result.Type == HitResult.Miss ? hpMissMultiplier : hpMultiplier;
|
||||||
|
}
|
||||||
|
}
|
@ -2,86 +2,17 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Scoring
|
namespace osu.Game.Rulesets.Mania.Scoring
|
||||||
{
|
{
|
||||||
internal class ManiaScoreProcessor : ScoreProcessor
|
internal class ManiaScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The hit HP multiplier at OD = 0.
|
|
||||||
/// </summary>
|
|
||||||
private const double hp_multiplier_min = 0.75;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The hit HP multiplier at OD = 0.
|
|
||||||
/// </summary>
|
|
||||||
private const double hp_multiplier_mid = 0.85;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The hit HP multiplier at OD = 0.
|
|
||||||
/// </summary>
|
|
||||||
private const double hp_multiplier_max = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The MISS HP multiplier at OD = 0.
|
|
||||||
/// </summary>
|
|
||||||
private const double hp_multiplier_miss_min = 0.5;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The MISS HP multiplier at OD = 5.
|
|
||||||
/// </summary>
|
|
||||||
private const double hp_multiplier_miss_mid = 0.75;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The MISS HP multiplier at OD = 10.
|
|
||||||
/// </summary>
|
|
||||||
private const double hp_multiplier_miss_max = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The MISS HP multiplier. This is multiplied to the miss hp increase.
|
|
||||||
/// </summary>
|
|
||||||
private double hpMissMultiplier = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The HIT HP multiplier. This is multiplied to hit hp increases.
|
|
||||||
/// </summary>
|
|
||||||
private double hpMultiplier = 1;
|
|
||||||
|
|
||||||
public ManiaScoreProcessor(IBeatmap beatmap)
|
public ManiaScoreProcessor(IBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyBeatmap(IBeatmap beatmap)
|
|
||||||
{
|
|
||||||
base.ApplyBeatmap(beatmap);
|
|
||||||
|
|
||||||
BeatmapDifficulty difficulty = beatmap.BeatmapInfo.BaseDifficulty;
|
|
||||||
hpMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_min, hp_multiplier_mid, hp_multiplier_max);
|
|
||||||
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(difficulty.DrainRate, hp_multiplier_miss_min, hp_multiplier_miss_mid, hp_multiplier_miss_max);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void SimulateAutoplay(IBeatmap beatmap)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
base.SimulateAutoplay(beatmap);
|
|
||||||
|
|
||||||
if (!HasFailed)
|
|
||||||
break;
|
|
||||||
|
|
||||||
hpMultiplier *= 1.01;
|
|
||||||
hpMissMultiplier *= 0.98;
|
|
||||||
|
|
||||||
Reset(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override double HealthAdjustmentFactorFor(JudgementResult result)
|
|
||||||
=> result.Type == HitResult.Miss ? hpMissMultiplier : hpMultiplier;
|
|
||||||
|
|
||||||
public override HitWindows CreateHitWindows() => new ManiaHitWindows();
|
public override HitWindows CreateHitWindows() => new ManiaHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Mods
|
namespace osu.Game.Rulesets.Osu.Mods
|
||||||
{
|
{
|
||||||
public class OsuModBlinds : Mod, IApplicableToDrawableRuleset<OsuHitObject>, IApplicableToScoreProcessor
|
public class OsuModBlinds : Mod, IApplicableToDrawableRuleset<OsuHitObject>, IApplicableToHealthProcessor
|
||||||
{
|
{
|
||||||
public override string Name => "Blinds";
|
public override string Name => "Blinds";
|
||||||
public override string Description => "Play with blinds on your screen.";
|
public override string Description => "Play with blinds on your screen.";
|
||||||
@ -37,9 +37,9 @@ namespace osu.Game.Rulesets.Osu.Mods
|
|||||||
drawableRuleset.Overlays.Add(blinds = new DrawableOsuBlinds(drawableRuleset.Playfield.HitObjectContainer, drawableRuleset.Beatmap));
|
drawableRuleset.Overlays.Add(blinds = new DrawableOsuBlinds(drawableRuleset.Playfield.HitObjectContainer, drawableRuleset.Beatmap));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
|
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
|
||||||
{
|
{
|
||||||
scoreProcessor.Health.ValueChanged += health => { blinds.AnimateClosedness((float)health.NewValue); };
|
healthProcessor.Health.ValueChanged += health => { blinds.AnimateClosedness((float)health.NewValue); };
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
|
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
|
||||||
|
@ -38,6 +38,8 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new OsuScoreProcessor(beatmap);
|
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new OsuScoreProcessor(beatmap);
|
||||||
|
|
||||||
|
public override HealthProcessor CreateHealthProcessor(IBeatmap beatmap) => new OsuHealthProcessor(beatmap);
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new OsuBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new OsuBeatmapProcessor(beatmap);
|
public override IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => new OsuBeatmapProcessor(beatmap);
|
||||||
|
54
osu.Game.Rulesets.Osu/Scoring/OsuHealthProcessor.cs
Normal file
54
osu.Game.Rulesets.Osu/Scoring/OsuHealthProcessor.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Scoring
|
||||||
|
{
|
||||||
|
public class OsuHealthProcessor : HealthProcessor
|
||||||
|
{
|
||||||
|
public OsuHealthProcessor(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private float hpDrainRate;
|
||||||
|
|
||||||
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override double HealthAdjustmentFactorFor(JudgementResult result)
|
||||||
|
{
|
||||||
|
switch (result.Type)
|
||||||
|
{
|
||||||
|
case HitResult.Great:
|
||||||
|
return 10.2 - hpDrainRate;
|
||||||
|
|
||||||
|
case HitResult.Good:
|
||||||
|
return 8 - hpDrainRate;
|
||||||
|
|
||||||
|
case HitResult.Meh:
|
||||||
|
return 4 - hpDrainRate;
|
||||||
|
|
||||||
|
// case HitResult.SliderTick:
|
||||||
|
// return Math.Max(7 - hpDrainRate, 0) * 0.01;
|
||||||
|
|
||||||
|
case HitResult.Miss:
|
||||||
|
return hpDrainRate;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new OsuJudgementResult(hitObject, judgement);
|
||||||
|
}
|
||||||
|
}
|
@ -16,39 +16,6 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private float hpDrainRate;
|
|
||||||
|
|
||||||
protected override void ApplyBeatmap(IBeatmap beatmap)
|
|
||||||
{
|
|
||||||
base.ApplyBeatmap(beatmap);
|
|
||||||
|
|
||||||
hpDrainRate = beatmap.BeatmapInfo.BaseDifficulty.DrainRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override double HealthAdjustmentFactorFor(JudgementResult result)
|
|
||||||
{
|
|
||||||
switch (result.Type)
|
|
||||||
{
|
|
||||||
case HitResult.Great:
|
|
||||||
return 10.2 - hpDrainRate;
|
|
||||||
|
|
||||||
case HitResult.Good:
|
|
||||||
return 8 - hpDrainRate;
|
|
||||||
|
|
||||||
case HitResult.Meh:
|
|
||||||
return 4 - hpDrainRate;
|
|
||||||
|
|
||||||
// case HitResult.SliderTick:
|
|
||||||
// return Math.Max(7 - hpDrainRate, 0) * 0.01;
|
|
||||||
|
|
||||||
case HitResult.Miss:
|
|
||||||
return hpDrainRate;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new OsuJudgementResult(hitObject, judgement);
|
protected override JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new OsuJudgementResult(hitObject, judgement);
|
||||||
|
|
||||||
public override HitWindows CreateHitWindows() => new OsuHitWindows();
|
public override HitWindows CreateHitWindows() => new OsuHitWindows();
|
||||||
|
58
osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs
Normal file
58
osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Scoring
|
||||||
|
{
|
||||||
|
public class TaikoHealthProcessor : HealthProcessor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A value used for calculating <see cref="hpMultiplier"/>.
|
||||||
|
/// </summary>
|
||||||
|
private const double object_count_factor = 3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Taiko fails at the end of the map if the player has not half-filled their HP bar.
|
||||||
|
/// </summary>
|
||||||
|
protected override bool DefaultFailCondition => JudgedHits == MaxHits && Health.Value <= 0.5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HP multiplier for a successful <see cref="HitResult"/>.
|
||||||
|
/// </summary>
|
||||||
|
private double hpMultiplier;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HP multiplier for a <see cref="HitResult.Miss"/>.
|
||||||
|
/// </summary>
|
||||||
|
private double hpMissMultiplier;
|
||||||
|
|
||||||
|
public TaikoHealthProcessor(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.OfType<Hit>().Count() * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
|
||||||
|
|
||||||
|
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override double HealthAdjustmentFactorFor(JudgementResult result)
|
||||||
|
=> result.Type == HitResult.Miss ? hpMissMultiplier : hpMultiplier;
|
||||||
|
|
||||||
|
protected override void Reset(bool storeResults)
|
||||||
|
{
|
||||||
|
base.Reset(storeResults);
|
||||||
|
|
||||||
|
Health.Value = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,60 +1,18 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Scoring
|
namespace osu.Game.Rulesets.Taiko.Scoring
|
||||||
{
|
{
|
||||||
internal class TaikoScoreProcessor : ScoreProcessor
|
internal class TaikoScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// A value used for calculating <see cref="hpMultiplier"/>.
|
|
||||||
/// </summary>
|
|
||||||
private const double object_count_factor = 3;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Taiko fails at the end of the map if the player has not half-filled their HP bar.
|
|
||||||
/// </summary>
|
|
||||||
protected override bool DefaultFailCondition => JudgedHits == MaxHits && Health.Value <= 0.5;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// HP multiplier for a successful <see cref="HitResult"/>.
|
|
||||||
/// </summary>
|
|
||||||
private double hpMultiplier;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// HP multiplier for a <see cref="HitResult.Miss"/>.
|
|
||||||
/// </summary>
|
|
||||||
private double hpMissMultiplier;
|
|
||||||
|
|
||||||
public TaikoScoreProcessor(IBeatmap beatmap)
|
public TaikoScoreProcessor(IBeatmap beatmap)
|
||||||
: base(beatmap)
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ApplyBeatmap(IBeatmap beatmap)
|
|
||||||
{
|
|
||||||
base.ApplyBeatmap(beatmap);
|
|
||||||
|
|
||||||
hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.OfType<Hit>().Count() * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
|
|
||||||
|
|
||||||
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override double HealthAdjustmentFactorFor(JudgementResult result)
|
|
||||||
=> result.Type == HitResult.Miss ? hpMissMultiplier : hpMultiplier;
|
|
||||||
|
|
||||||
protected override void Reset(bool storeResults)
|
|
||||||
{
|
|
||||||
base.Reset(storeResults);
|
|
||||||
|
|
||||||
Health.Value = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override HitWindows CreateHitWindows() => new TaikoHitWindows();
|
public override HitWindows CreateHitWindows() => new TaikoHitWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
|
|
||||||
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new TaikoScoreProcessor(beatmap);
|
public override ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new TaikoScoreProcessor(beatmap);
|
||||||
|
|
||||||
|
public override HealthProcessor CreateHealthProcessor(IBeatmap beatmap) => new TaikoHealthProcessor(beatmap);
|
||||||
|
|
||||||
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap, this);
|
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap, this);
|
||||||
|
|
||||||
public const string SHORT_NAME = "taiko";
|
public const string SHORT_NAME = "taiko";
|
||||||
|
@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
ScoreProcessor.FailConditions += (_, __) => true;
|
HealthProcessor.FailConditions += (_, __) => true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||||
AddUntilStep("wait for multiple judged objects", () => ((FailPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.Count(h => h.AllJudged) > 1);
|
AddUntilStep("wait for multiple judged objects", () => ((FailPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.Count(h => h.AllJudged) > 1);
|
||||||
AddAssert("total judgements == 1", () => ((FailPlayer)Player).ScoreProcessor.JudgedHits == 1);
|
AddAssert("total judgements == 1", () => ((FailPlayer)Player).HealthProcessor.JudgedHits >= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FailPlayer : TestPlayer
|
private class FailPlayer : TestPlayer
|
||||||
{
|
{
|
||||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
public new HealthProcessor HealthProcessor => base.HealthProcessor;
|
||||||
|
|
||||||
public FailPlayer()
|
public FailPlayer()
|
||||||
: base(false, false)
|
: base(false, false)
|
||||||
@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
ScoreProcessor.FailConditions += (_, __) => true;
|
HealthProcessor.FailConditions += (_, __) => true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
AddStep("create overlay", () =>
|
AddStep("create overlay", () =>
|
||||||
{
|
{
|
||||||
Child = hudOverlay = new HUDOverlay(null, null, Array.Empty<Mod>());
|
Child = hudOverlay = new HUDOverlay(null, null, null, Array.Empty<Mod>());
|
||||||
|
|
||||||
action?.Invoke(hudOverlay);
|
action?.Invoke(hudOverlay);
|
||||||
});
|
});
|
||||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
public void TestResumeWithResumeOverlay()
|
public void TestResumeWithResumeOverlay()
|
||||||
{
|
{
|
||||||
AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre));
|
AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre));
|
||||||
AddUntilStep("wait for hitobjects", () => Player.ScoreProcessor.Health.Value < 1);
|
AddUntilStep("wait for hitobjects", () => Player.HealthProcessor.Health.Value < 1);
|
||||||
|
|
||||||
pauseAndConfirm();
|
pauseAndConfirm();
|
||||||
resume();
|
resume();
|
||||||
@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
public void TestPauseWithResumeOverlay()
|
public void TestPauseWithResumeOverlay()
|
||||||
{
|
{
|
||||||
AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre));
|
AddStep("move cursor to center", () => InputManager.MoveMouseTo(Player.ScreenSpaceDrawQuad.Centre));
|
||||||
AddUntilStep("wait for hitobjects", () => Player.ScoreProcessor.Health.Value < 1);
|
AddUntilStep("wait for hitobjects", () => Player.HealthProcessor.Health.Value < 1);
|
||||||
|
|
||||||
pauseAndConfirm();
|
pauseAndConfirm();
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
AddStep("move cursor to button", () =>
|
AddStep("move cursor to button", () =>
|
||||||
InputManager.MoveMouseTo(Player.HUDOverlay.HoldToQuit.Children.OfType<HoldToConfirmContainer>().First().ScreenSpaceDrawQuad.Centre));
|
InputManager.MoveMouseTo(Player.HUDOverlay.HoldToQuit.Children.OfType<HoldToConfirmContainer>().First().ScreenSpaceDrawQuad.Centre));
|
||||||
AddUntilStep("wait for hitobjects", () => Player.ScoreProcessor.Health.Value < 1);
|
AddUntilStep("wait for hitobjects", () => Player.HealthProcessor.Health.Value < 1);
|
||||||
|
|
||||||
pauseAndConfirm();
|
pauseAndConfirm();
|
||||||
resumeAndConfirm();
|
resumeAndConfirm();
|
||||||
@ -285,7 +285,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
protected class PausePlayer : TestPlayer
|
protected class PausePlayer : TestPlayer
|
||||||
{
|
{
|
||||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
public new HealthProcessor HealthProcessor => base.HealthProcessor;
|
||||||
|
|
||||||
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
public new HUDOverlay HUDOverlay => base.HUDOverlay;
|
||||||
|
|
||||||
|
@ -67,9 +67,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
AddRepeatStep(@"add many simple", sendManyNotifications, 3);
|
AddRepeatStep(@"add many simple", sendManyNotifications, 3);
|
||||||
|
|
||||||
AddWaitStep("wait some", 5);
|
waitForCompletion();
|
||||||
|
|
||||||
checkProgressingCount(0);
|
|
||||||
|
|
||||||
AddStep(@"progress #3", sendUploadProgress);
|
AddStep(@"progress #3", sendUploadProgress);
|
||||||
|
|
||||||
@ -77,9 +75,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
checkDisplayedCount(33);
|
checkDisplayedCount(33);
|
||||||
|
|
||||||
AddWaitStep("wait some", 10);
|
waitForCompletion();
|
||||||
|
|
||||||
checkProgressingCount(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -109,9 +105,9 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
AddStep(@"background progress #1", sendBackgroundUploadProgress);
|
AddStep(@"background progress #1", sendBackgroundUploadProgress);
|
||||||
|
|
||||||
AddWaitStep("wait some", 5);
|
checkProgressingCount(1);
|
||||||
|
|
||||||
checkProgressingCount(0);
|
waitForCompletion();
|
||||||
|
|
||||||
checkDisplayedCount(2);
|
checkDisplayedCount(2);
|
||||||
|
|
||||||
@ -190,6 +186,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
|
|
||||||
private void checkProgressingCount(int expected) => AddAssert($"progressing count is {expected}", () => progressingNotifications.Count == expected);
|
private void checkProgressingCount(int expected) => AddAssert($"progressing count is {expected}", () => progressingNotifications.Count == expected);
|
||||||
|
|
||||||
|
private void waitForCompletion() => AddUntilStep("wait for notification progress completion", () => progressingNotifications.Count == 0);
|
||||||
|
|
||||||
private void sendBarrage()
|
private void sendBarrage()
|
||||||
{
|
{
|
||||||
switch (RNG.Next(0, 4))
|
switch (RNG.Next(0, 4))
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -13,15 +14,15 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
public abstract class ScreenTitle : CompositeDrawable, IHasAccentColour
|
public abstract class ScreenTitle : CompositeDrawable, IHasAccentColour
|
||||||
{
|
{
|
||||||
public const float ICON_WIDTH = ICON_SIZE + icon_spacing;
|
public const float ICON_WIDTH = ICON_SIZE + spacing;
|
||||||
|
|
||||||
public const float ICON_SIZE = 25;
|
public const float ICON_SIZE = 30;
|
||||||
|
private const float spacing = 6;
|
||||||
|
private const int text_offset = 2;
|
||||||
|
|
||||||
private SpriteIcon iconSprite;
|
private SpriteIcon iconSprite;
|
||||||
private readonly OsuSpriteText titleText, pageText;
|
private readonly OsuSpriteText titleText, pageText;
|
||||||
|
|
||||||
private const float icon_spacing = 10;
|
|
||||||
|
|
||||||
protected IconUsage Icon
|
protected IconUsage Icon
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
@ -63,26 +64,35 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Spacing = new Vector2(icon_spacing, 0),
|
Spacing = new Vector2(spacing, 0),
|
||||||
Children = new[]
|
|
||||||
{
|
|
||||||
CreateIcon(),
|
|
||||||
new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
Spacing = new Vector2(6, 0),
|
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
|
CreateIcon().With(t =>
|
||||||
|
{
|
||||||
|
t.Anchor = Anchor.Centre;
|
||||||
|
t.Origin = Anchor.Centre;
|
||||||
|
}),
|
||||||
titleText = new OsuSpriteText
|
titleText = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Font = OsuFont.GetFont(size: 30, weight: FontWeight.Light),
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold),
|
||||||
|
Margin = new MarginPadding { Bottom = text_offset }
|
||||||
|
},
|
||||||
|
new Circle
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Size = new Vector2(4),
|
||||||
|
Colour = Color4.Gray,
|
||||||
},
|
},
|
||||||
pageText = new OsuSpriteText
|
pageText = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Font = OsuFont.GetFont(size: 30, weight: FontWeight.Light),
|
Anchor = Anchor.Centre,
|
||||||
}
|
Origin = Anchor.Centre,
|
||||||
}
|
Font = OsuFont.GetFont(size: 20),
|
||||||
|
Margin = new MarginPadding { Bottom = text_offset }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -16,8 +15,6 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ScreenTitleTextureIcon : CompositeDrawable
|
public class ScreenTitleTextureIcon : CompositeDrawable
|
||||||
{
|
{
|
||||||
private const float circle_allowance = 0.8f;
|
|
||||||
|
|
||||||
private readonly string textureName;
|
private readonly string textureName;
|
||||||
|
|
||||||
public ScreenTitleTextureIcon(string textureName)
|
public ScreenTitleTextureIcon(string textureName)
|
||||||
@ -26,38 +23,16 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures, OsuColour colours)
|
private void load(TextureStore textures)
|
||||||
{
|
{
|
||||||
Size = new Vector2(ScreenTitle.ICON_SIZE / circle_allowance);
|
Size = new Vector2(ScreenTitle.ICON_SIZE);
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChild = new Sprite
|
||||||
{
|
|
||||||
new CircularContainer
|
|
||||||
{
|
|
||||||
Masking = true,
|
|
||||||
BorderColour = colours.Violet,
|
|
||||||
BorderThickness = 3,
|
|
||||||
MaskingSmoothness = 1,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
new Sprite
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Texture = textures.Get(textureName),
|
Texture = textures.Get(textureName),
|
||||||
Size = new Vector2(circle_allowance),
|
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
},
|
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = colours.Violet,
|
|
||||||
Alpha = 0,
|
|
||||||
AlwaysPresent = true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ namespace osu.Game.Overlays.Changelog
|
|||||||
|
|
||||||
public ChangelogHeaderTitle()
|
public ChangelogHeaderTitle()
|
||||||
{
|
{
|
||||||
Title = "Changelog";
|
Title = "changelog";
|
||||||
Version = null;
|
Version = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ namespace osu.Game.Overlays.News
|
|||||||
{
|
{
|
||||||
public class NewsHeader : OverlayHeader
|
public class NewsHeader : OverlayHeader
|
||||||
{
|
{
|
||||||
private const string front_page_string = "Front Page";
|
private const string front_page_string = "frontpage";
|
||||||
|
|
||||||
private NewsHeaderTitle title;
|
private NewsHeaderTitle title;
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ namespace osu.Game.Overlays.News
|
|||||||
ShowFrontPage?.Invoke();
|
ShowFrontPage?.Invoke();
|
||||||
};
|
};
|
||||||
|
|
||||||
Current.ValueChanged += showArticle;
|
Current.ValueChanged += showPost;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -42,7 +42,7 @@ namespace osu.Game.Overlays.News
|
|||||||
TabControl.AccentColour = colour.Violet;
|
TabControl.AccentColour = colour.Violet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showArticle(ValueChangedEvent<string> e)
|
private void showPost(ValueChangedEvent<string> e)
|
||||||
{
|
{
|
||||||
if (e.OldValue != null)
|
if (e.OldValue != null)
|
||||||
TabControl.RemoveItem(e.OldValue);
|
TabControl.RemoveItem(e.OldValue);
|
||||||
@ -52,12 +52,12 @@ namespace osu.Game.Overlays.News
|
|||||||
TabControl.AddItem(e.NewValue);
|
TabControl.AddItem(e.NewValue);
|
||||||
TabControl.Current.Value = e.NewValue;
|
TabControl.Current.Value = e.NewValue;
|
||||||
|
|
||||||
title.IsReadingArticle = true;
|
title.IsReadingPost = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TabControl.Current.Value = front_page_string;
|
TabControl.Current.Value = front_page_string;
|
||||||
title.IsReadingArticle = false;
|
title.IsReadingPost = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,17 +84,17 @@ namespace osu.Game.Overlays.News
|
|||||||
|
|
||||||
private class NewsHeaderTitle : ScreenTitle
|
private class NewsHeaderTitle : ScreenTitle
|
||||||
{
|
{
|
||||||
private const string article_string = "Article";
|
private const string post_string = "post";
|
||||||
|
|
||||||
public bool IsReadingArticle
|
public bool IsReadingPost
|
||||||
{
|
{
|
||||||
set => Section = value ? article_string : front_page_string;
|
set => Section = value ? post_string : front_page_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NewsHeaderTitle()
|
public NewsHeaderTitle()
|
||||||
{
|
{
|
||||||
Title = "News";
|
Title = "news";
|
||||||
IsReadingArticle = false;
|
IsReadingPost = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/news");
|
protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/news");
|
||||||
|
@ -101,8 +101,8 @@ namespace osu.Game.Overlays.Profile
|
|||||||
{
|
{
|
||||||
public ProfileHeaderTitle()
|
public ProfileHeaderTitle()
|
||||||
{
|
{
|
||||||
Title = "Player";
|
Title = "player";
|
||||||
Section = "Info";
|
Section = "info";
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
15
osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs
Normal file
15
osu.Game/Rulesets/Mods/IApplicableToHealthProcessor.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mods
|
||||||
|
{
|
||||||
|
public interface IApplicableToHealthProcessor : IApplicableMod
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provide a <see cref="HealthProcessor"/> to a mod. Called once on initialisation of a play instance.
|
||||||
|
/// </summary>
|
||||||
|
void ApplyToHealthProcessor(HealthProcessor healthProcessor);
|
||||||
|
}
|
||||||
|
}
|
@ -8,11 +8,10 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
public abstract class ModEasy : Mod, IApplicableToDifficulty, IApplicableFailOverride, IApplicableToScoreProcessor
|
public abstract class ModEasy : Mod, IApplicableToDifficulty, IApplicableFailOverride, IApplicableToHealthProcessor
|
||||||
{
|
{
|
||||||
public override string Name => "Easy";
|
public override string Name => "Easy";
|
||||||
public override string Acronym => "EZ";
|
public override string Acronym => "EZ";
|
||||||
@ -59,11 +58,9 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
public bool RestartOnFail => false;
|
public bool RestartOnFail => false;
|
||||||
|
|
||||||
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
|
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
|
||||||
{
|
{
|
||||||
health = scoreProcessor.Health.GetBoundCopy();
|
health = healthProcessor.Health.GetBoundCopy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,6 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override IconUsage Icon => OsuIcon.ModPerfect;
|
public override IconUsage Icon => OsuIcon.ModPerfect;
|
||||||
public override string Description => "SS or quit.";
|
public override string Description => "SS or quit.";
|
||||||
|
|
||||||
protected override bool FailCondition(ScoreProcessor scoreProcessor, JudgementResult result) => scoreProcessor.Accuracy.Value != 1;
|
protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) => result.Type != result.Judgement.MaxResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,10 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
public abstract class ModSuddenDeath : Mod, IApplicableToScoreProcessor, IApplicableFailOverride
|
public abstract class ModSuddenDeath : Mod, IApplicableToHealthProcessor, IApplicableFailOverride
|
||||||
{
|
{
|
||||||
public override string Name => "Sudden Death";
|
public override string Name => "Sudden Death";
|
||||||
public override string Acronym => "SD";
|
public override string Acronym => "SD";
|
||||||
@ -24,13 +23,11 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public bool AllowFail => true;
|
public bool AllowFail => true;
|
||||||
public bool RestartOnFail => true;
|
public bool RestartOnFail => true;
|
||||||
|
|
||||||
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
|
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
|
||||||
{
|
{
|
||||||
scoreProcessor.FailConditions += FailCondition;
|
healthProcessor.FailConditions += FailCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
|
protected virtual bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) => !result.IsHit && result.Judgement.AffectsCombo;
|
||||||
|
|
||||||
protected virtual bool FailCondition(ScoreProcessor scoreProcessor, JudgementResult result) => scoreProcessor.Combo.Value == 0 && result.Judgement.AffectsCombo;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,12 @@ namespace osu.Game.Rulesets
|
|||||||
/// <returns>The score processor.</returns>
|
/// <returns>The score processor.</returns>
|
||||||
public virtual ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new ScoreProcessor(beatmap);
|
public virtual ScoreProcessor CreateScoreProcessor(IBeatmap beatmap) => new ScoreProcessor(beatmap);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="HealthProcessor"/> for a beatmap converted to this ruleset.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The health processor.</returns>
|
||||||
|
public virtual HealthProcessor CreateHealthProcessor(IBeatmap beatmap) => new HealthProcessor(beatmap);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a <see cref="IBeatmapConverter"/> to convert a <see cref="IBeatmap"/> to one that is applicable for this <see cref="Ruleset"/>.
|
/// Creates a <see cref="IBeatmapConverter"/> to convert a <see cref="IBeatmap"/> to one that is applicable for this <see cref="Ruleset"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
84
osu.Game/Rulesets/Scoring/HealthProcessor.cs
Normal file
84
osu.Game/Rulesets/Scoring/HealthProcessor.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.MathUtils;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Scoring
|
||||||
|
{
|
||||||
|
public class HealthProcessor : JudgementProcessor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when the <see cref="ScoreProcessor"/> is in a failed state.
|
||||||
|
/// Return true if the fail was permitted.
|
||||||
|
/// </summary>
|
||||||
|
public event Func<bool> Failed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Additional conditions on top of <see cref="DefaultFailCondition"/> that cause a failing state.
|
||||||
|
/// </summary>
|
||||||
|
public event Func<HealthProcessor, JudgementResult, bool> FailConditions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current health.
|
||||||
|
/// </summary>
|
||||||
|
public readonly BindableDouble Health = new BindableDouble(1) { MinValue = 0, MaxValue = 1 };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this ScoreProcessor has already triggered the failed state.
|
||||||
|
/// </summary>
|
||||||
|
public bool HasFailed { get; private set; }
|
||||||
|
|
||||||
|
public HealthProcessor(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ApplyResultInternal(JudgementResult result)
|
||||||
|
{
|
||||||
|
result.HealthAtJudgement = Health.Value;
|
||||||
|
result.FailedAtJudgement = HasFailed;
|
||||||
|
|
||||||
|
if (HasFailed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Health.Value += HealthAdjustmentFactorFor(result) * result.Judgement.HealthIncreaseFor(result);
|
||||||
|
|
||||||
|
if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Failed?.Invoke() != false)
|
||||||
|
HasFailed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void RevertResultInternal(JudgementResult result)
|
||||||
|
{
|
||||||
|
Health.Value = result.HealthAtJudgement;
|
||||||
|
|
||||||
|
// Todo: Revert HasFailed state with proper player support
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An adjustment factor which is multiplied into the health increase provided by a <see cref="JudgementResult"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The <see cref="JudgementResult"/> for which the adjustment should apply.</param>
|
||||||
|
/// <returns>The adjustment factor.</returns>
|
||||||
|
protected virtual double HealthAdjustmentFactorFor(JudgementResult result) => 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default conditions for failing.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool DefaultFailCondition => Precision.AlmostBigger(Health.MinValue, Health.Value);
|
||||||
|
|
||||||
|
protected override void Reset(bool storeResults)
|
||||||
|
{
|
||||||
|
base.Reset(storeResults);
|
||||||
|
|
||||||
|
Health.Value = 1;
|
||||||
|
HasFailed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
146
osu.Game/Rulesets/Scoring/JudgementProcessor.cs
Normal file
146
osu.Game/Rulesets/Scoring/JudgementProcessor.cs
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Scoring
|
||||||
|
{
|
||||||
|
public abstract class JudgementProcessor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when all <see cref="HitObject"/>s have been judged by this <see cref="JudgementProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
public event Action AllJudged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by this <see cref="JudgementProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<JudgementResult> NewJudgement;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of hits that can be judged.
|
||||||
|
/// </summary>
|
||||||
|
protected int MaxHits { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The total number of judged <see cref="HitObject"/>s at the current point in time.
|
||||||
|
/// </summary>
|
||||||
|
public int JudgedHits { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether all <see cref="Judgement"/>s have been processed.
|
||||||
|
/// </summary>
|
||||||
|
public bool HasCompleted => JudgedHits == MaxHits;
|
||||||
|
|
||||||
|
protected JudgementProcessor(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
|
Reset(false);
|
||||||
|
SimulateAutoplay(beatmap);
|
||||||
|
Reset(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies any properties of the <see cref="IBeatmap"/> which affect scoring to this <see cref="ScoreProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The <see cref="IBeatmap"/> to read properties from.</param>
|
||||||
|
protected virtual void ApplyBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
||||||
|
public void ApplyResult(JudgementResult result)
|
||||||
|
{
|
||||||
|
JudgedHits++;
|
||||||
|
|
||||||
|
ApplyResultInternal(result);
|
||||||
|
|
||||||
|
NewJudgement?.Invoke(result);
|
||||||
|
|
||||||
|
if (HasCompleted)
|
||||||
|
AllJudged?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The judgement scoring result.</param>
|
||||||
|
public void RevertResult(JudgementResult result)
|
||||||
|
{
|
||||||
|
JudgedHits--;
|
||||||
|
|
||||||
|
RevertResultInternal(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Any changes applied via this method can be reverted via <see cref="RevertResultInternal"/>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
||||||
|
protected abstract void ApplyResultInternal(JudgementResult result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/> via <see cref="ApplyResultInternal"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The judgement scoring result.</param>
|
||||||
|
protected abstract void RevertResultInternal(JudgementResult result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets this <see cref="JudgementProcessor"/> to a default state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="storeResults">Whether to store the current state of the <see cref="JudgementProcessor"/> for future use.</param>
|
||||||
|
protected virtual void Reset(bool storeResults)
|
||||||
|
{
|
||||||
|
if (storeResults)
|
||||||
|
MaxHits = JudgedHits;
|
||||||
|
|
||||||
|
JudgedHits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the <see cref="JudgementResult"/> that represents the scoring result for a <see cref="HitObject"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hitObject">The <see cref="HitObject"/> which was judged.</param>
|
||||||
|
/// <param name="judgement">The <see cref="Judgement"/> that provides the scoring information.</param>
|
||||||
|
protected virtual JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new JudgementResult(hitObject, judgement);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Simulates an autoplay of the <see cref="IBeatmap"/> to determine scoring values.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This provided temporarily. DO NOT USE.</remarks>
|
||||||
|
/// <param name="beatmap">The <see cref="IBeatmap"/> to simulate.</param>
|
||||||
|
protected virtual void SimulateAutoplay(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
foreach (var obj in beatmap.HitObjects)
|
||||||
|
simulate(obj);
|
||||||
|
|
||||||
|
void simulate(HitObject obj)
|
||||||
|
{
|
||||||
|
foreach (var nested in obj.NestedHitObjects)
|
||||||
|
simulate(nested);
|
||||||
|
|
||||||
|
var judgement = obj.CreateJudgement();
|
||||||
|
if (judgement == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var result = CreateResult(obj, judgement);
|
||||||
|
if (result == null)
|
||||||
|
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
||||||
|
|
||||||
|
result.Type = judgement.MaxResult;
|
||||||
|
|
||||||
|
ApplyResult(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,44 +7,19 @@ using System.Diagnostics;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.TypeExtensions;
|
|
||||||
using osu.Framework.MathUtils;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Scoring
|
namespace osu.Game.Rulesets.Scoring
|
||||||
{
|
{
|
||||||
public class ScoreProcessor
|
public class ScoreProcessor : JudgementProcessor
|
||||||
{
|
{
|
||||||
private const double base_portion = 0.3;
|
private const double base_portion = 0.3;
|
||||||
private const double combo_portion = 0.7;
|
private const double combo_portion = 0.7;
|
||||||
private const double max_score = 1000000;
|
private const double max_score = 1000000;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when the <see cref="ScoreProcessor"/> is in a failed state.
|
|
||||||
/// This may occur regardless of whether an <see cref="AllJudged"/> event is invoked.
|
|
||||||
/// Return true if the fail was permitted.
|
|
||||||
/// </summary>
|
|
||||||
public event Func<bool> Failed;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when all <see cref="HitObject"/>s have been judged.
|
|
||||||
/// </summary>
|
|
||||||
public event Action AllJudged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by the <see cref="ScoreProcessor"/>.
|
|
||||||
/// </summary>
|
|
||||||
public event Action<JudgementResult> NewJudgement;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Additional conditions on top of <see cref="DefaultFailCondition"/> that cause a failing state.
|
|
||||||
/// </summary>
|
|
||||||
public event Func<ScoreProcessor, JudgementResult, bool> FailConditions;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current total score.
|
/// The current total score.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -55,11 +30,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableDouble Accuracy = new BindableDouble(1) { MinValue = 0, MaxValue = 1 };
|
public readonly BindableDouble Accuracy = new BindableDouble(1) { MinValue = 0, MaxValue = 1 };
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The current health.
|
|
||||||
/// </summary>
|
|
||||||
public readonly BindableDouble Health = new BindableDouble(1) { MinValue = 0, MaxValue = 1 };
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current combo.
|
/// The current combo.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -85,26 +55,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Bindable<ScoringMode> Mode = new Bindable<ScoringMode>();
|
public readonly Bindable<ScoringMode> Mode = new Bindable<ScoringMode>();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether all <see cref="Judgement"/>s have been processed.
|
|
||||||
/// </summary>
|
|
||||||
public bool HasCompleted => JudgedHits == MaxHits;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether this ScoreProcessor has already triggered the failed state.
|
|
||||||
/// </summary>
|
|
||||||
public bool HasFailed { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The maximum number of hits that can be judged.
|
|
||||||
/// </summary>
|
|
||||||
protected int MaxHits { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The total number of judged <see cref="HitObject"/>s at the current point in time.
|
|
||||||
/// </summary>
|
|
||||||
public int JudgedHits { get; private set; }
|
|
||||||
|
|
||||||
private double maxHighestCombo;
|
private double maxHighestCombo;
|
||||||
|
|
||||||
private double maxBaseScore;
|
private double maxBaseScore;
|
||||||
@ -115,8 +65,14 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
private double scoreMultiplier = 1;
|
private double scoreMultiplier = 1;
|
||||||
|
|
||||||
public ScoreProcessor(IBeatmap beatmap)
|
public ScoreProcessor(IBeatmap beatmap)
|
||||||
|
: base(beatmap)
|
||||||
{
|
{
|
||||||
Debug.Assert(base_portion + combo_portion == 1.0);
|
Debug.Assert(base_portion + combo_portion == 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
|
{
|
||||||
|
base.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
Combo.ValueChanged += combo => HighestCombo.Value = Math.Max(HighestCombo.Value, combo.NewValue);
|
Combo.ValueChanged += combo => HighestCombo.Value = Math.Max(HighestCombo.Value, combo.NewValue);
|
||||||
Accuracy.ValueChanged += accuracy =>
|
Accuracy.ValueChanged += accuracy =>
|
||||||
@ -126,12 +82,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
Rank.Value = mod.AdjustRank(Rank.Value, accuracy.NewValue);
|
Rank.Value = mod.AdjustRank(Rank.Value, accuracy.NewValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
ApplyBeatmap(beatmap);
|
|
||||||
|
|
||||||
Reset(false);
|
|
||||||
SimulateAutoplay(beatmap);
|
|
||||||
Reset(true);
|
|
||||||
|
|
||||||
if (maxBaseScore == 0 || maxHighestCombo == 0)
|
if (maxBaseScore == 0 || maxHighestCombo == 0)
|
||||||
{
|
{
|
||||||
Mode.Value = ScoringMode.Classic;
|
Mode.Value = ScoringMode.Classic;
|
||||||
@ -150,91 +100,16 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies any properties of the <see cref="IBeatmap"/> which affect scoring to this <see cref="ScoreProcessor"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="beatmap">The <see cref="IBeatmap"/> to read properties from.</param>
|
|
||||||
protected virtual void ApplyBeatmap(IBeatmap beatmap)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Simulates an autoplay of the <see cref="IBeatmap"/> to determine scoring values.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>This provided temporarily. DO NOT USE.</remarks>
|
|
||||||
/// <param name="beatmap">The <see cref="IBeatmap"/> to simulate.</param>
|
|
||||||
protected virtual void SimulateAutoplay(IBeatmap beatmap)
|
|
||||||
{
|
|
||||||
foreach (var obj in beatmap.HitObjects)
|
|
||||||
simulate(obj);
|
|
||||||
|
|
||||||
void simulate(HitObject obj)
|
|
||||||
{
|
|
||||||
foreach (var nested in obj.NestedHitObjects)
|
|
||||||
simulate(nested);
|
|
||||||
|
|
||||||
var judgement = obj.CreateJudgement();
|
|
||||||
if (judgement == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var result = CreateResult(obj, judgement);
|
|
||||||
if (result == null)
|
|
||||||
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
|
||||||
|
|
||||||
result.Type = judgement.MaxResult;
|
|
||||||
|
|
||||||
ApplyResult(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
|
||||||
public void ApplyResult(JudgementResult result)
|
|
||||||
{
|
|
||||||
ApplyResultInternal(result);
|
|
||||||
|
|
||||||
updateScore();
|
|
||||||
updateFailed(result);
|
|
||||||
|
|
||||||
NewJudgement?.Invoke(result);
|
|
||||||
|
|
||||||
if (HasCompleted)
|
|
||||||
AllJudged?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The judgement scoring result.</param>
|
|
||||||
public void RevertResult(JudgementResult result)
|
|
||||||
{
|
|
||||||
RevertResultInternal(result);
|
|
||||||
updateScore();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Dictionary<HitResult, int> scoreResultCounts = new Dictionary<HitResult, int>();
|
private readonly Dictionary<HitResult, int> scoreResultCounts = new Dictionary<HitResult, int>();
|
||||||
|
|
||||||
/// <summary>
|
protected sealed override void ApplyResultInternal(JudgementResult result)
|
||||||
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Any changes applied via this method can be reverted via <see cref="RevertResultInternal"/>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
|
|
||||||
protected virtual void ApplyResultInternal(JudgementResult result)
|
|
||||||
{
|
{
|
||||||
result.ComboAtJudgement = Combo.Value;
|
result.ComboAtJudgement = Combo.Value;
|
||||||
result.HighestComboAtJudgement = HighestCombo.Value;
|
result.HighestComboAtJudgement = HighestCombo.Value;
|
||||||
result.HealthAtJudgement = Health.Value;
|
|
||||||
result.FailedAtJudgement = HasFailed;
|
|
||||||
|
|
||||||
if (HasFailed)
|
if (result.FailedAtJudgement)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JudgedHits++;
|
|
||||||
|
|
||||||
if (result.Judgement.AffectsCombo)
|
if (result.Judgement.AffectsCombo)
|
||||||
{
|
{
|
||||||
switch (result.Type)
|
switch (result.Type)
|
||||||
@ -266,26 +141,17 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
rollingMaxBaseScore += result.Judgement.MaxNumericResult;
|
rollingMaxBaseScore += result.Judgement.MaxNumericResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
Health.Value += HealthAdjustmentFactorFor(result) * result.Judgement.HealthIncreaseFor(result);
|
updateScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
protected sealed override void RevertResultInternal(JudgementResult result)
|
||||||
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/> via <see cref="ApplyResultInternal"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The judgement scoring result.</param>
|
|
||||||
protected virtual void RevertResultInternal(JudgementResult result)
|
|
||||||
{
|
{
|
||||||
Combo.Value = result.ComboAtJudgement;
|
Combo.Value = result.ComboAtJudgement;
|
||||||
HighestCombo.Value = result.HighestComboAtJudgement;
|
HighestCombo.Value = result.HighestComboAtJudgement;
|
||||||
Health.Value = result.HealthAtJudgement;
|
|
||||||
|
|
||||||
// Todo: Revert HasFailed state with proper player support
|
|
||||||
|
|
||||||
if (result.FailedAtJudgement)
|
if (result.FailedAtJudgement)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
JudgedHits--;
|
|
||||||
|
|
||||||
if (result.Judgement.IsBonus)
|
if (result.Judgement.IsBonus)
|
||||||
{
|
{
|
||||||
if (result.IsHit)
|
if (result.IsHit)
|
||||||
@ -299,14 +165,9 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
baseScore -= result.Judgement.NumericResultFor(result);
|
baseScore -= result.Judgement.NumericResultFor(result);
|
||||||
rollingMaxBaseScore -= result.Judgement.MaxNumericResult;
|
rollingMaxBaseScore -= result.Judgement.MaxNumericResult;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
updateScore();
|
||||||
/// An adjustment factor which is multiplied into the health increase provided by a <see cref="JudgementResult"/>.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="result">The <see cref="JudgementResult"/> for which the adjustment should apply.</param>
|
|
||||||
/// <returns>The adjustment factor.</returns>
|
|
||||||
protected virtual double HealthAdjustmentFactorFor(JudgementResult result) => 1;
|
|
||||||
|
|
||||||
private void updateScore()
|
private void updateScore()
|
||||||
{
|
{
|
||||||
@ -330,24 +191,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the score is in a failed state and notifies subscribers.
|
|
||||||
/// <para>
|
|
||||||
/// This can only ever notify subscribers once.
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
|
||||||
private void updateFailed(JudgementResult result)
|
|
||||||
{
|
|
||||||
if (HasFailed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Failed?.Invoke() != false)
|
|
||||||
HasFailed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScoreRank rankFrom(double acc)
|
private ScoreRank rankFrom(double acc)
|
||||||
{
|
{
|
||||||
if (acc == 1)
|
if (acc == 1)
|
||||||
@ -372,30 +215,27 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// Resets this ScoreProcessor to a default state.
|
/// Resets this ScoreProcessor to a default state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="storeResults">Whether to store the current state of the <see cref="ScoreProcessor"/> for future use.</param>
|
/// <param name="storeResults">Whether to store the current state of the <see cref="ScoreProcessor"/> for future use.</param>
|
||||||
protected virtual void Reset(bool storeResults)
|
protected override void Reset(bool storeResults)
|
||||||
{
|
{
|
||||||
|
base.Reset(storeResults);
|
||||||
|
|
||||||
scoreResultCounts.Clear();
|
scoreResultCounts.Clear();
|
||||||
|
|
||||||
if (storeResults)
|
if (storeResults)
|
||||||
{
|
{
|
||||||
MaxHits = JudgedHits;
|
|
||||||
maxHighestCombo = HighestCombo.Value;
|
maxHighestCombo = HighestCombo.Value;
|
||||||
maxBaseScore = baseScore;
|
maxBaseScore = baseScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
JudgedHits = 0;
|
|
||||||
baseScore = 0;
|
baseScore = 0;
|
||||||
rollingMaxBaseScore = 0;
|
rollingMaxBaseScore = 0;
|
||||||
bonusScore = 0;
|
bonusScore = 0;
|
||||||
|
|
||||||
TotalScore.Value = 0;
|
TotalScore.Value = 0;
|
||||||
Accuracy.Value = 1;
|
Accuracy.Value = 1;
|
||||||
Health.Value = 1;
|
|
||||||
Combo.Value = 0;
|
Combo.Value = 0;
|
||||||
Rank.Value = ScoreRank.X;
|
Rank.Value = ScoreRank.X;
|
||||||
HighestCombo.Value = 0;
|
HighestCombo.Value = 0;
|
||||||
|
|
||||||
HasFailed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -416,22 +256,10 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
score.Statistics[result] = GetStatistic(result);
|
score.Statistics[result] = GetStatistic(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The default conditions for failing.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual bool DefaultFailCondition => Precision.AlmostBigger(Health.MinValue, Health.Value);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a <see cref="HitWindows"/> for this processor.
|
/// Create a <see cref="HitWindows"/> for this processor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual HitWindows CreateHitWindows() => new HitWindows();
|
public virtual HitWindows CreateHitWindows() => new HitWindows();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates the <see cref="JudgementResult"/> that represents the scoring result for a <see cref="HitObject"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hitObject">The <see cref="HitObject"/> which was judged.</param>
|
|
||||||
/// <param name="judgement">The <see cref="Judgement"/> that provides the scoring information.</param>
|
|
||||||
protected virtual JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new JudgementResult(hitObject, judgement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ScoringMode
|
public enum ScoringMode
|
||||||
|
@ -41,6 +41,7 @@ namespace osu.Game.Screens.Play
|
|||||||
public Bindable<bool> ShowHealthbar = new Bindable<bool>(true);
|
public Bindable<bool> ShowHealthbar = new Bindable<bool>(true);
|
||||||
|
|
||||||
private readonly ScoreProcessor scoreProcessor;
|
private readonly ScoreProcessor scoreProcessor;
|
||||||
|
private readonly HealthProcessor healthProcessor;
|
||||||
private readonly DrawableRuleset drawableRuleset;
|
private readonly DrawableRuleset drawableRuleset;
|
||||||
private readonly IReadOnlyList<Mod> mods;
|
private readonly IReadOnlyList<Mod> mods;
|
||||||
|
|
||||||
@ -63,9 +64,10 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private IEnumerable<Drawable> hideTargets => new Drawable[] { visibilityContainer, KeyCounter };
|
private IEnumerable<Drawable> hideTargets => new Drawable[] { visibilityContainer, KeyCounter };
|
||||||
|
|
||||||
public HUDOverlay(ScoreProcessor scoreProcessor, DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods)
|
public HUDOverlay(ScoreProcessor scoreProcessor, HealthProcessor healthProcessor, DrawableRuleset drawableRuleset, IReadOnlyList<Mod> mods)
|
||||||
{
|
{
|
||||||
this.scoreProcessor = scoreProcessor;
|
this.scoreProcessor = scoreProcessor;
|
||||||
|
this.healthProcessor = healthProcessor;
|
||||||
this.drawableRuleset = drawableRuleset;
|
this.drawableRuleset = drawableRuleset;
|
||||||
this.mods = mods;
|
this.mods = mods;
|
||||||
|
|
||||||
@ -119,7 +121,10 @@ namespace osu.Game.Screens.Play
|
|||||||
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
|
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
|
||||||
{
|
{
|
||||||
if (scoreProcessor != null)
|
if (scoreProcessor != null)
|
||||||
BindProcessor(scoreProcessor);
|
BindScoreProcessor(scoreProcessor);
|
||||||
|
|
||||||
|
if (healthProcessor != null)
|
||||||
|
BindHealthProcessor(healthProcessor);
|
||||||
|
|
||||||
if (drawableRuleset != null)
|
if (drawableRuleset != null)
|
||||||
{
|
{
|
||||||
@ -288,15 +293,19 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay();
|
protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay();
|
||||||
|
|
||||||
protected virtual void BindProcessor(ScoreProcessor processor)
|
protected virtual void BindScoreProcessor(ScoreProcessor processor)
|
||||||
{
|
{
|
||||||
ScoreCounter?.Current.BindTo(processor.TotalScore);
|
ScoreCounter?.Current.BindTo(processor.TotalScore);
|
||||||
AccuracyCounter?.Current.BindTo(processor.Accuracy);
|
AccuracyCounter?.Current.BindTo(processor.Accuracy);
|
||||||
ComboCounter?.Current.BindTo(processor.Combo);
|
ComboCounter?.Current.BindTo(processor.Combo);
|
||||||
HealthDisplay?.Current.BindTo(processor.Health);
|
|
||||||
|
|
||||||
if (HealthDisplay is StandardHealthDisplay shd)
|
if (HealthDisplay is StandardHealthDisplay shd)
|
||||||
processor.NewJudgement += shd.Flash;
|
processor.NewJudgement += shd.Flash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void BindHealthProcessor(HealthProcessor processor)
|
||||||
|
{
|
||||||
|
HealthDisplay?.Current.BindTo(processor.Health);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,9 @@ namespace osu.Game.Screens.Play
|
|||||||
public BreakOverlay BreakOverlay;
|
public BreakOverlay BreakOverlay;
|
||||||
|
|
||||||
protected ScoreProcessor ScoreProcessor { get; private set; }
|
protected ScoreProcessor ScoreProcessor { get; private set; }
|
||||||
|
|
||||||
|
protected HealthProcessor HealthProcessor { get; private set; }
|
||||||
|
|
||||||
protected DrawableRuleset DrawableRuleset { get; private set; }
|
protected DrawableRuleset DrawableRuleset { get; private set; }
|
||||||
|
|
||||||
protected HUDOverlay HUDOverlay { get; private set; }
|
protected HUDOverlay HUDOverlay { get; private set; }
|
||||||
@ -131,6 +134,8 @@ namespace osu.Game.Screens.Play
|
|||||||
ScoreProcessor = ruleset.CreateScoreProcessor(playableBeatmap);
|
ScoreProcessor = ruleset.CreateScoreProcessor(playableBeatmap);
|
||||||
ScoreProcessor.Mods.BindTo(Mods);
|
ScoreProcessor.Mods.BindTo(Mods);
|
||||||
|
|
||||||
|
HealthProcessor = ruleset.CreateHealthProcessor(playableBeatmap);
|
||||||
|
|
||||||
if (!ScoreProcessor.Mode.Disabled)
|
if (!ScoreProcessor.Mode.Disabled)
|
||||||
config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode);
|
config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode);
|
||||||
|
|
||||||
@ -145,15 +150,28 @@ namespace osu.Game.Screens.Play
|
|||||||
// bind clock into components that require it
|
// bind clock into components that require it
|
||||||
DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused);
|
DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused);
|
||||||
|
|
||||||
DrawableRuleset.OnNewResult += ScoreProcessor.ApplyResult;
|
DrawableRuleset.OnNewResult += r =>
|
||||||
DrawableRuleset.OnRevertResult += ScoreProcessor.RevertResult;
|
{
|
||||||
|
HealthProcessor.ApplyResult(r);
|
||||||
|
ScoreProcessor.ApplyResult(r);
|
||||||
|
};
|
||||||
|
|
||||||
// Bind ScoreProcessor to ourselves
|
DrawableRuleset.OnRevertResult += r =>
|
||||||
|
{
|
||||||
|
HealthProcessor.RevertResult(r);
|
||||||
|
ScoreProcessor.RevertResult(r);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind the judgement processors to ourselves
|
||||||
ScoreProcessor.AllJudged += onCompletion;
|
ScoreProcessor.AllJudged += onCompletion;
|
||||||
ScoreProcessor.Failed += onFail;
|
HealthProcessor.Failed += onFail;
|
||||||
|
|
||||||
foreach (var mod in Mods.Value.OfType<IApplicableToScoreProcessor>())
|
foreach (var mod in Mods.Value.OfType<IApplicableToScoreProcessor>())
|
||||||
mod.ApplyToScoreProcessor(ScoreProcessor);
|
mod.ApplyToScoreProcessor(ScoreProcessor);
|
||||||
|
|
||||||
|
foreach (var mod in Mods.Value.OfType<IApplicableToHealthProcessor>())
|
||||||
|
mod.ApplyToHealthProcessor(HealthProcessor);
|
||||||
|
|
||||||
BreakOverlay.IsBreakTime.ValueChanged += _ => updatePauseOnFocusLostState();
|
BreakOverlay.IsBreakTime.ValueChanged += _ => updatePauseOnFocusLostState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,7 +215,7 @@ namespace osu.Game.Screens.Play
|
|||||||
// display the cursor above some HUD elements.
|
// display the cursor above some HUD elements.
|
||||||
DrawableRuleset.Cursor?.CreateProxy() ?? new Container(),
|
DrawableRuleset.Cursor?.CreateProxy() ?? new Container(),
|
||||||
DrawableRuleset.ResumeOverlay?.CreateProxy() ?? new Container(),
|
DrawableRuleset.ResumeOverlay?.CreateProxy() ?? new Container(),
|
||||||
HUDOverlay = new HUDOverlay(ScoreProcessor, DrawableRuleset, Mods.Value)
|
HUDOverlay = new HUDOverlay(ScoreProcessor, HealthProcessor, DrawableRuleset, Mods.Value)
|
||||||
{
|
{
|
||||||
HoldToQuit =
|
HoldToQuit =
|
||||||
{
|
{
|
||||||
@ -342,7 +360,7 @@ namespace osu.Game.Screens.Play
|
|||||||
private void onCompletion()
|
private void onCompletion()
|
||||||
{
|
{
|
||||||
// Only show the completion screen if the player hasn't failed
|
// Only show the completion screen if the player hasn't failed
|
||||||
if (ScoreProcessor.HasFailed || completionProgressDelegate != null)
|
if (HealthProcessor.HasFailed || completionProgressDelegate != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ValidForResume = false;
|
ValidForResume = false;
|
||||||
@ -350,18 +368,7 @@ namespace osu.Game.Screens.Play
|
|||||||
if (!showResults) return;
|
if (!showResults) return;
|
||||||
|
|
||||||
using (BeginDelayedSequence(1000))
|
using (BeginDelayedSequence(1000))
|
||||||
{
|
scheduleGotoRanking();
|
||||||
completionProgressDelegate = Schedule(delegate
|
|
||||||
{
|
|
||||||
if (!this.IsCurrentScreen()) return;
|
|
||||||
|
|
||||||
var score = CreateScore();
|
|
||||||
if (DrawableRuleset.ReplayScore == null)
|
|
||||||
scoreManager.Import(score).Wait();
|
|
||||||
|
|
||||||
this.Push(CreateResults(score));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual ScoreInfo CreateScore()
|
protected virtual ScoreInfo CreateScore()
|
||||||
@ -542,7 +549,7 @@ namespace osu.Game.Screens.Play
|
|||||||
if (completionProgressDelegate != null && !completionProgressDelegate.Cancelled && !completionProgressDelegate.Completed)
|
if (completionProgressDelegate != null && !completionProgressDelegate.Cancelled && !completionProgressDelegate.Completed)
|
||||||
{
|
{
|
||||||
// proceed to result screen if beatmap already finished playing
|
// proceed to result screen if beatmap already finished playing
|
||||||
completionProgressDelegate.RunTask();
|
scheduleGotoRanking();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,6 +584,19 @@ namespace osu.Game.Screens.Play
|
|||||||
storyboardReplacesBackground.Value = false;
|
storyboardReplacesBackground.Value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void scheduleGotoRanking()
|
||||||
|
{
|
||||||
|
completionProgressDelegate?.Cancel();
|
||||||
|
completionProgressDelegate = Schedule(delegate
|
||||||
|
{
|
||||||
|
var score = CreateScore();
|
||||||
|
if (DrawableRuleset.ReplayScore == null)
|
||||||
|
scoreManager.Import(score).Wait();
|
||||||
|
|
||||||
|
this.Push(CreateResults(score));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user