Merge pull request #17991 from frenzibyte/invoke-all-fail-conditions

Fix `HealthProcessor` fail conditions not handling multiple invocations
This commit is contained in:
Dean Herbert 2022-04-27 16:31:36 +09:00 committed by GitHub
commit 26f34e8fb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 7 deletions

View File

@ -9,6 +9,10 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModSuddenDeath : ModSuddenDeath
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray();
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[]
{
typeof(OsuModAutopilot),
typeof(OsuModTarget),
}).ToArray();
}
}

View File

@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Description => @"Practice keeping up with the beat of the song.";
public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles) };
public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSuddenDeath) };
[SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))]
public Bindable<int?> Seed { get; } = new Bindable<int?>

View File

@ -160,6 +160,40 @@ namespace osu.Game.Tests.Gameplay
assertHealthNotEqualTo(1);
}
[Test]
public void TestFailConditions()
{
var beatmap = createBeatmap(0, 1000);
createProcessor(beatmap);
AddStep("setup fail conditions", () => processor.FailConditions += ((_, result) => result.Type == HitResult.Miss));
AddStep("apply perfect hit result", () => processor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new Judgement()) { Type = HitResult.Perfect }));
AddAssert("not failed", () => !processor.HasFailed);
AddStep("apply miss hit result", () => processor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new Judgement()) { Type = HitResult.Miss }));
AddAssert("failed", () => processor.HasFailed);
}
[TestCase(HitResult.Miss)]
[TestCase(HitResult.Meh)]
public void TestMultipleFailConditions(HitResult resultApplied)
{
var beatmap = createBeatmap(0, 1000);
createProcessor(beatmap);
AddStep("setup multiple fail conditions", () =>
{
processor.FailConditions += ((_, result) => result.Type == HitResult.Miss);
processor.FailConditions += ((_, result) => result.Type == HitResult.Meh);
});
AddStep("apply perfect hit result", () => processor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new Judgement()) { Type = HitResult.Perfect }));
AddAssert("not failed", () => !processor.HasFailed);
AddStep($"apply {resultApplied.ToString().ToLower()} hit result", () => processor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new Judgement()) { Type = resultApplied }));
AddAssert("failed", () => processor.HasFailed);
}
[Test]
public void TestBonusObjectsExcludedFromDrain()
{

View File

@ -43,11 +43,11 @@ namespace osu.Game.Rulesets.Scoring
Health.Value += GetHealthIncreaseFor(result);
if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true)
return;
if (Failed?.Invoke() != false)
HasFailed = true;
if (meetsAnyFailCondition(result))
{
if (Failed?.Invoke() != false)
HasFailed = true;
}
}
protected override void RevertResultInternal(JudgementResult result)
@ -69,6 +69,28 @@ namespace osu.Game.Rulesets.Scoring
/// </summary>
protected virtual bool DefaultFailCondition => Precision.AlmostBigger(Health.MinValue, Health.Value);
/// <summary>
/// Whether the current state of <see cref="HealthProcessor"/> or the provided <paramref name="result"/> meets any fail condition.
/// </summary>
/// <param name="result">The judgement result.</param>
private bool meetsAnyFailCondition(JudgementResult result)
{
if (DefaultFailCondition)
return true;
if (FailConditions != null)
{
foreach (var condition in FailConditions.GetInvocationList())
{
bool conditionResult = (bool)condition.Method.Invoke(condition.Target, new object[] { this, result });
if (conditionResult)
return true;
}
}
return false;
}
protected override void Reset(bool storeResults)
{
base.Reset(storeResults);