mirror of
https://github.com/ppy/osu.git
synced 2025-01-13 15:33:21 +08:00
Merge branch 'master' into osu-selection-scaling
This commit is contained in:
commit
94996f2cc0
@ -52,6 +52,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.904.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.904.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.925.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1001.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Mods
|
|||||||
public void TestDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Droplet { StartTime = 1000 }), shouldMiss);
|
public void TestDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Droplet { StartTime = 1000 }), shouldMiss);
|
||||||
|
|
||||||
// We only care about testing misses, hits are tested via JuiceStream
|
// We only care about testing misses, hits are tested via JuiceStream
|
||||||
[TestCase(false)]
|
[TestCase(true)]
|
||||||
public void TestTinyDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new TinyDroplet { StartTime = 1000 }), shouldMiss);
|
public void TestTinyDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new TinyDroplet { StartTime = 1000 }), shouldMiss);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestCatchComboCounter()
|
public void TestCatchComboCounter()
|
||||||
{
|
{
|
||||||
AddRepeatStep("perform hit", () => performJudgement(HitResult.Perfect), 20);
|
AddRepeatStep("perform hit", () => performJudgement(HitResult.Great), 20);
|
||||||
AddStep("perform miss", () => performJudgement(HitResult.Miss));
|
AddStep("perform miss", () => performJudgement(HitResult.Miss));
|
||||||
|
|
||||||
AddStep("randomize judged object colour", () =>
|
AddStep("randomize judged object colour", () =>
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
{
|
{
|
||||||
mods = Score.Mods;
|
mods = Score.Mods;
|
||||||
|
|
||||||
fruitsHit = Score.Statistics.GetOrDefault(HitResult.Perfect);
|
fruitsHit = Score.Statistics.GetOrDefault(HitResult.Great);
|
||||||
ticksHit = Score.Statistics.GetOrDefault(HitResult.LargeTickHit);
|
ticksHit = Score.Statistics.GetOrDefault(HitResult.LargeTickHit);
|
||||||
tinyTicksHit = Score.Statistics.GetOrDefault(HitResult.SmallTickHit);
|
tinyTicksHit = Score.Statistics.GetOrDefault(HitResult.SmallTickHit);
|
||||||
tinyTicksMissed = Score.Statistics.GetOrDefault(HitResult.SmallTickMiss);
|
tinyTicksMissed = Score.Statistics.GetOrDefault(HitResult.SmallTickMiss);
|
||||||
|
@ -8,31 +8,7 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
|||||||
{
|
{
|
||||||
public class CatchBananaJudgement : CatchJudgement
|
public class CatchBananaJudgement : CatchJudgement
|
||||||
{
|
{
|
||||||
public override bool AffectsCombo => false;
|
public override HitResult MaxResult => HitResult.LargeBonus;
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case HitResult.Perfect:
|
|
||||||
return 1100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override double HealthIncreaseFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case HitResult.Perfect:
|
|
||||||
return DEFAULT_MAX_HEALTH_INCREASE * 0.75;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool ShouldExplodeFor(JudgementResult result) => true;
|
public override bool ShouldExplodeFor(JudgementResult result) => true;
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,6 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
|||||||
{
|
{
|
||||||
public class CatchDropletJudgement : CatchJudgement
|
public class CatchDropletJudgement : CatchJudgement
|
||||||
{
|
{
|
||||||
protected override int NumericResultFor(HitResult result)
|
public override HitResult MaxResult => HitResult.LargeTickHit;
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case HitResult.Perfect:
|
|
||||||
return 30;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,19 +9,7 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
|||||||
{
|
{
|
||||||
public class CatchJudgement : Judgement
|
public class CatchJudgement : Judgement
|
||||||
{
|
{
|
||||||
public override HitResult MaxResult => HitResult.Perfect;
|
public override HitResult MaxResult => HitResult.Great;
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case HitResult.Perfect:
|
|
||||||
return 300;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether fruit on the platter should explode or drop.
|
/// Whether fruit on the platter should explode or drop.
|
||||||
|
@ -7,30 +7,6 @@ namespace osu.Game.Rulesets.Catch.Judgements
|
|||||||
{
|
{
|
||||||
public class CatchTinyDropletJudgement : CatchJudgement
|
public class CatchTinyDropletJudgement : CatchJudgement
|
||||||
{
|
{
|
||||||
public override bool AffectsCombo => false;
|
public override HitResult MaxResult => HitResult.SmallTickHit;
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case HitResult.Perfect:
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override double HealthIncreaseFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case HitResult.Perfect:
|
|
||||||
return 0.02;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Rulesets.Catch.UI;
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -86,7 +85,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
|
|||||||
if (CheckPosition == null) return;
|
if (CheckPosition == null) return;
|
||||||
|
|
||||||
if (timeOffset >= 0 && Result != null)
|
if (timeOffset >= 0 && Result != null)
|
||||||
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss);
|
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateStateTransforms(ArmedState state)
|
protected override void UpdateStateTransforms(ArmedState state)
|
||||||
|
@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Catch.Scoring
|
|||||||
{
|
{
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case HitResult.Perfect:
|
case HitResult.Great:
|
||||||
case HitResult.Miss:
|
case HitResult.Miss:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,5 @@ namespace osu.Game.Rulesets.Catch.Scoring
|
|||||||
{
|
{
|
||||||
public class CatchScoreProcessor : ScoreProcessor
|
public class CatchScoreProcessor : ScoreProcessor
|
||||||
{
|
{
|
||||||
public override HitWindows CreateHitWindows() => new CatchHitWindows();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public void OnNewResult(DrawableCatchHitObject judgedObject, JudgementResult result)
|
public void OnNewResult(DrawableCatchHitObject judgedObject, JudgementResult result)
|
||||||
{
|
{
|
||||||
if (!result.Judgement.AffectsCombo || !result.HasResult)
|
if (!result.Type.AffectsCombo() || !result.HasResult)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (result.Type == HitResult.Miss)
|
if (result.Type == HitResult.Miss)
|
||||||
@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public void OnRevertResult(DrawableCatchHitObject judgedObject, JudgementResult result)
|
public void OnRevertResult(DrawableCatchHitObject judgedObject, JudgementResult result)
|
||||||
{
|
{
|
||||||
if (!result.Judgement.AffectsCombo || !result.HasResult)
|
if (!result.Type.AffectsCombo() || !result.HasResult)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
updateCombo(result.ComboAtJudgement, judgedObject.AccentColour.Value);
|
updateCombo(result.ComboAtJudgement, judgedObject.AccentColour.Value);
|
||||||
|
@ -11,6 +11,7 @@ using osu.Game.Rulesets.Catch.Objects.Drawables;
|
|||||||
using osu.Game.Rulesets.Catch.Replays;
|
using osu.Game.Rulesets.Catch.Replays;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
public void OnNewResult(DrawableCatchHitObject fruit, JudgementResult result)
|
public void OnNewResult(DrawableCatchHitObject fruit, JudgementResult result)
|
||||||
{
|
{
|
||||||
if (result.Judgement is IgnoreJudgement)
|
if (!result.Type.IsScorable())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
void runAfterLoaded(Action action)
|
void runAfterLoaded(Action action)
|
||||||
|
@ -45,9 +45,9 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertHeadJudgement(HitResult.Miss);
|
assertHeadJudgement(HitResult.Miss);
|
||||||
assertTickJudgement(HitResult.Miss);
|
assertTickJudgement(HitResult.LargeTickMiss);
|
||||||
assertTailJudgement(HitResult.Miss);
|
assertTailJudgement(HitResult.Miss);
|
||||||
assertNoteJudgement(HitResult.Perfect);
|
assertNoteJudgement(HitResult.IgnoreHit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertHeadJudgement(HitResult.Miss);
|
assertHeadJudgement(HitResult.Miss);
|
||||||
assertTickJudgement(HitResult.Miss);
|
assertTickJudgement(HitResult.LargeTickMiss);
|
||||||
assertTailJudgement(HitResult.Miss);
|
assertTailJudgement(HitResult.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertHeadJudgement(HitResult.Miss);
|
assertHeadJudgement(HitResult.Miss);
|
||||||
assertTickJudgement(HitResult.Miss);
|
assertTickJudgement(HitResult.LargeTickMiss);
|
||||||
assertTailJudgement(HitResult.Miss);
|
assertTailJudgement(HitResult.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertHeadJudgement(HitResult.Perfect);
|
assertHeadJudgement(HitResult.Perfect);
|
||||||
assertTickJudgement(HitResult.Perfect);
|
assertTickJudgement(HitResult.LargeTickHit);
|
||||||
assertTailJudgement(HitResult.Miss);
|
assertTailJudgement(HitResult.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertHeadJudgement(HitResult.Perfect);
|
assertHeadJudgement(HitResult.Perfect);
|
||||||
assertTickJudgement(HitResult.Perfect);
|
assertTickJudgement(HitResult.LargeTickHit);
|
||||||
assertTailJudgement(HitResult.Perfect);
|
assertTailJudgement(HitResult.Perfect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertHeadJudgement(HitResult.Perfect);
|
assertHeadJudgement(HitResult.Perfect);
|
||||||
assertTickJudgement(HitResult.Miss);
|
assertTickJudgement(HitResult.LargeTickMiss);
|
||||||
assertTailJudgement(HitResult.Miss);
|
assertTailJudgement(HitResult.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertHeadJudgement(HitResult.Perfect);
|
assertHeadJudgement(HitResult.Perfect);
|
||||||
assertTickJudgement(HitResult.Perfect);
|
assertTickJudgement(HitResult.LargeTickHit);
|
||||||
assertTailJudgement(HitResult.Miss);
|
assertTailJudgement(HitResult.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertHeadJudgement(HitResult.Perfect);
|
assertHeadJudgement(HitResult.Perfect);
|
||||||
assertTickJudgement(HitResult.Perfect);
|
assertTickJudgement(HitResult.LargeTickHit);
|
||||||
assertTailJudgement(HitResult.Meh);
|
assertTailJudgement(HitResult.Meh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertHeadJudgement(HitResult.Miss);
|
assertHeadJudgement(HitResult.Miss);
|
||||||
assertTickJudgement(HitResult.Perfect);
|
assertTickJudgement(HitResult.LargeTickHit);
|
||||||
assertTailJudgement(HitResult.Miss);
|
assertTailJudgement(HitResult.Miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +217,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertHeadJudgement(HitResult.Miss);
|
assertHeadJudgement(HitResult.Miss);
|
||||||
assertTickJudgement(HitResult.Perfect);
|
assertTickJudgement(HitResult.LargeTickHit);
|
||||||
assertTailJudgement(HitResult.Meh);
|
assertTailJudgement(HitResult.Meh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +235,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
assertHeadJudgement(HitResult.Miss);
|
assertHeadJudgement(HitResult.Miss);
|
||||||
assertTickJudgement(HitResult.Miss);
|
assertTickJudgement(HitResult.LargeTickMiss);
|
||||||
assertTailJudgement(HitResult.Meh);
|
assertTailJudgement(HitResult.Meh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,10 +280,10 @@ namespace osu.Game.Rulesets.Mania.Tests
|
|||||||
}, beatmap);
|
}, beatmap);
|
||||||
|
|
||||||
AddAssert("first hold note missed", () => judgementResults.Where(j => beatmap.HitObjects[0].NestedHitObjects.Contains(j.HitObject))
|
AddAssert("first hold note missed", () => judgementResults.Where(j => beatmap.HitObjects[0].NestedHitObjects.Contains(j.HitObject))
|
||||||
.All(j => j.Type == HitResult.Miss));
|
.All(j => !j.Type.IsHit()));
|
||||||
|
|
||||||
AddAssert("second hold note missed", () => judgementResults.Where(j => beatmap.HitObjects[1].NestedHitObjects.Contains(j.HitObject))
|
AddAssert("second hold note missed", () => judgementResults.Where(j => beatmap.HitObjects[1].NestedHitObjects.Contains(j.HitObject))
|
||||||
.All(j => j.Type == HitResult.Perfect));
|
.All(j => j.Type.IsHit()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertHeadJudgement(HitResult result)
|
private void assertHeadJudgement(HitResult result)
|
||||||
|
@ -7,18 +7,6 @@ namespace osu.Game.Rulesets.Mania.Judgements
|
|||||||
{
|
{
|
||||||
public class HoldNoteTickJudgement : ManiaJudgement
|
public class HoldNoteTickJudgement : ManiaJudgement
|
||||||
{
|
{
|
||||||
protected override int NumericResultFor(HitResult result) => result == MaxResult ? 20 : 0;
|
public override HitResult MaxResult => HitResult.LargeTickHit;
|
||||||
|
|
||||||
protected override double HealthIncreaseFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case HitResult.Perfect:
|
|
||||||
return 0.01;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,34 +2,10 @@
|
|||||||
// 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.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Judgements
|
namespace osu.Game.Rulesets.Mania.Judgements
|
||||||
{
|
{
|
||||||
public class ManiaJudgement : Judgement
|
public class ManiaJudgement : Judgement
|
||||||
{
|
{
|
||||||
protected override int NumericResultFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case HitResult.Meh:
|
|
||||||
return 50;
|
|
||||||
|
|
||||||
case HitResult.Ok:
|
|
||||||
return 100;
|
|
||||||
|
|
||||||
case HitResult.Good:
|
|
||||||
return 200;
|
|
||||||
|
|
||||||
case HitResult.Great:
|
|
||||||
return 300;
|
|
||||||
|
|
||||||
case HitResult.Perfect:
|
|
||||||
return 350;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,7 +239,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
{
|
{
|
||||||
if (Tail.AllJudged)
|
if (Tail.AllJudged)
|
||||||
{
|
{
|
||||||
ApplyResult(r => r.Type = HitResult.Perfect);
|
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
||||||
endHold();
|
endHold();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -17,6 +16,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DrawableHoldNoteTick : DrawableManiaHitObject<HoldNoteTick>
|
public class DrawableHoldNoteTick : DrawableManiaHitObject<HoldNoteTick>
|
||||||
{
|
{
|
||||||
|
public override bool DisplayResult => false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// References the time at which the user started holding the hold note.
|
/// References the time at which the user started holding the hold note.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -73,9 +74,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
|||||||
var startTime = HoldStartTime?.Invoke();
|
var startTime = HoldStartTime?.Invoke();
|
||||||
|
|
||||||
if (startTime == null || startTime > HitObject.StartTime)
|
if (startTime == null || startTime > HitObject.StartTime)
|
||||||
ApplyResult(r => r.Type = HitResult.Miss);
|
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
||||||
else
|
else
|
||||||
ApplyResult(r => r.Type = HitResult.Perfect);
|
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,5 @@ namespace osu.Game.Rulesets.Mania.Scoring
|
|||||||
protected override double DefaultAccuracyPortion => 0.95;
|
protected override double DefaultAccuracyPortion => 0.95;
|
||||||
|
|
||||||
protected override double DefaultComboPortion => 0.05;
|
protected override double DefaultComboPortion => 0.05;
|
||||||
|
|
||||||
public override HitWindows CreateHitWindows() => new ManiaHitWindows();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,9 @@ namespace osu.Game.Rulesets.Mania.Skinning
|
|||||||
|
|
||||||
private Drawable getResult(HitResult result)
|
private Drawable getResult(HitResult result)
|
||||||
{
|
{
|
||||||
|
if (!hitresult_mapping.ContainsKey(result))
|
||||||
|
return null;
|
||||||
|
|
||||||
string filename = this.GetManiaSkinConfig<string>(hitresult_mapping[result])?.Value
|
string filename = this.GetManiaSkinConfig<string>(hitresult_mapping[result])?.Value
|
||||||
?? default_hitresult_skin_filenames[result];
|
?? default_hitresult_skin_filenames[result];
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
if (result.IsHit)
|
if (result.IsHit)
|
||||||
hitPolicy.HandleHit(judgedObject);
|
hitPolicy.HandleHit(judgedObject);
|
||||||
|
|
||||||
if (!result.IsHit || !judgedObject.DisplayResult || !DisplayJudgements.Value)
|
if (!result.IsHit || !DisplayJudgements.Value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
HitObjectArea.Explosions.Add(hitExplosionPool.Get(e => e.Apply(result)));
|
HitObjectArea.Explosions.Add(hitExplosionPool.Get(e => e.Apply(result)));
|
||||||
|
@ -209,9 +209,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Great);
|
addJudgementAssert(hitObjects[0], HitResult.Great);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Great);
|
addJudgementAssert(hitObjects[1], HitResult.IgnoreHit);
|
||||||
addJudgementAssert("slider head", () => ((Slider)hitObjects[1]).HeadCircle, HitResult.Miss);
|
addJudgementAssert("slider head", () => ((Slider)hitObjects[1]).HeadCircle, HitResult.Miss);
|
||||||
addJudgementAssert("slider tick", () => ((Slider)hitObjects[1]).NestedHitObjects[1] as SliderTick, HitResult.Great);
|
addJudgementAssert("slider tick", () => ((Slider)hitObjects[1]).NestedHitObjects[1] as SliderTick, HitResult.LargeTickHit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -252,9 +252,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Great);
|
addJudgementAssert(hitObjects[0], HitResult.Great);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Great);
|
addJudgementAssert(hitObjects[1], HitResult.IgnoreHit);
|
||||||
addJudgementAssert("slider head", () => ((Slider)hitObjects[1]).HeadCircle, HitResult.Great);
|
addJudgementAssert("slider head", () => ((Slider)hitObjects[1]).HeadCircle, HitResult.Great);
|
||||||
addJudgementAssert("slider tick", () => ((Slider)hitObjects[1]).NestedHitObjects[1] as SliderTick, HitResult.Great);
|
addJudgementAssert("slider tick", () => ((Slider)hitObjects[1]).NestedHitObjects[1] as SliderTick, HitResult.LargeTickHit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -331,7 +331,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
});
|
});
|
||||||
|
|
||||||
addJudgementAssert(hitObjects[0], HitResult.Great);
|
addJudgementAssert(hitObjects[0], HitResult.Great);
|
||||||
addJudgementAssert(hitObjects[1], HitResult.Great);
|
addJudgementAssert(hitObjects[1], HitResult.IgnoreHit);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addJudgementAssert(OsuHitObject hitObject, HitResult result)
|
private void addJudgementAssert(OsuHitObject hitObject, HitResult result)
|
||||||
|
@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.RightButton }, Time = time_during_slide_2 },
|
new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.RightButton }, Time = time_during_slide_2 },
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Tracking retained", assertGreatJudge);
|
AddAssert("Tracking retained", assertMaxJudge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.RightButton }, Time = time_during_slide_1 },
|
new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.RightButton }, Time = time_during_slide_1 },
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Tracking retained", assertGreatJudge);
|
AddAssert("Tracking retained", assertMaxJudge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -115,7 +115,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.RightButton }, Time = time_during_slide_1 },
|
new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.RightButton }, Time = time_during_slide_1 },
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Tracking retained", assertGreatJudge);
|
AddAssert("Tracking retained", assertMaxJudge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -288,7 +288,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new OsuReplayFrame { Position = new Vector2(slider_path_length, OsuHitObject.OBJECT_RADIUS * 1.199f), Actions = { OsuAction.LeftButton }, Time = time_slider_end },
|
new OsuReplayFrame { Position = new Vector2(slider_path_length, OsuHitObject.OBJECT_RADIUS * 1.199f), Actions = { OsuAction.LeftButton }, Time = time_slider_end },
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Tracking kept", assertGreatJudge);
|
AddAssert("Tracking kept", assertMaxJudge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -312,13 +312,13 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
AddAssert("Tracking dropped", assertMidSliderJudgementFail);
|
AddAssert("Tracking dropped", assertMidSliderJudgementFail);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool assertGreatJudge() => judgementResults.Any() && judgementResults.All(t => t.Type == HitResult.Great);
|
private bool assertMaxJudge() => judgementResults.Any() && judgementResults.All(t => t.Type == t.Judgement.MaxResult);
|
||||||
|
|
||||||
private bool assertHeadMissTailTracked() => judgementResults[^2].Type == HitResult.Great && judgementResults.First().Type == HitResult.Miss;
|
private bool assertHeadMissTailTracked() => judgementResults[^2].Type == HitResult.IgnoreHit && judgementResults.First().Type == HitResult.Miss;
|
||||||
|
|
||||||
private bool assertMidSliderJudgements() => judgementResults[^2].Type == HitResult.Great;
|
private bool assertMidSliderJudgements() => judgementResults[^2].Type == HitResult.IgnoreHit;
|
||||||
|
|
||||||
private bool assertMidSliderJudgementFail() => judgementResults[^2].Type == HitResult.Miss;
|
private bool assertMidSliderJudgementFail() => judgementResults[^2].Type == HitResult.IgnoreMiss;
|
||||||
|
|
||||||
private ScoreAccessibleReplayPlayer currentPlayer;
|
private ScoreAccessibleReplayPlayer currentPlayer;
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ using System.Linq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
@ -146,7 +145,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
{
|
{
|
||||||
// multipled by 2 to nullify the score multiplier. (autoplay mod selected)
|
// multipled by 2 to nullify the score multiplier. (autoplay mod selected)
|
||||||
var totalScore = ((ScoreExposedPlayer)Player).ScoreProcessor.TotalScore.Value * 2;
|
var totalScore = ((ScoreExposedPlayer)Player).ScoreProcessor.TotalScore.Value * 2;
|
||||||
return totalScore == (int)(drawableSpinner.RotationTracker.RateAdjustedRotation / 360) * SpinnerTick.SCORE_PER_TICK;
|
return totalScore == (int)(drawableSpinner.RotationTracker.RateAdjustedRotation / 360) * new SpinnerTick().CreateJudgement().MaxNumericResult;
|
||||||
});
|
});
|
||||||
|
|
||||||
addSeekStep(0);
|
addSeekStep(0);
|
||||||
@ -194,13 +193,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
addSeekStep(0);
|
addSeekStep(0);
|
||||||
|
|
||||||
AddStep("adjust track rate", () => MusicController.CurrentTrack.AddAdjustment(AdjustableProperty.Tempo, new BindableDouble(rate)));
|
AddStep("adjust track rate", () => Player.GameplayClockContainer.UserPlaybackRate.Value = rate);
|
||||||
// autoplay replay frames use track time;
|
|
||||||
// if a spin takes 1000ms in track time and we're playing with a 2x rate adjustment, the spin will take 500ms of *real* time.
|
|
||||||
// therefore we need to apply the rate adjustment to the replay itself to change from track time to real time,
|
|
||||||
// as real time is what we care about for spinners
|
|
||||||
// (so we're making the spin take 1000ms in real time *always*, regardless of the track clock's rate).
|
|
||||||
transformReplay(replay => applyRateAdjustment(replay, rate));
|
|
||||||
|
|
||||||
addSeekStep(1000);
|
addSeekStep(1000);
|
||||||
AddAssert("progress almost same", () => Precision.AlmostEquals(expectedProgress, drawableSpinner.Progress, 0.05));
|
AddAssert("progress almost same", () => Precision.AlmostEquals(expectedProgress, drawableSpinner.Progress, 0.05));
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
private double accuracy;
|
private double accuracy;
|
||||||
private int scoreMaxCombo;
|
private int scoreMaxCombo;
|
||||||
private int countGreat;
|
private int countGreat;
|
||||||
private int countGood;
|
private int countOk;
|
||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
accuracy = Score.Accuracy;
|
accuracy = Score.Accuracy;
|
||||||
scoreMaxCombo = Score.MaxCombo;
|
scoreMaxCombo = Score.MaxCombo;
|
||||||
countGreat = Score.Statistics.GetOrDefault(HitResult.Great);
|
countGreat = Score.Statistics.GetOrDefault(HitResult.Great);
|
||||||
countGood = Score.Statistics.GetOrDefault(HitResult.Good);
|
countOk = Score.Statistics.GetOrDefault(HitResult.Ok);
|
||||||
countMeh = Score.Statistics.GetOrDefault(HitResult.Meh);
|
countMeh = Score.Statistics.GetOrDefault(HitResult.Meh);
|
||||||
countMiss = Score.Statistics.GetOrDefault(HitResult.Miss);
|
countMiss = Score.Statistics.GetOrDefault(HitResult.Miss);
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
int amountHitObjectsWithAccuracy = countHitCircles;
|
int amountHitObjectsWithAccuracy = countHitCircles;
|
||||||
|
|
||||||
if (amountHitObjectsWithAccuracy > 0)
|
if (amountHitObjectsWithAccuracy > 0)
|
||||||
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countGood * 2 + countMeh) / (double)(amountHitObjectsWithAccuracy * 6);
|
betterAccuracyPercentage = ((countGreat - (totalHits - amountHitObjectsWithAccuracy)) * 6 + countOk * 2 + countMeh) / (double)(amountHitObjectsWithAccuracy * 6);
|
||||||
else
|
else
|
||||||
betterAccuracyPercentage = 0;
|
betterAccuracyPercentage = 0;
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
return accuracyValue;
|
return accuracyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int totalHits => countGreat + countGood + countMeh + countMiss;
|
private int totalHits => countGreat + countOk + countMeh + countMiss;
|
||||||
private int totalSuccessfulHits => countGreat + countGood + countMeh;
|
private int totalSuccessfulHits => countGreat + countOk + countMeh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,6 @@ namespace osu.Game.Rulesets.Osu.Judgements
|
|||||||
{
|
{
|
||||||
public class OsuIgnoreJudgement : OsuJudgement
|
public class OsuIgnoreJudgement : OsuJudgement
|
||||||
{
|
{
|
||||||
public override bool AffectsCombo => false;
|
public override HitResult MaxResult => HitResult.IgnoreHit;
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result) => 0;
|
|
||||||
|
|
||||||
protected override double HealthIncreaseFor(HitResult result) => 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,23 +9,5 @@ namespace osu.Game.Rulesets.Osu.Judgements
|
|||||||
public class OsuJudgement : Judgement
|
public class OsuJudgement : Judgement
|
||||||
{
|
{
|
||||||
public override HitResult MaxResult => HitResult.Great;
|
public override HitResult MaxResult => HitResult.Great;
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case HitResult.Meh:
|
|
||||||
return 50;
|
|
||||||
|
|
||||||
case HitResult.Good:
|
|
||||||
return 100;
|
|
||||||
|
|
||||||
case HitResult.Great:
|
|
||||||
return 300;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
Tracking.BindValueChanged(updateSlidingSample);
|
Tracking.BindValueChanged(updateSlidingSample);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SkinnableSound slidingSample;
|
private PausableSkinnableSound slidingSample;
|
||||||
|
|
||||||
protected override void LoadSamples()
|
protected override void LoadSamples()
|
||||||
{
|
{
|
||||||
@ -103,19 +103,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
var clone = HitObject.SampleControlPoint.ApplyTo(firstSample);
|
var clone = HitObject.SampleControlPoint.ApplyTo(firstSample);
|
||||||
clone.Name = "sliderslide";
|
clone.Name = "sliderslide";
|
||||||
|
|
||||||
AddInternal(slidingSample = new SkinnableSound(clone)
|
AddInternal(slidingSample = new PausableSkinnableSound(clone)
|
||||||
{
|
{
|
||||||
Looping = true
|
Looping = true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void StopAllSamples()
|
||||||
|
{
|
||||||
|
base.StopAllSamples();
|
||||||
|
slidingSample?.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
private void updateSlidingSample(ValueChangedEvent<bool> tracking)
|
private void updateSlidingSample(ValueChangedEvent<bool> tracking)
|
||||||
{
|
{
|
||||||
// note that samples will not start playing if exiting a seek operation in the middle of a slider.
|
if (tracking.NewValue)
|
||||||
// may be something we want to address at a later point, but not so easy to make happen right now
|
|
||||||
// (SkinnableSound would need to expose whether the sample is already playing and this logic would need to run in Update).
|
|
||||||
if (tracking.NewValue && ShouldPlaySamples)
|
|
||||||
slidingSample?.Play();
|
slidingSample?.Play();
|
||||||
else
|
else
|
||||||
slidingSample?.Stop();
|
slidingSample?.Stop();
|
||||||
|
@ -9,7 +9,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
@ -50,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (sliderRepeat.StartTime <= Time.Current)
|
if (sliderRepeat.StartTime <= Time.Current)
|
||||||
ApplyResult(r => r.Type = drawableSlider.Tracking.Value ? HitResult.Great : HitResult.Miss);
|
ApplyResult(r => r.Type = drawableSlider.Tracking.Value ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateInitialTransforms()
|
protected override void UpdateInitialTransforms()
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
@ -46,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (!userTriggered && timeOffset >= 0)
|
if (!userTriggered && timeOffset >= 0)
|
||||||
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : HitResult.Miss);
|
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePosition() => Position = HitObject.Position - slider.Position;
|
private void updatePosition() => Position = HitObject.Position - slider.Position;
|
||||||
|
@ -10,7 +10,6 @@ using osuTK.Graphics;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
{
|
{
|
||||||
@ -64,7 +63,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
{
|
{
|
||||||
if (timeOffset >= 0)
|
if (timeOffset >= 0)
|
||||||
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : HitResult.Miss);
|
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateInitialTransforms()
|
protected override void UpdateInitialTransforms()
|
||||||
|
@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
isSpinning.BindValueChanged(updateSpinningSample);
|
isSpinning.BindValueChanged(updateSpinningSample);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SkinnableSound spinningSample;
|
private PausableSkinnableSound spinningSample;
|
||||||
private const float spinning_sample_initial_frequency = 1.0f;
|
private const float spinning_sample_initial_frequency = 1.0f;
|
||||||
private const float spinning_sample_modulated_base_frequency = 0.5f;
|
private const float spinning_sample_modulated_base_frequency = 0.5f;
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
var clone = HitObject.SampleControlPoint.ApplyTo(firstSample);
|
var clone = HitObject.SampleControlPoint.ApplyTo(firstSample);
|
||||||
clone.Name = "spinnerspin";
|
clone.Name = "spinnerspin";
|
||||||
|
|
||||||
AddInternal(spinningSample = new SkinnableSound(clone)
|
AddInternal(spinningSample = new PausableSkinnableSound(clone)
|
||||||
{
|
{
|
||||||
Volume = { Value = 0 },
|
Volume = { Value = 0 },
|
||||||
Looping = true,
|
Looping = true,
|
||||||
@ -113,10 +113,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
|
|
||||||
private void updateSpinningSample(ValueChangedEvent<bool> tracking)
|
private void updateSpinningSample(ValueChangedEvent<bool> tracking)
|
||||||
{
|
{
|
||||||
// note that samples will not start playing if exiting a seek operation in the middle of a spinner.
|
if (tracking.NewValue)
|
||||||
// may be something we want to address at a later point, but not so easy to make happen right now
|
|
||||||
// (SkinnableSound would need to expose whether the sample is already playing and this logic would need to run in Update).
|
|
||||||
if (tracking.NewValue && ShouldPlaySamples)
|
|
||||||
{
|
{
|
||||||
spinningSample?.Play();
|
spinningSample?.Play();
|
||||||
spinningSample?.VolumeTo(1, 200);
|
spinningSample?.VolumeTo(1, 200);
|
||||||
@ -127,6 +124,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void StopAllSamples()
|
||||||
|
{
|
||||||
|
base.StopAllSamples();
|
||||||
|
spinningSample?.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
protected override void AddNestedHitObject(DrawableHitObject hitObject)
|
||||||
{
|
{
|
||||||
base.AddNestedHitObject(hitObject);
|
base.AddNestedHitObject(hitObject);
|
||||||
@ -217,7 +220,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
if (Progress >= 1)
|
if (Progress >= 1)
|
||||||
r.Type = HitResult.Great;
|
r.Type = HitResult.Great;
|
||||||
else if (Progress > .9)
|
else if (Progress > .9)
|
||||||
r.Type = HitResult.Good;
|
r.Type = HitResult.Ok;
|
||||||
else if (Progress > .75)
|
else if (Progress > .75)
|
||||||
r.Type = HitResult.Meh;
|
r.Type = HitResult.Meh;
|
||||||
else if (Time.Current >= Spinner.EndTime)
|
else if (Time.Current >= Spinner.EndTime)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// 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 osu.Game.Rulesets.Scoring;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
{
|
{
|
||||||
public class DrawableSpinnerTick : DrawableOsuHitObject
|
public class DrawableSpinnerTick : DrawableOsuHitObject
|
||||||
@ -18,6 +16,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
/// Apply a judgement result.
|
/// Apply a judgement result.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hit">Whether this tick was reached.</param>
|
/// <param name="hit">Whether this tick was reached.</param>
|
||||||
internal void TriggerResult(bool hit) => ApplyResult(r => r.Type = hit ? r.Judgement.MaxResult : HitResult.Miss);
|
internal void TriggerResult(bool hit) => ApplyResult(r => r.Type = hit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SpinnerBonusDisplay : CompositeDrawable
|
public class SpinnerBonusDisplay : CompositeDrawable
|
||||||
{
|
{
|
||||||
|
private static readonly int score_per_tick = new SpinnerBonusTick().CreateJudgement().MaxNumericResult;
|
||||||
|
|
||||||
private readonly OsuSpriteText bonusCounter;
|
private readonly OsuSpriteText bonusCounter;
|
||||||
|
|
||||||
public SpinnerBonusDisplay()
|
public SpinnerBonusDisplay()
|
||||||
@ -36,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
displayedCount = count;
|
displayedCount = count;
|
||||||
bonusCounter.Text = $"{SpinnerBonusTick.SCORE_PER_TICK * count}";
|
bonusCounter.Text = $"{score_per_tick * count}";
|
||||||
bonusCounter.FadeOutFromOne(1500);
|
bonusCounter.FadeOutFromOne(1500);
|
||||||
bonusCounter.ScaleTo(1.5f).Then().ScaleTo(1f, 1000, Easing.OutQuint);
|
bonusCounter.ScaleTo(1.5f).Then().ScaleTo(1f, 1000, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
// 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;
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
||||||
@ -77,6 +79,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
|
|
||||||
private bool rotationTransferred;
|
private bool rotationTransferred;
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
private GameplayClock gameplayClock { get; set; }
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
@ -126,7 +131,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
currentRotation += angle;
|
currentRotation += angle;
|
||||||
// rate has to be applied each frame, because it's not guaranteed to be constant throughout playback
|
// rate has to be applied each frame, because it's not guaranteed to be constant throughout playback
|
||||||
// (see: ModTimeRamp)
|
// (see: ModTimeRamp)
|
||||||
RateAdjustedRotation += (float)(Math.Abs(angle) * Clock.Rate);
|
RateAdjustedRotation += (float)(Math.Abs(angle) * (gameplayClock?.TrueGameplayRate ?? Clock.Rate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
|
|
||||||
public class SliderRepeatJudgement : OsuJudgement
|
public class SliderRepeatJudgement : OsuJudgement
|
||||||
{
|
{
|
||||||
protected override int NumericResultFor(HitResult result) => result == MaxResult ? 30 : 0;
|
public override HitResult MaxResult => HitResult.LargeTickHit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,9 +29,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
|
|
||||||
public class SliderTailJudgement : OsuJudgement
|
public class SliderTailJudgement : OsuJudgement
|
||||||
{
|
{
|
||||||
protected override int NumericResultFor(HitResult result) => 0;
|
public override HitResult MaxResult => HitResult.IgnoreHit;
|
||||||
|
|
||||||
public override bool AffectsCombo => false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
|
|
||||||
public class SliderTickJudgement : OsuJudgement
|
public class SliderTickJudgement : OsuJudgement
|
||||||
{
|
{
|
||||||
protected override int NumericResultFor(HitResult result) => result == MaxResult ? 10 : 0;
|
public override HitResult MaxResult => HitResult.LargeTickHit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
{
|
{
|
||||||
public class SpinnerBonusTick : SpinnerTick
|
public class SpinnerBonusTick : SpinnerTick
|
||||||
{
|
{
|
||||||
public new const int SCORE_PER_TICK = 50;
|
|
||||||
|
|
||||||
public SpinnerBonusTick()
|
public SpinnerBonusTick()
|
||||||
{
|
{
|
||||||
Samples.Add(new HitSampleInfo { Name = "spinnerbonus" });
|
Samples.Add(new HitSampleInfo { Name = "spinnerbonus" });
|
||||||
@ -20,9 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
|
|
||||||
public class OsuSpinnerBonusTickJudgement : OsuSpinnerTickJudgement
|
public class OsuSpinnerBonusTickJudgement : OsuSpinnerTickJudgement
|
||||||
{
|
{
|
||||||
protected override int NumericResultFor(HitResult result) => result == MaxResult ? SCORE_PER_TICK : 0;
|
public override HitResult MaxResult => HitResult.LargeBonus;
|
||||||
|
|
||||||
protected override double HealthIncreaseFor(HitResult result) => base.HealthIncreaseFor(result) * 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,19 +9,13 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
{
|
{
|
||||||
public class SpinnerTick : OsuHitObject
|
public class SpinnerTick : OsuHitObject
|
||||||
{
|
{
|
||||||
public const int SCORE_PER_TICK = 10;
|
|
||||||
|
|
||||||
public override Judgement CreateJudgement() => new OsuSpinnerTickJudgement();
|
public override Judgement CreateJudgement() => new OsuSpinnerTickJudgement();
|
||||||
|
|
||||||
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
|
||||||
|
|
||||||
public class OsuSpinnerTickJudgement : OsuJudgement
|
public class OsuSpinnerTickJudgement : OsuJudgement
|
||||||
{
|
{
|
||||||
public override bool AffectsCombo => false;
|
public override HitResult MaxResult => HitResult.SmallBonus;
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result) => result == MaxResult ? SCORE_PER_TICK : 0;
|
|
||||||
|
|
||||||
protected override double HealthIncreaseFor(HitResult result) => result == MaxResult ? 0.6 * base.HealthIncreaseFor(result) : 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,13 +137,13 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
if (!(h is Spinner))
|
if (!(h is Spinner))
|
||||||
AddFrameToReplay(new OsuReplayFrame(h.StartTime - hitWindows.WindowFor(HitResult.Meh), new Vector2(h.StackedPosition.X, h.StackedPosition.Y)));
|
AddFrameToReplay(new OsuReplayFrame(h.StartTime - hitWindows.WindowFor(HitResult.Meh), new Vector2(h.StackedPosition.X, h.StackedPosition.Y)));
|
||||||
}
|
}
|
||||||
else if (h.StartTime - hitWindows.WindowFor(HitResult.Good) > endTime + hitWindows.WindowFor(HitResult.Good) + 50)
|
else if (h.StartTime - hitWindows.WindowFor(HitResult.Ok) > endTime + hitWindows.WindowFor(HitResult.Ok) + 50)
|
||||||
{
|
{
|
||||||
if (!(prev is Spinner) && h.StartTime - endTime < 1000)
|
if (!(prev is Spinner) && h.StartTime - endTime < 1000)
|
||||||
AddFrameToReplay(new OsuReplayFrame(endTime + hitWindows.WindowFor(HitResult.Good), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y)));
|
AddFrameToReplay(new OsuReplayFrame(endTime + hitWindows.WindowFor(HitResult.Ok), new Vector2(prev.StackedEndPosition.X, prev.StackedEndPosition.Y)));
|
||||||
|
|
||||||
if (!(h is Spinner))
|
if (!(h is Spinner))
|
||||||
AddFrameToReplay(new OsuReplayFrame(h.StartTime - hitWindows.WindowFor(HitResult.Good), new Vector2(h.StackedPosition.X, h.StackedPosition.Y)));
|
AddFrameToReplay(new OsuReplayFrame(h.StartTime - hitWindows.WindowFor(HitResult.Ok), new Vector2(h.StackedPosition.X, h.StackedPosition.Y)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
private static readonly DifficultyRange[] osu_ranges =
|
private static readonly DifficultyRange[] osu_ranges =
|
||||||
{
|
{
|
||||||
new DifficultyRange(HitResult.Great, 80, 50, 20),
|
new DifficultyRange(HitResult.Great, 80, 50, 20),
|
||||||
new DifficultyRange(HitResult.Good, 140, 100, 60),
|
new DifficultyRange(HitResult.Ok, 140, 100, 60),
|
||||||
new DifficultyRange(HitResult.Meh, 200, 150, 100),
|
new DifficultyRange(HitResult.Meh, 200, 150, 100),
|
||||||
new DifficultyRange(HitResult.Miss, 400, 400, 400),
|
new DifficultyRange(HitResult.Miss, 400, 400, 400),
|
||||||
};
|
};
|
||||||
@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case HitResult.Great:
|
case HitResult.Great:
|
||||||
case HitResult.Good:
|
case HitResult.Ok:
|
||||||
case HitResult.Meh:
|
case HitResult.Meh:
|
||||||
case HitResult.Miss:
|
case HitResult.Miss:
|
||||||
return true;
|
return true;
|
||||||
|
@ -25,7 +25,5 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
return new OsuJudgementResult(hitObject, judgement);
|
return new OsuJudgementResult(hitObject, judgement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override HitWindows CreateHitWindows() => new OsuHitWindows();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
|||||||
createDrawableRuleset();
|
createDrawableRuleset();
|
||||||
|
|
||||||
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle);
|
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle);
|
||||||
assertStateAfterResult(new JudgementResult(new StrongHitObject(), new TaikoStrongJudgement()) { Type = HitResult.Miss }, TaikoMascotAnimationState.Idle);
|
assertStateAfterResult(new JudgementResult(new StrongHitObject(), new TaikoStrongJudgement()) { Type = HitResult.IgnoreMiss }, TaikoMascotAnimationState.Idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -102,8 +102,8 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
|||||||
|
|
||||||
createDrawableRuleset();
|
createDrawableRuleset();
|
||||||
|
|
||||||
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Good }, TaikoMascotAnimationState.Kiai);
|
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Ok }, TaikoMascotAnimationState.Kiai);
|
||||||
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoStrongJudgement()) { Type = HitResult.Miss }, TaikoMascotAnimationState.Kiai);
|
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoStrongJudgement()) { Type = HitResult.IgnoreMiss }, TaikoMascotAnimationState.Kiai);
|
||||||
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss }, TaikoMascotAnimationState.Fail);
|
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss }, TaikoMascotAnimationState.Fail);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
|||||||
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle);
|
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle);
|
||||||
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss }, TaikoMascotAnimationState.Fail);
|
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss }, TaikoMascotAnimationState.Fail);
|
||||||
assertStateAfterResult(new JudgementResult(new DrumRoll(), new TaikoDrumRollJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle);
|
assertStateAfterResult(new JudgementResult(new DrumRoll(), new TaikoDrumRollJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle);
|
||||||
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Good }, TaikoMascotAnimationState.Idle);
|
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Ok }, TaikoMascotAnimationState.Idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
@ -130,7 +130,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
|||||||
|
|
||||||
AddRepeatStep("reach 49 combo", () => applyNewResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }), 49);
|
AddRepeatStep("reach 49 combo", () => applyNewResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }), 49);
|
||||||
|
|
||||||
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Good }, TaikoMascotAnimationState.Clear);
|
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Ok }, TaikoMascotAnimationState.Clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(true, TaikoMascotAnimationState.Kiai)]
|
[TestCase(true, TaikoMascotAnimationState.Kiai)]
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
|||||||
public void TestNormalHit()
|
public void TestNormalHit()
|
||||||
{
|
{
|
||||||
AddStep("Great", () => SetContents(() => getContentFor(createHit(HitResult.Great))));
|
AddStep("Great", () => SetContents(() => getContentFor(createHit(HitResult.Great))));
|
||||||
AddStep("Good", () => SetContents(() => getContentFor(createHit(HitResult.Good))));
|
AddStep("Ok", () => SetContents(() => getContentFor(createHit(HitResult.Ok))));
|
||||||
AddStep("Miss", () => SetContents(() => getContentFor(createHit(HitResult.Miss))));
|
AddStep("Miss", () => SetContents(() => getContentFor(createHit(HitResult.Miss))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
|||||||
public void TestStrongHit([Values(false, true)] bool hitBoth)
|
public void TestStrongHit([Values(false, true)] bool hitBoth)
|
||||||
{
|
{
|
||||||
AddStep("Great", () => SetContents(() => getContentFor(createStrongHit(HitResult.Great, hitBoth))));
|
AddStep("Great", () => SetContents(() => getContentFor(createStrongHit(HitResult.Great, hitBoth))));
|
||||||
AddStep("Good", () => SetContents(() => getContentFor(createStrongHit(HitResult.Good, hitBoth))));
|
AddStep("Good", () => SetContents(() => getContentFor(createStrongHit(HitResult.Ok, hitBoth))));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable getContentFor(DrawableTestHit hit)
|
private Drawable getContentFor(DrawableTestHit hit)
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
AddToggleStep("Toggle passing", passing => this.ChildrenOfType<LegacyTaikoScroller>().ForEach(s => s.LastResult.Value =
|
AddToggleStep("Toggle passing", passing => this.ChildrenOfType<LegacyTaikoScroller>().ForEach(s => s.LastResult.Value =
|
||||||
new JudgementResult(null, new Judgement()) { Type = passing ? HitResult.Perfect : HitResult.Miss }));
|
new JudgementResult(null, new Judgement()) { Type = passing ? HitResult.Great : HitResult.Miss }));
|
||||||
|
|
||||||
AddToggleStep("toggle playback direction", reversed => this.reversed = reversed);
|
AddToggleStep("toggle playback direction", reversed => this.reversed = reversed);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
|
|
||||||
DrawableDrumRollTick h;
|
DrawableDrumRollTick h;
|
||||||
DrawableRuleset.Playfield.Add(h = new DrawableDrumRollTick(tick) { JudgementType = hitType });
|
DrawableRuleset.Playfield.Add(h = new DrawableDrumRollTick(tick) { JudgementType = hitType });
|
||||||
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(tick, new TaikoDrumRollTickJudgement()) { Type = HitResult.Perfect });
|
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(tick, new TaikoDrumRollTickJudgement()) { Type = HitResult.Great });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
|
|
||||||
private void addHitJudgement(bool kiai)
|
private void addHitJudgement(bool kiai)
|
||||||
{
|
{
|
||||||
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Good : HitResult.Great;
|
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Ok : HitResult.Great;
|
||||||
|
|
||||||
var cpi = new ControlPointInfo();
|
var cpi = new ControlPointInfo();
|
||||||
cpi.Add(0, new EffectControlPoint { KiaiMode = kiai });
|
cpi.Add(0, new EffectControlPoint { KiaiMode = kiai });
|
||||||
@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
Hit hit = new Hit();
|
Hit hit = new Hit();
|
||||||
hit.ApplyDefaults(cpi, new BeatmapDifficulty());
|
hit.ApplyDefaults(cpi, new BeatmapDifficulty());
|
||||||
|
|
||||||
var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) };
|
var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Ok ? -0.1f : -0.05f, hitResult == HitResult.Ok ? 0.1f : 0.05f) };
|
||||||
|
|
||||||
DrawableRuleset.Playfield.Add(h);
|
DrawableRuleset.Playfield.Add(h);
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
|
|
||||||
private void addStrongHitJudgement(bool kiai)
|
private void addStrongHitJudgement(bool kiai)
|
||||||
{
|
{
|
||||||
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Good : HitResult.Great;
|
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Ok : HitResult.Great;
|
||||||
|
|
||||||
var cpi = new ControlPointInfo();
|
var cpi = new ControlPointInfo();
|
||||||
cpi.Add(0, new EffectControlPoint { KiaiMode = kiai });
|
cpi.Add(0, new EffectControlPoint { KiaiMode = kiai });
|
||||||
@ -130,7 +130,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
|||||||
Hit hit = new Hit();
|
Hit hit = new Hit();
|
||||||
hit.ApplyDefaults(cpi, new BeatmapDifficulty());
|
hit.ApplyDefaults(cpi, new BeatmapDifficulty());
|
||||||
|
|
||||||
var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) };
|
var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Ok ? -0.1f : -0.05f, hitResult == HitResult.Ok ? 0.1f : 0.05f) };
|
||||||
|
|
||||||
DrawableRuleset.Playfield.Add(h);
|
DrawableRuleset.Playfield.Add(h);
|
||||||
|
|
||||||
|
@ -42,9 +42,9 @@ namespace osu.Game.Rulesets.Taiko.Audio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SkinnableSound addSound(HitSampleInfo hitSampleInfo, double lifetimeStart, double lifetimeEnd)
|
private PausableSkinnableSound addSound(HitSampleInfo hitSampleInfo, double lifetimeStart, double lifetimeEnd)
|
||||||
{
|
{
|
||||||
var drawable = new SkinnableSound(hitSampleInfo)
|
var drawable = new PausableSkinnableSound(hitSampleInfo)
|
||||||
{
|
{
|
||||||
LifetimeStart = lifetimeStart,
|
LifetimeStart = lifetimeStart,
|
||||||
LifetimeEnd = lifetimeEnd
|
LifetimeEnd = lifetimeEnd
|
||||||
@ -57,8 +57,8 @@ namespace osu.Game.Rulesets.Taiko.Audio
|
|||||||
|
|
||||||
public class DrumSample
|
public class DrumSample
|
||||||
{
|
{
|
||||||
public SkinnableSound Centre;
|
public PausableSkinnableSound Centre;
|
||||||
public SkinnableSound Rim;
|
public PausableSkinnableSound Rim;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
|
|
||||||
private Mod[] mods;
|
private Mod[] mods;
|
||||||
private int countGreat;
|
private int countGreat;
|
||||||
private int countGood;
|
private int countOk;
|
||||||
private int countMeh;
|
private int countMeh;
|
||||||
private int countMiss;
|
private int countMiss;
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
{
|
{
|
||||||
mods = Score.Mods;
|
mods = Score.Mods;
|
||||||
countGreat = Score.Statistics.GetOrDefault(HitResult.Great);
|
countGreat = Score.Statistics.GetOrDefault(HitResult.Great);
|
||||||
countGood = Score.Statistics.GetOrDefault(HitResult.Good);
|
countOk = Score.Statistics.GetOrDefault(HitResult.Ok);
|
||||||
countMeh = Score.Statistics.GetOrDefault(HitResult.Meh);
|
countMeh = Score.Statistics.GetOrDefault(HitResult.Meh);
|
||||||
countMiss = Score.Statistics.GetOrDefault(HitResult.Miss);
|
countMiss = Score.Statistics.GetOrDefault(HitResult.Miss);
|
||||||
|
|
||||||
@ -102,6 +102,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
return accValue * Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
|
return accValue * Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int totalHits => countGreat + countGood + countMeh + countMiss;
|
private int totalHits => countGreat + countOk + countMeh + countMiss;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,19 +7,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements
|
|||||||
{
|
{
|
||||||
public class TaikoDrumRollTickJudgement : TaikoJudgement
|
public class TaikoDrumRollTickJudgement : TaikoJudgement
|
||||||
{
|
{
|
||||||
public override bool AffectsCombo => false;
|
public override HitResult MaxResult => HitResult.SmallTickHit;
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
case HitResult.Great:
|
|
||||||
return 200;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override double HealthIncreaseFor(HitResult result)
|
protected override double HealthIncreaseFor(HitResult result)
|
||||||
{
|
{
|
||||||
|
@ -10,21 +10,6 @@ namespace osu.Game.Rulesets.Taiko.Judgements
|
|||||||
{
|
{
|
||||||
public override HitResult MaxResult => HitResult.Great;
|
public override HitResult MaxResult => HitResult.Great;
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
case HitResult.Good:
|
|
||||||
return 100;
|
|
||||||
|
|
||||||
case HitResult.Great:
|
|
||||||
return 300;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override double HealthIncreaseFor(HitResult result)
|
protected override double HealthIncreaseFor(HitResult result)
|
||||||
{
|
{
|
||||||
switch (result)
|
switch (result)
|
||||||
@ -32,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements
|
|||||||
case HitResult.Miss:
|
case HitResult.Miss:
|
||||||
return -1.0;
|
return -1.0;
|
||||||
|
|
||||||
case HitResult.Good:
|
case HitResult.Ok:
|
||||||
return 1.1;
|
return 1.1;
|
||||||
|
|
||||||
case HitResult.Great:
|
case HitResult.Great:
|
||||||
|
@ -7,9 +7,9 @@ namespace osu.Game.Rulesets.Taiko.Judgements
|
|||||||
{
|
{
|
||||||
public class TaikoStrongJudgement : TaikoJudgement
|
public class TaikoStrongJudgement : TaikoJudgement
|
||||||
{
|
{
|
||||||
|
public override HitResult MaxResult => HitResult.SmallBonus;
|
||||||
|
|
||||||
// MainObject already changes the HP
|
// MainObject already changes the HP
|
||||||
protected override double HealthIncreaseFor(HitResult result) => 0;
|
protected override double HealthIncreaseFor(HitResult result) => 0;
|
||||||
|
|
||||||
public override bool AffectsCombo => false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
if (countHit >= HitObject.RequiredGoodHits)
|
if (countHit >= HitObject.RequiredGoodHits)
|
||||||
{
|
{
|
||||||
ApplyResult(r => r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Good);
|
ApplyResult(r => r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Ok);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ApplyResult(r => r.Type = HitResult.Miss);
|
ApplyResult(r => r.Type = HitResult.Miss);
|
||||||
@ -174,7 +174,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
if (!MainObject.Judged)
|
if (!MainObject.Judged)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ApplyResult(r => r.Type = MainObject.IsHit ? HitResult.Great : HitResult.Miss);
|
ApplyResult(r => r.Type = MainObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action) => false;
|
public override bool OnPressed(TaikoAction action) => false;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -34,14 +33,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (timeOffset > HitObject.HitWindow)
|
if (timeOffset > HitObject.HitWindow)
|
||||||
ApplyResult(r => r.Type = HitResult.Miss);
|
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.Abs(timeOffset) > HitObject.HitWindow)
|
if (Math.Abs(timeOffset) > HitObject.HitWindow)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ApplyResult(r => r.Type = HitResult.Great);
|
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateStateTransforms(ArmedState state)
|
protected override void UpdateStateTransforms(ArmedState state)
|
||||||
@ -74,7 +73,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
if (!MainObject.Judged)
|
if (!MainObject.Judged)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ApplyResult(r => r.Type = MainObject.IsHit ? HitResult.Great : HitResult.Miss);
|
ApplyResult(r => r.Type = MainObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action) => false;
|
public override bool OnPressed(TaikoAction action) => false;
|
||||||
|
@ -257,19 +257,19 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
if (!MainObject.Result.IsHit)
|
if (!MainObject.Result.IsHit)
|
||||||
{
|
{
|
||||||
ApplyResult(r => r.Type = HitResult.Miss);
|
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userTriggered)
|
if (!userTriggered)
|
||||||
{
|
{
|
||||||
if (timeOffset - MainObject.Result.TimeOffset > second_hit_window)
|
if (timeOffset - MainObject.Result.TimeOffset > second_hit_window)
|
||||||
ApplyResult(r => r.Type = HitResult.Miss);
|
ApplyResult(r => r.Type = r.Judgement.MinResult);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.Abs(timeOffset - MainObject.Result.TimeOffset) <= second_hit_window)
|
if (Math.Abs(timeOffset - MainObject.Result.TimeOffset) <= second_hit_window)
|
||||||
ApplyResult(r => r.Type = MainObject.Result.Type);
|
ApplyResult(r => r.Type = r.Judgement.MaxResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnPressed(TaikoAction action)
|
public override bool OnPressed(TaikoAction action)
|
||||||
|
@ -175,7 +175,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTick?.TriggerResult(HitResult.Great);
|
nextTick?.TriggerResult(true);
|
||||||
|
|
||||||
var numHits = ticks.Count(r => r.IsHit);
|
var numHits = ticks.Count(r => r.IsHit);
|
||||||
|
|
||||||
@ -208,10 +208,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
tick.TriggerResult(HitResult.Miss);
|
tick.TriggerResult(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var hitResult = numHits > HitObject.RequiredHits / 2 ? HitResult.Good : HitResult.Miss;
|
var hitResult = numHits > HitObject.RequiredHits / 2 ? HitResult.Ok : HitResult.Miss;
|
||||||
|
|
||||||
ApplyResult(r => r.Type = hitResult);
|
ApplyResult(r => r.Type = hitResult);
|
||||||
}
|
}
|
||||||
|
@ -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.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -19,10 +18,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
|
|||||||
|
|
||||||
protected override void UpdateInitialTransforms() => this.FadeOut();
|
protected override void UpdateInitialTransforms() => this.FadeOut();
|
||||||
|
|
||||||
public void TriggerResult(HitResult type)
|
public void TriggerResult(bool hit)
|
||||||
{
|
{
|
||||||
HitObject.StartTime = Time.Current;
|
HitObject.StartTime = Time.Current;
|
||||||
ApplyResult(r => r.Type = type);
|
ApplyResult(r => r.Type = hit ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
protected override void CheckForResult(bool userTriggered, double timeOffset)
|
||||||
|
@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
|||||||
private static readonly DifficultyRange[] taiko_ranges =
|
private static readonly DifficultyRange[] taiko_ranges =
|
||||||
{
|
{
|
||||||
new DifficultyRange(HitResult.Great, 50, 35, 20),
|
new DifficultyRange(HitResult.Great, 50, 35, 20),
|
||||||
new DifficultyRange(HitResult.Good, 120, 80, 50),
|
new DifficultyRange(HitResult.Ok, 120, 80, 50),
|
||||||
new DifficultyRange(HitResult.Miss, 135, 95, 70),
|
new DifficultyRange(HitResult.Miss, 135, 95, 70),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
|||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case HitResult.Great:
|
case HitResult.Great:
|
||||||
case HitResult.Good:
|
case HitResult.Ok:
|
||||||
case HitResult.Miss:
|
case HitResult.Miss:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,5 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
|||||||
protected override double DefaultAccuracyPortion => 0.75;
|
protected override double DefaultAccuracyPortion => 0.75;
|
||||||
|
|
||||||
protected override double DefaultComboPortion => 0.25;
|
protected override double DefaultComboPortion => 0.25;
|
||||||
|
|
||||||
public override HitWindows CreateHitWindows() => new TaikoHitWindows();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,64 @@
|
|||||||
// 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.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Skinning
|
namespace osu.Game.Rulesets.Taiko.Skinning
|
||||||
{
|
{
|
||||||
public class LegacyHitExplosion : CompositeDrawable
|
public class LegacyHitExplosion : CompositeDrawable
|
||||||
{
|
{
|
||||||
public LegacyHitExplosion(Drawable sprite)
|
private readonly Drawable sprite;
|
||||||
{
|
private readonly Drawable strongSprite;
|
||||||
InternalChild = sprite;
|
|
||||||
|
|
||||||
|
private DrawableStrongNestedHit nestedStrongHit;
|
||||||
|
private bool switchedToStrongSprite;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new legacy hit explosion.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Contrary to stable's, this implementation doesn't require a frame-perfect hit
|
||||||
|
/// for the strong sprite to be displayed.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="sprite">The normal legacy explosion sprite.</param>
|
||||||
|
/// <param name="strongSprite">The strong legacy explosion sprite.</param>
|
||||||
|
public LegacyHitExplosion(Drawable sprite, Drawable strongSprite = null)
|
||||||
|
{
|
||||||
|
this.sprite = sprite;
|
||||||
|
this.strongSprite = strongSprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(DrawableHitObject judgedObject)
|
||||||
|
{
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
AddInternal(sprite.With(s =>
|
||||||
|
{
|
||||||
|
s.Anchor = Anchor.Centre;
|
||||||
|
s.Origin = Anchor.Centre;
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (strongSprite != null)
|
||||||
|
{
|
||||||
|
AddInternal(strongSprite.With(s =>
|
||||||
|
{
|
||||||
|
s.Alpha = 0;
|
||||||
|
s.Anchor = Anchor.Centre;
|
||||||
|
s.Origin = Anchor.Centre;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (judgedObject is DrawableHit hit)
|
||||||
|
nestedStrongHit = hit.NestedHitObjects.SingleOrDefault() as DrawableStrongNestedHit;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -33,5 +76,25 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
|
|
||||||
Expire(true);
|
Expire(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (shouldSwitchToStrongSprite() && !switchedToStrongSprite)
|
||||||
|
{
|
||||||
|
sprite.FadeOut(50, Easing.OutQuint);
|
||||||
|
strongSprite.FadeIn(50, Easing.OutQuint);
|
||||||
|
switchedToStrongSprite = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool shouldSwitchToStrongSprite()
|
||||||
|
{
|
||||||
|
if (nestedStrongHit == null || strongSprite == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return nestedStrongHit.IsHit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
var r = result.NewValue;
|
var r = result.NewValue;
|
||||||
|
|
||||||
// always ignore hitobjects that don't affect combo (drumroll ticks etc.)
|
// always ignore hitobjects that don't affect combo (drumroll ticks etc.)
|
||||||
if (r?.Judgement.AffectsCombo == false)
|
if (r?.Type.AffectsCombo() == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
passing = r == null || r.Type > HitResult.Miss;
|
passing = r == null || r.Type > HitResult.Miss;
|
||||||
|
@ -74,15 +74,23 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGood:
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGoodStrong:
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGreat:
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGreatStrong:
|
|
||||||
case TaikoSkinComponents.TaikoExplosionMiss:
|
case TaikoSkinComponents.TaikoExplosionMiss:
|
||||||
|
|
||||||
var sprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false);
|
var missSprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false);
|
||||||
if (sprite != null)
|
if (missSprite != null)
|
||||||
return new LegacyHitExplosion(sprite);
|
return new LegacyHitExplosion(missSprite);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
case TaikoSkinComponents.TaikoExplosionOk:
|
||||||
|
case TaikoSkinComponents.TaikoExplosionGreat:
|
||||||
|
|
||||||
|
var hitName = getHitName(taikoComponent.Component);
|
||||||
|
var hitSprite = this.GetAnimation(hitName, true, false);
|
||||||
|
var strongHitSprite = this.GetAnimation($"{hitName}k", true, false);
|
||||||
|
|
||||||
|
if (hitSprite != null)
|
||||||
|
return new LegacyHitExplosion(hitSprite, strongHitSprite);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -106,20 +114,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning
|
|||||||
case TaikoSkinComponents.TaikoExplosionMiss:
|
case TaikoSkinComponents.TaikoExplosionMiss:
|
||||||
return "taiko-hit0";
|
return "taiko-hit0";
|
||||||
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGood:
|
case TaikoSkinComponents.TaikoExplosionOk:
|
||||||
return "taiko-hit100";
|
return "taiko-hit100";
|
||||||
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGoodStrong:
|
|
||||||
return "taiko-hit100k";
|
|
||||||
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGreat:
|
case TaikoSkinComponents.TaikoExplosionGreat:
|
||||||
return "taiko-hit300";
|
return "taiko-hit300";
|
||||||
|
|
||||||
case TaikoSkinComponents.TaikoExplosionGreatStrong:
|
|
||||||
return "taiko-hit300k";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(component), "Invalid result type");
|
throw new ArgumentOutOfRangeException(nameof(component), $"Invalid component type: {component}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SampleChannel GetSample(ISampleInfo sampleInfo) => Source.GetSample(new LegacyTaikoSampleInfo(sampleInfo));
|
public override SampleChannel GetSample(ISampleInfo sampleInfo) => Source.GetSample(new LegacyTaikoSampleInfo(sampleInfo));
|
||||||
|
@ -16,10 +16,8 @@ namespace osu.Game.Rulesets.Taiko
|
|||||||
PlayfieldBackgroundRight,
|
PlayfieldBackgroundRight,
|
||||||
BarLine,
|
BarLine,
|
||||||
TaikoExplosionMiss,
|
TaikoExplosionMiss,
|
||||||
TaikoExplosionGood,
|
TaikoExplosionOk,
|
||||||
TaikoExplosionGoodStrong,
|
|
||||||
TaikoExplosionGreat,
|
TaikoExplosionGreat,
|
||||||
TaikoExplosionGreatStrong,
|
|
||||||
Scroller,
|
Scroller,
|
||||||
Mascot,
|
Mascot,
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
{
|
{
|
||||||
switch (Result.Type)
|
switch (Result.Type)
|
||||||
{
|
{
|
||||||
case HitResult.Good:
|
case HitResult.Ok:
|
||||||
JudgementBody.Colour = colours.GreenLight;
|
JudgementBody.Colour = colours.GreenLight;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ using osu.Framework.Graphics.Textures;
|
|||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Judgements;
|
using osu.Game.Rulesets.Taiko.Judgements;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
lastObjectHit = true;
|
lastObjectHit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.Judgement.AffectsCombo)
|
if (!result.Type.AffectsCombo())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lastObjectHit = result.IsHit;
|
lastObjectHit = result.IsHit;
|
||||||
@ -115,7 +116,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool triggerComboClear(JudgementResult judgementResult)
|
private bool triggerComboClear(JudgementResult judgementResult)
|
||||||
=> (judgementResult.ComboAtJudgement + 1) % 50 == 0 && judgementResult.Judgement.AffectsCombo && judgementResult.IsHit;
|
=> (judgementResult.ComboAtJudgement + 1) % 50 == 0 && judgementResult.Type.AffectsCombo() && judgementResult.IsHit;
|
||||||
|
|
||||||
private bool triggerSwellClear(JudgementResult judgementResult)
|
private bool triggerSwellClear(JudgementResult judgementResult)
|
||||||
=> judgementResult.Judgement is TaikoSwellJudgement && judgementResult.IsHit;
|
=> judgementResult.Judgement is TaikoSwellJudgement && judgementResult.IsHit;
|
||||||
|
@ -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 System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -10,7 +9,6 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.Taiko.Objects;
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.UI
|
namespace osu.Game.Rulesets.Taiko.UI
|
||||||
@ -50,39 +48,24 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Child = skinnable = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(JudgedObject)), _ => new DefaultHitExplosion(JudgedObject, result));
|
Child = skinnable = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(result)), _ => new DefaultHitExplosion(JudgedObject, result));
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaikoSkinComponents getComponentName(DrawableHitObject judgedObject)
|
private static TaikoSkinComponents getComponentName(HitResult result)
|
||||||
{
|
{
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case HitResult.Miss:
|
case HitResult.Miss:
|
||||||
return TaikoSkinComponents.TaikoExplosionMiss;
|
return TaikoSkinComponents.TaikoExplosionMiss;
|
||||||
|
|
||||||
case HitResult.Good:
|
case HitResult.Ok:
|
||||||
return useStrongExplosion(judgedObject)
|
return TaikoSkinComponents.TaikoExplosionOk;
|
||||||
? TaikoSkinComponents.TaikoExplosionGoodStrong
|
|
||||||
: TaikoSkinComponents.TaikoExplosionGood;
|
|
||||||
|
|
||||||
case HitResult.Great:
|
case HitResult.Great:
|
||||||
return useStrongExplosion(judgedObject)
|
return TaikoSkinComponents.TaikoExplosionGreat;
|
||||||
? TaikoSkinComponents.TaikoExplosionGreatStrong
|
|
||||||
: TaikoSkinComponents.TaikoExplosionGreat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(judgedObject), "Invalid result type");
|
throw new ArgumentOutOfRangeException(nameof(result), $"Invalid result type: {result}");
|
||||||
}
|
|
||||||
|
|
||||||
private bool useStrongExplosion(DrawableHitObject judgedObject)
|
|
||||||
{
|
|
||||||
if (!(judgedObject.HitObject is Hit))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!(judgedObject.NestedHitObjects.SingleOrDefault() is DrawableStrongNestedHit nestedHit))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return judgedObject.Result.Type == nestedHit.Result.Type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -215,16 +215,12 @@ namespace osu.Game.Rulesets.Taiko.UI
|
|||||||
private void addDrumRollHit(DrawableDrumRollTick drawableTick) =>
|
private void addDrumRollHit(DrawableDrumRollTick drawableTick) =>
|
||||||
drumRollHitContainer.Add(new DrawableFlyingHit(drawableTick));
|
drumRollHitContainer.Add(new DrawableFlyingHit(drawableTick));
|
||||||
|
|
||||||
/// <remarks>
|
private void addExplosion(DrawableHitObject drawableObject, HitResult result, HitType type)
|
||||||
/// As legacy skins have different explosions for singular and double strong hits,
|
|
||||||
/// explosion addition is scheduled to ensure that both hits are processed if they occur on the same frame.
|
|
||||||
/// </remarks>
|
|
||||||
private void addExplosion(DrawableHitObject drawableObject, HitResult result, HitType type) => Schedule(() =>
|
|
||||||
{
|
{
|
||||||
hitExplosionContainer.Add(new HitExplosion(drawableObject, result));
|
hitExplosionContainer.Add(new HitExplosion(drawableObject, result));
|
||||||
if (drawableObject.HitObject.Kiai)
|
if (drawableObject.HitObject.Kiai)
|
||||||
kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type));
|
kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type));
|
||||||
});
|
}
|
||||||
|
|
||||||
private class ProxyContainer : LifetimeManagementContainer
|
private class ProxyContainer : LifetimeManagementContainer
|
||||||
{
|
{
|
||||||
|
@ -170,7 +170,7 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
|
|
||||||
beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = 0 });
|
beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = 0 });
|
||||||
for (double time = 0; time < 5000; time += 100)
|
for (double time = 0; time < 5000; time += 100)
|
||||||
beatmap.HitObjects.Add(new JudgeableHitObject(false) { StartTime = time });
|
beatmap.HitObjects.Add(new JudgeableHitObject(HitResult.LargeBonus) { StartTime = time });
|
||||||
beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = 5000 });
|
beatmap.HitObjects.Add(new JudgeableHitObject { StartTime = 5000 });
|
||||||
|
|
||||||
createProcessor(beatmap);
|
createProcessor(beatmap);
|
||||||
@ -236,23 +236,23 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
|
|
||||||
private class JudgeableHitObject : HitObject
|
private class JudgeableHitObject : HitObject
|
||||||
{
|
{
|
||||||
private readonly bool affectsCombo;
|
private readonly HitResult maxResult;
|
||||||
|
|
||||||
public JudgeableHitObject(bool affectsCombo = true)
|
public JudgeableHitObject(HitResult maxResult = HitResult.Perfect)
|
||||||
{
|
{
|
||||||
this.affectsCombo = affectsCombo;
|
this.maxResult = maxResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Judgement CreateJudgement() => new TestJudgement(affectsCombo);
|
public override Judgement CreateJudgement() => new TestJudgement(maxResult);
|
||||||
protected override HitWindows CreateHitWindows() => new HitWindows();
|
protected override HitWindows CreateHitWindows() => new HitWindows();
|
||||||
|
|
||||||
private class TestJudgement : Judgement
|
private class TestJudgement : Judgement
|
||||||
{
|
{
|
||||||
public override bool AffectsCombo { get; }
|
public override HitResult MaxResult { get; }
|
||||||
|
|
||||||
public TestJudgement(bool affectsCombo)
|
public TestJudgement(HitResult maxResult)
|
||||||
{
|
{
|
||||||
AffectsCombo = affectsCombo;
|
MaxResult = maxResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,7 +263,7 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
public double Duration { get; set; } = 5000;
|
public double Duration { get; set; } = 5000;
|
||||||
|
|
||||||
public JudgeableLongHitObject()
|
public JudgeableLongHitObject()
|
||||||
: base(false)
|
: base(HitResult.LargeBonus)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,13 +17,13 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestNoScoreIncreaseFromMiss()
|
public void TestNoScoreIncreaseFromMiss()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<TestHitObject> { HitObjects = { new TestHitObject() } };
|
var beatmap = new Beatmap<HitObject> { HitObjects = { new HitObject() } };
|
||||||
|
|
||||||
var scoreProcessor = new ScoreProcessor();
|
var scoreProcessor = new ScoreProcessor();
|
||||||
scoreProcessor.ApplyBeatmap(beatmap);
|
scoreProcessor.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
// Apply a miss judgement
|
// Apply a miss judgement
|
||||||
scoreProcessor.ApplyResult(new JudgementResult(new TestHitObject(), new TestJudgement()) { Type = HitResult.Miss });
|
scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new TestJudgement()) { Type = HitResult.Miss });
|
||||||
|
|
||||||
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(0.0));
|
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(0.0));
|
||||||
}
|
}
|
||||||
@ -31,37 +31,25 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestOnlyBonusScore()
|
public void TestOnlyBonusScore()
|
||||||
{
|
{
|
||||||
var beatmap = new Beatmap<TestBonusHitObject> { HitObjects = { new TestBonusHitObject() } };
|
var beatmap = new Beatmap<HitObject> { HitObjects = { new HitObject() } };
|
||||||
|
|
||||||
var scoreProcessor = new ScoreProcessor();
|
var scoreProcessor = new ScoreProcessor();
|
||||||
scoreProcessor.ApplyBeatmap(beatmap);
|
scoreProcessor.ApplyBeatmap(beatmap);
|
||||||
|
|
||||||
// Apply a judgement
|
// Apply a judgement
|
||||||
scoreProcessor.ApplyResult(new JudgementResult(new TestBonusHitObject(), new TestBonusJudgement()) { Type = HitResult.Perfect });
|
scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new TestJudgement(HitResult.LargeBonus)) { Type = HitResult.LargeBonus });
|
||||||
|
|
||||||
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(100));
|
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(Judgement.LARGE_BONUS_SCORE));
|
||||||
}
|
|
||||||
|
|
||||||
private class TestHitObject : HitObject
|
|
||||||
{
|
|
||||||
public override Judgement CreateJudgement() => new TestJudgement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestJudgement : Judgement
|
private class TestJudgement : Judgement
|
||||||
{
|
{
|
||||||
protected override int NumericResultFor(HitResult result) => 100;
|
public override HitResult MaxResult { get; }
|
||||||
}
|
|
||||||
|
|
||||||
private class TestBonusHitObject : HitObject
|
public TestJudgement(HitResult maxResult = HitResult.Perfect)
|
||||||
{
|
{
|
||||||
public override Judgement CreateJudgement() => new TestBonusJudgement();
|
MaxResult = maxResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestBonusJudgement : Judgement
|
|
||||||
{
|
|
||||||
public override bool AffectsCombo => false;
|
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result) => 100;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Graphics.Audio;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
@ -106,9 +108,14 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
Beatmap.Value = new TestCustomSkinWorkingBeatmap(new OsuRuleset().RulesetInfo, Audio);
|
Beatmap.Value = new TestCustomSkinWorkingBeatmap(new OsuRuleset().RulesetInfo, Audio);
|
||||||
SelectedMods.Value = new[] { testedMod };
|
SelectedMods.Value = new[] { testedMod };
|
||||||
|
|
||||||
Add(gameplayContainer = new GameplayClockContainer(Beatmap.Value, 0));
|
var beatmapSkinSourceContainer = new BeatmapSkinProvidingContainer(Beatmap.Value.Skin);
|
||||||
|
|
||||||
gameplayContainer.Add(sample = new TestDrawableStoryboardSample(new StoryboardSampleInfo("test-sample", 1, 1))
|
Add(gameplayContainer = new GameplayClockContainer(Beatmap.Value, 0)
|
||||||
|
{
|
||||||
|
Child = beatmapSkinSourceContainer
|
||||||
|
});
|
||||||
|
|
||||||
|
beatmapSkinSourceContainer.Add(sample = new TestDrawableStoryboardSample(new StoryboardSampleInfo("test-sample", 1, 1))
|
||||||
{
|
{
|
||||||
Clock = gameplayContainer.GameplayClock
|
Clock = gameplayContainer.GameplayClock
|
||||||
});
|
});
|
||||||
@ -116,7 +123,7 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
|
|
||||||
AddStep("start", () => gameplayContainer.Start());
|
AddStep("start", () => gameplayContainer.Start());
|
||||||
|
|
||||||
AddAssert("sample playback rate matches mod rates", () => sample.Channel.AggregateFrequency.Value == expectedRate);
|
AddAssert("sample playback rate matches mod rates", () => sample.ChildrenOfType<DrawableSample>().First().AggregateFrequency.Value == expectedRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestSkin : LegacySkin
|
private class TestSkin : LegacySkin
|
||||||
@ -168,8 +175,6 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
: base(sampleInfo)
|
: base(sampleInfo)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public new SampleChannel Channel => base.Channel;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,10 +35,10 @@ namespace osu.Game.Tests.Rulesets.Scoring
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.Meh, 750_000)]
|
[TestCase(ScoringMode.Standardised, HitResult.Meh, 750_000)]
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.Good, 800_000)]
|
[TestCase(ScoringMode.Standardised, HitResult.Ok, 800_000)]
|
||||||
[TestCase(ScoringMode.Standardised, HitResult.Great, 1_000_000)]
|
[TestCase(ScoringMode.Standardised, HitResult.Great, 1_000_000)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Meh, 50)]
|
[TestCase(ScoringMode.Classic, HitResult.Meh, 50)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Good, 100)]
|
[TestCase(ScoringMode.Classic, HitResult.Ok, 100)]
|
||||||
[TestCase(ScoringMode.Classic, HitResult.Great, 300)]
|
[TestCase(ScoringMode.Classic, HitResult.Great, 300)]
|
||||||
public void TestSingleOsuHit(ScoringMode scoringMode, HitResult hitResult, int expectedScore)
|
public void TestSingleOsuHit(ScoringMode scoringMode, HitResult hitResult, int expectedScore)
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics.Audio;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Editing
|
||||||
|
{
|
||||||
|
public class TestSceneEditorSamplePlayback : EditorTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSlidingSampleStopsOnSeek()
|
||||||
|
{
|
||||||
|
DrawableSlider slider = null;
|
||||||
|
DrawableSample[] samples = null;
|
||||||
|
|
||||||
|
AddStep("get first slider", () =>
|
||||||
|
{
|
||||||
|
slider = Editor.ChildrenOfType<DrawableSlider>().OrderBy(s => s.HitObject.StartTime).First();
|
||||||
|
samples = slider.ChildrenOfType<DrawableSample>().ToArray();
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("start playback", () => EditorClock.Start());
|
||||||
|
|
||||||
|
AddUntilStep("wait for slider sliding then seek", () =>
|
||||||
|
{
|
||||||
|
if (!slider.Tracking.Value)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!samples.Any(s => s.Playing))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
EditorClock.Seek(20000);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("slider samples are not playing", () => samples.Length == 5 && samples.All(s => s.Played && !s.Playing));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Osu.Beatmaps;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Edit;
|
using osu.Game.Screens.Edit;
|
||||||
using osu.Game.Screens.Edit.Timing;
|
using osu.Game.Screens.Edit.Timing;
|
||||||
|
|
||||||
@ -17,16 +17,26 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[Cached(typeof(IBeatSnapProvider))]
|
[Cached(typeof(IBeatSnapProvider))]
|
||||||
private readonly EditorBeatmap editorBeatmap;
|
private readonly EditorBeatmap editorBeatmap;
|
||||||
|
|
||||||
|
protected override bool ScrollUsingMouseWheel => false;
|
||||||
|
|
||||||
public TestSceneTimingScreen()
|
public TestSceneTimingScreen()
|
||||||
{
|
{
|
||||||
editorBeatmap = new EditorBeatmap(new OsuBeatmap());
|
editorBeatmap = new EditorBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
|
Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap);
|
||||||
|
Beatmap.Disabled = true;
|
||||||
|
|
||||||
Child = new TimingScreen();
|
Child = new TimingScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
Beatmap.Disabled = false;
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new OsuSpriteText { Text = $@"Great: {hitWindows?.WindowFor(HitResult.Great)}" },
|
new OsuSpriteText { Text = $@"Great: {hitWindows?.WindowFor(HitResult.Great)}" },
|
||||||
new OsuSpriteText { Text = $@"Good: {hitWindows?.WindowFor(HitResult.Good)}" },
|
new OsuSpriteText { Text = $@"Good: {hitWindows?.WindowFor(HitResult.Ok)}" },
|
||||||
new OsuSpriteText { Text = $@"Meh: {hitWindows?.WindowFor(HitResult.Meh)}" },
|
new OsuSpriteText { Text = $@"Meh: {hitWindows?.WindowFor(HitResult.Meh)}" },
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -158,7 +158,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
public void TestQuickRetryFromFailedGameplay()
|
public void TestQuickRetryFromFailedGameplay()
|
||||||
{
|
{
|
||||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||||
AddStep("quick retry", () => Player.GameplayClockContainer.OfType<HotkeyRetryOverlay>().First().Action?.Invoke());
|
AddStep("quick retry", () => Player.GameplayClockContainer.ChildrenOfType<HotkeyRetryOverlay>().First().Action?.Invoke());
|
||||||
|
|
||||||
confirmExited();
|
confirmExited();
|
||||||
}
|
}
|
||||||
@ -167,7 +167,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
public void TestQuickExitFromFailedGameplay()
|
public void TestQuickExitFromFailedGameplay()
|
||||||
{
|
{
|
||||||
AddUntilStep("wait for fail", () => Player.HasFailed);
|
AddUntilStep("wait for fail", () => Player.HasFailed);
|
||||||
AddStep("quick exit", () => Player.GameplayClockContainer.OfType<HotkeyExitOverlay>().First().Action?.Invoke());
|
AddStep("quick exit", () => Player.GameplayClockContainer.ChildrenOfType<HotkeyExitOverlay>().First().Action?.Invoke());
|
||||||
|
|
||||||
confirmExited();
|
confirmExited();
|
||||||
}
|
}
|
||||||
@ -183,7 +183,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestQuickExitFromGameplay()
|
public void TestQuickExitFromGameplay()
|
||||||
{
|
{
|
||||||
AddStep("quick exit", () => Player.GameplayClockContainer.OfType<HotkeyExitOverlay>().First().Action?.Invoke());
|
AddStep("quick exit", () => Player.GameplayClockContainer.ChildrenOfType<HotkeyExitOverlay>().First().Action?.Invoke());
|
||||||
|
|
||||||
confirmExited();
|
confirmExited();
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
public class TestSceneSkinnableSound : OsuTestScene
|
public class TestSceneSkinnableSound : OsuTestScene
|
||||||
{
|
{
|
||||||
[Cached]
|
[Cached(typeof(ISamplePlaybackDisabler))]
|
||||||
private GameplayClock gameplayClock = new GameplayClock(new FramedClock());
|
private GameplayClock gameplayClock = new GameplayClock(new FramedClock());
|
||||||
|
|
||||||
private TestSkinSourceContainer skinSource;
|
private TestSkinSourceContainer skinSource;
|
||||||
private SkinnableSound skinnableSound;
|
private PausableSkinnableSound skinnableSound;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp() => Schedule(() =>
|
public void SetUp() => Schedule(() =>
|
||||||
@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
Clock = gameplayClock,
|
Clock = gameplayClock,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = skinnableSound = new SkinnableSound(new SampleInfo("normal-sliderslide"))
|
Child = skinnableSound = new PausableSkinnableSound(new SampleInfo("normal-sliderslide"))
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Tournament.Components
|
|||||||
{
|
{
|
||||||
base.Bindable = new Bindable<string>();
|
base.Bindable = new Bindable<string>();
|
||||||
|
|
||||||
((OsuTextBox)Control).OnCommit = (sender, newText) =>
|
((OsuTextBox)Control).OnCommit += (sender, newText) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -38,6 +38,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
Rank = Rank,
|
Rank = Rank,
|
||||||
Ruleset = ruleset,
|
Ruleset = ruleset,
|
||||||
Mods = mods,
|
Mods = mods,
|
||||||
|
IsLegacyScore = true
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Statistics != null)
|
if (Statistics != null)
|
||||||
|
@ -59,12 +59,13 @@ namespace osu.Game.Online.Chat
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Height = textbox_height,
|
Height = textbox_height,
|
||||||
PlaceholderText = "type your message",
|
PlaceholderText = "type your message",
|
||||||
OnCommit = postMessage,
|
|
||||||
ReleaseFocusOnCommit = false,
|
ReleaseFocusOnCommit = false,
|
||||||
HoldFocus = true,
|
HoldFocus = true,
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
textbox.OnCommit += postMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel.BindValueChanged(channelChanged);
|
Channel.BindValueChanged(channelChanged);
|
||||||
|
@ -11,9 +11,11 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Online.Leaderboards;
|
using osu.Game.Online.Leaderboards;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Users.Drawables;
|
using osu.Game.Users.Drawables;
|
||||||
|
using osu.Game.Utils;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -55,6 +57,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
highAccuracyColour = colours.GreenLight;
|
highAccuracyColour = colours.GreenLight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The statistics that appear in the table, in order of appearance.
|
||||||
|
/// </summary>
|
||||||
|
private readonly List<HitResult> statisticResultTypes = new List<HitResult>();
|
||||||
|
|
||||||
private bool showPerformancePoints;
|
private bool showPerformancePoints;
|
||||||
|
|
||||||
public void DisplayScores(IReadOnlyList<ScoreInfo> scores, bool showPerformanceColumn)
|
public void DisplayScores(IReadOnlyList<ScoreInfo> scores, bool showPerformanceColumn)
|
||||||
@ -65,11 +72,12 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
showPerformancePoints = showPerformanceColumn;
|
showPerformancePoints = showPerformanceColumn;
|
||||||
|
statisticResultTypes.Clear();
|
||||||
|
|
||||||
for (int i = 0; i < scores.Count; i++)
|
for (int i = 0; i < scores.Count; i++)
|
||||||
backgroundFlow.Add(new ScoreTableRowBackground(i, scores[i], row_height));
|
backgroundFlow.Add(new ScoreTableRowBackground(i, scores[i], row_height));
|
||||||
|
|
||||||
Columns = createHeaders(scores.FirstOrDefault());
|
Columns = createHeaders(scores);
|
||||||
Content = scores.Select((s, i) => createContent(i, s)).ToArray().ToRectangular();
|
Content = scores.Select((s, i) => createContent(i, s)).ToArray().ToRectangular();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +87,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
backgroundFlow.Clear();
|
backgroundFlow.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TableColumn[] createHeaders(ScoreInfo score)
|
private TableColumn[] createHeaders(IReadOnlyList<ScoreInfo> scores)
|
||||||
{
|
{
|
||||||
var columns = new List<TableColumn>
|
var columns = new List<TableColumn>
|
||||||
{
|
{
|
||||||
@ -92,10 +100,17 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 120))
|
new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 120))
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var statistic in score.SortedStatistics.Take(score.SortedStatistics.Count() - 1))
|
// All statistics across all scores, unordered.
|
||||||
columns.Add(new TableColumn(statistic.Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 35, maxSize: 60)));
|
var allScoreStatistics = scores.SelectMany(s => s.GetStatisticsForDisplay().Select(stat => stat.result)).ToHashSet();
|
||||||
|
|
||||||
columns.Add(new TableColumn(score.SortedStatistics.LastOrDefault().Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 45, maxSize: 95)));
|
foreach (var result in OrderAttributeUtils.GetValuesInOrder<HitResult>())
|
||||||
|
{
|
||||||
|
if (!allScoreStatistics.Contains(result))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
columns.Add(new TableColumn(result.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 35, maxSize: 60)));
|
||||||
|
statisticResultTypes.Add(result);
|
||||||
|
}
|
||||||
|
|
||||||
if (showPerformancePoints)
|
if (showPerformancePoints)
|
||||||
columns.Add(new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)));
|
columns.Add(new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)));
|
||||||
@ -148,13 +163,18 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var kvp in score.SortedStatistics)
|
var availableStatistics = score.GetStatisticsForDisplay().ToDictionary(tuple => tuple.result);
|
||||||
|
|
||||||
|
foreach (var result in statisticResultTypes)
|
||||||
{
|
{
|
||||||
|
if (!availableStatistics.TryGetValue(result, out var stat))
|
||||||
|
stat = (result, 0, null);
|
||||||
|
|
||||||
content.Add(new OsuSpriteText
|
content.Add(new OsuSpriteText
|
||||||
{
|
{
|
||||||
Text = $"{kvp.Value}",
|
Text = stat.maxCount == null ? $"{stat.count}" : $"{stat.count}/{stat.maxCount}",
|
||||||
Font = OsuFont.GetFont(size: text_size),
|
Font = OsuFont.GetFont(size: text_size),
|
||||||
Colour = kvp.Value == 0 ? Color4.Gray : Color4.White
|
Colour = stat.count == 0 ? Color4.Gray : Color4.White
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
ppColumn.Alpha = value.Beatmap?.Status == BeatmapSetOnlineStatus.Ranked ? 1 : 0;
|
ppColumn.Alpha = value.Beatmap?.Status == BeatmapSetOnlineStatus.Ranked ? 1 : 0;
|
||||||
ppColumn.Text = $@"{value.PP:N0}";
|
ppColumn.Text = $@"{value.PP:N0}";
|
||||||
|
|
||||||
statisticsColumns.ChildrenEnumerable = value.SortedStatistics.Select(kvp => createStatisticsColumn(kvp.Key, kvp.Value));
|
statisticsColumns.ChildrenEnumerable = value.GetStatisticsForDisplay().Select(s => createStatisticsColumn(s.result, s.count, s.maxCount));
|
||||||
modsColumn.Mods = value.Mods;
|
modsColumn.Mods = value.Mods;
|
||||||
|
|
||||||
if (scoreManager != null)
|
if (scoreManager != null)
|
||||||
@ -125,9 +125,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextColumn createStatisticsColumn(HitResult hitResult, int count) => new TextColumn(hitResult.GetDescription(), smallFont, bottom_columns_min_width)
|
private TextColumn createStatisticsColumn(HitResult hitResult, int count, int? maxCount) => new TextColumn(hitResult.GetDescription(), smallFont, bottom_columns_min_width)
|
||||||
{
|
{
|
||||||
Text = count.ToString()
|
Text = maxCount == null ? $"{count}" : $"{count}/{maxCount}"
|
||||||
};
|
};
|
||||||
|
|
||||||
private class InfoColumn : CompositeDrawable
|
private class InfoColumn : CompositeDrawable
|
||||||
|
@ -146,7 +146,6 @@ namespace osu.Game.Overlays
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Height = 1,
|
Height = 1,
|
||||||
PlaceholderText = "type your message",
|
PlaceholderText = "type your message",
|
||||||
OnCommit = postMessage,
|
|
||||||
ReleaseFocusOnCommit = false,
|
ReleaseFocusOnCommit = false,
|
||||||
HoldFocus = true,
|
HoldFocus = true,
|
||||||
}
|
}
|
||||||
@ -186,6 +185,8 @@ namespace osu.Game.Overlays
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
textbox.OnCommit += postMessage;
|
||||||
|
|
||||||
ChannelTabControl.Current.ValueChanged += current => channelManager.CurrentChannel.Value = current.NewValue;
|
ChannelTabControl.Current.ValueChanged += current => channelManager.CurrentChannel.Value = current.NewValue;
|
||||||
ChannelTabControl.ChannelSelectorActive.ValueChanged += active => ChannelSelectionOverlay.State.Value = active.NewValue ? Visibility.Visible : Visibility.Hidden;
|
ChannelTabControl.ChannelSelectorActive.ValueChanged += active => ChannelSelectionOverlay.State.Value = active.NewValue ? Visibility.Visible : Visibility.Hidden;
|
||||||
ChannelSelectionOverlay.State.ValueChanged += state =>
|
ChannelSelectionOverlay.State.ValueChanged += state =>
|
||||||
|
@ -75,7 +75,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
filter.Search.OnCommit = (sender, newText) =>
|
filter.Search.OnCommit += (sender, newText) =>
|
||||||
{
|
{
|
||||||
BeatmapInfo toSelect = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
|
BeatmapInfo toSelect = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
|
||||||
|
|
||||||
|
@ -236,7 +236,6 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
PlaceholderText = "password",
|
PlaceholderText = "password",
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
TabbableContentContainer = this,
|
TabbableContentContainer = this,
|
||||||
OnCommit = (sender, newText) => performLogin()
|
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
@ -276,6 +275,8 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
password.OnCommit += (sender, newText) => performLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool AcceptsFocus => true;
|
public override bool AcceptsFocus => true;
|
||||||
|
@ -7,10 +7,6 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
{
|
{
|
||||||
public class IgnoreJudgement : Judgement
|
public class IgnoreJudgement : Judgement
|
||||||
{
|
{
|
||||||
public override bool AffectsCombo => false;
|
public override HitResult MaxResult => HitResult.IgnoreHit;
|
||||||
|
|
||||||
protected override int NumericResultFor(HitResult result) => 0;
|
|
||||||
|
|
||||||
protected override double HealthIncreaseFor(HitResult result) => 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// 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;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
@ -11,31 +12,69 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Judgement
|
public class Judgement
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The score awarded for a small bonus.
|
||||||
|
/// </summary>
|
||||||
|
public const int SMALL_BONUS_SCORE = 10;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The score awarded for a large bonus.
|
||||||
|
/// </summary>
|
||||||
|
public const int LARGE_BONUS_SCORE = 50;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default health increase for a maximum judgement, as a proportion of total health.
|
/// The default health increase for a maximum judgement, as a proportion of total health.
|
||||||
/// By default, each maximum judgement restores 5% of total health.
|
/// By default, each maximum judgement restores 5% of total health.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected const double DEFAULT_MAX_HEALTH_INCREASE = 0.05;
|
protected const double DEFAULT_MAX_HEALTH_INCREASE = 0.05;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this <see cref="Judgement"/> should affect the current combo.
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("Has no effect. Use HitResult members instead (e.g. use small-tick or bonus to not affect combo).")] // Can be removed 20210328
|
||||||
|
public virtual bool AffectsCombo => true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this <see cref="Judgement"/> should be counted as base (combo) or bonus score.
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("Has no effect. Use HitResult members instead (e.g. use small-tick or bonus to not affect combo).")] // Can be removed 20210328
|
||||||
|
public virtual bool IsBonus => !AffectsCombo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum <see cref="HitResult"/> that can be achieved.
|
/// The maximum <see cref="HitResult"/> that can be achieved.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual HitResult MaxResult => HitResult.Perfect;
|
public virtual HitResult MaxResult => HitResult.Perfect;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this <see cref="Judgement"/> should affect the current combo.
|
/// The minimum <see cref="HitResult"/> that can be achieved - the inverse of <see cref="MaxResult"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool AffectsCombo => true;
|
public HitResult MinResult
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (MaxResult)
|
||||||
|
{
|
||||||
|
case HitResult.SmallBonus:
|
||||||
|
case HitResult.LargeBonus:
|
||||||
|
case HitResult.IgnoreHit:
|
||||||
|
return HitResult.IgnoreMiss;
|
||||||
|
|
||||||
/// <summary>
|
case HitResult.SmallTickHit:
|
||||||
/// Whether this <see cref="Judgement"/> should be counted as base (combo) or bonus score.
|
return HitResult.SmallTickMiss;
|
||||||
/// </summary>
|
|
||||||
public virtual bool IsBonus => !AffectsCombo;
|
case HitResult.LargeTickHit:
|
||||||
|
return HitResult.LargeTickMiss;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return HitResult.Miss;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The numeric score representation for the maximum achievable result.
|
/// The numeric score representation for the maximum achievable result.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int MaxNumericResult => NumericResultFor(MaxResult);
|
public int MaxNumericResult => ToNumericResult(MaxResult);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The health increase for the maximum achievable result.
|
/// The health increase for the maximum achievable result.
|
||||||
@ -47,14 +86,15 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="result">The <see cref="HitResult"/> to find the numeric score representation for.</param>
|
/// <param name="result">The <see cref="HitResult"/> to find the numeric score representation for.</param>
|
||||||
/// <returns>The numeric score representation of <paramref name="result"/>.</returns>
|
/// <returns>The numeric score representation of <paramref name="result"/>.</returns>
|
||||||
protected virtual int NumericResultFor(HitResult result) => result > HitResult.Miss ? 1 : 0;
|
[Obsolete("Has no effect. Use ToNumericResult(HitResult) (standardised across all rulesets).")] // Can be made non-virtual 20210328
|
||||||
|
protected virtual int NumericResultFor(HitResult result) => ToNumericResult(result);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the numeric score representation of a <see cref="JudgementResult"/>.
|
/// Retrieves the numeric score representation of a <see cref="JudgementResult"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="result">The <see cref="JudgementResult"/> to find the numeric score representation for.</param>
|
/// <param name="result">The <see cref="JudgementResult"/> to find the numeric score representation for.</param>
|
||||||
/// <returns>The numeric score representation of <paramref name="result"/>.</returns>
|
/// <returns>The numeric score representation of <paramref name="result"/>.</returns>
|
||||||
public int NumericResultFor(JudgementResult result) => NumericResultFor(result.Type);
|
public int NumericResultFor(JudgementResult result) => ToNumericResult(result.Type);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the numeric health increase of a <see cref="HitResult"/>.
|
/// Retrieves the numeric health increase of a <see cref="HitResult"/>.
|
||||||
@ -65,26 +105,44 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
{
|
{
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case HitResult.SmallTickHit:
|
||||||
|
return DEFAULT_MAX_HEALTH_INCREASE * 0.05;
|
||||||
|
|
||||||
|
case HitResult.SmallTickMiss:
|
||||||
|
return -DEFAULT_MAX_HEALTH_INCREASE * 0.05;
|
||||||
|
|
||||||
|
case HitResult.LargeTickHit:
|
||||||
|
return DEFAULT_MAX_HEALTH_INCREASE * 0.1;
|
||||||
|
|
||||||
|
case HitResult.LargeTickMiss:
|
||||||
|
return -DEFAULT_MAX_HEALTH_INCREASE * 0.1;
|
||||||
|
|
||||||
case HitResult.Miss:
|
case HitResult.Miss:
|
||||||
return -DEFAULT_MAX_HEALTH_INCREASE;
|
return -DEFAULT_MAX_HEALTH_INCREASE;
|
||||||
|
|
||||||
case HitResult.Meh:
|
case HitResult.Meh:
|
||||||
return -DEFAULT_MAX_HEALTH_INCREASE * 0.05;
|
return -DEFAULT_MAX_HEALTH_INCREASE * 0.5;
|
||||||
|
|
||||||
case HitResult.Ok:
|
case HitResult.Ok:
|
||||||
return -DEFAULT_MAX_HEALTH_INCREASE * 0.01;
|
return -DEFAULT_MAX_HEALTH_INCREASE * 0.3;
|
||||||
|
|
||||||
case HitResult.Good:
|
case HitResult.Good:
|
||||||
return DEFAULT_MAX_HEALTH_INCREASE * 0.5;
|
return DEFAULT_MAX_HEALTH_INCREASE * 0.1;
|
||||||
|
|
||||||
case HitResult.Great:
|
case HitResult.Great:
|
||||||
return DEFAULT_MAX_HEALTH_INCREASE;
|
return DEFAULT_MAX_HEALTH_INCREASE * 0.8;
|
||||||
|
|
||||||
case HitResult.Perfect:
|
case HitResult.Perfect:
|
||||||
return DEFAULT_MAX_HEALTH_INCREASE * 1.05;
|
return DEFAULT_MAX_HEALTH_INCREASE;
|
||||||
|
|
||||||
default:
|
case HitResult.SmallBonus:
|
||||||
return 0;
|
return DEFAULT_MAX_HEALTH_INCREASE * 0.1;
|
||||||
|
|
||||||
|
case HitResult.LargeBonus:
|
||||||
|
return DEFAULT_MAX_HEALTH_INCREASE * 0.2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +153,42 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
/// <returns>The numeric health increase of <paramref name="result"/>.</returns>
|
/// <returns>The numeric health increase of <paramref name="result"/>.</returns>
|
||||||
public double HealthIncreaseFor(JudgementResult result) => HealthIncreaseFor(result.Type);
|
public double HealthIncreaseFor(JudgementResult result) => HealthIncreaseFor(result.Type);
|
||||||
|
|
||||||
public override string ToString() => $"AffectsCombo:{AffectsCombo} MaxResult:{MaxResult} MaxScore:{MaxNumericResult}";
|
public override string ToString() => $"MaxResult:{MaxResult} MaxScore:{MaxNumericResult}";
|
||||||
|
|
||||||
|
public static int ToNumericResult(HitResult result)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case HitResult.SmallTickHit:
|
||||||
|
return 10;
|
||||||
|
|
||||||
|
case HitResult.LargeTickHit:
|
||||||
|
return 30;
|
||||||
|
|
||||||
|
case HitResult.Meh:
|
||||||
|
return 50;
|
||||||
|
|
||||||
|
case HitResult.Ok:
|
||||||
|
return 100;
|
||||||
|
|
||||||
|
case HitResult.Good:
|
||||||
|
return 200;
|
||||||
|
|
||||||
|
case HitResult.Great:
|
||||||
|
return 300;
|
||||||
|
|
||||||
|
case HitResult.Perfect:
|
||||||
|
return 350;
|
||||||
|
|
||||||
|
case HitResult.SmallBonus:
|
||||||
|
return SMALL_BONUS_SCORE;
|
||||||
|
|
||||||
|
case HitResult.LargeBonus:
|
||||||
|
return LARGE_BONUS_SCORE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether a successful hit occurred.
|
/// Whether a successful hit occurred.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsHit => Type > HitResult.Miss;
|
public bool IsHit => Type.IsHit();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="JudgementResult"/>.
|
/// Creates a new <see cref="JudgementResult"/>.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// 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 osu.Framework.Audio.Sample;
|
using osu.Framework.Graphics.Audio;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IApplicableToSample : IApplicableMod
|
public interface IApplicableToSample : IApplicableMod
|
||||||
{
|
{
|
||||||
void ApplyToSample(SampleChannel sample);
|
void ApplyToSample(DrawableSample sample);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,10 +52,10 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
public class NightcoreBeatContainer : BeatSyncedContainer
|
public class NightcoreBeatContainer : BeatSyncedContainer
|
||||||
{
|
{
|
||||||
private SkinnableSound hatSample;
|
private PausableSkinnableSound hatSample;
|
||||||
private SkinnableSound clapSample;
|
private PausableSkinnableSound clapSample;
|
||||||
private SkinnableSound kickSample;
|
private PausableSkinnableSound kickSample;
|
||||||
private SkinnableSound finishSample;
|
private PausableSkinnableSound finishSample;
|
||||||
|
|
||||||
private int? firstBeat;
|
private int? firstBeat;
|
||||||
|
|
||||||
@ -69,10 +69,10 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
hatSample = new SkinnableSound(new SampleInfo("nightcore-hat")),
|
hatSample = new PausableSkinnableSound(new SampleInfo("nightcore-hat")),
|
||||||
clapSample = new SkinnableSound(new SampleInfo("nightcore-clap")),
|
clapSample = new PausableSkinnableSound(new SampleInfo("nightcore-clap")),
|
||||||
kickSample = new SkinnableSound(new SampleInfo("nightcore-kick")),
|
kickSample = new PausableSkinnableSound(new SampleInfo("nightcore-kick")),
|
||||||
finishSample = new SkinnableSound(new SampleInfo("nightcore-finish")),
|
finishSample = new PausableSkinnableSound(new SampleInfo("nightcore-finish")),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,8 +16,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
public override string Description => "SS or quit.";
|
public override string Description => "SS or quit.";
|
||||||
|
|
||||||
protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
|
protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
|
||||||
=> !(result.Judgement is IgnoreJudgement)
|
=> result.Type.AffectsAccuracy()
|
||||||
&& result.Judgement.AffectsCombo
|
|
||||||
&& result.Type != result.Judgement.MaxResult;
|
&& result.Type != result.Judgement.MaxResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
// 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.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Sample;
|
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Audio;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
track.AddAdjustment(AdjustableProperty.Tempo, SpeedChange);
|
track.AddAdjustment(AdjustableProperty.Tempo, SpeedChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void ApplyToSample(SampleChannel sample)
|
public virtual void ApplyToSample(DrawableSample sample)
|
||||||
{
|
{
|
||||||
sample.AddAdjustment(AdjustableProperty.Frequency, SpeedChange);
|
sample.AddAdjustment(AdjustableProperty.Frequency, SpeedChange);
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
healthProcessor.FailConditions += FailCondition;
|
healthProcessor.FailConditions += FailCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) => !result.IsHit && result.Judgement.AffectsCombo;
|
protected virtual bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
|
||||||
|
=> result.Type.AffectsCombo()
|
||||||
|
&& !result.IsHit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,11 @@ using System.Linq;
|
|||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.UI;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Game.Rulesets.UI;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
AdjustPitch.TriggerChange();
|
AdjustPitch.TriggerChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyToSample(SampleChannel sample)
|
public void ApplyToSample(DrawableSample sample)
|
||||||
{
|
{
|
||||||
sample.AddAdjustment(AdjustableProperty.Frequency, SpeedChange);
|
sample.AddAdjustment(AdjustableProperty.Frequency, SpeedChange);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Extensions.TypeExtensions;
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -17,7 +18,6 @@ using osu.Game.Rulesets.Objects.Types;
|
|||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Screens.Play;
|
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Objects.Drawables
|
namespace osu.Game.Rulesets.Objects.Drawables
|
||||||
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>(Color4.Gray);
|
public readonly Bindable<Color4> AccentColour = new Bindable<Color4>(Color4.Gray);
|
||||||
|
|
||||||
protected SkinnableSound Samples { get; private set; }
|
protected PausableSkinnableSound Samples { get; private set; }
|
||||||
|
|
||||||
public virtual IEnumerable<HitSampleInfo> GetSamples() => HitObject.Samples;
|
public virtual IEnumerable<HitSampleInfo> GetSamples() => HitObject.Samples;
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
|
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Samples = new SkinnableSound(samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)));
|
Samples = new PausableSkinnableSound(samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)));
|
||||||
AddInternal(Samples);
|
AddInternal(Samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,9 +359,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
|
||||||
private GameplayClock gameplayClock { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculate the position to be used for sample playback at a specified X position (0..1).
|
/// Calculate the position to be used for sample playback at a specified X position (0..1).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -374,24 +371,24 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
return balance_adjust_amount * (userPositionalHitSounds.Value ? position - 0.5f : 0);
|
return balance_adjust_amount * (userPositionalHitSounds.Value ? position - 0.5f : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether samples should currently be playing. Will be false during seek operations.
|
|
||||||
/// </summary>
|
|
||||||
protected bool ShouldPlaySamples => gameplayClock?.IsSeeking != true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Plays all the hit sounds for this <see cref="DrawableHitObject"/>.
|
/// Plays all the hit sounds for this <see cref="DrawableHitObject"/>.
|
||||||
/// This is invoked automatically when this <see cref="DrawableHitObject"/> is hit.
|
/// This is invoked automatically when this <see cref="DrawableHitObject"/> is hit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void PlaySamples()
|
public virtual void PlaySamples()
|
||||||
{
|
{
|
||||||
if (Samples != null && ShouldPlaySamples)
|
if (Samples != null)
|
||||||
{
|
{
|
||||||
Samples.Balance.Value = CalculateSamplePlaybackBalance(SamplePlaybackPosition);
|
Samples.Balance.Value = CalculateSamplePlaybackBalance(SamplePlaybackPosition);
|
||||||
Samples.Play();
|
Samples.Play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stops playback of all samples. Automatically called when <see cref="DrawableHitObject{TObject}"/>'s lifetime has been exceeded.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void StopAllSamples() => Samples?.Stop();
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
@ -460,6 +457,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
foreach (var nested in NestedHitObjects)
|
foreach (var nested in NestedHitObjects)
|
||||||
nested.OnKilled();
|
nested.OnKilled();
|
||||||
|
|
||||||
|
StopAllSamples();
|
||||||
|
|
||||||
UpdateResult(false);
|
UpdateResult(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,6 +474,30 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
if (!Result.HasResult)
|
if (!Result.HasResult)
|
||||||
throw new InvalidOperationException($"{GetType().ReadableName()} applied a {nameof(JudgementResult)} but did not update {nameof(JudgementResult.Type)}.");
|
throw new InvalidOperationException($"{GetType().ReadableName()} applied a {nameof(JudgementResult)} but did not update {nameof(JudgementResult.Type)}.");
|
||||||
|
|
||||||
|
// Some (especially older) rulesets use scorable judgements instead of the newer ignorehit/ignoremiss judgements.
|
||||||
|
// Can be removed 20210328
|
||||||
|
if (Result.Judgement.MaxResult == HitResult.IgnoreHit)
|
||||||
|
{
|
||||||
|
HitResult originalType = Result.Type;
|
||||||
|
|
||||||
|
if (Result.Type == HitResult.Miss)
|
||||||
|
Result.Type = HitResult.IgnoreMiss;
|
||||||
|
else if (Result.Type >= HitResult.Meh && Result.Type <= HitResult.Perfect)
|
||||||
|
Result.Type = HitResult.IgnoreHit;
|
||||||
|
|
||||||
|
if (Result.Type != originalType)
|
||||||
|
{
|
||||||
|
Logger.Log($"{GetType().ReadableName()} applied an invalid hit result ({originalType}) when {nameof(HitResult.IgnoreMiss)} or {nameof(HitResult.IgnoreHit)} is expected.\n"
|
||||||
|
+ $"This has been automatically adjusted to {Result.Type}, and support will be removed from 2020-03-28 onwards.", level: LogLevel.Important);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Result.Type.IsValidHitResult(Result.Judgement.MinResult, Result.Judgement.MaxResult))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"{GetType().ReadableName()} applied an invalid hit result (was: {Result.Type}, expected: [{Result.Judgement.MinResult} ... {Result.Judgement.MaxResult}]).");
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure that the judgement is given a valid time offset, because this may not get set by the caller
|
// Ensure that the judgement is given a valid time offset, because this may not get set by the caller
|
||||||
var endTime = HitObject.GetEndTime();
|
var endTime = HitObject.GetEndTime();
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
{
|
{
|
||||||
base.ApplyResultInternal(result);
|
base.ApplyResultInternal(result);
|
||||||
|
|
||||||
if (!result.Judgement.IsBonus)
|
if (!result.Type.IsBonus())
|
||||||
healthIncreases.Add((result.HitObject.GetEndTime() + result.TimeOffset, GetHealthIncreaseFor(result)));
|
healthIncreases.Add((result.HitObject.GetEndTime() + result.TimeOffset, GetHealthIncreaseFor(result)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,15 +2,19 @@
|
|||||||
// 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.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using osu.Game.Utils;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Scoring
|
namespace osu.Game.Rulesets.Scoring
|
||||||
{
|
{
|
||||||
|
[HasOrderedElements]
|
||||||
public enum HitResult
|
public enum HitResult
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that the object has not been judged yet.
|
/// Indicates that the object has not been judged yet.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description(@"")]
|
[Description(@"")]
|
||||||
|
[Order(14)]
|
||||||
None,
|
None,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -21,47 +25,169 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// "too far in the future). It should also define when a forced miss should be triggered (as a result of no user input in time).
|
/// "too far in the future). It should also define when a forced miss should be triggered (as a result of no user input in time).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Description(@"Miss")]
|
[Description(@"Miss")]
|
||||||
|
[Order(5)]
|
||||||
Miss,
|
Miss,
|
||||||
|
|
||||||
[Description(@"Meh")]
|
[Description(@"Meh")]
|
||||||
|
[Order(4)]
|
||||||
Meh,
|
Meh,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Optional judgement.
|
|
||||||
/// </summary>
|
|
||||||
[Description(@"OK")]
|
[Description(@"OK")]
|
||||||
|
[Order(3)]
|
||||||
Ok,
|
Ok,
|
||||||
|
|
||||||
[Description(@"Good")]
|
[Description(@"Good")]
|
||||||
|
[Order(2)]
|
||||||
Good,
|
Good,
|
||||||
|
|
||||||
[Description(@"Great")]
|
[Description(@"Great")]
|
||||||
|
[Order(1)]
|
||||||
Great,
|
Great,
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Optional judgement.
|
|
||||||
/// </summary>
|
|
||||||
[Description(@"Perfect")]
|
[Description(@"Perfect")]
|
||||||
|
[Order(0)]
|
||||||
Perfect,
|
Perfect,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates small tick miss.
|
/// Indicates small tick miss.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Order(11)]
|
||||||
SmallTickMiss,
|
SmallTickMiss,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates a small tick hit.
|
/// Indicates a small tick hit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Description(@"S Tick")]
|
||||||
|
[Order(7)]
|
||||||
SmallTickHit,
|
SmallTickHit,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates a large tick miss.
|
/// Indicates a large tick miss.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Order(10)]
|
||||||
LargeTickMiss,
|
LargeTickMiss,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates a large tick hit.
|
/// Indicates a large tick hit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
LargeTickHit
|
[Description(@"L Tick")]
|
||||||
|
[Order(6)]
|
||||||
|
LargeTickHit,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a small bonus.
|
||||||
|
/// </summary>
|
||||||
|
[Description("S Bonus")]
|
||||||
|
[Order(9)]
|
||||||
|
SmallBonus,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a large bonus.
|
||||||
|
/// </summary>
|
||||||
|
[Description("L Bonus")]
|
||||||
|
[Order(8)]
|
||||||
|
LargeBonus,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a miss that should be ignored for scoring purposes.
|
||||||
|
/// </summary>
|
||||||
|
[Order(13)]
|
||||||
|
IgnoreMiss,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates a hit that should be ignored for scoring purposes.
|
||||||
|
/// </summary>
|
||||||
|
[Order(12)]
|
||||||
|
IgnoreHit,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class HitResultExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a <see cref="HitResult"/> increases/decreases the combo, and affects the combo portion of the score.
|
||||||
|
/// </summary>
|
||||||
|
public static bool AffectsCombo(this HitResult result)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case HitResult.Miss:
|
||||||
|
case HitResult.Meh:
|
||||||
|
case HitResult.Ok:
|
||||||
|
case HitResult.Good:
|
||||||
|
case HitResult.Great:
|
||||||
|
case HitResult.Perfect:
|
||||||
|
case HitResult.LargeTickHit:
|
||||||
|
case HitResult.LargeTickMiss:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a <see cref="HitResult"/> affects the accuracy portion of the score.
|
||||||
|
/// </summary>
|
||||||
|
public static bool AffectsAccuracy(this HitResult result)
|
||||||
|
=> IsScorable(result) && !IsBonus(result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a <see cref="HitResult"/> should be counted as bonus score.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsBonus(this HitResult result)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case HitResult.SmallBonus:
|
||||||
|
case HitResult.LargeBonus:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a <see cref="HitResult"/> represents a successful hit.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsHit(this HitResult result)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case HitResult.None:
|
||||||
|
case HitResult.IgnoreMiss:
|
||||||
|
case HitResult.Miss:
|
||||||
|
case HitResult.SmallTickMiss:
|
||||||
|
case HitResult.LargeTickMiss:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a <see cref="HitResult"/> is scorable.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsScorable(this HitResult result) => result >= HitResult.Miss && result < HitResult.IgnoreMiss;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a <see cref="HitResult"/> is valid within a given <see cref="HitResult"/> range.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The <see cref="HitResult"/> to check.</param>
|
||||||
|
/// <param name="minResult">The minimum <see cref="HitResult"/>.</param>
|
||||||
|
/// <param name="maxResult">The maximum <see cref="HitResult"/>.</param>
|
||||||
|
/// <returns>Whether <see cref="HitResult"/> falls between <paramref name="minResult"/> and <paramref name="maxResult"/>.</returns>
|
||||||
|
public static bool IsValidHitResult(this HitResult result, HitResult minResult, HitResult maxResult)
|
||||||
|
{
|
||||||
|
if (result == HitResult.None)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (result == minResult || result == maxResult)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Debug.Assert(minResult <= maxResult);
|
||||||
|
return result > minResult && result < maxResult;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
private double maxBaseScore;
|
private double maxBaseScore;
|
||||||
private double rollingMaxBaseScore;
|
private double rollingMaxBaseScore;
|
||||||
private double baseScore;
|
private double baseScore;
|
||||||
private double bonusScore;
|
|
||||||
|
|
||||||
private readonly List<HitEvent> hitEvents = new List<HitEvent>();
|
private readonly List<HitEvent> hitEvents = new List<HitEvent>();
|
||||||
private HitObject lastHitObject;
|
private HitObject lastHitObject;
|
||||||
@ -116,14 +115,15 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
if (result.FailedAtJudgement)
|
if (result.FailedAtJudgement)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (result.Judgement.AffectsCombo)
|
if (!result.Type.IsScorable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (result.Type.AffectsCombo())
|
||||||
{
|
{
|
||||||
switch (result.Type)
|
switch (result.Type)
|
||||||
{
|
{
|
||||||
case HitResult.None:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HitResult.Miss:
|
case HitResult.Miss:
|
||||||
|
case HitResult.LargeTickMiss:
|
||||||
Combo.Value = 0;
|
Combo.Value = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -133,22 +133,16 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double scoreIncrease = result.Type == HitResult.Miss ? 0 : result.Judgement.NumericResultFor(result);
|
double scoreIncrease = result.Type.IsHit() ? result.Judgement.NumericResultFor(result) : 0;
|
||||||
|
|
||||||
if (result.Judgement.IsBonus)
|
if (!result.Type.IsBonus())
|
||||||
{
|
{
|
||||||
if (result.IsHit)
|
|
||||||
bonusScore += scoreIncrease;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (result.HasResult)
|
|
||||||
scoreResultCounts[result.Type] = scoreResultCounts.GetOrDefault(result.Type) + 1;
|
|
||||||
|
|
||||||
baseScore += scoreIncrease;
|
baseScore += scoreIncrease;
|
||||||
rollingMaxBaseScore += result.Judgement.MaxNumericResult;
|
rollingMaxBaseScore += result.Judgement.MaxNumericResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scoreResultCounts[result.Type] = scoreResultCounts.GetOrDefault(result.Type) + 1;
|
||||||
|
|
||||||
hitEvents.Add(CreateHitEvent(result));
|
hitEvents.Add(CreateHitEvent(result));
|
||||||
lastHitObject = result.HitObject;
|
lastHitObject = result.HitObject;
|
||||||
|
|
||||||
@ -171,22 +165,19 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
if (result.FailedAtJudgement)
|
if (result.FailedAtJudgement)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
double scoreIncrease = result.Type == HitResult.Miss ? 0 : result.Judgement.NumericResultFor(result);
|
if (!result.Type.IsScorable())
|
||||||
|
return;
|
||||||
|
|
||||||
if (result.Judgement.IsBonus)
|
double scoreIncrease = result.Type.IsHit() ? result.Judgement.NumericResultFor(result) : 0;
|
||||||
{
|
|
||||||
if (result.IsHit)
|
|
||||||
bonusScore -= scoreIncrease;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (result.HasResult)
|
|
||||||
scoreResultCounts[result.Type] = scoreResultCounts.GetOrDefault(result.Type) - 1;
|
|
||||||
|
|
||||||
|
if (!result.Type.IsBonus())
|
||||||
|
{
|
||||||
baseScore -= scoreIncrease;
|
baseScore -= scoreIncrease;
|
||||||
rollingMaxBaseScore -= result.Judgement.MaxNumericResult;
|
rollingMaxBaseScore -= result.Judgement.MaxNumericResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scoreResultCounts[result.Type] = scoreResultCounts.GetOrDefault(result.Type) - 1;
|
||||||
|
|
||||||
Debug.Assert(hitEvents.Count > 0);
|
Debug.Assert(hitEvents.Count > 0);
|
||||||
lastHitObject = hitEvents[^1].LastHitObject;
|
lastHitObject = hitEvents[^1].LastHitObject;
|
||||||
hitEvents.RemoveAt(hitEvents.Count - 1);
|
hitEvents.RemoveAt(hitEvents.Count - 1);
|
||||||
@ -207,7 +198,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
return GetScore(mode, maxHighestCombo,
|
return GetScore(mode, maxHighestCombo,
|
||||||
maxBaseScore > 0 ? baseScore / maxBaseScore : 0,
|
maxBaseScore > 0 ? baseScore / maxBaseScore : 0,
|
||||||
maxHighestCombo > 0 ? (double)HighestCombo.Value / maxHighestCombo : 0,
|
maxHighestCombo > 0 ? (double)HighestCombo.Value / maxHighestCombo : 0,
|
||||||
bonusScore);
|
scoreResultCounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -217,9 +208,9 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// <param name="maxCombo">The maximum combo achievable in the beatmap.</param>
|
/// <param name="maxCombo">The maximum combo achievable in the beatmap.</param>
|
||||||
/// <param name="accuracyRatio">The accuracy percentage achieved by the player.</param>
|
/// <param name="accuracyRatio">The accuracy percentage achieved by the player.</param>
|
||||||
/// <param name="comboRatio">The proportion of <paramref name="maxCombo"/> achieved by the player.</param>
|
/// <param name="comboRatio">The proportion of <paramref name="maxCombo"/> achieved by the player.</param>
|
||||||
/// <param name="bonusScore">Any bonus score to be added.</param>
|
/// <param name="statistics">Any statistics to be factored in.</param>
|
||||||
/// <returns>The total score.</returns>
|
/// <returns>The total score.</returns>
|
||||||
public double GetScore(ScoringMode mode, int maxCombo, double accuracyRatio, double comboRatio, double bonusScore)
|
public double GetScore(ScoringMode mode, int maxCombo, double accuracyRatio, double comboRatio, Dictionary<HitResult, int> statistics)
|
||||||
{
|
{
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
@ -228,14 +219,18 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
double accuracyScore = accuracyPortion * accuracyRatio;
|
double accuracyScore = accuracyPortion * accuracyRatio;
|
||||||
double comboScore = comboPortion * comboRatio;
|
double comboScore = comboPortion * comboRatio;
|
||||||
|
|
||||||
return (max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier;
|
return (max_score * (accuracyScore + comboScore) + getBonusScore(statistics)) * scoreMultiplier;
|
||||||
|
|
||||||
case ScoringMode.Classic:
|
case ScoringMode.Classic:
|
||||||
// should emulate osu-stable's scoring as closely as we can (https://osu.ppy.sh/help/wiki/Score/ScoreV1)
|
// should emulate osu-stable's scoring as closely as we can (https://osu.ppy.sh/help/wiki/Score/ScoreV1)
|
||||||
return bonusScore + (accuracyRatio * maxCombo * 300) * (1 + Math.Max(0, (comboRatio * maxCombo) - 1) * scoreMultiplier / 25);
|
return getBonusScore(statistics) + (accuracyRatio * maxCombo * 300) * (1 + Math.Max(0, (comboRatio * maxCombo) - 1) * scoreMultiplier / 25);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double getBonusScore(Dictionary<HitResult, int> statistics)
|
||||||
|
=> statistics.GetOrDefault(HitResult.SmallBonus) * Judgement.SMALL_BONUS_SCORE
|
||||||
|
+ statistics.GetOrDefault(HitResult.LargeBonus) * Judgement.LARGE_BONUS_SCORE;
|
||||||
|
|
||||||
private ScoreRank rankFrom(double acc)
|
private ScoreRank rankFrom(double acc)
|
||||||
{
|
{
|
||||||
if (acc == 1)
|
if (acc == 1)
|
||||||
@ -282,7 +277,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
|
|
||||||
baseScore = 0;
|
baseScore = 0;
|
||||||
rollingMaxBaseScore = 0;
|
rollingMaxBaseScore = 0;
|
||||||
bonusScore = 0;
|
|
||||||
|
|
||||||
TotalScore.Value = 0;
|
TotalScore.Value = 0;
|
||||||
Accuracy.Value = 1;
|
Accuracy.Value = 1;
|
||||||
@ -309,9 +303,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
score.Rank = Rank.Value;
|
score.Rank = Rank.Value;
|
||||||
score.Date = DateTimeOffset.Now;
|
score.Date = DateTimeOffset.Now;
|
||||||
|
|
||||||
var hitWindows = CreateHitWindows();
|
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r.IsScorable()))
|
||||||
|
|
||||||
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => r > HitResult.None && hitWindows.IsHitResultAllowed(r)))
|
|
||||||
score.Statistics[result] = GetStatistic(result);
|
score.Statistics[result] = GetStatistic(result);
|
||||||
|
|
||||||
score.HitEvents = hitEvents;
|
score.HitEvents = hitEvents;
|
||||||
@ -320,6 +312,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a <see cref="HitWindows"/> for this processor.
|
/// Create a <see cref="HitWindows"/> for this processor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Method is now unused.")] // Can be removed 20210328
|
||||||
public virtual HitWindows CreateHitWindows() => new HitWindows();
|
public virtual HitWindows CreateHitWindows() => new HitWindows();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,10 @@
|
|||||||
// 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;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
@ -59,7 +62,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
{
|
{
|
||||||
if (clock != null)
|
if (clock != null)
|
||||||
{
|
{
|
||||||
stabilityGameplayClock.ParentGameplayClock = parentGameplayClock = clock;
|
parentGameplayClock = stabilityGameplayClock.ParentGameplayClock = clock;
|
||||||
GameplayClock.IsPaused.BindTo(clock.IsPaused);
|
GameplayClock.IsPaused.BindTo(clock.IsPaused);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,7 +218,9 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
private class StabilityGameplayClock : GameplayClock
|
private class StabilityGameplayClock : GameplayClock
|
||||||
{
|
{
|
||||||
public IFrameBasedClock ParentGameplayClock;
|
public GameplayClock ParentGameplayClock;
|
||||||
|
|
||||||
|
public override IEnumerable<Bindable<double>> NonGameplayAdjustments => ParentGameplayClock?.NonGameplayAdjustments ?? Enumerable.Empty<Bindable<double>>();
|
||||||
|
|
||||||
public StabilityGameplayClock(FramedClock underlyingClock)
|
public StabilityGameplayClock(FramedClock underlyingClock)
|
||||||
: base(underlyingClock)
|
: base(underlyingClock)
|
||||||
|
@ -28,37 +28,9 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int? GetCount300(this ScoreInfo scoreInfo)
|
public static int? GetCount300(this ScoreInfo scoreInfo) => getCount(scoreInfo, HitResult.Great);
|
||||||
{
|
|
||||||
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
case 3:
|
|
||||||
return getCount(scoreInfo, HitResult.Great);
|
|
||||||
|
|
||||||
case 2:
|
public static void SetCount300(this ScoreInfo scoreInfo, int value) => scoreInfo.Statistics[HitResult.Great] = value;
|
||||||
return getCount(scoreInfo, HitResult.Perfect);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetCount300(this ScoreInfo scoreInfo, int value)
|
|
||||||
{
|
|
||||||
switch (scoreInfo.Ruleset?.ID ?? scoreInfo.RulesetID)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
case 3:
|
|
||||||
scoreInfo.Statistics[HitResult.Great] = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
scoreInfo.Statistics[HitResult.Perfect] = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int? GetCountKatu(this ScoreInfo scoreInfo)
|
public static int? GetCountKatu(this ScoreInfo scoreInfo)
|
||||||
{
|
{
|
||||||
@ -94,8 +66,6 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
return getCount(scoreInfo, HitResult.Good);
|
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
return getCount(scoreInfo, HitResult.Ok);
|
return getCount(scoreInfo, HitResult.Ok);
|
||||||
|
|
||||||
@ -112,9 +82,6 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
scoreInfo.Statistics[HitResult.Good] = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
scoreInfo.Statistics[HitResult.Ok] = value;
|
scoreInfo.Statistics[HitResult.Ok] = value;
|
||||||
break;
|
break;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user